atomsystem 0.4.1 → 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 +112 -52
- package/atom.design.md +17 -0
- package/components/blocks/BlockDetailPageContent.tsx +337 -0
- package/components/blocks/BlockViewerCard.tsx +229 -0
- package/components/blocks/BlocksSidebar.tsx +93 -0
- package/components/blocks/CardListBlock.tsx +214 -0
- package/components/blocks/FileExplorerBlock.tsx +203 -0
- package/components/blocks/InteractiveChatBlock.tsx +217 -0
- package/components/blocks/MetricStatsBlock.tsx +150 -0
- package/components/blocks/PricingPlanBlock.tsx +175 -0
- package/components/blocks/RealtimeChartBlock.tsx +242 -0
- package/components/blocks/SliderShowcaseBlock.tsx +136 -0
- package/components/blocks/index.ts +8 -0
- package/components/ui/Container.tsx +45 -0
- package/components/ui/Layout.tsx +220 -0
- package/components/ui/Switch.tsx +39 -0
- package/components/ui/Table.tsx +88 -0
- package/components/ui/Tabs.tsx +58 -0
- package/components/ui/Tree.tsx +121 -0
- package/components/ui/index.ts +6 -0
- package/css/atom-ui.css +41 -716
- package/dist/cli.cjs +633 -41
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +630 -39
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +265 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -4
- package/dist/index.d.ts +13 -4
- package/dist/index.js +265 -3
- package/dist/index.js.map +1 -1
- package/package.json +7 -1
- package/presets/agents.guide.md +49 -0
- package/presets/blocks.md +101 -0
- package/presets/components.md +142 -0
- package/presets/default.design.md +17 -0
- package/tokens/token.json +63 -1
- package/tokens/tokens.json +63 -1
package/dist/cli.cjs
CHANGED
|
@@ -1,23 +1,447 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var fs2 = require('fs');
|
|
5
|
+
var path2 = require('path');
|
|
6
6
|
var url = require('url');
|
|
7
|
+
var http = require('http');
|
|
7
8
|
|
|
8
9
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
9
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
11
|
|
|
11
|
-
var
|
|
12
|
-
var
|
|
12
|
+
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
13
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
14
|
+
var http__default = /*#__PURE__*/_interopDefault(http);
|
|
13
15
|
|
|
16
|
+
// src/tokenCompiler.ts
|
|
17
|
+
function compileTokensToCss(tokenJson) {
|
|
18
|
+
const cssVars = [];
|
|
19
|
+
function traverse(obj) {
|
|
20
|
+
if (!obj || typeof obj !== "object") return;
|
|
21
|
+
if (obj.variable && obj.$value !== void 0) {
|
|
22
|
+
cssVars.push(` ${obj.variable}: ${obj.$value};`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
for (const key of Object.keys(obj)) {
|
|
26
|
+
if (key.startsWith("$")) continue;
|
|
27
|
+
traverse(obj[key]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
traverse(tokenJson);
|
|
31
|
+
return `:root {
|
|
32
|
+
${cssVars.join("\n")}
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/studioServer.ts
|
|
38
|
+
function startLocalTokenStudio(options = {}) {
|
|
39
|
+
const port = options.port || 4e3;
|
|
40
|
+
const cwd = options.cwd || process.cwd();
|
|
41
|
+
const tokenJsonPath = path2__default.default.join(cwd, "tokens", "token.json");
|
|
42
|
+
const cssPath = path2__default.default.join(cwd, "css", "atom-ui.css");
|
|
43
|
+
path2__default.default.join(cwd, "atom.design.md");
|
|
44
|
+
const server = http__default.default.createServer((req, res) => {
|
|
45
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
46
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
47
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
48
|
+
if (req.method === "OPTIONS") {
|
|
49
|
+
res.writeHead(200);
|
|
50
|
+
res.end();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const url = new URL(req.url || "/", `http://localhost:${port}`);
|
|
54
|
+
if (url.pathname === "/api/tokens" && req.method === "GET") {
|
|
55
|
+
let data = {};
|
|
56
|
+
if (fs2__default.default.existsSync(tokenJsonPath)) {
|
|
57
|
+
try {
|
|
58
|
+
data = JSON.parse(fs2__default.default.readFileSync(tokenJsonPath, "utf-8"));
|
|
59
|
+
} catch (e) {
|
|
60
|
+
data = { error: "Failed to parse tokens/token.json" };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
64
|
+
res.end(JSON.stringify(data));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (url.pathname === "/api/tokens" && req.method === "POST") {
|
|
68
|
+
let body = "";
|
|
69
|
+
req.on("data", (chunk) => {
|
|
70
|
+
body += chunk;
|
|
71
|
+
});
|
|
72
|
+
req.on("end", () => {
|
|
73
|
+
try {
|
|
74
|
+
const newTokens = JSON.parse(body);
|
|
75
|
+
const tokensDir = path2__default.default.dirname(tokenJsonPath);
|
|
76
|
+
if (!fs2__default.default.existsSync(tokensDir)) fs2__default.default.mkdirSync(tokensDir, { recursive: true });
|
|
77
|
+
fs2__default.default.writeFileSync(tokenJsonPath, JSON.stringify(newTokens, null, 2), "utf-8");
|
|
78
|
+
const compiledCss = compileTokensToCss(newTokens);
|
|
79
|
+
const cssDir = path2__default.default.dirname(cssPath);
|
|
80
|
+
if (!fs2__default.default.existsSync(cssDir)) fs2__default.default.mkdirSync(cssDir, { recursive: true });
|
|
81
|
+
fs2__default.default.writeFileSync(cssPath, compiledCss, "utf-8");
|
|
82
|
+
res.writeHead(200, { "Content-Type": "application/json; charset=utf-8" });
|
|
83
|
+
res.end(JSON.stringify({ success: true, message: "Tokens and CSS compiled successfully!" }));
|
|
84
|
+
} catch (err) {
|
|
85
|
+
res.writeHead(400, { "Content-Type": "application/json; charset=utf-8" });
|
|
86
|
+
res.end(JSON.stringify({ success: false, error: err.message }));
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (url.pathname === "/" || url.pathname === "/index.html") {
|
|
92
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
93
|
+
res.end(getStudioHtml());
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
res.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
97
|
+
res.end("Not Found");
|
|
98
|
+
});
|
|
99
|
+
server.listen(port, () => {
|
|
100
|
+
console.log(`
|
|
101
|
+
\u{1F3A8} AtomSystem Local Token Studio running at:`);
|
|
102
|
+
console.log(` \u{1F449} http://localhost:${port}
|
|
103
|
+
`);
|
|
104
|
+
console.log(` Tokens file: ${path2__default.default.relative(cwd, tokenJsonPath)}`);
|
|
105
|
+
console.log(` Compiled CSS: ${path2__default.default.relative(cwd, cssPath)}`);
|
|
106
|
+
console.log(`
|
|
107
|
+
Press Ctrl+C to stop the studio server.
|
|
108
|
+
`);
|
|
109
|
+
});
|
|
110
|
+
return server;
|
|
111
|
+
}
|
|
112
|
+
function getStudioHtml() {
|
|
113
|
+
return `<!DOCTYPE html>
|
|
114
|
+
<html lang="ko">
|
|
115
|
+
<head>
|
|
116
|
+
<meta charset="UTF-8">
|
|
117
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
118
|
+
<title>AtomSystem Local Token Studio</title>
|
|
119
|
+
<style>
|
|
120
|
+
:root {
|
|
121
|
+
--bg: #0a0a0a;
|
|
122
|
+
--card-bg: #141414;
|
|
123
|
+
--border: #262626;
|
|
124
|
+
--text: #ededed;
|
|
125
|
+
--muted: #888888;
|
|
126
|
+
--accent: #3182f6;
|
|
127
|
+
--radius: 8px;
|
|
128
|
+
}
|
|
129
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
130
|
+
body {
|
|
131
|
+
background: var(--bg);
|
|
132
|
+
color: var(--text);
|
|
133
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Pretendard, sans-serif;
|
|
134
|
+
padding: 32px 20px;
|
|
135
|
+
line-height: 1.5;
|
|
136
|
+
}
|
|
137
|
+
.container { max-width: 1100px; margin: 0 auto; }
|
|
138
|
+
header {
|
|
139
|
+
display: flex;
|
|
140
|
+
justify-content: space-between;
|
|
141
|
+
align-items: flex-end;
|
|
142
|
+
padding-bottom: 24px;
|
|
143
|
+
border-bottom: 1px solid var(--border);
|
|
144
|
+
margin-bottom: 32px;
|
|
145
|
+
}
|
|
146
|
+
h1 { font-size: 24px; font-weight: 700; letter-spacing: -0.02em; }
|
|
147
|
+
p.desc { font-size: 13px; color: var(--muted); margin-top: 4px; }
|
|
148
|
+
.badge {
|
|
149
|
+
font-size: 11px;
|
|
150
|
+
font-family: monospace;
|
|
151
|
+
padding: 3px 8px;
|
|
152
|
+
background: #1a1a1a;
|
|
153
|
+
border: 1px solid var(--border);
|
|
154
|
+
border-radius: 4px;
|
|
155
|
+
color: var(--muted);
|
|
156
|
+
}
|
|
157
|
+
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
|
|
158
|
+
@media (max-width: 860px) { .grid { grid-template-columns: 1fr; } }
|
|
159
|
+
.card {
|
|
160
|
+
background: var(--card-bg);
|
|
161
|
+
border: 1px solid var(--border);
|
|
162
|
+
border-radius: var(--radius);
|
|
163
|
+
padding: 20px;
|
|
164
|
+
}
|
|
165
|
+
h2 { font-size: 15px; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; justify-content: space-between; }
|
|
166
|
+
.field { margin-bottom: 16px; }
|
|
167
|
+
label { display: block; font-size: 12px; font-weight: 500; margin-bottom: 6px; color: var(--text); }
|
|
168
|
+
.meta { font-size: 11px; color: var(--muted); font-family: monospace; margin-top: 4px; }
|
|
169
|
+
.input-row { display: flex; gap: 8px; align-items: center; }
|
|
170
|
+
input[type="text"], select {
|
|
171
|
+
flex: 1;
|
|
172
|
+
background: #1e1e1e;
|
|
173
|
+
border: 1px solid var(--border);
|
|
174
|
+
color: var(--text);
|
|
175
|
+
padding: 8px 12px;
|
|
176
|
+
font-size: 13px;
|
|
177
|
+
border-radius: 6px;
|
|
178
|
+
outline: none;
|
|
179
|
+
}
|
|
180
|
+
input[type="color"] {
|
|
181
|
+
-webkit-appearance: none;
|
|
182
|
+
border: 1px solid var(--border);
|
|
183
|
+
width: 38px;
|
|
184
|
+
height: 38px;
|
|
185
|
+
border-radius: 6px;
|
|
186
|
+
background: none;
|
|
187
|
+
cursor: pointer;
|
|
188
|
+
padding: 2px;
|
|
189
|
+
}
|
|
190
|
+
.btn-save {
|
|
191
|
+
background: var(--text);
|
|
192
|
+
color: var(--bg);
|
|
193
|
+
border: none;
|
|
194
|
+
padding: 10px 20px;
|
|
195
|
+
font-size: 13px;
|
|
196
|
+
font-weight: 600;
|
|
197
|
+
border-radius: 6px;
|
|
198
|
+
cursor: pointer;
|
|
199
|
+
transition: opacity 0.2s;
|
|
200
|
+
}
|
|
201
|
+
.btn-save:hover { opacity: 0.9; }
|
|
202
|
+
.preview-box {
|
|
203
|
+
border: 1px solid var(--border);
|
|
204
|
+
border-radius: 8px;
|
|
205
|
+
padding: 20px;
|
|
206
|
+
background: #0f0f0f;
|
|
207
|
+
display: flex;
|
|
208
|
+
flex-direction: column;
|
|
209
|
+
gap: 12px;
|
|
210
|
+
}
|
|
211
|
+
.preview-btn {
|
|
212
|
+
padding: 10px 18px;
|
|
213
|
+
border-radius: var(--sample-radius, 8px);
|
|
214
|
+
background: var(--sample-primary, #3182f6);
|
|
215
|
+
color: #ffffff;
|
|
216
|
+
border: none;
|
|
217
|
+
font-size: 13px;
|
|
218
|
+
font-weight: 600;
|
|
219
|
+
cursor: pointer;
|
|
220
|
+
display: inline-flex;
|
|
221
|
+
align-items: center;
|
|
222
|
+
justify-content: center;
|
|
223
|
+
gap: 6px;
|
|
224
|
+
}
|
|
225
|
+
.preview-card {
|
|
226
|
+
padding: 16px;
|
|
227
|
+
border-radius: var(--sample-radius, 8px);
|
|
228
|
+
background: var(--sample-surface, #18181b);
|
|
229
|
+
border: 1px solid var(--border);
|
|
230
|
+
color: var(--text);
|
|
231
|
+
font-size: 13px;
|
|
232
|
+
}
|
|
233
|
+
.toast {
|
|
234
|
+
position: fixed;
|
|
235
|
+
bottom: 24px;
|
|
236
|
+
right: 24px;
|
|
237
|
+
background: #10b981;
|
|
238
|
+
color: #000;
|
|
239
|
+
padding: 10px 18px;
|
|
240
|
+
border-radius: 6px;
|
|
241
|
+
font-size: 13px;
|
|
242
|
+
font-weight: 600;
|
|
243
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.5);
|
|
244
|
+
display: none;
|
|
245
|
+
}
|
|
246
|
+
</style>
|
|
247
|
+
</head>
|
|
248
|
+
<body>
|
|
249
|
+
<div class="container">
|
|
250
|
+
<header>
|
|
251
|
+
<div>
|
|
252
|
+
<div class="badge" style="margin-bottom: 8px; display: inline-block;">W3C DTCG Zero-Runtime</div>
|
|
253
|
+
<h1>AtomSystem Local Token Studio</h1>
|
|
254
|
+
<p class="desc">\uB85C\uCEEC \uD658\uACBD(tokens/token.json)\uC758 \uD1A0\uD070\uC744 GUI\uB85C \uC9C1\uC811 \uC218\uC815\uD558\uACE0 \uC2E4\uC2DC\uAC04\uC73C\uB85C css/atom-ui.css\uB85C \uC7AC\uCEF4\uD30C\uC77C\uD569\uB2C8\uB2E4.</p>
|
|
255
|
+
</div>
|
|
256
|
+
<button class="btn-save" onclick="saveTokens()">\uC800\uC7A5 \uBC0F CSS \uC7AC\uCEF4\uD30C\uC77C</button>
|
|
257
|
+
</header>
|
|
258
|
+
|
|
259
|
+
<div class="grid">
|
|
260
|
+
<!-- 1. Color Tokens -->
|
|
261
|
+
<div class="card">
|
|
262
|
+
<h2>\u{1F3A8} \uC2DC\uB9E8\uD2F1 \uBE0C\uB79C\uB4DC & \uC11C\uD53C\uC2A4 \uD1A0\uD070</h2>
|
|
263
|
+
|
|
264
|
+
<div class="field">
|
|
265
|
+
<label>\uBE0C\uB79C\uB4DC \uB300\uD45C \uC0C9\uC0C1 (Primary Color)</label>
|
|
266
|
+
<div class="input-row">
|
|
267
|
+
<input type="color" id="picker-primary" oninput="onColorChange('primary', this.value)">
|
|
268
|
+
<input type="text" id="val-primary" oninput="onColorChange('primary', this.value)">
|
|
269
|
+
</div>
|
|
270
|
+
<div class="meta">var(--atom-color-primary)</div>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<div class="field">
|
|
274
|
+
<label>\uD638\uBC84 \uC0C1\uD0DC \uC0C9\uC0C1 (Primary Hover)</label>
|
|
275
|
+
<div class="input-row">
|
|
276
|
+
<input type="color" id="picker-primary-hover" oninput="onColorChange('primary-hover', this.value)">
|
|
277
|
+
<input type="text" id="val-primary-hover" oninput="onColorChange('primary-hover', this.value)">
|
|
278
|
+
</div>
|
|
279
|
+
<div class="meta">var(--atom-color-primary-hover)</div>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<div class="field">
|
|
283
|
+
<label>\uC11C\uD53C\uC2A4 \uBC30\uACBD (Surface Background)</label>
|
|
284
|
+
<div class="input-row">
|
|
285
|
+
<input type="color" id="picker-bg-surface" oninput="onColorChange('bg-surface', this.value)">
|
|
286
|
+
<input type="text" id="val-bg-surface" oninput="onColorChange('bg-surface', this.value)">
|
|
287
|
+
</div>
|
|
288
|
+
<div class="meta">var(--atom-bg-surface)</div>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
<div class="field">
|
|
292
|
+
<label>\uAE30\uBCF8 \uBAA8\uC11C\uB9AC \uACE1\uB960 (Border Radius)</label>
|
|
293
|
+
<select id="val-radius" onchange="onRadiusChange(this.value)">
|
|
294
|
+
<option value="4px">4px (Sharp Minimal)</option>
|
|
295
|
+
<option value="6px">6px (Swiss Modern)</option>
|
|
296
|
+
<option value="8px">8px (Standard Clean)</option>
|
|
297
|
+
<option value="12px">12px (Rounded Friendly)</option>
|
|
298
|
+
<option value="16px">16px (Toss Soft)</option>
|
|
299
|
+
</select>
|
|
300
|
+
<div class="meta">var(--atom-radius-md)</div>
|
|
301
|
+
</div>
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
<!-- 2. Live Previewer -->
|
|
305
|
+
<div class="card">
|
|
306
|
+
<h2>\u26A1 \uC2E4\uC2DC\uAC04 \uD1A0\uD070 \uBC18\uC601 \uD504\uB9AC\uBDF0</h2>
|
|
307
|
+
<div class="preview-box" id="preview-box">
|
|
308
|
+
<div class="preview-card" id="sample-card">
|
|
309
|
+
<div style="font-weight: 600; margin-bottom: 4px;">\uB300\uC2DC\uBCF4\uB4DC \uC704\uC82F \uCEF4\uD3EC\uB10C\uD2B8</div>
|
|
310
|
+
<div style="color: var(--muted); font-size: 12px; margin-bottom: 14px;">
|
|
311
|
+
\uD1A0\uD070 \uBCC0\uACBD \uC2DC \uC2E4\uC2DC\uAC04\uC73C\uB85C \uB514\uC790\uC778\uC774 \uBC18\uC601\uB418\uBA70 \uC989\uC2DC CSS \uD30C\uC77C\uC5D0 \uB3D9\uAE30\uD654\uB429\uB2C8\uB2E4.
|
|
312
|
+
</div>
|
|
313
|
+
<button class="preview-btn" id="sample-btn">\uD655\uC778 \uBC0F \uC2B9\uC778</button>
|
|
314
|
+
</div>
|
|
315
|
+
|
|
316
|
+
<div style="font-size: 11px; font-family: monospace; color: var(--muted); background: #161616; padding: 12px; border-radius: 6px; border: 1px solid var(--border);">
|
|
317
|
+
<div>// \uCEF4\uD30C\uC77C \uB300\uC0C1 \uD30C\uC77C</div>
|
|
318
|
+
<div style="color: #60a5fa; margin-top: 4px;">tokens/token.json (W3C DTCG)</div>
|
|
319
|
+
<div style="color: #34d399; margin-top: 2px;">css/atom-ui.css (0KB Pure CSS)</div>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
</div>
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
|
|
326
|
+
<div id="toast" class="toast">\u2713 \uD1A0\uD070 \uBC0F CSS\uAC00 \uC131\uACF5\uC801\uC73C\uB85C \uC7AC\uCEF4\uD30C\uC77C\uB418\uC5C8\uC2B5\uB2C8\uB2E4!</div>
|
|
327
|
+
|
|
328
|
+
<script>
|
|
329
|
+
let currentTokens = {};
|
|
330
|
+
|
|
331
|
+
async function loadTokens() {
|
|
332
|
+
try {
|
|
333
|
+
const res = await fetch('/api/tokens');
|
|
334
|
+
currentTokens = await res.json();
|
|
335
|
+
populateFields();
|
|
336
|
+
updatePreview();
|
|
337
|
+
} catch (e) {
|
|
338
|
+
console.error('Failed to fetch tokens', e);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function populateFields() {
|
|
343
|
+
const primary = currentTokens?.color?.brand?.['color-primary']?.$value || '#3182f6';
|
|
344
|
+
const hover = currentTokens?.color?.brand?.['color-primary-hover']?.$value || '#1b64da';
|
|
345
|
+
const surface = currentTokens?.color?.surface?.['bg-surface']?.$value || '#18181b';
|
|
346
|
+
const radius = currentTokens?.borderRadius?.md?.$value || '8px';
|
|
347
|
+
|
|
348
|
+
document.getElementById('picker-primary').value = primary.startsWith('#') ? primary : '#3182f6';
|
|
349
|
+
document.getElementById('val-primary').value = primary;
|
|
350
|
+
|
|
351
|
+
document.getElementById('picker-primary-hover').value = hover.startsWith('#') ? hover : '#1b64da';
|
|
352
|
+
document.getElementById('val-primary-hover').value = hover;
|
|
353
|
+
|
|
354
|
+
document.getElementById('picker-bg-surface').value = surface.startsWith('#') ? surface : '#18181b';
|
|
355
|
+
document.getElementById('val-bg-surface').value = surface;
|
|
356
|
+
|
|
357
|
+
document.getElementById('val-radius').value = radius;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function onColorChange(key, val) {
|
|
361
|
+
if (!currentTokens.color) currentTokens.color = {};
|
|
362
|
+
if (key === 'primary') {
|
|
363
|
+
document.getElementById('picker-primary').value = val.startsWith('#') ? val : '#3182f6';
|
|
364
|
+
document.getElementById('val-primary').value = val;
|
|
365
|
+
if (!currentTokens.color.brand) currentTokens.color.brand = {};
|
|
366
|
+
if (!currentTokens.color.brand['color-primary']) currentTokens.color.brand['color-primary'] = { variable: '--atom-color-primary' };
|
|
367
|
+
currentTokens.color.brand['color-primary'].$value = val;
|
|
368
|
+
}
|
|
369
|
+
if (key === 'primary-hover') {
|
|
370
|
+
document.getElementById('picker-primary-hover').value = val.startsWith('#') ? val : '#1b64da';
|
|
371
|
+
document.getElementById('val-primary-hover').value = val;
|
|
372
|
+
if (!currentTokens.color.brand) currentTokens.color.brand = {};
|
|
373
|
+
if (!currentTokens.color.brand['color-primary-hover']) currentTokens.color.brand['color-primary-hover'] = { variable: '--atom-color-primary-hover' };
|
|
374
|
+
currentTokens.color.brand['color-primary-hover'].$value = val;
|
|
375
|
+
}
|
|
376
|
+
if (key === 'bg-surface') {
|
|
377
|
+
document.getElementById('picker-bg-surface').value = val.startsWith('#') ? val : '#18181b';
|
|
378
|
+
document.getElementById('val-bg-surface').value = val;
|
|
379
|
+
if (!currentTokens.color.surface) currentTokens.color.surface = {};
|
|
380
|
+
if (!currentTokens.color.surface['bg-surface']) currentTokens.color.surface['bg-surface'] = { variable: '--atom-bg-surface' };
|
|
381
|
+
currentTokens.color.surface['bg-surface'].$value = val;
|
|
382
|
+
}
|
|
383
|
+
updatePreview();
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function onRadiusChange(val) {
|
|
387
|
+
if (!currentTokens.borderRadius) currentTokens.borderRadius = {};
|
|
388
|
+
if (!currentTokens.borderRadius.md) currentTokens.borderRadius.md = { variable: '--atom-radius-md' };
|
|
389
|
+
currentTokens.borderRadius.md.$value = val;
|
|
390
|
+
updatePreview();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function updatePreview() {
|
|
394
|
+
const primary = document.getElementById('val-primary').value;
|
|
395
|
+
const surface = document.getElementById('val-bg-surface').value;
|
|
396
|
+
const radius = document.getElementById('val-radius').value;
|
|
397
|
+
|
|
398
|
+
const btn = document.getElementById('sample-btn');
|
|
399
|
+
const card = document.getElementById('sample-card');
|
|
400
|
+
|
|
401
|
+
btn.style.backgroundColor = primary;
|
|
402
|
+
btn.style.borderRadius = radius;
|
|
403
|
+
card.style.backgroundColor = surface;
|
|
404
|
+
card.style.borderRadius = radius;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async function saveTokens() {
|
|
408
|
+
try {
|
|
409
|
+
const res = await fetch('/api/tokens', {
|
|
410
|
+
method: 'POST',
|
|
411
|
+
headers: { 'Content-Type': 'application/json' },
|
|
412
|
+
body: JSON.stringify(currentTokens)
|
|
413
|
+
});
|
|
414
|
+
const result = await res.json();
|
|
415
|
+
if (result.success) {
|
|
416
|
+
showToast();
|
|
417
|
+
} else {
|
|
418
|
+
alert('\uC800\uC7A5 \uC2E4\uD328: ' + result.error);
|
|
419
|
+
}
|
|
420
|
+
} catch (e) {
|
|
421
|
+
alert('\uC11C\uBC84 \uD1B5\uC2E0 \uC624\uB958: ' + e.message);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function showToast() {
|
|
426
|
+
const toast = document.getElementById('toast');
|
|
427
|
+
toast.style.display = 'block';
|
|
428
|
+
setTimeout(() => { toast.style.display = 'none'; }, 2500);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
loadTokens();
|
|
432
|
+
</script>
|
|
433
|
+
</body>
|
|
434
|
+
</html>`;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// src/cli.ts
|
|
14
438
|
function getPkgRoot() {
|
|
15
439
|
try {
|
|
16
440
|
if (typeof __dirname !== "undefined") {
|
|
17
|
-
return
|
|
441
|
+
return path2__default.default.resolve(__dirname, "..");
|
|
18
442
|
}
|
|
19
443
|
const currentFile = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cli.cjs', document.baseURI).href)));
|
|
20
|
-
return
|
|
444
|
+
return path2__default.default.resolve(path2__default.default.dirname(currentFile), "..");
|
|
21
445
|
} catch {
|
|
22
446
|
return process.cwd();
|
|
23
447
|
}
|
|
@@ -25,43 +449,190 @@ function getPkgRoot() {
|
|
|
25
449
|
var PKG_ROOT = getPkgRoot();
|
|
26
450
|
var args = process.argv.slice(2);
|
|
27
451
|
var command = args[0] || "help";
|
|
452
|
+
var targetName = args[1];
|
|
28
453
|
function copyFileSafe(src, dest, label) {
|
|
29
|
-
const targetDir =
|
|
30
|
-
if (!
|
|
31
|
-
|
|
454
|
+
const targetDir = path2__default.default.dirname(dest);
|
|
455
|
+
if (!fs2__default.default.existsSync(targetDir)) {
|
|
456
|
+
fs2__default.default.mkdirSync(targetDir, { recursive: true });
|
|
32
457
|
}
|
|
33
|
-
|
|
34
|
-
console.log(` \u2713
|
|
458
|
+
fs2__default.default.copyFileSync(src, dest);
|
|
459
|
+
console.log(` \u2713 ${label} -> ${path2__default.default.relative(process.cwd(), dest)}`);
|
|
35
460
|
}
|
|
36
461
|
function handleInit() {
|
|
37
462
|
const cwd = process.cwd();
|
|
38
|
-
console.log("\n\u{1F680} Initializing AtomSystem
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
copyFileSafe(
|
|
463
|
+
console.log("\n\u{1F680} Initializing AtomSystem Universal Design System...\n");
|
|
464
|
+
const srcAgentGuide = path2__default.default.join(PKG_ROOT, "presets", "agents.guide.md");
|
|
465
|
+
if (fs2__default.default.existsSync(srcAgentGuide)) {
|
|
466
|
+
copyFileSafe(srcAgentGuide, path2__default.default.join(cwd, "AGENTS.md"), "Universal AI Guide (AGENTS.md)");
|
|
467
|
+
copyFileSafe(srcAgentGuide, path2__default.default.join(cwd, "CLAUDE.md"), "Claude Code Guidelines (CLAUDE.md)");
|
|
468
|
+
copyFileSafe(srcAgentGuide, path2__default.default.join(cwd, ".cursorrules"), "Cursor Rules (.cursorrules)");
|
|
469
|
+
}
|
|
470
|
+
const srcSkill = path2__default.default.join(PKG_ROOT, "skills", "atomsystem.skill.md");
|
|
471
|
+
if (fs2__default.default.existsSync(srcSkill)) {
|
|
472
|
+
copyFileSafe(srcSkill, path2__default.default.join(cwd, ".agents", "skills", "atomsystem", "SKILL.md"), "Agent Skill (.agents/skills/atomsystem/SKILL.md)");
|
|
473
|
+
}
|
|
474
|
+
const specs = [
|
|
475
|
+
{ src: path2__default.default.join(PKG_ROOT, "presets", "default.design.md"), dest: path2__default.default.join(cwd, "atom.design.md"), label: "Design Tokens (atom.design.md)" },
|
|
476
|
+
{ src: path2__default.default.join(PKG_ROOT, "presets", "components.md"), dest: path2__default.default.join(cwd, "atom.components.md"), label: "Components Spec (atom.components.md)" },
|
|
477
|
+
{ src: path2__default.default.join(PKG_ROOT, "presets", "blocks.md"), dest: path2__default.default.join(cwd, "atom.blocks.md"), label: "Design Blocks Spec (atom.blocks.md)" },
|
|
478
|
+
{ src: path2__default.default.join(PKG_ROOT, "presets", "uxPattern.md"), dest: path2__default.default.join(cwd, "atom.uxPattern.md"), label: "UX Patterns (atom.uxPattern.md)" }
|
|
479
|
+
];
|
|
480
|
+
specs.forEach((s) => {
|
|
481
|
+
if (fs2__default.default.existsSync(s.src)) {
|
|
482
|
+
copyFileSafe(s.src, s.dest, s.label);
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
const srcToken = path2__default.default.join(PKG_ROOT, "tokens", "token.json");
|
|
486
|
+
if (fs2__default.default.existsSync(srcToken)) {
|
|
487
|
+
copyFileSafe(srcToken, path2__default.default.join(cwd, "tokens", "token.json"), "W3C DTCG Token JSON (tokens/token.json)");
|
|
488
|
+
}
|
|
489
|
+
const srcCss = path2__default.default.join(PKG_ROOT, "css", "atom-ui.css");
|
|
490
|
+
if (fs2__default.default.existsSync(srcCss)) {
|
|
491
|
+
copyFileSafe(srcCss, path2__default.default.join(cwd, "css", "atom-ui.css"), "Zero-Runtime Semantic CSS (css/atom-ui.css)");
|
|
492
|
+
}
|
|
493
|
+
console.log("\n\u2728 AtomSystem initialization completed successfully!");
|
|
494
|
+
console.log("\n\u{1F3A8} Local Token Studio Available:");
|
|
495
|
+
console.log(' Run "npx atomsystem studio" to launch the local web customizer GUI.');
|
|
496
|
+
console.log(" You can visually edit tokens and immediately recompile css/atom-ui.css.");
|
|
497
|
+
console.log("\n\u{1F4CC} How AI Coding Works Now:");
|
|
498
|
+
console.log(" Any AI assistant (Claude Code, Cursor, Copilot, Antigravity) will now");
|
|
499
|
+
console.log(" AUTOMATICALLY detect the design tokens, components, and UX patterns.");
|
|
500
|
+
console.log("\n\u{1F4CC} You can now ask your AI:");
|
|
501
|
+
console.log(' "\uB300\uC2DC\uBCF4\uB4DC \uD654\uBA74\uC5D0 \uC2E4\uC2DC\uAC04 \uCC28\uD2B8\uC640 \uAC00\uACA9 \uC815\uCC45 \uBE14\uB85D\uC744 \uB808\uACE0\uCC98\uB7FC \uC870\uB9BD\uD574\uC918."');
|
|
502
|
+
console.log(' "atom.design.md\uC758 \uC0C9\uC0C1 \uD1A0\uD070\uC744 \uBC14\uD0D5\uC73C\uB85C \uACB0\uC81C \uD655\uC778 \uBAA8\uB2EC\uC744 \uB9CC\uB4E4\uC5B4\uC918."\n');
|
|
503
|
+
}
|
|
504
|
+
var COMPONENT_MAP = {
|
|
505
|
+
button: "Button.tsx",
|
|
506
|
+
card: "Card.tsx",
|
|
507
|
+
badge: "Badge.tsx",
|
|
508
|
+
input: "Input.tsx",
|
|
509
|
+
table: "Table.tsx",
|
|
510
|
+
tabs: "Tabs.tsx",
|
|
511
|
+
switch: "Switch.tsx",
|
|
512
|
+
modal: "Modal.tsx",
|
|
513
|
+
container: "Container.tsx",
|
|
514
|
+
layout: "Layout.tsx"
|
|
515
|
+
};
|
|
516
|
+
var BLOCK_MAP = {
|
|
517
|
+
"realtime-chart": { file: "RealtimeChartBlock.tsx", deps: ["card", "button", "badge"] },
|
|
518
|
+
"interactive-chat": { file: "InteractiveChatBlock.tsx", deps: ["card", "input", "button", "badge"] },
|
|
519
|
+
"pricing-table": { file: "PricingPlanBlock.tsx", deps: ["card", "button", "badge"] },
|
|
520
|
+
"card-list": { file: "CardListBlock.tsx", deps: ["card", "input", "button", "badge"] },
|
|
521
|
+
"interactive-slider": { file: "SliderShowcaseBlock.tsx", deps: ["card", "button", "badge"] },
|
|
522
|
+
"metric-stats": { file: "MetricStatsBlock.tsx", deps: ["card", "badge"] },
|
|
523
|
+
"file-explorer": { file: "FileExplorerBlock.tsx", deps: ["card", "button", "badge"] }
|
|
524
|
+
};
|
|
525
|
+
function handleAdd(name) {
|
|
526
|
+
if (!name) {
|
|
527
|
+
console.error("\n\u274C Please specify an item to add. Example: npx atomsystem add button\n");
|
|
528
|
+
handleList();
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const cwd = process.cwd();
|
|
532
|
+
const normalized = name.toLowerCase().trim();
|
|
533
|
+
if (COMPONENT_MAP[normalized]) {
|
|
534
|
+
const fileName = COMPONENT_MAP[normalized];
|
|
535
|
+
const src = path2__default.default.join(PKG_ROOT, "components", "ui", fileName);
|
|
536
|
+
const dest = path2__default.default.join(cwd, "components", "ui", fileName);
|
|
537
|
+
if (fs2__default.default.existsSync(src)) {
|
|
538
|
+
copyFileSafe(src, dest, `Component (${fileName})`);
|
|
539
|
+
console.log(`
|
|
540
|
+
\u2705 Added ${normalized} component to components/ui/${fileName}
|
|
541
|
+
`);
|
|
542
|
+
} else {
|
|
543
|
+
console.error(`
|
|
544
|
+
\u274C Source component file not found: ${src}
|
|
545
|
+
`);
|
|
546
|
+
}
|
|
547
|
+
return;
|
|
43
548
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
549
|
+
if (BLOCK_MAP[normalized]) {
|
|
550
|
+
const { file, deps } = BLOCK_MAP[normalized];
|
|
551
|
+
console.log(`
|
|
552
|
+
\u{1F4E6} Adding block "${normalized}" and its dependent components...
|
|
553
|
+
`);
|
|
554
|
+
deps.forEach((dep) => {
|
|
555
|
+
const depFile = COMPONENT_MAP[dep];
|
|
556
|
+
if (depFile) {
|
|
557
|
+
const srcDep = path2__default.default.join(PKG_ROOT, "components", "ui", depFile);
|
|
558
|
+
const destDep = path2__default.default.join(cwd, "components", "ui", depFile);
|
|
559
|
+
if (fs2__default.default.existsSync(srcDep)) {
|
|
560
|
+
copyFileSafe(srcDep, destDep, `Dependent Component (${depFile})`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
const srcBlock = path2__default.default.join(PKG_ROOT, "components", "blocks", file);
|
|
565
|
+
const destBlock = path2__default.default.join(cwd, "components", "blocks", file);
|
|
566
|
+
if (fs2__default.default.existsSync(srcBlock)) {
|
|
567
|
+
copyFileSafe(srcBlock, destBlock, `Block (${file})`);
|
|
568
|
+
console.log(`
|
|
569
|
+
\u2705 Block "${normalized}" successfully added to components/blocks/${file}
|
|
570
|
+
`);
|
|
571
|
+
} else {
|
|
572
|
+
console.error(`
|
|
573
|
+
\u274C Source block file not found: ${srcBlock}
|
|
574
|
+
`);
|
|
575
|
+
}
|
|
576
|
+
return;
|
|
48
577
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
578
|
+
console.error(`
|
|
579
|
+
\u274C Unknown item: "${name}".`);
|
|
580
|
+
handleList();
|
|
581
|
+
}
|
|
582
|
+
function handleList() {
|
|
583
|
+
console.log(`
|
|
584
|
+
Available Components:
|
|
585
|
+
- button (Button, ButtonVariants)
|
|
586
|
+
- card (Card container)
|
|
587
|
+
- badge (Status badge)
|
|
588
|
+
- input (Input with status)
|
|
589
|
+
- table (Table, Header, Row, Cell)
|
|
590
|
+
- tabs (TabsList, TabsTrigger)
|
|
591
|
+
- switch (A11y Switch toggle)
|
|
592
|
+
- modal (Dialog with Esc key support)
|
|
593
|
+
|
|
594
|
+
Available Design Blocks:
|
|
595
|
+
- realtime-chart (Live streaming candlestick/line chart)
|
|
596
|
+
- interactive-chat (AI chatbot feed with suggestions)
|
|
597
|
+
- pricing-table (Monthly/annual tier pricing table)
|
|
598
|
+
- card-list (Responsive grid & list filter)
|
|
599
|
+
- interactive-slider (Cost simulation calculator & carousel)
|
|
600
|
+
- metric-stats (4 KPI executive metric cards)
|
|
601
|
+
- file-explorer (Hierarchical directory tree explorer)
|
|
602
|
+
|
|
603
|
+
Install any item:
|
|
604
|
+
npx atomsystem add <item-name>
|
|
605
|
+
`);
|
|
606
|
+
}
|
|
607
|
+
function handleBuildTokens() {
|
|
608
|
+
const cwd = process.cwd();
|
|
609
|
+
const tokenJsonPath = path2__default.default.join(cwd, "tokens", "token.json");
|
|
610
|
+
const cssPath = path2__default.default.join(cwd, "css", "atom-ui.css");
|
|
611
|
+
if (!fs2__default.default.existsSync(tokenJsonPath)) {
|
|
612
|
+
console.error(`
|
|
613
|
+
\u274C tokens/token.json not found at ${tokenJsonPath}. Run 'npx atomsystem init' first.
|
|
614
|
+
`);
|
|
615
|
+
return;
|
|
53
616
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
617
|
+
try {
|
|
618
|
+
const tokens = JSON.parse(fs2__default.default.readFileSync(tokenJsonPath, "utf-8"));
|
|
619
|
+
const css = compileTokensToCss(tokens);
|
|
620
|
+
const cssDir = path2__default.default.dirname(cssPath);
|
|
621
|
+
if (!fs2__default.default.existsSync(cssDir)) fs2__default.default.mkdirSync(cssDir, { recursive: true });
|
|
622
|
+
fs2__default.default.writeFileSync(cssPath, css, "utf-8");
|
|
623
|
+
console.log(`
|
|
624
|
+
\u2728 Successfully compiled tokens to ${path2__default.default.relative(cwd, cssPath)}!
|
|
625
|
+
`);
|
|
626
|
+
} catch (err) {
|
|
627
|
+
console.error(`
|
|
628
|
+
\u274C Failed to compile tokens: ${err.message}
|
|
629
|
+
`);
|
|
58
630
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console.log(' "atom.design.md\uC640 atom.uxPattern.md\uB97C \uCC38\uACE0\uD558\uC5EC \uACB0\uC81C \uD654\uBA74 \uCEF4\uD3EC\uB10C\uD2B8\uB97C \uB9CC\uB4E4\uC5B4\uC918."\n');
|
|
631
|
+
}
|
|
632
|
+
function handleStudio() {
|
|
633
|
+
const portArg = args.find((a) => a.startsWith("--port="));
|
|
634
|
+
const port = portArg ? parseInt(portArg.split("=")[1], 10) : 4e3;
|
|
635
|
+
startLocalTokenStudio({ port, cwd: process.cwd() });
|
|
65
636
|
}
|
|
66
637
|
function showHelp() {
|
|
67
638
|
console.log(`
|
|
@@ -71,24 +642,45 @@ Usage:
|
|
|
71
642
|
npx atomsystem <command> [options]
|
|
72
643
|
|
|
73
644
|
Commands:
|
|
74
|
-
init
|
|
75
|
-
|
|
76
|
-
|
|
645
|
+
init Initialize AI guidelines, tokens, specs, and CSS in your project
|
|
646
|
+
studio Launch Local Web Token Studio GUI (interactive token customizer)
|
|
647
|
+
build:tokens Compile tokens/token.json into zero-runtime css/atom-ui.css
|
|
648
|
+
add <name> Add a component or block directly to your project
|
|
649
|
+
list List all available components and blocks
|
|
650
|
+
help Display this help message
|
|
651
|
+
version Print version info
|
|
652
|
+
|
|
653
|
+
Options for studio:
|
|
654
|
+
--port=<port> Port for the local studio server (default: 4000)
|
|
77
655
|
`);
|
|
78
656
|
}
|
|
79
657
|
function showVersion() {
|
|
80
|
-
const pkgPath =
|
|
81
|
-
if (
|
|
82
|
-
const pkg = JSON.parse(
|
|
658
|
+
const pkgPath = path2__default.default.join(PKG_ROOT, "package.json");
|
|
659
|
+
if (fs2__default.default.existsSync(pkgPath)) {
|
|
660
|
+
const pkg = JSON.parse(fs2__default.default.readFileSync(pkgPath, "utf-8"));
|
|
83
661
|
console.log(`atomsystem v${pkg.version}`);
|
|
84
662
|
} else {
|
|
85
|
-
console.log("atomsystem v0.
|
|
663
|
+
console.log("atomsystem v0.5.0");
|
|
86
664
|
}
|
|
87
665
|
}
|
|
88
666
|
switch (command) {
|
|
89
667
|
case "init":
|
|
90
668
|
handleInit();
|
|
91
669
|
break;
|
|
670
|
+
case "studio":
|
|
671
|
+
case "editor":
|
|
672
|
+
handleStudio();
|
|
673
|
+
break;
|
|
674
|
+
case "build:tokens":
|
|
675
|
+
case "compile":
|
|
676
|
+
handleBuildTokens();
|
|
677
|
+
break;
|
|
678
|
+
case "add":
|
|
679
|
+
handleAdd(targetName);
|
|
680
|
+
break;
|
|
681
|
+
case "list":
|
|
682
|
+
handleList();
|
|
683
|
+
break;
|
|
92
684
|
case "version":
|
|
93
685
|
case "-v":
|
|
94
686
|
case "--version":
|