add catpucchin theme and nuqs for url state

This commit is contained in:
Aman Varshney
2025-04-21 06:43:10 +05:30
parent 0253195969
commit 9f0798d8b6
14 changed files with 347 additions and 170 deletions

View File

@@ -12,6 +12,7 @@
"dependencies": {
"@heroicons/react": "^2.2.0",
"@radix-ui/react-scroll-area": "^1.2.5",
"@radix-ui/react-switch": "^1.2.2",
"@xyflow/react": "^12.5.5",
"babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405",
"class-variance-authority": "^0.7.1",
@@ -22,6 +23,7 @@
"lucide-react": "^0.501.0",
"motion": "^12.7.4",
"next": "15.2.3",
"nuqs": "^2.4.3",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-tweet": "^3.2.2",

View File

@@ -52,7 +52,7 @@ const CodeContainer = () => {
return (
<div className="mx-auto mt-4 w-full max-w-3xl">
<div className="overflow-hidden rounded-lg border border-border bg-card shadow-md">
<div className="overflow-hidden rounded-lg border border-border bg-background">
<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" />
@@ -66,7 +66,7 @@ const CodeContainer = () => {
<button
type="button"
onClick={() => setIsOpen(!isOpen)}
className="flex items-center gap-1 rounded border border-border bg-card px-2 py-1 text-foreground text-xs hover:bg-muted"
className="flex items-center gap-1 rounded border border-border bg-background px-2 py-1 text-foreground text-xs hover:bg-muted"
>
<Terminal className="h-3 w-3 text-muted-foreground" />
<span>{selectedPM}</span>
@@ -90,7 +90,7 @@ 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-border bg-card shadow-lg"
className="absolute right-0 z-50 mt-1 w-28 rounded-md border border-border bg-background"
>
{(["npm", "pnpm", "bun"] as const).map((pm) => (
<button
@@ -110,7 +110,7 @@ const CodeContainer = () => {
</div>
</div>
<div className="bg-card p-4 text-left font-mono text-sm">
<div className="bg-background p-4 text-left font-mono text-sm">
<div className="flex items-center">
<span className="mr-2 text-muted-foreground">$</span>
<div className="flex-grow">

View File

@@ -1,5 +1,3 @@
import { cn } from "@/lib/utils";
import { Code, Sliders, Terminal, TerminalSquare } from "lucide-react";
import { motion } from "motion/react";
import StackArchitect from "./StackArchitech";
@@ -32,48 +30,6 @@ export default function CustomizableSection() {
Configure your ideal TypeScript environment with all the options you
need
</p>
<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-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-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-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>
<span>--addons</span>
</div>
</div>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.4, delay: 0.3 }}
className="flex flex-wrap justify-center gap-2 pt-2 sm:gap-3"
>
<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>
@@ -82,22 +38,10 @@ export default function CustomizableSection() {
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-50px" }}
transition={{ duration: 0.6, delay: 0.2 }}
className="relative"
className="relative border"
>
<StackArchitect />
</motion.div>
</section>
);
}
function Badge({
children,
color,
}: { children: React.ReactNode; color: string }) {
const baseClasses =
"rounded-full border px-2.5 py-1 font-medium text-xs shadow-sm";
const colorClasses = `bg-[--color-${color}]/10 text-[--color-${color}] border-[--color-${color}]/30`;
return <span className={cn(baseClasses, colorClasses)}>{children}</span>;
}

View File

@@ -75,7 +75,7 @@ const Navbar = () => {
)}
>
<div
className="absolute rounded-md bg-card shadow-sm transition-all duration-200 ease-in-out"
className="absolute rounded-md bg-background transition-all duration-200 ease-in-out"
style={bgStyles}
/>
<Link
@@ -188,7 +188,7 @@ const Navbar = () => {
: "pointer-events-none opacity-0",
)}
>
<div className="mx-4 mt-4 overflow-hidden rounded-lg border border-border bg-card/95 shadow-lg">
<div className="mx-4 mt-4 overflow-hidden rounded-lg border border-border bg-background/95">
<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" />

View File

@@ -1,5 +1,6 @@
"use client";
import { ThemeToggle } from "@/components/theme-toggle";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
DEFAULT_STACK,
@@ -7,6 +8,7 @@ import {
type StackState,
TECH_OPTIONS,
} from "@/lib/constant";
import { stackParsers, stackQueryStatesOptions } from "@/lib/stack-url-state";
import { cn } from "@/lib/utils";
import {
Check,
@@ -24,6 +26,7 @@ import {
import { motion } from "motion/react";
import Image from "next/image";
import Link from "next/link";
import { useQueryStates } from "nuqs";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
const validateProjectName = (name: string): string | undefined => {
@@ -106,8 +109,44 @@ const TechIcon = ({
);
};
const getBadgeColors = (category: string): string => {
switch (category) {
case "frontend":
return "border-blue-300 bg-blue-100 text-blue-800 dark:border-blue-700/30 dark:bg-blue-900/30 dark:text-blue-300";
case "runtime":
return "border-amber-300 bg-amber-100 text-amber-800 dark:border-amber-700/30 dark:bg-amber-900/30 dark:text-amber-300";
case "backendFramework":
return "border-sky-300 bg-sky-100 text-sky-800 dark:border-sky-700/30 dark:bg-sky-900/30 dark:text-sky-300";
case "api":
return "border-indigo-300 bg-indigo-100 text-indigo-800 dark:border-indigo-700/30 dark:bg-indigo-900/30 dark:text-indigo-300";
case "database":
return "border-emerald-300 bg-emerald-100 text-emerald-800 dark:border-emerald-700/30 dark:bg-emerald-900/30 dark:text-emerald-300";
case "orm":
return "border-cyan-300 bg-cyan-100 text-cyan-800 dark:border-cyan-700/30 dark:bg-cyan-900/30 dark:text-cyan-300";
case "auth":
return "border-green-300 bg-green-100 text-green-800 dark:border-green-700/30 dark:bg-green-900/30 dark:text-green-300";
case "dbSetup":
return "border-pink-300 bg-pink-100 text-pink-800 dark:border-pink-700/30 dark:bg-pink-900/30 dark:text-pink-300";
case "addons":
return "border-violet-300 bg-violet-100 text-violet-800 dark:border-violet-700/30 dark:bg-violet-900/30 dark:text-violet-300";
case "examples":
return "border-teal-300 bg-teal-100 text-teal-800 dark:border-teal-700/30 dark:bg-teal-900/30 dark:text-teal-300";
case "packageManager":
return "border-orange-300 bg-orange-100 text-orange-800 dark:border-orange-700/30 dark:bg-orange-900/30 dark:text-orange-300";
case "git":
case "install":
return "border-gray-300 bg-gray-100 text-gray-700 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400";
default:
return "border-gray-300 bg-gray-100 text-gray-800 dark:border-gray-700/30 dark:bg-gray-900/30 dark:text-gray-300";
}
};
const StackArchitect = () => {
const [stack, setStack] = useState<StackState>(DEFAULT_STACK);
const [stack, setStack] = useQueryStates(
stackParsers,
stackQueryStatesOptions,
);
const [command, setCommand] = useState("");
const [copied, setCopied] = useState(false);
const [compatNotes, setCompatNotes] = useState<
@@ -154,7 +193,9 @@ const StackArchitect = () => {
// biome-ignore lint/correctness/useExhaustiveDependencies: <explanation>
useEffect(() => {
setStack((currentStack) => {
const calculateAdjustedStack = (
currentStack: StackState,
): StackState | null => {
const nextStack = { ...currentStack };
let changed = false;
@@ -247,8 +288,13 @@ const StackArchitect = () => {
);
if (nextStack.examples.length !== originalExamplesLength) changed = true;
return changed ? nextStack : currentStack;
});
return changed ? nextStack : null;
};
const adjustedStack = calculateAdjustedStack(stack);
if (adjustedStack) {
setStack(adjustedStack);
}
}, [
stack.database,
stack.orm,
@@ -259,6 +305,7 @@ const StackArchitect = () => {
stack.addons,
stack.examples,
stack.backendFramework,
setStack,
]);
const generateCommand = useCallback((stackState: StackState) => {
@@ -282,7 +329,7 @@ const StackArchitect = () => {
key: K,
value: StackState[K],
) => {
const defaultValue = DEFAULT_STACK[key];
const defaultValue = stackParsers[key]?.defaultValue;
if (Array.isArray(defaultValue) && Array.isArray(value)) {
return (
@@ -550,9 +597,9 @@ const StackArchitect = () => {
const handleTechSelect = useCallback(
(category: keyof typeof TECH_OPTIONS, techId: string) => {
setStack((prev) => {
const currentStack = { ...prev };
setStack((currentStack) => {
const catKey = category as keyof StackState;
const update: Partial<StackState> = {};
if (
catKey === "frontend" ||
@@ -575,7 +622,7 @@ const StackArchitect = () => {
} else if (isSelected) {
nextArray = nextArray.filter((id) => id !== techId);
if (nextArray.length === 0) {
return prev;
return {};
}
} else {
nextArray = nextArray.filter((id) => id !== "none");
@@ -591,16 +638,23 @@ const StackArchitect = () => {
nextArray.push(techId);
}
}
return { ...currentStack, [catKey]: [...new Set(nextArray)] };
if (
JSON.stringify([...new Set(nextArray)].sort()) !==
JSON.stringify(currentArray.sort())
) {
update[catKey] = [...new Set(nextArray)];
}
} else {
if (currentStack[catKey] !== techId) {
update[catKey] = techId;
}
}
if (currentStack[catKey] === techId) {
return prev;
}
return { ...currentStack, [catKey]: techId };
return update;
});
},
[],
[setStack],
);
const getDisabledReason = useCallback(
@@ -709,12 +763,11 @@ const StackArchitect = () => {
const resetStack = useCallback(() => {
setStack(DEFAULT_STACK);
setProjectNameError(validateProjectName(DEFAULT_STACK.projectName || ""));
setShowHelp(false);
setShowPresets(false);
setActiveCategory(CATEGORY_ORDER[0]);
contentRef.current?.scrollTo(0, 0);
}, []);
}, [setStack]);
useEffect(() => {
setProjectNameError(validateProjectName(stack.projectName || ""));
@@ -728,29 +781,28 @@ const StackArchitect = () => {
const loadSavedStack = useCallback(() => {
if (lastSavedStack) {
setStack(lastSavedStack);
setProjectNameError(
validateProjectName(lastSavedStack.projectName || ""),
);
setShowHelp(false);
setShowPresets(false);
setActiveCategory(CATEGORY_ORDER[0]);
contentRef.current?.scrollTo(0, 0);
}
}, [lastSavedStack]);
}, [lastSavedStack, setStack]);
const applyPreset = useCallback((presetId: string) => {
const preset = PRESET_TEMPLATES.find(
(template) => template.id === presetId,
);
if (preset) {
setStack(preset.stack);
setProjectNameError(validateProjectName(preset.stack.projectName || ""));
setShowPresets(false);
setShowHelp(false);
setActiveCategory(CATEGORY_ORDER[0]);
contentRef.current?.scrollTo(0, 0);
}
}, []);
const applyPreset = useCallback(
(presetId: string) => {
const preset = PRESET_TEMPLATES.find(
(template) => template.id === presetId,
);
if (preset) {
setStack(preset.stack);
setShowPresets(false);
setShowHelp(false);
setActiveCategory(CATEGORY_ORDER[0]);
contentRef.current?.scrollTo(0, 0);
}
},
[setStack],
);
const handleSidebarClick = (category: string) => {
setActiveCategory(category);
@@ -768,19 +820,23 @@ const StackArchitect = () => {
return (
<div
className={cn(
"flex h-screen flex-col overflow-hidden border-border bg-background text-foreground shadow-xl",
"flex h-screen flex-col overflow-hidden border-border bg-background text-foreground",
)}
>
<div
className={cn(
"flex flex-shrink-0 items-center justify-between border-border border-b bg-card px-2 py-2 sm:px-4",
"grid w-full flex-shrink-0 grid-cols-3 items-center justify-center border-border border-b bg-background 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">
<Link href={"/"}>
<div className="mr-auto font-mono text-muted-foreground text-xs">
Home
</div>
</Link>
<div className="mx-auto hidden font-mono text-muted-foreground text-xs sm:block">
Create Better T Stack
</div>
<div className="flex space-x-2">
<div className="ml-auto flex space-x-2">
<button
type="button"
onClick={() => setShowHelp(!showHelp)}
@@ -803,11 +859,10 @@ const StackArchitect = () => {
</button>
<button
type="button"
onClick={() => setShowPresets(!showPresets)}
className={cn(
"text-muted-foreground transition-colors hover:text-foreground",
)}
title="Presets"
title="GitHub Repository"
>
<Link
href={"https://github.com/AmanVarshney01/create-better-t-stack"}
@@ -816,6 +871,7 @@ const StackArchitect = () => {
<Github className="h-4 w-4" />
</Link>
</button>
<ThemeToggle />
</div>
</div>
@@ -862,7 +918,7 @@ const StackArchitect = () => {
type="button"
key={preset.id}
onClick={() => applyPreset(preset.id)}
className="rounded border border-border bg-card p-2 text-left transition-colors hover:bg-muted"
className="rounded border border-border bg-background p-2 text-left transition-colors hover:bg-muted"
>
<div className="font-medium text-foreground text-sm">
{preset.name}
@@ -876,7 +932,7 @@ const StackArchitect = () => {
</div>
)}
<div className="flex-shrink-0 p-3 pb-0 font-mono sm:p-4 sm:pb-0">
<div className="flex-shrink-0 bg-background 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-muted-foreground text-xs">
@@ -887,11 +943,10 @@ const StackArchitect = () => {
value={stack.projectName || ""}
onChange={(e) => {
const newValue = e.target.value;
setStack((prev) => ({ ...prev, projectName: newValue }));
setProjectNameError(validateProjectName(newValue));
setStack({ projectName: newValue });
}}
className={cn(
"w-full rounded border bg-card px-2 py-1 font-mono text-sm focus:outline-none sm:w-auto",
"w-full rounded border bg-background px-2 py-1 font-mono text-sm focus:outline-none sm:w-auto",
projectNameError
? "border-destructive bg-destructive/10 text-destructive-foreground"
: "border-border focus:border-primary",
@@ -908,7 +963,7 @@ const StackArchitect = () => {
<button
type="button"
onClick={resetStack}
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"
className="flex items-center gap-1 rounded border border-border bg-background px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
title="Reset to defaults"
>
<RefreshCw className="h-3 w-3" />
@@ -918,7 +973,7 @@ const StackArchitect = () => {
<button
type="button"
onClick={loadSavedStack}
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"
className="flex items-center gap-1 rounded border border-border bg-background px-2 py-1 text-muted-foreground text-xs transition-colors hover:bg-muted"
title="Load saved preferences"
>
<Settings className="h-3 w-3" />
@@ -929,7 +984,7 @@ const StackArchitect = () => {
id="save-stack-button"
type="button"
onClick={saveCurrentStack}
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"
className="flex items-center gap-1 rounded border border-chart-4 bg-chart-4/10 px-2 py-1 text-chart-4 text-xs transition-colors hover:bg-chart-4/20"
title="Save current preferences"
>
<Star className="h-3 w-3" />
@@ -937,10 +992,9 @@ const StackArchitect = () => {
</button>
</div>
</div>
<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-[--color-chart-4]">$</span>
<div className="relative mb-4 overflow-hidden rounded border border-border bg-background p-2 pr-16 sm:pr-20">
<div className="flex overflow-x-auto">
<span className="mr-2 select-none text-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>
@@ -948,13 +1002,24 @@ const StackArchitect = () => {
<button
type="button"
onClick={copyToClipboard}
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"
className={cn(
"-translate-y-1/2 absolute top-1/2 right-1 flex items-center gap-1 rounded px-2 py-1 text-xs transition-colors",
copied
? "bg-muted text-chart-4"
: "text-muted-foreground hover:bg-muted hover:text-foreground",
)}
title={copied ? "Copied!" : "Copy command"}
>
{copied ? (
<Check className="h-4 w-4 text-[--color-chart-4]" />
<>
<Check className="h-3 w-3 flex-shrink-0" />
<span>Copied</span>
</>
) : (
<ClipboardCopy className="h-4 w-4" />
<>
<ClipboardCopy className="h-3 w-3 flex-shrink-0" />
<span>Copy</span>
</>
)}
</button>
</div>
@@ -1052,7 +1117,7 @@ const StackArchitect = () => {
<span>{getCategoryDisplayName(category)}</span>
{compatNotes[category]?.hasIssue && (
<span title="Compatibility issue affects this section">
<InfoIcon className="h-3 w-3 flex-shrink-0 text-[--color-chart-5]" />{" "}
<InfoIcon className="h-3 w-3 flex-shrink-0 text-chart-5" />{" "}
</span>
)}
</button>
@@ -1093,16 +1158,14 @@ const StackArchitect = () => {
className={cn(
"mb-4 rounded-md border p-3",
notesInfo.hasIssue
? "border-[--color-chart-5] bg-[--color-chart-5]/10"
? "border-chart-5 bg-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",
notesInfo.hasIssue ? "text-chart-5" : "text-primary",
)}
>
<InfoIcon className="h-4 w-4 flex-shrink-0" />
@@ -1116,7 +1179,7 @@ const StackArchitect = () => {
className={cn(
"list-inside list-disc space-y-1 text-xs",
notesInfo.hasIssue
? "text-[--color-chart-5]/90"
? "text-chart-5/90"
: "text-primary/90",
)}
>
@@ -1235,36 +1298,4 @@ const StackArchitect = () => {
);
};
const getBadgeColors = (category: string): string => {
switch (category) {
case "frontend":
return "border-blue-300 bg-blue-100 text-blue-800 dark:border-blue-700/30 dark:bg-blue-900/30 dark:text-blue-300";
case "runtime":
return "border-amber-300 bg-amber-100 text-amber-800 dark:border-amber-700/30 dark:bg-amber-900/30 dark:text-amber-300";
case "backendFramework":
return "border-sky-300 bg-sky-100 text-sky-800 dark:border-sky-700/30 dark:bg-sky-900/30 dark:text-sky-300";
case "api":
return "border-indigo-300 bg-indigo-100 text-indigo-800 dark:border-indigo-700/30 dark:bg-indigo-900/30 dark:text-indigo-300";
case "database":
return "border-emerald-300 bg-emerald-100 text-emerald-800 dark:border-emerald-700/30 dark:bg-emerald-900/30 dark:text-emerald-300";
case "orm":
return "border-cyan-300 bg-cyan-100 text-cyan-800 dark:border-cyan-700/30 dark:bg-cyan-900/30 dark:text-cyan-300";
case "auth":
return "border-green-300 bg-green-100 text-green-800 dark:border-green-700/30 dark:bg-green-900/30 dark:text-green-300";
case "dbSetup":
return "border-pink-300 bg-pink-100 text-pink-800 dark:border-pink-700/30 dark:bg-pink-900/30 dark:text-pink-300";
case "addons":
return "border-violet-300 bg-violet-100 text-violet-800 dark:border-violet-700/30 dark:bg-violet-900/30 dark:text-violet-300";
case "examples":
return "border-teal-300 bg-teal-100 text-teal-800 dark:border-teal-700/30 dark:bg-teal-900/30 dark:text-teal-300";
case "packageManager":
return "border-orange-300 bg-orange-100 text-orange-800 dark:border-orange-700/30 dark:bg-orange-900/30 dark:text-orange-300";
case "git":
case "install":
return "border-gray-300 bg-gray-100 text-gray-700 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400";
default:
return "border-gray-300 bg-gray-100 text-gray-800 dark:border-gray-700/30 dark:bg-gray-900/30 dark:text-gray-300";
}
};
export default StackArchitect;

View File

@@ -119,7 +119,7 @@ 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-border bg-card shadow-xl">
<div className="overflow-hidden rounded-xl border border-border bg-background">
<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" />

View File

@@ -1,9 +1,9 @@
import type { ReactNode } from "react";
import { type ReactNode, Suspense } 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">
{children}
<Suspense>{children}</Suspense>
</main>
);
}

View File

@@ -119,13 +119,13 @@ export default function HomePage() {
<div className="hidden w-1/3 items-center sm:flex">
<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 className="h-2 w-2 rounded-full bg-primary/60" />
</div>
<div className="px-4 sm:px-6">
<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",
"flex h-8 w-8 items-center justify-center rounded-full border border-primary/80 bg-card sm:h-9 sm:w-9",
)}
>
<svg
@@ -145,7 +145,7 @@ export default function HomePage() {
</div>
<div className="hidden w-1/3 items-center sm:flex">
<div className="h-2 w-2 rounded-full bg-primary/60 shadow-sm" />
<div className="h-2 w-2 rounded-full bg-primary/60" />
<div className="h-px flex-grow bg-gradient-to-l from-transparent via-primary/30 to-primary/50" />
</div>

View File

@@ -1,5 +1,5 @@
@import "tailwindcss";
/* @import "fumadocs-ui/css/ocean.css"; */
@import "fumadocs-ui/css/ocean.css";
@import "fumadocs-ui/css/preset.css";
@import "tw-animate-css";

View File

@@ -1,6 +1,7 @@
import { RootProvider } from "fumadocs-ui/provider";
import type { Metadata } from "next";
import { Poppins } from "next/font/google";
import { NuqsAdapter } from "nuqs/adapters/next/app";
import type { ReactNode } from "react";
import "./global.css";
@@ -94,7 +95,7 @@ export default function Layout({ children }: { children: ReactNode }) {
enableSystem: true,
}}
>
{children}
<NuqsAdapter>{children}</NuqsAdapter>
</RootProvider>
</body>
</html>

View File

@@ -0,0 +1,62 @@
"use client";
import { cn } from "@/lib/utils"; // Make sure you have this utility
import * as SwitchPrimitives from "@radix-ui/react-switch";
import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes";
import * as React from "react";
export function ThemeToggle({ className }: { className?: string }) {
const { theme, setTheme } = useTheme();
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
const isChecked = mounted ? theme === "dark" : false;
const handleCheckedChange = (checked: boolean) => {
setTheme(checked ? "dark" : "light");
};
if (!mounted) {
return (
<button
type="button"
className={cn(
"inline-flex h-5 w-10 shrink-0 cursor-not-allowed items-center rounded-full border-2 border-transparent bg-input opacity-50",
className,
)}
disabled
aria-label="Toggle theme (loading)"
>
<span className="block h-4 w-4 rounded-full bg-background shadow-lg ring-0" />
</button>
);
}
return (
<SwitchPrimitives.Root
checked={isChecked}
onCheckedChange={handleCheckedChange}
className={cn(
"peer inline-flex h-4 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className,
)}
aria-label="Toggle theme between light and dark"
>
<SwitchPrimitives.Thumb
className={cn(
"pointer-events-none flex h-3 w-3 items-center justify-center rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
)}
>
{isChecked ? (
<Moon className="size-2 text-foreground" />
) : (
<Sun className="size-2 text-foreground" />
)}
</SwitchPrimitives.Thumb>
</SwitchPrimitives.Root>
);
}

View File

@@ -0,0 +1,31 @@
"use client";
import * as SwitchPrimitive from "@radix-ui/react-switch";
import type * as React from "react";
import { cn } from "@/lib/utils";
function Switch({
className,
...props
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
return (
<SwitchPrimitive.Root
data-slot="switch"
className={cn(
"peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input dark:data-[state=unchecked]:bg-input/80",
className,
)}
{...props}
>
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
className={cn(
"pointer-events-none block size-4 rounded-full bg-background ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0 dark:data-[state=checked]:bg-primary-foreground dark:data-[state=unchecked]:bg-foreground",
)}
/>
</SwitchPrimitive.Root>
);
}
export { Switch };

View File

@@ -0,0 +1,72 @@
import { DEFAULT_STACK, type StackState, TECH_OPTIONS } from "@/lib/constant";
import {
type UrlKeys,
parseAsArrayOf,
parseAsString,
parseAsStringEnum,
} from "nuqs";
const getValidIds = (category: keyof typeof TECH_OPTIONS): string[] => {
return TECH_OPTIONS[category]?.map((opt) => opt.id) ?? [];
};
export const stackParsers = {
projectName: parseAsString.withDefault(DEFAULT_STACK.projectName),
frontend: parseAsArrayOf(parseAsString).withDefault(DEFAULT_STACK.frontend),
runtime: parseAsStringEnum<StackState["runtime"]>(
getValidIds("runtime"),
).withDefault(DEFAULT_STACK.runtime),
backendFramework: parseAsStringEnum<StackState["backendFramework"]>(
getValidIds("backendFramework"),
).withDefault(DEFAULT_STACK.backendFramework),
api: parseAsStringEnum<StackState["api"]>(getValidIds("api")).withDefault(
DEFAULT_STACK.api,
),
database: parseAsStringEnum<StackState["database"]>(
getValidIds("database"),
).withDefault(DEFAULT_STACK.database),
orm: parseAsStringEnum<StackState["orm"]>(getValidIds("orm")).withDefault(
DEFAULT_STACK.orm,
),
dbSetup: parseAsStringEnum<StackState["dbSetup"]>(
getValidIds("dbSetup"),
).withDefault(DEFAULT_STACK.dbSetup),
auth: parseAsStringEnum<StackState["auth"]>(["true", "false"]).withDefault(
DEFAULT_STACK.auth,
),
packageManager: parseAsStringEnum<StackState["packageManager"]>(
getValidIds("packageManager"),
).withDefault(DEFAULT_STACK.packageManager),
addons: parseAsArrayOf(parseAsString).withDefault(DEFAULT_STACK.addons),
examples: parseAsArrayOf(parseAsString).withDefault(DEFAULT_STACK.examples),
git: parseAsStringEnum<StackState["git"]>(["true", "false"]).withDefault(
DEFAULT_STACK.git,
),
install: parseAsStringEnum<StackState["install"]>([
"true",
"false",
]).withDefault(DEFAULT_STACK.install),
};
export const stackUrlKeys: UrlKeys<typeof stackParsers> = {
projectName: "name",
frontend: "fe",
runtime: "rt",
backendFramework: "be",
api: "api",
database: "db",
orm: "orm",
dbSetup: "dbs",
auth: "au",
packageManager: "pm",
addons: "add",
examples: "ex",
git: "git",
install: "i",
};
export const stackQueryStatesOptions = {
history: "replace" as const,
shallow: false,
urlKeys: stackUrlKeys,
};

View File

@@ -44,6 +44,7 @@
"dependencies": {
"@heroicons/react": "^2.2.0",
"@radix-ui/react-scroll-area": "^1.2.5",
"@radix-ui/react-switch": "^1.2.2",
"@xyflow/react": "^12.5.5",
"babel-plugin-react-compiler": "^19.0.0-beta-e993439-20250405",
"class-variance-authority": "^0.7.1",
@@ -54,6 +55,7 @@
"lucide-react": "^0.501.0",
"motion": "^12.7.4",
"next": "15.2.3",
"nuqs": "^2.4.3",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-tweet": "^3.2.2",
@@ -364,21 +366,25 @@
"@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-switch": ["@radix-ui/react-switch@1.2.2", "", { "dependencies": { "@radix-ui/primitive": "1.1.2", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.0", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7Z8n6L+ifMIIYZ83f28qWSceUpkXuslI2FJ34+kDMTiyj91ENdpdQ7VCidrzj5JfwfZTeano/BnGBbu/jqa5rQ=="],
"@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.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-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.2", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", "@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-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg=="],
"@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA=="],
"@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.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=="],
"@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ=="],
"@radix-ui/react-use-rect": ["@radix-ui/react-use-rect@1.1.0", "", { "dependencies": { "@radix-ui/rect": "1.1.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ=="],
"@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.0", "", { "dependencies": { "@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-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw=="],
"@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ=="],
"@radix-ui/react-visually-hidden": ["@radix-ui/react-visually-hidden@1.1.2", "", { "dependencies": { "@radix-ui/react-primitive": "2.0.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-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q=="],
@@ -1262,6 +1268,8 @@
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
"mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="],
"motion": ["motion@12.7.4", "", { "dependencies": { "framer-motion": "^12.7.4", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-MBGrMbYageHw4iZJn+pGTr7abq5n53jCxYkhFC1It3vYukQPRWg5zij46MnwYGpLR8KG465MLHSASXot9edYOw=="],
"motion-dom": ["motion-dom@12.7.4", "", { "dependencies": { "motion-utils": "^12.7.2" } }, "sha512-1ZUHAoSUMMxP6jPqyxlk9XUfb6NxMsnWPnH2YGhrOhTURLcXWbETi6eemoKb60Pe32NVJYduL4B62VQSO5Jq8Q=="],
@@ -1288,6 +1296,8 @@
"npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="],
"nuqs": ["nuqs@2.4.3", "", { "dependencies": { "mitt": "^3.0.1" }, "peerDependencies": { "@remix-run/react": ">=2", "next": ">=14.2.0", "react": ">=18.2.0 || ^19.0.0-0", "react-router": "^6 || ^7", "react-router-dom": "^6 || ^7" }, "optionalPeers": ["@remix-run/react", "next", "react-router", "react-router-dom"] }, "sha512-BgtlYpvRwLYiJuWzxt34q2bXu/AIS66sLU1QePIMr2LWkb+XH0vKXdbLSgn9t6p7QKzwI7f38rX3Wl9llTXQ8Q=="],
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
@@ -1756,6 +1766,8 @@
"@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-accordion/@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-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=="],
@@ -1768,6 +1780,8 @@
"@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-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-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=="],
@@ -1786,6 +1800,8 @@
"@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-dialog/@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-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=="],
@@ -1816,8 +1832,12 @@
"@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-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-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-navigation-menu/@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=="],
"@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=="],
@@ -1828,6 +1848,8 @@
"@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-popover/@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-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=="],
@@ -1838,6 +1860,8 @@
"@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-popper/@radix-ui/react-use-size": ["@radix-ui/react-use-size@1.1.0", "", { "dependencies": { "@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-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw=="],
"@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=="],
@@ -1856,6 +1880,8 @@
"@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-roving-focus/@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-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=="],
@@ -1868,12 +1894,10 @@
"@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-tabs/@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-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=="],
@@ -2022,14 +2046,24 @@
"@next/eslint-plugin-next/fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"@radix-ui/react-accordion/@radix-ui/react-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-collapsible/@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-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-dialog/@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-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-popover/@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-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=="],
"@radix-ui/react-tabs/@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=="],
"@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=="],