From 6433757262ecaf0fc8f10c74b38037ae5e5b19c5 Mon Sep 17 00:00:00 2001 From: leedano Date: Wed, 25 Mar 2026 16:01:48 +0900 Subject: [PATCH] =?UTF-8?q?refactor(design):=20=EC=83=89=EC=83=81=20?= =?UTF-8?q?=ED=8C=94=EB=A0=88=ED=8A=B8=20=EC=BB=A8=ED=85=90=EC=B8=A0=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0=20+=20base.css=20=ED=99=95=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/common/styles/base.css | 78 ++ .../src/pages/design/ColorPaletteContent.tsx | 1077 ++++++++++------- 2 files changed, 747 insertions(+), 408 deletions(-) diff --git a/frontend/src/common/styles/base.css b/frontend/src/common/styles/base.css index aefe5f5..bd49569 100644 --- a/frontend/src/common/styles/base.css +++ b/frontend/src/common/styles/base.css @@ -23,6 +23,84 @@ --fM: JetBrains Mono, monospace; --rS: 6px; --rM: 8px; + + /* === Design Token System === */ + + /* Static */ + --static-black: #131415; + --static-white: #ffffff; + + /* Gray */ + --gray-100: #f1f5f9; + --gray-200: #e2e8f0; + --gray-300: #cbd5e1; + --gray-400: #94a3b8; + --gray-500: #64748b; + --gray-600: #475569; + --gray-700: #334155; + --gray-800: #1e293b; + --gray-900: #0f172a; + --gray-1000: #020617; + + /* Blue */ + --blue-100: #dbeafe; + --blue-200: #bfdbfe; + --blue-300: #93c5fd; + --blue-400: #60a5fa; + --blue-500: #3b82f6; + --blue-600: #2563eb; + --blue-700: #1d4ed8; + --blue-800: #1e40af; + --blue-900: #1e3a8a; + --blue-1000: #172554; + + /* Green */ + --green-100: #dcfce7; + --green-200: #bbf7d0; + --green-300: #86efac; + --green-400: #4ade80; + --green-500: #22c55e; + --green-600: #16a34a; + --green-700: #15803d; + --green-800: #166534; + --green-900: #14532d; + --green-1000: #052e16; + + /* Yellow */ + --yellow-100: #fef9c3; + --yellow-200: #fef08a; + --yellow-300: #fde047; + --yellow-400: #facc15; + --yellow-500: #eab308; + --yellow-600: #ca8a04; + --yellow-700: #a16207; + --yellow-800: #854d0e; + --yellow-900: #713f12; + --yellow-1000: #422006; + + /* Red */ + --red-100: #fee2e2; + --red-200: #fecaca; + --red-300: #fca5a5; + --red-400: #f87171; + --red-500: #ef4444; + --red-600: #dc2626; + --red-700: #b91c1c; + --red-800: #991b1b; + --red-900: #7f1d1d; + --red-1000: #450a0a; + + /* Purple */ + --purple-100: #f3e8ff; + --purple-200: #e9d5ff; + --purple-300: #d8b4fe; + --purple-400: #c084fc; + --purple-500: #a855f7; + --purple-600: #9333ea; + --purple-700: #7e22ce; + --purple-800: #6b21a8; + --purple-900: #581c87; + --purple-1000: #3b0764; } * { diff --git a/frontend/src/pages/design/ColorPaletteContent.tsx b/frontend/src/pages/design/ColorPaletteContent.tsx index b0ac543..803f4e7 100644 --- a/frontend/src/pages/design/ColorPaletteContent.tsx +++ b/frontend/src/pages/design/ColorPaletteContent.tsx @@ -1,158 +1,434 @@ -// ColorPaletteContent.tsx — WING-OPS Color Palette 콘텐츠 (다크/라이트 테마 지원) +// ColorPaletteContent.tsx — WING-OPS Color 파운데이션 페이지 (다크/라이트 테마 지원) +import { useState } from 'react'; import type { DesignTheme } from './designTheme'; -// ---------- 데이터 타입 ---------- +// ---------- 타입 ---------- -interface PrimitiveColorStep { +interface ColorStep { + step: number; + color: string; +} + +interface Marker { + step: number; label: string; +} + +interface ContrastRating { + step: number; + rating: string; +} + +interface ColorScaleBarProps { + steps: ColorStep[]; + markers?: Marker[]; + contrastRatings?: ContrastRating[]; + darkBg?: boolean; + isDark: boolean; +} + +interface ColorToken { + name: string; hex: string; } -interface PrimitiveColorGroup { - name: string; - steps: PrimitiveColorStep[]; +interface ColorTokenGroup { + title: string; + tokens: ColorToken[]; } -interface SemanticToken { - token: string; - dark: string; - light: string; - usage: string[]; -} +// ---------- 데이터 ---------- -interface SemanticCategory { - name: string; - tokens: SemanticToken[]; -} +const TRANSPARENCY_STEPS = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]; -// ---------- Primitive Colors 데이터 ---------- +const GRAY_STEPS: ColorStep[] = [ + { step: 0, color: '#f8fafc' }, + { step: 5, color: '#f1f5f9' }, + { step: 10, color: '#e2e8f0' }, + { step: 20, color: '#cbd5e1' }, + { step: 30, color: '#94a3b8' }, + { step: 40, color: '#64748b' }, + { step: 50, color: '#475569' }, + { step: 60, color: '#334155' }, + { step: 70, color: '#1e293b' }, + { step: 80, color: '#0f172a' }, + { step: 90, color: '#0c1322' }, + { step: 95, color: '#070d19' }, + { step: 100, color: '#020617' }, +]; -const PRIMITIVE_COLORS: PrimitiveColorGroup[] = [ +const PRIMARY_STEPS: ColorStep[] = [ + { step: 0, color: '#ecfeff' }, + { step: 5, color: '#cffafe' }, + { step: 10, color: '#a5f3fc' }, + { step: 20, color: '#67e8f9' }, + { step: 30, color: '#22d3ee' }, + { step: 40, color: '#06b6d4' }, + { step: 50, color: '#0891b2' }, + { step: 60, color: '#0e7490' }, + { step: 70, color: '#155e75' }, + { step: 80, color: '#164e63' }, + { step: 90, color: '#134152' }, + { step: 95, color: '#0c3140' }, + { step: 100, color: '#042f2e' }, +]; + +const SECONDARY_STEPS: ColorStep[] = [ + { step: 0, color: '#f0f4fa' }, + { step: 5, color: '#e1e8f4' }, + { step: 10, color: '#c3d1e8' }, + { step: 20, color: '#8da4c8' }, + { step: 30, color: '#5a7eb0' }, + { step: 40, color: '#3d6399' }, + { step: 50, color: '#2d4f80' }, + { step: 60, color: '#1e3a66' }, + { step: 70, color: '#1a2236' }, + { step: 80, color: '#121929' }, + { step: 90, color: '#0f1524' }, + { step: 95, color: '#0a0e1a' }, + { step: 100, color: '#050811' }, +]; + +const PRIMARY_CONTRAST_RATINGS: ContrastRating[] = PRIMARY_STEPS.map(({ step }) => ({ + step, + rating: step <= 30 ? 'AAA' : step <= 50 ? 'AA' : 'AAA', +})); + +const SECONDARY_CONTRAST_RATINGS: ContrastRating[] = SECONDARY_STEPS.map(({ step }) => ({ + step, + rating: step <= 30 ? 'AAA' : step <= 50 ? 'AA' : 'AAA', +})); + +const COLOR_TOKEN_GROUPS: ColorTokenGroup[] = [ { - name: 'Navy', - steps: [ - { label: '0', hex: '#0a0e1a' }, - { label: '1', hex: '#0f1524' }, - { label: '2', hex: '#121929' }, - { label: '3', hex: '#1a2236' }, - { label: 'hover', hex: '#1e2844' }, + title: 'Static', + tokens: [ + { name: 'static.black', hex: '#131415' }, + { name: 'static.white', hex: '#ffffff' }, ], }, { - name: 'Cyan', - steps: [ - { label: '00', hex: '#ecfeff' }, { label: '10', hex: '#cffafe' }, - { label: '20', hex: '#a5f3fc' }, { label: '30', hex: '#67e8f9' }, - { label: '40', hex: '#22d3ee' }, { label: '50', hex: '#06b6d4' }, - { label: '60', hex: '#0891b2' }, { label: '70', hex: '#0e7490' }, - { label: '80', hex: '#155e75' }, { label: '90', hex: '#164e63' }, - { label: '100', hex: '#083344' }, + title: 'Gray', + tokens: [ + { name: 'gray.100', hex: '#f1f5f9' }, + { name: 'gray.200', hex: '#e2e8f0' }, + { name: 'gray.300', hex: '#cbd5e1' }, + { name: 'gray.400', hex: '#94a3b8' }, + { name: 'gray.500', hex: '#64748b' }, + { name: 'gray.600', hex: '#475569' }, + { name: 'gray.700', hex: '#334155' }, + { name: 'gray.800', hex: '#1e293b' }, + { name: 'gray.900', hex: '#0f172a' }, + { name: 'gray.1000', hex: '#020617' }, ], }, { - name: 'Blue', - steps: [ - { label: '00', hex: '#eff6ff' }, { label: '10', hex: '#dbeafe' }, - { label: '20', hex: '#bfdbfe' }, { label: '30', hex: '#93c5fd' }, - { label: '40', hex: '#60a5fa' }, { label: '50', hex: '#3b82f6' }, - { label: '60', hex: '#2563eb' }, { label: '70', hex: '#1d4ed8' }, - { label: '80', hex: '#1e40af' }, { label: '90', hex: '#1e3a8a' }, - { label: '100', hex: '#172554' }, + title: 'Blue', + tokens: [ + { name: 'blue.100', hex: '#dbeafe' }, + { name: 'blue.200', hex: '#bfdbfe' }, + { name: 'blue.300', hex: '#93c5fd' }, + { name: 'blue.400', hex: '#60a5fa' }, + { name: 'blue.500', hex: '#3b82f6' }, + { name: 'blue.600', hex: '#2563eb' }, + { name: 'blue.700', hex: '#1d4ed8' }, + { name: 'blue.800', hex: '#1e40af' }, + { name: 'blue.900', hex: '#1e3a8a' }, + { name: 'blue.1000', hex: '#172554' }, ], }, { - name: 'Red', - steps: [ - { label: '00', hex: '#fef2f2' }, { label: '10', hex: '#fee2e2' }, - { label: '20', hex: '#fecaca' }, { label: '30', hex: '#fca5a5' }, - { label: '40', hex: '#f87171' }, { label: '50', hex: '#ef4444' }, - { label: '60', hex: '#dc2626' }, { label: '70', hex: '#b91c1c' }, - { label: '80', hex: '#991b1b' }, { label: '90', hex: '#7f1d1d' }, - { label: '100', hex: '#450a0a' }, + title: 'Green', + tokens: [ + { name: 'green.100', hex: '#dcfce7' }, + { name: 'green.200', hex: '#bbf7d0' }, + { name: 'green.300', hex: '#86efac' }, + { name: 'green.400', hex: '#4ade80' }, + { name: 'green.500', hex: '#22c55e' }, + { name: 'green.600', hex: '#16a34a' }, + { name: 'green.700', hex: '#15803d' }, + { name: 'green.800', hex: '#166534' }, + { name: 'green.900', hex: '#14532d' }, + { name: 'green.1000', hex: '#052e16' }, ], }, { - name: 'Green', - steps: [ - { label: '00', hex: '#f0fdf4' }, { label: '10', hex: '#dcfce7' }, - { label: '20', hex: '#bbf7d0' }, { label: '30', hex: '#86efac' }, - { label: '40', hex: '#4ade80' }, { label: '50', hex: '#22c55e' }, - { label: '60', hex: '#16a34a' }, { label: '70', hex: '#15803d' }, - { label: '80', hex: '#166534' }, { label: '90', hex: '#14532d' }, - { label: '100', hex: '#052e16' }, + title: 'Yellow', + tokens: [ + { name: 'yellow.100', hex: '#fef9c3' }, + { name: 'yellow.200', hex: '#fef08a' }, + { name: 'yellow.300', hex: '#fde047' }, + { name: 'yellow.400', hex: '#facc15' }, + { name: 'yellow.500', hex: '#eab308' }, + { name: 'yellow.600', hex: '#ca8a04' }, + { name: 'yellow.700', hex: '#a16207' }, + { name: 'yellow.800', hex: '#854d0e' }, + { name: 'yellow.900', hex: '#713f12' }, + { name: 'yellow.1000', hex: '#422006' }, ], }, { - name: 'Orange', - steps: [ - { label: '00', hex: '#fff7ed' }, { label: '10', hex: '#ffedd5' }, - { label: '20', hex: '#fed7aa' }, { label: '30', hex: '#fdba74' }, - { label: '40', hex: '#fb923c' }, { label: '50', hex: '#f97316' }, - { label: '60', hex: '#ea580c' }, { label: '70', hex: '#c2410c' }, - { label: '80', hex: '#9a3412' }, { label: '90', hex: '#7c2d12' }, - { label: '100', hex: '#431407' }, + title: 'Red', + tokens: [ + { name: 'red.100', hex: '#fee2e2' }, + { name: 'red.200', hex: '#fecaca' }, + { name: 'red.300', hex: '#fca5a5' }, + { name: 'red.400', hex: '#f87171' }, + { name: 'red.500', hex: '#ef4444' }, + { name: 'red.600', hex: '#dc2626' }, + { name: 'red.700', hex: '#b91c1c' }, + { name: 'red.800', hex: '#991b1b' }, + { name: 'red.900', hex: '#7f1d1d' }, + { name: 'red.1000', hex: '#450a0a' }, ], }, { - name: 'Yellow', - steps: [ - { label: '00', hex: '#fefce8' }, { label: '10', hex: '#fef9c3' }, - { label: '20', hex: '#fef08a' }, { label: '30', hex: '#fde047' }, - { label: '40', hex: '#facc15' }, { label: '50', hex: '#eab308' }, - { label: '60', hex: '#ca8a04' }, { label: '70', hex: '#a16207' }, - { label: '80', hex: '#854d0e' }, { label: '90', hex: '#713f12' }, - { label: '100', hex: '#422006' }, + title: 'Purple', + tokens: [ + { name: 'purple.100', hex: '#f3e8ff' }, + { name: 'purple.200', hex: '#e9d5ff' }, + { name: 'purple.300', hex: '#d8b4fe' }, + { name: 'purple.400', hex: '#c084fc' }, + { name: 'purple.500', hex: '#a855f7' }, + { name: 'purple.600', hex: '#9333ea' }, + { name: 'purple.700', hex: '#7e22ce' }, + { name: 'purple.800', hex: '#6b21a8' }, + { name: 'purple.900', hex: '#581c87' }, + { name: 'purple.1000', hex: '#3b0764' }, ], }, ]; -// ---------- Semantic Colors 데이터 ---------- +// ---------- 헬퍼 ---------- -const SEMANTIC_CATEGORIES: SemanticCategory[] = [ - { - name: 'Text', - tokens: [ - { token: 'text-1', dark: '#edf0f7', light: '#0f172a', usage: ['기본 텍스트 색상', '아이콘 기본 색상'] }, - { token: 'text-2', dark: '#b0b8cc', light: '#475569', usage: ['보조 텍스트 색상'] }, - { token: 'text-3', dark: '#8690a6', light: '#94a3b8', usage: ['비활성 텍스트', '플레이스홀더'] }, - ], - }, - { - name: 'Background', - tokens: [ - { token: 'bg-0', dark: '#0a0e1a', light: '#f8fafc', usage: ['페이지 배경'] }, - { token: 'bg-1', dark: '#0f1524', light: '#ffffff', usage: ['사이드바', '패널'] }, - { token: 'bg-2', dark: '#121929', light: '#f1f5f9', usage: ['테이블 헤더'] }, - { token: 'bg-3', dark: '#1a2236', light: '#e2e8f0', usage: ['카드 배경'] }, - { token: 'bg-hover', dark: '#1e2844', light: '#cbd5e1', usage: ['호버 상태'] }, - ], - }, - { - name: 'Border', - tokens: [ - { token: 'border', dark: '#1e2a42', light: '#cbd5e1', usage: ['기본 구분선'] }, - { token: 'border-light', dark: '#2a3a5c', light: '#e2e8f0', usage: ['연한 구분선'] }, - ], - }, - { - name: 'Accent', - tokens: [ - { token: 'primary-cyan', dark: '#06b6d4', light: '#06b6d4', usage: ['주요 강조', '활성 상태'] }, - { token: 'primary-blue', dark: '#3b82f6', light: '#0891b2', usage: ['보조 강조'] }, - { token: 'primary-purple', dark: '#a855f7', light: '#6366f1', usage: ['3차 강조'] }, - ], - }, - { - name: 'Status', - tokens: [ - { token: 'status-red', dark: '#ef4444', light: '#dc2626', usage: ['위험', '삭제'] }, - { token: 'status-orange', dark: '#f97316', light: '#c2410c', usage: ['주의'] }, - { token: 'status-yellow', dark: '#eab308', light: '#b45309', usage: ['경고'] }, - { token: 'status-green', dark: '#22c55e', light: '#047857', usage: ['정상', '성공'] }, - ], - }, -]; +const hexToRgb = (hex: string): string => { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + return `rgb(${r}, ${g}, ${b})`; +}; + +// ---------- 내부 컴포넌트: ColorScaleBar ---------- + +const ColorScaleBar = ({ + steps, + markers, + contrastRatings, + darkBg = false, + isDark, +}: ColorScaleBarProps) => { + const badgeBg = isDark ? '#374151' : '#374151'; + const badgeText = isDark ? '#e5e7eb' : '#fff'; + + const getContrastRating = (step: number): string | undefined => { + return contrastRatings?.find((r) => r.step === step)?.rating; + }; + + const getMarker = (step: number): Marker | undefined => { + return markers?.find((m) => m.step === step); + }; + + return ( +
+ {/* 색상 바 */} +
+ {steps.map(({ step, color }, idx) => { + const isFirst = idx === 0; + const isLast = idx === steps.length - 1; + const textColor = step < 50 + ? (darkBg ? '#e2e8f0' : '#1e293b') + : '#e2e8f0'; + + const rating = getContrastRating(step); + + return ( +
+ {/* 상단: 단계 번호 */} + {step} + {/* 하단: 접근성 등급 */} + {rating && ( + + {rating} + + )} +
+ ); + })} +
+ + {/* 마커 행 */} + {markers && markers.length > 0 && ( +
+ {steps.map(({ step }, idx) => { + const marker = getMarker(step); + const pct = (idx / (steps.length - 1)) * 100; + + if (!marker) return null; + + return ( +
+ {/* 점선 */} +
+ {/* 뱃지 */} + + {marker.label} + +
+ ); + })} +
+ )} +
+ ); +}; + +// ---------- 내부 컴포넌트: TransparencyRow ---------- + +interface TransparencyRowProps { + label: string; + rgbBase: string; // 'rgba base: "0,0,0"' or "255,255,255" + markerStep: number; + markerLabel: string; + isDark: boolean; +} + +const TransparencyRow = ({ + label, + rgbBase, + markerStep, + markerLabel, + isDark, +}: TransparencyRowProps) => { + const sectionCardBg = isDark ? 'rgba(255,255,255,0.03)' : '#f5f5f5'; + const badgeBg = '#374151'; + const badgeText = isDark ? '#e5e7eb' : '#fff'; + + const checkerboard = `repeating-conic-gradient(#d0d0d0 0% 25%, #fff 0% 50%)`; + + return ( +
+ + {label} + +
+ {/* 체크보드 + 색상 오버레이 */} +
+
+ {TRANSPARENCY_STEPS.map((step) => { + const alpha = step / 100; + const color = `rgba(${rgbBase},${alpha})`; + const isBlack = rgbBase === '0,0,0'; + const textColor = isBlack + ? (step < 50 ? '#333' : '#fff') + : (step < 50 ? '#333' : '#aaa'); + + return ( +
+ + {step} + +
+ ); + })} +
+
+ + {/* 마커 */} +
+ {TRANSPARENCY_STEPS.map((step, idx) => { + if (step !== markerStep) return null; + const pct = (idx / (TRANSPARENCY_STEPS.length - 1)) * 100; + + return ( +
+
+ + {markerLabel} + +
+ ); + })} +
+
+
+ ); +}; // ---------- Props ---------- @@ -165,324 +441,309 @@ interface ColorPaletteContentProps { export const ColorPaletteContent = ({ theme }: ColorPaletteContentProps) => { const t = theme; const isDark = t.mode === 'dark'; + const [activeColorTab, setActiveColorTab] = useState<'usage' | 'token'>('usage'); + + const sectionCardBg = isDark ? 'rgba(255,255,255,0.03)' : '#f5f5f5'; + const dividerColor = isDark ? 'rgba(255,255,255,0.08)' : '#e5e7eb'; return ( -
+
+
- {/* ── 섹션 1: 헤더 ── */} -
-
+ {/* ── 섹션 1: 헤더 ── */} +
+

