Skip to content

Conversation

@changsu1993
Copy link

@changsu1993 changsu1993 commented Nov 24, 2025

Chapter3-1. UI 컴포넌트 모듈화와 디자인 시스템

과제 목표

레거시 코드베이스를 현대적인 디자인 시스템으로 개편하는 실무 경험

  1. 정리되지 않은 레거시 코드의 문제점 식별 및 분석
  2. TailwindCSS, shadcn/ui, CVA 등의 현대 도구 활용
  3. 일관된 디자인 토큰과 컴포넌트 API 구축
  4. UI와 비즈니스 로직이 적절한 분리된 리팩토링

Before 패키지 분석 후 After 패키지 개편

개편 목표

디자인 시스템

  • TailwindCSS 기반 일관된 디자인 토큰 정의
  • 하드코딩 제거, 재사용 가능한 스타일 시스템 구축
  • dark mode, 반응형 등 확장 가능한 구조

컴포넌트 아키텍처

  • UI 컴포넌트는 순수하게 UI만 담당
  • 도메인 로직은 적절히 분리
  • 일관된 컴포넌트 API 설계

사용할 도구

TailwindCSS 4.x

  • 디자인 토큰 기반 스타일링
  • 유틸리티 클래스 활용
  • dark mode, 반응형 내장 지원

shadcn/ui

  • Radix UI 기반, 접근성 내장
  • 복사 가능한 컴포넌트 (라이브러리가 아닌 소스코드)
  • 자유로운 커스터마이징

CVA (Class Variance Authority)

  • 선언적 variants 패턴
  • 타입 안전한 스타일 조합
  • 조건부 스타일링 처리

React Hook Form + Zod

  • 선언적 폼 검증
  • 타입 안전한 스키마
  • 최소 리렌더링 최적화

필수 과제

1. 디자인 시스템 구축

  • TailwindCSS 설정 및 디자인 토큰 정의
  • shadcn/ui 컴포넌트 설치 (Button, Input, Select, Card, Table 등)
  • CVA를 활용한 variants 패턴 적용
  • 일관된 스타일 시스템 구축

2. Before 패키지 분석

  • Before 패키지 실행 및 전체 코드 탐색
  • 스타일링, 컴포넌트 설계, 폼 관리 측면에서 문제점 파악
  • 개선이 필요한 부분과 그 이유 정리

3. 컴포넌트 개편

  • UI와 비즈니스 로직 분리
  • 순수한 UI 컴포넌트로 재구성
  • 일관된 컴포넌트 API 설계
  • 적절한 컴포넌트 구조 설계

심화 과제

  • Dark Mode 완전 지원 (CSS Variables + Tailwind)
  • Design Token 시스템 고도화 (색상 팔레트, 타이포그래피 스케일)
  • 뷰와 비즈니스로직이 분리되도록

과제 회고

https://changsu1993.github.io/front_7th_chapter3-1/
https://changsu1993.github.io/front_7th_chapter3-1/storybook/

과제를 진행하면서 느낀 점, 배운 점을 자유롭게 작성해주세요.

Before 패키지에서 발견한 문제점

  • 뒤죽박죽 스타일링
  • prop 다름
  • form 컴포넌트 안에 복잡한 로직

개편 과정에서 집중한 부분

  • css 변수 통일
  • CVA로 variant 패턴 정리
  • 복잡한 로직이 아닌 명확한 역할 분리 (ui는 ui의 역할로만!)
  • 테스트 깨지는 문제 해결

사용한 기술 스택 경험

어려웠던 점과 해결 방법

리뷰받고 싶거나 질문하고 싶은 내용

@changsu1993 changsu1993 changed the title docs: 과제를 위한 빈 커밋 [6팀 박창수] Chapter3-1. UI 컴포넌트 모듈화와 디자인 시스템 Nov 24, 2025
changsu1993 and others added 22 commits November 24, 2025 16:18
- TailwindCSS v4 + CVA 설정
- Radix UI 프리미티브 설치
- shadcn/ui 스타일 컴포넌트 구현:
  - Button, Badge, Input, Label
  - Textarea, Checkbox, Card
  - Alert, Dialog, Select, Table
- 디자인 토큰 (CSS 변수) 설정
- Dark mode 지원 준비
- 일관된 API를 가진 Form 컴포넌트:
  - FormField: 기본 래퍼 컴포넌트
  - FormInput, FormSelect, FormTextarea, FormCheckbox
  - 공통 props: name, label, helperText, error, disabled, required
- Header 컴포넌트: props 기반 커스터마이징 지원
- 모든 컴포넌트에 접근성 속성 추가 (aria-describedby, aria-invalid)
- Storybook 8.6.14 설정 (.storybook/main.ts, preview.ts)
- 주요 컴포넌트 Stories 작성:
  - Button: variants, sizes, icons, loading states
  - Badge: variants, status examples
  - Card: layouts, post/user card examples
  - Alert: variants, with/without title
  - FormInput: states, types, validation
  - Table: basic, badges, actions, empty state
