update theme

This commit is contained in:
Aman Varshney
2025-04-21 03:31:35 +05:30
parent b0e19a54c5
commit 0253195969
24 changed files with 928 additions and 929 deletions

21
apps/web/components.json Normal file
View File

@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/app/global.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}

View File

@@ -11,18 +11,21 @@
},
"dependencies": {
"@heroicons/react": "^2.2.0",
"@radix-ui/react-scroll-area": "^1.2.5",
"@xyflow/react": "^12.5.5",
"babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405",
"canvas-confetti": "^1.9.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"fumadocs-core": "15.1.2",
"fumadocs-mdx": "11.5.7",
"fumadocs-ui": "15.1.2",
"lucide-react": "^0.485.0",
"lucide-react": "^0.501.0",
"motion": "^12.7.4",
"next": "15.2.3",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-tweet": "^3.2.2"
"react-tweet": "^3.2.2",
"tailwind-merge": "^3.2.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.3",

View File

@@ -0,0 +1,3 @@
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="45" fill="black" />
</svg>

After

Width:  |  Height:  |  Size: 122 B

View File

@@ -1,16 +0,0 @@
import React from "react";
const BackgroundGradients = () => {
return (
<div className="-z-10 fixed inset-0 overflow-hidden">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_30%_20%,rgba(59,130,246,0.04)_0%,transparent_40%),radial-gradient(circle_at_70%_60%,rgba(79,70,229,0.03)_0%,transparent_40%)] dark:bg-[radial-gradient(circle_at_30%_20%,rgba(59,130,246,0.1)_0%,transparent_40%),radial-gradient(circle_at_70%_60%,rgba(79,70,229,0.08)_0%,transparent_40%)]" />
<div className="absolute inset-0 opacity-20 dark:opacity-25">
<div className="absolute top-1/4 left-1/3 h-28 w-28 rounded-full bg-blue-300/30 blur-[120px] dark:bg-blue-500/20" />
<div className="absolute top-2/3 right-1/4 h-32 w-32 rounded-full bg-indigo-300/30 blur-[140px] dark:bg-indigo-500/20" />
</div>
<div className="absolute inset-0 bg-[linear-gradient(to_right,#e5e7eb_1px,transparent_1px),linear-gradient(to_bottom,#e5e7eb_1px,transparent_1px)] bg-[size:4rem_4rem] opacity-[0.15] [mask-image:radial-gradient(ellipse_60%_50%_at_50%_0%,#000_70%,transparent_100%)] dark:bg-[linear-gradient(to_right,#1f2937_1px,transparent_1px),linear-gradient(to_bottom,#1f2937_1px,transparent_1px)]" />
</div>
);
};
export default BackgroundGradients;

View File

@@ -1,12 +0,0 @@
import React from "react";
const CenterLines = () => {
return (
<>
<div className="-translate-y-1/2 absolute top-3/4 left-0 h-14 w-80 rotate-180 transform rounded-bl-3xl border-slate-700 border-b-2 border-l-2 shadow-lg backdrop-blur-sm dark:border-slate-300" />
<div className="-translate-y-1/2 absolute top-3/4 right-0 h-14 w-80 rotate-180 transform rounded-br-3xl border-slate-700 border-r-2 border-b-2 shadow-lg backdrop-blur-sm dark:border-slate-300" />
</>
);
};
export default CenterLines;

View File

