From 9ad969a3316c1c023a82dfc785e099c012d952b2 Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 17:03:37 +0900 Subject: [PATCH 01/12] =?UTF-8?q?feat:=20=EB=B8=94=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EA=B8=80=20=EB=AA=A9=EB=A1=9D=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BlogPage/components/PostList/index.tsx | 135 ++++++++++++++++++ .../BlogPage/components/PostList/style.ts | 17 +++ 2 files changed, 152 insertions(+) create mode 100644 src/views/BlogPage/components/PostList/index.tsx create mode 100644 src/views/BlogPage/components/PostList/style.ts diff --git a/src/views/BlogPage/components/PostList/index.tsx b/src/views/BlogPage/components/PostList/index.tsx new file mode 100644 index 00000000..4f1cd37c --- /dev/null +++ b/src/views/BlogPage/components/PostList/index.tsx @@ -0,0 +1,135 @@ +import type { GetPostListResponseType } from '@src/lib/types/blog'; +import Post from '@src/views/BlogPage/components/Post'; +import * as S from './style'; + +/** + * 다음과 같이 데이터가 들어온다고 가정하고 작성하였습니다. (솝티클 리스트) + * TODO: 솝티클, 활동 후기 API 업데이트 후 리스펀스 값에 따른 코드 수정이 필요합니다. + * + * export const TEMP_POST_LIST: GetPostListResponseType = { + limit: 12, + totalCount: 6, + totalPage: 1, + currentPage: 1, + data: [ + { + id: 9, + part: 'WEB', + generation: 29, + thumbnailUrl: + 'https://img1.daumcdn.net/thumb/R800x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSUZWn%2Fbtsf4gsXxvD%2FpbaSFQ1k33fGg7ypx8WvBK%2Fimg.jpg', + title: 'React CleanCode #1, 합성으로 관심사를 분리하기', + description: + '서언 안녕하세요. React CleanCode 첫 번째 주제로 Composition(합성)을 다룹니다. 최근에 회사에서 많은 코드를 작성하면서 느끼는 것이 있었는데요. 바로 프론트엔드가 다루어야할 관심사가 너무나 많다는 것입니다. 크게는 UI 로직(단순 UI, 애니메이션 로직, 하드코딩적인 요소), 서버 로직(데이터 패칭, 업데이트 로직, 유저 인증인가 로직, 로딩처리, 에러처리), 로그 등 이 있습니다. React를 사용하며 이러한 관심사를 잘 분리하지 않는다면, 스파게티 코드가 된다는 것을 체감했습니다. 그러면 어떻게 관심사의 지옥에서 벗어날 수 있을까요? 즉 관심사를 어떻게 잘 분리해야 할까요? 관심사 분리는 보통 함수(클래스) 분리를 통해 이루어집니다. React에서 함수의 실체는 훅, 컴포넌트,..', + author: '김의진', + authorProfileImageUrl: + 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/d25ea454-f980-400a-8b43-b35924e17cb0-7112F4F0-F803-40B7-91BD-BD629CE03F4C.jpeg', + sopticleUrl: 'https://happysisyphe.tistory.com/62', + uploadedAt: '2023-10-06T12:06:01.002Z', + likeCount: 2, + liked: false, + }, + { + id: 7, + part: 'WEB', + generation: 29, + thumbnailUrl: + 'https://velog.velcdn.com/images/1106laura/post/a43a5d48-f4a5-45f5-9be5-60e2480f25dd/2022-01-20%2004.41.36.gif', + title: 'Recoil을 사용하여 커스텀 토스트 훅 만들기', + description: 'recoil, typescript, styled component를 이용한 커스텀 토스트 훅 만들기', + author: '김서진', + authorProfileImageUrl: + 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/f7e05159-eb47-4830-a6b9-661688e1c4f6-IMG_2984.jpeg', + sopticleUrl: 'https://velog.io/@1106laura/custom-toast-hook-with-recoil', + uploadedAt: '2023-09-28T13:22:15.445Z', + likeCount: 2, + liked: false, + }, + { + id: 6, + part: 'SERVER', + generation: 32, + thumbnailUrl: + 'https://img1.daumcdn.net/thumb/R800x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBUhpy%2Fbtsovr8iQhu%2FF8Ip7lTNRcsACOTTe5PwW0%2Fimg.png', + title: '[GO SOPT] 파이썬과 Mysql 그리고 구글스프레드 시트를 연동하여 기획이랑 소통하는 법', + description: + '오늘은 GO SOPT 32기 앱잼을 하며 똑똑하게 기획과 소통하며 프로젝트에서 더미데이터를 쌓을 수 있었던 방법에 대해 기술하려고 한다 사담을 더하자면, 우리 서비스를 요약하자면 건강한 빵집에 대한 정보를 알 수 있고 이 빵집에 대해 리뷰를 남김으로써 다른 사용자와 정보 공유를 할 수 있다 사용했던 기술은 다음과 같다 1. Google Spread Sheet 2. Google API 3. python 4. mysql(AWS의 RDS에 구축했다) 5. chatGPT 1. Google Spread Sheet 기획이 건강한 빵집을 선별하여 필요한 정보를 수집해주었다 서비스에 구축한 데이터베이스에서 필요한 정보 중 이렇게 기획에서 넘겨주어야 할 데이터는 위와 같이 테이블 형태로 미리 양식을 만들어 공유해주었다 ..', + author: '김성은', + authorProfileImageUrl: + 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/0f35c598-dc21-489b-8d7b-b5ca9743d258-증명사진_김성은.jpg', + sopticleUrl: 'https://fascination-euna.tistory.com/257', + uploadedAt: '2023-09-16T12:24:41.363Z', + likeCount: 5, + liked: false, + }, + { + id: 3, + part: 'WEB', + generation: 30, + thumbnailUrl: + 'https://velog.velcdn.com/images/treejy/post/2f717b0f-0254-4f28-9363-84e021e8dd03/image.png', + title: 'SOPT makers 1기 Playground 팀 FE 개발자들의 KPT 회고 ', + description: 'SOPT makers 1기 Playground 팀 FE 개발자들의 생생한 회고 기록!', + author: '남주영', + authorProfileImageUrl: + 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/4d0d3f93-f401-46ab-ad1a-307ea4a21bed-2F8EADCA-D14D-48FE-82F9-3D2FDA1A97DA.jpeg', + sopticleUrl: + 'https://velog.io/@treejy/SOPT-makers-1%EA%B8%B0-Playground-%ED%8C%80-FE-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%93%A4%EC%9D%98-KPT-%ED%9A%8C%EA%B3%A0', + uploadedAt: '2023-09-03T15:14:11.101Z', + likeCount: 8, + liked: false, + }, + { + id: 2, + part: 'PLAN', + generation: 27, + thumbnailUrl: + 'https://img1.daumcdn.net/thumb/R1280x0/?fname=http://t1.daumcdn.net/brunch/service/user/9dEO/image/jUTvyYARIQneOVRzxBr9Ez2a7zM.png', + title: '동아리 공식 프로덕트 만들기 : Makers', + description: + '지난 1년 동안의 2가지 프로덕트 탄생기와 성장기 짧은 후기글 | 2019년 하반기부터 활동해 오던 SOPT 활동을 Makers에서 마무리하게 되었다. 처음 기획을 배울 수 있게 해 준 활동이자, IT 도메인의 여러 사람들을 만나게 해 준 연결고리 그리고 이후에는 애정으로 참여해 온 동아리인지라 꽤 오랜 기간 몸담고 있었다. 물론 언젠가 멘토로는 참여할 수 있겠지만, 애정으로 참여했던 활동 멤버로서는 이제 막을 내리게 되', + author: '김나연', + authorProfileImageUrl: + 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/be8348c8-6d5c-476d-9e64-d1ef21d8a7b1-스크린샷 2022-11-05 오후 2.03.21.png', + sopticleUrl: 'https://brunch.co.kr/@ny0303/101', + uploadedAt: '2023-07-07T09:43:12.193Z', + likeCount: 21, + liked: false, + }, + { + id: 1, + part: 'WEB', + generation: 29, + thumbnailUrl: + 'https://velog.velcdn.com/images/tekiter/post/5c70c015-696c-4d82-89da-3d2dc413aeb3/image.png', + title: 'React에서 사용하는 RustPython', + description: 'RustPython으로 브라우저에서 서버 없이 Python을 실행시켜보자.', + author: '박건영', + authorProfileImageUrl: + 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/45a0271c-895c-427b-9ff2-a2efb4daa7ce-1679161408215.jpg', + sopticleUrl: 'https://velog.io/@tekiter/react-rustpython', + uploadedAt: '2023-06-26T11:04:20.252Z', + likeCount: 17, + liked: false, + }, + ], + hasNextPage: false, + hasPrevPage: false, +}; + */ + +interface PostListProps { + postList: GetPostListResponseType; +} + +function PostList({ postList }: PostListProps) { + return ( + + {postList.data.map((post) => ( + + ))} + + ); +} + +export default PostList; diff --git a/src/views/BlogPage/components/PostList/style.ts b/src/views/BlogPage/components/PostList/style.ts new file mode 100644 index 00000000..00a56787 --- /dev/null +++ b/src/views/BlogPage/components/PostList/style.ts @@ -0,0 +1,17 @@ +import styled from '@emotion/styled'; + +export const PostList = styled.div` + display: flex; + flex-direction: column; + gap: 80px; + + width: 100%; + max-width: 900px; + min-width: 335px; + margin-top: 2px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + gap: 36px; + } +`; From e437d10bce896b9ecfffa374d362c59746ee5b6b Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 17:06:39 +0900 Subject: [PATCH 02/12] =?UTF-8?q?asset:=20=EB=B9=88=20=ED=95=98=ED=8A=B8?= =?UTF-8?q?=20svg=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/ic_heart_unfilled.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/assets/icons/ic_heart_unfilled.svg diff --git a/src/assets/icons/ic_heart_unfilled.svg b/src/assets/icons/ic_heart_unfilled.svg new file mode 100644 index 00000000..1457abb5 --- /dev/null +++ b/src/assets/icons/ic_heart_unfilled.svg @@ -0,0 +1,3 @@ + + + From 60e183b91ebd2d63b8a2229370a2e9995fca873b Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 17:07:06 +0900 Subject: [PATCH 03/12] =?UTF-8?q?feat:=20=EB=B8=94=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EA=B8=80=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/BlogPage/components/Post/index.tsx | 68 +++++++ src/views/BlogPage/components/Post/style.ts | 201 +++++++++++++++++++ 2 files changed, 269 insertions(+) create mode 100644 src/views/BlogPage/components/Post/index.tsx create mode 100644 src/views/BlogPage/components/Post/style.ts diff --git a/src/views/BlogPage/components/Post/index.tsx b/src/views/BlogPage/components/Post/index.tsx new file mode 100644 index 00000000..b3887e12 --- /dev/null +++ b/src/views/BlogPage/components/Post/index.tsx @@ -0,0 +1,68 @@ +import Image from 'next/image'; +import { useEffect, useRef, useState } from 'react'; +import icHeartUnfilled from '@src/assets/icons/ic_heart_unfilled.svg'; +import type { PostType } from '@src/lib/types/blog'; +import { formatDate } from '@src/lib/utils/dateFormat'; +import { parsePartToKorean } from '@src/lib/utils/parsePartToKorean'; +import DefaultProfileImage from '@src/views/BlogPage/components/DefaultProfileImage'; +import * as S from './style'; + +const TWO_LINE_TITLE_HEIGHT = 72; + +interface PostProps { + post: PostType; +} + +function Post({ post }: PostProps) { + const { authorProfileImageUrl } = post; + const titleRef = useRef(null); + const [descriptionLine, setDescriptionLine] = useState(1); + + useEffect(() => { + if (titleRef.current) { + const titleHeight = titleRef.current.clientHeight; + setDescriptionLine(titleHeight >= TWO_LINE_TITLE_HEIGHT ? 1 : 2); + } + }, []); + + return ( + +
+ + + {authorProfileImageUrl ? ( + + ) : ( + + )} +
{post.author}
+
+ +
{formatDate(new Date(post.uploadedAt), 'yyyymmdd', '.')}
+
+ + {post.title} + {post.description} + + + {post.generation}기 + {parsePartToKorean(post.part)} + +
+ + + + 좋아요 + {post.likeCount} + + +
+ ); +} + +export default Post; diff --git a/src/views/BlogPage/components/Post/style.ts b/src/views/BlogPage/components/Post/style.ts new file mode 100644 index 00000000..f2aad956 --- /dev/null +++ b/src/views/BlogPage/components/Post/style.ts @@ -0,0 +1,201 @@ +import styled from '@emotion/styled'; +import { colors } from '@sopt-makers/colors'; +import Image from 'next/image'; + +export const Post = styled.div` + display: flex; + justify-content: space-between; + gap: 36px; + + cursor: pointer; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + gap: 16px; + } +`; + +export const Header = styled.div` + display: flex; + margin-bottom: 4px; + + color: ${colors.gray100}; + font-size: 14px; + font-weight: 400; + line-height: 160%; + letter-spacing: -0.21px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + margin-bottom: 0; + + font-size: 12px; + font-weight: 500; + line-height: 135%; /* 16.2px */ + letter-spacing: -0.18px; + } +`; + +export const Profile = styled.div` + display: flex; + align-items: center; + gap: 6px; +`; + +export const ProfileImage = styled(Image)` + border-radius: 18px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + width: 15px; + height: 15px; + } +`; + +export const Divider = styled.div` + padding: 0 2px 0 2px; +`; + +export const Body = styled.div` + height: 94px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + display: flex; + align-items: center; + height: 53px; + } +`; + +export const Title = styled.div` + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; + text-overflow: ellipsis; + word-break: break-all; + + max-height: 72px; + + color: ${colors.white}; + font-size: 24px; + font-weight: 600; + line-height: 150%; + letter-spacing: -0.48px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + font-size: 16px; + letter-spacing: -0.24px; + } +`; + +export const Description = styled.div<{ descriptionLine: number }>` + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: ${({ descriptionLine }) => descriptionLine}; + overflow: hidden; + text-overflow: ellipsis; + word-break: break-all; + + color: ${colors.gray200}; + font-size: 16px; + font-weight: 400; + line-height: 160%; + letter-spacing: -0.24px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + display: none; + } +`; + +export const TagList = styled.div` + display: flex; + gap: 8px; + margin-top: 10px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + margin-top: 18px; + } +`; + +export const Tag = styled.div` + display: flex; + justify-content: center; + align-items: center; + + height: 28px; + padding: 0px 6px; + border-radius: 6px; + background: ${colors.gray700}; + + color: ${colors.gray50}; + font-size: 12px; + font-weight: 500; + line-height: 135%; /* 16.2px */ + letter-spacing: -0.18px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + height: 20px; + + font-size: 11px; + font-weight: 600; + letter-spacing: -0.165px; + } +`; + +export const ThumbnailWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; + + position: relative; + width: 239px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + width: 105px; + } +`; + +export const Thumbnail = styled(Image)` + border-radius: 8px; + object-fit: cover; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + width: 105px; + height: 70px; + border-radius: 5px; + } +`; + +export const Like = styled.div` + display: flex; + justify-content: center; + align-items: center; + gap: 3px; + + position: absolute; + top: 10px; + right: 10px; + + height: 28px; + padding: 2px 8px; + border-radius: 6px; + background: rgba(28, 29, 30, 0.8); + + color: ${colors.gray100}; + font-size: 14px; + font-weight: 400; + line-height: 160%; /* 22.4px */ + letter-spacing: -0.21px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + display: none; + } +`; From 8edccd26f0378c7be224990ba93f76bf14a861ad Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 17:07:29 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=ED=94=84?= =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/ic_profile_default.svg | 13 +++++++++++++ .../components/DefaultProfileImage/index.tsx | 13 +++++++++++++ .../components/DefaultProfileImage/style.ts | 13 +++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 src/assets/icons/ic_profile_default.svg create mode 100644 src/views/BlogPage/components/DefaultProfileImage/index.tsx create mode 100644 src/views/BlogPage/components/DefaultProfileImage/style.ts diff --git a/src/assets/icons/ic_profile_default.svg b/src/assets/icons/ic_profile_default.svg new file mode 100644 index 00000000..3cb5b146 --- /dev/null +++ b/src/assets/icons/ic_profile_default.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/views/BlogPage/components/DefaultProfileImage/index.tsx b/src/views/BlogPage/components/DefaultProfileImage/index.tsx new file mode 100644 index 00000000..fa11ddee --- /dev/null +++ b/src/views/BlogPage/components/DefaultProfileImage/index.tsx @@ -0,0 +1,13 @@ +import Image from 'next/image'; +import icProfileDefault from '@src/assets/icons/ic_profile_default.svg'; +import * as S from './style'; + +function DefaultProfileImage() { + return ( + + 작성자 프로필 이미지 + + ); +} + +export default DefaultProfileImage; diff --git a/src/views/BlogPage/components/DefaultProfileImage/style.ts b/src/views/BlogPage/components/DefaultProfileImage/style.ts new file mode 100644 index 00000000..fff60363 --- /dev/null +++ b/src/views/BlogPage/components/DefaultProfileImage/style.ts @@ -0,0 +1,13 @@ +import styled from '@emotion/styled'; +import { colors } from '@sopt-makers/colors'; + +export const DefaultProfileImage = styled.div` + display: flex; + justify-content: center; + align-items: center; + + width: 18px; + height: 18px; + border-radius: 18px; + background-color: ${colors.gray700}; +`; From 94c6f8c35b11ffc49c61842c018c66d105e4664b Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 17:07:51 +0900 Subject: [PATCH 05/12] =?UTF-8?q?feat:=20=EB=B8=94=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EA=B8=80=20=EB=A6=AC=EC=8A=A4=ED=8E=80=EC=8A=A4=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/types/blog.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/lib/types/blog.ts diff --git a/src/lib/types/blog.ts b/src/lib/types/blog.ts new file mode 100644 index 00000000..b13b59a2 --- /dev/null +++ b/src/lib/types/blog.ts @@ -0,0 +1,26 @@ +/* TODO: 솝티클, 활동 후기 API 업데이트 후 수정 예정 */ + +export type PostType = { + id: number; + part: string; + generation: number; + thumbnailUrl: string; + title: string; + description: string; + author: string; + authorProfileImageUrl: string | null; + sopticleUrl: string; + uploadedAt: string; + likeCount: number; + liked: boolean; +}; + +export type GetPostListResponseType = { + limit: number; + totalCount: number; + totalPage: number; + currentPage: number; + data: PostType[]; + hasNextPage: boolean; + hasPrevPage: boolean; +}; From f50da90623e143ad7d040d70043233603ee1a29d Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 22:28:19 +0900 Subject: [PATCH 06/12] =?UTF-8?q?feat:=20=EB=B8=94=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EA=B8=80=20=ED=97=A4=EB=8D=94,=20=EC=A2=8B=EC=95=84=EC=9A=94?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/ic_heart_filled.svg | 3 + .../BlogPage/components/Post/Header/index.tsx | 39 ++++++++++ .../BlogPage/components/Post/Header/style.ts | 46 ++++++++++++ .../BlogPage/components/Post/Like/index.tsx | 25 +++++++ .../BlogPage/components/Post/Like/style.ts | 34 +++++++++ src/views/BlogPage/components/Post/index.tsx | 39 +++------- src/views/BlogPage/components/Post/style.ts | 75 ++----------------- 7 files changed, 162 insertions(+), 99 deletions(-) create mode 100644 src/assets/icons/ic_heart_filled.svg create mode 100644 src/views/BlogPage/components/Post/Header/index.tsx create mode 100644 src/views/BlogPage/components/Post/Header/style.ts create mode 100644 src/views/BlogPage/components/Post/Like/index.tsx create mode 100644 src/views/BlogPage/components/Post/Like/style.ts diff --git a/src/assets/icons/ic_heart_filled.svg b/src/assets/icons/ic_heart_filled.svg new file mode 100644 index 00000000..85eb2468 --- /dev/null +++ b/src/assets/icons/ic_heart_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/views/BlogPage/components/Post/Header/index.tsx b/src/views/BlogPage/components/Post/Header/index.tsx new file mode 100644 index 00000000..02c4134b --- /dev/null +++ b/src/views/BlogPage/components/Post/Header/index.tsx @@ -0,0 +1,39 @@ +import { BlogPostType } from '@src/lib/types/blog'; +import { formatDate } from '@src/lib/utils/dateFormat'; +import DefaultProfileImage from '@src/views/BlogPage/components/DefaultProfileImage'; +import * as S from './style'; + +interface HeaderProps { + selectedTap: string; + post: BlogPostType; +} + +function Header({ selectedTap, post }: HeaderProps) { + return ( + + {selectedTap === 'ARTICLE' ? ( + <> + + {post.authorProfileImageUrl ? ( + + ) : ( + + )} +
{post.author}
+
+ +
{formatDate(new Date(post.uploadedAt), 'yyyymmdd', '.')}
+ + ) : ( +
{post.subject}
+ )} +
+ ); +} + +export default Header; diff --git a/src/views/BlogPage/components/Post/Header/style.ts b/src/views/BlogPage/components/Post/Header/style.ts new file mode 100644 index 00000000..886d4323 --- /dev/null +++ b/src/views/BlogPage/components/Post/Header/style.ts @@ -0,0 +1,46 @@ +import styled from '@emotion/styled'; +import { colors } from '@sopt-makers/colors'; +import Image from 'next/image'; + +export const Header = styled.div` + display: flex; + height: 23px; + margin-bottom: 4px; + + color: ${colors.gray200}; + font-size: 14px; + font-weight: 400; + line-height: 160%; + letter-spacing: -0.21px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + height: 16px; + margin-bottom: 0; + + font-size: 12px; + font-weight: 500; + line-height: 135%; /* 16.2px */ + letter-spacing: -0.18px; + } +`; + +export const Profile = styled.div` + display: flex; + align-items: center; + gap: 6px; +`; + +export const ProfileImage = styled(Image)` + border-radius: 18px; + + /* 모바일 뷰 */ + @media (max-width: 767px) { + width: 15px; + height: 15px; + } +`; + +export const Divider = styled.div` + padding: 0 2px 0 2px; +`; diff --git a/src/views/BlogPage/components/Post/Like/index.tsx b/src/views/BlogPage/components/Post/Like/index.tsx new file mode 100644 index 00000000..9f915940 --- /dev/null +++ b/src/views/BlogPage/components/Post/Like/index.tsx @@ -0,0 +1,25 @@ +import Image from 'next/image'; +import icHeartFilled from '@src/assets/icons/ic_heart_filled.svg'; +import icHeartUnfilled from '@src/assets/icons/ic_heart_unfilled.svg'; +import { BlogPostType } from '@src/lib/types/blog'; +import * as S from './style'; + +interface LikeProps { + post: BlogPostType; +} + +function Like({ post }: LikeProps) { + return ( + + 좋아요 + {post.likeCount} + + ); +} + +export default Like; diff --git a/src/views/BlogPage/components/Post/Like/style.ts b/src/views/BlogPage/components/Post/Like/style.ts new file mode 100644 index 00000000..235699f0 --- /dev/null +++ b/src/views/BlogPage/components/Post/Like/style.ts @@ -0,0 +1,34 @@ +import styled from '@emotion/styled'; +import { colors } from '@sopt-makers/colors'; + +export const Like = styled.div` + display: flex; + justify-content: center; + align-items: center; + gap: 3px; + + position: absolute; + top: 10px; + right: 10px; + + height: 28px; + padding: 2px 8px; + border-radius: 6px; + background: ${colors.grayAlpha100}; + + color: ${colors.gray100}; + font-size: 14px; + font-weight: 400; + line-height: 160%; /* 22.4px */ + letter-spacing: -0.21px; + + transition: opacity 0.1s ease-out; + &:hover { + opacity: 0.8; + } + + /* 모바일 뷰 */ + @media (max-width: 767px) { + display: none; + } +`; diff --git a/src/views/BlogPage/components/Post/index.tsx b/src/views/BlogPage/components/Post/index.tsx index b3887e12..970b2089 100644 --- a/src/views/BlogPage/components/Post/index.tsx +++ b/src/views/BlogPage/components/Post/index.tsx @@ -1,20 +1,18 @@ -import Image from 'next/image'; import { useEffect, useRef, useState } from 'react'; -import icHeartUnfilled from '@src/assets/icons/ic_heart_unfilled.svg'; -import type { PostType } from '@src/lib/types/blog'; -import { formatDate } from '@src/lib/utils/dateFormat'; +import type { BlogPostType } from '@src/lib/types/blog'; import { parsePartToKorean } from '@src/lib/utils/parsePartToKorean'; -import DefaultProfileImage from '@src/views/BlogPage/components/DefaultProfileImage'; +import Header from '@src/views/BlogPage/components/Post/Header'; +import Like from '@src/views/BlogPage/components/Post/Like'; import * as S from './style'; const TWO_LINE_TITLE_HEIGHT = 72; interface PostProps { - post: PostType; + selectedTap: string; + post: BlogPostType; } -function Post({ post }: PostProps) { - const { authorProfileImageUrl } = post; +function Post({ selectedTap, post }: PostProps) { const titleRef = useRef(null); const [descriptionLine, setDescriptionLine] = useState(1); @@ -26,25 +24,9 @@ function Post({ post }: PostProps) { }, []); return ( - +
- - - {authorProfileImageUrl ? ( - - ) : ( - - )} -
{post.author}
-
- -
{formatDate(new Date(post.uploadedAt), 'yyyymmdd', '.')}
-
+
{post.title} {post.description} @@ -56,10 +38,7 @@ function Post({ post }: PostProps) {
- - 좋아요 - {post.likeCount} - + {selectedTap === 'ARTICLE' && }
); diff --git a/src/views/BlogPage/components/Post/style.ts b/src/views/BlogPage/components/Post/style.ts index f2aad956..775756a9 100644 --- a/src/views/BlogPage/components/Post/style.ts +++ b/src/views/BlogPage/components/Post/style.ts @@ -1,61 +1,25 @@ import styled from '@emotion/styled'; import { colors } from '@sopt-makers/colors'; import Image from 'next/image'; +import Link from 'next/link'; -export const Post = styled.div` +export const Post = styled(Link)` display: flex; justify-content: space-between; gap: 36px; cursor: pointer; - - /* 모바일 뷰 */ - @media (max-width: 767px) { - gap: 16px; - } -`; - -export const Header = styled.div` - display: flex; - margin-bottom: 4px; - - color: ${colors.gray100}; - font-size: 14px; - font-weight: 400; - line-height: 160%; - letter-spacing: -0.21px; - - /* 모바일 뷰 */ - @media (max-width: 767px) { - margin-bottom: 0; - - font-size: 12px; - font-weight: 500; - line-height: 135%; /* 16.2px */ - letter-spacing: -0.18px; + transition: opacity 0.2s linear; + &:hover { + opacity: 0.8; } -`; - -export const Profile = styled.div` - display: flex; - align-items: center; - gap: 6px; -`; - -export const ProfileImage = styled(Image)` - border-radius: 18px; /* 모바일 뷰 */ @media (max-width: 767px) { - width: 15px; - height: 15px; + gap: 16px; } `; -export const Divider = styled.div` - padding: 0 2px 0 2px; -`; - export const Body = styled.div` height: 94px; @@ -172,30 +136,3 @@ export const Thumbnail = styled(Image)` border-radius: 5px; } `; - -export const Like = styled.div` - display: flex; - justify-content: center; - align-items: center; - gap: 3px; - - position: absolute; - top: 10px; - right: 10px; - - height: 28px; - padding: 2px 8px; - border-radius: 6px; - background: rgba(28, 29, 30, 0.8); - - color: ${colors.gray100}; - font-size: 14px; - font-weight: 400; - line-height: 160%; /* 22.4px */ - letter-spacing: -0.21px; - - /* 모바일 뷰 */ - @media (max-width: 767px) { - display: none; - } -`; From 42e6afb740ea2262eac45530cbcdef0405d5bef6 Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 22:28:43 +0900 Subject: [PATCH 07/12] =?UTF-8?q?feat:=20=EC=84=A0=ED=83=9D=ED=95=9C=20?= =?UTF-8?q?=ED=83=AD=20props=20=EB=B0=9B=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BlogPage/components/PostList/index.tsx | 125 +----------------- 1 file changed, 5 insertions(+), 120 deletions(-) diff --git a/src/views/BlogPage/components/PostList/index.tsx b/src/views/BlogPage/components/PostList/index.tsx index 4f1cd37c..0f1547dd 100644 --- a/src/views/BlogPage/components/PostList/index.tsx +++ b/src/views/BlogPage/components/PostList/index.tsx @@ -1,132 +1,17 @@ -import type { GetPostListResponseType } from '@src/lib/types/blog'; +import type { BlogPostListType } from '@src/lib/types/blog'; import Post from '@src/views/BlogPage/components/Post'; import * as S from './style'; -/** - * 다음과 같이 데이터가 들어온다고 가정하고 작성하였습니다. (솝티클 리스트) - * TODO: 솝티클, 활동 후기 API 업데이트 후 리스펀스 값에 따른 코드 수정이 필요합니다. - * - * export const TEMP_POST_LIST: GetPostListResponseType = { - limit: 12, - totalCount: 6, - totalPage: 1, - currentPage: 1, - data: [ - { - id: 9, - part: 'WEB', - generation: 29, - thumbnailUrl: - 'https://img1.daumcdn.net/thumb/R800x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSUZWn%2Fbtsf4gsXxvD%2FpbaSFQ1k33fGg7ypx8WvBK%2Fimg.jpg', - title: 'React CleanCode #1, 합성으로 관심사를 분리하기', - description: - '서언 안녕하세요. React CleanCode 첫 번째 주제로 Composition(합성)을 다룹니다. 최근에 회사에서 많은 코드를 작성하면서 느끼는 것이 있었는데요. 바로 프론트엔드가 다루어야할 관심사가 너무나 많다는 것입니다. 크게는 UI 로직(단순 UI, 애니메이션 로직, 하드코딩적인 요소), 서버 로직(데이터 패칭, 업데이트 로직, 유저 인증인가 로직, 로딩처리, 에러처리), 로그 등 이 있습니다. React를 사용하며 이러한 관심사를 잘 분리하지 않는다면, 스파게티 코드가 된다는 것을 체감했습니다. 그러면 어떻게 관심사의 지옥에서 벗어날 수 있을까요? 즉 관심사를 어떻게 잘 분리해야 할까요? 관심사 분리는 보통 함수(클래스) 분리를 통해 이루어집니다. React에서 함수의 실체는 훅, 컴포넌트,..', - author: '김의진', - authorProfileImageUrl: - 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/d25ea454-f980-400a-8b43-b35924e17cb0-7112F4F0-F803-40B7-91BD-BD629CE03F4C.jpeg', - sopticleUrl: 'https://happysisyphe.tistory.com/62', - uploadedAt: '2023-10-06T12:06:01.002Z', - likeCount: 2, - liked: false, - }, - { - id: 7, - part: 'WEB', - generation: 29, - thumbnailUrl: - 'https://velog.velcdn.com/images/1106laura/post/a43a5d48-f4a5-45f5-9be5-60e2480f25dd/2022-01-20%2004.41.36.gif', - title: 'Recoil을 사용하여 커스텀 토스트 훅 만들기', - description: 'recoil, typescript, styled component를 이용한 커스텀 토스트 훅 만들기', - author: '김서진', - authorProfileImageUrl: - 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/f7e05159-eb47-4830-a6b9-661688e1c4f6-IMG_2984.jpeg', - sopticleUrl: 'https://velog.io/@1106laura/custom-toast-hook-with-recoil', - uploadedAt: '2023-09-28T13:22:15.445Z', - likeCount: 2, - liked: false, - }, - { - id: 6, - part: 'SERVER', - generation: 32, - thumbnailUrl: - 'https://img1.daumcdn.net/thumb/R800x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBUhpy%2Fbtsovr8iQhu%2FF8Ip7lTNRcsACOTTe5PwW0%2Fimg.png', - title: '[GO SOPT] 파이썬과 Mysql 그리고 구글스프레드 시트를 연동하여 기획이랑 소통하는 법', - description: - '오늘은 GO SOPT 32기 앱잼을 하며 똑똑하게 기획과 소통하며 프로젝트에서 더미데이터를 쌓을 수 있었던 방법에 대해 기술하려고 한다 사담을 더하자면, 우리 서비스를 요약하자면 건강한 빵집에 대한 정보를 알 수 있고 이 빵집에 대해 리뷰를 남김으로써 다른 사용자와 정보 공유를 할 수 있다 사용했던 기술은 다음과 같다 1. Google Spread Sheet 2. Google API 3. python 4. mysql(AWS의 RDS에 구축했다) 5. chatGPT 1. Google Spread Sheet 기획이 건강한 빵집을 선별하여 필요한 정보를 수집해주었다 서비스에 구축한 데이터베이스에서 필요한 정보 중 이렇게 기획에서 넘겨주어야 할 데이터는 위와 같이 테이블 형태로 미리 양식을 만들어 공유해주었다 ..', - author: '김성은', - authorProfileImageUrl: - 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/0f35c598-dc21-489b-8d7b-b5ca9743d258-증명사진_김성은.jpg', - sopticleUrl: 'https://fascination-euna.tistory.com/257', - uploadedAt: '2023-09-16T12:24:41.363Z', - likeCount: 5, - liked: false, - }, - { - id: 3, - part: 'WEB', - generation: 30, - thumbnailUrl: - 'https://velog.velcdn.com/images/treejy/post/2f717b0f-0254-4f28-9363-84e021e8dd03/image.png', - title: 'SOPT makers 1기 Playground 팀 FE 개발자들의 KPT 회고 ', - description: 'SOPT makers 1기 Playground 팀 FE 개발자들의 생생한 회고 기록!', - author: '남주영', - authorProfileImageUrl: - 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/4d0d3f93-f401-46ab-ad1a-307ea4a21bed-2F8EADCA-D14D-48FE-82F9-3D2FDA1A97DA.jpeg', - sopticleUrl: - 'https://velog.io/@treejy/SOPT-makers-1%EA%B8%B0-Playground-%ED%8C%80-FE-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%93%A4%EC%9D%98-KPT-%ED%9A%8C%EA%B3%A0', - uploadedAt: '2023-09-03T15:14:11.101Z', - likeCount: 8, - liked: false, - }, - { - id: 2, - part: 'PLAN', - generation: 27, - thumbnailUrl: - 'https://img1.daumcdn.net/thumb/R1280x0/?fname=http://t1.daumcdn.net/brunch/service/user/9dEO/image/jUTvyYARIQneOVRzxBr9Ez2a7zM.png', - title: '동아리 공식 프로덕트 만들기 : Makers', - description: - '지난 1년 동안의 2가지 프로덕트 탄생기와 성장기 짧은 후기글 | 2019년 하반기부터 활동해 오던 SOPT 활동을 Makers에서 마무리하게 되었다. 처음 기획을 배울 수 있게 해 준 활동이자, IT 도메인의 여러 사람들을 만나게 해 준 연결고리 그리고 이후에는 애정으로 참여해 온 동아리인지라 꽤 오랜 기간 몸담고 있었다. 물론 언젠가 멘토로는 참여할 수 있겠지만, 애정으로 참여했던 활동 멤버로서는 이제 막을 내리게 되', - author: '김나연', - authorProfileImageUrl: - 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/be8348c8-6d5c-476d-9e64-d1ef21d8a7b1-스크린샷 2022-11-05 오후 2.03.21.png', - sopticleUrl: 'https://brunch.co.kr/@ny0303/101', - uploadedAt: '2023-07-07T09:43:12.193Z', - likeCount: 21, - liked: false, - }, - { - id: 1, - part: 'WEB', - generation: 29, - thumbnailUrl: - 'https://velog.velcdn.com/images/tekiter/post/5c70c015-696c-4d82-89da-3d2dc413aeb3/image.png', - title: 'React에서 사용하는 RustPython', - description: 'RustPython으로 브라우저에서 서버 없이 Python을 실행시켜보자.', - author: '박건영', - authorProfileImageUrl: - 'https://s3.ap-northeast-2.amazonaws.com/sopt-makers-internal//prod/image/project/45a0271c-895c-427b-9ff2-a2efb4daa7ce-1679161408215.jpg', - sopticleUrl: 'https://velog.io/@tekiter/react-rustpython', - uploadedAt: '2023-06-26T11:04:20.252Z', - likeCount: 17, - liked: false, - }, - ], - hasNextPage: false, - hasPrevPage: false, -}; - */ - interface PostListProps { - postList: GetPostListResponseType; + selectedTap: string; // REVIEW || ARTICLE + postList: BlogPostListType; } -function PostList({ postList }: PostListProps) { +function PostList({ selectedTap, postList }: PostListProps) { return ( {postList.data.map((post) => ( - + ))} ); From bf1f2f989b8ecb3cc06218613f931eeae1b488a5 Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 22:30:30 +0900 Subject: [PATCH 08/12] =?UTF-8?q?feat:=20=EB=B8=94=EB=A1=9C=EA=B7=B8=20?= =?UTF-8?q?=EA=B8=80=20=EA=B3=B5=ED=86=B5=20=ED=83=80=EC=9E=85=20=EC=84=A0?= =?UTF-8?q?=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/types/blog.ts | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/lib/types/blog.ts b/src/lib/types/blog.ts index b13b59a2..9eb520a5 100644 --- a/src/lib/types/blog.ts +++ b/src/lib/types/blog.ts @@ -1,6 +1,14 @@ -/* TODO: 솝티클, 활동 후기 API 업데이트 후 수정 예정 */ +export type BlogPostListType = { + limit: number; + totalCount: number; + totalPage: number; + currentPage: number; + data: BlogPostType[]; + hasNextPage: boolean; + hasPrevPage: boolean; +}; -export type PostType = { +export type BlogPostType = { id: number; part: string; generation: number; @@ -9,18 +17,13 @@ export type PostType = { description: string; author: string; authorProfileImageUrl: string | null; - sopticleUrl: string; + url: string; uploadedAt: string; - likeCount: number; - liked: boolean; -}; -export type GetPostListResponseType = { - limit: number; - totalCount: number; - totalPage: number; - currentPage: number; - data: PostType[]; - hasNextPage: boolean; - hasPrevPage: boolean; + /* article */ + likeCount?: number; + liked?: boolean; + + /* review */ + subject?: string; }; From 7ee3ceed1fdc9d8e01f479ebe1bd8d6162345b16 Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Sun, 22 Oct 2023 22:54:34 +0900 Subject: [PATCH 09/12] =?UTF-8?q?chore:=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=AA=85=20=EB=B0=8F=20=EC=9C=84=EC=B9=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DefaultProfileImage/index.tsx | 0 .../DefaultProfileImage/style.ts | 0 .../{Post => BlogPost}/Header/index.tsx | 16 +++---- .../{Post => BlogPost}/Header/style.ts | 0 .../{Post => BlogPost}/Like/index.tsx | 8 ++-- .../{Post => BlogPost}/Like/style.ts | 0 .../BlogPage/components/BlogPost/index.ts | 3 ++ .../BlogPage/components/BlogPost/index.tsx | 47 +++++++++++++++++++ .../components/{Post => BlogPost}/style.ts | 2 +- .../components/BlogPostList/index.tsx | 20 ++++++++ .../{PostList => BlogPostList}/style.ts | 2 +- src/views/BlogPage/components/Post/index.tsx | 47 ------------------- .../BlogPage/components/PostList/index.tsx | 20 -------- 13 files changed, 84 insertions(+), 81 deletions(-) rename src/views/BlogPage/components/{ => BlogPost}/DefaultProfileImage/index.tsx (100%) rename src/views/BlogPage/components/{ => BlogPost}/DefaultProfileImage/style.ts (100%) rename src/views/BlogPage/components/{Post => BlogPost}/Header/index.tsx (60%) rename src/views/BlogPage/components/{Post => BlogPost}/Header/style.ts (100%) rename src/views/BlogPage/components/{Post => BlogPost}/Like/index.tsx (71%) rename src/views/BlogPage/components/{Post => BlogPost}/Like/style.ts (100%) create mode 100644 src/views/BlogPage/components/BlogPost/index.ts create mode 100644 src/views/BlogPage/components/BlogPost/index.tsx rename src/views/BlogPage/components/{Post => BlogPost}/style.ts (98%) create mode 100644 src/views/BlogPage/components/BlogPostList/index.tsx rename src/views/BlogPage/components/{PostList => BlogPostList}/style.ts (85%) delete mode 100644 src/views/BlogPage/components/Post/index.tsx delete mode 100644 src/views/BlogPage/components/PostList/index.tsx diff --git a/src/views/BlogPage/components/DefaultProfileImage/index.tsx b/src/views/BlogPage/components/BlogPost/DefaultProfileImage/index.tsx similarity index 100% rename from src/views/BlogPage/components/DefaultProfileImage/index.tsx rename to src/views/BlogPage/components/BlogPost/DefaultProfileImage/index.tsx diff --git a/src/views/BlogPage/components/DefaultProfileImage/style.ts b/src/views/BlogPage/components/BlogPost/DefaultProfileImage/style.ts similarity index 100% rename from src/views/BlogPage/components/DefaultProfileImage/style.ts rename to src/views/BlogPage/components/BlogPost/DefaultProfileImage/style.ts diff --git a/src/views/BlogPage/components/Post/Header/index.tsx b/src/views/BlogPage/components/BlogPost/Header/index.tsx similarity index 60% rename from src/views/BlogPage/components/Post/Header/index.tsx rename to src/views/BlogPage/components/BlogPost/Header/index.tsx index 02c4134b..4f2cf1aa 100644 --- a/src/views/BlogPage/components/Post/Header/index.tsx +++ b/src/views/BlogPage/components/BlogPost/Header/index.tsx @@ -1,22 +1,22 @@ import { BlogPostType } from '@src/lib/types/blog'; import { formatDate } from '@src/lib/utils/dateFormat'; -import DefaultProfileImage from '@src/views/BlogPage/components/DefaultProfileImage'; +import { DefaultProfileImage } from '@src/views/BlogPage/components/BlogPost'; import * as S from './style'; interface HeaderProps { selectedTap: string; - post: BlogPostType; + blogPost: BlogPostType; } -function Header({ selectedTap, post }: HeaderProps) { +function Header({ selectedTap, blogPost }: HeaderProps) { return ( {selectedTap === 'ARTICLE' ? ( <> - {post.authorProfileImageUrl ? ( + {blogPost.authorProfileImageUrl ? ( )} -
{post.author}
+
{blogPost.author}
-
{formatDate(new Date(post.uploadedAt), 'yyyymmdd', '.')}
+
{formatDate(new Date(blogPost.uploadedAt), 'yyyymmdd', '.')}
) : ( -
{post.subject}
+
{blogPost.subject}
)}
); diff --git a/src/views/BlogPage/components/Post/Header/style.ts b/src/views/BlogPage/components/BlogPost/Header/style.ts similarity index 100% rename from src/views/BlogPage/components/Post/Header/style.ts rename to src/views/BlogPage/components/BlogPost/Header/style.ts diff --git a/src/views/BlogPage/components/Post/Like/index.tsx b/src/views/BlogPage/components/BlogPost/Like/index.tsx similarity index 71% rename from src/views/BlogPage/components/Post/Like/index.tsx rename to src/views/BlogPage/components/BlogPost/Like/index.tsx index 9f915940..f482d866 100644 --- a/src/views/BlogPage/components/Post/Like/index.tsx +++ b/src/views/BlogPage/components/BlogPost/Like/index.tsx @@ -5,19 +5,19 @@ import { BlogPostType } from '@src/lib/types/blog'; import * as S from './style'; interface LikeProps { - post: BlogPostType; + blogPost: BlogPostType; } -function Like({ post }: LikeProps) { +function Like({ blogPost }: LikeProps) { return ( 좋아요 - {post.likeCount} + {blogPost.likeCount} ); } diff --git a/src/views/BlogPage/components/Post/Like/style.ts b/src/views/BlogPage/components/BlogPost/Like/style.ts similarity index 100% rename from src/views/BlogPage/components/Post/Like/style.ts rename to src/views/BlogPage/components/BlogPost/Like/style.ts diff --git a/src/views/BlogPage/components/BlogPost/index.ts b/src/views/BlogPage/components/BlogPost/index.ts new file mode 100644 index 00000000..2342e8bf --- /dev/null +++ b/src/views/BlogPage/components/BlogPost/index.ts @@ -0,0 +1,3 @@ +export { default as DefaultProfileImage } from './DefaultProfileImage'; +export { default as Header } from './Header'; +export { default as Like } from './Like'; diff --git a/src/views/BlogPage/components/BlogPost/index.tsx b/src/views/BlogPage/components/BlogPost/index.tsx new file mode 100644 index 00000000..b062cfe1 --- /dev/null +++ b/src/views/BlogPage/components/BlogPost/index.tsx @@ -0,0 +1,47 @@ +import { useEffect, useRef, useState } from 'react'; +import type { BlogPostType } from '@src/lib/types/blog'; +import { parsePartToKorean } from '@src/lib/utils/parsePartToKorean'; +import { Like } from '@src/views/BlogPage/components/BlogPost'; +import * as S from './style'; +import Header from '@src/views/BlogPage/components/BlogPost/Header'; + +const TWO_LINE_TITLE_HEIGHT = 72; + +interface BlogPostProps { + selectedTap: string; + blogPost: BlogPostType; +} + +function BlogPost({ selectedTap, blogPost }: BlogPostProps) { + const titleRef = useRef(null); + const [descriptionLine, setDescriptionLine] = useState(1); + + useEffect(() => { + if (titleRef.current) { + const titleHeight = titleRef.current.clientHeight; + setDescriptionLine(titleHeight >= TWO_LINE_TITLE_HEIGHT ? 1 : 2); + } + }, []); + + return ( + +
+
+ + {blogPost.title} + {blogPost.description} + + + {blogPost.generation}기 + {parsePartToKorean(blogPost.part)} + +
+ + + {selectedTap === 'ARTICLE' && } + +
+ ); +} + +export default BlogPost; diff --git a/src/views/BlogPage/components/Post/style.ts b/src/views/BlogPage/components/BlogPost/style.ts similarity index 98% rename from src/views/BlogPage/components/Post/style.ts rename to src/views/BlogPage/components/BlogPost/style.ts index 775756a9..27f32466 100644 --- a/src/views/BlogPage/components/Post/style.ts +++ b/src/views/BlogPage/components/BlogPost/style.ts @@ -3,7 +3,7 @@ import { colors } from '@sopt-makers/colors'; import Image from 'next/image'; import Link from 'next/link'; -export const Post = styled(Link)` +export const BlogPost = styled(Link)` display: flex; justify-content: space-between; gap: 36px; diff --git a/src/views/BlogPage/components/BlogPostList/index.tsx b/src/views/BlogPage/components/BlogPostList/index.tsx new file mode 100644 index 00000000..8223d146 --- /dev/null +++ b/src/views/BlogPage/components/BlogPostList/index.tsx @@ -0,0 +1,20 @@ +import type { BlogPostListType } from '@src/lib/types/blog'; +import BlogPost from '@src/views/BlogPage/components/BlogPost'; +import * as S from './style'; + +interface BlogPostListProps { + selectedTap: string; // REVIEW || ARTICLE + blogPostList: BlogPostListType; +} + +function BlogPostList({ selectedTap, blogPostList }: BlogPostListProps) { + return ( + + {blogPostList.data.map((blogPost) => ( + + ))} + + ); +} + +export default BlogPostList; diff --git a/src/views/BlogPage/components/PostList/style.ts b/src/views/BlogPage/components/BlogPostList/style.ts similarity index 85% rename from src/views/BlogPage/components/PostList/style.ts rename to src/views/BlogPage/components/BlogPostList/style.ts index 00a56787..8be095fc 100644 --- a/src/views/BlogPage/components/PostList/style.ts +++ b/src/views/BlogPage/components/BlogPostList/style.ts @@ -1,6 +1,6 @@ import styled from '@emotion/styled'; -export const PostList = styled.div` +export const BlogPostList = styled.div` display: flex; flex-direction: column; gap: 80px; diff --git a/src/views/BlogPage/components/Post/index.tsx b/src/views/BlogPage/components/Post/index.tsx deleted file mode 100644 index 970b2089..00000000 --- a/src/views/BlogPage/components/Post/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useEffect, useRef, useState } from 'react'; -import type { BlogPostType } from '@src/lib/types/blog'; -import { parsePartToKorean } from '@src/lib/utils/parsePartToKorean'; -import Header from '@src/views/BlogPage/components/Post/Header'; -import Like from '@src/views/BlogPage/components/Post/Like'; -import * as S from './style'; - -const TWO_LINE_TITLE_HEIGHT = 72; - -interface PostProps { - selectedTap: string; - post: BlogPostType; -} - -function Post({ selectedTap, post }: PostProps) { - const titleRef = useRef(null); - const [descriptionLine, setDescriptionLine] = useState(1); - - useEffect(() => { - if (titleRef.current) { - const titleHeight = titleRef.current.clientHeight; - setDescriptionLine(titleHeight >= TWO_LINE_TITLE_HEIGHT ? 1 : 2); - } - }, []); - - return ( - -
-
- - {post.title} - {post.description} - - - {post.generation}기 - {parsePartToKorean(post.part)} - -
- - - {selectedTap === 'ARTICLE' && } - -
- ); -} - -export default Post; diff --git a/src/views/BlogPage/components/PostList/index.tsx b/src/views/BlogPage/components/PostList/index.tsx deleted file mode 100644 index 0f1547dd..00000000 --- a/src/views/BlogPage/components/PostList/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import type { BlogPostListType } from '@src/lib/types/blog'; -import Post from '@src/views/BlogPage/components/Post'; -import * as S from './style'; - -interface PostListProps { - selectedTap: string; // REVIEW || ARTICLE - postList: BlogPostListType; -} - -function PostList({ selectedTap, postList }: PostListProps) { - return ( - - {postList.data.map((post) => ( - - ))} - - ); -} - -export default PostList; From 10e9171806961f2beaf0c74099f2bb535dad89e5 Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Mon, 23 Oct 2023 00:25:36 +0900 Subject: [PATCH 10/12] =?UTF-8?q?fix:=20re-export=EC=9A=A9=20index.ts=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/BlogPage/components/BlogPost/Header/index.tsx | 2 +- src/views/BlogPage/components/BlogPost/index.ts | 3 --- src/views/BlogPage/components/BlogPost/index.tsx | 8 +++----- 3 files changed, 4 insertions(+), 9 deletions(-) delete mode 100644 src/views/BlogPage/components/BlogPost/index.ts diff --git a/src/views/BlogPage/components/BlogPost/Header/index.tsx b/src/views/BlogPage/components/BlogPost/Header/index.tsx index 4f2cf1aa..75c394f9 100644 --- a/src/views/BlogPage/components/BlogPost/Header/index.tsx +++ b/src/views/BlogPage/components/BlogPost/Header/index.tsx @@ -1,6 +1,6 @@ import { BlogPostType } from '@src/lib/types/blog'; import { formatDate } from '@src/lib/utils/dateFormat'; -import { DefaultProfileImage } from '@src/views/BlogPage/components/BlogPost'; +import DefaultProfileImage from '@src/views/BlogPage/components/BlogPost/DefaultProfileImage'; import * as S from './style'; interface HeaderProps { diff --git a/src/views/BlogPage/components/BlogPost/index.ts b/src/views/BlogPage/components/BlogPost/index.ts deleted file mode 100644 index 2342e8bf..00000000 --- a/src/views/BlogPage/components/BlogPost/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { default as DefaultProfileImage } from './DefaultProfileImage'; -export { default as Header } from './Header'; -export { default as Like } from './Like'; diff --git a/src/views/BlogPage/components/BlogPost/index.tsx b/src/views/BlogPage/components/BlogPost/index.tsx index b062cfe1..02921f2a 100644 --- a/src/views/BlogPage/components/BlogPost/index.tsx +++ b/src/views/BlogPage/components/BlogPost/index.tsx @@ -1,9 +1,9 @@ import { useEffect, useRef, useState } from 'react'; import type { BlogPostType } from '@src/lib/types/blog'; import { parsePartToKorean } from '@src/lib/utils/parsePartToKorean'; -import { Like } from '@src/views/BlogPage/components/BlogPost'; -import * as S from './style'; import Header from '@src/views/BlogPage/components/BlogPost/Header'; +import Like from '@src/views/BlogPage/components/BlogPost/Like'; +import * as S from './style'; const TWO_LINE_TITLE_HEIGHT = 72; @@ -12,7 +12,7 @@ interface BlogPostProps { blogPost: BlogPostType; } -function BlogPost({ selectedTap, blogPost }: BlogPostProps) { +export default function BlogPost({ selectedTap, blogPost }: BlogPostProps) { const titleRef = useRef(null); const [descriptionLine, setDescriptionLine] = useState(1); @@ -43,5 +43,3 @@ function BlogPost({ selectedTap, blogPost }: BlogPostProps) { ); } - -export default BlogPost; From ec63b7038059c0f2e6ed7eb8c5e6603a5be8bacb Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Mon, 23 Oct 2023 00:27:15 +0900 Subject: [PATCH 11/12] =?UTF-8?q?fix:=20=EA=B8=B0=EB=B3=B8=20=EB=82=B4?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EC=BD=94=EB=93=9C=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=EC=97=90=20=EB=A7=9E=EC=B6=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/BlogPost/DefaultProfileImage/index.tsx | 4 +--- src/views/BlogPage/components/BlogPost/Header/index.tsx | 4 +--- src/views/BlogPage/components/BlogPost/Like/index.tsx | 4 +--- src/views/BlogPage/components/BlogPostList/index.tsx | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/views/BlogPage/components/BlogPost/DefaultProfileImage/index.tsx b/src/views/BlogPage/components/BlogPost/DefaultProfileImage/index.tsx index fa11ddee..a1719617 100644 --- a/src/views/BlogPage/components/BlogPost/DefaultProfileImage/index.tsx +++ b/src/views/BlogPage/components/BlogPost/DefaultProfileImage/index.tsx @@ -2,12 +2,10 @@ import Image from 'next/image'; import icProfileDefault from '@src/assets/icons/ic_profile_default.svg'; import * as S from './style'; -function DefaultProfileImage() { +export default function DefaultProfileImage() { return ( 작성자 프로필 이미지 ); } - -export default DefaultProfileImage; diff --git a/src/views/BlogPage/components/BlogPost/Header/index.tsx b/src/views/BlogPage/components/BlogPost/Header/index.tsx index 75c394f9..84ca29e1 100644 --- a/src/views/BlogPage/components/BlogPost/Header/index.tsx +++ b/src/views/BlogPage/components/BlogPost/Header/index.tsx @@ -8,7 +8,7 @@ interface HeaderProps { blogPost: BlogPostType; } -function Header({ selectedTap, blogPost }: HeaderProps) { +export default function Header({ selectedTap, blogPost }: HeaderProps) { return ( {selectedTap === 'ARTICLE' ? ( @@ -35,5 +35,3 @@ function Header({ selectedTap, blogPost }: HeaderProps) { ); } - -export default Header; diff --git a/src/views/BlogPage/components/BlogPost/Like/index.tsx b/src/views/BlogPage/components/BlogPost/Like/index.tsx index f482d866..92b766a4 100644 --- a/src/views/BlogPage/components/BlogPost/Like/index.tsx +++ b/src/views/BlogPage/components/BlogPost/Like/index.tsx @@ -8,7 +8,7 @@ interface LikeProps { blogPost: BlogPostType; } -function Like({ blogPost }: LikeProps) { +export default function Like({ blogPost }: LikeProps) { return ( ); } - -export default Like; diff --git a/src/views/BlogPage/components/BlogPostList/index.tsx b/src/views/BlogPage/components/BlogPostList/index.tsx index 8223d146..c73e336e 100644 --- a/src/views/BlogPage/components/BlogPostList/index.tsx +++ b/src/views/BlogPage/components/BlogPostList/index.tsx @@ -7,7 +7,7 @@ interface BlogPostListProps { blogPostList: BlogPostListType; } -function BlogPostList({ selectedTap, blogPostList }: BlogPostListProps) { +export default function BlogPostList({ selectedTap, blogPostList }: BlogPostListProps) { return ( {blogPostList.data.map((blogPost) => ( @@ -16,5 +16,3 @@ function BlogPostList({ selectedTap, blogPostList }: BlogPostListProps) { ); } - -export default BlogPostList; From 5fbb73900edb27bf78f73a553bec119c9f241558 Mon Sep 17 00:00:00 2001 From: solar3070 <> Date: Mon, 23 Oct 2023 17:17:16 +0900 Subject: [PATCH 12/12] =?UTF-8?q?chore:=20colors=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/styles/colors.ts | 79 ---------------------------------------- 1 file changed, 79 deletions(-) delete mode 100644 src/lib/styles/colors.ts diff --git a/src/lib/styles/colors.ts b/src/lib/styles/colors.ts deleted file mode 100644 index 64ce3eba..00000000 --- a/src/lib/styles/colors.ts +++ /dev/null @@ -1,79 +0,0 @@ -export const colors = { - white: '#FFFFFF', - black: '#000000', - - gray10: '#FCFCFC', - gray30: '#F0F0F0', - gray50: '#E4E4E5', - gray100: '#C3C3C6', - gray200: '#9D9DA4', - gray300: '#808087', - gray400: '#66666D', - gray500: '#515159', - gray600: '#3F3F47', - gray700: '#2E2E35', - gray800: '#202025', - gray950: '#0F0F12', - - blue50: '#C8E1FF', - blue100: '#8FC0FF', - blue200: '#619EFF', - blue300: '#4485FF', - blue400: '#346FFA', - blue500: '#2C53DF', - blue600: '#2649B3', - blue700: '#253B8C', - blue800: '#23306A', - blue900: '#20274D', - - red50: '#FFD1D3', - red100: '#FFA8AD', - red200: '#FE818B', - red300: '#FA616D', - red400: '#F04251', - red500: '#CA2F3D', - red600: '#9E2733', - red700: '#7A242D', - red800: '#562025', - red900: '#3C2020', - - green50: '#CCFFEC', - green100: '#82F6CB', - green200: '#4EE4AD', - green300: '#26CF91', - green400: '#16BF81', - green500: '#13A06C', - green600: '#138A5E', - green700: '#136D4C', - green800: '#13533C', - green900: '#15372B', - - yellow50: '#FFF4D4', - yellow100: '#FFE9B2', - yellow200: '#FFDE8A', - yellow300: '#FFCD59', - yellow400: '#FFC234', - yellow500: '#FFB326', - yellow600: '#EBA01E', - yellow700: '#B57B1D', - yellow800: '#72531E', - yellow900: '#3D301A', - - orange50: '#FFECE5', - orange100: '#FFCEBD', - orange200: '#FFA480', - orange300: '#FF834A', - orange400: '#F77234', - orange500: '#D4591C', - orange600: '#AD4E17', - orange700: '#853D11', - orange800: '#5C2B0C', - orange900: '#422109', - - attention: '#FFC234', - error: '#F04251', - background: '#0F0F12', - secondary: '#F77234', - success: '#346FFA', - information: '#16BF81', -};