- react-router-dom 도입, /design 경로에 디자인 토큰/컴포넌트 카탈로그 페이지 추가 - SCAT 지도에서 하드코딩된 제주 해안선 좌표 제거, 인접 구간 기반 동적 방향 계산으로 전환 - @/ path alias 추가, SVG 아이콘 에셋 추가
381 lines
12 KiB
TypeScript
381 lines
12 KiB
TypeScript
// designTheme.ts — 디자인 시스템 페이지 다크/라이트 테마 정의
|
|
|
|
export type ThemeMode = 'dark' | 'light';
|
|
|
|
// ---------- 토큰 인터페이스 ----------
|
|
export interface BgToken {
|
|
bg: string;
|
|
token: string;
|
|
hex: string;
|
|
desc: string;
|
|
isHover?: boolean;
|
|
}
|
|
|
|
export interface AccentToken {
|
|
color: string;
|
|
name: string;
|
|
token: string;
|
|
badge: string;
|
|
glow: string;
|
|
badgeBg: string;
|
|
badgeBorder: string;
|
|
badgeText: string;
|
|
}
|
|
|
|
export interface StatusToken {
|
|
color: string;
|
|
bg: string;
|
|
border: string;
|
|
label: string;
|
|
hex: string;
|
|
glow?: string;
|
|
}
|
|
|
|
export interface BorderToken {
|
|
token: string;
|
|
hex: string;
|
|
border: string;
|
|
barBg: string;
|
|
}
|
|
|
|
export interface TextTokenItem {
|
|
token: string;
|
|
sampleText: string;
|
|
sampleClass: string;
|
|
desc: string;
|
|
descColor: string;
|
|
}
|
|
|
|
// ---------- 테마 인터페이스 ----------
|
|
export interface DesignTheme {
|
|
mode: ThemeMode;
|
|
|
|
// 레이아웃
|
|
pageBg: string;
|
|
sidebarBg: string;
|
|
sidebarBorder: string;
|
|
sidebarShadow: string;
|
|
headerBg: string;
|
|
headerBorder: string;
|
|
|
|
// 텍스트
|
|
textPrimary: string;
|
|
textSecondary: string;
|
|
textMuted: string;
|
|
textAccent: string;
|
|
|
|
// 카드
|
|
cardBg: string;
|
|
cardBorder: string;
|
|
cardBorderHover: string;
|
|
cardShadow: string;
|
|
|
|
// 섹션
|
|
sectionTitle: string;
|
|
sectionSub: string;
|
|
sectionSubSpacing: string;
|
|
|
|
// 테이블
|
|
tableContainerBg: string;
|
|
tableHeaderBg: string;
|
|
tableRowBorder: string;
|
|
tableDataRowBg: string;
|
|
|
|
// 뱃지
|
|
badgeRadius: string;
|
|
statusBadgeBg: string;
|
|
statusBadgeBorder: string;
|
|
statusBadgeDot: string;
|
|
statusBadgeText: string;
|
|
systemActiveBg: string;
|
|
systemActiveBorder: string;
|
|
systemActiveShadow: string;
|
|
|
|
// 폰트 뱃지 (06 타이포그래피)
|
|
fontBadgePrimaryBg: string;
|
|
fontBadgePrimaryText: string;
|
|
fontBadgeSecondaryBorder: string;
|
|
fontBadgeSecondaryText: string;
|
|
|
|
// 타이포 샘플 텍스트
|
|
typoSampleText: string;
|
|
typoSizeText: string;
|
|
typoPropertiesText: string;
|
|
typoActionBg: string;
|
|
typoActionBorder: string;
|
|
typoActionText: string;
|
|
typoDataText: string;
|
|
typoCoordText: string;
|
|
|
|
// 02 테두리 색상
|
|
borderCardBg: string;
|
|
borderCardShadow: string;
|
|
|
|
// 03 텍스트 색상
|
|
textSectionBg: string;
|
|
textSectionBorder: string;
|
|
|
|
// 07 radius
|
|
radiusSmLabel: string;
|
|
radiusMdLabel: string;
|
|
radiusCardBg: string;
|
|
radiusCardBorder: string;
|
|
radiusCardShadow: string;
|
|
radiusDescText: string;
|
|
|
|
// 푸터
|
|
footerBorder: string;
|
|
footerText: string;
|
|
footerAccent: string;
|
|
|
|
// 01 배경색 카드 스와치 border
|
|
swatchBorder: string;
|
|
swatchBorderHover: string;
|
|
|
|
// 데이터 토큰
|
|
bgTokens: BgToken[];
|
|
accentTokens: AccentToken[];
|
|
statusTokens: StatusToken[];
|
|
borderTokens: BorderToken[];
|
|
textTokens: TextTokenItem[];
|
|
}
|
|
|
|
// ---------- DARK 테마 ----------
|
|
export const DARK_THEME: DesignTheme = {
|
|
mode: 'dark',
|
|
|
|
pageBg: '#0a0e1a',
|
|
sidebarBg: '#171b28',
|
|
sidebarBorder: 'rgba(255,255,255,0.05)',
|
|
sidebarShadow: 'rgba(0,0,0,0.4)',
|
|
headerBg: '#0a0e1a',
|
|
headerBorder: 'rgba(255,255,255,0.05)',
|
|
|
|
textPrimary: '#dfe2f3',
|
|
textSecondary: '#c2c6d6',
|
|
textMuted: '#8c909f',
|
|
textAccent: '#4cd7f6',
|
|
|
|
cardBg: '#171b28',
|
|
cardBorder: 'rgba(66,71,84,0.10)',
|
|
cardBorderHover: 'rgba(66,71,84,0.20)',
|
|
cardShadow: 'none',
|
|
|
|
sectionTitle: '#adc6ff',
|
|
sectionSub: '#8c909f',
|
|
sectionSubSpacing: '1px',
|
|
|
|
tableContainerBg: '#171b28',
|
|
tableHeaderBg: '#1b1f2c',
|
|
tableRowBorder: 'rgba(66,71,84,0.10)',
|
|
tableDataRowBg: 'rgba(10,14,26,0.50)',
|
|
|
|
badgeRadius: 'rounded-xl',
|
|
statusBadgeBg: 'transparent',
|
|
statusBadgeBorder: 'transparent',
|
|
statusBadgeDot: 'transparent',
|
|
statusBadgeText: 'transparent',
|
|
systemActiveBg: '#171b28',
|
|
systemActiveBorder: 'rgba(66,71,84,0.10)',
|
|
systemActiveShadow: '0px 0px 8px 0px rgba(76, 215, 246, 0.5)',
|
|
|
|
fontBadgePrimaryBg: '#edf0f7',
|
|
fontBadgePrimaryText: '#0a0e1a',
|
|
fontBadgeSecondaryBorder: 'rgba(66,71,84,0.30)',
|
|
fontBadgeSecondaryText: '#8c909f',
|
|
|
|
typoSampleText: '#c2c6d6',
|
|
typoSizeText: '#8c909f',
|
|
typoPropertiesText: '#c2c6d6',
|
|
typoActionBg: 'rgba(76,215,246,0.10)',
|
|
typoActionBorder: 'rgba(76,215,246,0.20)',
|
|
typoActionText: '#4cd7f6',
|
|
typoDataText: '#4cd7f6',
|
|
typoCoordText: '#8c909f',
|
|
|
|
borderCardBg: 'rgba(15,21,36,0.50)',
|
|
borderCardShadow: 'none',
|
|
|
|
textSectionBg: '#0a0e1a',
|
|
textSectionBorder: 'rgba(66,71,84,0.10)',
|
|
|
|
radiusSmLabel: 'radius-sm (6px)',
|
|
radiusMdLabel: 'radius-md (10px)',
|
|
radiusCardBg: '#171b28',
|
|
radiusCardBorder: 'rgba(66,71,84,0.20)',
|
|
radiusCardShadow: 'none',
|
|
radiusDescText: '#c2c6d6',
|
|
|
|
footerBorder: 'rgba(66,71,84,0.10)',
|
|
footerText: '#8c909f',
|
|
footerAccent: '#4cd7f6',
|
|
|
|
swatchBorder: 'rgba(255,255,255,0.05)',
|
|
swatchBorderHover: 'rgba(76,215,246,0.20)',
|
|
|
|
bgTokens: [
|
|
{ bg: '#0a0e1a', token: 'bg-0', hex: '#0a0e1a', desc: 'Primary page canvas, deepest immersion layer.' },
|
|
{ bg: '#0f1524', token: 'bg-1', hex: '#0f1524', desc: 'Surface Level 1: Sidebar containers and utility panels.' },
|
|
{ bg: '#121929', token: 'bg-2', hex: '#121929', desc: 'Surface Level 2: Table headers and subtle sectional shifts.' },
|
|
{ bg: '#1a2236', token: 'bg-3', hex: '#1a2236', desc: 'Surface Level 3: Elevated cards and floating elements.' },
|
|
{ bg: '#1e2844', token: 'bg-hover', hex: '#1e2844', desc: 'Interactive states, list item highlighting.', isHover: true },
|
|
],
|
|
|
|
accentTokens: [
|
|
{
|
|
color: '#06b6d4', name: 'Cyan Accent', token: 'primary', badge: 'Primary Action',
|
|
glow: '0px 0px 15px 0px rgba(6,182,212,0.4)',
|
|
badgeBg: 'rgba(6,182,212,0.10)', badgeBorder: 'rgba(6,182,212,0.25)', badgeText: '#06b6d4',
|
|
},
|
|
{
|
|
color: '#3b82f6', name: 'Blue Accent', token: 'secondary', badge: 'Information',
|
|
glow: '0px 0px 15px 0px rgba(59,130,246,0.3)',
|
|
badgeBg: 'rgba(59,130,246,0.10)', badgeBorder: 'rgba(59,130,246,0.25)', badgeText: '#3b82f6',
|
|
},
|
|
{
|
|
color: '#a855f7', name: 'Purple Accent', token: 'tertiary', badge: 'Operations',
|
|
glow: '0px 0px 15px 0px rgba(168,85,247,0.3)',
|
|
badgeBg: 'rgba(168,85,247,0.10)', badgeBorder: 'rgba(168,85,247,0.25)', badgeText: '#a855f7',
|
|
},
|
|
],
|
|
|
|
statusTokens: [
|
|
{ color: '#ef4444', bg: 'rgba(239,68,68,0.05)', border: 'rgba(239,68,68,0.20)', label: '위험 Critical', hex: '#ef4444', glow: '0px 0px 8px 0px rgba(239, 68, 68, 0.6)' },
|
|
{ color: '#f97316', bg: 'rgba(249,115,22,0.05)', border: 'rgba(249,115,22,0.20)', label: '주의 Warning', hex: '#f97316' },
|
|
{ color: '#eab308', bg: 'rgba(234,179,8,0.05)', border: 'rgba(234,179,8,0.20)', label: '경고 Caution', hex: '#eab308' },
|
|
{ color: '#22c55e', bg: 'rgba(34,197,94,0.05)', border: 'rgba(34,197,94,0.20)', label: '정상 Normal', hex: '#22c55e' },
|
|
],
|
|
|
|
borderTokens: [
|
|
{ token: 'border', hex: '#1e2a42', border: '#1e2a42', barBg: '#1e2a42' },
|
|
{ token: 'border-light', hex: '#2a3a5c', border: '#2a3a5c', barBg: '#2a3a5c' },
|
|
],
|
|
|
|
textTokens: [
|
|
{ token: 'text-1', sampleText: '주요 텍스트 Primary Text', sampleClass: 'text-[#edf0f7] font-korean text-[15px] font-bold', desc: 'Headings, active values, and primary labels.', descColor: 'rgba(237,240,247,0.60)' },
|
|
{ token: 'text-2', sampleText: '보조 텍스트 Secondary Text', sampleClass: 'text-[#b0b8cc] font-korean text-[15px] font-medium', desc: 'Supporting labels and secondary information.', descColor: 'rgba(176,184,204,0.60)' },
|
|
{ token: 'text-3', sampleText: '비활성 텍스트 Muted Text', sampleClass: 'text-[#8690a6] font-korean text-[15px]', desc: 'Disabled states, placeholders, and captions.', descColor: 'rgba(134,144,166,0.60)' },
|
|
],
|
|
};
|
|
|
|
// ---------- LIGHT 테마 ----------
|
|
export const LIGHT_THEME: DesignTheme = {
|
|
mode: 'light',
|
|
|
|
pageBg: '#f8fafc',
|
|
sidebarBg: '#ffffff',
|
|
sidebarBorder: '#e2e8f0',
|
|
sidebarShadow: 'rgba(0,0,0,0.05)',
|
|
headerBg: '#ffffff',
|
|
headerBorder: '#e2e8f0',
|
|
|
|
textPrimary: '#0f172a',
|
|
textSecondary: '#64748b',
|
|
textMuted: '#94a3b8',
|
|
textAccent: '#06b6d4',
|
|
|
|
cardBg: '#ffffff',
|
|
cardBorder: '#e2e8f0',
|
|
cardBorderHover: 'rgba(6,182,212,0.20)',
|
|
cardShadow: '0px 1px 2px 0px rgba(0,0,0,0.05)',
|
|
|
|
sectionTitle: '#1e293b',
|
|
sectionSub: '#94a3b8',
|
|
sectionSubSpacing: '-0.5px',
|
|
|
|
tableContainerBg: '#ffffff',
|
|
tableHeaderBg: '#f8fafc',
|
|
tableRowBorder: '#f1f5f9',
|
|
tableDataRowBg: 'rgba(248,250,252,0.50)',
|
|
|
|
badgeRadius: 'rounded-full',
|
|
statusBadgeBg: 'transparent',
|
|
statusBadgeBorder: 'transparent',
|
|
statusBadgeDot: 'transparent',
|
|
statusBadgeText: 'transparent',
|
|
systemActiveBg: '#ffffff',
|
|
systemActiveBorder: '#e2e8f0',
|
|
systemActiveShadow: '0px 1px 2px 0px rgba(0,0,0,0.05)',
|
|
|
|
fontBadgePrimaryBg: '#0f172a',
|
|
fontBadgePrimaryText: '#ffffff',
|
|
fontBadgeSecondaryBorder: '#cbd5e1',
|
|
fontBadgeSecondaryText: '#64748b',
|
|
|
|
typoSampleText: '#64748b',
|
|
typoSizeText: '#0f172a',
|
|
typoPropertiesText: '#94a3b8',
|
|
typoActionBg: 'rgba(6,182,212,0.10)',
|
|
typoActionBorder: 'rgba(6,182,212,0.20)',
|
|
typoActionText: '#06b6d4',
|
|
typoDataText: '#06b6d4',
|
|
typoCoordText: '#94a3b8',
|
|
|
|
borderCardBg: '#ffffff',
|
|
borderCardShadow: '0px 1px 2px 0px rgba(0,0,0,0.05)',
|
|
|
|
textSectionBg: '#ffffff',
|
|
textSectionBorder: '#e2e8f0',
|
|
|
|
radiusSmLabel: 'radius-sm (4px)',
|
|
radiusMdLabel: 'radius-md (8px)',
|
|
radiusCardBg: '#ffffff',
|
|
radiusCardBorder: '#e2e8f0',
|
|
radiusCardShadow: '0px 1px 2px 0px rgba(0,0,0,0.05)',
|
|
radiusDescText: '#475569',
|
|
|
|
footerBorder: '#e2e8f0',
|
|
footerText: '#94a3b8',
|
|
footerAccent: '#06b6d4',
|
|
|
|
swatchBorder: '#e2e8f0',
|
|
swatchBorderHover: 'rgba(6,182,212,0.20)',
|
|
|
|
bgTokens: [
|
|
{ bg: '#f8fafc', token: 'bg-0', hex: '#f8fafc', desc: 'Primary page canvas, lightest foundation layer.' },
|
|
{ bg: '#ffffff', token: 'bg-1', hex: '#ffffff', desc: 'Surface Level 1: Sidebar containers and utility panels.' },
|
|
{ bg: '#f1f5f9', token: 'bg-2', hex: '#f1f5f9', desc: 'Surface Level 2: Table headers and subtle sectional shifts.' },
|
|
{ bg: '#e2e8f0', token: 'bg-3', hex: '#e2e8f0', desc: 'Surface Level 3: Elevated cards and floating elements.' },
|
|
{ bg: '#cbd5e1', token: 'bg-hover', hex: '#cbd5e1', desc: 'Interactive states, list item highlighting.', isHover: true },
|
|
],
|
|
|
|
accentTokens: [
|
|
{
|
|
color: '#06b6d4', name: 'Cyan Accent', token: 'primary', badge: 'Primary Action',
|
|
glow: '0px 1px 2px 0px rgba(0,0,0,0.05)',
|
|
badgeBg: 'rgba(6,182,212,0.10)', badgeBorder: 'rgba(6,182,212,0.25)', badgeText: '#06b6d4',
|
|
},
|
|
{
|
|
color: '#0891b2', name: 'Teal Accent', token: 'secondary', badge: 'Information',
|
|
glow: '0px 1px 2px 0px rgba(0,0,0,0.05)',
|
|
badgeBg: 'rgba(8,145,178,0.10)', badgeBorder: 'rgba(8,145,178,0.25)', badgeText: '#0891b2',
|
|
},
|
|
{
|
|
color: '#6366f1', name: 'Indigo Accent', token: 'tertiary', badge: 'Operations',
|
|
glow: '0px 1px 2px 0px rgba(0,0,0,0.05)',
|
|
badgeBg: 'rgba(99,102,241,0.10)', badgeBorder: 'rgba(99,102,241,0.25)', badgeText: '#6366f1',
|
|
},
|
|
],
|
|
|
|
statusTokens: [
|
|
{ color: '#dc2626', bg: '#fef2f2', border: '#fecaca', label: '위험 Critical', hex: '#f87171' },
|
|
{ color: '#c2410c', bg: '#fff7ed', border: '#fed7aa', label: '주의 Warning', hex: '#fb923c' },
|
|
{ color: '#b45309', bg: '#fffbeb', border: '#fde68a', label: '경고 Caution', hex: '#fbbf24' },
|
|
{ color: '#047857', bg: '#ecfdf5', border: '#a7f3d0', label: '정상 Normal', hex: '#34d399' },
|
|
],
|
|
|
|
borderTokens: [
|
|
{ token: 'border', hex: '#cbd5e1', border: '#cbd5e1', barBg: '#cbd5e1' },
|
|
{ token: 'border-light', hex: '#e2e8f0', border: '#e2e8f0', barBg: '#e2e8f0' },
|
|
],
|
|
|
|
textTokens: [
|
|
{ token: 'text-1', sampleText: '주요 텍스트 Primary Text', sampleClass: 'text-[#0f172a] font-korean text-[15px] font-bold', desc: 'Headings, active values, and primary labels.', descColor: '#64748b' },
|
|
{ token: 'text-2', sampleText: '보조 텍스트 Secondary Text', sampleClass: 'text-[#475569] font-korean text-[15px] font-medium', desc: 'Supporting labels and secondary information.', descColor: '#64748b' },
|
|
{ token: 'text-3', sampleText: '비활성 텍스트 Muted Text', sampleClass: 'text-[#94a3b8] font-korean text-[15px]', desc: 'Disabled states, placeholders, and captions.', descColor: '#94a3b8' },
|
|
],
|
|
};
|
|
|
|
export const getTheme = (mode: ThemeMode): DesignTheme =>
|
|
mode === 'dark' ? DARK_THEME : LIGHT_THEME;
|