@@ -1,4 +1,5 @@
"use client";
import { cn } from "@/lib/utils";
import { Check, ClipboardCopy, Terminal } from "lucide-react";
import { motion } from "motion/react";
import { useEffect, useRef, useState } from "react";
@@ -51,28 +52,26 @@ const CodeContainer = () => {
return (
<div className="mx-auto mt-4 w-full max-w-3xl">
<div className="overflow-hidden rounded-lg border border-gray-200 bg-white shadow-md dark:border-gray-800 dark:bg-gray-950">
<div className="flex items-center justify-between bg-gray-100 px-3 py-2 dark:bg-gray-900">
<div className="overflow-hidden rounded-lg border border-border bg-card shadow-md">
<div className="flex items-center justify-between bg-muted px-3 py-2">
<div className="flex gap-1.5">
<div className="h-2.5 w-2.5 rounded-full bg-red-500" />
<div className="h-2.5 w-2.5 rounded-full bg-yellow-500" />
<div className="h-2.5 w-2.5 rounded-full bg-green-500" />
</div>
<div className="text-gray-600 text-xs dark:text-gray-400">
Terminal
</div>
<div className="text-muted-foreground text-xs">Terminal</div>
<div className="relative" ref={menuRef}>
<button
type="button"
onClick={() => setIsOpen(!isOpen)}
className="flex items-center gap-1 rounded border border-gray-200 bg-white px-2 py-1 text-gray-700 text-xs hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
className="flex items-center gap-1 rounded border border-border bg-card px-2 py-1 text-foreground text-xs hover:bg-muted"
>
<Terminal className="h-3 w-3 text-gray-600 dark:text-gray-400" />
<Terminal className="h-3 w-3 text-muted-foreground" />
<span>{selectedPM}</span>
<svg
className="h-3 w-3 text-gray-500"
className="h-3 w-3 text-muted-foreground"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
@@ -91,17 +90,16 @@ const CodeContainer = () => {
<motion.div
initial={{ opacity: 0, y: -5 }}
animate={{ opacity: 1, y: 0 }}
className="absolute right-0 z-50 mt-1 w-28 rounded-md border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-800"
className="absolute right-0 z-50 mt-1 w-28 rounded-md border border-border bg-card shadow-lg"
>
{(["npm", "pnpm", "bun"] as const).map((pm) => (
<button
type="button"
key={pm}
className={`block w-full px-3 py-1.5 text-left text-xs ${
selectedPM === pm
? "bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-gray-200"
: "text-gray-700 hover:bg-gray-50 dark:text-gray-300 dark:hover:bg-gray-700/50"
}`}
className={cn(
"block w-full px-3 py-1.5 text-left text-foreground text-xs",
selectedPM === pm ? "bg-muted" : "hover:bg-muted/50",
)}
onClick={() => copyToClipboard(pm)}
>
{pm === "bun" ? "🥟 bun" : pm}
@@ -112,26 +110,27 @@ const CodeContainer = () => {
</div>
</div>
<div className="bg-gray-50 p-4 text-left font-mono text-sm dark:bg-gray-900">
<div className="bg-card p-4 text-left font-mono text-sm">
<div className="flex items-center">
<span className="mr-2 text-gray-600 dark:text-gray-400">$</span>
<span className="mr-2 text-muted-foreground">$</span>
<div className="flex-grow">
<span className="text-gray-800 dark:text-gray-200">
{commands[selectedPM]}
</span>
<span className="text-foreground">{commands[selectedPM]}</span>
{step === 0 && (
<span
className={`ml-0.5 inline-block h-4 w-2 bg-gray-800 dark:bg-white ${showCursor ? "opacity-100" : "opacity-0"}`}
className={cn(
"ml-0.5 inline-block h-4 w-2 bg-foreground",
showCursor ? "opacity-100" : "opacity-0",
)}
/>
)}
</div>
<button
type="button"
onClick={() => copyToClipboard(selectedPM)}
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300"
className="text-muted-foreground hover:text-foreground"
>
{copied ? (
<Check className="h-4 w-4 text-gray-600 dark:text-gray-400" />
<Check className="h-4 w-4 text-[--color-chart-4]" />
) : (
<ClipboardCopy className="h-4 w-4" />
)}
@@ -141,55 +140,47 @@ const CodeContainer = () => {
{step > 0 && (
<div className="mt-3 space-y-1.5 text-sm">
{step > 0 && (
<div className="text-gray-600 dark:text-gray-400">
<div className="text-muted-foreground">
Creating a new Better-T-Stack project
</div>
)}
{step > 1 && (
<div className="ml-2 grid grid-cols-[80px_1fr] gap-x-2 text-gray-700 text-xs dark:text-gray-300">
<div className="ml-2 grid grid-cols-[80px_1fr] gap-x-2 text-muted-foreground text-xs">
<span>Project:</span>
<span className="text-gray-800 dark:text-gray-200">
my-app
</span>
<span className="text-foreground">my-app</span>
<span>Frontend:</span>
<span className="text-gray-800 dark:text-gray-200">
React Web
</span>
<span className="text-foreground">React Web</span>
<span>Backend:</span>
<span className="text-gray-800 dark:text-gray-200">Hono</span>
<span className="text-foreground">Hono</span>
<span>Database:</span>
<span className="text-gray-800 dark:text-gray-200">
SQLite + Drizzle
</span>
<span className="text-foreground">SQLite + Drizzle</span>
</div>
)}
{step > 2 && (
<div className="text-gray-600 dark:text-gray-400">
<div className="text-muted-foreground">
Creating project structure
</div>
)}
{step > 3 && (
<div className="text-gray-600 dark:text-gray-400">
<div className="text-muted-foreground">
Installing dependencies
</div>
)}
{step > 4 && (
<div className="mt-2 border-gray-400 border-l-2 bg-gray-100 py-2 pl-3 text-xs dark:border-gray-600 dark:bg-gray-800">
<span className="font-semibold text-gray-800 dark:text-gray-200">
<div className="mt-2 border-border border-l-2 bg-muted py-2 pl-3 text-xs">
<span className="font-semibold text-foreground">
Project created successfully! Run:
</span>
<div className="mt-1 flex flex-wrap gap-1">
<code className="rounded bg-gray-200 px-1 py-0.5 text-gray-800 dark:bg-gray-700 dark:text-white">
<code className="rounded bg-secondary px-1 py-0.5 text-secondary-foreground">
cd my-app
</code>
<span className="text-gray-700 dark:text-gray-300">
and
</span>
<code className="rounded bg-gray-200 px-1 py-0.5 text-gray-800 dark:bg-gray-700 dark:text-white">
<span className="text-muted-foreground">and</span>
<code className="rounded bg-secondary px-1 py-0.5 text-secondary-foreground">
{selectedPM === "npm"
? "npm run dev"
: selectedPM === "pnpm"
@@ -204,17 +195,20 @@ const CodeContainer = () => {
{step > 4 && (
<div className="mt-3 flex items-center">
<span className="mr-2 text-gray-600 dark:text-gray-400">$</span>
<span className="mr-2 text-muted-foreground">$</span>
<span
className={`inline-block h-4 w-2 bg-gray-800 dark:bg-white ${showCursor ? "opacity-100" : "opacity-0"}`}
className={cn(
"inline-block h-4 w-2 bg-foreground",
showCursor ? "opacity-100" : "opacity-0",
)}
/>
</div>
)}
</div>
<div className="border-gray-200 border-t bg-gray-50 px-4 py-1.5 text-left text-gray-600 text-xs dark:border-gray-800 dark:bg-gray-900 dark:text-gray-400">
<div className="border-border border-t bg-muted px-4 py-1.5 text-left text-muted-foreground text-xs">
For customization options:{" "}
<code className="rounded bg-gray-200 px-1 py-0.5 text-gray-700 dark:bg-gray-700 dark:text-gray-300">
<code className="rounded bg-secondary px-1 py-0.5 text-secondary-foreground">
{selectedPM === "npm"
? "npx"
: selectedPM === "pnpm"

View File

@@ -1,37 +0,0 @@
"use client";
import { Check, Copy } from "lucide-react";
import { useState } from "react";
interface CommandDisplayProps {
command: string;
}
export function CommandDisplay({ command }: CommandDisplayProps) {
const [copied, setCopied] = useState(false);
const copyToClipboard = async () => {
await navigator.clipboard.writeText(command);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="group relative">
<div className="w-fit overflow-x-auto rounded-lg border border-gray-200 bg-gray-100/80 p-4 font-mono text-gray-800 text-sm backdrop-blur-xl dark:border-gray-800 dark:bg-gray-950/20 dark:text-gray-300">
<button
type="button"
onClick={copyToClipboard}
className="-translate-y-1/2 absolute top-1/2 right-4 rounded-md p-2 transition-colors hover:bg-gray-200 dark:hover:bg-gray-800"
>
{copied ? (
<Check className="h-4 w-4 text-green-500" />
) : (
<Copy className="h-4 w-4 text-gray-500 dark:text-gray-400" />
)}
</button>
<pre className="pr-12 max-sm:text-xs">{command}</pre>
</div>
</div>
);
}

View File

@@ -1,3 +1,4 @@
import { cn } from "@/lib/utils";
import { Code, Sliders, Terminal, TerminalSquare } from "lucide-react";
import { motion } from "motion/react";
import StackArchitect from "./StackArchitech";
@@ -14,11 +15,10 @@ export default function CustomizableSection() {
className="relative"
>
<h2 className="font-bold font-mono text-2xl tracking-tight sm:text-3xl md:text-4xl lg:text-5xl">
<span className="border-blue-500 border-b-2 pb-1 text-gray-900 dark:text-blue-100">
<span className="border-primary border-b-2 pb-1 text-foreground dark:text-primary">
Your Stack, Your Choice
</span>
</h2>
<div className="-inset-x-1/4 -inset-y-1/2 -z-10 absolute bg-gradient-to-r from-blue-300/0 via-blue-300/10 to-blue-300/0 blur-3xl dark:from-blue-800/0 dark:via-blue-800/10 dark:to-blue-800/0" />
</motion.div>
<motion.div
@@ -28,31 +28,31 @@ export default function CustomizableSection() {
transition={{ duration: 0.5, delay: 0.2 }}
className="mx-auto max-w-3xl space-y-6"
>
<p className="font-mono text-gray-700 text-lg leading-relaxed sm:text-xl dark:text-gray-300">
<p className="font-mono text-lg text-muted-foreground leading-relaxed sm:text-xl">
Configure your ideal TypeScript environment with all the options you
need
</p>
<div className="flex flex-wrap justify-center gap-2 text-gray-700 text-xs sm:gap-3 sm:text-sm dark:text-gray-300">
<div className="flex items-center gap-1.5 rounded-md border border-gray-200 bg-gray-100 px-3 py-1.5 shadow-sm transition-colors dark:border-gray-800 dark:bg-gray-900/50">
<div className="flex flex-wrap justify-center gap-2 text-muted-foreground text-xs sm:gap-3 sm:text-sm">
<div className="flex items-center gap-1.5 rounded-md border border-border bg-muted px-3 py-1.5 shadow-sm transition-colors">
<Terminal className="h-3.5 w-3.5">
<title>Runtime Options</title>
</Terminal>
<span>--runtime</span>
</div>
<div className="flex items-center gap-1.5 rounded-md border border-gray-200 bg-gray-100 px-3 py-1.5 shadow-sm transition-colors dark:border-gray-800 dark:bg-gray-900/50">
<div className="flex items-center gap-1.5 rounded-md border border-border bg-muted px-3 py-1.5 shadow-sm transition-colors">
<Code className="h-3.5 w-3.5">
<title>Framework Options</title>
</Code>
<span>--framework</span>
</div>
<div className="flex items-center gap-1.5 rounded-md border border-gray-200 bg-gray-100 px-3 py-1.5 shadow-sm transition-colors dark:border-gray-800 dark:bg-gray-900/50">
<div className="flex items-center gap-1.5 rounded-md border border-border bg-muted px-3 py-1.5 shadow-sm transition-colors">
<TerminalSquare className="h-3.5 w-3.5">
<title>Database Options</title>
</TerminalSquare>
<span>--database</span>
</div>
<div className="flex items-center gap-1.5 rounded-md border border-gray-200 bg-gray-100 px-3 py-1.5 shadow-sm transition-colors dark:border-gray-800 dark:bg-gray-900/50">
<div className="flex items-center gap-1.5 rounded-md border border-border bg-muted px-3 py-1.5 shadow-sm transition-colors">
<Sliders className="h-3.5 w-3.5">
<title>Addon Options</title>
</Sliders>
@@ -68,12 +68,12 @@ export default function CustomizableSection() {
transition={{ duration: 0.4, delay: 0.3 }}
className="flex flex-wrap justify-center gap-2 pt-2 sm:gap-3"
>
<Badge color="amber">Bun or Node</Badge>
<Badge color="blue">Hono or Elysia</Badge>
<Badge color="indigo">SQLite or PostgreSQL</Badge>
<Badge color="cyan">Drizzle or Prisma</Badge>
<Badge color="green">Authentication</Badge>
<Badge color="violet">Optional Addons</Badge>
<Badge color="chart-5">Bun or Node</Badge>
<Badge color="chart-2">Hono or Elysia</Badge>
<Badge color="chart-3">SQLite or PostgreSQL</Badge>
<Badge color="chart-2">Drizzle or Prisma</Badge>
<Badge color="chart-4">Authentication</Badge>
<Badge color="chart-1">Optional Addons</Badge>
</motion.div>
</div>
@@ -84,7 +84,6 @@ export default function CustomizableSection() {
transition={{ duration: 0.6, delay: 0.2 }}
className="relative"
>
<div className="-z-10 absolute inset-0 bg-gradient-to-r from-blue-500/5 via-transparent to-indigo-500/5 blur-3xl" />
<StackArchitect />
</motion.div>
</section>
@@ -95,26 +94,10 @@ function Badge({
children,
color,
}: { children: React.ReactNode; color: string }) {
const colorMap = {
amber:
"bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300 border-amber-200 dark:border-amber-800/30",
blue: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300 border-blue-200 dark:border-blue-800/30",
indigo:
"bg-indigo-100 text-indigo-800 dark:bg-indigo-900/30 dark:text-indigo-300 border-indigo-200 dark:border-indigo-800/30",
cyan: "bg-cyan-100 text-cyan-800 dark:bg-cyan-900/30 dark:text-cyan-300 border-cyan-200 dark:border-cyan-800/30",
green:
"bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300 border-green-200 dark:border-green-800/30",
violet:
"bg-violet-100 text-violet-800 dark:bg-violet-900/30 dark:text-violet-300 border-violet-200 dark:border-violet-800/30",
};
const baseClasses =
"rounded-full border px-2.5 py-1 font-medium text-xs shadow-sm";
return (
<span
className={`rounded-full border px-2.5 py-1 font-medium text-xs ${
colorMap[color as keyof typeof colorMap]
} shadow-sm`}
>
{children}
</span>
);
const colorClasses = `bg-[--color-${color}]/10 text-[--color-${color}] border-[--color-${color}]/30`;
return <span className={cn(baseClasses, colorClasses)}>{children}</span>;
}

View File

@@ -1,138 +0,0 @@
import { ArrowRight, Code2, Shield, Zap } from "lucide-react";
import React from "react";
const Featured = () => {
return (
<>
<div className="relative z-50 mx-auto w-full max-w-6xl py-24">
<div className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3">
{[
{
icon: Shield,
title: "Type-Safe by Default",
description:
"End-to-end type safety from database to frontend. Catch errors before they happen.",
},
{
icon: Zap,
title: "Lightning Fast",
description:
"Built on Bun's lightning-fast runtime with optimal configurations for performance.",
},
{
icon: Code2,
title: "Developer Experience",
description:
"Modern tooling and intuitive APIs make development a breeze.",
},
].map((feature) => (
<div
key={feature.title}
className="group relative rounded-xl border border-gray-200 bg-white p-6 transition-all hover:border-gray-300 dark:border-gray-800 dark:bg-gray-900/50 dark:hover:border-gray-700"
>
<div className="absolute inset-0 rounded-xl bg-gradient-to-r from-blue-500/10 to-purple-500/10 opacity-0 transition-opacity group-hover:opacity-100" />
<feature.icon className="mb-4 h-10 w-10 text-blue-500 dark:text-blue-400" />
<h3 className="mb-2 font-semibold text-gray-900 text-xl dark:text-white">
{feature.title}
</h3>
<p className="text-gray-600 dark:text-gray-400">
{feature.description}
</p>
</div>
))}
</div>
</div>
<div className="relative z-50 w-full border-gray-200 border-y bg-gray-50 dark:border-gray-800 dark:bg-gray-900/50">
<div className="mx-auto max-w-6xl py-24">
<div className="mb-12 text-center">
<h2 className="mb-4 font-bold text-3xl text-gray-900 md:text-4xl dark:text-white">
Write Better Code, Faster
</h2>
<p className="mx-auto max-w-2xl text-gray-600 dark:text-gray-400">
Leverage the power of TypeScript with our carefully selected tools
and frameworks.
</p>
</div>
<div className="grid items-center gap-12 md:grid-cols-2">
<div className="space-y-6">
{[
{
title: "Type-Safe API Calls",
description:
"No more guessing API shapes. tRPC ensures type safety across your stack.",
},
{
title: "Database Type Safety",
description:
"Drizzle ORM provides type-safe database queries with great DX.",
},
{
title: "Modern Authentication",
description:
"Secure authentication with Better-Auth, built for modern web apps.",
},
].map((item) => (
<div
key={item.title}
className="flex items-start space-x-4 rounded-lg p-4 transition-colors hover:bg-gray-100 dark:hover:bg-gray-800/50"
>
<ArrowRight className="mt-1 h-6 w-6 text-blue-500 dark:text-blue-400" />
<div>
<h3 className="font-semibold text-gray-900 text-lg dark:text-white">
{item.title}
</h3>
<p className="text-gray-600 dark:text-gray-400">
{item.description}
</p>
</div>
</div>
))}
</div>
<div className="relative">
<div className="absolute inset-0 bg-gradient-to-r from-blue-500/10 to-purple-500/10 blur-xl" />
<div className="relative rounded-lg border border-gray-200 bg-white p-6 dark:border-gray-800 dark:bg-gray-900">
<pre className="overflow-x-auto text-gray-700 text-sm dark:text-gray-300">
<code>{`// Type-safe API endpoint
export const userRouter = router({
get: publicProcedure
.input(z.string())
.query(async ({ input }) => {
const user = await db
.select()
.from(users)
.where(eq(users.id, input));
return user;
})
});`}</code>
</pre>
</div>
</div>
</div>
</div>
</div>
<div className="relative z-50 mx-auto w-full max-w-6xl py-24 text-center">
<h2 className="mb-6 font-bold text-3xl text-gray-900 md:text-4xl dark:text-white">
Ready to Build Something Amazing?
</h2>
<p className="mx-auto mb-8 max-w-xl text-gray-600 dark:text-gray-400">
Start your next project with Better-T Stack and experience the future
of web development.
</p>
<button
type="button"
className="group inline-flex items-center rounded-full bg-blue-600 px-8 py-3 font-semibold text-white transition-colors hover:bg-blue-700"
>
Get Started
<ArrowRight className="ml-2 h-5 w-5 transform transition-transform group-hover:translate-x-1" />
</button>
</div>
</>
);
};
export default Featured;

View File

@@ -3,14 +3,14 @@ import Link from "next/link";
const Footer = () => {
return (
<footer className="relative w-full border-gray-200 border-t font-mono dark:border-gray-800">
<footer className="relative w-full border-border border-t font-mono">
<div className="mx-auto max-w-6xl px-4 py-12 sm:px-6">
<div className="mb-12 grid gap-8 md:grid-cols-3">
<div>
<h3 className="mb-4 flex items-center gap-2 font-bold text-gray-900 text-lg dark:text-white">
<h3 className="mb-4 flex items-center gap-2 font-bold text-foreground text-lg">
<span>Better-T Stack</span>
</h3>
<p className="text-gray-600 leading-relaxed dark:text-gray-400">
<p className="text-muted-foreground leading-relaxed">
Type-safe, modern TypeScript scaffolding for full-stack web
development
</p>
@@ -19,7 +19,7 @@ const Footer = () => {
<Link
href="https://github.com/better-t-stack/create-better-t-stack"
target="_blank"
className="text-gray-500 transition-colors hover:text-gray-900 dark:hover:text-white"
className="text-muted-foreground transition-colors hover:text-foreground"
aria-label="GitHub"
>
<Github size={18} />
@@ -27,7 +27,7 @@ const Footer = () => {
<Link
href="https://www.npmjs.com/package/create-better-t-stack"
target="_blank"
className="text-gray-500 transition-colors hover:text-gray-900 dark:hover:text-white"
className="text-muted-foreground transition-colors hover:text-foreground"
aria-label="NPM"
>
<svg
@@ -44,15 +44,15 @@ const Footer = () => {
</div>
<div>
<h3 className="mb-4 font-bold text-gray-900 text-lg dark:text-white">
<h3 className="mb-4 font-bold text-foreground text-lg">
Resources
</h3>
<ul className="space-y-2.5 text-gray-600 dark:text-gray-400">
<ul className="space-y-2.5 text-muted-foreground">
<li>
<Link
target="_blank"
href="https://github.com/better-t-stack/create-better-t-stack"
className="transition-colors hover:text-blue-600 dark:hover:text-blue-400"
className="transition-colors hover:text-primary"
>
GitHub Repository
</Link>
@@ -61,7 +61,7 @@ const Footer = () => {
<Link
target="_blank"
href="https://www.npmjs.com/package/create-better-t-stack"
className="transition-colors hover:text-blue-600 dark:hover:text-blue-400"
className="transition-colors hover:text-primary"
>
NPM Package
</Link>
@@ -70,30 +70,30 @@ const Footer = () => {
<Link
target="_blank"
href="https://my-better-t-app-client.pages.dev/"
className="transition-colors hover:text-blue-600 dark:hover:text-blue-400"
className="transition-colors hover:text-primary"
>
Demo Application
</Link>
</li>
{/* <li>
{/*
<li>
<Link
target="_blank"
href="https://github.com/better-t-stack/create-better-t-stack#readme"
className="hover:text-blue-600 dark:hover:text-blue-400 transition-colors"
className="hover:text-primary transition-colors"
>
Documentation
</Link>
</li> */}
</li>
*/}
</ul>
</div>
<div>
<h3 className="mb-4 font-bold text-gray-900 text-lg dark:text-white">
Contact
</h3>
<div className="space-y-2.5 text-gray-600 dark:text-gray-400">
<h3 className="mb-4 font-bold text-foreground text-lg">Contact</h3>
<div className="space-y-2.5 text-muted-foreground">
<p className="flex items-center">
<span className="mr-2 rounded bg-gray-100 px-2 py-1 font-mono text-sm dark:bg-gray-800">
<span className="mr-2 rounded bg-muted px-2 py-1 font-mono text-sm">
$
</span>
<span>amanvarshney.work@gmail.com</span>
@@ -106,13 +106,13 @@ const Footer = () => {
</div>
</div>
<div className="mt-12 flex flex-col items-center justify-between gap-4 border-gray-200 border-t pt-6 sm:flex-row dark:border-gray-800">
<p className="text-gray-500 text-sm">
<div className="mt-12 flex flex-col items-center justify-between gap-4 border-border border-t pt-6 sm:flex-row">
<p className="text-muted-foreground text-sm">
© {new Date().getFullYear()} Better-T Stack. All rights reserved.
</p>
<p className="flex items-center gap-1.5 text-gray-500 text-sm">
<p className="flex items-center gap-1.5 text-muted-foreground text-sm">
Built with
<span className="bg-gradient-to-r from-blue-500 to-indigo-600 bg-clip-text font-medium text-transparent">
<span className="bg-gradient-to-r from-primary to-primary/80 bg-clip-text font-medium text-transparent">
TypeScript
</span>
</p>

View File

@@ -1,4 +1,5 @@
"use client";
import { cn } from "@/lib/utils";
import { Github, Maximize2, Menu, X } from "lucide-react";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
@@ -47,33 +48,34 @@ const Navbar = () => {
return (
<>
<nav
className={`fixed top-0 z-[100] flex w-full items-center justify-between px-4 py-4 transition-all duration-300 sm:px-8 ${
scrolled
? "bg-transparent"
: "bg-gray-50/80 backdrop-blur-xl dark:bg-gray-950/80"
}`}
className={cn(
"fixed top-0 z-[100] flex w-full items-center justify-between px-4 py-4 transition-all duration-300 sm:px-8",
scrolled ? "bg-transparent" : "bg-background/80 backdrop-blur-xl",
)}
>
<div
className={`flex flex-row items-center space-x-3 transition-opacity duration-300 ${
scrolled ? "opacity-0" : "opacity-100"
}`}
className={cn(
"flex flex-row items-center space-x-3 transition-opacity duration-300",
scrolled ? "opacity-0" : "opacity-100",
)}
>
<div className="flex h-4 w-4 items-center justify-center rounded-sm">
<span className="text-blue-600 text-md dark:text-blue-500">$_</span>
<span className="text-md text-primary">$_</span>
</div>
<span className="font-semibold text-gray-600 text-md dark:text-gray-100">
<span className="font-semibold text-foreground text-md">
Better-T Stack
</span>
</div>
<div className="-translate-x-1/2 absolute left-1/2 hidden transform md:block">
<div
className={`relative flex items-center rounded-lg border border-gray-200 bg-gray-100/90 px-1.5 py-1 text-sm backdrop-blur-sm transition-all duration-500 ease-out dark:border-gray-800 dark:bg-gray-900/90 ${
scrolled ? "w-[352px]" : "w-[245px]"
}`}
className={cn(
"relative flex items-center rounded-lg border border-border bg-muted/90 px-1.5 py-1 text-sm backdrop-blur-sm transition-all duration-500 ease-out",
scrolled ? "w-[352px]" : "w-[245px]",
)}
>
<div
className="absolute rounded-md bg-white shadow-sm transition-all duration-200 ease-in-out dark:bg-gray-800"
className="absolute rounded-md bg-card shadow-sm transition-all duration-200 ease-in-out"
style={bgStyles}
/>
<Link
@@ -82,9 +84,9 @@ const Navbar = () => {
linkRefs.current.home = ref;
}}
onMouseOver={() => setActiveLink("home")}
className="relative flex items-center gap-1 rounded-md px-4 py-2 font-mono text-gray-700 transition-colors hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-300"
className="relative flex items-center gap-1 rounded-md px-4 py-2 font-mono text-muted-foreground transition-colors hover:text-primary"
>
<span className="text-blue-600 dark:text-blue-400">~/</span>
<span className="text-primary">~/</span>
home
</Link>
@@ -96,7 +98,7 @@ const Navbar = () => {
}}
onMouseOver={() => setActiveLink("demo")}
onMouseLeave={() => setActiveLink("home")}
className="relative flex items-center gap-2 rounded-md px-4 py-2 font-mono text-gray-700 transition-colors hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-300"
className="relative flex items-center gap-2 rounded-md px-4 py-2 font-mono text-muted-foreground transition-colors hover:text-primary"
>
<span>demo</span>
</Link>
@@ -109,7 +111,7 @@ const Navbar = () => {
}}
onMouseOver={() => setActiveLink("npm")}
onMouseLeave={() => setActiveLink("home")}
className="relative flex items-center gap-2 rounded-md px-4 py-2 font-mono text-gray-700 transition-colors hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-300"
className="relative flex items-center gap-2 rounded-md px-4 py-2 font-mono text-muted-foreground transition-colors hover:text-primary"
>
<PackageIcon pm="npm" className="h-4 w-4 rounded-full" />{" "}
<span>npm</span>
@@ -123,11 +125,12 @@ const Navbar = () => {
}}
onMouseOver={() => setActiveLink("github")}
onMouseLeave={() => setActiveLink("home")}
className={`relative flex items-center gap-2 rounded-md px-4 py-2 font-mono text-gray-700 transition-colors hover:text-blue-600 dark:text-gray-300 dark:hover:text-blue-300 ${
className={cn(
"relative flex items-center gap-2 rounded-md px-4 py-2 font-mono text-muted-foreground transition-colors hover:text-primary",
scrolled
? "translate-y-0 opacity-100"
: "pointer-events-none opacity-0"
}`}
: "pointer-events-none opacity-0",
)}
>
<Github className="size-4">
<title>GitHub</title>
@@ -138,13 +141,14 @@ const Navbar = () => {
</div>
<div
className={`hidden justify-end gap-2 transition-opacity duration-300 md:flex ${
scrolled ? "pointer-events-none opacity-0" : "opacity-100"
}`}
className={cn(
"hidden justify-end gap-2 transition-opacity duration-300 md:flex",
scrolled ? "pointer-events-none opacity-0" : "opacity-100",
)}
>
<Link
href="/new"
className="inline-flex items-center rounded-lg border border-blue-300 bg-blue-100/90 px-4 py-1 font-mono text-blue-700 text-sm backdrop-blur-sm transition-colors hover:bg-blue-200 dark:border-blue-800 dark:bg-blue-900/90 dark:text-blue-300 dark:hover:bg-blue-800/50"
className="inline-flex items-center rounded-lg border border-primary/50 bg-primary/10 px-4 py-1 font-mono text-primary text-sm backdrop-blur-sm transition-colors hover:bg-primary/20"
>
<Maximize2 className="mr-1 size-4" />
Stack Builder
@@ -152,7 +156,7 @@ const Navbar = () => {
<Link
href="https://www.github.com/better-t-stack/create-better-t-stack"
target="_blank"
className="inline-flex items-center rounded-lg border border-gray-200 bg-gray-100/90 px-4 py-1 font-mono text-gray-700 text-sm backdrop-blur-sm transition-colors hover:text-blue-600 dark:border-gray-800 dark:bg-gray-900/90 dark:text-gray-300 dark:hover:text-blue-300"
className="inline-flex items-center rounded-lg border border-border bg-muted/90 px-4 py-1 font-mono text-muted-foreground text-sm backdrop-blur-sm transition-colors hover:bg-muted hover:text-primary"
>
<Github className="mr-1 size-4">
<title>GitHub</title>
@@ -164,7 +168,7 @@ const Navbar = () => {
<button
type="button"
onClick={toggleMobileMenu}
className="flex items-center justify-center rounded-md p-2 text-gray-700 hover:bg-gray-100/50 focus:outline-none md:hidden dark:text-gray-300 dark:hover:bg-gray-800/50"
className="flex items-center justify-center rounded-md p-2 text-foreground hover:bg-muted/50 focus:outline-none md:hidden"
aria-expanded={mobileMenuOpen}
>
{mobileMenuOpen ? (
@@ -177,39 +181,38 @@ const Navbar = () => {
</nav>
<div
className={`fixed inset-0 z-[99] pt-16 backdrop-blur-md transition-all duration-300 ease-in-out md:hidden ${
className={cn(
"fixed inset-0 z-[99] pt-16 backdrop-blur-md transition-all duration-300 ease-in-out md:hidden",
mobileMenuOpen
? "pointer-events-auto opacity-100"
: "pointer-events-none opacity-0"
}`}
: "pointer-events-none opacity-0",
)}
>
<div className="mx-4 mt-4 overflow-hidden rounded-lg border border-gray-300 bg-gray-100/95 shadow-lg dark:border-gray-700 dark:bg-gray-900/95">
<div className="flex items-center bg-gray-200 px-4 py-2 dark:bg-gray-800">
<div className="mx-4 mt-4 overflow-hidden rounded-lg border border-border bg-card/95 shadow-lg">
<div className="flex items-center bg-muted px-4 py-2">
<div className="mr-4 flex space-x-2">
<div className="h-3 w-3 rounded-full bg-red-500" />
<div className="h-3 w-3 rounded-full bg-yellow-500" />
<div className="h-3 w-3 rounded-full bg-green-500" />
</div>
<div className="font-mono text-gray-600 text-sm dark:text-gray-300">
<div className="font-mono text-muted-foreground text-sm">
better-t-stack:~
</div>
</div>
<div className="p-4 font-mono text-sm">
<div className="pb-3">
<span className="text-green-600 dark:text-green-500">
<span className="text-[--color-chart-4]">
user@better-t-stack
</span>
<span className="text-gray-600 dark:text-gray-400">:~$</span>
<span className="ml-2 text-gray-800 dark:text-gray-200">
ls -la
</span>
<span className="text-muted-foreground">:~$</span>
<span className="ml-2 text-foreground">ls -la</span>
</div>
<div className="space-y-2 border-gray-300 border-l-2 pl-4 dark:border-gray-700">
<div className="space-y-2 border-border border-l-2 pl-4">
<Link
href="/"
className="block text-blue-600 hover:underline dark:text-blue-400"
className="block text-primary hover:underline"
onClick={() => setMobileMenuOpen(false)}
>
~/home
@@ -218,7 +221,7 @@ const Navbar = () => {
<Link
href="https://my-better-t-app-client.pages.dev/"
target="_blank"
className="block text-blue-600 hover:underline dark:text-blue-400"
className="block text-primary hover:underline"
onClick={() => setMobileMenuOpen(false)}
>
~/demo
@@ -229,7 +232,7 @@ const Navbar = () => {
<Link
href="https://www.npmjs.com/package/create-better-t-stack"
target="_blank"
className="block text-blue-600 hover:underline dark:text-blue-400"
className="block text-primary hover:underline"
onClick={() => setMobileMenuOpen(false)}
>
~/npm
@@ -237,11 +240,11 @@ const Navbar = () => {
</div>
<div className="flex items-center">
<Github className="mr-1 size-4 text-gray-700 dark:text-gray-300" />
<Github className="mr-1 size-4 text-foreground" />
<Link
href="https://www.github.com/better-t-stack/create-better-t-stack"
target="_blank"
className="block text-blue-600 hover:underline dark:text-blue-400"
className="block text-primary hover:underline"
onClick={() => setMobileMenuOpen(false)}
>
~/github
@@ -250,20 +253,18 @@ const Navbar = () => {
</div>
<div className="mt-6 pb-3">
<span className="text-green-600 dark:text-green-500">
<span className="text-[--color-chart-4]">
user@better-t-stack
</span>
<span className="text-gray-600 dark:text-gray-400">:~$</span>
<span className="ml-2 text-gray-800 dark:text-gray-200">
star-repo
</span>
<span className="text-muted-foreground">:~$</span>
<span className="ml-2 text-foreground">star-repo</span>
</div>
<div className="border-gray-300 border-l-2 pb-2 pl-4 dark:border-gray-700">
<div className="border-border border-l-2 pb-2 pl-4">
<Link
href="https://www.github.com/better-t-stack/create-better-t-stack"
target="_blank"
className="inline-flex items-center rounded-md bg-gray-200 px-4 py-2 text-gray-800 transition-colors hover:bg-gray-300 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700"
className="inline-flex items-center rounded-md bg-muted px-4 py-2 text-foreground transition-colors hover:bg-muted/80"
onClick={() => setMobileMenuOpen(false)}
>
<Github className="mr-1 size-5" />
@@ -272,11 +273,11 @@ const Navbar = () => {
</div>
<div className="mt-4">
<span className="text-green-600 dark:text-green-500">
<span className="text-[--color-chart-4]">
user@better-t-stack
</span>
<span className="text-gray-600 dark:text-gray-400">:~$</span>
<span className="ml-2 animate-pulse"></span>
<span className="text-muted-foreground">:~$</span>
<span className="ml-2 animate-pulse text-foreground"></span>
</div>
</div>
</div>

View File

@@ -1,5 +1,6 @@
"use client";
import { cn } from "@/lib/utils";
import { useEffect, useState } from "react";
const NpmPackage = () => {
@@ -9,21 +10,33 @@ const NpmPackage = () => {
useEffect(() => {
const getLatestVersion = async () => {
setVersionLoading(true);
const res = await fetch(
"https://registry.npmjs.org/create-better-t-stack/latest",
);
const data = await res.json();
setVersionLoading(false);
setVersion(data.version);
try {
const res = await fetch(
"https://registry.npmjs.org/create-better-t-stack/latest",
);
if (!res.ok) throw new Error("Failed to fetch version");
const data = await res.json();
setVersion(data.version);
} catch (error) {
console.error("Error fetching NPM version:", error);
setVersion("?.?.?");
} finally {
setVersionLoading(false);
}
};
getLatestVersion();
}, []);
return (
<div className="mt-2 flex items-center justify-center">
<span className="mr-2 inline-block h-5 w-3 animate-pulse bg-blue-400 dark:bg-blue-500" />
<span className="font-mono text-gray-700 text-xl dark:text-gray-300">
{versionLoading ? "[v1.0.0]" : `[v${version}]`}
<span
className={cn(
"mr-2 inline-block h-5 w-3 bg-primary",
versionLoading && "animate-pulse",
)}
/>
<span className="font-mono text-muted-foreground text-xl">
{versionLoading ? "[v?.?.?]" : `[v${version}]`}
</span>
</div>
);

View File

@@ -1,5 +0,0 @@
const SafetyMessage = () => {
return <div className="relative" />;
};
export default SafetyMessage;

View File

@@ -1,16 +1,19 @@
"use client";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
DEFAULT_STACK,
PRESET_TEMPLATES,
type StackState,
TECH_OPTIONS,
} from "@/lib/constant";
import { cn } from "@/lib/utils";
import {
Check,
Circle,
CircleCheck,
ClipboardCopy,
Github,
HelpCircle,
InfoIcon,
RefreshCw,
@@ -20,6 +23,7 @@ import {
} from "lucide-react";
import { motion } from "motion/react";
import Image from "next/image";
import Link from "next/link";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
const validateProjectName = (name: string): string | undefined => {
@@ -158,7 +162,6 @@ const StackArchitect = () => {
const isPWACompat = hasPWACompatibleFrontend(nextStack.frontend);
const isNative = hasNativeFrontend(nextStack.frontend);
// Database/ORM/Auth/DB Setup auto-fix
if (nextStack.database === "none") {
if (nextStack.orm !== "none") {
nextStack.orm = "none";
@@ -212,13 +215,11 @@ const StackArchitect = () => {
changed = true;
}
// API auto-fix for Native
if (isNative && nextStack.api !== "trpc") {
nextStack.api = "trpc";
changed = true;
}
// Addons auto-fix
const incompatibleAddons: string[] = [];
if (!isPWACompat) incompatibleAddons.push("pwa", "tauri");
const originalAddonsLength = nextStack.addons.length;
@@ -235,7 +236,6 @@ const StackArchitect = () => {
changed = true;
}
// Examples auto-fix
const incompatibleExamples: string[] = [];
if (!isWeb) incompatibleExamples.push("todo", "ai");
if (nextStack.database === "none") incompatibleExamples.push("todo");
@@ -608,18 +608,13 @@ const StackArchitect = () => {
const catKey = category as keyof StackState;
if (
(catKey === "frontend" ||
catKey === "addons" ||
catKey === "examples") &&
catKey === "frontend" &&
Array.isArray(stack[catKey]) &&
(stack[catKey] as string[]).length === 1 &&
(stack[catKey] as string[])[0] === techId
(stack[catKey] as string[])[0] === techId &&
techId !== "none"
) {
if (catKey === "frontend" && techId === "none") {
} else if (catKey !== "frontend") {
} else {
return "At least one frontend option must be selected.";
}
return "At least one frontend option must be selected.";
}
if (
@@ -630,7 +625,9 @@ const StackArchitect = () => {
) &&
stack[catKey] === techId
) {
return "This option is currently selected.";
if (techId !== "none" && techId !== "false") {
return "This option is currently selected.";
}
}
if (catKey === "api" && techId !== "trpc" && currentHasNativeFrontend) {
@@ -769,21 +766,27 @@ const StackArchitect = () => {
};
return (
<div className="flex h-screen flex-col overflow-hidden border-gray-300 bg-gray-100 text-gray-800 shadow-xl dark:border-gray-700 dark:bg-gray-900 dark:text-white">
<div className="flex flex-shrink-0 items-center justify-between border-gray-300 border-b bg-gray-200 px-2 py-2 sm:px-4 dark:border-gray-700 dark:bg-gray-800">
<div className="flex space-x-2">
<div className="h-3 w-3 rounded-full bg-red-500" />
<div className="h-3 w-3 rounded-full bg-yellow-500" />
<div className="h-3 w-3 rounded-full bg-green-500" />
</div>
<div className="hidden font-mono text-gray-600 text-xs sm:block dark:text-gray-400">
Stack Architect Terminal
<div
className={cn(
"flex h-screen flex-col overflow-hidden border-border bg-background text-foreground shadow-xl",
)}
>
<div
className={cn(
"flex flex-shrink-0 items-center justify-between border-border border-b bg-card px-2 py-2 sm:px-4",
)}
>
<div className="font-mono text-muted-foreground text-xs">Home</div>
<div className="hidden font-mono text-muted-foreground text-xs sm:block">
Create Better T Stack
</div>
<div className="flex space-x-2">
<button
type="button"
onClick={() => setShowHelp(!showHelp)}
className="text-gray-600 transition-colors hover:text-gray-800 dark:text-gray-400 dark:hover:text-white"
className={cn(
"text-muted-foreground transition-colors hover:text-foreground",
)}
title="Help"
>
<HelpCircle className="h-4 w-4" />
@@ -791,20 +794,37 @@ const StackArchitect = () => {
<button
type="button"
onClick={() => setShowPresets(!showPresets)}
className="text-gray-600 transition-colors hover:text-gray-800 dark:text-gray-400 dark:hover:text-white"
className={cn(
"text-muted-foreground transition-colors hover:text-foreground",
)}
title="Presets"
>
<Star className="h-4 w-4" />
</button>
<button
type="button"
onClick={() => setShowPresets(!showPresets)}
className={cn(
"text-muted-foreground transition-colors hover:text-foreground",
)}
title="Presets"
>
<Link
href={"https://github.com/AmanVarshney01/create-better-t-stack"}
target="_blank"
>
<Github className="h-4 w-4" />
</Link>
</button>
</div>
</div>
{showHelp && (
<div className="flex-shrink-0 border-gray-300 border-b bg-blue-50 p-3 sm:p-4 dark:border-gray-700 dark:bg-blue-900/20">
<h3 className="mb-2 font-medium text-blue-800 text-sm dark:text-blue-300">
<div className="flex-shrink-0 border-border border-b bg-background p-3 text-foreground sm:p-4">
<h3 className="mb-2 font-medium text-sm">
How to Use Stack Architect
</h3>
<ul className="list-disc space-y-1 pl-5 text-blue-700 text-xs dark:text-blue-400">
<ul className="list-disc space-y-1 pl-5 text-xs">
<li>Use the sidebar to navigate between configuration sections.</li>
<li>Select your preferred technologies in the main area.</li>
<li>
@@ -832,8 +852,8 @@ const StackArchitect = () => {
)}
{showPresets && (
<div className="flex-shrink-0 border-gray-300 border-b bg-amber-50 p-3 sm:p-4 dark:border-gray-700 dark:bg-amber-900/20">
<h3 className="mb-2 font-medium text-amber-800 text-sm dark:text-amber-300">
<div className="flex-shrink-0 border-border border-b bg-background p-3 sm:p-4">
<h3 className="mb-2 font-medium text-foreground text-sm">
Quick Start Presets
</h3>
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
@@ -842,12 +862,12 @@ const StackArchitect = () => {
type="button"
key={preset.id}
onClick={() => applyPreset(preset.id)}
className="rounded border border-amber-200 p-2 text-left transition-colors hover:bg-amber-100 dark:border-amber-700 dark:hover:bg-amber-800/30"
className="rounded border border-border bg-card p-2 text-left transition-colors hover:bg-muted"
>
<div className="font-medium text-amber-700 text-sm dark:text-amber-300">
<div className="font-medium text-foreground text-sm">
{preset.name}
</div>
<div className="text-amber-600 text-xs dark:text-amber-400">
<div className="text-muted-foreground text-xs">
{preset.description}
</div>
</button>
@@ -859,7 +879,7 @@ const StackArchitect = () => {
<div className="flex-shrink-0 p-3 pb-0 font-mono sm:p-4 sm:pb-0">
<div className="mb-3 flex flex-col justify-between gap-y-3 sm:flex-row sm:items-start">
<label className="flex flex-col">
<span className="mb-1 text-gray-600 text-xs dark:text-gray-400">
<span className="mb-1 text-muted-foreground text-xs">
Project Name:
</span>
<input
@@ -870,22 +890,25 @@ const StackArchitect = () => {
setStack((prev) => ({ ...prev, projectName: newValue }));
setProjectNameError(validateProjectName(newValue));
}}
className={`w-full rounded border px-2 py-1 font-mono text-sm focus:outline-none sm:w-auto ${
className={cn(
"w-full rounded border bg-card px-2 py-1 font-mono text-sm focus:outline-none sm:w-auto",
projectNameError
? "border-red-500 bg-red-50 dark:border-red-500 dark:bg-red-900/20"
: "border-gray-300 bg-gray-200 focus:border-blue-500 dark:border-gray-700 dark:bg-gray-800 dark:focus:border-blue-400"
}`}
? "border-destructive bg-destructive/10 text-destructive-foreground"
: "border-border focus:border-primary",
)}
placeholder="my-better-t-app"
/>
{projectNameError && (
<p className="mt-1 text-red-500 text-xs">{projectNameError}</p>
<p className="mt-1 text-destructive text-xs">
{projectNameError}
</p>
)}
</label>
<div className="flex flex-wrap gap-2">
<button
type="button"
onClick={resetStack}
className="flex items-center gap-1 rounded border border-gray-300 bg-gray-200 px-2 py-1 text-gray-700 text-xs transition-colors hover:bg-gray-300 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
className="flex items-center gap-1 rounded border border-border bg-card px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
title="Reset to defaults"
>
<RefreshCw className="h-3 w-3" />
@@ -895,7 +918,7 @@ const StackArchitect = () => {
<button
type="button"
onClick={loadSavedStack}
className="flex items-center gap-1 rounded border border-blue-300 bg-blue-100 px-2 py-1 text-blue-700 text-xs transition-colors hover:bg-blue-200 dark:border-blue-700 dark:bg-blue-900/50 dark:text-blue-300 dark:hover:bg-blue-800/50"
className="flex items-center gap-1 rounded border border-primary bg-primary/10 px-2 py-1 text-primary text-xs transition-colors hover:bg-primary/20"
title="Load saved preferences"
>
<Settings className="h-3 w-3" />
@@ -906,7 +929,7 @@ const StackArchitect = () => {
id="save-stack-button"
type="button"
onClick={saveCurrentStack}
className="flex items-center gap-1 rounded border border-green-300 bg-green-100 px-2 py-1 text-green-700 text-xs transition-colors hover:bg-green-200 dark:border-green-700 dark:bg-green-900/50 dark:text-green-300 dark:hover:bg-green-800/50"
className="flex items-center gap-1 rounded border border-[--color-chart-4] bg-[--color-chart-4]/10 px-2 py-1 text-[--color-chart-4] text-xs transition-colors hover:bg-[--color-chart-4]/20"
title="Save current preferences"
>
<Star className="h-3 w-3" />
@@ -915,23 +938,21 @@ const StackArchitect = () => {
</div>
</div>
<div className="relative mb-4 overflow-hidden rounded border border-gray-300 bg-gray-200 p-2 dark:border-gray-700 dark:bg-gray-800">
<div className="relative mb-4 overflow-hidden rounded border border-border bg-card p-2">
<div className="flex overflow-x-auto pr-10">
<span className="mr-2 select-none text-green-600 dark:text-green-400">
$
</span>
<code className="no-scrollbar inline-flex items-center overflow-x-auto whitespace-pre break-words text-gray-700 text-xs sm:text-sm dark:text-gray-300">
<span className="mr-2 select-none text-[--color-chart-4]">$</span>
<code className="no-scrollbar inline-flex items-center overflow-x-auto whitespace-pre break-words text-muted-foreground text-xs sm:text-sm">
{command}
</code>
</div>
<button
type="button"
onClick={copyToClipboard}
className="-translate-y-1/2 absolute top-1/2 right-1 rounded p-1 text-gray-500 transition-colors hover:bg-gray-300 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200"
className="-translate-y-1/2 absolute top-1/2 right-1 rounded p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
title={copied ? "Copied!" : "Copy command"}
>
{copied ? (
<Check className="h-4 w-4 text-green-500" />
<Check className="h-4 w-4 text-[--color-chart-4]" />
) : (
<ClipboardCopy className="h-4 w-4" />
)}
@@ -960,9 +981,10 @@ const StackArchitect = () => {
.map((tech) => (
<span
key={`${category}-${tech.id}`}
className={`inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs ${getBadgeColors(
category,
)}`}
className={cn(
"inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs",
getBadgeColors(category),
)}
>
<TechIcon
icon={tech.icon}
@@ -994,9 +1016,10 @@ const StackArchitect = () => {
return (
<span
key={`${category}-${tech.id}`}
className={`inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs ${getBadgeColors(
category,
)}`}
className={cn(
"inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs",
getBadgeColors(category),
)}
>
<TechIcon
icon={tech.icon}
@@ -1012,23 +1035,24 @@ const StackArchitect = () => {
</div>
<div className="flex flex-grow overflow-hidden">
<nav className="hidden w-48 flex-shrink-0 overflow-y-auto border-gray-300 border-r bg-gray-200/50 p-2 md:flex dark:border-gray-700 dark:bg-gray-800/50">
<nav className="hidden w-48 flex-shrink-0 overflow-y-auto border-border border-r p-2 md:flex">
<ul className="space-y-1">
{CATEGORY_ORDER.map((category) => (
<li key={category}>
<button
type="button"
onClick={() => handleSidebarClick(category)}
className={`flex w-full items-center justify-between rounded px-2 py-1.5 text-left font-mono text-xs transition-colors ${
className={cn(
"flex w-full items-center justify-between rounded px-2 py-1.5 text-left font-mono text-xs transition-colors",
activeCategory === category
? "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"
: "text-gray-600 hover:bg-gray-300/50 dark:text-gray-400 dark:hover:bg-gray-700/50"
}`}
? "bg-primary/10 text-primary"
: "text-muted-foreground hover:bg-muted/50",
)}
>
<span>{getCategoryDisplayName(category)}</span>
{compatNotes[category]?.hasIssue && (
<span title="Compatibility issue affects this section">
<InfoIcon className="h-3 w-3 flex-shrink-0 text-orange-500 dark:text-orange-400" />
<InfoIcon className="h-3 w-3 flex-shrink-0 text-[--color-chart-5]" />{" "}
</span>
)}
</button>
@@ -1037,170 +1061,175 @@ const StackArchitect = () => {
</ul>
</nav>
<main
ref={contentRef}
className="flex-grow overflow-y-auto scroll-smooth p-4"
>
{CATEGORY_ORDER.map((categoryKey) => {
const categoryOptions =
TECH_OPTIONS[categoryKey as keyof typeof TECH_OPTIONS] || [];
const categoryDisplayName = getCategoryDisplayName(categoryKey);
const notesInfo = compatNotes[categoryKey];
<ScrollArea className="flex-1">
<main
ref={contentRef}
className="flex-grow overflow-y-auto scroll-smooth p-4"
>
{CATEGORY_ORDER.map((categoryKey) => {
const categoryOptions =
TECH_OPTIONS[categoryKey as keyof typeof TECH_OPTIONS] || [];
const categoryDisplayName = getCategoryDisplayName(categoryKey);
const notesInfo = compatNotes[categoryKey];
return (
<section
ref={(el) => {
sectionRefs.current[categoryKey] = el;
}}
key={categoryKey}
id={`section-${categoryKey}`}
className="mb-8 scroll-mt-4"
>
<div className="mb-3 flex items-center border-gray-300 border-b pb-2 text-gray-700 dark:border-gray-700 dark:text-gray-300">
<Terminal className="mr-2 h-5 w-5 flex-shrink-0" />
<h2 className="font-semibold text-base">
{categoryDisplayName}
</h2>
</div>
{notesInfo?.notes && notesInfo.notes.length > 0 && (
<div
className={`mb-4 rounded-md border p-3 ${
notesInfo.hasIssue
? "border-orange-200 bg-orange-50 dark:border-orange-800 dark:bg-orange-900/20"
: "border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-900/20"
}`}
>
<div
className={`mb-1 flex items-center gap-2 font-medium text-xs sm:text-sm ${
notesInfo.hasIssue
? "text-orange-800 dark:text-orange-300"
: "text-blue-800 dark:text-blue-300"
}`}
>
<InfoIcon className="h-4 w-4 flex-shrink-0" />
<span>
{notesInfo.hasIssue
? "Compatibility Issues / Auto-Adjustments"
: "Notes"}
</span>
</div>
<ul
className={`list-inside list-disc space-y-1 text-xs ${
notesInfo.hasIssue
? "text-orange-700 dark:text-orange-400"
: "text-blue-700 dark:text-blue-400"
}`}
>
{notesInfo.notes.map((note, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
<li key={index}>{note}</li>
))}
</ul>
return (
<section
ref={(el) => {
sectionRefs.current[categoryKey] = el;
}}
key={categoryKey}
id={`section-${categoryKey}`}
className="mb-8 scroll-mt-4"
>
<div className="mb-3 flex items-center border-border border-b pb-2 text-muted-foreground">
<Terminal className="mr-2 h-5 w-5 flex-shrink-0" />
<h2 className="font-semibold text-base text-foreground">
{categoryDisplayName}
</h2>
</div>
)}
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{categoryOptions.map((tech) => {
let isSelected = false;
const category = categoryKey as keyof StackState;
if (
category === "addons" ||
category === "examples" ||
category === "frontend"
) {
isSelected = (
(stack[category] as string[]) || []
).includes(tech.id);
} else {
isSelected = stack[category] === tech.id;
}
const disabledReason = getDisabledReason(
categoryKey as keyof typeof TECH_OPTIONS,
tech.id,
);
const isDisabled = !!disabledReason && !isSelected;
return (
<motion.div
key={tech.id}
className={`relative rounded border p-3 transition-all ${
isDisabled
? "cursor-not-allowed opacity-60"
: "cursor-pointer"
} ${
isSelected
? "border-blue-400 bg-blue-100 ring-1 ring-blue-300 dark:border-blue-600 dark:bg-blue-900/40 dark:ring-blue-700"
: `border-gray-300 dark:border-gray-700 ${
!isDisabled
? "hover:border-gray-400 hover:bg-gray-200/50 dark:hover:border-gray-600 dark:hover:bg-gray-800/50"
: ""
}`
}`}
title={
isDisabled
? (disabledReason ?? "Option disabled")
: tech.description
}
whileHover={!isDisabled ? { scale: 1.02 } : undefined}
whileTap={!isDisabled ? { scale: 0.98 } : undefined}
onClick={() =>
!isDisabled &&
handleTechSelect(
categoryKey as keyof typeof TECH_OPTIONS,
tech.id,
)
}
>
<div className="flex items-start">
<div className="mt-1 mr-3 flex-shrink-0">
{isSelected ? (
<CircleCheck className="h-5 w-5 text-blue-600 dark:text-blue-400" />
) : (
<Circle className="h-5 w-5 text-gray-400 dark:text-gray-600" />
)}
</div>
<div className="flex-grow">
<div className="flex items-center justify-between">
<div className="flex items-center">
<TechIcon
icon={tech.icon}
name={tech.name}
className="mr-2 h-5 w-5"
/>
<span
className={`font-medium ${
isSelected
? "text-blue-800 dark:text-blue-300"
: "text-gray-800 dark:text-gray-200"
} text-sm`}
>
{tech.name}
</span>
</div>
</div>
<p className="mt-1 text-gray-600 text-xs dark:text-gray-400">
{tech.description}
</p>
</div>
</div>
{tech.default && !isSelected && !isDisabled && (
<span className="absolute top-1 right-1 ml-2 flex-shrink-0 rounded bg-gray-300 px-1 py-0.5 text-[10px] text-gray-600 dark:bg-gray-700 dark:text-gray-400">
Default
</span>
{notesInfo?.notes && notesInfo.notes.length > 0 && (
<div
className={cn(
"mb-4 rounded-md border p-3",
notesInfo.hasIssue
? "border-[--color-chart-5] bg-[--color-chart-5]/10"
: "border-primary bg-primary/10",
)}
>
<div
className={cn(
"mb-1 flex items-center gap-2 font-medium text-xs sm:text-sm",
notesInfo.hasIssue
? "text-[--color-chart-5]"
: "text-primary",
)}
</motion.div>
);
})}
</div>
</section>
);
})}
>
<InfoIcon className="h-4 w-4 flex-shrink-0" />
<span>
{notesInfo.hasIssue
? "Compatibility Issues / Auto-Adjustments"
: "Notes"}
</span>
</div>
<ul
className={cn(
"list-inside list-disc space-y-1 text-xs",
notesInfo.hasIssue
? "text-[--color-chart-5]/90"
: "text-primary/90",
)}
>
{notesInfo.notes.map((note, index) => (
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
<li key={index}>{note}</li>
))}
</ul>
</div>
)}
<div className="h-10" />
</main>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
{categoryOptions.map((tech) => {
let isSelected = false;
const category = categoryKey as keyof StackState;
if (
category === "addons" ||
category === "examples" ||
category === "frontend"
) {
isSelected = (
(stack[category] as string[]) || []
).includes(tech.id);
} else {
isSelected = stack[category] === tech.id;
}
const disabledReason = getDisabledReason(
categoryKey as keyof typeof TECH_OPTIONS,
tech.id,
);
const isDisabled = !!disabledReason && !isSelected;
return (
<motion.div
key={tech.id}
className={cn(
"relative rounded border p-3 transition-all",
isDisabled
? "cursor-not-allowed opacity-60"
: "cursor-pointer",
isSelected
? "border-primary bg-primary/10 ring-1 ring-primary"
: `border-border ${
!isDisabled
? "hover:border-muted hover:bg-muted"
: ""
}`,
)}
title={
isDisabled
? (disabledReason ?? "Option disabled")
: tech.description
}
whileHover={!isDisabled ? { scale: 1.02 } : undefined}
whileTap={!isDisabled ? { scale: 0.98 } : undefined}
onClick={() =>
!isDisabled &&
handleTechSelect(
categoryKey as keyof typeof TECH_OPTIONS,
tech.id,
)
}
>
<div className="flex items-start">
<div className="mt-1 mr-3 flex-shrink-0">
{isSelected ? (
<CircleCheck className="h-5 w-5 text-primary" />
) : (
<Circle className="h-5 w-5 text-muted-foreground" />
)}
</div>
<div className="flex-grow">
<div className="flex items-center justify-between">
<div className="flex items-center">
<TechIcon
icon={tech.icon}
name={tech.name}
className="mr-2 h-5 w-5"
/>
<span
className={cn(
"font-medium text-sm",
isSelected
? "text-primary"
: "text-foreground",
)}
>
{tech.name}
</span>
</div>
</div>
<p className="mt-1 text-muted-foreground text-xs">
{tech.description}
</p>
</div>
</div>
{tech.default && !isSelected && !isDisabled && (
<span className="absolute top-1 right-1 ml-2 flex-shrink-0 rounded bg-muted px-1 py-0.5 text-[10px] text-muted-foreground">
Default
</span>
)}
</motion.div>
);
})}
</div>
</section>
);
})}
<div className="h-10" />
</main>
</ScrollArea>
</div>
</div>
);

View File

@@ -1,275 +0,0 @@
import { motion } from "motion/react";
import React, { useState } from "react";
interface TechItem {
name: string;
description: string;
category: "frontend" | "backend" | "database" | "tooling" | "core";
}
const techStack: TechItem[] = [
{
name: "TypeScript",
description: "Type safety across the entire stack",
category: "core",
},
{
name: "React",
description: "JavaScript library for user interfaces",
category: "frontend",
},
{
name: "TanStack Router",
description: "Type-safe routing with file-based routes",
category: "frontend",
},
{
name: "TanStack Query",
description: "Powerful data synchronization",
category: "frontend",
},
{
name: "Tailwind CSS",
description: "Utility-first CSS framework",
category: "frontend",
},
{
name: "shadcn/ui",
description: "Re-usable UI components",
category: "frontend",
},
{
name: "Hono",
description: "Ultrafast web framework",
category: "backend",
},
{
name: "tRPC",
description: "End-to-end type-safe APIs",
category: "backend",
},
{
name: "Better-Auth",
description: "Modern authentication solution",
category: "backend",
},
{
name: "Drizzle ORM",
description: "TypeScript-first ORM",
category: "database",
},
{
name: "Prisma",
description: "Next-generation ORM",
category: "database",
},
{
name: "SQLite + Turso",
description: "Serverless SQLite with edge replication",
category: "database",
},
{
name: "PostgreSQL",
description: "Advanced open-source relational database",
category: "database",
},
{
name: "Biome",
description: "Fast formatter and linter",
category: "tooling",
},
{
name: "Husky",
description: "Git hooks made easy",
category: "tooling",
},
{
name: "PWA",
description: "Progressive Web App support",
category: "tooling",
},
{
name: "Tauri",
description: "Build desktop and mobile apps with web tech",
category: "tooling",
},
{
name: "Docker",
description: "Containerized deployments",
category: "tooling",
},
{
name: "Turborepo",
description: "Optimized build system for monorepos",
category: "core",
},
];
const categoryIcons = {
frontend: "🖥️",
backend: "⚙️",
database: "🗄️",
tooling: "🔧",
core: "⚡",
};
export default function TechShowcase() {
const [activeCategory, setActiveCategory] = useState<string | null>(null);
const categories = Array.from(
new Set(techStack.map((item) => item.category)),
);
const filteredTech = activeCategory
? techStack.filter((tech) => tech.category === activeCategory)
: techStack;
const groupedTech = !activeCategory
? categories.map((category) => ({
category,
items: techStack.filter((tech) => tech.category === category),
}))
: null;
return (
<section className="mx-auto w-full max-w-6xl px-4 py-16">
<div className="mb-8 flex flex-wrap justify-center gap-3">
<button
type="button"
className={`rounded-md px-4 py-2 font-mono text-sm transition-colors ${
activeCategory === null
? "bg-blue-500 text-white dark:text-white"
: "bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
}`}
onClick={() => setActiveCategory(null)}
>
all technologies
</button>
{categories.map((category) => (
<button
key={category}
type="button"
className={`rounded-md px-4 py-2 font-mono text-sm transition-colors ${
activeCategory === category
? "bg-blue-500 text-white dark:text-white"
: "bg-gray-200 text-gray-800 hover:bg-gray-300 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700"
}`}
onClick={() => setActiveCategory(category)}
>
{categoryIcons[category as keyof typeof categoryIcons]} {category}
</button>
))}
</div>
{activeCategory && (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{filteredTech.map((tech) => (
<motion.div
key={tech.name}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
className="rounded-lg border border-gray-200 bg-white/50 p-4 backdrop-blur-sm transition-colors hover:border-blue-500/30 dark:border-gray-800 dark:bg-gray-900/50"
>
<h3 className="mb-2 font-semibold text-gray-900 text-lg dark:text-white">
{tech.name}
</h3>
<p className="text-gray-600 text-sm dark:text-gray-400">
{tech.description}
</p>
<div className="mt-3 font-mono text-gray-500 text-xs dark:text-gray-500">
{tech.category === "tooling" || tech.category === "database" ? (
<span>
{tech.name === "Drizzle ORM" ||
tech.name === "Prisma" ||
tech.name === "SQLite + Turso" ||
tech.name === "PostgreSQL" ? (
<code>--{tech.name.toLowerCase().split(" ")[0]}</code>
) : (
<code>--{tech.name.toLowerCase()}</code>
)}
</span>
) : (
<span>Included by default</span>
)}
</div>
</motion.div>
))}
</div>
)}
{!activeCategory && groupedTech && (
<div className="space-y-12">
{groupedTech.map((group) => (
<div key={group.category} className="relative">
<div className="mb-4 flex items-center">
<div className="mr-3 flex h-6 w-6 items-center justify-center rounded-full bg-blue-100 text-blue-500 dark:bg-blue-500/20 dark:text-blue-300">
{categoryIcons[group.category as keyof typeof categoryIcons]}
</div>
<h2 className="font-mono font-semibold text-blue-500 text-xl dark:text-blue-300">
{group.category}/
</h2>
</div>
<div className="ml-3 border-gray-200 border-l-2 pb-4 pl-6 dark:border-gray-800">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{group.items.map((tech) => (
<motion.div
key={tech.name}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="rounded-md border border-gray-200 bg-white/30 p-4 backdrop-blur-sm transition-colors hover:bg-gray-100/50 dark:border-gray-800 dark:bg-gray-900/30 dark:hover:bg-gray-800/30"
>
<div className="flex items-start justify-between">
<h3 className="font-semibold text-gray-900 text-lg dark:text-white">
{tech.name}
</h3>
<div className="rounded bg-gray-100 px-2 py-1 font-mono text-gray-600 text-xs dark:bg-gray-800 dark:text-gray-400">
{group.category === "tooling" ||
tech.category === "database"
? "optional"
: "core"}
</div>
</div>
<p className="mt-2 text-gray-600 text-sm dark:text-gray-400">
{tech.description}
</p>
<div className="mt-3 flex items-center justify-between border-gray-200 border-t pt-2 dark:border-gray-800">
<span className="font-mono text-gray-500 text-xs dark:text-gray-500">
{group.category === "tooling" ||
tech.category === "database"
? tech.name === "Drizzle ORM" ||
tech.name === "Prisma" ||
tech.name === "SQLite + Turso" ||
tech.name === "PostgreSQL"
? `--${tech.name.toLowerCase().split(" ")[0]}`
: `--${tech.name.toLowerCase()}`
: "included by default"}
</span>
<span
className={`h-2 w-2 ${group.category === "tooling" || tech.category === "database" ? "bg-yellow-500" : "bg-green-500"} rounded-full`}
/>
</div>
</motion.div>
))}
</div>
</div>
</div>
))}
</div>
)}
<div className="mt-10 text-center">
<div className="inline-block rounded-md border border-gray-200 bg-white/50 px-5 py-3 font-mono text-gray-600 text-sm backdrop-blur-sm dark:border-gray-800 dark:bg-gray-900/50 dark:text-gray-400">
<span className="text-green-500 dark:text-green-400">$</span> npx
create-better-t-stack
<span className="text-blue-500 dark:text-blue-400">
{" "}
your-options
</span>
</div>
</div>
</section>
);
}

View File

@@ -1,5 +1,6 @@
"use client";
import { cn } from "@/lib/utils";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { motion } from "motion/react";
import { useEffect, useState } from "react";
@@ -94,11 +95,10 @@ export default function Testimonials() {
className="relative"
>
<h2 className="font-bold font-mono text-xl tracking-tight sm:text-2xl md:text-3xl lg:text-4xl xl:text-5xl">
<span className="border-blue-500 border-b-2 pb-1 text-gray-900 dark:text-blue-100">
<span className="border-primary border-b-2 pb-1 text-foreground dark:text-primary">
Developer Feedback
</span>
</h2>
<div className="-inset-x-1/4 -inset-y-1/2 -z-10 absolute bg-gradient-to-r from-blue-300/0 via-blue-300/10 to-blue-300/0 blur-3xl dark:from-blue-800/0 dark:via-blue-800/10 dark:to-blue-800/0" />
</motion.div>
<motion.p
@@ -106,7 +106,7 @@ export default function Testimonials() {
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.5, delay: 0.2 }}
className="mx-auto max-w-3xl font-mono text-base text-gray-700 leading-relaxed sm:text-lg md:text-xl dark:text-gray-300"
className="mx-auto max-w-3xl font-mono text-base text-muted-foreground leading-relaxed sm:text-lg md:text-xl"
>
what devs are saying about Better-T-Stack
</motion.p>
@@ -119,14 +119,14 @@ export default function Testimonials() {
transition={{ duration: 0.5, delay: 0.3 }}
className="relative mt-4 sm:mt-8"
>
<div className="overflow-hidden rounded-xl border border-gray-300 bg-gray-100 shadow-xl dark:border-gray-700 dark:bg-gray-900">
<div className="flex items-center justify-between bg-gray-200 px-2 py-2 sm:px-4 dark:bg-gray-800">
<div className="overflow-hidden rounded-xl border border-border bg-card shadow-xl">
<div className="flex items-center justify-between bg-muted px-2 py-2 sm:px-4">
<div className="flex space-x-1 sm:space-x-2">
<div className="h-2 w-2 rounded-full bg-red-500 sm:h-3 sm:w-3" />
<div className="h-2 w-2 rounded-full bg-yellow-500 sm:h-3 sm:w-3" />
<div className="h-2 w-2 rounded-full bg-green-500 sm:h-3 sm:w-3" />
</div>
<div className="font-mono text-[10px] text-gray-600 sm:text-xs dark:text-gray-400">
<div className="font-mono text-[10px] text-muted-foreground sm:text-xs">
Developer Feedback
</div>
<div className="flex items-center gap-1 sm:gap-2">
@@ -134,7 +134,7 @@ export default function Testimonials() {
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={handlePrev}
className="flex h-5 w-5 items-center justify-center rounded bg-gray-300 text-gray-700 transition-colors hover:bg-gray-400 sm:h-6 sm:w-6 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
className="flex h-5 w-5 items-center justify-center rounded bg-secondary text-secondary-foreground transition-colors hover:bg-muted sm:h-6 sm:w-6"
title="Previous testimonials"
aria-label="Previous testimonials"
>
@@ -145,7 +145,7 @@ export default function Testimonials() {
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={handleNext}
className="flex h-5 w-5 items-center justify-center rounded bg-gray-300 text-gray-700 transition-colors hover:bg-gray-400 sm:h-6 sm:w-6 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600"
className="flex h-5 w-5 items-center justify-center rounded bg-secondary text-secondary-foreground transition-colors hover:bg-muted sm:h-6 sm:w-6"
title="Next testimonials"
aria-label="Next testimonials"
>
@@ -162,9 +162,9 @@ export default function Testimonials() {
</div>
</div>
<div className="flex items-center justify-between border-gray-300 border-t bg-gray-200 px-2 py-2 sm:p-3 dark:border-gray-700 dark:bg-gray-800">
<div className="flex items-center justify-between border-border border-t bg-muted px-2 py-2 sm:p-3">
<div className="flex items-center">
<span className="text-[10px] text-gray-700 sm:text-xs dark:text-gray-300">
<span className="text-[10px] text-muted-foreground sm:text-xs">
{currentPage}/{totalPages}
</span>
</div>
@@ -172,24 +172,33 @@ export default function Testimonials() {
<div className="flex items-center gap-2 sm:gap-3">
<div className="flex items-center gap-1">
{Array.from({ length: Math.min(totalPages, 5) }).map((_, i) => {
const isActive = i === Math.min(currentPage - 1, 4);
const pageNum =
totalPages <= 5
? i
: currentPage <= 3
? i
: currentPage >= totalPages - 1
? totalPages - 5 + i
: currentPage - 3 + i;
const isActive = pageNum === currentPage - 1;
return (
<button
type="button"
// biome-ignore lint/suspicious/noArrayIndexKey: pagination indicator
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
key={i}
onClick={() => setStartIndex(i * tweetsPerPage)}
className={`h-1 w-1 rounded-full transition-colors sm:h-1.5 sm:w-1.5 ${
onClick={() => setStartIndex(pageNum * tweetsPerPage)}
className={cn(
"h-1 w-1 rounded-full transition-colors sm:h-1.5 sm:w-1.5",
isActive
? "bg-blue-500"
: "bg-gray-400 hover:bg-gray-500 dark:bg-gray-600"
}`}
aria-label={`Go to page ${i + 1}`}
? "bg-primary"
: "bg-muted-foreground/50 hover:bg-muted-foreground/70",
)}
aria-label={`Go to page ${pageNum + 1}`}
/>
);
})}
{totalPages > 5 && (
<span className="text-[8px] text-gray-500 sm:text-[10px] dark:text-gray-400">
<span className="text-[8px] text-muted-foreground sm:text-[10px]">
...
</span>
)}
@@ -197,8 +206,6 @@ export default function Testimonials() {
</div>
</div>
</div>
<div className="-z-10 absolute inset-0 bg-gradient-to-r from-blue-500/5 via-transparent to-indigo-500/5 blur-3xl" />
</motion.div>
</section>
);

View File

@@ -2,7 +2,7 @@ import type { ReactNode } from "react";
export default function Layout({ children }: { children: ReactNode }) {
return (
<main className="relative z-10 grid min-h-svh grid-cols-1 grid-rows-[auto_1fr_auto] overflow-hidden bg-gradient-to-b from-gray-50 to-gray-100 transition-color duration-300 dark:from-gray-950 dark:to-black">
<main className="relative z-10 grid min-h-svh grid-cols-1 grid-rows-[auto_1fr_auto] overflow-hidden">
{children}
</main>
);

View File

@@ -5,7 +5,7 @@ import StackArchitect from "../_components/StackArchitech";
export default function FullScreenStackArchitect() {
return (
<div className="flex h-svh flex-col overflow-y-auto bg-gradient-to-b from-white to-gray-50 dark:from-gray-950 dark:to-gray-900">
<div className="flex h-svh flex-col bg-background">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}

View File

@@ -1,8 +1,8 @@
"use client";
import ShinyText from "@/app/(home)/_components/ShinyText";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";
import React from "react";
import BackgroundGradients from "./_components/BackgroundGradients";
import CodeContainer from "./_components/CodeContainer";
import CustomizableSection from "./_components/CustomizableSection";
import Footer from "./_components/Footer";
@@ -48,9 +48,7 @@ export default function HomePage() {
return (
<>
<Navbar />
<main className="flex min-h-screen flex-col items-center justify-start overflow-x-hidden px-0 pt-24 pb-10 sm:px-4 sm:pb-16 md:px-8 md:pt-28 lg:pt-32">
<BackgroundGradients />
<main className="flex min-h-screen flex-col items-center justify-start overflow-x-hidden bg-background px-0 pt-24 pb-10 sm:px-4 sm:pb-16 md:px-8 md:pt-28 lg:pt-32">
<motion.div
className="relative z-10 mx-auto mb-16 max-w-5xl text-center sm:mb-20"
initial="hidden"
@@ -63,7 +61,7 @@ export default function HomePage() {
className="font-bold font-mono text-4xl xs:text-5xl tracking-tight sm:text-6xl md:text-7xl"
variants={itemVariants}
>
<span className="border-blue-500 border-b-2 pb-1 text-gray-900 dark:text-blue-100">
<span className="border-primary border-b-2 pb-1 text-foreground dark:text-primary">
Better-T Stack
</span>
</motion.h1>
@@ -73,7 +71,7 @@ export default function HomePage() {
</motion.div>
<motion.p
className="max-w-2xl px-1 font-mono text-gray-600 text-lg sm:text-xl dark:text-gray-300"
className="max-w-2xl px-1 font-mono text-lg text-muted-foreground sm:text-xl"
variants={itemVariants}
>
A modern CLI tool for scaffolding end-to-end type-safe
@@ -92,7 +90,7 @@ export default function HomePage() {
<ShinyText
text="Type-safe. Modern. Minimal. Fast."
speed={3}
className="font-mono text-gray-600 text-xs xs:text-sm sm:text-base dark:text-gray-400"
className="font-mono text-muted-foreground text-xs xs:text-sm sm:text-base"
/>
</motion.div>
</div>
@@ -119,15 +117,20 @@ export default function HomePage() {
<div className="relative mx-auto max-w-5xl">
<div className="flex items-center justify-center">
<div className="hidden w-1/3 items-center sm:flex">
<div className="h-px flex-grow bg-gradient-to-r from-transparent via-blue-500/30 to-blue-500/50" />
<div className="h-2 w-2 rounded-full bg-blue-500/60 shadow-sm" />
<div className="h-px flex-grow bg-gradient-to-r from-transparent via-primary/30 to-primary/50" />
<div className="h-2 w-2 rounded-full bg-primary/60 shadow-sm" />
</div>
<div className="px-4 sm:px-6">
<div className="flex h-8 w-8 items-center justify-center rounded-full border border-blue-500/80 bg-white shadow-md sm:h-9 sm:w-9 dark:border-blue-400/70 dark:bg-gray-900">
<div
className={cn(
"flex h-8 w-8 items-center justify-center rounded-full border border-primary/80 bg-card shadow-md sm:h-9 sm:w-9",
)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-4 w-4 text-blue-500 sm:h-5 sm:w-5 dark:text-blue-400"
className="h-4 w-4 text-primary sm:h-5 sm:w-5"
viewBox="0 0 20 20"
fill="currentColor"
>
@@ -142,11 +145,13 @@ export default function HomePage() {
</div>
<div className="hidden w-1/3 items-center sm:flex">
<div className="h-2 w-2 rounded-full bg-blue-500/60 shadow-sm" />
<div className="h-px flex-grow bg-gradient-to-l from-transparent via-blue-500/30 to-blue-500/50" />
<div className="h-2 w-2 rounded-full bg-primary/60 shadow-sm" />
<div className="h-px flex-grow bg-gradient-to-l from-transparent via-primary/30 to-primary/50" />
</div>
</div>
<div className="mt-6 h-px w-full bg-gradient-to-r from-transparent via-blue-500/30 to-transparent sm:hidden" />
<div className="mt-6 h-px w-full bg-gradient-to-r from-transparent via-primary/30 to-transparent sm:hidden" />
</div>
</motion.div>

View File

@@ -1,6 +1,7 @@
@import "tailwindcss";
@import "fumadocs-ui/css/ocean.css";
/* @import "fumadocs-ui/css/ocean.css"; */
@import "fumadocs-ui/css/preset.css";
@import "tw-animate-css";
@source '../../../../node_modules/fumadocs-ui/dist/**/*.js';
@@ -12,6 +13,7 @@
.react-tweet-theme {
--tweet-container-margin: 0 !important;
@apply !bg-background;
}
.shiny-text {
@@ -78,3 +80,199 @@
-ms-overflow-style: none;
scrollbar-width: none;
}
@theme inline {
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
--font-sans: Montserrat, sans-serif;
--font-mono: Fira Code, monospace;
--font-serif: Georgia, serif;
--radius: 0.35rem;
--tracking-tighter: calc(var(--tracking-normal) - 0.05em);
--tracking-tight: calc(var(--tracking-normal) - 0.025em);
--tracking-wide: calc(var(--tracking-normal) + 0.025em);
--tracking-wider: calc(var(--tracking-normal) + 0.05em);
--tracking-widest: calc(var(--tracking-normal) + 0.1em);
--tracking-normal: var(--tracking-normal);
--shadow-2xl: var(--shadow-2xl);
--shadow-xl: var(--shadow-xl);
--shadow-lg: var(--shadow-lg);
--shadow-md: var(--shadow-md);
--shadow: var(--shadow);
--shadow-sm: var(--shadow-sm);
--shadow-xs: var(--shadow-xs);
--shadow-2xs: var(--shadow-2xs);
--spacing: var(--spacing);
--letter-spacing: var(--letter-spacing);
--shadow-offset-y: var(--shadow-offset-y);
--shadow-offset-x: var(--shadow-offset-x);
--shadow-spread: var(--shadow-spread);
--shadow-blur: var(--shadow-blur);
--shadow-opacity: var(--shadow-opacity);
--color-shadow-color: var(--shadow-color);
--color-destructive-foreground: var(--destructive-foreground);
}
:root {
--radius: 0.35rem;
--background: oklch(0.96 0.01 264.53);
--foreground: oklch(0.44 0.04 279.33);
--card: oklch(1.0 0 0);
--card-foreground: oklch(0.44 0.04 279.33);
--popover: oklch(0.86 0.01 268.48);
--popover-foreground: oklch(0.44 0.04 279.33);
--primary: oklch(0.55 0.25 297.02);
--primary-foreground: oklch(1.0 0 0);
--secondary: oklch(0.86 0.01 268.48);
--secondary-foreground: oklch(0.44 0.04 279.33);
--muted: oklch(0.91 0.01 264.51);
--muted-foreground: oklch(0.55 0.03 279.08);
--accent: oklch(0.68 0.14 235.38);
--accent-foreground: oklch(1.0 0 0);
--destructive: oklch(0.55 0.22 19.81);
--border: oklch(0.81 0.02 271.2);
--input: oklch(0.86 0.01 268.48);
--ring: oklch(0.55 0.25 297.02);
--chart-1: oklch(0.55 0.25 297.02);
--chart-2: oklch(0.68 0.14 235.38);
--chart-3: oklch(0.63 0.18 140.44);
--chart-4: oklch(0.69 0.2 42.43);
--chart-5: oklch(0.71 0.1 33.1);
--sidebar: oklch(0.93 0.01 264.52);
--sidebar-foreground: oklch(0.44 0.04 279.33);
--sidebar-primary: oklch(0.55 0.25 297.02);
--sidebar-primary-foreground: oklch(1.0 0 0);
--sidebar-accent: oklch(0.68 0.14 235.38);
--sidebar-accent-foreground: oklch(1.0 0 0);
--sidebar-border: oklch(0.81 0.02 271.2);
--sidebar-ring: oklch(0.55 0.25 297.02);
--destructive-foreground: oklch(1.0 0 0);
--font-sans: Montserrat, sans-serif;
--font-serif: Georgia, serif;
--font-mono: Fira Code, monospace;
--shadow-color: hsl(240 30% 25%);
--shadow-opacity: 0.12;
--shadow-blur: 6px;
--shadow-spread: 0px;
--shadow-offset-x: 0px;
--shadow-offset-y: 4px;
--letter-spacing: 0em;
--spacing: 0.25rem;
--shadow-2xs: 0px 4px 6px 0px hsl(240 30% 25% / 0.06);
--shadow-xs: 0px 4px 6px 0px hsl(240 30% 25% / 0.06);
--shadow-sm: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px
hsl(240 30% 25% / 0.12);
--shadow: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px
hsl(240 30% 25% / 0.12);
--shadow-md: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 2px 4px -1px
hsl(240 30% 25% / 0.12);
--shadow-lg: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 4px 6px -1px
hsl(240 30% 25% / 0.12);
--shadow-xl: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 8px 10px -1px
hsl(240 30% 25% / 0.12);
--shadow-2xl: 0px 4px 6px 0px hsl(240 30% 25% / 0.3);
--tracking-normal: 0em;
}
.dark {
--background: oklch(0.22 0.03 284.06);
--foreground: oklch(0.88 0.04 272.28);
--card: oklch(0.24 0.03 283.91);
--card-foreground: oklch(0.88 0.04 272.28);
--popover: oklch(0.4 0.03 280.15);
--popover-foreground: oklch(0.88 0.04 272.28);
--primary: oklch(0.79 0.12 304.77);
--primary-foreground: oklch(0.24 0.03 283.91);
--secondary: oklch(0.48 0.03 278.64);
--secondary-foreground: oklch(0.88 0.04 272.28);
--muted: oklch(0.3 0.03 276.21);
--muted-foreground: oklch(0.75 0.04 273.93);
--accent: oklch(0.85 0.08 210.25);
--accent-foreground: oklch(0.24 0.03 283.91);
--destructive: oklch(0.76 0.13 2.76);
--border: oklch(0.32 0.03 281.98);
--input: oklch(0.32 0.03 281.98);
--ring: oklch(0.79 0.12 304.77);
--chart-1: oklch(0.79 0.12 304.77);
--chart-2: oklch(0.85 0.08 210.25);
--chart-3: oklch(0.86 0.11 142.72);
--chart-4: oklch(0.82 0.1 52.63);
--chart-5: oklch(0.92 0.02 30.49);
--sidebar: oklch(0.18 0.02 284.2);
--sidebar-foreground: oklch(0.88 0.04 272.28);
--sidebar-primary: oklch(0.79 0.12 304.77);
--sidebar-primary-foreground: oklch(0.24 0.03 283.91);
--sidebar-accent: oklch(0.85 0.08 210.25);
--sidebar-accent-foreground: oklch(0.24 0.03 283.91);
--sidebar-border: oklch(0.4 0.03 280.15);
--sidebar-ring: oklch(0.79 0.12 304.77);
--destructive-foreground: oklch(0.24 0.03 283.91);
--radius: 0.35rem;
--font-sans: Montserrat, sans-serif;
--font-serif: Georgia, serif;
--font-mono: Fira Code, monospace;
--shadow-color: hsl(240 30% 25%);
--shadow-opacity: 0.12;
--shadow-blur: 6px;
--shadow-spread: 0px;
--shadow-offset-x: 0px;
--shadow-offset-y: 4px;
--letter-spacing: 0em;
--spacing: 0.25rem;
--shadow-2xs: 0px 4px 6px 0px hsl(240 30% 25% / 0.06);
--shadow-xs: 0px 4px 6px 0px hsl(240 30% 25% / 0.06);
--shadow-sm: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px
hsl(240 30% 25% / 0.12);
--shadow: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 1px 2px -1px
hsl(240 30% 25% / 0.12);
--shadow-md: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 2px 4px -1px
hsl(240 30% 25% / 0.12);
--shadow-lg: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 4px 6px -1px
hsl(240 30% 25% / 0.12);
--shadow-xl: 0px 4px 6px 0px hsl(240 30% 25% / 0.12), 0px 8px 10px -1px
hsl(240 30% 25% / 0.12);
--shadow-2xl: 0px 4px 6px 0px hsl(240 30% 25% / 0.3);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
body {
@apply bg-background text-foreground;
letter-spacing: var(--tracking-normal);
}
}

View File

@@ -0,0 +1,58 @@
"use client";
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
import type * as React from "react";
import { cn } from "@/lib/utils";
function ScrollArea({
className,
children,
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
return (
<ScrollAreaPrimitive.Root
data-slot="scroll-area"
className={cn("relative", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport
data-slot="scroll-area-viewport"
className="size-full rounded-[inherit] outline-none transition-[color,box-shadow] focus-visible:outline-1 focus-visible:ring-[3px] focus-visible:ring-ring/50"
>
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
);
}
function ScrollBar({
className,
orientation = "vertical",
...props
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
return (
<ScrollAreaPrimitive.ScrollAreaScrollbar
data-slot="scroll-area-scrollbar"
orientation={orientation}
className={cn(
"flex touch-none select-none p-px transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent",
className,
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb
data-slot="scroll-area-thumb"
className="relative flex-1 rounded-full bg-border"
/>
</ScrollAreaPrimitive.ScrollAreaScrollbar>
);
}
export { ScrollArea, ScrollBar };

View File

@@ -12,7 +12,7 @@ export const TECH_OPTIONS = {
id: "orpc",
name: "oRPC",
description: "Opinionated RPC framework",
icon: "🧩",
icon: "/icon/orpc.svg",
color: "from-indigo-400 to-indigo-600",
},
],

View File

@@ -0,0 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

193
bun.lock
View File

@@ -43,18 +43,21 @@
"version": "0.0.0",
"dependencies": {
"@heroicons/react": "^2.2.0",
"@radix-ui/react-scroll-area": "^1.2.5",
"@xyflow/react": "^12.5.5",
"babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405",
"canvas-confetti": "^1.9.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"fumadocs-core": "15.1.2",
"fumadocs-mdx": "11.5.7",
"fumadocs-ui": "15.1.2",
"lucide-react": "^0.485.0",
"lucide-react": "^0.501.0",
"motion": "^12.7.4",
"next": "15.2.3",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-tweet": "^3.2.2",
"tailwind-merge": "^3.2.0",
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.3",
@@ -315,9 +318,9 @@
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
"@radix-ui/number": ["@radix-ui/number@1.1.0", "", {}, "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ=="],
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.2", "", {}, "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA=="],
"@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collapsible": "1.1.3", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-controllable-state": "1.1.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-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A=="],
@@ -327,13 +330,13 @@
"@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.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-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw=="],
"@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-compose-refs": ["@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-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg=="],
"@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@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.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.5", "@radix-ui/react-focus-guards": "1.1.1", "@radix-ui/react-focus-scope": "1.1.2", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-portal": "1.1.4", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-slot": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.0", "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-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw=="],
"@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg=="],
"@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.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-escape-keydown": "1.1.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-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg=="],
@@ -351,25 +354,25 @@
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.4", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-layout-effect": "1.1.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-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA=="],
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.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-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
"@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.3", "", { "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-IrVLIhskYhH3nLvtcBLQFZr61tBG7wx7O3kEmdzcYwRGAEBmBicGGL7ATzNgruYJ3xBTbuzEEq9OXJM3PAX3tA=="],
"@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@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-roving-focus@1.1.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-collection": "1.1.2", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-controllable-state": "1.1.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-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw=="],
"@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.3", "", { "dependencies": { "@radix-ui/number": "1.1.0", "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.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-l7+NNBfBYYJa9tNqVcP2AGvxdE3lmE6kFTBXdvHgUaZuy+4wGCL1Cl2AfaR7RKyimj7lZURGLwFO59k4eBnDJQ=="],
"@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.5", "", { "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.3", "@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-VyLjxI8/gXYn+Wij1FLpXjZp6Z/uNklUFQQ75tOpJNESeNaZ2kCRfjiEDmHgWmLeUPeJGwrqbgRmcdFjtYEkMA=="],
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ=="],
"@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-id": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-roving-focus": "1.1.2", "@radix-ui/react-use-controllable-state": "1.1.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-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng=="],
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
"@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw=="],
"@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.0", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw=="],
"@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-use-layout-effect": ["@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-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ=="],
"@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og=="],
@@ -631,8 +634,6 @@
"caniuse-lite": ["caniuse-lite@1.0.30001699", "", {}, "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w=="],
"canvas-confetti": ["canvas-confetti@1.9.3", "", {}, "sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
"chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
@@ -1135,7 +1136,7 @@
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
"lucide-react": ["lucide-react@0.485.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-NvyQJ0LKyyCxL23nPKESlr/jmz8r7fJO1bkuptSNYSy0s8VVj4ojhX0YAgmE1e0ewfxUZjIlZpvH+otfTnla8Q=="],
"lucide-react": ["lucide-react@0.501.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-E2KoyhW59fCb/yUbR3rbDer83fqn7a8NG91ZhIot2yWaPHjPyGzzsNKh40N//GezYShAuycf3TcQksRQznIsRw=="],
"markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="],
@@ -1555,7 +1556,7 @@
"swr": ["swr@2.3.3", "", { "dependencies": { "dequal": "^2.0.3", "use-sync-external-store": "^1.4.0" }, "peerDependencies": { "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A=="],
"tailwind-merge": ["tailwind-merge@3.0.2", "", {}, "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw=="],
"tailwind-merge": ["tailwind-merge@3.2.0", "", {}, "sha512-FQT/OVqCD+7edmmJpsgCsY820RTD5AkBryuG5IUqR5YQZSdj5xlH5nLgH7YPths7WsLPSpSBNneJdM8aS8aeFA=="],
"tailwindcss": ["tailwindcss@4.1.3", "", {}, "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g=="],
@@ -1745,6 +1746,136 @@
"@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/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/react-accordion/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-accordion/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-accordion/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg=="],
"@radix-ui/react-accordion/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-arrow/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-collapsible/@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/react-collapsible/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-collapsible/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-collapsible/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.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-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
"@radix-ui/react-collapsible/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-collapsible/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-collection/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-collection/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-collection/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-dialog/@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/react-dialog/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-dialog/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-dialog/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.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-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
"@radix-ui/react-dialog/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-dismissable-layer/@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/react-dismissable-layer/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-dismissable-layer/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-dismissable-layer/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"@radix-ui/react-focus-scope/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-focus-scope/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-focus-scope/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"@radix-ui/react-id/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-navigation-menu/@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/react-navigation-menu/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-navigation-menu/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-navigation-menu/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg=="],
"@radix-ui/react-navigation-menu/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.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-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
"@radix-ui/react-navigation-menu/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-navigation-menu/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"@radix-ui/react-navigation-menu/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-popover/@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/react-popover/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-popover/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-popover/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.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-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
"@radix-ui/react-popover/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-popper/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-popper/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-popper/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-popper/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"@radix-ui/react-popper/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-portal/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-portal/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@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/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/react-roving-focus/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-roving-focus/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-roving-focus/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg=="],
"@radix-ui/react-roving-focus/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-roving-focus/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-tabs/@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"@radix-ui/react-tabs/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"@radix-ui/react-tabs/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg=="],
"@radix-ui/react-tabs/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.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-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
"@radix-ui/react-tabs/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@radix-ui/react-use-controllable-state/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"@radix-ui/react-use-escape-keydown/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"@radix-ui/react-use-size/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"@types/fs-extra/@types/node": ["@types/node@22.13.1", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew=="],
"@types/jsonfile/@types/node": ["@types/node@22.13.1", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-jK8uzQlrvXqEU91UxiK5J7pKHyzgnI1Qnl0QDHIgVGuolJhRb9EEl28Cj9b3rGR8B2lhFCtvIm5os8lFnO/1Ew=="],
@@ -1783,8 +1914,14 @@
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"fumadocs-ui/@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg=="],
"fumadocs-ui/@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.3", "", { "dependencies": { "@radix-ui/number": "1.1.0", "@radix-ui/primitive": "1.1.1", "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-context": "1.1.1", "@radix-ui/react-direction": "1.1.0", "@radix-ui/react-presence": "1.1.2", "@radix-ui/react-primitive": "2.0.2", "@radix-ui/react-use-callback-ref": "1.1.0", "@radix-ui/react-use-layout-effect": "1.1.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-l7+NNBfBYYJa9tNqVcP2AGvxdE3lmE6kFTBXdvHgUaZuy+4wGCL1Cl2AfaR7RKyimj7lZURGLwFO59k4eBnDJQ=="],
"fumadocs-ui/lucide-react": ["lucide-react@0.483.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-WldsY17Qb/T3VZdMnVQ9C3DDIP7h1ViDTHVdVGnLZcvHNg30zH/MTQ04RTORjexoGmpsXroiQXZ4QyR0kBy0FA=="],
"fumadocs-ui/tailwind-merge": ["tailwind-merge@3.0.2", "", {}, "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw=="],
"glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"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=="],
@@ -1885,6 +2022,14 @@
"@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-dialog/@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-popover/@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@radix-ui/react-tabs/@radix-ui/react-presence/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"@radix-ui/react-tabs/@radix-ui/react-presence/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"@types/fs-extra/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
"@types/jsonfile/@types/node/undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
@@ -1895,6 +2040,22 @@
"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-scroll-area/@radix-ui/number": ["@radix-ui/number@1.1.0", "", {}, "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ=="],
"fumadocs-ui/@radix-ui/react-scroll-area/@radix-ui/primitive": ["@radix-ui/primitive@1.1.1", "", {}, "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA=="],
"fumadocs-ui/@radix-ui/react-scroll-area/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
"fumadocs-ui/@radix-ui/react-scroll-area/@radix-ui/react-context": ["@radix-ui/react-context@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q=="],
"fumadocs-ui/@radix-ui/react-scroll-area/@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.2", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.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-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg=="],
"fumadocs-ui/@radix-ui/react-scroll-area/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.0.2", "", { "dependencies": { "@radix-ui/react-slot": "1.1.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-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w=="],
"fumadocs-ui/@radix-ui/react-scroll-area/@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw=="],
"fumadocs-ui/@radix-ui/react-scroll-area/@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.0", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w=="],
"glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"gray-matter/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="],