diff --git a/CLAUDE.md b/CLAUDE.md index 200cbb5..6a6e91d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -77,6 +77,37 @@ snp-connection-monitoring/ - Git 워크플로우: `.claude/rules/git-workflow.md` 참조 - 팀 정책: `.claude/rules/team-policy.md` 참조 +## 디자인 시스템 + +`docs/design/` 디렉토리에 프론트엔드 디자인 시스템 가이드가 있다. + +| 문서 | 내용 | +|------|------| +| `docs/design/colors.md` | 브랜드 컬러 스케일, CSS 변수 토큰, 시멘틱 컬러, 차트 팔레트 | +| `docs/design/typography.md` | 폰트 패밀리, 타입 스케일(8단계), 한글 규칙 | +| `docs/design/spacing.md` | 4px 기반 스케일, 컴포넌트별 여백, 12컬럼 그리드 | +| `docs/design/components.md` | Button, Badge, Card, Input, Modal, Toast 스펙 | +| `docs/design/icons.md` | Lucide React, 사이즈/색상 규칙 | +| `docs/design/motion.md` | Duration, Easing, prefers-reduced-motion | +| `docs/design/code-conventions.md` | 파일명, Tailwind 클래스 순서, cn(), forwardRef | +| `docs/design/do-dont.md` | 올바른 사용법과 금지 패턴 | + +### 프롬프트 템플릿 + +| 문서 | 용도 | +|------|------| +| `docs/design/prompts/new-component.md` | 새 컴포넌트 생성 요청 템플릿 | +| `docs/design/prompts/review-checklist.md` | 디자인 리뷰 체크리스트 (9개 카테고리) | +| `docs/design/prompts/refactor-style.md` | 스타일 리팩토링 요청 템플릿 | + +### 핵심 규칙 + +- **CSS 변수 토큰** 사용 — HEX 하드코딩 금지 (`var(--color-*)`) +- **cn() 유틸리티** 사용 — `src/utils/cn.ts` (clsx + tailwind-merge) +- **Lucide React** 아이콘만 사용 — 다른 라이브러리 혼용 금지 +- **4px 스페이싱 스케일** — 임의 px 값 금지 +- **차트 팔레트** — `src/constants/chart.ts`의 `CHART_COLORS` 상수 사용 + ## 의존성 관리 - Maven: Nexus 프록시 레포지토리 (`.mvn/settings.xml`) diff --git a/claude-code-design-system-prompt.md b/claude-code-design-system-prompt.md new file mode 100644 index 0000000..de069b2 --- /dev/null +++ b/claude-code-design-system-prompt.md @@ -0,0 +1,499 @@ +# SNP Connection Monitoring — 디자인 시스템 적용 프롬프트 + +아래 프롬프트를 Claude Code에 붙여넣어 실행하세요. + +--- + +``` +해양 데이터 시스템(SNP Connection Monitoring) 프로젝트에 디자인 시스템을 적용해줘. +프로젝트 규칙(.claude/rules/)과 CLAUDE.md를 반드시 읽고 따라줘. + +## 0. 사전 준비 + +- develop 브랜치에서 `feature/design-system` 브랜치를 생성해서 작업 +- 커밋 메시지는 Conventional Commits 형식 (프로젝트 git-workflow.md 참조) + +## 1. 디자인 가이드 문서 생성 + +`docs/design/` 디렉토리 아래에 아래 파일들을 생성해줘. + +### 1-1. docs/design/colors.md + +해양 데이터 시스템 컬러 시스템. 내용: + +**브랜드 컬러 원본:** +| 역할 | HEX | 설명 | +|------|-----|------| +| Primary | #6D94C5 | Slate Blue — 신뢰, 전문성 | +| Secondary | #CBDCEB | Powder Blue — 부드러운 보조 | +| Accent | #E8DFCA | Warm Sand — 따뜻한 포인트 | +| Background | #F5EFE6 | Warm Cream — 배경색 | + +**브랜드 컬러 스케일 (50~950):** + +Primary (Slate Blue, hue≈213°): +- 50: #F5F7F9, 100: #E5EBF2, 200: #D2DAE5, 300: #B7C5D7, 400: #8AA5C7 +- 500: #6D94C5, 600: #507FB9, 700: #3B669C, 800: #2D507B, 900: #1B2C41, 950: #0E1A2B + +Secondary (Powder Blue, hue≈210°): +- 50: #F5F7F9, 100: #E6EDF5, 200: #D1DAE5, 300: #B7C8D7, 400: #89AAC8 +- 500: #CBDCEB, 600: #6B9AC8, 700: #4E88BB, 800: #396E9D, 900: #1B2F41, 950: #0E1A2B + +Accent (Warm Sand, hue≈38°): +- 50: #F9F8F6, 100: #F2EDE4, 200: #E4E0D7, 300: #D5CDB9, 400: #C4B48C +- 500: #E8DFCA, 600: #B59854, 700: #9A7E3E, 800: #786230, 900: #3F351D, 950: #2B2312 + +**디자인 토큰 (CSS 변수 — Light / Dark):** + +| 토큰 | Light | Dark | +|------|-------|------| +| --color-primary | #507FB9 | #B7C5D7 | +| --color-primary-hover | #3B669C | #D2DAE5 | +| --color-primary-active | #2D507B | #8AA5C7 | +| --color-primary-subtle | #F5F7F9 | #1B2C41 | +| --color-primary-text | #2D507B | #D2DAE5 | +| --color-secondary | #CBDCEB | #B7C8D7 | +| --color-secondary-hover | #89AAC8 | #D1DAE5 | +| --color-secondary-active | #4E88BB | #89AAC8 | +| --color-secondary-subtle | #F5F7F9 | #1B2F41 | +| --color-secondary-text | #396E9D | #D1DAE5 | +| --color-accent | #E8DFCA | #D5CDB9 | +| --color-accent-hover | #C4B48C | #E4E0D7 | +| --color-accent-active | #B59854 | #C4B48C | +| --color-accent-subtle | #F9F8F6 | #3F351D | +| --color-accent-text | #786230 | #E4E0D7 | + +**시멘틱 컬러 (Light / Dark):** + +| 역할 | Light | Dark | +|------|-------|------| +| Success | #059669 | #34D399 | +| Warning | #D97706 | #FBBF24 | +| Danger | #DC2626 | #FCA5A5 | +| Info | #0284C7 | #38BDF8 | + +**뉴트럴 (Blue-tinted warm gray):** + +| 토큰 | Light | Dark | +|------|-------|------| +| --color-bg-base | #F5EFE6 | #131416 | +| --color-bg-surface | #FFFFFF | #1E2023 | +| --color-bg-elevated | #FFFFFF | #282A2E | +| --color-border | #D5D2CC | #3A3C41 | +| --color-border-strong | #9198A1 | #5C6570 | +| --color-text-primary | #1E2329 | #F4F5F5 | +| --color-text-secondary | #5C6570 | #9198A1 | +| --color-text-tertiary | #9198A1 | #5C6570 | + +**다크모드 토큰 사용 가이드:** +다크모드 시멘틱 토큰(--color-primary, --color-secondary, --color-accent)은 텍스트/아이콘용 밝은 톤이다. +버튼/뱃지처럼 배경색이 필요한 인터랙티브 요소는 다크모드에서 스케일 값(600~700)을 직접 사용해야 한다. +- 텍스트/아이콘: `text-[--color-primary]` → 다크모드에서 자동으로 밝은 톤 적용 (OK) +- 버튼 배경: `bg-[--color-primary]` → 다크모드에서 `dark:bg-[--color-primary-600]`으로 오버라이드 (필수) + +**차트 팔레트 (Cool+Warm 교차):** + +Light: +1. #507FB9 (Primary 600) +2. #B59854 (Accent 600) +3. #4E88BB (Secondary 700) +4. #9A7E3E (Accent 700) +5. #3B669C (Primary 700) +6. #C4B48C (Accent 400) + +Dark (채도 강화 — 400~500 스케일 사용): +1. #6D94C5 (Primary 500) +2. #C4B48C (Accent 400) +3. #6B9AC8 (Secondary 600) +4. #B59854 (Accent 600) +5. #8AA5C7 (Primary 400) +6. #D5CDB9 (Accent 300) + +### 1-2. docs/design/typography.md + +타이포그래피 시스템: +- 기본 폰트: Pretendard (한글), Inter (영문/숫자) +- 8단계 타입 스케일: Display 48px, H1 36px, H2 30px, H3 24px, Body-lg 18px, Body 16px, Caption 14px, Overline 12px +- line-height: heading 1.2~1.3, body 1.5~1.6 +- font-weight: 300(light), 400(regular), 500(medium), 600(semibold), 700(bold) +- 한국어 word-break: keep-all 규칙 + +### 1-3. docs/design/spacing.md + +스페이싱 시스템: +- 4px 기반 스케일: 0(0px), 0.5(2px), 1(4px), 1.5(6px), 2(8px), 3(12px), 4(16px), 5(20px), 6(24px), 8(32px), 10(40px), 12(48px), 16(64px), 20(80px), 24(96px) +- 컴포넌트별 내부 여백: Button(px-4 py-2), Card(p-4~p-6), Input(px-3 py-2), Modal(p-6) +- 반응형 브레이크포인트: sm 640px, md 768px, lg 1024px, xl 1280px, 2xl 1536px +- 그리드: 12컬럼, gap-4~gap-6 + +### 1-4. docs/design/components.md + +컴포넌트 스펙: + +**Button 변형 (Light 모드):** +- primary: bg-[--color-primary] text-white hover:bg-[--color-primary-hover] +- secondary: bg-[--color-secondary] text-[--color-secondary-text] hover:bg-[--color-secondary-hover] +- accent: bg-[--color-accent] text-[--color-accent-text] hover:bg-[--color-accent-hover] +- outline: border border-[--color-border-strong] text-[--color-text-primary] hover:bg-[--color-primary-subtle] +- ghost: text-[--color-text-secondary] hover:bg-[--color-primary-subtle] +- danger: bg-danger-600 text-white hover:bg-danger-700 + +**Button 변형 (Dark 모드) — 채도/대비 강화:** +다크모드에서 시멘틱 토큰(--color-primary 등)은 연한 파스텔 톤이라 버튼 배경으로 부적합. +스케일 값(600~700)을 직접 사용하여 선명한 대비를 확보한다. +- primary: dark:bg-[--color-primary-600] dark:text-white dark:hover:bg-[--color-primary-500] +- secondary: dark:bg-[--color-secondary-700] dark:text-white dark:hover:bg-[--color-secondary-600] +- accent: dark:bg-[--color-accent-600] dark:text-white dark:hover:bg-[--color-accent-500] +- outline: dark:border-[--color-primary-400] dark:text-[--color-primary-300] dark:hover:bg-primary-600/15 +- ghost: dark:text-[--color-primary-300] dark:hover:bg-primary-600/12 +- danger: dark:bg-[#EF4444] dark:text-white dark:hover:bg-[#DC2626] + +**Button 사이즈:** sm(h-8 px-3 text-sm), md(h-10 px-4 text-sm), lg(h-12 px-6 text-base) + +**Badge 변형:** default, primary, secondary, accent, success, warning, danger +**Card:** bg-[--color-bg-surface] border border-[--color-border] rounded-lg shadow-sm +**Input:** border-[--color-border] focus:ring-2 focus:ring-[--color-primary]/30 focus:border-[--color-primary] +**Modal:** bg-[--color-bg-surface] rounded-xl shadow-2xl, overlay bg-black/50 +**Toast:** success(green), error(red), warning(amber), info(blue) — 시멘틱 컬러 사용 + +### 1-5. docs/design/icons.md + +아이콘 시스템: +- Lucide React 사용 +- 사이즈: xs(14px), sm(16px), md(20px), lg(24px), xl(32px) +- 색상: 시멘틱 토큰 사용 (text-[--color-text-secondary] 기본) +- 인터랙티브 아이콘: hover 상태 시 text-[--color-primary] + +### 1-6. docs/design/motion.md + +모션 시스템: +- Duration: fast(100ms), normal(200ms), slow(300ms), slower(500ms) +- Easing: ease-out(진입), ease-in(퇴장), ease-in-out(이동) +- 패턴: fade-in, slide-up, scale, collapse +- prefers-reduced-motion: reduce 시 애니메이션 비활성화 + +### 1-7. docs/design/code-conventions.md + +코드 컨벤션: +- 파일명: PascalCase(컴포넌트), camelCase(유틸/훅), kebab-case(CSS) +- Tailwind 클래스 순서: layout → sizing → spacing → border → bg → text → effect → transition +- cn() 유틸리티 사용 (clsx + twMerge) +- import 순서: react → 외부 → 내부(@/) → 타입 → 스타일 +- forwardRef 패턴: DOM 래핑 컴포넌트에 적용 + +### 1-8. docs/design/do-dont.md + +Do/Don't 가이드: +- DO: CSS 변수 토큰 사용 (bg-[--color-primary]) +- DON'T: 하드코딩 HEX (#6D94C5, #507FB9, #5C6570, #9198A1, #D5D2CC, #1E2329 등) +- DO: 시멘틱 컬러로 상태 표현 +- DON'T: 임의 색상으로 상태 표현 +- DO: spacing 스케일 사용 (p-4, gap-6) +- DON'T: 임의 px값 (p-[13px]) +- DO: cn() 유틸리티로 조건부 클래스 +- DON'T: 삼항연산자로 className 문자열 조합 +- DO: 다크모드 버튼에 스케일 값 사용 (dark:bg-[--color-primary-600]) +- DON'T: 다크모드 버튼에 시멘틱 토큰 그대로 사용 (dark:bg-[--color-primary] → 연한 파스텔톤으로 구분 안됨) + +### 1-9. docs/design/prompts/new-component.md + +새 컴포넌트 생성 프롬프트 템플릿: +``` +[컴포넌트명] 컴포넌트를 만들어줘. +- docs/design/ 가이드 참조 +- Props interface 정의 +- 변형(variant), 사이즈(size) 지원 +- 다크모드 대응 (CSS 변수 토큰) +- forwardRef 적용 (DOM 래핑 시) +- cn() 유틸리티 사용 +``` + +### 1-10. docs/design/prompts/review-checklist.md + +디자인 리뷰 체크리스트 (9개 카테고리): +1. 컬러: CSS 변수 토큰 사용 여부, 하드코딩 HEX 없는지 +2. 타이포그래피: 타입 스케일 준수 +3. 스페이싱: 4px 스케일 준수 +4. 반응형: 브레이크포인트 대응 +5. 다크모드: .dark 클래스 + CSS 변수 동작 +6. 접근성: color contrast 4.5:1 이상 +7. 컴포넌트: variant/size 시스템 준수 +8. 모션: duration/easing 스케일 준수 +9. 코드: cn(), forwardRef, import 순서 + +### 1-11. docs/design/prompts/refactor-style.md + +스타일 리팩토링 프롬프트 템플릿: +``` +[파일/컴포넌트] 스타일을 디자인 시스템으로 리팩토링해줘. +- 하드코딩 색상 → CSS 변수 토큰 +- Tailwind 기본 색상(bg-gray-*, text-blue-*) → 커스텀 토큰 +- spacing 임의값 → 스케일 값 +- docs/design/ 가이드 기준으로 검증 +``` + +## 2. frontend/src/index.css 수정 + +현재 내용 유지하면서, `@import 'tailwindcss';` 뒤에 `@theme` 블록과 다크모드 블록을 추가해줘: + +```css +@import 'tailwindcss'; + +@custom-variant dark (&:where(.dark, .dark *)); + +@theme { + /* === Brand: Primary (Slate Blue) === */ + --color-primary-50: #F5F7F9; + --color-primary-100: #E5EBF2; + --color-primary-200: #D2DAE5; + --color-primary-300: #B7C5D7; + --color-primary-400: #8AA5C7; + --color-primary-500: #6D94C5; + --color-primary-600: #507FB9; + --color-primary-700: #3B669C; + --color-primary-800: #2D507B; + --color-primary-900: #1B2C41; + --color-primary-950: #0E1A2B; + + /* === Brand: Secondary (Powder Blue) === */ + --color-secondary-50: #F5F7F9; + --color-secondary-100: #E6EDF5; + --color-secondary-200: #D1DAE5; + --color-secondary-300: #B7C8D7; + --color-secondary-400: #89AAC8; + --color-secondary-500: #CBDCEB; + --color-secondary-600: #6B9AC8; + --color-secondary-700: #4E88BB; + --color-secondary-800: #396E9D; + --color-secondary-900: #1B2F41; + --color-secondary-950: #0E1A2B; + + /* === Brand: Accent (Warm Sand) === */ + --color-accent-50: #F9F8F6; + --color-accent-100: #F2EDE4; + --color-accent-200: #E4E0D7; + --color-accent-300: #D5CDB9; + --color-accent-400: #C4B48C; + --color-accent-500: #E8DFCA; + --color-accent-600: #B59854; + --color-accent-700: #9A7E3E; + --color-accent-800: #786230; + --color-accent-900: #3F351D; + --color-accent-950: #2B2312; + + /* === Semantic === */ + --color-success: #059669; + --color-warning: #D97706; + --color-danger: #DC2626; + --color-info: #0284C7; + + /* === Neutral (Light defaults) === */ + --color-bg-base: #F5EFE6; + --color-bg-surface: #FFFFFF; + --color-bg-elevated: #FFFFFF; + --color-border: #D5D2CC; + --color-border-strong: #9198A1; + --color-text-primary: #1E2329; + --color-text-secondary: #5C6570; + --color-text-tertiary: #9198A1; + + /* === Design Tokens (Light defaults) === */ + --color-primary: #507FB9; + --color-primary-hover: #3B669C; + --color-primary-active: #2D507B; + --color-primary-subtle: #F5F7F9; + --color-primary-text: #2D507B; + --color-secondary: #CBDCEB; + --color-secondary-hover: #89AAC8; + --color-secondary-active: #4E88BB; + --color-secondary-subtle: #F5F7F9; + --color-secondary-text: #396E9D; + --color-accent: #E8DFCA; + --color-accent-hover: #C4B48C; + --color-accent-active: #B59854; + --color-accent-subtle: #F9F8F6; + --color-accent-text: #786230; + + /* === Chart Palette === */ + --color-chart-1: #507FB9; + --color-chart-2: #B59854; + --color-chart-3: #4E88BB; + --color-chart-4: #9A7E3E; + --color-chart-5: #3B669C; + --color-chart-6: #C4B48C; + + /* === Typography === */ + --font-sans: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, 'Helvetica Neue', 'Segoe UI', 'Apple SD Gothic Neo', 'Noto Sans KR', 'Malgun Gothic', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', sans-serif; + --font-mono: 'JetBrains Mono', 'Fira Code', Consolas, Monaco, 'Courier New', monospace; +} + +/* === Dark Mode === */ +@media (prefers-color-scheme: dark) { + :root:not(.light) { + --color-success: #34D399; + --color-warning: #FBBF24; + --color-danger: #FCA5A5; + --color-info: #38BDF8; + + --color-bg-base: #131416; + --color-bg-surface: #1E2023; + --color-bg-elevated: #282A2E; + --color-border: #3A3C41; + --color-border-strong: #5C6570; + --color-text-primary: #F4F5F5; + --color-text-secondary: #9198A1; + --color-text-tertiary: #5C6570; + + --color-primary: #B7C5D7; + --color-primary-hover: #D2DAE5; + --color-primary-active: #8AA5C7; + --color-primary-subtle: #1B2C41; + --color-primary-text: #D2DAE5; + --color-secondary: #B7C8D7; + --color-secondary-hover: #D1DAE5; + --color-secondary-active: #89AAC8; + --color-secondary-subtle: #1B2F41; + --color-secondary-text: #D1DAE5; + --color-accent: #D5CDB9; + --color-accent-hover: #E4E0D7; + --color-accent-active: #C4B48C; + --color-accent-subtle: #3F351D; + --color-accent-text: #E4E0D7; + + --color-chart-1: #6D94C5; + --color-chart-2: #C4B48C; + --color-chart-3: #6B9AC8; + --color-chart-4: #B59854; + --color-chart-5: #8AA5C7; + --color-chart-6: #D5CDB9; + } +} + +.dark { + --color-success: #34D399; + --color-warning: #FBBF24; + --color-danger: #FCA5A5; + --color-info: #38BDF8; + + --color-bg-base: #131416; + --color-bg-surface: #1E2023; + --color-bg-elevated: #282A2E; + --color-border: #3A3C41; + --color-border-strong: #5C6570; + --color-text-primary: #F4F5F5; + --color-text-secondary: #9198A1; + --color-text-tertiary: #5C6570; + + --color-primary: #B7C5D7; + --color-primary-hover: #D2DAE5; + --color-primary-active: #8AA5C7; + --color-primary-subtle: #1B2C41; + --color-primary-text: #D2DAE5; + --color-secondary: #B7C8D7; + --color-secondary-hover: #D1DAE5; + --color-secondary-active: #89AAC8; + --color-secondary-subtle: #1B2F41; + --color-secondary-text: #D1DAE5; + --color-accent: #D5CDB9; + --color-accent-hover: #E4E0D7; + --color-accent-active: #C4B48C; + --color-accent-subtle: #3F351D; + --color-accent-text: #E4E0D7; + + --color-chart-1: #6D94C5; + --color-chart-2: #C4B48C; + --color-chart-3: #6B9AC8; + --color-chart-4: #B59854; + --color-chart-5: #8AA5C7; + --color-chart-6: #D5CDB9; +} + +/* Dark mode date input calendar icon */ +.dark input[type="date"]::-webkit-calendar-picker-indicator { + filter: invert(1); +} +``` + +## 3. cn() 유틸리티 생성 + +`frontend/src/utils/cn.ts` 파일을 생성: +```ts +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs)); +``` + +clsx와 tailwind-merge 패키지가 없으면 설치해줘: +```bash +cd frontend && npm install clsx tailwind-merge +``` + +## 4. 차트 팔레트 상수 파일 생성 + +`frontend/src/constants/chart.ts`: +```ts +export const CHART_COLORS = [ + 'var(--color-chart-1)', + 'var(--color-chart-2)', + 'var(--color-chart-3)', + 'var(--color-chart-4)', + 'var(--color-chart-5)', + 'var(--color-chart-6)', +] as const; + +/** CSS computed value가 필요한 경우 (Recharts 등) */ +export const CHART_COLORS_HEX = { + light: ['#507FB9', '#B59854', '#4E88BB', '#9A7E3E', '#3B669C', '#C4B48C'], + dark: ['#6D94C5', '#C4B48C', '#6B9AC8', '#B59854', '#8AA5C7', '#D5CDB9'], +} as const; +``` + +## 5. CLAUDE.md에 디자인 가이드 참조 추가 + +CLAUDE.md의 `## 팀 규칙` 섹션 아래에 다음을 추가: + +```markdown +## 디자인 시스템 + +- 컬러 시스템: `docs/design/colors.md` +- 타이포그래피: `docs/design/typography.md` +- 스페이싱/레이아웃: `docs/design/spacing.md` +- 컴포넌트 스펙: `docs/design/components.md` +- 아이콘: `docs/design/icons.md` +- 모션: `docs/design/motion.md` +- 코드 컨벤션: `docs/design/code-conventions.md` +- Do/Don't: `docs/design/do-dont.md` + +### 프롬프트 템플릿 +- 새 컴포넌트: `docs/design/prompts/new-component.md` +- 리뷰 체크리스트: `docs/design/prompts/review-checklist.md` +- 스타일 리팩토링: `docs/design/prompts/refactor-style.md` + +### 핵심 규칙 +- 색상은 반드시 CSS 변수 토큰 사용 (하드코딩 HEX 금지) +- 브랜드 컬러: Primary #6D94C5(Slate Blue), Secondary #CBDCEB(Powder Blue), Accent #E8DFCA(Warm Sand), BG #F5EFE6(Warm Cream) +- 다크모드: `.dark` 클래스 + CSS 변수 자동 전환 +- 차트: CHART_COLORS_HEX 상수 사용 (Cool+Warm 교차 배치) +- Tailwind 기본 색상(gray-*, blue-* 등) 대신 커스텀 토큰 사용 +``` + +## 6. 빌드 검증 + +모든 파일 생성 후: +1. `cd frontend && npm run build` 로 프론트엔드 빌드 성공 확인 +2. 에러 없으면 커밋: + - 1차 커밋: `docs(design): 디자인 시스템 가이드 문서 추가` + - 2차 커밋: `feat(frontend): 디자인 토큰 및 테마 시스템 적용` + +## 주의사항 + +- 기존 컴포넌트의 하드코딩 색상(bg-gray-900, text-blue-500 등)은 이번 작업에서는 변경하지 않는다 (별도 리팩토링 예정) +- ThemeContext.tsx는 이미 존재하므로 수정하지 않는다 +- `@theme` 블록은 반드시 `@import 'tailwindcss';` 뒤, `@custom-variant` 뒤에 위치해야 한다 +- npm 레지스트리는 frontend/.npmrc에 설정된 Nexus 프록시를 사용한다 +``` + +--- + +**사용법:** 위의 ` ``` ` 블록 안의 전체 내용을 복사하여 Claude Code에 프롬프트로 입력하세요. diff --git a/design-system-preview.html b/design-system-preview.html new file mode 100644 index 0000000..91854da --- /dev/null +++ b/design-system-preview.html @@ -0,0 +1,670 @@ + + + + + +SNP Connection Monitoring — 디자인 시스템 프리뷰 + + + +
+ + + + + +
+
+

