@mizumi25/cli 0.1.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/docs-generator.js +713 -0
- package/index.js +416 -0
- package/package.json +20 -0
- package/watcher.js +56 -0
|
@@ -0,0 +1,713 @@
|
|
|
1
|
+
// packages/cli/docs-generator.js
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export class DocsGenerator {
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.config = config;
|
|
9
|
+
this.tokens = config.tokens || {};
|
|
10
|
+
this.patterns = config.patterns || {};
|
|
11
|
+
this.animations = config.animations || {};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
generate() {
|
|
15
|
+
return `<!DOCTYPE html>
|
|
16
|
+
<html lang="en">
|
|
17
|
+
<head>
|
|
18
|
+
<meta charset="UTF-8">
|
|
19
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
20
|
+
<title>Mizumi Docs š</title>
|
|
21
|
+
<style>
|
|
22
|
+
* { margin:0; padding:0; box-sizing:border-box; }
|
|
23
|
+
|
|
24
|
+
body {
|
|
25
|
+
font-family: system-ui, sans-serif;
|
|
26
|
+
background: #0f172a;
|
|
27
|
+
color: #e2e8f0;
|
|
28
|
+
min-height: 100vh;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Layout */
|
|
32
|
+
.sidebar {
|
|
33
|
+
position: fixed;
|
|
34
|
+
top: 0; left: 0;
|
|
35
|
+
width: 240px;
|
|
36
|
+
height: 100vh;
|
|
37
|
+
background: #1e293b;
|
|
38
|
+
border-right: 1px solid #334155;
|
|
39
|
+
overflow-y: auto;
|
|
40
|
+
padding: 24px 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.main {
|
|
44
|
+
margin-left: 240px;
|
|
45
|
+
padding: 40px;
|
|
46
|
+
max-width: 1000px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/* Sidebar */
|
|
50
|
+
.sidebar-logo {
|
|
51
|
+
padding: 0 20px 24px;
|
|
52
|
+
border-bottom: 1px solid #334155;
|
|
53
|
+
margin-bottom: 16px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.sidebar-logo h1 {
|
|
57
|
+
font-size: 20px;
|
|
58
|
+
font-weight: 800;
|
|
59
|
+
color: #38bdf8;
|
|
60
|
+
letter-spacing: -0.5px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.sidebar-logo span {
|
|
64
|
+
font-size: 12px;
|
|
65
|
+
color: #64748b;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.nav-section {
|
|
69
|
+
padding: 8px 20px 4px;
|
|
70
|
+
font-size: 11px;
|
|
71
|
+
font-weight: 700;
|
|
72
|
+
text-transform: uppercase;
|
|
73
|
+
letter-spacing: 1px;
|
|
74
|
+
color: #475569;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.nav-link {
|
|
78
|
+
display: block;
|
|
79
|
+
padding: 8px 20px;
|
|
80
|
+
color: #94a3b8;
|
|
81
|
+
text-decoration: none;
|
|
82
|
+
font-size: 14px;
|
|
83
|
+
transition: all 0.15s;
|
|
84
|
+
border-left: 3px solid transparent;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.nav-link:hover {
|
|
88
|
+
color: #e2e8f0;
|
|
89
|
+
background: #334155;
|
|
90
|
+
border-left-color: #38bdf8;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Sections */
|
|
94
|
+
.section {
|
|
95
|
+
margin-bottom: 64px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.section-title {
|
|
99
|
+
font-size: 28px;
|
|
100
|
+
font-weight: 700;
|
|
101
|
+
color: #f1f5f9;
|
|
102
|
+
margin-bottom: 8px;
|
|
103
|
+
padding-bottom: 16px;
|
|
104
|
+
border-bottom: 1px solid #334155;
|
|
105
|
+
letter-spacing: -0.5px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.section-sub {
|
|
109
|
+
font-size: 18px;
|
|
110
|
+
font-weight: 600;
|
|
111
|
+
color: #cbd5e1;
|
|
112
|
+
margin: 32px 0 16px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Cards */
|
|
116
|
+
.card-grid {
|
|
117
|
+
display: grid;
|
|
118
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
119
|
+
gap: 12px;
|
|
120
|
+
margin-bottom: 24px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.doc-card {
|
|
124
|
+
background: #1e293b;
|
|
125
|
+
border: 1px solid #334155;
|
|
126
|
+
border-radius: 10px;
|
|
127
|
+
padding: 16px;
|
|
128
|
+
transition: border-color 0.15s;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.doc-card:hover { border-color: #38bdf8; }
|
|
132
|
+
|
|
133
|
+
.doc-card-name {
|
|
134
|
+
font-family: monospace;
|
|
135
|
+
font-size: 13px;
|
|
136
|
+
color: #38bdf8;
|
|
137
|
+
margin-bottom: 8px;
|
|
138
|
+
font-weight: 600;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.doc-card-value {
|
|
142
|
+
font-size: 12px;
|
|
143
|
+
color: #64748b;
|
|
144
|
+
word-break: break-all;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* Color swatches */
|
|
148
|
+
.color-swatch {
|
|
149
|
+
width: 100%;
|
|
150
|
+
height: 40px;
|
|
151
|
+
border-radius: 6px;
|
|
152
|
+
margin-bottom: 8px;
|
|
153
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Pattern rows */
|
|
157
|
+
.pattern-row {
|
|
158
|
+
background: #1e293b;
|
|
159
|
+
border: 1px solid #334155;
|
|
160
|
+
border-radius: 10px;
|
|
161
|
+
padding: 16px 20px;
|
|
162
|
+
margin-bottom: 8px;
|
|
163
|
+
display: flex;
|
|
164
|
+
align-items: flex-start;
|
|
165
|
+
gap: 16px;
|
|
166
|
+
flex-wrap: wrap;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.pattern-name {
|
|
170
|
+
font-family: monospace;
|
|
171
|
+
font-size: 14px;
|
|
172
|
+
color: #38bdf8;
|
|
173
|
+
font-weight: 600;
|
|
174
|
+
min-width: 160px;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.pattern-arrow {
|
|
178
|
+
color: #475569;
|
|
179
|
+
font-size: 14px;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.pattern-value {
|
|
183
|
+
font-family: monospace;
|
|
184
|
+
font-size: 13px;
|
|
185
|
+
color: #94a3b8;
|
|
186
|
+
flex: 1;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Animation rows */
|
|
190
|
+
.anim-row {
|
|
191
|
+
background: #1e293b;
|
|
192
|
+
border: 1px solid #334155;
|
|
193
|
+
border-radius: 10px;
|
|
194
|
+
padding: 16px 20px;
|
|
195
|
+
margin-bottom: 8px;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.anim-header {
|
|
199
|
+
display: flex;
|
|
200
|
+
align-items: center;
|
|
201
|
+
gap: 12px;
|
|
202
|
+
margin-bottom: 8px;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.anim-name {
|
|
206
|
+
font-family: monospace;
|
|
207
|
+
font-size: 14px;
|
|
208
|
+
color: #38bdf8;
|
|
209
|
+
font-weight: 600;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.anim-type {
|
|
213
|
+
font-size: 11px;
|
|
214
|
+
font-weight: 700;
|
|
215
|
+
padding: 2px 8px;
|
|
216
|
+
border-radius: 999px;
|
|
217
|
+
text-transform: uppercase;
|
|
218
|
+
letter-spacing: 0.5px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.type-entrance { background: #0d3b26; color: #34d399; }
|
|
222
|
+
.type-hover { background: #1e1a3b; color: #a78bfa; }
|
|
223
|
+
.type-click { background: #3b1a1a; color: #f87171; }
|
|
224
|
+
.type-scroll { background: #1a2e3b; color: #38bdf8; }
|
|
225
|
+
.type-stagger { background: #2e2a0d; color: #fbbf24; }
|
|
226
|
+
.type-loop { background: #2e1a3b; color: #e879f9; }
|
|
227
|
+
|
|
228
|
+
.anim-config {
|
|
229
|
+
font-family: monospace;
|
|
230
|
+
font-size: 12px;
|
|
231
|
+
color: #64748b;
|
|
232
|
+
line-height: 1.6;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* Usage box */
|
|
236
|
+
.usage-box {
|
|
237
|
+
background: #0f172a;
|
|
238
|
+
border: 1px solid #334155;
|
|
239
|
+
border-radius: 6px;
|
|
240
|
+
padding: 10px 14px;
|
|
241
|
+
margin-top: 8px;
|
|
242
|
+
font-family: monospace;
|
|
243
|
+
font-size: 12px;
|
|
244
|
+
color: #86efac;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Spacing preview */
|
|
248
|
+
.spacing-preview {
|
|
249
|
+
display: flex;
|
|
250
|
+
align-items: center;
|
|
251
|
+
gap: 12px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.spacing-bar {
|
|
255
|
+
background: #38bdf8;
|
|
256
|
+
height: 16px;
|
|
257
|
+
border-radius: 3px;
|
|
258
|
+
opacity: 0.7;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* Search */
|
|
262
|
+
.search-bar {
|
|
263
|
+
width: 100%;
|
|
264
|
+
background: #1e293b;
|
|
265
|
+
border: 1px solid #334155;
|
|
266
|
+
border-radius: 10px;
|
|
267
|
+
padding: 12px 16px;
|
|
268
|
+
color: #e2e8f0;
|
|
269
|
+
font-size: 14px;
|
|
270
|
+
margin-bottom: 32px;
|
|
271
|
+
outline: none;
|
|
272
|
+
transition: border-color 0.15s;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.search-bar:focus { border-color: #38bdf8; }
|
|
276
|
+
.search-bar::placeholder { color: #475569; }
|
|
277
|
+
|
|
278
|
+
/* Stats bar */
|
|
279
|
+
.stats-bar {
|
|
280
|
+
display: flex;
|
|
281
|
+
gap: 24px;
|
|
282
|
+
margin-bottom: 48px;
|
|
283
|
+
flex-wrap: wrap;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.stat {
|
|
287
|
+
background: #1e293b;
|
|
288
|
+
border: 1px solid #334155;
|
|
289
|
+
border-radius: 10px;
|
|
290
|
+
padding: 16px 24px;
|
|
291
|
+
text-align: center;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.stat-number {
|
|
295
|
+
font-size: 28px;
|
|
296
|
+
font-weight: 800;
|
|
297
|
+
color: #38bdf8;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.stat-label {
|
|
301
|
+
font-size: 12px;
|
|
302
|
+
color: #64748b;
|
|
303
|
+
margin-top: 2px;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* Header */
|
|
307
|
+
.docs-header {
|
|
308
|
+
margin-bottom: 48px;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.docs-header h1 {
|
|
312
|
+
font-size: 40px;
|
|
313
|
+
font-weight: 800;
|
|
314
|
+
color: #f1f5f9;
|
|
315
|
+
letter-spacing: -1px;
|
|
316
|
+
margin-bottom: 8px;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.docs-header p {
|
|
320
|
+
color: #64748b;
|
|
321
|
+
font-size: 16px;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.badge {
|
|
325
|
+
display: inline-block;
|
|
326
|
+
background: #0c2a1a;
|
|
327
|
+
color: #34d399;
|
|
328
|
+
border: 1px solid #34d399;
|
|
329
|
+
padding: 3px 10px;
|
|
330
|
+
border-radius: 999px;
|
|
331
|
+
font-size: 12px;
|
|
332
|
+
font-weight: 600;
|
|
333
|
+
margin-left: 8px;
|
|
334
|
+
vertical-align: middle;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* Scrollbar */
|
|
338
|
+
::-webkit-scrollbar { width: 6px; }
|
|
339
|
+
::-webkit-scrollbar-track { background: #0f172a; }
|
|
340
|
+
::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; }
|
|
341
|
+
</style>
|
|
342
|
+
</head>
|
|
343
|
+
<body>
|
|
344
|
+
|
|
345
|
+
<!-- SIDEBAR -->
|
|
346
|
+
<nav class="sidebar">
|
|
347
|
+
<div class="sidebar-logo">
|
|
348
|
+
<h1>š Mizumi</h1>
|
|
349
|
+
<span>v0.1.0 Docs</span>
|
|
350
|
+
</div>
|
|
351
|
+
|
|
352
|
+
<div class="nav-section">Getting Started</div>
|
|
353
|
+
<a href="#overview" class="nav-link">Overview</a>
|
|
354
|
+
|
|
355
|
+
<div class="nav-section">Design Tokens</div>
|
|
356
|
+
<a href="#colors" class="nav-link">Colors</a>
|
|
357
|
+
<a href="#spacing" class="nav-link">Spacing</a>
|
|
358
|
+
<a href="#typography" class="nav-link">Typography</a>
|
|
359
|
+
<a href="#radius" class="nav-link">Border Radius</a>
|
|
360
|
+
<a href="#shadows" class="nav-link">Shadows</a>
|
|
361
|
+
|
|
362
|
+
<div class="nav-section">Patterns</div>
|
|
363
|
+
<a href="#patterns" class="nav-link">All Patterns</a>
|
|
364
|
+
|
|
365
|
+
<div class="nav-section">Animations</div>
|
|
366
|
+
<a href="#animations" class="nav-link">All Animations</a>
|
|
367
|
+
<a href="#modifiers" class="nav-link">Modifiers</a>
|
|
368
|
+
</nav>
|
|
369
|
+
|
|
370
|
+
<!-- MAIN -->
|
|
371
|
+
<main class="main">
|
|
372
|
+
|
|
373
|
+
<!-- Header -->
|
|
374
|
+
<div class="docs-header">
|
|
375
|
+
<h1>Mizumi Docs <span class="badge">v0.1.0</span></h1>
|
|
376
|
+
<p>Auto-generated from your mizumi.config.js</p>
|
|
377
|
+
</div>
|
|
378
|
+
|
|
379
|
+
<!-- Search -->
|
|
380
|
+
<input
|
|
381
|
+
class="search-bar"
|
|
382
|
+
type="text"
|
|
383
|
+
placeholder="Search tokens, patterns, animations..."
|
|
384
|
+
oninput="handleSearch(this.value)"
|
|
385
|
+
>
|
|
386
|
+
|
|
387
|
+
<!-- Stats -->
|
|
388
|
+
<div class="stats-bar">
|
|
389
|
+
<div class="stat">
|
|
390
|
+
<div class="stat-number">${this.countTokens()}</div>
|
|
391
|
+
<div class="stat-label">Tokens</div>
|
|
392
|
+
</div>
|
|
393
|
+
<div class="stat">
|
|
394
|
+
<div class="stat-number">${Object.keys(this.patterns).length}</div>
|
|
395
|
+
<div class="stat-label">Patterns</div>
|
|
396
|
+
</div>
|
|
397
|
+
<div class="stat">
|
|
398
|
+
<div class="stat-number">${Object.keys(this.animations).length}</div>
|
|
399
|
+
<div class="stat-label">Animations</div>
|
|
400
|
+
</div>
|
|
401
|
+
<div class="stat">
|
|
402
|
+
<div class="stat-number">${Object.keys(this.config.rules?.breakpoints || {}).length}</div>
|
|
403
|
+
<div class="stat-label">Breakpoints</div>
|
|
404
|
+
</div>
|
|
405
|
+
</div>
|
|
406
|
+
|
|
407
|
+
<!-- COLORS -->
|
|
408
|
+
<section class="section" id="colors">
|
|
409
|
+
<h2 class="section-title">Colors</h2>
|
|
410
|
+
<div class="card-grid">
|
|
411
|
+
${this.generateColorCards()}
|
|
412
|
+
</div>
|
|
413
|
+
</section>
|
|
414
|
+
|
|
415
|
+
<!-- SPACING -->
|
|
416
|
+
<section class="section" id="spacing">
|
|
417
|
+
<h2 class="section-title">Spacing</h2>
|
|
418
|
+
<div style="display:flex; flex-direction:column; gap:8px;">
|
|
419
|
+
${this.generateSpacingRows()}
|
|
420
|
+
</div>
|
|
421
|
+
</section>
|
|
422
|
+
|
|
423
|
+
<!-- TYPOGRAPHY -->
|
|
424
|
+
<section class="section" id="typography">
|
|
425
|
+
<h2 class="section-title">Typography</h2>
|
|
426
|
+
<div style="display:flex; flex-direction:column; gap:12px;">
|
|
427
|
+
${this.generateTypographyRows()}
|
|
428
|
+
</div>
|
|
429
|
+
</section>
|
|
430
|
+
|
|
431
|
+
<!-- RADIUS -->
|
|
432
|
+
<section class="section" id="radius">
|
|
433
|
+
<h2 class="section-title">Border Radius</h2>
|
|
434
|
+
<div class="card-grid">
|
|
435
|
+
${this.generateRadiusCards()}
|
|
436
|
+
</div>
|
|
437
|
+
</section>
|
|
438
|
+
|
|
439
|
+
<!-- SHADOWS -->
|
|
440
|
+
<section class="section" id="shadows">
|
|
441
|
+
<h2 class="section-title">Shadows</h2>
|
|
442
|
+
<div style="display:flex; flex-direction:column; gap:12px;">
|
|
443
|
+
${this.generateShadowCards()}
|
|
444
|
+
</div>
|
|
445
|
+
</section>
|
|
446
|
+
|
|
447
|
+
<!-- PATTERNS -->
|
|
448
|
+
<section class="section" id="patterns">
|
|
449
|
+
<h2 class="section-title">Patterns</h2>
|
|
450
|
+
<div id="patterns-list">
|
|
451
|
+
${this.generatePatternRows()}
|
|
452
|
+
</div>
|
|
453
|
+
</section>
|
|
454
|
+
|
|
455
|
+
<!-- ANIMATIONS -->
|
|
456
|
+
<section class="section" id="animations">
|
|
457
|
+
<h2 class="section-title">Animations</h2>
|
|
458
|
+
<div id="animations-list">
|
|
459
|
+
${this.generateAnimationRows()}
|
|
460
|
+
</div>
|
|
461
|
+
</section>
|
|
462
|
+
|
|
463
|
+
<!-- MODIFIERS -->
|
|
464
|
+
<section class="section" id="modifiers">
|
|
465
|
+
<h2 class="section-title">Animation Modifiers</h2>
|
|
466
|
+
<p style="color:#64748b; margin-bottom:24px; font-size:14px;">
|
|
467
|
+
Stack these onto any animation class to customize behavior.
|
|
468
|
+
</p>
|
|
469
|
+
|
|
470
|
+
<h3 class="section-sub">Duration</h3>
|
|
471
|
+
<div class="card-grid">
|
|
472
|
+
${[100,150,200,300,500,800,1000].map(d => `
|
|
473
|
+
<div class="doc-card">
|
|
474
|
+
<div class="doc-card-name">duration-${d}</div>
|
|
475
|
+
<div class="doc-card-value">${d}ms ā ${d/1000}s</div>
|
|
476
|
+
</div>
|
|
477
|
+
`).join('')}
|
|
478
|
+
${['fast','normal','slow','slower'].map(n => `
|
|
479
|
+
<div class="doc-card">
|
|
480
|
+
<div class="doc-card-name">duration-${n}</div>
|
|
481
|
+
<div class="doc-card-value">Token-based</div>
|
|
482
|
+
</div>
|
|
483
|
+
`).join('')}
|
|
484
|
+
</div>
|
|
485
|
+
|
|
486
|
+
<h3 class="section-sub">Delay</h3>
|
|
487
|
+
<div class="card-grid">
|
|
488
|
+
${[0,100,150,200,300,500,1000].map(d => `
|
|
489
|
+
<div class="doc-card">
|
|
490
|
+
<div class="doc-card-name">delay-${d}</div>
|
|
491
|
+
<div class="doc-card-value">${d}ms ā ${d/1000}s</div>
|
|
492
|
+
</div>
|
|
493
|
+
`).join('')}
|
|
494
|
+
</div>
|
|
495
|
+
|
|
496
|
+
<h3 class="section-sub">Easing</h3>
|
|
497
|
+
<div class="card-grid">
|
|
498
|
+
${['smooth','bouncy','sharp','back','linear'].map(e => `
|
|
499
|
+
<div class="doc-card">
|
|
500
|
+
<div class="doc-card-name">ease-${e}</div>
|
|
501
|
+
<div class="doc-card-value">${this.easeToGSAP(e)}</div>
|
|
502
|
+
</div>
|
|
503
|
+
`).join('')}
|
|
504
|
+
</div>
|
|
505
|
+
|
|
506
|
+
<h3 class="section-sub">Data Attribute Overrides</h3>
|
|
507
|
+
<div class="card-grid">
|
|
508
|
+
${['data-gsap-duration','data-gsap-delay','data-gsap-ease','data-gsap-y','data-gsap-x','data-gsap-scale','data-gsap-opacity'].map(a => `
|
|
509
|
+
<div class="doc-card">
|
|
510
|
+
<div class="doc-card-name">${a}</div>
|
|
511
|
+
<div class="doc-card-value">Highest priority override</div>
|
|
512
|
+
</div>
|
|
513
|
+
`).join('')}
|
|
514
|
+
</div>
|
|
515
|
+
</section>
|
|
516
|
+
|
|
517
|
+
</main>
|
|
518
|
+
|
|
519
|
+
<script>
|
|
520
|
+
// Search functionality
|
|
521
|
+
function handleSearch(query) {
|
|
522
|
+
const q = query.toLowerCase().trim();
|
|
523
|
+
const allRows = document.querySelectorAll(
|
|
524
|
+
'.doc-card, .pattern-row, .anim-row'
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
allRows.forEach(row => {
|
|
528
|
+
const text = row.textContent.toLowerCase();
|
|
529
|
+
row.style.display = !q || text.includes(q) ? '' : 'none';
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Smooth scroll for nav links
|
|
534
|
+
document.querySelectorAll('.nav-link').forEach(link => {
|
|
535
|
+
link.addEventListener('click', e => {
|
|
536
|
+
e.preventDefault();
|
|
537
|
+
const target = document.querySelector(link.getAttribute('href'));
|
|
538
|
+
if (target) target.scrollIntoView({ behavior: 'smooth' });
|
|
539
|
+
});
|
|
540
|
+
});
|
|
541
|
+
</script>
|
|
542
|
+
|
|
543
|
+
</body>
|
|
544
|
+
</html>`;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
generateColorCards() {
|
|
548
|
+
const cards = [];
|
|
549
|
+
if (!this.tokens.colors) return '';
|
|
550
|
+
|
|
551
|
+
for (const [k, v] of Object.entries(this.tokens.colors)) {
|
|
552
|
+
if (typeof v === 'object') {
|
|
553
|
+
for (const [shade, color] of Object.entries(v)) {
|
|
554
|
+
const name = shade === 'DEFAULT' ? k : `${k}-${shade}`;
|
|
555
|
+
cards.push(`
|
|
556
|
+
<div class="doc-card">
|
|
557
|
+
<div class="color-swatch" style="background:${color};"></div>
|
|
558
|
+
<div class="doc-card-name">${name}</div>
|
|
559
|
+
<div class="doc-card-value">${color}</div>
|
|
560
|
+
<div class="doc-card-value" style="margin-top:4px;">
|
|
561
|
+
bg-${name} Ā· color-${name}
|
|
562
|
+
</div>
|
|
563
|
+
</div>
|
|
564
|
+
`);
|
|
565
|
+
}
|
|
566
|
+
} else {
|
|
567
|
+
cards.push(`
|
|
568
|
+
<div class="doc-card">
|
|
569
|
+
<div class="color-swatch" style="background:${v};"></div>
|
|
570
|
+
<div class="doc-card-name">${k}</div>
|
|
571
|
+
<div class="doc-card-value">${v}</div>
|
|
572
|
+
<div class="doc-card-value" style="margin-top:4px;">
|
|
573
|
+
bg-${k} Ā· color-${k}
|
|
574
|
+
</div>
|
|
575
|
+
</div>
|
|
576
|
+
`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return cards.join('');
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
generateSpacingRows() {
|
|
583
|
+
if (!this.tokens.spacing) return '';
|
|
584
|
+
return Object.entries(this.tokens.spacing).map(([k, v]) => {
|
|
585
|
+
const px = parseInt(v);
|
|
586
|
+
return `
|
|
587
|
+
<div class="pattern-row">
|
|
588
|
+
<div class="pattern-name">pad-${k} Ā· mar-${k} Ā· gap-${k}</div>
|
|
589
|
+
<div class="spacing-preview">
|
|
590
|
+
<div class="spacing-bar" style="width:${Math.min(px * 2, 200)}px;"></div>
|
|
591
|
+
<span style="color:#64748b; font-size:13px;">${v}</span>
|
|
592
|
+
</div>
|
|
593
|
+
</div>
|
|
594
|
+
`;
|
|
595
|
+
}).join('');
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
generateTypographyRows() {
|
|
599
|
+
if (!this.tokens.typography) return '';
|
|
600
|
+
return Object.entries(this.tokens.typography).map(([k, v]) => `
|
|
601
|
+
<div class="pattern-row">
|
|
602
|
+
<div class="pattern-name">text-${k}</div>
|
|
603
|
+
<div style="flex:1;">
|
|
604
|
+
<div style="font-size:${v.size}; font-weight:${v.weight}; line-height:${v.line}; color:#e2e8f0; margin-bottom:4px;">
|
|
605
|
+
The quick brown fox
|
|
606
|
+
</div>
|
|
607
|
+
<div style="font-size:12px; color:#64748b;">
|
|
608
|
+
${v.size} Ā· weight ${v.weight} Ā· line ${v.line}
|
|
609
|
+
</div>
|
|
610
|
+
</div>
|
|
611
|
+
</div>
|
|
612
|
+
`).join('');
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
generateRadiusCards() {
|
|
616
|
+
if (!this.tokens.radius) return '';
|
|
617
|
+
return Object.entries(this.tokens.radius).map(([k, v]) => `
|
|
618
|
+
<div class="doc-card" style="text-align:center;">
|
|
619
|
+
<div style="
|
|
620
|
+
width:48px; height:48px;
|
|
621
|
+
background:#38bdf8;
|
|
622
|
+
border-radius:${v};
|
|
623
|
+
margin:0 auto 12px;
|
|
624
|
+
opacity:0.7;
|
|
625
|
+
"></div>
|
|
626
|
+
<div class="doc-card-name">rounded-${k}</div>
|
|
627
|
+
<div class="doc-card-value">${v}</div>
|
|
628
|
+
</div>
|
|
629
|
+
`).join('');
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
generateShadowCards() {
|
|
633
|
+
if (!this.tokens.shadows) return '';
|
|
634
|
+
return Object.entries(this.tokens.shadows).map(([k, v]) => `
|
|
635
|
+
<div class="pattern-row">
|
|
636
|
+
<div class="pattern-name">shadow-${k}</div>
|
|
637
|
+
<div style="
|
|
638
|
+
width:60px; height:32px;
|
|
639
|
+
background:#1e293b;
|
|
640
|
+
border-radius:6px;
|
|
641
|
+
box-shadow:${v};
|
|
642
|
+
flex-shrink:0;
|
|
643
|
+
"></div>
|
|
644
|
+
<div class="doc-card-value" style="font-family:monospace; font-size:12px;">${v}</div>
|
|
645
|
+
</div>
|
|
646
|
+
`).join('');
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
generatePatternRows() {
|
|
650
|
+
return Object.entries(this.patterns).map(([name, value]) => `
|
|
651
|
+
<div class="pattern-row">
|
|
652
|
+
<div class="pattern-name">.${name}</div>
|
|
653
|
+
<div class="pattern-arrow">ā</div>
|
|
654
|
+
<div class="pattern-value">${value}</div>
|
|
655
|
+
<div class="usage-box" style="width:100%;">
|
|
656
|
+
<div class="${name}">...</div>
|
|
657
|
+
</div>
|
|
658
|
+
</div>
|
|
659
|
+
`).join('');
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
generateAnimationRows() {
|
|
663
|
+
return Object.entries(this.animations).map(([name, config]) => {
|
|
664
|
+
const type = this.getAnimType(config);
|
|
665
|
+
return `
|
|
666
|
+
<div class="anim-row">
|
|
667
|
+
<div class="anim-header">
|
|
668
|
+
<div class="anim-name">.${name}</div>
|
|
669
|
+
<span class="anim-type type-${type}">${type}</span>
|
|
670
|
+
</div>
|
|
671
|
+
<div class="anim-config">${JSON.stringify(config, null, 2)}</div>
|
|
672
|
+
<div class="usage-box">
|
|
673
|
+
<div class="${name}">...</div>
|
|
674
|
+
</div>
|
|
675
|
+
</div>
|
|
676
|
+
`;
|
|
677
|
+
}).join('');
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
getAnimType(config) {
|
|
681
|
+
if (config.hover) return 'hover';
|
|
682
|
+
if (config.active) return 'click';
|
|
683
|
+
if (config.targets === 'children') return 'stagger';
|
|
684
|
+
if (config.scrollTrigger) return 'scroll';
|
|
685
|
+
if (config.repeat === -1) return 'loop';
|
|
686
|
+
return 'entrance';
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
easeToGSAP(name) {
|
|
690
|
+
const map = {
|
|
691
|
+
smooth: 'power2.out',
|
|
692
|
+
bouncy: 'elastic.out(1, 0.5)',
|
|
693
|
+
sharp: 'power4.inOut',
|
|
694
|
+
back: 'back.out(1.7)',
|
|
695
|
+
linear: 'none'
|
|
696
|
+
};
|
|
697
|
+
return map[name] || name;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
countTokens() {
|
|
701
|
+
let count = 0;
|
|
702
|
+
for (const [, v] of Object.entries(this.tokens)) {
|
|
703
|
+
if (typeof v === 'object') {
|
|
704
|
+
for (const [, val] of Object.entries(v)) {
|
|
705
|
+
if (typeof val === 'object') count += Object.keys(val).length;
|
|
706
|
+
else count++;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
return count;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// packages/cli/index.js
|
|
3
|
+
|
|
4
|
+
import { watch } from './watcher.js';
|
|
5
|
+
import { DocsGenerator } from './docs-generator.js';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import Mizumi from '../core/index.js';
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
10
|
+
|
|
11
|
+
// Get command from args
|
|
12
|
+
const args = process.argv.slice(2);
|
|
13
|
+
const command = args[0];
|
|
14
|
+
|
|
15
|
+
// CLI commands
|
|
16
|
+
const commands = {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Initialize Mizumi in current project
|
|
20
|
+
* npx mizumi init
|
|
21
|
+
*/
|
|
22
|
+
init() {
|
|
23
|
+
console.log('š Initializing Mizumi...\n');
|
|
24
|
+
|
|
25
|
+
// Default config template
|
|
26
|
+
const configTemplate = `// mizumi.config.js
|
|
27
|
+
export {
|
|
28
|
+
tokens: {
|
|
29
|
+
colors: {
|
|
30
|
+
primary: {
|
|
31
|
+
DEFAULT: '#3B82F6',
|
|
32
|
+
50: '#EFF6FF',
|
|
33
|
+
600: '#2563EB',
|
|
34
|
+
900: '#1E3A8A'
|
|
35
|
+
},
|
|
36
|
+
secondary: '#8B5CF6',
|
|
37
|
+
neutral: {
|
|
38
|
+
50: '#F9FAFB',
|
|
39
|
+
100: '#F3F4F6',
|
|
40
|
+
200: '#E5E7EB',
|
|
41
|
+
500: '#6B7280',
|
|
42
|
+
900: '#111827'
|
|
43
|
+
},
|
|
44
|
+
surface: '#FFFFFF',
|
|
45
|
+
text: '#111827',
|
|
46
|
+
success: '#10B981',
|
|
47
|
+
error: '#EF4444'
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
spacing: {
|
|
51
|
+
xs: '4px',
|
|
52
|
+
sm: '8px',
|
|
53
|
+
md: '16px',
|
|
54
|
+
lg: '24px',
|
|
55
|
+
xl: '32px',
|
|
56
|
+
'2xl': '48px',
|
|
57
|
+
'3xl': '64px'
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
typography: {
|
|
61
|
+
h1: { size: '48px', weight: 700, line: 1.2 },
|
|
62
|
+
h2: { size: '36px', weight: 600, line: 1.3 },
|
|
63
|
+
h3: { size: '24px', weight: 600, line: 1.4 },
|
|
64
|
+
body: { size: '16px', weight: 400, line: 1.6 },
|
|
65
|
+
small: { size: '14px', weight: 400, line: 1.5 }
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
radius: {
|
|
69
|
+
none: '0',
|
|
70
|
+
sm: '4px',
|
|
71
|
+
md: '8px',
|
|
72
|
+
lg: '16px',
|
|
73
|
+
full: '9999px'
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
shadows: {
|
|
77
|
+
none: 'none',
|
|
78
|
+
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
|
79
|
+
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1)',
|
|
80
|
+
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1)',
|
|
81
|
+
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1)'
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
animations: {
|
|
85
|
+
duration: {
|
|
86
|
+
fast: 150,
|
|
87
|
+
normal: 300,
|
|
88
|
+
slow: 500
|
|
89
|
+
},
|
|
90
|
+
easing: {
|
|
91
|
+
smooth: 'power2.out',
|
|
92
|
+
bouncy: 'elastic.out(1, 0.5)',
|
|
93
|
+
sharp: 'power4.inOut'
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
patterns: {
|
|
99
|
+
// Layout
|
|
100
|
+
'flex-center': 'flex items-center justify-center',
|
|
101
|
+
'flex-between': 'flex items-center justify-between',
|
|
102
|
+
'flex-col-center': 'flex flex-col items-center justify-center',
|
|
103
|
+
|
|
104
|
+
// Containers
|
|
105
|
+
container: 'max-w-6xl mx-auto pad-x-md',
|
|
106
|
+
section: 'pad-y-2xl',
|
|
107
|
+
|
|
108
|
+
// Cards
|
|
109
|
+
card: 'bg-surface pad-md rounded-lg shadow-md',
|
|
110
|
+
'card-elevated': 'card shadow-xl',
|
|
111
|
+
'card-flat': 'card shadow-sm',
|
|
112
|
+
'card-hover': 'card transition cursor-pointer',
|
|
113
|
+
|
|
114
|
+
// Buttons
|
|
115
|
+
button: 'pad-sm pad-x-lg rounded-md cursor-pointer transition inline-flex items-center justify-center',
|
|
116
|
+
'btn-primary': 'button bg-primary color-white',
|
|
117
|
+
'btn-secondary': 'button bg-secondary color-white',
|
|
118
|
+
'btn-ghost': 'button bg-transparent color-primary',
|
|
119
|
+
'btn-outline': 'button border border-primary color-primary',
|
|
120
|
+
|
|
121
|
+
// Inputs
|
|
122
|
+
input: 'pad-sm rounded-md border border-neutral-200 transition',
|
|
123
|
+
|
|
124
|
+
// Text
|
|
125
|
+
heading: 'text-h1 color-text',
|
|
126
|
+
subheading: 'text-h3 color-neutral-500',
|
|
127
|
+
'text-muted': 'color-neutral-500'
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
animations: {
|
|
131
|
+
// Entrance
|
|
132
|
+
'animate-fade-in': {
|
|
133
|
+
from: { opacity: 0 },
|
|
134
|
+
to: { opacity: 1 },
|
|
135
|
+
duration: 300,
|
|
136
|
+
ease: 'power2.out'
|
|
137
|
+
},
|
|
138
|
+
'animate-slide-up': {
|
|
139
|
+
from: { y: 100, opacity: 0 },
|
|
140
|
+
to: { y: 0, opacity: 1 },
|
|
141
|
+
duration: 300,
|
|
142
|
+
ease: 'power2.out'
|
|
143
|
+
},
|
|
144
|
+
'animate-scale-in': {
|
|
145
|
+
from: { scale: 0, opacity: 0 },
|
|
146
|
+
to: { scale: 1, opacity: 1 },
|
|
147
|
+
duration: 300,
|
|
148
|
+
ease: 'back.out'
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
// Scroll
|
|
152
|
+
'scroll-trigger': {
|
|
153
|
+
scrollTrigger: {
|
|
154
|
+
trigger: 'self',
|
|
155
|
+
start: 'top 80%',
|
|
156
|
+
toggleActions: 'play none none reverse'
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
// Hover
|
|
161
|
+
'hover-lift': {
|
|
162
|
+
hover: { y: -8, duration: 150 }
|
|
163
|
+
},
|
|
164
|
+
'hover-scale': {
|
|
165
|
+
hover: { scale: 1.05, duration: 150 }
|
|
166
|
+
},
|
|
167
|
+
'hover-glow': {
|
|
168
|
+
hover: {
|
|
169
|
+
boxShadow: '0 0 20px rgba(59, 130, 246, 0.5)',
|
|
170
|
+
duration: 150
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// Click
|
|
175
|
+
'active-press': {
|
|
176
|
+
active: { scale: 0.95, duration: 100 }
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
// Stagger
|
|
180
|
+
'stagger-children-100': {
|
|
181
|
+
targets: 'children',
|
|
182
|
+
stagger: 0.1,
|
|
183
|
+
from: { opacity: 0, y: 20 },
|
|
184
|
+
to: { opacity: 1, y: 0 }
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
rules: {
|
|
189
|
+
darkMode: false,
|
|
190
|
+
responsive: true,
|
|
191
|
+
breakpoints: {
|
|
192
|
+
sm: '640px',
|
|
193
|
+
md: '768px',
|
|
194
|
+
lg: '1024px',
|
|
195
|
+
xl: '1280px'
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
`;
|
|
200
|
+
|
|
201
|
+
// Check if config already exists
|
|
202
|
+
const configPath = path.join(process.cwd(), 'mizumi.config.js');
|
|
203
|
+
|
|
204
|
+
if (fs.existsSync(configPath)) {
|
|
205
|
+
console.log('ā ļø mizumi.config.js already exists, skipping...');
|
|
206
|
+
} else {
|
|
207
|
+
fs.writeFileSync(configPath, configTemplate);
|
|
208
|
+
console.log('ā
Created: mizumi.config.js');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Create .mizumi directory
|
|
212
|
+
const mizumiDir = path.join(process.cwd(), '.mizumi');
|
|
213
|
+
if (!fs.existsSync(mizumiDir)) {
|
|
214
|
+
fs.mkdirSync(mizumiDir);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Create .gitignore entry
|
|
218
|
+
const gitignorePath = path.join(process.cwd(), '.gitignore');
|
|
219
|
+
if (fs.existsSync(gitignorePath)) {
|
|
220
|
+
const gitignore = fs.readFileSync(gitignorePath, 'utf8');
|
|
221
|
+
if (!gitignore.includes('.mizumi')) {
|
|
222
|
+
fs.appendFileSync(gitignorePath, '\n# Mizumi generated files\n.mizumi/\n');
|
|
223
|
+
console.log('ā
Updated: .gitignore');
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
fs.writeFileSync(gitignorePath, '# Mizumi generated files\n.mizumi/\n');
|
|
227
|
+
console.log('ā
Created: .gitignore');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
console.log('\nš Mizumi initialized successfully!');
|
|
231
|
+
console.log('\nNext steps:');
|
|
232
|
+
console.log(' 1. Edit mizumi.config.js to customize your tokens');
|
|
233
|
+
console.log(' 2. Run: node mizumi build');
|
|
234
|
+
console.log(' 3. Import .mizumi/mizumi.css in your project');
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Build CSS from config
|
|
239
|
+
* npx mizumi build
|
|
240
|
+
*/
|
|
241
|
+
build: async function() {
|
|
242
|
+
console.log('š Building Mizumi CSS...\n');
|
|
243
|
+
|
|
244
|
+
// Find config file
|
|
245
|
+
const configPath = path.join(process.cwd(), 'mizumi.config.js');
|
|
246
|
+
if (!fs.existsSync(configPath)) {
|
|
247
|
+
console.error('ā mizumi.config.js not found!');
|
|
248
|
+
console.error(' Run: node mizumi init');
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Load config
|
|
253
|
+
const configModule = await import(pathToFileURL(configPath).href);
|
|
254
|
+
const config = configModule.default || configModule; // ā handles both ESM and CommonJS
|
|
255
|
+
|
|
256
|
+
// Generate CSS + Runtime JS
|
|
257
|
+
const mizumi = new Mizumi(config);
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
const outDir = path.join(process.cwd(), '.mizumi');
|
|
261
|
+
mizumi.build(outDir); // ā now passes directory, not file path
|
|
262
|
+
|
|
263
|
+
console.log('\nš Build complete!');
|
|
264
|
+
console.log(' Add to your HTML:');
|
|
265
|
+
console.log(' <link rel="stylesheet" href=".mizumi/mizumi.css">');
|
|
266
|
+
console.log(' <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>');
|
|
267
|
+
console.log(' <script src=".mizumi/mizumi-runtime.js"></script>');
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* List all patterns
|
|
275
|
+
* npx mizumi list
|
|
276
|
+
*/
|
|
277
|
+
list: async function() {
|
|
278
|
+
const configPath = path.join(process.cwd(), 'mizumi.config.js');
|
|
279
|
+
|
|
280
|
+
if (!fs.existsSync(configPath)) {
|
|
281
|
+
console.error('ā mizumi.config.js not found! Run: node mizumi init');
|
|
282
|
+
process.exit(1);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
const configModule = await import(pathToFileURL(configPath).href);
|
|
287
|
+
const config = configModule.default || configModule; // ā handles both ESM and CommonJS
|
|
288
|
+
|
|
289
|
+
// Generate CSS + Runtime JS
|
|
290
|
+
const mizumi = new Mizumi(config);
|
|
291
|
+
|
|
292
|
+
console.log('\nš Mizumi Patterns:\n');
|
|
293
|
+
|
|
294
|
+
for (const [name, value] of Object.entries(config.patterns || {})) {
|
|
295
|
+
const expanded = mizumi.expandClassName(name);
|
|
296
|
+
console.log(` .${name}`);
|
|
297
|
+
console.log(` ā ${expanded}`);
|
|
298
|
+
console.log('');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
console.log('\nš Mizumi Animations:\n');
|
|
302
|
+
|
|
303
|
+
for (const [name, value] of Object.entries(config.animations || {})) {
|
|
304
|
+
console.log(` .${name}`);
|
|
305
|
+
console.log(` ā GSAP: ${JSON.stringify(value).slice(0, 60)}...`);
|
|
306
|
+
console.log('');
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Explain what a class does
|
|
312
|
+
* npx mizumi explain "card"
|
|
313
|
+
*/
|
|
314
|
+
explain: async function() {
|
|
315
|
+
const className = args[1];
|
|
316
|
+
|
|
317
|
+
if (!className) {
|
|
318
|
+
console.error('ā Please provide a class name');
|
|
319
|
+
console.error(' Usage: node mizumi explain "card"');
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const configPath = path.join(process.cwd(), 'mizumi.config.js');
|
|
324
|
+
|
|
325
|
+
const configModule = await import(pathToFileURL(configPath).href);
|
|
326
|
+
const config = configModule.default || configModule;
|
|
327
|
+
|
|
328
|
+
const mizumi = new Mizumi(config);
|
|
329
|
+
|
|
330
|
+
console.log(`\nš Explaining: "${className}"\n`);
|
|
331
|
+
|
|
332
|
+
const classes = className.split(' ');
|
|
333
|
+
|
|
334
|
+
for (const cls of classes) {
|
|
335
|
+
// Check if it's a pattern
|
|
336
|
+
if (config.patterns?.[cls]) {
|
|
337
|
+
const expanded = mizumi.expandClassName(cls);
|
|
338
|
+
console.log(` Pattern: .${cls}`);
|
|
339
|
+
console.log(` Expands to: ${expanded}`);
|
|
340
|
+
}
|
|
341
|
+
// Check if it's an animation
|
|
342
|
+
else if (config.animations?.[cls]) {
|
|
343
|
+
console.log(` Animation: .${cls}`);
|
|
344
|
+
console.log(` Config: ${JSON.stringify(config.animations[cls], null, 4)}`);
|
|
345
|
+
}
|
|
346
|
+
// Check if it's a utility
|
|
347
|
+
else {
|
|
348
|
+
console.log(` Utility: .${cls}`);
|
|
349
|
+
console.log(` (Built-in utility class)`);
|
|
350
|
+
}
|
|
351
|
+
console.log('');
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
watch() {
|
|
356
|
+
watch();
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Show help
|
|
361
|
+
*/
|
|
362
|
+
help() {
|
|
363
|
+
console.log(`
|
|
364
|
+
š Mizumi CSS Framework v0.1.0
|
|
365
|
+
|
|
366
|
+
Commands:
|
|
367
|
+
init Initialize Mizumi in project
|
|
368
|
+
build Generate CSS + runtime JS
|
|
369
|
+
watch Watch config and auto-rebuild
|
|
370
|
+
docs Generate documentation page
|
|
371
|
+
list List all patterns & animations
|
|
372
|
+
explain <class> Explain what a class does
|
|
373
|
+
help Show help
|
|
374
|
+
|
|
375
|
+
Examples:
|
|
376
|
+
node mizumi init
|
|
377
|
+
node mizumi build
|
|
378
|
+
node mizumi watch
|
|
379
|
+
node mizumi list
|
|
380
|
+
node mizumi explain "card animate-fade-in"
|
|
381
|
+
`);
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
docs: async function() {
|
|
387
|
+
console.log('š Generating Mizumi Docs...\n');
|
|
388
|
+
const cfgPath = path.join(process.cwd(), 'mizumi.config.js');
|
|
389
|
+
if (!fs.existsSync(cfgPath)) {
|
|
390
|
+
console.error('ā mizumi.config.js not found!');
|
|
391
|
+
process.exit(1);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const configModule = await import(pathToFileURL(cfgPath).href);
|
|
395
|
+
const config = configModule.default || configModule;
|
|
396
|
+
|
|
397
|
+
const generator = new DocsGenerator(config);
|
|
398
|
+
const html = generator.generate();
|
|
399
|
+
const outDir = path.join(process.cwd(), '.mizumi');
|
|
400
|
+
const outPath = path.join(outDir, 'docs.html');
|
|
401
|
+
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir);
|
|
402
|
+
fs.writeFileSync(outPath, html);
|
|
403
|
+
console.log(`ā
Docs generated: ${outPath}`);
|
|
404
|
+
console.log('\nš Open in browser:');
|
|
405
|
+
console.log(` .mizumi/docs.html`);
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// Run command
|
|
411
|
+
if (commands[command]) {
|
|
412
|
+
await commands[command](); // top-level await is allowed in ESM
|
|
413
|
+
} else {
|
|
414
|
+
console.error(`ā Unknown command: ${command}`);
|
|
415
|
+
commands.help();
|
|
416
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mizumi25/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for Mizumi CSS framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mizumi": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": ["cli", "mizumi", "css", "design-tokens"],
|
|
11
|
+
"author": "Mizumi Kaito / James Rafty Damasing Libago",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/Mizumi25/MizumiPackage"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"chokidar": "^4.0.3"
|
|
19
|
+
}
|
|
20
|
+
}
|
package/watcher.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// packages/cli/watcher.js
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { DocsGenerator } from './docs-generator.js';
|
|
5
|
+
import Mizumi from '../core/index.js';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
function watch() {
|
|
9
|
+
const configPath = path.join(process.cwd(), 'mizumi.config.js');
|
|
10
|
+
const outDir = path.join(process.cwd(), '.mizumi');
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(configPath)) {
|
|
13
|
+
console.error('ā mizumi.config.js not found! Run: node mizumi init');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
console.log('š Mizumi watching for changes...');
|
|
18
|
+
console.log(` Watching: mizumi.config.js`);
|
|
19
|
+
console.log(' Press Ctrl+C to stop\n');
|
|
20
|
+
|
|
21
|
+
// Run initial build
|
|
22
|
+
runBuild(configPath, outDir);
|
|
23
|
+
|
|
24
|
+
// Watch the config file
|
|
25
|
+
const watcher = chokidar.watch(configPath, {
|
|
26
|
+
persistent: true,
|
|
27
|
+
ignoreInitial: true
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
watcher.on('change', () => {
|
|
31
|
+
console.log('\nš Config changed! Rebuilding...');
|
|
32
|
+
runBuild(configPath, outDir);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
watcher.on('error', err => {
|
|
36
|
+
console.error('ā Watcher error:', err);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function runBuild(configPath, outDir) {
|
|
41
|
+
try {
|
|
42
|
+
// Clear require cache so config changes are picked up
|
|
43
|
+
delete require.cache[require.resolve(configPath)];
|
|
44
|
+
|
|
45
|
+
const config = require(configPath);
|
|
46
|
+
const mizumi = new Mizumi(config);
|
|
47
|
+
mizumi.build(outDir);
|
|
48
|
+
|
|
49
|
+
console.log(`ā° ${new Date().toLocaleTimeString()} ā Ready!\n`);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error('ā Build failed:', err.message);
|
|
52
|
+
console.log(' Fix the error and save again...\n');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { watch };
|