diff --git a/.changeset/wide-buses-carry.md b/.changeset/wide-buses-carry.md new file mode 100644 index 0000000..fa6e910 --- /dev/null +++ b/.changeset/wide-buses-carry.md @@ -0,0 +1,5 @@ +--- +"create-better-t-stack": patch +--- + +use spaces instead of commas in flags diff --git a/apps/cli/README.md b/apps/cli/README.md index 912b199..e40aec3 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -1,6 +1,6 @@ # Create Better-T-Stack CLI -A CLI tool for scaffolding type-safe full-stack apps with Hono/Elysia backends, React web frontends, and Expo native apps, all connected through tRPC. +A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations ## Quick Start @@ -49,10 +49,10 @@ Options: --orm ORM type (none, drizzle, prisma) --auth Include authentication --no-auth Exclude authentication - --frontend Frontend types (web,native or both) - --addons Additional addons (pwa,tauri,biome,husky) + --frontend Frontend types (web, native, none) + --addons Additional addons (pwa, tauri, biome, husky) --no-addons Skip all additional addons - --examples Examples to include (todo,ai) + --examples Examples to include (todo, ai) --no-examples Skip all examples --git Initialize git repository --no-git Skip git initialization @@ -75,7 +75,7 @@ npx create-better-t-stack my-app -y Create a project with specific options: ```bash -npx create-better-t-stack my-app --database postgres --orm drizzle --auth --addons pwa,biome +npx create-better-t-stack my-app --database postgres --orm drizzle --auth --addons pwa biome ``` Create a project with Elysia and Node.js runtime: @@ -85,10 +85,10 @@ npx create-better-t-stack my-app --backend elysia --runtime node Create a project with specific frontend options: ```bash -npx create-better-t-stack my-app --frontend web,native +npx create-better-t-stack my-app --frontend web native ``` Create a project with examples: ```bash -npx create-better-t-stack my-app --examples todo,ai +npx create-better-t-stack my-app --examples todo ai ``` diff --git a/apps/cli/package.json b/apps/cli/package.json index cdeea28..16255e7 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -7,10 +7,7 @@ "bin": { "create-better-t-stack": "dist/index.js" }, - "files": [ - "dist", - "template" - ], + "files": ["dist", "template"], "keywords": [], "repository": { "type": "git", diff --git a/apps/cli/src/helpers/create-project.ts b/apps/cli/src/helpers/create-project.ts index 7abdb70..5affabe 100644 --- a/apps/cli/src/helpers/create-project.ts +++ b/apps/cli/src/helpers/create-project.ts @@ -10,6 +10,7 @@ import { createReadme } from "./create-readme"; import { setupDatabase } from "./db-setup"; import { setupEnvironmentVariables } from "./env-setup"; import { setupExamples } from "./examples-setup"; +import { installDependencies } from "./install-dependencies"; import { displayPostInstallInstructions } from "./post-installation"; import { initializeGit, updatePackageConfigurations } from "./project-config"; import { setupRuntime } from "./runtime-setup"; @@ -91,6 +92,14 @@ export async function createProject(options: ProjectConfig): Promise { await updatePackageConfigurations(projectDir, options); await createReadme(projectDir, options); + if (!options.noInstall) { + await installDependencies({ + projectDir, + packageManager: options.packageManager, + addons: options.addons, + }); + } + displayPostInstallInstructions( options.database, options.projectName, diff --git a/apps/cli/src/helpers/examples-setup.ts b/apps/cli/src/helpers/examples-setup.ts index e01b036..667d8fd 100644 --- a/apps/cli/src/helpers/examples-setup.ts +++ b/apps/cli/src/helpers/examples-setup.ts @@ -81,7 +81,6 @@ app.post("/ai", async (c) => { return stream(c, (stream) => stream.pipe(result.toDataStream())); });`; - // Add the import section if (indexContent.includes("import {")) { const lastImportIndex = indexContent.lastIndexOf("import"); const endOfLastImport = indexContent.indexOf("\n", lastImportIndex); @@ -94,7 +93,6 @@ ${indexContent.substring(endOfLastImport + 1)}`; ${indexContent}`; } - // Add the route handler const trpcHandlerIndex = indexContent.indexOf('app.use("/trpc"') || indexContent.indexOf("app.use(trpc("); @@ -103,7 +101,6 @@ ${indexContent}`; ${indexContent.substring(trpcHandlerIndex)}`; } else { - // Add it near the end before export const exportIndex = indexContent.indexOf("export default"); if (exportIndex !== -1) { indexContent = `${indexContent.substring(0, exportIndex)}${aiRouteHandler} diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts index d87e02d..f04c5d1 100644 --- a/apps/cli/src/index.ts +++ b/apps/cli/src/index.ts @@ -3,13 +3,18 @@ import { Command } from "commander"; import pc from "picocolors"; import { DEFAULT_CONFIG } from "./constants"; import { createProject } from "./helpers/create-project"; -import { installDependencies } from "./helpers/install-dependencies"; import { gatherConfig } from "./prompts/config-prompts"; import type { + CLIOptions, ProjectAddons, + ProjectBackend, ProjectConfig, + ProjectDatabase, ProjectExamples, ProjectFrontend, + ProjectOrm, + ProjectPackageManager, + ProjectRuntime, } from "./types"; import { displayConfig } from "./utils/display-config"; import { generateReproducibleCommand } from "./utils/generate-reproducible-command"; @@ -36,22 +41,13 @@ async function main() { .option("--orm ", "ORM type (none, drizzle, prisma)") .option("--auth", "Include authentication") .option("--no-auth", "Exclude authentication") + .option("--frontend ", "Frontend types (web, native, none)") .option( - "--frontend ", - "Frontend types (web,native or both)", - (val) => val.split(",") as ProjectFrontend[], - ) - .option( - "--addons ", - "Additional addons (pwa,tauri,biome,husky)", - (val) => val.split(",") as ProjectAddons[], + "--addons ", + "Additional addons (pwa, tauri, biome, husky)", ) .option("--no-addons", "Skip all additional addons") - .option( - "--examples ", - "Examples to include (todo,ai)", - (val) => val.split(",") as ProjectExamples[], - ) + .option("--examples ", "Examples to include (todo, ai)") .option("--no-examples", "Skip all examples") .option("--git", "Initialize git repository") .option("--no-git", "Skip git initialization") @@ -70,93 +66,12 @@ async function main() { renderTitle(); intro(pc.magenta("Creating a new Better-T-Stack project")); - const options = program.opts(); + const options = program.opts() as CLIOptions; const projectDirectory = program.args[0]; - if ( - options.database && - !["none", "sqlite", "postgres"].includes(options.database) - ) { - cancel( - pc.red( - `Invalid database type: ${options.database}. Must be none, sqlite, or postgres.`, - ), - ); - process.exit(1); - } + validateOptions(options); - if (options.orm && !["none", "drizzle", "prisma"].includes(options.orm)) { - cancel( - pc.red( - `Invalid ORM type: ${options.orm}. Must be none, drizzle, or prisma.`, - ), - ); - process.exit(1); - } - - if ( - options.packageManager && - !["npm", "pnpm", "bun"].includes(options.packageManager) - ) { - cancel( - pc.red( - `Invalid package manager: ${options.packageManager}. Must be npm, pnpm, or bun.`, - ), - ); - process.exit(1); - } - - if (options.backend && !["hono", "elysia"].includes(options.backend)) { - cancel( - pc.red( - `Invalid backend framework: ${options.backend}. Must be hono or elysia.`, - ), - ); - process.exit(1); - } - - if (options.runtime && !["bun", "node"].includes(options.runtime)) { - cancel( - pc.red(`Invalid runtime: ${options.runtime}. Must be bun or node.`), - ); - process.exit(1); - } - - if (options.examples && options.examples.length > 0) { - const validExamples = ["todo", "ai"]; - const invalidExamples = options.examples.filter( - (example: ProjectExamples) => !validExamples.includes(example), - ); - - if (invalidExamples.length > 0) { - cancel( - pc.red( - `Invalid example(s): ${invalidExamples.join(", ")}. Valid options are: ${validExamples.join(", ")}.`, - ), - ); - process.exit(1); - } - } - - const flagConfig: Partial = { - ...(projectDirectory && { projectName: projectDirectory }), - ...(options.database && { database: options.database }), - ...(options.orm && { orm: options.orm }), - ...("auth" in options && { auth: options.auth }), - ...(options.packageManager && { packageManager: options.packageManager }), - ...("git" in options && { git: options.git }), - ...("install" in options && { noInstall: !options.install }), - ...("turso" in options && { turso: options.turso }), - ...(options.backend && { backend: options.backend }), - ...(options.runtime && { runtime: options.runtime }), - ...(options.frontend && { frontend: options.frontend }), - ...((options.addons || options.addons === false) && { - addons: options.addons === false ? [] : options.addons, - }), - ...((options.examples || options.examples === false) && { - examples: options.examples === false ? [] : options.examples, - }), - }; + const flagConfig = processFlags(options, projectDirectory); if (!options.yes && Object.keys(flagConfig).length > 0) { log.info(pc.yellow("Using these pre-selected options:")); @@ -178,15 +93,7 @@ async function main() { log.message(""); } - const projectDir = await createProject(config); - - if (!config.noInstall) { - await installDependencies({ - projectDir, - packageManager: config.packageManager, - addons: config.addons, - }); - } + await createProject(config); log.success( pc.blue( @@ -211,6 +118,322 @@ async function main() { } } +function validateOptions(options: CLIOptions): void { + if ( + options.database && + !["none", "sqlite", "postgres"].includes(options.database) + ) { + cancel( + pc.red( + `Invalid database type: ${options.database}. Must be none, sqlite, or postgres.`, + ), + ); + process.exit(1); + } + + if (options.orm && !["none", "drizzle", "prisma"].includes(options.orm)) { + cancel( + pc.red( + `Invalid ORM type: ${options.orm}. Must be none, drizzle, or prisma.`, + ), + ); + process.exit(1); + } + + if (options.database === "none") { + if (options.auth === true) { + cancel( + pc.red( + "Authentication requires a database. Cannot use --auth with --database none.", + ), + ); + process.exit(1); + } + + if (options.orm && options.orm !== "none") { + cancel( + pc.red( + `Cannot use ORM with no database. Cannot use --orm ${options.orm} with --database none.`, + ), + ); + process.exit(1); + } + + if ("turso" in options && options.turso === true) { + cancel( + pc.red( + "Turso setup requires a SQLite database. Cannot use --turso with --database none.", + ), + ); + process.exit(1); + } + } + + if ( + "turso" in options && + options.turso === true && + options.database && + options.database !== "sqlite" + ) { + cancel( + pc.red( + `Turso setup requires a SQLite database. Cannot use --turso with --database ${options.database}`, + ), + ); + process.exit(1); + } + + if ( + "turso" in options && + options.turso === true && + options.orm === "prisma" + ) { + cancel( + pc.red( + "Turso setup is not compatible with Prisma. Cannot use --turso with --orm prisma", + ), + ); + process.exit(1); + } + + if ( + options.packageManager && + !["npm", "pnpm", "bun"].includes(options.packageManager) + ) { + cancel( + pc.red( + `Invalid package manager: ${options.packageManager}. Must be npm, pnpm, or bun.`, + ), + ); + process.exit(1); + } + + if (options.backend && !["hono", "elysia"].includes(options.backend)) { + cancel( + pc.red( + `Invalid backend framework: ${options.backend}. Must be hono or elysia.`, + ), + ); + process.exit(1); + } + + if (options.runtime && !["bun", "node"].includes(options.runtime)) { + cancel(pc.red(`Invalid runtime: ${options.runtime}. Must be bun or node.`)); + process.exit(1); + } + + if ( + options.examples && + Array.isArray(options.examples) && + options.examples.length > 0 + ) { + const validExamples = ["todo", "ai"]; + const invalidExamples = options.examples.filter( + (example: string) => !validExamples.includes(example), + ); + + if (invalidExamples.length > 0) { + cancel( + pc.red( + `Invalid example(s): ${invalidExamples.join(", ")}. Valid options are: ${validExamples.join(", ")}.`, + ), + ); + process.exit(1); + } + + if (options.examples.includes("ai") && options.backend === "elysia") { + cancel( + pc.red( + "AI example is only compatible with Hono backend. Cannot use --examples ai with --backend elysia", + ), + ); + process.exit(1); + } + + if ( + options.frontend && + !options.frontend.includes("web") && + !options.frontend.includes("none") + ) { + cancel( + pc.red( + "Examples require a web frontend. Cannot use --examples with --frontend native only", + ), + ); + process.exit(1); + } + } + + if (options.frontend && options.frontend.length > 0) { + const validFrontends = ["web", "native", "none"]; + const invalidFrontends = options.frontend.filter( + (frontend: string) => !validFrontends.includes(frontend), + ); + + if (invalidFrontends.length > 0) { + cancel( + pc.red( + `Invalid frontend(s): ${invalidFrontends.join(", ")}. Valid options are: ${validFrontends.join(", ")}.`, + ), + ); + process.exit(1); + } + + if (options.frontend.includes("none") && options.frontend.length > 1) { + cancel(pc.red(`Cannot combine 'none' with other frontend options.`)); + process.exit(1); + } + } + + if (options.addons && options.addons.length > 0) { + const validAddons = ["pwa", "tauri", "biome", "husky"]; + const invalidAddons = options.addons.filter( + (addon: string) => !validAddons.includes(addon), + ); + + if (invalidAddons.length > 0) { + cancel( + pc.red( + `Invalid addon(s): ${invalidAddons.join(", ")}. Valid options are: ${validAddons.join(", ")}.`, + ), + ); + process.exit(1); + } + + const webSpecificAddons = ["pwa", "tauri"]; + const hasWebSpecificAddons = options.addons.some((addon) => + webSpecificAddons.includes(addon), + ); + + if ( + hasWebSpecificAddons && + options.frontend && + !options.frontend.includes("web") && + !options.frontend.includes("none") + ) { + cancel( + pc.red( + `PWA and Tauri addons require a web frontend. Cannot use --addons ${options.addons + .filter((a) => webSpecificAddons.includes(a)) + .join(", ")} with --frontend native only`, + ), + ); + process.exit(1); + } + } +} + +function processFlags( + options: CLIOptions, + projectDirectory?: string, +): Partial { + let frontend: ProjectFrontend[] | undefined = undefined; + if (options.frontend) { + if (options.frontend.includes("none")) { + frontend = []; + } else { + frontend = options.frontend.filter( + (f): f is ProjectFrontend => f === "web" || f === "native", + ); + } + } + + const database = options.database as ProjectDatabase | undefined; + let orm: ProjectOrm | undefined; + if (options.orm) { + orm = options.orm as ProjectOrm; + } + + let auth: boolean | undefined = "auth" in options ? options.auth : undefined; + let tursoOption: boolean | undefined = + "turso" in options ? options.turso : undefined; + + if (database === "none") { + orm = "none"; + auth = false; + tursoOption = false; + } + + let examples: ProjectExamples[] | undefined; + if ("examples" in options) { + if (options.examples === false) { + examples = []; + } else if (Array.isArray(options.examples)) { + examples = options.examples.filter( + (ex): ex is ProjectExamples => ex === "todo" || ex === "ai", + ); + + if (frontend && frontend.length > 0 && !frontend.includes("web")) { + examples = []; + log.warn( + pc.yellow("Examples require web frontend - ignoring examples flag"), + ); + } + + if (examples.includes("ai") && options.backend === "elysia") { + examples = examples.filter((ex) => ex !== "ai"); + log.warn( + pc.yellow( + "AI example is not compatible with Elysia - removing AI example", + ), + ); + } + } + } + + let addons: ProjectAddons[] | undefined; + if ("addons" in options) { + if (options.addons === undefined) { + addons = []; + } else if (options.addons) { + addons = options.addons.filter( + (addon): addon is ProjectAddons => + addon === "pwa" || + addon === "tauri" || + addon === "biome" || + addon === "husky", + ); + + if (frontend && frontend.length > 0 && !frontend.includes("web")) { + addons = addons.filter((addon) => !["pwa", "tauri"].includes(addon)); + if (addons.length !== options.addons.length) { + log.warn( + pc.yellow( + "PWA and Tauri addons require web frontend - removing these addons", + ), + ); + } + } + + if (addons.includes("husky") && !addons.includes("biome")) { + addons.push("biome"); + } + } + } + + const backend = options.backend as ProjectBackend | undefined; + const runtime = options.runtime as ProjectRuntime | undefined; + const packageManager = options.packageManager as + | ProjectPackageManager + | undefined; + + return { + ...(projectDirectory && { projectName: projectDirectory }), + ...(database !== undefined && { database }), + ...(orm !== undefined && { orm }), + ...(auth !== undefined && { auth }), + ...(packageManager && { packageManager }), + ...("git" in options && { git: options.git }), + ...("install" in options && { noInstall: !options.install }), + ...(tursoOption !== undefined && { turso: tursoOption }), + ...(backend && { backend }), + ...(runtime && { runtime }), + ...(frontend !== undefined && { frontend }), + ...(addons !== undefined && { addons }), + ...(examples !== undefined && { examples }), + }; +} + main().catch((err) => { log.error("Aborting installation..."); if (err instanceof Error) { diff --git a/apps/cli/src/types.ts b/apps/cli/src/types.ts index 2c2b376..fd62bc5 100644 --- a/apps/cli/src/types.ts +++ b/apps/cli/src/types.ts @@ -22,3 +22,19 @@ export interface ProjectConfig { turso?: boolean; frontend: ProjectFrontend[]; } + +export type CLIOptions = { + yes?: boolean; + database?: string; + orm?: string; + auth?: boolean; + frontend?: string[]; + addons?: string[]; + examples?: string[] | boolean; + git?: boolean; + packageManager?: string; + install?: boolean; + turso?: boolean; + backend?: string; + runtime?: string; +}; diff --git a/apps/cli/src/utils/generate-reproducible-command.ts b/apps/cli/src/utils/generate-reproducible-command.ts index 0868de3..cc01055 100644 --- a/apps/cli/src/utils/generate-reproducible-command.ts +++ b/apps/cli/src/utils/generate-reproducible-command.ts @@ -32,17 +32,17 @@ export function generateReproducibleCommand(config: ProjectConfig): string { } if (config.frontend && config.frontend.length > 0) { - flags.push(`--frontend ${config.frontend.join(",")}`); + flags.push(`--frontend ${config.frontend.join(" ")}`); } if (config.addons && config.addons.length > 0) { - flags.push(`--addons ${config.addons.join(",")}`); + flags.push(`--addons ${config.addons.join(" ")}`); } else { flags.push("--no-addons"); } if (config.examples && config.examples.length > 0) { - flags.push(`--examples ${config.examples.join(",")}`); + flags.push(`--examples ${config.examples.join(" ")}`); } else { flags.push("--no-examples"); } diff --git a/apps/cli/template/base/apps/native/lib/constants.ts b/apps/cli/template/base/apps/native/lib/constants.ts index b2030fd..b1dd3db 100644 --- a/apps/cli/template/base/apps/native/lib/constants.ts +++ b/apps/cli/template/base/apps/native/lib/constants.ts @@ -1,18 +1,18 @@ export const NAV_THEME = { light: { - background: "hsl(0 0% 100%)", // background - border: "hsl(240 5.9% 90%)", // border - card: "hsl(0 0% 100%)", // card - notification: "hsl(0 84.2% 60.2%)", // destructive - primary: "hsl(240 5.9% 10%)", // primary - text: "hsl(240 10% 3.9%)", // foreground + background: "hsl(0 0% 100%)", + border: "hsl(240 5.9% 90%)", + card: "hsl(0 0% 100%)", + notification: "hsl(0 84.2% 60.2%)", + primary: "hsl(240 5.9% 10%)", + text: "hsl(240 10% 3.9%)", }, dark: { - background: "hsl(240 10% 3.9%)", // background - border: "hsl(240 3.7% 15.9%)", // border - card: "hsl(240 10% 3.9%)", // card - notification: "hsl(0 72% 51%)", // destructive - primary: "hsl(0 0% 98%)", // primary - text: "hsl(0 0% 98%)", // foreground + background: "hsl(240 10% 3.9%)", + border: "hsl(240 3.7% 15.9%)", + card: "hsl(240 10% 3.9%)", + notification: "hsl(0 72% 51%)", + primary: "hsl(0 0% 98%)", + text: "hsl(0 0% 98%)", }, }; diff --git a/apps/cli/template/with-auth/apps/server/src/with-elysia-index.ts b/apps/cli/template/with-auth/apps/server/src/with-elysia-index.ts index e1d0f13..84577a1 100644 --- a/apps/cli/template/with-auth/apps/server/src/with-elysia-index.ts +++ b/apps/cli/template/with-auth/apps/server/src/with-elysia-index.ts @@ -19,9 +19,8 @@ const app = new Elysia() const { request } = context; if (["POST", "GET"].includes(request.method)) { return auth.handler(request); - } else { - context.error(405); } + context.error(405); }) .all("/trpc/*", async (context) => { const res = await fetchRequestHandler({ @@ -34,5 +33,5 @@ const app = new Elysia() }) .get("/", () => "OK") .listen(3000, () => { - console.log(`Server is running on http://localhost:3000`); + console.log("Server is running on http://localhost:3000"); }); diff --git a/apps/web/src/app/(home)/_components/StackArchitech.tsx b/apps/web/src/app/(home)/_components/StackArchitech.tsx index b50fb44..7a36e8b 100644 --- a/apps/web/src/app/(home)/_components/StackArchitech.tsx +++ b/apps/web/src/app/(home)/_components/StackArchitech.tsx @@ -393,72 +393,58 @@ const StackArchitect = () => { } const projectName = stackState.projectName || "my-better-t-app"; - const flags: string[] = ["--yes"]; // Start with yes flag + const flags: string[] = ["--yes"]; - // Only add flags that differ from defaults - - // Frontend (default is web) if (stackState.frontend.length === 1 && stackState.frontend[0] === "none") { flags.push("--frontend none"); } else if ( !(stackState.frontend.length === 1 && stackState.frontend[0] === "web") ) { - flags.push(`--frontend ${stackState.frontend.join(",")}`); + flags.push(`--frontend ${stackState.frontend.join(" ")}`); } - // Database (default is sqlite) if (stackState.database !== "sqlite") { flags.push(`--database ${stackState.database}`); } - // ORM (default is drizzle) if (stackState.database !== "none" && stackState.orm !== "drizzle") { flags.push(`--orm ${stackState.orm}`); } - // Auth (default is true) if (stackState.auth === "false") { flags.push("--no-auth"); } - // Turso (default is false) if (stackState.turso === "true") { flags.push("--turso"); } - // Backend (default is hono) if (stackState.backendFramework !== "hono") { flags.push(`--backend ${stackState.backendFramework}`); } - // Runtime (default is bun) if (stackState.runtime !== "bun") { flags.push(`--runtime ${stackState.runtime}`); } - // Package manager (default is bun) if (stackState.packageManager !== "bun") { flags.push(`--package-manager ${stackState.packageManager}`); } - // Git (default is true) if (stackState.git === "false") { flags.push("--no-git"); } - // Install (default is true) if (stackState.install === "false") { flags.push("--no-install"); } - // Addons (default is none) if (stackState.addons.length > 0) { - flags.push(`--addons ${stackState.addons.join(",")}`); + flags.push(`--addons ${stackState.addons.join(" ")}`); } - // Examples (default is none) if (stackState.examples.length > 0) { - flags.push(`--examples ${stackState.examples.join(",")}`); + flags.push(`--examples ${stackState.examples.join(" ")}`); } return `${base} ${projectName} ${flags.join(" ")}`; @@ -486,7 +472,6 @@ const StackArchitect = () => { if (currentSelection.includes(techId)) { if (currentSelection.length === 1) { - // Don't remove the last frontend option return prev; } @@ -512,9 +497,7 @@ const StackArchitect = () => { }; } - // Adding a frontend option if (currentSelection.includes("none")) { - // Replace "none" with the selected option return { ...prev, frontend: [techId], diff --git a/apps/web/src/app/(home)/_components/Testimonials.tsx b/apps/web/src/app/(home)/_components/Testimonials.tsx index 6ef4a8e..6613d0f 100644 --- a/apps/web/src/app/(home)/_components/Testimonials.tsx +++ b/apps/web/src/app/(home)/_components/Testimonials.tsx @@ -42,7 +42,6 @@ export default function Testimonials() { return () => window.removeEventListener("resize", handleResize); }, []); - // Get visible tweets const getVisibleTweets = () => { const visible = []; for (let i = 0; i < tweetsPerPage; i++) { diff --git a/apps/web/src/app/layout.config.tsx b/apps/web/src/app/layout.config.tsx index 6d9d957..2e62b1f 100644 --- a/apps/web/src/app/layout.config.tsx +++ b/apps/web/src/app/layout.config.tsx @@ -9,7 +9,6 @@ import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared"; */ export const baseOptions: BaseLayoutProps = { nav: { - // can be JSX too! title: "Better-T-Stack", enabled: false, }, diff --git a/package.json b/package.json index 93b43d9..7f32a4c 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "typescript": "5.7.3" }, "lint-staged": { - "*": ["biome check --write ."] + "*": ["bun biome check --write ."] }, "engines": { "node": ">=20"