From f589cb0f94df0c14a04e5259fcc75dd18c2e8f1c Mon Sep 17 00:00:00 2001 From: htlee Date: Wed, 8 Apr 2026 11:23:38 +0900 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=EC=B9=B4=ED=83=88=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=20=EB=B0=B0=EC=A7=80=20=ED=85=8C=EB=A7=88=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=20+=20=EB=8B=A8=EC=86=8D=20=EC=A1=B0=EC=B9=98=20?= =?UTF-8?q?=EA=B0=80=EB=8F=85=EC=84=B1=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 변경: - badgeVariants 8 intent 모두 라이트/다크 팔레트 분리 - 다크: 밝은 솔리드 배경(-400) + slate-900 글자 + 강한 보더(-600) - 라이트: 파스텔 배경(-100) + 진한 글자(-900) + 소프트 보더(-300) - base에서 text-on-bright 제거 (intent별로 관리) - classes 기반 카탈로그 4종에 dark: 변형 추가로 라이트 모드 대응: - eventStatuses: bg-red-100 text-red-800 dark:bg-red-500/20 dark:text-red-400 - enforcementResults: 동일 패턴 (red/purple/yellow/green) - patrolStatuses: border 포함 (7 상태) - enforcementActions: classes 필드 신규 추가 (기존에 없어서 fallback grey로 떨어져 라이트 모드에서 글자 안 보이던 원인) - CatalogSection fallback classes도 dark: 변형 추가 (안전장치) - enforcementActions에 getEnforcementActionClasses() 헬퍼 신규 빌드 검증: - tsc ✅, vite build ✅ - CSS 확인: .dark\:bg-red-400:is(.dark *) 컴파일 정상 --- .../design-system/sections/CatalogSection.tsx | 5 ++- frontend/src/lib/theme/variants.ts | 37 +++++++++++-------- .../shared/constants/enforcementActions.ts | 11 ++++++ .../shared/constants/enforcementResults.ts | 8 ++-- .../src/shared/constants/eventStatuses.ts | 8 ++-- .../src/shared/constants/patrolStatuses.ts | 21 +++++++---- 6 files changed, 58 insertions(+), 32 deletions(-) diff --git a/frontend/src/design-system/sections/CatalogSection.tsx b/frontend/src/design-system/sections/CatalogSection.tsx index b055dfc..7400088 100644 --- a/frontend/src/design-system/sections/CatalogSection.tsx +++ b/frontend/src/design-system/sections/CatalogSection.tsx @@ -70,7 +70,10 @@ function CatalogBadges({ catalog, idPrefix }: { catalog: AnyCatalog; idPrefix: s ) : ( {label} diff --git a/frontend/src/lib/theme/variants.ts b/frontend/src/lib/theme/variants.ts index 447fd17..30a249d 100644 --- a/frontend/src/lib/theme/variants.ts +++ b/frontend/src/lib/theme/variants.ts @@ -19,29 +19,34 @@ export const cardVariants = cva('rounded-xl border border-border', { /** 뱃지 변형 — 위험도/상태별 150회+ 반복 패턴 통합 * - * 가독성 정책: - * - 배경: 색상별 진한 솔리드(-400) — 명확한 분류 식별 - * - 텍스트: 시맨틱 토큰 text-on-bright (theme.css = #0f172a) — 테마 무관 일관 가독성 - * - 보더: 같은 색상 계열 -600 (배경 강조) + * 가독성 정책 (테마별 팔레트 분리): + * - **다크 모드**: 솔리드 밝은 배경(-400) + 진한 글자(slate-900) + 강한 보더(-600) + * → 어두운 페이지에서 밝게 튀어 명확한 분류 식별 + * - **라이트 모드**: 파스텔 배경(-100) + 진한 글자(-900) + 부드러운 보더(-300) + * → 흰 배경에 어울리는 소프트 토큰, 글자와 배경 대비 충분 * - 가운데 정렬 - * - 폰트 크기: rem 기반 (root font-size 대비 비율) — 화면 비율에 따라 자동 조정 + * - 폰트 크기: rem 기반 — 화면 비율 대비 자동 조정 * - * className override는 cn(tailwind-merge) 덕분에 같은 그룹(text-color/font-size/bg) 충돌 시 - * 마지막 명시값이 적용 — !important 없이 의도된 override만 허용. + * className override는 cn(tailwind-merge) 덕분에 같은 그룹 충돌 시 마지막 명시값 적용. */ export const badgeVariants = cva( - 'inline-flex items-center justify-center whitespace-nowrap rounded-md border px-2 py-0.5 font-semibold transition-colors text-center text-on-bright', + 'inline-flex items-center justify-center whitespace-nowrap rounded-md border px-2 py-0.5 font-semibold transition-colors text-center', { variants: { intent: { - critical: 'bg-red-400 border-red-600', - high: 'bg-orange-400 border-orange-600', - warning: 'bg-yellow-400 border-yellow-600', - info: 'bg-blue-400 border-blue-600', - success: 'bg-green-400 border-green-600', - muted: 'bg-slate-400 border-slate-600', - purple: 'bg-purple-400 border-purple-600', - cyan: 'bg-cyan-400 border-cyan-600', + critical: + 'bg-red-100 text-red-900 border-red-300 dark:bg-red-400 dark:text-slate-900 dark:border-red-600', + high: 'bg-orange-100 text-orange-900 border-orange-300 dark:bg-orange-400 dark:text-slate-900 dark:border-orange-600', + warning: + 'bg-yellow-100 text-yellow-900 border-yellow-300 dark:bg-yellow-400 dark:text-slate-900 dark:border-yellow-600', + info: 'bg-blue-100 text-blue-900 border-blue-300 dark:bg-blue-400 dark:text-slate-900 dark:border-blue-600', + success: + 'bg-green-100 text-green-900 border-green-300 dark:bg-green-400 dark:text-slate-900 dark:border-green-600', + muted: + 'bg-slate-100 text-slate-800 border-slate-300 dark:bg-slate-400 dark:text-slate-900 dark:border-slate-600', + purple: + 'bg-purple-100 text-purple-900 border-purple-300 dark:bg-purple-400 dark:text-slate-900 dark:border-purple-600', + cyan: 'bg-cyan-100 text-cyan-900 border-cyan-300 dark:bg-cyan-400 dark:text-slate-900 dark:border-cyan-600', }, // rem 기반 — root font-size 대비 비율, 화면 비율 변경 시 자동 조정 // xs ≈ 11px, sm ≈ 12px, md ≈ 13px, lg ≈ 14px (root 14px 기준) diff --git a/frontend/src/shared/constants/enforcementActions.ts b/frontend/src/shared/constants/enforcementActions.ts index a95b107..e9249af 100644 --- a/frontend/src/shared/constants/enforcementActions.ts +++ b/frontend/src/shared/constants/enforcementActions.ts @@ -19,6 +19,7 @@ export interface EnforcementActionMeta { code: EnforcementAction; i18nKey: string; fallback: { ko: string; en: string }; + classes: string; hex: string; order: number; } @@ -28,6 +29,7 @@ export const ENFORCEMENT_ACTIONS: Record = { code: 'NEW', i18nKey: 'eventStatus.NEW', fallback: { ko: '신규', en: 'New' }, - classes: 'bg-red-500/20 text-red-400', + classes: 'bg-red-100 text-red-800 dark:bg-red-500/20 dark:text-red-400', order: 1, }, ACK: { code: 'ACK', i18nKey: 'eventStatus.ACK', fallback: { ko: '확인', en: 'Acknowledged' }, - classes: 'bg-orange-500/20 text-orange-400', + classes: 'bg-orange-100 text-orange-800 dark:bg-orange-500/20 dark:text-orange-400', order: 2, }, IN_PROGRESS: { code: 'IN_PROGRESS', i18nKey: 'eventStatus.IN_PROGRESS', fallback: { ko: '처리중', en: 'In Progress' }, - classes: 'bg-blue-500/20 text-blue-400', + classes: 'bg-blue-100 text-blue-800 dark:bg-blue-500/20 dark:text-blue-400', order: 3, }, RESOLVED: { code: 'RESOLVED', i18nKey: 'eventStatus.RESOLVED', fallback: { ko: '완료', en: 'Resolved' }, - classes: 'bg-green-500/20 text-green-400', + classes: 'bg-green-100 text-green-800 dark:bg-green-500/20 dark:text-green-400', order: 4, }, FALSE_POSITIVE: { diff --git a/frontend/src/shared/constants/patrolStatuses.ts b/frontend/src/shared/constants/patrolStatuses.ts index a8a314c..721cd9d 100644 --- a/frontend/src/shared/constants/patrolStatuses.ts +++ b/frontend/src/shared/constants/patrolStatuses.ts @@ -29,49 +29,56 @@ export const PATROL_STATUSES: Record = { code: 'IN_PURSUIT', i18nKey: 'patrolStatus.IN_PURSUIT', fallback: { ko: '추적중', en: 'In Pursuit' }, - classes: 'bg-red-500/20 text-red-400 border-red-500/30', + classes: + 'bg-red-100 text-red-800 border-red-300 dark:bg-red-500/20 dark:text-red-400 dark:border-red-500/30', order: 1, }, INSPECTING: { code: 'INSPECTING', i18nKey: 'patrolStatus.INSPECTING', fallback: { ko: '검문중', en: 'Inspecting' }, - classes: 'bg-orange-500/20 text-orange-400 border-orange-500/30', + classes: + 'bg-orange-100 text-orange-800 border-orange-300 dark:bg-orange-500/20 dark:text-orange-400 dark:border-orange-500/30', order: 2, }, ON_PATROL: { code: 'ON_PATROL', i18nKey: 'patrolStatus.ON_PATROL', fallback: { ko: '초계중', en: 'On Patrol' }, - classes: 'bg-blue-500/20 text-blue-400 border-blue-500/30', + classes: + 'bg-blue-100 text-blue-800 border-blue-300 dark:bg-blue-500/20 dark:text-blue-400 dark:border-blue-500/30', order: 3, }, RETURNING: { code: 'RETURNING', i18nKey: 'patrolStatus.RETURNING', fallback: { ko: '귀항중', en: 'Returning' }, - classes: 'bg-purple-500/20 text-purple-400 border-purple-500/30', + classes: + 'bg-purple-100 text-purple-800 border-purple-300 dark:bg-purple-500/20 dark:text-purple-400 dark:border-purple-500/30', order: 4, }, AVAILABLE: { code: 'AVAILABLE', i18nKey: 'patrolStatus.AVAILABLE', fallback: { ko: '가용', en: 'Available' }, - classes: 'bg-green-500/20 text-green-400 border-green-500/30', + classes: + 'bg-green-100 text-green-800 border-green-300 dark:bg-green-500/20 dark:text-green-400 dark:border-green-500/30', order: 5, }, STANDBY: { code: 'STANDBY', i18nKey: 'patrolStatus.STANDBY', fallback: { ko: '대기', en: 'Standby' }, - classes: 'bg-slate-500/20 text-slate-400 border-slate-500/30', + classes: + 'bg-slate-100 text-slate-700 border-slate-300 dark:bg-slate-500/20 dark:text-slate-400 dark:border-slate-500/30', order: 6, }, MAINTENANCE: { code: 'MAINTENANCE', i18nKey: 'patrolStatus.MAINTENANCE', fallback: { ko: '정비중', en: 'Maintenance' }, - classes: 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30', + classes: + 'bg-yellow-100 text-yellow-800 border-yellow-300 dark:bg-yellow-500/20 dark:text-yellow-400 dark:border-yellow-500/30', order: 7, }, };