From fe65c107c893912f4a8143fb73371c1f36eab208 Mon Sep 17 00:00:00 2001 From: caadiq Date: Sat, 18 Apr 2026 12:36:58 +0900 Subject: [PATCH] =?UTF-8?q?=ED=95=B4=EB=B0=A9=20=EB=82=A0=EC=A7=9C=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=EA=B8=B0=20+=20DatePicker=20=ED=85=8C?= =?UTF-8?q?=EB=A7=88=20=ED=86=A0=ED=81=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Liberation 루트/ProgressBar/QuestSelector/WeeklyDefault/WeeklyScheduler 전체 이관 - DatePicker 드롭다운(연도/월/일 선택) 모두 semantic 토큰으로 대응 - 세그먼트 바, 배지, 탭, 초기화 버튼, 보스 Row 모두 테마 대응 Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/components/DatePicker.jsx | 138 +++++++++++------- .../src/features/liberation/Liberation.jsx | 135 +++++++++++------ .../liberation/components/ProgressBar.jsx | 48 ++++-- .../liberation/components/QuestSelector.jsx | 45 ++++-- .../liberation/components/WeeklyDefault.jsx | 93 ++++++++---- .../liberation/components/WeeklyScheduler.jsx | 88 ++++++++--- 6 files changed, 367 insertions(+), 180 deletions(-) diff --git a/frontend/src/components/DatePicker.jsx b/frontend/src/components/DatePicker.jsx index 0223b2a..2473fff 100644 --- a/frontend/src/components/DatePicker.jsx +++ b/frontend/src/components/DatePicker.jsx @@ -97,14 +97,19 @@ export default function DatePicker({ value, onChange, placeholder = '날짜 선 @@ -149,43 +162,51 @@ export default function DatePicker({ value, onChange, placeholder = '날짜 선 {viewMode === 'years' ? ( -
연도
+
연도
- {years.map((y) => ( - - ))} + {years.map((y) => { + const isActive = year === y + const isCurrent = currentYear === y && !isActive + return ( + + ) + })}
-
+
- {monthNames.map((m, i) => ( - - ))} + {monthNames.map((m, i) => { + const isActive = month === i + const isCurrent = (currentYear === year && currentMonth === i) && !isActive + return ( + + ) + })}
) : ( @@ -194,9 +215,11 @@ export default function DatePicker({ value, onChange, placeholder = '날짜 선 {['일', '월', '화', '수', '목', '금', '토'].map((d, i) => (
{d}
@@ -207,20 +230,25 @@ export default function DatePicker({ value, onChange, placeholder = '날짜 선 const dw = i % 7 const selected = isSelected(day) const today = isToday(day) + const textColor = today && !selected ? 'var(--accent-bright)' + : day && !selected && !today && dw === 0 ? 'var(--danger-text)' + : day && !selected && !today && dw === 6 ? '#60a5fa' + : day && !selected && !today ? 'var(--text-emphasis)' + : undefined return ( - ))} + ].map((tab) => { + const active = liberationType === tab.key + return ( + + ) + })} {liberationType === 'destiny' ? ( -
-
구현 예정
-
데스티니 해방 계산기는 준비 중입니다.
+
+
구현 예정
+
데스티니 해방 계산기는 준비 중입니다.
) : (<> {/* 계산 모드 탭 */} -
+
{[ { key: 'simple', label: '단순 계산' }, { key: 'weekly', label: '주차별 계산' }, - ].map((t) => ( - - ))} + ].map((t) => { + const active = calcMode === t.key + return ( + + ) + })}
{/* 현재 진행 상태 입력 */} -
-
현재 진행 상태
+
+
현재 진행 상태
- + setState((prev) => ({ ...prev, startDate: dayjs(d).toISOString() }))} @@ -341,7 +376,7 @@ export default function Liberation() {
- + setState((prev) => ({ ...prev, startChapter: idx }))} @@ -349,15 +384,28 @@ export default function Liberation() {
- -
+ +
setState((prev) => ({ ...prev, currentPoints: n }))} className="flex-1 min-w-0 bg-transparent px-3 h-12 text-base text-right tabular-nums outline-none" + style={{ color: 'var(--text-strong)' }} /> - + / {(GENESIS_CHAPTERS[state.startChapter]?.required ?? 0).toLocaleString()}
@@ -381,7 +429,12 @@ export default function Liberation() { diff --git a/frontend/src/features/liberation/components/WeeklyDefault.jsx b/frontend/src/features/liberation/components/WeeklyDefault.jsx index 71e279d..faca444 100644 --- a/frontend/src/features/liberation/components/WeeklyDefault.jsx +++ b/frontend/src/features/liberation/components/WeeklyDefault.jsx @@ -7,11 +7,11 @@ const PARTY_OPTIONS = [1, 2, 3, 4, 5, 6].map((n) => ({ value: n, label: `${n}인 const NONE_DIFFICULTY = { key: 'none', label: '격파 불가', points: 0 } function diffLabel(d, party) { - if (d.key === 'none') return 격파 불가 + if (d.key === 'none') return 격파 불가 const earned = calcPoints(d.points, party) return ( - {d.label} +{earned} + {d.label} +{earned} ) } @@ -22,13 +22,20 @@ export function BossRow({ boss, sel, onChange, monthly = false, showDone = true .map((d) => ({ value: d.key, label: diffLabel(d, sel.party) })) return ( -
+
{boss.name} - {monthly && 월간} + {monthly && ( + + 월간 + + )}
@@ -54,13 +61,18 @@ export function BossRow({ boss, sel, onChange, monthly = false, showDone = true type="button" disabled={disabled} onClick={() => onChange({ done: !sel.done })} - className={`shrink-0 w-20 rounded-md h-8 text-xs font-semibold transition border ${ - disabled - ? 'border-white/5 text-gray-700 cursor-not-allowed' - : sel.done - ? 'bg-emerald-500/20 border-emerald-500/50 text-emerald-300' - : 'border-white/10 text-gray-500 hover:border-white/20 hover:text-gray-300' - }`} + className="shrink-0 w-20 rounded-md h-8 text-xs font-semibold border disabled:cursor-not-allowed" + style={disabled ? { + borderColor: 'var(--panel-border)', + color: 'var(--text-dim)', + } : sel.done ? { + background: 'var(--selected-bg)', + borderColor: 'var(--selected-border)', + color: 'var(--accent-bright)', + } : { + borderColor: 'var(--btn-border)', + color: 'var(--text-dim)', + }} > {sel.done ? '완료' : '미완료'} @@ -78,42 +90,59 @@ export default function WeeklyDefault({ weekly, onChange, totalWeekly, totalMont } return ( -
+
-
주간 보스 설정
+
주간 보스 설정
{mode === 'weekly' ? ( <> - {totalWeekly} - + - {totalMonthly} - / - {(remaining ?? 0).toLocaleString()} + {totalWeekly} + + + {totalMonthly} + / + {(remaining ?? 0).toLocaleString()} ) : ( - +{totalWeekly + totalMonthly} + +{totalWeekly + totalMonthly} )}
{mode === 'simple' ? ( -
- {WEEKLY_BOSSES.map((boss) => ( - + {WEEKLY_BOSSES.map((boss, i) => ( +
updateBoss(boss.key, patch)} - /> + className={i > 0 ? 'border-t' : ''} + style={i > 0 ? { borderColor: 'var(--row-divider)' } : undefined} + > + updateBoss(boss.key, patch)} + /> +
))} {MONTHLY_BOSSES.map((boss) => ( - + className="border-t" + style={{ borderColor: 'var(--row-divider)' }} + > + +
))}
) : ( diff --git a/frontend/src/features/liberation/components/WeeklyScheduler.jsx b/frontend/src/features/liberation/components/WeeklyScheduler.jsx index 9556f61..ded6c0d 100644 --- a/frontend/src/features/liberation/components/WeeklyScheduler.jsx +++ b/frontend/src/features/liberation/components/WeeklyScheduler.jsx @@ -63,8 +63,13 @@ function BossAvatar({ boss, difficulty, size = 40 }) { return (
{boss.name}
@@ -72,9 +77,9 @@ function BossAvatar({ boss, difficulty, size = 40 }) { className="text-[10px] font-bold leading-none rounded flex items-center justify-center border" style={{ width: 16, height: 16, - color: badge?.color || '#4b5563', + color: badge?.color || 'var(--text-dim)', background: badge?.bg || 'transparent', - borderColor: badge?.border || 'rgba(255,255,255,0.08)', + borderColor: badge?.border || 'var(--panel-border)', }} > {badge?.label || '-'} @@ -94,17 +99,25 @@ function WeekEditor({ config, onChange, isCurrent, monthlyLockedByWeek }) { const blackmageLocked = monthlyLockedByWeek != null return ( -
- {WEEKLY_BOSSES.map((boss) => ( - + {WEEKLY_BOSSES.map((boss, i) => ( +
updateBoss(boss.key, patch)} - showDone={isCurrent} - /> + className={i > 0 ? 'border-t' : ''} + style={i > 0 ? { borderColor: 'var(--row-divider)' } : undefined} + > + updateBoss(boss.key, patch)} + showDone={isCurrent} + /> +
))} -
+
{blackmageLocked && ( -
+
이번 달 검은 마법사는 {monthlyLockedByWeek}주차에 배정되어 있습니다.
)} @@ -210,7 +226,11 @@ export default function WeeklyScheduler({ startDate, weeks: weeksProp, onChangeW return (