atomsystem 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # AtomSystem (`atomsystem`)
2
2
 
3
3
  > **Universal Design Token & Agent-Driven UI System**
4
- > React, Vue, Svelte, Pure HTML 어디서든 즉시 동작하는 W3C DTCG 호환 디자인 시스템
4
+ > React, Vue, Svelte, Pure HTML 어디서든 즉시 동작하는 W3C DTCG 호환 디자인 시스템 & 로컬 토큰 스튜디오
5
5
 
6
6
  [![npm version](https://img.shields.io/npm/v/atomsystem.svg)](https://www.npmjs.com/package/atomsystem)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
@@ -20,21 +20,70 @@ npm install atomsystem
20
20
 
21
21
  ### 2. 프로젝트 초기화 (CLI)
22
22
 
23
- 프로젝트 루트에서 `init` 명령을 실행하면 AI Agent 전용 스킬, 디자인 가이드, UX 패턴, 토큰 규격 파일이 한 번에 자동 세팅됩니다.
23
+ 프로젝트 루트에서 `init` 명령을 실행하면 AI Agent 전용 가이드라인, 4단계 레고 조립 규격, W3C DTCG 토큰 파일이 한 번에 자동 세팅됩니다.
24
24
 
25
25
  ```bash
26
26
  npx atomsystem init
27
27
  ```
28
28
 
29
29
  생성되는 파일:
30
- - `.agents/skills/atomsystem/SKILL.md`: AI Coding Agent(Antigravity, Cursor, Claude 등) 연동 스킬
31
- - `atom.design.md`: 브랜드 및 타이포그래피, 컬러, 컴포넌트 디자인 가이드
32
- - `atom.uxPattern.md`: 폼 검증, 모달 인터랙션, 로딩 상태 등 표준 UX 패턴 가이드
33
- - `tokens/token.json`: W3C DTCG 표준 규격 디자인 토큰
30
+ - `AGENTS.md` / `CLAUDE.md` / `.cursorrules`: 범용 AI 어시스턴트(Antigravity, Cursor, Claude Code, Copilot 등) 공통 지침
31
+ - `.agents/skills/atomsystem/SKILL.md`: AI Agent 자동 분석 및 토큰 구축 스킬
32
+ - `atom.design.md` & `tokens/token.json`: 브랜드, 타이포그래피, 컬러, 여백, 곡률 W3C DTCG 표준 명세
33
+ - `atom.components.md`: 원자/분자 UI 컴포넌트 명세
34
+ - `atom.blocks.md`: 실시간 차트, AI 챗 등 완성형 블록 명세
35
+ - `atom.uxPattern.md`: 폼 검증, 결제 플로우, 로딩 상태 등 표준 UX 패턴 가이드
36
+ - `css/atom-ui.css`: 0KB 제로 런타임 시맨틱 순수 CSS
34
37
 
35
38
  ---
36
39
 
37
- ## 🎨 사용 방법 (Usage)
40
+ ## 🎨 로컬 토큰 스튜디오 (Local Token Studio GUI)
41
+
42
+ 설치 후 별도의 설정 없이 **로컬에서 직접 디자인 토큰을 변경하고 스타일을 실시간 재컴파일**할 수 있는 내장 웹 GUI 도구를 제공합니다.
43
+
44
+ ```bash
45
+ # 로컬 토큰 스튜디오 GUI 실행 (기본 포트: 4000)
46
+ npx atomsystem studio
47
+
48
+ # 또는 다른 포트로 실행
49
+ npx atomsystem studio --port=5000
50
+ ```
51
+
52
+ 1. **브라우저 접속**: `http://localhost:4000`에 접속합니다.
53
+ 2. **시각적 편집**: 컬러 피커 및 셀렉터를 통해 브랜드 색상, 서피스 배경, 모서리 곡률(Radius)을 직접 변경합니다.
54
+ 3. **원클릭 저장 & 0ms 자동 컴파일**:
55
+ - `tokens/token.json`에 최신 W3C 토큰이 저장됩니다.
56
+ - 동시에 `css/atom-ui.css`가 제로 런타임 CSS 변수로 자동 재컴파일됩니다.
57
+
58
+ ```bash
59
+ # 터미널에서 CLI로 직접 CSS 재컴파일 시
60
+ npx atomsystem build:tokens
61
+ ```
62
+
63
+ ---
64
+
65
+ ## 📦 컴포넌트 & 블록 추가 (CLI Add)
66
+
67
+ 원하는 컴포넌트나 블록을 프로젝트에 소스 코드로 직접 내려받아 커스텀할 수 있습니다 (Component-First 원칙 보장).
68
+
69
+ ```bash
70
+ # 지원 항목 목록 확인
71
+ npx atomsystem list
72
+
73
+ # 개별 컴포넌트 추가
74
+ npx atomsystem add button
75
+ npx atomsystem add container
76
+ npx atomsystem add layout
77
+
78
+ # 완성형 디자인 블록 추가 (필요 컴포넌트 자동 의존성 복사)
79
+ npx atomsystem add realtime-chart
80
+ npx atomsystem add interactive-chat
81
+ npx atomsystem add pricing-table
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 💻 사용 방법 (Usage)
38
87
 
39
88
  ### 1) CSS 스타일 불러오기
40
89
 
@@ -52,11 +101,28 @@ import 'atomsystem/css/atom-ui.css';
52
101
 
53
102
  ---
54
103
 
55
- ### 2) UI 컴포넌트 & 시멘틱 클래스 사용
104
+ ### 2) UI 컴포넌트 & 레이아웃 사용
56
105
 
57
- AtomSystem의 모든 컴포넌트는 프레임워크에 구애받지 않고 클래스명만으로 즉시 동작합니다.
106
+ 프레임워크에 구애받지 않고 클래스명만으로 즉시 동작하거나, React 컴포넌트를 import하여 사용할 수 있습니다.
58
107
 
59
- #### 시멘틱 클래스 (HTML / JSX / Vue 공통)
108
+ #### React 컴포넌트 Import
109
+ ```tsx
110
+ import { Button, Card, Badge, Container, Layout, Stack, Grid } from 'atomsystem';
111
+
112
+ export function Example() {
113
+ return (
114
+ <Container size="xl">
115
+ <Card variant="interactive">
116
+ <Badge variant="primary">New</Badge>
117
+ <h3>대시보드</h3>
118
+ <Button variant="primary" size="md">시작하기</Button>
119
+ </Card>
120
+ </Container>
121
+ );
122
+ }
123
+ ```
124
+
125
+ #### 순수 시맨틱 CSS 클래스 (HTML / Vue / Vanilla JS)
60
126
  ```html
61
127
  <!-- 버튼 -->
62
128
  <button class="atom-btn atom-btn-primary">확인</button>
@@ -67,64 +133,57 @@ AtomSystem의 모든 컴포넌트는 프레임워크에 구애받지 않고 클
67
133
  <h2 class="atom-title-2">계좌 송금</h2>
68
134
  <p class="atom-body-2">수수료 없는 간편 송금 서비스</p>
69
135
  </div>
70
-
71
- <!-- 인풋 -->
72
- <div class="atom-input-group">
73
- <label class="atom-label">이메일</label>
74
- <input class="atom-input" type="email" placeholder="user@example.com" />
75
- </div>
76
136
  ```
77
137
 
78
- #### React 컴포넌트 직접 Import
138
+ ---
139
+
140
+ ### 3) 3,800+ 무료 오픈소스 아이콘 시스템 연동
141
+
142
+ Lucide 아이콘 풀세트(3,875개)를 지원하며, 시스템 및 테마 에디터와 완벽하게 연동됩니다.
143
+
79
144
  ```tsx
80
- import { Button } from 'atomsystem/components/Button';
81
- import { Card } from 'atomsystem/components/Card';
82
- import { Badge } from 'atomsystem/components/Badge';
145
+ import { Sparkles, Heart, Search } from 'lucide-react';
83
146
 
84
- export function Example() {
147
+ export function IconWidget() {
85
148
  return (
86
- <Card variant="interactive">
87
- <Badge variant="primary">New</Badge>
88
- <h3>대시보드</h3>
89
- <Button variant="primary" size="md">시작하기</Button>
90
- </Card>
149
+ <button className="inline-flex items-center gap-2 px-3 py-1.5 rounded-(--radius) bg-(--bg-secondary) text-(--text-primary)">
150
+ <Sparkles className="w-4 h-4 text-(--accent-primary)" />
151
+ <span>AI 추천</span>
152
+ </button>
91
153
  );
92
154
  }
93
155
  ```
94
156
 
95
157
  ---
96
158
 
97
- ### 3) 디자인 토큰 & 테마 엔진 활용 (JS / TS)
98
-
99
- W3C DTCG 규격 JSON 및 토큰 메타데이터를 직접 import하여 사용할 수 있습니다.
100
-
101
- ```typescript
102
- import {
103
- BASE_COLOR_TOKENS,
104
- TYPOGRAPHY_TOKENS,
105
- RADIUS_TOKENS,
106
- generateCssVariables
107
- } from 'atomsystem';
159
+ ### 4) 다국어(i18n) 지원
108
160
 
109
- // W3C 표준 JSON 직접 가져오기
110
- import tokenJson from 'atomsystem/token.json';
111
-
112
- // 동적 CSS Custom Properties 생성
113
- const cssVars = generateCssVariables();
114
- ```
161
+ 한국어(`ko`), 영어(`en`), 일본어(`ja`) 3개 국어를 기본 지원하며 헤더 스위처를 통해 즉시 전환할 수 있습니다.
115
162
 
116
163
  ---
117
164
 
118
- ### 4) AI Agent 연동 (Agent-Driven UI)
165
+ ### 5) AI Agent 연동 (Agent-Driven UI)
119
166
 
120
- `npx atomsystem init`으로 초기화된 프로젝트에서는 AI 코딩 어시스턴트(Antigravity, Cursor, GitHub Copilot 등)에게 마크다운 가이드 기반으로 작업 지시를 내릴 수 있습니다:
167
+ `npx atomsystem init`으로 초기화된 프로젝트에서는 AI 코딩 어시스턴트(Antigravity, Cursor, Claude Code 등)에게 말로만 작업 지시를 내릴 수 있습니다:
121
168
 
122
169
  ```text
123
- "atom.design.md 가이드의 컬러와 atom.uxPattern.md의 모달 패턴을 준수해서
124
- 회원가입 완료 모달 컴포넌트를 만들어줘."
170
+ "atom.design.md의 색상 토큰과 atom.blocks.md의 realtime-chart 구조를 참고해서
171
+ 주식 시세 대시보드 화면을 만들어줘."
125
172
  ```
126
173
 
127
- AI Agent는 자동으로 디자인 토큰과 UX 표준을 적용하여 일관된 고품질 UI 코드를 생성합니다.
174
+ AI Agent는 자동으로 디자인 토큰과 컴포넌트 우선(Component-First) 레고 조립 파이프라인을 준수하여 일관된 고품질 UI 코드를 생성합니다.
175
+
176
+ ---
177
+
178
+ ## 🛠️ CLI 명령어 요약
179
+
180
+ | 명령어 | 설명 |
181
+ | :--- | :--- |
182
+ | `npx atomsystem init` | AI 지침서, 4단계 규격서, W3C 토큰, CSS 초기화 |
183
+ | `npx atomsystem studio` | 로컬 웹 토큰 스튜디오(GUI) 실행 (`http://localhost:4000`) |
184
+ | `npx atomsystem build:tokens` | `tokens/token.json`을 `css/atom-ui.css`로 일괄 재컴파일 |
185
+ | `npx atomsystem add <name>` | 컴포넌트(`button`, `container`, `layout` 등) 또는 블록 다운로드 |
186
+ | `npx atomsystem list` | 추가 가능한 모든 컴포넌트 및 디자인 블록 목록 출력 |
128
187
 
129
188
  ---
130
189
 
@@ -132,10 +191,11 @@ AI Agent는 자동으로 디자인 토큰과 UX 표준을 적용하여 일관된
132
191
 
133
192
  | 경로 | 설명 |
134
193
  | :--- | :--- |
135
- | `atomsystem` | 토큰 데이터 모델, 테마 엔진, 색상/타이포 유틸리티 |
136
- | `atomsystem/css/atom-ui.css` | 전역 스타일 및 시멘틱 UI 클래스 (`.atom-btn`, `.atom-card` 등) |
137
- | `atomsystem/components/*` | React UI 컴포넌트 풀세트 (`Button`, `Input`, `Card`, `Badge`, `Modal`, `Calendar`, `Select`, `Accordion`, `Radio`, `Slider`, `Avatar`, `Progress`, `Skeleton`, `Breadcrumb`, `Separator`, `Textarea`, `Pagination`, `Tooltip`) |
138
- | `atomsystem/token.json` | W3C DTCG 포맷 단일 진실 공급원 토큰 파일 |
194
+ | `atomsystem` | 토큰 데이터 모델, 컴포넌트 스펙, 테마 엔진 |
195
+ | `atomsystem/css/atom-ui.css` | 전역 스타일 및 제로 런타임 시맨틱 UI 클래스 |
196
+ | `atomsystem/components/*` | React UI 컴포넌트 (`Button`, `Card`, `Input`, `Container`, `Layout` 등) |
197
+ | `atomsystem/blocks/*` | 레고 조합 완성형 블록 (`RealtimeChart`, `InteractiveChat` 등) |
198
+ | `atomsystem/token.json` | W3C DTCG 포맷 단일 진실 공급원(SSOT) 토큰 파일 |
139
199
  | `atomsystem/design.md` | 마크다운 기반 디자인 시스템 가이드 규격 |
140
200
  | `atomsystem/uxPattern.md` | 마크다운 기반 UX 인터랙션 패턴 가이드 |
141
201
  | `atomsystem/skill` | AI Coding Agent 자동화 스킬 정의서 |
@@ -0,0 +1,337 @@
1
+ 'use client';
2
+
3
+ import React, { useState } from 'react';
4
+ import Link from 'next/link';
5
+ import { Header } from '@/components/Header';
6
+ import { BlocksSidebar } from '@/components/blocks/BlocksSidebar';
7
+ import { BlockItem } from '@/lib/data/blocks';
8
+ import {
9
+ RealtimeChartBlock,
10
+ InteractiveChatBlock,
11
+ CardListBlock,
12
+ SliderShowcaseBlock,
13
+ PricingPlanBlock,
14
+ MetricStatsBlock,
15
+ FileExplorerBlock,
16
+ } from '@/components/blocks';
17
+ import { Button } from '@/components/ui';
18
+ import { CodeHighlight } from '@/components/common/CodeHighlight';
19
+ import {
20
+ Terminal,
21
+ Copy,
22
+ Check,
23
+ Monitor,
24
+ Tablet,
25
+ Smartphone,
26
+ Code2,
27
+ Sparkles,
28
+ Layers,
29
+ ArrowLeft,
30
+ ChevronRight,
31
+ Sliders,
32
+ ExternalLink,
33
+ } from 'lucide-react';
34
+
35
+ interface BlockDetailPageContentProps {
36
+ block: BlockItem;
37
+ }
38
+
39
+ export function BlockDetailPageContent({ block }: BlockDetailPageContentProps) {
40
+ const [viewport, setViewport] = useState<'desktop' | 'tablet' | 'mobile'>('desktop');
41
+ const [codeTab, setCodeTab] = useState<'react' | 'html'>('react');
42
+ const [copiedCode, setCopiedCode] = useState(false);
43
+ const [copiedCli, setCopiedCli] = useState(false);
44
+
45
+ const cliCommand = `npx atomsystem add ${block.id}`;
46
+
47
+ const handleCopyCode = () => {
48
+ const code = codeTab === 'react' ? block.codeSnippets.react : block.codeSnippets.htmlCss;
49
+ navigator.clipboard.writeText(code);
50
+ setCopiedCode(true);
51
+ setTimeout(() => setCopiedCode(false), 2000);
52
+ };
53
+
54
+ const handleCopyCli = () => {
55
+ navigator.clipboard.writeText(cliCommand);
56
+ setCopiedCli(true);
57
+ setTimeout(() => setCopiedCli(false), 2000);
58
+ };
59
+
60
+ const getViewportMaxWidth = () => {
61
+ switch (viewport) {
62
+ case 'mobile':
63
+ return 'max-w-[390px]';
64
+ case 'tablet':
65
+ return 'max-w-[768px]';
66
+ default:
67
+ return 'max-w-full';
68
+ }
69
+ };
70
+
71
+ const renderBlock = () => {
72
+ switch (block.id) {
73
+ case 'realtime-chart':
74
+ return <RealtimeChartBlock />;
75
+ case 'interactive-chat':
76
+ return <InteractiveChatBlock />;
77
+ case 'card-list':
78
+ return <CardListBlock />;
79
+ case 'interactive-slider':
80
+ return <SliderShowcaseBlock />;
81
+ case 'pricing-table':
82
+ return <PricingPlanBlock />;
83
+ case 'metric-stats':
84
+ return <MetricStatsBlock />;
85
+ case 'file-explorer':
86
+ return <FileExplorerBlock />;
87
+ default:
88
+ return null;
89
+ }
90
+ };
91
+
92
+ return (
93
+ <div className="min-h-screen bg-(--bg-primary) text-(--text-primary) flex flex-col font-sans transition-colors">
94
+ <Header />
95
+
96
+ <div className="flex-1 flex max-w-[1600px] w-full mx-auto overflow-hidden">
97
+ {/* 1. Left Docs Sidebar */}
98
+ <div className="hidden lg:block h-[calc(100vh-45px)] sticky top-11">
99
+ <BlocksSidebar activeId={block.id} />
100
+ </div>
101
+
102
+ {/* 2. Main Content Area */}
103
+ <main className="flex-1 p-5 sm:p-8 lg:p-10 overflow-y-auto max-w-5xl">
104
+ {/* Breadcrumb */}
105
+ <div className="flex items-center gap-1.5 text-xs text-(--text-secondary) mb-4">
106
+ <Link href="/blocks" className="hover:text-(--text-primary) transition-colors">
107
+ Blocks
108
+ </Link>
109
+ <ChevronRight className="w-3 h-3 opacity-40" />
110
+ <span className="capitalize">{block.category}</span>
111
+ <ChevronRight className="w-3 h-3 opacity-40" />
112
+ <span className="text-(--text-primary) font-semibold">{block.id}</span>
113
+ </div>
114
+
115
+ {/* Header & Meta */}
116
+ <div className="space-y-3 mb-8">
117
+ <div className="flex flex-wrap items-center gap-2">
118
+ <h1 className="text-2xl sm:text-3xl font-bold tracking-tight text-(--text-primary)">
119
+ {block.title}
120
+ </h1>
121
+ <span className="font-mono text-xs px-2 py-0.5 rounded-(--radius-sm) bg-(--bg-secondary) text-(--text-secondary) border border-(--border-subtle)">
122
+ {block.badge}
123
+ </span>
124
+ </div>
125
+ <p className="text-sm sm:text-base text-(--text-secondary) leading-relaxed">
126
+ {block.summary}
127
+ </p>
128
+
129
+ {/* CLI Install Box */}
130
+ <div className="flex items-center gap-2 pt-2">
131
+ <div className="flex items-center gap-2 px-3 py-1.5 rounded-(--radius-sm) border border-(--border-subtle) bg-(--bg-secondary)/40 font-mono text-xs text-(--text-primary)">
132
+ <Terminal className="w-3.5 h-3.5 text-(--accent-primary)" />
133
+ <span>{cliCommand}</span>
134
+ </div>
135
+ <Button
136
+ variant="outline"
137
+ size="sm"
138
+ onClick={handleCopyCli}
139
+ className="text-xs flex items-center gap-1"
140
+ >
141
+ {copiedCli ? <Check className="w-3.5 h-3.5 text-emerald-600" /> : <Copy className="w-3.5 h-3.5" />}
142
+ <span>{copiedCli ? '복사됨' : '복사'}</span>
143
+ </Button>
144
+ </div>
145
+ </div>
146
+
147
+ {/* Live Interactive Preview Container */}
148
+ <section className="space-y-3 mb-10">
149
+ <div className="flex items-center justify-between">
150
+ <h2 className="text-xs font-semibold uppercase tracking-wider text-(--text-secondary)">
151
+ 라이브 인터랙티브 프리뷰
152
+ </h2>
153
+
154
+ {/* Viewport Resizer Controls */}
155
+ <div className="hidden sm:flex items-center gap-0.5 bg-(--bg-secondary) p-0.5 rounded-(--radius-sm) border border-(--border-subtle)">
156
+ <button
157
+ onClick={() => setViewport('desktop')}
158
+ className={`p-1 rounded-(--radius-sm) transition-colors ${
159
+ viewport === 'desktop'
160
+ ? 'bg-(--bg-primary) text-(--text-primary)'
161
+ : 'text-(--text-secondary) hover:text-(--text-primary)'
162
+ }`}
163
+ title="Desktop 100%"
164
+ >
165
+ <Monitor className="w-3.5 h-3.5" />
166
+ </button>
167
+ <button
168
+ onClick={() => setViewport('tablet')}
169
+ className={`p-1 rounded-(--radius-sm) transition-colors ${
170
+ viewport === 'tablet'
171
+ ? 'bg-(--bg-primary) text-(--text-primary)'
172
+ : 'text-(--text-secondary) hover:text-(--text-primary)'
173
+ }`}
174
+ title="Tablet 768px"
175
+ >
176
+ <Tablet className="w-3.5 h-3.5" />
177
+ </button>
178
+ <button
179
+ onClick={() => setViewport('mobile')}
180
+ className={`p-1 rounded-(--radius-sm) transition-colors ${
181
+ viewport === 'mobile'
182
+ ? 'bg-(--bg-primary) text-(--text-primary)'
183
+ : 'text-(--text-secondary) hover:text-(--text-primary)'
184
+ }`}
185
+ title="Mobile 390px"
186
+ >
187
+ <Smartphone className="w-3.5 h-3.5" />
188
+ </button>
189
+ </div>
190
+ </div>
191
+
192
+ {/* Clean White Preview Box */}
193
+ <div className="p-4 sm:p-6 rounded-(--radius) bg-(--bg-primary) border border-(--border-subtle) flex justify-center items-center">
194
+ <div className={`w-full transition-all duration-300 mx-auto ${getViewportMaxWidth()}`}>
195
+ {renderBlock()}
196
+ </div>
197
+ </div>
198
+ </section>
199
+
200
+ {/* Lego Assembly Pipeline: Components & Tokens & Template */}
201
+ <section className="space-y-3 mb-10">
202
+ <h2 className="text-xs font-semibold uppercase tracking-wider text-(--text-secondary)">
203
+ 레고 조립 구조 (Token → Component → Block → Template)
204
+ </h2>
205
+
206
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-3 text-xs">
207
+ {/* 1. Tokens Used */}
208
+ <div className="p-4 rounded-(--radius) border border-(--border-subtle) bg-(--bg-primary) flex flex-col justify-between">
209
+ <div>
210
+ <div className="font-semibold text-(--text-primary) mb-0.5">
211
+ 주입된 토큰 (Tokens)
212
+ </div>
213
+ <p className="text-[11px] text-(--text-secondary) mb-2.5">블록의 곡률, 간격, 컬러의 원천</p>
214
+ <div className="flex flex-wrap gap-1">
215
+ {block.tokensUsed.map((token) => (
216
+ <span key={token} className="font-mono text-[11px] px-1.5 py-0.5 rounded-(--radius-sm) bg-(--bg-secondary) text-(--text-secondary)">
217
+ {token}
218
+ </span>
219
+ ))}
220
+ </div>
221
+ </div>
222
+ </div>
223
+
224
+ {/* 2. Components Used */}
225
+ <div className="p-4 rounded-(--radius) border border-(--border-subtle) bg-(--bg-primary) flex flex-col justify-between">
226
+ <div>
227
+ <div className="font-semibold text-(--text-primary) mb-0.5">
228
+ 조합된 컴포넌트 (Components)
229
+ </div>
230
+ <p className="text-[11px] text-(--text-secondary) mb-2.5">블록을 구성하는 기초 레고 피스</p>
231
+ <div className="flex flex-wrap gap-1.5">
232
+ {block.componentsUsed.map((comp) => (
233
+ <Link
234
+ key={comp}
235
+ href={`/components/${comp.toLowerCase()}`}
236
+ className="font-mono text-xs font-medium text-(--text-primary) hover:underline"
237
+ >
238
+ .{comp}
239
+ </Link>
240
+ ))}
241
+ </div>
242
+ </div>
243
+ </div>
244
+
245
+ {/* 3. Template Usage */}
246
+ <div className="p-4 rounded-(--radius) border border-(--border-subtle) bg-(--bg-primary) flex flex-col justify-between">
247
+ <div>
248
+ <div className="font-semibold text-(--text-primary) mb-0.5">
249
+ 결합 템플릿 (Template)
250
+ </div>
251
+ <p className="text-[11px] text-(--text-secondary) mb-2.5">이 블록이 꽂히는 실제 화면</p>
252
+ <div className="text-xs text-(--text-secondary) leading-relaxed">
253
+ {block.templateUsage}
254
+ </div>
255
+ </div>
256
+ </div>
257
+ </div>
258
+ </section>
259
+
260
+ {/* Features & Key Specs Section */}
261
+ <section className="space-y-3 mb-10">
262
+ <h2 className="text-xs font-semibold uppercase tracking-wider text-(--text-secondary)">
263
+ 핵심 설계 기능 및 접근성 (Features & A11y)
264
+ </h2>
265
+ <ul className="space-y-1.5 p-4 rounded-(--radius) border border-(--border-subtle) bg-(--bg-primary) text-xs text-(--text-secondary)">
266
+ {block.features.map((f, i) => (
267
+ <li key={i} className="flex items-start gap-2">
268
+ <span className="text-(--text-muted) select-none">•</span>
269
+ <span className="leading-relaxed">{f}</span>
270
+ </li>
271
+ ))}
272
+ </ul>
273
+ </section>
274
+
275
+ {/* Code Snippets Section */}
276
+ <section className="space-y-3 mb-12">
277
+ <div className="flex items-center justify-between">
278
+ <h2 className="text-xs font-semibold uppercase tracking-wider text-(--text-secondary)">
279
+ 소스 코드 (Installation & Usage)
280
+ </h2>
281
+
282
+ <div className="flex items-center gap-2">
283
+ <div className="flex rounded-(--radius-sm) border border-(--border-subtle) p-0.5 bg-(--bg-secondary) text-xs">
284
+ <Button
285
+ variant={codeTab === 'react' ? 'primary' : 'ghost'}
286
+ size="sm"
287
+ onClick={() => setCodeTab('react')}
288
+ className="px-2.5 py-1 text-xs"
289
+ >
290
+ React / Next.js
291
+ </Button>
292
+ <Button
293
+ variant={codeTab === 'html' ? 'primary' : 'ghost'}
294
+ size="sm"
295
+ onClick={() => setCodeTab('html')}
296
+ className="px-2.5 py-1 text-xs"
297
+ >
298
+ HTML & CSS
299
+ </Button>
300
+ </div>
301
+
302
+ <button
303
+ onClick={handleCopyCode}
304
+ className="flex items-center gap-1 px-2.5 py-1 rounded-(--radius-sm) text-xs font-medium bg-(--bg-primary) hover:bg-(--bg-secondary) text-(--text-primary) border border-(--border-subtle) transition-colors"
305
+ >
306
+ {copiedCode ? (
307
+ <>
308
+ <Check className="w-3.5 h-3.5 text-emerald-600" />
309
+ <span className="text-emerald-600 font-semibold">복사됨</span>
310
+ </>
311
+ ) : (
312
+ <>
313
+ <Copy className="w-3.5 h-3.5 text-(--text-secondary)" />
314
+ <span>코드 복사</span>
315
+ </>
316
+ )}
317
+ </button>
318
+ </div>
319
+ </div>
320
+
321
+ <div className="rounded-(--radius) border border-(--border-subtle) bg-(--bg-primary) overflow-hidden">
322
+ <div className="px-4 py-2 border-b border-(--border-subtle) bg-(--bg-secondary)/40 text-xs font-mono text-(--text-secondary) flex justify-between items-center">
323
+ <span>{codeTab === 'react' ? `${block.id}.tsx` : `${block.id}.html`}</span>
324
+ <span>Zero-Runtime CSS Tokens</span>
325
+ </div>
326
+ <CodeHighlight
327
+ code={codeTab === 'react' ? block.codeSnippets.react : block.codeSnippets.htmlCss}
328
+ language={codeTab === 'react' ? 'tsx' : 'html'}
329
+ className="p-4 max-h-[460px]"
330
+ />
331
+ </div>
332
+ </section>
333
+ </main>
334
+ </div>
335
+ </div>
336
+ );
337
+ }