eva-css-fluid 1.0.4 → 2.0.5

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/src/_config.scss CHANGED
@@ -6,6 +6,8 @@
6
6
  // ===========================================
7
7
 
8
8
  @use "sass:list";
9
+ @use "sass:map";
10
+ @use "sass:meta";
9
11
 
10
12
  // ===========================================
11
13
  // SIZE CONFIGURATION
@@ -23,6 +25,14 @@ $build-class: true !default; // Generate utility classes
23
25
  $build-color-classes: true !default; // Generate color classes
24
26
  $custom-class: false !default; // Enable custom class filtering
25
27
  $name-by-size: true !default; // Use size values in variable names
28
+ $debug: false !default; // Show class generation summary
29
+
30
+ // ===========================================
31
+ // CUSTOM CLASS CONFIGURATION
32
+ // ===========================================
33
+ // Used when $custom-class is true to filter which classes are generated
34
+ // Example: (w: (50, 100), px: (24), g: (24, 50))
35
+ $class-config: () !default;
26
36
 
27
37
  // ===========================================
28
38
  // DERIVED CONFIGURATION
@@ -68,3 +78,48 @@ $properties: (
68
78
  $font-properties: (
69
79
  fs: font-size,
70
80
  );
81
+
82
+ // ===========================================
83
+ // CONFIGURATION VALIDATION
84
+ // ===========================================
85
+
86
+ // Validate that required base sizes exist
87
+ @if not list.index($sizes, 16) {
88
+ @error "EVA CSS: Size 16 is required as a base size. Please add 16 to your $sizes configuration.";
89
+ }
90
+
91
+ // Validate that sizes list is not empty
92
+ @if list.length($sizes) == 0 {
93
+ @error "EVA CSS: $sizes cannot be empty. Please provide at least one size value.";
94
+ }
95
+
96
+ // Validate that font-sizes list is not empty
97
+ @if list.length($font-sizes) == 0 {
98
+ @error "EVA CSS: $font-sizes cannot be empty. Please provide at least one font size value.";
99
+ }
100
+
101
+ // Validate custom-class configuration
102
+ @if $custom-class and meta.type-of($class-config) != "map" {
103
+ @error "EVA CSS: When $custom-class is true, $class-config must be a map. Example: (w: (50, 100), px: (24))";
104
+ }
105
+
106
+ // Validate that class-config properties exist in $properties
107
+ @if $custom-class and list.length(map.keys($class-config)) > 0 {
108
+ @each $key in map.keys($class-config) {
109
+ @if not map.has-key($properties, $key) {
110
+ @error "EVA CSS: Unknown property '#{$key}' in $class-config. Available properties: #{map.keys($properties)}";
111
+ }
112
+
113
+ // Validate that sizes in class-config exist in $sizes
114
+ $allowed-sizes: map.get($class-config, $key);
115
+ @if meta.type-of($allowed-sizes) != "list" {
116
+ @error "EVA CSS: Value for '#{$key}' in $class-config must be a list of sizes. Example: (24, 50, 100)";
117
+ }
118
+
119
+ @each $size in $allowed-sizes {
120
+ @if not list.index($sizes, $size) {
121
+ @error "EVA CSS: Size #{$size} in $class-config for property '#{$key}' is not in $sizes list. Available sizes: #{$sizes}";
122
+ }
123
+ }
124
+ }
125
+ }
package/src/_eva.scss CHANGED
@@ -40,6 +40,8 @@ $px-rem-suffix: true !default; // Valeurs statiques de debug uniquement
40
40
  $build-class: false !default; // DEV: false | PROD: true
41
41
  $custom-class: false !default; // true pour filtrage personnalisé des classes
42
42
  $name-by-size: true !default; // true = utilise les valeurs, false = utilise l'index
43
+ $class-config: () !default; // Configuration pour custom-class mode
44
+ $debug: false !default; // Show class generation summary
43
45
 
44
46
 
45
47
 
@@ -81,7 +83,89 @@ $font-properties: (
81
83
  fs: font-size,
82
84
  );
83
85
 
86
+ // ===========================================
87
+ // CONFIGURATION VALIDATION
88
+ // ===========================================
84
89
 
90
+ // Validate that required base sizes exist
91
+ @if not list.index($sizes, 16) {
92
+ @error "EVA CSS: Size 16 is required as a base size. Please add 16 to your $sizes configuration.";
93
+ }
94
+
95
+ // Validate that sizes list is not empty
96
+ @if list.length($sizes) == 0 {
97
+ @error "EVA CSS: $sizes cannot be empty. Please provide at least one size value.";
98
+ }
99
+
100
+ // Validate that font-sizes list is not empty
101
+ @if list.length($font-sizes) == 0 {
102
+ @error "EVA CSS: $font-sizes cannot be empty. Please provide at least one font size value.";
103
+ }
104
+
105
+ // Validate custom-class configuration
106
+ @if $custom-class and meta.type-of($class-config) != "map" {
107
+ @error "EVA CSS: When $custom-class is true, $class-config must be a map. Example: (w: (50, 100), px: (24))";
108
+ }
109
+
110
+ // Validate that class-config properties exist in $properties
111
+ @if $custom-class and list.length(map.keys($class-config)) > 0 {
112
+ @each $key in map.keys($class-config) {
113
+ @if not map.has-key($properties, $key) {
114
+ @error "EVA CSS: Unknown property '#{$key}' in $class-config. Available properties: #{map.keys($properties)}";
115
+ }
116
+
117
+ // Validate that sizes in class-config exist in $sizes
118
+ $allowed-sizes: map.get($class-config, $key);
119
+ @if meta.type-of($allowed-sizes) != "list" {
120
+ @error "EVA CSS: Value for '#{$key}' in $class-config must be a list of sizes. Example: (24, 50, 100)";
121
+ }
122
+
123
+ @each $size in $allowed-sizes {
124
+ @if not list.index($sizes, $size) {
125
+ @error "EVA CSS: Size #{$size} in $class-config for property '#{$key}' is not in $sizes list. Available sizes: #{$sizes}";
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ // ===========================================
132
+ // DEBUG MODE OUTPUT
133
+ // ===========================================
134
+
135
+ @if $debug {
136
+ @debug "╔══════════════════════════════════════════════════════════════";
137
+ @debug "║ EVA CSS - Configuration Summary";
138
+ @debug "╠══════════════════════════════════════════════════════════════";
139
+ @debug "║ Sizes: #{$sizes}";
140
+ @debug "║ Total sizes: #{list.length($sizes)}";
141
+ @debug "║ Font sizes: #{$font-sizes}";
142
+ @debug "║ Total font sizes: #{list.length($font-sizes)}";
143
+ @debug "╠══════════════════════════════════════════════════════════════";
144
+ @debug "║ Build Configuration:";
145
+ @debug "║ - Build classes: #{$build-class}";
146
+ @debug "║ - Custom class mode: #{$custom-class}";
147
+ @debug "║ - Px/Rem suffix: #{$px-rem-suffix}";
148
+ @debug "║ - Name by size: #{$name-by-size}";
149
+
150
+ @if $custom-class and list.length(map.keys($class-config)) > 0 {
151
+ @debug "╠══════════════════════════════════════════════════════════════";
152
+ @debug "║ Custom Class Configuration:";
153
+ @each $key in map.keys($class-config) {
154
+ $allowed-sizes: map.get($class-config, $key);
155
+ @debug "║ - #{$key}: #{$allowed-sizes} (#{list.length($allowed-sizes)} sizes)";
156
+ }
157
+ }
158
+
159
+ @if $build-class {
160
+ $class-count: list.length($sizes) * list.length(map.keys($properties)) * list.length($sizing-class);
161
+ @debug "╠══════════════════════════════════════════════════════════════";
162
+ @debug "║ Estimated Utility Classes:";
163
+ @debug "║ - Size properties: ~#{$class-count} classes";
164
+ @debug "║ - Available properties: #{map.keys($properties)}";
165
+ }
166
+
167
+ @debug "╚══════════════════════════════════════════════════════════════";
168
+ }
85
169
 
86
170
  @function round2($number) {
87
171
  @return math.div(math.round($number * 100), 100);
@@ -0,0 +1,539 @@
1
+ /**
2
+ * EVA CSS CLI Interactive Commands
3
+ *
4
+ * Commands: init, setup
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+ const readline = require('readline');
10
+
11
+ // CLI colors
12
+ const colors = {
13
+ reset: '\x1b[0m',
14
+ bright: '\x1b[1m',
15
+ dim: '\x1b[2m',
16
+ green: '\x1b[32m',
17
+ blue: '\x1b[34m',
18
+ cyan: '\x1b[36m',
19
+ yellow: '\x1b[33m',
20
+ red: '\x1b[31m'
21
+ };
22
+
23
+ function log(msg) {
24
+ console.log(msg);
25
+ }
26
+
27
+ function success(msg) {
28
+ log(`${colors.green}✅${colors.reset} ${msg}`);
29
+ }
30
+
31
+ function info(msg) {
32
+ log(`${colors.blue}ℹ${colors.reset} ${msg}`);
33
+ }
34
+
35
+ function error(msg) {
36
+ log(`${colors.red}❌${colors.reset} ${msg}`);
37
+ }
38
+
39
+ function title(msg) {
40
+ log(`\n${colors.bright}${colors.cyan}${msg}${colors.reset}\n`);
41
+ }
42
+
43
+ // Readline interface for prompts
44
+ function prompt(question) {
45
+ const rl = readline.createInterface({
46
+ input: process.stdin,
47
+ output: process.stdout
48
+ });
49
+
50
+ return new Promise(resolve => {
51
+ rl.question(`${colors.cyan}?${colors.reset} ${question} `, answer => {
52
+ rl.close();
53
+ resolve(answer.trim());
54
+ });
55
+ });
56
+ }
57
+
58
+ async function select(question, options) {
59
+ log(`${colors.cyan}?${colors.reset} ${question}`);
60
+ options.forEach((opt, i) => {
61
+ const description = opt.description ? ` ${colors.dim}- ${opt.description}${colors.reset}` : '';
62
+ log(` ${colors.dim}${i + 1}.${colors.reset} ${opt.label}${description}`);
63
+ });
64
+
65
+ const answer = await prompt(` Select (1-${options.length}):`);
66
+ const index = parseInt(answer) - 1;
67
+
68
+ if (index >= 0 && index < options.length) {
69
+ return options[index].value;
70
+ }
71
+
72
+ error('Invalid selection, using default');
73
+ return options[0].value;
74
+ }
75
+
76
+ async function confirm(question, defaultValue = true) {
77
+ const defaultText = defaultValue ? 'Y/n' : 'y/N';
78
+ const answer = await prompt(`${question} (${defaultText})`);
79
+
80
+ if (!answer) return defaultValue;
81
+ return answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
82
+ }
83
+
84
+ /**
85
+ * Generate eva.config.cjs template
86
+ */
87
+ function generateEvaConfig(options) {
88
+ const { sizes, fontSizes, buildClass, debug, workflow } = options;
89
+
90
+ return `/**
91
+ * EVA CSS Configuration
92
+ *
93
+ * This configuration file defines your design tokens.
94
+ * Customize sizes, font sizes, and build options.
95
+ *
96
+ * Documentation: https://github.com/nkdeus/eva/blob/main/packages/eva-css/docs/JSON-CONFIG.md
97
+ */
98
+
99
+ module.exports = {
100
+ // Design sizes - extracted from your design system
101
+ // These become CSS variables: var(--4), var(--8), var(--16), etc.
102
+ sizes: [${sizes.join(', ')}],
103
+
104
+ // Font sizes for typography
105
+ // These become CSS variables: var(--14), var(--16), var(--20), etc.
106
+ fontSizes: [${fontSizes.join(', ')}],
107
+
108
+ // Generate utility classes (.w-64, .p-16, .fs-24, etc.)
109
+ buildClass: ${buildClass},
110
+
111
+ // Show configuration during build (useful for debugging)
112
+ debug: ${debug},
113
+
114
+ // Theme configuration
115
+ theme: {
116
+ name: 'eva',
117
+ colors: {
118
+ // Using EVA default colors
119
+ // You can customize: brand, accent, extra
120
+ },
121
+
122
+ lightMode: {
123
+ lightness: 96.4, // Light background
124
+ darkness: 6.4 // Dark text
125
+ },
126
+
127
+ darkMode: {
128
+ lightness: 5, // Dark background
129
+ darkness: 95 // Light text
130
+ },
131
+
132
+ // Auto-switch based on system preference
133
+ autoSwitch: false
134
+ }${workflow === 'json' ? `,
135
+
136
+ // Optional: CSS purging for production
137
+ // Uncomment to reduce file size by 60-90%
138
+ /*
139
+ purge: {
140
+ enabled: true,
141
+ content: ['*.html', 'src/**/*.{js,jsx,tsx,vue}'],
142
+ css: 'dist/main.css',
143
+ output: 'dist/main-purged.css',
144
+ safelist: ['theme-', 'current-', 'toggle-']
145
+ }
146
+ */` : ''}
147
+ };
148
+ `;
149
+ }
150
+
151
+ /**
152
+ * Generate build script for JSON config workflow
153
+ */
154
+ function generateBuildScript() {
155
+ return `#!/usr/bin/env node
156
+ /**
157
+ * EVA CSS Build Script
158
+ *
159
+ * This script loads eva.config.cjs and injects it into SCSS compilation.
160
+ *
161
+ * USAGE:
162
+ * node scripts/build.js <input.scss> <output.css>
163
+ */
164
+
165
+ const fs = require('fs');
166
+ const path = require('path');
167
+ const { execSync } = require('child_process');
168
+
169
+ /**
170
+ * Load EVA configuration from eva.config.cjs
171
+ */
172
+ function loadConfig() {
173
+ const configPath = path.join(process.cwd(), 'eva.config.cjs');
174
+
175
+ if (!fs.existsSync(configPath)) {
176
+ console.log('⚠️ No eva.config.cjs found');
177
+ return null;
178
+ }
179
+
180
+ delete require.cache[require.resolve(configPath)];
181
+ return require(configPath);
182
+ }
183
+
184
+ /**
185
+ * Convert configuration to SCSS variables
186
+ */
187
+ function generateScssWithParams(config) {
188
+ const params = [];
189
+
190
+ if (config.sizes) {
191
+ params.push(\`$sizes: (\${config.sizes.join(', ')})\`);
192
+ }
193
+
194
+ if (config.fontSizes) {
195
+ params.push(\`$font-sizes: (\${config.fontSizes.join(', ')})\`);
196
+ }
197
+
198
+ if (typeof config.buildClass === 'boolean') {
199
+ params.push(\`$build-class: \${config.buildClass}\`);
200
+ }
201
+
202
+ if (typeof config.debug === 'boolean') {
203
+ params.push(\`$debug: \${config.debug}\`);
204
+ }
205
+
206
+ return params.join(',\\n ');
207
+ }
208
+
209
+ /**
210
+ * Build CSS from SCSS with configuration injection
211
+ */
212
+ function buildCss(inputScss, outputCss, config) {
213
+ if (!fs.existsSync(inputScss)) {
214
+ console.error(\`❌ Input file not found: \${inputScss}\`);
215
+ process.exit(1);
216
+ }
217
+
218
+ const outputDir = path.dirname(outputCss);
219
+ if (!fs.existsSync(outputDir)) {
220
+ fs.mkdirSync(outputDir, { recursive: true });
221
+ }
222
+
223
+ const inputDir = path.dirname(inputScss);
224
+ const inputBase = path.basename(inputScss, '.scss');
225
+ const tempPath = path.join(inputDir, \`.\${inputBase}-temp.scss\`);
226
+
227
+ try {
228
+ const content = fs.readFileSync(inputScss, 'utf8');
229
+ let output = content;
230
+
231
+ if (config) {
232
+ const params = generateScssWithParams(config);
233
+
234
+ if (params) {
235
+ output = content.replace(
236
+ /@use\\s+['"]eva-css\\/index['"];?/g,
237
+ \`@use 'eva-css/index' with (\\n \${params}\\n);\`
238
+ );
239
+
240
+ console.log('✅ Config injected into SCSS');
241
+ }
242
+ }
243
+
244
+ fs.writeFileSync(tempPath, output);
245
+
246
+ console.log('🔨 Compiling SCSS...');
247
+ execSync(
248
+ \`npx sass --load-path=node_modules \${tempPath}:\${outputCss}\`,
249
+ { stdio: 'inherit' }
250
+ );
251
+
252
+ if (fs.existsSync(outputCss)) {
253
+ const stats = fs.statSync(outputCss);
254
+ const sizeKB = (stats.size / 1024).toFixed(2);
255
+ console.log(\`✅ CSS compiled: \${outputCss} (\${sizeKB} KB)\`);
256
+ }
257
+ } catch (error) {
258
+ console.error('❌ Build failed:', error.message);
259
+ process.exit(1);
260
+ } finally {
261
+ if (fs.existsSync(tempPath)) {
262
+ fs.unlinkSync(tempPath);
263
+ }
264
+ }
265
+ }
266
+
267
+ /**
268
+ * Main execution
269
+ */
270
+ function main() {
271
+ const [,, input, output] = process.argv;
272
+
273
+ if (!input || !output) {
274
+ console.log('Usage: node scripts/build.js <input.scss> <output.css>');
275
+ process.exit(1);
276
+ }
277
+
278
+ console.log('🚀 EVA CSS Build\\n');
279
+ console.log(\`📥 Input: \${input}\`);
280
+ console.log(\`📤 Output: \${output}\\n\`);
281
+
282
+ const config = loadConfig();
283
+ buildCss(input, output, config);
284
+
285
+ console.log('\\n✨ Build complete!\\n');
286
+ }
287
+
288
+ if (require.main === module) {
289
+ main();
290
+ }
291
+
292
+ module.exports = { loadConfig, generateScssWithParams, buildCss };
293
+ `;
294
+ }
295
+
296
+ /**
297
+ * eva-css init command
298
+ * Initialize EVA CSS in existing project
299
+ */
300
+ async function initCommand() {
301
+ try {
302
+ title('🎨 EVA CSS Initialization');
303
+
304
+ // Check if eva.config.cjs already exists
305
+ const configPath = path.join(process.cwd(), 'eva.config.cjs');
306
+ if (fs.existsSync(configPath)) {
307
+ error('eva.config.cjs already exists!');
308
+ const overwrite = await confirm('Overwrite?', false);
309
+ if (!overwrite) {
310
+ log('\nAborted.');
311
+ process.exit(0);
312
+ }
313
+ }
314
+
315
+ // Get configuration from user
316
+ log('');
317
+ info('Configure your design system:\n');
318
+
319
+ const sizesInput = await prompt('Design sizes (comma-separated) [4, 8, 16, 32, 64, 128]:');
320
+ const sizes = sizesInput ? sizesInput.split(',').map(s => parseInt(s.trim())) : [4, 8, 16, 32, 64, 128];
321
+
322
+ const fontSizesInput = await prompt('Font sizes (comma-separated) [14, 16, 20, 24, 32, 48]:');
323
+ const fontSizes = fontSizesInput ? fontSizesInput.split(',').map(s => parseInt(s.trim())) : [14, 16, 20, 24, 32, 48];
324
+
325
+ const buildClass = await confirm('Generate utility classes?', true);
326
+ const debug = await confirm('Enable debug mode?', false);
327
+
328
+ // Generate config file
329
+ const configContent = generateEvaConfig({
330
+ sizes,
331
+ fontSizes,
332
+ buildClass,
333
+ debug,
334
+ workflow: 'json'
335
+ });
336
+
337
+ fs.writeFileSync(configPath, configContent);
338
+ success('Created eva.config.cjs');
339
+
340
+ // Success message
341
+ title('✅ EVA CSS Initialized!');
342
+
343
+ log(`${colors.bright}Next steps:${colors.reset}\n`);
344
+ log(` ${colors.dim}1.${colors.reset} Run ${colors.cyan}npx eva-css validate${colors.reset} to verify configuration`);
345
+ log(` ${colors.dim}2.${colors.reset} Import EVA CSS in your SCSS: ${colors.dim}@use 'eva-css/index';${colors.reset}`);
346
+ log(` ${colors.dim}3.${colors.reset} Use ${colors.cyan}eva-css setup${colors.reset} for full project setup with build scripts\n`);
347
+
348
+ log(`${colors.dim}Documentation: https://github.com/nkdeus/eva/blob/main/packages/eva-css/README.md${colors.reset}\n`);
349
+
350
+ } catch (err) {
351
+ error(`Failed to initialize: ${err.message}`);
352
+ process.exit(1);
353
+ }
354
+ }
355
+
356
+ /**
357
+ * eva-css setup command
358
+ * Complete project setup with workflow choice
359
+ */
360
+ async function setupCommand() {
361
+ try {
362
+ title('🚀 EVA CSS Project Setup');
363
+
364
+ // Choose workflow
365
+ log('');
366
+ const workflow = await select('Choose your workflow:', [
367
+ {
368
+ label: 'SCSS Variables',
369
+ value: 'scss',
370
+ description: 'Simple, works with npx sass directly'
371
+ },
372
+ {
373
+ label: 'JSON Config',
374
+ value: 'json',
375
+ description: 'Centralized config, requires build script'
376
+ }
377
+ ]);
378
+
379
+ log('');
380
+ info('Configure your design system:\n');
381
+
382
+ const sizesInput = await prompt('Design sizes (comma-separated) [4, 8, 16, 32, 64, 128]:');
383
+ const sizes = sizesInput ? sizesInput.split(',').map(s => parseInt(s.trim())) : [4, 8, 16, 32, 64, 128];
384
+
385
+ const fontSizesInput = await prompt('Font sizes (comma-separated) [14, 16, 20, 24, 32, 48]:');
386
+ const fontSizes = fontSizesInput ? fontSizesInput.split(',').map(s => parseInt(s.trim())) : [14, 16, 20, 24, 32, 48];
387
+
388
+ const buildClass = await confirm('Generate utility classes?', true);
389
+ const debug = await confirm('Enable debug mode?', false);
390
+
391
+ log('\n📁 Setting up project files...\n');
392
+
393
+ // Create directories
394
+ if (!fs.existsSync('styles')) {
395
+ fs.mkdirSync('styles', { recursive: true });
396
+ success('Created styles/');
397
+ }
398
+
399
+ if (!fs.existsSync('dist')) {
400
+ fs.mkdirSync('dist', { recursive: true });
401
+ success('Created dist/');
402
+ }
403
+
404
+ if (workflow === 'json') {
405
+ // JSON Config workflow
406
+
407
+ // 1. Create eva.config.cjs
408
+ const configContent = generateEvaConfig({ sizes, fontSizes, buildClass, debug, workflow });
409
+ fs.writeFileSync('eva.config.cjs', configContent);
410
+ success('Created eva.config.cjs');
411
+
412
+ // 2. Create build script
413
+ if (!fs.existsSync('scripts')) {
414
+ fs.mkdirSync('scripts', { recursive: true });
415
+ }
416
+ fs.writeFileSync('scripts/build.js', generateBuildScript());
417
+ success('Created scripts/build.js');
418
+
419
+ // 3. Create clean SCSS (no config inline)
420
+ const scssContent = `// EVA CSS
421
+ // Configuration is loaded from eva.config.cjs
422
+
423
+ @use 'eva-css/index';
424
+
425
+ // Your custom styles here
426
+
427
+ body {
428
+ margin: 0;
429
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
430
+ transition: background 0.3s, color 0.3s;
431
+ }
432
+ `;
433
+ fs.writeFileSync('styles/main.scss', scssContent);
434
+ success('Created styles/main.scss');
435
+
436
+ // 4. Update or create package.json scripts
437
+ const packageJsonPath = 'package.json';
438
+ let packageJson = {};
439
+
440
+ if (fs.existsSync(packageJsonPath)) {
441
+ packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
442
+ } else {
443
+ packageJson = {
444
+ name: path.basename(process.cwd()),
445
+ version: '1.0.0',
446
+ private: true
447
+ };
448
+ }
449
+
450
+ packageJson.scripts = packageJson.scripts || {};
451
+ packageJson.scripts.build = 'node scripts/build.js styles/main.scss dist/main.css';
452
+ packageJson.scripts.watch = 'nodemon --watch styles --watch eva.config.cjs --ext scss,cjs --exec "npm run build"';
453
+ packageJson.scripts.validate = 'eva-css validate';
454
+
455
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
456
+ success('Updated package.json scripts');
457
+
458
+ // Success message
459
+ title('✅ JSON Config Workflow Setup Complete!');
460
+
461
+ log(`${colors.bright}Next steps:${colors.reset}\n`);
462
+ log(` ${colors.dim}1.${colors.reset} Install dependencies: ${colors.cyan}npm install --save-dev sass nodemon${colors.reset}`);
463
+ log(` ${colors.dim}2.${colors.reset} Validate config: ${colors.cyan}npm run validate${colors.reset}`);
464
+ log(` ${colors.dim}3.${colors.reset} Build CSS: ${colors.cyan}npm run build${colors.reset}`);
465
+ log(` ${colors.dim}4.${colors.reset} Watch mode: ${colors.cyan}npm run watch${colors.reset}\n`);
466
+
467
+ } else {
468
+ // SCSS Variables workflow
469
+
470
+ // Create SCSS with inline config
471
+ const scssContent = `// EVA CSS - SCSS Variables Configuration
472
+
473
+ @use 'eva-css/index' with (
474
+ // Design sizes from your design system
475
+ $sizes: (${sizes.join(', ')}),
476
+
477
+ // Font sizes for typography
478
+ $font-sizes: (${fontSizes.join(', ')}),
479
+
480
+ // Generate utility classes
481
+ $build-class: ${buildClass},
482
+
483
+ // Show debug info during build
484
+ $debug: ${debug}
485
+ );
486
+
487
+ // Your custom styles here
488
+
489
+ body {
490
+ margin: 0;
491
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
492
+ transition: background 0.3s, color 0.3s;
493
+ }
494
+ `;
495
+ fs.writeFileSync('styles/main.scss', scssContent);
496
+ success('Created styles/main.scss');
497
+
498
+ // Update or create package.json scripts
499
+ const packageJsonPath = 'package.json';
500
+ let packageJson = {};
501
+
502
+ if (fs.existsSync(packageJsonPath)) {
503
+ packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
504
+ } else {
505
+ packageJson = {
506
+ name: path.basename(process.cwd()),
507
+ version: '1.0.0',
508
+ private: true
509
+ };
510
+ }
511
+
512
+ packageJson.scripts = packageJson.scripts || {};
513
+ packageJson.scripts.build = 'sass --load-path=node_modules styles/main.scss:dist/main.css';
514
+ packageJson.scripts.watch = 'sass --watch --load-path=node_modules styles/main.scss:dist/main.css';
515
+
516
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
517
+ success('Updated package.json scripts');
518
+
519
+ // Success message
520
+ title('✅ SCSS Variables Workflow Setup Complete!');
521
+
522
+ log(`${colors.bright}Next steps:${colors.reset}\n`);
523
+ log(` ${colors.dim}1.${colors.reset} Install Sass: ${colors.cyan}npm install --save-dev sass${colors.reset}`);
524
+ log(` ${colors.dim}2.${colors.reset} Build CSS: ${colors.cyan}npm run build${colors.reset}`);
525
+ log(` ${colors.dim}3.${colors.reset} Watch mode: ${colors.cyan}npm run watch${colors.reset}\n`);
526
+ }
527
+
528
+ log(`${colors.dim}Documentation: https://github.com/nkdeus/eva/blob/main/packages/eva-css/README.md${colors.reset}\n`);
529
+
530
+ } catch (err) {
531
+ error(`Setup failed: ${err.message}`);
532
+ process.exit(1);
533
+ }
534
+ }
535
+
536
+ module.exports = {
537
+ initCommand,
538
+ setupCommand
539
+ };