apexcss-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/README.md +284 -0
- package/bin/apexcss.js +23 -0
- package/cli/commands/build.js +376 -0
- package/cli/commands/doctor.js +286 -0
- package/cli/commands/init.js +339 -0
- package/cli/commands/watch.js +150 -0
- package/cli/index.js +129 -0
- package/cli/utils/config-builder.js +1934 -0
- package/cli/utils/config-loader.js +963 -0
- package/cli/utils/framework-detector.js +189 -0
- package/cli/utils/logger.js +121 -0
- package/package.json +72 -0
|
@@ -0,0 +1,1934 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ApexCSS Configuration Builder
|
|
5
|
+
*
|
|
6
|
+
* This script generates SCSS configuration files from JavaScript config.
|
|
7
|
+
* It allows users to customize the framework via a JS config file.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node tools/config-builder.js --config=apex.config.js
|
|
11
|
+
* node tools/config-builder.js --watch
|
|
12
|
+
*
|
|
13
|
+
* Options:
|
|
14
|
+
* --config Path to configuration file (default: src/apex.config.js)
|
|
15
|
+
* --output Output directory (default: src/config)
|
|
16
|
+
* --watch Watch for changes and rebuild automatically
|
|
17
|
+
* --help Show help
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import fs from 'node:fs/promises';
|
|
21
|
+
import path from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
|
|
24
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
25
|
+
|
|
26
|
+
const LOG_PREFIX = '[apex-config-builder]';
|
|
27
|
+
|
|
28
|
+
function logInfo(message) {
|
|
29
|
+
console.log(`${LOG_PREFIX} INFO: ${message}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function logWarn(message) {
|
|
33
|
+
console.warn(`${LOG_PREFIX} WARN: ${message}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function logError(message) {
|
|
37
|
+
console.error(`${LOG_PREFIX} ERROR: ${message}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Complete default configuration with all feature toggles
|
|
41
|
+
const defaultConfig = {
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Feature Toggles - Enable/disable utility categories
|
|
44
|
+
// ============================================================================
|
|
45
|
+
features: {
|
|
46
|
+
// Core Layout Utilities
|
|
47
|
+
display: true,
|
|
48
|
+
flexbox: true,
|
|
49
|
+
grid: true,
|
|
50
|
+
positioning: true,
|
|
51
|
+
visibility: true,
|
|
52
|
+
|
|
53
|
+
// Core Spacing Utilities
|
|
54
|
+
spacing: true,
|
|
55
|
+
sizing: true,
|
|
56
|
+
|
|
57
|
+
// Core Typography Utilities
|
|
58
|
+
typography: true,
|
|
59
|
+
|
|
60
|
+
// Core Visual Utilities
|
|
61
|
+
colors: true,
|
|
62
|
+
backgrounds: true,
|
|
63
|
+
borders: true,
|
|
64
|
+
shadows: true,
|
|
65
|
+
opacity: true,
|
|
66
|
+
overflow: true,
|
|
67
|
+
objectFit: true,
|
|
68
|
+
|
|
69
|
+
// Core Interaction Utilities
|
|
70
|
+
cursor: true,
|
|
71
|
+
transitions: true,
|
|
72
|
+
|
|
73
|
+
// Extended Layout Utilities
|
|
74
|
+
flexExtended: true,
|
|
75
|
+
gridExtended: true,
|
|
76
|
+
float: true,
|
|
77
|
+
containerQueries: true,
|
|
78
|
+
isolation: true,
|
|
79
|
+
placeItems: true,
|
|
80
|
+
justifyItems: true,
|
|
81
|
+
spaceBetween: true,
|
|
82
|
+
columns: true,
|
|
83
|
+
columnsExtended: true,
|
|
84
|
+
|
|
85
|
+
// Extended Typography Utilities
|
|
86
|
+
typographyExtended: true,
|
|
87
|
+
fontExtended: true,
|
|
88
|
+
letterSpacing: true,
|
|
89
|
+
lineHeight: true,
|
|
90
|
+
textAlignLast: true,
|
|
91
|
+
textDecorationExtended: true,
|
|
92
|
+
textJustify: true,
|
|
93
|
+
textIndent: true,
|
|
94
|
+
textShadow: true,
|
|
95
|
+
textEmphasis: true,
|
|
96
|
+
textOrientation: true,
|
|
97
|
+
textUnderline: true,
|
|
98
|
+
hangingPunctuation: true,
|
|
99
|
+
hyphenate: true,
|
|
100
|
+
initialLetter: true,
|
|
101
|
+
tabSize: true,
|
|
102
|
+
wordBreak: true,
|
|
103
|
+
wordWrap: true,
|
|
104
|
+
writingMode: true,
|
|
105
|
+
unicodeBidi: true,
|
|
106
|
+
|
|
107
|
+
// Extended Visual Utilities
|
|
108
|
+
backgroundExtended: true,
|
|
109
|
+
colorModifiers: false,
|
|
110
|
+
blendModes: true,
|
|
111
|
+
masks: true,
|
|
112
|
+
borderRadiusLogical: true,
|
|
113
|
+
ring: true,
|
|
114
|
+
outline: true,
|
|
115
|
+
appearance: true,
|
|
116
|
+
accentColor: true,
|
|
117
|
+
colorScheme: true,
|
|
118
|
+
|
|
119
|
+
// Extended Interaction Utilities
|
|
120
|
+
interaction: true,
|
|
121
|
+
userSelect: true,
|
|
122
|
+
willChange: true,
|
|
123
|
+
all: true,
|
|
124
|
+
caret: true,
|
|
125
|
+
scroll: true,
|
|
126
|
+
overscrollBehavior: true,
|
|
127
|
+
overscrollBehaviorExtended: true,
|
|
128
|
+
overflowExtended: true,
|
|
129
|
+
|
|
130
|
+
// Effects (Animations, Transforms, Filters)
|
|
131
|
+
animations: true,
|
|
132
|
+
transforms: true,
|
|
133
|
+
transforms3d: true,
|
|
134
|
+
filters: true,
|
|
135
|
+
aspectRatio: true,
|
|
136
|
+
imageRendering: true,
|
|
137
|
+
transitionBehavior: true,
|
|
138
|
+
|
|
139
|
+
// Content Utilities (Lists, Tables, Print)
|
|
140
|
+
list: true,
|
|
141
|
+
listStyleExtended: true,
|
|
142
|
+
table: true,
|
|
143
|
+
counter: true,
|
|
144
|
+
caption: true,
|
|
145
|
+
quotes: true,
|
|
146
|
+
orphans: true,
|
|
147
|
+
widows: true,
|
|
148
|
+
pageBreak: true,
|
|
149
|
+
break: true,
|
|
150
|
+
verticalAlign: true,
|
|
151
|
+
|
|
152
|
+
// Advanced/Specialized Utilities
|
|
153
|
+
arbitrary: false,
|
|
154
|
+
logicalProperties: true,
|
|
155
|
+
sizingLogical: true,
|
|
156
|
+
offset: true,
|
|
157
|
+
shapeOutside: true,
|
|
158
|
+
markerExtended: true,
|
|
159
|
+
zoom: true,
|
|
160
|
+
fieldSizing: true,
|
|
161
|
+
svg: true,
|
|
162
|
+
box: true,
|
|
163
|
+
divide: true,
|
|
164
|
+
|
|
165
|
+
// State Variants
|
|
166
|
+
states: true,
|
|
167
|
+
hover: true,
|
|
168
|
+
focus: true,
|
|
169
|
+
active: true,
|
|
170
|
+
disabled: true,
|
|
171
|
+
|
|
172
|
+
// Theme Support
|
|
173
|
+
darkMode: true,
|
|
174
|
+
rtl: true,
|
|
175
|
+
accessibility: true,
|
|
176
|
+
zIndex: true
|
|
177
|
+
},
|
|
178
|
+
|
|
179
|
+
// ============================================================================
|
|
180
|
+
// Breakpoints - Responsive design breakpoints
|
|
181
|
+
// ============================================================================
|
|
182
|
+
breakpoints: {
|
|
183
|
+
sm: '320px',
|
|
184
|
+
md: '768px',
|
|
185
|
+
lg: '1024px',
|
|
186
|
+
xl: '1280px',
|
|
187
|
+
xxl: '2560px',
|
|
188
|
+
xxxl: '3840px'
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
// ============================================================================
|
|
192
|
+
// Spacing Scale - Margin, padding, and gap values
|
|
193
|
+
// ============================================================================
|
|
194
|
+
spacing: {
|
|
195
|
+
0: '0',
|
|
196
|
+
px: '1px',
|
|
197
|
+
0.5: '0.125rem',
|
|
198
|
+
1: '0.25rem',
|
|
199
|
+
1.5: '0.375rem',
|
|
200
|
+
2: '0.5rem',
|
|
201
|
+
2.5: '0.625rem',
|
|
202
|
+
3: '0.75rem',
|
|
203
|
+
3.5: '0.875rem',
|
|
204
|
+
4: '1rem',
|
|
205
|
+
5: '1.25rem',
|
|
206
|
+
6: '1.5rem',
|
|
207
|
+
7: '1.75rem',
|
|
208
|
+
8: '2rem',
|
|
209
|
+
9: '2.25rem',
|
|
210
|
+
10: '2.5rem',
|
|
211
|
+
11: '2.75rem',
|
|
212
|
+
12: '3rem',
|
|
213
|
+
14: '3.5rem',
|
|
214
|
+
16: '4rem',
|
|
215
|
+
20: '5rem',
|
|
216
|
+
24: '6rem',
|
|
217
|
+
28: '7rem',
|
|
218
|
+
32: '8rem',
|
|
219
|
+
36: '9rem',
|
|
220
|
+
40: '10rem',
|
|
221
|
+
44: '11rem',
|
|
222
|
+
48: '12rem',
|
|
223
|
+
52: '13rem',
|
|
224
|
+
56: '14rem',
|
|
225
|
+
60: '15rem',
|
|
226
|
+
64: '16rem',
|
|
227
|
+
72: '18rem',
|
|
228
|
+
80: '20rem',
|
|
229
|
+
96: '24rem'
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
// ============================================================================
|
|
233
|
+
// Fractional Widths - Percentage-based width utilities (w-1/2, w-1/3, etc.)
|
|
234
|
+
// ============================================================================
|
|
235
|
+
fractionalWidths: {
|
|
236
|
+
// Enable/disable specific denominators
|
|
237
|
+
// When enabled, generates utilities like w-1/2, w-1/3, w-2/3, etc.
|
|
238
|
+
halves: true,
|
|
239
|
+
thirds: true,
|
|
240
|
+
quarters: true,
|
|
241
|
+
fifths: true,
|
|
242
|
+
sixths: true,
|
|
243
|
+
twelfths: true
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
// ============================================================================
|
|
247
|
+
// Column Configuration - CSS Multi-Column Layout
|
|
248
|
+
// ============================================================================
|
|
249
|
+
columns: {
|
|
250
|
+
// Column counts to generate utilities for
|
|
251
|
+
counts: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
|
252
|
+
// Column widths
|
|
253
|
+
widths: {
|
|
254
|
+
'xs': '20rem',
|
|
255
|
+
'sm': '24rem',
|
|
256
|
+
'md': '28rem',
|
|
257
|
+
'lg': '32rem',
|
|
258
|
+
'xl': '36rem',
|
|
259
|
+
'2xl': '42rem',
|
|
260
|
+
'3xl': '48rem',
|
|
261
|
+
'4xl': '56rem',
|
|
262
|
+
'5xl': '64rem',
|
|
263
|
+
'6xl': '72rem',
|
|
264
|
+
'7xl': '80rem'
|
|
265
|
+
},
|
|
266
|
+
// Column rule styles
|
|
267
|
+
ruleStyles: {
|
|
268
|
+
'solid': 'solid',
|
|
269
|
+
'dashed': 'dashed',
|
|
270
|
+
'dotted': 'dotted',
|
|
271
|
+
'double': 'double',
|
|
272
|
+
'none': 'none'
|
|
273
|
+
},
|
|
274
|
+
// Column rule widths
|
|
275
|
+
ruleWidths: {
|
|
276
|
+
'0': '0px',
|
|
277
|
+
'default': '1px',
|
|
278
|
+
'2': '2px',
|
|
279
|
+
'4': '4px',
|
|
280
|
+
'8': '8px'
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
// ============================================================================
|
|
285
|
+
// Text Shadow Values
|
|
286
|
+
// ============================================================================
|
|
287
|
+
textShadow: {
|
|
288
|
+
'none': 'none',
|
|
289
|
+
'sm': '0 1px 2px 0 rgb(0 0 0 / 0.05)',
|
|
290
|
+
'default': '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
|
|
291
|
+
'md': '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
|
|
292
|
+
'lg': '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
|
|
293
|
+
'xl': '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
|
|
294
|
+
'2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)',
|
|
295
|
+
'inner': 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)'
|
|
296
|
+
},
|
|
297
|
+
|
|
298
|
+
// ============================================================================
|
|
299
|
+
// Ring Widths - Focus ring widths
|
|
300
|
+
// ============================================================================
|
|
301
|
+
ringWidths: {
|
|
302
|
+
'0': '0px',
|
|
303
|
+
'1': '1px',
|
|
304
|
+
'2': '2px',
|
|
305
|
+
'4': '4px',
|
|
306
|
+
'8': '8px',
|
|
307
|
+
'default': '3px'
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
// ============================================================================
|
|
311
|
+
// Ring Colors - Focus ring colors
|
|
312
|
+
// ============================================================================
|
|
313
|
+
ringColors: {
|
|
314
|
+
"inherit": "inherit",
|
|
315
|
+
"current": "currentcolor",
|
|
316
|
+
"transparent": "transparent",
|
|
317
|
+
"white": "#fff",
|
|
318
|
+
"black": "#000",
|
|
319
|
+
"primary": "var(--color-primary-500)",
|
|
320
|
+
"gray": "var(--color-gray-500)"
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
// ============================================================================
|
|
324
|
+
// Ring Opacity Values
|
|
325
|
+
// ============================================================================
|
|
326
|
+
ringOpacity: {
|
|
327
|
+
"0": "0",
|
|
328
|
+
"5": "0.05",
|
|
329
|
+
"10": "0.1",
|
|
330
|
+
"20": "0.2",
|
|
331
|
+
"25": "0.25",
|
|
332
|
+
"30": "0.3",
|
|
333
|
+
"40": "0.4",
|
|
334
|
+
"50": "0.5",
|
|
335
|
+
"60": "0.6",
|
|
336
|
+
"70": "0.7",
|
|
337
|
+
"75": "0.75",
|
|
338
|
+
"80": "0.8",
|
|
339
|
+
"90": "0.9",
|
|
340
|
+
"95": "0.95",
|
|
341
|
+
"100": "1"
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
// ============================================================================
|
|
345
|
+
// Outline Widths - Focus outline widths
|
|
346
|
+
// ============================================================================
|
|
347
|
+
outlineWidths: {
|
|
348
|
+
"0": "0px",
|
|
349
|
+
"1": "1px",
|
|
350
|
+
"2": "2px",
|
|
351
|
+
"4": "4px",
|
|
352
|
+
"8": "8px",
|
|
353
|
+
"default": "3px"
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
// ============================================================================
|
|
357
|
+
// Outline Offsets
|
|
358
|
+
// ============================================================================
|
|
359
|
+
outlineOffsets: {
|
|
360
|
+
"0": "0px",
|
|
361
|
+
"1": "1px",
|
|
362
|
+
"2": "2px",
|
|
363
|
+
"4": "4px",
|
|
364
|
+
"8": "8px",
|
|
365
|
+
"default": "0px"
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
// ============================================================================
|
|
369
|
+
// Blend Modes - CSS blend modes for mix-blend-mode and background-blend-mode
|
|
370
|
+
// ============================================================================
|
|
371
|
+
blendModes: {
|
|
372
|
+
'normal': 'normal',
|
|
373
|
+
'multiply': 'multiply',
|
|
374
|
+
'screen': 'screen',
|
|
375
|
+
'overlay': 'overlay',
|
|
376
|
+
'darken': 'darken',
|
|
377
|
+
'lighten': 'lighten',
|
|
378
|
+
'color-dodge': 'color-dodge',
|
|
379
|
+
'color-burn': 'color-burn',
|
|
380
|
+
'hard-light': 'hard-light',
|
|
381
|
+
'soft-light': 'soft-light',
|
|
382
|
+
'difference': 'difference',
|
|
383
|
+
'exclusion': 'exclusion',
|
|
384
|
+
'hue': 'hue',
|
|
385
|
+
'saturation': 'saturation',
|
|
386
|
+
'color': 'color',
|
|
387
|
+
'luminosity': 'luminosity'
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
// ============================================================================
|
|
391
|
+
// Colors - OKLCH Color Scales (Perceptually uniform color space)
|
|
392
|
+
// Define base colors with OKLCH values, and full scales will be generated
|
|
393
|
+
// Format: { lightness: 0-100%, chroma: 0-0.4, hue: 0-360 }
|
|
394
|
+
// ============================================================================
|
|
395
|
+
colors: {
|
|
396
|
+
// Primary Blue
|
|
397
|
+
primary: {
|
|
398
|
+
hue: 250,
|
|
399
|
+
chroma: 0.18,
|
|
400
|
+
// Scale will be generated from these lightness values
|
|
401
|
+
lightnessScale: {
|
|
402
|
+
50: 95, 100: 90, 200: 85, 300: 78, 400: 70,
|
|
403
|
+
500: 62, 600: 55, 700: 45, 800: 35, 900: 25, 950: 20
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
// Gray (neutral, low chroma)
|
|
407
|
+
gray: {
|
|
408
|
+
hue: 250,
|
|
409
|
+
chroma: 0.02,
|
|
410
|
+
lightnessScale: {
|
|
411
|
+
50: 96, 100: 90, 200: 85, 300: 78, 400: 70,
|
|
412
|
+
500: 65, 600: 55, 700: 45, 800: 35, 900: 25, 950: 18
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
// Success Green
|
|
416
|
+
success: {
|
|
417
|
+
hue: 145,
|
|
418
|
+
chroma: 0.20,
|
|
419
|
+
lightnessScale: {
|
|
420
|
+
50: 95, 100: 90, 200: 85, 300: 78, 400: 70,
|
|
421
|
+
500: 62, 600: 55, 700: 45, 800: 35, 900: 25, 950: 20
|
|
422
|
+
}
|
|
423
|
+
},
|
|
424
|
+
// Warning Amber
|
|
425
|
+
warning: {
|
|
426
|
+
hue: 80,
|
|
427
|
+
chroma: 0.16,
|
|
428
|
+
lightnessScale: {
|
|
429
|
+
50: 95, 100: 90, 200: 85, 300: 78, 400: 70,
|
|
430
|
+
500: 72, 600: 60, 700: 50, 800: 40, 900: 30, 950: 25
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
// Danger Red
|
|
434
|
+
danger: {
|
|
435
|
+
hue: 25,
|
|
436
|
+
chroma: 0.22,
|
|
437
|
+
lightnessScale: {
|
|
438
|
+
50: 95, 100: 90, 200: 85, 300: 78, 400: 70,
|
|
439
|
+
500: 62, 600: 55, 700: 45, 800: 35, 900: 25, 950: 20
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
// Info Sky
|
|
443
|
+
info: {
|
|
444
|
+
hue: 220,
|
|
445
|
+
chroma: 0.14,
|
|
446
|
+
lightnessScale: {
|
|
447
|
+
50: 95, 100: 90, 200: 85, 300: 78, 400: 70,
|
|
448
|
+
500: 62, 600: 55, 700: 45, 800: 35, 900: 25, 950: 20
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
// Extended palette
|
|
452
|
+
extended: {
|
|
453
|
+
blue: { hue: 250, chroma: 0.18 },
|
|
454
|
+
green: { hue: 145, chroma: 0.20 },
|
|
455
|
+
red: { hue: 25, chroma: 0.22 },
|
|
456
|
+
yellow: { hue: 90, chroma: 0.18 },
|
|
457
|
+
purple: { hue: 300, chroma: 0.22 },
|
|
458
|
+
orange: { hue: 55, chroma: 0.18 },
|
|
459
|
+
teal: { hue: 180, chroma: 0.16 },
|
|
460
|
+
pink: { hue: 340, chroma: 0.18 }
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
|
|
464
|
+
// ============================================================================
|
|
465
|
+
// Color Configuration Maps - For programmatic utility generation
|
|
466
|
+
// These maps drive the generation of color utilities in the framework
|
|
467
|
+
// ============================================================================
|
|
468
|
+
colorConfig: {
|
|
469
|
+
// Color shades used for scale generation
|
|
470
|
+
shades: [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950],
|
|
471
|
+
|
|
472
|
+
// Color families for utility generation
|
|
473
|
+
families: {
|
|
474
|
+
gray: 'gray',
|
|
475
|
+
primary: 'primary',
|
|
476
|
+
success: 'success',
|
|
477
|
+
warning: 'warning',
|
|
478
|
+
danger: 'danger',
|
|
479
|
+
info: 'info',
|
|
480
|
+
blue: 'blue',
|
|
481
|
+
green: 'green',
|
|
482
|
+
red: 'red',
|
|
483
|
+
yellow: 'yellow',
|
|
484
|
+
purple: 'purple',
|
|
485
|
+
orange: 'orange',
|
|
486
|
+
teal: 'teal',
|
|
487
|
+
pink: 'pink'
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
// Background opacity values for color modifiers
|
|
491
|
+
bgOpacityValues: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100],
|
|
492
|
+
|
|
493
|
+
// Gradient color stops
|
|
494
|
+
gradientColors: {
|
|
495
|
+
primary: 'primary',
|
|
496
|
+
secondary: 'secondary',
|
|
497
|
+
success: 'success',
|
|
498
|
+
danger: 'danger',
|
|
499
|
+
warning: 'warning',
|
|
500
|
+
info: 'info',
|
|
501
|
+
light: 'light',
|
|
502
|
+
dark: 'dark',
|
|
503
|
+
white: 'white',
|
|
504
|
+
black: 'black',
|
|
505
|
+
transparent: 'transparent',
|
|
506
|
+
current: 'current'
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
|
|
510
|
+
// ============================================================================
|
|
511
|
+
// Typography - Font families, sizes, weights, spacing
|
|
512
|
+
// ============================================================================
|
|
513
|
+
typography: {
|
|
514
|
+
fontFamily: {
|
|
515
|
+
sans: ['ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'sans-serif'],
|
|
516
|
+
serif: ['ui-serif', 'Georgia', 'Cambria', 'Times New Roman', 'Times', 'serif'],
|
|
517
|
+
mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', 'monospace']
|
|
518
|
+
},
|
|
519
|
+
fontSize: {
|
|
520
|
+
xs: ['0.75rem', { lineHeight: '1rem' }],
|
|
521
|
+
sm: ['0.875rem', { lineHeight: '1.25rem' }],
|
|
522
|
+
base: ['1rem', { lineHeight: '1.5rem' }],
|
|
523
|
+
lg: ['1.125rem', { lineHeight: '1.75rem' }],
|
|
524
|
+
xl: ['1.25rem', { lineHeight: '1.75rem' }],
|
|
525
|
+
'2xl': ['1.5rem', { lineHeight: '2rem' }],
|
|
526
|
+
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
|
|
527
|
+
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
|
|
528
|
+
'5xl': ['3rem', { lineHeight: '1' }],
|
|
529
|
+
'6xl': ['3.75rem', { lineHeight: '1' }],
|
|
530
|
+
'7xl': ['4.5rem', { lineHeight: '1' }],
|
|
531
|
+
'8xl': ['6rem', { lineHeight: '1' }],
|
|
532
|
+
'9xl': ['8rem', { lineHeight: '1' }]
|
|
533
|
+
},
|
|
534
|
+
fontWeight: {
|
|
535
|
+
thin: '100',
|
|
536
|
+
extralight: '200',
|
|
537
|
+
light: '300',
|
|
538
|
+
normal: '400',
|
|
539
|
+
medium: '500',
|
|
540
|
+
semibold: '600',
|
|
541
|
+
bold: '700',
|
|
542
|
+
extrabold: '800',
|
|
543
|
+
black: '900'
|
|
544
|
+
},
|
|
545
|
+
letterSpacing: {
|
|
546
|
+
tighter: '-0.05em',
|
|
547
|
+
tight: '-0.025em',
|
|
548
|
+
normal: '0em',
|
|
549
|
+
wide: '0.025em',
|
|
550
|
+
wider: '0.05em',
|
|
551
|
+
widest: '0.1em'
|
|
552
|
+
},
|
|
553
|
+
lineHeight: {
|
|
554
|
+
none: '1',
|
|
555
|
+
tight: '1.25',
|
|
556
|
+
snug: '1.375',
|
|
557
|
+
normal: '1.5',
|
|
558
|
+
relaxed: '1.625',
|
|
559
|
+
loose: '2'
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
|
|
563
|
+
// ============================================================================
|
|
564
|
+
// Border Radius - Corner roundness values
|
|
565
|
+
// ============================================================================
|
|
566
|
+
borderRadius: {
|
|
567
|
+
none: '0',
|
|
568
|
+
sm: '0.125rem',
|
|
569
|
+
default: '0.25rem',
|
|
570
|
+
md: '0.375rem',
|
|
571
|
+
lg: '0.5rem',
|
|
572
|
+
xl: '0.75rem',
|
|
573
|
+
'2xl': '1rem',
|
|
574
|
+
'3xl': '1.5rem',
|
|
575
|
+
full: '9999px'
|
|
576
|
+
},
|
|
577
|
+
|
|
578
|
+
// ============================================================================
|
|
579
|
+
// Shadows - Box shadow values
|
|
580
|
+
// ============================================================================
|
|
581
|
+
shadows: {
|
|
582
|
+
sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
|
|
583
|
+
default: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
|
|
584
|
+
md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
|
|
585
|
+
lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
|
|
586
|
+
xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)',
|
|
587
|
+
'2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)',
|
|
588
|
+
inner: 'inset 0 2px 4px 0 rgb(0 0 0 / 0.05)',
|
|
589
|
+
none: 'none'
|
|
590
|
+
},
|
|
591
|
+
|
|
592
|
+
// ============================================================================
|
|
593
|
+
// Transitions - Animation timing
|
|
594
|
+
// ============================================================================
|
|
595
|
+
transition: {
|
|
596
|
+
duration: {
|
|
597
|
+
75: '75ms',
|
|
598
|
+
100: '100ms',
|
|
599
|
+
150: '150ms',
|
|
600
|
+
200: '200ms',
|
|
601
|
+
300: '300ms',
|
|
602
|
+
500: '500ms',
|
|
603
|
+
700: '700ms',
|
|
604
|
+
1000: '1000ms'
|
|
605
|
+
},
|
|
606
|
+
timing: {
|
|
607
|
+
linear: 'linear',
|
|
608
|
+
default: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
609
|
+
in: 'cubic-bezier(0.4, 0, 1, 1)',
|
|
610
|
+
out: 'cubic-bezier(0, 0, 0.2, 1)',
|
|
611
|
+
'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)'
|
|
612
|
+
}
|
|
613
|
+
},
|
|
614
|
+
|
|
615
|
+
// ============================================================================
|
|
616
|
+
// Z-Index - Stacking order values
|
|
617
|
+
// ============================================================================
|
|
618
|
+
zIndex: {
|
|
619
|
+
auto: 'auto',
|
|
620
|
+
0: '0',
|
|
621
|
+
10: '10',
|
|
622
|
+
20: '20',
|
|
623
|
+
30: '30',
|
|
624
|
+
40: '40',
|
|
625
|
+
50: '50'
|
|
626
|
+
},
|
|
627
|
+
|
|
628
|
+
// ============================================================================
|
|
629
|
+
// Opacity - Transparency values
|
|
630
|
+
// ============================================================================
|
|
631
|
+
opacity: {
|
|
632
|
+
0: '0',
|
|
633
|
+
5: '0.05',
|
|
634
|
+
10: '0.1',
|
|
635
|
+
20: '0.2',
|
|
636
|
+
25: '0.25',
|
|
637
|
+
30: '0.3',
|
|
638
|
+
40: '0.4',
|
|
639
|
+
50: '0.5',
|
|
640
|
+
60: '0.6',
|
|
641
|
+
70: '0.7',
|
|
642
|
+
75: '0.75',
|
|
643
|
+
80: '0.8',
|
|
644
|
+
90: '0.9',
|
|
645
|
+
95: '0.95',
|
|
646
|
+
100: '1'
|
|
647
|
+
},
|
|
648
|
+
|
|
649
|
+
// ============================================================================
|
|
650
|
+
// Filter Configuration
|
|
651
|
+
// ============================================================================
|
|
652
|
+
filterBlurValues: {
|
|
653
|
+
0: '0',
|
|
654
|
+
default: '8px',
|
|
655
|
+
sm: '4px',
|
|
656
|
+
md: '12px',
|
|
657
|
+
lg: '16px',
|
|
658
|
+
xl: '24px',
|
|
659
|
+
'2xl': '40px',
|
|
660
|
+
'3xl': '64px'
|
|
661
|
+
},
|
|
662
|
+
|
|
663
|
+
filterBrightnessValues: {
|
|
664
|
+
0: '0',
|
|
665
|
+
50: '0.5',
|
|
666
|
+
75: '0.75',
|
|
667
|
+
90: '0.9',
|
|
668
|
+
95: '0.95',
|
|
669
|
+
100: '1',
|
|
670
|
+
105: '1.05',
|
|
671
|
+
110: '1.1',
|
|
672
|
+
125: '1.25',
|
|
673
|
+
150: '1.5',
|
|
674
|
+
200: '2'
|
|
675
|
+
},
|
|
676
|
+
|
|
677
|
+
filterContrastValues: {
|
|
678
|
+
0: '0',
|
|
679
|
+
50: '0.5',
|
|
680
|
+
75: '0.75',
|
|
681
|
+
100: '1',
|
|
682
|
+
125: '1.25',
|
|
683
|
+
150: '1.5',
|
|
684
|
+
200: '2'
|
|
685
|
+
},
|
|
686
|
+
|
|
687
|
+
filterGrayscaleValues: {
|
|
688
|
+
0: '0',
|
|
689
|
+
default: '100%'
|
|
690
|
+
},
|
|
691
|
+
|
|
692
|
+
filterHueRotateValues: {
|
|
693
|
+
0: '0deg',
|
|
694
|
+
15: '15deg',
|
|
695
|
+
30: '30deg',
|
|
696
|
+
60: '60deg',
|
|
697
|
+
90: '90deg',
|
|
698
|
+
180: '180deg'
|
|
699
|
+
},
|
|
700
|
+
|
|
701
|
+
filterInvertValues: {
|
|
702
|
+
0: '0',
|
|
703
|
+
default: '100%'
|
|
704
|
+
},
|
|
705
|
+
|
|
706
|
+
filterSaturateValues: {
|
|
707
|
+
0: '0',
|
|
708
|
+
50: '0.5',
|
|
709
|
+
100: '1',
|
|
710
|
+
150: '1.5',
|
|
711
|
+
200: '2'
|
|
712
|
+
},
|
|
713
|
+
|
|
714
|
+
filterSepiaValues: {
|
|
715
|
+
0: '0',
|
|
716
|
+
default: '100%'
|
|
717
|
+
},
|
|
718
|
+
|
|
719
|
+
// ============================================================================
|
|
720
|
+
// Divide Configuration
|
|
721
|
+
// ============================================================================
|
|
722
|
+
divideWidths: {
|
|
723
|
+
0: '0px',
|
|
724
|
+
1: '1px',
|
|
725
|
+
2: '2px',
|
|
726
|
+
4: '4px',
|
|
727
|
+
8: '8px'
|
|
728
|
+
},
|
|
729
|
+
|
|
730
|
+
divideColors: {
|
|
731
|
+
current: 'currentcolor',
|
|
732
|
+
transparent: 'transparent',
|
|
733
|
+
primary: 'var(--color-primary-500)',
|
|
734
|
+
secondary: 'var(--color-secondary-500)',
|
|
735
|
+
gray: 'var(--color-gray-500)'
|
|
736
|
+
},
|
|
737
|
+
|
|
738
|
+
divideStyles: {
|
|
739
|
+
solid: 'solid',
|
|
740
|
+
dashed: 'dashed',
|
|
741
|
+
dotted: 'dotted',
|
|
742
|
+
double: 'double',
|
|
743
|
+
none: 'none'
|
|
744
|
+
},
|
|
745
|
+
|
|
746
|
+
dropShadowValues: {
|
|
747
|
+
none: '0 0 #0000',
|
|
748
|
+
default: '0 1px 2px 0 rgb(0 0 0 / 0.1)',
|
|
749
|
+
sm: '0 1px 1px 0 rgb(0 0 0 / 0.05)',
|
|
750
|
+
md: '0 4px 6px -1px rgb(0 0 0 / 0.1)',
|
|
751
|
+
lg: '0 10px 15px -3px rgb(0 0 0 / 0.1)',
|
|
752
|
+
xl: '0 20px 25px -5px rgb(0 0 0 / 0.1)',
|
|
753
|
+
'2xl': '0 25px 50px -12px rgb(0 0 0 / 0.25)'
|
|
754
|
+
},
|
|
755
|
+
|
|
756
|
+
backdropOpacityValues: {
|
|
757
|
+
0: '0',
|
|
758
|
+
25: '0.25',
|
|
759
|
+
50: '0.5',
|
|
760
|
+
75: '0.75',
|
|
761
|
+
100: '1'
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Generate SCSS configuration from user config
|
|
767
|
+
*/
|
|
768
|
+
/**
|
|
769
|
+
* Generate SCSS configuration from user config
|
|
770
|
+
* @param {object} config - User configuration
|
|
771
|
+
* @returns {string} - Generated SCSS content
|
|
772
|
+
*/
|
|
773
|
+
function generateSCSS(config) {
|
|
774
|
+
const merged = mergeDeep(defaultConfig, config);
|
|
775
|
+
|
|
776
|
+
const sections = [
|
|
777
|
+
generateHeader(),
|
|
778
|
+
generateFeatureToggles(merged.features),
|
|
779
|
+
generateBreakpoints(merged.breakpoints),
|
|
780
|
+
generateSpacing(merged.spacing),
|
|
781
|
+
generateFractionalWidths(merged.fractionalWidths),
|
|
782
|
+
generateColumns(merged.columns),
|
|
783
|
+
generateTextShadow(merged.textShadow),
|
|
784
|
+
generateBlendModes(merged.blendModes),
|
|
785
|
+
generateFilterConfig(merged),
|
|
786
|
+
generateRingWidths(merged.ringWidths),
|
|
787
|
+
generateRingColors(merged.ringColors),
|
|
788
|
+
generateRingOpacity(merged.ringOpacity),
|
|
789
|
+
generateOutlineWidths(merged.outlineWidths),
|
|
790
|
+
generateOutlineOffsets(merged.outlineOffsets),
|
|
791
|
+
generateColors(merged.colors),
|
|
792
|
+
generateColorConfig(merged.colorConfig),
|
|
793
|
+
generateTypography(merged.typography),
|
|
794
|
+
generateBorderRadius(merged.borderRadius),
|
|
795
|
+
generateShadows(merged.shadows),
|
|
796
|
+
generateTransitions(merged.transition),
|
|
797
|
+
generateZIndex(merged.zIndex),
|
|
798
|
+
generateOpacity(merged.opacity),
|
|
799
|
+
generateDivideConfig(merged),
|
|
800
|
+
generateFooter()
|
|
801
|
+
];
|
|
802
|
+
|
|
803
|
+
return sections.join('\n\n');
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Generate file header
|
|
808
|
+
* @returns {string} - Header content
|
|
809
|
+
*/
|
|
810
|
+
function generateHeader() {
|
|
811
|
+
return `// ============================================================================
|
|
812
|
+
// ApexCSS Configuration - Auto-generated by config-builder.js
|
|
813
|
+
// ============================================================================
|
|
814
|
+
// This file is automatically generated. Do not edit directly.
|
|
815
|
+
// Instead, modify your apex.config.js and run: npm run config:build
|
|
816
|
+
// ============================================================================`;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Generate file footer
|
|
821
|
+
* @returns {string} - Footer content
|
|
822
|
+
*/
|
|
823
|
+
function generateFooter() {
|
|
824
|
+
return `// ============================================================================
|
|
825
|
+
// End of ApexCSS Configuration
|
|
826
|
+
// ============================================================================`;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Generate feature toggle variables with categorization
|
|
831
|
+
*/
|
|
832
|
+
function generateFeatureToggles(features) {
|
|
833
|
+
const categories = {
|
|
834
|
+
'Core Layout': ['display', 'flexbox', 'grid', 'positioning', 'visibility'],
|
|
835
|
+
'Core Spacing': ['spacing', 'sizing'],
|
|
836
|
+
'Core Typography': ['typography'],
|
|
837
|
+
'Core Visual': ['colors', 'backgrounds', 'borders', 'shadows', 'opacity', 'overflow', 'objectFit'],
|
|
838
|
+
'Core Interaction': ['cursor', 'transitions'],
|
|
839
|
+
'Extended Layout': ['flexExtended', 'gridExtended', 'float', 'containerQueries', 'isolation', 'placeItems', 'justifyItems', 'spaceBetween', 'columns', 'columnsExtended'],
|
|
840
|
+
'Extended Typography': ['typographyExtended', 'fontExtended', 'letterSpacing', 'lineHeight', 'textAlignLast', 'textDecorationExtended', 'textJustify', 'textIndent', 'textShadow', 'textEmphasis', 'textOrientation', 'textUnderline', 'hangingPunctuation', 'hyphenate', 'initialLetter', 'tabSize', 'wordBreak', 'wordWrap', 'writingMode', 'unicodeBidi'],
|
|
841
|
+
'Extended Visual': ['backgroundExtended', 'colorModifiers', 'blendModes', 'masks', 'borderRadiusLogical', 'ring', 'outline', 'appearance', 'accentColor', 'colorScheme'],
|
|
842
|
+
'Extended Interaction': ['interaction', 'userSelect', 'willChange', 'all', 'caret', 'scroll', 'overscrollBehavior', 'overscrollBehaviorExtended', 'overflowExtended'],
|
|
843
|
+
'Effects': ['animations', 'transforms', 'transforms3d', 'filters', 'aspectRatio', 'imageRendering', 'transitionBehavior'],
|
|
844
|
+
'Content': ['list', 'listStyleExtended', 'table', 'counter', 'caption', 'quotes', 'orphans', 'widows', 'pageBreak', 'break', 'verticalAlign'],
|
|
845
|
+
'Advanced': ['arbitrary', 'logicalProperties', 'sizingLogical', 'offset', 'shapeOutside', 'markerExtended', 'zoom', 'fieldSizing', 'svg', 'box', 'divide'],
|
|
846
|
+
'State Variants': ['states', 'hover', 'focus', 'active', 'disabled'],
|
|
847
|
+
'Theme Support': ['darkMode', 'rtl', 'accessibility', 'zIndex']
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
let output = [];
|
|
851
|
+
|
|
852
|
+
for (const [category, keys] of Object.entries(categories)) {
|
|
853
|
+
output.push(`// ${category}`);
|
|
854
|
+
keys.forEach(key => {
|
|
855
|
+
if (key in features) {
|
|
856
|
+
const varName = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
857
|
+
const comment = features[key] ? 'enabled' : 'disabled';
|
|
858
|
+
output.push(`$enable-${varName}: ${features[key]} !default; // ${comment}`);
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
output.push('');
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
return output.join('\n');
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Generate breakpoint variables and CSS custom properties
|
|
869
|
+
*/
|
|
870
|
+
function generateBreakpoints(breakpoints) {
|
|
871
|
+
const lines = [];
|
|
872
|
+
|
|
873
|
+
// Individual SCSS variables
|
|
874
|
+
lines.push('// Individual breakpoint variables');
|
|
875
|
+
Object.entries(breakpoints).forEach(([key, value]) => {
|
|
876
|
+
lines.push(`$breakpoint-${key}: ${value} !default;`);
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
// SCSS map for iteration
|
|
880
|
+
lines.push('');
|
|
881
|
+
lines.push('// Breakpoints map for SCSS iteration');
|
|
882
|
+
lines.push('$breakpoints: (');
|
|
883
|
+
Object.entries(breakpoints).forEach(([key, value], index, arr) => {
|
|
884
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
885
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
886
|
+
});
|
|
887
|
+
lines.push(') !default;');
|
|
888
|
+
|
|
889
|
+
// Breakpoint class name prefixes (for responsive utility class naming)
|
|
890
|
+
lines.push('');
|
|
891
|
+
lines.push('// Breakpoint prefixes for responsive class names');
|
|
892
|
+
lines.push('$breakpoint-prefixes: (');
|
|
893
|
+
Object.entries(breakpoints).forEach(([key, value], index, arr) => {
|
|
894
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
895
|
+
// For 'xxl', use 'xxl' directly. For others, use the key as-is
|
|
896
|
+
const prefix = key === 'xxl' ? 'xxl' : key;
|
|
897
|
+
lines.push(` "${key}": ${prefix}${comma}`);
|
|
898
|
+
});
|
|
899
|
+
lines.push(') !default;');
|
|
900
|
+
|
|
901
|
+
// Alias for backwards compatibility with code that uses $breakpoint-class-names
|
|
902
|
+
lines.push('');
|
|
903
|
+
lines.push('// Alias for backwards compatibility');
|
|
904
|
+
lines.push('$breakpoint-class-names: $breakpoint-prefixes !default;');
|
|
905
|
+
|
|
906
|
+
return lines.join('\n');
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* Generate spacing scale
|
|
911
|
+
*/
|
|
912
|
+
function generateSpacing(spacing) {
|
|
913
|
+
const lines = [];
|
|
914
|
+
|
|
915
|
+
lines.push('$spacing-scale: (');
|
|
916
|
+
Object.entries(spacing).forEach(([key, value], index, arr) => {
|
|
917
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
918
|
+
// Keep numeric keys unquoted for proper numeric comparisons in Sass
|
|
919
|
+
lines.push(` ${key}: ${value}${comma}`);
|
|
920
|
+
});
|
|
921
|
+
lines.push(') !default;');
|
|
922
|
+
|
|
923
|
+
return lines.join('\n');
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* Generate fractional widths configuration
|
|
928
|
+
* Outputs a Sass map with enabled fractional width values
|
|
929
|
+
*/
|
|
930
|
+
function generateFractionalWidths(config) {
|
|
931
|
+
const widths = [];
|
|
932
|
+
|
|
933
|
+
if (config.halves) {
|
|
934
|
+
widths.push(' "1\\\\/2": 50%');
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
if (config.thirds) {
|
|
938
|
+
widths.push(' "1\\\\/3": 33.3333%');
|
|
939
|
+
widths.push(' "2\\\\/3": 66.6667%');
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (config.quarters) {
|
|
943
|
+
widths.push(' "1\\\\/4": 25%');
|
|
944
|
+
widths.push(' "2\\\\/4": 50%');
|
|
945
|
+
widths.push(' "3\\\\/4": 75%');
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
if (config.fifths) {
|
|
949
|
+
widths.push(' "1\\\\/5": 20%');
|
|
950
|
+
widths.push(' "2\\\\/5": 40%');
|
|
951
|
+
widths.push(' "3\\\\/5": 60%');
|
|
952
|
+
widths.push(' "4\\\\/5": 80%');
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (config.sixths) {
|
|
956
|
+
widths.push(' "1\\\\/6": 16.6667%');
|
|
957
|
+
widths.push(' "2\\\\/6": 33.3333%');
|
|
958
|
+
widths.push(' "3\\\\/6": 50%');
|
|
959
|
+
widths.push(' "4\\\\/6": 66.6667%');
|
|
960
|
+
widths.push(' "5\\\\/6": 83.3333%');
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
if (config.twelfths) {
|
|
964
|
+
widths.push(' "1\\\\/12": 8.3333%');
|
|
965
|
+
widths.push(' "2\\\\/12": 16.6667%');
|
|
966
|
+
widths.push(' "3\\\\/12": 25%');
|
|
967
|
+
widths.push(' "4\\\\/12": 33.3333%');
|
|
968
|
+
widths.push(' "5\\\\/12": 41.6667%');
|
|
969
|
+
widths.push(' "6\\\\/12": 50%');
|
|
970
|
+
widths.push(' "7\\\\/12": 58.3333%');
|
|
971
|
+
widths.push(' "8\\\\/12": 66.6667%');
|
|
972
|
+
widths.push(' "9\\\\/12": 75%');
|
|
973
|
+
widths.push(' "10\\\\/12": 83.3333%');
|
|
974
|
+
widths.push(' "11\\\\/12": 91.6667%');
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
const lines = ['$fractional-widths: ('];
|
|
978
|
+
widths.forEach((line, index) => {
|
|
979
|
+
const comma = index < widths.length - 1 ? ',' : '';
|
|
980
|
+
lines.push(line + comma);
|
|
981
|
+
});
|
|
982
|
+
lines.push(') !default;');
|
|
983
|
+
|
|
984
|
+
return lines.join('\n');
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Generate column configuration
|
|
989
|
+
*/
|
|
990
|
+
function generateColumns(columns) {
|
|
991
|
+
const lines = [];
|
|
992
|
+
|
|
993
|
+
// Column counts
|
|
994
|
+
lines.push('$column-counts: (');
|
|
995
|
+
columns.counts.forEach((count, index) => {
|
|
996
|
+
const comma = index < columns.counts.length - 1 ? ',' : '';
|
|
997
|
+
lines.push(` ${count}${comma}`);
|
|
998
|
+
});
|
|
999
|
+
lines.push(') !default;');
|
|
1000
|
+
|
|
1001
|
+
// Column widths
|
|
1002
|
+
lines.push('$column-widths: (');
|
|
1003
|
+
Object.entries(columns.widths).forEach(([key, value], index, arr) => {
|
|
1004
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1005
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1006
|
+
});
|
|
1007
|
+
lines.push(') !default;');
|
|
1008
|
+
|
|
1009
|
+
// Column rule styles
|
|
1010
|
+
lines.push('$column-rule-styles: (');
|
|
1011
|
+
Object.entries(columns.ruleStyles).forEach(([key, value], index, arr) => {
|
|
1012
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1013
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1014
|
+
});
|
|
1015
|
+
lines.push(') !default;');
|
|
1016
|
+
|
|
1017
|
+
// Column rule widths
|
|
1018
|
+
lines.push('$column-rule-widths: (');
|
|
1019
|
+
Object.entries(columns.ruleWidths).forEach(([key, value], index, arr) => {
|
|
1020
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1021
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1022
|
+
});
|
|
1023
|
+
lines.push(') !default;');
|
|
1024
|
+
|
|
1025
|
+
return lines.join('\n');
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* Generate text shadow values
|
|
1030
|
+
*/
|
|
1031
|
+
function generateTextShadow(textShadow) {
|
|
1032
|
+
const lines = ['$text-shadow-values: ('];
|
|
1033
|
+
Object.entries(textShadow).forEach(([key, value], index, arr) => {
|
|
1034
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1035
|
+
// Quote the value to prevent Sass from parsing rgb() / as division
|
|
1036
|
+
lines.push(` "${key}": "${value}"${comma}`);
|
|
1037
|
+
});
|
|
1038
|
+
lines.push(') !default;');
|
|
1039
|
+
return lines.join('\n');
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Generate ring widths configuration
|
|
1044
|
+
*/
|
|
1045
|
+
function generateRingWidths(ringWidths) {
|
|
1046
|
+
const lines = ['$ring-widths: ('];
|
|
1047
|
+
Object.entries(ringWidths).forEach(([key, value], index, arr) => {
|
|
1048
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1049
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1050
|
+
});
|
|
1051
|
+
lines.push(') !default;');
|
|
1052
|
+
return lines.join('\n');
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Generate ring colors configuration
|
|
1057
|
+
*/
|
|
1058
|
+
function generateRingColors(ringColors) {
|
|
1059
|
+
const lines = ["$ring-colors: ("];
|
|
1060
|
+
Object.entries(ringColors).forEach(([key, value], index, arr) => {
|
|
1061
|
+
const comma = index < arr.length - 1 ? "," : "";
|
|
1062
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1063
|
+
});
|
|
1064
|
+
lines.push(") !default;");
|
|
1065
|
+
return lines.join("\n");
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* Generate ring opacity configuration
|
|
1070
|
+
*/
|
|
1071
|
+
function generateRingOpacity(ringOpacity) {
|
|
1072
|
+
const lines = ["$ring-opacity-values: ("];
|
|
1073
|
+
Object.entries(ringOpacity).forEach(([key, value], index, arr) => {
|
|
1074
|
+
const comma = index < arr.length - 1 ? "," : "";
|
|
1075
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1076
|
+
});
|
|
1077
|
+
lines.push(") !default;");
|
|
1078
|
+
return lines.join("\n");
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* Generate outline widths configuration
|
|
1083
|
+
*/
|
|
1084
|
+
function generateOutlineWidths(outlineWidths) {
|
|
1085
|
+
const lines = ["$outline-widths: ("];
|
|
1086
|
+
Object.entries(outlineWidths).forEach(([key, value], index, arr) => {
|
|
1087
|
+
const comma = index < arr.length - 1 ? "," : "";
|
|
1088
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1089
|
+
});
|
|
1090
|
+
lines.push(") !default;");
|
|
1091
|
+
return lines.join("\n");
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/**
|
|
1095
|
+
* Generate outline offsets configuration
|
|
1096
|
+
*/
|
|
1097
|
+
function generateOutlineOffsets(outlineOffsets) {
|
|
1098
|
+
const lines = ["$outline-offsets: ("];
|
|
1099
|
+
Object.entries(outlineOffsets).forEach(([key, value], index, arr) => {
|
|
1100
|
+
const comma = index < arr.length - 1 ? "," : "";
|
|
1101
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1102
|
+
});
|
|
1103
|
+
lines.push(") !default;");
|
|
1104
|
+
return lines.join("\n");
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* Generate blend modes configuration
|
|
1109
|
+
*/
|
|
1110
|
+
function generateBlendModes(blendModes) {
|
|
1111
|
+
const lines = ['$blend-modes: ('];
|
|
1112
|
+
Object.entries(blendModes).forEach(([key, value], index, arr) => {
|
|
1113
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1114
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1115
|
+
});
|
|
1116
|
+
lines.push(') !default;');
|
|
1117
|
+
return lines.join('\n');
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
/**
|
|
1121
|
+
* Generate divide configuration
|
|
1122
|
+
*/
|
|
1123
|
+
function generateDivideConfig(config) {
|
|
1124
|
+
const lines = [];
|
|
1125
|
+
|
|
1126
|
+
// Divide widths
|
|
1127
|
+
lines.push('$divide-widths: (');
|
|
1128
|
+
Object.entries(config.divideWidths).forEach(([key, value], index, arr) => {
|
|
1129
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1130
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1131
|
+
});
|
|
1132
|
+
lines.push(') !default;');
|
|
1133
|
+
|
|
1134
|
+
// Divide colors
|
|
1135
|
+
lines.push('$divide-colors: (');
|
|
1136
|
+
Object.entries(config.divideColors).forEach(([key, value], index, arr) => {
|
|
1137
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1138
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1139
|
+
});
|
|
1140
|
+
lines.push(') !default;');
|
|
1141
|
+
|
|
1142
|
+
// Divide styles
|
|
1143
|
+
lines.push('$divide-styles: (');
|
|
1144
|
+
Object.entries(config.divideStyles).forEach(([key, value], index, arr) => {
|
|
1145
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1146
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1147
|
+
});
|
|
1148
|
+
lines.push(') !default;');
|
|
1149
|
+
|
|
1150
|
+
return lines.join('\n');
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
/**
|
|
1154
|
+
* Generate filter configuration
|
|
1155
|
+
*/
|
|
1156
|
+
function generateFilterConfig(config) {
|
|
1157
|
+
const lines = [];
|
|
1158
|
+
|
|
1159
|
+
// Filter blur values
|
|
1160
|
+
lines.push('$filter-blur-values: (');
|
|
1161
|
+
Object.entries(config.filterBlurValues).forEach(([key, value], index, arr) => {
|
|
1162
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1163
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1164
|
+
});
|
|
1165
|
+
lines.push(') !default;');
|
|
1166
|
+
|
|
1167
|
+
// Filter brightness values
|
|
1168
|
+
lines.push('$filter-brightness-values: (');
|
|
1169
|
+
Object.entries(config.filterBrightnessValues).forEach(([key, value], index, arr) => {
|
|
1170
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1171
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1172
|
+
});
|
|
1173
|
+
lines.push(') !default;');
|
|
1174
|
+
|
|
1175
|
+
// Filter contrast values
|
|
1176
|
+
lines.push('$filter-contrast-values: (');
|
|
1177
|
+
Object.entries(config.filterContrastValues).forEach(([key, value], index, arr) => {
|
|
1178
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1179
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1180
|
+
});
|
|
1181
|
+
lines.push(') !default;');
|
|
1182
|
+
|
|
1183
|
+
// Filter grayscale values
|
|
1184
|
+
lines.push('$filter-grayscale-values: (');
|
|
1185
|
+
Object.entries(config.filterGrayscaleValues).forEach(([key, value], index, arr) => {
|
|
1186
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1187
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1188
|
+
});
|
|
1189
|
+
lines.push(') !default;');
|
|
1190
|
+
|
|
1191
|
+
// Filter hue-rotate values
|
|
1192
|
+
lines.push('$filter-hue-rotate-values: (');
|
|
1193
|
+
Object.entries(config.filterHueRotateValues).forEach(([key, value], index, arr) => {
|
|
1194
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1195
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1196
|
+
});
|
|
1197
|
+
lines.push(') !default;');
|
|
1198
|
+
|
|
1199
|
+
// Filter invert values
|
|
1200
|
+
lines.push('$filter-invert-values: (');
|
|
1201
|
+
Object.entries(config.filterInvertValues).forEach(([key, value], index, arr) => {
|
|
1202
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1203
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1204
|
+
});
|
|
1205
|
+
lines.push(') !default;');
|
|
1206
|
+
|
|
1207
|
+
// Filter saturate values
|
|
1208
|
+
lines.push('$filter-saturate-values: (');
|
|
1209
|
+
Object.entries(config.filterSaturateValues).forEach(([key, value], index, arr) => {
|
|
1210
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1211
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1212
|
+
});
|
|
1213
|
+
lines.push(') !default;');
|
|
1214
|
+
|
|
1215
|
+
// Filter sepia values
|
|
1216
|
+
lines.push('$filter-sepia-values: (');
|
|
1217
|
+
Object.entries(config.filterSepiaValues).forEach(([key, value], index, arr) => {
|
|
1218
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1219
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1220
|
+
});
|
|
1221
|
+
lines.push(') !default;');
|
|
1222
|
+
|
|
1223
|
+
// Drop shadow values
|
|
1224
|
+
lines.push('$drop-shadow-values: (');
|
|
1225
|
+
Object.entries(config.dropShadowValues).forEach(([key, value], index, arr) => {
|
|
1226
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1227
|
+
lines.push(` "${key}": "${value}"${comma}`);
|
|
1228
|
+
});
|
|
1229
|
+
lines.push(') !default;');
|
|
1230
|
+
|
|
1231
|
+
// Backdrop opacity values
|
|
1232
|
+
lines.push('$backdrop-opacity-values: (');
|
|
1233
|
+
Object.entries(config.backdropOpacityValues).forEach(([key, value], index, arr) => {
|
|
1234
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1235
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1236
|
+
});
|
|
1237
|
+
lines.push(') !default;');
|
|
1238
|
+
|
|
1239
|
+
return lines.join('\n');
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
/**
|
|
1243
|
+
* Generate OKLCH color variables from configuration
|
|
1244
|
+
* Colors are now defined with OKLCH format: { hue, chroma, lightnessScale }
|
|
1245
|
+
*/
|
|
1246
|
+
function generateColors(colors) {
|
|
1247
|
+
const lines = [];
|
|
1248
|
+
const shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
|
|
1249
|
+
const defaultLightnessScale = {
|
|
1250
|
+
50: 95, 100: 90, 200: 85, 300: 78, 400: 70,
|
|
1251
|
+
500: 62, 600: 55, 700: 45, 800: 35, 900: 25, 950: 20
|
|
1252
|
+
};
|
|
1253
|
+
|
|
1254
|
+
// Primary colors
|
|
1255
|
+
if (colors.primary) {
|
|
1256
|
+
lines.push('// Primary Color Scale (OKLCH)');
|
|
1257
|
+
const { hue, chroma, lightnessScale } = colors.primary;
|
|
1258
|
+
shades.forEach(shade => {
|
|
1259
|
+
const lightness = lightnessScale[shade];
|
|
1260
|
+
lines.push(`$color-primary-${shade}: oklch(${lightness}% ${chroma} ${hue}deg) !default;`);
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// Gray scale
|
|
1265
|
+
if (colors.gray) {
|
|
1266
|
+
lines.push('');
|
|
1267
|
+
lines.push('// Gray Scale (OKLCH)');
|
|
1268
|
+
const { hue, chroma, lightnessScale } = colors.gray;
|
|
1269
|
+
shades.forEach(shade => {
|
|
1270
|
+
const lightness = lightnessScale[shade];
|
|
1271
|
+
lines.push(`$color-gray-${shade}: oklch(${lightness}% ${chroma} ${hue}deg) !default;`);
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
// Semantic colors
|
|
1276
|
+
const semanticColors = ['success', 'warning', 'danger', 'info'];
|
|
1277
|
+
semanticColors.forEach(colorName => {
|
|
1278
|
+
if (colors[colorName]) {
|
|
1279
|
+
lines.push('');
|
|
1280
|
+
lines.push(`// ${colorName.charAt(0).toUpperCase() + colorName.slice(1)} Color Scale (OKLCH)`);
|
|
1281
|
+
const { hue, chroma, lightnessScale } = colors[colorName];
|
|
1282
|
+
shades.forEach(shade => {
|
|
1283
|
+
const lightness = lightnessScale[shade];
|
|
1284
|
+
lines.push(`$color-${colorName}-${shade}: oklch(${lightness}% ${chroma} ${hue}deg) !default;`);
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
});
|
|
1288
|
+
|
|
1289
|
+
// Extended color palette
|
|
1290
|
+
if (colors.extended) {
|
|
1291
|
+
lines.push('');
|
|
1292
|
+
lines.push('// Extended Color Palette (OKLCH)');
|
|
1293
|
+
Object.entries(colors.extended).forEach(([colorName, config]) => {
|
|
1294
|
+
const { hue, chroma } = config;
|
|
1295
|
+
shades.forEach(shade => {
|
|
1296
|
+
const lightness = defaultLightnessScale[shade];
|
|
1297
|
+
lines.push(`$color-${colorName}-${shade}: oklch(${lightness}% ${chroma} ${hue}deg) !default;`);
|
|
1298
|
+
});
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
// Semantic aliases
|
|
1303
|
+
lines.push('');
|
|
1304
|
+
lines.push('// Semantic Color Aliases');
|
|
1305
|
+
lines.push('$color-primary: $color-primary-500 !default;');
|
|
1306
|
+
lines.push('$color-success: $color-success-500 !default;');
|
|
1307
|
+
lines.push('$color-warning: $color-warning-500 !default;');
|
|
1308
|
+
lines.push('$color-danger: $color-danger-500 !default;');
|
|
1309
|
+
lines.push('$color-info: $color-info-500 !default;');
|
|
1310
|
+
|
|
1311
|
+
return lines.join('\n');
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* Generate color configuration maps for utility generation
|
|
1316
|
+
*/
|
|
1317
|
+
function generateColorConfig(colorConfig) {
|
|
1318
|
+
const lines = [];
|
|
1319
|
+
|
|
1320
|
+
// Color shades
|
|
1321
|
+
lines.push('');
|
|
1322
|
+
lines.push('// ============================================================================');
|
|
1323
|
+
lines.push('// Color Scale Maps (for programmatic utility generation)');
|
|
1324
|
+
lines.push('// ============================================================================');
|
|
1325
|
+
lines.push('');
|
|
1326
|
+
lines.push('// Color shades used for scale generation');
|
|
1327
|
+
lines.push(`$color-shades: (${colorConfig.shades.join(', ')}) !default;`);
|
|
1328
|
+
lines.push('');
|
|
1329
|
+
|
|
1330
|
+
// Color families
|
|
1331
|
+
lines.push('// Color families for utility generation');
|
|
1332
|
+
lines.push('$color-families: (');
|
|
1333
|
+
Object.entries(colorConfig.families).forEach(([key, value], index, arr) => {
|
|
1334
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1335
|
+
lines.push(` "${key}": "${value}"${comma}`);
|
|
1336
|
+
});
|
|
1337
|
+
lines.push(') !default;');
|
|
1338
|
+
lines.push('');
|
|
1339
|
+
|
|
1340
|
+
// Background opacity values
|
|
1341
|
+
lines.push('// Background opacity values for color modifiers');
|
|
1342
|
+
lines.push(`$bg-opacity-values: (${colorConfig.bgOpacityValues.join(', ')}) !default;`);
|
|
1343
|
+
lines.push('');
|
|
1344
|
+
|
|
1345
|
+
// Gradient colors
|
|
1346
|
+
lines.push('// Gradient color stops');
|
|
1347
|
+
lines.push('$gradient-colors: (');
|
|
1348
|
+
Object.entries(colorConfig.gradientColors).forEach(([key, value], index, arr) => {
|
|
1349
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1350
|
+
lines.push(` "${key}": "${value}"${comma}`);
|
|
1351
|
+
});
|
|
1352
|
+
lines.push(') !default;');
|
|
1353
|
+
|
|
1354
|
+
return lines.join('\n');
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Generate typography configuration
|
|
1359
|
+
*/
|
|
1360
|
+
function generateTypography(typography) {
|
|
1361
|
+
const lines = [];
|
|
1362
|
+
|
|
1363
|
+
// Font families
|
|
1364
|
+
lines.push('// Font Families');
|
|
1365
|
+
lines.push('$font-families: (');
|
|
1366
|
+
Object.entries(typography.fontFamily).forEach(([key, value], index, arr) => {
|
|
1367
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1368
|
+
const fontList = Array.isArray(value) ? value.join(', ') : value;
|
|
1369
|
+
lines.push(` "${key}": "${fontList}"${comma}`);
|
|
1370
|
+
});
|
|
1371
|
+
lines.push(') !default;');
|
|
1372
|
+
lines.push('');
|
|
1373
|
+
|
|
1374
|
+
// Font sizes
|
|
1375
|
+
lines.push('// Font Sizes');
|
|
1376
|
+
lines.push('$font-sizes: (');
|
|
1377
|
+
Object.entries(typography.fontSize).forEach(([key, value], index, arr) => {
|
|
1378
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1379
|
+
const size = Array.isArray(value) ? value[0] : value;
|
|
1380
|
+
lines.push(` "${key}": ${size}${comma}`);
|
|
1381
|
+
});
|
|
1382
|
+
lines.push(') !default;');
|
|
1383
|
+
lines.push('');
|
|
1384
|
+
|
|
1385
|
+
// Font weights
|
|
1386
|
+
lines.push('// Font Weights');
|
|
1387
|
+
lines.push('$font-weights: (');
|
|
1388
|
+
const sassColorNames = new Set(['black', 'white', 'red', 'green', 'blue', 'gray', 'orange', 'purple', 'yellow', 'pink', 'brown', 'cyan', 'magenta', 'navy', 'olive', 'silver', 'teal', 'maroon', 'aqua', 'fuchsia', 'lime']);
|
|
1389
|
+
Object.entries(typography.fontWeight).forEach(([key, value], index, arr) => {
|
|
1390
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1391
|
+
const safeKey = sassColorNames.has(key) ? `"${key}"` : key;
|
|
1392
|
+
lines.push(` ${safeKey}: ${value}${comma}`);
|
|
1393
|
+
});
|
|
1394
|
+
lines.push(') !default;');
|
|
1395
|
+
lines.push('');
|
|
1396
|
+
|
|
1397
|
+
// Letter spacing
|
|
1398
|
+
lines.push('// Letter Spacing');
|
|
1399
|
+
lines.push('$letter-spacing: (');
|
|
1400
|
+
Object.entries(typography.letterSpacing).forEach(([key, value], index, arr) => {
|
|
1401
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1402
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1403
|
+
});
|
|
1404
|
+
lines.push(') !default;');
|
|
1405
|
+
lines.push('');
|
|
1406
|
+
|
|
1407
|
+
// Line heights
|
|
1408
|
+
lines.push('// Line Heights');
|
|
1409
|
+
lines.push('$line-heights: (');
|
|
1410
|
+
Object.entries(typography.lineHeight).forEach(([key, value], index, arr) => {
|
|
1411
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1412
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1413
|
+
});
|
|
1414
|
+
lines.push(') !default;');
|
|
1415
|
+
|
|
1416
|
+
return lines.join('\n');
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
/**
|
|
1420
|
+
* Generate border radius scale
|
|
1421
|
+
*/
|
|
1422
|
+
function generateBorderRadius(borderRadius) {
|
|
1423
|
+
const lines = [];
|
|
1424
|
+
|
|
1425
|
+
lines.push('$border-radius-scale: (');
|
|
1426
|
+
Object.entries(borderRadius).forEach(([key, value], index, arr) => {
|
|
1427
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1428
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1429
|
+
});
|
|
1430
|
+
lines.push(') !default;');
|
|
1431
|
+
|
|
1432
|
+
return lines.join('\n');
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
/**
|
|
1436
|
+
* Generate shadow variables
|
|
1437
|
+
*/
|
|
1438
|
+
function generateShadows(shadows) {
|
|
1439
|
+
const lines = [];
|
|
1440
|
+
|
|
1441
|
+
lines.push('$shadows: (');
|
|
1442
|
+
Object.entries(shadows).forEach(([key, value], index, arr) => {
|
|
1443
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1444
|
+
const needsQuotes = value.includes(',');
|
|
1445
|
+
lines.push(` "${key}": ${needsQuotes ? `"${value}"` : value}${comma}`);
|
|
1446
|
+
});
|
|
1447
|
+
lines.push(') !default;');
|
|
1448
|
+
|
|
1449
|
+
return lines.join('\n');
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Generate transition configuration
|
|
1454
|
+
*/
|
|
1455
|
+
function generateTransitions(transition) {
|
|
1456
|
+
const lines = [];
|
|
1457
|
+
|
|
1458
|
+
// Durations
|
|
1459
|
+
lines.push('// Transition Durations');
|
|
1460
|
+
lines.push('$transition-duration: (');
|
|
1461
|
+
Object.entries(transition.duration).forEach(([key, value], index, arr) => {
|
|
1462
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1463
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1464
|
+
});
|
|
1465
|
+
lines.push(') !default;');
|
|
1466
|
+
lines.push('');
|
|
1467
|
+
|
|
1468
|
+
// Timing functions
|
|
1469
|
+
lines.push('// Transition Timing Functions');
|
|
1470
|
+
lines.push('$transition-timing: (');
|
|
1471
|
+
Object.entries(transition.timing).forEach(([key, value], index, arr) => {
|
|
1472
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1473
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1474
|
+
});
|
|
1475
|
+
lines.push(') !default;');
|
|
1476
|
+
|
|
1477
|
+
return lines.join('\n');
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
/**
|
|
1481
|
+
* Generate z-index scale
|
|
1482
|
+
*/
|
|
1483
|
+
function generateZIndex(zIndex) {
|
|
1484
|
+
const lines = [];
|
|
1485
|
+
|
|
1486
|
+
lines.push('$z-index: (');
|
|
1487
|
+
Object.entries(zIndex).forEach(([key, value], index, arr) => {
|
|
1488
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1489
|
+
lines.push(` "${key}": ${value}${comma}`);
|
|
1490
|
+
});
|
|
1491
|
+
lines.push(') !default;');
|
|
1492
|
+
|
|
1493
|
+
return lines.join('\n');
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* Generate opacity scale
|
|
1498
|
+
*/
|
|
1499
|
+
function generateOpacity(opacity) {
|
|
1500
|
+
const lines = [];
|
|
1501
|
+
|
|
1502
|
+
lines.push('$opacity-scale: (');
|
|
1503
|
+
Object.entries(opacity).forEach(([key, value], index, arr) => {
|
|
1504
|
+
const comma = index < arr.length - 1 ? ',' : '';
|
|
1505
|
+
// Keep numeric keys unquoted for proper numeric comparisons in Sass
|
|
1506
|
+
lines.push(` ${key}: ${value}${comma}`);
|
|
1507
|
+
});
|
|
1508
|
+
lines.push(') !default;');
|
|
1509
|
+
|
|
1510
|
+
return lines.join('\n');
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
/**
|
|
1514
|
+
* Generate a complete sample config file
|
|
1515
|
+
*/
|
|
1516
|
+
function generateSampleConfig() {
|
|
1517
|
+
// Generate the features section from defaultConfig
|
|
1518
|
+
const featureCategories = {
|
|
1519
|
+
'Core Layout': ['display', 'flexbox', 'grid', 'positioning', 'visibility'],
|
|
1520
|
+
'Core Spacing': ['spacing', 'sizing'],
|
|
1521
|
+
'Core Typography': ['typography'],
|
|
1522
|
+
'Core Visual': ['colors', 'backgrounds', 'borders', 'shadows', 'opacity', 'overflow', 'objectFit'],
|
|
1523
|
+
'Core Interaction': ['cursor', 'transitions'],
|
|
1524
|
+
'Extended Layout': ['flexExtended', 'gridExtended', 'float', 'containerQueries', 'isolation', 'placeItems', 'justifyItems', 'spaceBetween', 'columns', 'columnsExtended'],
|
|
1525
|
+
'Extended Typography': ['typographyExtended', 'fontExtended', 'letterSpacing', 'lineHeight', 'textAlignLast', 'textDecorationExtended', 'textJustify', 'textIndent', 'textShadow', 'textEmphasis', 'textOrientation', 'textUnderline', 'hangingPunctuation', 'hyphenate', 'initialLetter', 'tabSize', 'wordBreak', 'wordWrap', 'writingMode', 'unicodeBidi'],
|
|
1526
|
+
'Extended Visual': ['backgroundExtended', 'colorModifiers', 'blendModes', 'masks', 'borderRadiusLogical', 'ring', 'outline', 'appearance', 'accentColor', 'colorScheme'],
|
|
1527
|
+
'Extended Interaction': ['interaction', 'userSelect', 'willChange', 'all', 'caret', 'scroll', 'overscrollBehavior', 'overscrollBehaviorExtended', 'overflowExtended'],
|
|
1528
|
+
'Effects': ['animations', 'transforms', 'transforms3d', 'filters', 'aspectRatio', 'imageRendering', 'transitionBehavior'],
|
|
1529
|
+
'Content': ['list', 'listStyleExtended', 'table', 'counter', 'caption', 'quotes', 'orphans', 'widows', 'pageBreak', 'break', 'verticalAlign'],
|
|
1530
|
+
'Advanced': ['arbitrary', 'logicalProperties', 'sizingLogical', 'offset', 'shapeOutside', 'markerExtended', 'zoom', 'fieldSizing', 'svg', 'box', 'divide'],
|
|
1531
|
+
'State Variants': ['states', 'hover', 'focus', 'active', 'disabled'],
|
|
1532
|
+
'Theme Support': ['darkMode', 'rtl', 'accessibility', 'zIndex']
|
|
1533
|
+
};
|
|
1534
|
+
|
|
1535
|
+
let featuresSection = '';
|
|
1536
|
+
for (const [category, keys] of Object.entries(featureCategories)) {
|
|
1537
|
+
featuresSection += ` // ${category}\n`;
|
|
1538
|
+
keys.forEach(key => {
|
|
1539
|
+
if (key in defaultConfig.features) {
|
|
1540
|
+
featuresSection += ` ${key}: true,\n`;
|
|
1541
|
+
}
|
|
1542
|
+
});
|
|
1543
|
+
featuresSection += '\n';
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
return `/**
|
|
1547
|
+
* ApexCSS Configuration File
|
|
1548
|
+
*
|
|
1549
|
+
* This is your configuration file for customizing ApexCSS.
|
|
1550
|
+
* All features are enabled by default. Set any feature to false to disable it
|
|
1551
|
+
* and reduce your bundle size.
|
|
1552
|
+
*
|
|
1553
|
+
* Usage:
|
|
1554
|
+
* 1. Modify the values below to customize the framework
|
|
1555
|
+
* 2. Run: npm run config:build
|
|
1556
|
+
* 3. The SCSS files will be regenerated with your customizations
|
|
1557
|
+
*
|
|
1558
|
+
*/
|
|
1559
|
+
|
|
1560
|
+
export default {
|
|
1561
|
+
// ============================================================================
|
|
1562
|
+
// Feature Toggles - Enable/disable utility categories
|
|
1563
|
+
// ============================================================================
|
|
1564
|
+
features: {
|
|
1565
|
+
${featuresSection.trim()}
|
|
1566
|
+
},
|
|
1567
|
+
|
|
1568
|
+
// ============================================================================
|
|
1569
|
+
// Breakpoints - Customize responsive breakpoints
|
|
1570
|
+
// ============================================================================
|
|
1571
|
+
breakpoints: {
|
|
1572
|
+
sm: '320px',
|
|
1573
|
+
md: '768px',
|
|
1574
|
+
lg: '1024px',
|
|
1575
|
+
xl: '1280px',
|
|
1576
|
+
xxl: '1536px'
|
|
1577
|
+
},
|
|
1578
|
+
|
|
1579
|
+
// ============================================================================
|
|
1580
|
+
// Spacing Scale - Customize margin/padding values
|
|
1581
|
+
// ============================================================================
|
|
1582
|
+
spacing: {
|
|
1583
|
+
0: '0',
|
|
1584
|
+
1: '0.25rem',
|
|
1585
|
+
2: '0.5rem',
|
|
1586
|
+
4: '1rem',
|
|
1587
|
+
8: '2rem',
|
|
1588
|
+
16: '4rem'
|
|
1589
|
+
// Add or remove values as needed
|
|
1590
|
+
},
|
|
1591
|
+
|
|
1592
|
+
// ============================================================================
|
|
1593
|
+
// Colors - Customize your color palette (OKLCH format)
|
|
1594
|
+
// ============================================================================
|
|
1595
|
+
// Define colors with OKLCH format: { hue, chroma, lightnessScale }
|
|
1596
|
+
// - hue: 0-360 (color wheel angle)
|
|
1597
|
+
// - chroma: 0-0.4 (color intensity)
|
|
1598
|
+
// - lightnessScale: { 50: 95, 100: 90, ... 950: 20 } (perceptual lightness values)
|
|
1599
|
+
//
|
|
1600
|
+
// Example: Change primary from blue (250) to purple (300):
|
|
1601
|
+
// primary: { hue: 300, chroma: 0.18, lightnessScale: { ... } }
|
|
1602
|
+
// ============================================================================
|
|
1603
|
+
colors: {
|
|
1604
|
+
primary: {
|
|
1605
|
+
hue: 250, // Blue
|
|
1606
|
+
chroma: 0.18, // Moderate saturation
|
|
1607
|
+
lightnessScale: {
|
|
1608
|
+
50: 95, 100: 90, 200: 85, 300: 78, 400: 70,
|
|
1609
|
+
500: 62, 600: 55, 700: 45, 800: 35, 900: 25, 950: 20
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
// Add your brand colors here:
|
|
1613
|
+
// brand: {
|
|
1614
|
+
// hue: 340, // Pink
|
|
1615
|
+
// chroma: 0.20,
|
|
1616
|
+
// lightnessScale: { 50: 95, 100: 90, ... 950: 20 }
|
|
1617
|
+
// }
|
|
1618
|
+
}
|
|
1619
|
+
};
|
|
1620
|
+
`;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
/**
|
|
1624
|
+
* Deep merge two objects
|
|
1625
|
+
* @param {object} target - Target object
|
|
1626
|
+
* @param {object} source - Source object
|
|
1627
|
+
* @returns {object} - Merged object
|
|
1628
|
+
*/
|
|
1629
|
+
function mergeDeep(target, source) {
|
|
1630
|
+
const output = { ...target };
|
|
1631
|
+
if (isObject(target) && isObject(source)) {
|
|
1632
|
+
Object.keys(source).forEach(key => {
|
|
1633
|
+
if (isObject(source[key])) {
|
|
1634
|
+
if (!(key in target)) {
|
|
1635
|
+
output[key] = source[key];
|
|
1636
|
+
} else {
|
|
1637
|
+
output[key] = mergeDeep(target[key], source[key]);
|
|
1638
|
+
}
|
|
1639
|
+
} else {
|
|
1640
|
+
output[key] = source[key];
|
|
1641
|
+
}
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
return output;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
/**
|
|
1648
|
+
* Check if value is a plain object
|
|
1649
|
+
* @param {*} item - Value to check
|
|
1650
|
+
* @returns {boolean}
|
|
1651
|
+
*/
|
|
1652
|
+
function isObject(item) {
|
|
1653
|
+
return Boolean(item && typeof item === 'object' && !Array.isArray(item));
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
/**
|
|
1657
|
+
* Get the type of a value
|
|
1658
|
+
* @param {*} value - Value to check
|
|
1659
|
+
* @returns {string} - Type name
|
|
1660
|
+
*/
|
|
1661
|
+
function getType(value) {
|
|
1662
|
+
if (Array.isArray(value)) {
|
|
1663
|
+
return 'array';
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
if (value === null) {
|
|
1667
|
+
return 'null';
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
return typeof value;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
/**
|
|
1674
|
+
* Validate user config shape and value types against defaults.
|
|
1675
|
+
* Unknown keys are warnings to keep customization flexible, but type mismatches
|
|
1676
|
+
* are treated as hard errors so generated SCSS remains valid.
|
|
1677
|
+
*/
|
|
1678
|
+
function validateUserConfig(userConfig, defaults = defaultConfig, currentPath = '') {
|
|
1679
|
+
const errors = [];
|
|
1680
|
+
const warnings = [];
|
|
1681
|
+
|
|
1682
|
+
if (!isObject(userConfig)) {
|
|
1683
|
+
if (userConfig === undefined || userConfig === null) {
|
|
1684
|
+
return { errors, warnings };
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
errors.push(`Configuration root must be an object, received ${getType(userConfig)}.`);
|
|
1688
|
+
return { errors, warnings };
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
Object.entries(userConfig).forEach(([key, value]) => {
|
|
1692
|
+
const pathKey = currentPath ? `${currentPath}.${key}` : key;
|
|
1693
|
+
const isTopLevel = currentPath === '';
|
|
1694
|
+
const isFeatureKey = currentPath === 'features';
|
|
1695
|
+
|
|
1696
|
+
if (!(key in defaults)) {
|
|
1697
|
+
if (isTopLevel || isFeatureKey) {
|
|
1698
|
+
warnings.push(`Unknown config key \`${pathKey}\` will be ignored by generators.`);
|
|
1699
|
+
}
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
const defaultValue = defaults[key];
|
|
1704
|
+
const expectedType = getType(defaultValue);
|
|
1705
|
+
const actualType = getType(value);
|
|
1706
|
+
|
|
1707
|
+
if (expectedType !== actualType) {
|
|
1708
|
+
errors.push(
|
|
1709
|
+
`Invalid type for \`${pathKey}\`: expected ${expectedType}, received ${actualType}.`
|
|
1710
|
+
);
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
if (expectedType === 'object') {
|
|
1715
|
+
const nested = validateUserConfig(value, defaultValue, pathKey);
|
|
1716
|
+
errors.push(...nested.errors);
|
|
1717
|
+
warnings.push(...nested.warnings);
|
|
1718
|
+
}
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
if (isObject(userConfig.features)) {
|
|
1722
|
+
Object.entries(userConfig.features).forEach(([featureKey, featureValue]) => {
|
|
1723
|
+
if (typeof featureValue !== 'boolean') {
|
|
1724
|
+
errors.push(
|
|
1725
|
+
`Invalid feature toggle \`features.${featureKey}\`: expected boolean, received ${getType(featureValue)}.`
|
|
1726
|
+
);
|
|
1727
|
+
}
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
return { errors, warnings };
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
/**
|
|
1735
|
+
* Parse command line arguments
|
|
1736
|
+
*/
|
|
1737
|
+
function parseArgs() {
|
|
1738
|
+
const args = process.argv.slice(2);
|
|
1739
|
+
const options = {
|
|
1740
|
+
config: 'src/apex.config.js',
|
|
1741
|
+
output: 'src/config',
|
|
1742
|
+
watch: false,
|
|
1743
|
+
init: false
|
|
1744
|
+
};
|
|
1745
|
+
|
|
1746
|
+
args.forEach(arg => {
|
|
1747
|
+
if (arg.startsWith('--config=')) {
|
|
1748
|
+
options.config = arg.split('=')[1];
|
|
1749
|
+
} else if (arg.startsWith('--output=')) {
|
|
1750
|
+
options.output = arg.split('=')[1];
|
|
1751
|
+
} else if (arg === '--watch' || arg === '-w') {
|
|
1752
|
+
options.watch = true;
|
|
1753
|
+
} else if (arg === '--init') {
|
|
1754
|
+
options.init = true;
|
|
1755
|
+
} else if (arg === '--help' || arg === '-h') {
|
|
1756
|
+
showHelp();
|
|
1757
|
+
process.exit(0);
|
|
1758
|
+
}
|
|
1759
|
+
});
|
|
1760
|
+
|
|
1761
|
+
return options;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
/**
|
|
1765
|
+
* Show help message
|
|
1766
|
+
*/
|
|
1767
|
+
function showHelp() {
|
|
1768
|
+
console.log(`
|
|
1769
|
+
ApexCSS Configuration Builder
|
|
1770
|
+
|
|
1771
|
+
Usage: node config-builder.js [options]
|
|
1772
|
+
|
|
1773
|
+
Options:
|
|
1774
|
+
--config=<file> Config file path (default: src/apex.config.js)
|
|
1775
|
+
--output=<dir> Output directory (default: src/config)
|
|
1776
|
+
--watch, -w Watch for changes and rebuild
|
|
1777
|
+
--init Create sample config file
|
|
1778
|
+
--help, -h Show this help
|
|
1779
|
+
|
|
1780
|
+
Examples:
|
|
1781
|
+
node config-builder.js
|
|
1782
|
+
node config-builder.js --config=custom.config.js
|
|
1783
|
+
node config-builder.js --watch
|
|
1784
|
+
node config-builder.js --init
|
|
1785
|
+
`);
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
/**
|
|
1789
|
+
* Load user configuration (optional)
|
|
1790
|
+
* Users can directly edit src/config/_custom-config.scss instead
|
|
1791
|
+
*/
|
|
1792
|
+
async function loadConfig(configPath) {
|
|
1793
|
+
const fullPath = path.resolve(process.cwd(), configPath);
|
|
1794
|
+
|
|
1795
|
+
try {
|
|
1796
|
+
await fs.access(fullPath);
|
|
1797
|
+
const module = await import(fullPath + '?t=' + Date.now());
|
|
1798
|
+
const loaded = module.default || module;
|
|
1799
|
+
|
|
1800
|
+
if (!isObject(loaded)) {
|
|
1801
|
+
throw new Error(`Expected exported config object but received ${getType(loaded)}.`);
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
return loaded;
|
|
1805
|
+
} catch (err) {
|
|
1806
|
+
if (err?.code === 'ENOENT') {
|
|
1807
|
+
logInfo(`Config file not found at ${configPath}; using defaults.`);
|
|
1808
|
+
return {};
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
throw new Error(`Failed to load config file ${configPath}: ${err.message}`);
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
/**
|
|
1816
|
+
* Main build function
|
|
1817
|
+
*/
|
|
1818
|
+
async function build(options) {
|
|
1819
|
+
try {
|
|
1820
|
+
// Load user config
|
|
1821
|
+
const userConfig = await loadConfig(options.config);
|
|
1822
|
+
const validation = validateUserConfig(userConfig);
|
|
1823
|
+
|
|
1824
|
+
validation.warnings.forEach(logWarn);
|
|
1825
|
+
|
|
1826
|
+
if (validation.errors.length > 0) {
|
|
1827
|
+
const details = validation.errors.map(error => `- ${error}`).join('\n');
|
|
1828
|
+
throw new Error(`Configuration validation failed:\n${details}`);
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1831
|
+
const mergedConfig = mergeDeep(defaultConfig, userConfig);
|
|
1832
|
+
|
|
1833
|
+
// Generate SCSS
|
|
1834
|
+
const scss = generateSCSS(userConfig);
|
|
1835
|
+
|
|
1836
|
+
// Ensure output directory exists
|
|
1837
|
+
await fs.mkdir(options.output, { recursive: true });
|
|
1838
|
+
|
|
1839
|
+
// Write SCSS file
|
|
1840
|
+
const scssPath = path.join(options.output, '_custom-config.scss');
|
|
1841
|
+
await fs.writeFile(scssPath, scss);
|
|
1842
|
+
logInfo(`Generated: ${scssPath}`);
|
|
1843
|
+
|
|
1844
|
+
if (isObject(mergedConfig.features)) {
|
|
1845
|
+
const featureEntries = Object.values(mergedConfig.features);
|
|
1846
|
+
const enabled = featureEntries.filter(Boolean).length;
|
|
1847
|
+
const total = featureEntries.length;
|
|
1848
|
+
logInfo(`Feature toggles enabled: ${enabled}/${total}`);
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
console.log('\nš Configuration built successfully!');
|
|
1852
|
+
console.log(' Run "npm run build" to compile the framework.\n');
|
|
1853
|
+
|
|
1854
|
+
} catch (err) {
|
|
1855
|
+
logError(`Build failed: ${err.message}`);
|
|
1856
|
+
process.exit(1);
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
/**
|
|
1861
|
+
* Initialize config file
|
|
1862
|
+
*/
|
|
1863
|
+
async function init() {
|
|
1864
|
+
const configPath = path.resolve(process.cwd(), 'src/apex.config.js');
|
|
1865
|
+
|
|
1866
|
+
const sample = generateSampleConfig();
|
|
1867
|
+
await fs.writeFile(configPath, sample);
|
|
1868
|
+
console.log('ā
Created: src/apex.config.js\\n');
|
|
1869
|
+
console.log(' Edit this file to customize ApexCSS, then run:');
|
|
1870
|
+
console.log(' npm run config:build\\n');
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
/**
|
|
1874
|
+
* Watch for changes
|
|
1875
|
+
*/
|
|
1876
|
+
async function watch(options) {
|
|
1877
|
+
const configPath = path.resolve(process.cwd(), options.config);
|
|
1878
|
+
|
|
1879
|
+
logInfo(`Watching ${options.config} for changes...`);
|
|
1880
|
+
console.log('');
|
|
1881
|
+
|
|
1882
|
+
// Initial build
|
|
1883
|
+
await build(options);
|
|
1884
|
+
|
|
1885
|
+
// Watch for changes
|
|
1886
|
+
const { watchFile } = await import('fs');
|
|
1887
|
+
watchFile(configPath, async (curr, prev) => {
|
|
1888
|
+
if (curr.mtime !== prev.mtime) {
|
|
1889
|
+
console.log(`š Config changed, rebuilding...\\n`);
|
|
1890
|
+
await build(options);
|
|
1891
|
+
}
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
// Main execution
|
|
1896
|
+
async function main() {
|
|
1897
|
+
const options = parseArgs();
|
|
1898
|
+
|
|
1899
|
+
if (options.init) {
|
|
1900
|
+
await init();
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
if (options.watch) {
|
|
1905
|
+
await watch(options);
|
|
1906
|
+
} else {
|
|
1907
|
+
await build(options);
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
/**
|
|
1912
|
+
* Check if this module is being run directly
|
|
1913
|
+
* @returns {boolean}
|
|
1914
|
+
*/
|
|
1915
|
+
function isDirectExecution() {
|
|
1916
|
+
if (!process.argv[1]) {
|
|
1917
|
+
return false;
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
return path.resolve(process.argv[1]) === __filename;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
if (isDirectExecution()) {
|
|
1924
|
+
main();
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
export {
|
|
1928
|
+
build,
|
|
1929
|
+
defaultConfig,
|
|
1930
|
+
generateSCSS,
|
|
1931
|
+
isObject,
|
|
1932
|
+
mergeDeep,
|
|
1933
|
+
validateUserConfig
|
|
1934
|
+
};
|