+ Foundations +

Color

- WING-OPS 인터페이스에서 사용되는 색상 체계입니다. Primitive Token(원시 팔레트)과 Semantic Token(의미 기반 토큰) 두 계층으로 구성됩니다. + 브랜드 아이덴티티를 유지하기 위한 컬러 사용 기준입니다.
핵심 정보를 강조하고 현재 상태를 명확하게 전달합니다.

- {/* 토큰 네이밍 다이어그램 카드 */} -
- - bg - - - — - - - 0 - -
-
- - Category - - - 색상 범주 (bg, text, border, status…) - -
-
-
- - Value - - - 단계 또는 역할 (0–3, hover, red, cyan…) - -
-
-
-
- - {/* ── 섹션 2: Primitive Tokens ── */} -
-
-

- Primitive Tokens -

-
    -
  • Tailwind CSS 기반 색상 스케일로 구성된 원시 팔레트입니다.
  • -
  • 각 색조(Hue)는 00(가장 밝음)에서 100(가장 어두움)까지 11단계로 표현됩니다.
  • -
  • Navy는 UI 배경 계층에만 사용되는 특수 팔레트입니다.
  • -
-
- -
- {PRIMITIVE_COLORS.map((group) => ( -
- {/* 그룹명 */} - - {group.name} - - - {/* 가로 컬러 바 */} -
- {group.steps.map((step) => ( -
-
-
- - {step.label} - - - {step.hex} - -
-
- ))} -
-
- ))} -
-
- - {/* ── 섹션 3: Semantic Colors ── */} -
-
-

