diff --git a/.prettierrc.json b/.prettierrc.json index 99fcc78..ea15e31 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -3,5 +3,11 @@ "singleQuote": true, "trailingComma": "all", "useTabs": false, - "tabWidth": 2 + "tabWidth": 2, + "bracketSpacing": true, + "jsxSingleQuote": false, + "printWidth": 80, + "proseWrap": "preserve", + "quoteProps": "as-needed", + "endOfLine": "lf" } diff --git a/src/app/profile/application/page.tsx b/src/app/profile/application/page.tsx new file mode 100644 index 0000000..a821e7a --- /dev/null +++ b/src/app/profile/application/page.tsx @@ -0,0 +1,34 @@ +'use client' + +import { Arrow } from '@/assets' +import { ApplicationBox } from '@/components' +import { applicationData } from '@/constants' +import { useRouter } from 'next/navigation' + +export default function MyApplicationPage() { + const router = useRouter() + + return ( + <main className="min-h-[100dvh] p-[60px_0_120px] flex justify-center"> + <section className="flex flex-col gap-10 px-10 sm:px-6 max-w-[1280px] w-full"> + <div className="flex flex-col gap-8"> + <button + onClick={() => router.back()} + className="p-2 rounded-lg border border-gray200 group hover:bg-gray50 transition-colors w-fit" + > + <Arrow className="group-hover:-translate-x-1 transition-transform" /> + </button> + <div className="flex flex-col gap-2"> + <h3 className="text-titleLarge">공유한 지원서 자료</h3> + <p className="text-bodySmall text-gray600">8개 내 지원서 자료</p> + </div> + </div> + <article className="grid grid-cols-3 md:grid-cols-2 sm:grid-cols-1 gap-3"> + {applicationData.map((value, index) => ( + <ApplicationBox key={index} {...value} /> + ))} + </article> + </section> + </main> + ) +} diff --git a/src/app/profile/edit/page.tsx b/src/app/profile/edit/page.tsx new file mode 100644 index 0000000..157dd1b --- /dev/null +++ b/src/app/profile/edit/page.tsx @@ -0,0 +1,52 @@ +'use client' + +import { Add, Arrow, DecorationImg_1 } from '@/assets' +import { Button, Input, Select } from '@/components' +import Image from 'next/image' +import { useRouter } from 'next/navigation' + +export default function ProfileEditPage() { + const router = useRouter() + + return ( + <main className="min-h-[100dvh] flex justify-center"> + <section className="flex flex-col gap-16 p-[60px_40px_120px] sm:px-6 max-w-[600px] w-full"> + <div className="flex flex-col gap-8"> + <button + onClick={() => router.back()} + className="p-2 rounded-lg border border-gray200 group hover:bg-gray50 transition-colors w-fit" + > + <Arrow className="group-hover:-translate-x-1 transition-transform" /> + </button> + <h3 className="text-titleLarge">프로필 수정</h3> + </div> + <article className="flex gap-10 items-center"> + <Image + src={DecorationImg_1} + alt="Profile Image" + width={240} + height={240} + priority + className="size-[120px] rounded-full border border-gray100" + /> + <button className="p-12 rounded-full border border-gray200 bg-gray100"> + <Add /> + </button> + </article> + <article className="flex flex-col gap-10"> + <Input label="기수" placeholder="기수를 입력해 주세요." value="8" /> + <Select + label="전공" + placeholder="전공 선택" + value="Frontend" + options={[{ value: 'Frontend', name: 'Frontend' }]} + change={() => {}} + /> + </article> + <Button size="large" className="w-full"> + 프로필 수정하기 + </Button> + </section> + </main> + ) +} diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx new file mode 100644 index 0000000..f2118b5 --- /dev/null +++ b/src/app/profile/page.tsx @@ -0,0 +1,113 @@ +import { Arrow, Bag, DecorationImg_1, GradientImg, User } from '@/assets' +import { ApplicationBox, Button, TipBox } from '@/components' +import { applicationData, tipData } from '@/constants' +import Image from 'next/image' +import Link from 'next/link' + +export default function ProfilePage() { + return ( + <main className="flex flex-col items-center"> + <div className="flex justify-center h-[180px] w-full relative"> + <Image + src={GradientImg} + alt="Profile Banner" + width={1920} + height={180} + className="w-full h-full object-cover border-b-2 border-gray100" + priority + /> + <Image + src={DecorationImg_1} + alt="User Profile" + width={240} + height={240} + className="size-[120px] absolute -bottom-[60px] rounded-full border border-gray100" + priority + /> + </div> + <section className="flex flex-col items-center gap-10 p-[60px_40px_120px] sm:px-6 max-w-[880px] w-full"> + <div className="flex flex-col items-center gap-1 py-6"> + <p className="text-titleMedium">마이클</p> + <p className="text-bodySmall text-gray600">팔로잉 24 | 팔로워 40</p> + </div> + <div className="flex gap-3"> + <Button kind="gray" size="small"> + 로그아웃 + </Button> + <Link href="/profile/edit"> + <Button kind="blue" size="small"> + 정보 수정하기 + </Button> + </Link> + </div> + <article className="flex flex-col gap-6 w-full"> + <h5 className="text-titleSmall">기본 정보</h5> + <div className="flex gap-10"> + <div className="flex flex-col items-center gap-2"> + <div className="p-3 rounded-xl border border-blue100 bg-blue50"> + <User size={28} className="text-blue500" /> + </div> + <div className="flex flex-col items-center gap-[2px]"> + <p className="text-bodySmall">기수</p> + <p className="text-labelMedium text-gray600">8기</p> + </div> + </div> + <div className="flex flex-col items-center gap-2"> + <div className="p-3 rounded-xl border border-blue100 bg-blue50"> + <Bag size={28} className="text-blue500" /> + </div> + <div className="flex flex-col items-center gap-[2px]"> + <p className="text-bodySmall">전공</p> + <p className="text-labelMedium text-gray600">Frontend</p> + </div> + </div> + </div> + </article> + <div className="w-full h-[1px] bg-gray200"></div> + <article className="flex flex-col gap-6 w-full"> + <div className="flex items-center justify-between w-full"> + <h5 className="text-titleSmall">공유한 지원서 자료</h5> + <Link + href="/profile/application" + className="flex items-center text-gray600 group" + > + <p className="text-labelLarge">더보기</p> + <Arrow + direction="right" + size={16} + className="group-hover:translate-x-1 transition-transform" + /> + </Link> + </div> + <div className="grid gap-3 grid-cols-2 sm:grid-cols-1"> + {applicationData.map((value, index) => ( + <ApplicationBox key={index} {...value} /> + ))} + </div> + </article> + <div className="w-full h-[1px] bg-gray200"></div> + <article className="flex flex-col gap-6 w-full"> + <div className="flex items-center justify-between w-full"> + <h5 className="text-titleSmall">공유한 지원서 팁</h5> + <Link + href="/profile/tip" + className="flex items-center text-gray600 group" + > + <p className="text-labelLarge">더보기</p> + <Arrow + direction="right" + size={16} + className="group-hover:translate-x-1 transition-transform" + /> + </Link> + </div> + <div className="grid gap-3 grid-cols-2 sm:grid-cols-1"> + {tipData.map((value, index) => ( + <TipBox key={index} {...value} /> + ))} + </div> + </article> + </section> + </main> + ) +} diff --git a/src/app/profile/tip/page.tsx b/src/app/profile/tip/page.tsx new file mode 100644 index 0000000..3685c33 --- /dev/null +++ b/src/app/profile/tip/page.tsx @@ -0,0 +1,34 @@ +'use client' + +import { Arrow } from '@/assets' +import { TipBox } from '@/components' +import { tipData } from '@/constants' +import { useRouter } from 'next/navigation' + +export default function MyTipPage() { + const router = useRouter() + + return ( + <main className="min-h-[100dvh] p-[60px_0_120px] flex justify-center"> + <section className="flex flex-col gap-10 px-10 sm:px-6 max-w-[1280px] w-full"> + <div className="flex flex-col gap-8"> + <button + onClick={() => router.back()} + className="p-2 rounded-lg border border-gray200 group hover:bg-gray50 transition-colors w-fit" + > + <Arrow className="group-hover:-translate-x-1 transition-transform" /> + </button> + <div className="flex flex-col gap-2"> + <h3 className="text-titleLarge">공유한 지원서 팁</h3> + <p className="text-bodySmall text-gray600">8개 내 지원서 팁</p> + </div> + </div> + <article className="grid grid-cols-3 md:grid-cols-2 sm:grid-cols-1 gap-3"> + {tipData.map((value, index) => ( + <TipBox key={index} {...value} /> + ))} + </article> + </section> + </main> + ) +} diff --git a/src/components/ApplicationBox.tsx b/src/components/ApplicationBox.tsx index c74b1c1..6edb2c6 100644 --- a/src/components/ApplicationBox.tsx +++ b/src/components/ApplicationBox.tsx @@ -1,28 +1,28 @@ 'use client' -import { ApplicationFileType, ApplicationPreviewType } from "@/types" -import { dateToString } from "@/utils" -import { useRouter } from "next/navigation" +import { ApplicationFileType, ApplicationPreviewType } from '@/types' +import { dateToString } from '@/utils' +import Link from 'next/link' interface ApplicationBoxProps { - tag: keyof typeof tagColor - title: string - name: string - date: string - mainMajor?: string - subMajor?: string + tag: keyof typeof tagColor + title: string + name: string + date: string + mainMajor?: string + subMajor?: string } const tagToKorean: Record<ApplicationFileType, string> = { - Portfolio: '포트폴리오', - PersonalStatement: '자기소개서', - Resume: '이력서', + Portfolio: '포트폴리오', + PersonalStatement: '자기소개서', + Resume: '이력서', } const tagColor: Record<ApplicationFileType, string> = { - Portfolio: 'bg-attentionBackground text-attention', - PersonalStatement: 'bg-coutionBackground text-coution', - Resume: 'bg-gray100 text-gray500', + Portfolio: 'bg-attentionBackground text-attention', + PersonalStatement: 'bg-coutionBackground text-coution', + Resume: 'bg-gray100 text-gray500', } /** @@ -35,38 +35,50 @@ const tagColor: Record<ApplicationFileType, string> = { <ApplicationBox tag="포트폴리오" title="제목" name="유저이름" mainMajor="Frontend" /> ``` */ -export const ApplicationBox = ({ post_id, post_title, post_post_type, user_oauth_id, post_major, post_created_at }: ApplicationPreviewType) => { - const router = useRouter() - - return ( - <div onClick={() => router.push(`/application/${post_id}`)} className="flex flex-col w-full p-8 gap-3 border border-gray100 bg-white rounded-3xl cursor-pointer"> - <div className={`px-[11px] w-fit h-fit py-1 rounded-full text-labelLarge ${tagColor[post_post_type]}`}>{tagToKorean[post_post_type]}</div> - <div className="flex flex-col gap-2"> - <span className="text-titleMedium text-black truncate">{post_title}</span> - <div className="flex justify-between items-center flex-wrap text-nowrap"> - <div className="text-bodySmall text-gray600 flex items-center gap-2"> - <span>{user_oauth_id}</span> - <div className="w-0.5 h-0.5 bg-gray600 rounded-full" /> - <span>{dateToString(post_created_at)}</span> - </div> - { - post_post_type !== 'Resume' && - <span className="text-labelLarge text-gray500">{post_major}</span> - } - {/* {tag !== '이력서' && ( - <div className="text-labelLarge text-gray500 flex items-center gap-2"> - <span>{mainMajor}</span> - { - subMajor && - <> - <span className="text-gray200">|</span> - <span>{subMajor}</span> - </> - } - </div> - )} */} - </div> +export const ApplicationBox = ({ + post_id, + post_title, + post_post_type, + user_oauth_id, + post_major, + post_created_at, +}: ApplicationPreviewType) => { + return ( + <Link + href={`/application/${post_id}`} + className="flex flex-col w-full p-8 sm:p-6 gap-3 border border-gray100 bg-white rounded-3xl cursor-pointer group" + > + <div + className={`px-[11px] w-fit h-fit py-1 rounded-full text-labelLarge ${tagColor[post_post_type]}`} + > + {tagToKorean[post_post_type]} + </div> + <div className="flex flex-col gap-2"> + <span className="text-titleMedium sm:text-titleSmall text-black group-hover:text-blue500 truncate transition-colors"> + {post_title} + </span> + <div className="flex justify-between items-center flex-wrap text-nowrap"> + <div className="text-bodySmall sm:text-labelMedium text-gray600 flex items-center gap-2"> + <span>{user_oauth_id}</span> + <div className="w-0.5 h-0.5 bg-gray600 rounded-full" /> + <span>{dateToString(post_created_at)}</span> + </div> + {post_post_type !== 'Resume' && ( + <span className="text-labelLarge text-gray500">{post_major}</span> + )} + {/* {tag !== '이력서' && ( + <div className="text-labelLarge text-gray500 flex items-center gap-2"> + <span>{mainMajor}</span> + {subMajor && ( + <> + <span className="text-gray200">|</span> + <span>{subMajor}</span> + </> + )} </div> - </div > - ) + )} */} + </div> + </div> + </Link> + ) } diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 331d015..847975e 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -81,16 +81,23 @@ export const Header = () => { </section> {hasToken ? ( <section className="flex gap-6 items-center"> - <Button kind="blue" size="small" className="sm:hidden" onClick={() => setModal(!modal)}> + <Button + kind="blue" + size="small" + className="sm:hidden" + onClick={() => setModal(!modal)} + > 내 지원서 ∙ 팁 공유 </Button> - <Image - src={PropofolLogo} - width={36} - height={36} - alt="유저 프로필 이미지" - className="w-9 h-9 object-cover rounded-full cursor-pointer" - /> + <Link href="/profile"> + <Image + src={PropofolLogo} + width={36} + height={36} + alt="유저 프로필 이미지" + className="w-9 h-9 object-cover rounded-full cursor-pointer" + /> + </Link> </section> ) : ( <Button kind="primary" size="small" onClick={() => setModal(!modal)}> diff --git a/src/components/TipBox.tsx b/src/components/TipBox.tsx index 68c94ce..e0b1491 100644 --- a/src/components/TipBox.tsx +++ b/src/components/TipBox.tsx @@ -1,10 +1,10 @@ -import { dateToString } from "@/utils"; +import { dateToString } from '@/utils' interface TipBoxProps { - title: string - content?: string - name: string - date: string + title: string + content?: string + name: string + date: string } /** @@ -16,29 +16,34 @@ interface TipBoxProps { ``` */ export const TipBox = ({ title, content, name, date }: TipBoxProps) => { - return ( - <> - { - content === undefined ? - <div className="p-8 flex sm:flex-col w-full min-w-[240px] gap-2.5 justify-between items-center sm:items-start border border-gray100 bg-white rounded-3xl cursor-pointer"> - <span className="text-titleSmall text-black truncate w-full">{title}</span> - <div className="text-bodySmall text-gray600 flex justify-end items-center gap-2 w-fit sm:w-full text-nowrap"> - <span>{name}</span> - <div className="w-0.5 h-0.5 bg-gray600 rounded-full" /> - <span>{dateToString(date)}</span> - </div> - </div> - : - <div className="p-8 flex flex-col w-full min-w-[240px] gap-2.5 justify-between items-start border border-gray100 bg-white rounded-3xl cursor-pointer"> - <span className="text-titleSmall text-black truncate w-full">{title}</span> - <span className="text-bodySmall text-gray500 line-clamp-2 w-full">{content}</span> - <div className="text-bodySmall text-gray600 flex items-center gap-2 w-fit sm:w-full text-nowrap"> - <span>{name}</span> - <div className="w-0.5 h-0.5 bg-gray600 rounded-full" /> - <span>{dateToString(date)}</span> - </div> - </div> - } - </> - ) + return ( + <> + {content === undefined ? ( + <div className="p-8 flex sm:flex-col w-full min-w-[240px] gap-2.5 justify-between items-center sm:items-start border border-gray100 bg-white rounded-3xl cursor-pointer"> + <span className="text-titleSmall text-black truncate w-full"> + {title} + </span> + <div className="text-bodySmall text-gray600 flex justify-end items-center gap-2 w-fit sm:w-full text-nowrap"> + <span>{name}</span> + <div className="w-0.5 h-0.5 bg-gray600 rounded-full" /> + <span>{dateToString(date)}</span> + </div> + </div> + ) : ( + <div className="p-8 sm:p-6 flex flex-col w-full min-w-[240px] gap-2 items-start border border-gray100 bg-white rounded-3xl cursor-pointer group"> + <span className="text-titleSmall text-black group-hover:text-blue500 transition-colors truncate w-full"> + {title} + </span> + <span className="text-bodySmall sm:text-labelMedium text-gray500 line-clamp-2 w-full flex-1"> + {content} + </span> + <div className="text-bodySmall sm:text-labelMedium text-gray600 flex items-center gap-2 w-fit sm:w-full text-nowrap pt-3"> + <span>{name}</span> + <div className="w-0.5 h-0.5 bg-gray600 rounded-full" /> + <span>{dateToString(date)}</span> + </div> + </div> + )} + </> + ) } diff --git a/src/constants/dummy.ts b/src/constants/dummy.ts new file mode 100644 index 0000000..eacc163 --- /dev/null +++ b/src/constants/dummy.ts @@ -0,0 +1,59 @@ +import { ApplicationPreviewType } from '@/types' + +export const applicationData: ApplicationPreviewType[] = [ + { + post_id: 0, + post_title: '개인적으로 완벽한 포트폴리오', + post_post_type: 'Portfolio', + user_oauth_id: '이강혁', + post_major: 'Backend', + post_created_at: '2024-05-16 01:00:01+00', + }, + { + post_id: 1, + post_title: '완벽에 가까운 포트폴리오', + post_post_type: 'Portfolio', + user_oauth_id: '이강혁', + post_major: 'Backend', + post_created_at: '2024-05-16 01:00:01+00', + }, + { + post_id: 2, + post_title: '자기소개의 완벽한 예', + post_post_type: 'PersonalStatement', + user_oauth_id: '강진현', + post_major: 'Frontend', + post_created_at: '2024-05-16 01:00:01+00', + }, + { + post_id: 3, + post_title: '자기소개의 완벽한 예', + post_post_type: 'PersonalStatement', + user_oauth_id: '강진현', + post_major: 'Frontend', + post_created_at: '2024-05-16 01:00:01+00', + }, +] + +export const tipData = [ + { + title: '지원서 작성 팁 3가지', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim', + name: '이강혁', + date: '2024-05-16 01:00:01+00', + }, + { + title: '지원서 작성 팁 3가지', + content: 'eiusmod tembna aliqua. Ut enim', + name: '이강혁', + date: '2024-05-16 01:00:01+00', + }, + { + title: '지원서 작성 팁 3가지', + content: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim', + name: '이강혁', + date: '2024-05-16 01:00:01+00', + }, +] diff --git a/src/constants/index.ts b/src/constants/index.ts new file mode 100644 index 0000000..1e9de72 --- /dev/null +++ b/src/constants/index.ts @@ -0,0 +1 @@ +export { applicationData, tipData } from './dummy'