saha-ui 1.11.0 → 1.11.1
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 +703 -82
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -3,26 +3,109 @@
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { execSync } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
6
7
|
|
|
7
8
|
const R = process.cwd();
|
|
8
9
|
const a = process.argv.slice(2);
|
|
9
10
|
const c = a[ 0 ] || "init";
|
|
10
11
|
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
// Helpers
|
|
13
|
+
const rd = (f) => fs.readFileSync(f, "utf8");
|
|
14
|
+
const wr = (f, s) => {
|
|
15
|
+
fs.mkdirSync(path.dirname(f), { recursive: true });
|
|
16
|
+
fs.writeFileSync(f, s, "utf8");
|
|
17
|
+
};
|
|
18
|
+
const fE = (f) => fs.existsSync(f) && fs.statSync(f).isFile();
|
|
19
|
+
const dE = (d) => fs.existsSync(d) && fs.statSync(d).isDirectory();
|
|
20
|
+
|
|
21
|
+
// package.json
|
|
22
|
+
const P = (() => {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(rd(path.join(R, "package.json")));
|
|
25
|
+
} catch {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
})();
|
|
29
|
+
const D = { ...(P.dependencies || {}), ...(P.devDependencies || {}) };
|
|
30
|
+
const F = D.next ? "next" : "react";
|
|
31
|
+
|
|
32
|
+
// ----------------------------------------------
|
|
33
|
+
// Tailwind detection from package.json only
|
|
34
|
+
// ----------------------------------------------
|
|
35
|
+
const TAILWIND_CONFIG_FILES = [
|
|
36
|
+
"tailwind.config.js",
|
|
37
|
+
"tailwind.config.ts",
|
|
38
|
+
"tailwind.config.mjs",
|
|
39
|
+
"tailwind.config.cjs",
|
|
40
|
+
"tailwind.config.mts",
|
|
41
|
+
"tailwind.config.cts",
|
|
42
|
+
];
|
|
14
43
|
|
|
44
|
+
const parseMajor = (v) => {
|
|
45
|
+
const m = String(v || "").match(/(\d+)/);
|
|
46
|
+
return m ? parseInt(m[ 1 ], 10) : 0;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function assertTailwindFromPkgJson() {
|
|
50
|
+
const versionRange =
|
|
51
|
+
(P.dependencies && P.dependencies.tailwindcss) ||
|
|
52
|
+
(P.devDependencies && P.devDependencies.tailwindcss);
|
|
53
|
+
|
|
54
|
+
if (!versionRange) {
|
|
55
|
+
console.error("❌ Tailwind CSS is not listed in package.json.");
|
|
56
|
+
console.error("Please add Tailwind first, then re-run this command.");
|
|
57
|
+
console.error("Examples:");
|
|
58
|
+
console.error(" - v4: npm i -D tailwindcss");
|
|
59
|
+
console.error(" Optional: npm i -D @tailwindcss/postcss // PostCSS flow");
|
|
60
|
+
console.error(" Optional: npm i -D @tailwindcss/cli // CLI flow");
|
|
61
|
+
console.error(" - v3: npm i -D tailwindcss postcss autoprefixer && npx tailwindcss init -p");
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const major = parseMajor(versionRange);
|
|
66
|
+
console.log(`🔎 Tailwind in package.json: "${versionRange}" (detected major v${major})`);
|
|
67
|
+
return { versionRange, major };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// v3 requires a tailwind.config.* file to exist
|
|
71
|
+
function assertTailwindV3ConfigPresent() {
|
|
72
|
+
const configPath = TAILWIND_CONFIG_FILES
|
|
73
|
+
.map((f) => path.join(R, f))
|
|
74
|
+
.find((p) => fE(p));
|
|
75
|
+
if (!configPath) {
|
|
76
|
+
console.error("❌ Tailwind v3 detected, but no tailwind.config.* found.");
|
|
77
|
+
console.error("Please run: npx tailwindcss init -p");
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
console.log("✅ Tailwind v3 config file detected.");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ----------------------------------------------
|
|
84
|
+
// React presence
|
|
85
|
+
// ----------------------------------------------
|
|
86
|
+
function assertReactPresent() {
|
|
87
|
+
if (!D.react) {
|
|
88
|
+
console.error("❌ This setup currently supports React/Next projects only.");
|
|
89
|
+
console.error("React dependency was not found in package.json.");
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
console.log("✅ React detected.");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ----------------------------------------------
|
|
96
|
+
// saha-ui presence + deps sync
|
|
97
|
+
// ----------------------------------------------
|
|
15
98
|
function ensureSahaUIInstalled() {
|
|
16
99
|
try {
|
|
17
100
|
const pkgPath = path.join(R, "package.json");
|
|
18
|
-
if (!
|
|
101
|
+
if (!fE(pkgPath)) {
|
|
19
102
|
console.error("❌ No package.json found in this directory.");
|
|
20
103
|
console.error("Please run this command inside your project folder.");
|
|
21
104
|
process.exit(1);
|
|
22
105
|
}
|
|
23
106
|
|
|
24
|
-
const pkg = JSON.parse(
|
|
25
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
107
|
+
const pkg = JSON.parse(rd(pkgPath));
|
|
108
|
+
const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
26
109
|
if (!deps[ "saha-ui" ]) {
|
|
27
110
|
console.log("\n📦 saha-ui not found in your project.");
|
|
28
111
|
console.log("Installing saha-ui@latest for you...\n");
|
|
@@ -41,21 +124,17 @@ function ensureSahaUIInstalled() {
|
|
|
41
124
|
}
|
|
42
125
|
}
|
|
43
126
|
|
|
44
|
-
// ───────────────────────────────────────────────
|
|
45
|
-
// 🆕 Step 2: Install saha-ui dependencies in main project
|
|
46
|
-
// ───────────────────────────────────────────────
|
|
47
|
-
|
|
48
127
|
function installSahaUIDeps() {
|
|
49
128
|
try {
|
|
50
|
-
const sahaPath = path.dirname(
|
|
129
|
+
const sahaPath = path.dirname(fileURLToPath(import.meta.url));
|
|
51
130
|
const pkgPath = path.resolve(sahaPath, "../package.json");
|
|
52
131
|
|
|
53
|
-
if (!
|
|
132
|
+
if (!fE(pkgPath)) {
|
|
54
133
|
console.warn("⚠️ Could not find saha-ui package.json to sync dependencies.");
|
|
55
134
|
return;
|
|
56
135
|
}
|
|
57
136
|
|
|
58
|
-
const sahaPkg = JSON.parse(
|
|
137
|
+
const sahaPkg = JSON.parse(rd(pkgPath));
|
|
59
138
|
const deps = { ...(sahaPkg.dependencies || {}), ...(sahaPkg.peerDependencies || {}) };
|
|
60
139
|
|
|
61
140
|
const depNames = Object.entries(deps)
|
|
@@ -67,7 +146,7 @@ function installSahaUIDeps() {
|
|
|
67
146
|
return;
|
|
68
147
|
}
|
|
69
148
|
|
|
70
|
-
console.log("📦 Installing saha-ui
|
|
149
|
+
console.log("📦 Installing saha-ui dependencies into your project...");
|
|
71
150
|
execSync(`npm install ${depNames} --save-dev`, {
|
|
72
151
|
stdio: "inherit",
|
|
73
152
|
cwd: R,
|
|
@@ -78,63 +157,9 @@ function installSahaUIDeps() {
|
|
|
78
157
|
}
|
|
79
158
|
}
|
|
80
159
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
//
|
|
84
|
-
// Your Original saha-ui Tailwind/CSS logic below
|
|
85
|
-
// ───────────────────────────────────────────────
|
|
86
|
-
|
|
87
|
-
const rd = (f) => fs.readFileSync(f, "utf8");
|
|
88
|
-
const wr = (f, s) => {
|
|
89
|
-
fs.mkdirSync(path.dirname(f), { recursive: true });
|
|
90
|
-
fs.writeFileSync(f, s, "utf8");
|
|
91
|
-
};
|
|
92
|
-
const fE = (f) => fs.existsSync(f) && fs.statSync(f).isFile();
|
|
93
|
-
const dE = (d) => fs.existsSync(d) && fs.statSync(d).isDirectory();
|
|
94
|
-
|
|
95
|
-
// Parse package.json
|
|
96
|
-
const P = (() => {
|
|
97
|
-
try {
|
|
98
|
-
return JSON.parse(rd(path.join(R, "package.json")));
|
|
99
|
-
} catch {
|
|
100
|
-
return {};
|
|
101
|
-
}
|
|
102
|
-
})();
|
|
103
|
-
|
|
104
|
-
const D = { ...(P.dependencies || {}), ...(P.devDependencies || {}) };
|
|
105
|
-
const F = D.next ? "next" : "react";
|
|
106
|
-
|
|
107
|
-
const checkTailwind = () => {
|
|
108
|
-
const tailwindVersion = D.tailwindcss || D.tailwind;
|
|
109
|
-
|
|
110
|
-
if (!tailwindVersion) {
|
|
111
|
-
console.error("\n❌ Error: Tailwind CSS is not installed!");
|
|
112
|
-
console.error("\nInstalling Tailwind CSS automatically for you...");
|
|
113
|
-
execSync("npm install -D tailwindcss postcss autoprefixer", { stdio: "inherit", cwd: R });
|
|
114
|
-
execSync("npx tailwindcss init -p", { stdio: "inherit", cwd: R });
|
|
115
|
-
console.log("\n✅ Tailwind CSS installed and configured!");
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const configFiles = [
|
|
119
|
-
"tailwind.config.js",
|
|
120
|
-
"tailwind.config.ts",
|
|
121
|
-
"tailwind.config.mjs",
|
|
122
|
-
"tailwind.config.cjs",
|
|
123
|
-
];
|
|
124
|
-
const hasConfig = configFiles.some((f) => fE(path.join(R, f)));
|
|
125
|
-
|
|
126
|
-
if (!hasConfig) {
|
|
127
|
-
console.log("\n⚙️ Creating Tailwind config...");
|
|
128
|
-
execSync("npx tailwindcss init -p", { stdio: "inherit", cwd: R });
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const versionMatch = (D.tailwindcss || "3.0.0").match(/(\d+)\.(\d+)\.(\d+)/);
|
|
132
|
-
const majorVersion = versionMatch ? parseInt(versionMatch[ 1 ]) : 3;
|
|
133
|
-
console.log(`✅ Tailwind CSS v${D.tailwindcss || "latest"} detected`);
|
|
134
|
-
|
|
135
|
-
return { version: D.tailwindcss || "latest", major: majorVersion };
|
|
136
|
-
};
|
|
137
|
-
|
|
160
|
+
// ----------------------------------------------
|
|
161
|
+
// CSS file selection (Next vs React)
|
|
162
|
+
// ----------------------------------------------
|
|
138
163
|
const N = [
|
|
139
164
|
"app/globals.css",
|
|
140
165
|
"app/global.css",
|
|
@@ -153,6 +178,7 @@ const pick = () => {
|
|
|
153
178
|
const f = path.join(R, x);
|
|
154
179
|
if (fE(f)) return f;
|
|
155
180
|
}
|
|
181
|
+
|
|
156
182
|
if (F === "next") {
|
|
157
183
|
const A = dE(path.join(R, "app")) && path.join(R, "app/globals.css");
|
|
158
184
|
const B = dE(path.join(R, "src/app")) && path.join(R, "src/app/globals.css");
|
|
@@ -160,20 +186,601 @@ const pick = () => {
|
|
|
160
186
|
const T = dE(path.join(R, "src/styles")) && path.join(R, "src/styles/globals.css");
|
|
161
187
|
return A || B || S || T || path.join(R, "app/globals.css");
|
|
162
188
|
}
|
|
189
|
+
|
|
163
190
|
return dE(path.join(R, "src")) ? path.join(R, "src/index.css") : path.join(R, "index.css");
|
|
164
191
|
};
|
|
165
192
|
|
|
166
|
-
//
|
|
167
|
-
|
|
193
|
+
// ----------------------------------------------
|
|
194
|
+
// CSS payloads (your CSS)
|
|
195
|
+
// ----------------------------------------------
|
|
168
196
|
const M = "/* saha-ui */";
|
|
169
197
|
const TW = /@import\s+["']tailwindcss["'];?/;
|
|
170
198
|
|
|
171
|
-
//
|
|
199
|
+
// CSS for Tailwind v4+
|
|
200
|
+
const CSS_V4 = `@import "tailwindcss";
|
|
201
|
+
|
|
202
|
+
@custom-variant dark (&:is(.dark *));
|
|
203
|
+
|
|
204
|
+
@theme inline {
|
|
205
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
206
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
207
|
+
--radius-lg: var(--radius);
|
|
208
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
209
|
+
|
|
210
|
+
--color-background: var(--background);
|
|
211
|
+
--color-foreground: var(--foreground);
|
|
212
|
+
--color-card: var(--card);
|
|
213
|
+
--color-card-foreground: var(--card-foreground);
|
|
214
|
+
--color-popover: var(--popover);
|
|
215
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
216
|
+
--color-primary: var(--primary);
|
|
217
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
218
|
+
--color-secondary: var(--secondary);
|
|
219
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
220
|
+
--color-muted: var(--muted);
|
|
221
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
222
|
+
--color-accent: var(--accent);
|
|
223
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
224
|
+
--color-destructive: var(--destructive);
|
|
225
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
226
|
+
--color-border: var(--border);
|
|
227
|
+
--color-input: var(--input);
|
|
228
|
+
--color-ring: var(--ring);
|
|
229
|
+
--color-chart-1: var(--chart-1);
|
|
230
|
+
--color-chart-2: var(--chart-2);
|
|
231
|
+
--color-chart-3: var(--chart-3);
|
|
232
|
+
--color-chart-4: var(--chart-4);
|
|
233
|
+
--color-chart-5: var(--chart-5);
|
|
234
|
+
--color-success: var(--success);
|
|
235
|
+
--color-success-foreground: var(--success-foreground);
|
|
236
|
+
--color-warning: var(--warning);
|
|
237
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
238
|
+
--color-error: var(--error);
|
|
239
|
+
--color-error-foreground: var(--error-foreground);
|
|
240
|
+
--color-info: var(--info);
|
|
241
|
+
--color-info-foreground: var(--info-foreground);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
:root {
|
|
245
|
+
--radius: 0.625rem;
|
|
246
|
+
--background: oklch(0.98 0.003 200);
|
|
247
|
+
--foreground: oklch(0.15 0.01 200);
|
|
248
|
+
--card: oklch(1 0 0);
|
|
249
|
+
--card-foreground: oklch(0.15 0.01 200);
|
|
250
|
+
--popover: oklch(1 0 0);
|
|
251
|
+
--popover-foreground: oklch(0.15 0.01 200);
|
|
252
|
+
--primary: oklch(48.151% 0.23085 269.463);
|
|
253
|
+
--primary-foreground: oklch(1 0 0);
|
|
254
|
+
--secondary: oklch(0.65 0.25 340);
|
|
255
|
+
--secondary-foreground: oklch(1 0 0);
|
|
256
|
+
--muted: oklch(0.96 0.005 200);
|
|
257
|
+
--muted-foreground: oklch(0.45 0.01 200);
|
|
258
|
+
--accent: oklch(0.65 0.12 185);
|
|
259
|
+
--accent-foreground: oklch(1 0 0);
|
|
260
|
+
--success: oklch(0.60 0.15 145);
|
|
261
|
+
--success-foreground: oklch(1 0 0);
|
|
262
|
+
--warning: oklch(0.70 0.15 65);
|
|
263
|
+
--warning-foreground: oklch(0.15 0.01 200);
|
|
264
|
+
--error: oklch(0.60 0.20 25);
|
|
265
|
+
--error-foreground: oklch(1 0 0);
|
|
266
|
+
--destructive: oklch(0.60 0.20 25);
|
|
267
|
+
--destructive-foreground: oklch(1 0 0);
|
|
268
|
+
--info: oklch(0.60 0.15 250);
|
|
269
|
+
--info-foreground: oklch(1 0 0);
|
|
270
|
+
--border: oklch(0.92 0.005 200);
|
|
271
|
+
--input: oklch(0.96 0.005 200);
|
|
272
|
+
--ring: oklch(0.60 0.18 275);
|
|
273
|
+
--chart-1: oklch(0.60 0.18 275);
|
|
274
|
+
--chart-2: oklch(0.60 0.15 145);
|
|
275
|
+
--chart-3: oklch(0.60 0.15 250);
|
|
276
|
+
--chart-4: oklch(0.65 0.25 340);
|
|
277
|
+
--chart-5: oklch(0.65 0.12 185);
|
|
278
|
+
|
|
279
|
+
--glass-bg: oklch(1 0 0 / 0.25);
|
|
280
|
+
--glass-bg-hover: oklch(1 0 0 / 0.35);
|
|
281
|
+
--glass-border: oklch(0.60 0.18 275 / 0.15);
|
|
282
|
+
--glass-shadow: 0 8px 32px 0 oklch(0.60 0.18 275 / 0.12);
|
|
283
|
+
--glass-blur: 16px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.dark {
|
|
287
|
+
--background: oklch(0.08 0.005 200);
|
|
288
|
+
--foreground: oklch(0.95 0.005 200);
|
|
289
|
+
--card: oklch(0.12 0.01 200);
|
|
290
|
+
--card-foreground: oklch(0.95 0.005 200);
|
|
291
|
+
--popover: oklch(0.12 0.01 200);
|
|
292
|
+
--popover-foreground: oklch(0.95 0.005 200);
|
|
293
|
+
--primary: oklch(41.145% 0.14945 272.396);
|
|
294
|
+
--primary-foreground: oklch(0.98 0.003 200);
|
|
295
|
+
--secondary: oklch(0.70 0.25 340);
|
|
296
|
+
--secondary-foreground: oklch(0.98 0.003 200);
|
|
297
|
+
--muted: oklch(0.15 0.01 200);
|
|
298
|
+
--muted-foreground: oklch(0.65 0.005 200);
|
|
299
|
+
--accent: oklch(0.70 0.15 185);
|
|
300
|
+
--accent-foreground: oklch(0.98 0.003 200);
|
|
301
|
+
--success: oklch(0.65 0.18 145);
|
|
302
|
+
--success-foreground: oklch(0.98 0.003 200);
|
|
303
|
+
--warning: oklch(0.75 0.18 65);
|
|
304
|
+
--warning-foreground: oklch(0.98 0.003 200);
|
|
305
|
+
--error: oklch(0.65 0.22 25);
|
|
306
|
+
--error-foreground: oklch(0.98 0.003 200);
|
|
307
|
+
--destructive: oklch(0.65 0.22 25);
|
|
308
|
+
--destructive-foreground: oklch(0.98 0.003 200);
|
|
309
|
+
--info: oklch(0.65 0.18 250);
|
|
310
|
+
--info-foreground: oklch(0.98 0.003 200);
|
|
311
|
+
--border: oklch(0.20 0.01 200);
|
|
312
|
+
--input: oklch(0.15 0.01 200);
|
|
313
|
+
--ring: oklch(0.68 0.20 275);
|
|
314
|
+
--chart-1: oklch(0.68 0.20 275);
|
|
315
|
+
--chart-2: oklch(0.65 0.18 145);
|
|
316
|
+
--chart-3: oklch(0.65 0.18 250);
|
|
317
|
+
--chart-4: oklch(0.70 0.25 340);
|
|
318
|
+
--chart-5: oklch(0.70 0.15 185);
|
|
319
|
+
|
|
320
|
+
--glass-bg: oklch(0.12 0.01 200 / 0.5);
|
|
321
|
+
--glass-bg-hover: oklch(0.12 0.01 200 / 0.7);
|
|
322
|
+
--glass-border: oklch(0.68 0.20 275 / 0.2);
|
|
323
|
+
--glass-shadow: 0 8px 32px 0 oklch(0 0 0 / 0.6);
|
|
324
|
+
--glass-blur: 16px;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
@layer base {
|
|
328
|
+
* {
|
|
329
|
+
@apply border-border outline-ring/50;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
body {
|
|
333
|
+
@apply bg-background text-foreground;
|
|
334
|
+
background: linear-gradient(
|
|
335
|
+
135deg,
|
|
336
|
+
oklch(0.98 0.003 200) 0%,
|
|
337
|
+
oklch(0.96 0.02 270) 50%,
|
|
338
|
+
oklch(0.98 0.02 340) 100%
|
|
339
|
+
);
|
|
340
|
+
background-attachment: fixed;
|
|
341
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
342
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
343
|
+
-webkit-font-smoothing: antialiased;
|
|
344
|
+
-moz-osx-font-smoothing: grayscale;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.dark body {
|
|
348
|
+
@apply text-foreground;
|
|
349
|
+
color: oklch(0.95 0.005 200);
|
|
350
|
+
background: linear-gradient(
|
|
351
|
+
135deg,
|
|
352
|
+
oklch(0.08 0.005 200) 0%,
|
|
353
|
+
oklch(0.10 0.01 200) 50%,
|
|
354
|
+
oklch(0.12 0.01 200) 100%
|
|
355
|
+
);
|
|
356
|
+
background-attachment: fixed;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.dark {
|
|
360
|
+
color-scheme: dark;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
@layer components {
|
|
365
|
+
.glass {
|
|
366
|
+
background: var(--glass-bg);
|
|
367
|
+
backdrop-filter: blur(var(--glass-blur)) saturate(180%);
|
|
368
|
+
-webkit-backdrop-filter: blur(var(--glass-blur)) saturate(180%);
|
|
369
|
+
border: 1px solid var(--glass-border);
|
|
370
|
+
box-shadow: var(--glass-shadow);
|
|
371
|
+
position: relative;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.glass::before {
|
|
375
|
+
content: '';
|
|
376
|
+
position: absolute;
|
|
377
|
+
inset: 0;
|
|
378
|
+
border-radius: inherit;
|
|
379
|
+
padding: 1px;
|
|
380
|
+
background: linear-gradient(
|
|
381
|
+
135deg,
|
|
382
|
+
oklch(1 0 0 / 0.4) 0%,
|
|
383
|
+
oklch(1 0 0 / 0.1) 50%,
|
|
384
|
+
oklch(1 0 0 / 0) 100%
|
|
385
|
+
);
|
|
386
|
+
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
387
|
+
-webkit-mask-composite: xor;
|
|
388
|
+
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
389
|
+
mask-composite: exclude;
|
|
390
|
+
pointer-events: none;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.dark .glass::before {
|
|
394
|
+
background: linear-gradient(
|
|
395
|
+
135deg,
|
|
396
|
+
oklch(0.68 0.20 275 / 0.3) 0%,
|
|
397
|
+
oklch(0.68 0.20 275 / 0.1) 50%,
|
|
398
|
+
oklch(0.68 0.20 275 / 0) 100%
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.glass-hover:hover {
|
|
403
|
+
background: var(--glass-bg-hover);
|
|
404
|
+
transform: translateY(-2px);
|
|
405
|
+
box-shadow: 0 12px 48px 0 oklch(0.60 0.18 275 / 0.2);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.dark .glass-hover:hover {
|
|
409
|
+
box-shadow: 0 12px 48px 0 oklch(0 0 0 / 0.7);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.glass-strong {
|
|
413
|
+
background: var(--glass-bg);
|
|
414
|
+
backdrop-filter: blur(24px) saturate(200%);
|
|
415
|
+
-webkit-backdrop-filter: blur(24px) saturate(200%);
|
|
416
|
+
border: 1px solid var(--glass-border);
|
|
417
|
+
box-shadow: var(--glass-shadow), inset 0 1px 0 oklch(1 0 0 / 0.3);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.dark .glass-strong {
|
|
421
|
+
box-shadow: var(--glass-shadow), inset 0 1px 0 oklch(0.68 0.20 275 / 0.2);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.glass-subtle {
|
|
425
|
+
background: var(--glass-bg);
|
|
426
|
+
backdrop-filter: blur(8px) saturate(150%);
|
|
427
|
+
-webkit-backdrop-filter: blur(8px) saturate(150%);
|
|
428
|
+
border: 1px solid var(--glass-border);
|
|
429
|
+
box-shadow: 0 1px 2px 0 oklch(0 0 0 / 0.05);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
@layer utilities {
|
|
434
|
+
@keyframes progress-stripes {
|
|
435
|
+
0% {
|
|
436
|
+
background-position: 0 0;
|
|
437
|
+
}
|
|
438
|
+
100% {
|
|
439
|
+
background-position: 1.5rem 0;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
@keyframes progress-indeterminate {
|
|
444
|
+
0% {
|
|
445
|
+
left: -40%;
|
|
446
|
+
transform: scaleX(0.6);
|
|
447
|
+
}
|
|
448
|
+
50% {
|
|
449
|
+
transform: scaleX(1);
|
|
450
|
+
}
|
|
451
|
+
100% {
|
|
452
|
+
left: 100%;
|
|
453
|
+
transform: scaleX(0.6);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
@keyframes progress-shimmer {
|
|
458
|
+
0% {
|
|
459
|
+
transform: translateX(-100%) scaleX(0);
|
|
460
|
+
opacity: 0;
|
|
461
|
+
}
|
|
462
|
+
10% {
|
|
463
|
+
opacity: 1;
|
|
464
|
+
}
|
|
465
|
+
50% {
|
|
466
|
+
transform: translateX(0%) scaleX(1);
|
|
467
|
+
}
|
|
468
|
+
90% {
|
|
469
|
+
opacity: 1;
|
|
470
|
+
}
|
|
471
|
+
100% {
|
|
472
|
+
transform: translateX(100%) scaleX(0);
|
|
473
|
+
opacity: 0;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
@keyframes progress-glow-pulse {
|
|
478
|
+
0%, 100% {
|
|
479
|
+
filter: brightness(1) saturate(1);
|
|
480
|
+
}
|
|
481
|
+
50% {
|
|
482
|
+
filter: brightness(1.15) saturate(1.2);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
@keyframes collapsible-down {
|
|
487
|
+
from {
|
|
488
|
+
height: 0;
|
|
489
|
+
opacity: 0;
|
|
490
|
+
}
|
|
491
|
+
to {
|
|
492
|
+
height: var(--radix-collapsible-content-height);
|
|
493
|
+
opacity: 1;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
@keyframes collapsible-up {
|
|
498
|
+
from {
|
|
499
|
+
height: var(--radix-collapsible-content-height);
|
|
500
|
+
opacity: 1;
|
|
501
|
+
}
|
|
502
|
+
to {
|
|
503
|
+
height: 0;
|
|
504
|
+
opacity: 0;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
.scrollbar-none {
|
|
509
|
+
-ms-overflow-style: none;
|
|
510
|
+
scrollbar-width: none;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.scrollbar-none::-webkit-scrollbar {
|
|
514
|
+
display: none;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
[role="menu"],
|
|
518
|
+
[role="listbox"] {
|
|
519
|
+
-ms-overflow-style: none;
|
|
520
|
+
scrollbar-width: none;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
[role="menu"]::-webkit-scrollbar,
|
|
524
|
+
[role="listbox"]::-webkit-scrollbar {
|
|
525
|
+
display: none;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
[contenteditable][data-placeholder]:empty:before {
|
|
529
|
+
content: attr(data-placeholder);
|
|
530
|
+
color: hsl(var(--muted-foreground));
|
|
531
|
+
opacity: 0.5;
|
|
532
|
+
pointer-events: none;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
[contenteditable]:focus:empty:before {
|
|
536
|
+
content: attr(data-placeholder);
|
|
537
|
+
color: hsl(var(--muted-foreground));
|
|
538
|
+
opacity: 0.3;
|
|
539
|
+
}
|
|
540
|
+
}`;
|
|
541
|
+
|
|
542
|
+
// CSS for Tailwind v3
|
|
543
|
+
const CSS_V3 = `@tailwind base;
|
|
544
|
+
@tailwind components;
|
|
545
|
+
@tailwind utilities;
|
|
546
|
+
|
|
547
|
+
:root {
|
|
548
|
+
--radius: 0.625rem;
|
|
549
|
+
--background: 0 0% 98%;
|
|
550
|
+
--foreground: 222 47% 11%;
|
|
551
|
+
--card: 0 0% 100%;
|
|
552
|
+
--card-foreground: 222 47% 11%;
|
|
553
|
+
--popover: 0 0% 100%;
|
|
554
|
+
--popover-foreground: 222 47% 11%;
|
|
555
|
+
--primary: 269 70% 48%;
|
|
556
|
+
--primary-foreground: 0 0% 100%;
|
|
557
|
+
--secondary: 340 75% 65%;
|
|
558
|
+
--secondary-foreground: 0 0% 100%;
|
|
559
|
+
--muted: 220 13% 95%;
|
|
560
|
+
--muted-foreground: 220 9% 46%;
|
|
561
|
+
--accent: 185 50% 65%;
|
|
562
|
+
--accent-foreground: 0 0% 100%;
|
|
563
|
+
--success: 145 60% 60%;
|
|
564
|
+
--success-foreground: 0 0% 100%;
|
|
565
|
+
--warning: 65 60% 70%;
|
|
566
|
+
--warning-foreground: 222 47% 11%;
|
|
567
|
+
--error: 25 80% 60%;
|
|
568
|
+
--error-foreground: 0 0% 100%;
|
|
569
|
+
--destructive: 25 80% 60%;
|
|
570
|
+
--destructive-foreground: 0 0% 100%;
|
|
571
|
+
--info: 250 60% 60%;
|
|
572
|
+
--info-foreground: 0 0% 100%;
|
|
573
|
+
--border: 220 13% 91%;
|
|
574
|
+
--input: 220 13% 95%;
|
|
575
|
+
--ring: 275 70% 60%;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.dark {
|
|
579
|
+
--background: 222 47% 8%;
|
|
580
|
+
--foreground: 220 13% 95%;
|
|
581
|
+
--card: 222 47% 12%;
|
|
582
|
+
--card-foreground: 220 13% 95%;
|
|
583
|
+
--popover: 222 47% 12%;
|
|
584
|
+
--popover-foreground: 220 13% 95%;
|
|
585
|
+
--primary: 272 60% 41%;
|
|
586
|
+
--primary-foreground: 0 0% 98%;
|
|
587
|
+
--secondary: 340 75% 70%;
|
|
588
|
+
--secondary-foreground: 0 0% 98%;
|
|
589
|
+
--muted: 222 47% 15%;
|
|
590
|
+
--muted-foreground: 220 13% 65%;
|
|
591
|
+
--accent: 185 60% 70%;
|
|
592
|
+
--accent-foreground: 0 0% 98%;
|
|
593
|
+
--success: 145 70% 65%;
|
|
594
|
+
--success-foreground: 0 0% 98%;
|
|
595
|
+
--warning: 65 70% 75%;
|
|
596
|
+
--warning-foreground: 0 0% 98%;
|
|
597
|
+
--error: 25 85% 65%;
|
|
598
|
+
--error-foreground: 0 0% 98%;
|
|
599
|
+
--destructive: 25 85% 65%;
|
|
600
|
+
--destructive-foreground: 0 0% 98%;
|
|
601
|
+
--info: 250 70% 65%;
|
|
602
|
+
--info-foreground: 0 0% 98%;
|
|
603
|
+
--border: 222 47% 20%;
|
|
604
|
+
--input: 222 47% 15%;
|
|
605
|
+
--ring: 275 75% 68%;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
@layer base {
|
|
609
|
+
* {
|
|
610
|
+
@apply border-border;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
body {
|
|
614
|
+
@apply bg-background text-foreground;
|
|
615
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
616
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
617
|
+
-webkit-font-smoothing: antialiased;
|
|
618
|
+
-moz-osx-font-smoothing: grayscale;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
@layer components {
|
|
623
|
+
.glass {
|
|
624
|
+
background: rgba(255, 255, 255, 0.25);
|
|
625
|
+
backdrop-filter: blur(16px) saturate(180%);
|
|
626
|
+
-webkit-backdrop-filter: blur(16px) saturate(180%);
|
|
627
|
+
border: 1px solid rgba(255, 255, 255, 0.18);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.dark .glass {
|
|
631
|
+
background: rgba(18, 18, 23, 0.5);
|
|
632
|
+
border: 1px solid rgba(139, 92, 246, 0.2);
|
|
633
|
+
}
|
|
634
|
+
}`;
|
|
635
|
+
|
|
636
|
+
// ----------------------------------------------
|
|
637
|
+
// Update Tailwind config for v3 (manual hints)
|
|
638
|
+
// ----------------------------------------------
|
|
639
|
+
const updateTailwindConfig = () => {
|
|
640
|
+
const configFiles = [
|
|
641
|
+
"tailwind.config.js",
|
|
642
|
+
"tailwind.config.ts",
|
|
643
|
+
"tailwind.config.mjs",
|
|
644
|
+
"tailwind.config.cjs",
|
|
645
|
+
];
|
|
646
|
+
|
|
647
|
+
let configPath = null;
|
|
648
|
+
for (const cf of configFiles) {
|
|
649
|
+
const p = path.join(R, cf);
|
|
650
|
+
if (fE(p)) {
|
|
651
|
+
configPath = p;
|
|
652
|
+
break;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
if (!configPath) {
|
|
657
|
+
console.warn("⚠️ Warning: Could not find Tailwind config file");
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
172
660
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
661
|
+
const config = rd(configPath);
|
|
662
|
+
|
|
663
|
+
if (config.includes("theme:") && config.includes("extend:")) {
|
|
664
|
+
console.log("ℹ️ Tailwind config already has theme.extend");
|
|
665
|
+
console.log("\n📝 Please manually add these to your tailwind.config:");
|
|
666
|
+
console.log(`
|
|
667
|
+
theme: {
|
|
668
|
+
extend: {
|
|
669
|
+
colors: {
|
|
670
|
+
border: "hsl(var(--border))",
|
|
671
|
+
input: "hsl(var(--input))",
|
|
672
|
+
ring: "hsl(var(--ring))",
|
|
673
|
+
background: "hsl(var(--background))",
|
|
674
|
+
foreground: "hsl(var(--foreground))",
|
|
675
|
+
primary: { DEFAULT: "hsl(var(--primary))", foreground: "hsl(var(--primary-foreground))" },
|
|
676
|
+
secondary: { DEFAULT: "hsl(var(--secondary))", foreground: "hsl(var(--secondary-foreground))" },
|
|
677
|
+
muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))" },
|
|
678
|
+
accent: { DEFAULT: "hsl(var(--accent))", foreground: "hsl(var(--accent-foreground))" },
|
|
679
|
+
destructive: { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))" },
|
|
680
|
+
success: { DEFAULT: "hsl(var(--success))", foreground: "hsl(var(--success-foreground))" },
|
|
681
|
+
warning: { DEFAULT: "hsl(var(--warning))", foreground: "hsl(var(--warning-foreground))" },
|
|
682
|
+
error: { DEFAULT: "hsl(var(--error))", foreground: "hsl(var(--error-foreground))" },
|
|
683
|
+
info: { DEFAULT: "hsl(var(--info))", foreground: "hsl(var(--info-foreground))" },
|
|
684
|
+
card: { DEFAULT: "hsl(var(--card))", foreground: "hsl(var(--card-foreground))" },
|
|
685
|
+
popover: { DEFAULT: "hsl(var(--popover))", foreground: "hsl(var(--popover-foreground))" },
|
|
686
|
+
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))" },
|
|
687
|
+
},
|
|
688
|
+
borderRadius: {
|
|
689
|
+
lg: "var(--radius)",
|
|
690
|
+
md: "calc(var(--radius) - 2px)",
|
|
691
|
+
sm: "calc(var(--radius) - 4px)",
|
|
692
|
+
},
|
|
693
|
+
keyframes: {
|
|
694
|
+
"progress-stripes": { "0%": { backgroundPosition: "0 0" }, "100%": { backgroundPosition: "1.5rem 0" } },
|
|
695
|
+
"progress-indeterminate": { "0%": { left: "-40%", transform: "scaleX(0.6)" }, "50%": { transform: "scaleX(1)" }, "100%": { left: "100%", transform: "scaleX(0.6)" } },
|
|
696
|
+
"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" } },
|
|
697
|
+
"progress-glow-pulse": { "0%, 100%": { filter: "brightness(1) saturate(1)" }, "50%": { filter: "brightness(1.15) saturate(1.2)" } },
|
|
698
|
+
"collapsible-down": { from: { height: "0", opacity: "0" }, to: { height: "var(--radix-collapsible-content-height)", opacity: "1" } },
|
|
699
|
+
"collapsible-up": { from: { height: "var(--radix-collapsible-content-height)", opacity: "1" }, to: { height: "0", opacity: "0" } },
|
|
700
|
+
},
|
|
701
|
+
animation: {
|
|
702
|
+
"progress-stripes": "progress-stripes 1s linear infinite",
|
|
703
|
+
"progress-indeterminate": "progress-indeterminate 1.5s ease-in-out infinite",
|
|
704
|
+
"progress-shimmer": "progress-shimmer 2s ease-in-out infinite",
|
|
705
|
+
"progress-glow-pulse": "progress-glow-pulse 2s ease-in-out infinite",
|
|
706
|
+
"collapsible-down": "collapsible-down 0.2s ease-out",
|
|
707
|
+
"collapsible-up": "collapsible-up 0.2s ease-out",
|
|
708
|
+
},
|
|
709
|
+
},
|
|
710
|
+
}
|
|
711
|
+
`);
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
// ----------------------------------------------
|
|
716
|
+
// Inject
|
|
717
|
+
// ----------------------------------------------
|
|
718
|
+
const inject = (f, tailwindInfo) => {
|
|
719
|
+
const ex = fE(f);
|
|
720
|
+
const cur = ex ? rd(f) : "";
|
|
721
|
+
|
|
722
|
+
if (cur.includes(M)) {
|
|
723
|
+
console.log(`✅ saha-ui: CSS already injected in ${path.relative(R, f)}`);
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const hasTailwindV4Import = TW.test(cur);
|
|
728
|
+
const hasTailwindV3Import = cur.includes("@tailwind");
|
|
729
|
+
const hasTailwindImport = hasTailwindV4Import || hasTailwindV3Import;
|
|
730
|
+
|
|
731
|
+
const CSS = tailwindInfo.major >= 4 ? CSS_V4 : CSS_V3;
|
|
732
|
+
|
|
733
|
+
let cssToInject = CSS;
|
|
734
|
+
if (hasTailwindImport) {
|
|
735
|
+
if (hasTailwindV4Import) {
|
|
736
|
+
cssToInject = CSS.replace(/^@import\s+["']tailwindcss["'];?\n*/, "").trim();
|
|
737
|
+
} else if (hasTailwindV3Import) {
|
|
738
|
+
cssToInject = CSS.replace(/@tailwind\s+(base|components|utilities);?\n*/g, "").trim();
|
|
739
|
+
}
|
|
740
|
+
}
|
|
176
741
|
|
|
742
|
+
let out;
|
|
743
|
+
if (hasTailwindV4Import) {
|
|
744
|
+
out = cur.replace(TW, (m) => `${m}\n${M}\n${cssToInject}`);
|
|
745
|
+
} else if (hasTailwindV3Import) {
|
|
746
|
+
const tailwindDirectives = cur.match(/@tailwind\s+(base|components|utilities);?\n*/g);
|
|
747
|
+
if (tailwindDirectives) {
|
|
748
|
+
const lastDirective = tailwindDirectives[ tailwindDirectives.length - 1 ];
|
|
749
|
+
const lastIndex = cur.lastIndexOf(lastDirective);
|
|
750
|
+
const beforeDirective = cur.substring(0, lastIndex + lastDirective.length);
|
|
751
|
+
const afterDirective = cur.substring(lastIndex + lastDirective.length);
|
|
752
|
+
out = `${beforeDirective}\n${M}\n${cssToInject}\n${afterDirective}`;
|
|
753
|
+
} else {
|
|
754
|
+
out = `${M}\n${cssToInject}\n\n${cur}`;
|
|
755
|
+
}
|
|
756
|
+
} else {
|
|
757
|
+
out = `${M}\n${CSS}\n\n${cur}`;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
wr(f, out);
|
|
761
|
+
console.log(`\n✅ saha-ui: Injected CSS into ${path.relative(R, f)} (${F})`);
|
|
762
|
+
console.log(`📦 Using Tailwind v${tailwindInfo.major} configuration`);
|
|
763
|
+
|
|
764
|
+
if (tailwindInfo.major < 4) {
|
|
765
|
+
console.log("\n⚠️ Tailwind v3 detected - you may need to update your tailwind.config");
|
|
766
|
+
updateTailwindConfig();
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (!ex) {
|
|
770
|
+
if (F === "next") {
|
|
771
|
+
console.log("\n📝 Next steps:");
|
|
772
|
+
console.log(" - Ensure root layout imports this CSS:");
|
|
773
|
+
console.log(" app/layout.tsx -> import './globals.css'");
|
|
774
|
+
} else {
|
|
775
|
+
console.log("\n📝 Next steps:");
|
|
776
|
+
console.log(" - Ensure src/main.tsx imports './index.css'");
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
// ----------------------------------------------
|
|
782
|
+
// Main
|
|
783
|
+
// ----------------------------------------------
|
|
177
784
|
const run = () => {
|
|
178
785
|
if (c !== "init") {
|
|
179
786
|
console.log("Usage: npx saha-ui init");
|
|
@@ -182,13 +789,27 @@ const run = () => {
|
|
|
182
789
|
|
|
183
790
|
console.log("\n🚀 Initializing saha-ui...\n");
|
|
184
791
|
|
|
185
|
-
|
|
186
|
-
|
|
792
|
+
// 1) Determine Tailwind version from package.json only
|
|
793
|
+
const tailwindInfo = assertTailwindFromPkgJson();
|
|
187
794
|
|
|
188
|
-
//
|
|
795
|
+
// 2) For v3, ensure config exists. For v4, no mandatory CLI/PostCSS check.
|
|
796
|
+
if (tailwindInfo.major < 4) {
|
|
797
|
+
assertTailwindV3ConfigPresent();
|
|
798
|
+
} else {
|
|
799
|
+
console.log("ℹ️ Tailwind v4 detected. PostCSS/CLI are optional; proceeding to inject CSS.");
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// 3) Proceed only if React is present
|
|
803
|
+
assertReactPresent();
|
|
804
|
+
|
|
805
|
+
// 4) Ensure saha-ui is installed, then install its deps to the main project
|
|
806
|
+
ensureSahaUIInstalled();
|
|
189
807
|
installSahaUIDeps();
|
|
190
808
|
|
|
191
|
-
|
|
809
|
+
// 5) Inject CSS (v4: just CSS; v3: CSS + config hints)
|
|
810
|
+
inject(pick(), tailwindInfo);
|
|
811
|
+
|
|
812
|
+
console.log("\n✨ Done!\n");
|
|
192
813
|
};
|
|
193
814
|
|
|
194
|
-
run();
|
|
815
|
+
run();
|