Files
sam-design/src/DESIGN_SYSTEM_EXAMPLE.md
정재웅 060b9ce2ef 프로젝트 초기 설정 및 구조 추가
- Vite + React 프로젝트 구조 설정
- 불필요한 PDF 파일 삭제

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 13:01:43 +09:00

13 KiB

디자인 시스템 실전 예제

예제: 품목관리 페이지 분석

품목관리 페이지(ItemManagement.tsx)를 아토믹 디자인 시스템으로 분해해보겠습니다.

페이지 전체 구조

ItemManagement (Page)
│
├── PageHeader (Organism)
│   ├── 📦 Icon (Atom) - Archive icon
│   ├── "품목관리" (Text)
│   └── "제품 및 자재 품목을 관리합니다" (Text)
│
├── StatCards (Organism)
│   ├── StatCard (Molecule)
│   │   ├── 📊 Icon (Atom) - Box icon
│   │   ├── "총 품목" (Label)
│   │   └── "74" (Value)
│   │
│   ├── StatCard (Molecule)
│   │   ├── 📦 Icon (Atom) - Package icon
│   │   ├── "제품" (Label)
│   │   └── "15" (Value)
│   │
│   ├── StatCard (Molecule)
│   │   ├── 🔧 Icon (Atom) - Wrench icon
│   │   ├── "반제품" (Label)
│   │   └── "28" (Value)
│   │
│   └── StatCard (Molecule)
│       ├── 📋 Icon (Atom) - Archive icon
│       ├── "자재" (Label)
│       └── "31" (Value)
│
├── SearchFilter (Organism)
│   ├── SearchBar (Molecule)
│   │   ├── 🔍 Icon (Atom) - Search icon
│   │   └── Input (Atom) - "품목명, 품목코드 검색..."
│   │
│   ├── Select (Atom) - 품목 유형 필터
│   └── Button (Atom) - "+ 품목 등록"
│
└── DataTable (Organism)
    ├── Table (Atom)
    │   ├── 품목코드 (Column)
    │   ├── 품목명 (Column)
    │   ├── 품목유형 (Column)
    │   │   └── StatusBadge (Molecule)
    │   │       └── Badge (Atom)
    │   ├── 규격 (Column)
    │   ├── 단위 (Column)
    │   ├── 단가 (Column)
    │   ├── 재고 (Column)
    │   └── 관리 (Column)
    │       └── TableActions (Molecule)
    │           ├── Button (Atom) - 보기
    │           ├── Button (Atom) - 수정
    │           └── Button (Atom) - 삭제
    │
    └── Pagination (Component)

코드 예제: 품목관리 페이지

1. 기존 방식 (비추천)

// ❌ 모든 것을 직접 구현
export function ItemManagement() {
  return (
    <div className="p-6">
      {/* 헤더를 직접 구현 */}
      <div className="flex items-center gap-3 mb-6">
        <div className="bg-blue-100 p-3 rounded-lg">
          <Archive className="w-6 h-6 text-blue-600" />
        </div>
        <div>
          <h1 className="text-2xl font-semibold">품목관리</h1>
          <p className="text-gray-600">제품  자재 품목을 관리합니다</p>
        </div>
      </div>

      {/* 통계 카드를 직접 구현 */}
      <div className="grid grid-cols-4 gap-4 mb-6">
        <div className="bg-white p-4 rounded-lg border">
          <div className="flex items-center justify-between">
            <div>
              <p className="text-sm text-gray-600"> 품목</p>
              <p className="text-2xl font-semibold">74</p>
            </div>
            <div className="bg-blue-100 p-3 rounded-lg">
              <Box className="w-5 h-5 text-blue-600" />
            </div>
          </div>
        </div>
        {/* 나머지 카드들... */}
      </div>

      {/* 검색/필터를 직접 구현 */}
      <div className="flex gap-4 mb-6">
        <div className="flex-1 relative">
          <Search className="absolute left-3 top-3 w-4 h-4 text-gray-400" />
          <input
            type="text"
            placeholder="품목명, 품목코드 검색..."
            className="w-full pl-10 pr-4 py-2 border rounded-lg"
          />
        </div>
        {/* 필터들... */}
      </div>

      {/* 테이블을 직접 구현 */}
      <table className="w-full">
        {/* 테이블 내용... */}
      </table>
    </div>
  );
}

문제점:

  • 코드가 길고 복잡함 (500+ 줄)
  • 재사용 불가능
  • 다른 페이지와 일관성 없음
  • 유지보수 어려움
  • 스타일 변경 시 모든 페이지 수정 필요

2. 아토믹 디자인 시스템 방식 (권장)

// ✅ 컴포넌트 재사용
import { PageHeader } from "./organisms/PageHeader";
import { StatCards } from "./organisms/StatCards";
import { SearchFilter } from "./organisms/SearchFilter";
import { DataTable } from "./organisms/DataTable";
import { Archive, Box, Package, Wrench } from "lucide-react";

