From d7f8db88ee9a534f383ebfef22bc80c43cab5163 Mon Sep 17 00:00:00 2001 From: htlee Date: Wed, 8 Apr 2026 11:28:02 +0900 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20Badge=20=EB=8B=A4=ED=81=AC=20?= =?UTF-8?q?=ED=8C=94=EB=A0=88=ED=8A=B8=EB=A5=BC=20translucent=EB=A1=9C=20?= =?UTF-8?q?=ED=86=B5=EC=9D=BC=20+=20=EC=87=BC=EC=BC=80=EC=9D=B4=EC=8A=A4?= =?UTF-8?q?=20=ED=95=9C/=EC=98=81=20=EB=B3=91=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - badgeVariants 다크 팔레트를 classes 기반 4종 카탈로그와 동일 패턴으로 통일 - 이전: dark:bg-X-400 dark:text-slate-900 dark:border-X-600 (솔리드) - 이후: dark:bg-X-500/20 dark:text-X-400 dark:border-X-500/30 (translucent) - 라이트 팔레트는 그대로 유지 (이미 통일되어 있음) - CatalogSection: 각 카탈로그 항목을 [code / 한글 배지 / 영문 배지] 3열 행으로 렌더 - 한글/영문 라벨 두 버전을 한눈에 비교 검토 가능 - 추적 ID Trk는 행 전체를 감싸서 호버/복사 동작 --- .../design-system/sections/CatalogSection.tsx | 62 +++++++++++++------ frontend/src/lib/theme/variants.ts | 22 +++---- 2 files changed, 53 insertions(+), 31 deletions(-) diff --git a/frontend/src/design-system/sections/CatalogSection.tsx b/frontend/src/design-system/sections/CatalogSection.tsx index 7400088..9ea946a 100644 --- a/frontend/src/design-system/sections/CatalogSection.tsx +++ b/frontend/src/design-system/sections/CatalogSection.tsx @@ -43,10 +43,14 @@ interface AnyMeta { type AnyCatalog = Record; -function getLabel(meta: AnyMeta): string { +function getKoLabel(meta: AnyMeta): string { return meta.fallback?.ko ?? meta.label ?? meta.code; } +function getEnLabel(meta: AnyMeta): string | undefined { + return meta.fallback?.en; +} + /** classes가 문자열인 경우 그대로, 객체인 경우 bg+text 조합 */ function getFallbackClasses(meta: AnyMeta): string | undefined { if (typeof meta.classes === 'string') return meta.classes; @@ -56,31 +60,49 @@ function getFallbackClasses(meta: AnyMeta): string | undefined { return undefined; } -/** 카탈로그 항목을 Badge 또는 fallback span으로 렌더 */ +/** 단일 배지 렌더 — Badge(intent) 또는 span(classes) */ +function renderBadge(meta: AnyMeta, label: string): ReactNode { + if (meta.intent) { + return ( + + {label} + + ); + } + const classes = + getFallbackClasses(meta) ?? + 'bg-slate-100 text-slate-700 border-slate-300 dark:bg-slate-500/20 dark:text-slate-300 dark:border-slate-500/30'; + return ( + + {label} + + ); +} + +/** 카탈로그 항목을 행 단위로 렌더: [code] [한글 배지] [영문 배지] */ function CatalogBadges({ catalog, idPrefix }: { catalog: AnyCatalog; idPrefix: string }) { const entries = Object.values(catalog); return ( -
+
{entries.map((meta) => { - const label = getLabel(meta); + const koLabel = getKoLabel(meta); + const enLabel = getEnLabel(meta); const trkId = `${idPrefix}-${meta.code}`; - const content: ReactNode = meta.intent ? ( - - {label} - - ) : ( - - {label} - - ); return ( - - {content} + + + {meta.code} + +
{renderBadge(meta, koLabel)}
+
+ {enLabel ? ( + renderBadge(meta, enLabel) + ) : ( + (no en) + )} +
); })} diff --git a/frontend/src/lib/theme/variants.ts b/frontend/src/lib/theme/variants.ts index 30a249d..e382698 100644 --- a/frontend/src/lib/theme/variants.ts +++ b/frontend/src/lib/theme/variants.ts @@ -19,9 +19,9 @@ export const cardVariants = cva('rounded-xl border border-border', { /** 뱃지 변형 — 위험도/상태별 150회+ 반복 패턴 통합 * - * 가독성 정책 (테마별 팔레트 분리): - * - **다크 모드**: 솔리드 밝은 배경(-400) + 진한 글자(slate-900) + 강한 보더(-600) - * → 어두운 페이지에서 밝게 튀어 명확한 분류 식별 + * 가독성 정책 (테마별 팔레트 분리 + classes 기반 카탈로그와 통일): + * - **다크 모드**: 반투명 배경(-500/20) + 밝은 글자(-400) + 반투명 보더(-500/30) + * → 어두운 페이지에서 은은하게 녹아들며 글자 강조 (classes 기반 4종과 동일 패턴) * - **라이트 모드**: 파스텔 배경(-100) + 진한 글자(-900) + 부드러운 보더(-300) * → 흰 배경에 어울리는 소프트 토큰, 글자와 배경 대비 충분 * - 가운데 정렬 @@ -35,18 +35,18 @@ export const badgeVariants = cva( variants: { intent: { 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', + 'bg-red-100 text-red-900 border-red-300 dark:bg-red-500/20 dark:text-red-400 dark:border-red-500/30', + high: 'bg-orange-100 text-orange-900 border-orange-300 dark:bg-orange-500/20 dark:text-orange-400 dark:border-orange-500/30', 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', + 'bg-yellow-100 text-yellow-900 border-yellow-300 dark:bg-yellow-500/20 dark:text-yellow-400 dark:border-yellow-500/30', + info: 'bg-blue-100 text-blue-900 border-blue-300 dark:bg-blue-500/20 dark:text-blue-400 dark:border-blue-500/30', success: - 'bg-green-100 text-green-900 border-green-300 dark:bg-green-400 dark:text-slate-900 dark:border-green-600', + 'bg-green-100 text-green-900 border-green-300 dark:bg-green-500/20 dark:text-green-400 dark:border-green-500/30', muted: - 'bg-slate-100 text-slate-800 border-slate-300 dark:bg-slate-400 dark:text-slate-900 dark:border-slate-600', + 'bg-slate-100 text-slate-700 border-slate-300 dark:bg-slate-500/20 dark:text-slate-300 dark:border-slate-500/30', 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', + 'bg-purple-100 text-purple-900 border-purple-300 dark:bg-purple-500/20 dark:text-purple-400 dark:border-purple-500/30', + cyan: 'bg-cyan-100 text-cyan-900 border-cyan-300 dark:bg-cyan-500/20 dark:text-cyan-400 dark:border-cyan-500/30', }, // rem 기반 — root font-size 대비 비율, 화면 비율 변경 시 자동 조정 // xs ≈ 11px, sm ≈ 12px, md ≈ 13px, lg ≈ 14px (root 14px 기준)