add starlight docs addon

This commit is contained in:
Aman Varshney
2025-04-10 20:35:15 +05:30
parent 6847603b5c
commit aac6a7d267
11 changed files with 118 additions and 20 deletions

View File

@@ -0,0 +1,5 @@
---
"create-better-t-stack": minor
---
add starlight docs addon

View File

@@ -32,6 +32,7 @@ Follow the prompts to configure your project or use the `--yes` flag for default
- **Authentication**: Optional auth setup with Better-Auth - **Authentication**: Optional auth setup with Better-Auth
- **Progressive Web App**: Add PWA support with service workers and installable apps - **Progressive Web App**: Add PWA support with service workers and installable apps
- **Desktop Apps**: Build native desktop apps with Tauri integration - **Desktop Apps**: Build native desktop apps with Tauri integration
- **Documentation**: Add an Astro Starlight documentation site to your project
- **Code Quality**: Biome for linting and formatting - **Code Quality**: Biome for linting and formatting
- **Git Hooks**: Husky with lint-staged for pre-commit checks - **Git Hooks**: Husky with lint-staged for pre-commit checks
- **Examples**: Todo app with full CRUD functionality, AI Chat using AI SDK - **Examples**: Todo app with full CRUD functionality, AI Chat using AI SDK
@@ -45,12 +46,12 @@ Usage: create-better-t-stack [project-directory] [options]
Options: Options:
-V, --version Output the version number -V, --version Output the version number
-y, --yes Use default configuration -y, --yes Use default configuration
--database <type> Database type (none, sqlite, postgres, mongodb) --database <type> Database type (none, sqlite, postgres, mysql, mongodb)
--orm <type> ORM type (none, drizzle, prisma) --orm <type> ORM type (none, drizzle, prisma)
--auth Include authentication --auth Include authentication
--no-auth Exclude authentication --no-auth Exclude authentication
--frontend <types...> Frontend types (tanstack-router, react-router, tanstack-start, native, none) --frontend <types...> Frontend types (tanstack-router, react-router, tanstack-start, native, none)
--addons <types...> Additional addons (pwa, tauri, biome, husky, none) --addons <types...> Additional addons (pwa, tauri, starlight, biome, husky, none)
--examples <types...> Examples to include (todo, ai) --examples <types...> Examples to include (todo, ai)
--no-examples Skip all examples --no-examples Skip all examples
--git Initialize git repository --git Initialize git repository
@@ -95,3 +96,8 @@ Create a project with Turso database setup:
```bash ```bash
npx create-better-t-stack my-app --db-setup turso npx create-better-t-stack my-app --db-setup turso
``` ```
Create a project with documentation site:
```bash
npx create-better-t-stack my-app --addons starlight
```

View File