대시보드

+
+
+ +
+ +
+
+ +
+ + +
+
+
총 API 요청
+
오늘
+
12,847
+
+ + +12.5% vs 어제 +
+
+
+
활성 서비스
+
연결된 서비스
+
24 / 26
+
+ + 2개 서비스 점검중 +
+
+
+
평균 응답 시간
+
최근 1시간
+
142ms
+
+ + -8.2% 개선 +
+
+
+
에러율
+
최근 24시간
+
0.34%
+
+ + 정상 범위 +
+
+
+ + +
+
+
+
+
시간대별 API 요청 추이
+
최근 12시간
+
+
+ + + +
+
+
+
00
+
01
+
02
+
03
+
04
+
05
+
06
+
07
+
08
+
09
+
10
+
11
+
+
+ +
+
서비스별 요청 비율
+
전체 트래픽 기준
+
+
+ + + + + + + + +
+
26
+
서비스
+
+
+
+
AIS 34.8%
+
기상 22.0%
+
항로 15.9%
+
조류 10.1%
+
기타 17.2%
+
+
+
+
+ + +
+
+
+
서비스 연결 현황
+
모니터링 대상 서비스 목록
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
서비스명상태API 키요청수응답시간마지막 응답
AIS 선박위치 API 정상snp-ais-****-7f2a4,52189ms방금 전
해양기상 데이터 정상snp-wth-****-3e8b2,847156ms3초 전
항로 정보 서비스 지연snp-rte-****-9d1c2,054342ms12초 전
조류/해류 API 점검snp-crt-****-5a7e1,30210분 전
CCTV 영상 서비스 장애snp-cam-****-2b4f12345분 전
+
+
+ + +
+
컴포넌트 시스템
+ +
+
Buttons
+
+ + + + + + +
+
+ + + +
+
+ +
+
Badges
+
+ Default + Primary + Secondary + Accent + Success + Warning + Danger + Info +
+
+ +
+
Inputs
+
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
Toasts
+
+
✓ 서비스가 정상적으로 등록되었습니다.
+
⚠ 응답 시간이 임계값을 초과했습니다.
+
✕ 서비스 연결에 실패했습니다.
+
ℹ 시스템 점검이 예정되어 있습니다.
+
+
+
+ + +
+
컬러 팔레트
+ +
Primary — Slate Blue
+
+
50
+
100
+
200
+
300
+
400
+
500
+
600
+
700
+
800
+
900
+
950
+
+ +
Secondary — Powder Blue
+
+
50
+
100
+
200
+
300
+
400
+
500
+
600
+
700
+
800
+
900
+
950
+
+ +
Accent — Warm Sand
+
+
50
+
100
+
200
+
300
+
400
+
500
+
600
+
700
+
800
+
900
+
950
+
+ +
Chart Palette — Cool + Warm 교차
+
+
1
+
2
+
3
+
4
+
5
+
6
+
+
+ +
+
+
+ + + + diff --git a/docs/design/code-conventions.md b/docs/design/code-conventions.md new file mode 100644 index 0000000..9b7b884 --- /dev/null +++ b/docs/design/code-conventions.md @@ -0,0 +1,212 @@ +# 코드 컨벤션 + +프론트엔드 디자인 시스템 적용을 위한 코드 작성 규칙. + +--- + +## 파일 네이밍 + +| 유형 | 규칙 | 예시 | +|------|------|------| +| 컴포넌트 | PascalCase | `Button.tsx`, `UserCard.tsx` | +| 훅 | camelCase, `use` 접두사 | `useModal.ts`, `useTheme.ts` | +| 유틸리티 | camelCase | `cn.ts`, `formatDate.ts` | +| 상수 | camelCase | `chart.ts`, `routes.ts` | +| 타입 | camelCase | `user.ts`, `apihub.ts` | +| 스타일 | camelCase | `index.css` | + +컴포넌트 파일 당 하나의 `export default` 컴포넌트. + +--- + +## Tailwind 클래스 순서 + +가독성을 위해 다음 순서로 클래스를 작성한다. Prettier + prettier-plugin-tailwindcss로 자동 정렬 권장. + +1. **레이아웃** — `flex`, `grid`, `block`, `hidden`, `relative`, `fixed`, `z-*` +2. **크기** — `w-*`, `h-*`, `min-w-*`, `max-w-*`, `size-*` +3. **여백** — `m-*`, `mx-*`, `my-*`, `p-*`, `px-*`, `py-*`, `gap-*` +4. **테두리** — `border*`, `rounded-*`, `ring-*`, `outline-*` +5. **배경** — `bg-*`, `shadow-*`, `backdrop-*` +6. **텍스트** — `text-*`, `font-*`, `leading-*`, `tracking-*`, `truncate` +7. **색상** — `text-[var(*)]`, `bg-[var(*)]` +8. **상호작용** — `cursor-*`, `select-*`, `pointer-events-*` +9. **트랜지션** — `transition-*`, `duration-*`, `ease-*`, `animate-*` +10. **반응형** — `sm:*`, `md:*`, `lg:*`, `xl:*` +11. **다크모드** — `dark:*` +12. **상태** — `hover:*`, `focus:*`, `active:*`, `disabled:*`, `aria-*:` + +```tsx +// 올바른 예 +
+``` + +--- + +## cn() 유틸리티 + +`clsx` + `tailwind-merge` 조합. 조건부 클래스와 클래스 충돌 해결에 사용한다. + +```ts +// src/utils/cn.ts +import { type ClassValue, clsx } from 'clsx'; +import { twMerge } from 'tailwind-merge'; + +export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs)); +``` + +### 사용 패턴 + +```tsx +// 기본 사용 +
+ +// 조건부 클래스 + +
+ + +
...
+ + +
+ + +
+
+ +``` + +### 사이즈 + +| Size | max-width | +|------|-----------| +| `sm` | `max-w-sm` (384px) | +| `md` | `max-w-md` (448px) | +| `lg` | `max-w-lg` (512px) | +| `xl` | `max-w-xl` (576px) | + +### 접근성 + +- `role="dialog"`, `aria-modal="true"`, `aria-labelledby` 필수 +- 열릴 때 첫 번째 포커스 가능 요소로 포커스 이동 +- Escape 키로 닫기 +- Backdrop 클릭 시 닫기 (선택적) +- 열린 동안 body 스크롤 잠금 + +--- + +## Toast + +### 위치 + +`fixed bottom-4 right-4 z-[60]` (Modal보다 위) + +### 변형 + +| Variant | 아이콘 | 색상 | +|---------|--------|------| +| `success` | CheckCircle | `--color-success` | +| `warning` | AlertTriangle | `--color-warning` | +| `error` | XCircle | `--color-danger` | +| `info` | Info | `--color-info` | + +### 구조 + +```html +
+ + + +
+``` + +### 동작 + +- 기본 자동 닫힘: 4000ms +- 진입: `translate-y-2 opacity-0` → `translate-y-0 opacity-100` +- 퇴장: `translate-y-0 opacity-100` → `translate-y-2 opacity-0` +- 트랜지션: `duration-200 ease-out` diff --git a/docs/design/do-dont.md b/docs/design/do-dont.md new file mode 100644 index 0000000..5a54466 --- /dev/null +++ b/docs/design/do-dont.md @@ -0,0 +1,212 @@ +# Do & Don't + +디자인 시스템 적용 시 자주 발생하는 실수와 올바른 방법. + +--- + +## CSS 변수 토큰 + +### 색상 + +**DO** — CSS 변수 토큰 사용 + +```tsx +
+``` + +**DON'T** — HEX 하드코딩 + +```tsx +// 다크 모드 전환 불가, 토큰 변경 시 전부 수정 필요 +
+``` + +**DON'T** — Tailwind 기본 팔레트로 브랜드 컬러 표현 + +```tsx +// 브랜드 컬러(#6D94C5)와 blue-500(#3B82F6)은 다른 색상 +
+``` + +--- + +## 시멘틱 컬러 + +**DO** — 의미에 맞는 시멘틱 컬러 사용 + +```tsx +// 성공 상태 +완료 + +// 오류 메시지 +

