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/MIGRATION.md +337 -0
- package/README.md +441 -3
- package/cli.cjs +73 -0
- package/dist/eva.css +2133 -2093
- package/dist/eva.css.map +1 -1
- package/dist/eva.min.css +1 -1
- package/dist/eva.min.css.map +1 -1
- package/dist/test.css +5689 -0
- package/dist/test.css.map +1 -0
- package/eva.config.template.js +216 -0
- package/index.scss +9 -0
- package/package.json +85 -52
- package/scripts/build-with-config.cjs +169 -0
- package/src/_colors.scss +41 -6
- package/src/_config.scss +55 -0
- package/src/_eva.scss +84 -0
- package/src/cli-commands.cjs +539 -0
- package/src/colors-only.scss +16 -0
- package/src/config-loader.cjs +319 -0
- package/src/config-schema.cjs +455 -0
- package/src/core.scss +43 -0
- package/src/index.scss +5 -1
- package/src/variables.scss +33 -0
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
|
+
};
|