diff --git a/apps/web/components/BorderBeam.tsx b/apps/web/components/BorderBeam.tsx new file mode 100644 index 0000000..80a51d8 --- /dev/null +++ b/apps/web/components/BorderBeam.tsx @@ -0,0 +1,94 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import { type MotionStyle, type Transition, motion } from "motion/react"; + +interface BorderBeamProps { + /** + * The size of the border beam. + */ + size?: number; + /** + * The duration of the border beam. + */ + duration?: number; + /** + * The delay of the border beam. + */ + delay?: number; + /** + * The color of the border beam from. + */ + colorFrom?: string; + /** + * The color of the border beam to. + */ + colorTo?: string; + /** + * The motion transition of the border beam. + */ + transition?: Transition; + /** + * The class name of the border beam. + */ + className?: string; + /** + * The style of the border beam. + */ + style?: React.CSSProperties; + /** + * Whether to reverse the animation direction. + */ + reverse?: boolean; + /** + * The initial offset position (0-100). + */ + initialOffset?: number; +} + +export const BorderBeam = ({ + className, + size = 50, + delay = 0, + duration = 6, + colorFrom = "#ffaa40", + colorTo = "#9c40ff", + transition, + style, + reverse = false, + initialOffset = 0, +}: BorderBeamProps) => { + return ( +
+ +
+ ); +}; diff --git a/apps/web/package.json b/apps/web/package.json index bc861b3..138ab73 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,6 +10,8 @@ "postinstall": "fumadocs-mdx" }, "dependencies": { + "@xyflow/react": "^12.4.3", + "framer-motion": "^12.4.3", "fumadocs-core": "15.0.6", "fumadocs-mdx": "11.5.3", "fumadocs-ui": "15.0.6", diff --git a/apps/web/src/app/(home)/_components/CustomizableSection.tsx b/apps/web/src/app/(home)/_components/CustomizableSection.tsx new file mode 100644 index 0000000..765ce44 --- /dev/null +++ b/apps/web/src/app/(home)/_components/CustomizableSection.tsx @@ -0,0 +1,60 @@ +import { motion } from "framer-motion"; +import CustomizableStack from "./CustomizableStack"; + +export default function CustomizableSection() { + return ( +
+
+ + Your Stack, Your Choice + + +

+ Better-T Stack comes with carefully selected defaults, but we + understand one size doesn't fit all. + + {" "} + Customize your stack{" "} + + while maintaining full type safety and integration. +

+ +
+ + Multiple Database Options + + + Flexible Authentication + + + Alternative ORMs + + + Framework Choices + +
+
+
+ + +
+ + +
+ ); +} diff --git a/apps/web/src/app/(home)/_components/CustomizableStack.tsx b/apps/web/src/app/(home)/_components/CustomizableStack.tsx new file mode 100644 index 0000000..5ac5993 --- /dev/null +++ b/apps/web/src/app/(home)/_components/CustomizableStack.tsx @@ -0,0 +1,177 @@ +"use client"; + +import { + Background, + type Connection, + type Edge, + ReactFlow, + useEdgesState, + useNodesState, +} from "@xyflow/react"; +import { useCallback, useState } from "react"; +import { TechSelector } from "./TechSelector"; +import "@xyflow/react/dist/style.css"; +import { initialNodes } from "@/lib/constant"; +import { TechNodeComponent } from "./TechNodeComponent"; + +const initialEdges = [ + { id: "bun-hono", source: "bun", target: "hono", animated: true }, + { id: "bun-tanstack", source: "bun", target: "tanstack", animated: true }, + { id: "hono-libsql", source: "hono", target: "libsql", animated: true }, + { id: "libsql-drizzle", source: "libsql", target: "drizzle", animated: true }, + { + id: "hono-better-auth", + source: "hono", + target: "better-auth", + animated: true, + }, + { id: "bun-tailwind", source: "bun", target: "tailwind", animated: true }, + { + id: "tailwind-shadcn", + source: "tailwind", + target: "shadcn", + animated: true, + }, +]; + +const nodeTypes = { + techNode: TechNodeComponent, +}; + +const CustomizableStack = () => { + const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes); + const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges); + const [activeNodes, setActiveNodes] = useState({ + backend: "hono", + database: "libsql", + orm: "drizzle", + auth: "better-auth", + }); + + const handleTechSelect = useCallback( + (category: string, techId: string) => { + setActiveNodes((prev) => ({ ...prev, [category]: techId })); + + setNodes((nds) => + nds.map((node) => ({ + ...node, + data: { + ...node.data, + isActive: node.data.isStatic + ? true + : node.data.category === category + ? node.id === techId + : node.data.isActive, + }, + })), + ); + + const sourceNodes = nodes.filter( + (n) => n.data.isActive && !n.data.isStatic, + ); + const targetNode = nodes.find((n) => n.id === techId); + + if (!targetNode) return; + + setEdges((eds) => + eds.filter( + (edge) => + !nodes.some( + (n) => + n.data.category === category && + (edge.source === n.id || edge.target === n.id), + ), + ), + ); + + setEdges((eds) => [ + ...eds, + ...sourceNodes.map((source) => ({ + id: `${source.id}-${techId}`, + source: source.id, + target: techId, + animated: true, + })), + ]); + }, + [nodes, setNodes, setEdges], + ); + + const onConnect = useCallback( + (connection: Connection) => { + const sourceNode = nodes.find((n) => n.id === connection.source); + const targetNode = nodes.find((n) => n.id === connection.target); + + if (!sourceNode || !targetNode) return; + + if (sourceNode.data.group === targetNode.data.group) { + return; + } + + const edgesToRemove = edges.filter((edge) => { + const edgeTarget = nodes.find((n) => n.id === edge.target); + return edgeTarget?.data.group === targetNode.data.group; + }); + + setEdges((eds) => { + const newEdges = eds.filter((edge) => !edgesToRemove.includes(edge)); + return [...newEdges, { ...(connection as Edge), animated: true }]; + }); + + setNodes((nds) => + nds.map((node) => ({ + ...node, + data: { + ...node.data, + isActive: + node.id === connection.source || node.id === connection.target + ? true + : node.data.group !== targetNode.data.group + ? node.data.isActive + : false, + }, + })), + ); + }, + [nodes, edges, setEdges, setNodes], + ); + + return ( +
+ +
+
+ Select technologies from the left panel to customize your stack. The + graph will automatically update connections. +
+
+
+
+ + + +
+
+ ); +}; + +export default CustomizableStack; diff --git a/apps/web/src/app/(home)/_components/Navbar.tsx b/apps/web/src/app/(home)/_components/Navbar.tsx index e3e59d6..b643894 100644 --- a/apps/web/src/app/(home)/_components/Navbar.tsx +++ b/apps/web/src/app/(home)/_components/Navbar.tsx @@ -56,7 +56,7 @@ const Navbar = () => {
{ style={{ transform: scrolled ? "translateY(0)" : "translateY(-8px)", }} - className={`text-gray-300 hover:text-white transition-all duration-300 py-2 px-4 rounded-full ${ + className={`text-violet-700 hover:text-white transition-all duration-300 py-2 px-4 rounded-full ${ scrolled ? "opacity-100 translate-y-0" : "opacity-0 pointer-events-none" diff --git a/apps/web/src/app/(home)/_components/SideCircles.tsx b/apps/web/src/app/(home)/_components/SideCircles.tsx index 1db09ef..2dec64e 100644 --- a/apps/web/src/app/(home)/_components/SideCircles.tsx +++ b/apps/web/src/app/(home)/_components/SideCircles.tsx @@ -2,14 +2,14 @@ const SideCircles = () => { return ( <>
-
-
-
+
+
+
-
-
-
+
+
+
); diff --git a/apps/web/src/app/(home)/_components/TechConstellation.tsx b/apps/web/src/app/(home)/_components/TechConstellation.tsx index 63dddae..4254a79 100644 --- a/apps/web/src/app/(home)/_components/TechConstellation.tsx +++ b/apps/web/src/app/(home)/_components/TechConstellation.tsx @@ -153,7 +153,7 @@ const TechConstellation = () => { return (
+ + +
+
+ {data.label} +
+
+ {data.description} +
+ {!data.isDefault && !data.isStatic && ( +
+ Alternative Option +
+ )} +
+ + +
+ ); +} diff --git a/apps/web/src/app/(home)/_components/TechSelector.tsx b/apps/web/src/app/(home)/_components/TechSelector.tsx new file mode 100644 index 0000000..a0a0040 --- /dev/null +++ b/apps/web/src/app/(home)/_components/TechSelector.tsx @@ -0,0 +1,81 @@ +type TechOption = { + id: string; + label: string; + category: string; +}; + +const techOptions: Record = { + backend: [ + { id: "hono", label: "Hono", category: "backend" }, + { id: "express", label: "Express", category: "backend" }, + ], + database: [ + { id: "libsql", label: "libSQL", category: "database" }, + { id: "postgres", label: "PostgreSQL", category: "database" }, + ], + orm: [ + { id: "drizzle", label: "Drizzle", category: "orm" }, + { id: "prisma", label: "Prisma", category: "orm" }, + ], + auth: [ + { id: "better-auth", label: "Better-Auth", category: "auth" }, + { id: "no-auth", label: "No Auth", category: "auth" }, + ], +}; + +interface TechSelectorProps { + onSelect: (category: string, techId: string) => void; + activeNodes: Record; +} + +export function TechSelector({ onSelect, activeNodes }: TechSelectorProps) { + return ( +
+
Customize Stack
+ {Object.entries(techOptions).map(([category, options]) => ( +
+
{category}
+
+ {options.map((option) => ( + onSelect(category, option.id)} + > + {option.label} + + ))} +
+
+ ))} +
+ ); +} + +const Badge = ({ + children, + className, + ...props +}: { + children: React.ReactNode; + variant: "primary" | "secondary"; + className?: string; + onClick?: () => void; +}) => { + return ( + + {children} + + ); +}; diff --git a/apps/web/src/app/(home)/page.tsx b/apps/web/src/app/(home)/page.tsx index 80d5c39..0bb0141 100644 --- a/apps/web/src/app/(home)/page.tsx +++ b/apps/web/src/app/(home)/page.tsx @@ -4,7 +4,8 @@ import { Poppins } from "next/font/google"; import React from "react"; import BackgroundGradients from "./_components/BackgroundGradients"; import CodeContainer from "./_components/CodeContainer"; -import Featured from "./_components/FeaturedSection"; +import CustomizableSection from "./_components/CustomizableSection"; +// import Featured from "./_components/FeaturedSection"; import NpmPackage from "./_components/NpmPackage"; import SideCircles from "./_components/SideCircles"; import Spotlight from "./_components/Spotlight"; @@ -62,6 +63,7 @@ export default function HomePage() {
+

@@ -90,9 +92,9 @@ export default function HomePage() {

-
- + + ); } diff --git a/apps/web/src/app/global.css b/apps/web/src/app/global.css index 3cc1174..1e81c16 100644 --- a/apps/web/src/app/global.css +++ b/apps/web/src/app/global.css @@ -52,3 +52,16 @@ opacity: 0; animation: fadeInUp 0.5s ease-out forwards; } + +.border-beam { + animation: border-beam 3s linear infinite; +} + +@keyframes border-beam { + 0% { + background-position: 0% 50%; + } + 100% { + background-position: 200% 50%; + } +} diff --git a/apps/web/src/lib/constant.ts b/apps/web/src/lib/constant.ts index 0c330eb..f929674 100644 --- a/apps/web/src/lib/constant.ts +++ b/apps/web/src/lib/constant.ts @@ -9,6 +9,7 @@ import { ServerCog, Workflow, } from "lucide-react"; +import type { TechNode } from "./types"; export const technologies = [ { @@ -103,3 +104,161 @@ export const technologies = [ left: "left-[6rem]", }, ]; + +export const initialNodes: TechNode[] = [ + { + id: "bun", + type: "techNode", + position: { x: 536, y: 204 }, + data: { + label: "Bun", + category: "core", + description: "Fast all-in-one JavaScript runtime", + isDefault: true, + isActive: true, + }, + }, + { + id: "tanstack", + type: "techNode", + position: { x: 362, y: 296 }, + data: { + label: "TanStack Router", + category: "frontend", + description: "Type-safe routing", + isDefault: true, + isActive: true, + group: "router", + }, + }, + { + id: "tailwind", + type: "techNode", + position: { x: 494, y: 379 }, + data: { + label: "Tailwind CSS", + category: "frontend", + description: "Utility-first CSS framework", + isDefault: true, + isActive: true, + isStatic: true, + }, + }, + { + id: "shadcn", + type: "techNode", + position: { x: 358, y: 486 }, + data: { + label: "shadcn/ui", + category: "frontend", + description: "Re-usable components", + isDefault: true, + isActive: true, + isStatic: true, + }, + }, + { + id: "hono", + type: "techNode", + position: { x: 700, y: 325 }, + data: { + label: "Hono", + category: "backend", + description: "Ultrafast web framework", + isDefault: true, + isActive: true, + group: "backend", + }, + }, + { + id: "express", + type: "techNode", + position: { x: 897, y: 389 }, + data: { + label: "Express", + category: "backend", + description: "Fast, unopinionated web framework", + isDefault: false, + isActive: false, + group: "backend", + }, + }, + { + id: "libsql", + type: "techNode", + position: { x: 544, y: 532 }, + data: { + label: "libSQL", + category: "database", + description: "SQLite-compatible database", + isDefault: true, + isActive: true, + group: "database", + }, + }, + { + id: "postgres", + type: "techNode", + position: { x: 318, y: 579 }, + data: { + label: "PostgreSQL", + category: "database", + description: "Advanced SQL database", + isDefault: false, + isActive: false, + group: "database", + }, + }, + { + id: "drizzle", + type: "techNode", + position: { x: 559, y: 651 }, + data: { + label: "Drizzle", + category: "orm", + description: "TypeScript ORM", + isDefault: true, + isActive: true, + group: "orm", + }, + }, + { + id: "prisma", + type: "techNode", + position: { x: 707, y: 675 }, + data: { + label: "Prisma", + category: "orm", + description: "Next-generation ORM", + isDefault: false, + isActive: false, + group: "orm", + }, + }, + { + id: "better-auth", + type: "techNode", + position: { x: 770, y: 502 }, + data: { + label: "Better-Auth", + category: "auth", + description: "Modern authentication", + isDefault: true, + isActive: true, + group: "auth", + }, + }, + { + id: "no-auth", + type: "techNode", + position: { x: 950, y: 621 }, + data: { + label: "No Auth", + category: "auth", + description: "No authentication needed", + isDefault: false, + isActive: false, + group: "auth", + }, + }, +]; diff --git a/apps/web/src/lib/types.ts b/apps/web/src/lib/types.ts new file mode 100644 index 0000000..27650f2 --- /dev/null +++ b/apps/web/src/lib/types.ts @@ -0,0 +1,32 @@ +export type TechCategory = + | "core" + | "frontend" + | "backend" + | "database" + | "auth" + | "orm" + | "router"; + +export interface TechNode { + id: string; + type: string; + position: { x: number; y: number }; + data: { + label: string; + category: TechCategory; + description: string; + isDefault: boolean; + alternatives?: string[]; + isActive: boolean; + group?: TechCategory; + isStatic?: boolean; + }; +} + +export interface TechEdge { + id: string; + source: string; + target: string; + type?: string; + animated?: boolean; +} diff --git a/bun.lock b/bun.lock index 1e45b0f..032bddf 100644 --- a/bun.lock +++ b/bun.lock @@ -39,6 +39,8 @@ "name": "web", "version": "0.0.0", "dependencies": { + "@xyflow/react": "^12.4.3", + "framer-motion": "^12.4.3", "fumadocs-core": "15.0.6", "fumadocs-mdx": "11.5.3", "fumadocs-ui": "15.0.6", @@ -448,6 +450,18 @@ "@types/acorn": ["@types/acorn@4.0.6", "", { "dependencies": { "@types/estree": "*" } }, "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ=="], + "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], + + "@types/d3-drag": ["@types/d3-drag@3.0.7", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ=="], + + "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "*" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], + + "@types/d3-selection": ["@types/d3-selection@3.0.11", "", {}, "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w=="], + + "@types/d3-transition": ["@types/d3-transition@3.0.9", "", { "dependencies": { "@types/d3-selection": "*" } }, "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg=="], + + "@types/d3-zoom": ["@types/d3-zoom@3.0.8", "", { "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw=="], + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], "@types/degit": ["@types/degit@2.8.6", "", {}, "sha512-y0M7sqzsnHB6cvAeTCBPrCQNQiZe8U4qdzf8uBVmOWYap5MMTN/gB2iEqrIqFiYcsyvP74GnGD5tgsHttielFw=="], @@ -498,6 +512,10 @@ "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + "@xyflow/react": ["@xyflow/react@12.4.3", "", { "dependencies": { "@xyflow/system": "0.0.51", "classcat": "^5.0.3", "zustand": "^4.4.0" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "sha512-oO50TIY4rbgOURK5pmvL4LwLOQdh6YkvrvOBZPBedltJ1TINCRp0FiyYKfYhLnaDcW8/aayvGtFpUcSkPQxpGg=="], + + "@xyflow/system": ["@xyflow/system@0.0.51", "", { "dependencies": { "@types/d3-drag": "^3.0.7", "@types/d3-selection": "^3.0.10", "@types/d3-transition": "^3.0.8", "@types/d3-zoom": "^3.0.8", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0" } }, "sha512-cYnuM3oWQQjx2Rdz0LdZCnbUaWZdZDiik20kPDYsa5SIlq++ZDIcKiDF6a93ncfMv9Ej5GWfDkouE7bObrdRqQ=="], + "acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], @@ -596,6 +614,8 @@ "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + "classcat": ["classcat@5.0.5", "", {}, "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w=="], + "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], "cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="], @@ -634,6 +654,24 @@ "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + + "d3-dispatch": ["d3-dispatch@3.0.1", "", {}, "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="], + + "d3-drag": ["d3-drag@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" } }, "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg=="], + + "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], + + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "1 - 3" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + + "d3-selection": ["d3-selection@3.0.0", "", {}, "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="], + + "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], + + "d3-transition": ["d3-transition@3.0.1", "", { "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w=="], + + "d3-zoom": ["d3-zoom@3.0.0", "", { "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" } }, "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw=="], + "damerau-levenshtein": ["damerau-levenshtein@1.0.8", "", {}, "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA=="], "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], @@ -794,6 +832,8 @@ "foreground-child": ["foreground-child@3.3.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" } }, "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg=="], + "framer-motion": ["framer-motion@12.4.3", "", { "dependencies": { "motion-dom": "^12.0.0", "motion-utils": "^12.0.0", "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-rsMeO7w3dKyNG09o3cGwSH49iHU+VgDmfSSfsX+wfkO3zDA6WWkh4sUsMXd155YROjZP+7FTIhDrBYfgZeHjKQ=="], + "fs-extra": ["fs-extra@11.3.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew=="], "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], @@ -1184,6 +1224,10 @@ "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], + "motion-dom": ["motion-dom@12.0.0", "", { "dependencies": { "motion-utils": "^12.0.0" } }, "sha512-CvYd15OeIR6kHgMdonCc1ihsaUG4MYh/wrkz8gZ3hBX/uamyZCXN9S9qJoYF03GqfTt7thTV/dxnHYX4+55vDg=="], + + "motion-utils": ["motion-utils@12.0.0", "", {}, "sha512-MNFiBKbbqnmvOjkPyOKgHUp3Q6oiokLkI1bEwm5QA28cxMZrv0CbbBGDNmhF6DIXsi1pCQBSs0dX8xjeER1tmA=="], + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], @@ -1566,6 +1610,8 @@ "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + "use-sync-external-store": ["use-sync-external-store@1.4.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], @@ -1602,6 +1648,8 @@ "zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="], + "zustand": ["zustand@4.5.6", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-ibr/n1hBzLLj5Y+yUcU7dYw8p6WnIVzdJbnX+1YpaScvZVF2ziugqHs+LAmHw4lWO9c/zRj+K1ncgWDQuthEdQ=="], + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], "@changesets/apply-release-plan/fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="],