@nons-dev/uikit 0.1.5 → 0.1.6
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/generated/components.json +1 -1
- package/package.json +1 -1
- package/readme.md +46 -5
- package/scripts/cli.mjs +283 -14
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -49,23 +49,44 @@ The `nons.config.yaml` file at your project root is the **single source of truth
|
|
|
49
49
|
|
|
50
50
|
```yaml
|
|
51
51
|
theme:
|
|
52
|
-
preset: nons
|
|
52
|
+
preset: nons
|
|
53
53
|
|
|
54
54
|
brand:
|
|
55
|
-
name: Nons
|
|
55
|
+
name: Nons
|
|
56
56
|
|
|
57
57
|
direction:
|
|
58
|
-
default: rtl
|
|
58
|
+
default: rtl
|
|
59
59
|
|
|
60
60
|
locale:
|
|
61
|
-
default: fa
|
|
62
|
-
supported: [fa, en]
|
|
61
|
+
default: fa
|
|
62
|
+
supported: [fa, en]
|
|
63
63
|
|
|
64
64
|
font:
|
|
65
65
|
fa:
|
|
66
66
|
family: IRANSansX
|
|
67
67
|
en:
|
|
68
68
|
family: Satoshi
|
|
69
|
+
|
|
70
|
+
tokens:
|
|
71
|
+
colors:
|
|
72
|
+
light:
|
|
73
|
+
--color-primary: '#9FE870'
|
|
74
|
+
--color-danger: '#F31260'
|
|
75
|
+
# ... override any CSS custom property
|
|
76
|
+
dark:
|
|
77
|
+
--color-primary: '#9FE870'
|
|
78
|
+
--color-danger: '#f31260'
|
|
79
|
+
spacing:
|
|
80
|
+
--space-4: 16px
|
|
81
|
+
# ... typography, radius, shadows, z-index, opacity, button, alert
|
|
82
|
+
|
|
83
|
+
theme-mappings:
|
|
84
|
+
light:
|
|
85
|
+
--bg-primary: var(--color-ui-window)
|
|
86
|
+
--text-primary: var(--color-text-default)
|
|
87
|
+
dark:
|
|
88
|
+
--bg-primary: var(--color-ui-window)
|
|
89
|
+
--text-primary: var(--color-text-default)
|
|
69
90
|
```
|
|
70
91
|
|
|
71
92
|
Run `npx @nons-dev/uikit generate` to regenerate CSS variables from your config.
|
|
@@ -81,6 +102,26 @@ npx @nons-dev/uikit schema <name> # Show schema JSON for a component
|
|
|
81
102
|
npx @nons-dev/uikit search <query> # Search components by name or description
|
|
82
103
|
```
|
|
83
104
|
|
|
105
|
+
## Customizing Colors & Tokens
|
|
106
|
+
|
|
107
|
+
Edit `nons.config.yaml` in your project root, then regenerate:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx @nons-dev/uikit generate
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This produces `generated/tokens.css` (color schemes + all tokens) and `generated/theme.css` (semantic theme mappings). Import them in your app after the uikit CSS:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import '@nons-dev/uikit/style.css'
|
|
117
|
+
import './generated/tokens.css'
|
|
118
|
+
import './generated/theme.css'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The generated CSS uses `:root` / `[data-theme="dark"]` blocks — your custom values override the defaults with the same specificity.
|
|
122
|
+
|
|
123
|
+
All visual values in the uikit reference CSS custom properties (`var(--color-primary)`), so changing a token in YAML propagates to every component.
|
|
124
|
+
|
|
84
125
|
## Documentation
|
|
85
126
|
|
|
86
127
|
| Resource | Description |
|
package/scripts/cli.mjs
CHANGED
|
@@ -16,7 +16,6 @@ const GREEN = '\x1b[32m'
|
|
|
16
16
|
const CYAN = '\x1b[36m'
|
|
17
17
|
const YELLOW = '\x1b[33m'
|
|
18
18
|
const MAGENTA = '\x1b[35m'
|
|
19
|
-
const WHITE = '\x1b[37m'
|
|
20
19
|
const GRAY = '\x1b[90m'
|
|
21
20
|
const RED = '\x1b[31m'
|
|
22
21
|
const BLUE = '\x1b[34m'
|
|
@@ -41,6 +40,168 @@ font:
|
|
|
41
40
|
family: IRANSansX
|
|
42
41
|
en:
|
|
43
42
|
family: Satoshi
|
|
43
|
+
# Faces loaded automatically from @nons-dev/uikit/dist/font/
|
|
44
|
+
# Uncomment and customize src to use your own font files:
|
|
45
|
+
# faces:
|
|
46
|
+
# - family: Satoshi
|
|
47
|
+
# weight: 400
|
|
48
|
+
# src: fonts/Satoshi-Regular.woff2
|
|
49
|
+
# format: woff2
|
|
50
|
+
# - family: IRANSansX
|
|
51
|
+
# weight: 400
|
|
52
|
+
# src: fonts/IRANSansX-Regular.woff
|
|
53
|
+
# format: woff
|
|
54
|
+
|
|
55
|
+
tokens:
|
|
56
|
+
colors:
|
|
57
|
+
light:
|
|
58
|
+
--color-text-default: '#37352F'
|
|
59
|
+
--color-text-grey: '#787774'
|
|
60
|
+
--color-ui-window: '#FFFFFF'
|
|
61
|
+
--color-ui-sidebar: '#F7F6F3'
|
|
62
|
+
--color-ui-hover: rgba(55, 53, 47, 0.08)
|
|
63
|
+
--color-primary: '#9FE870'
|
|
64
|
+
--color-primary-bg: rgba(159, 232, 112, 0.15)
|
|
65
|
+
--color-primary-dark: '#163300'
|
|
66
|
+
--color-primary-text: var(--color-primary-dark)
|
|
67
|
+
--color-primary-selected-bg: rgba(159, 232, 112, 0.08)
|
|
68
|
+
--color-danger: '#F31260'
|
|
69
|
+
--color-danger-bg: '#FEE7EF'
|
|
70
|
+
--color-success: '#17C964'
|
|
71
|
+
--color-success-bg: '#E8FAF0'
|
|
72
|
+
--color-warning: '#F5A524'
|
|
73
|
+
--color-warning-bg: '#FEFCE8'
|
|
74
|
+
--color-secondary: '#7828C8'
|
|
75
|
+
--color-secondary-bg: '#F2EAFA'
|
|
76
|
+
--color-info: '#006FEE'
|
|
77
|
+
--color-info-bg: '#E7F3F8'
|
|
78
|
+
--color-default: '#11181C'
|
|
79
|
+
--color-default-bg: '#F4F4F5'
|
|
80
|
+
--color-border: '#D5D5D2'
|
|
81
|
+
--color-text-secondary: var(--color-text-grey)
|
|
82
|
+
--color-white: '#FFFFFF'
|
|
83
|
+
dark:
|
|
84
|
+
--color-text-default: '#FFFFFF'
|
|
85
|
+
--color-text-grey: '#979A9B'
|
|
86
|
+
--color-ui-window: '#111111'
|
|
87
|
+
--color-ui-sidebar: '#000000'
|
|
88
|
+
--color-ui-hover: rgba(255, 255, 255, 0.08)
|
|
89
|
+
--color-primary: '#9FE870'
|
|
90
|
+
--color-primary-bg: rgba(159, 232, 112, 0.15)
|
|
91
|
+
--color-primary-dark: '#163300'
|
|
92
|
+
--color-primary-text: var(--color-primary-dark)
|
|
93
|
+
--color-primary-selected-bg: rgba(159, 232, 112, 0.08)
|
|
94
|
+
--color-danger: '#f31260'
|
|
95
|
+
--color-danger-bg: '#310413'
|
|
96
|
+
--color-success: '#17c964'
|
|
97
|
+
--color-success-bg: '#052814'
|
|
98
|
+
--color-warning: '#f5a524'
|
|
99
|
+
--color-warning-bg: '#312107'
|
|
100
|
+
--color-secondary: '#9353d3'
|
|
101
|
+
--color-secondary-bg: '#180828'
|
|
102
|
+
--color-info: '#006fee'
|
|
103
|
+
--color-info-bg: '#001731'
|
|
104
|
+
--color-default: '#006fee'
|
|
105
|
+
--color-default-bg: '#001731'
|
|
106
|
+
--color-border: '#1D1D1D'
|
|
107
|
+
--color-text-secondary: var(--color-text-grey)
|
|
108
|
+
--color-white: '#FFFFFF'
|
|
109
|
+
|
|
110
|
+
spacing:
|
|
111
|
+
--space-0-5: 2px
|
|
112
|
+
--space-1: 4px
|
|
113
|
+
--space-2: 8px
|
|
114
|
+
--space-2-5: 10px
|
|
115
|
+
--space-3: 12px
|
|
116
|
+
--space-4: 16px
|
|
117
|
+
--space-5: 24px
|
|
118
|
+
--space-6: 32px
|
|
119
|
+
--space-8: 48px
|
|
120
|
+
--space-10: 64px
|
|
121
|
+
--space-3-5: 14px
|
|
122
|
+
--space-4-5: 18px
|
|
123
|
+
--border-width: 1px
|
|
124
|
+
--border-width-lg: 2px
|
|
125
|
+
|
|
126
|
+
typography:
|
|
127
|
+
--font-family: "'IRANSansX', 'Satoshi', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif"
|
|
128
|
+
--font-family-mono: "'SF Mono', 'Fira Code', 'Fira Mono', 'Roboto Mono', monospace"
|
|
129
|
+
--font-size-xs: 12px
|
|
130
|
+
--font-size-sm: 12px
|
|
131
|
+
--font-size-md: 14px
|
|
132
|
+
--font-size-lg: 16px
|
|
133
|
+
--font-size-xl: 18px
|
|
134
|
+
--font-size-2xl: 24px
|
|
135
|
+
--font-weight-normal: 400
|
|
136
|
+
--font-weight-medium: 500
|
|
137
|
+
--font-weight-bold: 700
|
|
138
|
+
--line-height-sm: 18px
|
|
139
|
+
--line-height-md: 22px
|
|
140
|
+
--line-height-lg: 30px
|
|
141
|
+
|
|
142
|
+
radius:
|
|
143
|
+
--radius-sm: 4px
|
|
144
|
+
--radius-md: 8px
|
|
145
|
+
--radius-lg: 12px
|
|
146
|
+
--radius-xl: 16px
|
|
147
|
+
--radius-full: 9999px
|
|
148
|
+
|
|
149
|
+
shadows:
|
|
150
|
+
light:
|
|
151
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06)
|
|
152
|
+
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.08)
|
|
153
|
+
--shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.1)
|
|
154
|
+
dark:
|
|
155
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3)
|
|
156
|
+
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.35)
|
|
157
|
+
--shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.4)
|
|
158
|
+
|
|
159
|
+
z-index:
|
|
160
|
+
--z-dropdown: 100
|
|
161
|
+
--z-popover: 90
|
|
162
|
+
--z-tooltip: 150
|
|
163
|
+
--z-modal: 1000
|
|
164
|
+
--z-panel: 200
|
|
165
|
+
|
|
166
|
+
opacity:
|
|
167
|
+
--opacity-disabled: 0.5
|
|
168
|
+
--opacity-secondary: 0.6
|
|
169
|
+
--opacity-placeholder: 0.6
|
|
170
|
+
--opacity-hint: 0.8
|
|
171
|
+
--opacity-hover: 0.8
|
|
172
|
+
|
|
173
|
+
button:
|
|
174
|
+
--btn-border-radius: 8px
|
|
175
|
+
--btn-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05)
|
|
176
|
+
--btn-padding: 10px 16px
|
|
177
|
+
--btn-font-size: 14px
|
|
178
|
+
--btn-font-weight: 500
|
|
179
|
+
--btn-font-family: "'IRANSansX', sans-serif"
|
|
180
|
+
|
|
181
|
+
alert:
|
|
182
|
+
--alert-border-radius: 16px
|
|
183
|
+
--alert-padding: 12px
|
|
184
|
+
--alert-gap: 16px
|
|
185
|
+
|
|
186
|
+
theme-mappings:
|
|
187
|
+
light:
|
|
188
|
+
--bg-primary: var(--color-ui-window)
|
|
189
|
+
--bg-sidebar: var(--color-ui-sidebar)
|
|
190
|
+
--bg-hover: var(--color-ui-hover)
|
|
191
|
+
--bg-card: var(--color-ui-window)
|
|
192
|
+
--text-primary: var(--color-text-default)
|
|
193
|
+
--text-secondary: var(--color-text-secondary)
|
|
194
|
+
--border-primary: var(--color-border)
|
|
195
|
+
--overlay-bg: rgba(0, 0, 0, 0.4)
|
|
196
|
+
dark:
|
|
197
|
+
--bg-primary: var(--color-ui-window)
|
|
198
|
+
--bg-sidebar: var(--color-ui-sidebar)
|
|
199
|
+
--bg-hover: var(--color-ui-hover)
|
|
200
|
+
--bg-card: '#161816'
|
|
201
|
+
--text-primary: var(--color-text-default)
|
|
202
|
+
--text-secondary: var(--color-text-grey)
|
|
203
|
+
--border-primary: var(--color-border)
|
|
204
|
+
--overlay-bg: rgba(0, 0, 0, 0.6)
|
|
44
205
|
`
|
|
45
206
|
|
|
46
207
|
// ── Data ──
|
|
@@ -70,6 +231,111 @@ function searchComponents(data, query) {
|
|
|
70
231
|
)
|
|
71
232
|
}
|
|
72
233
|
|
|
234
|
+
// ── Generate helpers ──
|
|
235
|
+
|
|
236
|
+
function writeTokenBlock(tokens, indent) {
|
|
237
|
+
return Object.entries(tokens || {}).map(([k, v]) => `${indent}${k}: ${v};`).join('\n')
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function generateFontCSS(config) {
|
|
241
|
+
const faces = config.font?.faces
|
|
242
|
+
if (!faces || !faces.length) return ''
|
|
243
|
+
const lines = []
|
|
244
|
+
for (const face of faces) {
|
|
245
|
+
lines.push('@font-face {')
|
|
246
|
+
lines.push(` font-family: '${face.family}';`)
|
|
247
|
+
lines.push(` src: url('./${face.src}') format('${face.format}');`)
|
|
248
|
+
lines.push(` font-weight: ${face.weight};`)
|
|
249
|
+
lines.push(' font-style: normal;')
|
|
250
|
+
lines.push(' font-display: swap;')
|
|
251
|
+
lines.push('}')
|
|
252
|
+
lines.push('')
|
|
253
|
+
}
|
|
254
|
+
return lines.join('\n')
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function generateTokensCSS(config) {
|
|
258
|
+
const lines = []
|
|
259
|
+
const fonts = generateFontCSS(config)
|
|
260
|
+
if (fonts) lines.push(fonts)
|
|
261
|
+
|
|
262
|
+
const t = config.tokens || {}
|
|
263
|
+
|
|
264
|
+
// Light & dark color schemes
|
|
265
|
+
const hasLight = t.colors?.light && Object.keys(t.colors.light).length
|
|
266
|
+
const hasDark = t.colors?.dark && Object.keys(t.colors.dark).length
|
|
267
|
+
|
|
268
|
+
if (hasLight) {
|
|
269
|
+
lines.push(':root {')
|
|
270
|
+
lines.push(' color-scheme: light;')
|
|
271
|
+
lines.push(writeTokenBlock(t.colors.light, ' '))
|
|
272
|
+
lines.push('}')
|
|
273
|
+
lines.push('')
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (hasDark) {
|
|
277
|
+
lines.push('[data-theme="dark"] {')
|
|
278
|
+
lines.push(' color-scheme: dark;')
|
|
279
|
+
lines.push(writeTokenBlock(t.colors.dark, ' '))
|
|
280
|
+
lines.push('}')
|
|
281
|
+
lines.push('')
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Flat token sections (no light/dark split)
|
|
285
|
+
const flatSections = {
|
|
286
|
+
spacing: 'Spacing', typography: 'Typography', radius: 'Border Radius',
|
|
287
|
+
'z-index': 'Z-Index', opacity: 'Opacity', button: 'Button', alert: 'Alert',
|
|
288
|
+
}
|
|
289
|
+
for (const [section, label] of Object.entries(flatSections)) {
|
|
290
|
+
const tokens = t[section]
|
|
291
|
+
if (!tokens || !Object.keys(tokens).length) continue
|
|
292
|
+
lines.push(`/* ${label} */`)
|
|
293
|
+
lines.push(':root {')
|
|
294
|
+
lines.push(writeTokenBlock(tokens, ' '))
|
|
295
|
+
lines.push('}')
|
|
296
|
+
lines.push('')
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Shadows (light + dark)
|
|
300
|
+
const hasShadowLight = t.shadows?.light && Object.keys(t.shadows.light).length
|
|
301
|
+
const hasShadowDark = t.shadows?.dark && Object.keys(t.shadows.dark).length
|
|
302
|
+
if (hasShadowLight) {
|
|
303
|
+
lines.push(':root {')
|
|
304
|
+
lines.push(' color-scheme: light;')
|
|
305
|
+
lines.push(writeTokenBlock(t.shadows.light, ' '))
|
|
306
|
+
lines.push('}')
|
|
307
|
+
lines.push('')
|
|
308
|
+
}
|
|
309
|
+
if (hasShadowDark) {
|
|
310
|
+
lines.push('[data-theme="dark"] {')
|
|
311
|
+
lines.push(' color-scheme: dark;')
|
|
312
|
+
lines.push(writeTokenBlock(t.shadows.dark, ' '))
|
|
313
|
+
lines.push('}')
|
|
314
|
+
lines.push('')
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return lines.join('\n')
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function generateThemeCSS(config) {
|
|
321
|
+
const m = config['theme-mappings']
|
|
322
|
+
if (!m) return ''
|
|
323
|
+
const lines = []
|
|
324
|
+
|
|
325
|
+
lines.push(':root {')
|
|
326
|
+
lines.push(' color-scheme: light;')
|
|
327
|
+
if (m.light) lines.push(writeTokenBlock(m.light, ' '))
|
|
328
|
+
lines.push('}')
|
|
329
|
+
|
|
330
|
+
lines.push('')
|
|
331
|
+
lines.push('[data-theme="dark"] {')
|
|
332
|
+
lines.push(' color-scheme: dark;')
|
|
333
|
+
if (m.dark) lines.push(writeTokenBlock(m.dark, ' '))
|
|
334
|
+
lines.push('}')
|
|
335
|
+
|
|
336
|
+
return lines.join('\n')
|
|
337
|
+
}
|
|
338
|
+
|
|
73
339
|
// ── Commands ──
|
|
74
340
|
|
|
75
341
|
function cmdInit() {
|
|
@@ -93,16 +359,19 @@ function cmdGenerate() {
|
|
|
93
359
|
const generatedDir = path.join(CWD, 'generated')
|
|
94
360
|
if (!fs.existsSync(generatedDir)) fs.mkdirSync(generatedDir, { recursive: true })
|
|
95
361
|
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
const tokens = config.tokens?.[section]
|
|
100
|
-
if (!tokens) continue
|
|
101
|
-
for (const [key, val] of Object.entries(tokens)) lines.push(` ${key}: ${val};`)
|
|
102
|
-
}
|
|
103
|
-
lines.push('}')
|
|
104
|
-
fs.writeFileSync(path.join(generatedDir, 'tokens.css'), lines.join('\n'), 'utf-8')
|
|
362
|
+
// tokens.css
|
|
363
|
+
const tokensCSS = generateTokensCSS(config)
|
|
364
|
+
fs.writeFileSync(path.join(generatedDir, 'tokens.css'), tokensCSS, 'utf-8')
|
|
105
365
|
console.log(`${GREEN}✓${RESET} generated/tokens.css`)
|
|
366
|
+
|
|
367
|
+
// theme.css
|
|
368
|
+
const themeCSS = generateThemeCSS(config)
|
|
369
|
+
if (themeCSS) {
|
|
370
|
+
fs.writeFileSync(path.join(generatedDir, 'theme.css'), themeCSS, 'utf-8')
|
|
371
|
+
console.log(`${GREEN}✓${RESET} generated/theme.css`)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
console.log(`${YELLOW}ℹ${RESET} Import in your app:\n import './generated/tokens.css'\n import './generated/theme.css'`)
|
|
106
375
|
}
|
|
107
376
|
|
|
108
377
|
function cmdList() {
|
|
@@ -225,19 +494,19 @@ function printHelp() {
|
|
|
225
494
|
console.log(`\n${BOLD}${CYAN}Nons UIKit CLI${RESET}\n`)
|
|
226
495
|
console.log(`${BOLD}Commands:${RESET}\n`)
|
|
227
496
|
console.log(` ${GREEN}init${RESET} Create nons.config.yaml in current directory`)
|
|
228
|
-
console.log(` ${GREEN}generate${RESET} Generate
|
|
497
|
+
console.log(` ${GREEN}generate${RESET} Generate tokens.css + theme.css from config`)
|
|
229
498
|
console.log(` ${GREEN}list${RESET} List all components`)
|
|
230
499
|
console.log(` ${GREEN}show${RESET} ${DIM}<name>${RESET} Show full detail for a component`)
|
|
231
500
|
console.log(` ${GREEN}schema${RESET} ${DIM}<name>${RESET} Show schema JSON for a component`)
|
|
232
501
|
console.log(` ${GREEN}search${RESET} ${DIM}<query>${RESET} Search components by name/description`)
|
|
233
502
|
console.log(` ${GREEN}help${RESET} Show this help\n`)
|
|
234
503
|
console.log(`${BOLD}Usage:${RESET}\n`)
|
|
504
|
+
console.log(` ${DIM}npx @nons-dev/uikit init${RESET}`)
|
|
505
|
+
console.log(` ${DIM}npx @nons-dev/uikit generate${RESET}`)
|
|
235
506
|
console.log(` ${DIM}npx @nons-dev/uikit list${RESET}`)
|
|
236
507
|
console.log(` ${DIM}npx @nons-dev/uikit show Button${RESET}`)
|
|
237
508
|
console.log(` ${DIM}npx @nons-dev/uikit schema Input${RESET}`)
|
|
238
|
-
console.log(` ${DIM}npx @nons-dev/uikit search table${RESET}`)
|
|
239
|
-
console.log(` ${DIM}npx @nons-dev/uikit init${RESET}`)
|
|
240
|
-
console.log(` ${DIM}npx @nons-dev/uikit generate${RESET}\n`)
|
|
509
|
+
console.log(` ${DIM}npx @nons-dev/uikit search table${RESET}\n`)
|
|
241
510
|
}
|
|
242
511
|
|
|
243
512
|
// ── Main ──
|