- Dark mode 지원을 위한 배경 설정
- a11y addon 포함
- 레거시 컴포넌트 import를 @/components/ui로 변경
- 인라인 스타일을 TailwindCSS 클래스로 교체
- Modal -> Dialog 컴포넌트로 변경
- FormInput, FormSelect, FormTextarea 새 API 적용
- Table 수동 구성 (TableHeader, TableBody, TableRow 등)
- Badge 컴포넌트로 상태 표시 개선
- Stats 카드를 Card 컴포넌트로 변경
- 비즈니스 로직은 페이지 컴포넌트에 유지 (관심사 분리)
- 필수/심화 구현 사항 체크리스트 추가
- 컴포넌트 구조 비교 (Atomic Design → flat ui/)
- 스타일링 방식 비교 (인라인 → TailwindCSS + CVA)
- 컴포넌트 API 일관성 개선 내용
- 비즈니스 로직 분리 예제
- 접근성 개선 사항
- Modal → Dialog 마이그레이션
- 기술 스택 비교 테이블
- 실행 방법 추가
- ThemeProvider 컴포넌트 추가 (light/dark/system 테마 지원)
- ThemeToggle 버튼 컴포넌트 추가
- localStorage에 테마 설정 저장
- App.tsx에 ThemeProvider 및 Header에 toggle 버튼 추가
- 레거시 Header를 새로운 Header 컴포넌트로 교체
- README 심화 구현 체크리스트 완료 표시
- 하드코딩된 색상(text-gray-800, bg-gray-100 등)을 CSS 변수 기반으로 변경
- 통계 카드에 dark: 변형 클래스 추가
- 테이블 컨테이너 배경색을 bg-background로 변경
- 테두리를 border-border로 통일
- hooks/: useAlert, useModalState, useFormState, useEntityManagement, useEntityStats, useBadgeVariant
- tokens/: colors, typography, spacing, variants 디자인 토큰
- ManagementPage 리팩토링으로 커스텀 훅 적용
- atoms/, molecules/, organisms/ 폴더 삭제
- shadcn/ui 스타일로 components/ui/ 폴더만 사용
- CSS 변수를 before 패키지의 원본 색상으로 변경
  - primary: #1976d2 (btn-primary)
  - destructive: #d32f2f (btn-danger)
  - success: #388e3c (btn-success)
  - warning: #f57c00 (badge-warning)
  - info: #0288d1 (badge-info)
- tokens/colors.ts에 legacyColors 참조 추가
- 다크모드 색상도 적절히 조정
- styles/index.css: Alert 전용 CSS 변수 추가 (bg, border, text)
  - Light mode: info, success, warning, destructive, default
  - Dark mode: 각 타입별 적절한 다크 테마 색상
- alert.tsx: CVA에 CSS 변수 참조 방식 적용
- tokens/colors.ts: legacyAlertColors 참조 및 CSS 변수 매핑 추가
- tokens/variants.ts: alertVariants CSS 변수 방식으로 업데이트

디자인 시스템 원칙 준수: 하드코딩 대신 CSS 변수 기반 토큰 시스템 사용
- useBadgeVariant: getCategoryVariant 함수 추가 (카테고리별 색상 매핑)
- useBadgeVariant: 상태/역할 색상을 before와 일치하도록 수정
  - archived: destructive → secondary (회색)
  - admin: info → destructive (빨간색)
  - moderator: default → warning (주황색)
  - user: secondary → default (파란색)
- ManagementPage: 카테고리 Badge에 색상 적용
- ManagementPage: 보관/복원 버튼 색상 before와 일치
- useFormState: initialState dependency로 인한 무한 루프 버그 수정

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
v3/v4 문법 혼용 방지를 위한 스킬 파일 생성
- @theme directive 및 v4 설정 방식 가이드
- 프로젝트 디자인 토큰 참조
- CVA 패턴 예제 포함

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- native-select.tsx 추가 (CVA 기반)
- FormSelect를 Native Select 기반으로 변경
- ManagementPage에서 SelectItem → option 태그로 변경
- DialogContent에 aria-describedby 명시적 처리 (접근성 경고 해결)
- 미사용 Radix Select 컴포넌트 삭제 (번들 크기 48KB 감소)

테스트 코드 수정 없이 native select 사용으로 테스트 통과

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- @radix-ui/react-select, @radix-ui/react-alert-dialog 제거
- FormSelect.stories.tsx 추가 (Native Select 기반)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- components.css 삭제 (Tailwind CSS 사용으로 불필요)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- legacyColors, legacyAlertColors 제거 (before 참조용 불필요)
- variants.ts 삭제 (컴포넌트 내부에서 CVA 직접 정의)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- eslint.config.js: 미사용 storybook 플러그인 import 제거
- eslint.config.js: shadcn/ui 패턴 허용 (allowConstantExport)
- useEntityManagement.ts: 불필요한 try/catch 제거
- input.tsx, textarea.tsx: 빈 interface를 type alias로 변경
- native-select.tsx: 미사용 nativeSelectVariants export 제거

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- vite.config.ts: base 경로 설정
- .storybook/main.ts: Storybook base 경로 설정
- .github/workflows/deploy.yml: 자동 배포 workflow 추가

배포 URL:
- App: https://changsu1993.github.io/front_7th_chapter3-1/
- Storybook: https://changsu1993.github.io/front_7th_chapter3-1/storybook/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant