bunkit-cli 1.3.3 → 1.4.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/dist/index.js +1327 -1051
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14851,39 +14851,89 @@ var init_monorepo = __esm(() => {
|
|
|
14851
14851
|
init_fs();
|
|
14852
14852
|
});
|
|
14853
14853
|
|
|
14854
|
+
// ../core/src/presets/custom.ts
|
|
14855
|
+
function getPresetsDir() {
|
|
14856
|
+
return join(process.env.HOME || process.env.USERPROFILE || ".", ".bunkit");
|
|
14857
|
+
}
|
|
14858
|
+
function getPresetsFile() {
|
|
14859
|
+
return join(getPresetsDir(), "presets.json");
|
|
14860
|
+
}
|
|
14861
|
+
async function loadCustomPresets() {
|
|
14862
|
+
try {
|
|
14863
|
+
const presetsDir = getPresetsDir();
|
|
14864
|
+
await ensureDirectory(presetsDir);
|
|
14865
|
+
const content = await readFile(getPresetsFile());
|
|
14866
|
+
return JSON.parse(content);
|
|
14867
|
+
} catch (_error) {
|
|
14868
|
+
return {};
|
|
14869
|
+
}
|
|
14870
|
+
}
|
|
14871
|
+
async function saveCustomPreset(preset) {
|
|
14872
|
+
await ensureDirectory(getPresetsDir());
|
|
14873
|
+
const presets = await loadCustomPresets();
|
|
14874
|
+
const existing = presets[preset.name];
|
|
14875
|
+
presets[preset.name] = {
|
|
14876
|
+
...preset,
|
|
14877
|
+
createdAt: existing?.createdAt || new Date().toISOString(),
|
|
14878
|
+
updatedAt: new Date().toISOString()
|
|
14879
|
+
};
|
|
14880
|
+
await writeFile(getPresetsFile(), JSON.stringify(presets, null, 2));
|
|
14881
|
+
}
|
|
14882
|
+
async function deleteCustomPreset(name) {
|
|
14883
|
+
const presets = await loadCustomPresets();
|
|
14884
|
+
if (!presets[name]) {
|
|
14885
|
+
return false;
|
|
14886
|
+
}
|
|
14887
|
+
delete presets[name];
|
|
14888
|
+
await writeFile(getPresetsFile(), JSON.stringify(presets, null, 2));
|
|
14889
|
+
return true;
|
|
14890
|
+
}
|
|
14891
|
+
async function getCustomPreset(name) {
|
|
14892
|
+
const presets = await loadCustomPresets();
|
|
14893
|
+
return presets[name] || null;
|
|
14894
|
+
}
|
|
14895
|
+
async function listCustomPresets() {
|
|
14896
|
+
const presets = await loadCustomPresets();
|
|
14897
|
+
return Object.values(presets);
|
|
14898
|
+
}
|
|
14899
|
+
var init_custom2 = __esm(() => {
|
|
14900
|
+
init_dist();
|
|
14901
|
+
init_fs();
|
|
14902
|
+
});
|
|
14903
|
+
|
|
14854
14904
|
// ../core/src/presets/registry.ts
|
|
14855
14905
|
class PresetRegistry {
|
|
14856
14906
|
static aliasMap = null;
|
|
14857
14907
|
static getAliasMap() {
|
|
14858
|
-
if (!
|
|
14859
|
-
|
|
14908
|
+
if (!PresetRegistry.aliasMap) {
|
|
14909
|
+
PresetRegistry.aliasMap = new Map;
|
|
14860
14910
|
for (const [name, definition] of Object.entries(PRESET_DEFINITIONS)) {
|
|
14861
|
-
|
|
14911
|
+
PresetRegistry.aliasMap.set(name, name);
|
|
14862
14912
|
for (const alias of definition.aliases) {
|
|
14863
|
-
|
|
14913
|
+
PresetRegistry.aliasMap.set(alias, name);
|
|
14864
14914
|
}
|
|
14865
14915
|
}
|
|
14866
14916
|
}
|
|
14867
|
-
return
|
|
14917
|
+
return PresetRegistry.aliasMap;
|
|
14868
14918
|
}
|
|
14869
14919
|
static normalize(input) {
|
|
14870
|
-
const map =
|
|
14920
|
+
const map = PresetRegistry.getAliasMap();
|
|
14871
14921
|
return map.get(input) || null;
|
|
14872
14922
|
}
|
|
14873
14923
|
static get(input) {
|
|
14874
|
-
const normalized =
|
|
14924
|
+
const normalized = PresetRegistry.normalize(input);
|
|
14875
14925
|
if (!normalized)
|
|
14876
14926
|
return null;
|
|
14877
14927
|
return PRESET_DEFINITIONS[normalized];
|
|
14878
14928
|
}
|
|
14879
14929
|
static hasCapability(input, capability) {
|
|
14880
|
-
const preset =
|
|
14930
|
+
const preset = PresetRegistry.get(input);
|
|
14881
14931
|
if (!preset)
|
|
14882
14932
|
return false;
|
|
14883
14933
|
return preset.capabilities[capability];
|
|
14884
14934
|
}
|
|
14885
14935
|
static isMonorepo(input) {
|
|
14886
|
-
return
|
|
14936
|
+
return PresetRegistry.hasCapability(input, "isMonorepo");
|
|
14887
14937
|
}
|
|
14888
14938
|
static getSelectOptions() {
|
|
14889
14939
|
return Object.values(PRESET_DEFINITIONS).map((preset) => ({
|
|
@@ -14896,10 +14946,10 @@ class PresetRegistry {
|
|
|
14896
14946
|
return Object.values(PRESET_DEFINITIONS).filter((preset) => preset.capabilities[capability]);
|
|
14897
14947
|
}
|
|
14898
14948
|
static isValid(input) {
|
|
14899
|
-
return
|
|
14949
|
+
return PresetRegistry.normalize(input) !== null;
|
|
14900
14950
|
}
|
|
14901
14951
|
static getAllValidNames() {
|
|
14902
|
-
return Array.from(
|
|
14952
|
+
return Array.from(PresetRegistry.getAliasMap().keys());
|
|
14903
14953
|
}
|
|
14904
14954
|
}
|
|
14905
14955
|
var PRESET_DEFINITIONS;
|
|
@@ -15097,14 +15147,14 @@ var init_registry = __esm(() => {
|
|
|
15097
15147
|
autoprefixer: "^10.4.23",
|
|
15098
15148
|
"radix-ui": "^1.4.3",
|
|
15099
15149
|
"@radix-ui/react-slot": "^1.2.4",
|
|
15100
|
-
"@base-ui/react": "^1.
|
|
15101
|
-
shadcn: "^3.
|
|
15150
|
+
"@base-ui/react": "^1.2.0",
|
|
15151
|
+
shadcn: "^3.8.5",
|
|
15102
15152
|
"class-variance-authority": "^0.7.1",
|
|
15103
15153
|
clsx: "^2.1.1",
|
|
15104
15154
|
"tailwind-merge": "^3.4.0",
|
|
15105
15155
|
"tw-animate-css": "^1.4.0",
|
|
15106
|
-
"@phosphor-icons/react": "^2.1.10",
|
|
15107
15156
|
"iconoir-react": "^7.11.0",
|
|
15157
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
15108
15158
|
ultracite: "^6.4.2",
|
|
15109
15159
|
"@biomejs/biome": "^2.3.10",
|
|
15110
15160
|
vitest: "^4.0.16",
|
|
@@ -15158,14 +15208,14 @@ var init_registry = __esm(() => {
|
|
|
15158
15208
|
autoprefixer: "^10.4.23",
|
|
15159
15209
|
"radix-ui": "^1.4.3",
|
|
15160
15210
|
"@radix-ui/react-slot": "^1.2.4",
|
|
15161
|
-
"@base-ui/react": "^1.
|
|
15162
|
-
shadcn: "^3.
|
|
15211
|
+
"@base-ui/react": "^1.2.0",
|
|
15212
|
+
shadcn: "^3.8.5",
|
|
15163
15213
|
"class-variance-authority": "^0.7.1",
|
|
15164
15214
|
clsx: "^2.1.1",
|
|
15165
15215
|
"tailwind-merge": "^3.4.0",
|
|
15166
15216
|
"tw-animate-css": "^1.4.0",
|
|
15167
|
-
"@phosphor-icons/react": "^2.1.10",
|
|
15168
15217
|
"iconoir-react": "^7.11.0",
|
|
15218
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
15169
15219
|
ultracite: "^6.4.2",
|
|
15170
15220
|
"@biomejs/biome": "^2.3.10",
|
|
15171
15221
|
vitest: "^4.0.16",
|
|
@@ -15221,14 +15271,14 @@ var init_registry = __esm(() => {
|
|
|
15221
15271
|
autoprefixer: "^10.4.23",
|
|
15222
15272
|
"radix-ui": "^1.4.3",
|
|
15223
15273
|
"@radix-ui/react-slot": "^1.2.4",
|
|
15224
|
-
"@base-ui/react": "^1.
|
|
15225
|
-
shadcn: "^3.
|
|
15274
|
+
"@base-ui/react": "^1.2.0",
|
|
15275
|
+
shadcn: "^3.8.5",
|
|
15226
15276
|
"class-variance-authority": "^0.7.1",
|
|
15227
15277
|
clsx: "^2.1.1",
|
|
15228
15278
|
"tailwind-merge": "^3.4.0",
|
|
15229
15279
|
"tw-animate-css": "^1.4.0",
|
|
15230
|
-
"@phosphor-icons/react": "^2.1.10",
|
|
15231
15280
|
"iconoir-react": "^7.11.0",
|
|
15281
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
15232
15282
|
ultracite: "^6.4.2",
|
|
15233
15283
|
"@biomejs/biome": "^2.3.10",
|
|
15234
15284
|
vitest: "^4.0.16",
|
|
@@ -15240,60 +15290,10 @@ var init_registry = __esm(() => {
|
|
|
15240
15290
|
};
|
|
15241
15291
|
});
|
|
15242
15292
|
|
|
15243
|
-
// ../core/src/presets/custom.ts
|
|
15244
|
-
function getPresetsDir() {
|
|
15245
|
-
return join(process.env.HOME || process.env.USERPROFILE || ".", ".bunkit");
|
|
15246
|
-
}
|
|
15247
|
-
function getPresetsFile() {
|
|
15248
|
-
return join(getPresetsDir(), "presets.json");
|
|
15249
|
-
}
|
|
15250
|
-
async function loadCustomPresets() {
|
|
15251
|
-
try {
|
|
15252
|
-
const presetsDir = getPresetsDir();
|
|
15253
|
-
await ensureDirectory(presetsDir);
|
|
15254
|
-
const content = await readFile(getPresetsFile());
|
|
15255
|
-
return JSON.parse(content);
|
|
15256
|
-
} catch (_error) {
|
|
15257
|
-
return {};
|
|
15258
|
-
}
|
|
15259
|
-
}
|
|
15260
|
-
async function saveCustomPreset(preset) {
|
|
15261
|
-
await ensureDirectory(getPresetsDir());
|
|
15262
|
-
const presets = await loadCustomPresets();
|
|
15263
|
-
const existing = presets[preset.name];
|
|
15264
|
-
presets[preset.name] = {
|
|
15265
|
-
...preset,
|
|
15266
|
-
createdAt: existing?.createdAt || new Date().toISOString(),
|
|
15267
|
-
updatedAt: new Date().toISOString()
|
|
15268
|
-
};
|
|
15269
|
-
await writeFile(getPresetsFile(), JSON.stringify(presets, null, 2));
|
|
15270
|
-
}
|
|
15271
|
-
async function deleteCustomPreset(name) {
|
|
15272
|
-
const presets = await loadCustomPresets();
|
|
15273
|
-
if (!presets[name]) {
|
|
15274
|
-
return false;
|
|
15275
|
-
}
|
|
15276
|
-
delete presets[name];
|
|
15277
|
-
await writeFile(getPresetsFile(), JSON.stringify(presets, null, 2));
|
|
15278
|
-
return true;
|
|
15279
|
-
}
|
|
15280
|
-
async function getCustomPreset(name) {
|
|
15281
|
-
const presets = await loadCustomPresets();
|
|
15282
|
-
return presets[name] || null;
|
|
15283
|
-
}
|
|
15284
|
-
async function listCustomPresets() {
|
|
15285
|
-
const presets = await loadCustomPresets();
|
|
15286
|
-
return Object.values(presets);
|
|
15287
|
-
}
|
|
15288
|
-
var init_custom2 = __esm(() => {
|
|
15289
|
-
init_dist();
|
|
15290
|
-
init_fs();
|
|
15291
|
-
});
|
|
15292
|
-
|
|
15293
15293
|
// ../core/src/presets/index.ts
|
|
15294
15294
|
var init_presets = __esm(() => {
|
|
15295
|
-
init_registry();
|
|
15296
15295
|
init_custom2();
|
|
15296
|
+
init_registry();
|
|
15297
15297
|
});
|
|
15298
15298
|
|
|
15299
15299
|
// ../core/src/project.ts
|
|
@@ -15465,6 +15465,7 @@ function createTemplateContext(config) {
|
|
|
15465
15465
|
shadcnMenuAccent: config.shadcnMenuAccent,
|
|
15466
15466
|
shadcnMenuColor: config.shadcnMenuColor,
|
|
15467
15467
|
shadcnRadius: config.shadcnRadius,
|
|
15468
|
+
shadcnRtl: config.shadcnRtl,
|
|
15468
15469
|
supabasePreset: config.supabasePreset,
|
|
15469
15470
|
supabaseFeatures: config.supabaseFeatures,
|
|
15470
15471
|
supabaseWithDrizzle: config.supabaseWithDrizzle
|
|
@@ -19444,6 +19445,17 @@ var init_zod = __esm(() => {
|
|
|
19444
19445
|
});
|
|
19445
19446
|
|
|
19446
19447
|
// ../core/src/types.ts
|
|
19448
|
+
function inferShadcnBase(style) {
|
|
19449
|
+
if (style?.startsWith("base-")) {
|
|
19450
|
+
return "base-ui";
|
|
19451
|
+
}
|
|
19452
|
+
return "radix";
|
|
19453
|
+
}
|
|
19454
|
+
function isModernShadcnStyle(style) {
|
|
19455
|
+
if (!style)
|
|
19456
|
+
return false;
|
|
19457
|
+
return style.startsWith("radix-") || style.startsWith("base-");
|
|
19458
|
+
}
|
|
19447
19459
|
var ProjectConfigSchema, FeatureConfigSchema;
|
|
19448
19460
|
var init_types2 = __esm(() => {
|
|
19449
19461
|
init_zod();
|
|
@@ -19490,13 +19502,27 @@ var init_types2 = __esm(() => {
|
|
|
19490
19502
|
tsStrictness: exports_external.enum(["strict", "moderate", "loose"]).default("strict"),
|
|
19491
19503
|
uiLibrary: exports_external.enum(["shadcn", "none"]).optional(),
|
|
19492
19504
|
cssFramework: exports_external.enum(["tailwind", "vanilla", "css-modules"]).optional(),
|
|
19493
|
-
shadcnStyle: exports_external.enum([
|
|
19505
|
+
shadcnStyle: exports_external.enum([
|
|
19506
|
+
"radix-maia",
|
|
19507
|
+
"radix-vega",
|
|
19508
|
+
"radix-nova",
|
|
19509
|
+
"radix-lyra",
|
|
19510
|
+
"radix-mira",
|
|
19511
|
+
"base-maia",
|
|
19512
|
+
"base-vega",
|
|
19513
|
+
"base-nova",
|
|
19514
|
+
"base-lyra",
|
|
19515
|
+
"base-mira",
|
|
19516
|
+
"new-york",
|
|
19517
|
+
"default"
|
|
19518
|
+
]).optional(),
|
|
19494
19519
|
shadcnBase: exports_external.enum(["radix", "base-ui"]).optional(),
|
|
19495
19520
|
shadcnBaseColor: exports_external.enum(["neutral", "gray", "zinc", "stone", "slate"]).optional(),
|
|
19496
19521
|
shadcnIconLibrary: exports_external.enum(["phosphor", "lucide", "iconoir"]).optional(),
|
|
19497
19522
|
shadcnMenuAccent: exports_external.enum(["subtle", "bold"]).optional(),
|
|
19498
19523
|
shadcnMenuColor: exports_external.enum(["default", "muted"]).optional(),
|
|
19499
19524
|
shadcnRadius: exports_external.string().optional(),
|
|
19525
|
+
shadcnRtl: exports_external.boolean().optional(),
|
|
19500
19526
|
testing: exports_external.enum(["bun-test", "vitest", "none"]).default("bun-test"),
|
|
19501
19527
|
docker: exports_external.boolean().default(false),
|
|
19502
19528
|
cicd: exports_external.boolean().default(false),
|
|
@@ -19571,6 +19597,7 @@ __export(exports_src, {
|
|
|
19571
19597
|
logger: () => logger,
|
|
19572
19598
|
loadCustomPresets: () => loadCustomPresets,
|
|
19573
19599
|
listCustomPresets: () => listCustomPresets,
|
|
19600
|
+
isModernShadcnStyle: () => isModernShadcnStyle,
|
|
19574
19601
|
isGitRepository: () => isGitRepository,
|
|
19575
19602
|
isGitAvailable: () => isGitAvailable,
|
|
19576
19603
|
isDirectoryEmpty: () => isDirectoryEmpty,
|
|
@@ -19578,6 +19605,7 @@ __export(exports_src, {
|
|
|
19578
19605
|
installDevDependencies: () => installDevDependencies,
|
|
19579
19606
|
installDependencies: () => installDependencies,
|
|
19580
19607
|
initGit: () => initGit,
|
|
19608
|
+
inferShadcnBase: () => inferShadcnBase,
|
|
19581
19609
|
getWorkspaceName: () => getWorkspaceName,
|
|
19582
19610
|
getRootPackageJson: () => getRootPackageJson,
|
|
19583
19611
|
getProjectName: () => getProjectName,
|
|
@@ -21850,11 +21878,13 @@ async function writeMonorepoRootPackageJson(projectPath, projectName, catalog, o
|
|
|
21850
21878
|
});
|
|
21851
21879
|
}
|
|
21852
21880
|
async function writeNextjsAppPackageJson(appPath, scopeName, appName, options = {}) {
|
|
21881
|
+
const iconLibrary = options.shadcnIconLibrary || "iconoir";
|
|
21882
|
+
const iconPackageName = iconLibrary === "iconoir" ? "iconoir-react" : iconLibrary === "phosphor" ? "@phosphor-icons/react" : "lucide-react";
|
|
21853
21883
|
const dependencies = {
|
|
21854
21884
|
react: "catalog:",
|
|
21855
21885
|
"react-dom": "catalog:",
|
|
21856
21886
|
next: "catalog:",
|
|
21857
|
-
|
|
21887
|
+
[iconPackageName]: "catalog:"
|
|
21858
21888
|
};
|
|
21859
21889
|
if (options.usesTypes) {
|
|
21860
21890
|
dependencies[`@${scopeName}/types`] = "workspace:*";
|
|
@@ -21916,7 +21946,23 @@ async function writeHonoApiPackageJson(appPath, scopeName, options = {}) {
|
|
|
21916
21946
|
}
|
|
21917
21947
|
});
|
|
21918
21948
|
}
|
|
21919
|
-
async function writeUiPackageJson(packagePath, scopeName) {
|
|
21949
|
+
async function writeUiPackageJson(packagePath, scopeName, options = {}) {
|
|
21950
|
+
const shadcnBase = options.shadcnBase || "radix";
|
|
21951
|
+
const iconLibrary = options.shadcnIconLibrary || "iconoir";
|
|
21952
|
+
const uiFoundationDeps = {};
|
|
21953
|
+
if (shadcnBase === "base-ui") {
|
|
21954
|
+
uiFoundationDeps["@base-ui/react"] = "catalog:";
|
|
21955
|
+
} else {
|
|
21956
|
+
uiFoundationDeps["radix-ui"] = "catalog:";
|
|
21957
|
+
}
|
|
21958
|
+
const iconDeps = {};
|
|
21959
|
+
if (iconLibrary === "iconoir") {
|
|
21960
|
+
iconDeps["iconoir-react"] = "catalog:";
|
|
21961
|
+
} else if (iconLibrary === "phosphor") {
|
|
21962
|
+
iconDeps["@phosphor-icons/react"] = "catalog:";
|
|
21963
|
+
} else {
|
|
21964
|
+
iconDeps["lucide-react"] = "catalog:";
|
|
21965
|
+
}
|
|
21920
21966
|
await writePackageJson(packagePath, {
|
|
21921
21967
|
name: `@${scopeName}/ui`,
|
|
21922
21968
|
version: "0.0.0",
|
|
@@ -21936,13 +21982,11 @@ async function writeUiPackageJson(packagePath, scopeName) {
|
|
|
21936
21982
|
lint: "tsc --noEmit"
|
|
21937
21983
|
},
|
|
21938
21984
|
dependencies: {
|
|
21939
|
-
|
|
21940
|
-
"@radix-ui/react-slot": "catalog:",
|
|
21985
|
+
...uiFoundationDeps,
|
|
21941
21986
|
"class-variance-authority": "catalog:",
|
|
21942
21987
|
clsx: "catalog:",
|
|
21943
21988
|
"tailwind-merge": "catalog:",
|
|
21944
|
-
|
|
21945
|
-
"iconoir-react": "catalog:",
|
|
21989
|
+
...iconDeps,
|
|
21946
21990
|
"tw-animate-css": "catalog:",
|
|
21947
21991
|
shadcn: "catalog:",
|
|
21948
21992
|
tailwindcss: "catalog:",
|
|
@@ -28715,9 +28759,10 @@ function generateModernThemeCSS(baseColor, customRadius) {
|
|
|
28715
28759
|
async function setupShadcnWeb(projectPath, context) {
|
|
28716
28760
|
await ensureDirectory(join(projectPath, "src/components/ui"));
|
|
28717
28761
|
await ensureDirectory(join(projectPath, "src/lib"));
|
|
28718
|
-
const style = context.shadcnStyle || "
|
|
28762
|
+
const style = context.shadcnStyle || "radix-maia";
|
|
28719
28763
|
const baseColor = context.shadcnBaseColor || "zinc";
|
|
28720
28764
|
const radius = context.shadcnRadius || "0.625rem";
|
|
28765
|
+
const iconLibrary = context.shadcnIconLibrary || "iconoir";
|
|
28721
28766
|
const componentsJson = {
|
|
28722
28767
|
$schema: "https://ui.shadcn.com/schema.json",
|
|
28723
28768
|
style,
|
|
@@ -28729,7 +28774,7 @@ async function setupShadcnWeb(projectPath, context) {
|
|
|
28729
28774
|
baseColor,
|
|
28730
28775
|
cssVariables: true
|
|
28731
28776
|
},
|
|
28732
|
-
iconLibrary
|
|
28777
|
+
iconLibrary,
|
|
28733
28778
|
aliases: {
|
|
28734
28779
|
components: "@/components",
|
|
28735
28780
|
utils: "@/lib/utils",
|
|
@@ -28738,6 +28783,9 @@ async function setupShadcnWeb(projectPath, context) {
|
|
|
28738
28783
|
hooks: "@/hooks"
|
|
28739
28784
|
}
|
|
28740
28785
|
};
|
|
28786
|
+
if (context.shadcnRtl) {
|
|
28787
|
+
componentsJson.rtl = true;
|
|
28788
|
+
}
|
|
28741
28789
|
await writeFile(join(projectPath, "components.json"), JSON.stringify(componentsJson, null, 2));
|
|
28742
28790
|
const utilsContent = `import { clsx, type ClassValue } from 'clsx';
|
|
28743
28791
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -28755,20 +28803,36 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
28755
28803
|
if (!packageJson.dependencies) {
|
|
28756
28804
|
packageJson.dependencies = {};
|
|
28757
28805
|
}
|
|
28758
|
-
|
|
28806
|
+
const shadcnBase = inferShadcnBase(context.shadcnStyle);
|
|
28807
|
+
if (shadcnBase === "base-ui") {
|
|
28808
|
+
packageJson.dependencies["@base-ui/react"] = "catalog:";
|
|
28809
|
+
} else {
|
|
28810
|
+
packageJson.dependencies["radix-ui"] = "catalog:";
|
|
28811
|
+
}
|
|
28759
28812
|
packageJson.dependencies["class-variance-authority"] = "catalog:";
|
|
28760
28813
|
packageJson.dependencies.clsx = "catalog:";
|
|
28761
28814
|
packageJson.dependencies["tailwind-merge"] = "catalog:";
|
|
28762
|
-
|
|
28815
|
+
const iconPackageName = iconLibrary === "iconoir" ? "iconoir-react" : iconLibrary === "phosphor" ? "@phosphor-icons/react" : "lucide-react";
|
|
28816
|
+
packageJson.dependencies[iconPackageName] = "catalog:";
|
|
28763
28817
|
if (!packageJson.catalog) {
|
|
28764
28818
|
packageJson.catalog = {};
|
|
28765
28819
|
}
|
|
28766
|
-
|
|
28820
|
+
if (shadcnBase === "base-ui") {
|
|
28821
|
+
packageJson.catalog["@base-ui/react"] = "^1.2.0";
|
|
28822
|
+
} else {
|
|
28823
|
+
packageJson.catalog["radix-ui"] = "^1.4.3";
|
|
28824
|
+
}
|
|
28767
28825
|
packageJson.catalog["class-variance-authority"] = "^0.7.1";
|
|
28768
28826
|
packageJson.catalog.clsx = "^2.1.1";
|
|
28769
28827
|
packageJson.catalog["tailwind-merge"] = "^3.4.0";
|
|
28770
|
-
packageJson.catalog["lucide-react"] = "^0.562.0";
|
|
28771
28828
|
packageJson.catalog["tw-animate-css"] = "^1.2.9";
|
|
28829
|
+
if (iconLibrary === "iconoir") {
|
|
28830
|
+
packageJson.catalog["iconoir-react"] = "^7.11.0";
|
|
28831
|
+
} else if (iconLibrary === "phosphor") {
|
|
28832
|
+
packageJson.catalog["@phosphor-icons/react"] = "^2.1.10";
|
|
28833
|
+
} else {
|
|
28834
|
+
packageJson.catalog["lucide-react"] = "^0.562.0";
|
|
28835
|
+
}
|
|
28772
28836
|
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
28773
28837
|
const globalsCssPath = join(projectPath, "src/app/globals.css");
|
|
28774
28838
|
let globalsCss = "";
|
|
@@ -28795,9 +28859,11 @@ ${shadcnCss}`;
|
|
|
28795
28859
|
async function setupShadcnMonorepo(projectPath, context) {
|
|
28796
28860
|
const packageName = context.packageName || context.projectName.toLowerCase().replace(/\s+/g, "-");
|
|
28797
28861
|
const uiPackageName = `@${packageName}/ui`;
|
|
28798
|
-
const style = context.shadcnStyle || "
|
|
28862
|
+
const style = context.shadcnStyle || "radix-maia";
|
|
28799
28863
|
const baseColor = context.shadcnBaseColor || "zinc";
|
|
28800
28864
|
const radius = context.shadcnRadius || "0.625rem";
|
|
28865
|
+
const iconLibrary = context.shadcnIconLibrary || "iconoir";
|
|
28866
|
+
const shadcnBase = inferShadcnBase(context.shadcnStyle);
|
|
28801
28867
|
await ensureDirectory(join(projectPath, "packages/ui/src/components"));
|
|
28802
28868
|
await ensureDirectory(join(projectPath, "packages/ui/src/lib"));
|
|
28803
28869
|
await ensureDirectory(join(projectPath, "packages/ui/src/hooks"));
|
|
@@ -28819,11 +28885,11 @@ async function setupShadcnMonorepo(projectPath, context) {
|
|
|
28819
28885
|
"./components/ui/*": "./src/components/ui/*/index.ts"
|
|
28820
28886
|
},
|
|
28821
28887
|
dependencies: {
|
|
28822
|
-
"@
|
|
28888
|
+
...shadcnBase === "base-ui" ? { "@base-ui/react": "catalog:" } : { "radix-ui": "catalog:" },
|
|
28823
28889
|
"class-variance-authority": "catalog:",
|
|
28824
28890
|
clsx: "catalog:",
|
|
28825
28891
|
"tailwind-merge": "catalog:",
|
|
28826
|
-
"lucide-react": "catalog:",
|
|
28892
|
+
...iconLibrary === "iconoir" ? { "iconoir-react": "catalog:" } : iconLibrary === "phosphor" ? { "@phosphor-icons/react": "catalog:" } : { "lucide-react": "catalog:" },
|
|
28827
28893
|
tailwindcss: "catalog:",
|
|
28828
28894
|
"@tailwindcss/postcss": "catalog:"
|
|
28829
28895
|
},
|
|
@@ -28845,7 +28911,7 @@ async function setupShadcnMonorepo(projectPath, context) {
|
|
|
28845
28911
|
baseColor,
|
|
28846
28912
|
cssVariables: true
|
|
28847
28913
|
},
|
|
28848
|
-
iconLibrary
|
|
28914
|
+
iconLibrary,
|
|
28849
28915
|
aliases: {
|
|
28850
28916
|
components: "./src/components",
|
|
28851
28917
|
ui: "./src/components/ui",
|
|
@@ -28854,6 +28920,9 @@ async function setupShadcnMonorepo(projectPath, context) {
|
|
|
28854
28920
|
lib: "@/lib"
|
|
28855
28921
|
}
|
|
28856
28922
|
};
|
|
28923
|
+
if (context.shadcnRtl) {
|
|
28924
|
+
uiComponentsJson.rtl = true;
|
|
28925
|
+
}
|
|
28857
28926
|
await writeFile(join(projectPath, "packages/ui/components.json"), JSON.stringify(uiComponentsJson, null, 2));
|
|
28858
28927
|
const uiUtilsContent = `import { clsx, type ClassValue } from 'clsx';
|
|
28859
28928
|
import { twMerge } from 'tailwind-merge';
|
|
@@ -28943,7 +29012,7 @@ export default config;
|
|
|
28943
29012
|
baseColor,
|
|
28944
29013
|
cssVariables: true
|
|
28945
29014
|
},
|
|
28946
|
-
iconLibrary
|
|
29015
|
+
iconLibrary,
|
|
28947
29016
|
aliases: {
|
|
28948
29017
|
components: "@/components",
|
|
28949
29018
|
hooks: "@/hooks",
|
|
@@ -28952,6 +29021,9 @@ export default config;
|
|
|
28952
29021
|
ui: "@workspace/ui/components/ui"
|
|
28953
29022
|
}
|
|
28954
29023
|
};
|
|
29024
|
+
if (context.shadcnRtl) {
|
|
29025
|
+
appComponentsJson.rtl = true;
|
|
29026
|
+
}
|
|
28955
29027
|
await writeFile(join(appPath, "components.json"), JSON.stringify(appComponentsJson, null, 2));
|
|
28956
29028
|
const layoutPath = join(appPath, "src/app/layout.tsx");
|
|
28957
29029
|
if (await fileExists(layoutPath)) {
|
|
@@ -29047,16 +29119,26 @@ export default nextConfig;
|
|
|
29047
29119
|
rootPackageJson.catalog = {};
|
|
29048
29120
|
}
|
|
29049
29121
|
const shadcnDependencies = {
|
|
29050
|
-
"@radix-ui/react-slot": "^1.2.4",
|
|
29051
29122
|
"class-variance-authority": "^0.7.1",
|
|
29052
29123
|
clsx: "^2.1.1",
|
|
29053
29124
|
"tailwind-merge": "^3.4.0",
|
|
29054
|
-
"lucide-react": "^0.562.0",
|
|
29055
29125
|
"tw-animate-css": "^1.2.9",
|
|
29056
29126
|
"@types/react": "^19.2.7",
|
|
29057
29127
|
"@types/react-dom": "^19.2.3",
|
|
29058
29128
|
typescript: "^5.9.3"
|
|
29059
29129
|
};
|
|
29130
|
+
if (shadcnBase === "base-ui") {
|
|
29131
|
+
shadcnDependencies["@base-ui/react"] = "^1.2.0";
|
|
29132
|
+
} else {
|
|
29133
|
+
shadcnDependencies["radix-ui"] = "^1.4.3";
|
|
29134
|
+
}
|
|
29135
|
+
if (iconLibrary === "iconoir") {
|
|
29136
|
+
shadcnDependencies["iconoir-react"] = "^7.11.0";
|
|
29137
|
+
} else if (iconLibrary === "phosphor") {
|
|
29138
|
+
shadcnDependencies["@phosphor-icons/react"] = "^2.1.10";
|
|
29139
|
+
} else {
|
|
29140
|
+
shadcnDependencies["lucide-react"] = "^0.562.0";
|
|
29141
|
+
}
|
|
29060
29142
|
Object.assign(rootPackageJson.catalog, shadcnDependencies);
|
|
29061
29143
|
await writeFile(rootPackageJsonPath, JSON.stringify(rootPackageJson, null, 2));
|
|
29062
29144
|
await createShadcnDocs(join(projectPath, "packages/ui"), true, context);
|
|
@@ -29451,11 +29533,15 @@ async function buildEnterprisePreset(projectPath, context) {
|
|
|
29451
29533
|
autoprefixer: "^10.4.23",
|
|
29452
29534
|
postcss: "^8.5.6",
|
|
29453
29535
|
"@tailwindcss/postcss": "^4.1.18",
|
|
29536
|
+
"radix-ui": "^1.4.3",
|
|
29454
29537
|
"@radix-ui/react-slot": "^1.2.4",
|
|
29538
|
+
"@base-ui/react": "^1.2.0",
|
|
29539
|
+
shadcn: "^3.8.5",
|
|
29455
29540
|
"class-variance-authority": "^0.7.1",
|
|
29456
29541
|
clsx: "^2.1.1",
|
|
29457
29542
|
"tailwind-merge": "^3.4.0",
|
|
29458
29543
|
"iconoir-react": "^7.11.0",
|
|
29544
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
29459
29545
|
"lucide-react": "^0.562.0",
|
|
29460
29546
|
"tw-animate-css": "^1.2.9",
|
|
29461
29547
|
"@biomejs/biome": "^2.3.10",
|
|
@@ -29628,9 +29714,11 @@ async function buildEnterprisePreset(projectPath, context) {
|
|
|
29628
29714
|
const enterpriseContext = {
|
|
29629
29715
|
...context,
|
|
29630
29716
|
uiLibrary: "shadcn",
|
|
29631
|
-
shadcnStyle: context.shadcnStyle || "
|
|
29717
|
+
shadcnStyle: context.shadcnStyle || "radix-maia",
|
|
29632
29718
|
shadcnBaseColor: context.shadcnBaseColor || "zinc",
|
|
29633
|
-
shadcnRadius: context.shadcnRadius || "0.625rem"
|
|
29719
|
+
shadcnRadius: context.shadcnRadius || "0.625rem",
|
|
29720
|
+
shadcnIconLibrary: context.shadcnIconLibrary || "iconoir",
|
|
29721
|
+
shadcnRtl: context.shadcnRtl
|
|
29634
29722
|
};
|
|
29635
29723
|
await setupShadcnMonorepo(projectPath, enterpriseContext);
|
|
29636
29724
|
}
|
|
@@ -29791,11 +29879,15 @@ async function buildFullPreset(projectPath, context) {
|
|
|
29791
29879
|
autoprefixer: "^10.4.23",
|
|
29792
29880
|
postcss: "^8.5.6",
|
|
29793
29881
|
"@tailwindcss/postcss": "^4.1.18",
|
|
29882
|
+
"radix-ui": "^1.4.3",
|
|
29794
29883
|
"@radix-ui/react-slot": "^1.2.4",
|
|
29884
|
+
"@base-ui/react": "^1.2.0",
|
|
29885
|
+
shadcn: "^3.8.5",
|
|
29795
29886
|
"class-variance-authority": "^0.7.1",
|
|
29796
29887
|
clsx: "^2.1.1",
|
|
29797
29888
|
"tailwind-merge": "^3.4.0",
|
|
29798
29889
|
"iconoir-react": "^7.11.0",
|
|
29890
|
+
"@phosphor-icons/react": "^2.1.10",
|
|
29799
29891
|
"lucide-react": "^0.562.0",
|
|
29800
29892
|
"tw-animate-css": "^1.2.9",
|
|
29801
29893
|
...context.codeQuality === "biome" ? { "@biomejs/biome": "^2.3.10" } : {},
|
|
@@ -30589,1046 +30681,1023 @@ networks:
|
|
|
30589
30681
|
const fullContext = {
|
|
30590
30682
|
...context,
|
|
30591
30683
|
uiLibrary: "shadcn",
|
|
30592
|
-
shadcnStyle: context.shadcnStyle || "
|
|
30684
|
+
shadcnStyle: context.shadcnStyle || "radix-maia",
|
|
30593
30685
|
shadcnBaseColor: context.shadcnBaseColor || "zinc",
|
|
30594
|
-
shadcnRadius: context.shadcnRadius || "0.625rem"
|
|
30686
|
+
shadcnRadius: context.shadcnRadius || "0.625rem",
|
|
30687
|
+
shadcnIconLibrary: context.shadcnIconLibrary || "iconoir",
|
|
30688
|
+
shadcnRtl: context.shadcnRtl
|
|
30595
30689
|
};
|
|
30596
30690
|
await setupShadcnMonorepo(projectPath, fullContext);
|
|
30597
30691
|
}
|
|
30598
30692
|
await setupTooling(projectPath, context);
|
|
30599
30693
|
await setupVSCodeDebug(projectPath, context, "full");
|
|
30600
30694
|
}
|
|
30601
|
-
// ../templates/src/builders/
|
|
30695
|
+
// ../templates/src/builders/full-v2.ts
|
|
30602
30696
|
init_src();
|
|
30603
30697
|
init_dist();
|
|
30604
|
-
|
|
30605
|
-
const indexContent = `console.log('Hello from ${context.projectName}! \uD83C\uDF5E');
|
|
30606
|
-
|
|
30607
|
-
// Your code here
|
|
30608
|
-
const greet = (name: string): void => {
|
|
30609
|
-
console.log(\`Welcome, \${name}!\`);
|
|
30610
|
-
};
|
|
30698
|
+
init_package_json();
|
|
30611
30699
|
|
|
30612
|
-
|
|
30613
|
-
|
|
30614
|
-
|
|
30615
|
-
|
|
30700
|
+
// ../templates/src/shared/ui-package.ts
|
|
30701
|
+
init_src();
|
|
30702
|
+
init_dist();
|
|
30703
|
+
init_package_json();
|
|
30704
|
+
async function buildUiPackage(packagesPath, options) {
|
|
30705
|
+
const uiPath = join(packagesPath, "ui");
|
|
30706
|
+
await ensureDirectory(join(uiPath, "src/components"));
|
|
30707
|
+
await ensureDirectory(join(uiPath, "src/hooks"));
|
|
30708
|
+
await ensureDirectory(join(uiPath, "src/lib"));
|
|
30709
|
+
await ensureDirectory(join(uiPath, "src/styles"));
|
|
30710
|
+
const style = options.shadcnStyle || "radix-maia";
|
|
30711
|
+
const useModernStyle = isModernShadcnStyle(style);
|
|
30712
|
+
const shadcnBase = options.shadcnBase || inferShadcnBase(style);
|
|
30713
|
+
const iconLibrary = options.shadcnIconLibrary || "iconoir";
|
|
30714
|
+
await writeUiPackageJson(uiPath, options.scopeName, {
|
|
30715
|
+
shadcnBase,
|
|
30716
|
+
shadcnIconLibrary: iconLibrary
|
|
30717
|
+
});
|
|
30718
|
+
await writeFile(join(uiPath, "tsconfig.json"), JSON.stringify({
|
|
30719
|
+
extends: "../../tooling/typescript/library.json",
|
|
30616
30720
|
compilerOptions: {
|
|
30617
|
-
lib: ["ESNext"],
|
|
30618
|
-
target: "ESNext",
|
|
30619
|
-
module: "ESNext",
|
|
30620
|
-
moduleDetection: "force",
|
|
30621
30721
|
jsx: "react-jsx",
|
|
30622
|
-
|
|
30623
|
-
|
|
30624
|
-
|
|
30625
|
-
|
|
30626
|
-
|
|
30627
|
-
|
|
30628
|
-
|
|
30629
|
-
|
|
30630
|
-
|
|
30631
|
-
|
|
30632
|
-
|
|
30633
|
-
|
|
30722
|
+
rootDir: "./src",
|
|
30723
|
+
outDir: "./dist",
|
|
30724
|
+
baseUrl: ".",
|
|
30725
|
+
paths: {
|
|
30726
|
+
"@/*": ["./src/*"]
|
|
30727
|
+
}
|
|
30728
|
+
},
|
|
30729
|
+
include: ["src/**/*"],
|
|
30730
|
+
exclude: ["node_modules"]
|
|
30731
|
+
}, null, 2));
|
|
30732
|
+
const componentsJson = {
|
|
30733
|
+
$schema: "https://ui.shadcn.com/schema.json",
|
|
30734
|
+
style,
|
|
30735
|
+
rsc: true,
|
|
30736
|
+
tsx: true,
|
|
30737
|
+
tailwind: {
|
|
30738
|
+
config: "",
|
|
30739
|
+
css: "./src/styles/globals.css",
|
|
30740
|
+
baseColor: options.shadcnBaseColor || "zinc",
|
|
30741
|
+
cssVariables: true,
|
|
30742
|
+
prefix: ""
|
|
30743
|
+
},
|
|
30744
|
+
iconLibrary,
|
|
30745
|
+
aliases: {
|
|
30746
|
+
components: "@/components",
|
|
30747
|
+
utils: "@/lib/utils",
|
|
30748
|
+
ui: "@/components/ui",
|
|
30749
|
+
lib: "@/lib",
|
|
30750
|
+
hooks: "@/hooks"
|
|
30634
30751
|
}
|
|
30635
30752
|
};
|
|
30636
|
-
|
|
30637
|
-
|
|
30638
|
-
|
|
30639
|
-
|
|
30640
|
-
await setupUltracite(projectPath, context);
|
|
30641
|
-
} else {
|
|
30642
|
-
await setupBiome(projectPath, context);
|
|
30753
|
+
if (useModernStyle) {
|
|
30754
|
+
componentsJson.menuColor = options.shadcnMenuColor || "default";
|
|
30755
|
+
componentsJson.menuAccent = options.shadcnMenuAccent || "subtle";
|
|
30756
|
+
componentsJson.registries = {};
|
|
30643
30757
|
}
|
|
30644
|
-
|
|
30645
|
-
|
|
30646
|
-
}
|
|
30647
|
-
// ../templates/src/builders/monorepo-bun.ts
|
|
30648
|
-
init_src();
|
|
30649
|
-
init_dist();
|
|
30650
|
-
var databaseSetupMap6 = {
|
|
30651
|
-
"postgres-drizzle": setupPostgresDrizzle,
|
|
30652
|
-
"postgres-prisma": setupPostgresPrisma,
|
|
30653
|
-
"mysql-drizzle": setupMySQLDrizzle,
|
|
30654
|
-
"mysql-prisma": setupMySQLPrisma,
|
|
30655
|
-
supabase: setupSupabaseOnly,
|
|
30656
|
-
"supabase-drizzle": setupSupabaseDrizzle,
|
|
30657
|
-
"supabase-prisma": setupSupabasePrisma,
|
|
30658
|
-
"sqlite-drizzle": setupSQLiteDrizzle,
|
|
30659
|
-
"sqlite-prisma": setupSQLitePrisma,
|
|
30660
|
-
none: async () => {}
|
|
30661
|
-
};
|
|
30662
|
-
async function buildMonorepoBunPreset(projectPath, context) {
|
|
30663
|
-
await ensureDirectory(join(projectPath, "apps/web"));
|
|
30664
|
-
await ensureDirectory(join(projectPath, "apps/api"));
|
|
30665
|
-
await ensureDirectory(join(projectPath, "packages/types"));
|
|
30666
|
-
await ensureDirectory(join(projectPath, "packages/utils"));
|
|
30667
|
-
if (context.database && context.database !== "none") {
|
|
30668
|
-
await ensureDirectory(join(projectPath, "packages/db"));
|
|
30758
|
+
if (options.shadcnRtl) {
|
|
30759
|
+
componentsJson.rtl = true;
|
|
30669
30760
|
}
|
|
30670
|
-
|
|
30671
|
-
|
|
30672
|
-
|
|
30673
|
-
|
|
30674
|
-
|
|
30675
|
-
|
|
30676
|
-
|
|
30677
|
-
|
|
30678
|
-
|
|
30679
|
-
|
|
30680
|
-
|
|
30681
|
-
|
|
30682
|
-
|
|
30683
|
-
|
|
30684
|
-
|
|
30685
|
-
|
|
30686
|
-
|
|
30687
|
-
|
|
30688
|
-
|
|
30689
|
-
|
|
30690
|
-
|
|
30691
|
-
|
|
30692
|
-
|
|
30693
|
-
|
|
30694
|
-
|
|
30695
|
-
|
|
30696
|
-
"drizzle-kit": "^0.31.8",
|
|
30697
|
-
postgres: "^3.4.7",
|
|
30698
|
-
"@supabase/supabase-js": "^2.88.0",
|
|
30699
|
-
"@prisma/client": "^7.2.0",
|
|
30700
|
-
prisma: "^7.2.0",
|
|
30701
|
-
mysql2: "^3.16.0",
|
|
30702
|
-
"better-auth": "^1.4.7",
|
|
30703
|
-
"next-auth": "^4.24.13",
|
|
30704
|
-
"@auth/drizzle-adapter": "^1.11.1",
|
|
30705
|
-
tailwindcss: "^4.1.18",
|
|
30706
|
-
autoprefixer: "^10.4.23",
|
|
30707
|
-
postcss: "^8.5.6",
|
|
30708
|
-
typescript: "^5.9.3",
|
|
30709
|
-
"@types/react": "^19.2.7",
|
|
30710
|
-
"@types/react-dom": "^19.2.3",
|
|
30711
|
-
"@types/node": "^25.0.3"
|
|
30712
|
-
}
|
|
30713
|
-
};
|
|
30714
|
-
await writeFile(join(projectPath, "package.json"), JSON.stringify(rootPackageJson, null, 2));
|
|
30715
|
-
const apiPath = join(projectPath, "apps/api");
|
|
30716
|
-
await setupBunServeNative(apiPath, context, true);
|
|
30717
|
-
const apiPackageJson = {
|
|
30718
|
-
name: `@${context.packageName}/api`,
|
|
30719
|
-
version: "0.0.0",
|
|
30720
|
-
private: true,
|
|
30721
|
-
scripts: {
|
|
30722
|
-
dev: "bun run --hot src/index.ts",
|
|
30723
|
-
start: "bun run src/index.ts",
|
|
30724
|
-
debug: "bun --inspect src/index.ts",
|
|
30725
|
-
"debug:brk": "bun --inspect-brk src/index.ts",
|
|
30726
|
-
"debug:wait": "bun --inspect-wait src/index.ts"
|
|
30727
|
-
},
|
|
30728
|
-
dependencies: {
|
|
30729
|
-
[`@${context.packageName}/types`]: "workspace:*"
|
|
30730
|
-
},
|
|
30731
|
-
devDependencies: {
|
|
30732
|
-
"@types/bun": "latest",
|
|
30733
|
-
typescript: "catalog:"
|
|
30734
|
-
}
|
|
30735
|
-
};
|
|
30736
|
-
await writeFile(join(apiPath, "package.json"), JSON.stringify(apiPackageJson, null, 2));
|
|
30737
|
-
const webPath = join(projectPath, "apps/web");
|
|
30738
|
-
await setupBunFullstack(webPath, context);
|
|
30739
|
-
const webPackageJson = {
|
|
30740
|
-
name: `@${context.packageName}/web`,
|
|
30741
|
-
version: "0.0.0",
|
|
30742
|
-
private: true,
|
|
30743
|
-
scripts: {
|
|
30744
|
-
dev: "bun run --hot src/index.ts",
|
|
30745
|
-
build: "bun build src/index.ts --outdir ./dist --target bun",
|
|
30746
|
-
start: "bun run dist/index.js",
|
|
30747
|
-
debug: "bun --inspect src/index.ts",
|
|
30748
|
-
"debug:brk": "bun --inspect-brk src/index.ts",
|
|
30749
|
-
"debug:wait": "bun --inspect-wait src/index.ts"
|
|
30750
|
-
},
|
|
30751
|
-
dependencies: {
|
|
30752
|
-
react: "catalog:",
|
|
30753
|
-
"react-dom": "catalog:",
|
|
30754
|
-
[`@${context.packageName}/types`]: "workspace:*"
|
|
30755
|
-
},
|
|
30756
|
-
devDependencies: {
|
|
30757
|
-
"@types/react": "catalog:",
|
|
30758
|
-
"@types/react-dom": "catalog:",
|
|
30759
|
-
"@types/bun": "latest",
|
|
30760
|
-
typescript: "catalog:"
|
|
30761
|
-
}
|
|
30762
|
-
};
|
|
30763
|
-
await writeFile(join(webPath, "package.json"), JSON.stringify(webPackageJson, null, 2));
|
|
30764
|
-
if (context.database && context.database !== "none") {
|
|
30765
|
-
await databaseSetupMap6[context.database](join(projectPath, "packages/db"), context, true);
|
|
30766
|
-
}
|
|
30767
|
-
if (context.redis) {
|
|
30768
|
-
await setupRedis(join(projectPath, "packages"), context, true);
|
|
30769
|
-
}
|
|
30770
|
-
if (context.auth === "better-auth") {
|
|
30771
|
-
await setupBetterAuth(join(projectPath, "packages"), context, true);
|
|
30772
|
-
} else if (context.auth === "nextauth") {
|
|
30773
|
-
await setupNextAuth(join(projectPath, "packages"), context, true);
|
|
30774
|
-
}
|
|
30775
|
-
if (context.useBunSecrets) {
|
|
30776
|
-
await setupBunSecrets(join(projectPath, "packages"), context, true);
|
|
30777
|
-
}
|
|
30778
|
-
if (context.codeQuality === "biome") {
|
|
30779
|
-
await setupBiome(projectPath, context);
|
|
30761
|
+
await writeFile(join(uiPath, "components.json"), JSON.stringify(componentsJson, null, 2));
|
|
30762
|
+
await writeFile(join(uiPath, "postcss.config.mjs"), `export default {
|
|
30763
|
+
plugins: {
|
|
30764
|
+
'@tailwindcss/postcss': {},
|
|
30765
|
+
},
|
|
30766
|
+
};
|
|
30767
|
+
`);
|
|
30768
|
+
const appsToScan = options.appsToScan || ["web", "platform"];
|
|
30769
|
+
const appSourcePaths = appsToScan.map((app) => `@source "../../../apps/${app}/src/**/*.{ts,tsx}";`);
|
|
30770
|
+
const baseColor = options.shadcnBaseColor || "zinc";
|
|
30771
|
+
const customRadius = options.shadcnRadius || "0.625rem";
|
|
30772
|
+
let globalsCss;
|
|
30773
|
+
if (useModernStyle) {
|
|
30774
|
+
const modernThemeCSS = generateModernThemeCSS(baseColor, customRadius);
|
|
30775
|
+
const shadcnImport = shadcnBase === "base-ui" ? "" : `
|
|
30776
|
+
@import "shadcn/tailwind.css";`;
|
|
30777
|
+
globalsCss = `@import "tailwindcss";
|
|
30778
|
+
@import "tw-animate-css";${shadcnImport}
|
|
30779
|
+
${appSourcePaths.join(`
|
|
30780
|
+
`)}
|
|
30781
|
+
@source "../**/*.{ts,tsx}";
|
|
30782
|
+
|
|
30783
|
+
@custom-variant dark (&:is(.dark *));
|
|
30784
|
+
|
|
30785
|
+
${modernThemeCSS}
|
|
30786
|
+
`;
|
|
30780
30787
|
} else {
|
|
30781
|
-
|
|
30782
|
-
|
|
30783
|
-
|
|
30784
|
-
|
|
30785
|
-
|
|
30786
|
-
|
|
30787
|
-
|
|
30788
|
+
const theme = themes[baseColor] || themes.zinc;
|
|
30789
|
+
const themeCSS = generateThemeCSS(theme, customRadius);
|
|
30790
|
+
globalsCss = `@import "tailwindcss";
|
|
30791
|
+
${appSourcePaths.join(`
|
|
30792
|
+
`)}
|
|
30793
|
+
@source "../**/*.{ts,tsx}";
|
|
30794
|
+
|
|
30795
|
+
${themeCSS}
|
|
30796
|
+
`;
|
|
30788
30797
|
}
|
|
30789
|
-
await
|
|
30790
|
-
await
|
|
30791
|
-
|
|
30792
|
-
|
|
30793
|
-
|
|
30794
|
-
|
|
30795
|
-
|
|
30796
|
-
|
|
30797
|
-
|
|
30798
|
-
|
|
30799
|
-
|
|
30800
|
-
|
|
30801
|
-
|
|
30802
|
-
|
|
30803
|
-
|
|
30804
|
-
|
|
30805
|
-
|
|
30806
|
-
|
|
30798
|
+
await writeFile(join(uiPath, "src/styles/globals.css"), globalsCss);
|
|
30799
|
+
await writeFile(join(uiPath, "src/lib/utils.ts"), `import { clsx, type ClassValue } from 'clsx';
|
|
30800
|
+
import { twMerge } from 'tailwind-merge';
|
|
30801
|
+
|
|
30802
|
+
export function cn(...inputs: ClassValue[]) {
|
|
30803
|
+
return twMerge(clsx(inputs));
|
|
30804
|
+
}
|
|
30805
|
+
`);
|
|
30806
|
+
await writeFile(join(uiPath, "src/components/index.ts"), `/**
|
|
30807
|
+
* UI Components
|
|
30808
|
+
*
|
|
30809
|
+
* Add shadcn/ui components using:
|
|
30810
|
+
* bunx shadcn@latest add button card dialog ...
|
|
30811
|
+
*
|
|
30812
|
+
* Then export them here for use across apps.
|
|
30813
|
+
*/
|
|
30814
|
+
|
|
30815
|
+
// Export components as they are added
|
|
30816
|
+
// Example: export { Button } from './ui/button';
|
|
30817
|
+
|
|
30818
|
+
// Empty export to make this a valid ES module
|
|
30819
|
+
export {};
|
|
30820
|
+
`);
|
|
30821
|
+
await writeFile(join(uiPath, "src/hooks/index.ts"), `/**
|
|
30822
|
+
* Shared Hooks
|
|
30823
|
+
*
|
|
30824
|
+
* Custom React hooks shared across apps.
|
|
30825
|
+
*/
|
|
30826
|
+
|
|
30827
|
+
// Export hooks as they are added
|
|
30828
|
+
// Example: export { useMediaQuery } from './use-media-query';
|
|
30829
|
+
|
|
30830
|
+
// Empty export to make this a valid ES module
|
|
30831
|
+
export {};
|
|
30832
|
+
`);
|
|
30833
|
+
await writeFile(join(uiPath, "src/index.ts"), `/**
|
|
30834
|
+
* @${options.scopeName}/ui - Shared UI Components
|
|
30835
|
+
*
|
|
30836
|
+
* This package provides:
|
|
30837
|
+
* - shadcn/ui components (add with: bunx shadcn@latest add <component>)
|
|
30838
|
+
* - Tailwind CSS v4 configuration
|
|
30839
|
+
* - Shared hooks and utilities
|
|
30840
|
+
*
|
|
30841
|
+
* Usage in apps:
|
|
30842
|
+
* - Import globals.css: import '@${options.scopeName}/ui/globals.css';
|
|
30843
|
+
* - Import components: import { Button } from '@${options.scopeName}/ui/components';
|
|
30844
|
+
* - Import utils: import { cn } from '@${options.scopeName}/ui/lib/utils';
|
|
30845
|
+
*/
|
|
30846
|
+
|
|
30847
|
+
export * from './lib/utils';
|
|
30848
|
+
export * from './hooks';
|
|
30849
|
+
export * from './components';
|
|
30850
|
+
`);
|
|
30851
|
+
}
|
|
30852
|
+
async function buildTypesPackage(packagesPath, scopeName) {
|
|
30853
|
+
const typesPath = join(packagesPath, "types");
|
|
30854
|
+
await ensureDirectory(join(typesPath, "src"));
|
|
30855
|
+
const { writeTypesPackageJson: writeTypesPackageJson2 } = await Promise.resolve().then(() => (init_package_json(), exports_package_json));
|
|
30856
|
+
await writeTypesPackageJson2(typesPath, scopeName);
|
|
30857
|
+
await writeFile(join(typesPath, "tsconfig.json"), JSON.stringify({
|
|
30858
|
+
extends: "../../tooling/typescript/library.json",
|
|
30859
|
+
compilerOptions: {
|
|
30860
|
+
rootDir: "./src",
|
|
30861
|
+
outDir: "./dist"
|
|
30862
|
+
},
|
|
30863
|
+
include: ["src/**/*"],
|
|
30864
|
+
exclude: ["node_modules"]
|
|
30865
|
+
}, null, 2));
|
|
30866
|
+
await writeFile(join(typesPath, "src/index.ts"), `/**
|
|
30867
|
+
* @${scopeName}/types - Shared TypeScript Types
|
|
30868
|
+
*
|
|
30869
|
+
* Define types that are shared across multiple packages/apps here.
|
|
30870
|
+
*/
|
|
30871
|
+
|
|
30872
|
+
// Example types - replace with your actual types
|
|
30873
|
+
|
|
30807
30874
|
export interface User {
|
|
30808
|
-
id:
|
|
30809
|
-
name: string;
|
|
30875
|
+
id: string;
|
|
30810
30876
|
email: string;
|
|
30877
|
+
name?: string;
|
|
30811
30878
|
createdAt: Date;
|
|
30879
|
+
updatedAt: Date;
|
|
30812
30880
|
}
|
|
30813
30881
|
|
|
30814
|
-
export interface ApiResponse<T
|
|
30882
|
+
export interface ApiResponse<T> {
|
|
30815
30883
|
success: boolean;
|
|
30816
30884
|
data?: T;
|
|
30817
|
-
error?:
|
|
30818
|
-
|
|
30819
|
-
|
|
30820
|
-
`;
|
|
30821
|
-
await writeFile(join(projectPath, "packages/types/index.ts"), typesIndex);
|
|
30822
|
-
const utilsPackageJson = {
|
|
30823
|
-
name: `@${context.packageName}/utils`,
|
|
30824
|
-
version: "0.0.0",
|
|
30825
|
-
private: true,
|
|
30826
|
-
main: "./index.ts",
|
|
30827
|
-
types: "./index.ts",
|
|
30828
|
-
scripts: {},
|
|
30829
|
-
dependencies: {},
|
|
30830
|
-
devDependencies: {
|
|
30831
|
-
typescript: "catalog:"
|
|
30832
|
-
}
|
|
30885
|
+
error?: {
|
|
30886
|
+
code: string;
|
|
30887
|
+
message: string;
|
|
30833
30888
|
};
|
|
30834
|
-
await ensureDirectory(join(projectPath, "packages/utils"));
|
|
30835
|
-
await writeFile(join(projectPath, "packages/utils/package.json"), JSON.stringify(utilsPackageJson, null, 2));
|
|
30836
|
-
const utilsIndex = `// Shared utilities across the monorepo
|
|
30837
|
-
export function formatDate(date: Date): string {
|
|
30838
|
-
return date.toISOString();
|
|
30839
30889
|
}
|
|
30840
30890
|
|
|
30841
|
-
export
|
|
30842
|
-
|
|
30891
|
+
export interface PaginatedResponse<T> extends ApiResponse<T[]> {
|
|
30892
|
+
pagination: {
|
|
30893
|
+
page: number;
|
|
30894
|
+
perPage: number;
|
|
30895
|
+
total: number;
|
|
30896
|
+
totalPages: number;
|
|
30897
|
+
};
|
|
30843
30898
|
}
|
|
30844
|
-
|
|
30845
|
-
|
|
30846
|
-
|
|
30847
|
-
const
|
|
30848
|
-
|
|
30849
|
-
|
|
30850
|
-
|
|
30899
|
+
`);
|
|
30900
|
+
}
|
|
30901
|
+
async function buildUtilsPackage(packagesPath, scopeName) {
|
|
30902
|
+
const utilsPath = join(packagesPath, "utils");
|
|
30903
|
+
await ensureDirectory(join(utilsPath, "src"));
|
|
30904
|
+
const { writeUtilsPackageJson: writeUtilsPackageJson2 } = await Promise.resolve().then(() => (init_package_json(), exports_package_json));
|
|
30905
|
+
await writeUtilsPackageJson2(utilsPath, scopeName);
|
|
30906
|
+
await writeFile(join(utilsPath, "tsconfig.json"), JSON.stringify({
|
|
30907
|
+
extends: "../../tooling/typescript/library.json",
|
|
30908
|
+
compilerOptions: {
|
|
30909
|
+
rootDir: "./src",
|
|
30910
|
+
outDir: "./dist"
|
|
30911
|
+
},
|
|
30912
|
+
include: ["src/**/*"],
|
|
30851
30913
|
exclude: ["node_modules"]
|
|
30914
|
+
}, null, 2));
|
|
30915
|
+
await writeFile(join(utilsPath, "src/index.ts"), `/**
|
|
30916
|
+
* @${scopeName}/utils - Shared Utilities
|
|
30917
|
+
*
|
|
30918
|
+
* Utility functions shared across packages and apps.
|
|
30919
|
+
*/
|
|
30920
|
+
|
|
30921
|
+
/**
|
|
30922
|
+
* Format a date to a human-readable string
|
|
30923
|
+
*/
|
|
30924
|
+
export function formatDate(date: Date | string, locale = 'en-US'): string {
|
|
30925
|
+
const d = typeof date === 'string' ? new Date(date) : date;
|
|
30926
|
+
return d.toLocaleDateString(locale, {
|
|
30927
|
+
year: 'numeric',
|
|
30928
|
+
month: 'long',
|
|
30929
|
+
day: 'numeric',
|
|
30930
|
+
});
|
|
30931
|
+
}
|
|
30932
|
+
|
|
30933
|
+
/**
|
|
30934
|
+
* Format a number as currency
|
|
30935
|
+
*/
|
|
30936
|
+
export function formatCurrency(
|
|
30937
|
+
amount: number,
|
|
30938
|
+
currency = 'USD',
|
|
30939
|
+
locale = 'en-US'
|
|
30940
|
+
): string {
|
|
30941
|
+
return new Intl.NumberFormat(locale, {
|
|
30942
|
+
style: 'currency',
|
|
30943
|
+
currency,
|
|
30944
|
+
}).format(amount);
|
|
30945
|
+
}
|
|
30946
|
+
|
|
30947
|
+
/**
|
|
30948
|
+
* Sleep for a specified number of milliseconds
|
|
30949
|
+
*/
|
|
30950
|
+
export function sleep(ms: number): Promise<void> {
|
|
30951
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
30952
|
+
}
|
|
30953
|
+
|
|
30954
|
+
/**
|
|
30955
|
+
* Safely parse JSON with a fallback value
|
|
30956
|
+
*/
|
|
30957
|
+
export function safeJsonParse<T>(json: string, fallback: T): T {
|
|
30958
|
+
try {
|
|
30959
|
+
return JSON.parse(json) as T;
|
|
30960
|
+
} catch {
|
|
30961
|
+
return fallback;
|
|
30962
|
+
}
|
|
30963
|
+
}
|
|
30964
|
+
|
|
30965
|
+
/**
|
|
30966
|
+
* Generate a random ID
|
|
30967
|
+
*/
|
|
30968
|
+
export function generateId(length = 12): string {
|
|
30969
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
30970
|
+
let result = '';
|
|
30971
|
+
for (let i = 0; i < length; i++) {
|
|
30972
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
30973
|
+
}
|
|
30974
|
+
return result;
|
|
30975
|
+
}
|
|
30976
|
+
|
|
30977
|
+
/**
|
|
30978
|
+
* Debounce a function
|
|
30979
|
+
*/
|
|
30980
|
+
export function debounce<T extends (...args: unknown[]) => unknown>(
|
|
30981
|
+
func: T,
|
|
30982
|
+
wait: number
|
|
30983
|
+
): (...args: Parameters<T>) => void {
|
|
30984
|
+
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
30985
|
+
return (...args: Parameters<T>) => {
|
|
30986
|
+
if (timeout) clearTimeout(timeout);
|
|
30987
|
+
timeout = setTimeout(() => func(...args), wait);
|
|
30852
30988
|
};
|
|
30853
|
-
await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify(tsconfigContent, null, 2));
|
|
30854
30989
|
}
|
|
30855
|
-
|
|
30856
|
-
|
|
30857
|
-
|
|
30858
|
-
|
|
30859
|
-
|
|
30860
|
-
|
|
30861
|
-
|
|
30862
|
-
|
|
30990
|
+
|
|
30991
|
+
/**
|
|
30992
|
+
* Check if running on server
|
|
30993
|
+
* Uses a type-safe approach that works without DOM types
|
|
30994
|
+
*/
|
|
30995
|
+
export function isServer(): boolean {
|
|
30996
|
+
return !(typeof window !== 'undefined' && window.document);
|
|
30997
|
+
}
|
|
30998
|
+
|
|
30999
|
+
/**
|
|
31000
|
+
* Check if running on client
|
|
31001
|
+
* Uses a type-safe approach that works without DOM types
|
|
31002
|
+
*/
|
|
31003
|
+
export function isClient(): boolean {
|
|
31004
|
+
return typeof window !== 'undefined' && !!window.document;
|
|
31005
|
+
}
|
|
31006
|
+
|
|
31007
|
+
// Declare window for environments without DOM types
|
|
31008
|
+
declare const window: { document?: unknown } | undefined;
|
|
31009
|
+
`);
|
|
31010
|
+
}
|
|
31011
|
+
|
|
31012
|
+
// ../templates/src/builders/full-v2.ts
|
|
31013
|
+
async function buildFullPresetV2(projectPath, context) {
|
|
31014
|
+
const preset = PresetRegistry.get("nextjs-monorepo");
|
|
31015
|
+
if (!preset) {
|
|
31016
|
+
throw new Error("nextjs-monorepo preset not found in registry");
|
|
31017
|
+
}
|
|
31018
|
+
const scopeName = context.packageName;
|
|
31019
|
+
const directories = [
|
|
31020
|
+
"apps/web/src/app",
|
|
31021
|
+
"apps/web/src/components",
|
|
31022
|
+
"apps/web/src/lib",
|
|
31023
|
+
"apps/platform/src/app",
|
|
31024
|
+
"apps/platform/src/components",
|
|
31025
|
+
"apps/platform/src/lib",
|
|
31026
|
+
"apps/api/src/routes",
|
|
31027
|
+
"apps/api/src/middleware",
|
|
31028
|
+
"packages/ui",
|
|
31029
|
+
"packages/types",
|
|
31030
|
+
"packages/utils",
|
|
31031
|
+
"tooling/typescript"
|
|
31032
|
+
];
|
|
31033
|
+
for (const dir of directories) {
|
|
31034
|
+
await ensureDirectory(join(projectPath, dir));
|
|
31035
|
+
}
|
|
31036
|
+
const catalog = preset.catalogEntries || {};
|
|
31037
|
+
await writeMonorepoRootPackageJson(projectPath, scopeName, catalog, {
|
|
31038
|
+
hasWeb: true,
|
|
31039
|
+
hasPlatform: true,
|
|
31040
|
+
hasApi: true,
|
|
31041
|
+
codeQuality: context.codeQuality === "biome" ? "biome" : "ultracite"
|
|
31042
|
+
});
|
|
31043
|
+
await writeFile(join(projectPath, "bunfig.toml"), generateBunfigContent(context));
|
|
31044
|
+
await writeNextjsAppPackageJson(join(projectPath, "apps/web"), scopeName, "web", {
|
|
31045
|
+
usesUi: true,
|
|
31046
|
+
usesTypes: true,
|
|
31047
|
+
shadcnIconLibrary: context.shadcnIconLibrary || "iconoir"
|
|
31048
|
+
});
|
|
31049
|
+
await writeFile(join(projectPath, "apps/web/src/app/layout.tsx"), `import type { Metadata } from 'next';
|
|
31050
|
+
import '@${scopeName}/ui/globals.css';
|
|
30863
31051
|
|
|
30864
31052
|
export const metadata: Metadata = {
|
|
30865
31053
|
title: '${context.projectName}',
|
|
30866
|
-
description: '
|
|
30867
|
-
}
|
|
31054
|
+
description: 'Enterprise SaaS built with bunkit',
|
|
31055
|
+
};
|
|
30868
31056
|
|
|
30869
31057
|
export default function RootLayout({
|
|
30870
31058
|
children,
|
|
30871
31059
|
}: {
|
|
30872
|
-
children: React.ReactNode
|
|
31060
|
+
children: React.ReactNode;
|
|
30873
31061
|
}) {
|
|
30874
31062
|
return (
|
|
30875
31063
|
<html lang="en">
|
|
30876
|
-
<body>{children}</body>
|
|
31064
|
+
<body className="antialiased">{children}</body>
|
|
30877
31065
|
</html>
|
|
30878
|
-
)
|
|
31066
|
+
);
|
|
30879
31067
|
}
|
|
30880
|
-
|
|
30881
|
-
await writeFile(join(projectPath, "src/app/
|
|
30882
|
-
|
|
31068
|
+
`);
|
|
31069
|
+
await writeFile(join(projectPath, "apps/web/src/app/page.tsx"), `import { Home, Rocket, Book } from 'iconoir-react';
|
|
31070
|
+
|
|
31071
|
+
export default function HomePage() {
|
|
30883
31072
|
return (
|
|
30884
|
-
<main className="min-h-screen flex items-center justify-center">
|
|
30885
|
-
<div className="text-center">
|
|
30886
|
-
<
|
|
30887
|
-
|
|
31073
|
+
<main className="min-h-screen flex items-center justify-center bg-gradient-to-br from-background to-muted">
|
|
31074
|
+
<div className="text-center space-y-8 p-8 max-w-3xl">
|
|
31075
|
+
<div className="flex justify-center">
|
|
31076
|
+
<Home className="w-16 h-16 text-primary" />
|
|
31077
|
+
</div>
|
|
31078
|
+
<h1 className="text-5xl font-bold tracking-tight">
|
|
31079
|
+
Welcome to ${context.projectName}
|
|
30888
31080
|
</h1>
|
|
30889
|
-
<p className="text-
|
|
30890
|
-
|
|
31081
|
+
<p className="text-xl text-muted-foreground">
|
|
31082
|
+
Enterprise-grade SaaS built with Next.js 16, React 19, Hono, and Bun
|
|
30891
31083
|
</p>
|
|
31084
|
+
<div className="flex gap-4 justify-center pt-4">
|
|
31085
|
+
<a
|
|
31086
|
+
href="/dashboard"
|
|
31087
|
+
className="inline-flex items-center gap-2 px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition font-medium"
|
|
31088
|
+
>
|
|
31089
|
+
<Rocket className="w-5 h-5" />
|
|
31090
|
+
Get Started
|
|
31091
|
+
</a>
|
|
31092
|
+
<a
|
|
31093
|
+
href="/docs"
|
|
31094
|
+
className="inline-flex items-center gap-2 px-6 py-3 bg-secondary text-secondary-foreground rounded-lg hover:bg-secondary/90 transition font-medium"
|
|
31095
|
+
>
|
|
31096
|
+
<Book className="w-5 h-5" />
|
|
31097
|
+
Documentation
|
|
31098
|
+
</a>
|
|
31099
|
+
</div>
|
|
30892
31100
|
</div>
|
|
30893
31101
|
</main>
|
|
30894
|
-
)
|
|
31102
|
+
);
|
|
30895
31103
|
}
|
|
30896
|
-
|
|
30897
|
-
|
|
30898
|
-
// When you add dynamic routes with params, make your component async and await params:
|
|
30899
|
-
// export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
|
|
30900
|
-
// const { slug } = await params;
|
|
30901
|
-
// return <div>{slug}</div>;
|
|
30902
|
-
// }
|
|
30903
|
-
`;
|
|
30904
|
-
await writeFile(join(projectPath, "src/app/page.tsx"), pageContent);
|
|
30905
|
-
const globalsCssContent = `@import "tailwindcss";
|
|
30906
|
-
`;
|
|
30907
|
-
await writeFile(join(projectPath, "src/app/globals.css"), globalsCssContent);
|
|
30908
|
-
const nextConfigContent = `import type { NextConfig } from 'next';
|
|
31104
|
+
`);
|
|
31105
|
+
await writeFile(join(projectPath, "apps/web/next.config.ts"), `import type { NextConfig } from 'next';
|
|
30909
31106
|
|
|
30910
31107
|
const nextConfig: NextConfig = {
|
|
30911
|
-
|
|
31108
|
+
transpilePackages: ['@${scopeName}/ui'],
|
|
30912
31109
|
};
|
|
30913
31110
|
|
|
30914
31111
|
export default nextConfig;
|
|
30915
|
-
|
|
30916
|
-
await writeFile(join(projectPath, "
|
|
30917
|
-
|
|
30918
|
-
|
|
30919
|
-
const config: Config = {
|
|
30920
|
-
content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
|
|
30921
|
-
theme: {
|
|
30922
|
-
extend: {},
|
|
30923
|
-
},
|
|
30924
|
-
plugins: [],
|
|
30925
|
-
};
|
|
30926
|
-
|
|
30927
|
-
export default config;
|
|
30928
|
-
`;
|
|
30929
|
-
await writeFile(join(projectPath, "tailwind.config.ts"), tailwindConfigContent);
|
|
30930
|
-
const getTsCompilerOptions = () => {
|
|
30931
|
-
const baseOptions = {
|
|
30932
|
-
target: "ES2017",
|
|
30933
|
-
lib: ["dom", "dom.iterable", "esnext"],
|
|
30934
|
-
allowJs: true,
|
|
30935
|
-
skipLibCheck: true,
|
|
30936
|
-
noEmit: true,
|
|
30937
|
-
esModuleInterop: true,
|
|
30938
|
-
module: "esnext",
|
|
30939
|
-
moduleResolution: "bundler",
|
|
30940
|
-
resolveJsonModule: true,
|
|
30941
|
-
isolatedModules: true,
|
|
30942
|
-
jsx: "react-jsx",
|
|
30943
|
-
incremental: true,
|
|
30944
|
-
plugins: [{ name: "next" }],
|
|
30945
|
-
paths: context.pathAliases ? { "@/*": ["./src/*"] } : undefined
|
|
30946
|
-
};
|
|
30947
|
-
if (context.tsStrictness === "strict") {
|
|
30948
|
-
return {
|
|
30949
|
-
...baseOptions,
|
|
30950
|
-
strict: true,
|
|
30951
|
-
noUnusedLocals: true,
|
|
30952
|
-
noUnusedParameters: true,
|
|
30953
|
-
noFallthroughCasesInSwitch: true,
|
|
30954
|
-
noImplicitReturns: true
|
|
30955
|
-
};
|
|
30956
|
-
}
|
|
30957
|
-
if (context.tsStrictness === "moderate") {
|
|
30958
|
-
return {
|
|
30959
|
-
...baseOptions,
|
|
30960
|
-
strict: true,
|
|
30961
|
-
noUnusedLocals: false,
|
|
30962
|
-
noUnusedParameters: false
|
|
30963
|
-
};
|
|
30964
|
-
}
|
|
30965
|
-
return {
|
|
30966
|
-
...baseOptions,
|
|
30967
|
-
strict: false,
|
|
30968
|
-
noImplicitAny: false
|
|
30969
|
-
};
|
|
30970
|
-
};
|
|
30971
|
-
const tsconfigContent = {
|
|
30972
|
-
compilerOptions: getTsCompilerOptions(),
|
|
30973
|
-
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/dev/types/**/*.ts"],
|
|
30974
|
-
exclude: ["node_modules"]
|
|
30975
|
-
};
|
|
30976
|
-
await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify(tsconfigContent, null, 2));
|
|
30977
|
-
const bunfigContent = generateBunfigContent(context);
|
|
30978
|
-
await writeFile(join(projectPath, "bunfig.toml"), bunfigContent);
|
|
30979
|
-
if (context.codeQuality === "ultracite") {
|
|
30980
|
-
await setupUltracite(projectPath, context);
|
|
30981
|
-
} else {
|
|
30982
|
-
await setupBiome(projectPath, context);
|
|
30983
|
-
}
|
|
30984
|
-
if (context.docker) {
|
|
30985
|
-
await setupDocker(projectPath, context);
|
|
30986
|
-
}
|
|
30987
|
-
if (context.cicd) {
|
|
30988
|
-
await setupGitHubActions(projectPath, context);
|
|
30989
|
-
}
|
|
30990
|
-
if (context.uiLibrary === "shadcn" && context.cssFramework === "tailwind") {
|
|
30991
|
-
await setupShadcnWeb(projectPath, context);
|
|
30992
|
-
}
|
|
30993
|
-
await setupVSCodeDebug(projectPath, context, "web");
|
|
30994
|
-
const packageJsonPath = join(projectPath, "package.json");
|
|
30995
|
-
const existingPackageJson = JSON.parse(await Bun.file(packageJsonPath).text());
|
|
30996
|
-
existingPackageJson.dependencies = {
|
|
30997
|
-
react: "^19.2.3",
|
|
30998
|
-
"react-dom": "^19.2.3",
|
|
30999
|
-
next: "^16.0.10",
|
|
31000
|
-
...existingPackageJson.dependencies
|
|
31001
|
-
};
|
|
31002
|
-
existingPackageJson.devDependencies = {
|
|
31003
|
-
...existingPackageJson.devDependencies,
|
|
31004
|
-
"@types/react": "^19.2.7",
|
|
31005
|
-
"@types/react-dom": "^19.2.3",
|
|
31006
|
-
"@types/node": "^25.0.3"
|
|
31007
|
-
};
|
|
31008
|
-
if (!existingPackageJson.scripts) {
|
|
31009
|
-
existingPackageJson.scripts = {};
|
|
31010
|
-
}
|
|
31011
|
-
if (!existingPackageJson.scripts.dev) {
|
|
31012
|
-
existingPackageJson.scripts.dev = "bun run --bun next dev --turbopack";
|
|
31013
|
-
}
|
|
31014
|
-
if (!existingPackageJson.scripts.build) {
|
|
31015
|
-
existingPackageJson.scripts.build = "bun run --bun next build";
|
|
31016
|
-
}
|
|
31017
|
-
if (!existingPackageJson.scripts.start) {
|
|
31018
|
-
existingPackageJson.scripts.start = "bun run --bun next start";
|
|
31019
|
-
}
|
|
31020
|
-
if (!existingPackageJson.scripts.debug) {
|
|
31021
|
-
existingPackageJson.scripts.debug = "bun --inspect node_modules/.bin/next dev --turbopack";
|
|
31022
|
-
}
|
|
31023
|
-
if (!existingPackageJson.scripts["debug:brk"]) {
|
|
31024
|
-
existingPackageJson.scripts["debug:brk"] = "bun --inspect-brk node_modules/.bin/next dev --turbopack";
|
|
31025
|
-
}
|
|
31026
|
-
if (!existingPackageJson.scripts["debug:wait"]) {
|
|
31027
|
-
existingPackageJson.scripts["debug:wait"] = "bun --inspect-wait node_modules/.bin/next dev --turbopack";
|
|
31028
|
-
}
|
|
31029
|
-
await writeFile(packageJsonPath, JSON.stringify(existingPackageJson, null, 2));
|
|
31030
|
-
await generateNextjsReadme(projectPath, context);
|
|
31031
|
-
}
|
|
31032
|
-
// ../templates/src/builders/full-v2.ts
|
|
31033
|
-
init_src();
|
|
31034
|
-
init_dist();
|
|
31035
|
-
init_package_json();
|
|
31036
|
-
|
|
31037
|
-
// ../templates/src/shared/ui-package.ts
|
|
31038
|
-
init_src();
|
|
31039
|
-
init_dist();
|
|
31040
|
-
init_package_json();
|
|
31041
|
-
function isModernStyle(style) {
|
|
31042
|
-
return style === "radix-maia" || style === "radix-vega" || style === "radix-nova" || style === "radix-lyra" || style === "radix-mira";
|
|
31043
|
-
}
|
|
31044
|
-
async function buildUiPackage(packagesPath, options) {
|
|
31045
|
-
const uiPath = join(packagesPath, "ui");
|
|
31046
|
-
await ensureDirectory(join(uiPath, "src/components"));
|
|
31047
|
-
await ensureDirectory(join(uiPath, "src/hooks"));
|
|
31048
|
-
await ensureDirectory(join(uiPath, "src/lib"));
|
|
31049
|
-
await ensureDirectory(join(uiPath, "src/styles"));
|
|
31050
|
-
await writeUiPackageJson(uiPath, options.scopeName);
|
|
31051
|
-
await writeFile(join(uiPath, "tsconfig.json"), JSON.stringify({
|
|
31052
|
-
extends: "../../tooling/typescript/library.json",
|
|
31112
|
+
`);
|
|
31113
|
+
await writeFile(join(projectPath, "apps/web/tsconfig.json"), JSON.stringify({
|
|
31114
|
+
extends: "../../tooling/typescript/nextjs.json",
|
|
31053
31115
|
compilerOptions: {
|
|
31054
|
-
jsx: "react-jsx",
|
|
31055
|
-
rootDir: "./src",
|
|
31056
|
-
outDir: "./dist",
|
|
31057
|
-
baseUrl: ".",
|
|
31058
31116
|
paths: {
|
|
31059
31117
|
"@/*": ["./src/*"]
|
|
31060
31118
|
}
|
|
31061
31119
|
},
|
|
31062
|
-
include: ["
|
|
31120
|
+
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
31063
31121
|
exclude: ["node_modules"]
|
|
31064
31122
|
}, null, 2));
|
|
31065
|
-
|
|
31066
|
-
const useModernStyle = isModernStyle(style);
|
|
31067
|
-
const iconLibrary = options.shadcnIconLibrary || (useModernStyle ? "phosphor" : "iconoir");
|
|
31068
|
-
const componentsJson = {
|
|
31069
|
-
$schema: "https://ui.shadcn.com/schema.json",
|
|
31070
|
-
style,
|
|
31071
|
-
rsc: true,
|
|
31072
|
-
tsx: true,
|
|
31073
|
-
tailwind: {
|
|
31074
|
-
config: "",
|
|
31075
|
-
css: "./src/styles/globals.css",
|
|
31076
|
-
baseColor: options.shadcnBaseColor || "zinc",
|
|
31077
|
-
cssVariables: true,
|
|
31078
|
-
prefix: ""
|
|
31079
|
-
},
|
|
31080
|
-
iconLibrary,
|
|
31081
|
-
aliases: {
|
|
31082
|
-
components: "@/components",
|
|
31083
|
-
utils: "@/lib/utils",
|
|
31084
|
-
ui: "@/components/ui",
|
|
31085
|
-
lib: "@/lib",
|
|
31086
|
-
hooks: "@/hooks"
|
|
31087
|
-
}
|
|
31088
|
-
};
|
|
31089
|
-
if (useModernStyle) {
|
|
31090
|
-
componentsJson.menuColor = options.shadcnMenuColor || "default";
|
|
31091
|
-
componentsJson.menuAccent = options.shadcnMenuAccent || "subtle";
|
|
31092
|
-
componentsJson.registries = {};
|
|
31093
|
-
}
|
|
31094
|
-
await writeFile(join(uiPath, "components.json"), JSON.stringify(componentsJson, null, 2));
|
|
31095
|
-
await writeFile(join(uiPath, "postcss.config.mjs"), `export default {
|
|
31123
|
+
await writeFile(join(projectPath, "apps/web/postcss.config.mjs"), `export default {
|
|
31096
31124
|
plugins: {
|
|
31097
31125
|
'@tailwindcss/postcss': {},
|
|
31098
31126
|
},
|
|
31099
31127
|
};
|
|
31100
31128
|
`);
|
|
31101
|
-
|
|
31102
|
-
|
|
31103
|
-
|
|
31104
|
-
|
|
31105
|
-
|
|
31106
|
-
|
|
31107
|
-
|
|
31108
|
-
globalsCss = `@import "tailwindcss";
|
|
31109
|
-
@import "tw-animate-css";
|
|
31110
|
-
@import "shadcn/tailwind.css";
|
|
31111
|
-
${appSourcePaths.join(`
|
|
31112
|
-
`)}
|
|
31113
|
-
@source "../**/*.{ts,tsx}";
|
|
31129
|
+
await writeNextjsAppPackageJson(join(projectPath, "apps/platform"), scopeName, "platform", {
|
|
31130
|
+
usesUi: true,
|
|
31131
|
+
usesTypes: true,
|
|
31132
|
+
shadcnIconLibrary: context.shadcnIconLibrary || "iconoir"
|
|
31133
|
+
});
|
|
31134
|
+
await writeFile(join(projectPath, "apps/platform/src/app/layout.tsx"), `import type { Metadata } from 'next';
|
|
31135
|
+
import '@${scopeName}/ui/globals.css';
|
|
31114
31136
|
|
|
31115
|
-
|
|
31137
|
+
export const metadata: Metadata = {
|
|
31138
|
+
title: '${context.projectName} - Admin',
|
|
31139
|
+
description: 'Admin dashboard for ${context.projectName}',
|
|
31140
|
+
};
|
|
31116
31141
|
|
|
31117
|
-
|
|
31118
|
-
|
|
31119
|
-
|
|
31120
|
-
|
|
31121
|
-
|
|
31122
|
-
|
|
31123
|
-
|
|
31124
|
-
|
|
31125
|
-
|
|
31142
|
+
export default function RootLayout({
|
|
31143
|
+
children,
|
|
31144
|
+
}: {
|
|
31145
|
+
children: React.ReactNode;
|
|
31146
|
+
}) {
|
|
31147
|
+
return (
|
|
31148
|
+
<html lang="en">
|
|
31149
|
+
<body className="antialiased">{children}</body>
|
|
31150
|
+
</html>
|
|
31151
|
+
);
|
|
31152
|
+
}
|
|
31153
|
+
`);
|
|
31154
|
+
await writeFile(join(projectPath, "apps/platform/src/app/page.tsx"), `import { ViewGrid, User, Dollar, GraphUp } from 'iconoir-react';
|
|
31126
31155
|
|
|
31127
|
-
|
|
31128
|
-
|
|
31129
|
-
|
|
31130
|
-
|
|
31131
|
-
|
|
31132
|
-
|
|
31156
|
+
export default function DashboardPage() {
|
|
31157
|
+
return (
|
|
31158
|
+
<main className="min-h-screen bg-background">
|
|
31159
|
+
<div className="max-w-7xl mx-auto py-12 px-4">
|
|
31160
|
+
<header className="mb-8 flex items-center gap-3">
|
|
31161
|
+
<ViewGrid className="w-8 h-8 text-primary" />
|
|
31162
|
+
<div>
|
|
31163
|
+
<h1 className="text-3xl font-bold">Admin Dashboard</h1>
|
|
31164
|
+
<p className="text-muted-foreground">
|
|
31165
|
+
Manage your ${context.projectName} platform
|
|
31166
|
+
</p>
|
|
31167
|
+
</div>
|
|
31168
|
+
</header>
|
|
31133
31169
|
|
|
31134
|
-
|
|
31135
|
-
|
|
31170
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
31171
|
+
<div className="bg-card p-6 rounded-lg border shadow-sm">
|
|
31172
|
+
<div className="flex items-center gap-3 mb-2">
|
|
31173
|
+
<User className="w-5 h-5 text-blue-500" />
|
|
31174
|
+
<h2 className="text-lg font-semibold">Users</h2>
|
|
31175
|
+
</div>
|
|
31176
|
+
<p className="text-3xl font-bold">1,234</p>
|
|
31177
|
+
</div>
|
|
31178
|
+
<div className="bg-card p-6 rounded-lg border shadow-sm">
|
|
31179
|
+
<div className="flex items-center gap-3 mb-2">
|
|
31180
|
+
<Dollar className="w-5 h-5 text-green-500" />
|
|
31181
|
+
<h2 className="text-lg font-semibold">Revenue</h2>
|
|
31182
|
+
</div>
|
|
31183
|
+
<p className="text-3xl font-bold">$12,345</p>
|
|
31184
|
+
</div>
|
|
31185
|
+
<div className="bg-card p-6 rounded-lg border shadow-sm">
|
|
31186
|
+
<div className="flex items-center gap-3 mb-2">
|
|
31187
|
+
<GraphUp className="w-5 h-5 text-purple-500" />
|
|
31188
|
+
<h2 className="text-lg font-semibold">Active</h2>
|
|
31189
|
+
</div>
|
|
31190
|
+
<p className="text-3xl font-bold">567</p>
|
|
31191
|
+
</div>
|
|
31192
|
+
</div>
|
|
31193
|
+
</div>
|
|
31194
|
+
</main>
|
|
31195
|
+
);
|
|
31136
31196
|
}
|
|
31137
31197
|
`);
|
|
31138
|
-
await writeFile(join(
|
|
31139
|
-
* UI Components
|
|
31140
|
-
*
|
|
31141
|
-
* Add shadcn/ui components using:
|
|
31142
|
-
* bunx shadcn@latest add button card dialog ...
|
|
31143
|
-
*
|
|
31144
|
-
* Then export them here for use across apps.
|
|
31145
|
-
*/
|
|
31198
|
+
await writeFile(join(projectPath, "apps/platform/next.config.ts"), `import type { NextConfig } from 'next';
|
|
31146
31199
|
|
|
31147
|
-
|
|
31148
|
-
|
|
31149
|
-
|
|
31150
|
-
// Empty export to make this a valid ES module
|
|
31151
|
-
export {};
|
|
31152
|
-
`);
|
|
31153
|
-
await writeFile(join(uiPath, "src/hooks/index.ts"), `/**
|
|
31154
|
-
* Shared Hooks
|
|
31155
|
-
*
|
|
31156
|
-
* Custom React hooks shared across apps.
|
|
31157
|
-
*/
|
|
31158
|
-
|
|
31159
|
-
// Export hooks as they are added
|
|
31160
|
-
// Example: export { useMediaQuery } from './use-media-query';
|
|
31161
|
-
|
|
31162
|
-
// Empty export to make this a valid ES module
|
|
31163
|
-
export {};
|
|
31164
|
-
`);
|
|
31165
|
-
await writeFile(join(uiPath, "src/index.ts"), `/**
|
|
31166
|
-
* @${options.scopeName}/ui - Shared UI Components
|
|
31167
|
-
*
|
|
31168
|
-
* This package provides:
|
|
31169
|
-
* - shadcn/ui components (add with: bunx shadcn@latest add <component>)
|
|
31170
|
-
* - Tailwind CSS v4 configuration
|
|
31171
|
-
* - Shared hooks and utilities
|
|
31172
|
-
*
|
|
31173
|
-
* Usage in apps:
|
|
31174
|
-
* - Import globals.css: import '@${options.scopeName}/ui/globals.css';
|
|
31175
|
-
* - Import components: import { Button } from '@${options.scopeName}/ui/components';
|
|
31176
|
-
* - Import utils: import { cn } from '@${options.scopeName}/ui/lib/utils';
|
|
31177
|
-
*/
|
|
31200
|
+
const nextConfig: NextConfig = {
|
|
31201
|
+
transpilePackages: ['@${scopeName}/ui'],
|
|
31202
|
+
};
|
|
31178
31203
|
|
|
31179
|
-
export
|
|
31180
|
-
export * from './hooks';
|
|
31181
|
-
export * from './components';
|
|
31204
|
+
export default nextConfig;
|
|
31182
31205
|
`);
|
|
31183
|
-
|
|
31184
|
-
|
|
31185
|
-
const typesPath = join(packagesPath, "types");
|
|
31186
|
-
await ensureDirectory(join(typesPath, "src"));
|
|
31187
|
-
const { writeTypesPackageJson: writeTypesPackageJson2 } = await Promise.resolve().then(() => (init_package_json(), exports_package_json));
|
|
31188
|
-
await writeTypesPackageJson2(typesPath, scopeName);
|
|
31189
|
-
await writeFile(join(typesPath, "tsconfig.json"), JSON.stringify({
|
|
31190
|
-
extends: "../../tooling/typescript/library.json",
|
|
31206
|
+
await writeFile(join(projectPath, "apps/platform/tsconfig.json"), JSON.stringify({
|
|
31207
|
+
extends: "../../tooling/typescript/nextjs.json",
|
|
31191
31208
|
compilerOptions: {
|
|
31192
|
-
|
|
31193
|
-
|
|
31209
|
+
paths: {
|
|
31210
|
+
"@/*": ["./src/*"]
|
|
31211
|
+
}
|
|
31194
31212
|
},
|
|
31195
|
-
include: ["
|
|
31213
|
+
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
31196
31214
|
exclude: ["node_modules"]
|
|
31197
31215
|
}, null, 2));
|
|
31198
|
-
await writeFile(join(
|
|
31199
|
-
|
|
31200
|
-
|
|
31201
|
-
|
|
31202
|
-
|
|
31216
|
+
await writeFile(join(projectPath, "apps/platform/postcss.config.mjs"), `export default {
|
|
31217
|
+
plugins: {
|
|
31218
|
+
'@tailwindcss/postcss': {},
|
|
31219
|
+
},
|
|
31220
|
+
};
|
|
31221
|
+
`);
|
|
31222
|
+
await writeHonoApiPackageJson(join(projectPath, "apps/api"), scopeName, {
|
|
31223
|
+
usesTypes: true
|
|
31224
|
+
});
|
|
31225
|
+
await writeFile(join(projectPath, "apps/api/src/index.ts"), `import { Hono } from 'hono';
|
|
31226
|
+
import { logger } from 'hono/logger';
|
|
31227
|
+
import { cors } from 'hono/cors';
|
|
31203
31228
|
|
|
31204
|
-
|
|
31229
|
+
const app = new Hono();
|
|
31205
31230
|
|
|
31206
|
-
|
|
31207
|
-
|
|
31208
|
-
|
|
31209
|
-
name?: string;
|
|
31210
|
-
createdAt: Date;
|
|
31211
|
-
updatedAt: Date;
|
|
31212
|
-
}
|
|
31231
|
+
// Middleware
|
|
31232
|
+
app.use('*', logger());
|
|
31233
|
+
app.use('*', cors());
|
|
31213
31234
|
|
|
31214
|
-
|
|
31215
|
-
|
|
31216
|
-
|
|
31217
|
-
|
|
31218
|
-
|
|
31219
|
-
|
|
31220
|
-
};
|
|
31221
|
-
}
|
|
31235
|
+
// Routes
|
|
31236
|
+
app.get('/', (context) => {
|
|
31237
|
+
return context.json({
|
|
31238
|
+
name: '${context.projectName} API',
|
|
31239
|
+
version: '1.0.0',
|
|
31240
|
+
timestamp: new Date().toISOString(),
|
|
31241
|
+
});
|
|
31242
|
+
});
|
|
31222
31243
|
|
|
31223
|
-
|
|
31224
|
-
|
|
31225
|
-
|
|
31226
|
-
|
|
31227
|
-
|
|
31228
|
-
|
|
31229
|
-
|
|
31230
|
-
}
|
|
31244
|
+
app.get('/health', (context) => {
|
|
31245
|
+
return context.json({ status: 'ok' });
|
|
31246
|
+
});
|
|
31247
|
+
|
|
31248
|
+
app.get('/api/users', (context) => {
|
|
31249
|
+
return context.json({
|
|
31250
|
+
users: [
|
|
31251
|
+
{ id: '1', email: 'john@example.com', name: 'John Doe' },
|
|
31252
|
+
{ id: '2', email: 'jane@example.com', name: 'Jane Smith' },
|
|
31253
|
+
],
|
|
31254
|
+
});
|
|
31255
|
+
});
|
|
31256
|
+
|
|
31257
|
+
// 404 handler
|
|
31258
|
+
app.notFound((context) => {
|
|
31259
|
+
return context.json({ error: 'Not found' }, 404);
|
|
31260
|
+
});
|
|
31261
|
+
|
|
31262
|
+
// Error handler
|
|
31263
|
+
app.onError((error, context) => {
|
|
31264
|
+
console.error('Error:', error);
|
|
31265
|
+
return context.json({ error: 'Internal server error' }, 500);
|
|
31266
|
+
});
|
|
31267
|
+
|
|
31268
|
+
// Start server with HMR
|
|
31269
|
+
const server = Bun.serve({
|
|
31270
|
+
fetch: app.fetch,
|
|
31271
|
+
port: 3002,
|
|
31272
|
+
development: {
|
|
31273
|
+
hmr: true,
|
|
31274
|
+
},
|
|
31275
|
+
});
|
|
31276
|
+
|
|
31277
|
+
console.log(\`\uD83D\uDE80 ${context.projectName} API running on \${server.url}\`);
|
|
31278
|
+
|
|
31279
|
+
export default app;
|
|
31231
31280
|
`);
|
|
31232
|
-
|
|
31233
|
-
|
|
31234
|
-
const utilsPath = join(packagesPath, "utils");
|
|
31235
|
-
await ensureDirectory(join(utilsPath, "src"));
|
|
31236
|
-
const { writeUtilsPackageJson: writeUtilsPackageJson2 } = await Promise.resolve().then(() => (init_package_json(), exports_package_json));
|
|
31237
|
-
await writeUtilsPackageJson2(utilsPath, scopeName);
|
|
31238
|
-
await writeFile(join(utilsPath, "tsconfig.json"), JSON.stringify({
|
|
31239
|
-
extends: "../../tooling/typescript/library.json",
|
|
31281
|
+
await writeFile(join(projectPath, "apps/api/tsconfig.json"), JSON.stringify({
|
|
31282
|
+
extends: "../../tooling/typescript/api.json",
|
|
31240
31283
|
compilerOptions: {
|
|
31241
|
-
|
|
31242
|
-
outDir: "./dist"
|
|
31284
|
+
types: ["bun-types"]
|
|
31243
31285
|
},
|
|
31244
31286
|
include: ["src/**/*"],
|
|
31245
31287
|
exclude: ["node_modules"]
|
|
31246
31288
|
}, null, 2));
|
|
31247
|
-
await
|
|
31248
|
-
|
|
31249
|
-
|
|
31250
|
-
|
|
31251
|
-
|
|
31252
|
-
|
|
31253
|
-
|
|
31254
|
-
|
|
31255
|
-
|
|
31256
|
-
|
|
31257
|
-
|
|
31258
|
-
return d.toLocaleDateString(locale, {
|
|
31259
|
-
year: 'numeric',
|
|
31260
|
-
month: 'long',
|
|
31261
|
-
day: 'numeric',
|
|
31289
|
+
await buildUiPackage(join(projectPath, "packages"), {
|
|
31290
|
+
scopeName,
|
|
31291
|
+
shadcnStyle: context.shadcnStyle || "radix-maia",
|
|
31292
|
+
shadcnBase: context.shadcnBase || "radix",
|
|
31293
|
+
shadcnBaseColor: context.shadcnBaseColor || "zinc",
|
|
31294
|
+
shadcnIconLibrary: context.shadcnIconLibrary || "iconoir",
|
|
31295
|
+
shadcnMenuAccent: context.shadcnMenuAccent || "subtle",
|
|
31296
|
+
shadcnMenuColor: context.shadcnMenuColor || "default",
|
|
31297
|
+
shadcnRadius: context.shadcnRadius || "0.625rem",
|
|
31298
|
+
shadcnRtl: context.shadcnRtl,
|
|
31299
|
+
appsToScan: ["web", "platform"]
|
|
31262
31300
|
});
|
|
31301
|
+
await buildTypesPackage(join(projectPath, "packages"), scopeName);
|
|
31302
|
+
await buildUtilsPackage(join(projectPath, "packages"), scopeName);
|
|
31303
|
+
await setupTooling(projectPath, context);
|
|
31304
|
+
await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify({
|
|
31305
|
+
extends: "./tooling/typescript/base.json",
|
|
31306
|
+
include: ["apps/*/src/**/*", "packages/*/src/**/*"],
|
|
31307
|
+
exclude: ["node_modules", "**/node_modules", "**/.next"]
|
|
31308
|
+
}, null, 2));
|
|
31309
|
+
if (context.codeQuality === "ultracite") {
|
|
31310
|
+
await setupUltracite(projectPath, context);
|
|
31311
|
+
} else {
|
|
31312
|
+
await setupBiome(projectPath, context);
|
|
31313
|
+
}
|
|
31314
|
+
if (context.docker) {
|
|
31315
|
+
await setupDocker(projectPath, context);
|
|
31316
|
+
}
|
|
31317
|
+
if (context.cicd) {
|
|
31318
|
+
await setupGitHubActions(projectPath, context);
|
|
31319
|
+
}
|
|
31320
|
+
await setupVSCodeDebug(projectPath, context, "full");
|
|
31321
|
+
await generateMonorepoReadme(projectPath, context, "nextjs");
|
|
31263
31322
|
}
|
|
31323
|
+
// ../templates/src/builders/minimal.ts
|
|
31324
|
+
init_src();
|
|
31325
|
+
init_dist();
|
|
31326
|
+
async function buildMinimalPreset(projectPath, context) {
|
|
31327
|
+
const indexContent = `console.log('Hello from ${context.projectName}! \uD83C\uDF5E');
|
|
31264
31328
|
|
|
31265
|
-
|
|
31266
|
-
|
|
31267
|
-
|
|
31268
|
-
|
|
31269
|
-
amount: number,
|
|
31270
|
-
currency = 'USD',
|
|
31271
|
-
locale = 'en-US'
|
|
31272
|
-
): string {
|
|
31273
|
-
return new Intl.NumberFormat(locale, {
|
|
31274
|
-
style: 'currency',
|
|
31275
|
-
currency,
|
|
31276
|
-
}).format(amount);
|
|
31277
|
-
}
|
|
31278
|
-
|
|
31279
|
-
/**
|
|
31280
|
-
* Sleep for a specified number of milliseconds
|
|
31281
|
-
*/
|
|
31282
|
-
export function sleep(ms: number): Promise<void> {
|
|
31283
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
31284
|
-
}
|
|
31329
|
+
// Your code here
|
|
31330
|
+
const greet = (name: string): void => {
|
|
31331
|
+
console.log(\`Welcome, \${name}!\`);
|
|
31332
|
+
};
|
|
31285
31333
|
|
|
31286
|
-
|
|
31287
|
-
|
|
31288
|
-
|
|
31289
|
-
|
|
31290
|
-
|
|
31291
|
-
|
|
31292
|
-
|
|
31293
|
-
|
|
31334
|
+
greet('Bun');
|
|
31335
|
+
`;
|
|
31336
|
+
await writeFile(join(projectPath, "src/index.ts"), indexContent);
|
|
31337
|
+
const tsconfigContent = {
|
|
31338
|
+
compilerOptions: {
|
|
31339
|
+
lib: ["ESNext"],
|
|
31340
|
+
target: "ESNext",
|
|
31341
|
+
module: "ESNext",
|
|
31342
|
+
moduleDetection: "force",
|
|
31343
|
+
jsx: "react-jsx",
|
|
31344
|
+
allowJs: true,
|
|
31345
|
+
moduleResolution: "bundler",
|
|
31346
|
+
allowImportingTsExtensions: true,
|
|
31347
|
+
verbatimModuleSyntax: true,
|
|
31348
|
+
noEmit: true,
|
|
31349
|
+
strict: true,
|
|
31350
|
+
skipLibCheck: true,
|
|
31351
|
+
noFallthroughCasesInSwitch: true,
|
|
31352
|
+
noUnusedLocals: false,
|
|
31353
|
+
noUnusedParameters: false,
|
|
31354
|
+
noPropertyAccessFromIndexSignature: false,
|
|
31355
|
+
types: ["bun-types"]
|
|
31356
|
+
}
|
|
31357
|
+
};
|
|
31358
|
+
await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify(tsconfigContent, null, 2));
|
|
31359
|
+
const bunfigContent = generateBunfigContent(context);
|
|
31360
|
+
await writeFile(join(projectPath, "bunfig.toml"), bunfigContent);
|
|
31361
|
+
if (context.codeQuality === "ultracite") {
|
|
31362
|
+
await setupUltracite(projectPath, context);
|
|
31363
|
+
} else {
|
|
31364
|
+
await setupBiome(projectPath, context);
|
|
31294
31365
|
}
|
|
31366
|
+
await setupVSCodeDebug(projectPath, context, "minimal");
|
|
31367
|
+
await generateMinimalReadme(projectPath, context);
|
|
31295
31368
|
}
|
|
31296
|
-
|
|
31297
|
-
|
|
31298
|
-
|
|
31299
|
-
|
|
31300
|
-
|
|
31301
|
-
|
|
31302
|
-
|
|
31303
|
-
|
|
31304
|
-
|
|
31369
|
+
// ../templates/src/builders/monorepo-bun.ts
|
|
31370
|
+
init_src();
|
|
31371
|
+
init_dist();
|
|
31372
|
+
var databaseSetupMap6 = {
|
|
31373
|
+
"postgres-drizzle": setupPostgresDrizzle,
|
|
31374
|
+
"postgres-prisma": setupPostgresPrisma,
|
|
31375
|
+
"mysql-drizzle": setupMySQLDrizzle,
|
|
31376
|
+
"mysql-prisma": setupMySQLPrisma,
|
|
31377
|
+
supabase: setupSupabaseOnly,
|
|
31378
|
+
"supabase-drizzle": setupSupabaseDrizzle,
|
|
31379
|
+
"supabase-prisma": setupSupabasePrisma,
|
|
31380
|
+
"sqlite-drizzle": setupSQLiteDrizzle,
|
|
31381
|
+
"sqlite-prisma": setupSQLitePrisma,
|
|
31382
|
+
none: async () => {}
|
|
31383
|
+
};
|
|
31384
|
+
async function buildMonorepoBunPreset(projectPath, context) {
|
|
31385
|
+
await ensureDirectory(join(projectPath, "apps/web"));
|
|
31386
|
+
await ensureDirectory(join(projectPath, "apps/api"));
|
|
31387
|
+
await ensureDirectory(join(projectPath, "packages/types"));
|
|
31388
|
+
await ensureDirectory(join(projectPath, "packages/utils"));
|
|
31389
|
+
if (context.database && context.database !== "none") {
|
|
31390
|
+
await ensureDirectory(join(projectPath, "packages/db"));
|
|
31305
31391
|
}
|
|
31306
|
-
|
|
31307
|
-
}
|
|
31308
|
-
|
|
31309
|
-
|
|
31310
|
-
|
|
31311
|
-
|
|
31312
|
-
|
|
31313
|
-
|
|
31314
|
-
|
|
31315
|
-
|
|
31316
|
-
|
|
31317
|
-
|
|
31318
|
-
|
|
31319
|
-
|
|
31392
|
+
const rootPackageJson = {
|
|
31393
|
+
name: `${context.packageName}-monorepo`,
|
|
31394
|
+
version: "0.0.0",
|
|
31395
|
+
private: true,
|
|
31396
|
+
workspaces: ["apps/*", "packages/*"],
|
|
31397
|
+
scripts: {
|
|
31398
|
+
dev: 'bun run --filter "*" dev',
|
|
31399
|
+
build: 'bun run --filter "*" build',
|
|
31400
|
+
lint: context.codeQuality === "biome" ? "biome check ." : "ultracite check .",
|
|
31401
|
+
format: context.codeQuality === "biome" ? "biome check --write ." : "ultracite fix .",
|
|
31402
|
+
test: "bun test",
|
|
31403
|
+
"dev:web": 'bun run --filter "@*/web" dev',
|
|
31404
|
+
"dev:api": 'bun run --filter "@*/api" dev',
|
|
31405
|
+
debug: "bun --inspect apps/api/src/index.ts",
|
|
31406
|
+
"debug:brk": "bun --inspect-brk apps/api/src/index.ts",
|
|
31407
|
+
"debug:wait": "bun --inspect-wait apps/api/src/index.ts"
|
|
31408
|
+
},
|
|
31409
|
+
devDependencies: {
|
|
31410
|
+
"@types/bun": "latest",
|
|
31411
|
+
typescript: "catalog:",
|
|
31412
|
+
...context.codeQuality === "biome" ? { "@biomejs/biome": "catalog:" } : {}
|
|
31413
|
+
},
|
|
31414
|
+
catalog: {
|
|
31415
|
+
react: "^19.2.3",
|
|
31416
|
+
"react-dom": "^19.2.3",
|
|
31417
|
+
"drizzle-orm": "^0.45.1",
|
|
31418
|
+
"drizzle-kit": "^0.31.8",
|
|
31419
|
+
postgres: "^3.4.7",
|
|
31420
|
+
"@supabase/supabase-js": "^2.88.0",
|
|
31421
|
+
"@prisma/client": "^7.2.0",
|
|
31422
|
+
prisma: "^7.2.0",
|
|
31423
|
+
mysql2: "^3.16.0",
|
|
31424
|
+
"better-auth": "^1.4.7",
|
|
31425
|
+
"next-auth": "^4.24.13",
|
|
31426
|
+
"@auth/drizzle-adapter": "^1.11.1",
|
|
31427
|
+
tailwindcss: "^4.1.18",
|
|
31428
|
+
autoprefixer: "^10.4.23",
|
|
31429
|
+
postcss: "^8.5.6",
|
|
31430
|
+
typescript: "^5.9.3",
|
|
31431
|
+
"@types/react": "^19.2.7",
|
|
31432
|
+
"@types/react-dom": "^19.2.3",
|
|
31433
|
+
"@types/node": "^25.0.3"
|
|
31434
|
+
}
|
|
31320
31435
|
};
|
|
31321
|
-
|
|
31322
|
-
|
|
31323
|
-
|
|
31324
|
-
|
|
31325
|
-
|
|
31326
|
-
|
|
31327
|
-
|
|
31328
|
-
|
|
31329
|
-
|
|
31330
|
-
|
|
31331
|
-
|
|
31332
|
-
|
|
31333
|
-
|
|
31334
|
-
|
|
31335
|
-
|
|
31336
|
-
|
|
31337
|
-
}
|
|
31338
|
-
|
|
31339
|
-
|
|
31340
|
-
|
|
31341
|
-
|
|
31342
|
-
}
|
|
31343
|
-
|
|
31344
|
-
|
|
31345
|
-
|
|
31346
|
-
const
|
|
31347
|
-
|
|
31348
|
-
|
|
31436
|
+
await writeFile(join(projectPath, "package.json"), JSON.stringify(rootPackageJson, null, 2));
|
|
31437
|
+
const apiPath = join(projectPath, "apps/api");
|
|
31438
|
+
await setupBunServeNative(apiPath, context, true);
|
|
31439
|
+
const apiPackageJson = {
|
|
31440
|
+
name: `@${context.packageName}/api`,
|
|
31441
|
+
version: "0.0.0",
|
|
31442
|
+
private: true,
|
|
31443
|
+
scripts: {
|
|
31444
|
+
dev: "bun run --hot src/index.ts",
|
|
31445
|
+
start: "bun run src/index.ts",
|
|
31446
|
+
debug: "bun --inspect src/index.ts",
|
|
31447
|
+
"debug:brk": "bun --inspect-brk src/index.ts",
|
|
31448
|
+
"debug:wait": "bun --inspect-wait src/index.ts"
|
|
31449
|
+
},
|
|
31450
|
+
dependencies: {
|
|
31451
|
+
[`@${context.packageName}/types`]: "workspace:*"
|
|
31452
|
+
},
|
|
31453
|
+
devDependencies: {
|
|
31454
|
+
"@types/bun": "latest",
|
|
31455
|
+
typescript: "catalog:"
|
|
31456
|
+
}
|
|
31457
|
+
};
|
|
31458
|
+
await writeFile(join(apiPath, "package.json"), JSON.stringify(apiPackageJson, null, 2));
|
|
31459
|
+
const webPath = join(projectPath, "apps/web");
|
|
31460
|
+
await setupBunFullstack(webPath, context);
|
|
31461
|
+
const webPackageJson = {
|
|
31462
|
+
name: `@${context.packageName}/web`,
|
|
31463
|
+
version: "0.0.0",
|
|
31464
|
+
private: true,
|
|
31465
|
+
scripts: {
|
|
31466
|
+
dev: "bun run --hot src/index.ts",
|
|
31467
|
+
build: "bun build src/index.ts --outdir ./dist --target bun",
|
|
31468
|
+
start: "bun run dist/index.js",
|
|
31469
|
+
debug: "bun --inspect src/index.ts",
|
|
31470
|
+
"debug:brk": "bun --inspect-brk src/index.ts",
|
|
31471
|
+
"debug:wait": "bun --inspect-wait src/index.ts"
|
|
31472
|
+
},
|
|
31473
|
+
dependencies: {
|
|
31474
|
+
react: "catalog:",
|
|
31475
|
+
"react-dom": "catalog:",
|
|
31476
|
+
[`@${context.packageName}/types`]: "workspace:*"
|
|
31477
|
+
},
|
|
31478
|
+
devDependencies: {
|
|
31479
|
+
"@types/react": "catalog:",
|
|
31480
|
+
"@types/react-dom": "catalog:",
|
|
31481
|
+
"@types/bun": "latest",
|
|
31482
|
+
typescript: "catalog:"
|
|
31483
|
+
}
|
|
31484
|
+
};
|
|
31485
|
+
await writeFile(join(webPath, "package.json"), JSON.stringify(webPackageJson, null, 2));
|
|
31486
|
+
if (context.database && context.database !== "none") {
|
|
31487
|
+
await databaseSetupMap6[context.database](join(projectPath, "packages/db"), context, true);
|
|
31349
31488
|
}
|
|
31350
|
-
|
|
31351
|
-
|
|
31352
|
-
"apps/web/src/app",
|
|
31353
|
-
"apps/web/src/components",
|
|
31354
|
-
"apps/web/src/lib",
|
|
31355
|
-
"apps/platform/src/app",
|
|
31356
|
-
"apps/platform/src/components",
|
|
31357
|
-
"apps/platform/src/lib",
|
|
31358
|
-
"apps/api/src/routes",
|
|
31359
|
-
"apps/api/src/middleware",
|
|
31360
|
-
"packages/ui",
|
|
31361
|
-
"packages/types",
|
|
31362
|
-
"packages/utils",
|
|
31363
|
-
"tooling/typescript"
|
|
31364
|
-
];
|
|
31365
|
-
for (const dir of directories) {
|
|
31366
|
-
await ensureDirectory(join(projectPath, dir));
|
|
31489
|
+
if (context.redis) {
|
|
31490
|
+
await setupRedis(join(projectPath, "packages"), context, true);
|
|
31367
31491
|
}
|
|
31368
|
-
|
|
31369
|
-
|
|
31370
|
-
|
|
31371
|
-
|
|
31372
|
-
|
|
31373
|
-
|
|
31374
|
-
|
|
31375
|
-
|
|
31376
|
-
|
|
31377
|
-
|
|
31378
|
-
|
|
31379
|
-
|
|
31380
|
-
|
|
31381
|
-
|
|
31382
|
-
|
|
31383
|
-
}
|
|
31384
|
-
|
|
31385
|
-
|
|
31386
|
-
|
|
31387
|
-
|
|
31388
|
-
|
|
31389
|
-
|
|
31390
|
-
|
|
31391
|
-
|
|
31392
|
-
|
|
31393
|
-
|
|
31394
|
-
|
|
31492
|
+
if (context.auth === "better-auth") {
|
|
31493
|
+
await setupBetterAuth(join(projectPath, "packages"), context, true);
|
|
31494
|
+
} else if (context.auth === "nextauth") {
|
|
31495
|
+
await setupNextAuth(join(projectPath, "packages"), context, true);
|
|
31496
|
+
}
|
|
31497
|
+
if (context.useBunSecrets) {
|
|
31498
|
+
await setupBunSecrets(join(projectPath, "packages"), context, true);
|
|
31499
|
+
}
|
|
31500
|
+
if (context.codeQuality === "biome") {
|
|
31501
|
+
await setupBiome(projectPath, context);
|
|
31502
|
+
} else {
|
|
31503
|
+
await setupUltracite(projectPath, context);
|
|
31504
|
+
}
|
|
31505
|
+
if (context.docker) {
|
|
31506
|
+
await setupDocker(projectPath, context);
|
|
31507
|
+
}
|
|
31508
|
+
if (context.cicd) {
|
|
31509
|
+
await setupGitHubActions(projectPath, context);
|
|
31510
|
+
}
|
|
31511
|
+
await setupTooling(projectPath, context);
|
|
31512
|
+
await setupVSCodeDebug(projectPath, context, "full");
|
|
31513
|
+
const bunfigContent = generateBunfigContent(context);
|
|
31514
|
+
await writeFile(join(projectPath, "bunfig.toml"), bunfigContent);
|
|
31515
|
+
const typesPackageJson = {
|
|
31516
|
+
name: `@${context.packageName}/types`,
|
|
31517
|
+
version: "0.0.0",
|
|
31518
|
+
private: true,
|
|
31519
|
+
main: "./index.ts",
|
|
31520
|
+
types: "./index.ts",
|
|
31521
|
+
scripts: {},
|
|
31522
|
+
devDependencies: {
|
|
31523
|
+
typescript: "catalog:"
|
|
31524
|
+
}
|
|
31525
|
+
};
|
|
31526
|
+
await ensureDirectory(join(projectPath, "packages/types"));
|
|
31527
|
+
await writeFile(join(projectPath, "packages/types/package.json"), JSON.stringify(typesPackageJson, null, 2));
|
|
31528
|
+
const typesIndex = `// Shared types across the monorepo
|
|
31529
|
+
export interface User {
|
|
31530
|
+
id: number;
|
|
31531
|
+
name: string;
|
|
31532
|
+
email: string;
|
|
31533
|
+
createdAt: Date;
|
|
31395
31534
|
}
|
|
31396
|
-
`);
|
|
31397
|
-
await writeFile(join(projectPath, "apps/web/src/app/page.tsx"), `import { Home, Rocket, Book } from 'iconoir-react';
|
|
31398
31535
|
|
|
31399
|
-
export
|
|
31400
|
-
|
|
31401
|
-
|
|
31402
|
-
|
|
31403
|
-
|
|
31404
|
-
|
|
31405
|
-
|
|
31406
|
-
|
|
31407
|
-
|
|
31408
|
-
|
|
31409
|
-
|
|
31410
|
-
|
|
31411
|
-
|
|
31412
|
-
|
|
31413
|
-
|
|
31414
|
-
|
|
31415
|
-
|
|
31416
|
-
|
|
31417
|
-
|
|
31418
|
-
|
|
31419
|
-
|
|
31420
|
-
|
|
31421
|
-
|
|
31422
|
-
|
|
31423
|
-
|
|
31424
|
-
<Book className="w-5 h-5" />
|
|
31425
|
-
Documentation
|
|
31426
|
-
</a>
|
|
31427
|
-
</div>
|
|
31428
|
-
</div>
|
|
31429
|
-
</main>
|
|
31430
|
-
);
|
|
31536
|
+
export interface ApiResponse<T = unknown> {
|
|
31537
|
+
success: boolean;
|
|
31538
|
+
data?: T;
|
|
31539
|
+
error?: string;
|
|
31540
|
+
timestamp: string;
|
|
31541
|
+
}
|
|
31542
|
+
`;
|
|
31543
|
+
await writeFile(join(projectPath, "packages/types/index.ts"), typesIndex);
|
|
31544
|
+
const utilsPackageJson = {
|
|
31545
|
+
name: `@${context.packageName}/utils`,
|
|
31546
|
+
version: "0.0.0",
|
|
31547
|
+
private: true,
|
|
31548
|
+
main: "./index.ts",
|
|
31549
|
+
types: "./index.ts",
|
|
31550
|
+
scripts: {},
|
|
31551
|
+
dependencies: {},
|
|
31552
|
+
devDependencies: {
|
|
31553
|
+
typescript: "catalog:"
|
|
31554
|
+
}
|
|
31555
|
+
};
|
|
31556
|
+
await ensureDirectory(join(projectPath, "packages/utils"));
|
|
31557
|
+
await writeFile(join(projectPath, "packages/utils/package.json"), JSON.stringify(utilsPackageJson, null, 2));
|
|
31558
|
+
const utilsIndex = `// Shared utilities across the monorepo
|
|
31559
|
+
export function formatDate(date: Date): string {
|
|
31560
|
+
return date.toISOString();
|
|
31431
31561
|
}
|
|
31432
|
-
`);
|
|
31433
|
-
await writeFile(join(projectPath, "apps/web/next.config.ts"), `import type { NextConfig } from 'next';
|
|
31434
|
-
|
|
31435
|
-
const nextConfig: NextConfig = {
|
|
31436
|
-
transpilePackages: ['@${scopeName}/ui'],
|
|
31437
|
-
};
|
|
31438
31562
|
|
|
31439
|
-
export
|
|
31440
|
-
|
|
31441
|
-
|
|
31442
|
-
|
|
31443
|
-
|
|
31444
|
-
|
|
31445
|
-
|
|
31446
|
-
|
|
31447
|
-
},
|
|
31448
|
-
include: ["
|
|
31563
|
+
export function capitalize(str: string): string {
|
|
31564
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
31565
|
+
}
|
|
31566
|
+
`;
|
|
31567
|
+
await writeFile(join(projectPath, "packages/utils/index.ts"), utilsIndex);
|
|
31568
|
+
await generateMonorepoReadme(projectPath, context, "bun");
|
|
31569
|
+
const tsconfigContent = {
|
|
31570
|
+
extends: "./tooling/typescript/base.json",
|
|
31571
|
+
compilerOptions: {},
|
|
31572
|
+
include: ["apps/*/src/**/*", "packages/*/**/*"],
|
|
31449
31573
|
exclude: ["node_modules"]
|
|
31450
|
-
}
|
|
31451
|
-
await writeFile(join(projectPath, "
|
|
31452
|
-
|
|
31453
|
-
|
|
31454
|
-
|
|
31455
|
-
|
|
31456
|
-
|
|
31457
|
-
await
|
|
31458
|
-
await
|
|
31459
|
-
import
|
|
31574
|
+
};
|
|
31575
|
+
await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify(tsconfigContent, null, 2));
|
|
31576
|
+
}
|
|
31577
|
+
// ../templates/src/builders/web.ts
|
|
31578
|
+
init_src();
|
|
31579
|
+
init_dist();
|
|
31580
|
+
async function buildWebPreset(projectPath, context) {
|
|
31581
|
+
await ensureDirectory(join(projectPath, "src/app"));
|
|
31582
|
+
await ensureDirectory(join(projectPath, "public"));
|
|
31583
|
+
const layoutContent = `import type { Metadata } from 'next'
|
|
31584
|
+
import './globals.css'
|
|
31460
31585
|
|
|
31461
31586
|
export const metadata: Metadata = {
|
|
31462
|
-
title: '${context.projectName}
|
|
31463
|
-
description: '
|
|
31464
|
-
}
|
|
31587
|
+
title: '${context.projectName}',
|
|
31588
|
+
description: 'Built with bunkit \uD83C\uDF5E',
|
|
31589
|
+
}
|
|
31465
31590
|
|
|
31466
31591
|
export default function RootLayout({
|
|
31467
31592
|
children,
|
|
31468
31593
|
}: {
|
|
31469
|
-
children: React.ReactNode
|
|
31594
|
+
children: React.ReactNode
|
|
31470
31595
|
}) {
|
|
31471
31596
|
return (
|
|
31472
31597
|
<html lang="en">
|
|
31473
|
-
<body
|
|
31598
|
+
<body>{children}</body>
|
|
31474
31599
|
</html>
|
|
31475
|
-
)
|
|
31600
|
+
)
|
|
31476
31601
|
}
|
|
31477
|
-
|
|
31478
|
-
await writeFile(join(projectPath, "
|
|
31479
|
-
|
|
31480
|
-
export default function DashboardPage() {
|
|
31602
|
+
`;
|
|
31603
|
+
await writeFile(join(projectPath, "src/app/layout.tsx"), layoutContent);
|
|
31604
|
+
const pageContent = `export default function Home() {
|
|
31481
31605
|
return (
|
|
31482
|
-
<main className="min-h-screen
|
|
31483
|
-
<div className="
|
|
31484
|
-
<
|
|
31485
|
-
|
|
31486
|
-
|
|
31487
|
-
|
|
31488
|
-
|
|
31489
|
-
|
|
31490
|
-
</p>
|
|
31491
|
-
</div>
|
|
31492
|
-
</header>
|
|
31493
|
-
|
|
31494
|
-
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
31495
|
-
<div className="bg-card p-6 rounded-lg border shadow-sm">
|
|
31496
|
-
<div className="flex items-center gap-3 mb-2">
|
|
31497
|
-
<User className="w-5 h-5 text-blue-500" />
|
|
31498
|
-
<h2 className="text-lg font-semibold">Users</h2>
|
|
31499
|
-
</div>
|
|
31500
|
-
<p className="text-3xl font-bold">1,234</p>
|
|
31501
|
-
</div>
|
|
31502
|
-
<div className="bg-card p-6 rounded-lg border shadow-sm">
|
|
31503
|
-
<div className="flex items-center gap-3 mb-2">
|
|
31504
|
-
<Dollar className="w-5 h-5 text-green-500" />
|
|
31505
|
-
<h2 className="text-lg font-semibold">Revenue</h2>
|
|
31506
|
-
</div>
|
|
31507
|
-
<p className="text-3xl font-bold">$12,345</p>
|
|
31508
|
-
</div>
|
|
31509
|
-
<div className="bg-card p-6 rounded-lg border shadow-sm">
|
|
31510
|
-
<div className="flex items-center gap-3 mb-2">
|
|
31511
|
-
<GraphUp className="w-5 h-5 text-purple-500" />
|
|
31512
|
-
<h2 className="text-lg font-semibold">Active</h2>
|
|
31513
|
-
</div>
|
|
31514
|
-
<p className="text-3xl font-bold">567</p>
|
|
31515
|
-
</div>
|
|
31516
|
-
</div>
|
|
31606
|
+
<main className="min-h-screen flex items-center justify-center">
|
|
31607
|
+
<div className="text-center">
|
|
31608
|
+
<h1 className="text-4xl font-bold mb-4">
|
|
31609
|
+
Welcome to ${context.projectName} \uD83C\uDF5E
|
|
31610
|
+
</h1>
|
|
31611
|
+
<p className="text-gray-600">
|
|
31612
|
+
Built with Next.js 16, React 19, and bunkit
|
|
31613
|
+
</p>
|
|
31517
31614
|
</div>
|
|
31518
31615
|
</main>
|
|
31519
|
-
)
|
|
31520
|
-
}
|
|
31521
|
-
`);
|
|
31522
|
-
await writeFile(join(projectPath, "apps/platform/next.config.ts"), `import type { NextConfig } from 'next';
|
|
31523
|
-
|
|
31524
|
-
const nextConfig: NextConfig = {
|
|
31525
|
-
transpilePackages: ['@${scopeName}/ui'],
|
|
31526
|
-
};
|
|
31527
|
-
|
|
31528
|
-
export default nextConfig;
|
|
31529
|
-
`);
|
|
31530
|
-
await writeFile(join(projectPath, "apps/platform/tsconfig.json"), JSON.stringify({
|
|
31531
|
-
extends: "../../tooling/typescript/nextjs.json",
|
|
31532
|
-
compilerOptions: {
|
|
31533
|
-
paths: {
|
|
31534
|
-
"@/*": ["./src/*"]
|
|
31535
|
-
}
|
|
31536
|
-
},
|
|
31537
|
-
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
31538
|
-
exclude: ["node_modules"]
|
|
31539
|
-
}, null, 2));
|
|
31540
|
-
await writeFile(join(projectPath, "apps/platform/postcss.config.mjs"), `export default {
|
|
31541
|
-
plugins: {
|
|
31542
|
-
'@tailwindcss/postcss': {},
|
|
31543
|
-
},
|
|
31544
|
-
};
|
|
31545
|
-
`);
|
|
31546
|
-
await writeHonoApiPackageJson(join(projectPath, "apps/api"), scopeName, {
|
|
31547
|
-
usesTypes: true
|
|
31548
|
-
});
|
|
31549
|
-
await writeFile(join(projectPath, "apps/api/src/index.ts"), `import { Hono } from 'hono';
|
|
31550
|
-
import { logger } from 'hono/logger';
|
|
31551
|
-
import { cors } from 'hono/cors';
|
|
31552
|
-
|
|
31553
|
-
const app = new Hono();
|
|
31554
|
-
|
|
31555
|
-
// Middleware
|
|
31556
|
-
app.use('*', logger());
|
|
31557
|
-
app.use('*', cors());
|
|
31558
|
-
|
|
31559
|
-
// Routes
|
|
31560
|
-
app.get('/', (context) => {
|
|
31561
|
-
return context.json({
|
|
31562
|
-
name: '${context.projectName} API',
|
|
31563
|
-
version: '1.0.0',
|
|
31564
|
-
timestamp: new Date().toISOString(),
|
|
31565
|
-
});
|
|
31566
|
-
});
|
|
31567
|
-
|
|
31568
|
-
app.get('/health', (context) => {
|
|
31569
|
-
return context.json({ status: 'ok' });
|
|
31570
|
-
});
|
|
31571
|
-
|
|
31572
|
-
app.get('/api/users', (context) => {
|
|
31573
|
-
return context.json({
|
|
31574
|
-
users: [
|
|
31575
|
-
{ id: '1', email: 'john@example.com', name: 'John Doe' },
|
|
31576
|
-
{ id: '2', email: 'jane@example.com', name: 'Jane Smith' },
|
|
31577
|
-
],
|
|
31578
|
-
});
|
|
31579
|
-
});
|
|
31616
|
+
)
|
|
31617
|
+
}
|
|
31580
31618
|
|
|
31581
|
-
//
|
|
31582
|
-
|
|
31583
|
-
|
|
31584
|
-
}
|
|
31619
|
+
// Next.js 16 Note:
|
|
31620
|
+
// When you add dynamic routes with params, make your component async and await params:
|
|
31621
|
+
// export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
|
|
31622
|
+
// const { slug } = await params;
|
|
31623
|
+
// return <div>{slug}</div>;
|
|
31624
|
+
// }
|
|
31625
|
+
`;
|
|
31626
|
+
await writeFile(join(projectPath, "src/app/page.tsx"), pageContent);
|
|
31627
|
+
const globalsCssContent = `@import "tailwindcss";
|
|
31628
|
+
`;
|
|
31629
|
+
await writeFile(join(projectPath, "src/app/globals.css"), globalsCssContent);
|
|
31630
|
+
const nextConfigContent = `import type { NextConfig } from 'next';
|
|
31585
31631
|
|
|
31586
|
-
|
|
31587
|
-
|
|
31588
|
-
|
|
31589
|
-
return context.json({ error: 'Internal server error' }, 500);
|
|
31590
|
-
});
|
|
31632
|
+
const nextConfig: NextConfig = {
|
|
31633
|
+
/* config options here */
|
|
31634
|
+
};
|
|
31591
31635
|
|
|
31592
|
-
|
|
31593
|
-
|
|
31594
|
-
|
|
31595
|
-
|
|
31596
|
-
development: {
|
|
31597
|
-
hmr: true,
|
|
31598
|
-
},
|
|
31599
|
-
});
|
|
31636
|
+
export default nextConfig;
|
|
31637
|
+
`;
|
|
31638
|
+
await writeFile(join(projectPath, "next.config.ts"), nextConfigContent);
|
|
31639
|
+
const tailwindConfigContent = `import type { Config } from 'tailwindcss';
|
|
31600
31640
|
|
|
31601
|
-
|
|
31641
|
+
const config: Config = {
|
|
31642
|
+
content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
|
|
31643
|
+
theme: {
|
|
31644
|
+
extend: {},
|
|
31645
|
+
},
|
|
31646
|
+
plugins: [],
|
|
31647
|
+
};
|
|
31602
31648
|
|
|
31603
|
-
export default
|
|
31604
|
-
|
|
31605
|
-
await writeFile(join(projectPath, "
|
|
31606
|
-
|
|
31607
|
-
|
|
31608
|
-
|
|
31609
|
-
|
|
31610
|
-
|
|
31649
|
+
export default config;
|
|
31650
|
+
`;
|
|
31651
|
+
await writeFile(join(projectPath, "tailwind.config.ts"), tailwindConfigContent);
|
|
31652
|
+
const getTsCompilerOptions = () => {
|
|
31653
|
+
const baseOptions = {
|
|
31654
|
+
target: "ES2017",
|
|
31655
|
+
lib: ["dom", "dom.iterable", "esnext"],
|
|
31656
|
+
allowJs: true,
|
|
31657
|
+
skipLibCheck: true,
|
|
31658
|
+
noEmit: true,
|
|
31659
|
+
esModuleInterop: true,
|
|
31660
|
+
module: "esnext",
|
|
31661
|
+
moduleResolution: "bundler",
|
|
31662
|
+
resolveJsonModule: true,
|
|
31663
|
+
isolatedModules: true,
|
|
31664
|
+
jsx: "react-jsx",
|
|
31665
|
+
incremental: true,
|
|
31666
|
+
plugins: [{ name: "next" }],
|
|
31667
|
+
paths: context.pathAliases ? { "@/*": ["./src/*"] } : undefined
|
|
31668
|
+
};
|
|
31669
|
+
if (context.tsStrictness === "strict") {
|
|
31670
|
+
return {
|
|
31671
|
+
...baseOptions,
|
|
31672
|
+
strict: true,
|
|
31673
|
+
noUnusedLocals: true,
|
|
31674
|
+
noUnusedParameters: true,
|
|
31675
|
+
noFallthroughCasesInSwitch: true,
|
|
31676
|
+
noImplicitReturns: true
|
|
31677
|
+
};
|
|
31678
|
+
}
|
|
31679
|
+
if (context.tsStrictness === "moderate") {
|
|
31680
|
+
return {
|
|
31681
|
+
...baseOptions,
|
|
31682
|
+
strict: true,
|
|
31683
|
+
noUnusedLocals: false,
|
|
31684
|
+
noUnusedParameters: false
|
|
31685
|
+
};
|
|
31686
|
+
}
|
|
31687
|
+
return {
|
|
31688
|
+
...baseOptions,
|
|
31689
|
+
strict: false,
|
|
31690
|
+
noImplicitAny: false
|
|
31691
|
+
};
|
|
31692
|
+
};
|
|
31693
|
+
const tsconfigContent = {
|
|
31694
|
+
compilerOptions: getTsCompilerOptions(),
|
|
31695
|
+
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/dev/types/**/*.ts"],
|
|
31611
31696
|
exclude: ["node_modules"]
|
|
31612
|
-
}
|
|
31613
|
-
await
|
|
31614
|
-
|
|
31615
|
-
|
|
31616
|
-
shadcnBase: context.shadcnBase || "radix",
|
|
31617
|
-
shadcnBaseColor: context.shadcnBaseColor || "zinc",
|
|
31618
|
-
shadcnIconLibrary: context.shadcnIconLibrary || "phosphor",
|
|
31619
|
-
shadcnMenuAccent: context.shadcnMenuAccent || "subtle",
|
|
31620
|
-
shadcnMenuColor: context.shadcnMenuColor || "default",
|
|
31621
|
-
shadcnRadius: context.shadcnRadius || "0.625rem",
|
|
31622
|
-
appsToScan: ["web", "platform"]
|
|
31623
|
-
});
|
|
31624
|
-
await buildTypesPackage(join(projectPath, "packages"), scopeName);
|
|
31625
|
-
await buildUtilsPackage(join(projectPath, "packages"), scopeName);
|
|
31626
|
-
await setupTooling(projectPath, context);
|
|
31627
|
-
await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify({
|
|
31628
|
-
extends: "./tooling/typescript/base.json",
|
|
31629
|
-
include: ["apps/*/src/**/*", "packages/*/src/**/*"],
|
|
31630
|
-
exclude: ["node_modules", "**/node_modules", "**/.next"]
|
|
31631
|
-
}, null, 2));
|
|
31697
|
+
};
|
|
31698
|
+
await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify(tsconfigContent, null, 2));
|
|
31699
|
+
const bunfigContent = generateBunfigContent(context);
|
|
31700
|
+
await writeFile(join(projectPath, "bunfig.toml"), bunfigContent);
|
|
31632
31701
|
if (context.codeQuality === "ultracite") {
|
|
31633
31702
|
await setupUltracite(projectPath, context);
|
|
31634
31703
|
} else {
|
|
@@ -31640,13 +31709,52 @@ export default app;
|
|
|
31640
31709
|
if (context.cicd) {
|
|
31641
31710
|
await setupGitHubActions(projectPath, context);
|
|
31642
31711
|
}
|
|
31643
|
-
|
|
31644
|
-
|
|
31712
|
+
if (context.uiLibrary === "shadcn" && context.cssFramework === "tailwind") {
|
|
31713
|
+
await setupShadcnWeb(projectPath, context);
|
|
31714
|
+
}
|
|
31715
|
+
await setupVSCodeDebug(projectPath, context, "web");
|
|
31716
|
+
const packageJsonPath = join(projectPath, "package.json");
|
|
31717
|
+
const existingPackageJson = JSON.parse(await Bun.file(packageJsonPath).text());
|
|
31718
|
+
existingPackageJson.dependencies = {
|
|
31719
|
+
react: "^19.2.3",
|
|
31720
|
+
"react-dom": "^19.2.3",
|
|
31721
|
+
next: "^16.0.10",
|
|
31722
|
+
...existingPackageJson.dependencies
|
|
31723
|
+
};
|
|
31724
|
+
existingPackageJson.devDependencies = {
|
|
31725
|
+
...existingPackageJson.devDependencies,
|
|
31726
|
+
"@types/react": "^19.2.7",
|
|
31727
|
+
"@types/react-dom": "^19.2.3",
|
|
31728
|
+
"@types/node": "^25.0.3"
|
|
31729
|
+
};
|
|
31730
|
+
if (!existingPackageJson.scripts) {
|
|
31731
|
+
existingPackageJson.scripts = {};
|
|
31732
|
+
}
|
|
31733
|
+
if (!existingPackageJson.scripts.dev) {
|
|
31734
|
+
existingPackageJson.scripts.dev = "bun run --bun next dev --turbopack";
|
|
31735
|
+
}
|
|
31736
|
+
if (!existingPackageJson.scripts.build) {
|
|
31737
|
+
existingPackageJson.scripts.build = "bun run --bun next build";
|
|
31738
|
+
}
|
|
31739
|
+
if (!existingPackageJson.scripts.start) {
|
|
31740
|
+
existingPackageJson.scripts.start = "bun run --bun next start";
|
|
31741
|
+
}
|
|
31742
|
+
if (!existingPackageJson.scripts.debug) {
|
|
31743
|
+
existingPackageJson.scripts.debug = "bun --inspect node_modules/.bin/next dev --turbopack";
|
|
31744
|
+
}
|
|
31745
|
+
if (!existingPackageJson.scripts["debug:brk"]) {
|
|
31746
|
+
existingPackageJson.scripts["debug:brk"] = "bun --inspect-brk node_modules/.bin/next dev --turbopack";
|
|
31747
|
+
}
|
|
31748
|
+
if (!existingPackageJson.scripts["debug:wait"]) {
|
|
31749
|
+
existingPackageJson.scripts["debug:wait"] = "bun --inspect-wait node_modules/.bin/next dev --turbopack";
|
|
31750
|
+
}
|
|
31751
|
+
await writeFile(packageJsonPath, JSON.stringify(existingPackageJson, null, 2));
|
|
31752
|
+
await generateNextjsReadme(projectPath, context);
|
|
31645
31753
|
}
|
|
31646
|
-
// ../templates/src/shared/index.ts
|
|
31647
|
-
init_package_json();
|
|
31648
31754
|
// ../templates/src/render.ts
|
|
31649
31755
|
var import_ejs = __toESM(require_ejs(), 1);
|
|
31756
|
+
// ../templates/src/shared/index.ts
|
|
31757
|
+
init_package_json();
|
|
31650
31758
|
// src/commands/add/component.ts
|
|
31651
31759
|
init_dist();
|
|
31652
31760
|
async function getPackageName(cwd2) {
|
|
@@ -33117,29 +33225,54 @@ async function enhancedInitCommand(options = {}) {
|
|
|
33117
33225
|
options: [
|
|
33118
33226
|
{
|
|
33119
33227
|
value: "radix-maia",
|
|
33120
|
-
label: "Maia (Recommended)",
|
|
33228
|
+
label: "Maia \u2014 Radix (Recommended)",
|
|
33121
33229
|
hint: "Modern, clean design with soft shadows and refined aesthetics"
|
|
33122
33230
|
},
|
|
33123
33231
|
{
|
|
33124
33232
|
value: "radix-vega",
|
|
33125
|
-
label: "Vega",
|
|
33233
|
+
label: "Vega \u2014 Radix",
|
|
33126
33234
|
hint: "Bold, vibrant design with stronger colors and contrast"
|
|
33127
33235
|
},
|
|
33128
33236
|
{
|
|
33129
33237
|
value: "radix-nova",
|
|
33130
|
-
label: "Nova",
|
|
33238
|
+
label: "Nova \u2014 Radix",
|
|
33131
33239
|
hint: "Minimalist design with subtle accents and clean lines"
|
|
33132
33240
|
},
|
|
33133
33241
|
{
|
|
33134
33242
|
value: "radix-lyra",
|
|
33135
|
-
label: "Lyra",
|
|
33243
|
+
label: "Lyra \u2014 Radix",
|
|
33136
33244
|
hint: "Elegant design with refined typography and spacing"
|
|
33137
33245
|
},
|
|
33138
33246
|
{
|
|
33139
33247
|
value: "radix-mira",
|
|
33140
|
-
label: "Mira",
|
|
33248
|
+
label: "Mira \u2014 Radix",
|
|
33141
33249
|
hint: "Playful design with rounded elements and soft colors"
|
|
33142
33250
|
},
|
|
33251
|
+
{
|
|
33252
|
+
value: "base-maia",
|
|
33253
|
+
label: "Maia \u2014 Base UI",
|
|
33254
|
+
hint: "Clean design using Base UI primitives (alternative to Radix)"
|
|
33255
|
+
},
|
|
33256
|
+
{
|
|
33257
|
+
value: "base-vega",
|
|
33258
|
+
label: "Vega \u2014 Base UI",
|
|
33259
|
+
hint: "Bold design using Base UI primitives"
|
|
33260
|
+
},
|
|
33261
|
+
{
|
|
33262
|
+
value: "base-nova",
|
|
33263
|
+
label: "Nova \u2014 Base UI",
|
|
33264
|
+
hint: "Minimalist design using Base UI primitives"
|
|
33265
|
+
},
|
|
33266
|
+
{
|
|
33267
|
+
value: "base-lyra",
|
|
33268
|
+
label: "Lyra \u2014 Base UI",
|
|
33269
|
+
hint: "Elegant design using Base UI primitives"
|
|
33270
|
+
},
|
|
33271
|
+
{
|
|
33272
|
+
value: "base-mira",
|
|
33273
|
+
label: "Mira \u2014 Base UI",
|
|
33274
|
+
hint: "Playful design using Base UI primitives"
|
|
33275
|
+
},
|
|
33143
33276
|
{
|
|
33144
33277
|
value: "new-york",
|
|
33145
33278
|
label: "New York (Legacy)",
|
|
@@ -33227,21 +33360,21 @@ async function enhancedInitCommand(options = {}) {
|
|
|
33227
33360
|
}
|
|
33228
33361
|
}
|
|
33229
33362
|
let shadcnIconLibrary = getOptionValue("BUNKIT_SHADCN_ICON_LIBRARY", options.shadcnIconLibrary);
|
|
33230
|
-
const
|
|
33363
|
+
const isModernStyle = shadcnStyle?.startsWith("radix-") || shadcnStyle?.startsWith("base-");
|
|
33231
33364
|
if (!shadcnIconLibrary && uiLibrary === "shadcn") {
|
|
33232
33365
|
if (!isNonInteractive) {
|
|
33233
33366
|
shadcnIconLibrary = await ve({
|
|
33234
33367
|
message: "\uD83D\uDD23 Icon library",
|
|
33235
33368
|
options: [
|
|
33236
33369
|
{
|
|
33237
|
-
value: "
|
|
33238
|
-
label:
|
|
33239
|
-
hint: "
|
|
33370
|
+
value: "iconoir",
|
|
33371
|
+
label: "Iconoir (Recommended)",
|
|
33372
|
+
hint: "bunkit default - 1600+ lightweight, tree-shakeable icons"
|
|
33240
33373
|
},
|
|
33241
33374
|
{
|
|
33242
|
-
value: "
|
|
33243
|
-
label:
|
|
33244
|
-
hint: "
|
|
33375
|
+
value: "phosphor",
|
|
33376
|
+
label: "Phosphor Icons",
|
|
33377
|
+
hint: "Modern icon library with consistent design - shadcn/ui default for new styles"
|
|
33245
33378
|
},
|
|
33246
33379
|
{
|
|
33247
33380
|
value: "lucide",
|
|
@@ -33255,39 +33388,19 @@ async function enhancedInitCommand(options = {}) {
|
|
|
33255
33388
|
process.exit(0);
|
|
33256
33389
|
}
|
|
33257
33390
|
} else {
|
|
33258
|
-
shadcnIconLibrary =
|
|
33391
|
+
shadcnIconLibrary = "iconoir";
|
|
33259
33392
|
}
|
|
33260
33393
|
}
|
|
33261
33394
|
let shadcnBase = getOptionValue("BUNKIT_SHADCN_BASE", options.shadcnBase);
|
|
33262
|
-
if (!shadcnBase && uiLibrary === "shadcn"
|
|
33263
|
-
if (
|
|
33264
|
-
shadcnBase =
|
|
33265
|
-
message: "\uD83E\uDDF1 Component foundation",
|
|
33266
|
-
options: [
|
|
33267
|
-
{
|
|
33268
|
-
value: "radix",
|
|
33269
|
-
label: "Radix UI (Recommended)",
|
|
33270
|
-
hint: "Battle-tested accessibility primitives - industry standard"
|
|
33271
|
-
},
|
|
33272
|
-
{
|
|
33273
|
-
value: "base-ui",
|
|
33274
|
-
label: "Base UI",
|
|
33275
|
-
hint: "Modern alternative with similar API - newer, experimental"
|
|
33276
|
-
}
|
|
33277
|
-
]
|
|
33278
|
-
});
|
|
33279
|
-
if (pD(shadcnBase)) {
|
|
33280
|
-
xe("Operation cancelled.");
|
|
33281
|
-
process.exit(0);
|
|
33282
|
-
}
|
|
33395
|
+
if (!shadcnBase && uiLibrary === "shadcn") {
|
|
33396
|
+
if (shadcnStyle?.startsWith("base-")) {
|
|
33397
|
+
shadcnBase = "base-ui";
|
|
33283
33398
|
} else {
|
|
33284
33399
|
shadcnBase = "radix";
|
|
33285
33400
|
}
|
|
33286
|
-
} else if (!shadcnBase) {
|
|
33287
|
-
shadcnBase = "radix";
|
|
33288
33401
|
}
|
|
33289
33402
|
let shadcnMenuAccent = getOptionValue("BUNKIT_SHADCN_MENU_ACCENT", options.shadcnMenuAccent);
|
|
33290
|
-
if (!shadcnMenuAccent && uiLibrary === "shadcn" &&
|
|
33403
|
+
if (!shadcnMenuAccent && uiLibrary === "shadcn" && isModernStyle) {
|
|
33291
33404
|
if (!isNonInteractive) {
|
|
33292
33405
|
shadcnMenuAccent = await ve({
|
|
33293
33406
|
message: "\u2728 Menu accent style",
|
|
@@ -33315,7 +33428,7 @@ async function enhancedInitCommand(options = {}) {
|
|
|
33315
33428
|
shadcnMenuAccent = "subtle";
|
|
33316
33429
|
}
|
|
33317
33430
|
let shadcnMenuColor = getOptionValue("BUNKIT_SHADCN_MENU_COLOR", options.shadcnMenuColor);
|
|
33318
|
-
if (!shadcnMenuColor && uiLibrary === "shadcn" &&
|
|
33431
|
+
if (!shadcnMenuColor && uiLibrary === "shadcn" && isModernStyle) {
|
|
33319
33432
|
if (!isNonInteractive) {
|
|
33320
33433
|
shadcnMenuColor = await ve({
|
|
33321
33434
|
message: "\uD83C\uDFAF Menu color scheme",
|
|
@@ -33342,6 +33455,21 @@ async function enhancedInitCommand(options = {}) {
|
|
|
33342
33455
|
} else if (!shadcnMenuColor) {
|
|
33343
33456
|
shadcnMenuColor = "default";
|
|
33344
33457
|
}
|
|
33458
|
+
let shadcnRtl = getOptionValue("BUNKIT_SHADCN_RTL", options.shadcnRtl, false);
|
|
33459
|
+
if (shadcnRtl === undefined && uiLibrary === "shadcn" && isModernStyle) {
|
|
33460
|
+
if (!isNonInteractive) {
|
|
33461
|
+
shadcnRtl = await ye({
|
|
33462
|
+
message: "\uD83D\uDD04 Enable RTL (right-to-left) support",
|
|
33463
|
+
initialValue: false
|
|
33464
|
+
});
|
|
33465
|
+
if (pD(shadcnRtl)) {
|
|
33466
|
+
xe("Operation cancelled.");
|
|
33467
|
+
process.exit(0);
|
|
33468
|
+
}
|
|
33469
|
+
} else {
|
|
33470
|
+
shadcnRtl = false;
|
|
33471
|
+
}
|
|
33472
|
+
}
|
|
33345
33473
|
let testing = getOptionValue("BUNKIT_TESTING", options.testing, "bun-test");
|
|
33346
33474
|
if (!testing) {
|
|
33347
33475
|
if (!isNonInteractive) {
|
|
@@ -33588,6 +33716,7 @@ async function enhancedInitCommand(options = {}) {
|
|
|
33588
33716
|
shadcnMenuAccent,
|
|
33589
33717
|
shadcnMenuColor,
|
|
33590
33718
|
shadcnRadius,
|
|
33719
|
+
shadcnRtl: shadcnRtl || false,
|
|
33591
33720
|
supabasePreset,
|
|
33592
33721
|
supabaseFeatures,
|
|
33593
33722
|
supabaseWithDrizzle
|
|
@@ -33797,6 +33926,130 @@ async function enhancedInitCommand(options = {}) {
|
|
|
33797
33926
|
}
|
|
33798
33927
|
}
|
|
33799
33928
|
|
|
33929
|
+
// src/commands/migrate.ts
|
|
33930
|
+
import { existsSync as existsSync3 } from "fs";
|
|
33931
|
+
init_source();
|
|
33932
|
+
init_dist();
|
|
33933
|
+
var VALID_MIGRATIONS = ["radix", "rtl", "icons"];
|
|
33934
|
+
var MIGRATION_DESCRIPTIONS = {
|
|
33935
|
+
radix: "Migrate to unified radix-ui package (replaces @radix-ui/react-* packages)",
|
|
33936
|
+
rtl: "Enable RTL (right-to-left) support in shadcn/ui components",
|
|
33937
|
+
icons: "Migrate icon library (e.g., lucide to iconoir or phosphor)"
|
|
33938
|
+
};
|
|
33939
|
+
function detectShadcnRoot(projectPath) {
|
|
33940
|
+
const monorepoPath = join(projectPath, "packages/ui");
|
|
33941
|
+
if (existsSync3(join(monorepoPath, "components.json"))) {
|
|
33942
|
+
return monorepoPath;
|
|
33943
|
+
}
|
|
33944
|
+
if (existsSync3(join(projectPath, "components.json"))) {
|
|
33945
|
+
return projectPath;
|
|
33946
|
+
}
|
|
33947
|
+
return null;
|
|
33948
|
+
}
|
|
33949
|
+
async function runBunInstall(projectPath) {
|
|
33950
|
+
const installSpinner = Y2();
|
|
33951
|
+
installSpinner.start("Resolving dependencies (bun install)...");
|
|
33952
|
+
try {
|
|
33953
|
+
const installProcess = Bun.spawn(["bun", "install"], {
|
|
33954
|
+
cwd: projectPath,
|
|
33955
|
+
stdout: "pipe",
|
|
33956
|
+
stderr: "pipe"
|
|
33957
|
+
});
|
|
33958
|
+
await installProcess.exited;
|
|
33959
|
+
if (installProcess.exitCode !== 0) {
|
|
33960
|
+
const stderr = await new Response(installProcess.stderr).text();
|
|
33961
|
+
installSpinner.stop(source_default.red("Failed to install dependencies"));
|
|
33962
|
+
Me(stderr, "Error Details");
|
|
33963
|
+
return false;
|
|
33964
|
+
}
|
|
33965
|
+
installSpinner.stop(source_default.green("Dependencies resolved"));
|
|
33966
|
+
return true;
|
|
33967
|
+
} catch (error) {
|
|
33968
|
+
installSpinner.stop(source_default.red("Failed to install dependencies"));
|
|
33969
|
+
Me(String(error), "Error Details");
|
|
33970
|
+
return false;
|
|
33971
|
+
}
|
|
33972
|
+
}
|
|
33973
|
+
async function runShadcnMigrate(shadcnRoot, migrationType) {
|
|
33974
|
+
const migrateSpinner = Y2();
|
|
33975
|
+
migrateSpinner.start(`Running shadcn migrate ${migrationType}...`);
|
|
33976
|
+
try {
|
|
33977
|
+
const migrateProcess = Bun.spawn(["bunx", "shadcn@latest", "migrate", migrationType], {
|
|
33978
|
+
cwd: shadcnRoot,
|
|
33979
|
+
stdout: "pipe",
|
|
33980
|
+
stderr: "pipe"
|
|
33981
|
+
});
|
|
33982
|
+
await migrateProcess.exited;
|
|
33983
|
+
if (migrateProcess.exitCode !== 0) {
|
|
33984
|
+
const stderr = await new Response(migrateProcess.stderr).text();
|
|
33985
|
+
migrateSpinner.stop(source_default.red(`Migration failed: ${migrationType}`));
|
|
33986
|
+
Me(stderr, "Error Details");
|
|
33987
|
+
return false;
|
|
33988
|
+
}
|
|
33989
|
+
migrateSpinner.stop(source_default.green(`Migration complete: ${migrationType}`));
|
|
33990
|
+
return true;
|
|
33991
|
+
} catch (error) {
|
|
33992
|
+
migrateSpinner.stop(source_default.red(`Migration failed: ${migrationType}`));
|
|
33993
|
+
Me(String(error), "Error Details");
|
|
33994
|
+
return false;
|
|
33995
|
+
}
|
|
33996
|
+
}
|
|
33997
|
+
function showPostMigrationAdvice(migrationType, isMonorepo) {
|
|
33998
|
+
const advice = [];
|
|
33999
|
+
switch (migrationType) {
|
|
34000
|
+
case "radix":
|
|
34001
|
+
advice.push("The unified radix-ui package replaces individual @radix-ui/react-* packages.", "Old packages can be removed from your package.json.", isMonorepo ? "Check packages/ui/package.json and root catalog for cleanup." : "Check package.json for cleanup.", "", "Run: bun install (to update lockfile)");
|
|
34002
|
+
break;
|
|
34003
|
+
case "rtl":
|
|
34004
|
+
advice.push("RTL support has been added to your components.", "Class names have been transformed for RTL compatibility.", 'components.json now includes "rtl": true.', "", 'Set dir="rtl" on your <html> element to activate RTL layout.');
|
|
34005
|
+
break;
|
|
34006
|
+
case "icons":
|
|
34007
|
+
advice.push("Icon imports have been updated in your components.", "Check components.json to verify the iconLibrary field.", "", "You may need to install the new icon package:", " bun add iconoir-react (bunkit default)", " bun add @phosphor-icons/react", " bun add lucide-react");
|
|
34008
|
+
break;
|
|
34009
|
+
}
|
|
34010
|
+
if (advice.length > 0) {
|
|
34011
|
+
Me(advice.join(`
|
|
34012
|
+
`), "Post-Migration");
|
|
34013
|
+
}
|
|
34014
|
+
}
|
|
34015
|
+
async function migrateCommand(migrationType) {
|
|
34016
|
+
if (!migrationType) {
|
|
34017
|
+
migrationType = await ve({
|
|
34018
|
+
message: "Select migration type",
|
|
34019
|
+
options: VALID_MIGRATIONS.map((migration2) => ({
|
|
34020
|
+
value: migration2,
|
|
34021
|
+
label: migration2,
|
|
34022
|
+
hint: MIGRATION_DESCRIPTIONS[migration2]
|
|
34023
|
+
}))
|
|
34024
|
+
});
|
|
34025
|
+
if (pD(migrationType)) {
|
|
34026
|
+
xe("Operation cancelled.");
|
|
34027
|
+
process.exit(0);
|
|
34028
|
+
}
|
|
34029
|
+
}
|
|
34030
|
+
if (!VALID_MIGRATIONS.includes(migrationType)) {
|
|
34031
|
+
throw new Error(`Invalid migration type: "${migrationType}". ` + `Valid types: ${VALID_MIGRATIONS.join(", ")}`);
|
|
34032
|
+
}
|
|
34033
|
+
const migration = migrationType;
|
|
34034
|
+
const projectPath = process.cwd();
|
|
34035
|
+
const shadcnRoot = detectShadcnRoot(projectPath);
|
|
34036
|
+
if (!shadcnRoot) {
|
|
34037
|
+
throw new Error("Could not find components.json. " + "Run this command from a project with shadcn/ui configured, " + "or from a monorepo root with packages/ui/components.json.");
|
|
34038
|
+
}
|
|
34039
|
+
const isMonorepo = shadcnRoot !== projectPath;
|
|
34040
|
+
M2.info(`${source_default.bold("Migration:")} ${migration} \u2014 ${MIGRATION_DESCRIPTIONS[migration]}`);
|
|
34041
|
+
M2.info(`${source_default.bold("Location:")} ${isMonorepo ? "packages/ui (monorepo)" : "(project root)"}`);
|
|
34042
|
+
const installSuccess = await runBunInstall(projectPath);
|
|
34043
|
+
if (!installSuccess) {
|
|
34044
|
+
throw new Error("Failed to resolve dependencies. Fix the errors above and try again.");
|
|
34045
|
+
}
|
|
34046
|
+
const migrateSuccess = await runShadcnMigrate(shadcnRoot, migration);
|
|
34047
|
+
if (!migrateSuccess) {
|
|
34048
|
+
throw new Error(`Migration "${migration}" failed. Check the errors above.`);
|
|
34049
|
+
}
|
|
34050
|
+
showPostMigrationAdvice(migration, isMonorepo);
|
|
34051
|
+
}
|
|
34052
|
+
|
|
33800
34053
|
// src/commands/preset.ts
|
|
33801
34054
|
init_src();
|
|
33802
34055
|
init_boxen();
|
|
@@ -33910,12 +34163,13 @@ Examples:
|
|
|
33910
34163
|
$ bunkit create nextjs my-app Create a Next.js web application
|
|
33911
34164
|
$ bunkit add workspace Add a new workspace to monorepo
|
|
33912
34165
|
$ bunkit add component --all Browse and add shadcn/ui components
|
|
34166
|
+
$ bunkit migrate radix Migrate to unified radix-ui package
|
|
33913
34167
|
$ bunkit catalog add zod ^3.24.1 Add package to dependency catalog
|
|
33914
34168
|
$ bunkit preset list List all custom presets
|
|
33915
34169
|
|
|
33916
34170
|
For more information, visit: https://github.com/Arakiss/bunkit
|
|
33917
34171
|
`);
|
|
33918
|
-
program2.command("init").description("Create a new project with full customization options").alias("i").option("--name <name>", "Project name (kebab-case recommended, e.g., my-awesome-app)").option("--preset <preset>", "Project preset: minimal | nextjs | hono-api | bun-api | bun-fullstack | nextjs-monorepo | bun-monorepo | enterprise-monorepo").option("--database <database>", "Database option: postgres-drizzle | postgres-prisma | mysql-drizzle | mysql-prisma | supabase | supabase-drizzle | supabase-prisma | sqlite-drizzle | sqlite-prisma | none").option("--auth <auth>", "Authentication system: better-auth | nextauth | supabase | none").option("--redis", "Enable Redis cache/session store").option("--use-bun-secrets", "Use Bun.secrets API instead of .env files").option("--supabase-preset <preset>", "Supabase configuration preset: full-stack | auth-only | database-only | custom").option("--supabase-features <features>", "Comma-separated Supabase features: auth,storage,realtime,edge-functions,database").option("--code-quality <tool>", "Code quality tool: ultracite | biome").option("--ts-strictness <level>", "TypeScript strictness level: strict | moderate | loose").option("--ui-library <library>", "UI component library: shadcn | none").option("--css-framework <framework>", "CSS framework: tailwind | vanilla | css-modules").option("--shadcn-style <style>", "shadcn/ui style: radix-maia | radix-vega | radix-nova | radix-lyra | radix-mira | new-york | default").option("--shadcn-base <base>", "shadcn/ui component foundation: radix | base-ui").option("--shadcn-base-color <color>", "shadcn/ui base color theme: zinc | slate | stone | gray | neutral").option("--shadcn-icon-library <library>", "shadcn/ui icon library: phosphor | lucide | iconoir").option("--shadcn-menu-accent <accent>", "shadcn/ui menu accent style: subtle | bold").option("--shadcn-menu-color <color>", "shadcn/ui menu color: default | muted").option("--shadcn-radius <radius>", "shadcn/ui border radius (CSS value, e.g., 0.5rem, 0.625rem)").option("--testing <framework>", "Testing framework: bun-test | vitest | none").option("--docker", "Include Docker configuration files").option("--cicd", "Include GitHub Actions CI/CD workflow").option("--no-git", "Skip Git repository initialization").option("--no-install", "Skip dependency installation after project creation").option("--non-interactive", "Run in non-interactive mode (requires all options via flags)").option("--save-preset <name>", "Save current configuration as a custom preset").option("--load-preset <name>", "Load configuration from a custom preset").addHelpText("after", `
|
|
34172
|
+
program2.command("init").description("Create a new project with full customization options").alias("i").option("--name <name>", "Project name (kebab-case recommended, e.g., my-awesome-app)").option("--preset <preset>", "Project preset: minimal | nextjs | hono-api | bun-api | bun-fullstack | nextjs-monorepo | bun-monorepo | enterprise-monorepo").option("--database <database>", "Database option: postgres-drizzle | postgres-prisma | mysql-drizzle | mysql-prisma | supabase | supabase-drizzle | supabase-prisma | sqlite-drizzle | sqlite-prisma | none").option("--auth <auth>", "Authentication system: better-auth | nextauth | supabase | none").option("--redis", "Enable Redis cache/session store").option("--use-bun-secrets", "Use Bun.secrets API instead of .env files").option("--supabase-preset <preset>", "Supabase configuration preset: full-stack | auth-only | database-only | custom").option("--supabase-features <features>", "Comma-separated Supabase features: auth,storage,realtime,edge-functions,database").option("--code-quality <tool>", "Code quality tool: ultracite | biome").option("--ts-strictness <level>", "TypeScript strictness level: strict | moderate | loose").option("--ui-library <library>", "UI component library: shadcn | none").option("--css-framework <framework>", "CSS framework: tailwind | vanilla | css-modules").option("--shadcn-style <style>", "shadcn/ui style: radix-maia | radix-vega | radix-nova | radix-lyra | radix-mira | base-maia | base-vega | base-nova | base-lyra | base-mira | new-york | default").option("--shadcn-base <base>", "shadcn/ui component foundation: radix | base-ui").option("--shadcn-base-color <color>", "shadcn/ui base color theme: zinc | slate | stone | gray | neutral").option("--shadcn-icon-library <library>", "shadcn/ui icon library: phosphor | lucide | iconoir").option("--shadcn-menu-accent <accent>", "shadcn/ui menu accent style: subtle | bold").option("--shadcn-menu-color <color>", "shadcn/ui menu color: default | muted").option("--shadcn-radius <radius>", "shadcn/ui border radius (CSS value, e.g., 0.5rem, 0.625rem)").option("--shadcn-rtl", "Enable RTL (right-to-left) support for shadcn/ui components").option("--testing <framework>", "Testing framework: bun-test | vitest | none").option("--docker", "Include Docker configuration files").option("--cicd", "Include GitHub Actions CI/CD workflow").option("--no-git", "Skip Git repository initialization").option("--no-install", "Skip dependency installation after project creation").option("--non-interactive", "Run in non-interactive mode (requires all options via flags)").option("--save-preset <name>", "Save current configuration as a custom preset").option("--load-preset <name>", "Load configuration from a custom preset").addHelpText("after", `
|
|
33919
34173
|
Examples:
|
|
33920
34174
|
$ bunkit init Interactive project creation
|
|
33921
34175
|
$ bunkit init --name my-app --preset nextjs Quick web app creation
|
|
@@ -34035,6 +34289,28 @@ Features:
|
|
|
34035
34289
|
process.exit(1);
|
|
34036
34290
|
}
|
|
34037
34291
|
});
|
|
34292
|
+
program2.command("migrate").argument("[type]", "Migration type: radix | rtl | icons").description("Run shadcn/ui migrations (unified radix-ui, RTL, icon library)").addHelpText("after", `
|
|
34293
|
+
Examples:
|
|
34294
|
+
$ bunkit migrate Interactive migration selection
|
|
34295
|
+
$ bunkit migrate radix Migrate to unified radix-ui package
|
|
34296
|
+
$ bunkit migrate rtl Enable RTL support in components
|
|
34297
|
+
$ bunkit migrate icons Migrate icon library
|
|
34298
|
+
|
|
34299
|
+
Migrations:
|
|
34300
|
+
radix Replace @radix-ui/react-* packages with unified radix-ui
|
|
34301
|
+
rtl Add RTL class transforms to installed components
|
|
34302
|
+
icons Migrate between icon libraries (lucide, iconoir, phosphor)
|
|
34303
|
+
`).action(async (migrationType) => {
|
|
34304
|
+
showBanner(VERSION);
|
|
34305
|
+
try {
|
|
34306
|
+
await migrateCommand(migrationType);
|
|
34307
|
+
Se(import_picocolors7.default.green("Migration completed successfully!"));
|
|
34308
|
+
} catch (error) {
|
|
34309
|
+
M2.error(error.message);
|
|
34310
|
+
Se(import_picocolors7.default.red("Migration failed"));
|
|
34311
|
+
process.exit(1);
|
|
34312
|
+
}
|
|
34313
|
+
});
|
|
34038
34314
|
var catalogCmd = new Command("catalog").alias("cat").description("Manage dependency catalog for version synchronization").addHelpText("after", `
|
|
34039
34315
|
Subcommands:
|
|
34040
34316
|
add <package> [version] Add package to catalog
|