Phase A: 쇼케이스의 카탈로그/variant 정보를 중앙 상수로 끌어올림
- shared/constants/catalogRegistry.ts 신규
- 19+ 카탈로그의 id/showcaseId/titleKo/titleEn/description/source/items를
단일 레지스트리로 통합 관리
- 새 카탈로그 추가 = 레지스트리에 1줄 추가로 쇼케이스 자동 노출
- CATALOG_REGISTRY + getCatalogById()
- lib/theme/variantMeta.ts 신규
- BADGE_INTENT_META: 8 intent의 titleKo/titleEn/description
- BUTTON_VARIANT_META: 5 variant의 titleKo/titleEn/description
- BADGE_INTENT_ORDER/SIZE_ORDER, BUTTON_VARIANT_ORDER/SIZE_ORDER
- 쇼케이스 섹션 리팩토링 — 하드코딩 제거
- CatalogSection: CATALOG_REGISTRY 자동 열거 (CATALOGS 배열 삭제)
- BadgeSection: BADGE_INTENT_META에서 의미 가이드 + titleKo 참조
- ButtonSection: BUTTON_VARIANT_META에서 의미 가이드 + titleKo 참조
효과:
- 카탈로그의 라벨/색상/intent 변경 시 쇼케이스와 실 페이지 동시 반영
- Badge/Button의 variant 의미가 variantMeta 한 곳에서 관리됨
- 쇼케이스 섹션에 분산돼 있던 하드코딩 제거 (INTENT_USAGE, VARIANT_USAGE 등)
다음 단계: 실 페이지를 PageContainer/PageHeader/Button/Input으로 마이그레이션
110 lines
4.1 KiB
TypeScript
110 lines
4.1 KiB
TypeScript
import { TrkSectionHeader, Trk } from '../lib/Trk';
|
||
import { Badge } from '@shared/components/ui/badge';
|
||
import {
|
||
BADGE_INTENT_META,
|
||
BADGE_INTENT_ORDER,
|
||
BADGE_SIZE_ORDER,
|
||
} from '@lib/theme/variantMeta';
|
||
|
||
export function BadgeSection() {
|
||
return (
|
||
<>
|
||
<TrkSectionHeader
|
||
id="TRK-SEC-badge"
|
||
title="Badge"
|
||
description={`${BADGE_INTENT_ORDER.length} intent × ${BADGE_SIZE_ORDER.length} size = ${BADGE_INTENT_ORDER.length * BADGE_SIZE_ORDER.length} 변형. CVA + cn()로 className override 허용, !important 없음.`}
|
||
/>
|
||
|
||
{/* 변형 그리드 */}
|
||
<h3 className="text-sm font-semibold text-heading mb-2 mt-2">변형 매트릭스</h3>
|
||
<Trk id="TRK-BADGE-matrix" className="ds-sample">
|
||
<div className="overflow-x-auto">
|
||
<table className="w-full border-collapse">
|
||
<thead>
|
||
<tr>
|
||
<th className="text-left text-[10px] text-hint font-mono pb-2 pr-3">
|
||
intent ↓ / size →
|
||
</th>
|
||
{BADGE_SIZE_ORDER.map((size) => (
|
||
<th key={size} className="text-left text-[10px] text-hint font-mono pb-2 px-2">
|
||
{size}
|
||
</th>
|
||
))}
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{BADGE_INTENT_ORDER.map((intent) => (
|
||
<tr key={intent}>
|
||
<td className="text-[11px] text-label font-mono pr-3 py-1.5">{intent}</td>
|
||
{BADGE_SIZE_ORDER.map((size) => (
|
||
<td key={size} className="px-2 py-1.5">
|
||
<Trk id={`TRK-BADGE-${intent}-${size}`} inline>
|
||
<Badge intent={intent} size={size}>
|
||
{intent.toUpperCase()}
|
||
</Badge>
|
||
</Trk>
|
||
</td>
|
||
))}
|
||
</tr>
|
||
))}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</Trk>
|
||
|
||
{/* intent 의미 가이드 (variantMeta에서 자동 열거) */}
|
||
<h3 className="text-sm font-semibold text-heading mb-2 mt-6">Intent 의미 가이드</h3>
|
||
<div className="ds-grid ds-grid-2">
|
||
{BADGE_INTENT_ORDER.map((intent) => {
|
||
const meta = BADGE_INTENT_META[intent];
|
||
return (
|
||
<Trk key={intent} id={`TRK-BADGE-usage-${intent}`} className="ds-sample">
|
||
<div className="flex items-center gap-3">
|
||
<Badge intent={intent} size="md">
|
||
{meta.titleKo}
|
||
</Badge>
|
||
<span className="text-xs text-label flex-1">{meta.description}</span>
|
||
</div>
|
||
</Trk>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{/* 사용 예시 코드 */}
|
||
<h3 className="text-sm font-semibold text-heading mb-2 mt-6">사용 예시</h3>
|
||
<Trk id="TRK-BADGE-usage-code" className="ds-sample">
|
||
<code className="ds-code">
|
||
{`import { Badge } from '@shared/components/ui/badge';
|
||
import { getAlertLevelIntent, getAlertLevelLabel } from '@shared/constants/alertLevels';
|
||
|
||
// 카탈로그 API와 결합 — 라벨/색상 변경은 카탈로그 파일에서만
|
||
<Badge intent={getAlertLevelIntent('CRITICAL')} size="sm">
|
||
{getAlertLevelLabel('CRITICAL', t, lang)}
|
||
</Badge>
|
||
|
||
// className override (tailwind-merge가 같은 그룹 충돌 감지)
|
||
<Badge intent="info" size="md" className="rounded-full px-3">
|
||
커스텀 둥근 배지
|
||
</Badge>`}
|
||
</code>
|
||
</Trk>
|
||
|
||
{/* 금지 패턴 */}
|
||
<h3 className="text-sm font-semibold text-heading mb-2 mt-6">금지 패턴</h3>
|
||
<Trk id="TRK-BADGE-antipattern" className="ds-sample border-red-500/30">
|
||
<div className="text-xs text-red-400 mb-2">❌ 아래 패턴은 사용하지 마세요</div>
|
||
<code className="ds-code">
|
||
{`// ❌ className 직접 작성 (intent prop 무시)
|
||
<Badge className="bg-red-400 text-white text-[11px]">...</Badge>
|
||
|
||
// ❌ !important 사용
|
||
<Badge className="!bg-red-400 !text-slate-900">...</Badge>
|
||
|
||
// ❌ <div className="bg-red-400 ..."> → Badge 컴포넌트 사용 필수
|
||
<div className="inline-flex bg-red-400 text-white rounded px-2">위험</div>`}
|
||
</code>
|
||
</Trk>
|
||
</>
|
||
);
|
||
}
|