create-bearnie 0.1.2 → 0.3.0
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/README.md +33 -3
- package/dist/index.js +365 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# create-bearnie
|
|
2
2
|
|
|
3
3
|
Create a new Astro project with Bearnie UI components pre-configured.
|
|
4
4
|
|
|
@@ -12,23 +12,53 @@ npx create-bearnie
|
|
|
12
12
|
npm create bearnie my-app
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
## Options
|
|
16
|
+
|
|
17
|
+
### `--full`
|
|
18
|
+
|
|
19
|
+
Include all components from the start:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx create-bearnie my-app --full
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This fetches all components from the registry and installs them in your project.
|
|
26
|
+
|
|
27
|
+
### `--theme`
|
|
28
|
+
|
|
29
|
+
Apply a custom theme from the [theme builder](https://bearnie.dev/create-bearnie-theme):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx create-bearnie my-app --theme="https://bearnie.dev/create-bearnie-theme#..."
|
|
33
|
+
```
|
|
34
|
+
|
|
15
35
|
## What's included
|
|
16
36
|
|
|
17
37
|
- Astro 5 with TypeScript
|
|
18
38
|
- Tailwind CSS v4 (via `@tailwindcss/vite`)
|
|
19
39
|
- Bearnie CSS variables and theme
|
|
20
40
|
- Simple landing page to get started
|
|
21
|
-
- Ready for components via `npx
|
|
41
|
+
- Ready for components via `npx bearnie add`
|
|
42
|
+
|
|
43
|
+
With `--full` flag:
|
|
44
|
+
- All Bearnie UI components
|
|
45
|
+
- Utility functions (`cn`, `focus-trap`)
|
|
46
|
+
- Additional dependencies (`clsx`, `tailwind-merge`)
|
|
22
47
|
|
|
23
48
|
## After creating your project
|
|
24
49
|
|
|
25
50
|
```bash
|
|
26
51
|
cd my-app
|
|
27
52
|
npm install
|
|
28
|
-
npx bearnie add button card dialog
|
|
29
53
|
npm run dev
|
|
30
54
|
```
|
|
31
55
|
|
|
56
|
+
Without `--full`, add components as needed:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx bearnie add button card dialog
|
|
60
|
+
```
|
|
61
|
+
|
|
32
62
|
## Learn more
|
|
33
63
|
|
|
34
64
|
- [Bearnie Documentation](https://bearnie.dev/docs)
|
package/dist/index.js
CHANGED
|
@@ -10,13 +10,290 @@ var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
10
10
|
var amber = (text) => pc.yellow(text);
|
|
11
11
|
var logo = `${amber("\u{1F43B}")} ${pc.bold("bearnie")}`;
|
|
12
12
|
var link = (text, url) => `\x1B]8;;${url}\x07${pc.cyan(text)}\x1B]8;;\x07`;
|
|
13
|
+
function parseThemeArg() {
|
|
14
|
+
const themeArg = process.argv.find((arg) => arg.startsWith("--theme="));
|
|
15
|
+
if (!themeArg) return null;
|
|
16
|
+
return themeArg.split("=")[1];
|
|
17
|
+
}
|
|
18
|
+
function parseFullArg() {
|
|
19
|
+
return process.argv.includes("--full");
|
|
20
|
+
}
|
|
21
|
+
var REGISTRY_URL = "https://bearnie.dev/registry";
|
|
22
|
+
var COMPONENT_NAMES = [
|
|
23
|
+
"accordion",
|
|
24
|
+
"alert",
|
|
25
|
+
"alert-dialog",
|
|
26
|
+
"aspect-ratio",
|
|
27
|
+
"avatar",
|
|
28
|
+
"badge",
|
|
29
|
+
"breadcrumb",
|
|
30
|
+
"button",
|
|
31
|
+
"button-group",
|
|
32
|
+
"card",
|
|
33
|
+
"carousel",
|
|
34
|
+
"checkbox",
|
|
35
|
+
"collapsible",
|
|
36
|
+
"command",
|
|
37
|
+
"context-menu",
|
|
38
|
+
"dialog",
|
|
39
|
+
"dropdown-menu",
|
|
40
|
+
"empty",
|
|
41
|
+
"file-upload",
|
|
42
|
+
"hover-card",
|
|
43
|
+
"input",
|
|
44
|
+
"input-group",
|
|
45
|
+
"input-otp",
|
|
46
|
+
"kbd",
|
|
47
|
+
"label",
|
|
48
|
+
"menubar",
|
|
49
|
+
"pagination",
|
|
50
|
+
"popover",
|
|
51
|
+
"progress",
|
|
52
|
+
"radio",
|
|
53
|
+
"scroll-area",
|
|
54
|
+
"select",
|
|
55
|
+
"separator",
|
|
56
|
+
"sheet",
|
|
57
|
+
"sidebar",
|
|
58
|
+
"skeleton",
|
|
59
|
+
"slider",
|
|
60
|
+
"spinner",
|
|
61
|
+
"stepper",
|
|
62
|
+
"switch",
|
|
63
|
+
"table",
|
|
64
|
+
"tabs",
|
|
65
|
+
"textarea",
|
|
66
|
+
"toast",
|
|
67
|
+
"toggle",
|
|
68
|
+
"tooltip",
|
|
69
|
+
"tree"
|
|
70
|
+
];
|
|
71
|
+
async function fetchComponent(name) {
|
|
72
|
+
try {
|
|
73
|
+
const response = await fetch(`${REGISTRY_URL}/${name}.json`);
|
|
74
|
+
if (!response.ok) return null;
|
|
75
|
+
return await response.json();
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function fetchUtility(name) {
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch(`${REGISTRY_URL}/${name}.json`);
|
|
83
|
+
if (!response.ok) return null;
|
|
84
|
+
return await response.json();
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function extractThemeHash(themeUrl) {
|
|
90
|
+
try {
|
|
91
|
+
const hashIndex = themeUrl.indexOf("#");
|
|
92
|
+
if (hashIndex === -1) return null;
|
|
93
|
+
return themeUrl.slice(hashIndex + 1);
|
|
94
|
+
} catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function decodeThemeConfig(hash) {
|
|
99
|
+
try {
|
|
100
|
+
const decoded = Buffer.from(hash, "base64").toString("utf-8");
|
|
101
|
+
return JSON.parse(decoded);
|
|
102
|
+
} catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function oklch(l, c, h) {
|
|
107
|
+
return `oklch(${l} ${c} ${h})`;
|
|
108
|
+
}
|
|
109
|
+
function generateThemeCSS(config) {
|
|
110
|
+
const radiusRem = config.radius / 16;
|
|
111
|
+
const fontFamily = config.font === "geist" ? "'Geist', sans-serif" : "Inter, sans-serif";
|
|
112
|
+
const neutralChroma = config.neutralHue > 0 ? 0.01 : 0;
|
|
113
|
+
const lightPrimary = config.primaryHue === 0 ? "oklch(0.205 0 0)" : oklch(0.55, 0.2, config.primaryHue);
|
|
114
|
+
const lightPrimaryFg = "oklch(0.985 0 0)";
|
|
115
|
+
const darkPrimary = config.primaryHue === 0 ? "oklch(0.985 0 0)" : oklch(0.7, 0.2, config.primaryHue);
|
|
116
|
+
const darkPrimaryFg = "oklch(0.205 0 0)";
|
|
117
|
+
return `@import "tailwindcss";
|
|
118
|
+
@plugin "@tailwindcss/forms";
|
|
119
|
+
|
|
120
|
+
@theme {
|
|
121
|
+
/* Typography */
|
|
122
|
+
--font-sans: ${fontFamily};
|
|
123
|
+
--font-mono: Geist Mono, monospace;
|
|
124
|
+
|
|
125
|
+
/* Border Radius - Base: ${radiusRem}rem */
|
|
126
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
127
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
128
|
+
--radius-lg: var(--radius);
|
|
129
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
130
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
131
|
+
--radius-full: 9999px;
|
|
132
|
+
|
|
133
|
+
/* Shadows */
|
|
134
|
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
135
|
+
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
136
|
+
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@theme inline {
|
|
140
|
+
/* Semantic Colors */
|
|
141
|
+
--color-background: var(--background);
|
|
142
|
+
--color-foreground: var(--foreground);
|
|
143
|
+
--color-card: var(--card);
|
|
144
|
+
--color-card-foreground: var(--card-foreground);
|
|
145
|
+
--color-popover: var(--popover);
|
|
146
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
147
|
+
--color-primary: var(--primary);
|
|
148
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
149
|
+
--color-secondary: var(--secondary);
|
|
150
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
151
|
+
--color-muted: var(--muted);
|
|
152
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
153
|
+
--color-accent: var(--accent);
|
|
154
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
155
|
+
--color-destructive: var(--destructive);
|
|
156
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
157
|
+
--color-success: var(--success);
|
|
158
|
+
--color-success-foreground: var(--success-foreground);
|
|
159
|
+
--color-warning: var(--warning);
|
|
160
|
+
--color-warning-foreground: var(--warning-foreground);
|
|
161
|
+
--color-info: var(--info);
|
|
162
|
+
--color-info-foreground: var(--info-foreground);
|
|
163
|
+
--color-border: var(--border);
|
|
164
|
+
--color-input: var(--input);
|
|
165
|
+
--color-ring: var(--ring);
|
|
166
|
+
--color-chart-1: var(--chart-1);
|
|
167
|
+
--color-chart-2: var(--chart-2);
|
|
168
|
+
--color-chart-3: var(--chart-3);
|
|
169
|
+
--color-chart-4: var(--chart-4);
|
|
170
|
+
--color-chart-5: var(--chart-5);
|
|
171
|
+
|
|
172
|
+
/* Sidebar Colors */
|
|
173
|
+
--color-sidebar: var(--sidebar);
|
|
174
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
175
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
176
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
177
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
178
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
179
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
180
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
:root {
|
|
184
|
+
--radius: ${radiusRem}rem;
|
|
185
|
+
--background: ${oklch(1, neutralChroma, config.neutralHue)};
|
|
186
|
+
--foreground: ${oklch(0.145, neutralChroma, config.neutralHue)};
|
|
187
|
+
--card: ${oklch(1, neutralChroma, config.neutralHue)};
|
|
188
|
+
--card-foreground: ${oklch(0.145, neutralChroma, config.neutralHue)};
|
|
189
|
+
--popover: ${oklch(1, neutralChroma, config.neutralHue)};
|
|
190
|
+
--popover-foreground: ${oklch(0.145, neutralChroma, config.neutralHue)};
|
|
191
|
+
--primary: ${lightPrimary};
|
|
192
|
+
--primary-foreground: ${lightPrimaryFg};
|
|
193
|
+
--secondary: ${oklch(0.97, neutralChroma, config.neutralHue)};
|
|
194
|
+
--secondary-foreground: ${oklch(0.205, neutralChroma, config.neutralHue)};
|
|
195
|
+
--muted: ${oklch(0.97, neutralChroma, config.neutralHue)};
|
|
196
|
+
--muted-foreground: ${oklch(0.556, neutralChroma, config.neutralHue)};
|
|
197
|
+
--accent: ${oklch(0.97, neutralChroma, config.neutralHue)};
|
|
198
|
+
--accent-foreground: ${oklch(0.205, neutralChroma, config.neutralHue)};
|
|
199
|
+
--destructive: ${oklch(0.577, 0.245, config.destructiveHue)};
|
|
200
|
+
--destructive-foreground: ${oklch(0.577, 0.245, config.destructiveHue)};
|
|
201
|
+
--success: ${oklch(0.564, 0.168, config.successHue)};
|
|
202
|
+
--success-foreground: ${oklch(0.564, 0.168, config.successHue)};
|
|
203
|
+
--warning: ${oklch(0.681, 0.15, config.warningHue)};
|
|
204
|
+
--warning-foreground: ${oklch(0.681, 0.15, config.warningHue)};
|
|
205
|
+
--info: ${oklch(0.609, 0.202, config.infoHue)};
|
|
206
|
+
--info-foreground: ${oklch(0.609, 0.202, config.infoHue)};
|
|
207
|
+
--border: ${oklch(0.922, neutralChroma, config.neutralHue)};
|
|
208
|
+
--input: ${oklch(0.922, neutralChroma, config.neutralHue)};
|
|
209
|
+
--ring: ${oklch(0.708, neutralChroma, config.neutralHue)};
|
|
210
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
211
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
212
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
213
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
214
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
215
|
+
|
|
216
|
+
/* Sidebar */
|
|
217
|
+
--sidebar: ${oklch(0.985, neutralChroma, config.neutralHue)};
|
|
218
|
+
--sidebar-foreground: ${oklch(0.145, neutralChroma, config.neutralHue)};
|
|
219
|
+
--sidebar-primary: ${lightPrimary};
|
|
220
|
+
--sidebar-primary-foreground: ${lightPrimaryFg};
|
|
221
|
+
--sidebar-accent: ${oklch(0.97, neutralChroma, config.neutralHue)};
|
|
222
|
+
--sidebar-accent-foreground: ${oklch(0.205, neutralChroma, config.neutralHue)};
|
|
223
|
+
--sidebar-border: ${oklch(0.922, neutralChroma, config.neutralHue)};
|
|
224
|
+
--sidebar-ring: ${oklch(0.708, neutralChroma, config.neutralHue)};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.dark {
|
|
228
|
+
--background: ${oklch(0.145, neutralChroma, config.neutralHue)};
|
|
229
|
+
--foreground: ${oklch(0.985, neutralChroma, config.neutralHue)};
|
|
230
|
+
--card: ${oklch(0.145, neutralChroma, config.neutralHue)};
|
|
231
|
+
--card-foreground: ${oklch(0.985, neutralChroma, config.neutralHue)};
|
|
232
|
+
--popover: ${oklch(0.145, neutralChroma, config.neutralHue)};
|
|
233
|
+
--popover-foreground: ${oklch(0.985, neutralChroma, config.neutralHue)};
|
|
234
|
+
--primary: ${darkPrimary};
|
|
235
|
+
--primary-foreground: ${darkPrimaryFg};
|
|
236
|
+
--secondary: ${oklch(0.269, neutralChroma, config.neutralHue)};
|
|
237
|
+
--secondary-foreground: ${oklch(0.985, neutralChroma, config.neutralHue)};
|
|
238
|
+
--muted: ${oklch(0.269, neutralChroma, config.neutralHue)};
|
|
239
|
+
--muted-foreground: ${oklch(0.708, neutralChroma, config.neutralHue)};
|
|
240
|
+
--accent: ${oklch(0.269, neutralChroma, config.neutralHue)};
|
|
241
|
+
--accent-foreground: ${oklch(0.985, neutralChroma, config.neutralHue)};
|
|
242
|
+
--destructive: ${oklch(0.65, 0.245, config.destructiveHue)};
|
|
243
|
+
--destructive-foreground: oklch(0.985 0 0);
|
|
244
|
+
--success: ${oklch(0.634, 0.168, config.successHue)};
|
|
245
|
+
--success-foreground: oklch(0.985 0 0);
|
|
246
|
+
--warning: ${oklch(0.785, 0.15, config.warningHue)};
|
|
247
|
+
--warning-foreground: oklch(0.985 0 0);
|
|
248
|
+
--info: ${oklch(0.701, 0.202, config.infoHue)};
|
|
249
|
+
--info-foreground: oklch(0.985 0 0);
|
|
250
|
+
--border: ${oklch(0.269, neutralChroma, config.neutralHue)};
|
|
251
|
+
--input: ${oklch(0.269, neutralChroma, config.neutralHue)};
|
|
252
|
+
--ring: ${oklch(0.439, neutralChroma, config.neutralHue)};
|
|
253
|
+
--chart-1: oklch(0.488 0.243 264.376);
|
|
254
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
255
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
256
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
257
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
258
|
+
|
|
259
|
+
/* Sidebar */
|
|
260
|
+
--sidebar: ${oklch(0.205, neutralChroma, config.neutralHue)};
|
|
261
|
+
--sidebar-foreground: ${oklch(0.985, neutralChroma, config.neutralHue)};
|
|
262
|
+
--sidebar-primary: ${config.primaryHue === 0 ? "oklch(0.488 0.243 264.376)" : oklch(0.7, 0.2, config.primaryHue)};
|
|
263
|
+
--sidebar-primary-foreground: oklch(0.985 0 0);
|
|
264
|
+
--sidebar-accent: ${oklch(0.269, neutralChroma, config.neutralHue)};
|
|
265
|
+
--sidebar-accent-foreground: ${oklch(0.985, neutralChroma, config.neutralHue)};
|
|
266
|
+
--sidebar-border: ${oklch(0.269, neutralChroma, config.neutralHue)};
|
|
267
|
+
--sidebar-ring: ${oklch(0.439, neutralChroma, config.neutralHue)};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/* Base styles */
|
|
271
|
+
* {
|
|
272
|
+
border-color: var(--border);
|
|
273
|
+
}
|
|
274
|
+
`;
|
|
275
|
+
}
|
|
13
276
|
async function main() {
|
|
277
|
+
const themeUrl = parseThemeArg();
|
|
278
|
+
const fullInstall = parseFullArg();
|
|
279
|
+
let themeConfig = null;
|
|
280
|
+
if (themeUrl) {
|
|
281
|
+
const hash = extractThemeHash(themeUrl);
|
|
282
|
+
if (hash) {
|
|
283
|
+
themeConfig = decodeThemeConfig(hash);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
14
286
|
console.log(`
|
|
15
287
|
${logo}
|
|
16
288
|
|
|
17
289
|
${amber("Hey!")} Let's create your Bearnie project.
|
|
290
|
+
${themeConfig ? ` ${pc.dim("Using custom theme from URL")}
|
|
291
|
+
` : ""}${fullInstall ? ` ${pc.dim("Full install: including all components")}
|
|
292
|
+
` : ""}
|
|
18
293
|
`);
|
|
19
|
-
let projectName = process.argv
|
|
294
|
+
let projectName = process.argv.find(
|
|
295
|
+
(arg, index) => index >= 2 && !arg.startsWith("--")
|
|
296
|
+
);
|
|
20
297
|
if (!projectName) {
|
|
21
298
|
const response = await prompts({
|
|
22
299
|
type: "text",
|
|
@@ -38,12 +315,13 @@ async function main() {
|
|
|
38
315
|
}
|
|
39
316
|
projectName = response.projectName;
|
|
40
317
|
}
|
|
41
|
-
const
|
|
318
|
+
const finalName = projectName;
|
|
319
|
+
const targetDir = path.resolve(process.cwd(), finalName);
|
|
42
320
|
if (fs.existsSync(targetDir)) {
|
|
43
321
|
const { overwrite } = await prompts({
|
|
44
322
|
type: "confirm",
|
|
45
323
|
name: "overwrite",
|
|
46
|
-
message: `Directory ${pc.cyan(
|
|
324
|
+
message: `Directory ${pc.cyan(finalName)} already exists. Overwrite?`,
|
|
47
325
|
initial: false
|
|
48
326
|
});
|
|
49
327
|
if (!overwrite) {
|
|
@@ -61,8 +339,68 @@ async function main() {
|
|
|
61
339
|
await fs.copy(templateDir, targetDir);
|
|
62
340
|
const pkgPath = path.join(targetDir, "package.json");
|
|
63
341
|
const pkg = await fs.readJson(pkgPath);
|
|
64
|
-
pkg.name =
|
|
342
|
+
pkg.name = finalName;
|
|
65
343
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
344
|
+
if (themeConfig) {
|
|
345
|
+
const globalCssPath = path.join(targetDir, "src", "styles", "global.css");
|
|
346
|
+
const customCSS = generateThemeCSS(themeConfig);
|
|
347
|
+
await fs.writeFile(globalCssPath, customCSS);
|
|
348
|
+
console.log(` ${pc.green("\u2713")} Applied custom theme`);
|
|
349
|
+
}
|
|
350
|
+
if (fullInstall) {
|
|
351
|
+
console.log(`
|
|
352
|
+
${pc.dim("Fetching components from registry...")}
|
|
353
|
+
`);
|
|
354
|
+
await fs.ensureDir(path.join(targetDir, "src", "components", "ui"));
|
|
355
|
+
await fs.ensureDir(path.join(targetDir, "src", "utils"));
|
|
356
|
+
const focusTrap = await fetchUtility("focus-trap");
|
|
357
|
+
if (focusTrap?.files) {
|
|
358
|
+
for (const file of focusTrap.files) {
|
|
359
|
+
const filePath = path.join(targetDir, "src", file.name);
|
|
360
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
361
|
+
await fs.writeFile(filePath, file.content);
|
|
362
|
+
}
|
|
363
|
+
console.log(` ${pc.green("\u2713")} Added focus-trap utility`);
|
|
364
|
+
}
|
|
365
|
+
const cnContent = `import { clsx, type ClassValue } from "clsx";
|
|
366
|
+
import { twMerge } from "tailwind-merge";
|
|
367
|
+
|
|
368
|
+
export function cn(...inputs: ClassValue[]) {
|
|
369
|
+
return twMerge(clsx(inputs));
|
|
370
|
+
}
|
|
371
|
+
`;
|
|
372
|
+
await fs.writeFile(path.join(targetDir, "src", "utils", "cn.ts"), cnContent);
|
|
373
|
+
console.log(` ${pc.green("\u2713")} Added cn utility`);
|
|
374
|
+
let installed = 0;
|
|
375
|
+
let failed = 0;
|
|
376
|
+
for (const componentName of COMPONENT_NAMES) {
|
|
377
|
+
const component = await fetchComponent(componentName);
|
|
378
|
+
if (component?.files) {
|
|
379
|
+
for (const file of component.files) {
|
|
380
|
+
const filePath = path.join(targetDir, "src", file.name);
|
|
381
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
382
|
+
await fs.writeFile(filePath, file.content);
|
|
383
|
+
}
|
|
384
|
+
installed++;
|
|
385
|
+
process.stdout.write(`\r ${pc.green("\u2713")} Installed ${installed}/${COMPONENT_NAMES.length} components`);
|
|
386
|
+
} else {
|
|
387
|
+
failed++;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
console.log("");
|
|
391
|
+
if (failed > 0) {
|
|
392
|
+
console.log(` ${pc.yellow("!")} ${failed} components failed to fetch`);
|
|
393
|
+
}
|
|
394
|
+
const pkgPath2 = path.join(targetDir, "package.json");
|
|
395
|
+
const pkg2 = await fs.readJson(pkgPath2);
|
|
396
|
+
pkg2.dependencies = {
|
|
397
|
+
...pkg2.dependencies,
|
|
398
|
+
"clsx": "^2.1.1",
|
|
399
|
+
"tailwind-merge": "^3.3.0"
|
|
400
|
+
};
|
|
401
|
+
await fs.writeJson(pkgPath2, pkg2, { spaces: 2 });
|
|
402
|
+
console.log(` ${pc.green("\u2713")} Added component dependencies`);
|
|
403
|
+
}
|
|
66
404
|
await fs.writeFile(
|
|
67
405
|
path.join(targetDir, ".gitignore"),
|
|
68
406
|
`# Dependencies
|
|
@@ -89,20 +427,41 @@ Thumbs.db
|
|
|
89
427
|
`
|
|
90
428
|
);
|
|
91
429
|
console.log(` ${pc.green("\u2713")} Created project files`);
|
|
92
|
-
|
|
430
|
+
if (fullInstall) {
|
|
431
|
+
console.log(`
|
|
432
|
+
${pc.green("Done!")} Your Bearnie project is ready with all components.
|
|
433
|
+
|
|
434
|
+
${pc.bold("Next steps:")}
|
|
435
|
+
|
|
436
|
+
${pc.dim("1.")} cd ${pc.cyan(finalName)}
|
|
437
|
+
${pc.dim("2.")} npm install
|
|
438
|
+
${pc.dim("3.")} npm run dev
|
|
439
|
+
|
|
440
|
+
${pc.dim("All components are in")} ${pc.cyan("src/components/ui/")}
|
|
441
|
+
|
|
442
|
+
${pc.dim("Browse components at")} ${link("bearnie.dev/docs/components", "https://bearnie.dev/docs/components")}
|
|
443
|
+
|
|
444
|
+
${pc.dim("Made by")} ${link("Michael", "https://michaelandreuzza.com")} ${pc.dim("at")} ${link("Lexington Themes", "https://lexingtonthemes.com")}
|
|
445
|
+
`);
|
|
446
|
+
} else {
|
|
447
|
+
console.log(`
|
|
93
448
|
${pc.green("Done!")} Your Bearnie project is ready.
|
|
94
449
|
|
|
95
450
|
${pc.bold("Next steps:")}
|
|
96
451
|
|
|
97
|
-
${pc.dim("1.")} cd ${pc.cyan(
|
|
452
|
+
${pc.dim("1.")} cd ${pc.cyan(finalName)}
|
|
98
453
|
${pc.dim("2.")} npm install
|
|
99
454
|
${pc.dim("3.")} npx bearnie add button card
|
|
100
455
|
${pc.dim("4.")} npm run dev
|
|
101
456
|
|
|
457
|
+
${pc.dim("Or use")} ${pc.cyan("--full")} ${pc.dim("to include all components:")}
|
|
458
|
+
npx create-bearnie my-app --full
|
|
459
|
+
|
|
102
460
|
${pc.dim("Browse components at")} ${link("bearnie.dev/docs/components", "https://bearnie.dev/docs/components")}
|
|
103
461
|
|
|
104
462
|
${pc.dim("Made by")} ${link("Michael", "https://michaelandreuzza.com")} ${pc.dim("at")} ${link("Lexington Themes", "https://lexingtonthemes.com")}
|
|
105
463
|
`);
|
|
464
|
+
}
|
|
106
465
|
}
|
|
107
466
|
main().catch((err) => {
|
|
108
467
|
console.error(`
|