- Semantic Colors -

-
    -
  • Primitive Token을 역할 기반으로 추상화한 의미 토큰입니다.
  • -
  • 다크/라이트 모드에 따라 실제 색상 값이 달라집니다.
  • -
  • 코드에서는 항상 Semantic Token을 사용하고, Primitive Token을 직접 참조하지 않습니다.
  • -
-
- -
- {SEMANTIC_CATEGORIES.map((category) => ( -
- {/* 카테고리 제목 (좌측 2px cyan accent bar) */} -
-
- - {category.name} - -
- - {/* 테이블 */} -
+ {(['usage', 'token'] as const).map((tab) => { + const isActive = activeColorTab === tab; + return ( + + ); + })} +
+ + {/* ── Usage 탭 콘텐츠 ── */} + {activeColorTab === 'usage' && ( + <> + {/* ── 섹션 2: Primary color ── */} +
+

+ 프라이머리 색상(primary color) +

+

+ Primary 색상은 해양 방제 시스템의 핵심 인터랙션 요소에 사용됩니다. Cyan~Blue 그라디언트가 주요 액션 버튼과 강조 요소에 적용됩니다. +

+ +
+ {/* Light Mode */}
+

+ Light Mode +

+ +
+ + {/* Dark Mode */} +
+

+ Dark Mode +

+ +
+
+
+ + {/* ── 섹션 3: Secondary color ── */} +
+

+ 세컨더리 색상(secondary color) +

+

+ Secondary 색상은 UI의 배경과 구조적 요소에 사용됩니다. Navy 계열로 다크 모드의 깊이감과 계층 구조를 표현합니다. +

+ +
+ {/* Light Mode */} +
+

+ Light Mode +

+ +
+ + {/* Dark Mode */} +
+

+ Dark Mode +

+ +
+
+
+ + {/* ── 섹션 4: Gray color ── */} +
+

+ 그레이 색상(gray color) / 네추럴, 중립 색상 +

+

+ Gray 색상은 주로 배경, 텍스트, 구분 선에 사용되며, 시각적 집중을 방해하지 않고 콘텐츠에 초점을 맞추도록 도와주는 중립적인 색상이다. +

+

+ 표준형 스타일의 그레이 색상은 주요 색상과 선명한 모드에서의 조화를 고려해 블루 그레이 계열을 사용한다. +

+ +
+ +
+
+ + {/* ── 섹션 5: Transparent ── */} +
+

+ Transparent +

+

+ 투명도와 음영을 활용하여 정보의 집중도를 조절합니다. 배경의 음영 처리는 투명도 65%를 사용합니다. +

+ +
+ {/* Black */} + + + {/* White */} + +
+
+ + )} + + {/* ── Token 탭 콘텐츠 ── */} + {activeColorTab === 'token' && ( +
+ {COLOR_TOKEN_GROUPS.map((group, groupIdx) => ( +
+

- {(['Token', 'Dark Mode', 'Light Mode', 'Usage'] as const).map((col) => ( -
+ {group.title} +

+
+ {group.tokens.map((token) => ( +
+ {/* 색상 스와치 */} +
+ {/* 토큰명 */} - {col} + {token.name} + {/* HEX + RGB */} +
+
+ {token.hex} +
+
+ {hexToRgb(token.hex)} +
+
))}
- - {/* 데이터 행 */} - {category.tokens.map((token, rowIdx) => ( -
- {/* Token 컬럼 */} -
- - {token.token} - -
- - {/* Dark Mode 컬럼 */} -
-
-
- - {token.dark} - -
-
- - {/* Light Mode 컬럼 */} -
-
-
- - {token.light} - -
-
- - {/* Usage 컬럼 */} -
-
    - {token.usage.map((u) => ( -
  • - - - {u} - -
  • - ))} -
-
-
- ))}
-
- ))} -
+ ))} +
+ )} +
);