create-kofi-stack 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/index.js +187 -32
- package/package.json +1 -1
package/LICENSE
CHANGED
package/dist/index.js
CHANGED
|
@@ -97,6 +97,18 @@ async function promptIncludeDocs(defaultValue) {
|
|
|
97
97
|
|
|
98
98
|
// src/prompts/shadcn.ts
|
|
99
99
|
import * as p2 from "@clack/prompts";
|
|
100
|
+
var colorPresets = {
|
|
101
|
+
blue: { primary: "221.2 83.2% 53.3%", secondary: "210 40% 96.1%", accent: "210 40% 96.1%" },
|
|
102
|
+
green: { primary: "142.1 76.2% 36.3%", secondary: "138 76% 97%", accent: "142.1 70.6% 45.3%" },
|
|
103
|
+
orange: { primary: "24.6 95% 53.1%", secondary: "30 80% 96%", accent: "20.5 90.2% 48.2%" },
|
|
104
|
+
red: { primary: "0 72.2% 50.6%", secondary: "0 85% 97%", accent: "0 84.2% 60.2%" },
|
|
105
|
+
violet: { primary: "262.1 83.3% 57.8%", secondary: "260 60% 96%", accent: "263.4 70% 50.4%" },
|
|
106
|
+
yellow: { primary: "47.9 95.8% 53.1%", secondary: "48 100% 96%", accent: "45.4 93.4% 47.5%" },
|
|
107
|
+
teal: { primary: "173 80% 40%", secondary: "166 76% 97%", accent: "172 66% 50.4%" },
|
|
108
|
+
rose: { primary: "346.8 77.2% 49.8%", secondary: "340 80% 97%", accent: "346.8 77.2% 49.8%" },
|
|
109
|
+
indigo: { primary: "238.7 83.5% 66.7%", secondary: "226 70% 97%", accent: "243.4 75.4% 58.6%" },
|
|
110
|
+
cyan: { primary: "189 94% 43%", secondary: "185 96% 97%", accent: "188 94.5% 42.7%" }
|
|
111
|
+
};
|
|
100
112
|
async function promptComponentLibrary(defaultValue) {
|
|
101
113
|
const library = await p2.select({
|
|
102
114
|
message: "Component library:",
|
|
@@ -194,6 +206,96 @@ async function promptIconLibrary(defaultValue) {
|
|
|
194
206
|
}
|
|
195
207
|
return iconLibrary;
|
|
196
208
|
}
|
|
209
|
+
async function promptPrimaryColor(defaultValue) {
|
|
210
|
+
const color = await p2.select({
|
|
211
|
+
message: "Primary brand color:",
|
|
212
|
+
options: [
|
|
213
|
+
{ value: "blue", label: "Blue", hint: "Professional, trustworthy" },
|
|
214
|
+
{ value: "green", label: "Green", hint: "Growth, success" },
|
|
215
|
+
{ value: "violet", label: "Violet", hint: "Creative, premium" },
|
|
216
|
+
{ value: "orange", label: "Orange", hint: "Energetic, friendly" },
|
|
217
|
+
{ value: "red", label: "Red", hint: "Bold, urgent" },
|
|
218
|
+
{ value: "teal", label: "Teal", hint: "Calm, modern" },
|
|
219
|
+
{ value: "rose", label: "Rose", hint: "Warm, approachable" },
|
|
220
|
+
{ value: "indigo", label: "Indigo", hint: "Deep, sophisticated" },
|
|
221
|
+
{ value: "cyan", label: "Cyan", hint: "Fresh, tech-forward" }
|
|
222
|
+
],
|
|
223
|
+
initialValue: defaultValue ?? "blue"
|
|
224
|
+
});
|
|
225
|
+
if (p2.isCancel(color)) {
|
|
226
|
+
throw new Error("Operation cancelled");
|
|
227
|
+
}
|
|
228
|
+
return colorPresets[color].primary;
|
|
229
|
+
}
|
|
230
|
+
async function promptHeadingFont(defaultValue) {
|
|
231
|
+
const font = await p2.select({
|
|
232
|
+
message: "Heading font:",
|
|
233
|
+
options: [
|
|
234
|
+
{ value: "dm-sans", label: "DM Sans", hint: "Modern, geometric" },
|
|
235
|
+
{ value: "inter", label: "Inter", hint: "Clean, versatile" },
|
|
236
|
+
{ value: "geist", label: "Geist", hint: "Vercel's modern font" },
|
|
237
|
+
{ value: "plus-jakarta", label: "Plus Jakarta Sans", hint: "Friendly, readable" },
|
|
238
|
+
{ value: "outfit", label: "Outfit", hint: "Contemporary, rounded" },
|
|
239
|
+
{ value: "space-grotesk", label: "Space Grotesk", hint: "Technical, distinctive" }
|
|
240
|
+
],
|
|
241
|
+
initialValue: defaultValue ?? "dm-sans"
|
|
242
|
+
});
|
|
243
|
+
if (p2.isCancel(font)) {
|
|
244
|
+
throw new Error("Operation cancelled");
|
|
245
|
+
}
|
|
246
|
+
return font;
|
|
247
|
+
}
|
|
248
|
+
async function promptBodyFont(defaultValue) {
|
|
249
|
+
const font = await p2.select({
|
|
250
|
+
message: "Body font:",
|
|
251
|
+
options: [
|
|
252
|
+
{ value: "inter", label: "Inter", hint: "Optimized for screens" },
|
|
253
|
+
{ value: "dm-sans", label: "DM Sans", hint: "Modern, geometric" },
|
|
254
|
+
{ value: "geist", label: "Geist", hint: "Vercel's modern font" },
|
|
255
|
+
{ value: "plus-jakarta", label: "Plus Jakarta Sans", hint: "Friendly, readable" },
|
|
256
|
+
{ value: "outfit", label: "Outfit", hint: "Contemporary, rounded" },
|
|
257
|
+
{ value: "space-grotesk", label: "Space Grotesk", hint: "Technical, distinctive" }
|
|
258
|
+
],
|
|
259
|
+
initialValue: defaultValue ?? "inter"
|
|
260
|
+
});
|
|
261
|
+
if (p2.isCancel(font)) {
|
|
262
|
+
throw new Error("Operation cancelled");
|
|
263
|
+
}
|
|
264
|
+
return font;
|
|
265
|
+
}
|
|
266
|
+
async function promptBorderRadius(defaultValue) {
|
|
267
|
+
const radius = await p2.select({
|
|
268
|
+
message: "Border radius:",
|
|
269
|
+
options: [
|
|
270
|
+
{ value: "none", label: "None", hint: "0px - Sharp edges" },
|
|
271
|
+
{ value: "sm", label: "Small", hint: "4px - Subtle rounding" },
|
|
272
|
+
{ value: "md", label: "Medium", hint: "8px - Balanced (default)" },
|
|
273
|
+
{ value: "lg", label: "Large", hint: "12px - More rounded" },
|
|
274
|
+
{ value: "xl", label: "Extra Large", hint: "16px - Very rounded" },
|
|
275
|
+
{ value: "full", label: "Full", hint: "Pill-shaped buttons" }
|
|
276
|
+
],
|
|
277
|
+
initialValue: defaultValue ?? "md"
|
|
278
|
+
});
|
|
279
|
+
if (p2.isCancel(radius)) {
|
|
280
|
+
throw new Error("Operation cancelled");
|
|
281
|
+
}
|
|
282
|
+
return radius;
|
|
283
|
+
}
|
|
284
|
+
async function promptSpacingScale(defaultValue) {
|
|
285
|
+
const spacing = await p2.select({
|
|
286
|
+
message: "Spacing scale:",
|
|
287
|
+
options: [
|
|
288
|
+
{ value: "compact", label: "Compact", hint: "Tighter spacing, denser UI" },
|
|
289
|
+
{ value: "default", label: "Default", hint: "Standard spacing" },
|
|
290
|
+
{ value: "relaxed", label: "Relaxed", hint: "More breathing room" }
|
|
291
|
+
],
|
|
292
|
+
initialValue: defaultValue ?? "default"
|
|
293
|
+
});
|
|
294
|
+
if (p2.isCancel(spacing)) {
|
|
295
|
+
throw new Error("Operation cancelled");
|
|
296
|
+
}
|
|
297
|
+
return spacing;
|
|
298
|
+
}
|
|
197
299
|
async function promptShadcnConfig(defaults) {
|
|
198
300
|
if (defaults?.componentLibrary && defaults?.styleVariant && defaults?.baseColor && defaults?.themeColor && defaults?.menuAccent && defaults?.iconLibrary) {
|
|
199
301
|
return {
|
|
@@ -213,6 +315,38 @@ async function promptShadcnConfig(defaults) {
|
|
|
213
315
|
const iconLibrary = defaults?.iconLibrary ?? await promptIconLibrary();
|
|
214
316
|
return { componentLibrary, styleVariant, baseColor, themeColor, menuAccent, iconLibrary };
|
|
215
317
|
}
|
|
318
|
+
async function promptDesignSystemConfig(defaults, themeColor) {
|
|
319
|
+
if (defaults?.primaryColor && defaults?.secondaryColor && defaults?.accentColor && defaults?.headingFont && defaults?.bodyFont && defaults?.borderRadius && defaults?.spacingScale) {
|
|
320
|
+
return {
|
|
321
|
+
primaryColor: defaults.primaryColor,
|
|
322
|
+
secondaryColor: defaults.secondaryColor,
|
|
323
|
+
accentColor: defaults.accentColor,
|
|
324
|
+
headingFont: defaults.headingFont,
|
|
325
|
+
bodyFont: defaults.bodyFont,
|
|
326
|
+
borderRadius: defaults.borderRadius,
|
|
327
|
+
spacingScale: defaults.spacingScale
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const defaultColorKey = themeColor ?? "blue";
|
|
331
|
+
const primaryColor = defaults?.primaryColor ?? await promptPrimaryColor(defaultColorKey);
|
|
332
|
+
const colorKey = Object.entries(colorPresets).find(([_, v]) => v.primary === primaryColor)?.[0] ?? "blue";
|
|
333
|
+
const colors = colorPresets[colorKey];
|
|
334
|
+
const secondaryColor = defaults?.secondaryColor ?? colors.secondary;
|
|
335
|
+
const accentColor = defaults?.accentColor ?? colors.accent;
|
|
336
|
+
const headingFont = defaults?.headingFont ?? await promptHeadingFont();
|
|
337
|
+
const bodyFont = defaults?.bodyFont ?? await promptBodyFont();
|
|
338
|
+
const borderRadius = defaults?.borderRadius ?? await promptBorderRadius();
|
|
339
|
+
const spacingScale = defaults?.spacingScale ?? await promptSpacingScale();
|
|
340
|
+
return {
|
|
341
|
+
primaryColor,
|
|
342
|
+
secondaryColor,
|
|
343
|
+
accentColor,
|
|
344
|
+
headingFont,
|
|
345
|
+
bodyFont,
|
|
346
|
+
borderRadius,
|
|
347
|
+
spacingScale
|
|
348
|
+
};
|
|
349
|
+
}
|
|
216
350
|
|
|
217
351
|
// src/prompts/auth.ts
|
|
218
352
|
import * as p3 from "@clack/prompts";
|
|
@@ -348,6 +482,11 @@ function parseOptions(options) {
|
|
|
348
482
|
themeColor: options.themeColor,
|
|
349
483
|
accent: options.accent,
|
|
350
484
|
iconLibrary: options.iconLibrary,
|
|
485
|
+
primaryColor: options.primaryColor,
|
|
486
|
+
headingFont: options.headingFont,
|
|
487
|
+
bodyFont: options.bodyFont,
|
|
488
|
+
borderRadius: options.borderRadius,
|
|
489
|
+
spacingScale: options.spacingScale,
|
|
351
490
|
authProviders: options.authProviders,
|
|
352
491
|
organizations: options.organizations,
|
|
353
492
|
yes: options.yes,
|
|
@@ -391,6 +530,34 @@ async function runPrompts(projectName, rawOptions) {
|
|
|
391
530
|
menuAccent: options.accent,
|
|
392
531
|
iconLibrary: options.iconLibrary
|
|
393
532
|
});
|
|
533
|
+
let designSystem;
|
|
534
|
+
if (structure === "monorepo") {
|
|
535
|
+
let primaryColorHsl = options.primaryColor;
|
|
536
|
+
if (primaryColorHsl && colorPresets[primaryColorHsl]) {
|
|
537
|
+
primaryColorHsl = colorPresets[primaryColorHsl].primary;
|
|
538
|
+
}
|
|
539
|
+
designSystem = await promptDesignSystemConfig(
|
|
540
|
+
{
|
|
541
|
+
primaryColor: primaryColorHsl,
|
|
542
|
+
headingFont: options.headingFont,
|
|
543
|
+
bodyFont: options.bodyFont,
|
|
544
|
+
borderRadius: options.borderRadius,
|
|
545
|
+
spacingScale: options.spacingScale
|
|
546
|
+
},
|
|
547
|
+
shadcn.themeColor
|
|
548
|
+
);
|
|
549
|
+
} else {
|
|
550
|
+
const colors = colorPresets[shadcn.themeColor] || colorPresets.blue;
|
|
551
|
+
designSystem = {
|
|
552
|
+
primaryColor: colors.primary,
|
|
553
|
+
secondaryColor: colors.secondary,
|
|
554
|
+
accentColor: colors.accent,
|
|
555
|
+
headingFont: "dm-sans",
|
|
556
|
+
bodyFont: "inter",
|
|
557
|
+
borderRadius: "md",
|
|
558
|
+
spacingScale: "default"
|
|
559
|
+
};
|
|
560
|
+
}
|
|
394
561
|
const auth = await promptAuthConfig({
|
|
395
562
|
providers: options.authProviders !== void 0 ? options.authProviders ? options.authProviders.split(",") : [] : void 0,
|
|
396
563
|
organizations: options.organizations
|
|
@@ -408,6 +575,7 @@ async function runPrompts(projectName, rawOptions) {
|
|
|
408
575
|
marketingSite,
|
|
409
576
|
includeDocs,
|
|
410
577
|
shadcn,
|
|
578
|
+
designSystem,
|
|
411
579
|
auth,
|
|
412
580
|
integrations,
|
|
413
581
|
targetDir
|
|
@@ -433,8 +601,19 @@ function getIconLibraryDisplayName(iconLibrary) {
|
|
|
433
601
|
};
|
|
434
602
|
return names[iconLibrary];
|
|
435
603
|
}
|
|
604
|
+
function getFontDisplayName(font) {
|
|
605
|
+
const names = {
|
|
606
|
+
"inter": "Inter",
|
|
607
|
+
"dm-sans": "DM Sans",
|
|
608
|
+
"geist": "Geist",
|
|
609
|
+
"plus-jakarta": "Plus Jakarta Sans",
|
|
610
|
+
"outfit": "Outfit",
|
|
611
|
+
"space-grotesk": "Space Grotesk"
|
|
612
|
+
};
|
|
613
|
+
return names[font];
|
|
614
|
+
}
|
|
436
615
|
function showConfigSummary(config) {
|
|
437
|
-
const apps = ["web"];
|
|
616
|
+
const apps = ["web", "design-system"];
|
|
438
617
|
if (config.structure === "monorepo") {
|
|
439
618
|
if (config.marketingSite !== "none") {
|
|
440
619
|
apps.push(`marketing (${config.marketingSite})`);
|
|
@@ -474,12 +653,13 @@ ${config.structure === "monorepo" ? `${pc.bold("Apps:")} ${apps.join(", ")}
|
|
|
474
653
|
` : ""}${pc.bold("Auth:")} ${authProviders.join(", ")}${config.auth.organizations ? " + Organizations" : ""}
|
|
475
654
|
${pc.bold("UI:")} ${getStyleDisplayName(config)} / ${config.shadcn.themeColor} / ${config.shadcn.menuAccent}
|
|
476
655
|
${pc.bold("Icons:")} ${getIconLibraryDisplayName(config.shadcn.iconLibrary)}
|
|
656
|
+
${pc.bold("Typography:")} ${getFontDisplayName(config.designSystem.headingFont)} / ${getFontDisplayName(config.designSystem.bodyFont)}
|
|
477
657
|
${extras.length > 0 ? `${pc.bold("Extras:")} ${extras.join(", ")}` : ""}`,
|
|
478
658
|
"Scaffolding project:"
|
|
479
659
|
);
|
|
480
660
|
}
|
|
481
661
|
async function showConfirmation(config) {
|
|
482
|
-
const apps = ["web"];
|
|
662
|
+
const apps = ["web", "design-system"];
|
|
483
663
|
if (config.structure === "monorepo") {
|
|
484
664
|
if (config.marketingSite !== "none") {
|
|
485
665
|
apps.push(`marketing (${config.marketingSite})`);
|
|
@@ -519,6 +699,7 @@ ${config.structure === "monorepo" ? `${pc.bold("Apps:")} ${apps.join(", ")}
|
|
|
519
699
|
` : ""}${pc.bold("Auth:")} ${authProviders.join(", ")}${config.auth.organizations ? " + Organizations" : ""}
|
|
520
700
|
${pc.bold("UI:")} ${getStyleDisplayName(config)} / ${config.shadcn.themeColor} / ${config.shadcn.menuAccent}
|
|
521
701
|
${pc.bold("Icons:")} ${getIconLibraryDisplayName(config.shadcn.iconLibrary)}
|
|
702
|
+
${pc.bold("Typography:")} ${getFontDisplayName(config.designSystem.headingFont)} / ${getFontDisplayName(config.designSystem.bodyFont)}
|
|
522
703
|
${extras.length > 0 ? `${pc.bold("Extras:")} ${extras.join(", ")}` : ""}`,
|
|
523
704
|
"Ready to scaffold your project:"
|
|
524
705
|
);
|
|
@@ -1812,7 +1993,7 @@ async function generateConvexPackageJson(convexDir) {
|
|
|
1812
1993
|
types: "./convex/index.ts",
|
|
1813
1994
|
dependencies: {
|
|
1814
1995
|
convex: "^1.17.0",
|
|
1815
|
-
"@convex-dev/better-auth": "^0.
|
|
1996
|
+
"@convex-dev/better-auth": "^0.10.0"
|
|
1816
1997
|
},
|
|
1817
1998
|
devDependencies: {
|
|
1818
1999
|
typescript: "^5.0.0"
|
|
@@ -2929,33 +3110,6 @@ async function generateSharedConfigs(targetDir) {
|
|
|
2929
3110
|
path14.join(targetDir, "packages/config-typescript/package.json"),
|
|
2930
3111
|
tsConfigPackage
|
|
2931
3112
|
);
|
|
2932
|
-
await ensureDir(path14.join(targetDir, "packages/config-tailwind"));
|
|
2933
|
-
const tailwindConfig = `import type { Config } from 'tailwindcss'
|
|
2934
|
-
|
|
2935
|
-
export default {
|
|
2936
|
-
content: [
|
|
2937
|
-
'./src/**/*.{js,ts,jsx,tsx,mdx}',
|
|
2938
|
-
'../../packages/ui/src/**/*.{js,ts,jsx,tsx}',
|
|
2939
|
-
],
|
|
2940
|
-
} satisfies Config
|
|
2941
|
-
`;
|
|
2942
|
-
const tailwindPackage = {
|
|
2943
|
-
name: "@repo/config-tailwind",
|
|
2944
|
-
version: "0.1.0",
|
|
2945
|
-
private: true,
|
|
2946
|
-
main: "tailwind.config.ts",
|
|
2947
|
-
devDependencies: {
|
|
2948
|
-
tailwindcss: "^4.0.0"
|
|
2949
|
-
}
|
|
2950
|
-
};
|
|
2951
|
-
await writeFile(
|
|
2952
|
-
path14.join(targetDir, "packages/config-tailwind/tailwind.config.ts"),
|
|
2953
|
-
tailwindConfig
|
|
2954
|
-
);
|
|
2955
|
-
await writeJSON(
|
|
2956
|
-
path14.join(targetDir, "packages/config-tailwind/package.json"),
|
|
2957
|
-
tailwindPackage
|
|
2958
|
-
);
|
|
2959
3113
|
await ensureDir(path14.join(targetDir, "packages/config-biome"));
|
|
2960
3114
|
const biomeConfigPackage = {
|
|
2961
3115
|
name: "@repo/config-biome",
|
|
@@ -3027,9 +3181,10 @@ async function generateUIPackage(config, targetDir) {
|
|
|
3027
3181
|
include: ["src/**/*"]
|
|
3028
3182
|
};
|
|
3029
3183
|
await writeJSON(path14.join(uiDir, "tsconfig.json"), tsConfig);
|
|
3184
|
+
const style = `${config.shadcn.componentLibrary}-${config.shadcn.styleVariant}`;
|
|
3030
3185
|
const componentsJson = {
|
|
3031
3186
|
$schema: "https://ui.shadcn.com/schema.json",
|
|
3032
|
-
style
|
|
3187
|
+
style,
|
|
3033
3188
|
rsc: false,
|
|
3034
3189
|
tsx: true,
|
|
3035
3190
|
tailwind: {
|
|
@@ -3038,7 +3193,7 @@ async function generateUIPackage(config, targetDir) {
|
|
|
3038
3193
|
baseColor: config.shadcn.baseColor,
|
|
3039
3194
|
cssVariables: true
|
|
3040
3195
|
},
|
|
3041
|
-
iconLibrary:
|
|
3196
|
+
iconLibrary: config.shadcn.iconLibrary,
|
|
3042
3197
|
aliases: {
|
|
3043
3198
|
components: "@/components",
|
|
3044
3199
|
utils: "@/lib/utils",
|