export function ItemManagement() {
  const stats = [
    { label: "총 품목", value: "74", icon: Box, iconColor: "text-blue-600" },
    { label: "제품", value: "15", icon: Package, iconColor: "text-green-600" },
    { label: "반제품", value: "28", icon: Wrench, iconColor: "text-orange-600" },
    { label: "자재", value: "31", icon: Archive, iconColor: "text-purple-600" },
  ];

  const columns = [
    { key: "itemCode", label: "품목코드" },
    { key: "itemName", label: "품목명" },
    { key: "itemType", label: "품목유형", render: (value) => <StatusBadge status={value} /> },
    { key: "spec", label: "규격" },
    { key: "unit", label: "단위" },
    { key: "unitPrice", label: "단가" },
    { key: "stock", label: "재고" },
  ];

  return (
    <div className="flex-1 overflow-auto">
      <PageHeader
        icon={Archive}
        title="품목관리"
        subtitle="제품 및 자재 품목을 관리합니다"
      />

      <div className="p-6">
        <StatCards stats={stats} />

        <SearchFilter
          searchValue={searchTerm}
          onSearchChange={setSearchTerm}
          searchPlaceholder="품목명, 품목코드 검색..."
          filters={[
            { type: "select", label: "품목 유형", value: filter, onChange: setFilter }
          ]}
          actions={[
            { label: "+ 품목 등록", onClick: handleCreate, variant: "default" }
          ]}
        />

        <DataTable
          columns={columns}
          data={filteredItems}
          onView={handleView}
          onEdit={handleEdit}
          onDelete={handleDelete}
        />
      </div>
    </div>
  );
}

장점:

  • 코드가 짧고 명확함 (100줄 이하)
  • 재사용 가능
  • 다른 페이지와 일관성 유지
  • 유지보수 쉬움
  • 컴포넌트만 수정하면 모든 페이지에 자동 반영

디자인 토큰 활용 예제

색상 변경 시나리오

