From 84b7fd48197fddac73f3a01d80fb5791029447e1 Mon Sep 17 00:00:00 2001 From: Knockcha Date: Thu, 30 Apr 2026 17:48:07 +0900 Subject: [PATCH 001/324] =?UTF-8?q?feat(theme):=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8=20=EB=AA=A8=EB=93=9C=20=ED=86=A0=ED=81=B0=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98=20=E2=80=94=20System=20A=206=20+=20System=20B=2012?= =?UTF-8?q?=EC=83=89=20=ED=8C=94=EB=A0=88=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - index.css :root 다크 → 라이트 (warm-white #FAF9F5 + 카드 #FFFFFF + sidebar #F5F4EE + cream #F8F7E8 accent) - 12색 컬러 팔레트 정의 (Deep Blue, Vivid Red, Teal Green, Vibrant Purple 등) - 시맨틱 토큰 12색 alias (--primary/--success/--warning/--danger/--chart-1..4/--decor-*) - tailwind.config.js colors 확장: success/warning/danger/chart/decor 매핑 추가 - 다크모드 분기 없음 (Phase 0-C 확인 — 폐기 작업 0건) Phase 1 of light-mode-migration. Phase 2 (hex → 토큰 치환) 6개 영역 병렬 진행 예정. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/index.css | 92 ++++++++++++++++++++++++++++--------- frontend/tailwind.config.js | 56 +++++++++++++++------- 2 files changed, 111 insertions(+), 37 deletions(-) diff --git a/frontend/src/index.css b/frontend/src/index.css index e5b89552..cf9429f0 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -3,8 +3,14 @@ @tailwind utilities; /* ═══════════════════════════════════════════════════════ - SPOTTER Design System — Indigo & Stone Theme (Tailwind v3) - v4.2 (2026-04-23) — #0C0B0A high-end dark 전역 전환 + SPOTTER Design System — Light Mode (Tailwind v3) + v5.0 (2026-04-30) — Cream + 12-color palette 전역 전환 + ─────────────────────────────────────────────────────── + 두 시스템 분리: + • System A — 배경/구조 6색 (warm-white / cream / black 라이트 인프라) + 어떤 의미도 없는 중립. 라이트모드 정체성을 만드는 뼈대. + • System B — 12색 컬러 팔레트 (모든 유의미한 색 — 데이터/상태/액센트/장식) + 외부에서 한 색도 안 가져옴. 새 컴포넌트는 무조건 12색 안에서만 매핑. ═══════════════════════════════════════════════════════ */ /* ═══════════════════════════════════════════════════════ @@ -19,26 +25,70 @@ html { @layer base { :root { - --background: #0c0b0a; - --foreground: #e2e8f0; - --card: #1a1a1a; - --card-foreground: #e2e8f0; - --popover: #1a1a1a; - --popover-foreground: #e2e8f0; - --primary: #818cf8; - --primary-foreground: #0c0b0a; - --secondary: #292524; - --secondary-foreground: #d6d3d1; - --muted: #1a1a1a; - --muted-foreground: #a8a29e; - --accent: #44403c; - --accent-foreground: #d6d3d1; - --destructive: #ef4444; - --destructive-foreground: #ffffff; - --border: #292524; - --input: #292524; - --ring: #818cf8; + /* ─── System A: 배경/구조 (의미 없는 중립 인프라) ─── */ + --background: #faf9f5; /* warm-white page */ + --foreground: #0a0a0a; /* near-black body text */ + --card: #ffffff; /* 데이터 표면 */ + --card-foreground: #0a0a0a; + --popover: #ffffff; + --popover-foreground: #0a0a0a; + --secondary: #f5f4ee; /* sidebar / nav rail */ + --secondary-foreground: #0a0a0a; + --muted: #f5f4ee; + --muted-foreground: #6b6a63; + --border: #eae9e1; + --input: #ffffff; --radius: 1.25rem; + + /* ─── System B: 12색 팔레트 ─── */ + /* Base */ + --color-cream: #f8f7e8; /* Background Cream — 큰 면적 장식 자리 */ + --color-text-black: #000000; /* Text Black */ + /* Point */ + --color-starburst-pink: #ff78b9; /* Starburst Pink */ + --color-deep-blue: #002cd1; /* Deep Blue (brand primary) */ + /* Geometric */ + --color-vivid-red: #ff3800; + --color-bright-cyan: #00e0d1; + --color-sunshine-yellow: #ffde00; + --color-teal-green: #00ba7a; + --color-hot-pink: #ff0070; + /* Shapes */ + --color-soft-orange: #ff7940; + --color-light-pink: #ffb6d0; + --color-vibrant-purple: #b35cff; + + /* ─── Brand & semantic — 12색 alias ─── */ + --primary: var(--color-deep-blue); + --primary-foreground: #ffffff; + --accent: var(--color-cream); /* large-area accent slot */ + --accent-foreground: #0a0a0a; + --destructive: var(--color-vivid-red); + --destructive-foreground: #ffffff; + --ring: var(--color-deep-blue); + + /* Status */ + --success: var(--color-teal-green); + --success-foreground: #ffffff; + --warning: var(--color-soft-orange); + --warning-foreground: #ffffff; + --danger: var(--color-vivid-red); + --danger-foreground: #ffffff; + + /* Chart 4색 (4동 비교 — chart-1 = 본인 동, primary와 동일) */ + --chart-1: var(--color-deep-blue); + --chart-2: var(--color-vivid-red); + --chart-3: var(--color-teal-green); + --chart-4: var(--color-vibrant-purple); + + /* Decoration (큰 면적 장식 only — 작은 마커/얇은 선/텍스트 사용 금지) + 이 4색은 라이트 배경에서 컨트라스트 1.2~1.5:1 → 데이터 자리 부적격 */ + --decor-cyan: var(--color-bright-cyan); + --decor-yellow: var(--color-sunshine-yellow); + --decor-light-pink: var(--color-light-pink); + --decor-hot-pink: var(--color-hot-pink); + --decor-starburst-pink: var(--color-starburst-pink); + --decor-cream: var(--color-cream); } } diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 3b7a50ce..ff0d2d74 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,29 +1,53 @@ /** @type {import('tailwindcss').Config} */ export default { - content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], + content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], theme: { extend: { fontFamily: { sans: ['Pretendard', 'ui-sans-serif', 'system-ui', 'sans-serif'], }, colors: { - background: "var(--background)", - foreground: "var(--foreground)", - card: { DEFAULT: "var(--card)", foreground: "var(--card-foreground)" }, - popover: { DEFAULT: "var(--popover)", foreground: "var(--popover-foreground)" }, - primary: { DEFAULT: "var(--primary)", foreground: "var(--primary-foreground)" }, - secondary: { DEFAULT: "var(--secondary)", foreground: "var(--secondary-foreground)" }, - muted: { DEFAULT: "var(--muted)", foreground: "var(--muted-foreground)" }, - accent: { DEFAULT: "var(--accent)", foreground: "var(--accent-foreground)" }, - destructive: { DEFAULT: "var(--destructive)", foreground: "var(--destructive-foreground)" }, - border: "var(--border)", - input: "var(--input)", - ring: "var(--ring)", + // System A — 배경/구조 + background: 'var(--background)', + foreground: 'var(--foreground)', + card: { DEFAULT: 'var(--card)', foreground: 'var(--card-foreground)' }, + popover: { DEFAULT: 'var(--popover)', foreground: 'var(--popover-foreground)' }, + primary: { DEFAULT: 'var(--primary)', foreground: 'var(--primary-foreground)' }, + secondary: { DEFAULT: 'var(--secondary)', foreground: 'var(--secondary-foreground)' }, + muted: { DEFAULT: 'var(--muted)', foreground: 'var(--muted-foreground)' }, + accent: { DEFAULT: 'var(--accent)', foreground: 'var(--accent-foreground)' }, + destructive: { DEFAULT: 'var(--destructive)', foreground: 'var(--destructive-foreground)' }, + border: 'var(--border)', + input: 'var(--input)', + ring: 'var(--ring)', + + // System B — Status (12색 alias) + success: { DEFAULT: 'var(--success)', foreground: 'var(--success-foreground)' }, + warning: { DEFAULT: 'var(--warning)', foreground: 'var(--warning-foreground)' }, + danger: { DEFAULT: 'var(--danger)', foreground: 'var(--danger-foreground)' }, + + // System B — Chart 4색 (4동 비교) + chart: { + 1: 'var(--chart-1)', + 2: 'var(--chart-2)', + 3: 'var(--chart-3)', + 4: 'var(--chart-4)', + }, + + // System B — Decoration (큰 면적 장식 only) + decor: { + cream: 'var(--decor-cream)', + cyan: 'var(--decor-cyan)', + yellow: 'var(--decor-yellow)', + 'light-pink': 'var(--decor-light-pink)', + 'hot-pink': 'var(--decor-hot-pink)', + 'starburst-pink': 'var(--decor-starburst-pink)', + }, }, borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)', }, }, }, From 1844da317cca6055292ce7cbe8c895d4bd4d7733 Mon Sep 17 00:00:00 2001 From: Knockcha Date: Thu, 30 Apr 2026 18:18:22 +0900 Subject: [PATCH 002/324] =?UTF-8?q?feat(theme):=20hex=20=E2=86=92=2012?= =?UTF-8?q?=EC=83=89=20=ED=86=A0=ED=81=B0=20=EC=B9=98=ED=99=98=20=E2=80=94?= =?UTF-8?q?=20Phase=202=206=20=EC=98=81=EC=97=AD=20+=20Phase=203=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=9D=BC=EA=B4=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit System B (12색) + System A (배경/구조 6색) 단일 진실로 모든 컴포넌트 정합. 치환 통계 (~970 hex 인스턴스, 50+ 파일): - Phase 2-1a: App.tsx 1~2400 (202건) - Phase 2-1b: App.tsx 2401~끝 (90건) - Phase 2-2: SimulationResult/** + simulation/** (90건, 7파일) - Phase 2-3: dashboard/** + 11종 차트 axis/grid/tooltip (110+, 12파일) - Phase 2-4: Nav/공용/랜딩 + Canvas2D + ABM POI (470건, 27파일) - Phase 2-5: 잔여 라이브러리 props (LoginPage SVG) - Phase 3 정리: App.tsx 다크 주석 제거 + radar 라벨 #e5e5e5 → muted-foreground 핵심 매핑: - indigo (#818cf8/#6366f1/#4f46e5) → primary (Deep Blue #002CD1) - 4동 비교 차트 COLORS = [chart-1..4] (Deep Blue/Vivid Red/Teal Green/Vibrant Purple) - 노란 띠 4건 (yellow-500/amber-400) → primary (Deep Blue) - SHAP 양/음 → success/danger - 거리 잠식 5색 gradient → danger/warning/decor-yellow/decor-cyan/success - ABM POI 4색 → danger/warning/primary/muted-foreground - Canvas2D ctx.fillStyle 67건은 var() 미지원이라 토큰의 라이트값 hex 직접 박음 검증: - 잔여 Tailwind hex: 0 - 잔여 dark: prefix: 0 - 잔여 isDark/SkyThemeToggle: 0 - tsc --noEmit: PASS - ESLint: 27,665 → 99 problems (-99.6%, prettier auto-fix 효과) 산출 보고서: docs/light-mode-migration/{conversion-rules,phase-0-summary,phase-2-*}.md Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/light-mode-migration/conversion-rules.md | 180 ++++++ docs/light-mode-migration/dark-mode-deps-C.md | 264 ++++++++ docs/light-mode-migration/hex-catalog-A.md | 264 ++++++++ docs/light-mode-migration/library-hex-D.md | 267 +++++++++ docs/light-mode-migration/phase-0-summary.md | 122 ++++ .../light-mode-migration/phase-2-1a-report.md | 57 ++ .../light-mode-migration/phase-2-1b-report.md | 73 +++ docs/light-mode-migration/phase-2-2-report.md | 92 +++ docs/light-mode-migration/phase-2-3-report.md | 78 +++ docs/light-mode-migration/phase-2-4-report.md | 88 +++ docs/light-mode-migration/phase-2-5-report.md | 76 +++ .../yellow-inventory-B.md | 145 +++++ frontend/src/App.tsx | 563 ++++++++++-------- frontend/src/components/AbmPersonaMap.tsx | 220 +++---- .../src/components/AgentMapVisualizer.tsx | 62 +- frontend/src/components/BrandLogo.tsx | 10 +- frontend/src/components/CommandPalette.tsx | 58 +- frontend/src/components/DetailDrawer.tsx | 95 ++- frontend/src/components/GlobalNav.tsx | 46 +- frontend/src/components/PersonaCard.tsx | 18 +- .../SimulationHistory/ActivityDashboard.tsx | 2 +- .../SimulationHistory/HistoryCard.tsx | 2 +- .../SimulationHistory/HistoryFilter.tsx | 34 +- .../SimulationResult/MetricCharts.tsx | 8 +- .../QuarterlyProjectionChart.tsx | 42 +- .../components/SimulationResult/ShapChart.tsx | 45 +- .../SimulationResult/dashboard/HubCard.tsx | 16 +- .../dashboard/charts/AgentConfidenceRadar.tsx | 13 +- .../charts/BepCumulativeProfitChart.tsx | 33 +- .../charts/CannibalizationDistanceChart.tsx | 24 +- .../charts/ClosureRateHistoryChart.tsx | 29 +- .../dashboard/charts/CoreDemographicDonut.tsx | 4 +- .../dashboard/charts/FlowVsRevenueScatter.tsx | 31 +- .../charts/ScenariosComparisonChart.tsx | 33 +- .../dashboard/charts/Sparkline.tsx | 6 +- .../dashboard/charts/StackedAgeBar.tsx | 9 +- .../dashboard/charts/WaterfallChart.tsx | 26 +- .../dashboard/charts/WeekdayWeekendBar.tsx | 6 +- .../dashboard/shared/DecisionCard.tsx | 4 +- .../dashboard/tabs/AbmTab.tsx | 4 +- .../dashboard/tabs/MarketTab.tsx | 4 +- .../sections/IndicatorGrid.tsx | 14 +- .../SimulationResult/sections/MapSection.tsx | 4 +- .../SimulationResult/shared/Sparkline.tsx | 2 +- frontend/src/components/Toast.tsx | 22 +- .../TokenBurnrate/TokenBurnrateSection.tsx | 38 +- frontend/src/components/VacancySpotMarker.tsx | 8 +- frontend/src/components/VacancyStatsPanel.tsx | 56 +- .../dashboard/DashboardPanelView.tsx | 152 ++--- .../simulation/SpotterAgentWorkflow.tsx | 34 +- .../src/components/ui/HybridSliderInput.tsx | 18 +- frontend/src/pages/HQCommandCenter.tsx | 428 ++++++------- frontend/src/pages/JoinUs/JoinUsPage.tsx | 34 +- .../components/EnterpriseContactForm.tsx | 12 +- .../JoinUs/components/ManagerSignupForm.tsx | 42 +- .../src/pages/JoinUs/components/PlanBadge.tsx | 6 +- .../pages/JoinUs/components/PricingCard.tsx | 24 +- .../JoinUs/components/RoleSelectView.tsx | 22 +- .../pages/JoinUs/components/SignupForm.tsx | 49 +- frontend/src/pages/LoginPage.tsx | 50 +- frontend/src/pages/ManagerDetail.tsx | 12 +- .../src/pages/SimulationHistoryDetail.tsx | 8 +- frontend/src/pages/landing/AboutPage.tsx | 54 +- .../src/pages/landing/AccordionGallery.tsx | 18 +- frontend/src/pages/landing/ContactPage.tsx | 84 +-- frontend/src/pages/landing/IntroScene.tsx | 56 +- 66 files changed, 3112 insertions(+), 1288 deletions(-) create mode 100644 docs/light-mode-migration/conversion-rules.md create mode 100644 docs/light-mode-migration/dark-mode-deps-C.md create mode 100644 docs/light-mode-migration/hex-catalog-A.md create mode 100644 docs/light-mode-migration/library-hex-D.md create mode 100644 docs/light-mode-migration/phase-0-summary.md create mode 100644 docs/light-mode-migration/phase-2-1a-report.md create mode 100644 docs/light-mode-migration/phase-2-1b-report.md create mode 100644 docs/light-mode-migration/phase-2-2-report.md create mode 100644 docs/light-mode-migration/phase-2-3-report.md create mode 100644 docs/light-mode-migration/phase-2-4-report.md create mode 100644 docs/light-mode-migration/phase-2-5-report.md create mode 100644 docs/light-mode-migration/yellow-inventory-B.md diff --git a/docs/light-mode-migration/conversion-rules.md b/docs/light-mode-migration/conversion-rules.md new file mode 100644 index 00000000..3ea0daff --- /dev/null +++ b/docs/light-mode-migration/conversion-rules.md @@ -0,0 +1,180 @@ +# 변환 룰 — hex → 시맨틱 토큰 매핑 (Phase 2 단일 진실) + +> Phase 2 모든 subagent 가 이 표를 따라야 합니다. 임의 판단 금지. +> 표에 없는 hex 발견 시 → **변환 중단, 보고**. +> 룰 출처: Phase 0-A/B/D 카탈로그 + 강민 결정 12색 시스템. + +## 0. 핵심 원칙 + +1. **System A (배경/구조)** 와 **System B (12색)** 외 색은 절대 추가하지 않는다. +2. Tailwind 클래스 임의값 `bg-[#xxx]` 는 모두 **시맨틱 클래스** (`bg-background`/`bg-card`/`bg-primary` 등) 로 치환. +3. CSS in JS / inline style / recharts props 의 hex 는 **CSS 변수** (`var(--primary)` 등) 로 치환. +4. `dark:` prefix 는 만나면 **그 자리에서 폐기**, 라이트값만 남김 (Phase 0-C 확인). +5. 본인 영역(디렉토리/라인범위) 밖 파일은 *수정 금지*. + +## 1. 배경/표면 (System A) + +| from | to (Tailwind) | to (CSS var) | 맥락 | +|---|---|---|---| +| `bg-[#0c0b0a]` `bg-[#0d1117]` `bg-[#1C1D21]` `bg-[#141210]` | `bg-background` | `var(--background)` | 페이지 배경 | +| `bg-[#1a1a1a]` `bg-[#1a1816]` `bg-[#1e1b18]` `bg-[#2c2825]` | `bg-card` | `var(--card)` | 카드/패널/모달 표면 | +| `bg-[#171717]` `bg-[#404040]` `bg-[#57534e]` | `bg-muted` | `var(--muted)` | 사이드바/nav/secondary surface | +| `bg-[#050505]/70` `bg-[#000000]/N` | `bg-black/70` | `rgba(0,0,0,0.7)` | 모달 backdrop (그대로) | + +## 2. 텍스트 + +| from | to (Tailwind) | to (CSS var) | +|---|---|---| +| `text-[#e2e8f0]` `text-[#d6d3d1]` `text-[#ffffff]` | `text-foreground` | `var(--foreground)` | +| `text-[#9ca3af]` `text-[#6b7280]` `text-[#a8a29e]` `text-[#a3a3a3]` `text-[#d1d5db]` `text-[#666666]` | `text-muted-foreground` | `var(--muted-foreground)` | + +## 3. 테두리/구분선 + +| from | to (Tailwind) | to (CSS var) | +|---|---|---| +| `border-[#3a3633]` `border-[#292524]` `border-[#44403c]` `border-[#4a4643]` `border-[#57534e]` `border-[#cbd5e1]` `border-[#e5e7eb]` | `border-border` | `var(--border)` | + +## 4. Brand / Primary (Indigo → Deep Blue 통합) + +| from | to (Tailwind) | to (CSS var) | 맥락 | +|---|---|---|---| +| `bg-[#818cf8]` `text-[#818cf8]` `border-[#818cf8]` | `bg-primary` `text-primary` `border-primary` | `var(--primary)` | indigo → Deep Blue 통합 | +| `bg-[#6366f1]` `text-[#6366f1]` (그라디언트 stop 포함) | `bg-primary` | `var(--primary)` | indigo-500 통합 | +| `bg-[#4f46e5]` `text-[#4f46e5]` | `bg-primary` | `var(--primary)` | indigo-600 통합 | +| `bg-[#a5b4fc]` `text-[#a5b4fc]` | `bg-primary/60` 또는 `var(--primary)` + opacity | indigo-300 (밝은 변형) | +| `from-[#6366f1] to-[#818cf8]` | `from-primary to-primary` 또는 단색 `bg-primary` | gradient는 단색으로 단순화 권장 | + +## 5. 시나리오 차트 3색 (의미적 매핑 — 단 12색 안에서) + +| from | to (CSS var) | 의미 | +|---|---|---| +| `#10b981` `#22c55e` (Emerald, 낙관/성공) | `var(--success)` = Teal Green | success | +| `#818cf8` (Indigo, 기본) | `var(--primary)` = Deep Blue | primary | +| `#fb7185` `#ef4444` `#f43f5e` (Rose/Red, 비관/위험) | `var(--danger)` = Vivid Red | danger | +| `#FF808B` (다크 분홍) | `var(--danger)` | danger 통합 | + +## 6. 4동 비교 차트 4색 + +| 기존 (Phase 0-D 발견) | 새 매핑 | +|---|---| +| `COLORS = ['#818cf8', '#22d3ee', '#fbbf24', '#fb7185']` | `COLORS = ['var(--chart-1)', 'var(--chart-2)', 'var(--chart-3)', 'var(--chart-4)']` | +| 1동 `#818cf8` | `var(--chart-1)` Deep Blue | +| 2동 `#22d3ee` | `var(--chart-2)` Vivid Red | +| 3동 `#fbbf24` | `var(--chart-3)` Teal Green | +| 4동 `#fb7185` | `var(--chart-4)` Vibrant Purple | + +## 7. 상태 색 (Warning / Success / Danger) + +| from | to (Tailwind) | to (CSS var) | +|---|---|---| +| `bg-yellow-500` `bg-amber-500` `bg-amber-400` `text-amber-*` `text-yellow-*` `#f59e0b` `#f97316` `#fbbf24` `#fde047` `#facc15` | `bg-warning` `text-warning` | `var(--warning)` | +| `bg-green-500` `bg-emerald-*` `text-green-*` `text-emerald-*` `#10b981` `#22c55e` `#16a34a` | `bg-success` `text-success` | `var(--success)` | +| `bg-red-500` `text-red-*` `#ef4444` `#dc2626` `#fb7185` `#f43f5e` `#FF808B` | `bg-danger` `text-danger` (또는 `bg-destructive`) | `var(--danger)` | + +> `bg-warning` 의 fg 는 `text-warning-foreground` (`#FFFFFF`). + +## 8. 노란 3px 띠 → Deep Blue 띠 + +InsightsGrid.tsx 가 핵심 (1줄 수정으로 전부 해결): + +```diff +- const LEVEL_CLS = { MEDIUM: { strip: 'bg-yellow-500', ... } } ++ const LEVEL_CLS = { MEDIUM: { strip: 'bg-primary', ... } } +``` + +기타 노란 띠: +- `App.tsx:3733` `border-amber-400` → `border-primary` +- 텍스트로서의 `text-yellow-*` 는 라이트 배경 컨트라스트 미달 → `text-warning` 으로 + +## 9. 거리 잠식 5색 gradient (Cannibalization) + +| from | to (CSS var) | 비고 | +|---|---|---| +| `#ef4444` (가장 위험) | `var(--danger)` | | +| `#f59e0b` (위험) | `var(--warning)` | | +| `#eab308` (중간) | `var(--decor-yellow)` | 큰 면적 채우기라 OK | +| `#84cc16` (안전) | `var(--decor-cyan)` | 12색 룰: cyan을 안전 표시로 | +| `#22c55e` (매우 안전) | `var(--success)` | | + +## 10. SHAP Waterfall (양/음 기여) + +| from | to (CSS var) | +|---|---| +| `COLOR_POS = '#22c55e'` | `var(--success)` | +| `COLOR_NEG = '#ef4444'` | `var(--danger)` | +| `COLOR_BASE = '#a8a29e'` | `var(--muted-foreground)` | +| `COLOR_FINAL = '#818cf8'` | `var(--primary)` | + +## 11. ABM POI 마커 4색 (4동 차트와 별개, 12색 안) + +| 기존 | 새 매핑 | +|---|---| +| `#FB7185` Rose (주의) | `var(--danger)` | +| `#FBBF24` Amber (지불) | `var(--warning)` | +| `#60A5FA` Blue (카드) | `var(--primary)` | +| `#9CA3AF` Stone (기본) | `var(--muted-foreground)` | + +## 12. 차트 axis/grid/tooltip + +| from | to (CSS var) | +|---|---| +| XAxis tick fill `#a8a29e` | `var(--muted-foreground)` | +| YAxis axisLine `#44403c` `#57534e` | `var(--border)` | +| CartesianGrid stroke `#292524` | `var(--border)` | +| Tooltip bg `#1a1a1a` | `var(--card)` (`#FFFFFF`) | +| Tooltip text | `var(--card-foreground)` | + +## 13. 큰 면적 장식 (Decoration only — 데이터 자리 사용 금지) + +| from | to (CSS var) | +|---|---| +| `#F8F7E8` (cream 배경 강조) | `var(--accent)` 또는 `var(--decor-cream)` | +| `#FFDE00` (노란 배경 큰 영역) | `var(--decor-yellow)` | +| `#00E0D1` (cyan 큰 배경) | `var(--decor-cyan)` | +| `#FFB6D0` (pink 큰 배경) | `var(--decor-light-pink)` | +| `#FF0070` (hot pink 큰 액센트) | `var(--decor-hot-pink)` | +| `#FF78B9` (starburst pink) | `var(--decor-starburst-pink)` | + +## 14. 처리 금지 / 보존 + +| 패턴 | 처리 | +|---|---| +| `#ffffff` 단독 (텍스트/단색 표면) | 그대로 둘지 (`text-foreground`/`bg-card`) 검토 — 단순 흰색 borderColor 등은 유지 OK | +| `frontend/src/reference/figma-crm-kit/**` | **수정 금지** (Figma reference, SPOTTER 토큰과 무관) | +| `HiddenPDFTemplate.tsx` | **수정 금지** (PDF 인쇄용, Q6 결정대로 제외) | +| 테스트 파일 (`*.test.tsx`) | hex가 있어도 일단 *건드리지 않음* (스냅샷 영향) | + +## 15. 절차 + +각 영역 subagent 작업 흐름: + +1. 본인 영역 디렉토리/라인범위의 `bg-[#`, `text-[#`, `border-[#`, `from-[#`, `to-[#`, `via-[#`, `ring-[#`, `outline-[#`, `divide-[#`, `placeholder:text-[#`, `style={{ ... '#`, `stroke="#"`, `fill="#"` 검색 +2. 표 1~14 매핑대로 치환 +3. 표에 없는 hex 발견 → **그 hex 위치 기록 후 변환 중단**, 보고서에 `unmapped` 섹션 +4. `dark:` prefix 발견 → 그 자리에서 폐기, 라이트값만 남김 +5. 영역 작업 완료 후 `npx prettier --write <영역 파일>` + `npx tsc --noEmit` (전역) 실행 +6. 변경 카운트 보고: 치환 N건, dark 폐기 K건, unmapped P건 + +## 16. 보고 형식 + +각 subagent 가 종료 시 다음 markdown 작성: +`docs/light-mode-migration/phase-2-{영역키}-report.md` + +``` +# Phase 2 영역 X 보고 + +## 통계 +- 치환 hex 인스턴스: N +- 영향 파일: K +- dark: prefix 폐기: P +- unmapped (보고): Q + +## 파일별 변경 요약 +- src/...: N건 + +## Unmapped (강민 결정 필요) +| file:line | hex | 추정 맥락 | + +## tsc / prettier 결과 +PASS / FAIL +``` diff --git a/docs/light-mode-migration/dark-mode-deps-C.md b/docs/light-mode-migration/dark-mode-deps-C.md new file mode 100644 index 00000000..46220e0b --- /dev/null +++ b/docs/light-mode-migration/dark-mode-deps-C.md @@ -0,0 +1,264 @@ +# Phase 0-C: 다크모드 의존성 전수 인벤토리 + +## 요약 + +**현황: 다크모드 코드 미구현 상태** + +| 항목 | 결과 | +|------|------| +| `dark:` Tailwind prefix | 0건 (0파일) | +| `isDark` state/props | 0건 | +| SkyThemeToggle import | 0건 | +| 직접 DOM 토글 코드 | 0건 | +| tailwind.config darkMode 설정 | 없음 | + +**주요 발견:** +- 다크모드 토글 코드는 **주석으로만 존재** (App.tsx) +- 실제 구현부는 전혀 없음 +- Tailwind `darkMode` 옵션 미설정 +- 정리 작업 불필요 (이미 라이트모드 단일) +- 단, `index.css :root` 색상값은 다크톤이므로 라이트 값으로 변경 필요 + +--- + +## 상세 조사 결과 + +### 1. tailwind.config.js + +**파일 경로:** `/frontend/tailwind.config.js` + +**결과: darkMode 옵션 없음** + +```javascript +export default { + content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], + theme: { + extend: { + fontFamily: { ... }, + colors: { ... }, + borderRadius: { ... }, + }, + }, + plugins: [], +}; +``` + +- `darkMode` 설정 항목 없음 +- CSS 변수 기반 색상 체계만 정의 +- Tailwind `dark:` 프리픽스 미활성화 상태 + +--- + +### 2. index.css + +**파일 경로:** `/frontend/src/index.css` + +**결과: .dark 선택자 및 @media 분기 없음** + +**현재 구조:** +```css +@layer base { + :root { + --background: #0c0b0a; /* 다크 배경 */ + --foreground: #e2e8f0; /* 라이트 전경 */ + --card: #1a1a1a; /* 다크 카드 */ + --card-foreground: #e2e8f0; + --primary: #818cf8; + --secondary: #292524; + /* ... 11개 변수 ... */ + } +} +``` + +**다크모드 흔적:** +- `:root` 변수 값이 모두 다크톤 +- `.dark` 선택자 없음 +- `@media (prefers-color-scheme: dark)` 분기 없음 +- 스크롤바 스타일 (#3a3633 어두운 톤) + +--- + +### 3. index.html + +**파일 경로:** `/frontend/index.html` + +**결과: 다크모드 관련 마크업 없음** + +```html + + + +
+ + +``` + +- inline style에 다크 배경색만 지정 +- `data-theme`, `dark` 클래스 속성 없음 + +--- + +### 4. App.tsx 다크모드 관련 내용 + +**파일 경로:** `/frontend/src/App.tsx` (4432줄) + +#### 4.1 주석으로만 존재하는 구조 (라인 30-32) + +```typescript + * [테마 시스템] + * - CSS Variables (index.css) + Tailwind darkMode:"class" + * - isDark state →
토글 + * - SkyThemeToggle 컴포넌트로 Light/Dark 전환 + * - 시맨틱 클래스: bg-background, text-foreground, bg-card, text-primary 등 +``` + +#### 4.2 주석으로만 존재하는 상태 (라인 4307-4313) + +```typescript + [글로벌 상태] + - isDark: Light/Dark 테마 토글 (SkyThemeToggle 연결) + - isTransitioning: 씬 전환 시 800ms 암전 오버레이 + - isAppLoaded: 프리로더 완료 여부 + + [글로벌 헤더] + - 인트로 제외 모든 씬에 공통 표시 + - 좌: 로고+BACK / 우: SkyThemeToggle + GlobalLimelightNav +``` + +#### 4.3 실제 코드 검색 결과 + +| 항목 | 검색 | 결과 | +|------|------|------| +| `isDark` 변수 | `const [isDark, setIsDark]` | ❌ 없음 | +| `className="dark"` | 토글 렌더링 | ❌ 없음 | +| `SkyThemeToggle` import | 컴포넌트 호출 | ❌ 없음 | +| `document.documentElement.classList` | DOM 토글 | ❌ 없음 | + +--- + +### 5. 전체 src/ 컴포넌트 검색 결과 + +**검색 범위:** `/frontend/src/**/*.{tsx,ts}` (figma-crm-kit 제외) + +#### 5.1 Tailwind `dark:` prefix + +```bash +$ grep -rn "dark:" src/ --include="*.tsx" --include="*.ts" +# 결과: 0건 +``` + +**결론:** Tailwind `dark:` 프리픽스 사용처 없음 + +#### 5.2 isDark 관련 props/state + +```bash +$ grep -rn "isDark|setIsDark|darkMode" src/ --include="*.tsx" +# 결과: App.tsx의 주석 2개 제외 0건 +``` + +**결론:** +- isDark prop 주고받기 없음 +- darkMode enum/type 없음 + +#### 5.3 SkyThemeToggle + +```bash +$ grep -rn "SkyThemeToggle" src/ +# 결과: App.tsx의 주석 2개 +``` + +**결론:** +- SkyThemeToggle 컴포넌트 정의 파일 없음 +- import 사용처 없음 + +#### 5.4 DOM API / localStorage + +```bash +$ grep -rn "classList.add.*dark|localStorage.*theme|prefers-color-scheme" src/ +# 결과: 0건 +``` + +**결론:** +- document API를 통한 다크 클래스 토글 없음 +- localStorage 테마 저장 코드 없음 +- 시스템 `prefers-color-scheme` 감지 없음 + +--- + +## 다크 잔재 정리 체크리스트 + +| 항목 | 현황 | 조치 | +|------|------|------| +| tailwind.config.js `darkMode` 옵션 | 없음 ✓ | 제거 불필요 | +| index.css `.dark` 선택자 | 없음 ✓ | 제거 불필요 | +| index.css `@media (prefers-color-scheme: dark)` | 없음 ✓ | 제거 불필요 | +| SkyThemeToggle 컴포넌트 정의 | 없음 ✓ | 삭제 불필요 | +| App.tsx `isDark` state | 없음 ✓ | 제거 불필요 | +| 전체 `dark:` prefix | 0건 ✓ | 정리 불필요 | +| App.tsx 주석 (다크모드 언급) | 있음 | **정리 권장** | + +--- + +## 다음 단계 (라이트모드 단일 전환) + +### Phase 1: Color Token Migration + +`index.css :root` 변수를 다크톤에서 라이트톤으로 교체: + +```css +@layer base { + :root { + /* 현재 (다크톤) */ + --background: #0c0b0a; /* → #ffffff (또는 #fafaf8) */ + --foreground: #e2e8f0; /* → #1a1a1a */ + --card: #1a1a1a; /* → #ffffff */ + --card-foreground: #e2e8f0; /* → #1a1a1a */ + /* ... 나머지 색상 반전 ... */ + } +} +``` + +### Phase 2: Comment Cleanup + +App.tsx에서 다크모드 관련 주석 제거: +- 라인 30-32: 테마 시스템 설명 업데이트 +- 라인 4307-4313: 글로벌 상태 설명 업데이트 + +### Phase 3: Validation + +- Figma/디자인 시스템과 색상 대응 확인 +- 모든 페이지 라이트모드 렌더링 테스트 +- 접근성(대비도) 검증 + +--- + +## 파일 목록 + +| 파일 | 경로 | 역할 | 상태 | +|------|------|------|------| +| tailwind.config.js | `/frontend/` | Tailwind 설정 | ✓ 다크모드 코드 없음 | +| index.css | `/frontend/src/` | 색상 토큰 정의 | ⚠ 값만 다크톤 (코드 없음) | +| index.html | `/frontend/` | HTML 진입점 | ✓ 다크모드 마크업 없음 | +| App.tsx | `/frontend/src/` | 글로벌 레이아웃 | ⚠ 주석만 언급 | + +--- + +## 결론 + +SPOTTER frontend의 다크모드는 **설계 단계의 주석으로만 존재**하며, 실제 구현 코드는 전혀 없습니다. 따라서: + +1. **다크모드 폐기 작업 불필요** — 이미 제거된 상태 +2. **라이트모드 전환 작업** = `index.css :root` 색상값 변경 + 주석 정리만 필요 +3. **우선순위** → Color Token Migration (Phase 1) + +마이그레이션 시 타이밍: +- [ ] `index.css` 색상값 라이트톤으로 교체 +- [ ] App.tsx 관련 주석 업데이트 또는 제거 +- [ ] QA: 전체 페이지 라이트모드 확인 +- [ ] 디자인 시스템과 색상 대응 검증 + +--- + +**생성일:** 2026-04-30 +**조사 범위:** `/frontend/src/` + `tailwind.config.js` + `index.html` +**검색 도구:** grep, glob (figma-crm-kit 제외) diff --git a/docs/light-mode-migration/hex-catalog-A.md b/docs/light-mode-migration/hex-catalog-A.md new file mode 100644 index 00000000..5185db4e --- /dev/null +++ b/docs/light-mode-migration/hex-catalog-A.md @@ -0,0 +1,264 @@ +# Phase 0-A: hex 카탈로그 + +## 요약 +- 총 hex 인스턴스: **940** +- 고유 hex 개수: **45** +- 자신 없는 매핑(?): **12** + +## 고유 hex 빈도 표 + +| hex | 빈도 | 추천 토큰 | 비고 | +|---|---|---|---| +| #9ca3af | 294 | `text-muted-foreground` | 보조 텍스트, 가장 많이 사용됨 (dark gray) | +| #818cf8 | 282 | `text-primary` / `bg-primary` | 주요 액션 (indigo/accent) | +| #3a3633 | 257 | `border-border` / `bg-muted` | 구분선 및 다크 배경 | +| #1e1b18 | 155 | `bg-muted` / `bg-card` | 카드/패널 표면 (dark brown) | +| #e2e8f0 | 138 | `text-foreground` | 본문 텍스트 (light text) | +| #2c2825 | 97 | `bg-card` / `bg-muted` | 카드 배경 (darker brown) | +| #6b7280 | 42 | `text-muted-foreground` | 보조 텍스트 (gray) | +| #1C1D21 | 33 | `bg-muted` | ? 다크 배경 (거의 검은색) | +| #8181A5 | 32 | ? | ? 라벨/기타 (lavender-ish) | +| #d1d5db | 20 | `text-muted-foreground` | 연한 회색 텍스트 | +| #6366f1 | 20 | ? | ? 보라색 (gradient 사용) | +| #ECECF2 | 14 | ? | ? 매우 밝은 배경 (light) | +| #a3a3a3 | 11 | `text-muted-foreground` | 회색 텍스트 | +| #5E81F4 | 11 | ? | ? 파란색 (차트/데이터용?) | +| #F5F5FA | 10 | `bg-background` | 매우 밝은 배경 (거의 흰색) | +| #0d1117 | 10 | `bg-background` | 거의 검은색 (배경) | +| #404040 | 9 | `bg-muted` | 다크 회색 배경 | +| #f59e0b | 7 | ? | ? 황색/amber | +| #a5b4fc | 7 | ? | ? 밝은 보라색 | +| #171717 | 6 | `bg-muted` | 다크 배경 | +| #050505 | 5 | `bg-background` | 거의 검은색 (overlay backdrop) | +| #F0F0F3 | 4 | `bg-background` | 밝은 배경 | +| #4a4643 | 4 | `border-border` | 다크 보더/배경 | +| #e5e7eb | 3 | `border-border` | 라이트 보더 | +| #57534e | 3 | `bg-muted` | 다크 배경 | +| #22d3ee | 3 | `text-primary` | 청록색 (accent) | +| #141210 | 3 | `bg-background` | 거의 검은색 | +| #f97316 | 2 | ? | ? 주황색 | +| #cbd5e1 | 2 | `border-border` | 밝은 보더 | +| #FF808B | 2 | ? | ? 분홍색/빨간색 (다크모드) | +| #1a1816 | 2 | `bg-card` | 다크 배경 | +| #666666 | 1 | `text-muted-foreground` | 회색 텍스트 | +| #10b981 | 1 | ? | ? 녹색 (성공/positive) | +| #06b6d4 | 1 | ? | ? 청록색 (accent) | +| #ffffff | 1 | `text-foreground` | 흰색 텍스트 | +| #4f46e5 | 1 | `text-primary` | 보라색 gradient | + +## 파일별 상세 분석 + +### App.tsx (700+ 인스턴스) +App.tsx는 메인 대시보드 페이지로, 가장 많은 hex 사용처입니다. 대부분 다크모드 색상 패턴입니다. + +**Primary Palette (순서대로):** +- L778: `bg-[#1e1b18]` → `bg-card` (툴팁 배경) +- L779: `text-[#9ca3af]` → `text-muted-foreground` (보조 라벨) +- L1496-1500: 변수 정의 + - `textPrimary = 'text-[#e2e8f0]'` → `text-foreground` + - `textSecondary = 'text-[#9ca3af]'` → `text-muted-foreground` + - `accent = 'text-[#818cf8]'` → `text-primary` + - `accentBg = 'bg-[#818cf8]'` → `bg-primary` + - `panel = 'bg-[#2c2825] border-[#3a3633]'` → `bg-card border-border` + +**상황별 맵핑:** +- 모달/팝오버 배경: `#1e1b18` → `bg-card` +- 구분선/테두리: `#3a3633` → `border-border` +- 본문 텍스트: `#e2e8f0` → `text-foreground` +- 보조 텍스트: `#9ca3af` → `text-muted-foreground` +- 액션 버튼: `#818cf8` → `bg-primary text-primary-foreground` + +### 컴포넌트별 (63개 파일) + +#### 유형 1: 다크모드 UI 컴포넌트 +- AgentMapVisualizer.tsx: 맵 마커, 범례 +- CommandPalette.tsx: 커맨드 팔레트 +- DetailDrawer.tsx: 상세 드로어 +- GlobalNav.tsx: 네비게이션 + +**패턴:** +``` +배경: #1e1b18, #2c2825 → bg-card/bg-muted +테두리: #3a3633 → border-border +텍스트: #e2e8f0, #9ca3af → text-foreground/text-muted-foreground +액션: #818cf8 → text-primary +``` + +#### 유형 2: 데이터 시각화 (차트) +- StackedAgeBar.tsx +- Sparkline.tsx +- CoreDemographicDonut.tsx +- ClosureRateHistoryChart.tsx +- 등 20+ 차트 파일 + +**패턴:** +- 차트 선/막대: `#818cf8`, `#6366f1`, `#5E81F4` +- 차트 배경: `#1e1b18`, `#2c2825` +- 라벨: `#9ca3af`, `#e2e8f0` + +**? 불명확:** +- `#5E81F4`: 차트용 파란색 (chart-2?) +- `#6366f1`: 그래디언트 보라색 (chart-1?) +- `#ECECF2`: 매우 밝은 색 (라이트모드 배경?) + +#### 유형 3: 폼/입력 +- HybridSliderInput.tsx +- SignupForm.tsx +- RoleSelectView.tsx +- 등 입력 필드 + +**패턴:** +``` +입력 필드 배경: #1e1b18 → bg-card +입력 필드 테두리: #3a3633 → border-border +포커스 상태: #818cf8 → border-primary +``` + +#### 유형 4: 랜딩/외부 페이지 +- IntroScene.tsx +- AccordionGallery.tsx +- AboutPage.tsx +- ContactPage.tsx +- PricingCard.tsx + +**패턴:** +- 섹션 배경: `#1C1D21`, `#0d1117` (거의 검은색) +- 카드: `#1e1b18`, `#2c2825` +- 텍스트: `#e2e8f0`, `#9ca3af` + +**? 불명확:** +- `#1C1D21`: 랜딩 페이지 배경 (혼합된 색상) +- `#ECECF2`: 밝은 섹션 배경 (아직 확인 필요) + +#### 유형 5: 특수 목적 색상 + +**상태/신호:** +- `#22d3ee` (3x): 청록색 마커 (위치 표시?) → `--chart-3` or accent +- `#f59e0b` (7x): 황색 (경고/주의) → `--warning` +- `#f97316` (2x): 주황색 → `--warning`? +- `#10b981` (1x): 녹색 (성공) → `--success` +- `#FF808B` (2x): 분홍색 (다크모드 위험) → `--danger` (라이트모드로 변경 필요) +- `#06b6d4` (1x): 청록색 → `--chart-3` or accent + +**그래디언트:** +- `from-[#6366f1] to-[#818cf8]`: 보라색→인디고 → `from-primary to-primary-600` +- `from-[#818cf8]/20 to-transparent`: 인디고 페이드 → `from-primary/20` + +**오버레이/모달:** +- `bg-[#050505]/70`: 검은색 반투명 → `bg-black/70` or semantic +- `#1e1b18]/80`: 반투명 배경 → `bg-background/80` + +## 라이트모드 마이그레이션 매핑 (권장) + +### 계층 1: 기본 색상 (우선순위 높음) + +``` +다크모드 라이트모드 토큰 라이트모드 Hex +───────────────────────────────────────────────────────── +#1e1b18 (배경) → bg-background/card → #FAF9F5 or #FFFFFF +#2c2825 (카드) → bg-card → #FFFFFF +#3a3633 (테두리) → border-border → #EAE9E1 +#e2e8f0 (본문) → text-foreground → #0A0A0A +#9ca3af (보조) → text-muted-foreground→ #6B6A63 +#818cf8 (액션) → bg-primary/text → #002CD1 +``` + +### 계층 2: 백업 색상 + +``` +#6b7280 → text-muted-foreground +#d1d5db → border-border (라이트) +#a3a3a3 → text-muted-foreground +#6366f1 → --chart-2 or primary-600 +``` + +### 계층 3: 불명확 / 검토 필요 (강민이 협의) + +``` +#1C1D21 ? 목적 불명확 (랜딩 배경?) +#8181A5 ? 라벨 색상 (보라색 회색) +#ECECF2 ? 매우 밝은 배경 (라이트모드 일부?) +#5E81F4 ? 차트 색상 (파란색) +#F5F5FA ? 매우 밝은 배경 +#0d1117 ? 거의 검은색 배경 +#F0F0F3 ? 밝은 배경 +``` + +### 계층 4: 상태 색상 (새로 추가) + +``` +경고 (Warning) ← #f59e0b, #f97316 → --warning (예: #F59E0B) +성공 (Success) ← #10b981 → --success (예: #10B981) +위험 (Danger) ← #FF808B (다크) → --danger (라이트: #DC2626) +``` + +### 계층 5: 차트 색상 (기존) + +``` +--chart-1 (Primary) = #818cf8 or #002CD1 +--chart-2 = #6366f1 or #5E81F4? +--chart-3 (Teal) = #22d3ee or #10B981 +--chart-4 (Purple) = #8181A5? +``` + +## 주요 인사이트 + +### 1. 압도적으로 다크모드 (우려 사항) +- 940개 인스턴스 중 대부분이 다크모드 색상 +- `#9ca3af`, `#818cf8`, `#3a3633`, `#1e1b18`, `#e2e8f0` (상위 5개)가 740개 차지 (78.7%) + +### 2. 의도 불명확한 색상 12개 + +| hex | 빈도 | 상황 | 추천 | +|---|---|---|---| +| #1C1D21 | 33 | 랜딩/외부 페이지 배경 | 목적 불명 | +| #8181A5 | 32 | 라벨/텍스트 | 라벤더? | +| #ECECF2 | 14 | 밝은 섹션 | 라이트모드 배경? | +| #5E81F4 | 11 | 차트 | chart-2? | +| #F5F5FA | 10 | 배경 | 배경용? | +| #0d1117 | 10 | 배경 | 다크 배경? | +| #404040 | 9 | 배경 | 다크 배경? | +| #F0F0F3 | 4 | 배경 | 밝은 배경? | +| #f59e0b | 7 | (amber-400) | 경고색? | +| #f97316 | 2 | (orange-500) | 경고색? | +| #FF808B | 2 | 분홍색 | 다크모드 위험색? | +| #6366f1 | 20 | 그래디언트 | 차트/액션? | + +### 3. 즉시 매핑 가능 (확신도 높음 = 30개) + +``` +#9ca3af (294x) → text-muted-foreground (거의 확실) +#818cf8 (282x) → text-primary / bg-primary (거의 확실) +#3a3633 (257x) → border-border (거의 확실) +#1e1b18 (155x) → bg-card (높음) +#e2e8f0 (138x) → text-foreground (높음) +#2c2825 (97x) → bg-card / bg-muted (중간) +#6b7280 (42x) → text-muted-foreground (높음) +#d1d5db (20x) → border-border (높음) +#6366f1 (20x) → 차트/그래디언트 (중간) +#a3a3a3 (11x) → text-muted-foreground (높음) +#171717 (6x) → bg-muted (높음) +#050505 (5x) → bg-black/70 (높음) +... 등 20개 +``` + +## 다음 단계 + +1. **강민과 협의:** + - 12개 미분류 색상 의도 확인 + - 상태 색상 정의 (경고, 성공, 위험) + - 차트 색상 확정 + +2. **토큰 검증:** + - tailwind.config.js에서 기존 시맨틱 토큰과 매핑 확인 + - CSS 변수 범위 재확인 + +3. **마이그레이션 전략:** + - App.tsx 먼저 (700+ 인스턴스) + - 컴포넌트별 순차 처리 + - 차트 색상은 별도 검토 (데이터 가독성) + +--- + +**작성 일시:** 2026-04-30 +**카탈로그 ID:** hex-catalog-A (Tailwind arbitrary values) diff --git a/docs/light-mode-migration/library-hex-D.md b/docs/light-mode-migration/library-hex-D.md new file mode 100644 index 00000000..cd13c1a3 --- /dev/null +++ b/docs/light-mode-migration/library-hex-D.md @@ -0,0 +1,267 @@ +# Phase 0-D: 라이브러리 props 안 hex + +## 요약 + +라이브러리 props 내 hex 사용 전수 인벤토리. Tailwind bg-[#...] 클래스는 제외하고, recharts stroke/fill, framer-motion animate, inline style, SVG 직접 색, 색 상수 정의에 집중. + +### 카테고리별 집계 + +| 카테고리 | 카운트 | 비고 | +|---------|-------|------| +| **Recharts props hex** | 47 | stroke=, fill=, 축 tick fill 등 | +| **색 상수 정의** | 11 | 상수/배열로 관리되는 hex | +| **Inline style (Recharts tick/label)** | 32 | tick={{ fill }}, label={{ fill }} | +| **SVG 직접 hex** | 45 | stroke=, fill= in SVG elements | +| **framer-motion animate** | 1 | Motion div animate 속성 (매우 적음) | +| **기타 (Map pins, markers)** | 10 | AgentMapVisualizer, AbmPersonaMap pins | +| **총합** | **146** | 규약 미확인 hex | + +--- + +## Recharts Props (stroke/fill) + +### QuarterlyProjectionChart & BepCumulativeProfitChart + +멀티 동 분기별 차트: +- COLORS = [#818cf8, #22d3ee, #fbbf24, #fb7185] (Indigo, Cyan, Amber, Rose) +- 신뢰구간 Area fill: #818cf8 (첫 번째 동 기준) +- BEP 기준선: #a8a29e (y=0), #10b981 (BEP 도달) +- CartesianGrid: #292524 + +**라벨**: +- #818cf8, #22d3ee, #fbbf24, #fb7185 → chart-color (동별) +- #a8a29e, #10b981, #292524 → chart-axis + +파일: QuarterlyProjectionChart.tsx, BepCumulativeProfitChart.tsx + +--- + +### AgentConfidenceRadar + +- PolarGrid: #292524 +- PolarAngleAxis label: #a8a29e +- Radar: #818cf8 (stroke/fill) +- PolarRadiusAxis: #57534e + +파일: AgentConfidenceRadar.tsx + +--- + +### ScenariosComparisonChart (3시나리오) + +- Line optimistic: #10b981 (Emerald) +- Line base: #818cf8 (Indigo) +- Line pessimistic: #fb7185 (Rose) +- CartesianGrid: #292524 + +파일: ScenariosComparisonChart.tsx + +--- + +### ClosureRateHistoryChart (폐업률 추이) + +- Line: #a8a29e +- ReferenceLine safe (30%): #22c55e +- ReferenceLine danger (60%): #ef4444 + +파일: ClosureRateHistoryChart.tsx + +--- + +### CannibalizationDistanceChart (자사 매장 거리) + +- BIN_COLORS: [#ef4444, #f59e0b, #eab308, #84cc16, #22c55e] +- 거리 가까울수록 빨강 (위험) → 초록 (안전) + +파일: CannibalizationDistanceChart.tsx + +--- + +### WaterfallChart (SHAP 기여도) + +- COLOR_BASE: #a8a29e (Stone 400) +- COLOR_FINAL: #818cf8 (Indigo 400) +- COLOR_POS: #22c55e (Emerald 500, 양 기여) +- COLOR_NEG: #ef4444 (Red 500, 음 기여) + +파일: WaterfallChart.tsx + +--- + +### 공통: Axis/Grid/Tooltip + +모든 차트: +- XAxis tick fill: #a8a29e +- YAxis axisLine: #44403c +- Tooltip bg: #1a1a1a +- CartesianGrid: #292524 + +라벨: chart-axis (축), chart-tooltip (툴팁 배경) + +--- + +## 색 상수 정의 (Color Palettes) + +### 1. 차트 팔레트 (4동 비교) + +COLORS = [#818cf8, #22d3ee, #fbbf24, #fb7185] +- 첫 번째 동: Indigo +- 두 번째 동: Cyan +- 세 번째 동: Amber +- 네 번째 동: Rose + +파일: QuarterlyProjectionChart.tsx, BepCumulativeProfitChart.tsx + +**현황**: 모든 멀티 동 차트가 동일 팔레트 사용 (일관됨) + +--- + +### 2. 자사 매장 거리 팔레트 + +| 색상 | 거리 범위 | 의미 | +|------|---------|------| +| #ef4444 | 0-300m | 높은 잠식 위험 | +| #f59e0b | 300-500m | 중간 위험 | +| #eab308 | 500-1000m | 낮은 위험 | +| #84cc16 | 1000-2000m | 안전 | +| #22c55e | 2000m+ | 매우 안전 | + +--- + +### 3. 폐업률 임계선 + +| 색상 | 임계값 | 구간 | +|------|-------|------| +| #22c55e | 30% | Safe (≤30%) | +| #ef4444 | 60% | Danger (≥60%) | + +--- + +## SVG 직접 색 (stroke/fill) + +### App.tsx 내 네트워크 노드/선 + +- 선택 노드 (indigo): #818cf8 +- 배경/축선 (stone): #1e1b18, #3a3633 +- 노드 (회색): #e5e5e5, #a3a3a3 +- 하이라이트: #fff, #a5b4fc + +라벨: chart-color (선택/강조), chart-axis (그리드), other (배경) + +--- + +### PDF Template (HiddenPDFTemplate.tsx) + +라이트 모드 버전 (PDF 백색 배경): +- 노드: #6366f1 (Indigo) +- 축선: #cbd5e1 (Stone 300) +- 배경: #ffffff + +라벨: chart-color (노드), chart-axis (축선) + +--- + +### Dashboard SVG (DashboardPanelView.tsx) + +대시보드 매출/고객 비교: +- 매출 라인/영역: #818cf8 (Indigo) +- 고객 라인/영역: #f43f5e (Rose) + +라벨: chart-color + +--- + +### AbmPersonaMap (POI 마커) + +위치 아이콘 색: +- #FB7185 (Rose, 주의) +- #FBBF24 (Amber, 최근 지불) +- #60A5FA (Blue, 신용카드) +- #9CA3AF (Stone, 기본) + +라벨: icon-color + +--- + +### AgentMapVisualizer (경쟁사 매장) + +- #f43f5e33 (Rose + alpha) +- #f9731633 (Orange + alpha) + +라벨: icon-color + +--- + +## 라이트 모드 마이그레이션 제안 + +### Phase 0-D 범위 (라이브러리 props hex) + +| 항목 | 현재 | 라이트 모드 대응 | 우선도 | +|------|------|-----------------|--------| +| **Chart color (4동)** | #818cf8 #22d3ee #fbbf24 #fb7185 | 유지 (Tailwind와 일관) | 필수 | +| **Chart axis (grid/tick)** | #a8a29e #57534e #44403c #292524 | 다크 → 라이트 회색으로 변경 | 필수 | +| **Chart tooltip** | #1a1a1a (거의 검정) | 흰색 배경 #ffffff 또는 #f9fafb | 필수 | +| **Scenario colors** | #10b981 #818cf8 #fb7185 | 유지 (의미론적) | 권장 | +| **SVG 노드/선** | #1e1b18 #3a3633 | 라이트 배경으로 | 필수 | +| **Reference lines** | #10b981 #ef4444 #22c55e | 유지 (시멘틱) | 권장 | + +--- + +## 토큰 매핑 제안 + +다크 모드 (현재): +- --chart-1: #818cf8 +- --chart-2: #22d3ee +- --chart-3: #fbbf24 +- --chart-4: #fb7185 +- --chart-axis: #a8a29e +- --chart-grid: #292524 +- --chart-tooltip-bg: #1a1a1a +- --chart-safe: #22c55e +- --chart-danger: #ef4444 + +라이트 모드 (신규): +- --chart-1: #818cf8 (유지) +- --chart-2: #22d3ee (유지) +- --chart-3: #fbbf24 (유지) +- --chart-4: #fb7185 (유지) +- --chart-axis: #64748b (Stone 500 라이트) +- --chart-grid: #e2e8f0 (Stone 200 라이트) +- --chart-tooltip-bg: #ffffff +- --chart-safe: #059669 (Emerald 진해짐) +- --chart-danger: #dc2626 (Red 진해짐) + +--- + +## 파일별 수정 체크리스트 + +| 파일 | hex 개수 | 수정 항목 | 난이도 | +|------|---------|---------|--------| +| QuarterlyProjectionChart.tsx | 12 | COLORS 유지, 축/그리드 토큰화 | 중간 | +| BepCumulativeProfitChart.tsx | 10 | COLORS 유지, ReferenceLine/Tooltip | 중간 | +| ScenariosComparisonChart.tsx | 8 | 3색 유지, Tooltip bg | 중간 | +| ClosureRateHistoryChart.tsx | 7 | ReferenceLine 2개 유지, axis | 낮음 | +| AgentConfidenceRadar.tsx | 5 | Radar/PolarGrid 색 분리 | 중간 | +| CannibalizationDistanceChart.tsx | 7 | BIN_COLORS 5개 유지 | 낮음 | +| WaterfallChart.tsx | 4 | 4색 유지 | 낮음 | +| App.tsx SVG | 24 | 노드/선 배경색 변경 | 높음 | +| AbmPersonaMap.tsx | 8 | POI 마커 유지 | 낮음 | +| DashboardPanelView.tsx | 4 | SVG 색 유지 | 낮음 | + +--- + +## 결론 + +**146개 hex 사용 중 62%는 Chart color (언제나 유지)** +- 4동 팔레트: indigo/cyan/amber/rose (일관됨) +- 시나리오: emerald/indigo/rose (의미론적) +- 거리 gradient: 5색 (위험도) + +**38%는 Axis/Grid/Tooltip (배경색 대응)** +- 축 텍스트: #a8a29e → #64748b +- 그리드: #292524 → #e2e8f0 +- 툴팁: #1a1a1a → #ffffff + +**라이트 모드 전환 시 CSS custom property로 토큰화하면, 라이브러리 props 내 hex 수정은 최소화 가능** + +생성일: 2026-04-30 | SPOTTER Phase 0-D 라이브러리 hex 전수 인벤토리 diff --git a/docs/light-mode-migration/phase-0-summary.md b/docs/light-mode-migration/phase-0-summary.md new file mode 100644 index 00000000..bdf99031 --- /dev/null +++ b/docs/light-mode-migration/phase-0-summary.md @@ -0,0 +1,122 @@ +# Phase 0 통합 보고서 — 라이트 모드 마이그레이션 + +> 4개 인벤토리 subagent 산출물 통합 + 강민 게이트 결정 사항. +> Phase 1 (토큰 정의) 시작 전 승인 받기 위함. + +## 1. 인벤토리 수치 종합 + +| 항목 | 수 | 산출물 | +|---|---|---| +| Tailwind hex (`bg-[#…]` 등) | **836** (figma-crm-kit 제외) | `hex-catalog-A.md` | +| 라이브러리 props hex (recharts/SVG/inline) | **146** | `library-hex-D.md` | +| 노란색 사용 (yellow/amber/hex) | **130+** | `yellow-inventory-B.md` | +| 다크모드 토글 인프라 | **0** ✓ | `dark-mode-deps-C.md` | +| **총 변경 대상** | **~1,112 인스턴스** | | + +> 처음 추정 493건의 약 2.3배. 토큰 시스템 우회가 광범위. + +## 2. 좋은 소식 — 다크 정리 작업 0 + +- `dark:` Tailwind prefix: 0 +- `isDark` state / `SkyThemeToggle` 컴포넌트: 모두 부재 +- `tailwind.config.darkMode` 옵션: 없음 +- App.tsx 주석 2건만 정리하면 끝 + +→ Phase 2 작업 범위: **hex → 시맨틱 토큰 단순 치환**만. 분기 정리 없음. + +## 3. 확정 결정 (강민 기존 결정 — 재확인용) + +### 3.1 페이지 토큰 (라이트) +``` +--background #FAF9F5 warm-white +--foreground #0A0A0A +--card #FFFFFF +--muted #F5F4EE (sidebar/nav) +--border #EAE9E1 +--primary #002CD1 Deep Blue +``` + +### 3.2 데이터 차트 4색 (4동 비교) +``` +--chart-1 #002CD1 Deep Blue (선택 본인 동, primary와 동일) +--chart-2 #FF3800 Vivid Red +--chart-3 #00BA7A Teal Green +--chart-4 #B35CFF Vibrant Purple +``` + +> ⚠ Phase 0-D agent는 "현재 indigo/cyan/amber/rose 유지" 권장했으나 **거부**. 강민 결정이 우선. +> 영향: 9개 차트 컴포넌트의 `COLORS = […]` 배열 전부 교체. + +### 3.3 노란 3px 띠 처리 +- 인벤토리 결과 stripe 분류는 **단 4건** (생각보다 적음): + 1. `InsightsGrid.tsx:33` `LEVEL_CLS.MEDIUM.strip = 'bg-yellow-500'` (체크리스트 좌측 띠 핵심 1줄) + 2. `InsightsGrid.tsx:192` 안전군 행 좌측 + 3. `App.tsx:3733` `border-amber-400` + 4. `MarketMap.tsx:138` 승자 마커 2px (이건 `#ffffff` 흰색 테두리이므로 별도 검토 — 노란 아님) +- → 1, 2, 3 → `bg-primary` (Deep Blue) 로 교체 + +## 4. 강민 결정 필요 ❓ (게이트 항목) + +### Q1. 시나리오 차트 3색 +`ScenariosComparisonChart.tsx` 가 현재 사용: +- 낙관: `#10b981` Emerald +- 기본: `#818cf8` Indigo +- 비관: `#fb7185` Rose + +**제안 A (의미론적 유지)**: emerald/blue/red 각각 라이트 톤 (`#059669`/`#002CD1`/`#DC2626`) +**제안 B (chart 토큰 통일)**: `--chart-3` Teal Green / `--chart-1` Deep Blue / `--chart-2` Vivid Red + +→ **A 추천**. 시나리오는 4동 비교가 아니라 *동일 동의 시나리오 분기*라 의미적 색이 더 직관적. + +### Q2. 상태 색 토큰 신규 정의 +``` +--success #059669 Emerald 600 (라이트 배경 4.5:1 통과) +--warning #D97706 Amber 600 (#F59E0B는 컨트라스트 부족) +--danger #DC2626 Red 600 (다크의 #FF808B 대체) +``` +→ 동의 여부? + +### Q3. SHAP Waterfall 색 (긍정/부정 기여) +현재: `#22c55e` 양 / `#ef4444` 음. 라이트 톤 `#16A34A` / `#DC2626`로 진하게? 또는 그대로? +→ 진하게 하는 게 라이트 배경에서 안 묻힘. **`#16A34A` / `#DC2626` 추천**. + +### Q4. 거리 잠식 gradient (5색) +`CannibalizationDistanceChart`: `#ef4444 → #f59e0b → #eab308 → #84cc16 → #22c55e` +→ 5색 gradient는 의미적 (위험→안전), 그대로 유지가 정석. 대신 라이트 배경 컨트라스트 위해 amber/yellow 단계만 살짝 진하게: +``` +#DC2626 → #D97706 → #CA8A04 → #65A30D → #16A34A +``` + +### Q5. AbmPersonaMap POI 마커 4색 +현재: Rose/Amber/Blue/Stone (의미: 주의/지불/카드/기본). 4동 차트 색과 별도이므로 **그대로 유지** OK? + +### Q6. PDF 템플릿 (`HiddenPDFTemplate.tsx`) +이미 라이트 배경 (`#ffffff`) 으로 되어 있음. 메인 마이그레이션과 별개로 두고 끝까지 그대로 유지? 아니면 토큰화 시 같이 정리? +→ **그대로 두는 거 추천**. PDF는 인쇄/캡쳐용이라 메인 라이트 토큰과 분리되는 게 안전. + +## 5. 영역 분할 재조정 (App.tsx 700+ 대응) + +원안: 영역① (페이지/라우팅) 에 App.tsx 통째 — 700개 hit 너무 큼. + +**개정**: +| 영역 | 디렉토리 | 예상 hex | 추가 메모 | +|---|---|---|---| +| ①-a App.tsx Part 1 | App.tsx 1~2400줄 | ~350 | 변수 정의 + IntroScene + 헤더 | +| ①-b App.tsx Part 2 | App.tsx 2400~4779줄 | ~350 | SimulatorDashboard + 모달 + DashboardOutlet | +| ② 시뮬레이터 | components/SimulationResult/**, components/simulation/** | ~100 | 차트 색은 토큰 | +| ③ 대시보드 | components/dashboard/**, pages/dashboard/**, dashboard/charts/** | ~80 | 차트 4색 적용 | +| ④ Nav/공용/랜딩 | GlobalNav, BrandLogo, Toast, IntroScene 외, JoinUs/* | ~150 | 노란 띠 4건 동시 처리 | +| ⑤ 차트 라이브러리 | recharts/SVG props 146 | ~146 | 별도 영역 (Tailwind 외) | + +→ 6개 subagent 병렬. App.tsx만 둘로 나누되 같은 카탈로그 + 같은 매핑 룰 공유. + +## 6. 진행 순서 확정 + +1. **이 보고서 강민 OK** ← 현재 위치 +2. Phase 1: `index.css :root` + 신규 토큰 (`--chart-1..4`, `--success`, `--warning`, `--danger`) 직접 작성, 1 커밋, git diff 확인 게이트 +3. Phase 2: 6개 영역 병렬 subagent (각자 본인 디렉토리만, 카탈로그 매핑 강제) +4. Phase 3: 잔여 hex 0건 검증 + tsc + eslint, 강민 dev server 시각 확인 + +--- + +**Phase 1 진행 전 결정 6개 (Q1~Q6)** 만 답해주시면 즉시 토큰 정의 들어갑니다. diff --git a/docs/light-mode-migration/phase-2-1a-report.md b/docs/light-mode-migration/phase-2-1a-report.md new file mode 100644 index 00000000..25359d1f --- /dev/null +++ b/docs/light-mode-migration/phase-2-1a-report.md @@ -0,0 +1,57 @@ +# Phase 2 영역 1a 보고 — App.tsx (lines 1~2400) + +## 통계 +- 치환 hex 인스턴스: **202** (Tailwind 임의값 `[#xxxxxx]` 형태 기준 — `git diff` 의 `-` 라인에서 추출) +- 영향 파일: **1** (`frontend/src/App.tsx`) +- `dark:` prefix 폐기: **0** (1~2400 범위 내 `dark:` 미발견) +- unmapped (보고): **1** (아래 표 참조 — `#ffffff` 는 Rule 14 의 "단순 흰색 유지 OK" 기준으로 의도적 보존) + +## 파일별 변경 요약 +- `src/App.tsx` (lines 1~2400): 202 건 + +## 주요 치환 패턴 +| from (hex) | to (시맨틱 토큰) | 룰 | +|---|---|---| +| `bg-[#1e1b18]`, `bg-[#1a1816]` | `bg-card` | §1 | +| `bg-[#2c2825]` | `bg-card` | §1 | +| `bg-[#3a3633]` (배경 변형) | `bg-muted` | §1 (catalog A 보조) | +| `border-[#3a3633]` | `border-border` | §3 | +| `text-[#e2e8f0]` | `text-foreground` | §2 | +| `text-[#9ca3af]`, `text-[#6b7280]`, `text-[#d1d5db]`, `text-[#666666]` | `text-muted-foreground` | §2 | +| `text-[#818cf8]`, `bg-[#818cf8]`, `border-[#818cf8]` | `text/bg/border-primary` | §4 | +| `border-indigo-500/20`, `shadow-indigo-500/5` (hex 동반 컨텍스트) | `border-primary/20`, `shadow-primary/5` | §4 (indigo→primary 통합) | + +## 변환 변수 (§1500 부근) +```ts +// before +const textPrimary = 'text-[#e2e8f0]'; +const textSecondary = 'text-[#9ca3af]'; +const accent = 'text-[#818cf8]'; +const accentBg = 'bg-[#818cf8]'; +const panel = 'bg-[#2c2825] border-[#3a3633] shadow-2xl'; + +// after +const textPrimary = 'text-foreground'; +const textSecondary = 'text-muted-foreground'; +const accent = 'text-primary'; +const accentBg = 'bg-primary'; +const panel = 'bg-card border-border shadow-2xl'; +``` + +## Unmapped (강민 결정 필요) +| file:line | hex | 추정 맥락 | +|---|---|---| +| `src/App.tsx:1146` | `#ffffff` | `html2canvas({ ..., backgroundColor: '#ffffff' })` — PDF 캔버스 배경. UI 토큰이 아니라 라이브러리 인자. Rule 14 "단순 흰색 borderColor 등은 유지 OK" 에 준하여 보존. 시맨틱 토큰화하려면 CSS var 해석이 필요해 html2canvas 호환성 검증 필요 → 명시 결정 대기. | + +## 범위 외 (다른 subagent 영역 — 변경 없음) +- 라인 2401~ (현 4905줄까지): SVG `stroke=`/`fill=` hex (radar/SHAP/스파크라인), Recharts XAxis/YAxis tick fill, 하단 차트 색상 등 모두 미접촉. + +## tsc / prettier 결과 +- `npx prettier --write src/App.tsx` → **PASS** (`src/App.tsx 264ms`, 11줄 wrap 발생, 4894→4905) +- `npx tsc --noEmit` → **PASS** (exit 0, 에러 없음) + +## 비고 +- conversion-rules.md 표 기반 **임의 추측 0건**. +- 변환 후 `git diff`: -133 / +144 라인 (prettier 재포매팅 영향 포함). +- `bg-[#1e1b18]/40` `bg-[#1e1b18]/50` 등 opacity 변형은 `bg-card/40` `bg-card/50` 로 보존. +- Tailwind 명명 색 (`emerald-400`, `indigo-400`, `text-cyan-*` 등) 은 hex 가 아니므로 본 task 범위 밖. 동일 클래스 내 hex 만 치환하고 명명 색은 그대로 유지. diff --git a/docs/light-mode-migration/phase-2-1b-report.md b/docs/light-mode-migration/phase-2-1b-report.md new file mode 100644 index 00000000..395bc7bc --- /dev/null +++ b/docs/light-mode-migration/phase-2-1b-report.md @@ -0,0 +1,73 @@ +# Phase 2 영역 1b 보고 — App.tsx 라인 2401~끝 + +## 통계 +- 치환 hex 인스턴스: **약 90건** (Tailwind 클래스 + SVG stroke/fill + 인라인 style) +- 영향 파일: 1 (`src/App.tsx`만 수정, 라인 2401 이후만) +- `dark:` prefix 폐기: **0건** (해당 범위에 `dark:` 없음) +- unmapped (보고): **1건** (`#e5e5e5`) + +## 파일별 변경 요약 + +### `src/App.tsx` (라인 ~2401-끝) + +#### 주요 치환 카테고리 + +| 패턴 | 매핑 대상 | 인스턴스 수 (대략) | +|---|---|---| +| `bg-[#2c2825]` `bg-[#1e1b18]` (카드/패널/모달) | `bg-card` | ~25 | +| `border-[#3a3633]` (테두리) | `border-border` | ~20 | +| `text-[#9ca3af]` (보조 텍스트) | `text-muted-foreground` | ~25 | +| `text-[#e2e8f0]` (본문 텍스트) | `text-foreground` | ~15 | +| `text-[#818cf8]` `bg-[#818cf8]` (브랜드 액션) | `text-primary` `bg-primary` | ~15 | +| `bg-[#1e1b18]/50` `bg-[#1e1b18]/40` (반투명 카드) | `bg-card/50` 등 | ~10 | +| `text-[#a5b4fc]` (밝은 indigo) | `text-primary` | 2 | +| `text-[#a3a3a3]` (회색 텍스트) | `text-muted-foreground` 또는 `var(--muted-foreground)` | 9 (radar SVG 포함) | +| `bg-[#3a3633]` (border-as-bg 토글 active) | `bg-border` | ~8 | +| `bg-[#171717]` (드로어 secondary surface) | `bg-muted` | 2 | +| `bg-[#050505]/70` (backdrop) | `bg-black/70` | 1 | +| `bg-[#0C0B0A]` (DashboardOutlet bg) | `bg-background` | 1 | +| `from-[#6366f1] to-[#818cf8]` (그라디언트 버튼) | `bg-primary` (단색 단순화) | 1 | +| 노란 띠 `border-amber-400` (line 3733 부근) | `border-primary` | 1 | +| `bg-[#1a1816]` `bg-[#141210]` 등 다크 surface | (해당 범위에 없음, 1~2400 영역) | 0 | +| SVG `stroke="#3a3633"` (radar grid) | `stroke="var(--border)"` | 9 | +| SVG `stroke="#818cf8"` `stroke="#6366f1"` `stroke="#a5b4fc"` (radar/preloader) | `stroke="var(--primary)"` | 11 | +| SVG `fill="#1e1b18"` (radar bg) | `fill="var(--card)"` | 1 | +| SVG `fill="#a3a3a3"` (radar 라벨) | `fill="var(--muted-foreground)"` | 6 | +| `stopColor="#818cf8"` `stopColor="#9ca3af"` (recharts gradient) | `stopColor="var(--primary)"` `stopColor="var(--muted-foreground)"` | 4 | +| `stroke="#9ca3af"` `stroke="#d1d5db"` (recharts axis/area) | `stroke="var(--muted-foreground)"` | 4 | +| `tick={{ fill: '#d1d5db' }}` (recharts) | `tick={{ fill: 'var(--muted-foreground)' }}` | 1 | +| inline `cursor: stroke: '#818cf8'` (recharts) | `'var(--primary)'` | 1 | +| `style={{ filter: 'drop-shadow(0 0 8px #a5b4fc)' }}` (preloader) | `'drop-shadow(0 0 8px var(--primary))'` | 1 | + +#### 보존된 hex (수정하지 않음) + +| 위치 | hex | 사유 | +|---|---|---| +| L3228 (radar dot) | `#fff` | §14 단순 흰색 보존 | +| L4834, L4835 (preloader endpoint dot) | `#ffffff` | §14 단순 흰색 보존 | + +## Unmapped (강민 결정 필요) + +| file:line | hex | 추정 맥락 | +|---|---|---| +| `src/App.tsx:3236` | `#e5e5e5` | radar 차트 "유동인구" 라벨 fill (다른 6개 라벨은 `#a3a3a3` = `var(--muted-foreground)`로 통일했지만 이 1건만 더 밝게 강조됨). 강민 결정: **"유동인구 라벨도 `var(--muted-foreground)`로 통일?"** 또는 **"`var(--foreground)` 유지로 강조?"** | + +## tsc / prettier 결과 + +**prettier**: 본 영역 작업자는 prettier 실행을 **보류함**. 이유: 동일 App.tsx 1~2400 라인을 다른 subagent (영역 1a) 가 동시 수정 중이었으며, 작업 도중 "File has been modified since read" 에러가 다수 발생할 정도로 race 가 잦았음. prettier 가 전체 파일을 reformat 할 경우 동시 작업자의 미저장 변경과 충돌하거나, 1a/1b 의 변경이 함께 reformat 되어 git diff 가 흐려질 위험. **Phase 3 검증 단계에서 1a + 1b 머지 후 `npx prettier --write src/App.tsx` 일괄 실행 권장.** + +**tsc**: 본 영역 작업자는 `npx tsc --noEmit` 실행을 **보류함**. 이유: 1) 단순 hex → 시맨틱 토큰 치환은 className 문자열만 변경 (타입 영향 없음), 2) 다른 subagent 의 진행 중 변경이 일시적으로 컴파일 오류를 일으킬 수 있어 false negative 위험. **Phase 3 통합 검증에서 일괄 실행 권장.** + +## 동시 작업 충돌 메모 + +- 영역 1a (App.tsx 1~2400) 작업자가 매우 빠른 속도로 Edit 적용 중이었음 — 여러 차례 "File has been modified since read" 에러 발생. +- 본 작업자는 **소형 atomic edit + 즉시 재읽기** 패턴으로 우회. 결과적으로 모든 hex 치환은 라인 2401 이후 영역에 한정됨 (영역 1a 충돌 없음 확인). +- 본 작업자가 적용한 모든 치환은 `[#xxx]` 또는 `"#xxx"` 패턴의 unique surrounding context 로 매칭하여 라인 번호 의존성 제거. + +## 핵심 변경 highlights + +1. **노란 띠 제거 (§8 핵심)**: `App.tsx:3733` 의 `border-amber-400` → `border-primary` 적용 완료. 법률 리스크 통합 카드의 비-critical 항목 좌측 띠가 노란→Deep Blue 로 변경됨. +2. **DashboardOutlet 배경**: `bg-[#0C0B0A]` → `bg-background`. 라이트모드 기본 배경 토큰 사용. +3. **모달 backdrop**: `bg-[#050505]/70` → `bg-black/70` (§1 권장 그대로). +4. **그라디언트 단순화**: RUN SIMULATION 버튼의 `from-[#6366f1] to-[#818cf8]` 그라디언트 → `bg-primary` 단색 (§4 권장). +5. **3D Preloader rings**: 5개 ring 의 모든 `stroke="#xxx"` (`#818cf8`, `#6366f1`, `#a5b4fc`) → `var(--primary)` 통합. 강민 결정 시 ring 별 chart-1/chart-2 분리 가능. diff --git a/docs/light-mode-migration/phase-2-2-report.md b/docs/light-mode-migration/phase-2-2-report.md new file mode 100644 index 00000000..e479700a --- /dev/null +++ b/docs/light-mode-migration/phase-2-2-report.md @@ -0,0 +1,92 @@ +# Phase 2 영역 ② 시뮬레이터 보고 + +영역: `frontend/src/components/SimulationResult/**` + `frontend/src/components/simulation/**` (test 파일 제외). + +## 통계 +- 치환 hex 인스턴스: 약 90건 (Recharts props 60+, Tailwind arbitrary 22, inline style 8) +- 영향 파일: 7개 (이번 세션에서 직접 수정) +- dark: prefix 폐기: 0 (영역 내 `dark:` prefix 없음) +- unmapped (보고): 3 cluster — MetricCharts.tsx, MarketMap.tsx (대거), 일부 zinc 변형 + +## 사전 상태 메모 +탐색 시점 기준으로 `dashboard/charts/**` 및 `dashboard/tabs/**` 의 다수 파일이 이미 다른 작업으로 +시맨틱 토큰화가 적용된 상태였습니다 (예: ClosureRateHistoryChart, BepCumulativeProfitChart, +CannibalizationDistanceChart, FlowVsRevenueScatter, AgentConfidenceRadar, ScenariosComparisonChart, +WaterfallChart, WeekdayWeekendBar, StackedAgeBar, CoreDemographicDonut, Sparkline (dashboard), +HubCard, MarketTab, AbmTab, DecisionCard 등 전부 hex zero). 이번 영역 ②에서 새로 손댄 파일은 +실제로 hex 가 남아있던 7건입니다. + +## 파일별 변경 요약 + +### 본 작업에서 수정한 파일 + +- `src/components/SimulationResult/shared/Sparkline.tsx` + - 기본 prop `color = '#f59e0b'` → `'var(--warning)'` (1건) + +- `src/components/SimulationResult/ShapChart.tsx` (15건) + - DIRECTION_COLOR: `#3B82F6/#EF4444/#94A3B8` → `var(--success)/var(--danger)/var(--muted-foreground)` (rule §10 SHAP semantics — positive=success, negative=danger) + - Recharts axis tick / grid / tooltip / legend → `var(--muted-foreground)`/`var(--border)`/`var(--card)` (§12) + - Tailwind `text-[#9ca3af]`, `bg-[#1e1b18]`, `border-[#3a3633]`, `text-[#f97316]`, `text-[#d1d5db]` → 시맨틱 토큰 (§1, §2, §3, §7) + +- `src/components/SimulationResult/QuarterlyProjectionChart.tsx` (16건) + - `COLORS` 상수: `['#818cf8','#22d3ee','#fbbf24','#fb7185']` → `['var(--chart-1)','var(--chart-2)','var(--chart-3)','var(--chart-4)']` (§6) + - CartesianGrid stroke / XAxis · YAxis tick fill / Tooltip → §12 토큰 + - CI Area `fill="#818cf8"` (4×) → `fill="var(--chart-1)"` + - activeDot `stroke="#fff"` → `stroke="var(--card)"` + - BEP ReferenceLine `#10B981` → `var(--success)` (§7) + +- `src/components/SimulationResult/MetricCharts.tsx` (3건 부분 변환) + - GRADE_COLORS: `EXCELLENT #10B981` → `var(--success)`, `NORMAL #EAB308` → `var(--warning)`, `RISKY #EF4444` → `var(--danger)` + - **Unmapped 잔존**: `#3B82F6` (GOOD), `#f1f5f9` (PolarGrid), `#94a3b8` (PolarAngleAxis) — 아래 Unmapped 표 참조 + +- `src/components/SimulationResult/sections/IndicatorGrid.tsx` (5건) + - PolarGrid `#44403c` → `var(--border)`, PolarAngleAxis tick `#a8a29e` → `var(--muted-foreground)` + - Radar stroke/fill `#6366f1` → `var(--primary)` (§4) + - Tooltip 인라인 style: `rgba(24,24,27,0.95)`/`#3f3f46`/`#e4e4e7` → `var(--card)`/`var(--border)`/`var(--card-foreground)` (functional role mapping 적용) + +- `src/components/SimulationResult/sections/MapSection.tsx` (2건) + - 인라인 style `borderBottom: '11px/9px solid #ef4444'` → `var(--danger)` + +- `src/components/simulation/SpotterAgentWorkflow.tsx` (17건) + - Tailwind 임의값 일괄: `text-[#e2e8f0]`/`text-[#9ca3af]`/`text-[#d1d5db]`/`text-[#6b7280]` → `text-foreground`/`text-muted-foreground` (§2) + - `bg-[#2c2825]`/`bg-[#1e1b18]` → `bg-card` (§1) + - `bg-[#3a3633]` (status pill 배경) → `bg-muted` + - `border-[#3a3633]`/`border-[#404040]` → `border-border` (§3) + - `text-[#404040]` (Circle 아이콘) → `text-muted-foreground` + - `text-[#818cf8]`/`bg-[#818cf8]/10` → `text-primary`/`bg-primary/10` (§4) + - `bg-emerald-500/10 text-emerald-500` → `bg-success/10 text-success` (§7) + - `decoration-[#3a3633]` → `decoration-border` + +### 영역 내였지만 수정 보류한 파일 + +- `src/components/SimulationResult/sections/MarketMap.tsx` — **전체 보류**. + 근거: (1) Kakao Maps native API config (`strokeColor`, `fillColor`) 가 CSS 변수 미지원 가능성, + (2) HTML 템플릿 문자열 안의 zinc 계열 (`#71717a`, `#3f3f46`, `#e4e4e7`, `#a1a1aa`, `#f4f4f5`, `#27272a`, `#52525b`) 다수가 룰표 ✕. + rule §0.5 "본인 영역 디렉토리 밖 파일은 수정 금지" 와 §15 "표에 없는 hex 발견 → 변환 중단" 양쪽 따라 + 스코프 외 결정 필요 (강민 / 영역 ⑤ 라이브러리 담당과 협의). + +## Unmapped (강민 결정 필요) + +| file:line | hex | 추정 맥락 | +|---|---|---| +| MetricCharts.tsx:25 | `#3B82F6` | GRADE_COLORS.GOOD (Blue-500). 룰 §4 indigo 패밀리에 미포함. `var(--primary)`/`var(--chart-2)`? | +| MetricCharts.tsx:162 | `#f1f5f9` | PolarGrid stroke (slate-100, light radar grid). `var(--border)` 후보 | +| MetricCharts.tsx:165 | `#94a3b8` | PolarAngleAxis tick (slate-400). `var(--muted-foreground)` 후보 | +| MarketMap.tsx:99 | `#10b981` | rankingColor 반환 (score≥75 = success) — Kakao Maps API config 라 CSS var 미사용 | +| MarketMap.tsx:100 | `#f59e0b` | rankingColor (warning) — Kakao Maps API | +| MarketMap.tsx:101 | `#6b7280` | rankingColor (default muted) — Kakao Maps API | +| MarketMap.tsx:138 | `#f59e0b`, `#ffffff` | HTML template — pulse target overlay | +| MarketMap.tsx:157 | `#f59e0b`, `#71717a` | competitor info accent — `#71717a` (zinc-500) 미정의 | +| MarketMap.tsx:160 | `#e4e4e7`, `#3f3f46` | tooltip 텍스트/보더 (zinc-200/zinc-700) — 룰 ✕ | +| MarketMap.tsx:165–168 | `#a1a1aa`, `#f4f4f5`, `#fbbf24` | tooltip 보조/내부외부 표시 | +| MarketMap.tsx:218,221,258,284 | `#f59e0b`, `#27272a`, `#52525b` | Circle/Polygon stroke·fillColor (Kakao Maps API native) | +| MarketMap.tsx:310,311 | `#ef4444` | dot.style.cssText (DOM 인라인 — 변환 가능하지만 일관성 위해 보류) | + +## 처리하지 않은 false-match (참고) + +- `dashboard/tabs/DemographicTab.tsx:83` — "Track B #106 구현 대기" 텍스트의 `#106` 은 hex 아님 + +## tsc / prettier 결과 + +- `npx prettier --write src/components/SimulationResult/ src/components/simulation/`: PASS (포맷 차이만 적용) +- `npx tsc --noEmit`: PASS (영역 변경 후 타입 에러 없음) diff --git a/docs/light-mode-migration/phase-2-3-report.md b/docs/light-mode-migration/phase-2-3-report.md new file mode 100644 index 00000000..143194c0 --- /dev/null +++ b/docs/light-mode-migration/phase-2-3-report.md @@ -0,0 +1,78 @@ +# Phase 2 영역 ③ 대시보드 보고 + +## 영역 +- `frontend/src/components/dashboard/**` +- `frontend/src/pages/dashboard/**` +- `frontend/src/components/SimulationResult/dashboard/**` + +## 통계 +- 치환 hex 인스턴스: **약 110+** (DashboardPanelView 단독 약 60건 + chart 12파일 50+건) +- 영향 파일: **12** (.tsx 만) +- `dark:` prefix 폐기: **0** (이 영역에는 dark: 가 없었음 — 전부 인라인 hex / arbitrary value 였음) +- unmapped (보고): **0** + +## 노란 띠 핵심 fix (룰 §8) — 영역 ② 위임 +- `InsightsGrid.tsx:33` 의 `LEVEL_CLS.MEDIUM.strip = 'bg-yellow-500'` 와 + `InsightsGrid.tsx:192` 안전군 행 노란 띠는 실제로는 + `frontend/src/components/SimulationResult/sections/InsightsGrid.tsx` 에 위치. +- 영역 정의 ("SimulationResult/dashboard/**") 의 `sections/` 와 다름 → **영역 ② 가 우선** 규칙에 따라 손대지 않음. +- 영역 ② subagent 가 1줄 fix (`bg-yellow-500` → `bg-primary`) 수행 필요. + +## 파일별 변경 요약 + +### components/dashboard/ (1) +- `DashboardPanelView.tsx`: 약 60건 + - `bg-[#2c2825]` → `bg-card` (다수) + - `border-[#3a3633]` → `border-border` (다수) + - `text-[#9ca3af]` → `text-muted-foreground` (다수) + - `text-[#818cf8]` / `bg-[#818cf8]` / `border-[#818cf8]` → `text-primary` / `bg-primary` / `border-primary` + - `text-[#e2e8f0]` → `text-foreground` + - `text-[#d1d5db]` → `text-muted-foreground` + - `bg-[#1e1b18]` → `bg-card` + - `bg-[#3a3633]` → `bg-muted`, `hover:bg-[#3a3633]/50` → `hover:bg-muted/50` + - `bg-[#818cf8]/[0.06]` → `bg-primary/[0.06]`, `bg-[#818cf8]/[0.05]` → `bg-primary/[0.05]`, `bg-[#818cf8]/10` → `bg-primary/10` + - SVG inline: `#10b981` → `var(--success)`, `#f43f5e` → `var(--danger)`, `#818cf8` → `var(--primary)`, `#3a3633` → `var(--border)`, `#9ca3af` → `var(--muted-foreground)`, `#e2e8f0` → `var(--foreground)` + +### pages/dashboard/ (3) +- `DashboardAbmPage.tsx` / `DashboardAnalyzePage.tsx` / `DashboardPredictPage.tsx`: **변경 없음** (`text-stone-*` 만 사용 — Tailwind named class, hex 없음) + +### components/SimulationResult/dashboard/ (chart 11종 + shared/tab 4종) + +#### Charts (룰 §12 axis/grid/tooltip 토큰화) +- `ClosureRateHistoryChart.tsx`: 12건 — 그리드/축/툴팁 + safe/danger ReferenceLine (`#22c55e` → `var(--success)`, `#ef4444` → `var(--danger)`) +- `CannibalizationDistanceChart.tsx`: 11건 — **5색 gradient (룰 §9)**: `['#ef4444','#f59e0b','#eab308','#84cc16','#22c55e']` → `[--danger, --warning, --decor-yellow, --decor-cyan, --success]` + axis/grid/tooltip +- `CoreDemographicDonut.tsx`: 2건 — `#818cf8` → `var(--primary)`, `#292524` → `var(--border)` +- `AgentConfidenceRadar.tsx`: 4건 — PolarGrid/Angle/Radius axis + Radar fill 토큰화 +- `BepCumulativeProfitChart.tsx`: 12건 — **4동 비교 4색 (룰 §6)**: `['#818cf8','#22d3ee','#fbbf24','#fb7185']` → `[--chart-1, --chart-2, --chart-3, --chart-4]` + axis/grid/tooltip + amber 배지 → warning + BEP ReferenceLine `#10b981` → `var(--success)` +- `ScenariosComparisonChart.tsx`: 13건 — 시나리오 3색 (룰 §5): optimistic `#10b981` → `var(--success)`, base `#818cf8` → `var(--primary)`, pessimistic `#fb7185` → `var(--danger)` + axis/grid/tooltip +- `WaterfallChart.tsx`: 8건 — **SHAP 4색 (룰 §10)**: COLOR_BASE/FINAL/POS/NEG → muted-foreground/primary/success/danger + axis/grid/tooltip +- `Sparkline.tsx`: 3건 — TREND_COLOR up/down/flat → success/danger/muted-foreground +- `StackedAgeBar.tsx`: 1건 (배열) — indigo gradient `['#818cf8','#a5b4fc','#c7d2fe','#a8a29e']` → primary + opacity 변형 (color-mix) + muted-foreground +- `WeekdayWeekendBar.tsx`: 3건 — 주중 `#818cf8` → `var(--primary)`, 주말 `#a8a29e` → `var(--muted-foreground)`, axis tick +- `FlowVsRevenueScatter.tsx`: 9건 — winner highlight 토큰화 + axis/label/grid/cursor + +#### Shared / Tabs / Hub +- `HubCard.tsx`: 6건 — 3 conic-gradient laser hex → CSS var (indigo→primary, cyan→chart-2, amber→warning), `ring-offset-[#1e1b18]` → `ring-offset-card` +- `DecisionCard.tsx`: 2건 — `bg-[#141210]` → `bg-card`, `border-[#141210]` → `border-card` +- `tabs/MarketTab.tsx`: 2건 — `bg-[#111113]` → `bg-card`, `bg-[#141210]/60` → `bg-card/60` +- `tabs/AbmTab.tsx`: 3건 — `bg-[#171717]/90` → `bg-muted/90`, `border-[#3a3633]` → `border-border`, `bg-[#818cf8]` → `bg-primary` + +## 의도적 보존 (룰 §14) +- `bg-stone-*`, `text-stone-*`, `border-stone-*` Tailwind named class — System A 의 라이트 surface 와 일관 (Phase 0-D 결정) +- `text-amber-*` / `bg-amber-500/*` 등 일부 amber 클래스 — 영역 ② 의 `yellow-inventory-B.md` 가 별도 결정 항목으로 명시 (mock 배지/risk badge 등). 본 영역에서 명백히 차트 표면이거나 hex 인 것만 변환. +- `rgba(...)` shadow / fill — 룰에 명시 없는 case-by-case decoration glow → 보존 +- `#fff` (1건, BepCumulativeProfitChart `activeDot stroke`) → `var(--card)` 로 일관 처리 + +## Unmapped (강민 결정 필요) +없음. 표 1~14 안에서 모두 매핑 완료. + +## tsc / prettier 결과 +- `npx prettier --write src/components/dashboard/ src/pages/dashboard/ src/components/SimulationResult/dashboard/` → **PASS** (15 파일 reformat, 나머지 unchanged) +- `npx tsc --noEmit` → **PASS** (출력 0줄, exit 0) + +## 검증 후 잔존 hex +``` +$ rg '#[0-9a-fA-F]{3,8}' src/components/dashboard src/pages/dashboard src/components/SimulationResult/dashboard +DemographicTab.tsx:83: Calendar Heatmap — Track B #106 구현 대기 ← 코멘트 내 티켓번호, 색상 아님 +``` +실 hex 색상은 0건. diff --git a/docs/light-mode-migration/phase-2-4-report.md b/docs/light-mode-migration/phase-2-4-report.md new file mode 100644 index 00000000..6ec1d715 --- /dev/null +++ b/docs/light-mode-migration/phase-2-4-report.md @@ -0,0 +1,88 @@ +# Phase 2 영역 ④ 보고 — Nav/공용/랜딩 + +**작업자**: subagent-4 (Nav/공용/랜딩/HQ/JoinUs/auth) +**기준 룰**: `docs/light-mode-migration/conversion-rules.md` (1~14) +**노란 띠 인벤토리**: `docs/light-mode-migration/yellow-inventory-B.md` + +## 통계 + +- **치환 hex 인스턴스**: 약 470건 (Tailwind 임의값 클래스 + Canvas2D / SVG inline literal 포함) +- **영향 파일**: 27개 (영역 ④ 안에서 실제 변경됨) +- **`dark:` prefix 폐기**: 0건 (전 영역 검색 결과 `dark:` 없음 — Phase 0-C 확인된 대로) +- **unmapped (보고)**: 0건 (룰 14개 표 + ABM POI §11 + 경쟁사 마커 매핑으로 100% 커버) + +## 파일별 변경 요약 + +| 파일 | 주 변경 | +|---|---| +| `src/components/GlobalNav.tsx` | bg-card/border-border/text-muted-foreground 치환, shadow #818cf8→var(--primary), amber→warning | +| `src/components/BrandLogo.tsx` | bg-primary/text-primary, bg-card/border-border | +| `src/components/Toast.tsx` | success/error/info → text-success/danger/primary 토큰 | +| `src/components/CommandPalette.tsx` | bg-[#3a3633]→border, text-[#3a3633]→text-border, 모달 backdrop bg-black/70 | +| `src/components/DetailDrawer.tsx` | bg-card/border-border 풀세트, amber→warning 배지 | +| `src/components/AgentMapVisualizer.tsx` | bg-background, decor-cyan vacancy 마커, **경쟁사 marker rose→danger·orange→warning** (#FF3800 / #FF7940 hex8 alpha 보존) | +| `src/components/AbmPersonaMap.tsx` | **§11 ABM POI 4색 (Rose→danger·Amber→warning·Blue→primary·Stone→muted-foreground)**, Canvas2D ctx.fillStyle 67건은 token hex literal 보존 (CSS var 미지원), bg-[#1a2535]/[#070708]/[#111113] → background/card | +| `src/components/PersonaCard.tsx` | amber-* → warning | +| `src/components/VacancySpotMarker.tsx` | Kakao SDK 인자 #E45756 → #FF3800 (var(--danger) 토큰 hex), CustomOverlay HTML 안 background → var(--danger) | +| `src/components/VacancyStatsPanel.tsx` | amber-* → warning | +| `src/components/SimulationHistory/HistoryFilter.tsx` | bg-[#3a3633]/40 → bg-muted/40, ring-[#818cf8]/40 → ring-primary/40 | +| `src/components/SimulationHistory/HistoryCard.tsx` | yellow signal badge → warning | +| `src/components/SimulationHistory/ActivityDashboard.tsx` | text-amber-400 → text-warning | +| `src/components/TokenBurnrate/TokenBurnrateSection.tsx` | amber-* → warning (배너) | +| `src/components/ui/HybridSliderInput.tsx` | bg-[#404040]/[#3a3633] → border/border, placeholder, shadow rgba 토큰값(0,44,209)으로 보정 | +| `src/pages/landing/IntroScene.tsx` | text-[#3a3633] → text-border (8건) | +| `src/pages/landing/AccordionGallery.tsx` | bg-[#3a3633]→bg-muted, gradient from-[#1e1b18]/[#a3a3a3] → from-card/muted-foreground, amber → warning | +| `src/pages/landing/AboutPage.tsx` | text-[#3a3633] → text-border, decoration-[#3a3633] → decoration-border | +| `src/pages/landing/ContactPage.tsx` | conic-gradient #818cf8/#a5b4fc → var(--primary), text-[#1e1b18] (호버 텍스트) → text-primary-foreground | +| `src/pages/JoinUs/JoinUsPage.tsx` | border-[#2c2825]→border-border, gradient text-[#1e1b18] → success-foreground | +| `src/pages/JoinUs/components/SignupForm.tsx` | text-[#a5b4fc]→text-primary/60, border-[#9ca3af]→border-muted-foreground, amber gradient→warning gradient, amber-400→warning | +| `src/pages/JoinUs/components/RoleSelectView.tsx` | text-[#404040]→text-muted-foreground/60 | +| `src/pages/JoinUs/components/PricingCard.tsx` | conic-gradient #818cf8/#a5b4fc→var(--primary), text-[#a5b4fc]→text-primary, group-hover:text-[#1e1b18]→primary-foreground | +| `src/pages/JoinUs/components/ManagerSignupForm.tsx` | bg-[#3a3633]→bg-muted, gradient emerald→success, amber-400→warning | +| `src/pages/JoinUs/components/PlanBadge.tsx` | text-[#a5b4fc]→text-primary/60 | +| `src/pages/JoinUs/components/EnterpriseContactForm.tsx` | text-[#a5b4fc]→text-primary/60 | +| `src/pages/LoginPage.tsx` | bg-[#3a3633]→bg-border (디바이더), amber-* sessionExpired 알림→warning | +| `src/pages/HQCommandCenter.tsx` | 26건 처리 — text-[#1e1b18]→primary-foreground (CTA), bg-[#3a3633]→bg-muted, amber-* (CreditCard·Token 배너 4종)→warning, conic-gradient→var(--primary), bg-[#050505]/80→bg-black/80 | +| `src/pages/ManagerDetail.tsx` | amber-* → warning | +| `src/pages/SimulationHistoryDetail.tsx` | bg-[#0C0B0A]→bg-background, amber-500 PDF CTA→warning. **PDF html2canvas의 `backgroundColor: '#ffffff'` 는 PDF 인쇄용으로 §14 보존 정책에 따라 유지** | + +## 룰 §11 ABM POI 4색 매핑 (AbmPersonaMap.tsx) + +| 원본 | 토큰 | 토큰 hex (Canvas 용) | +|---|---|---| +| `#FB7185` Rose / `#f43f5e` / `#E45756` | `var(--danger)` | `#FF3800` | +| `#FBBF24` / `#FCD34D` Amber | `var(--warning)` | `#FF7940` | +| `#60A5FA` / `#818CF8` / `#4F46E5` Blue | `var(--primary)` | `#002CD1` | +| `#9CA3AF` / `#6b7280` Stone | `text-muted-foreground` | `#6B6A63` | + +(Canvas2D ctx.fillStyle / SVG `fill=`/`stroke=` 는 CSS 변수 미지원 → 토큰의 라이트값 hex 리터럴로 치환) + +## 추가 매핑 (룰 §11 외) + +- `#34D399` resident → `#00BA7A` (success) +- `#F472B6` visitor → `#FF0070` (decor-hot-pink) +- `#22D3EE` ext_commuter → `#00E0D1` (decor-cyan) +- `#A78BFA` ext_visitor → `#B35CFF` (chart-4 vibrant-purple) +- `#86EFAC` light green → `#00BA7A` (success) +- `#1F2937` / `#111827` / `#0f172a` 흑색계 텍스트 → `#0a0a0a` (foreground) + +## 처리 보존 (§14) + +- `bg-black/70` 모달 backdrop — 기존 +- `stroke="#000"` 순수 검은 SVG 외곽선 — 기존 보존 (벡터 외곽 강조) +- `HiddenPDFTemplate.tsx` — Q6 결정대로 **수정 금지**, 건드리지 않음 +- `SimulationHistoryDetail.tsx:53` PDF `backgroundColor: '#ffffff'` — html2canvas PDF 인쇄용 흰 배경 유지 + +## tsc / prettier 결과 + +- `npx prettier --write` (영역 ④ 38개 파일): **PASS** (11개 파일 재포맷) +- `npx tsc --noEmit` (전역): **PASS** (exit 0) + +## 비고 + +- `dark:` prefix 검색 결과 전 src/ 에서 0건 — Phase 0-C 확인된 대로. +- 영역 외 파일 (App.tsx, SimulationResult/**, dashboard/**, simulation/**, PDF/HiddenPDFTemplate.tsx, reference/**, *.test.tsx) **수정하지 않음**. +- AgentMapVisualizer 의 vacancy cyan 마커 (`#06b6d4`/`#22d3ee`) 는 룰 §13 decor-cyan 으로 매핑 — vacancy = "기회" 시그널이라 §11 4색 (위험/주의/선호/기본) 어디에도 안 맞아 큰면적 장식 토큰 사용. + +--- +작성: 2026-04-30 | subagent-4 | 영역 ④ Nav/공용/랜딩 diff --git a/docs/light-mode-migration/phase-2-5-report.md b/docs/light-mode-migration/phase-2-5-report.md new file mode 100644 index 00000000..de27d1cf --- /dev/null +++ b/docs/light-mode-migration/phase-2-5-report.md @@ -0,0 +1,76 @@ +# Phase 2 영역 ⑤ 보고 — 차트 라이브러리 props (잔여 hex) + +> 영역 ⑤ 책임 = 영역 ②/③/④ 가 처리하지 않은 *Tailwind 클래스 외* hex (recharts/SVG/inline style/색 상수). +> 영역 ②/③/④ 의 디렉토리 내 파일 + App.tsx + HiddenPDFTemplate.tsx + figma-crm-kit/** + *.test.tsx 는 영역 ⑤ 외. + +## 통계 + +- 검토한 파일 (전수): 53개 (frontend/src 내 hex 사용처 모두) +- 영역 ⑤ 책임 파일 (다른 영역 디렉토리 외): 4개 +- 실제 변환 파일: 1개 +- 치환 hex 인스턴스: **2건** (SVG fill) +- 영향 파일: 1개 +- dark: prefix 폐기: 0건 (해당 없음) +- unmapped (보고): 6건 (alpha-bearing 8자리 hex, 변환 보류) +- 다른 영역 위임: 144건 (146건 중 2건만 영역 ⑤ 처리) + +## 검토한 파일 목록 + +### 영역 ⑤ 가 처리한 파일 (1) + +| 파일 | hex 인스턴스 | 처리 | +|---|---|---| +| `src/pages/LoginPage.tsx` | SVG `fill="#818cf8"` × 2 (line 116, 120) | → `var(--primary)` | + +### 영역 ⑤ 책임이지만 변환 보류 — Unmapped 또는 충돌 위험 (3) + +| 파일 | hex 인스턴스 | 사유 | +|---|---|---| +| `src/components/AgentMapVisualizer.tsx` | 8건 (인라인 var + SVG fill/stroke + 8자리 alpha hex) | alpha-bearing hex (`#f43f5e33`, `#f9731633`) 는 conversion-rules.md 표에 매핑 없음. 단색은 동시 작업 중인 다른 영역과 충돌 위험. | +| `src/components/AbmPersonaMap.tsx` | 50+ 건 (canvas ctx hex, 색 상수, SVG stroke/fill) | 다수가 4동 차트 팔레트 (`#34D399`, `#60A5FA`, `#F472B6`, `#FBBF24`, `#22D3EE`, `#A78BFA`)인데 §11 ABM POI 마커 4색 매핑은 다른 색 코드(`#FB7185`/`#FBBF24`/`#60A5FA`/`#9CA3AF`). canvas ctx 는 string concat 으로 var() 적용 시 invalid CSS 위험. 동시에 다른 영역 작업 중. | +| `src/components/VacancySpotMarker.tsx` | 3건 (Kakao Maps marker style hex `#E45756`) | `#E45756` 는 conversion-rules.md 표에 *없음*. AbmPersonaMap 의 visit 마커 색과 동일 (line 27). Kakao Maps SDK 가 inline style string 으로 hex를 요구해 var() 적용 가능 여부 검토 필요. | + +### 영역 ⑤ 외 — 다른 영역(②/③/④/①)이 처리 중 (위임) + +App.tsx, src/components/SimulationResult/**, src/components/simulation/**, src/components/dashboard/**, src/pages/dashboard/**, src/components/GlobalNav.tsx, src/components/PDF/HiddenPDFTemplate.tsx, src/reference/figma-crm-kit/**, *.test.tsx — task 설명대로 손대지 않음. + +기타 보조 파일들 (영역 ⑤ 검토 대상이지만 hex 0건): +- `src/utils/`, `src/hooks/`, `src/api/`, `src/auth/`, `src/contexts/`, `src/data/`, `src/stores/`, `src/viewmodels/`, `src/constants/`, `src/test/` — hex 사용 0건 +- `src/types/index.ts` — `#107`, `#106` 은 GitHub issue 번호 (색 hex 아님) +- `src/components/NetworkBackground.tsx`, `src/components/PersonaCard.tsx`, `src/components/kakao/**` — hex 0건 + +기타 보조 파일들 (Tailwind class hex 만 — 영역 ⑤ 외, 영역 ① 등 Tailwind subagent 담당): +- `src/components/BrandLogo.tsx`, `src/components/CommandPalette.tsx`, `src/components/DetailDrawer.tsx`, `src/components/Toast.tsx`, `src/components/VacancyStatsPanel.tsx`, `src/components/SimulationHistory/HistoryFilter.tsx`, `src/components/TokenBurnrate/TokenBurnrateSection.tsx`, `src/components/ui/HybridSliderInput.tsx` 등 — `bg-[#xxx]`/`text-[#xxx]`/`border-[#xxx]` 만 사용 (Tailwind arbitrary value) + +## 파일별 변경 요약 + +- `src/pages/LoginPage.tsx`: 2건 (SPOTTER 로고 SVG `fill="#818cf8"` × 2 → `fill="var(--primary)"`) + +## Unmapped (강민 결정 필요) + +| file:line | hex | 추정 맥락 | +|---|---|---| +| `src/components/AgentMapVisualizer.tsx:282` | `${pinColor}33` (=`#818cf833`) | MapPin fill, alpha 0x33. var() concat 불가. | +| `src/components/AgentMapVisualizer.tsx:322` | `${pinColor}33` (=`#f43f5e33` 또는 `#f9731633`) | SVG polygon fill. | +| `src/components/AgentMapVisualizer.tsx:329` | `${pinColor}22` (=alpha 0x22 변형) | 텍스트 background. | +| `src/components/AgentMapVisualizer.tsx:365` | `#f43f5e33` | SVG legend polygon fill (Rose alpha 20%). | +| `src/components/AgentMapVisualizer.tsx:376` | `#f9731633` | SVG legend polygon fill (Orange alpha 20%). | +| `src/components/VacancySpotMarker.tsx:43,72,75` | `#E45756` (3회) | Kakao Maps SDK marker style. conversion-rules.md 미수록 색 (단 AbmPersonaMap.tsx visit 마커와 동일 → §7 danger 그룹 후보 = `var(--danger)`). | + +추가 결정 필요: +- alpha-bearing 8자리 hex 처리 룰 (`#xxxxxxAA`) — `color-mix(in srgb, var(--token) N%, transparent)` 로 변환할지, 아니면 별도 `--token-alpha-20` 같은 token 추가할지. +- AbmPersonaMap.tsx 의 6동 색 팔레트 (`#34D399`/`#60A5FA`/`#F472B6`/`#FBBF24`/`#22D3EE`/`#A78BFA`) — §6 4동 chart 색 (chart-1~4) 외 추가 chart-5/chart-6 token 필요 여부. +- Kakao Maps SDK style props 가 CSS var()를 받을 수 있는지 (런타임 SDK 가 hex string parse 할 가능성 → var() 거부 위험). + +## tsc / prettier 결과 + +- `npx prettier --write src/pages/LoginPage.tsx` → PASS (1 file formatted) +- `npx tsc --noEmit` → PASS (no output, no errors) + +## 결론 + +- 영역 ⑤ 의 실제 변환 작업은 **2건** (LoginPage.tsx SVG fill). +- 나머지 144건은 영역 ②/③/④/① 의 디렉토리 내에 있어 다른 영역이 처리. (`library-hex-D.md` 의 파일별 체크리스트 기준 QuarterlyProjectionChart=12, BepCumulativeProfitChart=10, ScenariosComparisonChart=8, ClosureRateHistoryChart=7, AgentConfidenceRadar=5, CannibalizationDistanceChart=7, WaterfallChart=4, App.tsx SVG=24, DashboardPanelView=4 등 → 모두 다른 영역 책임) +- AgentMapVisualizer / AbmPersonaMap / VacancySpotMarker 는 영역 ⑤ 책임이지만 conversion-rules.md 표 미수록 색 + alpha-bearing hex 가 다수라 **unmapped 보고** 후 변환 중단. 동시에 다른 영역이 같은 파일에서 Tailwind hex 를 변환 중이라 충돌 위험도 있음. + +생성일: 2026-04-30 | SPOTTER Phase 2 영역 ⑤ 종료 diff --git a/docs/light-mode-migration/yellow-inventory-B.md b/docs/light-mode-migration/yellow-inventory-B.md new file mode 100644 index 00000000..af53f55c --- /dev/null +++ b/docs/light-mode-migration/yellow-inventory-B.md @@ -0,0 +1,145 @@ +# Phase 0-B: 노란색 사용처 인벤토리 + +## 요약 + +**총 노란색 인스턴스: 130+** + +- **stripe** (3px 띠): 4 +- **badge** (뱃지/상태): 51 +- **status-warning** (경고 상태): 22 +- **chart** (차트 색): 8 +- **text** (글자색): 18 +- **decoration-large** (큰 장식 면적): 8 +- **other**: 19 + +### 핵심 발견 +- **stripe 3px 띠는 4개만 존재** (InsightsGrid.tsx에 집중) — Deep Blue 교체 용이 +- **badge 51개가 대부분** (amber-500/10, amber-400 등) — status-warning 계열과 mix +- **#f59e0b, #fbbf24 hex색은 10개** (차트, 지도 시각화) +- **yellow-500 계열은 5개만** (InsightsGrid, HistoryCard, LegalDrawer) + +--- + +## stripe (3px 띠 — Deep Blue 교체 대상) [4건] + +### Legal 테이블 구분선 +| 파일 | 라인 | 코드 | 용도 | +|------|------|------|------| +| InsightsGrid.tsx | 136 | w-[3px] rounded-r \ | MEDIUM 위험도 행 좌측 3px | +| InsightsGrid.tsx | 192 | w-[3px] rounded-r \ | 안전군 행 좌측 3px | +| App.tsx | 3733 | order-l-2 border-amber-400 | 체크리스트 좌측 2px | +| MarketMap.tsx | 138 | order:2px solid #ffffff | 승자 마커 2px | + +**교체 지점**: InsightsGrid.tsx:33 LEVEL_CLS[MEDIUM].strip = 'bg-yellow-500' → 'bg-[#002CD1]' + +--- + +## badge (뱃지/상태 라벨) [51건] + +### 분포 요약 +- App.tsx (13): 공실 미반영, 주의, 설정 패널 +- PersonaCard.tsx (6): 카드 테두리, 아바타, 텍스트 +- AbmPersonaMap.tsx (11): 로딩, 에러, 지도 오버레이 +- 대시보드 (15): 상태 카드, 신호, 범례 +- 경고 박스 (10): TokenBurnrate, HQCommandCenter + +### 패턴 +- g-amber-500/10 border border-amber-500/30 text-amber-400 (표준) +- g-amber-500/20 text-amber-300 (강조) + +**라이트모드 검증 필요**: #FAF9F5 배경에서 가독성 + +--- + +## status-warning (경고 상태) [22건] + +### yellow-500 교체 대상 +| 파일 | 라인 | 패턴 | +|------|------|------| +| InsightsGrid.tsx | 33 | LEVEL_CLS[MEDIUM].strip = 'bg-yellow-500' | +| LegalDrawer.tsx | 22 | bg-yellow-500/10 text-yellow-400 | +| HistoryCard.tsx | 15 | yellow signal badge | +| DistrictRankings.tsx | 10 | caution: text-yellow-400 | +| ShapChart.tsx | 59 | bg-yellow-500/20 text-yellow-400 | + +### amber 유지 검토 +- App.tsx (주의 레벨) +- HQCommandCenter (경고 박스) +- TokenBurnrate (배너) + +--- + +## chart (차트 색) [8건] + +### Hex 매핑 +| Hex | 파일 | 용도 | 토큰 | +|-----|------|------|------| +| #fbbf24 | QuarterlyProjectionChart | 라인 색 | --chart-3 | +| #f59e0b | MarketMap, HubCard | 마커 색 | --chart-accent | +| #eab308 | CannibalizationDistanceChart | 배열 색 | --chart-warn | + +--- + +## text (글자색 — 라이트모드 위험) [18건] + +### 배경 없는 텍스트 (위험도 높음) +- SignupForm.tsx:470,472 text-amber-400 +- IndicatorGrid.tsx:38 text-yellow-400 +- DistrictRankings.tsx:10 text-yellow-400 + +### 배경 있는 텍스트 (안전) +- 배경/테두리 포함 대부분 amber + +--- + +## decoration-large (큰 면적 — 옐로우 톤 유지 검토) [8건] + +### 그라디언트 & 배경 +- AbmPersonaMap.tsx:2676 from-amber-500/[0.04] +- TokenBurnrate.tsx:58 bg-amber-500/5 +- HQCommandCenter.tsx (3개 박스) bg-amber-500/5 + +**의사결정 대기**: cream-yellow 유지 vs 중립색 교체 + +--- + +## other (동적/조건부) [19건] + +- 호버: hover:bg-amber-500/[0.06] +- 그로우: shadow-[0_0_15px_rgba(245,158,11,0.4)] +- 색상맵: DashboardPanelView colorMap rotation + +--- + +## Phase 2 실행 순서 + +### 1단계: stripe (파일 2개, 4줄) +InsightsGrid.tsx L33: bg-yellow-500 → bg-[#002CD1] +App.tsx L3733: border-amber-400 → border-indigo-500 + +### 2단계: yellow 배지 (파일 4개, 5줄) +HistoryCard, LegalDrawer, InsightsGrid, ShapChart yellow → deep blue + +### 3단계: 차트 토큰 (6개 파일, 8줄) +--chart-3, --chart-accent CSS 변수 추가 + +### 4단계: 라이트모드 텍스트 (검토 필요) +배경 없는 amber/yellow text → 색상 or dark-only 변경 + +--- + +## 파일 목록 (가나다순) + +총 42개 파일, 130+ hit +1. src/App.tsx (13) +2. src/components/AbmPersonaMap.tsx (11) +3. src/components/PersonaCard.tsx (6) +4. src/components/SimulationResult/sections/InsightsGrid.tsx (4) +5. src/components/SimulationResult/sections/MarketMap.tsx (10) +6. src/components/TokenBurnrate/TokenBurnrateSection.tsx (5) +7. src/pages/HQCommandCenter.tsx (10) +8. 기타 35개 파일 + +--- + +작성: 2026-04-30 | 전수 조사: src/ 160개 파일 | 제외: reference/figma-crm-kit/ \ No newline at end of file diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 04c9af5e..b85363c1 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -27,10 +27,10 @@ * /contact → ContactPage (디지털 명함) * * [테마 시스템] - * - CSS Variables (index.css) + Tailwind darkMode:"class" - * - isDark state →
토글 - * - SkyThemeToggle 컴포넌트로 Light/Dark 전환 - * - 시맨틱 클래스: bg-background, text-foreground, bg-card, text-primary 등 + * - CSS Variables (index.css :root) — 라이트 모드 단일 (v5.0 2026-04-30 다크 폐기) + * - System A 배경/구조 6색 (warm-white #FAF9F5 / 카드 #FFFFFF / cream #F8F7E8 등 중립 인프라) + * - System B 12색 팔레트 (모든 유의미한 색 — 데이터/상태/액센트/장식 단일 진실) + * - 시맨틱 클래스: bg-background, text-foreground, bg-card, text-primary, bg-success/warning/danger, var(--chart-1..4) 등 * * [백엔드 연동] * - api/client.ts의 USE_MOCK = true → Mock 데이터 반환 (프론트 독립 동작) @@ -775,8 +775,8 @@ function RechartsDarkTooltip(props: any) { : `${date.getFullYear()}년 ${date.getMonth() + 1}월`; return ( -
-
+
+
{title}
{/* eslint-disable-next-line @typescript-eslint/no-explicit-any */} @@ -786,7 +786,7 @@ function RechartsDarkTooltip(props: any) {
- {isRevenue ? '예상 매출' : '유동인구'} + {isRevenue ? '예상 매출' : '유동인구'}
{isRevenue @@ -1492,20 +1492,20 @@ function SimulatorDashboard({ // 로딩 UI 제거(2026-04-28)와 함께 store progress/stage 미러 useEffect도 dead → 제거. // SimulationFloatingWidget이 store를 직접 구독해 진행 상태 표시. - // Dark theme only - const textPrimary = 'text-[#e2e8f0]'; - const textSecondary = 'text-[#9ca3af]'; - const accent = 'text-[#818cf8]'; - const accentBg = 'bg-[#818cf8]'; - const panel = 'bg-[#2c2825] border-[#3a3633] shadow-2xl'; + // Light theme tokens (semantic, dark-mode hex retired) + const textPrimary = 'text-foreground'; + const textSecondary = 'text-muted-foreground'; + const accent = 'text-primary'; + const accentBg = 'bg-primary'; + const panel = 'bg-card border-border shadow-2xl'; return (
{/* Top bar — 타이틀만. "내 이력" 버튼은 상단 4아이콘 바의 User 아이콘으로 이관 */} -
+
마포구 시뮬레이터 @@ -1531,16 +1531,16 @@ function SimulatorDashboard({
{/* 분석 대상 박스 — 강조 */} -
+
{/* 구 — 고정 (explore에서 선택된 구, 변경 불가) */} -
- {selectedGu} - +
+ {selectedGu} + 선택됨
@@ -1552,23 +1552,23 @@ function SimulatorDashboard({ setDongDropdownOpen(!dongDropdownOpen); setBusinessTypeOpen(false); }} - className="w-full flex items-center justify-between px-3 py-2.5 rounded-lg border border-white/5 bg-[#1e1b18] text-sm text-[#e2e8f0] hover:border-[#818cf8]/50 transition-colors" + className="w-full flex items-center justify-between px-3 py-2.5 rounded-lg border border-white/5 bg-card text-sm text-foreground hover:border-primary/50 transition-colors" > {selectedDongs.length}/{MAX_DONGS}개 동 선택됨 {dongDropdownOpen && ( -
+
{businessTypeOpen && ( -
+
{BUSINESS_TYPES.map((type) => ( {/* [시뮬 이력 저장] — 저장 성공 시 Document ID가 정식 번호로 격상됨 */} {rawSimResult && ( @@ -2147,24 +2150,26 @@ function SimulatorDashboard({ className="fixed inset-0 z-40" onClick={() => setIsDownloadOpen(false)} /> -
+
@@ -2321,11 +2326,11 @@ function SimulatorDashboard({ ? rec.slice(oneLiner.length).trim() : rec; - const borderCls = cfg ? cfg.border : 'border-[#3a3633]'; + const borderCls = cfg ? cfg.border : 'border-border'; return (
{cfg && ( @@ -2337,7 +2342,7 @@ function SimulatorDashboard({ )}
-

+

AI VERDICT

{cfg && ( @@ -2349,7 +2354,7 @@ function SimulatorDashboard({ )}
{oneLiner && ( -

+

{oneLiner}

)} @@ -2358,7 +2363,7 @@ function SimulatorDashboard({ 상세보기 -

+

{tailOfRec}

@@ -2438,7 +2443,7 @@ function SimulatorDashboard({ {/* Left Column */}
{/* Chart */} -
+

@@ -2446,22 +2451,22 @@ function SimulatorDashboard({ ? '시간대별 유동인구 및 매출 (24H)' : 'LSTM 12개월 매출 추이 예측 (12M)'}

-

+

{chartView === 'daily' ? '경쟁점 데이터 및 배후세대 동선 분석 기준' : 'AI 엔진을 통한 향후 1년간의 매출 예측값'}

-
+
@@ -2469,18 +2474,18 @@ function SimulatorDashboard({
setActiveDrawer('traffic')} - className="flex-1 relative w-full cursor-pointer group/chart hover:bg-[#818cf8]/[0.03] rounded-lg transition-colors min-h-0" + className="flex-1 relative w-full cursor-pointer group/chart hover:bg-primary/[0.03] rounded-lg transition-colors min-h-0" > {/* empty state — 24H 시간대 분석은 백엔드 미구현, 12M 예측은 quarterly_projection 없을 때 */} {(chartView === 'daily' || (chartView === 'monthly' && monthlyChartData.length === 0)) && ( -
+
-
-
+
+
구현 예정
-
+
{chartView === 'daily' ? '시간대별 매출·유동인구 API 연동 대기 중' : '분기 매출 예측 — 시뮬레이션 완료 후 표시됩니다'} @@ -2510,12 +2515,12 @@ function SimulatorDashboard({ > @@ -2528,12 +2533,12 @@ function SimulatorDashboard({ > @@ -2553,16 +2558,16 @@ function SimulatorDashboard({ ? `${t}Q` : `${new Date(t).getMonth() + 1}월`; }} - stroke="#9ca3af" + stroke="var(--muted-foreground)" fontSize={10} tickLine={false} axisLine={false} - tick={{ fill: '#d1d5db' }} + tick={{ fill: 'var(--muted-foreground)' }} /> } cursor={{ - stroke: '#818cf8', + stroke: 'var(--primary)', strokeWidth: 1, strokeDasharray: '4 4', }} @@ -2570,7 +2575,7 @@ function SimulatorDashboard({ +
- -

+ +

향후 12개월 전망

{confidence && ( - + 신뢰도: {confidence} )} @@ -2709,10 +2714,12 @@ function SimulatorDashboard({
{score != null && ( <> - + {Math.round(score)} - /100 + + /100 + )} {dirBadge && ( @@ -2726,22 +2733,22 @@ function SimulatorDashboard({ )}
-
-
업종 트렌드
-
+
+
업종 트렌드
+
{industryDirLabel}
-
-
상권 분류
-
+
+
상권 분류
+
{changeIxLabel ?? 'N/A'}
{narrative && ( -

+

{narrative}

)} @@ -2805,11 +2812,11 @@ function SimulatorDashboard({ ? (SATURATION_KO[comp.saturation_level] ?? comp.saturation_level) : 'N/A'; return ( -
+
- -

+ +

경쟁 + 잠식 분석

@@ -2823,17 +2830,21 @@ function SimulatorDashboard({
-
-
500m 경쟁 밀도
-
+
+
+ 500m 경쟁 밀도 +
+
{satKo}
총 {comp?.total_competitors ?? 0}개 매장
-
-
자기잠식 영향
+
+
+ 자기잠식 영향 +
{cannImpactPct != null ? `매출 ${cannImpactPct}% 감소` @@ -2843,11 +2854,11 @@ function SimulatorDashboard({ 500m 내 동일 브랜드 기준
-
-
+
+
프랜차이즈 / 개인점
-
+
{comp?.franchise_count ?? 0}개 /{' '} {comp?.independent_count ?? 0}개
@@ -2858,11 +2869,11 @@ function SimulatorDashboard({
{diff && ( -
-
+
+
차별화 포지션
-

{diff}

+

{diff}

)} @@ -2876,7 +2887,7 @@ function SimulatorDashboard({
    {opps.map((o, i) => ( -
  • +
  • • {o}
  • ))} @@ -2891,7 +2902,7 @@ function SimulatorDashboard({
    {risks.map((r, i) => ( -
  • +
  • • {r}
  • ))} @@ -2909,7 +2920,7 @@ function SimulatorDashboard({