diff --git a/.pnp.cjs b/.pnp.cjs index e06311e6..dbb0fd87 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -29,6 +29,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./",\ "packageDependencies": [\ ["@chromatic-com/storybook", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:1.6.1"],\ + ["@dnd-kit/core", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:6.1.0"],\ ["@radix-ui/react-dialog", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:1.1.1"],\ ["@radix-ui/react-dropdown-menu", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:2.1.1"],\ ["@radix-ui/react-popover", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:1.1.1"],\ @@ -2876,6 +2877,81 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ + ["@dnd-kit/accessibility", [\ + ["npm:3.1.0", {\ + "packageLocation": "./.yarn/cache/@dnd-kit-accessibility-npm-3.1.0-c746ff31d6-fcb88c961e.zip/node_modules/@dnd-kit/accessibility/",\ + "packageDependencies": [\ + ["@dnd-kit/accessibility", "npm:3.1.0"]\ + ],\ + "linkType": "SOFT"\ + }],\ + ["virtual:c56d1254a2b254d10804c16afd3fd0503381dc2cb0b930038ba9faa2fec3a2651d9db43268b68ffa04f0d62b88d201d4de1f7ff943ecb3481f607a48f94d517e#npm:3.1.0", {\ + "packageLocation": "./.yarn/__virtual__/@dnd-kit-accessibility-virtual-2af1b278e8/0/cache/@dnd-kit-accessibility-npm-3.1.0-c746ff31d6-fcb88c961e.zip/node_modules/@dnd-kit/accessibility/",\ + "packageDependencies": [\ + ["@dnd-kit/accessibility", "virtual:c56d1254a2b254d10804c16afd3fd0503381dc2cb0b930038ba9faa2fec3a2651d9db43268b68ffa04f0d62b88d201d4de1f7ff943ecb3481f607a48f94d517e#npm:3.1.0"],\ + ["@types/react", "npm:18.3.3"],\ + ["react", "npm:18.3.1"],\ + ["tslib", "npm:2.6.3"]\ + ],\ + "packagePeers": [\ + "@types/react",\ + "react"\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@dnd-kit/core", [\ + ["npm:6.1.0", {\ + "packageLocation": "./.yarn/cache/@dnd-kit-core-npm-6.1.0-13c1618df7-3b8f46d2f4.zip/node_modules/@dnd-kit/core/",\ + "packageDependencies": [\ + ["@dnd-kit/core", "npm:6.1.0"]\ + ],\ + "linkType": "SOFT"\ + }],\ + ["virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:6.1.0", {\ + "packageLocation": "./.yarn/__virtual__/@dnd-kit-core-virtual-c56d1254a2/0/cache/@dnd-kit-core-npm-6.1.0-13c1618df7-3b8f46d2f4.zip/node_modules/@dnd-kit/core/",\ + "packageDependencies": [\ + ["@dnd-kit/core", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:6.1.0"],\ + ["@dnd-kit/accessibility", "virtual:c56d1254a2b254d10804c16afd3fd0503381dc2cb0b930038ba9faa2fec3a2651d9db43268b68ffa04f0d62b88d201d4de1f7ff943ecb3481f607a48f94d517e#npm:3.1.0"],\ + ["@dnd-kit/utilities", "virtual:c56d1254a2b254d10804c16afd3fd0503381dc2cb0b930038ba9faa2fec3a2651d9db43268b68ffa04f0d62b88d201d4de1f7ff943ecb3481f607a48f94d517e#npm:3.2.2"],\ + ["@types/react", "npm:18.3.3"],\ + ["@types/react-dom", "npm:18.3.0"],\ + ["react", "npm:18.3.1"],\ + ["react-dom", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:18.3.1"],\ + ["tslib", "npm:2.6.3"]\ + ],\ + "packagePeers": [\ + "@types/react-dom",\ + "@types/react",\ + "react-dom",\ + "react"\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ + ["@dnd-kit/utilities", [\ + ["npm:3.2.2", {\ + "packageLocation": "./.yarn/cache/@dnd-kit-utilities-npm-3.2.2-3fe8307947-8a5015c2fa.zip/node_modules/@dnd-kit/utilities/",\ + "packageDependencies": [\ + ["@dnd-kit/utilities", "npm:3.2.2"]\ + ],\ + "linkType": "SOFT"\ + }],\ + ["virtual:c56d1254a2b254d10804c16afd3fd0503381dc2cb0b930038ba9faa2fec3a2651d9db43268b68ffa04f0d62b88d201d4de1f7ff943ecb3481f607a48f94d517e#npm:3.2.2", {\ + "packageLocation": "./.yarn/__virtual__/@dnd-kit-utilities-virtual-a5cef4a422/0/cache/@dnd-kit-utilities-npm-3.2.2-3fe8307947-8a5015c2fa.zip/node_modules/@dnd-kit/utilities/",\ + "packageDependencies": [\ + ["@dnd-kit/utilities", "virtual:c56d1254a2b254d10804c16afd3fd0503381dc2cb0b930038ba9faa2fec3a2651d9db43268b68ffa04f0d62b88d201d4de1f7ff943ecb3481f607a48f94d517e#npm:3.2.2"],\ + ["@types/react", "npm:18.3.3"],\ + ["react", "npm:18.3.1"],\ + ["tslib", "npm:2.6.3"]\ + ],\ + "packagePeers": [\ + "@types/react",\ + "react"\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["@emnapi/runtime", [\ ["npm:1.2.0", {\ "packageLocation": "./.yarn/cache/@emnapi-runtime-npm-1.2.0-36d2203035-c9f5814f65.zip/node_modules/@emnapi/runtime/",\ @@ -8894,6 +8970,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageDependencies": [\ ["bbo-gak", "workspace:."],\ ["@chromatic-com/storybook", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:1.6.1"],\ + ["@dnd-kit/core", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:6.1.0"],\ ["@radix-ui/react-dialog", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:1.1.1"],\ ["@radix-ui/react-dropdown-menu", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:2.1.1"],\ ["@radix-ui/react-popover", "virtual:d9cd1cf96fc105240ce4126e416dd90faeefaf08cea474f2ffdd0a21bc6194bc993779567e0c0bf19c40cbbd585d546a065d8582fcc0925f8826e5fbca78aa72#npm:1.1.1"],\ diff --git a/.yarn/cache/@dnd-kit-accessibility-npm-3.1.0-c746ff31d6-fcb88c961e.zip b/.yarn/cache/@dnd-kit-accessibility-npm-3.1.0-c746ff31d6-fcb88c961e.zip new file mode 100644 index 00000000..84f3dc29 Binary files /dev/null and b/.yarn/cache/@dnd-kit-accessibility-npm-3.1.0-c746ff31d6-fcb88c961e.zip differ diff --git a/.yarn/cache/@dnd-kit-core-npm-6.1.0-13c1618df7-3b8f46d2f4.zip b/.yarn/cache/@dnd-kit-core-npm-6.1.0-13c1618df7-3b8f46d2f4.zip new file mode 100644 index 00000000..36c19589 Binary files /dev/null and b/.yarn/cache/@dnd-kit-core-npm-6.1.0-13c1618df7-3b8f46d2f4.zip differ diff --git a/.yarn/cache/@dnd-kit-utilities-npm-3.2.2-3fe8307947-8a5015c2fa.zip b/.yarn/cache/@dnd-kit-utilities-npm-3.2.2-3fe8307947-8a5015c2fa.zip new file mode 100644 index 00000000..dda40fd6 Binary files /dev/null and b/.yarn/cache/@dnd-kit-utilities-npm-3.2.2-3fe8307947-8a5015c2fa.zip differ diff --git a/.yarn/cache/@next-swc-darwin-arm64-npm-14.2.4-86d534c3ee-8.zip b/.yarn/cache/@next-swc-darwin-arm64-npm-14.2.4-86d534c3ee-8.zip deleted file mode 100644 index 36e475bf..00000000 Binary files a/.yarn/cache/@next-swc-darwin-arm64-npm-14.2.4-86d534c3ee-8.zip and /dev/null differ diff --git a/package.json b/package.json index 63d00f0d..02b2fac2 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "node": "20.2.0" }, "dependencies": { + "@dnd-kit/core": "^6.1.0", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-popover": "^1.1.1", diff --git a/src/app/(sidebar)/(my-info)/components/InfoCardList.tsx b/src/app/(sidebar)/(my-info)/components/InfoCardList.tsx index 6267ef92..dcbf0c31 100644 --- a/src/app/(sidebar)/(my-info)/components/InfoCardList.tsx +++ b/src/app/(sidebar)/(my-info)/components/InfoCardList.tsx @@ -4,7 +4,7 @@ import { useState } from 'react'; import { mockInfoCount, mockInfoList } from '../mock'; import { cn } from '@/utils/tailwind-util'; import { Icon } from '@/system/components'; -import { InfoCardItem } from './InfoCardItem'; +import { InfoCard } from '@/components/InfoCard'; const INFO_OPTIONS = ['경험 정리', '자기소개서', '면접 질문'] as const; @@ -46,11 +46,13 @@ export function InfoCardList() { -
+
+ ); } diff --git a/src/app/(sidebar)/(my-info)/mock.ts b/src/app/(sidebar)/(my-info)/mock.ts index b5273dcd..8e507ce2 100644 --- a/src/app/(sidebar)/(my-info)/mock.ts +++ b/src/app/(sidebar)/(my-info)/mock.ts @@ -1,4 +1,4 @@ -import { InfoCard } from '@/types/info'; +import { InfoCardType } from '@/types/info'; export const mockInfoCount = { '경험 정리': 1, @@ -6,7 +6,7 @@ export const mockInfoCount = { '면접 질문': 2, }; -export const mockInfoList: InfoCard[] = [ +export const mockInfoList: InfoCardType[] = [ { id: 1, title: '제목', diff --git a/src/app/(sidebar)/my-recruit/components/NewRecruitDialogContent/InputField.tsx b/src/app/(sidebar)/my-recruit/components/NewRecruitDialogContent/InputField.tsx index 274ceb2f..841e0d43 100644 --- a/src/app/(sidebar)/my-recruit/components/NewRecruitDialogContent/InputField.tsx +++ b/src/app/(sidebar)/my-recruit/components/NewRecruitDialogContent/InputField.tsx @@ -1,4 +1,4 @@ -import { If } from '@/components/If'; +import { If } from '@/system/utils/If'; import { ComponentProps, ReactNode } from 'react'; interface Props extends ComponentProps<'input'> { diff --git a/src/app/(sidebar)/my-recruit/components/NewRecruitDialogContent/NewRecruitDialogContent.tsx b/src/app/(sidebar)/my-recruit/components/NewRecruitDialogContent/NewRecruitDialogContent.tsx index f45ca13b..a0f08d35 100644 --- a/src/app/(sidebar)/my-recruit/components/NewRecruitDialogContent/NewRecruitDialogContent.tsx +++ b/src/app/(sidebar)/my-recruit/components/NewRecruitDialogContent/NewRecruitDialogContent.tsx @@ -1,4 +1,4 @@ -import { Spacing } from '@/components/Spacing'; +import { Spacing } from '@/system/utils/Spacing'; import { TouchButton } from '@/components/TouchButton'; import { Dialog } from '@/system/components/Dialog/ShadcnDialog'; import { color } from '@/system/token/color'; @@ -17,7 +17,7 @@ import { motion } from 'framer-motion'; import { Popover, PopoverContent, PopoverTrigger } from '@/system/components/Popover/Popover'; import { Calendar } from '@/system/components/Calendar/Calendar'; import { format } from 'date-fns/format'; -import { If } from '@/components/If'; +import { If } from '@/system/utils/If'; interface Props { onSubmit: () => void; diff --git a/src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx b/src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx index e6959e93..34927397 100644 --- a/src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx +++ b/src/app/(sidebar)/my-recruit/containers/AllRecruitment.tsx @@ -2,7 +2,7 @@ import { Icon } from '@/system/components'; import { RocketIcon } from './components/RocketIcon'; -import { Spacing } from '@/components/Spacing'; +import { Spacing } from '@/system/utils/Spacing'; import { DropdownMenu, DropdownMenuContent, @@ -14,8 +14,11 @@ import { color } from '@/system/token/color'; import { Dialog } from '@/system/components/Dialog/ShadcnDialog'; import { cardList } from '../mock'; import { RowCard } from './components/Card/RowCard'; +import { Droppable, useDndContext } from '@/lib/dnd-kit/dnd-kit'; export function AllRecruitment() { + const { over } = useDndContext(); + return ( <> @@ -48,7 +51,9 @@ export function AllRecruitment() {
{cardList.map((cardInfo) => ( - + + + ))}
diff --git a/src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx b/src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx index 3d31fd3d..2c4f05ba 100644 --- a/src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx +++ b/src/app/(sidebar)/my-recruit/containers/ProgressingRecruitment.tsx @@ -1,4 +1,4 @@ -import { Spacing } from '@/components/Spacing'; +import { Spacing } from '@/system/utils/Spacing'; import { ShoeIcon } from './components/ShoeIcon'; import { Dialog } from '@/system/components/Dialog/ShadcnDialog'; import { motion } from 'framer-motion'; diff --git a/src/app/(sidebar)/my-recruit/containers/RightSidebar.tsx b/src/app/(sidebar)/my-recruit/containers/RightSidebar.tsx new file mode 100644 index 00000000..40c962d5 --- /dev/null +++ b/src/app/(sidebar)/my-recruit/containers/RightSidebar.tsx @@ -0,0 +1,71 @@ +import { Spacing } from '@/system/utils/Spacing'; +import { TouchButton } from '@/components/TouchButton'; +import { Icon } from '@/system/components'; +import { color } from '@/system/token/color'; +import { mockInfoList } from '../mock'; +import { InfoCard } from '@/components/InfoCard'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/system/components/DropdownMenu/DropdownMenu'; +import { Draggable } from '@/lib/dnd-kit/dnd-kit'; +import { motion } from 'framer-motion'; + +interface Props { + onCloseButtonClick: () => void; +} + +const infoCategoryList = ['경험 정리', '자기소개서', '면접 질문']; + +export function RightSidebar({ onCloseButtonClick }: Props) { + return ( + + + + + + +
+ 내 정보 가져오기 + + +
+ 경험 정리 + +
+
+ + {infoCategoryList.map((item) => ( + {item} + ))} + +
+
+ + 카드를 공고 폴더로 드래그해보세요 + +
    + {mockInfoList.map((info) => ( +
  • + + + +
  • + ))} +
+
+
+ ); +} diff --git a/src/app/(sidebar)/my-recruit/containers/components/Card/BoxCard.tsx b/src/app/(sidebar)/my-recruit/containers/components/Card/BoxCard.tsx index b3924ead..6c69fd76 100644 --- a/src/app/(sidebar)/my-recruit/containers/components/Card/BoxCard.tsx +++ b/src/app/(sidebar)/my-recruit/containers/components/Card/BoxCard.tsx @@ -1,4 +1,4 @@ -import { Spacing } from '@/components/Spacing'; +import { Spacing } from '@/system/utils/Spacing'; import { Icon } from '@/system/components'; import { color } from '@/system/token/color'; import { dday } from '@/utils/date'; @@ -8,6 +8,7 @@ import { Dialog } from '@/system/components/Dialog/ShadcnDialog'; import { DueDateDialog } from '../DueDateDialog'; export type ProgressingCardType = { + id: number; type: '서류 마감' | '1차 면접' | '2차 면접'; status: '지원 완료' | '서류 통과' | '서류 탈락'; dueDate: Date | null; @@ -52,17 +53,3 @@ export function BoxCard({ type, title, status, dueDate, period }: ProgressingCar ); } - -const statusList = [ - { variant: 'text', text: '지원 준비' }, - { variant: 'text', text: '지원 완료' }, - { variant: 'border' }, - { variant: 'text', text: '서류 통과' }, - { variant: 'text', text: '서류 탈락' }, - { variant: 'border' }, - { variant: 'text', text: '면접 통과' }, - { variant: 'text', text: '면접 탈락' }, - { variant: 'border' }, - { variant: 'text', text: '최종 합격' }, - { variant: 'text', text: '최종 탈락' }, -] as const; diff --git a/src/app/(sidebar)/my-recruit/containers/components/Card/RowCard.tsx b/src/app/(sidebar)/my-recruit/containers/components/Card/RowCard.tsx index 1e9cc852..28742e06 100644 --- a/src/app/(sidebar)/my-recruit/containers/components/Card/RowCard.tsx +++ b/src/app/(sidebar)/my-recruit/containers/components/Card/RowCard.tsx @@ -1,24 +1,31 @@ -import { If } from '@/components/If'; -import { Spacing } from '@/components/Spacing'; +import { If } from '@/system/utils/If'; +import { Spacing } from '@/system/utils/Spacing'; import { Icon } from '@/system/components'; import { color } from '@/system/token/color'; import { dday } from '@/utils/date'; import { MoreButton } from '@/app/(sidebar)/my-recruit/containers/components/Card/common/MoreButton'; import { StatusButton } from './common/StatusButton'; +import { cn } from '@/utils'; interface RowCardProps { + id: number; type: '서류 마감' | '1차 면접' | '2차 면접'; status: '지원 완료' | '서류 통과' | '서류 탈락'; dueDate: Date | null; period: string; title: string; + highlighted?: boolean; } -export function RowCard({ type, title, status, dueDate, period }: RowCardProps) { +export function RowCard({ type, title, status, dueDate, period, highlighted = false }: RowCardProps) { return (
-
-
+
+
{period} diff --git a/src/app/(sidebar)/my-recruit/containers/components/Card/common/StatusButton.tsx b/src/app/(sidebar)/my-recruit/containers/components/Card/common/StatusButton.tsx index e643f4cd..45e2f89d 100644 --- a/src/app/(sidebar)/my-recruit/containers/components/Card/common/StatusButton.tsx +++ b/src/app/(sidebar)/my-recruit/containers/components/Card/common/StatusButton.tsx @@ -1,4 +1,4 @@ -import { SwitchCase } from '@/components/SwitchCase'; +import { SwitchCase } from '@/system/utils/SwitchCase'; import { Icon } from '@/system/components'; import { DropdownMenu, @@ -24,8 +24,9 @@ export function StatusButton({ currentStatus }: Props) {
- {statusList.map((item) => ( + {statusList.map((item, index) => ( -
-
-

내 공고 뽀각

-
- - - 내 정보 가져오기 - - -
- - - 새 공고 + + +
+
+
+

내 공고 뽀각

+
+ setSidebarOpened(!sidebarOpened)}> + + 내 정보 가져오기 + +
+ + + 새 공고 + +
+
- +
+ + + +
+ + {sidebarOpened ? setSidebarOpened(false)} /> : null} +
- - - - -
- - - - + + + + + ); } diff --git a/src/app/(sidebar)/write/components/TagSelector/TagSelector.tsx b/src/app/(sidebar)/write/components/TagSelector/TagSelector.tsx index 3cf90407..00f2a785 100644 --- a/src/app/(sidebar)/write/components/TagSelector/TagSelector.tsx +++ b/src/app/(sidebar)/write/components/TagSelector/TagSelector.tsx @@ -5,7 +5,7 @@ import { generateContext } from '@/lib'; import { cn } from '@/utils'; import { Remove } from '@/system/components/Icon/SVG/Remove'; import { SVGProps } from 'react'; -import { If } from '@/components/If'; +import { If } from '@/system/utils/If'; const [TagSelectorProvider, useTagSelectorContext] = generateContext< Omit diff --git a/src/app/(sidebar)/write/page.tsx b/src/app/(sidebar)/write/page.tsx index c0d6dc80..d8fa3007 100644 --- a/src/app/(sidebar)/write/page.tsx +++ b/src/app/(sidebar)/write/page.tsx @@ -5,9 +5,9 @@ import { useState } from 'react'; import { Input } from '@/system/components/Input/Input'; import { TagSelector } from './components/TagSelector/TagSelector'; import { abilityTags, personalityTags, categoryTags, tags, categories } from './components/TagSelector/constants'; -import { If } from '@/components/If'; +import { If } from '@/system/utils/If'; import { cn } from '@/utils'; -import { Spacing } from '@/components/Spacing'; +import { Spacing } from '@/system/utils/Spacing'; import { Icon } from '@/system/components'; import { DropdownMenu, diff --git a/src/app/(sidebar)/(my-info)/components/InfoCardItem.tsx b/src/components/InfoCard.tsx similarity index 72% rename from src/app/(sidebar)/(my-info)/components/InfoCardItem.tsx rename to src/components/InfoCard.tsx index aad65a48..c35d5300 100644 --- a/src/app/(sidebar)/(my-info)/components/InfoCardItem.tsx +++ b/src/components/InfoCard.tsx @@ -1,26 +1,27 @@ -import { Icon } from '@/system/components'; -import { Tag } from '@/system/components/Tag/Tag'; import { formatToYYMMDD } from '@/utils/date'; +import { Icon } from '@/system/components'; +import { Tag, TagColor } from '@/system/components/index'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/system/components/DropdownMenu/DropdownMenu'; -import { InfoCard } from '@/types/info'; +import { color } from '@/system/token/color'; +import { InfoCardType, TagType } from '@/types/info'; -interface Props extends InfoCard {} +type InfoCardProps = InfoCardType; -const TAG_TYPE_COLOR = { +const TAG_TYPE_COLOR: Record = { 역량: 'blue', 인성: 'purple', -} as const; +}; -export function InfoCardItem({ title, updatedDate, cardTagList }: Props) { +export function InfoCard({ title, updatedDate, cardTagList }: InfoCardProps) { const formattedDate = formatToYYMMDD(updatedDate, { separator: '.' }); return ( -
+
{formattedDate}
@@ -30,7 +31,7 @@ export function InfoCardItem({ title, updatedDate, cardTagList }: Props) { @@ -39,7 +40,7 @@ export function InfoCardItem({ title, updatedDate, cardTagList }: Props) {
삭제하기
- +
개별창으로 띄우기
diff --git a/src/container/Sidebar/SidebarButton.tsx b/src/container/Sidebar/SidebarButton.tsx index 61d97836..8b08d02c 100644 --- a/src/container/Sidebar/SidebarButton.tsx +++ b/src/container/Sidebar/SidebarButton.tsx @@ -1,4 +1,4 @@ -import { If } from '@/components/If'; +import { If } from '@/system/utils/If'; import { Icon, Text } from '@/system/components'; import { motion } from 'framer-motion'; import type { IconProps } from '@/system/components'; diff --git a/src/lib/dnd-kit/DndContextWithOverlay.tsx b/src/lib/dnd-kit/DndContextWithOverlay.tsx new file mode 100644 index 00000000..4b249a00 --- /dev/null +++ b/src/lib/dnd-kit/DndContextWithOverlay.tsx @@ -0,0 +1,43 @@ +import { ComponentProps, ReactNode, useEffect, useState } from 'react'; +import { DndContext, DragOverlay } from '@dnd-kit/core'; +import type { DragStartEvent, DragEndEvent } from '@dnd-kit/core'; +import { If } from '@/system/utils/If'; +import { mergeProps } from '@/utils/mergeProps'; +import { DndAdditionalProvider } from './context'; + +interface Props extends ComponentProps { + OverlayElement: (props: any) => ReactNode; +} + +export function DndContextWithOverlay({ OverlayElement, children, ...restProps }: Props) { + const [overlayElementData, setOverlayElementData] = useState(null); + const [selectedId, setSelectedId] = useState(); + + const onDragStart = ({ active }: DragStartEvent) => { + setOverlayElementData(active.data.current); + }; + + const onDragEnd = ({ over }: DragEndEvent) => { + setOverlayElementData(null); + setSelectedId(over?.id); + }; + + useEffect(() => { + if (selectedId != null) { + setSelectedId(undefined); + } + }, [selectedId]); + + return ( + + + + + + + + {children} + + + ); +} diff --git a/src/lib/dnd-kit/Draggable.tsx b/src/lib/dnd-kit/Draggable.tsx new file mode 100644 index 00000000..c4e837b3 --- /dev/null +++ b/src/lib/dnd-kit/Draggable.tsx @@ -0,0 +1,20 @@ +import React, { PropsWithChildren } from 'react'; +import { useDraggable } from '@dnd-kit/core'; + +interface DraggableProps { + id: string | number; + dataForOverlay: any; +} + +export function Draggable({ id, children, dataForOverlay }: PropsWithChildren) { + const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ + id: id, + data: dataForOverlay, + }); + + return ( +
+ {children} +
+ ); +} diff --git a/src/lib/dnd-kit/Droppable.tsx b/src/lib/dnd-kit/Droppable.tsx new file mode 100644 index 00000000..c0d65697 --- /dev/null +++ b/src/lib/dnd-kit/Droppable.tsx @@ -0,0 +1,30 @@ +import React, { ReactNode, useEffect } from 'react'; +import { useDroppable } from '@dnd-kit/core'; +import { useDndAdditionalContext } from './context'; +import { motion, useAnimationControls } from 'framer-motion'; + +interface DroppableProps { + id: string | number; + children?: ReactNode; +} + +export function Droppable({ id, children }: DroppableProps) { + const animationControl = useAnimationControls(); + const { setNodeRef } = useDroppable({ id }); + const { selectedId } = useDndAdditionalContext(); + + useEffect(() => { + if (selectedId === id) { + animationControl.start('highlight'); + } + }, [id, selectedId]); + + return ( + + {children} + + ); +} diff --git a/src/lib/dnd-kit/context.ts b/src/lib/dnd-kit/context.ts new file mode 100644 index 00000000..c9b7b1ae --- /dev/null +++ b/src/lib/dnd-kit/context.ts @@ -0,0 +1,9 @@ +import { generateContext } from '@/lib'; + +interface DndAdditionalContext { + selectedId: number | string; +} + +export const [DndAdditionalProvider, useDndAdditionalContext] = generateContext({ + name: 'DndContextWithOverlay', +}); diff --git a/src/lib/dnd-kit/dnd-kit.ts b/src/lib/dnd-kit/dnd-kit.ts new file mode 100644 index 00000000..94a6acbb --- /dev/null +++ b/src/lib/dnd-kit/dnd-kit.ts @@ -0,0 +1,4 @@ +export * from '@dnd-kit/core'; +export { Draggable } from './Draggable'; +export { Droppable } from './Droppable'; +export { DndContextWithOverlay } from './DndContextWithOverlay'; diff --git a/src/system/components/Icon/Icon.tsx b/src/system/components/Icon/Icon.tsx index 69c4f423..912a02da 100644 --- a/src/system/components/Icon/Icon.tsx +++ b/src/system/components/Icon/Icon.tsx @@ -26,11 +26,13 @@ import { CalendarFill } from './SVG/CalendarFill'; import { Clover } from './SVG/Clover'; import { DownChevron } from './SVG/DownChevron'; import { FolderFill } from './SVG/FolderFill'; +import { Close } from './SVG/Close'; const iconMap = { bell: Bell, copy: Copy, check: Check, + close: Close, division: Division, folder: Folder, folderFill: FolderFill, diff --git a/src/system/components/Icon/SVG/Close.tsx b/src/system/components/Icon/SVG/Close.tsx new file mode 100644 index 00000000..05f4524e --- /dev/null +++ b/src/system/components/Icon/SVG/Close.tsx @@ -0,0 +1,10 @@ +import { IconBaseType } from '@/system/components/Icon/SVG/type'; + +export function Close({ size, color }: IconBaseType) { + return ( + + + + + ); +} diff --git a/src/system/components/Icon/SVG/DownChevron.tsx b/src/system/components/Icon/SVG/DownChevron.tsx index 47033995..3050ff30 100644 --- a/src/system/components/Icon/SVG/DownChevron.tsx +++ b/src/system/components/Icon/SVG/DownChevron.tsx @@ -3,7 +3,7 @@ import { IconBaseType } from '@/system/components/Icon/SVG/type'; export function DownChevron({ color, size }: IconBaseType) { return ( - + ); } diff --git a/src/system/components/Tag/Tag.tsx b/src/system/components/Tag/Tag.tsx index db371dce..d77a671a 100644 --- a/src/system/components/Tag/Tag.tsx +++ b/src/system/components/Tag/Tag.tsx @@ -1,8 +1,9 @@ import { cn } from '@/utils/tailwind-util'; import { PropsWithChildren } from 'react'; +export type TagColor = 'default' | 'blue' | 'purple'; export interface TagProps { - color?: 'default' | 'blue' | 'purple'; + color?: TagColor; } // TODO: cva 사용 로직으로 변경 diff --git a/src/system/components/index.ts b/src/system/components/index.ts index ee17bbdd..41b6007d 100644 --- a/src/system/components/index.ts +++ b/src/system/components/index.ts @@ -4,3 +4,5 @@ export { Icon } from './Icon/Icon'; export type { IconProps } from './Icon/Icon'; export { Text } from './Text/Text'; export type { TextProps } from './Text/Text'; +export { Tag } from './Tag/Tag'; +export type { TagProps, TagColor } from './Tag/Tag'; diff --git a/src/components/If.tsx b/src/system/utils/If.tsx similarity index 100% rename from src/components/If.tsx rename to src/system/utils/If.tsx diff --git a/src/components/Spacing.tsx b/src/system/utils/Spacing.tsx similarity index 100% rename from src/components/Spacing.tsx rename to src/system/utils/Spacing.tsx diff --git a/src/components/SwitchCase.tsx b/src/system/utils/SwitchCase.tsx similarity index 100% rename from src/components/SwitchCase.tsx rename to src/system/utils/SwitchCase.tsx diff --git a/src/types/info.ts b/src/types/info.ts index 6b8a3ec1..a45f9a98 100644 --- a/src/types/info.ts +++ b/src/types/info.ts @@ -1,12 +1,12 @@ -export interface Tag { +export interface TagType { id: number; name: string; type: '인성' | '역량'; } -export interface InfoCard { +export interface InfoCardType { id: number; title: string; updatedDate: string; - cardTagList: Tag[]; + cardTagList: TagType[]; } diff --git a/src/utils/mergeProps.ts b/src/utils/mergeProps.ts new file mode 100644 index 00000000..1c1c4c4f --- /dev/null +++ b/src/utils/mergeProps.ts @@ -0,0 +1,49 @@ +/** + * https://github.com/andrewbranch/merge-props/blob/master/src/index.ts + */ +type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; + +function pushProp(target: { [key: string]: any }, key: string, value: any): void { + if (key === 'className') { + target.className = [target.className, value].join(' ').trim(); + } else if (key === 'style') { + target.style = { ...target.style, ...value }; + } else if (typeof value === 'function') { + const oldFn = target[key] as Function | undefined; + target[key] = oldFn + ? (...args: any[]) => { + oldFn(...args); + (value as Function)(...args); + } + : value; + } else if (value === undefined || (typeof value !== 'object' && value === target[key])) { + return; + } else if (!(key in target)) { + target[key] = value; + } else { + throw new Error( + `Didn’t know how to merge prop '${key}'. ` + `Only 'className', 'style', and event handlers are supported`, + ); + } +} + +export function mergeProps( + ...props: T +): { + [K in keyof UnionToIntersection]: K extends 'className' + ? string + : K extends 'style' + ? UnionToIntersection[K] + : Exclude[K], undefined>; +} { + if (props.length === 1) { + return props[0] as any; + } + + return props.reduce((merged, ps: any) => { + for (const key in ps) { + pushProp(merged, key, ps[key]); + } + return merged; + }, {}) as any; +} diff --git a/yarn.lock b/yarn.lock index fefbef36..dee32a39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1549,6 +1549,42 @@ __metadata: languageName: node linkType: hard +"@dnd-kit/accessibility@npm:^3.1.0": + version: 3.1.0 + resolution: "@dnd-kit/accessibility@npm:3.1.0" + dependencies: + tslib: ^2.0.0 + peerDependencies: + react: ">=16.8.0" + checksum: fcb88c961e2f4c226ab575bc4a13712419884bb0f60761befcaa23bcb6c9939dc2cac6633416f2a07baee9a8830350c6df444039332408cdaaf27cad17c6b64b + languageName: node + linkType: hard + +"@dnd-kit/core@npm:^6.1.0": + version: 6.1.0 + resolution: "@dnd-kit/core@npm:6.1.0" + dependencies: + "@dnd-kit/accessibility": ^3.1.0 + "@dnd-kit/utilities": ^3.2.2 + tslib: ^2.0.0 + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 3b8f46d2f4d2723abad4721c7bc4d1df2c4f6f26ce54673243666212cfa6f34f33e3255b53144a847da469dc736c966c19e4c45330f967ce8c01f8f878ec7f5b + languageName: node + linkType: hard + +"@dnd-kit/utilities@npm:^3.2.2": + version: 3.2.2 + resolution: "@dnd-kit/utilities@npm:3.2.2" + dependencies: + tslib: ^2.0.0 + peerDependencies: + react: ">=16.8.0" + checksum: 8a5015c2faa52760ab82a64287b2ac6a3d798867a1bca5ccbc1178560dbd9a1f9f1a21faea80f590ba1a4277c3eb7e7c4d3b4a39f1f32171bf6bc8174b370547 + languageName: node + linkType: hard + "@emnapi/runtime@npm:^1.1.1": version: 1.2.0 resolution: "@emnapi/runtime@npm:1.2.0" @@ -5386,6 +5422,7 @@ __metadata: resolution: "bbo-gak@workspace:." dependencies: "@chromatic-com/storybook": ^1.6.1 + "@dnd-kit/core": ^6.1.0 "@radix-ui/react-dialog": ^1.1.1 "@radix-ui/react-dropdown-menu": ^2.1.1 "@radix-ui/react-popover": ^1.1.1