@@ -7,6 +7,7 @@ import type {
ProjectPackageManager, ProjectPackageManager,
} from "../types"; } from "../types";
import { addPackageDependency } from "../utils/add-package-deps"; import { addPackageDependency } from "../utils/add-package-deps";
import { setupStarlight } from "./starlight-setup";
import { setupTauri } from "./tauri-setup"; import { setupTauri } from "./tauri-setup";
export async function setupAddons( export async function setupAddons(
@@ -30,6 +31,9 @@ export async function setupAddons(
if (addons.includes("husky")) { if (addons.includes("husky")) {
await setupHusky(projectDir); await setupHusky(projectDir);
} }
if (addons.includes("starlight")) {
await setupStarlight(projectDir, packageManager);
}
} }
export function getWebAppDir( export function getWebAppDir(

View File

@@ -36,10 +36,9 @@ async function initMongoDBAtlas(
stdio: "inherit", stdio: "inherit",
}); });
log.info(pc.yellow("Please enter your connection string"));
const connectionString = await text({ const connectionString = await text({
message: "Paste your complete MongoDB connection string:", message: "Paste your complete MongoDB connection string:",
placeholder: "mongodb://USERNAME:PASSWORD@HOST/DATABASE",
validate(value) { validate(value) {
if (!value) return "Please enter a connection string"; if (!value) return "Please enter a connection string";
if (!value.startsWith("mongodb")) { if (!value.startsWith("mongodb")) {

View File

@@ -43,6 +43,9 @@ export function displayPostInstallInstructions(
addons?.includes("pwa") && frontends?.includes("react-router") addons?.includes("pwa") && frontends?.includes("react-router")
? getPwaInstructions() ? getPwaInstructions()
: ""; : "";
const starlightInstructions = addons?.includes("starlight")
? getStarlightInstructions(runCmd)
: "";
const hasTanstackRouter = frontends?.includes("tanstack-router"); const hasTanstackRouter = frontends?.includes("tanstack-router");
const hasTanstackStart = frontends?.includes("tanstack-start"); const hasTanstackStart = frontends?.includes("tanstack-start");
@@ -64,7 +67,7 @@ ${
? `${hasWebFrontend ? `${pc.cyan("•")} Frontend: http://localhost:${webPort}\n` : ""}` ? `${hasWebFrontend ? `${pc.cyan("•")} Frontend: http://localhost:${webPort}\n` : ""}`
: `${pc.yellow("NOTE:")} You are creating a backend-only app (no frontend selected)\n` : `${pc.yellow("NOTE:")} You are creating a backend-only app (no frontend selected)\n`
}${pc.cyan("•")} API: http://localhost:3000 }${pc.cyan("•")} API: http://localhost:3000
${nativeInstructions ? `\n${nativeInstructions.trim()}` : ""}${databaseInstructions ? `\n${databaseInstructions.trim()}` : ""}${tauriInstructions ? `\n${tauriInstructions.trim()}` : ""}${lintingInstructions ? `\n${lintingInstructions.trim()}` : ""}${pwaInstructions ? `\n${pwaInstructions.trim()}` : ""} ${addons?.includes("starlight") ? `${pc.cyan("•")} Docs: http://localhost:4321\n` : ""}${nativeInstructions ? `\n${nativeInstructions.trim()}` : ""}${databaseInstructions ? `\n${databaseInstructions.trim()}` : ""}${tauriInstructions ? `\n${tauriInstructions.trim()}` : ""}${lintingInstructions ? `\n${lintingInstructions.trim()}` : ""}${pwaInstructions ? `\n${pwaInstructions.trim()}` : ""}${starlightInstructions ? `\n${starlightInstructions.trim()}` : ""}
\n${pc.bold("Like Better-T Stack?")} Please consider giving us a star on GitHub: \n${pc.bold("Like Better-T Stack?")} Please consider giving us a star on GitHub:
${pc.cyan("https://github.com/AmanVarshney01/create-better-t-stack")}`, ${pc.cyan("https://github.com/AmanVarshney01/create-better-t-stack")}`,
"Next steps", "Next steps",
@@ -120,3 +123,7 @@ function getTauriInstructions(runCmd?: string): string {
function getPwaInstructions(): string { function getPwaInstructions(): string {
return `${pc.bold("PWA with React Router v7:")}\n${pc.yellow("NOTE:")} There is a known compatibility issue between VitePWA and React Router v7.\nSee: https://github.com/vite-pwa/vite-plugin-pwa/issues/809\n`; return `${pc.bold("PWA with React Router v7:")}\n${pc.yellow("NOTE:")} There is a known compatibility issue between VitePWA and React Router v7.\nSee: https://github.com/vite-pwa/vite-plugin-pwa/issues/809\n`;
} }
function getStarlightInstructions(runCmd?: string): string {
return `${pc.bold("Documentation with Starlight:")}\n${pc.cyan("•")} Start docs site: ${`cd apps/docs && ${runCmd} dev`}\n${pc.cyan("•")} Build docs site: ${`cd apps/docs && ${runCmd} build`}\n`;
}

View File

@@ -0,0 +1,64 @@
import path from "node:path";
import { log, spinner } from "@clack/prompts";
import { execa } from "execa";
import pc from "picocolors";
import type { ProjectPackageManager } from "../types";
export async function setupStarlight(
projectDir: string,
packageManager: ProjectPackageManager,
): Promise<void> {
const s = spinner();
try {
s.start("Setting up Starlight documentation site...");
let cmd: string;
let args: string[];
switch (packageManager) {
case "npm":
cmd = "npx";
args = ["create-astro@latest"];
break;
case "pnpm":
cmd = "pnpm";
args = ["dlx", "create-astro@latest"];
break;
case "bun":
cmd = "bunx";
args = ["create-astro@latest"];
break;
default:
cmd = "npx";
args = ["create-astro@latest"];
}
args = [
...args,
"docs",
"--template",
"starlight",
"--no-install",
"--add",
"tailwind",
"--no-git",
"--skip-houston",
];
await execa(cmd, args, {
cwd: path.join(projectDir, "apps"),
env: {
CI: "true",
},
});
s.stop("Starlight documentation site setup successfully!");
} catch (error) {
s.stop(pc.red("Failed to set up Starlight documentation site"));
if (error instanceof Error) {
log.error(pc.red(error.message));
}
throw error;
}
}

View File

@@ -22,10 +22,9 @@ import { generateReproducibleCommand } from "./utils/generate-reproducible-comma
import { getLatestCLIVersion } from "./utils/get-latest-cli-version"; import { getLatestCLIVersion } from "./utils/get-latest-cli-version";
import { renderTitle } from "./utils/render-title"; import { renderTitle } from "./utils/render-title";
process.on("SIGINT", () => { const exit = () => process.exit(0);
log.error(pc.red("Operation cancelled")); process.on("SIGINT", exit);
process.exit(0); process.on("SIGTERM", exit);
});
const program = new Command(); const program = new Command();
@@ -51,7 +50,7 @@ async function main() {
) )
.option( .option(
"--addons <types...>", "--addons <types...>",
"Additional addons (pwa, tauri, biome, husky, none)", "Additional addons (pwa, tauri, starlight, biome, husky, none)",
) )
.option("--examples <types...>", "Examples to include (todo, ai)") .option("--examples <types...>", "Examples to include (todo, ai)")
.option("--no-examples", "Skip all examples") .option("--no-examples", "Skip all examples")
@@ -354,7 +353,7 @@ function processAndValidateFlags(
} }
if (options.addons && options.addons.length > 0) { if (options.addons && options.addons.length > 0) {
const validAddons = ["pwa", "tauri", "biome", "husky", "none"]; const validAddons = ["pwa", "tauri", "biome", "husky", "starlight", "none"];
const invalidAddons = options.addons.filter( const invalidAddons = options.addons.filter(
(addon: string) => !validAddons.includes(addon), (addon: string) => !validAddons.includes(addon),
); );
@@ -380,7 +379,8 @@ function processAndValidateFlags(
addon === "pwa" || addon === "pwa" ||
addon === "tauri" || addon === "tauri" ||
addon === "biome" || addon === "biome" ||
addon === "husky", addon === "husky" ||
addon === "starlight",
); );
const webSpecificAddons = ["pwa", "tauri"]; const webSpecificAddons = ["pwa", "tauri"];

View File

@@ -14,6 +14,11 @@ export async function getAddonsChoice(
frontends?.includes("tanstack-router"); frontends?.includes("tanstack-router");
const addonOptions = [ const addonOptions = [
{
value: "starlight" as const,
label: "Starlight",
hint: "Add Astro Starlight documentation site",
},
{ {
value: "biome" as const, value: "biome" as const,
label: "Biome", label: "Biome",

View File

@@ -62,12 +62,6 @@ export async function gatherConfig(
results.database !== "none", results.database !== "none",
results.frontend, results.frontend,
), ),
dbSetup: ({ results }) =>
getDBSetupChoice(
results.database ?? "none",
flags.dbSetup,
results.orm,
),
addons: ({ results }) => getAddonsChoice(flags.addons, results.frontend), addons: ({ results }) => getAddonsChoice(flags.addons, results.frontend),
examples: ({ results }) => examples: ({ results }) =>
getExamplesChoice( getExamplesChoice(
@@ -76,6 +70,12 @@ export async function gatherConfig(
results.frontend, results.frontend,
results.backend, results.backend,
), ),
dbSetup: ({ results }) =>
getDBSetupChoice(
results.database ?? "none",
flags.dbSetup,
results.orm,
),
git: () => getGitChoice(flags.git), git: () => getGitChoice(flags.git),
packageManager: () => getPackageManagerChoice(flags.packageManager), packageManager: () => getPackageManagerChoice(flags.packageManager),
noInstall: () => getNoInstallChoice(flags.noInstall), noInstall: () => getNoInstallChoice(flags.noInstall),

View File

@@ -6,7 +6,7 @@ export type ProjectDatabase =
| "none"; | "none";
export type ProjectOrm = "drizzle" | "prisma" | "none"; export type ProjectOrm = "drizzle" | "prisma" | "none";
export type ProjectPackageManager = "npm" | "pnpm" | "bun"; export type ProjectPackageManager = "npm" | "pnpm" | "bun";
export type ProjectAddons = "pwa" | "biome" | "tauri" | "husky"; export type ProjectAddons = "pwa" | "biome" | "tauri" | "husky" | "starlight";
export type ProjectBackend = "hono" | "elysia" | "express"; export type ProjectBackend = "hono" | "elysia" | "express";
export type ProjectRuntime = "node" | "bun"; export type ProjectRuntime = "node" | "bun";
export type ProjectExamples = "todo" | "ai"; export type ProjectExamples = "todo" | "ai";

View File

@@ -233,6 +233,14 @@ export const TECH_OPTIONS = {
color: "from-amber-500 to-amber-700", color: "from-amber-500 to-amber-700",
default: false, default: false,
}, },
{
id: "starlight",
name: "Starlight",
description: "Documentation site with Astro",
icon: "📚",
color: "from-teal-500 to-teal-700",
default: false,
},
{ {
id: "biome", id: "biome",
name: "Biome", name: "Biome",
@@ -379,7 +387,7 @@ export const PRESET_TEMPLATES = [
dbSetup: "turso", dbSetup: "turso",
auth: "true", auth: "true",
packageManager: "bun", packageManager: "bun",
addons: ["pwa", "biome", "husky", "tauri"], addons: ["pwa", "biome", "husky", "tauri", "starlight"],
examples: ["todo", "ai"], examples: ["todo", "ai"],
git: "true", git: "true",
install: "true", install: "true",