beaver-build 1.0.3 → 1.0.4

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.
Files changed (2) hide show
  1. package/dist/index.js +414 -30
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -271,9 +271,22 @@ var init_vite_config = __esm({
271
271
  TanStackRouterVite({ routesDirectory: './src/routes', generatedRouteTree: './src/routes/routeTree.gen.ts' }),` : "";
272
272
  return `import { defineConfig } from 'vite';
273
273
  import react from '@vitejs/plugin-react';
274
+ import path from 'path';
274
275
  ${tailwindImport}${tanstackImport}
275
276
  // https://vitejs.dev/config/
276
277
  export default defineConfig({
278
+ resolve: {
279
+ alias: {
280
+ '@': path.resolve(__dirname, './src'),
281
+ '@components': path.resolve(__dirname, './src/components'),
282
+ '@pages': path.resolve(__dirname, './src/pages'),
283
+ '@utils': path.resolve(__dirname, './src/utils'),
284
+ '@types': path.resolve(__dirname, './src/types'),
285
+ '@hooks': path.resolve(__dirname, './src/hooks'),
286
+ '@layouts': path.resolve(__dirname, './src/layouts'),
287
+ '@assets': path.resolve(__dirname, './src/assets'),
288
+ },
289
+ },
277
290
  plugins: [
278
291
  react(),${tailwindPlugin}${tanstackPlugin}
279
292
  ],
@@ -305,7 +318,18 @@ var init_tsconfig = __esm({
305
318
  strict: true,
306
319
  noUnusedLocals: true,
307
320
  noUnusedParameters: true,
308
- noFallthroughCasesInSwitch: true
321
+ noFallthroughCasesInSwitch: true,
322
+ baseUrl: ".",
323
+ paths: {
324
+ "@/*": ["./src/*"],
325
+ "@components/*": ["./src/components/*"],
326
+ "@pages/*": ["./src/pages/*"],
327
+ "@utils/*": ["./src/utils/*"],
328
+ "@types/*": ["./src/types/*"],
329
+ "@hooks/*": ["./src/hooks/*"],
330
+ "@layouts/*": ["./src/layouts/*"],
331
+ "@assets/*": ["./src/assets/*"]
332
+ }
309
333
  },
310
334
  include: ["src"],
311
335
  references: [{ path: "./tsconfig.node.json" }]
@@ -408,11 +432,11 @@ declare module '@tanstack/react-router' {
408
432
  }
409
433
  }
410
434
  ` : "";
411
- const inner = hasRouter ? `<RouterProvider router={router} />` : `<div>
412
- <h1>Hello from FSD</h1>
413
- </div>`;
435
+ const homeImport = !hasRouter ? `import { HomePage } from '@/pages/home';
436
+ ` : "";
437
+ const inner = hasRouter ? `<RouterProvider router={router} />` : `<HomePage />`;
414
438
  if (hasQuery) {
415
- return `${queryImports}${routerImports}${queryClientDef}
439
+ return `${queryImports}${homeImport}${routerImports}${queryClientDef}
416
440
  export const App = () => {
417
441
  return (
418
442
  <QueryClientProvider client={queryClient}>
@@ -430,12 +454,9 @@ export const App = () => {
430
454
  };
431
455
  `;
432
456
  }
433
- return `export const App = () => {
434
- return (
435
- <div>
436
- <h1>Hello from FSD</h1>
437
- </div>
438
- );
457
+ return `${homeImport}
458
+ export const App = () => {
459
+ return <HomePage />;
439
460
  };
440
461
  `;
441
462
  };
@@ -453,13 +474,13 @@ declare module '@tanstack/react-router' {
453
474
  }
454
475
  }
455
476
  ` : "";
456
- const inner = hasRouter ? `<RouterProvider router={router} />` : `<div>
457
- <h1>Hello from Bulletproof React</h1>
458
- </div>`;
477
+ const homeImport = !hasRouter ? `import Home from '@/pages/Home';
478
+ ` : "";
479
+ const inner = hasRouter ? `<RouterProvider router={router} />` : `<Home />`;
459
480
  const body = hasQuery ? `<AppProvider>
460
481
  ${inner}
461
482
  </AppProvider>` : inner;
462
- return `${providerImport}${routerImports}
483
+ return `${providerImport}${homeImport}${routerImports}
463
484
  const App = () => {
464
485
  return (
465
486
  ${body}
@@ -473,7 +494,7 @@ export default App;
473
494
  });
474
495
 
475
496
  // src/scaffold/react-vite/templates/router.ts
476
- var routeTreeGenTemplate, rootRouteTemplate, indexRouteTemplate;
497
+ var routeTreeGenTemplate, rootRouteTemplate, indexRouteFsdTemplate, indexRouteBprTemplate;
477
498
  var init_router = __esm({
478
499
  "src/scaffold/react-vite/templates/router.ts"() {
479
500
  "use strict";
@@ -524,19 +545,19 @@ export const Route = createRootRoute({
524
545
  ),
525
546
  });
526
547
  `;
527
- indexRouteTemplate = () => `import { createFileRoute } from '@tanstack/react-router';
548
+ indexRouteFsdTemplate = () => `import { createFileRoute } from '@tanstack/react-router';
549
+ import { HomePage } from '@/pages/home';
528
550
 
529
551
  export const Route = createFileRoute('/')({
530
- component: Index,
552
+ component: HomePage,
531
553
  });
554
+ `;
555
+ indexRouteBprTemplate = () => `import { createFileRoute } from '@tanstack/react-router';
556
+ import Home from '@/pages/Home';
532
557
 
533
- function Index() {
534
- return (
535
- <div>
536
- <h3>Welcome Home!</h3>
537
- </div>
538
- );
539
- }
558
+ export const Route = createFileRoute('/')({
559
+ component: Home,
560
+ });
540
561
  `;
541
562
  }
542
563
  });
@@ -655,6 +676,25 @@ var init_styles = __esm({
655
676
  "src/scaffold/react-vite/templates/styles.ts"() {
656
677
  "use strict";
657
678
  stylesCssTemplate = () => `@import "tailwindcss";
679
+
680
+ @theme {
681
+ /* Brand */
682
+ --color-primary: oklch(0.55 0.22 265);
683
+ --color-primary-fg: oklch(0.97 0.01 265);
684
+
685
+ /* Surfaces (dark-first) */
686
+ --color-surface: oklch(0.11 0.015 265);
687
+ --color-surface-muted: oklch(0.16 0.012 265);
688
+ --color-surface-high: oklch(0.21 0.010 265);
689
+
690
+ /* Text */
691
+ --color-text: oklch(0.97 0.000 0);
692
+ --color-text-muted: oklch(0.62 0.010 265);
693
+ --color-text-subtle: oklch(0.42 0.010 265);
694
+
695
+ /* Border */
696
+ --color-border: oklch(0.28 0.010 265);
697
+ }
658
698
  `;
659
699
  }
660
700
  });
@@ -675,7 +715,7 @@ declare module '*.css' {
675
715
  });
676
716
 
677
717
  // src/scaffold/react-vite/templates/copilot-instructions.ts
678
- var FSD_PATHS, BPR_PATHS, frontmatter, generalTemplate, componentsTemplate, hooksTemplate, routerTemplate, zustandTemplate, queryTemplate, tailwindTemplate, linterTemplate, getCopilotInstructionFiles;
718
+ var FSD_PATHS, BPR_PATHS, frontmatter, generalTemplate, componentsTemplate, hooksTemplate, routerTemplate, zustandTemplate, queryTemplate, tailwindTemplate, importsTemplate, linterTemplate, getCopilotInstructionFiles;
679
719
  var init_copilot_instructions = __esm({
680
720
  "src/scaffold/react-vite/templates/copilot-instructions.ts"() {
681
721
  "use strict";
@@ -758,6 +798,21 @@ Path-specific rules live in \`.github/instructions/*.instructions.md\` \u2014 th
758
798
  ## Stack
759
799
  ${stackLines}
760
800
 
801
+ ## Import aliases
802
+
803
+ Always use path aliases instead of relative imports. Project-wide aliases are pre-configured in \`tsconfig.json\` and \`vite.config.ts\`:
804
+
805
+ - \`@/*\` \u2192 \`./src/\` \u2014 use for any import from src, e.g. \`import Button from '@/components/Button'\`.
806
+ - \`@components/*\` \u2192 \`./src/components/\` \u2014 e.g. \`import { Modal } from '@components/Modal'\`.
807
+ - \`@pages/*\` \u2192 \`./src/pages/\` \u2014 e.g. \`import { HomePage } from '@pages/Home'\`.
808
+ - \`@utils/*\` \u2192 \`./src/utils/\` \u2014 e.g. \`import { cn } from '@utils/cn'\`.
809
+ - \`@types/*\` \u2192 \`./src/types/\` \u2014 e.g. \`import type { User } from '@types/user'\`.
810
+ - \`@hooks/*\` \u2192 \`./src/hooks/\` \u2014 e.g. \`import { useAuth } from '@hooks/useAuth'\`.
811
+ - \`@layouts/*\` \u2192 \`./src/layouts/\` \u2014 e.g. \`import { MainLayout } from '@layouts/MainLayout'\`.
812
+ - \`@assets/*\` \u2192 \`./src/assets/\` \u2014 e.g. \`import logo from '@assets/logo.svg'\`.
813
+
814
+ **Never use relative imports** like \`import Foo from '../../../components/Foo'\`. Always resolve through an alias.
815
+
761
816
  ## Naming conventions
762
817
 
763
818
  - **Components**: \`PascalCase.tsx\`, one component per file, named export (no default).
@@ -985,6 +1040,100 @@ Use \`:root\` for runtime values (e.g., animation targets, JS-readable tokens) t
985
1040
  }
986
1041
  }
987
1042
  \`\`\`
1043
+
1044
+ ### Color format \u2014 prefer oklch
1045
+
1046
+ Tailwind v4's built-in palette uses oklch. Use oklch for custom colors too so tokens stay perceptually uniform and mix cleanly with the defaults:
1047
+
1048
+ \`\`\`css
1049
+ @theme {
1050
+ --color-primary: oklch(0.55 0.22 265); /* L C H */
1051
+ --color-muted: oklch(0.62 0.01 265);
1052
+ }
1053
+ \`\`\`
1054
+
1055
+ Avoid hex or \`rgb()\` unless matching a fixed brand value.
1056
+
1057
+ ### Theme variables are also CSS custom properties
1058
+
1059
+ Every \`@theme\` variable is a real CSS custom property \u2014 read it anywhere:
1060
+
1061
+ \`\`\`css
1062
+ .my-element {
1063
+ color: var(--color-primary); /* same value as the text-primary utility */
1064
+ }
1065
+ \`\`\`
1066
+
1067
+ Use \`var()\` for CSS that Tailwind utilities cannot express (e.g. complex \`box-shadow\`, SVG \`fill\`, pseudo-element content).
1068
+
1069
+ ### Semantic token pattern \u2014 naming convention
1070
+
1071
+ Prefer **semantic names** (\`surface\`, \`text-muted\`, \`border\`) over raw scale names (\`slate-900\`, \`zinc-300\`). Semantic names decouple the design from the specific value and make theming easy:
1072
+
1073
+ \`\`\`css
1074
+ @theme {
1075
+ /* Brand */
1076
+ --color-primary: oklch(0.55 0.22 265);
1077
+ --color-primary-fg: oklch(0.97 0.01 265);
1078
+
1079
+ /* Surfaces (dark-first) */
1080
+ --color-surface: oklch(0.11 0.015 265);
1081
+ --color-surface-muted: oklch(0.16 0.012 265);
1082
+ --color-surface-high: oklch(0.21 0.010 265);
1083
+
1084
+ /* Text */
1085
+ --color-text: oklch(0.97 0.000 0);
1086
+ --color-text-muted: oklch(0.62 0.010 265);
1087
+ --color-text-subtle: oklch(0.42 0.010 265);
1088
+
1089
+ /* Border */
1090
+ --color-border: oklch(0.28 0.010 265);
1091
+ }
1092
+ \`\`\`
1093
+
1094
+ This generates: \`bg-primary\`, \`text-primary-fg\`, \`bg-surface\`, \`bg-surface-high/60\`, \`text-text\`, \`text-text-muted\`, \`border-border\`, etc. The \`/opacity\` modifier works on all generated utilities.
1095
+ `;
1096
+ };
1097
+ importsTemplate = () => {
1098
+ return frontmatter("**") + `# Import aliases and code organization
1099
+
1100
+ All imports use path aliases defined in \`tsconfig.json\` and \`vite.config.ts\`. This avoids fragile relative paths and makes moving files safe.
1101
+
1102
+ ## Available aliases
1103
+
1104
+ - \`@/*\` \u2192 \`./src/\` \u2014 shortest form, use when unambiguous
1105
+ - \`@components/*\` \u2014 components in \`./src/components/\`
1106
+ - \`@pages/*\` \u2014 pages in \`./src/pages/\`
1107
+ - \`@utils/*\` \u2014 utilities in \`./src/utils/\`
1108
+ - \`@types/*\` \u2014 types in \`./src/types/\`
1109
+ - \`@hooks/*\` \u2014 hooks in \`./src/hooks/\`
1110
+ - \`@layouts/*\` \u2014 layouts in \`./src/layouts/\`
1111
+ - \`@assets/*\` \u2014 assets in \`./src/assets/\`
1112
+
1113
+ ## Rules
1114
+
1115
+ - **Never use relative imports** (\`../../../\`). Always use an alias.
1116
+ - **Group imports**: standard library, third-party, then project aliases.
1117
+ - **Organize by type within a file**: imports, types, constants, then code.
1118
+
1119
+ ### Examples
1120
+
1121
+ \u2705 Good:
1122
+ \`\`\`typescript
1123
+ import { ReactNode } from 'react';
1124
+ import { QueryClient } from '@tanstack/react-query';
1125
+
1126
+ import { Button } from '@components/Button';
1127
+ import { useUser } from '@hooks/useUser';
1128
+ import type { User } from '@types/user';
1129
+ import { cn } from '@utils/cn';
1130
+ \`\`\`
1131
+
1132
+ \u274C Bad:
1133
+ \`\`\`typescript
1134
+ import { Button } from '../../../components/Button'; // relative path
1135
+ import Button from '@components/Button/Button'; // no file extension in alias
1136
+ \`\`\`
988
1137
  `;
989
1138
  };
990
1139
  linterTemplate = (cart) => {
@@ -1016,6 +1165,7 @@ Use \`:root\` for runtime values (e.g., animation targets, JS-readable tokens) t
1016
1165
  const hasLinter = cart.linter !== "NOT_USING";
1017
1166
  const files = [
1018
1167
  { relativePath: ".github/copilot-instructions.md", content: generalTemplate(cart) },
1168
+ { relativePath: ".github/instructions/imports.instructions.md", content: importsTemplate() },
1019
1169
  { relativePath: ".github/instructions/components.instructions.md", content: componentsTemplate(cart) },
1020
1170
  { relativePath: ".github/instructions/hooks.instructions.md", content: hooksTemplate(cart) }
1021
1171
  ];
@@ -1054,6 +1204,227 @@ Use \`:root\` for runtime values (e.g., animation targets, JS-readable tokens) t
1054
1204
  }
1055
1205
  });
1056
1206
 
1207
+ // src/scaffold/react-vite/templates/home-page.ts
1208
+ function buildBadges(o) {
1209
+ const badges = [
1210
+ { label: "React 19", bg: "#1e3a8a", fg: "#bfdbfe", border: "#3b82f6" },
1211
+ { label: "TypeScript", bg: "#1e3a8a", fg: "#bfdbfe", border: "#2563eb" },
1212
+ { label: "Vite 6", bg: "#4c1d95", fg: "#ddd6fe", border: "#8b5cf6" },
1213
+ { label: o.layout === "FSD" ? "FSD" : "Bulletproof React", bg: "#78350f", fg: "#fde68a", border: "#d97706" }
1214
+ ];
1215
+ if (o.hasRouter) badges.push({ label: "TanStack Router", bg: "#7f1d1d", fg: "#fecaca", border: "#ef4444" });
1216
+ if (o.hasZustand) badges.push({ label: "Zustand", bg: "#14532d", fg: "#bbf7d0", border: "#22c55e" });
1217
+ if (o.hasQuery) badges.push({ label: "TanStack Query", bg: "#7c2d12", fg: "#fed7aa", border: "#f97316" });
1218
+ if (o.hasTailwind) badges.push({ label: "Tailwind CSS v4", bg: "#164e63", fg: "#a5f3fc", border: "#06b6d4" });
1219
+ if (o.linter === "BIOME") badges.push({ label: "Biome", bg: "#1e3a5f", fg: "#bae6fd", border: "#0284c7" });
1220
+ if (o.linter === "ESLINT") badges.push({ label: "ESLint", bg: "#312e81", fg: "#c7d2fe", border: "#6366f1" });
1221
+ return badges;
1222
+ }
1223
+ function buildHomePage(o) {
1224
+ const badges = buildBadges(o);
1225
+ const storeImport = o.hasZustand ? `import { useAppStore } from '${o.storeImportPath}';
1226
+ ` : "";
1227
+ const queryImport = o.hasQuery ? `import { useQuery } from '@tanstack/react-query';
1228
+ ` : "";
1229
+ const postType = o.hasQuery ? `
1230
+ type Post = { id: number; title: string; body: string };
1231
+ ` : "";
1232
+ const exportKw = o.namedExport ? `export const ${o.componentName}` : `const ${o.componentName}`;
1233
+ const defaultExp = o.namedExport ? "" : `
1234
+ export default ${o.componentName};
1235
+ `;
1236
+ if (o.hasTailwind) {
1237
+ const badgesJsx = badges.map((b) => ` <span className="px-2.5 py-1 rounded-md text-xs font-medium" style={{ background: '${b.bg}80', color: '${b.fg}', border: '1px solid ${b.border}70' }}>${b.label}</span>`).join("\n");
1238
+ const counterCmp2 = o.hasZustand ? `
1239
+ const Counter = () => {
1240
+ const { count, increment, decrement, reset } = useAppStore();
1241
+ return (
1242
+ <div className="flex items-center gap-3">
1243
+ <button
1244
+ onClick={decrement}
1245
+ className="w-9 h-9 rounded-lg bg-surface-high hover:bg-surface-muted text-text text-xl font-bold transition-colors"
1246
+ >
1247
+ \u2212
1248
+ </button>
1249
+ <span className="text-3xl font-bold text-text w-14 text-center tabular-nums">{count}</span>
1250
+ <button
1251
+ onClick={increment}
1252
+ className="w-9 h-9 rounded-lg bg-surface-high hover:bg-surface-muted text-text text-xl font-bold transition-colors"
1253
+ >
1254
+ +
1255
+ </button>
1256
+ <button onClick={reset} className="ml-2 text-sm text-text-muted hover:text-text transition-colors">
1257
+ reset
1258
+ </button>
1259
+ </div>
1260
+ );
1261
+ };
1262
+ ` : "";
1263
+ const queryCmp2 = o.hasQuery ? `
1264
+ const QueryDemo = () => {
1265
+ const { data, isLoading, isError } = useQuery<Post>({
1266
+ queryKey: ['demo-post'],
1267
+ queryFn: () => fetch('https://jsonplaceholder.typicode.com/posts/1').then(r => r.json()),
1268
+ });
1269
+ if (isLoading) return <p className="text-text-muted text-sm">Fetching post\u2026</p>;
1270
+ if (isError) return <p className="text-red-400 text-sm">Failed to fetch.</p>;
1271
+ return (
1272
+ <div className="space-y-1">
1273
+ <p className="text-text text-sm font-medium">{data?.title}</p>
1274
+ <p className="text-text-muted text-xs leading-relaxed">{data?.body}</p>
1275
+ </div>
1276
+ );
1277
+ };
1278
+ ` : "";
1279
+ const zustandCard2 = o.hasZustand ? `
1280
+ <div className="rounded-xl p-5 mb-3 bg-surface-high/60 border border-border">
1281
+ <p className="text-xs font-semibold text-text-muted uppercase tracking-wider mb-3">Zustand \u2014 Counter</p>
1282
+ <Counter />
1283
+ </div>` : "";
1284
+ const queryCard2 = o.hasQuery ? `
1285
+ <div className="rounded-xl p-5 bg-surface-high/60 border border-border">
1286
+ <p className="text-xs font-semibold text-text-muted uppercase tracking-wider mb-3">TanStack Query \u2014 Fetched Post</p>
1287
+ <QueryDemo />
1288
+ </div>` : "";
1289
+ return `${storeImport}${queryImport}${postType}${counterCmp2}${queryCmp2}
1290
+ ${exportKw} = () => {
1291
+ return (
1292
+ <div className="min-h-screen flex items-center justify-center p-6 bg-gradient-to-br from-surface to-surface-muted">
1293
+ <div className="w-full max-w-lg">
1294
+ <div className="text-center mb-8">
1295
+ <div className="text-5xl mb-3">\u{1F680}</div>
1296
+ <h1 className="text-4xl font-bold text-text mb-2">${o.projectName}</h1>
1297
+ <p className="text-text-muted">Your React + Vite starter is ready.</p>
1298
+ </div>
1299
+
1300
+ <div className="rounded-xl p-5 mb-3 bg-surface-high/60 border border-border">
1301
+ <p className="text-xs font-semibold text-text-muted uppercase tracking-wider mb-3">Stack</p>
1302
+ <div className="flex flex-wrap gap-2">
1303
+ ${badgesJsx}
1304
+ </div>
1305
+ </div>${zustandCard2}${queryCard2}
1306
+ </div>
1307
+ </div>
1308
+ );
1309
+ };
1310
+ ${defaultExp}`;
1311
+ }
1312
+ const badgeDefs = badges.map((b) => ` { label: '${b.label}', bg: '${b.bg}80', fg: '${b.fg}', border: '${b.border}70' }`).join(",\n");
1313
+ const counterCmp = o.hasZustand ? `
1314
+ const Counter = () => {
1315
+ const { count, increment, decrement, reset } = useAppStore();
1316
+ const btn: React.CSSProperties = {
1317
+ width: '2.25rem', height: '2.25rem', borderRadius: '0.5rem',
1318
+ background: '#334155', border: 'none', color: 'white',
1319
+ fontSize: '1.25rem', cursor: 'pointer', lineHeight: 1,
1320
+ };
1321
+ return (
1322
+ <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
1323
+ <button style={btn} onClick={decrement}>\u2212</button>
1324
+ <span style={{ fontSize: '1.875rem', fontWeight: 700, color: 'white', width: '3.5rem', textAlign: 'center' }}>{count}</span>
1325
+ <button style={btn} onClick={increment}>+</button>
1326
+ <button
1327
+ onClick={reset}
1328
+ style={{ background: 'none', border: 'none', color: '#94a3b8', cursor: 'pointer', fontSize: '0.875rem', marginLeft: '0.5rem' }}
1329
+ >
1330
+ reset
1331
+ </button>
1332
+ </div>
1333
+ );
1334
+ };
1335
+ ` : "";
1336
+ const queryCmp = o.hasQuery ? `
1337
+ const QueryDemo = () => {
1338
+ const { data, isLoading, isError } = useQuery<Post>({
1339
+ queryKey: ['demo-post'],
1340
+ queryFn: () => fetch('https://jsonplaceholder.typicode.com/posts/1').then(r => r.json()),
1341
+ });
1342
+ if (isLoading) return <p style={{ color: '#94a3b8', fontSize: '0.875rem' }}>Fetching post\u2026</p>;
1343
+ if (isError) return <p style={{ color: '#f87171', fontSize: '0.875rem' }}>Failed to fetch.</p>;
1344
+ return (
1345
+ <div>
1346
+ <p style={{ color: 'white', fontSize: '0.875rem', fontWeight: 500, margin: '0 0 0.25rem' }}>{data?.title}</p>
1347
+ <p style={{ color: '#94a3b8', fontSize: '0.75rem', lineHeight: 1.6, margin: 0 }}>{data?.body}</p>
1348
+ </div>
1349
+ );
1350
+ };
1351
+ ` : "";
1352
+ const card = `{ background: 'rgba(30,41,59,0.6)', border: '1px solid rgba(71,85,105,0.5)', borderRadius: '0.75rem', padding: '1.25rem', marginBottom: '0.75rem' }`;
1353
+ const cardLabel = `{ fontSize: '0.65rem', fontWeight: 600, color: '#94a3b8', textTransform: 'uppercase' as const, letterSpacing: '0.1em', marginBottom: '0.75rem' }`;
1354
+ const zustandCard = o.hasZustand ? `
1355
+ <div style={${card}}>
1356
+ <p style={${cardLabel}}>Zustand \u2014 Counter</p>
1357
+ <Counter />
1358
+ </div>` : "";
1359
+ const queryCard = o.hasQuery ? `
1360
+ <div style={{ ...${card}, marginBottom: 0 }}>
1361
+ <p style={${cardLabel}}>TanStack Query \u2014 Fetched Post</p>
1362
+ <QueryDemo />
1363
+ </div>` : "";
1364
+ const reactImport = o.hasZustand ? `import type React from 'react';
1365
+ ` : "";
1366
+ return `${reactImport}${storeImport}${queryImport}${postType}
1367
+ const stackBadges = [
1368
+ ${badgeDefs},
1369
+ ];
1370
+ ${counterCmp}${queryCmp}
1371
+ ${exportKw} = () => {
1372
+ return (
1373
+ <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '1.5rem', background: 'linear-gradient(135deg, #020617 0%, #0f172a 100%)', fontFamily: 'system-ui, -apple-system, sans-serif' }}>
1374
+ <div style={{ width: '100%', maxWidth: '480px' }}>
1375
+ <div style={{ textAlign: 'center', marginBottom: '2rem' }}>
1376
+ <div style={{ fontSize: '3rem', marginBottom: '0.75rem' }}>\u{1F680}</div>
1377
+ <h1 style={{ fontSize: '2.25rem', fontWeight: 700, color: '#f8fafc', margin: '0 0 0.5rem' }}>${o.projectName}</h1>
1378
+ <p style={{ color: '#94a3b8', margin: 0 }}>Your React + Vite starter is ready.</p>
1379
+ </div>
1380
+
1381
+ <div style={${card}}>
1382
+ <p style={${cardLabel}}>Stack</p>
1383
+ <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.5rem' }}>
1384
+ {stackBadges.map(b => (
1385
+ <span key={b.label} style={{ background: b.bg, color: b.fg, border: \`1px solid \${b.border}\`, borderRadius: '0.375rem', padding: '0.25rem 0.625rem', fontSize: '0.75rem', fontWeight: 500 }}>
1386
+ {b.label}
1387
+ </span>
1388
+ ))}
1389
+ </div>
1390
+ </div>${zustandCard}${queryCard}
1391
+ </div>
1392
+ </div>
1393
+ );
1394
+ };
1395
+ ${defaultExp}`;
1396
+ }
1397
+ var homePageFsdTemplate, homePageBprTemplate;
1398
+ var init_home_page = __esm({
1399
+ "src/scaffold/react-vite/templates/home-page.ts"() {
1400
+ "use strict";
1401
+ homePageFsdTemplate = (cart) => buildHomePage({
1402
+ projectName: cart.projectName,
1403
+ layout: "FSD",
1404
+ hasTailwind: cart.css === "TAILWIND",
1405
+ hasZustand: cart.stateManagement === "ZUSTAND",
1406
+ hasQuery: cart.query === "TANSTACK_QUERY",
1407
+ hasRouter: cart.router === "TANSTACK_ROUTER",
1408
+ linter: cart.linter,
1409
+ storeImportPath: "@/shared/lib/store",
1410
+ componentName: "HomePage",
1411
+ namedExport: true
1412
+ });
1413
+ homePageBprTemplate = (cart) => buildHomePage({
1414
+ projectName: cart.projectName,
1415
+ layout: "BPR",
1416
+ hasTailwind: cart.css === "TAILWIND",
1417
+ hasZustand: cart.stateManagement === "ZUSTAND",
1418
+ hasQuery: cart.query === "TANSTACK_QUERY",
1419
+ hasRouter: cart.router === "TANSTACK_ROUTER",
1420
+ linter: cart.linter,
1421
+ storeImportPath: "@/stores/appStore",
1422
+ componentName: "Home",
1423
+ namedExport: false
1424
+ });
1425
+ }
1426
+ });
1427
+
1057
1428
  // src/scaffold/react-vite/templates/fsd-layout.ts
1058
1429
  var getFsdFileMap;
1059
1430
  var init_fsd_layout = __esm({
@@ -1072,6 +1443,7 @@ var init_fsd_layout = __esm({
1072
1443
  init_styles();
1073
1444
  init_vite_env_d_ts();
1074
1445
  init_copilot_instructions();
1446
+ init_home_page();
1075
1447
  getFsdFileMap = (cart) => {
1076
1448
  const hasRouter = cart.router === "TANSTACK_ROUTER";
1077
1449
  const hasZustand = cart.stateManagement === "ZUSTAND";
@@ -1089,8 +1461,7 @@ var init_fsd_layout = __esm({
1089
1461
  { relativePath: "src/app/index.tsx", content: appTsxFsdTemplate(hasRouter, hasQuery) },
1090
1462
  {
1091
1463
  relativePath: "src/pages/home/ui/HomePage.tsx",
1092
- content: `export const HomePage = () => <div>Home Page</div>;
1093
- `
1464
+ content: homePageFsdTemplate(cart)
1094
1465
  },
1095
1466
  {
1096
1467
  relativePath: "src/pages/home/index.ts",
@@ -1108,7 +1479,7 @@ var init_fsd_layout = __esm({
1108
1479
  if (hasRouter) {
1109
1480
  files.push(
1110
1481
  { relativePath: "src/routes/__root.tsx", content: rootRouteTemplate() },
1111
- { relativePath: "src/routes/index.tsx", content: indexRouteTemplate() },
1482
+ { relativePath: "src/routes/index.tsx", content: indexRouteFsdTemplate() },
1112
1483
  { relativePath: "src/routes/routeTree.gen.ts", content: routeTreeGenTemplate() }
1113
1484
  );
1114
1485
  }
@@ -1176,6 +1547,7 @@ var init_bpr_layout = __esm({
1176
1547
  init_styles();
1177
1548
  init_vite_env_d_ts();
1178
1549
  init_copilot_instructions();
1550
+ init_home_page();
1179
1551
  getBprFileMap = (cart) => {
1180
1552
  const hasRouter = cart.router === "TANSTACK_ROUTER";
1181
1553
  const hasZustand = cart.stateManagement === "ZUSTAND";
@@ -1191,6 +1563,7 @@ var init_bpr_layout = __esm({
1191
1563
  { relativePath: "src/vite-env.d.ts", content: viteEnvDtsTemplate() },
1192
1564
  { relativePath: "src/main.tsx", content: mainTsxTemplate(cart) },
1193
1565
  { relativePath: "src/App.tsx", content: appTsxBprTemplate(hasRouter, hasQuery) },
1566
+ { relativePath: "src/pages/Home.tsx", content: homePageBprTemplate(cart) },
1194
1567
  {
1195
1568
  relativePath: "src/providers/index.tsx",
1196
1569
  content: hasQuery ? queryProviderBprTemplate() : simpleProviderBprTemplate()
@@ -1208,7 +1581,7 @@ var init_bpr_layout = __esm({
1208
1581
  if (hasRouter) {
1209
1582
  files.push(
1210
1583
  { relativePath: "src/routes/__root.tsx", content: rootRouteTemplate() },
1211
- { relativePath: "src/routes/index.tsx", content: indexRouteTemplate() },
1584
+ { relativePath: "src/routes/index.tsx", content: indexRouteBprTemplate() },
1212
1585
  { relativePath: "src/routes/routeTree.gen.ts", content: routeTreeGenTemplate() }
1213
1586
  );
1214
1587
  }
@@ -1537,12 +1910,23 @@ var init_vite_config2 = __esm({
1537
1910
  const imports = [
1538
1911
  `import { defineConfig } from 'vite';`,
1539
1912
  `import react from '@vitejs/plugin-react';`,
1913
+ `import path from 'path';`,
1540
1914
  hasTailwind ? `import tailwindcss from '@tailwindcss/vite';` : ""
1541
1915
  ].filter(Boolean).join("\n");
1542
1916
  const plugins = ["react()", hasTailwind ? "tailwindcss()" : ""].filter(Boolean).join(",\n ");
1543
1917
  return `${imports}
1544
1918
 
1545
1919
  export default defineConfig({
1920
+ resolve: {
1921
+ alias: {
1922
+ '@': path.resolve(__dirname, './src'),
1923
+ '@components': path.resolve(__dirname, './src/components'),
1924
+ '@hooks': path.resolve(__dirname, './src/hooks'),
1925
+ '@lib': path.resolve(__dirname, './src/lib'),
1926
+ '@types': path.resolve(__dirname, './src/types'),
1927
+ '@utils': path.resolve(__dirname, './src/utils'),
1928
+ },
1929
+ },
1546
1930
  plugins: [
1547
1931
  ${plugins},
1548
1932
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beaver-build",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Interactive CLI tool for scaffolding modern web projects with production-ready configurations",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",