create-kofi-stack 1.2.18 → 1.2.19
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 +59 -605
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -80,16 +80,6 @@ async function promptMarketingSite(defaultValue) {
|
|
|
80
80
|
}
|
|
81
81
|
return marketing;
|
|
82
82
|
}
|
|
83
|
-
async function promptIncludeDocs(defaultValue) {
|
|
84
|
-
const includeDocs = await p.confirm({
|
|
85
|
-
message: "Include documentation site? (Fumadocs)",
|
|
86
|
-
initialValue: defaultValue ?? true
|
|
87
|
-
});
|
|
88
|
-
if (p.isCancel(includeDocs)) {
|
|
89
|
-
throw new Error("Operation cancelled");
|
|
90
|
-
}
|
|
91
|
-
return includeDocs;
|
|
92
|
-
}
|
|
93
83
|
|
|
94
84
|
// src/prompts/shadcn.ts
|
|
95
85
|
import * as p2 from "@clack/prompts";
|
|
@@ -471,7 +461,6 @@ function parseOptions(options) {
|
|
|
471
461
|
monorepo: options.monorepo,
|
|
472
462
|
single: options.single,
|
|
473
463
|
marketing: options.marketing,
|
|
474
|
-
docs: options.docs,
|
|
475
464
|
componentLibrary: options.componentLibrary,
|
|
476
465
|
style: options.style,
|
|
477
466
|
baseColor: options.baseColor,
|
|
@@ -505,18 +494,12 @@ async function runPrompts(projectName, rawOptions) {
|
|
|
505
494
|
structure = await promptProjectStructure();
|
|
506
495
|
}
|
|
507
496
|
let marketingSite = "none";
|
|
508
|
-
let includeDocs = false;
|
|
509
497
|
if (structure === "monorepo") {
|
|
510
498
|
if (options.marketing) {
|
|
511
499
|
marketingSite = options.marketing;
|
|
512
500
|
} else {
|
|
513
501
|
marketingSite = await promptMarketingSite();
|
|
514
502
|
}
|
|
515
|
-
if (options.docs !== void 0) {
|
|
516
|
-
includeDocs = options.docs;
|
|
517
|
-
} else {
|
|
518
|
-
includeDocs = await promptIncludeDocs();
|
|
519
|
-
}
|
|
520
503
|
}
|
|
521
504
|
const shadcn = await promptShadcnConfig({
|
|
522
505
|
componentLibrary: options.componentLibrary,
|
|
@@ -569,7 +552,6 @@ async function runPrompts(projectName, rawOptions) {
|
|
|
569
552
|
name,
|
|
570
553
|
structure,
|
|
571
554
|
marketingSite,
|
|
572
|
-
includeDocs,
|
|
573
555
|
shadcn,
|
|
574
556
|
designSystem,
|
|
575
557
|
auth,
|
|
@@ -614,9 +596,6 @@ function showConfigSummary(config) {
|
|
|
614
596
|
if (config.marketingSite !== "none") {
|
|
615
597
|
apps.push(`marketing (${config.marketingSite})`);
|
|
616
598
|
}
|
|
617
|
-
if (config.includeDocs) {
|
|
618
|
-
apps.push("docs");
|
|
619
|
-
}
|
|
620
599
|
}
|
|
621
600
|
const authProviders = ["Email/Password", "Google", ...config.auth.providers];
|
|
622
601
|
const extras = [];
|
|
@@ -660,9 +639,6 @@ async function showConfirmation(config) {
|
|
|
660
639
|
if (config.marketingSite !== "none") {
|
|
661
640
|
apps.push(`marketing (${config.marketingSite})`);
|
|
662
641
|
}
|
|
663
|
-
if (config.includeDocs) {
|
|
664
|
-
apps.push("docs");
|
|
665
|
-
}
|
|
666
642
|
}
|
|
667
643
|
const authProviders = ["Email/Password", "Google", ...config.auth.providers];
|
|
668
644
|
const extras = [];
|
|
@@ -709,7 +685,7 @@ ${extras.length > 0 ? `${pc.bold("Extras:")} ${extras.join(", ")}` : ""}`,
|
|
|
709
685
|
}
|
|
710
686
|
|
|
711
687
|
// src/generators/index.ts
|
|
712
|
-
import
|
|
688
|
+
import path18 from "path";
|
|
713
689
|
import * as p7 from "@clack/prompts";
|
|
714
690
|
import pc3 from "picocolors";
|
|
715
691
|
import ora from "ora";
|
|
@@ -2769,19 +2745,18 @@ async function generateRateLimiting(config, appDir) {
|
|
|
2769
2745
|
}
|
|
2770
2746
|
}
|
|
2771
2747
|
async function generateArcjet(appDir) {
|
|
2772
|
-
const content = `import arcjet, { shield,
|
|
2748
|
+
const content = `import arcjet, { shield, fixedWindow, detectBot } from '@arcjet/next'
|
|
2773
2749
|
import { env } from '@/env'
|
|
2774
2750
|
|
|
2775
2751
|
export const aj = arcjet({
|
|
2776
|
-
key: env.ARCJET_KEY
|
|
2777
|
-
characteristics: ['ip.src'],
|
|
2752
|
+
key: env.ARCJET_KEY!,
|
|
2778
2753
|
rules: [
|
|
2779
2754
|
// Shield protects against common attacks
|
|
2780
2755
|
shield({ mode: 'LIVE' }),
|
|
2781
|
-
// Rate limit API requests
|
|
2782
|
-
|
|
2756
|
+
// Rate limit API requests - 100 requests per minute
|
|
2757
|
+
fixedWindow({
|
|
2783
2758
|
mode: 'LIVE',
|
|
2784
|
-
|
|
2759
|
+
window: '1m',
|
|
2785
2760
|
max: 100,
|
|
2786
2761
|
}),
|
|
2787
2762
|
// Bot detection
|
|
@@ -4270,517 +4245,8 @@ S3_ENDPOINT="https://[PROJECT].supabase.co/storage/v1/s3"
|
|
|
4270
4245
|
await writeFile(path15.join(marketingDir, ".env.local"), envContent);
|
|
4271
4246
|
}
|
|
4272
4247
|
|
|
4273
|
-
// src/generators/fumadocs.ts
|
|
4274
|
-
import path16 from "path";
|
|
4275
|
-
async function generateFumadocs(config, docsDir) {
|
|
4276
|
-
await ensureDir(path16.join(docsDir, "content/docs"));
|
|
4277
|
-
await ensureDir(path16.join(docsDir, "src/app/docs/[[...slug]]"));
|
|
4278
|
-
await ensureDir(path16.join(docsDir, "src/lib"));
|
|
4279
|
-
await generateFumadocsPackageJson(docsDir);
|
|
4280
|
-
await generateFumadocsNextConfig(docsDir);
|
|
4281
|
-
await generateFumadocsTsConfig(docsDir);
|
|
4282
|
-
await generateFumadocsSource(docsDir);
|
|
4283
|
-
await generateFumadocsAppFiles(config, docsDir);
|
|
4284
|
-
await generateFumadocsContent(config, docsDir);
|
|
4285
|
-
}
|
|
4286
|
-
async function generateFumadocsPackageJson(docsDir) {
|
|
4287
|
-
const packageJson2 = {
|
|
4288
|
-
name: "@repo/docs",
|
|
4289
|
-
version: "0.1.0",
|
|
4290
|
-
private: true,
|
|
4291
|
-
scripts: {
|
|
4292
|
-
dev: "next dev --turbopack -p 3002",
|
|
4293
|
-
build: "next build",
|
|
4294
|
-
start: "next start",
|
|
4295
|
-
lint: "biome check .",
|
|
4296
|
-
"lint:fix": "biome check --write .",
|
|
4297
|
-
typecheck: "tsc --noEmit"
|
|
4298
|
-
},
|
|
4299
|
-
dependencies: {
|
|
4300
|
-
next: "^16.0.0",
|
|
4301
|
-
react: "^19.0.0",
|
|
4302
|
-
"react-dom": "^19.0.0",
|
|
4303
|
-
"fumadocs-core": "^16.0.0",
|
|
4304
|
-
"fumadocs-mdx": "^14.0.0",
|
|
4305
|
-
"fumadocs-ui": "^16.0.0",
|
|
4306
|
-
"@repo/ui": "workspace:*"
|
|
4307
|
-
},
|
|
4308
|
-
devDependencies: {
|
|
4309
|
-
"@repo/config-typescript": "workspace:*",
|
|
4310
|
-
"@types/node": "^20.0.0",
|
|
4311
|
-
"@types/react": "^19.0.0",
|
|
4312
|
-
"@types/react-dom": "^19.0.0",
|
|
4313
|
-
"@types/mdx": "^2.0.0",
|
|
4314
|
-
tailwindcss: "^4.0.0",
|
|
4315
|
-
"@tailwindcss/postcss": "^4.0.0",
|
|
4316
|
-
postcss: "^8.4.0",
|
|
4317
|
-
typescript: "^5.0.0"
|
|
4318
|
-
}
|
|
4319
|
-
};
|
|
4320
|
-
await writeJSON(path16.join(docsDir, "package.json"), packageJson2);
|
|
4321
|
-
}
|
|
4322
|
-
async function generateFumadocsNextConfig(docsDir) {
|
|
4323
|
-
const content = `import { createMDX } from 'fumadocs-mdx/next'
|
|
4324
|
-
import type { NextConfig } from 'next'
|
|
4325
|
-
|
|
4326
|
-
const withMDX = createMDX()
|
|
4327
|
-
|
|
4328
|
-
const config: NextConfig = {
|
|
4329
|
-
reactStrictMode: true,
|
|
4330
|
-
transpilePackages: ['@repo/ui'],
|
|
4331
|
-
}
|
|
4332
|
-
|
|
4333
|
-
export default withMDX(config)
|
|
4334
|
-
`;
|
|
4335
|
-
await writeFile(path16.join(docsDir, "next.config.ts"), content);
|
|
4336
|
-
}
|
|
4337
|
-
async function generateFumadocsTsConfig(docsDir) {
|
|
4338
|
-
const tsConfig = {
|
|
4339
|
-
compilerOptions: {
|
|
4340
|
-
target: "ES2020",
|
|
4341
|
-
lib: ["dom", "dom.iterable", "esnext"],
|
|
4342
|
-
allowJs: true,
|
|
4343
|
-
skipLibCheck: true,
|
|
4344
|
-
strict: true,
|
|
4345
|
-
noEmit: true,
|
|
4346
|
-
esModuleInterop: true,
|
|
4347
|
-
module: "esnext",
|
|
4348
|
-
moduleResolution: "bundler",
|
|
4349
|
-
resolveJsonModule: true,
|
|
4350
|
-
isolatedModules: true,
|
|
4351
|
-
jsx: "preserve",
|
|
4352
|
-
incremental: true,
|
|
4353
|
-
plugins: [{ name: "next" }],
|
|
4354
|
-
paths: {
|
|
4355
|
-
"@/*": ["./src/*"],
|
|
4356
|
-
"fumadocs-mdx:collections/*": ["./.source/*"]
|
|
4357
|
-
}
|
|
4358
|
-
},
|
|
4359
|
-
include: [
|
|
4360
|
-
"next-env.d.ts",
|
|
4361
|
-
"**/*.ts",
|
|
4362
|
-
"**/*.tsx",
|
|
4363
|
-
"**/*.mdx",
|
|
4364
|
-
".next/types/**/*.ts",
|
|
4365
|
-
".source/**/*.ts"
|
|
4366
|
-
],
|
|
4367
|
-
exclude: ["node_modules"]
|
|
4368
|
-
};
|
|
4369
|
-
await writeJSON(path16.join(docsDir, "tsconfig.json"), tsConfig);
|
|
4370
|
-
}
|
|
4371
|
-
async function generateFumadocsSource(docsDir) {
|
|
4372
|
-
const content = `import { docs } from 'fumadocs-mdx:collections/server'
|
|
4373
|
-
import { loader } from 'fumadocs-core/source'
|
|
4374
|
-
|
|
4375
|
-
export const source = loader({
|
|
4376
|
-
baseUrl: '/docs',
|
|
4377
|
-
source: docs.toFumadocsSource(),
|
|
4378
|
-
})
|
|
4379
|
-
`;
|
|
4380
|
-
await writeFile(path16.join(docsDir, "src/lib/source.ts"), content);
|
|
4381
|
-
}
|
|
4382
|
-
async function generateFumadocsAppFiles(config, docsDir) {
|
|
4383
|
-
const layoutContent = `import { RootProvider } from 'fumadocs-ui/provider/next'
|
|
4384
|
-
import { Inter } from 'next/font/google'
|
|
4385
|
-
import type { Metadata } from 'next'
|
|
4386
|
-
import type { ReactNode } from 'react'
|
|
4387
|
-
import './global.css'
|
|
4388
|
-
|
|
4389
|
-
const inter = Inter({
|
|
4390
|
-
subsets: ['latin'],
|
|
4391
|
-
})
|
|
4392
|
-
|
|
4393
|
-
export const metadata: Metadata = {
|
|
4394
|
-
title: {
|
|
4395
|
-
template: '%s | ${config.name} Docs',
|
|
4396
|
-
default: '${config.name} Documentation',
|
|
4397
|
-
},
|
|
4398
|
-
description: 'Documentation for ${config.name}',
|
|
4399
|
-
}
|
|
4400
|
-
|
|
4401
|
-
export default function RootLayout({ children }: { children: ReactNode }) {
|
|
4402
|
-
return (
|
|
4403
|
-
<html lang="en" className={inter.className} suppressHydrationWarning>
|
|
4404
|
-
<body className="flex flex-col min-h-screen">
|
|
4405
|
-
<RootProvider>{children}</RootProvider>
|
|
4406
|
-
</body>
|
|
4407
|
-
</html>
|
|
4408
|
-
)
|
|
4409
|
-
}
|
|
4410
|
-
`;
|
|
4411
|
-
await writeFile(path16.join(docsDir, "src/app/layout.tsx"), layoutContent);
|
|
4412
|
-
const docsLayoutContent = `import { DocsLayout } from 'fumadocs-ui/layouts/docs'
|
|
4413
|
-
import type { ReactNode } from 'react'
|
|
4414
|
-
import { source } from '@/lib/source'
|
|
4415
|
-
|
|
4416
|
-
export default function Layout({ children }: { children: ReactNode }) {
|
|
4417
|
-
return (
|
|
4418
|
-
<DocsLayout
|
|
4419
|
-
tree={source.pageTree}
|
|
4420
|
-
nav={{
|
|
4421
|
-
title: '${config.name} Docs',
|
|
4422
|
-
}}
|
|
4423
|
-
>
|
|
4424
|
-
{children}
|
|
4425
|
-
</DocsLayout>
|
|
4426
|
-
)
|
|
4427
|
-
}
|
|
4428
|
-
`;
|
|
4429
|
-
await writeFile(
|
|
4430
|
-
path16.join(docsDir, "src/app/docs/layout.tsx"),
|
|
4431
|
-
docsLayoutContent
|
|
4432
|
-
);
|
|
4433
|
-
const docsPageContent = `import { source } from '@/lib/source'
|
|
4434
|
-
import {
|
|
4435
|
-
DocsPage,
|
|
4436
|
-
DocsBody,
|
|
4437
|
-
DocsDescription,
|
|
4438
|
-
DocsTitle,
|
|
4439
|
-
} from 'fumadocs-ui/page'
|
|
4440
|
-
import { notFound } from 'next/navigation'
|
|
4441
|
-
import defaultMdxComponents from 'fumadocs-ui/mdx'
|
|
4442
|
-
|
|
4443
|
-
export default async function Page(props: {
|
|
4444
|
-
params: Promise<{ slug?: string[] }>
|
|
4445
|
-
}) {
|
|
4446
|
-
const params = await props.params
|
|
4447
|
-
const page = source.getPage(params.slug)
|
|
4448
|
-
if (!page) notFound()
|
|
4449
|
-
|
|
4450
|
-
const MDX = page.data.body
|
|
4451
|
-
|
|
4452
|
-
return (
|
|
4453
|
-
<DocsPage toc={page.data.toc} full={page.data.full}>
|
|
4454
|
-
<DocsTitle>{page.data.title}</DocsTitle>
|
|
4455
|
-
<DocsDescription>{page.data.description}</DocsDescription>
|
|
4456
|
-
<DocsBody>
|
|
4457
|
-
<MDX components={{ ...defaultMdxComponents }} />
|
|
4458
|
-
</DocsBody>
|
|
4459
|
-
</DocsPage>
|
|
4460
|
-
)
|
|
4461
|
-
}
|
|
4462
|
-
|
|
4463
|
-
export async function generateStaticParams() {
|
|
4464
|
-
return source.generateParams()
|
|
4465
|
-
}
|
|
4466
|
-
|
|
4467
|
-
export async function generateMetadata(props: {
|
|
4468
|
-
params: Promise<{ slug?: string[] }>
|
|
4469
|
-
}) {
|
|
4470
|
-
const params = await props.params
|
|
4471
|
-
const page = source.getPage(params.slug)
|
|
4472
|
-
if (!page) notFound()
|
|
4473
|
-
|
|
4474
|
-
return {
|
|
4475
|
-
title: page.data.title,
|
|
4476
|
-
description: page.data.description,
|
|
4477
|
-
}
|
|
4478
|
-
}
|
|
4479
|
-
`;
|
|
4480
|
-
await writeFile(
|
|
4481
|
-
path16.join(docsDir, "src/app/docs/[[...slug]]/page.tsx"),
|
|
4482
|
-
docsPageContent
|
|
4483
|
-
);
|
|
4484
|
-
const homePageContent = `import { redirect } from 'next/navigation'
|
|
4485
|
-
|
|
4486
|
-
export default function HomePage() {
|
|
4487
|
-
redirect('/docs')
|
|
4488
|
-
}
|
|
4489
|
-
`;
|
|
4490
|
-
await writeFile(path16.join(docsDir, "src/app/page.tsx"), homePageContent);
|
|
4491
|
-
const globalCssContent = `@import 'tailwindcss';
|
|
4492
|
-
@import 'fumadocs-ui/css/neutral.css';
|
|
4493
|
-
@import 'fumadocs-ui/css/preset.css';
|
|
4494
|
-
|
|
4495
|
-
@source '../node_modules/fumadocs-ui/dist/**/*.js';
|
|
4496
|
-
`;
|
|
4497
|
-
await writeFile(path16.join(docsDir, "src/app/global.css"), globalCssContent);
|
|
4498
|
-
const sourceConfigContent = `import { defineDocs, defineConfig } from 'fumadocs-mdx/config'
|
|
4499
|
-
|
|
4500
|
-
export const { docs, meta } = defineDocs({
|
|
4501
|
-
dir: 'content/docs',
|
|
4502
|
-
})
|
|
4503
|
-
|
|
4504
|
-
export default defineConfig()
|
|
4505
|
-
`;
|
|
4506
|
-
await writeFile(path16.join(docsDir, "source.config.ts"), sourceConfigContent);
|
|
4507
|
-
const postcssContent = `export default {
|
|
4508
|
-
plugins: {
|
|
4509
|
-
'@tailwindcss/postcss': {},
|
|
4510
|
-
},
|
|
4511
|
-
}
|
|
4512
|
-
`;
|
|
4513
|
-
await writeFile(path16.join(docsDir, "postcss.config.mjs"), postcssContent);
|
|
4514
|
-
}
|
|
4515
|
-
async function generateFumadocsContent(config, docsDir) {
|
|
4516
|
-
const metaJson = {
|
|
4517
|
-
title: "Documentation",
|
|
4518
|
-
pages: ["index", "getting-started", "---", "guides", "api"]
|
|
4519
|
-
};
|
|
4520
|
-
await writeJSON(path16.join(docsDir, "content/docs/meta.json"), metaJson);
|
|
4521
|
-
const indexContent = `---
|
|
4522
|
-
title: Introduction
|
|
4523
|
-
description: Welcome to ${config.name} documentation
|
|
4524
|
-
---
|
|
4525
|
-
|
|
4526
|
-
# Welcome to ${config.name}
|
|
4527
|
-
|
|
4528
|
-
This is the documentation for ${config.name}, built with [Fumadocs](https://fumadocs.vercel.app).
|
|
4529
|
-
|
|
4530
|
-
## Features
|
|
4531
|
-
|
|
4532
|
-
- Built with Next.js 15 and React 19
|
|
4533
|
-
- Convex for real-time database
|
|
4534
|
-
- Better-Auth for authentication
|
|
4535
|
-
- shadcn/ui components
|
|
4536
|
-
- Tailwind CSS v4
|
|
4537
|
-
|
|
4538
|
-
## Getting Started
|
|
4539
|
-
|
|
4540
|
-
Check out the [Getting Started](/docs/getting-started) guide to begin.
|
|
4541
|
-
`;
|
|
4542
|
-
await writeFile(
|
|
4543
|
-
path16.join(docsDir, "content/docs/index.mdx"),
|
|
4544
|
-
indexContent
|
|
4545
|
-
);
|
|
4546
|
-
const gettingStartedContent = `---
|
|
4547
|
-
title: Getting Started
|
|
4548
|
-
description: Get started with ${config.name}
|
|
4549
|
-
---
|
|
4550
|
-
|
|
4551
|
-
# Getting Started
|
|
4552
|
-
|
|
4553
|
-
This guide will help you get ${config.name} up and running.
|
|
4554
|
-
|
|
4555
|
-
## Prerequisites
|
|
4556
|
-
|
|
4557
|
-
- Node.js 18 or higher
|
|
4558
|
-
- pnpm package manager
|
|
4559
|
-
|
|
4560
|
-
## Installation
|
|
4561
|
-
|
|
4562
|
-
1. Clone the repository
|
|
4563
|
-
2. Install dependencies:
|
|
4564
|
-
|
|
4565
|
-
\`\`\`bash
|
|
4566
|
-
pnpm install
|
|
4567
|
-
\`\`\`
|
|
4568
|
-
|
|
4569
|
-
3. Copy environment variables:
|
|
4570
|
-
|
|
4571
|
-
\`\`\`bash
|
|
4572
|
-
cp .env.example .env.local
|
|
4573
|
-
\`\`\`
|
|
4574
|
-
|
|
4575
|
-
4. Set up Convex:
|
|
4576
|
-
|
|
4577
|
-
\`\`\`bash
|
|
4578
|
-
pnpm convex dev
|
|
4579
|
-
\`\`\`
|
|
4580
|
-
|
|
4581
|
-
5. Start the development server:
|
|
4582
|
-
|
|
4583
|
-
\`\`\`bash
|
|
4584
|
-
pnpm dev
|
|
4585
|
-
\`\`\`
|
|
4586
|
-
|
|
4587
|
-
## Next Steps
|
|
4588
|
-
|
|
4589
|
-
- [Configure authentication](/docs/guides/authentication)
|
|
4590
|
-
- [Set up your database schema](/docs/guides/database)
|
|
4591
|
-
- [Customize the UI](/docs/guides/customization)
|
|
4592
|
-
`;
|
|
4593
|
-
await writeFile(
|
|
4594
|
-
path16.join(docsDir, "content/docs/getting-started.mdx"),
|
|
4595
|
-
gettingStartedContent
|
|
4596
|
-
);
|
|
4597
|
-
await ensureDir(path16.join(docsDir, "content/docs/guides"));
|
|
4598
|
-
const guidesMetaJson = {
|
|
4599
|
-
title: "Guides",
|
|
4600
|
-
pages: ["authentication", "database", "customization"]
|
|
4601
|
-
};
|
|
4602
|
-
await writeJSON(
|
|
4603
|
-
path16.join(docsDir, "content/docs/guides/meta.json"),
|
|
4604
|
-
guidesMetaJson
|
|
4605
|
-
);
|
|
4606
|
-
const authGuideContent = `---
|
|
4607
|
-
title: Authentication
|
|
4608
|
-
description: Learn how to configure authentication in ${config.name}
|
|
4609
|
-
---
|
|
4610
|
-
|
|
4611
|
-
# Authentication
|
|
4612
|
-
|
|
4613
|
-
${config.name} uses Better-Auth with Convex for authentication.
|
|
4614
|
-
|
|
4615
|
-
## Supported Providers
|
|
4616
|
-
|
|
4617
|
-
- Email/Password (always enabled)
|
|
4618
|
-
- Google OAuth (always enabled)
|
|
4619
|
-
${config.auth.providers.map((p8) => `- ${p8.charAt(0).toUpperCase() + p8.slice(1)}`).join("\n")}
|
|
4620
|
-
|
|
4621
|
-
## Configuration
|
|
4622
|
-
|
|
4623
|
-
Authentication is configured in \`convex/auth.ts\`.
|
|
4624
|
-
|
|
4625
|
-
\`\`\`typescript
|
|
4626
|
-
export const { auth, createAuth } = new BetterAuth<DataModel>(components.betterAuth, {
|
|
4627
|
-
emailAndPassword: {
|
|
4628
|
-
enabled: true,
|
|
4629
|
-
},
|
|
4630
|
-
socialProviders: {
|
|
4631
|
-
google: {
|
|
4632
|
-
clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
4633
|
-
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
4634
|
-
},
|
|
4635
|
-
},
|
|
4636
|
-
})
|
|
4637
|
-
\`\`\`
|
|
4638
|
-
|
|
4639
|
-
## Using Authentication
|
|
4640
|
-
|
|
4641
|
-
Use the auth client in your components:
|
|
4642
|
-
|
|
4643
|
-
\`\`\`typescript
|
|
4644
|
-
import { signIn, signOut, useSession } from '@/lib/auth'
|
|
4645
|
-
|
|
4646
|
-
// Sign in
|
|
4647
|
-
await signIn.email({ email, password })
|
|
4648
|
-
|
|
4649
|
-
// Sign out
|
|
4650
|
-
await signOut()
|
|
4651
|
-
|
|
4652
|
-
// Get session
|
|
4653
|
-
const { data: session } = useSession()
|
|
4654
|
-
\`\`\`
|
|
4655
|
-
`;
|
|
4656
|
-
await writeFile(
|
|
4657
|
-
path16.join(docsDir, "content/docs/guides/authentication.mdx"),
|
|
4658
|
-
authGuideContent
|
|
4659
|
-
);
|
|
4660
|
-
const databaseGuideContent = `---
|
|
4661
|
-
title: Database
|
|
4662
|
-
description: Working with Convex database
|
|
4663
|
-
---
|
|
4664
|
-
|
|
4665
|
-
# Database
|
|
4666
|
-
|
|
4667
|
-
${config.name} uses Convex as its database.
|
|
4668
|
-
|
|
4669
|
-
## Schema
|
|
4670
|
-
|
|
4671
|
-
The database schema is defined in \`convex/schema.ts\`.
|
|
4672
|
-
|
|
4673
|
-
## Queries
|
|
4674
|
-
|
|
4675
|
-
Create queries to read data:
|
|
4676
|
-
|
|
4677
|
-
\`\`\`typescript
|
|
4678
|
-
import { query } from './_generated/server'
|
|
4679
|
-
|
|
4680
|
-
export const getUsers = query({
|
|
4681
|
-
handler: async (ctx) => {
|
|
4682
|
-
return await ctx.db.query('users').collect()
|
|
4683
|
-
},
|
|
4684
|
-
})
|
|
4685
|
-
\`\`\`
|
|
4686
|
-
|
|
4687
|
-
## Mutations
|
|
4688
|
-
|
|
4689
|
-
Create mutations to write data:
|
|
4690
|
-
|
|
4691
|
-
\`\`\`typescript
|
|
4692
|
-
import { mutation } from './_generated/server'
|
|
4693
|
-
import { v } from 'convex/values'
|
|
4694
|
-
|
|
4695
|
-
export const createUser = mutation({
|
|
4696
|
-
args: {
|
|
4697
|
-
name: v.string(),
|
|
4698
|
-
email: v.string(),
|
|
4699
|
-
},
|
|
4700
|
-
handler: async (ctx, args) => {
|
|
4701
|
-
return await ctx.db.insert('users', args)
|
|
4702
|
-
},
|
|
4703
|
-
})
|
|
4704
|
-
\`\`\`
|
|
4705
|
-
`;
|
|
4706
|
-
await writeFile(
|
|
4707
|
-
path16.join(docsDir, "content/docs/guides/database.mdx"),
|
|
4708
|
-
databaseGuideContent
|
|
4709
|
-
);
|
|
4710
|
-
const customizationGuideContent = `---
|
|
4711
|
-
title: Customization
|
|
4712
|
-
description: Customize the look and feel of ${config.name}
|
|
4713
|
-
---
|
|
4714
|
-
|
|
4715
|
-
# Customization
|
|
4716
|
-
|
|
4717
|
-
## Theme
|
|
4718
|
-
|
|
4719
|
-
The theme is configured in \`src/app/globals.css\` using Tailwind CSS v4.
|
|
4720
|
-
|
|
4721
|
-
### Colors
|
|
4722
|
-
|
|
4723
|
-
Update the theme colors in the CSS:
|
|
4724
|
-
|
|
4725
|
-
\`\`\`css
|
|
4726
|
-
@theme {
|
|
4727
|
-
--color-primary: oklch(0.6 0.2 250);
|
|
4728
|
-
--color-primary-foreground: oklch(0.98 0 0);
|
|
4729
|
-
}
|
|
4730
|
-
\`\`\`
|
|
4731
|
-
|
|
4732
|
-
### Dark Mode
|
|
4733
|
-
|
|
4734
|
-
Dark mode is supported out of the box. Define dark mode styles with:
|
|
4735
|
-
|
|
4736
|
-
\`\`\`css
|
|
4737
|
-
.dark {
|
|
4738
|
-
--color-background: oklch(0.145 0 0);
|
|
4739
|
-
}
|
|
4740
|
-
\`\`\`
|
|
4741
|
-
|
|
4742
|
-
## Components
|
|
4743
|
-
|
|
4744
|
-
UI components are in \`src/components/ui\`. Customize or add new components as needed.
|
|
4745
|
-
`;
|
|
4746
|
-
await writeFile(
|
|
4747
|
-
path16.join(docsDir, "content/docs/guides/customization.mdx"),
|
|
4748
|
-
customizationGuideContent
|
|
4749
|
-
);
|
|
4750
|
-
await ensureDir(path16.join(docsDir, "content/docs/api"));
|
|
4751
|
-
const apiMetaJson = {
|
|
4752
|
-
title: "API Reference",
|
|
4753
|
-
pages: ["overview"]
|
|
4754
|
-
};
|
|
4755
|
-
await writeJSON(
|
|
4756
|
-
path16.join(docsDir, "content/docs/api/meta.json"),
|
|
4757
|
-
apiMetaJson
|
|
4758
|
-
);
|
|
4759
|
-
const apiOverviewContent = `---
|
|
4760
|
-
title: API Overview
|
|
4761
|
-
description: API reference for ${config.name}
|
|
4762
|
-
---
|
|
4763
|
-
|
|
4764
|
-
# API Reference
|
|
4765
|
-
|
|
4766
|
-
This section contains the API reference for ${config.name}.
|
|
4767
|
-
|
|
4768
|
-
## Authentication API
|
|
4769
|
-
|
|
4770
|
-
See the [Better-Auth documentation](https://www.better-auth.com) for detailed API reference.
|
|
4771
|
-
|
|
4772
|
-
## Database API
|
|
4773
|
-
|
|
4774
|
-
See the [Convex documentation](https://docs.convex.dev) for database API reference.
|
|
4775
|
-
`;
|
|
4776
|
-
await writeFile(
|
|
4777
|
-
path16.join(docsDir, "content/docs/api/overview.mdx"),
|
|
4778
|
-
apiOverviewContent
|
|
4779
|
-
);
|
|
4780
|
-
}
|
|
4781
|
-
|
|
4782
4248
|
// src/generators/design-system.ts
|
|
4783
|
-
import
|
|
4249
|
+
import path16 from "path";
|
|
4784
4250
|
var fontImports = {
|
|
4785
4251
|
inter: {
|
|
4786
4252
|
import: "import { Inter } from 'next/font/google'",
|
|
@@ -4848,17 +4314,17 @@ var spacingMultipliers = {
|
|
|
4848
4314
|
relaxed: 1.125
|
|
4849
4315
|
};
|
|
4850
4316
|
async function generateDesignSystemApp(config, targetDir) {
|
|
4851
|
-
const appDir =
|
|
4852
|
-
await ensureDir(
|
|
4853
|
-
await ensureDir(
|
|
4854
|
-
await ensureDir(
|
|
4855
|
-
await ensureDir(
|
|
4856
|
-
await ensureDir(
|
|
4857
|
-
await ensureDir(
|
|
4858
|
-
await ensureDir(
|
|
4859
|
-
await ensureDir(
|
|
4860
|
-
await ensureDir(
|
|
4861
|
-
await ensureDir(
|
|
4317
|
+
const appDir = path16.join(targetDir, "apps/design-system");
|
|
4318
|
+
await ensureDir(path16.join(appDir, "src/app"));
|
|
4319
|
+
await ensureDir(path16.join(appDir, "src/app/colors"));
|
|
4320
|
+
await ensureDir(path16.join(appDir, "src/app/typography"));
|
|
4321
|
+
await ensureDir(path16.join(appDir, "src/app/spacing"));
|
|
4322
|
+
await ensureDir(path16.join(appDir, "src/app/brand"));
|
|
4323
|
+
await ensureDir(path16.join(appDir, "src/app/blocks"));
|
|
4324
|
+
await ensureDir(path16.join(appDir, "src/app/components"));
|
|
4325
|
+
await ensureDir(path16.join(appDir, "src/app/components/[slug]"));
|
|
4326
|
+
await ensureDir(path16.join(appDir, "src/lib"));
|
|
4327
|
+
await ensureDir(path16.join(appDir, "public/brand"));
|
|
4862
4328
|
await generatePackageJson2(config, appDir);
|
|
4863
4329
|
await generateTsConfig2(appDir);
|
|
4864
4330
|
await generateNextConfig2(appDir);
|
|
@@ -4911,7 +4377,7 @@ async function generatePackageJson2(config, appDir) {
|
|
|
4911
4377
|
typescript: "^5.0.0"
|
|
4912
4378
|
}
|
|
4913
4379
|
};
|
|
4914
|
-
await writeJSON(
|
|
4380
|
+
await writeJSON(path16.join(appDir, "package.json"), packageJson2);
|
|
4915
4381
|
}
|
|
4916
4382
|
async function generateTsConfig2(appDir) {
|
|
4917
4383
|
const tsConfig = {
|
|
@@ -4939,7 +4405,7 @@ async function generateTsConfig2(appDir) {
|
|
|
4939
4405
|
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
4940
4406
|
exclude: ["node_modules"]
|
|
4941
4407
|
};
|
|
4942
|
-
await writeJSON(
|
|
4408
|
+
await writeJSON(path16.join(appDir, "tsconfig.json"), tsConfig);
|
|
4943
4409
|
}
|
|
4944
4410
|
async function generateNextConfig2(appDir) {
|
|
4945
4411
|
const content = `import type { NextConfig } from 'next'
|
|
@@ -4950,7 +4416,7 @@ const nextConfig: NextConfig = {
|
|
|
4950
4416
|
|
|
4951
4417
|
export default nextConfig
|
|
4952
4418
|
`;
|
|
4953
|
-
await writeFile(
|
|
4419
|
+
await writeFile(path16.join(appDir, "next.config.ts"), content);
|
|
4954
4420
|
}
|
|
4955
4421
|
async function generatePostCssConfig2(appDir) {
|
|
4956
4422
|
const content = `export default {
|
|
@@ -4959,7 +4425,7 @@ async function generatePostCssConfig2(appDir) {
|
|
|
4959
4425
|
},
|
|
4960
4426
|
}
|
|
4961
4427
|
`;
|
|
4962
|
-
await writeFile(
|
|
4428
|
+
await writeFile(path16.join(appDir, "postcss.config.mjs"), content);
|
|
4963
4429
|
}
|
|
4964
4430
|
async function generateGlobalsCss2(config, appDir) {
|
|
4965
4431
|
const { designSystem } = config;
|
|
@@ -5219,7 +4685,7 @@ h1, h2, h3, h4, h5, h6 {
|
|
|
5219
4685
|
}
|
|
5220
4686
|
}
|
|
5221
4687
|
`;
|
|
5222
|
-
await writeFile(
|
|
4688
|
+
await writeFile(path16.join(appDir, "src/app/globals.css"), content);
|
|
5223
4689
|
}
|
|
5224
4690
|
async function generateLayoutTsx(config, appDir) {
|
|
5225
4691
|
const { designSystem } = config;
|
|
@@ -5418,7 +4884,7 @@ function ThemeToggle() {
|
|
|
5418
4884
|
)
|
|
5419
4885
|
}
|
|
5420
4886
|
`;
|
|
5421
|
-
await writeFile(
|
|
4887
|
+
await writeFile(path16.join(appDir, "src/app/layout.tsx"), content);
|
|
5422
4888
|
}
|
|
5423
4889
|
async function generateHomePage(config, appDir) {
|
|
5424
4890
|
const content = `export default function DesignSystemHome() {
|
|
@@ -5584,7 +5050,7 @@ function Principle({
|
|
|
5584
5050
|
)
|
|
5585
5051
|
}
|
|
5586
5052
|
`;
|
|
5587
|
-
await writeFile(
|
|
5053
|
+
await writeFile(path16.join(appDir, "src/app/page.tsx"), content);
|
|
5588
5054
|
}
|
|
5589
5055
|
async function generateColorsPage(config, appDir) {
|
|
5590
5056
|
const content = `export default function ColorsPage() {
|
|
@@ -5753,7 +5219,7 @@ function ColorCard({
|
|
|
5753
5219
|
)
|
|
5754
5220
|
}
|
|
5755
5221
|
`;
|
|
5756
|
-
await writeFile(
|
|
5222
|
+
await writeFile(path16.join(appDir, "src/app/colors/page.tsx"), content);
|
|
5757
5223
|
}
|
|
5758
5224
|
async function generateTypographyPage(config, appDir) {
|
|
5759
5225
|
const { designSystem } = config;
|
|
@@ -5910,7 +5376,7 @@ function WeightCard({ weight, name }: { weight: string; name: string }) {
|
|
|
5910
5376
|
)
|
|
5911
5377
|
}
|
|
5912
5378
|
`;
|
|
5913
|
-
await writeFile(
|
|
5379
|
+
await writeFile(path16.join(appDir, "src/app/typography/page.tsx"), content);
|
|
5914
5380
|
}
|
|
5915
5381
|
async function generateSpacingPage(config, appDir) {
|
|
5916
5382
|
const { designSystem } = config;
|
|
@@ -6043,7 +5509,7 @@ function PatternCard({
|
|
|
6043
5509
|
)
|
|
6044
5510
|
}
|
|
6045
5511
|
`;
|
|
6046
|
-
await writeFile(
|
|
5512
|
+
await writeFile(path16.join(appDir, "src/app/spacing/page.tsx"), content);
|
|
6047
5513
|
}
|
|
6048
5514
|
async function generateBrandPage(config, appDir) {
|
|
6049
5515
|
const content = `export default function BrandPage() {
|
|
@@ -6181,7 +5647,7 @@ function DownloadCard({
|
|
|
6181
5647
|
)
|
|
6182
5648
|
}
|
|
6183
5649
|
`;
|
|
6184
|
-
await writeFile(
|
|
5650
|
+
await writeFile(path16.join(appDir, "src/app/brand/page.tsx"), content);
|
|
6185
5651
|
}
|
|
6186
5652
|
async function generateBlocksPage(appDir) {
|
|
6187
5653
|
const content = `export default function BlocksPage() {
|
|
@@ -6243,7 +5709,7 @@ function BlockCard({ title, description }: { title: string; description: string
|
|
|
6243
5709
|
)
|
|
6244
5710
|
}
|
|
6245
5711
|
`;
|
|
6246
|
-
await writeFile(
|
|
5712
|
+
await writeFile(path16.join(appDir, "src/app/blocks/page.tsx"), content);
|
|
6247
5713
|
}
|
|
6248
5714
|
async function generateComponentsPage(appDir) {
|
|
6249
5715
|
const content = `export default function ComponentsPage() {
|
|
@@ -6323,7 +5789,7 @@ function CategoryCard({
|
|
|
6323
5789
|
)
|
|
6324
5790
|
}
|
|
6325
5791
|
`;
|
|
6326
|
-
await writeFile(
|
|
5792
|
+
await writeFile(path16.join(appDir, "src/app/components/page.tsx"), content);
|
|
6327
5793
|
}
|
|
6328
5794
|
async function generateComponentSlugPage(appDir) {
|
|
6329
5795
|
const content = `import { notFound } from 'next/navigation'
|
|
@@ -6427,7 +5893,7 @@ export function generateStaticParams() {
|
|
|
6427
5893
|
return components.map((slug) => ({ slug }))
|
|
6428
5894
|
}
|
|
6429
5895
|
`;
|
|
6430
|
-
await writeFile(
|
|
5896
|
+
await writeFile(path16.join(appDir, "src/app/components/[slug]/page.tsx"), content);
|
|
6431
5897
|
}
|
|
6432
5898
|
async function generateUtils(appDir) {
|
|
6433
5899
|
const content = `import { clsx, type ClassValue } from 'clsx'
|
|
@@ -6437,7 +5903,7 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
6437
5903
|
return twMerge(clsx(inputs))
|
|
6438
5904
|
}
|
|
6439
5905
|
`;
|
|
6440
|
-
await writeFile(
|
|
5906
|
+
await writeFile(path16.join(appDir, "src/lib/utils.ts"), content);
|
|
6441
5907
|
}
|
|
6442
5908
|
|
|
6443
5909
|
// src/setup/env-wizard.ts
|
|
@@ -6445,7 +5911,7 @@ import * as p6 from "@clack/prompts";
|
|
|
6445
5911
|
import pc2 from "picocolors";
|
|
6446
5912
|
import { exec } from "child_process";
|
|
6447
5913
|
import { promisify } from "util";
|
|
6448
|
-
import
|
|
5914
|
+
import path17 from "path";
|
|
6449
5915
|
var execAsync = promisify(exec);
|
|
6450
5916
|
async function runEnvSetupWizard(config) {
|
|
6451
5917
|
console.log();
|
|
@@ -6526,7 +5992,7 @@ This will open your browser to create a new project on Convex.
|
|
|
6526
5992
|
${pc2.dim("Note: Make sure you have a Convex account at https://convex.dev")}
|
|
6527
5993
|
`);
|
|
6528
5994
|
try {
|
|
6529
|
-
const convexDir = config.structure === "monorepo" ?
|
|
5995
|
+
const convexDir = config.structure === "monorepo" ? path17.join(config.targetDir, "packages/backend") : config.targetDir;
|
|
6530
5996
|
const { spawn } = await import("child_process");
|
|
6531
5997
|
p6.log.info(`Installing dependencies in ${pc2.dim(convexDir)}...`);
|
|
6532
5998
|
const installSuccess = await new Promise((resolve) => {
|
|
@@ -6802,7 +6268,7 @@ async function writeEnvFiles(config, envValues) {
|
|
|
6802
6268
|
return;
|
|
6803
6269
|
}
|
|
6804
6270
|
p6.log.step("Writing environment files...");
|
|
6805
|
-
const webEnvPath = config.structure === "monorepo" ?
|
|
6271
|
+
const webEnvPath = config.structure === "monorepo" ? path17.join(config.targetDir, "apps/web/.env.local") : path17.join(config.targetDir, ".env.local");
|
|
6806
6272
|
if (await pathExists(webEnvPath)) {
|
|
6807
6273
|
let content = await readFile(webEnvPath);
|
|
6808
6274
|
for (const [key, value] of Object.entries(envValues)) {
|
|
@@ -6821,7 +6287,7 @@ ${key}="${value}"`;
|
|
|
6821
6287
|
p6.log.success(`Updated ${config.structure === "monorepo" ? "apps/web/.env.local" : ".env.local"}`);
|
|
6822
6288
|
}
|
|
6823
6289
|
if (config.marketingSite === "payload" && config.structure === "monorepo") {
|
|
6824
|
-
const marketingEnvPath =
|
|
6290
|
+
const marketingEnvPath = path17.join(config.targetDir, "apps/marketing/.env.local");
|
|
6825
6291
|
if (await pathExists(marketingEnvPath)) {
|
|
6826
6292
|
let content = await readFile(marketingEnvPath);
|
|
6827
6293
|
const payloadEnvKeys = ["PAYLOAD_SECRET", "DATABASE_URL", "S3_ENDPOINT", "S3_REGION", "S3_BUCKET", "S3_ACCESS_KEY_ID", "S3_SECRET_ACCESS_KEY", "CRON_SECRET", "PREVIEW_SECRET"];
|
|
@@ -6882,7 +6348,7 @@ async function generateSingleProject(config, spinner) {
|
|
|
6882
6348
|
await generateShadcn(config, targetDir);
|
|
6883
6349
|
spinner.succeed("shadcn/ui configured");
|
|
6884
6350
|
spinner.start("Setting up Convex...");
|
|
6885
|
-
await generateConvex(config,
|
|
6351
|
+
await generateConvex(config, path18.join(targetDir, "convex"));
|
|
6886
6352
|
spinner.succeed("Convex configured");
|
|
6887
6353
|
spinner.start("Configuring Better-Auth...");
|
|
6888
6354
|
await generateBetterAuth(config, targetDir);
|
|
@@ -6925,7 +6391,7 @@ async function generateMonorepoProject(config, spinner) {
|
|
|
6925
6391
|
spinner.start("Creating shared UI package...");
|
|
6926
6392
|
await generateUIPackage(config, targetDir);
|
|
6927
6393
|
spinner.succeed("Shared UI package created");
|
|
6928
|
-
const webDir =
|
|
6394
|
+
const webDir = path18.join(targetDir, "apps/web");
|
|
6929
6395
|
spinner.start("Generating web application...");
|
|
6930
6396
|
await generateBaseNextjs(config, webDir);
|
|
6931
6397
|
await generateTailwind(config, webDir);
|
|
@@ -6935,10 +6401,10 @@ async function generateMonorepoProject(config, spinner) {
|
|
|
6935
6401
|
await generateEmail(config, webDir);
|
|
6936
6402
|
await updateWebTsConfig(webDir);
|
|
6937
6403
|
spinner.succeed("Web application generated");
|
|
6938
|
-
const backendDir =
|
|
6404
|
+
const backendDir = path18.join(targetDir, "packages/backend");
|
|
6939
6405
|
spinner.start("Setting up Convex backend...");
|
|
6940
6406
|
await ensureDir(backendDir);
|
|
6941
|
-
await generateConvex(config,
|
|
6407
|
+
await generateConvex(config, path18.join(backendDir, "convex"));
|
|
6942
6408
|
spinner.succeed("Convex backend configured");
|
|
6943
6409
|
if (config.integrations.analytics !== "none") {
|
|
6944
6410
|
spinner.start(`Setting up ${config.integrations.analytics} analytics...`);
|
|
@@ -6961,7 +6427,7 @@ async function generateMonorepoProject(config, spinner) {
|
|
|
6961
6427
|
spinner.succeed(`${config.integrations.monitoring} monitoring configured`);
|
|
6962
6428
|
}
|
|
6963
6429
|
if (config.marketingSite !== "none") {
|
|
6964
|
-
const marketingDir =
|
|
6430
|
+
const marketingDir = path18.join(targetDir, "apps/marketing");
|
|
6965
6431
|
spinner.start(`Generating ${config.marketingSite} marketing site...`);
|
|
6966
6432
|
if (config.marketingSite === "payload") {
|
|
6967
6433
|
await generatePayload(config, marketingDir);
|
|
@@ -6970,12 +6436,6 @@ async function generateMonorepoProject(config, spinner) {
|
|
|
6970
6436
|
}
|
|
6971
6437
|
spinner.succeed(`${config.marketingSite} marketing site generated`);
|
|
6972
6438
|
}
|
|
6973
|
-
if (config.includeDocs) {
|
|
6974
|
-
const docsDir = path19.join(targetDir, "apps/docs");
|
|
6975
|
-
spinner.start("Generating Fumadocs documentation site...");
|
|
6976
|
-
await generateFumadocs(config, docsDir);
|
|
6977
|
-
spinner.succeed("Fumadocs documentation site generated");
|
|
6978
|
-
}
|
|
6979
6439
|
spinner.start("Generating design system app...");
|
|
6980
6440
|
await generateDesignSystemApp(config, targetDir);
|
|
6981
6441
|
spinner.succeed("Design system app generated");
|
|
@@ -6992,7 +6452,7 @@ async function runPostGenerationSteps(config, spinner) {
|
|
|
6992
6452
|
}
|
|
6993
6453
|
spinner.start("Installing shadcn/ui components...");
|
|
6994
6454
|
try {
|
|
6995
|
-
const shadcnDir = config.structure === "monorepo" ?
|
|
6455
|
+
const shadcnDir = config.structure === "monorepo" ? path18.join(targetDir, "packages/ui") : targetDir;
|
|
6996
6456
|
await runShadcnAdd(shadcnDir);
|
|
6997
6457
|
spinner.succeed("shadcn/ui components installed");
|
|
6998
6458
|
} catch (error) {
|
|
@@ -7052,7 +6512,7 @@ async function generateBiomeConfig(targetDir) {
|
|
|
7052
6512
|
}
|
|
7053
6513
|
};
|
|
7054
6514
|
await writeFile(
|
|
7055
|
-
|
|
6515
|
+
path18.join(targetDir, "biome.json"),
|
|
7056
6516
|
JSON.stringify(biomeJson, null, 2)
|
|
7057
6517
|
);
|
|
7058
6518
|
}
|
|
@@ -7103,13 +6563,13 @@ yarn-error.log*
|
|
|
7103
6563
|
*.pem
|
|
7104
6564
|
.cache
|
|
7105
6565
|
`;
|
|
7106
|
-
await writeFile(
|
|
6566
|
+
await writeFile(path18.join(targetDir, ".gitignore"), gitignoreContent);
|
|
7107
6567
|
}
|
|
7108
6568
|
async function generateHuskyHooks(targetDir) {
|
|
7109
6569
|
const preCommitContent = `pnpm lint-staged
|
|
7110
6570
|
`;
|
|
7111
|
-
await ensureDir(
|
|
7112
|
-
await writeFile(
|
|
6571
|
+
await ensureDir(path18.join(targetDir, ".husky"));
|
|
6572
|
+
await writeFile(path18.join(targetDir, ".husky/pre-commit"), preCommitContent);
|
|
7113
6573
|
}
|
|
7114
6574
|
async function updateWebTsConfig(webDir) {
|
|
7115
6575
|
const tsConfig = {
|
|
@@ -7136,14 +6596,14 @@ async function updateWebTsConfig(webDir) {
|
|
|
7136
6596
|
exclude: ["node_modules"]
|
|
7137
6597
|
};
|
|
7138
6598
|
await writeFile(
|
|
7139
|
-
|
|
6599
|
+
path18.join(webDir, "tsconfig.json"),
|
|
7140
6600
|
JSON.stringify(tsConfig, null, 2)
|
|
7141
6601
|
);
|
|
7142
6602
|
}
|
|
7143
6603
|
async function generateNextjsMarketing(config, marketingDir) {
|
|
7144
|
-
await ensureDir(
|
|
7145
|
-
await ensureDir(
|
|
7146
|
-
await ensureDir(
|
|
6604
|
+
await ensureDir(path18.join(marketingDir, "src/app"));
|
|
6605
|
+
await ensureDir(path18.join(marketingDir, "src/components"));
|
|
6606
|
+
await ensureDir(path18.join(marketingDir, "public"));
|
|
7147
6607
|
const packageJson2 = {
|
|
7148
6608
|
name: "@repo/marketing",
|
|
7149
6609
|
version: "0.1.0",
|
|
@@ -7174,7 +6634,7 @@ async function generateNextjsMarketing(config, marketingDir) {
|
|
|
7174
6634
|
}
|
|
7175
6635
|
};
|
|
7176
6636
|
await writeFile(
|
|
7177
|
-
|
|
6637
|
+
path18.join(marketingDir, "package.json"),
|
|
7178
6638
|
JSON.stringify(packageJson2, null, 2)
|
|
7179
6639
|
);
|
|
7180
6640
|
const homePageContent = `export default function HomePage() {
|
|
@@ -7197,7 +6657,7 @@ async function generateNextjsMarketing(config, marketingDir) {
|
|
|
7197
6657
|
}
|
|
7198
6658
|
`;
|
|
7199
6659
|
await writeFile(
|
|
7200
|
-
|
|
6660
|
+
path18.join(marketingDir, "src/app/page.tsx"),
|
|
7201
6661
|
homePageContent
|
|
7202
6662
|
);
|
|
7203
6663
|
const layoutContent = `import type { Metadata } from 'next'
|
|
@@ -7221,7 +6681,7 @@ export default function RootLayout({
|
|
|
7221
6681
|
}
|
|
7222
6682
|
`;
|
|
7223
6683
|
await writeFile(
|
|
7224
|
-
|
|
6684
|
+
path18.join(marketingDir, "src/app/layout.tsx"),
|
|
7225
6685
|
layoutContent
|
|
7226
6686
|
);
|
|
7227
6687
|
const globalsCss = `@import "tailwindcss";
|
|
@@ -7233,7 +6693,7 @@ export default function RootLayout({
|
|
|
7233
6693
|
}
|
|
7234
6694
|
`;
|
|
7235
6695
|
await writeFile(
|
|
7236
|
-
|
|
6696
|
+
path18.join(marketingDir, "src/app/globals.css"),
|
|
7237
6697
|
globalsCss
|
|
7238
6698
|
);
|
|
7239
6699
|
const tsConfig = {
|
|
@@ -7260,7 +6720,7 @@ export default function RootLayout({
|
|
|
7260
6720
|
exclude: ["node_modules"]
|
|
7261
6721
|
};
|
|
7262
6722
|
await writeFile(
|
|
7263
|
-
|
|
6723
|
+
path18.join(marketingDir, "tsconfig.json"),
|
|
7264
6724
|
JSON.stringify(tsConfig, null, 2)
|
|
7265
6725
|
);
|
|
7266
6726
|
const nextConfig = `import type { NextConfig } from 'next'
|
|
@@ -7271,14 +6731,14 @@ const nextConfig: NextConfig = {
|
|
|
7271
6731
|
|
|
7272
6732
|
export default nextConfig
|
|
7273
6733
|
`;
|
|
7274
|
-
await writeFile(
|
|
6734
|
+
await writeFile(path18.join(marketingDir, "next.config.ts"), nextConfig);
|
|
7275
6735
|
const postcssConfig = `export default {
|
|
7276
6736
|
plugins: {
|
|
7277
6737
|
'@tailwindcss/postcss': {},
|
|
7278
6738
|
},
|
|
7279
6739
|
}
|
|
7280
6740
|
`;
|
|
7281
|
-
await writeFile(
|
|
6741
|
+
await writeFile(path18.join(marketingDir, "postcss.config.mjs"), postcssConfig);
|
|
7282
6742
|
}
|
|
7283
6743
|
function displaySuccessMessage(config) {
|
|
7284
6744
|
const apps = ["web"];
|
|
@@ -7286,9 +6746,6 @@ function displaySuccessMessage(config) {
|
|
|
7286
6746
|
if (config.marketingSite !== "none") {
|
|
7287
6747
|
apps.push("marketing");
|
|
7288
6748
|
}
|
|
7289
|
-
if (config.includeDocs) {
|
|
7290
|
-
apps.push("docs");
|
|
7291
|
-
}
|
|
7292
6749
|
apps.push("design-system");
|
|
7293
6750
|
}
|
|
7294
6751
|
console.log();
|
|
@@ -7321,9 +6778,6 @@ function displaySuccessMessage(config) {
|
|
|
7321
6778
|
if (config.marketingSite === "payload") {
|
|
7322
6779
|
console.log(` ${pc3.dim("-")} Payload CMS: ${pc3.cyan("https://payloadcms.com/docs")}`);
|
|
7323
6780
|
}
|
|
7324
|
-
if (config.includeDocs) {
|
|
7325
|
-
console.log(` ${pc3.dim("-")} Fumadocs: ${pc3.cyan("https://fumadocs.vercel.app")}`);
|
|
7326
|
-
}
|
|
7327
6781
|
console.log();
|
|
7328
6782
|
}
|
|
7329
6783
|
|
|
@@ -7351,7 +6805,7 @@ program.name("create-kofi-stack").description(
|
|
|
7351
6805
|
).version(packageJson.version).argument("[project-name]", "Name of the project").option("--monorepo", "Use monorepo structure with Turborepo").option("--single", "Use single app structure").option(
|
|
7352
6806
|
"--marketing <type>",
|
|
7353
6807
|
"Marketing site type: payload, nextjs, none"
|
|
7354
|
-
).option(
|
|
6808
|
+
).option(
|
|
7355
6809
|
"--component-library <library>",
|
|
7356
6810
|
"Component library: base (Base UI), radix (Radix UI)"
|
|
7357
6811
|
).option(
|