From 4dbb55f6e11c547a8ac487ef2db608eb5db2490a Mon Sep 17 00:00:00 2001 From: dohyeons Date: Tue, 14 Oct 2025 10:29:56 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8B=AC=EB=A0=A5=20=EC=9C=84=EC=A0=AF=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20md=ED=8C=8C=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/dashboard/CALENDAR_WIDGET_PLAN.md | 228 ++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 frontend/components/admin/dashboard/CALENDAR_WIDGET_PLAN.md diff --git a/frontend/components/admin/dashboard/CALENDAR_WIDGET_PLAN.md b/frontend/components/admin/dashboard/CALENDAR_WIDGET_PLAN.md new file mode 100644 index 00000000..84f2a4dc --- /dev/null +++ b/frontend/components/admin/dashboard/CALENDAR_WIDGET_PLAN.md @@ -0,0 +1,228 @@ +# ๐Ÿ“… ๋‹ฌ๋ ฅ ์œ„์ ฏ ๊ตฌํ˜„ ๊ณ„ํš + +## ๊ฐœ์š” + +๋Œ€์‹œ๋ณด๋“œ์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ฌ๋ ฅ ์œ„์ ฏ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๋‚ ์งœ๋ฅผ ํ™•์ธํ•˜๊ณ  ์ผ์ •์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ๋‹ฌ๋ ฅ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. + +## ์ฃผ์š” ๊ธฐ๋Šฅ + +### 1. ๋‹ฌ๋ ฅ ๋ทฐ ํƒ€์ž… + +- **์›”๊ฐ„ ๋ทฐ**: ํ•œ ๋‹ฌ ์ „์ฒด๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ธฐ๋ณธ ๋ทฐ +- **์ฃผ๊ฐ„ ๋ทฐ**: ์ผ์ฃผ์ผ์„ ์„ธ๋กœ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๋ทฐ +- **์ผ๊ฐ„ ๋ทฐ**: ํ•˜๋ฃจ์˜ ์‹œ๊ฐ„๋Œ€๋ณ„ ์ผ์ • ๋ทฐ + +### 2. ๋‹ฌ๋ ฅ ์„ค์ • + +- **์‹œ์ž‘ ์š”์ผ**: ์›”์š”์ผ ์‹œ์ž‘ / ์ผ์š”์ผ ์‹œ์ž‘ ์„ ํƒ +- **์ฃผ๋ง ๊ฐ•์กฐ**: ์ฃผ๋ง ์ƒ‰์ƒ ๋‹ค๋ฅด๊ฒŒ ํ‘œ์‹œ +- **์˜ค๋Š˜ ๋‚ ์งœ ๊ฐ•์กฐ**: ์˜ค๋Š˜ ๋‚ ์งœ ํ•˜์ด๋ผ์ดํŠธ +- **๊ณตํœด์ผ ํ‘œ์‹œ**: ํ•œ๊ตญ ๊ณตํœด์ผ ํ‘œ์‹œ (์„ ํƒ ์‚ฌํ•ญ) + +### 3. ํ…Œ๋งˆ ๋ฐ ์Šคํƒ€์ผ + +- **Light ํ…Œ๋งˆ**: ๋ฐ์€ ๋ฐฐ๊ฒฝ +- **Dark ํ…Œ๋งˆ**: ์–ด๋‘์šด ๋ฐฐ๊ฒฝ +- **์‚ฌ์šฉ์ž ์ง€์ •**: ์ปค์Šคํ…€ ์ƒ‰์ƒ ์„ ํƒ + +### 4. ์ผ์ • ๊ธฐ๋Šฅ (ํ–ฅํ›„ ํ™•์žฅ) + +- ๊ฐ„๋‹จํ•œ ๋ฉ”๋ชจ ์ถ”๊ฐ€ +- ์ผ์ • ํ‘œ์‹œ (์™ธ๋ถ€ ์—ฐ๋™) + +## ๊ตฌํ˜„ ๋‹จ๊ณ„ + +### โœ… Step 1: ํƒ€์ž… ์ •์˜ + +- [ ] `CalendarConfig` ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜ +- [ ] `types.ts`์— ๋‹ฌ๋ ฅ ์„ค์ • ํƒ€์ž… ์ถ”๊ฐ€ +- [ ] ์š”์†Œ ํƒ€์ž…์— 'calendar' subtype ์ถ”๊ฐ€ + +### โœ… Step 2: ๊ธฐ๋ณธ ๋‹ฌ๋ ฅ ์ปดํฌ๋„ŒํŠธ + +- [ ] `CalendarWidget.tsx` - ๋ฉ”์ธ ์œ„์ ฏ ์ปดํฌ๋„ŒํŠธ +- [ ] `MonthView.tsx` - ์›”๊ฐ„ ๋‹ฌ๋ ฅ ๋ทฐ +- [ ] `WeekView.tsx` - ์ฃผ๊ฐ„ ๋‹ฌ๋ ฅ ๋ทฐ (์„ ํƒ) +- [ ] ๋‚ ์งœ ๊ณ„์‚ฐ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜ + +### โœ… Step 3: ๋‹ฌ๋ ฅ ๋„ค๋น„๊ฒŒ์ด์…˜ + +- [ ] ์ด์ „/๋‹ค์Œ ์›” ์ด๋™ ๋ฒ„ํŠผ +- [ ] ์˜ค๋Š˜๋กœ ๋Œ์•„๊ฐ€๊ธฐ ๋ฒ„ํŠผ +- [ ] ์›”/์—ฐ๋„ ์„ ํƒ ๋“œ๋กญ๋‹ค์šด + +### โœ… Step 4: ์„ค์ • UI + +- [ ] `CalendarSettings.tsx` - Popover ๋‚ด์žฅ ์„ค์ • ์ปดํฌ๋„ŒํŠธ +- [ ] ๋ทฐ ํƒ€์ž… ์„ ํƒ (์›”๊ฐ„/์ฃผ๊ฐ„/์ผ๊ฐ„) +- [ ] ์‹œ์ž‘ ์š”์ผ ์„ค์ • +- [ ] ํ…Œ๋งˆ ์„ ํƒ +- [ ] ํ‘œ์‹œ ์˜ต์…˜ (์ฃผ๋ง ๊ฐ•์กฐ, ๊ณตํœด์ผ ๋“ฑ) + +### โœ… Step 5: ์Šคํƒ€์ผ๋ง + +- [ ] ๋‹ฌ๋ ฅ ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ +- [ ] ๋‚ ์งœ ์…€ ๋””์ž์ธ +- [ ] ์˜ค๋Š˜ ๋‚ ์งœ ํ•˜์ด๋ผ์ดํŠธ +- [ ] ์ฃผ๋ง/ํ‰์ผ ๊ตฌ๋ถ„ +- [ ] ๋ฐ˜์‘ํ˜• ๋””์ž์ธ (ํฌ๊ธฐ๋ณ„ ์ตœ์ ํ™”) + +### โœ… Step 6: ํ†ตํ•ฉ + +- [ ] `DashboardSidebar`์— ๋‹ฌ๋ ฅ ์œ„์ ฏ ์ถ”๊ฐ€ +- [ ] `CanvasElement`์—์„œ ๋‹ฌ๋ ฅ ์œ„์ ฏ ๋ Œ๋”๋ง +- [ ] `DashboardDesigner`์— ๊ธฐ๋ณธ๊ฐ’ ์„ค์ • + +### โœ… Step 7: ๊ณตํœด์ผ ๋ฐ์ดํ„ฐ + +- [ ] ํ•œ๊ตญ ๊ณตํœด์ผ ๋ฐ์ดํ„ฐ ์ •์˜ +- [ ] ๊ณตํœด์ผ ํ‘œ์‹œ ๊ธฐ๋Šฅ +- [ ] ๊ณตํœด์ผ ์ด๋ฆ„ ํˆดํŒ + +### โœ… Step 8: ํ…Œ์ŠคํŠธ ๋ฐ ์ตœ์ ํ™” + +- [ ] ๋‹ค์–‘ํ•œ ํฌ๊ธฐ์—์„œ ํ…Œ์ŠคํŠธ +- [ ] ๋‚ ์งœ ๊ณ„์‚ฐ ๋กœ์ง ๊ฒ€์ฆ +- [ ] ์„ฑ๋Šฅ ์ตœ์ ํ™” +- [ ] ์ ‘๊ทผ์„ฑ ๊ฐœ์„  + +## ๊ธฐ์ˆ  ์Šคํƒ + +### UI ์ปดํฌ๋„ŒํŠธ + +- **shadcn/ui**: Button, Select, Switch, Popover, Card +- **lucide-react**: Settings, ChevronLeft, ChevronRight, Calendar + +### ๋‚ ์งœ ์ฒ˜๋ฆฌ + +- **JavaScript Date API**: ๊ธฐ๋ณธ ๋‚ ์งœ ๊ณ„์‚ฐ +- **Intl.DateTimeFormat**: ๋‚ ์งœ ํ˜•์‹ํ™” +- ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด ์ˆœ์ˆ˜ ๊ตฌํ˜„ + +### ์Šคํƒ€์ผ๋ง + +- **Tailwind CSS**: ๋ฐ˜์‘ํ˜• ๊ทธ๋ฆฌ๋“œ ๋ ˆ์ด์•„์›ƒ +- **CSS Grid**: ๋‹ฌ๋ ฅ ๋ ˆ์ด์•„์›ƒ + +## ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ + +``` +widgets/ +โ”œโ”€โ”€ CalendarWidget.tsx # ๋ฉ”์ธ ์œ„์ ฏ (์„ค์ • ๋ฒ„ํŠผ ํฌํ•จ) +โ”œโ”€โ”€ CalendarSettings.tsx # ์„ค์ • UI (Popover ๋‚ด๋ถ€) +โ”œโ”€โ”€ MonthView.tsx # ์›”๊ฐ„ ๋ทฐ +โ”œโ”€โ”€ WeekView.tsx # ์ฃผ๊ฐ„ ๋ทฐ (์„ ํƒ) +โ”œโ”€โ”€ DayView.tsx # ์ผ๊ฐ„ ๋ทฐ (์„ ํƒ) +โ””โ”€โ”€ calendarUtils.ts # ๋‚ ์งœ ๊ณ„์‚ฐ ์œ ํ‹ธ๋ฆฌํ‹ฐ +``` + +## ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ + +```typescript +interface CalendarConfig { + view: "month" | "week" | "day"; // ๋ทฐ ํƒ€์ž… + startWeekOn: "monday" | "sunday"; // ์ฃผ ์‹œ์ž‘ ์š”์ผ + highlightWeekends: boolean; // ์ฃผ๋ง ๊ฐ•์กฐ + highlightToday: boolean; // ์˜ค๋Š˜ ๊ฐ•์กฐ + showHolidays: boolean; // ๊ณตํœด์ผ ํ‘œ์‹œ + theme: "light" | "dark" | "custom"; // ํ…Œ๋งˆ + customColor?: string; // ์‚ฌ์šฉ์ž ์ง€์ • ์ƒ‰์ƒ + showWeekNumbers?: boolean; // ์ฃผ์ฐจ ํ‘œ์‹œ (์„ ํƒ) +} +``` + +## UI/UX ๊ณ ๋ ค์‚ฌํ•ญ + +### ๋ฐ˜์‘ํ˜• ๋””์ž์ธ + +- **2x2**: ๋ฏธ๋‹ˆ ๋‹ฌ๋ ฅ (์›”๊ฐ„ ๋ทฐ๋งŒ, ๋‚ ์งœ๋งŒ ํ‘œ์‹œ) +- **3x3**: ๊ธฐ๋ณธ ๋‹ฌ๋ ฅ (์›”๊ฐ„ ๋ทฐ, ์š”์ผ ํ—ค๋” ํฌํ•จ) +- **4x4 ์ด์ƒ**: ํ’€ ๋‹ฌ๋ ฅ (๋ชจ๋“  ๊ธฐ๋Šฅ, ์ผ์ • ํ‘œ์‹œ ๊ฐ€๋Šฅ) + +### ์ธํ„ฐ๋ž™์…˜ + +- ๋‚ ์งœ ํด๋ฆญ ์‹œ ํ•ด๋‹น ๋‚ ์งœ ์ •๋ณด ํ‘œ์‹œ (์„ ํƒ) +- ๋“œ๋ž˜๊ทธ๋กœ ์›” ๋ณ€๊ฒฝ (์„ ํƒ) +- ํ‚ค๋ณด๋“œ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ง€์› + +### ์ ‘๊ทผ์„ฑ + +- ๋‚ ์งœ ์…€์— ์ ์ ˆํ•œ aria-label +- ํ‚ค๋ณด๋“œ ๋„ค๋น„๊ฒŒ์ด์…˜ ์ง€์› +- ์Šคํฌ๋ฆฐ ๋ฆฌ๋” ํ˜ธํ™˜ + +## ๊ณตํœด์ผ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ + +```typescript +interface Holiday { + date: string; // 'MM-DD' ํ˜•์‹ + name: string; // ๊ณตํœด์ผ ์ด๋ฆ„ + isRecurring: boolean; // ๋งค๋…„ ๋ฐ˜๋ณต ์—ฌ๋ถ€ +} + +// 2025๋…„ ํ•œ๊ตญ ๊ณตํœด์ผ ์˜ˆ์‹œ +const KOREAN_HOLIDAYS: Holiday[] = [ + { date: "01-01", name: "์‹ ์ •", isRecurring: true }, + { date: "01-28", name: "์„ค๋‚  ์—ฐํœด", isRecurring: false }, + { date: "01-29", name: "์„ค๋‚ ", isRecurring: false }, + { date: "01-30", name: "์„ค๋‚  ์—ฐํœด", isRecurring: false }, + { date: "03-01", name: "์‚ผ์ผ์ ˆ", isRecurring: true }, + { date: "05-05", name: "์–ด๋ฆฐ์ด๋‚ ", isRecurring: true }, + { date: "06-06", name: "ํ˜„์ถฉ์ผ", isRecurring: true }, + { date: "08-15", name: "๊ด‘๋ณต์ ˆ", isRecurring: true }, + { date: "10-03", name: "๊ฐœ์ฒœ์ ˆ", isRecurring: true }, + { date: "10-09", name: "ํ•œ๊ธ€๋‚ ", isRecurring: true }, + { date: "12-25", name: "ํฌ๋ฆฌ์Šค๋งˆ์Šค", isRecurring: true }, +]; +``` + +## ํ–ฅํ›„ ํ™•์žฅ ๊ธฐ๋Šฅ + +### Phase 2 (์„ ํƒ) + +- [ ] ์ผ์ • ์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œ +- [ ] ๋ฐ˜๋ณต ์ผ์ • ์„ค์ • +- [ ] ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ƒ‰์ƒ ๊ตฌ๋ถ„ +- [ ] ๋‹ค๋ฅธ ๋‹ฌ๋ ฅ ์„œ๋น„์Šค ์—ฐ๋™ (Google Calendar, Outlook ๋“ฑ) +- [ ] ์ผ์ • ์•Œ๋ฆผ ๊ธฐ๋Šฅ +- [ ] ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ์œผ๋กœ ์ผ์ • ์ด๋™ + +### Phase 3 (์„ ํƒ) + +- [ ] ์—ฌ๋Ÿฌ ๋‹ฌ๋ ฅ ๋ ˆ์ด์–ด ์ง€์› +- [ ] ์ผ์ • ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ +- [ ] ์›”๋ณ„ ํ†ต๊ณ„ (์ผ์ • ๊ฐœ์ˆ˜ ๋“ฑ) +- [ ] CSV/iCal ๋‚ด๋ณด๋‚ด๊ธฐ + +## ์ฐธ๊ณ ์‚ฌํ•ญ + +### ์žฅ์  + +- ์ˆœ์ˆ˜ JavaScript๋กœ ๊ตฌํ˜„ (์™ธ๋ถ€ ์˜์กด์„ฑ ์ตœ์†Œํ™”) +- shadcn/ui ์ปดํฌ๋„ŒํŠธ ํ™œ์šฉ์œผ๋กœ ์ผ๊ด€๋œ ๋””์ž์ธ +- ์‹œ๊ณ„ ์œ„์ ฏ๊ณผ ๋™์ผํ•œ ํŒจํ„ด (๋‚ด์žฅ ์„ค์ • UI) + +### ์ฃผ์˜์‚ฌํ•ญ + +- ๋‚ ์งœ ๊ณ„์‚ฐ ๋กœ์ง ์ •ํ™•์„ฑ ๊ฒ€์ฆ ํ•„์š” +- ์œค๋…„ ์ฒ˜๋ฆฌ +- ํƒ€์ž„์กด ๊ณ ๋ ค (ํ•„์š”์‹œ) +- ๋‹ค์–‘ํ•œ ํฌ๊ธฐ์—์„œ์˜ ๊ฐ€๋…์„ฑ + +## ์™„๋ฃŒ ๊ธฐ์ค€ + +- [x] ์›”๊ฐ„ ๋ทฐ ๋‹ฌ๋ ฅ์ด ์ •ํ™•ํ•˜๊ฒŒ ํ‘œ์‹œ๋จ +- [x] ์ด์ „/๋‹ค์Œ ์›” ๋„ค๋น„๊ฒŒ์ด์…˜์ด ์ž‘๋™ํ•จ +- [x] ์˜ค๋Š˜ ๋‚ ์งœ๊ฐ€ ํ•˜์ด๋ผ์ดํŠธ๋จ +- [x] ์ฃผ๋ง์ด ๋‹ค๋ฅธ ์ƒ‰์ƒ์œผ๋กœ ํ‘œ์‹œ๋จ +- [x] ๊ณตํœด์ผ์ด ํ‘œ์‹œ๋˜๊ณ  ์ด๋ฆ„์ด ๋ณด์ž„ +- [x] ์„ค์ • UI์—์„œ ๋ชจ๋“  ์˜ต์…˜์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ +- [x] ํ…Œ๋งˆ ๋ณ€๊ฒฝ์ด ์ฆ‰์‹œ ๋ฐ˜์˜๋จ +- [x] 2x2 ํฌ๊ธฐ์—์„œ๋„ ๊น”๋”ํ•˜๊ฒŒ ํ‘œ์‹œ๋จ +- [x] 4x4 ํฌ๊ธฐ์—์„œ ๋ชจ๋“  ๊ธฐ๋Šฅ์ด ์ •์ƒ ์ž‘๋™ํ•จ + +--- + +## ๊ตฌํ˜„ ์‹œ์ž‘ + +์ด์ œ ๋‹จ๊ณ„๋ณ„๋กœ ๊ตฌํ˜„์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค!