From 31b6cc7109de4a962c7d5d925b7c5a69146f3b33 Mon Sep 17 00:00:00 2001 From: Aman Varshney Date: Thu, 8 May 2025 14:27:05 +0530 Subject: [PATCH] fix stack builder --- apps/web/package.json | 1 + .../app/(home)/_components/StackArchitech.tsx | 1001 ++++++++--------- apps/web/src/components/ui/dialog.tsx | 134 +++ bun.lock | 89 +- 4 files changed, 700 insertions(+), 525 deletions(-) create mode 100644 apps/web/src/components/ui/dialog.tsx diff --git a/apps/web/package.json b/apps/web/package.json index 1835d08..c206196 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,6 +10,7 @@ "postinstall": "fumadocs-mdx" }, "dependencies": { + "@radix-ui/react-dialog": "^1.1.13", "@radix-ui/react-scroll-area": "^1.2.6", "@radix-ui/react-switch": "^1.2.2", "@radix-ui/react-tooltip": "^1.2.4", diff --git a/apps/web/src/app/(home)/_components/StackArchitech.tsx b/apps/web/src/app/(home)/_components/StackArchitech.tsx index 8b482e2..4540685 100644 --- a/apps/web/src/app/(home)/_components/StackArchitech.tsx +++ b/apps/web/src/app/(home)/_components/StackArchitech.tsx @@ -395,332 +395,323 @@ const analyzeStackCompatibility = (stack: StackState): CompatibilityResult => { message: "ORM set to 'Drizzle' (Mongoose only works with MongoDB)", }); } - if (nextStack.dbSetup === "mongodb-atlas") { - notes.database.notes.push( - "Relational databases are not compatible with MongoDB Atlas setup. DB Setup will be reset.", - ); - notes.dbSetup.notes.push( - "MongoDB Atlas setup requires MongoDB. It will be reset to 'Basic Setup'.", - ); - notes.database.hasIssue = true; - notes.dbSetup.hasIssue = true; - nextStack.dbSetup = "none"; - changed = true; - changes.push({ - category: "database", - message: "DB Setup reset to 'None' (MongoDB Atlas requires MongoDB)", - }); + if (nextStack.dbSetup === "turso") { + if (nextStack.database !== "sqlite") { + notes.dbSetup.notes.push( + "Turso requires SQLite. It will be selected.", + ); + notes.database.notes.push( + "Turso DB setup requires SQLite. It will be selected.", + ); + notes.dbSetup.hasIssue = true; + notes.database.hasIssue = true; + nextStack.database = "sqlite"; + changed = true; + changes.push({ + category: "dbSetup", + message: "Database set to 'SQLite' (required by Turso)", + }); + } + if (nextStack.orm !== "drizzle") { + notes.dbSetup.notes.push( + "Turso requires Drizzle ORM. It will be selected.", + ); + notes.orm.notes.push( + "Turso DB setup requires Drizzle ORM. It will be selected.", + ); + notes.dbSetup.hasIssue = true; + notes.orm.hasIssue = true; + nextStack.orm = "drizzle"; + changed = true; + changes.push({ + category: "dbSetup", + message: "ORM set to 'Drizzle' (required by Turso)", + }); + } + } else if (nextStack.dbSetup === "prisma-postgres") { + if (nextStack.database !== "postgres") { + notes.dbSetup.notes.push("Requires PostgreSQL. It will be selected."); + notes.database.notes.push( + "Prisma PostgreSQL setup requires PostgreSQL. It will be selected.", + ); + notes.dbSetup.hasIssue = true; + notes.database.hasIssue = true; + nextStack.database = "postgres"; + changed = true; + changes.push({ + category: "dbSetup", + message: + "Database set to 'PostgreSQL' (required by Prisma PostgreSQL setup)", + }); + } + if (nextStack.orm !== "prisma") { + notes.dbSetup.notes.push("Requires Prisma ORM. It will be selected."); + notes.orm.notes.push( + "Prisma PostgreSQL setup requires Prisma ORM. It will be selected.", + ); + notes.dbSetup.hasIssue = true; + notes.orm.hasIssue = true; + nextStack.orm = "prisma"; + changed = true; + changes.push({ + category: "dbSetup", + message: + "ORM set to 'Prisma' (required by Prisma PostgreSQL setup)", + }); + } + } else if (nextStack.dbSetup === "mongodb-atlas") { + if (nextStack.database !== "mongodb") { + notes.dbSetup.notes.push("Requires MongoDB. It will be selected."); + notes.database.notes.push( + "MongoDB Atlas setup requires MongoDB. It will be selected.", + ); + notes.dbSetup.hasIssue = true; + notes.database.hasIssue = true; + nextStack.database = "mongodb"; + changed = true; + changes.push({ + category: "dbSetup", + message: + "Database set to 'MongoDB' (required by MongoDB Atlas setup)", + }); + } + if (nextStack.orm !== "prisma" && nextStack.orm !== "mongoose") { + notes.dbSetup.notes.push( + "Requires Prisma or Mongoose ORM. Prisma will be selected.", + ); + notes.orm.notes.push( + "MongoDB Atlas setup requires Prisma or Mongoose ORM. Prisma will be selected.", + ); + notes.dbSetup.hasIssue = true; + notes.orm.hasIssue = true; + nextStack.orm = "prisma"; + changed = true; + changes.push({ + category: "dbSetup", + message: + "ORM set to 'Prisma' (MongoDB Atlas requires Prisma or Mongoose)", + }); + } + } else if (nextStack.dbSetup === "neon") { + if (nextStack.database !== "postgres") { + notes.dbSetup.notes.push( + "Neon requires PostgreSQL. It will be selected.", + ); + notes.database.notes.push( + "Neon DB setup requires PostgreSQL. It will be selected.", + ); + notes.dbSetup.hasIssue = true; + notes.database.hasIssue = true; + nextStack.database = "postgres"; + changed = true; + changes.push({ + category: "dbSetup", + message: "Database set to 'PostgreSQL' (required by Neon)", + }); + } } - } - if (nextStack.dbSetup === "turso") { - if (nextStack.database !== "sqlite") { - notes.dbSetup.notes.push("Turso requires SQLite. It will be selected."); - notes.database.notes.push( - "Turso DB setup requires SQLite. It will be selected.", + const isNuxt = nextStack.frontend.includes("nuxt"); + const isSvelte = nextStack.frontend.includes("svelte"); + const isSolid = nextStack.frontend.includes("solid"); + if ((isNuxt || isSvelte || isSolid) && nextStack.api === "trpc") { + const frontendName = isNuxt ? "Nuxt" : isSvelte ? "Svelte" : "Solid"; + notes.api.notes.push( + `${frontendName} requires oRPC. It will be selected automatically.`, ); - notes.dbSetup.hasIssue = true; - notes.database.hasIssue = true; - nextStack.database = "sqlite"; - changed = true; - changes.push({ - category: "dbSetup", - message: "Database set to 'SQLite' (required by Turso)", - }); - } - if (nextStack.orm !== "drizzle") { - notes.dbSetup.notes.push( - "Turso requires Drizzle ORM. It will be selected.", - ); - notes.orm.notes.push( - "Turso DB setup requires Drizzle ORM. It will be selected.", - ); - notes.dbSetup.hasIssue = true; - notes.orm.hasIssue = true; - nextStack.orm = "drizzle"; - changed = true; - changes.push({ - category: "dbSetup", - message: "ORM set to 'Drizzle' (required by Turso)", - }); - } - } else if (nextStack.dbSetup === "prisma-postgres") { - if (nextStack.database !== "postgres") { - notes.dbSetup.notes.push("Requires PostgreSQL. It will be selected."); - notes.database.notes.push( - "Prisma PostgreSQL setup requires PostgreSQL. It will be selected.", - ); - notes.dbSetup.hasIssue = true; - notes.database.hasIssue = true; - nextStack.database = "postgres"; - changed = true; - changes.push({ - category: "dbSetup", - message: - "Database set to 'PostgreSQL' (required by Prisma PostgreSQL setup)", - }); - } - if (nextStack.orm !== "prisma") { - notes.dbSetup.notes.push("Requires Prisma ORM. It will be selected."); - notes.orm.notes.push( - "Prisma PostgreSQL setup requires Prisma ORM. It will be selected.", - ); - notes.dbSetup.hasIssue = true; - notes.orm.hasIssue = true; - nextStack.orm = "prisma"; - changed = true; - changes.push({ - category: "dbSetup", - message: "ORM set to 'Prisma' (required by Prisma PostgreSQL setup)", - }); - } - } else if (nextStack.dbSetup === "mongodb-atlas") { - if (nextStack.database !== "mongodb") { - notes.dbSetup.notes.push("Requires MongoDB. It will be selected."); - notes.database.notes.push( - "MongoDB Atlas setup requires MongoDB. It will be selected.", - ); - notes.dbSetup.hasIssue = true; - notes.database.hasIssue = true; - nextStack.database = "mongodb"; - changed = true; - changes.push({ - category: "dbSetup", - message: - "Database set to 'MongoDB' (required by MongoDB Atlas setup)", - }); - } - if (nextStack.orm !== "prisma" && nextStack.orm !== "mongoose") { - notes.dbSetup.notes.push( - "Requires Prisma or Mongoose ORM. Prisma will be selected.", - ); - notes.orm.notes.push( - "MongoDB Atlas setup requires Prisma or Mongoose ORM. Prisma will be selected.", - ); - notes.dbSetup.hasIssue = true; - notes.orm.hasIssue = true; - nextStack.orm = "prisma"; - changed = true; - changes.push({ - category: "dbSetup", - message: - "ORM set to 'Prisma' (MongoDB Atlas requires Prisma or Mongoose)", - }); - } - } else if (nextStack.dbSetup === "neon") { - if (nextStack.database !== "postgres") { - notes.dbSetup.notes.push( - "Neon requires PostgreSQL. It will be selected.", - ); - notes.database.notes.push( - "Neon DB setup requires PostgreSQL. It will be selected.", - ); - notes.dbSetup.hasIssue = true; - notes.database.hasIssue = true; - nextStack.database = "postgres"; - changed = true; - changes.push({ - category: "dbSetup", - message: "Database set to 'PostgreSQL' (required by Neon)", - }); - } - } - - const isNuxt = nextStack.frontend.includes("nuxt"); - const isSvelte = nextStack.frontend.includes("svelte"); - const isSolid = nextStack.frontend.includes("solid"); - if ((isNuxt || isSvelte || isSolid) && nextStack.api === "trpc") { - const frontendName = isNuxt ? "Nuxt" : isSvelte ? "Svelte" : "Solid"; - notes.api.notes.push( - `${frontendName} requires oRPC. It will be selected automatically.`, - ); - notes.frontend.notes.push( - `Selected ${frontendName}: API will be set to oRPC.`, - ); - notes.api.hasIssue = true; - notes.frontend.hasIssue = true; - nextStack.api = "orpc"; - changed = true; - changes.push({ - category: "api", - message: `API set to 'oRPC' (required by ${frontendName})`, - }); - } - - const incompatibleAddons: string[] = []; - const isPWACompat = hasPWACompatibleFrontend(nextStack.frontend); - const isTauriCompat = hasTauriCompatibleFrontend(nextStack.frontend); - - if (!isPWACompat && nextStack.addons.includes("pwa")) { - incompatibleAddons.push("pwa"); - notes.frontend.notes.push( - "PWA addon requires TanStack/React Router or Solid. Addon will be removed.", - ); - notes.addons.notes.push( - "PWA requires TanStack/React Router/Solid. It will be removed.", - ); - notes.frontend.hasIssue = true; - notes.addons.hasIssue = true; - changes.push({ - category: "addons", - message: "PWA addon removed (requires compatible frontend)", - }); - } - if (!isTauriCompat && nextStack.addons.includes("tauri")) { - incompatibleAddons.push("tauri"); - notes.frontend.notes.push( - "Tauri addon requires TanStack/React Router, Nuxt, Svelte or Solid. Addon will be removed.", - ); - notes.addons.notes.push( - "Tauri requires TanStack/React Router/Nuxt/Svelte/Solid. It will be removed.", - ); - notes.frontend.hasIssue = true; - notes.addons.hasIssue = true; - changes.push({ - category: "addons", - message: "Tauri addon removed (requires compatible frontend)", - }); - } - - const originalAddonsLength = nextStack.addons.length; - if (incompatibleAddons.length > 0) { - nextStack.addons = nextStack.addons.filter( - (addon) => !incompatibleAddons.includes(addon), - ); - if (nextStack.addons.length !== originalAddonsLength) changed = true; - } - - if ( - nextStack.addons.includes("husky") && - !nextStack.addons.includes("biome") - ) { - notes.addons.notes.push( - "Husky addon is selected without Biome. Consider adding Biome for lint-staged integration.", - ); - } - - const incompatibleExamples: string[] = []; - const isWeb = hasWebFrontend(nextStack.frontend); - const isNativeOnly = checkHasNativeFrontend(nextStack.frontend) && !isWeb; - - if (isNativeOnly) { - if (nextStack.examples.length > 0) { notes.frontend.notes.push( - "Examples are not supported with Native-only frontend. Examples will be removed.", + `Selected ${frontendName}: API will be set to oRPC.`, ); - notes.examples.notes.push( - "Examples require a web frontend. They will be removed.", + notes.api.hasIssue = true; + notes.frontend.hasIssue = true; + nextStack.api = "orpc"; + changed = true; + changes.push({ + category: "api", + message: `API set to 'oRPC' (required by ${frontendName})`, + }); + } + + const incompatibleAddons: string[] = []; + const isPWACompat = hasPWACompatibleFrontend(nextStack.frontend); + const isTauriCompat = hasTauriCompatibleFrontend(nextStack.frontend); + + if (!isPWACompat && nextStack.addons.includes("pwa")) { + incompatibleAddons.push("pwa"); + notes.frontend.notes.push( + "PWA addon requires TanStack/React Router or Solid. Addon will be removed.", + ); + notes.addons.notes.push( + "PWA requires TanStack/React Router/Solid. It will be removed.", ); notes.frontend.hasIssue = true; - notes.examples.hasIssue = true; - incompatibleExamples.push(...nextStack.examples); + notes.addons.hasIssue = true; changes.push({ - category: "examples", - message: "Examples removed (not supported with Native-only frontend)", + category: "addons", + message: "PWA addon removed (requires compatible frontend)", }); } - } else { - if (!isWeb) { - if (nextStack.examples.includes("todo")) { + if (!isTauriCompat && nextStack.addons.includes("tauri")) { + incompatibleAddons.push("tauri"); + notes.frontend.notes.push( + "Tauri addon requires TanStack/React Router, Nuxt, Svelte or Solid. Addon will be removed.", + ); + notes.addons.notes.push( + "Tauri requires TanStack/React Router/Nuxt/Svelte/Solid. It will be removed.", + ); + notes.frontend.hasIssue = true; + notes.addons.hasIssue = true; + changes.push({ + category: "addons", + message: "Tauri addon removed (requires compatible frontend)", + }); + } + + const originalAddonsLength = nextStack.addons.length; + if (incompatibleAddons.length > 0) { + nextStack.addons = nextStack.addons.filter( + (addon) => !incompatibleAddons.includes(addon), + ); + if (nextStack.addons.length !== originalAddonsLength) changed = true; + } + + if ( + nextStack.addons.includes("husky") && + !nextStack.addons.includes("biome") + ) { + notes.addons.notes.push( + "Husky addon is selected without Biome. Consider adding Biome for lint-staged integration.", + ); + } + + const incompatibleExamples: string[] = []; + const isWeb = hasWebFrontend(nextStack.frontend); + const isNativeOnly = checkHasNativeFrontend(nextStack.frontend) && !isWeb; + + if (isNativeOnly) { + if (nextStack.examples.length > 0) { + notes.frontend.notes.push( + "Examples are not supported with Native-only frontend. Examples will be removed.", + ); + notes.examples.notes.push( + "Examples require a web frontend. They will be removed.", + ); + notes.frontend.hasIssue = true; + notes.examples.hasIssue = true; + incompatibleExamples.push(...nextStack.examples); + changes.push({ + category: "examples", + message: + "Examples removed (not supported with Native-only frontend)", + }); + } + } else { + if (!isWeb) { + if (nextStack.examples.includes("todo")) { + incompatibleExamples.push("todo"); + changes.push({ + category: "examples", + message: "Todo example removed (requires web frontend)", + }); + } + if (nextStack.examples.includes("ai")) { + incompatibleExamples.push("ai"); + changes.push({ + category: "examples", + message: "AI example removed (requires web frontend)", + }); + } + } + if ( + nextStack.database === "none" && + nextStack.examples.includes("todo") + ) { incompatibleExamples.push("todo"); changes.push({ category: "examples", - message: "Todo example removed (requires web frontend)", + message: "Todo example removed (requires a database)", }); } - if (nextStack.examples.includes("ai")) { + if ( + nextStack.backend === "elysia" && + nextStack.examples.includes("ai") + ) { incompatibleExamples.push("ai"); changes.push({ category: "examples", - message: "AI example removed (requires web frontend)", + message: "AI example removed (not compatible with Elysia)", + }); + } + if (isSolid && nextStack.examples.includes("ai")) { + incompatibleExamples.push("ai"); + changes.push({ + category: "examples", + message: "AI example removed (not compatible with Solid)", }); } } - if ( - nextStack.database === "none" && - nextStack.examples.includes("todo") - ) { - incompatibleExamples.push("todo"); - changes.push({ - category: "examples", - message: "Todo example removed (requires a database)", - }); - } - if (nextStack.backend === "elysia" && nextStack.examples.includes("ai")) { - incompatibleExamples.push("ai"); - changes.push({ - category: "examples", - message: "AI example removed (not compatible with Elysia)", - }); - } - if (isSolid && nextStack.examples.includes("ai")) { - incompatibleExamples.push("ai"); - changes.push({ - category: "examples", - message: "AI example removed (not compatible with Solid)", - }); - } - } - const uniqueIncompatibleExamples = [...new Set(incompatibleExamples)]; - if (uniqueIncompatibleExamples.length > 0) { - if (!isWeb && !isNativeOnly) { + const uniqueIncompatibleExamples = [...new Set(incompatibleExamples)]; + if (uniqueIncompatibleExamples.length > 0) { + if (!isWeb && !isNativeOnly) { + if ( + uniqueIncompatibleExamples.includes("todo") || + uniqueIncompatibleExamples.includes("ai") + ) { + notes.frontend.notes.push( + "Examples require a web frontend. Incompatible examples will be removed.", + ); + notes.examples.notes.push( + "Requires a web frontend. Incompatible examples will be removed.", + ); + notes.frontend.hasIssue = true; + notes.examples.hasIssue = true; + } + } if ( - uniqueIncompatibleExamples.includes("todo") || - uniqueIncompatibleExamples.includes("ai") + nextStack.database === "none" && + uniqueIncompatibleExamples.includes("todo") ) { - notes.frontend.notes.push( - "Examples require a web frontend. Incompatible examples will be removed.", + notes.database.notes.push( + "Todo example requires a database. It will be removed.", ); notes.examples.notes.push( - "Requires a web frontend. Incompatible examples will be removed.", + "Todo example requires a database. It will be removed.", + ); + notes.database.hasIssue = true; + notes.examples.hasIssue = true; + } + if ( + nextStack.backend === "elysia" && + uniqueIncompatibleExamples.includes("ai") + ) { + notes.backend.notes.push( + "AI example is not compatible with Elysia. It will be removed.", + ); + notes.examples.notes.push( + "AI example is not compatible with Elysia. It will be removed.", + ); + notes.backend.hasIssue = true; + notes.examples.hasIssue = true; + } + if (isSolid && uniqueIncompatibleExamples.includes("ai")) { + notes.frontend.notes.push( + "AI example is not compatible with Solid. It will be removed.", + ); + notes.examples.notes.push( + "AI example is not compatible with Solid. It will be removed.", ); notes.frontend.hasIssue = true; notes.examples.hasIssue = true; } - } - if ( - nextStack.database === "none" && - uniqueIncompatibleExamples.includes("todo") - ) { - notes.database.notes.push( - "Todo example requires a database. It will be removed.", - ); - notes.examples.notes.push( - "Todo example requires a database. It will be removed.", - ); - notes.database.hasIssue = true; - notes.examples.hasIssue = true; - } - if ( - nextStack.backend === "elysia" && - uniqueIncompatibleExamples.includes("ai") - ) { - notes.backend.notes.push( - "AI example is not compatible with Elysia. It will be removed.", - ); - notes.examples.notes.push( - "AI example is not compatible with Elysia. It will be removed.", - ); - notes.backend.hasIssue = true; - notes.examples.hasIssue = true; - } - if (isSolid && uniqueIncompatibleExamples.includes("ai")) { - notes.frontend.notes.push( - "AI example is not compatible with Solid. It will be removed.", - ); - notes.examples.notes.push( - "AI example is not compatible with Solid. It will be removed.", - ); - notes.frontend.hasIssue = true; - notes.examples.hasIssue = true; - } - const originalExamplesLength = nextStack.examples.length; - nextStack.examples = nextStack.examples.filter( - (ex) => !uniqueIncompatibleExamples.includes(ex), - ); - if (nextStack.examples.length !== originalExamplesLength) changed = true; + const originalExamplesLength = nextStack.examples.length; + nextStack.examples = nextStack.examples.filter( + (ex) => !uniqueIncompatibleExamples.includes(ex), + ); + if (nextStack.examples.length !== originalExamplesLength) + changed = true; + } } } @@ -887,11 +878,7 @@ const StackArchitect = () => { const rules = useMemo(() => getCompatibilityRules(stack), [stack]); const getRandomStack = () => { - const randomStack: Partial = { - projectName: `my-random-stack-${Math.random() - .toString(36) - .substring(2, 7)}`, - }; + const randomStack: Partial = {}; for (const category of CATEGORY_ORDER) { const options = TECH_OPTIONS[category as keyof typeof TECH_OPTIONS] || []; @@ -965,96 +952,106 @@ const StackArchitect = () => { const techId = tech.id; if (rules.isConvex) { + const convexDefaults: Record = { + runtime: "none", + database: "none", + orm: "none", + api: "none", + auth: "false", + dbSetup: "none", + examples: ["todo"], + }; + if ( ["runtime", "database", "orm", "api", "auth", "dbSetup"].includes( catKey, ) ) { - const convexDefaults: Record = { - runtime: "none", - database: "none", - orm: "none", - api: "none", - auth: "false", - dbSetup: "none", - }; - - const requiredValue = convexDefaults[catKey as string]; - if (techId !== requiredValue && techId !== "none") { + const requiredValue = convexDefaults[catKey]; + if (catKey === "auth") { + if (techId === "true" && requiredValue === "false") { + addRule( + category, + techId, + "Disabled: Convex backend requires Authentication to be disabled.", + ); + } + } else if (String(techId) !== String(requiredValue)) { addRule( category, techId, - `Convex backend requires ${getCategoryDisplayName( + `Disabled: Convex backend requires ${getCategoryDisplayName( catKey, )} to be '${requiredValue}'.`, ); } - } - if (catKey === "examples" && techId !== "todo") { - addRule( - category, - techId, - "Convex backend only supports the 'Todo' example.", - ); - } - if ( + } else if (catKey === "examples") { + const requiredExamples = convexDefaults.examples as string[]; + if ( + !requiredExamples.includes(techId) && + techId !== "none" && + options.find((o) => o.id === techId) + ) { + addRule( + category, + techId, + "Disabled: Convex backend only supports the 'Todo' example.", + ); + } + } else if ( catKey === "frontend" && (techId === "nuxt" || techId === "solid") ) { addRule( category, techId, - `Convex backend is not compatible with ${tech.name}.`, + `Disabled: Convex backend is not compatible with ${tech.name}.`, ); } continue; } if (rules.isBackendNone) { - if ( - [ - "auth", - "database", - "orm", - "api", - "runtime", - "dbSetup", - "examples", - ].includes(catKey) + if (catKey === "auth" && techId === "true") { + addRule( + category, + techId, + "Disabled: Authentication requires a backend.", + ); + } else if ( + ["database", "orm", "api", "runtime", "dbSetup"].includes(catKey) && + techId !== "none" ) { - if ( - (catKey === "auth" && techId === "true") || - ((catKey === "database" || - catKey === "orm" || - catKey === "api" || - catKey === "runtime" || - catKey === "dbSetup") && - techId !== "none") || - (catKey === "examples" && techId !== "none") - ) { - addRule( - category, - techId, - `Cannot be selected when 'No Backend' is chosen. Will be set to 'None' or disabled.`, - ); - } + addRule( + category, + techId, + `Disabled: ${getCategoryDisplayName( + catKey, + )} cannot be selected when 'No Backend' is chosen (will be 'None').`, + ); + } else if (catKey === "examples" && techId !== "none") { + addRule( + category, + techId, + "Disabled: Examples cannot be selected when 'No Backend' is chosen.", + ); } } - if (catKey === "runtime" && techId === "none") { + if (catKey === "runtime" && techId === "none" && !rules.isConvex) { addRule( category, techId, - "Runtime 'None' is only available with the Convex backend.", + "Disabled: Runtime 'None' is only available with Convex backend.", ); } if (catKey === "api") { - if (techId === "none") { + if (techId === "none" && !rules.isConvex) { addRule( category, techId, - "API 'None' is only available with the Convex backend.", + "Disabled: API 'None' is only available with Convex backend.", ); } if (techId === "trpc" && rules.hasNuxtOrSvelteOrSolid) { @@ -1066,271 +1063,233 @@ const StackArchitect = () => { addRule( category, techId, - `tRPC is not supported with ${frontendName}. Use oRPC instead.`, + `Disabled: tRPC is not supported with ${frontendName}. oRPC will be automatically selected.`, ); } } if (catKey === "orm") { - if (techId === "none") { + if ( + stack.database === "none" && + techId !== "none" && + !rules.isConvex + ) { addRule( category, techId, - "ORM 'None' is only available with the Convex backend.", + "Disabled: ORM requires a database. Select a database or 'No ORM'.", + ); + } else if (stack.database === "mongodb") { + if ( + techId !== "prisma" && + techId !== "mongoose" && + techId !== "none" + ) { + addRule( + category, + techId, + "Disabled: With MongoDB, use Prisma, Mongoose, or No ORM.", + ); + } + } else if (["sqlite", "postgres", "mysql"].includes(stack.database)) { + if (techId === "mongoose") { + addRule( + category, + techId, + "Disabled: Mongoose ORM is for MongoDB. Choose a different ORM for relational databases.", + ); + } + } + + if (stack.dbSetup === "turso" && techId !== "drizzle") { + addRule( + category, + techId, + "Disabled: Turso DB setup requires Drizzle ORM.", + ); + } else if ( + stack.dbSetup === "prisma-postgres" && + techId !== "prisma" + ) { + addRule( + category, + techId, + "Disabled: Prisma PostgreSQL setup requires Prisma ORM.", + ); + } else if ( + stack.dbSetup === "mongodb-atlas" && + techId !== "prisma" && + techId !== "mongoose" + ) { + addRule( + category, + techId, + "Disabled: MongoDB Atlas setup requires Prisma or Mongoose ORM.", ); } } if (catKey === "dbSetup" && techId !== "none") { + if (stack.database === "none" && !rules.isBackendNone) { + addRule( + category, + techId, + "Disabled: A database must be selected to use this DB setup. Select 'Basic Setup' or a database first.", + ); + } + if (techId === "turso") { - if (stack.database !== "sqlite") { + if (stack.database !== "sqlite" && stack.database !== "none") { addRule( category, techId, - "Turso requires SQLite. It will be selected.", + "Disabled: Turso requires SQLite. (Will auto-select if chosen)", ); } - if (stack.orm !== "drizzle") { + if (stack.orm !== "drizzle" && stack.orm !== "none") { addRule( category, techId, - "Turso requires Drizzle ORM. It will be selected.", + "Disabled: Turso requires Drizzle ORM. (Will auto-select if chosen)", ); } } else if (techId === "prisma-postgres") { - if (stack.database !== "postgres") { + if (stack.database !== "postgres" && stack.database !== "none") { addRule( category, techId, - "Prisma PostgreSQL setup requires PostgreSQL. It will be selected.", + "Disabled: Requires PostgreSQL. (Will auto-select if chosen)", ); } - if (stack.orm !== "prisma") { + if (stack.orm !== "prisma" && stack.orm !== "none") { addRule( category, techId, - "Prisma PostgreSQL setup requires Prisma ORM. It will be selected.", + "Disabled: Requires Prisma ORM. (Will auto-select if chosen)", ); } } else if (techId === "mongodb-atlas") { - if (stack.database !== "mongodb") { + if (stack.database !== "mongodb" && stack.database !== "none") { addRule( category, techId, - "MongoDB Atlas setup requires MongoDB. It will be selected.", + "Disabled: Requires MongoDB. (Will auto-select if chosen)", ); } - if (stack.orm !== "prisma" && stack.orm !== "mongoose") { + if ( + stack.orm !== "prisma" && + stack.orm !== "mongoose" && + stack.orm !== "none" + ) { addRule( category, techId, - "MongoDB Atlas setup requires Prisma or Mongoose ORM. Prisma will be selected.", + "Disabled: Requires Prisma or Mongoose ORM. (Will auto-select Prisma if chosen)", ); } } else if (techId === "neon") { - if (stack.database !== "postgres") { + if (stack.database !== "postgres" && stack.database !== "none") { addRule( category, techId, - "Neon requires PostgreSQL. It will be selected.", + "Disabled: Neon requires PostgreSQL. (Will auto-select if chosen)", ); } } } - if ( - catKey === "auth" && - techId === "true" && - stack.database === "none" - ) { - addRule(category, techId, "Authentication requires a database."); - } - - if (catKey === "addons") { - const incompatibleAddons: string[] = []; - const isPWACompat = hasPWACompatibleFrontend(stack.frontend); - const isTauriCompat = hasTauriCompatibleFrontend(stack.frontend); - - if (!isPWACompat && stack.addons.includes("pwa")) { - incompatibleAddons.push("pwa"); + if (catKey === "auth" && techId === "true") { + if (stack.database === "none" && !rules.isBackendNone) { addRule( category, techId, - "PWA addon removed (requires compatible frontend)", - ); - } - if (!isTauriCompat && stack.addons.includes("tauri")) { - incompatibleAddons.push("tauri"); - addRule( - category, - techId, - "Tauri addon removed (requires compatible frontend)", - ); - } - - const originalAddonsLength = stack.addons.length; - if (incompatibleAddons.length > 0) { - stack.addons = stack.addons.filter( - (addon) => !incompatibleAddons.includes(addon), - ); - if (stack.addons.length !== originalAddonsLength) { - addRule( - category, - techId, - "Addons filtered (requires compatible frontend)", - ); - } - } - - if ( - stack.addons.includes("husky") && - !stack.addons.includes("biome") - ) { - addRule( - category, - techId, - "Husky addon is selected without Biome. Consider adding Biome for lint-staged integration.", + "Disabled: Authentication requires a database.", ); } } - if (catKey === "examples") { - const incompatibleExamples: string[] = []; - const isWeb = hasWebFrontend(stack.frontend); - const isNativeOnly = checkHasNativeFrontend(stack.frontend) && !isWeb; + if (catKey === "addons") { + if (techId === "pwa" && !rules.hasPWACompatible) { + addRule( + category, + techId, + "Disabled: PWA addon requires a compatible frontend (e.g., TanStack Router, Solid).", + ); + } + if (techId === "tauri" && !rules.hasTauriCompatible) { + addRule( + category, + techId, + "Disabled: Tauri addon requires a compatible frontend (e.g., TanStack Router, Nuxt, Svelte, Solid).", + ); + } + } - if (isNativeOnly) { - if (stack.examples.length > 0) { - addRule( - category, - techId, - "Examples removed (not supported with Native-only frontend)", - ); - } + if (catKey === "examples" && techId !== "none") { + if (rules.hasNativeOnly) { + addRule( + category, + techId, + "Disabled: Examples are not supported with a Native-only frontend.", + ); } else { - if (!isWeb) { - if (stack.examples.includes("todo")) { - incompatibleExamples.push("todo"); - addRule( - category, - techId, - "Todo example removed (requires web frontend)", - ); - } - if (stack.examples.includes("ai")) { - incompatibleExamples.push("ai"); - addRule( - category, - techId, - "AI example removed (requires web frontend)", - ); - } - } - if (stack.database === "none" && stack.examples.includes("todo")) { - incompatibleExamples.push("todo"); + if ( + !rules.hasWebFrontend && + (techId === "todo" || techId === "ai") + ) { addRule( category, techId, - "Todo example removed (requires a database)", + "Disabled: This example requires a web frontend.", ); } - if (stack.backend === "elysia" && stack.examples.includes("ai")) { - incompatibleExamples.push("ai"); - addRule( - category, - techId, - "AI example removed (not compatible with Elysia)", - ); - } - if (rules.hasSolid && stack.examples.includes("ai")) { - incompatibleExamples.push("ai"); - addRule( - category, - techId, - "AI example removed (not compatible with Solid)", - ); - } - } - - const uniqueIncompatibleExamples = [...new Set(incompatibleExamples)]; - if (uniqueIncompatibleExamples.length > 0) { - if (!isWeb && !isNativeOnly) { - if ( - uniqueIncompatibleExamples.includes("todo") || - uniqueIncompatibleExamples.includes("ai") - ) { - addRule( - category, - techId, - "Examples require a web frontend. Incompatible examples will be removed.", - ); - } - } if ( stack.database === "none" && - uniqueIncompatibleExamples.includes("todo") + techId === "todo" && + !rules.isConvex ) { addRule( category, techId, - "Todo example requires a database. It will be removed.", + "Disabled: The 'Todo' example requires a database.", ); } - if ( - stack.backend === "elysia" && - uniqueIncompatibleExamples.includes("ai") - ) { + if (stack.backend === "elysia" && techId === "ai") { addRule( category, techId, - "AI example is not compatible with Elysia. It will be removed.", + "Disabled: The 'AI' example is not compatible with an Elysia backend.", ); } - if (rules.hasSolid && uniqueIncompatibleExamples.includes("ai")) { + if (rules.hasSolid && techId === "ai") { addRule( category, techId, - "AI example is not compatible with Solid. It will be removed.", - ); - } - - const originalExamplesLength = stack.examples.length; - stack.examples = stack.examples.filter( - (ex) => !uniqueIncompatibleExamples.includes(ex), - ); - if (stack.examples.length !== originalExamplesLength) { - addRule( - category, - techId, - "Examples filtered (incompatible examples removed)", + "Disabled: The 'AI' example is not compatible with a Solid frontend.", ); } } } } } - return reasons; }, [stack, rules]); const selectedBadges = (() => { const badges: React.ReactNode[] = []; - // biome-ignore lint/complexity/noForEach: - CATEGORY_ORDER.forEach((category) => { + for (const category of CATEGORY_ORDER) { const categoryKey = category as keyof StackState; const options = TECH_OPTIONS[category as keyof typeof TECH_OPTIONS]; const selectedValue = stack[categoryKey]; - if (!options) return; + if (!options) continue; if (Array.isArray(selectedValue)) { - if (selectedValue.length === 0 || selectedValue[0] === "none") return; + if (selectedValue.length === 0 || selectedValue[0] === "none") continue; - // biome-ignore lint/complexity/noForEach: - selectedValue - .map((id) => options.find((opt) => opt.id === id)) - .filter((tech): tech is NonNullable => Boolean(tech)) - .forEach((tech) => { + for (const id of selectedValue) { + const tech = options.find((opt) => opt.id === id); + if (tech) { badges.push( { {tech.name} , ); - }); + } + } } else { const tech = options.find((opt) => opt.id === selectedValue); if ( @@ -1363,7 +1323,7 @@ const StackArchitect = () => { category === "auth") && tech.id === "true") ) { - return; + continue; } badges.push( { , ); } - }); + } return badges; })(); @@ -1395,7 +1355,6 @@ const StackArchitect = () => { } }, []); - // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect(() => { if (compatibilityAnalysis.adjustedStack) { if (compatibilityAnalysis.changes.length > 0) { @@ -1403,7 +1362,11 @@ const StackArchitect = () => { setLastChanges(compatibilityAnalysis.changes); setStack(compatibilityAnalysis.adjustedStack); } - }, [compatibilityAnalysis.adjustedStack, setStack]); + }, [ + compatibilityAnalysis.adjustedStack, + setStack, + compatibilityAnalysis.changes, + ]); useEffect(() => { const cmd = generateCommand(stack); diff --git a/apps/web/src/components/ui/dialog.tsx b/apps/web/src/components/ui/dialog.tsx new file mode 100644 index 0000000..f678566 --- /dev/null +++ b/apps/web/src/components/ui/dialog.tsx @@ -0,0 +1,134 @@ +"use client"; + +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { XIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +function Dialog({ + ...props +}: React.ComponentProps) { + return ; +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return ; +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return ; +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return ; +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DialogContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + {children} + + + Close + + + + ); +} + +function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}; diff --git a/bun.lock b/bun.lock index 55aed9a..ef2bc7d 100644 --- a/bun.lock +++ b/bun.lock @@ -42,6 +42,7 @@ "name": "web", "version": "0.0.0", "dependencies": { + "@radix-ui/react-dialog": "^1.1.13", "@radix-ui/react-scroll-area": "^1.2.6", "@radix-ui/react-switch": "^1.2.2", "@radix-ui/react-tooltip": "^1.2.4", @@ -394,15 +395,15 @@ "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], - "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.7", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.4", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.6", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-yI7S1ipkP5/+99qhSI6nthfo/tR6bL6Zgxi/+1UO6qPa6UeM6nlafWcQ65vB4rU2XjgjMfMhI3k9Y5MztA62VQ=="], + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.9", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.6", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.8", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.2", "@radix-ui/react-slot": "1.2.2", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ARFmqUyhIVS3+riWzwGTe7JLjqwqgnODBUZdqpWar/z1WFs9z76fuOs/2BOWCR+YboRn4/WN9aoaGVwqNRr8VA=="], "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], - "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw=="], + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.9", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.2", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-way197PiTvNp+WBP7svMJasHl+vibhWGQDb6Mgf5mhEWJkgb85z7Lfl9TUdkqpWsf8GRNmoopx9ZxCyDzmgRMQ=="], "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA=="], - "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA=="], + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.6", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.2", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-r9zpYNUQY+2jWHWZGyddQLL9YHkM/XvSFHVcWs7bdVuxMAnCwTAuy6Pf47Z4nw7dYcUou1vg/VgjjrrH03VeBw=="], "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], @@ -412,17 +413,17 @@ "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.4", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.4", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3p2Rgm/a1cK0r/UVkx5F/K9v/EplfjAeIFCGOPYPO4lZ0jtg4iSQXt/YGTSLWaf4x7NG6Z4+uKFcylcTZjeqDA=="], - "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.6", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw=="], + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.8", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-hQsTUIn7p7fxCPvao/q6wpbxmCwgLrlz+nOrJgC+RwfZqWY/WN+UMqkXzrtKbPrF82P43eCTl3ekeKuyAQbFeg=="], "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA=="], - "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.2", "", { "dependencies": { "@radix-ui/react-slot": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-uHa+l/lKfxuDD2zjN/0peM/RhhSmRjr5YWdk/37EnSv1nJ88uvG85DPexSm8HdFQROd2VdERJ6ynXbkCFi+APw=="], "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-collection": "1.1.4", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-C6oAg451/fQT3EGbWHbCQjYTtbyjNO1uzQgMzwyivcHT3GKNEmu1q3UuREhN+HzHAVtv3ivMVK08QlC+PkYw9Q=="], "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lj8OMlpPERXrQIHlEQdlXHJoRT52AMpBrgyPYylOhXYq5e/glsEdtOc/kCQlsTdtgN5U0iDbrrolDadvektJGQ=="], - "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-y7TBO4xN4Y94FvcWIOIh18fM4R1A8S4q1jhoz4PNzOoHsFcN8pogcFmZrTYAm4F9VRUrWP/Mw7xSKybIeRI+CQ=="], "@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7Z8n6L+ifMIIYZ83f28qWSceUpkXuslI2FJ34+kDMTiyj91ENdpdQ7VCidrzj5JfwfZTeano/BnGBbu/jqa5rQ=="], @@ -1766,6 +1767,50 @@ "@next/eslint-plugin-next/fast-glob": ["fast-glob@3.3.1", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg=="], + "@radix-ui/react-accordion/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-arrow/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-collapsible/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-collection/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-navigation-menu/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw=="], + + "@radix-ui/react-navigation-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-popover/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw=="], + + "@radix-ui/react-popover/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA=="], + + "@radix-ui/react-popover/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.6", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw=="], + + "@radix-ui/react-popover/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-popover/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-popper/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-roving-focus/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-scroll-area/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-switch/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-tabs/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-tooltip/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw=="], + + "@radix-ui/react-tooltip/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.6", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw=="], + + "@radix-ui/react-tooltip/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + + "@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-visually-hidden/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + "@tailwindcss/node/lightningcss": ["lightningcss@1.29.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.29.2", "lightningcss-darwin-x64": "1.29.2", "lightningcss-freebsd-x64": "1.29.2", "lightningcss-linux-arm-gnueabihf": "1.29.2", "lightningcss-linux-arm64-gnu": "1.29.2", "lightningcss-linux-arm64-musl": "1.29.2", "lightningcss-linux-x64-gnu": "1.29.2", "lightningcss-linux-x64-musl": "1.29.2", "lightningcss-win32-arm64-msvc": "1.29.2", "lightningcss-win32-x64-msvc": "1.29.2" } }, "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="], @@ -1818,6 +1863,10 @@ "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "fumadocs-ui/@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.7", "@radix-ui/react-focus-guards": "1.1.2", "@radix-ui/react-focus-scope": "1.1.4", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.6", "@radix-ui/react-presence": "1.1.4", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-slot": "1.2.0", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-yI7S1ipkP5/+99qhSI6nthfo/tR6bL6Zgxi/+1UO6qPa6UeM6nlafWcQ65vB4rU2XjgjMfMhI3k9Y5MztA62VQ=="], + + "fumadocs-ui/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + "globby/@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@2.3.0", "", {}, "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg=="], "gray-matter/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], @@ -1910,6 +1959,26 @@ "@next/eslint-plugin-next/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "@radix-ui/react-accordion/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-arrow/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-collapsible/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-navigation-menu/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-popper/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-roving-focus/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-scroll-area/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-switch/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-tabs/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + + "@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w=="], + "@tailwindcss/node/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.29.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA=="], "@tailwindcss/node/lightningcss/lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.29.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w=="], @@ -1940,6 +2009,14 @@ "cli-truncate/string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], + "fumadocs-ui/@radix-ui/react-dialog/@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.7", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw=="], + + "fumadocs-ui/@radix-ui/react-dialog/@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA=="], + + "fumadocs-ui/@radix-ui/react-dialog/@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.6", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw=="], + + "fumadocs-ui/@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.0", "", { "dependencies": { "@radix-ui/react-slot": "1.2.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw=="], + "gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], "lint-staged/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],