starwind 0.0.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/LICENSE +21 -0
- package/README.md +39 -0
- package/dist/chunk-JUEM67WU.js +621 -0
- package/dist/chunk-JUEM67WU.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +638 -0
- package/dist/index.js.map +1 -0
- package/dist/init-JA2KC6GS.js +7 -0
- package/dist/init-JA2KC6GS.js.map +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Boston343 (webreaper)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Starwind
|
|
2
|
+
|
|
3
|
+
A CLI for adding Astro components to your project.
|
|
4
|
+
|
|
5
|
+
## Initialization
|
|
6
|
+
|
|
7
|
+
Use the `init` command to initialize your project:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx starwind@latest init
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Adding Components
|
|
14
|
+
|
|
15
|
+
Use the `add` command to add components to your project:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx starwind@latest add [components...]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Example
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npx starwind@latest add button
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
You can also run the command without any argument to view a list of available components:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx starwind@latest add
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Documentation
|
|
34
|
+
|
|
35
|
+
Visit [https://starwind.dev/](https://starwind.dev/) to view the documentation.
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
Licensed under the [MIT license](https://github.com/boston343/starwind-ui/blob/main/LICENSE).
|
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
// src/commands/init.ts
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
// src/templates/starwind.css.ts
|
|
5
|
+
var tailwindConfig = `@import "tailwindcss";
|
|
6
|
+
@plugin "tailwindcss-animate";
|
|
7
|
+
@plugin "@tailwindcss/forms";
|
|
8
|
+
@variant dark (&:where(.dark, .dark *));
|
|
9
|
+
|
|
10
|
+
@theme {
|
|
11
|
+
--animate-accordion-down: accordion-down 0.2s ease-out;
|
|
12
|
+
--animate-accordion-up: accordion-up 0.2s ease-out;
|
|
13
|
+
|
|
14
|
+
@keyframes accordion-down {
|
|
15
|
+
from {
|
|
16
|
+
height: 0;
|
|
17
|
+
}
|
|
18
|
+
to {
|
|
19
|
+
height: var(--starwind-accordion-content-height);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@keyframes accordion-up {
|
|
24
|
+
from {
|
|
25
|
+
height: var(--starwind-accordion-content-height);
|
|
26
|
+
}
|
|
27
|
+
to {
|
|
28
|
+
height: 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@theme inline {
|
|
34
|
+
--color-background: var(--background);
|
|
35
|
+
--color-foreground: var(--foreground);
|
|
36
|
+
--color-card: var(--card);
|
|
37
|
+
--color-card-foreground: var(--card-foreground);
|
|
38
|
+
--color-popover: var(--popover);
|
|
39
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
40
|
+
--color-primary: var(--primary);
|
|
41
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
42
|
+
--color-secondary: var(--secondary);
|
|
43
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
44
|
+
--color-muted: var(--muted);
|
|
45
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
46
|
+
--color-accent: var(--accent);
|
|
47
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
48
|
+
--color-info: var(--info);
|
|
49
|
+
--color-info-foreground: var(--info-foreground);
|
|
50
|
+
--color-success: var(--success);
|
|
51
|
+
--color-success-foreground: var(--success-foreground);
|
|
52
|
+
--color-warning: var(--warning);
|
|
53
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
54
|
+
--color-error: var(--error);
|
|
55
|
+
--color-error-foreground: var(--error-foreground);
|
|
56
|
+
--color-border: var(--border);
|
|
57
|
+
--color-input: var(--input);
|
|
58
|
+
--color-outline: var(--outline);
|
|
59
|
+
|
|
60
|
+
--radius-xs: calc(var(--radius) - 0.375rem);
|
|
61
|
+
--radius-sm: calc(var(--radius) - 0.25rem);
|
|
62
|
+
--radius-md: calc(var(--radius) - 0.125rem);
|
|
63
|
+
--radius-lg: var(--radius);
|
|
64
|
+
--radius-xl: calc(var(--radius) + 0.25rem);
|
|
65
|
+
--radius-2xl: calc(var(--radius) + 0.5rem);
|
|
66
|
+
--radius-3xl: calc(var(--radius) + 1rem);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
@layer base {
|
|
70
|
+
:root {
|
|
71
|
+
--background: var(--color-neutral-50);
|
|
72
|
+
--foreground: var(--color-neutral-950);
|
|
73
|
+
--card: var(--color-neutral-50);
|
|
74
|
+
--card-foreground: var(--color-neutral-950);
|
|
75
|
+
--popover: var(--color-neutral-50);
|
|
76
|
+
--popover-foreground: var(--color-neutral-950);
|
|
77
|
+
--primary: var(--color-blue-700);
|
|
78
|
+
--primary-foreground: var(--color-neutral-50);
|
|
79
|
+
--secondary: var(--color-fuchsia-700);
|
|
80
|
+
--secondary-foreground: var(--color-neutral-50);
|
|
81
|
+
--muted: var(--color-neutral-100);
|
|
82
|
+
--muted-foreground: var(--color-neutral-600);
|
|
83
|
+
--accent: var(--color-neutral-200);
|
|
84
|
+
--accent-foreground: var(--color-neutral-900);
|
|
85
|
+
--info: var(--color-sky-300);
|
|
86
|
+
--info-foreground: var(--color-sky-950);
|
|
87
|
+
--success: var(--color-green-300);
|
|
88
|
+
--success-foreground: var(--color-green-950);
|
|
89
|
+
--warning: var(--color-amber-300);
|
|
90
|
+
--warning-foreground: var(--color-amber-950);
|
|
91
|
+
--error: var(--color-red-700);
|
|
92
|
+
--error-foreground: var(--color-neutral-50);
|
|
93
|
+
--border: var(--color-neutral-200);
|
|
94
|
+
--input: var(--color-neutral-200);
|
|
95
|
+
--outline: var(--color-blue-600);
|
|
96
|
+
--radius: 0.5rem;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.dark {
|
|
100
|
+
--background: var(--color-neutral-950);
|
|
101
|
+
--foreground: var(--color-neutral-50);
|
|
102
|
+
--card: var(--color-neutral-950);
|
|
103
|
+
--card-foreground: var(--color-neutral-50);
|
|
104
|
+
--popover: var(--color-neutral-950);
|
|
105
|
+
--popover-foreground: var(--color-neutral-50);
|
|
106
|
+
--primary: var(--color-blue-700);
|
|
107
|
+
--primary-foreground: var(--color-neutral-50);
|
|
108
|
+
--secondary: var(--color-fuchsia-300);
|
|
109
|
+
--secondary-foreground: var(--color-neutral-950);
|
|
110
|
+
--muted: var(--color-neutral-900);
|
|
111
|
+
--muted-foreground: var(--color-neutral-400);
|
|
112
|
+
--accent: var(--color-neutral-900);
|
|
113
|
+
--accent-foreground: var(--color-neutral-100);
|
|
114
|
+
--info: var(--color-sky-300);
|
|
115
|
+
--info-foreground: var(--color-sky-950);
|
|
116
|
+
--success: var(--color-green-300);
|
|
117
|
+
--success-foreground: var(--color-green-950);
|
|
118
|
+
--warning: var(--color-amber-300);
|
|
119
|
+
--warning-foreground: var(--color-amber-950);
|
|
120
|
+
--error: var(--color-red-800);
|
|
121
|
+
--error-foreground: var(--color-neutral-50);
|
|
122
|
+
--border: var(--color-neutral-800);
|
|
123
|
+
--input: var(--color-neutral-800);
|
|
124
|
+
--outline: var(--color-blue-600);
|
|
125
|
+
--radius: 0.5rem;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
* {
|
|
129
|
+
@apply border-border;
|
|
130
|
+
}
|
|
131
|
+
*:focus-visible {
|
|
132
|
+
@apply outline-outline;
|
|
133
|
+
}
|
|
134
|
+
html {
|
|
135
|
+
@apply bg-background text-foreground scheme-light dark:scheme-dark;
|
|
136
|
+
}
|
|
137
|
+
button {
|
|
138
|
+
@apply cursor-pointer;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@layer utilities {
|
|
143
|
+
/* transition-colors but without outline-color transition property */
|
|
144
|
+
.starwind-transition-colors {
|
|
145
|
+
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke,
|
|
146
|
+
--tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
|
|
147
|
+
transition-timing-function: var(--default-transition-timing-function);
|
|
148
|
+
transition-duration: var(--default-transition-duration);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
`;
|
|
152
|
+
|
|
153
|
+
// src/utils/highlighter.ts
|
|
154
|
+
import chalk from "chalk";
|
|
155
|
+
var highlighter = {
|
|
156
|
+
error: chalk.red,
|
|
157
|
+
warn: chalk.yellow,
|
|
158
|
+
info: chalk.cyan,
|
|
159
|
+
infoBright: chalk.cyanBright,
|
|
160
|
+
success: chalk.greenBright,
|
|
161
|
+
underline: chalk.underline,
|
|
162
|
+
title: chalk.bgBlue
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// src/utils/astro-config.ts
|
|
166
|
+
import * as p from "@clack/prompts";
|
|
167
|
+
import fs2 from "fs-extra";
|
|
168
|
+
|
|
169
|
+
// src/utils/fs.ts
|
|
170
|
+
import fs from "fs-extra";
|
|
171
|
+
async function ensureDirectory(dir) {
|
|
172
|
+
await fs.ensureDir(dir);
|
|
173
|
+
}
|
|
174
|
+
async function readJsonFile(filePath) {
|
|
175
|
+
return fs.readJson(filePath);
|
|
176
|
+
}
|
|
177
|
+
async function writeJsonFile(filePath, data) {
|
|
178
|
+
await fs.writeJson(filePath, data, { spaces: 2 });
|
|
179
|
+
}
|
|
180
|
+
async function fileExists(filePath) {
|
|
181
|
+
return fs.pathExists(filePath);
|
|
182
|
+
}
|
|
183
|
+
async function writeCssFile(filePath, content) {
|
|
184
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// src/utils/astro-config.ts
|
|
188
|
+
var CONFIG_EXTENSIONS = ["ts", "js", "mjs", "cjs"];
|
|
189
|
+
async function findAstroConfig() {
|
|
190
|
+
for (const ext of CONFIG_EXTENSIONS) {
|
|
191
|
+
const configPath = `astro.config.${ext}`;
|
|
192
|
+
if (await fileExists(configPath)) {
|
|
193
|
+
return configPath;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
async function setupAstroConfig() {
|
|
199
|
+
try {
|
|
200
|
+
let configPath = await findAstroConfig();
|
|
201
|
+
let content = "";
|
|
202
|
+
if (configPath) {
|
|
203
|
+
content = await fs2.readFile(configPath, "utf-8");
|
|
204
|
+
} else {
|
|
205
|
+
configPath = "astro.config.ts";
|
|
206
|
+
content = `import { defineConfig } from "astro/config";
|
|
207
|
+
|
|
208
|
+
export default defineConfig({});
|
|
209
|
+
`;
|
|
210
|
+
}
|
|
211
|
+
if (!content.includes('import tailwindcss from "@tailwindcss/vite"')) {
|
|
212
|
+
content = `import tailwindcss from "@tailwindcss/vite";
|
|
213
|
+
${content}`;
|
|
214
|
+
}
|
|
215
|
+
const configStart = content.indexOf("defineConfig(") + "defineConfig(".length;
|
|
216
|
+
const configEnd = content.lastIndexOf(");");
|
|
217
|
+
let config = content.slice(configStart, configEnd);
|
|
218
|
+
config = config.trim().replace(/^{|}$/g, "").trim();
|
|
219
|
+
if (!config.includes("experimental")) {
|
|
220
|
+
config += `
|
|
221
|
+
experimental: {
|
|
222
|
+
svg: {
|
|
223
|
+
mode: "sprite",
|
|
224
|
+
},
|
|
225
|
+
},`;
|
|
226
|
+
} else if (!config.includes("svg: {")) {
|
|
227
|
+
const expEnd = config.indexOf("experimental:") + "experimental:".length;
|
|
228
|
+
const blockStart = config.indexOf("{", expEnd) + 1;
|
|
229
|
+
config = config.slice(0, blockStart) + `
|
|
230
|
+
svg: {
|
|
231
|
+
mode: "sprite",
|
|
232
|
+
},` + config.slice(blockStart);
|
|
233
|
+
}
|
|
234
|
+
if (!config.includes("vite:")) {
|
|
235
|
+
config += `
|
|
236
|
+
vite: {
|
|
237
|
+
plugins: [tailwindcss()],
|
|
238
|
+
},`;
|
|
239
|
+
} else if (!config.includes("plugins: [")) {
|
|
240
|
+
const viteEnd = config.indexOf("vite:") + "vite:".length;
|
|
241
|
+
const blockStart = config.indexOf("{", viteEnd) + 1;
|
|
242
|
+
config = config.slice(0, blockStart) + `
|
|
243
|
+
plugins: [tailwindcss()],` + config.slice(blockStart);
|
|
244
|
+
} else if (!config.includes("tailwindcss()")) {
|
|
245
|
+
const pluginsStart = config.indexOf("plugins:") + "plugins:".length;
|
|
246
|
+
const arrayStart = config.indexOf("[", pluginsStart) + 1;
|
|
247
|
+
config = config.slice(0, arrayStart) + `tailwindcss(), ` + config.slice(arrayStart);
|
|
248
|
+
}
|
|
249
|
+
const newContent = `${content.slice(0, configStart)}{
|
|
250
|
+
${config}
|
|
251
|
+
}${content.slice(configEnd)}`;
|
|
252
|
+
await fs2.writeFile(configPath, newContent, "utf-8");
|
|
253
|
+
return true;
|
|
254
|
+
} catch (error) {
|
|
255
|
+
const errorMessage = error instanceof Error ? error.message : "An unknown error occurred";
|
|
256
|
+
p.log.error(highlighter.error(`Failed to setup Astro config: ${errorMessage}`));
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// src/utils/constants.ts
|
|
262
|
+
var MIN_ASTRO_VERSION = "5.0.0";
|
|
263
|
+
var PATHS = {
|
|
264
|
+
STARWIND_CORE: "@starwind-ui/core",
|
|
265
|
+
STARWIND_CORE_COMPONENTS: "src/components",
|
|
266
|
+
STARWIND_CORE_REGISTRY: "registry.json",
|
|
267
|
+
LOCAL_CSS_FILE: "src/styles/starwind.css",
|
|
268
|
+
LOCAL_CONFIG_FILE: "starwind.config.json",
|
|
269
|
+
LOCAL_STYLES_DIR: "src/styles",
|
|
270
|
+
LOCAL_COMPONENTS_DIR: "src/components"
|
|
271
|
+
};
|
|
272
|
+
var ASTRO_PACKAGES = {
|
|
273
|
+
core: "astro@latest"
|
|
274
|
+
};
|
|
275
|
+
var OTHER_PACKAGES = {
|
|
276
|
+
tailwindCore: "tailwindcss@latest",
|
|
277
|
+
tailwindVite: "@tailwindcss/vite@latest",
|
|
278
|
+
tailwindForms: "@tailwindcss/forms@latest",
|
|
279
|
+
tailwindAnimate: "tailwindcss-animate@latest",
|
|
280
|
+
tablerIcons: "@tabler/icons@latest"
|
|
281
|
+
};
|
|
282
|
+
function getOtherPackages() {
|
|
283
|
+
return Object.values(OTHER_PACKAGES);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// src/utils/config.ts
|
|
287
|
+
var defaultConfig = {
|
|
288
|
+
tailwind: {
|
|
289
|
+
css: "src/styles/starwind.css",
|
|
290
|
+
baseColor: "gray",
|
|
291
|
+
cssVariables: true
|
|
292
|
+
},
|
|
293
|
+
// aliases: {
|
|
294
|
+
// components: "@/components",
|
|
295
|
+
// },
|
|
296
|
+
componentDir: "src/components/starwind",
|
|
297
|
+
components: []
|
|
298
|
+
};
|
|
299
|
+
async function getConfig() {
|
|
300
|
+
try {
|
|
301
|
+
if (await fileExists(PATHS.LOCAL_CONFIG_FILE)) {
|
|
302
|
+
const config = await readJsonFile(PATHS.LOCAL_CONFIG_FILE);
|
|
303
|
+
return {
|
|
304
|
+
...defaultConfig,
|
|
305
|
+
...config,
|
|
306
|
+
components: Array.isArray(config.components) ? config.components : []
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
} catch (error) {
|
|
310
|
+
console.error("Error reading config:", error);
|
|
311
|
+
}
|
|
312
|
+
return defaultConfig;
|
|
313
|
+
}
|
|
314
|
+
async function updateConfig(updates, options = { appendComponents: true }) {
|
|
315
|
+
const currentConfig = await getConfig();
|
|
316
|
+
const currentComponents = Array.isArray(currentConfig.components) ? currentConfig.components : [];
|
|
317
|
+
const newConfig = {
|
|
318
|
+
...currentConfig,
|
|
319
|
+
tailwind: {
|
|
320
|
+
...currentConfig.tailwind,
|
|
321
|
+
...updates.tailwind || {}
|
|
322
|
+
},
|
|
323
|
+
componentDir: updates.componentDir ? updates.componentDir : currentConfig.componentDir,
|
|
324
|
+
components: updates.components ? options.appendComponents ? [...currentComponents, ...updates.components] : updates.components : currentComponents
|
|
325
|
+
};
|
|
326
|
+
try {
|
|
327
|
+
await writeJsonFile(PATHS.LOCAL_CONFIG_FILE, newConfig);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
throw new Error(
|
|
330
|
+
`Failed to update config: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/utils/package-manager.ts
|
|
336
|
+
import * as p2 from "@clack/prompts";
|
|
337
|
+
import { execa } from "execa";
|
|
338
|
+
async function requestPackageManager() {
|
|
339
|
+
const pm = await p2.select({
|
|
340
|
+
message: "Select your preferred package manager",
|
|
341
|
+
options: [
|
|
342
|
+
{ value: "pnpm", label: "pnpm", hint: "Default" },
|
|
343
|
+
{ value: "npm", label: "npm" },
|
|
344
|
+
{ value: "yarn", label: "yarn" },
|
|
345
|
+
{ value: "bun", label: "bun" }
|
|
346
|
+
]
|
|
347
|
+
});
|
|
348
|
+
if (p2.isCancel(pm)) {
|
|
349
|
+
p2.log.warn("No package manager selected, defaulting to npm");
|
|
350
|
+
return "npm";
|
|
351
|
+
}
|
|
352
|
+
return pm;
|
|
353
|
+
}
|
|
354
|
+
async function installDependencies(packages, pm, dev = false, force = false) {
|
|
355
|
+
const args = [
|
|
356
|
+
pm === "npm" ? "install" : "add",
|
|
357
|
+
...packages,
|
|
358
|
+
dev ? pm === "npm" || pm === "pnpm" ? "-D" : "--dev" : "",
|
|
359
|
+
force ? "--force" : ""
|
|
360
|
+
].filter(Boolean);
|
|
361
|
+
await execa(pm, args);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// src/utils/sleep.ts
|
|
365
|
+
var sleep = async (ms) => {
|
|
366
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// src/commands/init.ts
|
|
370
|
+
import * as p3 from "@clack/prompts";
|
|
371
|
+
import semver from "semver";
|
|
372
|
+
async function init(withinAdd = false) {
|
|
373
|
+
if (!withinAdd) {
|
|
374
|
+
p3.intro(highlighter.title(" Welcome to the Starwind CLI "));
|
|
375
|
+
}
|
|
376
|
+
try {
|
|
377
|
+
if (!await fileExists("package.json")) {
|
|
378
|
+
throw new Error(
|
|
379
|
+
"No package.json found. Please run this command in the root of your project."
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
const pkg = await readJsonFile("package.json");
|
|
383
|
+
const installTasks = [];
|
|
384
|
+
const configTasks = [];
|
|
385
|
+
const configChoices = await p3.group(
|
|
386
|
+
{
|
|
387
|
+
// ask where to install components
|
|
388
|
+
installLocation: () => p3.text({
|
|
389
|
+
message: "What is your components directory?",
|
|
390
|
+
placeholder: PATHS.LOCAL_COMPONENTS_DIR,
|
|
391
|
+
initialValue: PATHS.LOCAL_COMPONENTS_DIR,
|
|
392
|
+
validate(value) {
|
|
393
|
+
if (value.length === 0) return `Value is required!`;
|
|
394
|
+
if (path.isAbsolute(value)) return `Please use a relative path`;
|
|
395
|
+
if (value.includes("..")) return `Path traversal is not allowed`;
|
|
396
|
+
const invalidChars = /[<>:"|?*]/;
|
|
397
|
+
if (invalidChars.test(value)) return `Path contains invalid characters`;
|
|
398
|
+
const systemDirs = ["windows", "program files", "system32"];
|
|
399
|
+
if (systemDirs.some((dir) => value.toLowerCase().startsWith(dir))) {
|
|
400
|
+
return `Cannot install in system directories`;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}),
|
|
404
|
+
// ask where to add the css file
|
|
405
|
+
cssFile: () => p3.text({
|
|
406
|
+
message: `Where would you like to add the Tailwind ${highlighter.info(".css")} file?`,
|
|
407
|
+
placeholder: PATHS.LOCAL_CSS_FILE,
|
|
408
|
+
initialValue: PATHS.LOCAL_CSS_FILE,
|
|
409
|
+
validate(value) {
|
|
410
|
+
if (value.length === 0) return `Value is required!`;
|
|
411
|
+
if (!value.endsWith(".css")) return `File must end with .css extension`;
|
|
412
|
+
if (path.isAbsolute(value)) return `Please use a relative path`;
|
|
413
|
+
if (value.includes("..")) return `Path traversal is not allowed`;
|
|
414
|
+
const invalidChars = /[<>:"|?*]/;
|
|
415
|
+
if (invalidChars.test(value)) return `Path contains invalid characters`;
|
|
416
|
+
const systemDirs = ["windows", "program files", "system32"];
|
|
417
|
+
if (systemDirs.some((dir) => value.toLowerCase().startsWith(dir))) {
|
|
418
|
+
return `Cannot use system directories`;
|
|
419
|
+
}
|
|
420
|
+
const basename = path.basename(value, ".css");
|
|
421
|
+
if (!basename || basename.trim().length === 0) {
|
|
422
|
+
return `Invalid filename`;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}),
|
|
426
|
+
twBaseColor: () => p3.select({
|
|
427
|
+
message: "What Tailwind base color would you like to use?",
|
|
428
|
+
initialValue: "neutral",
|
|
429
|
+
options: [
|
|
430
|
+
{ label: "Neutral (default)", value: "neutral" },
|
|
431
|
+
{ label: "Stone", value: "stone" },
|
|
432
|
+
{ label: "Zinc", value: "zinc" },
|
|
433
|
+
{ label: "Gray", value: "gray" },
|
|
434
|
+
{ label: "Slate", value: "slate" }
|
|
435
|
+
]
|
|
436
|
+
})
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
// On Cancel callback that wraps the group
|
|
440
|
+
// So if the user cancels one of the prompts in the group this function will be called
|
|
441
|
+
onCancel: () => {
|
|
442
|
+
p3.cancel("Operation cancelled.");
|
|
443
|
+
process.exit(0);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
);
|
|
447
|
+
const cssFileDir = path.dirname(configChoices.cssFile);
|
|
448
|
+
const componentInstallDir = path.join(configChoices.installLocation, "starwind");
|
|
449
|
+
configTasks.push({
|
|
450
|
+
title: "Creating project structure",
|
|
451
|
+
task: async () => {
|
|
452
|
+
await ensureDirectory(componentInstallDir);
|
|
453
|
+
await ensureDirectory(cssFileDir);
|
|
454
|
+
await sleep(250);
|
|
455
|
+
return "Created project structure";
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
configTasks.push({
|
|
459
|
+
title: "Setup Astro config file",
|
|
460
|
+
task: async () => {
|
|
461
|
+
const success = await setupAstroConfig();
|
|
462
|
+
if (!success) {
|
|
463
|
+
throw new Error("Failed to setup Astro config");
|
|
464
|
+
}
|
|
465
|
+
await sleep(250);
|
|
466
|
+
return "Astro config setup completed";
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
const cssFileExists = await fileExists(configChoices.cssFile);
|
|
470
|
+
let updatedTailwindConfig = tailwindConfig;
|
|
471
|
+
if (configChoices.twBaseColor !== "gray") {
|
|
472
|
+
updatedTailwindConfig = updatedTailwindConfig.replace(
|
|
473
|
+
/--color-neutral-/g,
|
|
474
|
+
`--color-${configChoices.twBaseColor}-`
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
if (cssFileExists) {
|
|
478
|
+
const shouldOverride = await p3.confirm({
|
|
479
|
+
message: `${highlighter.info(configChoices.cssFile)} already exists. Do you want to override it?`
|
|
480
|
+
});
|
|
481
|
+
if (!shouldOverride) {
|
|
482
|
+
p3.log.info("Skipping Tailwind CSS configuration");
|
|
483
|
+
} else {
|
|
484
|
+
configTasks.push({
|
|
485
|
+
title: "Creating Tailwind CSS configuration",
|
|
486
|
+
task: async () => {
|
|
487
|
+
await writeCssFile(configChoices.cssFile, updatedTailwindConfig);
|
|
488
|
+
await sleep(250);
|
|
489
|
+
return "Created Tailwind configuration";
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
} else {
|
|
494
|
+
configTasks.push({
|
|
495
|
+
title: "Creating Tailwind CSS configuration",
|
|
496
|
+
task: async () => {
|
|
497
|
+
await writeCssFile(configChoices.cssFile, updatedTailwindConfig);
|
|
498
|
+
await sleep(250);
|
|
499
|
+
return "Created Tailwind configuration";
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
configTasks.push({
|
|
504
|
+
title: "Updating project configuration",
|
|
505
|
+
task: async () => {
|
|
506
|
+
await updateConfig({
|
|
507
|
+
tailwind: {
|
|
508
|
+
css: configChoices.cssFile,
|
|
509
|
+
baseColor: configChoices.twBaseColor,
|
|
510
|
+
cssVariables: true
|
|
511
|
+
},
|
|
512
|
+
// aliases: {
|
|
513
|
+
// components: "@/components",
|
|
514
|
+
// },
|
|
515
|
+
componentDir: configChoices.installLocation,
|
|
516
|
+
components: []
|
|
517
|
+
});
|
|
518
|
+
await sleep(250);
|
|
519
|
+
return "Updated project starwind configuration";
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
const pm = await requestPackageManager();
|
|
523
|
+
if (pkg.dependencies?.astro) {
|
|
524
|
+
const astroVersion = pkg.dependencies.astro.replace(/^\^|~/, "");
|
|
525
|
+
if (!semver.gte(astroVersion, MIN_ASTRO_VERSION)) {
|
|
526
|
+
const shouldUpgrade = await p3.confirm({
|
|
527
|
+
message: `Starwind requires Astro v${MIN_ASTRO_VERSION} or higher. Would you like to upgrade from v${astroVersion}?`,
|
|
528
|
+
initialValue: true
|
|
529
|
+
});
|
|
530
|
+
if (p3.isCancel(shouldUpgrade)) {
|
|
531
|
+
p3.cancel("Operation cancelled");
|
|
532
|
+
return process.exit(0);
|
|
533
|
+
}
|
|
534
|
+
if (!shouldUpgrade) {
|
|
535
|
+
p3.cancel("Astro v5 or higher is required to use Starwind");
|
|
536
|
+
return process.exit(1);
|
|
537
|
+
}
|
|
538
|
+
installTasks.push({
|
|
539
|
+
title: "Upgrading Astro",
|
|
540
|
+
task: async () => {
|
|
541
|
+
await installDependencies([ASTRO_PACKAGES.core], pm);
|
|
542
|
+
return "Upgraded Astro successfully";
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
} else {
|
|
547
|
+
const shouldInstall2 = await p3.confirm({
|
|
548
|
+
message: `Starwind requires Astro v${MIN_ASTRO_VERSION} or higher. Would you like to install it?`,
|
|
549
|
+
initialValue: true
|
|
550
|
+
});
|
|
551
|
+
if (p3.isCancel(shouldInstall2)) {
|
|
552
|
+
p3.cancel("Operation cancelled");
|
|
553
|
+
return process.exit(0);
|
|
554
|
+
}
|
|
555
|
+
if (!shouldInstall2) {
|
|
556
|
+
p3.cancel("Astro is required to use Starwind");
|
|
557
|
+
return process.exit(1);
|
|
558
|
+
}
|
|
559
|
+
installTasks.push({
|
|
560
|
+
title: `Installing ${ASTRO_PACKAGES.core}`,
|
|
561
|
+
task: async () => {
|
|
562
|
+
await installDependencies([ASTRO_PACKAGES.core], pm);
|
|
563
|
+
return `Installed ${highlighter.info(ASTRO_PACKAGES.core)} successfully`;
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
const otherPackages = getOtherPackages();
|
|
568
|
+
const shouldInstall = await p3.confirm({
|
|
569
|
+
message: `Install ${highlighter.info(otherPackages.join(", "))} using ${highlighter.info(pm)}?`
|
|
570
|
+
});
|
|
571
|
+
if (p3.isCancel(shouldInstall)) {
|
|
572
|
+
p3.cancel("Operation cancelled");
|
|
573
|
+
return process.exit(0);
|
|
574
|
+
}
|
|
575
|
+
if (shouldInstall) {
|
|
576
|
+
installTasks.push({
|
|
577
|
+
title: `Installing packages`,
|
|
578
|
+
task: async () => {
|
|
579
|
+
await installDependencies(getOtherPackages(), pm, false, false);
|
|
580
|
+
return `${highlighter.info("Packages installed successfully")}`;
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
} else {
|
|
584
|
+
p3.log.warn(
|
|
585
|
+
highlighter.warn(`Skipped installation of packages. Make sure to install them manually`)
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
if (installTasks.length > 0) {
|
|
589
|
+
await p3.tasks(installTasks);
|
|
590
|
+
}
|
|
591
|
+
if (configTasks.length > 0) {
|
|
592
|
+
await p3.tasks(configTasks);
|
|
593
|
+
}
|
|
594
|
+
await sleep(250);
|
|
595
|
+
p3.note(
|
|
596
|
+
`Make sure your layout imports the ${highlighter.infoBright(configChoices.cssFile)} file`,
|
|
597
|
+
"Next steps"
|
|
598
|
+
);
|
|
599
|
+
if (!withinAdd) {
|
|
600
|
+
sleep(1e3);
|
|
601
|
+
p3.outro("Enjoy using Starwind UI \u{1F680}");
|
|
602
|
+
}
|
|
603
|
+
} catch (error) {
|
|
604
|
+
p3.log.error(error instanceof Error ? error.message : "Failed to add components");
|
|
605
|
+
p3.cancel("Operation cancelled");
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export {
|
|
611
|
+
PATHS,
|
|
612
|
+
fileExists,
|
|
613
|
+
highlighter,
|
|
614
|
+
getConfig,
|
|
615
|
+
updateConfig,
|
|
616
|
+
requestPackageManager,
|
|
617
|
+
installDependencies,
|
|
618
|
+
sleep,
|
|
619
|
+
init
|
|
620
|
+
};
|
|
621
|
+
//# sourceMappingURL=chunk-JUEM67WU.js.map
|