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/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() {
-
+
{infoList.map((info) => (
-
+ -
+
+
))}
-
+
);
}
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) => (
-
-
-
내 공고 뽀각
-
-
-
- 내 정보 가져오기
-
-
-
-
-
- 새 공고
+
+
-
-
-
-
+
+
+
+
+
);
}
diff --git a/src/app/(sidebar)/write/[id]/components/TagSelector/TagSelector.tsx b/src/app/(sidebar)/write/[id]/components/TagSelector/TagSelector.tsx
index 3cf90407..00f2a785 100644
--- a/src/app/(sidebar)/write/[id]/components/TagSelector/TagSelector.tsx
+++ b/src/app/(sidebar)/write/[id]/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/components/MemoContainer/Memo/Memo.tsx b/src/app/(sidebar)/write/components/MemoContainer/Memo/Memo.tsx
new file mode 100644
index 00000000..67b86f0d
--- /dev/null
+++ b/src/app/(sidebar)/write/components/MemoContainer/Memo/Memo.tsx
@@ -0,0 +1,64 @@
+'use client';
+
+import { useState, useRef, useEffect, useCallback } from 'react';
+import { Textarea } from '@/system/components/Textarea/Textarea';
+import { RemoveMemo } from '@/system/components/Icon/SVG/RemoveMemo';
+import { AnimatePresence } from 'framer-motion';
+import { motion } from 'framer-motion';
+
+export default function Memo() {
+ const [text, setText] = useState('새로운 메모입니다');
+ const [showCloseButton, setShowCloseButton] = useState(false);
+ const textareaRef = useRef(null);
+
+ const adjustTextareaHeight = useCallback(() => {
+ const textarea = textareaRef.current;
+
+ if (textarea) {
+ textarea.style.height = 'auto';
+ textarea.style.height = `${textarea.scrollHeight}px`;
+ }
+ }, []);
+
+ useEffect(() => {
+ adjustTextareaHeight();
+ }, [text]);
+
+ return (
+ setShowCloseButton(true)}
+ onMouseLeave={() => setShowCloseButton(false)}>
+
+
+
+
+
+
+ {showCloseButton && (
+ // TODO: remove API
+
+
+
+ )}
+
+
+ {/* TODO: 날짜 및 시간 */}
+
00.00.00
+
+ );
+}
diff --git a/src/app/(sidebar)/write/components/MemoContainer/MemoContainer.tsx b/src/app/(sidebar)/write/components/MemoContainer/MemoContainer.tsx
new file mode 100644
index 00000000..8ee3fea4
--- /dev/null
+++ b/src/app/(sidebar)/write/components/MemoContainer/MemoContainer.tsx
@@ -0,0 +1,49 @@
+import { Icon } from '@/system/components';
+import { Textarea } from '@/system/components/Textarea/Textarea';
+import { useState } from 'react';
+import Memo from './Memo/Memo';
+import { cn } from '@/utils';
+
+const TEXT_DEFAULT_HEIGHT = 22;
+const TEXT_FOCUS_HEIGHT = 80;
+
+export default function MemoContainer() {
+ const [memo, setMemo] = useState('');
+ const [textareaHeight, setTextareaHeight] = useState(TEXT_DEFAULT_HEIGHT);
+
+ return (
+
+ );
+}
diff --git a/src/app/(sidebar)/write/page.tsx b/src/app/(sidebar)/write/page.tsx
new file mode 100644
index 00000000..079f13a7
--- /dev/null
+++ b/src/app/(sidebar)/write/page.tsx
@@ -0,0 +1,177 @@
+'use client';
+
+import dynamic from 'next/dynamic';
+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 '@/system/utils/If';
+import { cn } from '@/utils';
+import { Spacing } from '@/system/utils/Spacing';
+import { Icon } from '@/system/components';
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from '@/system/components/DropdownMenu/DropdownMenu';
+import MemoContainer from './components/MemoContainer/MemoContainer';
+import { TagSelector } from './[id]/components/TagSelector/TagSelector';
+import { abilityTags, personalityTags, categoryTags, tags, categories } from './[id]/components/TagSelector/constants';
+
+const Editor = dynamic(() => import('@/components/Editor/Editor').then(({ Editor }) => Editor), { ssr: false });
+
+export default function Page() {
+ const [category, setSelectedCategories] = useState<(typeof categories)[number] | null>(null);
+ const [selectedTags, setSelectedTags] = useState([]);
+
+ return (
+
+
+
+
+
+
00.00.00
+
+
+
+
+
+
+
+
+ 삭제하기
+
+
+
+
+
+
+
+
+
+ 분류
+
+
+ 카드의 종류를 선택해주세요
+
+
+ {
+ event.stopPropagation();
+ setSelectedCategories(null);
+ }}>
+ - {category?.value}
+
+
+
+
+
+
+
+
+ 어떤 단계를 위한 정보인가요? (택1)
+
+
+ {categoryTags.map((tag) => (
+ {
+ setSelectedCategories(tag);
+ }}>
+ {tag.value}
+
+ ))}
+
+
+
+
+
+
+ 태그
+
+
+ 태그를 선택해주세요
+
+
+ {selectedTags.map((tag) => (
+ {
+ event.stopPropagation();
+ setSelectedTags((prev) => prev.filter(({ value }) => value !== tag.value));
+ }}>
+ - {tag.value}
+
+ ))}
+
+
+
+
+
+
+ 최대 3개까지 설정 가능해요!
+
+
+ {abilityTags.map((tag) => (
+ {
+ if (selectedTags.length < 3 && !selectedTags.find(({ value }) => value === tag.value)) {
+ setSelectedTags((prev) => [...prev, tag]);
+ }
+ }}>
+ {tag.value}
+
+ ))}
+
+
+
+
+
+ {personalityTags.map((tag) => (
+ {
+ if (selectedTags.length < 3 && !selectedTags.find(({ value }) => value === tag.value)) {
+ setSelectedTags((prev) => [...prev, tag]);
+ }
+ }}>
+ {tag.value}
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
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 1f0247bf..588b85ee 100644
--- a/src/system/components/Icon/Icon.tsx
+++ b/src/system/components/Icon/Icon.tsx
@@ -29,11 +29,13 @@ import { RemoveMemo } from '@/system/components/Icon/SVG/RemoveMemo';
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