saha-ui 1.22.10 → 1.22.12
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/bin/cli.js +927 -200
- package/dist/components/Accordion/Accordion.d.ts +9 -0
- package/dist/components/Accordion/Accordion.d.ts.map +1 -0
- package/dist/components/Accordion/Accordion.js +324 -0
- package/dist/components/Accordion/Accordion.styles.d.ts +14 -0
- package/dist/components/Accordion/Accordion.styles.d.ts.map +1 -1
- package/dist/components/Accordion/Accordion.styles.js +83 -10
- package/dist/components/Accordion/Accordion.types.d.ts +108 -1
- package/dist/components/Accordion/Accordion.types.d.ts.map +1 -1
- package/dist/components/Accordion/index.d.ts +3 -6
- package/dist/components/Accordion/index.d.ts.map +1 -1
- package/dist/components/Accordion/index.js +7 -148
- package/dist/components/Affix/Affix.context.d.ts +15 -0
- package/dist/components/Affix/Affix.context.d.ts.map +1 -0
- package/dist/components/Affix/Affix.context.js +81 -0
- package/dist/components/Affix/Affix.d.ts +9 -0
- package/dist/components/Affix/Affix.d.ts.map +1 -0
- package/dist/components/Affix/Affix.hooks.d.ts +81 -0
- package/dist/components/Affix/Affix.hooks.d.ts.map +1 -0
- package/dist/components/Affix/Affix.hooks.js +278 -0
- package/dist/components/Affix/Affix.js +714 -0
- package/dist/components/Affix/Affix.styles.d.ts +14 -2
- package/dist/components/Affix/Affix.styles.d.ts.map +1 -1
- package/dist/components/Affix/Affix.styles.js +99 -28
- package/dist/components/Affix/Affix.types.d.ts +517 -45
- package/dist/components/Affix/Affix.types.d.ts.map +1 -1
- package/dist/components/Affix/Affix.utils.d.ts +89 -0
- package/dist/components/Affix/Affix.utils.d.ts.map +1 -0
- package/dist/components/Affix/Affix.utils.js +165 -0
- package/dist/components/Affix/index.d.ts +6 -47
- package/dist/components/Affix/index.d.ts.map +1 -1
- package/dist/components/Affix/index.js +47 -132
- package/dist/components/Alert/Alert.d.ts +5 -0
- package/dist/components/Alert/Alert.d.ts.map +1 -0
- package/dist/components/Alert/Alert.icons.d.ts +38 -0
- package/dist/components/Alert/Alert.icons.d.ts.map +1 -0
- package/dist/components/Alert/Alert.icons.js +165 -0
- package/dist/components/Alert/Alert.js +184 -0
- package/dist/components/Alert/Alert.styles.d.ts +24 -3
- package/dist/components/Alert/Alert.styles.d.ts.map +1 -1
- package/dist/components/Alert/Alert.styles.js +359 -54
- package/dist/components/Alert/Alert.types.d.ts +93 -28
- package/dist/components/Alert/Alert.types.d.ts.map +1 -1
- package/dist/components/Alert/AlertProvider.d.ts +6 -0
- package/dist/components/Alert/AlertProvider.d.ts.map +1 -0
- package/dist/components/Alert/AlertProvider.js +156 -0
- package/dist/components/Alert/index.d.ts +6 -4
- package/dist/components/Alert/index.d.ts.map +1 -1
- package/dist/components/Alert/index.js +20 -147
- package/dist/components/AppBar/AppBar.components.d.ts +88 -0
- package/dist/components/AppBar/AppBar.components.d.ts.map +1 -0
- package/dist/components/AppBar/AppBar.components.js +742 -0
- package/dist/components/AppBar/AppBar.context.d.ts +16 -0
- package/dist/components/AppBar/AppBar.context.d.ts.map +1 -0
- package/dist/components/AppBar/AppBar.context.js +37 -0
- package/dist/components/AppBar/AppBar.d.ts +10 -0
- package/dist/components/AppBar/AppBar.d.ts.map +1 -0
- package/dist/components/AppBar/AppBar.hooks.d.ts +49 -0
- package/dist/components/AppBar/AppBar.hooks.d.ts.map +1 -0
- package/dist/components/AppBar/AppBar.hooks.js +200 -0
- package/dist/components/AppBar/AppBar.js +486 -0
- package/dist/components/AppBar/AppBar.styles.d.ts +40 -3
- package/dist/components/AppBar/AppBar.styles.d.ts.map +1 -1
- package/dist/components/AppBar/AppBar.styles.js +476 -48
- package/dist/components/AppBar/AppBar.types.d.ts +529 -65
- package/dist/components/AppBar/AppBar.types.d.ts.map +1 -1
- package/dist/components/AppBar/index.d.ts +6 -56
- package/dist/components/AppBar/index.d.ts.map +1 -1
- package/dist/components/AppBar/index.js +42 -75
- package/dist/components/AspectRatio/AspectRatio.styles.d.ts +31 -6
- package/dist/components/AspectRatio/AspectRatio.styles.d.ts.map +1 -1
- package/dist/components/AspectRatio/AspectRatio.styles.js +157 -22
- package/dist/components/AspectRatio/AspectRatio.types.d.ts +220 -61
- package/dist/components/AspectRatio/AspectRatio.types.d.ts.map +1 -1
- package/dist/components/AspectRatio/LoadingIndicator.d.ts +36 -0
- package/dist/components/AspectRatio/LoadingIndicator.d.ts.map +1 -0
- package/dist/components/AspectRatio/LoadingIndicator.js +718 -0
- package/dist/components/AspectRatio/index.d.ts +3 -30
- package/dist/components/AspectRatio/index.d.ts.map +1 -1
- package/dist/components/AspectRatio/index.js +225 -65
- package/dist/components/Calendar/Calendar.styles.d.ts +1 -1
- package/dist/components/Carousel/Carousel.styles.d.ts +1 -1
- package/dist/components/Chart/charts/ComposedChartComponent.js +0 -1
- package/dist/components/Chart/components/ChartTooltip.js +0 -1
- package/dist/components/Checkbox/Checkbox.styles.d.ts +117 -4
- package/dist/components/Checkbox/Checkbox.styles.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.styles.js +482 -97
- package/dist/components/Checkbox/Checkbox.types.d.ts +174 -80
- package/dist/components/Checkbox/Checkbox.types.d.ts.map +1 -1
- package/dist/components/Checkbox/index.d.ts +9 -1
- package/dist/components/Checkbox/index.d.ts.map +1 -1
- package/dist/components/Checkbox/index.js +573 -228
- package/dist/components/DatePicker/DatePicker.styles.d.ts +2 -2
- package/dist/components/Dialog/Dialog.styles.d.ts +1 -1
- package/dist/components/Drawer/Drawer.styles.d.ts +1 -1
- package/dist/components/Form/Form.d.ts +83 -0
- package/dist/components/Form/Form.d.ts.map +1 -0
- package/dist/components/Form/Form.js +691 -0
- package/dist/components/Form/Form.styles.d.ts +34 -8
- package/dist/components/Form/Form.styles.d.ts.map +1 -1
- package/dist/components/Form/Form.styles.js +199 -113
- package/dist/components/Form/Form.types.d.ts +138 -164
- package/dist/components/Form/Form.types.d.ts.map +1 -1
- package/dist/components/Form/index.d.ts +2 -115
- package/dist/components/Form/index.d.ts.map +1 -1
- package/dist/components/Form/index.js +17 -336
- package/dist/components/HoverCard/HoverCard.styles.d.ts +1 -1
- package/dist/components/Input/index.d.ts +4 -39
- package/dist/components/Input/index.d.ts.map +1 -1
- package/dist/components/Input/index.js +123 -93
- package/dist/components/Item/index.js +1 -1
- package/dist/components/NavigationMenu/NavigationMenu.styles.d.ts +2 -2
- package/dist/components/Pagination/Pagination.styles.d.ts +1 -1
- package/dist/components/Rating/Rating.colors.d.ts +32 -0
- package/dist/components/Rating/Rating.colors.d.ts.map +1 -0
- package/dist/components/Rating/Rating.colors.js +149 -0
- package/dist/components/Rating/Rating.d.ts +10 -0
- package/dist/components/Rating/Rating.d.ts.map +1 -0
- package/dist/components/Rating/Rating.icons.d.ts +32 -0
- package/dist/components/Rating/Rating.icons.d.ts.map +1 -0
- package/dist/components/Rating/Rating.icons.js +209 -0
- package/dist/components/Rating/Rating.js +298 -0
- package/dist/components/Rating/Rating.styles.d.ts +18 -3
- package/dist/components/Rating/Rating.styles.d.ts.map +1 -1
- package/dist/components/Rating/Rating.styles.js +106 -65
- package/dist/components/Rating/Rating.types.d.ts +76 -13
- package/dist/components/Rating/Rating.types.d.ts.map +1 -1
- package/dist/components/Rating/index.d.ts +4 -16
- package/dist/components/Rating/index.d.ts.map +1 -1
- package/dist/components/Rating/index.js +11 -215
- package/dist/components/Resizable/Resizable.types.d.ts +7 -7
- package/dist/components/Resizable/Resizable.types.d.ts.map +1 -1
- package/dist/components/Resizable/index.d.ts +4 -4
- package/dist/components/Resizable/index.d.ts.map +1 -1
- package/dist/components/Resizable/index.js +53 -55
- package/dist/components/Skeleton/Skeleton.styles.d.ts +1 -1
- package/dist/components/Spinner/index.js +0 -1
- package/dist/components/Tab/Tab.styles.d.ts +2 -2
- package/dist/components/Table/Table.styles.d.ts +1 -1
- package/dist/components/Timeline/Timeline.styles.d.ts +2 -2
- package/dist/components/Toast/Toast.styles.d.ts +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/useAccordion.d.ts +85 -20
- package/dist/hooks/useAccordion.d.ts.map +1 -1
- package/dist/hooks/useAccordion.js +141 -27
- package/dist/hooks/useAlert.d.ts +4 -0
- package/dist/hooks/useAlert.d.ts.map +1 -0
- package/dist/hooks/useAlert.js +14 -0
- package/dist/hooks/useAnimatedHeight.d.ts +51 -0
- package/dist/hooks/useAnimatedHeight.d.ts.map +1 -0
- package/dist/hooks/useAnimatedHeight.js +58 -0
- package/dist/hooks/useAspectRatio.d.ts +5 -81
- package/dist/hooks/useAspectRatio.d.ts.map +1 -1
- package/dist/hooks/useAspectRatio.js +177 -44
- package/dist/hooks/useLazyMount.d.ts +49 -0
- package/dist/hooks/useLazyMount.d.ts.map +1 -0
- package/dist/hooks/useLazyMount.js +37 -0
- package/dist/hooks/useMergedRef.d.ts +23 -0
- package/dist/hooks/useMergedRef.d.ts.map +1 -0
- package/dist/hooks/useMergedRef.js +22 -0
- package/dist/index.d.ts +18 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +988 -936
- package/dist/lib/Slot.d.ts +30 -1
- package/dist/lib/Slot.d.ts.map +1 -1
- package/dist/lib/Slot.js +20 -17
- package/package.json +21 -20
package/bin/cli.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { execSync } from "node:child_process";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
+
import readline from "node:readline";
|
|
7
8
|
|
|
8
9
|
const R = process.cwd();
|
|
9
10
|
const a = process.argv.slice(2);
|
|
@@ -18,6 +19,464 @@ const wr = (f, s) => {
|
|
|
18
19
|
const fE = (f) => fs.existsSync(f) && fs.statSync(f).isFile();
|
|
19
20
|
const dE = (d) => fs.existsSync(d) && fs.statSync(d).isDirectory();
|
|
20
21
|
|
|
22
|
+
// ============================================
|
|
23
|
+
// PROMPT UTILITY
|
|
24
|
+
// ============================================
|
|
25
|
+
const prompt = (question) => {
|
|
26
|
+
const rl = readline.createInterface({
|
|
27
|
+
input: process.stdin,
|
|
28
|
+
output: process.stdout,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return new Promise((resolve) => {
|
|
32
|
+
rl.question(question, (answer) => {
|
|
33
|
+
rl.close();
|
|
34
|
+
resolve(answer.trim().toLowerCase());
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const confirmPrompt = async (question) => {
|
|
40
|
+
const answer = await prompt(`${question} (y/n): `);
|
|
41
|
+
return answer === "y" || answer === "yes";
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const selectPrompt = async (question, options) => {
|
|
45
|
+
console.log(`\n${question}`);
|
|
46
|
+
options.forEach((opt, idx) => {
|
|
47
|
+
console.log(` ${idx + 1}) ${opt.label}`);
|
|
48
|
+
});
|
|
49
|
+
const answer = await prompt("Enter your choice (1/2/3): ");
|
|
50
|
+
const idx = parseInt(answer, 10) - 1;
|
|
51
|
+
return options[ idx ]?.value || options[ 0 ].value;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// ============================================
|
|
55
|
+
// CSS PARSING UTILITIES
|
|
56
|
+
// ============================================
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Extract CSS block content (handles nested braces)
|
|
60
|
+
*/
|
|
61
|
+
const extractBlock = (css, startPattern) => {
|
|
62
|
+
const match = css.match(startPattern);
|
|
63
|
+
if (!match) return null;
|
|
64
|
+
|
|
65
|
+
const startIdx = match.index + match[ 0 ].length;
|
|
66
|
+
let braceCount = 1;
|
|
67
|
+
let endIdx = startIdx;
|
|
68
|
+
|
|
69
|
+
while (braceCount > 0 && endIdx < css.length) {
|
|
70
|
+
if (css[ endIdx ] === "{") braceCount++;
|
|
71
|
+
if (css[ endIdx ] === "}") braceCount--;
|
|
72
|
+
endIdx++;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
fullMatch: css.substring(match.index, endIdx),
|
|
77
|
+
content: css.substring(startIdx, endIdx - 1).trim(),
|
|
78
|
+
startIndex: match.index,
|
|
79
|
+
endIndex: endIdx,
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Parse CSS variables from a block
|
|
85
|
+
*/
|
|
86
|
+
const parseCSSVariables = (content) => {
|
|
87
|
+
const variables = {};
|
|
88
|
+
const varRegex = /--([\w-]+)\s*:\s*([^;]+);/g;
|
|
89
|
+
let match;
|
|
90
|
+
|
|
91
|
+
while ((match = varRegex.exec(content)) !== null) {
|
|
92
|
+
variables[ `--${match[ 1 ]}` ] = match[ 2 ].trim();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return variables;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Parse @keyframes from CSS
|
|
100
|
+
*/
|
|
101
|
+
const parseKeyframes = (css) => {
|
|
102
|
+
const keyframes = {};
|
|
103
|
+
const keyframeRegex = /@keyframes\s+([\w-]+)\s*\{/g;
|
|
104
|
+
let match;
|
|
105
|
+
|
|
106
|
+
while ((match = keyframeRegex.exec(css)) !== null) {
|
|
107
|
+
const name = match[ 1 ];
|
|
108
|
+
const block = extractBlock(css.substring(match.index), /@keyframes\s+[\w-]+\s*\{/);
|
|
109
|
+
if (block) {
|
|
110
|
+
keyframes[ name ] = block.fullMatch;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return keyframes;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Detect existing CSS structures
|
|
119
|
+
*/
|
|
120
|
+
const detectExistingStructures = (css) => {
|
|
121
|
+
return {
|
|
122
|
+
hasRoot: /:root\s*\{/.test(css),
|
|
123
|
+
hasDark: /\.dark\s*\{/.test(css),
|
|
124
|
+
hasThemeInline: /@theme\s+inline\s*\{/.test(css),
|
|
125
|
+
hasLayerBase: /@layer\s+base\s*\{/.test(css),
|
|
126
|
+
hasLayerComponents: /@layer\s+components\s*\{/.test(css),
|
|
127
|
+
hasLayerUtilities: /@layer\s+utilities\s*\{/.test(css),
|
|
128
|
+
hasCustomVariant: /@custom-variant\s+dark/.test(css),
|
|
129
|
+
hasTailwindImport: /@import\s+["']tailwindcss["']/.test(css),
|
|
130
|
+
hasTailwindDirectives: /@tailwind\s+(base|components|utilities)/.test(css),
|
|
131
|
+
hasKeyframes: /@keyframes/.test(css),
|
|
132
|
+
hasGlassClass: /\.glass\s*\{/.test(css),
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Extract :root variables from CSS
|
|
138
|
+
*/
|
|
139
|
+
const extractRootVariables = (css) => {
|
|
140
|
+
const block = extractBlock(css, /:root\s*\{/);
|
|
141
|
+
return block ? parseCSSVariables(block.content) : {};
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Extract .dark variables from CSS
|
|
146
|
+
*/
|
|
147
|
+
const extractDarkVariables = (css) => {
|
|
148
|
+
const block = extractBlock(css, /\.dark\s*\{/);
|
|
149
|
+
return block ? parseCSSVariables(block.content) : {};
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Merge CSS variables (add missing from source to target)
|
|
154
|
+
*/
|
|
155
|
+
const mergeVariables = (existing, incoming) => {
|
|
156
|
+
const merged = { ...existing };
|
|
157
|
+
let addedCount = 0;
|
|
158
|
+
|
|
159
|
+
for (const [ key, value ] of Object.entries(incoming)) {
|
|
160
|
+
if (!(key in merged)) {
|
|
161
|
+
merged[ key ] = value;
|
|
162
|
+
addedCount++;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { merged, addedCount };
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Generate CSS variable block string
|
|
171
|
+
*/
|
|
172
|
+
const generateVariableBlock = (variables, indent = " ") => {
|
|
173
|
+
return Object.entries(variables)
|
|
174
|
+
.map(([ key, value ]) => `${indent}${key}: ${value};`)
|
|
175
|
+
.join("\n");
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Replace or update :root block in CSS
|
|
180
|
+
*/
|
|
181
|
+
const updateRootBlock = (css, newVariables, mode = "merge") => {
|
|
182
|
+
const block = extractBlock(css, /:root\s*\{/);
|
|
183
|
+
|
|
184
|
+
if (!block) {
|
|
185
|
+
// No existing :root, add new one
|
|
186
|
+
const newBlock = `:root {\n${generateVariableBlock(newVariables)}\n}`;
|
|
187
|
+
return { css: `${newBlock}\n\n${css}`, added: Object.keys(newVariables).length };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (mode === "replace") {
|
|
191
|
+
const newBlock = `:root {\n${generateVariableBlock(newVariables)}\n}`;
|
|
192
|
+
return {
|
|
193
|
+
css: css.substring(0, block.startIndex) + newBlock + css.substring(block.endIndex),
|
|
194
|
+
added: Object.keys(newVariables).length,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Merge mode
|
|
199
|
+
const existingVars = parseCSSVariables(block.content);
|
|
200
|
+
const { merged, addedCount } = mergeVariables(existingVars, newVariables);
|
|
201
|
+
const newBlock = `:root {\n${generateVariableBlock(merged)}\n}`;
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
css: css.substring(0, block.startIndex) + newBlock + css.substring(block.endIndex),
|
|
205
|
+
added: addedCount,
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Replace or update .dark block in CSS
|
|
211
|
+
*/
|
|
212
|
+
const updateDarkBlock = (css, newVariables, mode = "merge") => {
|
|
213
|
+
const block = extractBlock(css, /\.dark\s*\{/);
|
|
214
|
+
|
|
215
|
+
if (!block) {
|
|
216
|
+
// No existing .dark, add new one
|
|
217
|
+
const newBlock = `.dark {\n${generateVariableBlock(newVariables)}\n}`;
|
|
218
|
+
// Insert after :root if exists
|
|
219
|
+
const rootBlock = extractBlock(css, /:root\s*\{/);
|
|
220
|
+
if (rootBlock) {
|
|
221
|
+
return {
|
|
222
|
+
css: css.substring(0, rootBlock.endIndex) + "\n\n" + newBlock + css.substring(rootBlock.endIndex),
|
|
223
|
+
added: Object.keys(newVariables).length,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return { css: `${newBlock}\n\n${css}`, added: Object.keys(newVariables).length };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (mode === "replace") {
|
|
230
|
+
const newBlock = `.dark {\n${generateVariableBlock(newVariables)}\n}`;
|
|
231
|
+
return {
|
|
232
|
+
css: css.substring(0, block.startIndex) + newBlock + css.substring(block.endIndex),
|
|
233
|
+
added: Object.keys(newVariables).length,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Merge mode
|
|
238
|
+
const existingVars = parseCSSVariables(block.content);
|
|
239
|
+
const { merged, addedCount } = mergeVariables(existingVars, newVariables);
|
|
240
|
+
const newBlock = `.dark {\n${generateVariableBlock(merged)}\n}`;
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
css: css.substring(0, block.startIndex) + newBlock + css.substring(block.endIndex),
|
|
244
|
+
added: addedCount,
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Merge keyframes (add missing)
|
|
250
|
+
*/
|
|
251
|
+
const mergeKeyframes = (css, incomingKeyframes) => {
|
|
252
|
+
const existingKeyframes = parseKeyframes(css);
|
|
253
|
+
let updatedCss = css;
|
|
254
|
+
let addedCount = 0;
|
|
255
|
+
|
|
256
|
+
const newKeyframes = [];
|
|
257
|
+
for (const [ name, keyframe ] of Object.entries(incomingKeyframes)) {
|
|
258
|
+
if (!(name in existingKeyframes)) {
|
|
259
|
+
newKeyframes.push(keyframe);
|
|
260
|
+
addedCount++;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (newKeyframes.length > 0) {
|
|
265
|
+
// Add new keyframes at the end of @layer utilities or at the end of file
|
|
266
|
+
const utilitiesBlock = extractBlock(css, /@layer\s+utilities\s*\{/);
|
|
267
|
+
if (utilitiesBlock) {
|
|
268
|
+
const insertPoint = utilitiesBlock.endIndex - 1;
|
|
269
|
+
const keyframesStr = "\n\n" + newKeyframes.join("\n\n") + "\n";
|
|
270
|
+
updatedCss = css.substring(0, insertPoint) + keyframesStr + css.substring(insertPoint);
|
|
271
|
+
} else {
|
|
272
|
+
updatedCss = css + "\n\n" + newKeyframes.join("\n\n");
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return { css: updatedCss, added: addedCount };
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// ============================================
|
|
280
|
+
// SAHA-UI CSS VARIABLES (extracted from your CSS)
|
|
281
|
+
// ============================================
|
|
282
|
+
const SAHA_UI_ROOT_VARIABLES = {
|
|
283
|
+
"--radius": "0.625rem",
|
|
284
|
+
"--background": "oklch(0.98 0.003 200)",
|
|
285
|
+
"--foreground": "oklch(0.15 0.01 200)",
|
|
286
|
+
"--card": "oklch(1 0 0)",
|
|
287
|
+
"--card-foreground": "oklch(0.15 0.01 200)",
|
|
288
|
+
"--popover": "oklch(1 0 0)",
|
|
289
|
+
"--popover-foreground": "oklch(0.15 0.01 200)",
|
|
290
|
+
"--primary": "oklch(48.151% 0.23085 269.463)",
|
|
291
|
+
"--primary-foreground": "oklch(1 0 0)",
|
|
292
|
+
"--secondary": "oklch(0.65 0.25 340)",
|
|
293
|
+
"--secondary-foreground": "oklch(1 0 0)",
|
|
294
|
+
"--muted": "oklch(0.96 0.005 200)",
|
|
295
|
+
"--muted-foreground": "oklch(0.45 0.01 200)",
|
|
296
|
+
"--accent": "oklch(0.65 0.12 185)",
|
|
297
|
+
"--accent-foreground": "oklch(1 0 0)",
|
|
298
|
+
"--success": "oklch(0.60 0.15 145)",
|
|
299
|
+
"--success-foreground": "oklch(1 0 0)",
|
|
300
|
+
"--warning": "oklch(0.70 0.15 65)",
|
|
301
|
+
"--warning-foreground": "oklch(0.15 0.01 200)",
|
|
302
|
+
"--error": "oklch(0.60 0.20 25)",
|
|
303
|
+
"--error-foreground": "oklch(1 0 0)",
|
|
304
|
+
"--destructive": "oklch(0.60 0.20 25)",
|
|
305
|
+
"--destructive-foreground": "oklch(1 0 0)",
|
|
306
|
+
"--info": "oklch(0.60 0.15 250)",
|
|
307
|
+
"--info-foreground": "oklch(1 0 0)",
|
|
308
|
+
"--border": "oklch(0.92 0.005 200)",
|
|
309
|
+
"--input": "oklch(0.96 0.005 200)",
|
|
310
|
+
"--ring": "oklch(0.60 0.18 275)",
|
|
311
|
+
"--chart-1": "oklch(0.60 0.18 275)",
|
|
312
|
+
"--chart-2": "oklch(0.60 0.15 145)",
|
|
313
|
+
"--chart-3": "oklch(0.60 0.15 250)",
|
|
314
|
+
"--chart-4": "oklch(0.65 0.25 340)",
|
|
315
|
+
"--chart-5": "oklch(0.65 0.12 185)",
|
|
316
|
+
"--glass-bg": "oklch(1 0 0 / 0.25)",
|
|
317
|
+
"--glass-bg-hover": "oklch(1 0 0 / 0.35)",
|
|
318
|
+
"--glass-border": "oklch(0.60 0.18 275 / 0.15)",
|
|
319
|
+
"--glass-shadow": "0 8px 32px 0 oklch(0.60 0.18 275 / 0.12)",
|
|
320
|
+
"--glass-blur": "16px",
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
const SAHA_UI_DARK_VARIABLES = {
|
|
324
|
+
"--background": "oklch(0.08 0.005 200)",
|
|
325
|
+
"--foreground": "oklch(0.95 0.005 200)",
|
|
326
|
+
"--card": "oklch(0.12 0.01 200)",
|
|
327
|
+
"--card-foreground": "oklch(0.95 0.005 200)",
|
|
328
|
+
"--popover": "oklch(0.12 0.01 200)",
|
|
329
|
+
"--popover-foreground": "oklch(0.95 0.005 200)",
|
|
330
|
+
"--primary": "oklch(41.145% 0.14945 272.396)",
|
|
331
|
+
"--primary-foreground": "oklch(0.98 0.003 200)",
|
|
332
|
+
"--secondary": "oklch(0.70 0.25 340)",
|
|
333
|
+
"--secondary-foreground": "oklch(0.98 0.003 200)",
|
|
334
|
+
"--muted": "oklch(0.15 0.01 200)",
|
|
335
|
+
"--muted-foreground": "oklch(0.65 0.005 200)",
|
|
336
|
+
"--accent": "oklch(0.70 0.15 185)",
|
|
337
|
+
"--accent-foreground": "oklch(0.98 0.003 200)",
|
|
338
|
+
"--success": "oklch(0.65 0.18 145)",
|
|
339
|
+
"--success-foreground": "oklch(0.98 0.003 200)",
|
|
340
|
+
"--warning": "oklch(0.75 0.18 65)",
|
|
341
|
+
"--warning-foreground": "oklch(0.98 0.003 200)",
|
|
342
|
+
"--error": "oklch(0.65 0.22 25)",
|
|
343
|
+
"--error-foreground": "oklch(0.98 0.003 200)",
|
|
344
|
+
"--destructive": "oklch(0.65 0.22 25)",
|
|
345
|
+
"--destructive-foreground": "oklch(0.98 0.003 200)",
|
|
346
|
+
"--info": "oklch(0.65 0.18 250)",
|
|
347
|
+
"--info-foreground": "oklch(0.98 0.003 200)",
|
|
348
|
+
"--border": "oklch(0.20 0.01 200)",
|
|
349
|
+
"--input": "oklch(0.15 0.01 200)",
|
|
350
|
+
"--ring": "oklch(0.68 0.20 275)",
|
|
351
|
+
"--chart-1": "oklch(0.68 0.20 275)",
|
|
352
|
+
"--chart-2": "oklch(0.65 0.18 145)",
|
|
353
|
+
"--chart-3": "oklch(0.65 0.18 250)",
|
|
354
|
+
"--chart-4": "oklch(0.70 0.25 340)",
|
|
355
|
+
"--chart-5": "oklch(0.70 0.15 185)",
|
|
356
|
+
"--glass-bg": "oklch(0.12 0.01 200 / 0.5)",
|
|
357
|
+
"--glass-bg-hover": "oklch(0.12 0.01 200 / 0.7)",
|
|
358
|
+
"--glass-border": "oklch(0.68 0.20 275 / 0.2)",
|
|
359
|
+
"--glass-shadow": "0 8px 32px 0 oklch(0 0 0 / 0.6)",
|
|
360
|
+
"--glass-blur": "16px",
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const SAHA_UI_KEYFRAMES = {
|
|
364
|
+
"gradient-x": `@keyframes gradient-x {
|
|
365
|
+
0%, 100% {
|
|
366
|
+
background-position: 0% 50%;
|
|
367
|
+
}
|
|
368
|
+
50% {
|
|
369
|
+
background-position: 100% 50%;
|
|
370
|
+
}
|
|
371
|
+
}`,
|
|
372
|
+
"draw-circle": `@keyframes draw-circle {
|
|
373
|
+
to {
|
|
374
|
+
stroke-dashoffset: 0;
|
|
375
|
+
}
|
|
376
|
+
}`,
|
|
377
|
+
"draw-check": `@keyframes draw-check {
|
|
378
|
+
to {
|
|
379
|
+
stroke-dashoffset: 0;
|
|
380
|
+
}
|
|
381
|
+
}`,
|
|
382
|
+
"draw-x": `@keyframes draw-x {
|
|
383
|
+
to {
|
|
384
|
+
stroke-dashoffset: 0;
|
|
385
|
+
}
|
|
386
|
+
}`,
|
|
387
|
+
"shake": `@keyframes shake {
|
|
388
|
+
0%, 100% {
|
|
389
|
+
transform: translateX(0);
|
|
390
|
+
}
|
|
391
|
+
25% {
|
|
392
|
+
transform: translateX(-2px);
|
|
393
|
+
}
|
|
394
|
+
75% {
|
|
395
|
+
transform: translateX(2px);
|
|
396
|
+
}
|
|
397
|
+
}`,
|
|
398
|
+
"bounce-in": `@keyframes bounce-in {
|
|
399
|
+
0% {
|
|
400
|
+
transform: scale(0);
|
|
401
|
+
opacity: 0;
|
|
402
|
+
}
|
|
403
|
+
50% {
|
|
404
|
+
transform: scale(1.2);
|
|
405
|
+
}
|
|
406
|
+
100% {
|
|
407
|
+
transform: scale(1);
|
|
408
|
+
opacity: 1;
|
|
409
|
+
}
|
|
410
|
+
}`,
|
|
411
|
+
"jelly": `@keyframes jelly {
|
|
412
|
+
0% { transform: scale(1, 1); }
|
|
413
|
+
30% { transform: scale(1.25, 0.75); }
|
|
414
|
+
40% { transform: scale(0.75, 1.25); }
|
|
415
|
+
50% { transform: scale(1.15, 0.85); }
|
|
416
|
+
65% { transform: scale(0.95, 1.05); }
|
|
417
|
+
75% { transform: scale(1.05, 0.95); }
|
|
418
|
+
100% { transform: scale(1, 1); }
|
|
419
|
+
}`,
|
|
420
|
+
"rubber-band": `@keyframes rubber-band {
|
|
421
|
+
0% { transform: scale(1); }
|
|
422
|
+
30% { transform: scale(1.25, 0.75); }
|
|
423
|
+
40% { transform: scale(0.75, 1.25); }
|
|
424
|
+
50% { transform: scale(1.15, 0.85); }
|
|
425
|
+
65% { transform: scale(0.95, 1.05); }
|
|
426
|
+
75% { transform: scale(1.05, 0.95); }
|
|
427
|
+
100% { transform: scale(1); }
|
|
428
|
+
}`,
|
|
429
|
+
"swing": `@keyframes swing {
|
|
430
|
+
20% { transform: rotate(15deg); }
|
|
431
|
+
40% { transform: rotate(-10deg); }
|
|
432
|
+
60% { transform: rotate(5deg); }
|
|
433
|
+
80% { transform: rotate(-5deg); }
|
|
434
|
+
100% { transform: rotate(0deg); }
|
|
435
|
+
}`,
|
|
436
|
+
"tada": `@keyframes tada {
|
|
437
|
+
0% { transform: scale(1); }
|
|
438
|
+
10%, 20% { transform: scale(0.9) rotate(-3deg); }
|
|
439
|
+
30%, 50%, 70%, 90% { transform: scale(1.1) rotate(3deg); }
|
|
440
|
+
40%, 60%, 80% { transform: scale(1.1) rotate(-3deg); }
|
|
441
|
+
100% { transform: scale(1) rotate(0); }
|
|
442
|
+
}`,
|
|
443
|
+
"heartbeat": `@keyframes heartbeat {
|
|
444
|
+
0% { transform: scale(1); }
|
|
445
|
+
14% { transform: scale(1.3); }
|
|
446
|
+
28% { transform: scale(1); }
|
|
447
|
+
42% { transform: scale(1.3); }
|
|
448
|
+
70% { transform: scale(1); }
|
|
449
|
+
}`,
|
|
450
|
+
"progress-stripes": `@keyframes progress-stripes {
|
|
451
|
+
0% { background-position: 0 0; }
|
|
452
|
+
100% { background-position: 1.5rem 0; }
|
|
453
|
+
}`,
|
|
454
|
+
"progress-indeterminate": `@keyframes progress-indeterminate {
|
|
455
|
+
0% { left: -40%; transform: scaleX(0.6); }
|
|
456
|
+
50% { transform: scaleX(1); }
|
|
457
|
+
100% { left: 100%; transform: scaleX(0.6); }
|
|
458
|
+
}`,
|
|
459
|
+
"progress-shimmer": `@keyframes progress-shimmer {
|
|
460
|
+
0% { transform: translateX(-100%) scaleX(0); opacity: 0; }
|
|
461
|
+
10% { opacity: 1; }
|
|
462
|
+
50% { transform: translateX(0%) scaleX(1); }
|
|
463
|
+
90% { opacity: 1; }
|
|
464
|
+
100% { transform: translateX(100%) scaleX(0); opacity: 0; }
|
|
465
|
+
}`,
|
|
466
|
+
"progress-glow-pulse": `@keyframes progress-glow-pulse {
|
|
467
|
+
0%, 100% { filter: brightness(1) saturate(1); }
|
|
468
|
+
50% { filter: brightness(1.15) saturate(1.2); }
|
|
469
|
+
}`,
|
|
470
|
+
"collapsible-down": `@keyframes collapsible-down {
|
|
471
|
+
from { height: 0; opacity: 0; }
|
|
472
|
+
to { height: var(--radix-collapsible-content-height); opacity: 1; }
|
|
473
|
+
}`,
|
|
474
|
+
"collapsible-up": `@keyframes collapsible-up {
|
|
475
|
+
from { height: var(--radix-collapsible-content-height); opacity: 1; }
|
|
476
|
+
to { height: 0; opacity: 0; }
|
|
477
|
+
}`,
|
|
478
|
+
};
|
|
479
|
+
|
|
21
480
|
// package.json
|
|
22
481
|
const P = (() => {
|
|
23
482
|
try {
|
|
@@ -206,7 +665,7 @@ const pick = () => {
|
|
|
206
665
|
const M = "/* saha-ui */";
|
|
207
666
|
const TW = /@import\s+["']tailwindcss["'];?/;
|
|
208
667
|
|
|
209
|
-
// CSS for Tailwind v4
|
|
668
|
+
// Full CSS for Tailwind v4 (when doing full replace or fresh install)
|
|
210
669
|
const CSS_V4 = `@import "tailwindcss";
|
|
211
670
|
|
|
212
671
|
@custom-variant dark (&:is(.dark *));
|
|
@@ -441,112 +900,228 @@ const CSS_V4 = `@import "tailwindcss";
|
|
|
441
900
|
}
|
|
442
901
|
|
|
443
902
|
@layer utilities {
|
|
903
|
+
@keyframes gradient-x {
|
|
904
|
+
0%, 100% { background-position: 0% 50%; }
|
|
905
|
+
50% { background-position: 100% 50%; }
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
@keyframes draw-circle {
|
|
909
|
+
to { stroke-dashoffset: 0; }
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
@keyframes draw-check {
|
|
913
|
+
to { stroke-dashoffset: 0; }
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
@keyframes draw-x {
|
|
917
|
+
to { stroke-dashoffset: 0; }
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
@keyframes shake {
|
|
921
|
+
0%, 100% { transform: translateX(0); }
|
|
922
|
+
25% { transform: translateX(-2px); }
|
|
923
|
+
75% { transform: translateX(2px); }
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
@keyframes bounce-in {
|
|
927
|
+
0% { transform: scale(0); opacity: 0; }
|
|
928
|
+
50% { transform: scale(1.2); }
|
|
929
|
+
100% { transform: scale(1); opacity: 1; }
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
@keyframes jelly {
|
|
933
|
+
0% { transform: scale(1, 1); }
|
|
934
|
+
30% { transform: scale(1.25, 0.75); }
|
|
935
|
+
40% { transform: scale(0.75, 1.25); }
|
|
936
|
+
50% { transform: scale(1.15, 0.85); }
|
|
937
|
+
65% { transform: scale(0.95, 1.05); }
|
|
938
|
+
75% { transform: scale(1.05, 0.95); }
|
|
939
|
+
100% { transform: scale(1, 1); }
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
@keyframes rubber-band {
|
|
943
|
+
0% { transform: scale(1); }
|
|
944
|
+
30% { transform: scale(1.25, 0.75); }
|
|
945
|
+
40% { transform: scale(0.75, 1.25); }
|
|
946
|
+
50% { transform: scale(1.15, 0.85); }
|
|
947
|
+
65% { transform: scale(0.95, 1.05); }
|
|
948
|
+
75% { transform: scale(1.05, 0.95); }
|
|
949
|
+
100% { transform: scale(1); }
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
@keyframes swing {
|
|
953
|
+
20% { transform: rotate(15deg); }
|
|
954
|
+
40% { transform: rotate(-10deg); }
|
|
955
|
+
60% { transform: rotate(5deg); }
|
|
956
|
+
80% { transform: rotate(-5deg); }
|
|
957
|
+
100% { transform: rotate(0deg); }
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
@keyframes tada {
|
|
961
|
+
0% { transform: scale(1); }
|
|
962
|
+
10%, 20% { transform: scale(0.9) rotate(-3deg); }
|
|
963
|
+
30%, 50%, 70%, 90% { transform: scale(1.1) rotate(3deg); }
|
|
964
|
+
40%, 60%, 80% { transform: scale(1.1) rotate(-3deg); }
|
|
965
|
+
100% { transform: scale(1) rotate(0); }
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
@keyframes heartbeat {
|
|
969
|
+
0% { transform: scale(1); }
|
|
970
|
+
14% { transform: scale(1.3); }
|
|
971
|
+
28% { transform: scale(1); }
|
|
972
|
+
42% { transform: scale(1.3); }
|
|
973
|
+
70% { transform: scale(1); }
|
|
974
|
+
}
|
|
975
|
+
|
|
444
976
|
@keyframes progress-stripes {
|
|
445
|
-
0% {
|
|
446
|
-
|
|
447
|
-
}
|
|
448
|
-
100% {
|
|
449
|
-
background-position: 1.5rem 0;
|
|
450
|
-
}
|
|
977
|
+
0% { background-position: 0 0; }
|
|
978
|
+
100% { background-position: 1.5rem 0; }
|
|
451
979
|
}
|
|
452
|
-
|
|
980
|
+
|
|
453
981
|
@keyframes progress-indeterminate {
|
|
454
|
-
0% {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
458
|
-
50% {
|
|
459
|
-
transform: scaleX(1);
|
|
460
|
-
}
|
|
461
|
-
100% {
|
|
462
|
-
left: 100%;
|
|
463
|
-
transform: scaleX(0.6);
|
|
464
|
-
}
|
|
982
|
+
0% { left: -40%; transform: scaleX(0.6); }
|
|
983
|
+
50% { transform: scaleX(1); }
|
|
984
|
+
100% { left: 100%; transform: scaleX(0.6); }
|
|
465
985
|
}
|
|
466
|
-
|
|
986
|
+
|
|
467
987
|
@keyframes progress-shimmer {
|
|
468
|
-
0% {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
opacity: 1;
|
|
474
|
-
}
|
|
475
|
-
50% {
|
|
476
|
-
transform: translateX(0%) scaleX(1);
|
|
477
|
-
}
|
|
478
|
-
90% {
|
|
479
|
-
opacity: 1;
|
|
480
|
-
}
|
|
481
|
-
100% {
|
|
482
|
-
transform: translateX(100%) scaleX(0);
|
|
483
|
-
opacity: 0;
|
|
484
|
-
}
|
|
988
|
+
0% { transform: translateX(-100%) scaleX(0); opacity: 0; }
|
|
989
|
+
10% { opacity: 1; }
|
|
990
|
+
50% { transform: translateX(0%) scaleX(1); }
|
|
991
|
+
90% { opacity: 1; }
|
|
992
|
+
100% { transform: translateX(100%) scaleX(0); opacity: 0; }
|
|
485
993
|
}
|
|
486
|
-
|
|
994
|
+
|
|
487
995
|
@keyframes progress-glow-pulse {
|
|
488
|
-
0%, 100% {
|
|
489
|
-
|
|
490
|
-
}
|
|
491
|
-
50% {
|
|
492
|
-
filter: brightness(1.15) saturate(1.2);
|
|
493
|
-
}
|
|
996
|
+
0%, 100% { filter: brightness(1) saturate(1); }
|
|
997
|
+
50% { filter: brightness(1.15) saturate(1.2); }
|
|
494
998
|
}
|
|
495
|
-
|
|
999
|
+
|
|
496
1000
|
@keyframes collapsible-down {
|
|
497
|
-
from {
|
|
498
|
-
|
|
499
|
-
opacity: 0;
|
|
500
|
-
}
|
|
501
|
-
to {
|
|
502
|
-
height: var(--radix-collapsible-content-height);
|
|
503
|
-
opacity: 1;
|
|
504
|
-
}
|
|
1001
|
+
from { height: 0; opacity: 0; }
|
|
1002
|
+
to { height: var(--radix-collapsible-content-height); opacity: 1; }
|
|
505
1003
|
}
|
|
506
|
-
|
|
1004
|
+
|
|
507
1005
|
@keyframes collapsible-up {
|
|
508
|
-
from {
|
|
509
|
-
|
|
510
|
-
opacity: 1;
|
|
511
|
-
}
|
|
512
|
-
to {
|
|
513
|
-
height: 0;
|
|
514
|
-
opacity: 0;
|
|
515
|
-
}
|
|
1006
|
+
from { height: var(--radix-collapsible-content-height); opacity: 1; }
|
|
1007
|
+
to { height: 0; opacity: 0; }
|
|
516
1008
|
}
|
|
517
|
-
|
|
1009
|
+
/* Progress bar animation */
|
|
1010
|
+
@keyframes progress-indeterminate {
|
|
1011
|
+
0% {
|
|
1012
|
+
transform: translateX(-100%);
|
|
1013
|
+
}
|
|
1014
|
+
100% {
|
|
1015
|
+
transform: translateX(400%);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
.animate-progress-indeterminate {
|
|
1020
|
+
animation: progress-indeterminate 1.5s ease-in-out infinite;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/* Tailwind animate-in classes (if not using tailwindcss-animate) */
|
|
1024
|
+
@keyframes enter {
|
|
1025
|
+
from {
|
|
1026
|
+
opacity: var(--tw-enter-opacity, 1);
|
|
1027
|
+
transform: translate3d(
|
|
1028
|
+
var(--tw-enter-translate-x, 0),
|
|
1029
|
+
var(--tw-enter-translate-y, 0),
|
|
1030
|
+
0
|
|
1031
|
+
)
|
|
1032
|
+
scale3d(
|
|
1033
|
+
var(--tw-enter-scale, 1),
|
|
1034
|
+
var(--tw-enter-scale, 1),
|
|
1035
|
+
var(--tw-enter-scale, 1)
|
|
1036
|
+
)
|
|
1037
|
+
rotate(var(--tw-enter-rotate, 0));
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
.animate-in {
|
|
1042
|
+
animation-name: enter;
|
|
1043
|
+
animation-duration: 150ms;
|
|
1044
|
+
--tw-enter-opacity: initial;
|
|
1045
|
+
--tw-enter-scale: initial;
|
|
1046
|
+
--tw-enter-rotate: initial;
|
|
1047
|
+
--tw-enter-translate-x: initial;
|
|
1048
|
+
--tw-enter-translate-y: initial;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
.fade-in {
|
|
1052
|
+
--tw-enter-opacity: 0;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.slide-in-from-top {
|
|
1056
|
+
--tw-enter-translate-y: -100%;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.slide-in-from-bottom {
|
|
1060
|
+
--tw-enter-translate-y: 100%;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
.duration-300 {
|
|
1064
|
+
animation-duration: 300ms;
|
|
1065
|
+
}
|
|
1066
|
+
/* Utility classes */
|
|
1067
|
+
.animate-bounce-in { animation: bounce-in 0.3s ease-out; }
|
|
1068
|
+
.animate-shake { animation: shake 0.5s ease-in-out; }
|
|
1069
|
+
.animate-jelly { animation: jelly 0.5s ease-in-out; }
|
|
1070
|
+
.animate-rubber-band { animation: rubber-band 0.5s ease-in-out; }
|
|
1071
|
+
.animate-swing { animation: swing 0.5s ease-in-out; }
|
|
1072
|
+
.animate-tada { animation: tada 0.5s ease-in-out; }
|
|
1073
|
+
.animate-heartbeat { animation: heartbeat 0.5s ease-in-out; }
|
|
1074
|
+
|
|
1075
|
+
.clip-path-hexagon { clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%); }
|
|
1076
|
+
.clip-path-octagon { clip-path: polygon(30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30%); }
|
|
1077
|
+
.clip-path-shield { clip-path: polygon(50% 0%, 100% 0%, 100% 75%, 50% 100%, 0% 75%, 0% 0%); }
|
|
1078
|
+
|
|
1079
|
+
.ease-elastic { transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); }
|
|
1080
|
+
.ease-bounce { transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); }
|
|
1081
|
+
|
|
518
1082
|
.scrollbar-none {
|
|
519
1083
|
-ms-overflow-style: none;
|
|
520
1084
|
scrollbar-width: none;
|
|
521
1085
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
[role="menu"],
|
|
528
|
-
[role="listbox"] {
|
|
1086
|
+
.scrollbar-none::-webkit-scrollbar { display: none; }
|
|
1087
|
+
|
|
1088
|
+
[role="menu"], [role="listbox"] {
|
|
529
1089
|
-ms-overflow-style: none;
|
|
530
1090
|
scrollbar-width: none;
|
|
531
1091
|
}
|
|
532
|
-
|
|
533
1092
|
[role="menu"]::-webkit-scrollbar,
|
|
534
|
-
[role="listbox"]::-webkit-scrollbar {
|
|
535
|
-
|
|
536
|
-
}
|
|
537
|
-
|
|
1093
|
+
[role="listbox"]::-webkit-scrollbar { display: none; }
|
|
1094
|
+
|
|
538
1095
|
[contenteditable][data-placeholder]:empty:before {
|
|
539
1096
|
content: attr(data-placeholder);
|
|
540
1097
|
color: hsl(var(--muted-foreground));
|
|
541
1098
|
opacity: 0.5;
|
|
542
1099
|
pointer-events: none;
|
|
543
1100
|
}
|
|
544
|
-
|
|
1101
|
+
|
|
545
1102
|
[contenteditable]:focus:empty:before {
|
|
546
1103
|
content: attr(data-placeholder);
|
|
547
1104
|
color: hsl(var(--muted-foreground));
|
|
548
1105
|
opacity: 0.3;
|
|
549
1106
|
}
|
|
1107
|
+
|
|
1108
|
+
input[type="number"] {
|
|
1109
|
+
-moz-appearance: textfield;
|
|
1110
|
+
-webkit-appearance: none;
|
|
1111
|
+
appearance: none;
|
|
1112
|
+
}
|
|
1113
|
+
input[type="number"]::-webkit-inner-spin-button,
|
|
1114
|
+
input[type="number"]::-webkit-outer-spin-button {
|
|
1115
|
+
-webkit-appearance: none;
|
|
1116
|
+
margin: 0;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1121
|
+
*, *::before, *::after {
|
|
1122
|
+
animation-duration: 0.01ms !important;
|
|
1123
|
+
animation-iteration-count: 1 !important;
|
|
1124
|
+
}
|
|
550
1125
|
}`;
|
|
551
1126
|
|
|
552
1127
|
// CSS for Tailwind v3
|
|
@@ -651,10 +1226,8 @@ const getRelativePathToNodeModules = (fromFile) => {
|
|
|
651
1226
|
const nodeModulesPath = path.join(R, "node_modules");
|
|
652
1227
|
let relativePath = path.relative(fromDir, nodeModulesPath);
|
|
653
1228
|
|
|
654
|
-
// Convert Windows backslashes to forward slashes for consistency
|
|
655
1229
|
relativePath = relativePath.replace(/\\/g, '/');
|
|
656
1230
|
|
|
657
|
-
// If in same directory, use ./
|
|
658
1231
|
if (!relativePath) {
|
|
659
1232
|
relativePath = '.';
|
|
660
1233
|
} else if (!relativePath.startsWith('.')) {
|
|
@@ -665,7 +1238,7 @@ const getRelativePathToNodeModules = (fromFile) => {
|
|
|
665
1238
|
};
|
|
666
1239
|
|
|
667
1240
|
// ----------------------------------------------
|
|
668
|
-
// Update Tailwind config for v3
|
|
1241
|
+
// Update Tailwind config for v3
|
|
669
1242
|
// ----------------------------------------------
|
|
670
1243
|
const updateTailwindConfig = (cssFilePath) => {
|
|
671
1244
|
const configFiles = [
|
|
@@ -686,171 +1259,325 @@ const updateTailwindConfig = (cssFilePath) => {
|
|
|
686
1259
|
|
|
687
1260
|
if (!configPath) {
|
|
688
1261
|
console.warn("⚠️ Warning: Could not find Tailwind config file");
|
|
689
|
-
console.log("\n📝 Please manually create tailwind.config.js and add
|
|
690
|
-
console.log(`
|
|
691
|
-
export default {
|
|
692
|
-
content: [
|
|
693
|
-
"./src/**/*.{js,jsx,ts,tsx}",
|
|
694
|
-
"./node_modules/saha-ui/dist/**/*.js", // ← Required for saha-ui
|
|
695
|
-
],
|
|
696
|
-
// ... rest of your config
|
|
697
|
-
};
|
|
698
|
-
`);
|
|
1262
|
+
console.log("\n📝 Please manually create tailwind.config.js and add saha-ui content path.");
|
|
699
1263
|
return;
|
|
700
1264
|
}
|
|
701
1265
|
|
|
702
|
-
// Calculate relative path from config file to node_modules
|
|
703
1266
|
const relativePathToNodeModules = getRelativePathToNodeModules(configPath);
|
|
704
1267
|
const sahaUIContentPath = `${relativePathToNodeModules}/saha-ui/dist/**/*.js`;
|
|
705
1268
|
|
|
706
1269
|
let config = rd(configPath);
|
|
707
1270
|
const contentPattern = /node_modules\/saha-ui\/dist\/\*\*\/\*\.js/;
|
|
708
1271
|
|
|
709
|
-
// Check if saha-ui content path already exists
|
|
710
1272
|
if (contentPattern.test(config)) {
|
|
711
1273
|
console.log("✅ Tailwind config already includes saha-ui content path");
|
|
712
1274
|
} else {
|
|
713
|
-
// Try to automatically add the content path
|
|
714
1275
|
const contentArrayRegex = /content\s*:\s*\[([\s\S]*?)\]/;
|
|
715
1276
|
const match = config.match(contentArrayRegex);
|
|
716
1277
|
|
|
717
1278
|
if (match) {
|
|
718
1279
|
const currentContent = match[ 1 ];
|
|
719
1280
|
const newContentPath = `\n "${sahaUIContentPath}",`;
|
|
720
|
-
|
|
721
|
-
// Add before the closing bracket
|
|
722
1281
|
const updatedContent = currentContent.trimEnd() + newContentPath;
|
|
723
1282
|
config = config.replace(contentArrayRegex, `content: [${updatedContent}\n ]`);
|
|
724
1283
|
|
|
725
1284
|
wr(configPath, config);
|
|
726
1285
|
console.log(`✅ Added saha-ui content path to ${path.relative(R, configPath)}`);
|
|
727
|
-
console.log(` Path: "${sahaUIContentPath}"`);
|
|
728
1286
|
} else {
|
|
729
1287
|
console.warn("⚠️ Could not automatically update content array");
|
|
730
|
-
console.log(
|
|
731
|
-
console.log(` "${sahaUIContentPath}"`);
|
|
1288
|
+
console.log(`\n📝 Please manually add: "${sahaUIContentPath}"`);
|
|
732
1289
|
}
|
|
733
1290
|
}
|
|
734
|
-
|
|
735
|
-
// Theme extension hints (manual for now to avoid breaking existing configs)
|
|
736
|
-
if (config.includes("theme:") && config.includes("extend:")) {
|
|
737
|
-
console.log("\nℹ️ Tailwind config already has theme.extend");
|
|
738
|
-
console.log("📝 If you haven't already, add these to your tailwind.config theme.extend:");
|
|
739
|
-
console.log(`
|
|
740
|
-
colors: {
|
|
741
|
-
border: "hsl(var(--border))",
|
|
742
|
-
input: "hsl(var(--input))",
|
|
743
|
-
ring: "hsl(var(--ring))",
|
|
744
|
-
background: "hsl(var(--background))",
|
|
745
|
-
foreground: "hsl(var(--foreground))",
|
|
746
|
-
primary: { DEFAULT: "hsl(var(--primary))", foreground: "hsl(var(--primary-foreground))" },
|
|
747
|
-
secondary: { DEFAULT: "hsl(var(--secondary))", foreground: "hsl(var(--secondary-foreground))" },
|
|
748
|
-
muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))" },
|
|
749
|
-
accent: { DEFAULT: "hsl(var(--accent))", foreground: "hsl(var(--accent-foreground))" },
|
|
750
|
-
destructive: { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))" },
|
|
751
|
-
success: { DEFAULT: "hsl(var(--success))", foreground: "hsl(var(--success-foreground))" },
|
|
752
|
-
warning: { DEFAULT: "hsl(var(--warning))", foreground: "hsl(var(--warning-foreground))" },
|
|
753
|
-
error: { DEFAULT: "hsl(var(--error))", foreground: "hsl(var(--error-foreground))" },
|
|
754
|
-
info: { DEFAULT: "hsl(var(--info))", foreground: "hsl(var(--info-foreground))" },
|
|
755
|
-
card: { DEFAULT: "hsl(var(--card))", foreground: "hsl(var(--card-foreground))" },
|
|
756
|
-
popover: { DEFAULT: "hsl(var(--popover))", foreground: "hsl(var(--popover-foreground))" },
|
|
757
|
-
chart: { 1: "hsl(var(--chart-1))", 2: "hsl(var(--chart-2))", 3: "hsl(var(--chart-3))", 4: "hsl(var(--chart-4))", 5: "hsl(var(--chart-5))" },
|
|
758
|
-
},
|
|
759
|
-
borderRadius: {
|
|
760
|
-
lg: "var(--radius)",
|
|
761
|
-
md: "calc(var(--radius) - 2px)",
|
|
762
|
-
sm: "calc(var(--radius) - 4px)",
|
|
763
|
-
},
|
|
764
|
-
keyframes: {
|
|
765
|
-
"progress-stripes": { "0%": { backgroundPosition: "0 0" }, "100%": { backgroundPosition: "1.5rem 0" } },
|
|
766
|
-
"progress-indeterminate": { "0%": { left: "-40%", transform: "scaleX(0.6)" }, "50%": { transform: "scaleX(1)" }, "100%": { left: "100%", transform: "scaleX(0.6)" } },
|
|
767
|
-
"progress-shimmer": { "0%": { transform: "translateX(-100%) scaleX(0)", opacity: "0" }, "10%": { opacity: "1" }, "50%": { transform: "translateX(0%) scaleX(1)" }, "90%": { opacity: "1" }, "100%": { transform: "translateX(100%) scaleX(0)", opacity: "0" } },
|
|
768
|
-
"progress-glow-pulse": { "0%, 100%": { filter: "brightness(1) saturate(1)" }, "50%": { filter: "brightness(1.15) saturate(1.2)" } },
|
|
769
|
-
"collapsible-down": { from: { height: "0", opacity: "0" }, to: { height: "var(--radix-collapsible-content-height)", opacity: "1" } },
|
|
770
|
-
"collapsible-up": { from: { height: "var(--radix-collapsible-content-height)", opacity: "1" }, to: { height: "0", opacity: "0" } },
|
|
771
|
-
},
|
|
772
|
-
animation: {
|
|
773
|
-
"progress-stripes": "progress-stripes 1s linear infinite",
|
|
774
|
-
"progress-indeterminate": "progress-indeterminate 1.5s ease-in-out infinite",
|
|
775
|
-
"progress-shimmer": "progress-shimmer 2s ease-in-out infinite",
|
|
776
|
-
"progress-glow-pulse": "progress-glow-pulse 2s ease-in-out infinite",
|
|
777
|
-
"collapsible-down": "collapsible-down 0.2s ease-out",
|
|
778
|
-
"collapsible-up": "collapsible-up 0.2s ease-out",
|
|
779
|
-
},
|
|
780
|
-
`);
|
|
781
|
-
}
|
|
782
1291
|
};
|
|
783
1292
|
|
|
784
1293
|
// ----------------------------------------------
|
|
785
|
-
// Inject
|
|
1294
|
+
// Smart Inject with Merge/Replace Options
|
|
786
1295
|
// ----------------------------------------------
|
|
787
|
-
const inject = (f, tailwindInfo) => {
|
|
1296
|
+
const inject = async (f, tailwindInfo) => {
|
|
788
1297
|
const ex = fE(f);
|
|
789
1298
|
const cur = ex ? rd(f) : "";
|
|
790
1299
|
|
|
791
|
-
|
|
792
|
-
const
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
// For Tailwind v4, always check and add @source if missing
|
|
796
|
-
if (hasTailwindV4Import) {
|
|
797
|
-
const relativePathToNodeModules = getRelativePathToNodeModules(f);
|
|
798
|
-
const sahaUISourcePath = `${relativePathToNodeModules}/saha-ui/dist/**/*.js`;
|
|
799
|
-
const sourcePattern = /source\s+["'][^"']*saha-ui[^"']*["']/;
|
|
1300
|
+
// Detect existing structures
|
|
1301
|
+
const structures = detectExistingStructures(cur);
|
|
1302
|
+
const hasExistingSetup = structures.hasRoot || structures.hasDark || structures.hasLayerBase;
|
|
800
1303
|
|
|
801
|
-
|
|
802
|
-
// Add @source to the @import line
|
|
803
|
-
const updatedContent = cur.replace(
|
|
804
|
-
/@import\s+["']tailwindcss["'];?/,
|
|
805
|
-
`@import "tailwindcss";
|
|
806
|
-
@source "${sahaUISourcePath}";`
|
|
807
|
-
);
|
|
808
|
-
wr(f, updatedContent);
|
|
809
|
-
console.log(`\n✅ Added @source "${sahaUISourcePath}" to Tailwind v4 import`);
|
|
810
|
-
} else {
|
|
811
|
-
console.log("✅ Tailwind v4 @source already includes saha-ui");
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// Now check if CSS content is already injected
|
|
1304
|
+
// Check if already injected
|
|
816
1305
|
if (cur.includes(M)) {
|
|
817
1306
|
console.log(`✅ saha-ui: CSS already injected in ${path.relative(R, f)}`);
|
|
818
1307
|
return;
|
|
819
1308
|
}
|
|
820
1309
|
|
|
1310
|
+
let mode = "fresh"; // fresh, replace, merge
|
|
1311
|
+
|
|
1312
|
+
// If existing setup detected, ask user what to do
|
|
1313
|
+
if (hasExistingSetup) {
|
|
1314
|
+
console.log("\n⚠️ Existing CSS setup detected in your file:");
|
|
1315
|
+
if (structures.hasRoot) console.log(" • :root variables found");
|
|
1316
|
+
if (structures.hasDark) console.log(" • .dark variables found");
|
|
1317
|
+
if (structures.hasLayerBase) console.log(" • @layer base found");
|
|
1318
|
+
if (structures.hasLayerComponents) console.log(" • @layer components found");
|
|
1319
|
+
if (structures.hasLayerUtilities) console.log(" • @layer utilities found");
|
|
1320
|
+
if (structures.hasKeyframes) console.log(" • @keyframes found");
|
|
1321
|
+
if (structures.hasGlassClass) console.log(" • .glass class found");
|
|
1322
|
+
|
|
1323
|
+
mode = await selectPrompt(
|
|
1324
|
+
"\nHow would you like to handle existing styles?",
|
|
1325
|
+
[
|
|
1326
|
+
{ label: "Replace all - Overwrite existing styles with saha-ui defaults", value: "replace" },
|
|
1327
|
+
{ label: "Merge - Keep your values, add missing saha-ui variables", value: "merge" },
|
|
1328
|
+
{ label: "Skip - Don't modify existing styles, only add new sections", value: "skip" },
|
|
1329
|
+
]
|
|
1330
|
+
);
|
|
1331
|
+
|
|
1332
|
+
console.log(`\n📝 Selected mode: ${mode}\n`);
|
|
1333
|
+
}
|
|
1334
|
+
|
|
821
1335
|
const CSS = tailwindInfo.major >= 4 ? CSS_V4 : CSS_V3;
|
|
822
1336
|
|
|
823
|
-
|
|
824
|
-
if (
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
1337
|
+
// Handle based on mode
|
|
1338
|
+
if (mode === "fresh" || mode === "replace") {
|
|
1339
|
+
// Full replacement or fresh install
|
|
1340
|
+
let out = "";
|
|
1341
|
+
|
|
1342
|
+
if (mode === "replace") {
|
|
1343
|
+
// Remove existing blocks that we'll replace
|
|
1344
|
+
let cleanedCss = cur;
|
|
1345
|
+
|
|
1346
|
+
// Remove :root block
|
|
1347
|
+
const rootBlock = extractBlock(cleanedCss, /:root\s*\{/);
|
|
1348
|
+
if (rootBlock) {
|
|
1349
|
+
cleanedCss = cleanedCss.substring(0, rootBlock.startIndex) + cleanedCss.substring(rootBlock.endIndex);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Remove .dark block
|
|
1353
|
+
const darkBlock = extractBlock(cleanedCss, /\.dark\s*\{/);
|
|
1354
|
+
if (darkBlock) {
|
|
1355
|
+
cleanedCss = cleanedCss.substring(0, darkBlock.startIndex) + cleanedCss.substring(darkBlock.endIndex);
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
// Remove @theme inline block (v4)
|
|
1359
|
+
const themeBlock = extractBlock(cleanedCss, /@theme\s+inline\s*\{/);
|
|
1360
|
+
if (themeBlock) {
|
|
1361
|
+
cleanedCss = cleanedCss.substring(0, themeBlock.startIndex) + cleanedCss.substring(themeBlock.endIndex);
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// Remove @layer base block
|
|
1365
|
+
const baseBlock = extractBlock(cleanedCss, /@layer\s+base\s*\{/);
|
|
1366
|
+
if (baseBlock) {
|
|
1367
|
+
cleanedCss = cleanedCss.substring(0, baseBlock.startIndex) + cleanedCss.substring(baseBlock.endIndex);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// Remove @layer components block
|
|
1371
|
+
const componentsBlock = extractBlock(cleanedCss, /@layer\s+components\s*\{/);
|
|
1372
|
+
if (componentsBlock) {
|
|
1373
|
+
cleanedCss = cleanedCss.substring(0, componentsBlock.startIndex) + cleanedCss.substring(componentsBlock.endIndex);
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
// Remove @layer utilities block
|
|
1377
|
+
const utilitiesBlock = extractBlock(cleanedCss, /@layer\s+utilities\s*\{/);
|
|
1378
|
+
if (utilitiesBlock) {
|
|
1379
|
+
cleanedCss = cleanedCss.substring(0, utilitiesBlock.startIndex) + cleanedCss.substring(utilitiesBlock.endIndex);
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
// Remove @custom-variant dark
|
|
1383
|
+
cleanedCss = cleanedCss.replace(/@custom-variant\s+dark\s*\([^)]*\)\s*;?\n*/g, "");
|
|
1384
|
+
|
|
1385
|
+
// Clean up multiple empty lines
|
|
1386
|
+
cleanedCss = cleanedCss.replace(/\n{3,}/g, "\n\n").trim();
|
|
1387
|
+
|
|
1388
|
+
// Now inject the CSS
|
|
1389
|
+
let cssToInject = CSS;
|
|
1390
|
+
|
|
1391
|
+
// Check if tailwind import/directives exist
|
|
1392
|
+
if (structures.hasTailwindImport) {
|
|
1393
|
+
cssToInject = CSS.replace(/^@import\s+["']tailwindcss["'][^;]*;?\n*/, "").trim();
|
|
1394
|
+
out = cleanedCss.replace(/@import\s+["']tailwindcss["'][^;]*;/, (m) => `${m}\n${M}\n${cssToInject}`);
|
|
1395
|
+
} else if (structures.hasTailwindDirectives) {
|
|
1396
|
+
cssToInject = CSS.replace(/@tailwind\s+(base|components|utilities);?\n*/g, "").trim();
|
|
1397
|
+
const tailwindDirectives = cleanedCss.match(/@tailwind\s+(base|components|utilities);?\n*/g);
|
|
1398
|
+
if (tailwindDirectives) {
|
|
1399
|
+
const lastDirective = tailwindDirectives[ tailwindDirectives.length - 1 ];
|
|
1400
|
+
const lastIndex = cleanedCss.lastIndexOf(lastDirective);
|
|
1401
|
+
const beforeDirective = cleanedCss.substring(0, lastIndex + lastDirective.length);
|
|
1402
|
+
const afterDirective = cleanedCss.substring(lastIndex + lastDirective.length);
|
|
1403
|
+
out = `${beforeDirective}\n${M}\n${cssToInject}\n${afterDirective}`;
|
|
1404
|
+
} else {
|
|
1405
|
+
out = `${M}\n${cssToInject}\n\n${cleanedCss}`;
|
|
1406
|
+
}
|
|
1407
|
+
} else {
|
|
1408
|
+
out = cleanedCss ? `${cleanedCss}\n\n${M}\n${CSS}` : `${M}\n${CSS}`;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
console.log("✅ Replaced existing styles with saha-ui defaults");
|
|
1412
|
+
} else {
|
|
1413
|
+
// Fresh install
|
|
1414
|
+
if (structures.hasTailwindImport) {
|
|
1415
|
+
const cssToInject = CSS.replace(/^@import\s+["']tailwindcss["'][^;]*;?\n*/, "").trim();
|
|
1416
|
+
out = cur.replace(/@import\s+["']tailwindcss["'][^;]*;/, (m) => `${m}\n${M}\n${cssToInject}`);
|
|
1417
|
+
} else if (structures.hasTailwindDirectives) {
|
|
1418
|
+
const cssToInject = CSS.replace(/@tailwind\s+(base|components|utilities);?\n*/g, "").trim();
|
|
1419
|
+
const tailwindDirectives = cur.match(/@tailwind\s+(base|components|utilities);?\n*/g);
|
|
1420
|
+
if (tailwindDirectives) {
|
|
1421
|
+
const lastDirective = tailwindDirectives[ tailwindDirectives.length - 1 ];
|
|
1422
|
+
const lastIndex = cur.lastIndexOf(lastDirective);
|
|
1423
|
+
out = `${cur.substring(0, lastIndex + lastDirective.length)}\n${M}\n${cssToInject}\n${cur.substring(lastIndex + lastDirective.length)}`;
|
|
1424
|
+
} else {
|
|
1425
|
+
out = `${M}\n${CSS}\n\n${cur}`;
|
|
1426
|
+
}
|
|
1427
|
+
} else {
|
|
1428
|
+
out = `${M}\n${CSS}\n\n${cur}`;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
wr(f, out);
|
|
1433
|
+
} else if (mode === "merge") {
|
|
1434
|
+
// Merge mode - add missing variables
|
|
1435
|
+
let updatedCss = cur;
|
|
1436
|
+
let totalAdded = 0;
|
|
1437
|
+
|
|
1438
|
+
// Merge :root variables
|
|
1439
|
+
const rootResult = updateRootBlock(updatedCss, SAHA_UI_ROOT_VARIABLES, "merge");
|
|
1440
|
+
updatedCss = rootResult.css;
|
|
1441
|
+
if (rootResult.added > 0) {
|
|
1442
|
+
console.log(` ✅ Added ${rootResult.added} missing :root variables`);
|
|
1443
|
+
totalAdded += rootResult.added;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
// Merge .dark variables
|
|
1447
|
+
const darkResult = updateDarkBlock(updatedCss, SAHA_UI_DARK_VARIABLES, "merge");
|
|
1448
|
+
updatedCss = darkResult.css;
|
|
1449
|
+
if (darkResult.added > 0) {
|
|
1450
|
+
console.log(` ✅ Added ${darkResult.added} missing .dark variables`);
|
|
1451
|
+
totalAdded += darkResult.added;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
// Merge keyframes
|
|
1455
|
+
const keyframeResult = mergeKeyframes(updatedCss, SAHA_UI_KEYFRAMES);
|
|
1456
|
+
updatedCss = keyframeResult.css;
|
|
1457
|
+
if (keyframeResult.added > 0) {
|
|
1458
|
+
console.log(` ✅ Added ${keyframeResult.added} missing @keyframes`);
|
|
1459
|
+
totalAdded += keyframeResult.added;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
// Add @custom-variant dark if missing (v4)
|
|
1463
|
+
if (tailwindInfo.major >= 4 && !structures.hasCustomVariant) {
|
|
1464
|
+
if (structures.hasTailwindImport) {
|
|
1465
|
+
updatedCss = updatedCss.replace(
|
|
1466
|
+
/@import\s+["']tailwindcss["'][^;]*;/,
|
|
1467
|
+
(m) => `${m}\n\n@custom-variant dark (&:is(.dark *));`
|
|
1468
|
+
);
|
|
1469
|
+
console.log(` ✅ Added @custom-variant dark`);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// Add @theme inline if missing (v4)
|
|
1474
|
+
if (tailwindInfo.major >= 4 && !structures.hasThemeInline) {
|
|
1475
|
+
const themeInline = `
|
|
1476
|
+
@theme inline {
|
|
1477
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
1478
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
1479
|
+
--radius-lg: var(--radius);
|
|
1480
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
1481
|
+
|
|
1482
|
+
--color-background: var(--background);
|
|
1483
|
+
--color-foreground: var(--foreground);
|
|
1484
|
+
--color-card: var(--card);
|
|
1485
|
+
--color-card-foreground: var(--card-foreground);
|
|
1486
|
+
--color-popover: var(--popover);
|
|
1487
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
1488
|
+
--color-primary: var(--primary);
|
|
1489
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
1490
|
+
--color-secondary: var(--secondary);
|
|
1491
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
1492
|
+
--color-muted: var(--muted);
|
|
1493
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
1494
|
+
--color-accent: var(--accent);
|
|
1495
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
1496
|
+
--color-destructive: var(--destructive);
|
|
1497
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
1498
|
+
--color-border: var(--border);
|
|
1499
|
+
--color-input: var(--input);
|
|
1500
|
+
--color-ring: var(--ring);
|
|
1501
|
+
--color-chart-1: var(--chart-1);
|
|
1502
|
+
--color-chart-2: var(--chart-2);
|
|
1503
|
+
--color-chart-3: var(--chart-3);
|
|
1504
|
+
--color-chart-4: var(--chart-4);
|
|
1505
|
+
--color-chart-5: var(--chart-5);
|
|
1506
|
+
--color-success: var(--success);
|
|
1507
|
+
--color-success-foreground: var(--success-foreground);
|
|
1508
|
+
--color-warning: var(--warning);
|
|
1509
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
1510
|
+
--color-error: var(--error);
|
|
1511
|
+
--color-error-foreground: var(--error-foreground);
|
|
1512
|
+
--color-info: var(--info);
|
|
1513
|
+
--color-info-foreground: var(--info-foreground);
|
|
1514
|
+
}`;
|
|
1515
|
+
|
|
1516
|
+
// Insert after @custom-variant or @import
|
|
1517
|
+
if (updatedCss.includes("@custom-variant dark")) {
|
|
1518
|
+
updatedCss = updatedCss.replace(
|
|
1519
|
+
/@custom-variant\s+dark\s*\([^)]*\)\s*;?/,
|
|
1520
|
+
(m) => `${m}\n${themeInline}`
|
|
1521
|
+
);
|
|
1522
|
+
} else if (structures.hasTailwindImport) {
|
|
1523
|
+
updatedCss = updatedCss.replace(
|
|
1524
|
+
/@import\s+["']tailwindcss["'][^;]*;/,
|
|
1525
|
+
(m) => `${m}\n${themeInline}`
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
console.log(` ✅ Added @theme inline block`);
|
|
829
1529
|
}
|
|
830
|
-
}
|
|
831
1530
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
const afterDirective = cur.substring(lastIndex + lastDirective.length);
|
|
844
|
-
out = `${beforeDirective}\n${M}\n${cssToInject}\n${afterDirective}`;
|
|
1531
|
+
// Add marker if not present
|
|
1532
|
+
if (!updatedCss.includes(M)) {
|
|
1533
|
+
if (structures.hasTailwindImport) {
|
|
1534
|
+
updatedCss = updatedCss.replace(/@import\s+["']tailwindcss["'][^;]*;/, (m) => `${m}\n${M}`);
|
|
1535
|
+
} else {
|
|
1536
|
+
updatedCss = `${M}\n${updatedCss}`;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
if (totalAdded > 0) {
|
|
1541
|
+
console.log(`\n✅ Merged ${totalAdded} total items into your CSS`);
|
|
845
1542
|
} else {
|
|
846
|
-
|
|
1543
|
+
console.log("\n✅ Your CSS already has all required saha-ui variables");
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
wr(f, updatedCss);
|
|
1547
|
+
} else if (mode === "skip") {
|
|
1548
|
+
// Skip mode - only add marker and @source for v4
|
|
1549
|
+
let updatedCss = cur;
|
|
1550
|
+
|
|
1551
|
+
if (!updatedCss.includes(M)) {
|
|
1552
|
+
if (structures.hasTailwindImport) {
|
|
1553
|
+
updatedCss = updatedCss.replace(/@import\s+["']tailwindcss["'][^;]*;/, (m) => `${m}\n${M}`);
|
|
1554
|
+
} else {
|
|
1555
|
+
updatedCss = `${M}\n${updatedCss}`;
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
console.log("✅ Skipped style modifications, only added saha-ui marker");
|
|
1560
|
+
wr(f, updatedCss);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// Add @source for Tailwind v4
|
|
1564
|
+
const updatedContent = rd(f);
|
|
1565
|
+
if (tailwindInfo.major >= 4 && structures.hasTailwindImport) {
|
|
1566
|
+
const relativePathToNodeModules = getRelativePathToNodeModules(f);
|
|
1567
|
+
const sahaUISourcePath = `${relativePathToNodeModules}/saha-ui/dist/**/*.js`;
|
|
1568
|
+
const sourcePattern = /source\s+["'][^"']*saha-ui[^"']*["']/;
|
|
1569
|
+
|
|
1570
|
+
if (!sourcePattern.test(updatedContent)) {
|
|
1571
|
+
const withSource = updatedContent.replace(
|
|
1572
|
+
/@import\s+["']tailwindcss["'];?/,
|
|
1573
|
+
`@import "tailwindcss";\n@source "${sahaUISourcePath}";`
|
|
1574
|
+
);
|
|
1575
|
+
wr(f, withSource);
|
|
1576
|
+
console.log(`✅ Added @source "${sahaUISourcePath}" for Tailwind v4`);
|
|
847
1577
|
}
|
|
848
|
-
} else {
|
|
849
|
-
out = `${M}\n${CSS}\n\n${cur}`;
|
|
850
1578
|
}
|
|
851
1579
|
|
|
852
|
-
|
|
853
|
-
console.log(`\n✅ saha-ui: Injected CSS into ${path.relative(R, f)} (${F})`);
|
|
1580
|
+
console.log(`\n✅ saha-ui: CSS processed in ${path.relative(R, f)} (${F})`);
|
|
854
1581
|
console.log(`📦 Using Tailwind v${tailwindInfo.major} configuration`);
|
|
855
1582
|
|
|
856
1583
|
if (tailwindInfo.major < 4) {
|
|
@@ -873,7 +1600,7 @@ const inject = (f, tailwindInfo) => {
|
|
|
873
1600
|
// ----------------------------------------------
|
|
874
1601
|
// Main
|
|
875
1602
|
// ----------------------------------------------
|
|
876
|
-
const run = () => {
|
|
1603
|
+
const run = async () => {
|
|
877
1604
|
if (c !== "init") {
|
|
878
1605
|
console.log("Usage: npx saha-ui init");
|
|
879
1606
|
return;
|
|
@@ -898,8 +1625,8 @@ const run = () => {
|
|
|
898
1625
|
ensureSahaUIInstalled();
|
|
899
1626
|
installSahaUIDeps();
|
|
900
1627
|
|
|
901
|
-
// 5) Inject CSS
|
|
902
|
-
inject(pick(), tailwindInfo);
|
|
1628
|
+
// 5) Inject CSS with smart merge/replace options
|
|
1629
|
+
await inject(pick(), tailwindInfo);
|
|
903
1630
|
|
|
904
1631
|
console.log("\n✨ Done!\n");
|
|
905
1632
|
};
|