{errorMessage}

+ +// 경고 알림 +
+``` + +**DON'T** — 브랜드 컬러를 시멘틱 용도로 사용 + +```tsx +// Primary 컬러는 성공/오류를 표현하지 않음 +

저장에 실패했습니다

+``` + +**DON'T** — 시멘틱 컬러를 장식 목적으로 사용 + +```tsx +// danger 컬러는 위험/오류 상황 전용 +인기 +``` + +--- + +## Spacing 스케일 + +**DO** — 4px 단위 스케일 사용 + +```tsx +
// 16px / 8px / 24px +
// 12px / 6px (sm 버튼) +``` + +**DON'T** — 임의의 px 값 + +```tsx +
+``` + +**DON'T** — 인라인 스타일로 여백 지정 + +```tsx +
+``` + +--- + +## cn() 유틸리티 + +**DO** — 조건부 클래스에 `cn()` 사용 + +```tsx + +``` + +### 텍스트와 인라인 정렬 + +```tsx + + + 2시간 전 + +``` + +### 아이콘 전용 버튼 + +```tsx + +``` + +### 상태 아이콘 + +```tsx + + + + +``` + +--- + +## 접근성 + +- 장식용 아이콘: `aria-hidden="true"` 필수 +- 의미 있는 아이콘: `aria-label` 또는 시각적으로 숨긴 텍스트 제공 + +```tsx +// 장식용 +