현재 Primary 색상을 파란색(#3B82F6)에서 초록색(#10B981)으로 변경한다면:

기존 방식:

// ❌ 모든 파일을 찾아서 수정해야 함
// ItemManagement.tsx
<div className="bg-blue-600">...</div>

// CustomerManagement.tsx
<div className="bg-blue-600">...</div>

// OrderManagement.tsx
<div className="bg-blue-600">...</div>

// ... 50개 이상의 파일 수정 필요

디자인 토큰 방식:

/* ✅ globals.css에서 한 줄만 수정 */
:root {
  --primary: #10B981; /* #3B82F6에서 변경 */
}

/* 모든 페이지에 자동 반영됨 */

실전 워크플로우

새 페이지 생성하기

Step 1: 템플릿 선택

// 목록 페이지인 경우
import { ListPageTemplate } from "./templates/ListPageTemplate";

// 폼 페이지인 경우
import { FormPageTemplate } from "./templates/FormPageTemplate";

// 대시보드 페이지인 경우
import { DashboardTemplate } from "./templates/DashboardTemplate";

Step 2: 데이터 준비

export function NewPage() {
  // 통계 데이터
  const stats = [
    { label: "총 개수", value: "100", icon: Box },
    { label: "진행중", value: "50", icon: Clock },
    { label: "완료", value: "30", icon: CheckCircle },
    { label: "보류", value: "20", icon: XCircle },
  ];

  // 테이블 컬럼
  const columns = [
    { key: "id", label: "ID" },
    { key: "name", label: "이름" },
    { key: "status", label: "상태", render: (value) => <StatusBadge status={value} /> },
  ];

  // 데이터
  const [data, setData] = useState([]);
  const [searchTerm, setSearchTerm] = useState("");
}

Step 3: 템플릿 적용

return (
  <ListPageTemplate
    // Header
    title="새 페이지"
    description="페이지 설명"
    icon={Database}
    
    // Stats
    stats={stats}
    
    // Search & Filter
    searchValue={searchTerm}
    onSearchChange={setSearchTerm}
    
    // Table
    columns={columns}
    data={filteredData}
    onView={handleView}
    onEdit={handleEdit}
    onDelete={handleDelete}
  />
);

완성! 3단계로 표준화된 페이지 생성 완료

컴포넌트 커스터마이징

예제: StatusBadge 색상 규칙 추가

현재 StatusBadge는 특정 상태값에 따라 자동으로 색상을 매핑합니다:

// StatusBadge.tsx (현재)
const getStatusColor = (status: string) => {
  const statusLower = status.toLowerCase();
  
  if (statusLower.includes('완료') || statusLower.includes('성공')) {
    return 'bg-green-100 text-green-800';
  }
  if (statusLower.includes('진행') || statusLower.includes('처리')) {
    return 'bg-blue-100 text-blue-800';
  }
  if (statusLower.includes('대기') || statusLower.includes('보류')) {
    return 'bg-yellow-100 text-yellow-800';
  }
  if (statusLower.includes('취소') || statusLower.includes('실패')) {
    return 'bg-red-100 text-red-800';
  }
  
  return 'bg-gray-100 text-gray-800';
};

새 상태 "검토중" 추가:

// StatusBadge.tsx (수정)
const getStatusColor = (status: string) => {
  const statusLower = status.toLowerCase();
  
  // ... 기존 코드 ...
  
  if (statusLower.includes('검토')) {
    return 'bg-purple-100 text-purple-800';
  }
  
  return 'bg-gray-100 text-gray-800';
};

이제 모든 페이지의 "검토중" 상태가 자동으로 보라색으로 표시됩니다!

반응형 디자인 자동 지원

아토믹 디자인 시스템의 모든 컴포넌트는 자동으로 반응형을 지원합니다:

// ✅ 자동으로 모바일/데스크톱 대응
<StatCards stats={stats} />

// 데스크톱: 4열 그리드
// 태블릿: 2열 그리드
// 모바일: 1열 스택

<DataTable columns={columns} data={data} />

// 데스크톱: 전체 테이블
// 모바일: 카드 형식으로 자동 전환

다크모드 자동 지원

모든 컴포넌트는 다크모드를 자동으로 지원합니다:

// ✅ 테마 변경만으로 모든 컴포넌트가 다크모드로 전환
setTheme('dark');

// globals.css의 .dark 클래스에 정의된 색상이 자동 적용

실전 팁

1. 컴포넌트 탐색기 활용

디자인 시스템 페이지에서 컴포넌트를 찾고 코드를 복사하세요:

  1. 기준정보 관리 → 디자인시스템 접속
  2. Atoms/Molecules/Organisms/Templates 탭 클릭
  3. 필요한 컴포넌트 찾기
  4. 사용법 코드 복사 버튼 클릭
  5. 코드에 붙여넣기

2. 일관성 체크리스트

새 페이지 생성 시:

  • PageHeader 사용
  • StatCards로 통계 표시 (4개)
  • SearchFilter로 검색/필터 구현
  • DataTable로 목록 표시
  • StatusBadge로 상태 표시
  • TableActions로 액션 버튼 구현

3. 성능 최적화

컴포넌트는 이미 최적화되어 있습니다:

  • Memoization 적용
  • Lazy loading 지원
  • Virtual scrolling (큰 테이블)
  • Code splitting

4. 접근성

모든 컴포넌트는 접근성을 고려하여 설계되었습니다:

  • Keyboard navigation
  • Screen reader 지원
  • ARIA labels
  • Focus management

마이그레이션 가이드

기존 페이지를 아토믹 디자인으로 전환하기

Before:

export function OldPage() {
  return (
    <div>
      <div className="flex items-center gap-3">
        <h1>페이지 제목</h1>
      </div>
      <div className="grid grid-cols-4 gap-4">
        {/* 통계 카드들 */}
      </div>
      <input type="text" placeholder="검색..." />
      <table>
        {/* 테이블 */}
      </table>
    </div>
  );
}

After:

import { PageHeader } from "./organisms/PageHeader";
import { StatCards } from "./organisms/StatCards";
import { SearchFilter } from "./organisms/SearchFilter";
import { DataTable } from "./organisms/DataTable";

export function NewPage() {
  return (
    <div className="flex-1 overflow-auto">
      <PageHeader icon={Database} title="페이지 제목" />
      <div className="p-6">
        <StatCards stats={stats} />
        <SearchFilter searchValue={search} onSearchChange={setSearch} />
        <DataTable columns={columns} data={data} />
      </div>
    </div>
  );
}

마이그레이션 시간: 약 30분

요약

왜 아토믹 디자인 시스템을 사용하나요?

  1. 재사용성 - 한 번 만들면 어디서나 사용
  2. 일관성 - 모든 페이지가 동일한 스타일
  3. 유지보수 - 컴포넌트 하나만 수정하면 전체 반영
  4. 생산성 - 새 페이지를 빠르게 생성
  5. 품질 - 검증된 컴포넌트 사용

시작하는 방법

  1. 학습: 디자인시스템 페이지에서 컴포넌트 구조 파악
  2. 실습: 간단한 페이지부터 시작 (ListPageTemplate 사용)
  3. 확장: 필요한 경우 컴포넌트 커스터마이징
  4. 공유: 새로운 패턴을 팀과 공유

다음 단계

  • 디자인 시스템 페이지 탐색
  • 컴포넌트 코드 복사하여 사용
  • 필요한 경우 새 Variant 추가
  • 팀과 베스트 프랙티스 공유