diff --git a/public/r/animated-list.json b/public/r/animated-list.json index 4eb4050..29179b5 100644 --- a/public/r/animated-list.json +++ b/public/r/animated-list.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "animated-list", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -26,5 +25,6 @@ "content": "import { cn } from \"@/lib/utils\";\ninterface Item {\n name: string;\n description: string;\n icon: string;\n color: string;\n time: string;\n}\n\nexport const Notification = ({\n name,\n description,\n icon,\n color,\n time,\n}: Item) => {\n return (\n \n
\n \n {icon}\n
\n
\n
\n {name}\n ·\n {time}\n
\n

\n {description}\n

\n
\n \n \n );\n};\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/animated-pricing.json b/public/r/animated-pricing.json index 8bce94f..4d18cec 100644 --- a/public/r/animated-pricing.json +++ b/public/r/animated-pricing.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "animated-pricing", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge" @@ -29,5 +28,6 @@ "content": "import React, { ReactNode, useState, useMemo, MouseEvent, CSSProperties } from 'react';\n\ninterface RippleState {\n key: number;\n x: number;\n y: number;\n size: number;\n color: string;\n}\n\ninterface RippleButtonProps {\n children: ReactNode;\n onClick?: (event: MouseEvent) => void;\n className?: string;\n disabled?: boolean;\n variant?: 'default' | 'hover' | 'ghost' | 'hoverborder';\n rippleColor?: string; // User override for the JS click ripple color\n rippleDuration?: number; // Duration for the JS click ripple (all variants)\n\n // For 'hover' variant\n hoverBaseColor?: string;\n hoverRippleColor?: string;\n\n // For 'hoverborder' variant\n hoverBorderEffectColor?: string; // Color of the visual effect forming the border\n hoverBorderEffectThickness?: string; // Thickness of the border effect (e.g., \"0.3em\", \"2px\")\n}\n\nconst hexToRgba = (hex: string, alpha: number): string => {\n let hexValue = hex.startsWith('#') ? hex.slice(1) : hex;\n if (hexValue.length === 3) {\n hexValue = hexValue.split('').map(char => char + char).join('');\n }\n const r = parseInt(hexValue.slice(0, 2), 16);\n const g = parseInt(hexValue.slice(2, 4), 16);\n const b = parseInt(hexValue.slice(4, 6), 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n};\n\nconst GRID_HOVER_NUM_COLS = 36;\nconst GRID_HOVER_NUM_ROWS = 12;\nconst GRID_HOVER_TOTAL_CELLS = GRID_HOVER_NUM_COLS * GRID_HOVER_NUM_ROWS;\nconst GRID_HOVER_RIPPLE_EFFECT_SIZE = \"18.973665961em\";\n\nconst JS_RIPPLE_KEYFRAMES = `\n @keyframes js-ripple-animation {\n 0% { transform: scale(0); opacity: 1; }\n 100% { transform: scale(1); opacity: 0; }\n }\n .animate-js-ripple-effect {\n animation: js-ripple-animation var(--ripple-duration) ease-out forwards;\n }\n`;\n\nconst RippleButton: React.FC = ({\n children,\n onClick,\n className = '',\n disabled = false,\n variant = 'default',\n rippleColor: userProvidedRippleColor,\n rippleDuration = 600,\n hoverBaseColor = '#6996e2',\n hoverRippleColor: customHoverRippleColor,\n hoverBorderEffectColor = '#6996e277',\n hoverBorderEffectThickness = '0.3em',\n}) => {\n const [jsRipples, setJsRipples] = useState([]);\n\n const determinedJsRippleColor = useMemo(() => {\n if (userProvidedRippleColor) {\n return userProvidedRippleColor;\n }\n return 'var(--button-ripple-color, rgba(0, 0, 0, 0.1))';\n }, [userProvidedRippleColor]);\n\n const dynamicGridHoverStyles = useMemo(() => {\n let nthChildHoverRules = '';\n const cellDim = 0.25;\n const initialTopOffset = 0.125;\n const initialLeftOffset = 0.1875;\n\n // Standardized hover transition duration for width and height\n const hoverEffectDuration = '0.9s'; // CHANGED: Standardized to 0.9s\n\n for (let r = 0; r < GRID_HOVER_NUM_ROWS; r++) {\n for (let c = 0; c < GRID_HOVER_NUM_COLS; c++) {\n const childIndex = r * GRID_HOVER_NUM_COLS + c + 1;\n const topPos = initialTopOffset + r * cellDim;\n const leftPos = initialLeftOffset + c * cellDim;\n\n if (variant === 'hover') {\n nthChildHoverRules += `\n .hover-variant-grid-cell:nth-child(${childIndex}):hover ~ .hover-variant-visual-ripple {\n top: ${topPos}em; left: ${leftPos}em;\n transition: width ${hoverEffectDuration} ease, height ${hoverEffectDuration} ease, top 0s linear, left 0s linear;\n }`;\n } else if (variant === 'hoverborder') {\n nthChildHoverRules += `\n .hoverborder-variant-grid-cell:nth-child(${childIndex}):hover ~ .hoverborder-variant-visual-ripple {\n top: ${topPos}em; left: ${leftPos}em;\n transition: width ${hoverEffectDuration} ease-out, height ${hoverEffectDuration} ease-out, top 0s linear, left 0s linear;\n }`; // Using ease-out for hoverborder as it was before, just changed duration\n }\n }\n }\n\n if (variant === 'hover') {\n const actualHoverRippleColor = customHoverRippleColor\n ? customHoverRippleColor\n : hexToRgba(hoverBaseColor, 0.466);\n return `\n .hover-variant-visual-ripple {\n background-color: ${actualHoverRippleColor};\n transition: width ${hoverEffectDuration} ease, height ${hoverEffectDuration} ease, top 99999s linear, left 99999s linear;\n }\n .hover-variant-grid-cell:hover ~ .hover-variant-visual-ripple {\n width: ${GRID_HOVER_RIPPLE_EFFECT_SIZE}; height: ${GRID_HOVER_RIPPLE_EFFECT_SIZE};\n }\n ${nthChildHoverRules}\n `;\n } else if (variant === 'hoverborder') {\n return `\n .hoverborder-variant-ripple-container {\n padding: ${hoverBorderEffectThickness};\n mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n mask-composite: exclude;\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n }\n .hoverborder-variant-visual-ripple {\n background-color: ${hoverBorderEffectColor};\n /* Ensure the base transition also uses the standardized duration for width/height */\n transition: width ${hoverEffectDuration} ease-out, height ${hoverEffectDuration} ease-out, top 99999s linear, left 9999s linear;\n }\n .hoverborder-variant-grid-cell:hover ~ .hoverborder-variant-visual-ripple {\n width: ${GRID_HOVER_RIPPLE_EFFECT_SIZE}; height: ${GRID_HOVER_RIPPLE_EFFECT_SIZE};\n }\n ${nthChildHoverRules}\n `;\n }\n return '';\n }, [variant, hoverBaseColor, customHoverRippleColor, hoverBorderEffectColor, hoverBorderEffectThickness]);\n\n const createJsRipple = (event: MouseEvent) => {\n const button = event.currentTarget;\n const rect = button.getBoundingClientRect();\n const size = Math.max(rect.width, rect.height) * 2;\n const x = event.clientX - rect.left - size / 2;\n const y = event.clientY - rect.top - size / 2;\n const newRipple: RippleState = { key: Date.now(), x, y, size, color: determinedJsRippleColor };\n setJsRipples(prev => [...prev, newRipple]);\n setTimeout(() => {\n setJsRipples(currentRipples => currentRipples.filter(r => r.key !== newRipple.key));\n }, rippleDuration);\n };\n\n const handleButtonClick = (event: MouseEvent) => {\n if (!disabled) {\n createJsRipple(event);\n if (onClick) onClick(event);\n }\n };\n\n const jsRippleElements = (\n
\n {jsRipples.map(ripple => (\n \n ))}\n
\n );\n\n if (variant === 'hover') {\n const hoverButtonFinalClassName = [\n \"relative\", \"rounded-lg\", \"text-lg\", \"px-4\", \"py-2\",\n \"border-none\", \"bg-transparent\", \"isolate\", \"overflow-hidden\", \"cursor-pointer\",\n disabled ? \"opacity-50 cursor-not-allowed pointer-events-none\" : \"\",\n className,\n ].filter(Boolean).join(\" \");\n return (\n <>\n \n ) : null}\n {globalKey ? (\n \n ) : null}\n {globalKey ? (\n \n ) : null}\n\n {variant === \"rainbow\"\n ? flow({\n colors: rainbowColors,\n })\n : null}\n {props.children}\n {id ? (\n {\n setOpen(false);\n if (globalKey) {\n localStorage.setItem(globalKey, \"true\");\n window.dispatchEvent(new Event(\"banner-status-changed\"));\n }\n }}\n className={cn(\n buttonVariants({\n variant: \"ghost\",\n className:\n \"absolute end-2 md:end-20 top-1/2 -translate-y-1/2 text-fd-muted-foreground/50\",\n size: \"icon\",\n }),\n )}\n >\n \n \n ) : null}\n \n );\n}\n\nconst maskImage =\n \"linear-gradient(to bottom,white,transparent), radial-gradient(circle at top center, white, transparent)\";\n\nfunction flow({ colors }: { colors: string[] }) {\n return (\n <>\n `${color} ${(i * 50) / colors.length}%`).join(\", \")})`,\n backgroundSize: \"200% 100%\",\n filter: \"saturate(2)\",\n } as object\n }\n />\n \n \n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/banner.json b/public/r/banner.json index 6924e24..dfa2425 100644 --- a/public/r/banner.json +++ b/public/r/banner.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "banner", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -22,5 +21,6 @@ "content": "\"use client\";\nimport { type HTMLAttributes, useEffect, useState } from \"react\";\nimport { X } from \"lucide-react\";\nimport { buttonVariants } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\ntype BannerVariant = \"rainbow\" | \"normal\";\n\nexport function Banner({\n id,\n xColor,\n variant = \"normal\",\n changeLayout = true,\n height = \"3rem\",\n rainbowColors = [\n \"rgba(0,149,255,0.56)\",\n \"rgba(231,77,255,0.77)\",\n \"rgba(255,0,0,0.73)\",\n \"rgba(131,255,166,0.66)\",\n ],\n ...props\n}: HTMLAttributes & {\n /**\n * @defaultValue 3rem\n */\n height?: string;\n\n xColor?: string;\n\n /**\n * @defaultValue 'normal'\n */\n variant?: BannerVariant;\n\n /**\n * For rainbow variant only, customise the colors\n */\n rainbowColors?: string[];\n\n /**\n * Change Fumadocs layout styles\n *\n * @defaultValue true\n */\n changeLayout?: boolean;\n}) {\n const [open, setOpen] = useState(true);\n const globalKey = id ? `nd-banner-${id}` : null;\n\n useEffect(() => {\n if (globalKey) setOpen(localStorage.getItem(globalKey) !== \"true\");\n }, [globalKey]);\n\n if (!open) return null;\n\n return (\n \n {changeLayout && open ? (\n \n ) : null}\n {globalKey ? (\n \n ) : null}\n {globalKey ? (\n \n ) : null}\n\n {variant === \"rainbow\"\n ? flow({\n colors: rainbowColors,\n })\n : null}\n {props.children}\n {id ? (\n {\n setOpen(false);\n if (globalKey) {\n localStorage.setItem(globalKey, \"true\");\n window.dispatchEvent(new Event(\"banner-status-changed\"));\n }\n }}\n className={cn(\n buttonVariants({\n variant: \"ghost\",\n className:\n \"absolute end-2 md:end-20 top-1/2 -translate-y-1/2 text-fd-muted-foreground/50\",\n size: \"icon\",\n }),\n )}\n >\n \n \n ) : null}\n \n );\n}\n\nconst maskImage =\n \"linear-gradient(to bottom,white,transparent), radial-gradient(circle at top center, white, transparent)\";\n\nfunction flow({ colors }: { colors: string[] }) {\n return (\n <>\n `${color} ${(i * 50) / colors.length}%`).join(\", \")})`,\n backgroundSize: \"200% 100%\",\n filter: \"saturate(2)\",\n } as object\n }\n />\n \n \n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/bars-background.json b/public/r/bars-background.json index 3a4effa..75014f8 100644 --- a/public/r/bars-background.json +++ b/public/r/bars-background.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "bars-background", - "type": "registry:component", "dependencies": [ "motion/react" ], @@ -18,5 +17,6 @@ "content": "'use client';\nimport { motion } from 'motion/react';\n\ninterface GradientBarsProps {\n bars?: number;\n colors?: string[];\n}\n\nexport const GradientBars = ({\n bars = 20,\n colors = ['#3ca2faD9', 'transparent'],\n}: GradientBarsProps) => {\n const gradientStyle = `linear-gradient(to top, ${colors.join(', ')})`;\n return (\n
\n
\n {Array.from({ length: bars }).map((_, index) => {\n const position = index / (bars - 1);\n const center = 0.5;\n const distance = Math.abs(position - center);\n const scale = 0.3 + 0.7 * Math.pow(distance * 2, 1.2);\n\n return (\n \n );\n })}\n
\n
\n );\n};\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/border-button.json b/public/r/border-button.json index 0247d22..c9b9c1f 100644 --- a/public/r/border-button.json +++ b/public/r/border-button.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "border-button", - "type": "registry:component", "dependencies": [ "react-icons", "clsx", @@ -20,5 +19,6 @@ "content": "import { cn } from \"@/lib/utils\";\nimport React from \"react\";\nimport { FaLocationArrow } from \"react-icons/fa\";\n\nconst BorderAnimationButton = ({ text , className}: { text: string , className?: string}) => {\n return (\n
\n \n

\n {text}\n \n

\n
\n );\n};\n\nexport default BorderAnimationButton;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/canvas-cursor.json b/public/r/canvas-cursor.json index 4064ccc..1e60dad 100644 --- a/public/r/canvas-cursor.json +++ b/public/r/canvas-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "canvas-cursor", - "type": "registry:component", "dependencies": [ "" ], @@ -18,5 +17,6 @@ "content": "/* eslint-disable no-var */\n/* eslint-disable @typescript-eslint/no-unused-expressions */\n/* eslint-disable @typescript-eslint/ban-ts-comment */\n// @ts-nocheck\n\"use client\";\n\n// this is a client component\nimport { useEffect } from \"react\";\n\nexport default function CanvasCursor() {\n useEffect(() => {\n renderCanvas();\n }, []);\n return (\n \n );\n}\n\nfunction n(e) {\n // @ts-ignore\n this.init(e || {});\n}\nn.prototype = {\n // @ts-ignore\n init: function (e) {\n // @ts-ignore\n this.phase = e.phase || 0;\n // @ts-ignore\n this.offset = e.offset || 0;\n // @ts-ignore\n this.frequency = e.frequency || 0.001;\n // @ts-ignore\n this.amplitude = e.amplitude || 1;\n },\n update: function () {\n return (\n // @ts-ignore\n (\n (this.phase += this.frequency),\n // @ts-ignore\n (e = this.offset + Math.sin(this.phase) * this.amplitude)\n )\n );\n },\n value: function () {\n return e;\n },\n};\n\n// @ts-ignore\nfunction Line(e) {\n // @ts-ignore\n this.init(e || {});\n}\n\nLine.prototype = {\n // @ts-ignore\n init: function (e) {\n // @ts-ignore\n this.spring = e.spring + 0.1 * Math.random() - 0.05;\n // @ts-ignore\n this.friction = E.friction + 0.01 * Math.random() - 0.005;\n // @ts-ignore\n this.nodes = [];\n for (var t, n = 0; n < E.size; n++) {\n t = new Node();\n // @ts-ignore\n t.x = pos.x;\n // @ts-ignore\n t.y = pos.y;\n // @ts-ignore\n this.nodes.push(t);\n }\n },\n update: function () {\n // @ts-ignore\n let e = this.spring,\n // @ts-ignore\n t = this.nodes[0];\n // @ts-ignore\n t.vx += (pos.x - t.x) * e;\n // @ts-ignore\n t.vy += (pos.y - t.y) * e;\n // @ts-ignore\n for (var n, i = 0, a = this.nodes.length; i < a; i++)\n // @ts-ignore\n ((t = this.nodes[i]),\n 0 < i &&\n // @ts-ignore\n ((n = this.nodes[i - 1]),\n (t.vx += (n.x - t.x) * e),\n (t.vy += (n.y - t.y) * e),\n (t.vx += n.vx * E.dampening),\n (t.vy += n.vy * E.dampening)),\n // @ts-ignore\n (t.vx *= this.friction),\n // @ts-ignore\n (t.vy *= this.friction),\n (t.x += t.vx),\n (t.y += t.vy),\n (e *= E.tension));\n },\n draw: function () {\n let e,\n t,\n // @ts-ignore\n n = this.nodes[0].x,\n // @ts-ignore\n i = this.nodes[0].y;\n // @ts-ignore\n ctx.beginPath();\n // @ts-ignore\n ctx.moveTo(n, i);\n // @ts-ignore\n for (var a = 1, o = this.nodes.length - 2; a < o; a++) {\n // @ts-ignore\n e = this.nodes[a];\n // @ts-ignore\n t = this.nodes[a + 1];\n n = 0.5 * (e.x + t.x);\n i = 0.5 * (e.y + t.y);\n // @ts-ignore\n ctx.quadraticCurveTo(e.x, e.y, n, i);\n }\n // @ts-ignore\n e = this.nodes[a];\n // @ts-ignore\n t = this.nodes[a + 1];\n // @ts-ignore\n ctx.quadraticCurveTo(e.x, e.y, t.x, t.y);\n // @ts-ignore\n ctx.stroke();\n // @ts-ignore\n ctx.closePath();\n },\n};\n\n// @ts-ignore\nfunction onMousemove(e) {\n function o() {\n lines = [];\n for (let e = 0; e < E.trails; e++)\n lines.push(new Line({ spring: 0.45 + (e / E.trails) * 0.025 }));\n }\n // @ts-ignore\n function c(e) {\n (e.touches\n ? // @ts-ignore\n ((pos.x = e.touches[0].pageX), (pos.y = e.touches[0].pageY))\n : // @ts-ignore\n ((pos.x = e.clientX), (pos.y = e.clientY)),\n e.preventDefault());\n }\n // @ts-ignore\n function l(e) {\n // @ts-ignore\n 1 == e.touches.length &&\n ((pos.x = e.touches[0].pageX), (pos.y = e.touches[0].pageY));\n }\n (document.removeEventListener(\"mousemove\", onMousemove),\n document.removeEventListener(\"touchstart\", onMousemove),\n document.addEventListener(\"mousemove\", c),\n document.addEventListener(\"touchmove\", c),\n document.addEventListener(\"touchstart\", l),\n c(e),\n o(),\n render());\n}\n\nfunction render() {\n // @ts-ignore\n if (ctx.running) {\n // @ts-ignore\n ctx.globalCompositeOperation = \"source-over\";\n // @ts-ignore\n ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n // @ts-ignore\n ctx.globalCompositeOperation = \"lighter\";\n // @ts-ignore\n ctx.strokeStyle = \"hsla(\" + Math.round(f.update()) + \",100%,50%,0.025)\";\n // @ts-ignore\n ctx.lineWidth = 10;\n for (var e, t = 0; t < E.trails; t++) {\n // @ts-ignore\n (e = lines[t]).update();\n e.draw();\n }\n // @ts-ignore\n ctx.frame++;\n window.requestAnimationFrame(render);\n }\n}\n\nfunction resizeCanvas() {\n // @ts-ignore\n ctx.canvas.width = window.innerWidth - 20;\n // @ts-ignore\n ctx.canvas.height = window.innerHeight;\n}\n\n// @ts-ignore\nvar ctx,\n // @ts-ignore\n f,\n e = 0,\n pos = {},\n // @ts-ignore\n lines = [],\n E = {\n debug: true,\n friction: 0.5,\n trails: 80,\n size: 50,\n dampening: 0.025,\n tension: 0.99,\n };\nfunction Node() {\n this.x = 0;\n this.y = 0;\n this.vy = 0;\n this.vx = 0;\n}\n\nexport const renderCanvas = function () {\n // @ts-ignore\n ctx = document.getElementById(\"canvas\").getContext(\"2d\");\n ctx.running = true;\n ctx.frame = 1;\n f = new n({\n phase: Math.random() * 2 * Math.PI,\n amplitude: 85,\n frequency: 0.0015,\n offset: 285,\n });\n document.addEventListener(\"mousemove\", onMousemove);\n document.addEventListener(\"touchstart\", onMousemove);\n document.body.addEventListener(\"orientationchange\", resizeCanvas);\n window.addEventListener(\"resize\", resizeCanvas);\n window.addEventListener(\"focus\", () => {\n // @ts-ignore\n if (!ctx.running) {\n // @ts-ignore\n ctx.running = true;\n render();\n }\n });\n window.addEventListener(\"blur\", () => {\n // @ts-ignore\n ctx.running = true;\n });\n resizeCanvas();\n};\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/code-cursor.json b/public/r/code-cursor.json index fa6d9f6..0c927b7 100644 --- a/public/r/code-cursor.json +++ b/public/r/code-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "code-cursor", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React, { useEffect, useRef } from \"react\";\n\ninterface IBinaryChar {\n x: number;\n y: number;\n alpha: number;\n char: \"0\" | \"1\";\n color: string;\n update: () => void;\n draw: () => void;\n}\n\nconst CodeCursor = () => {\n const canvasRef = useRef(null);\n const particles: IBinaryChar[] = [];\n\n useEffect(() => {\n const canvas = canvasRef.current!;\n const ctx = canvas.getContext(\"2d\")!;\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n\n class BinaryChar {\n x: number;\n y: number;\n alpha: number;\n char: \"0\" | \"1\";\n color: string;\n\n constructor(x: number, y: number) {\n this.x = x;\n this.y = y;\n this.alpha = 1;\n this.char = Math.random() > 0.5 ? \"1\" : \"0\";\n\n // Assign different colors for 0 and 1\n this.color = this.char === \"0\" ? \"#00FFC6\" : \"#00B4FF\"; // mint and blue\n }\n\n update() {\n this.y -= 0.5;\n this.alpha -= 0.02;\n }\n\n draw() {\n ctx.fillStyle = `${this.color}${Math.floor(this.alpha * 255)\n .toString(16)\n .padStart(2, \"0\")}`; // Apply fading alpha as hex\n ctx.font = \"18px monospace\";\n ctx.fillText(this.char, this.x, this.y);\n }\n }\n\n const animate = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n particles.forEach((p, i) => {\n p.update();\n p.draw();\n if (p.alpha <= 0) particles.splice(i, 1);\n });\n requestAnimationFrame(animate);\n };\n\n animate();\n\n const onMove = (e: MouseEvent) => {\n for (let i = 0; i < 2; i++) {\n particles.push(new BinaryChar(e.clientX, e.clientY));\n }\n };\n\n window.addEventListener(\"mousemove\", onMove);\n\n return () => {\n window.removeEventListener(\"mousemove\", onMove);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n return (\n \n );\n};\n\nexport default CodeCursor;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/contact-form.json b/public/r/contact-form.json index 4021681..a293277 100644 --- a/public/r/contact-form.json +++ b/public/r/contact-form.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "contact-form", - "type": "registry:component", "dependencies": [ "framer-motion", "clsx", @@ -35,5 +34,6 @@ "content": "\"use client\";\nimport { useState, useRef, ReactNode } from \"react\";\nimport { motion, useMotionValue, useTransform } from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nconst ShinyTextArea = ({\n className,\n icon,\n placeholder,\n name,\n rows = 4,\n required,\n borderHoverAnimation = \"1px solid var(--primary-color)\",\n focus = \"focus:border-[var(--primary-color)]\",\n}: {\n className?: string;\n icon?: ReactNode;\n placeholder: string;\n name: string;\n rows?: number;\n required?: boolean;\n borderHoverAnimation?: string;\n focus?: string;\n}) => {\n const divRef = useRef(null);\n const [, setIsFocused] = useState(false);\n const positionX = useMotionValue(0);\n const positionY = useMotionValue(0);\n const [opacity, setOpacity] = useState(0);\n\n const handleMouseMove = (e: React.MouseEvent) => {\n if (divRef.current) {\n const rect = divRef.current.getBoundingClientRect();\n positionX.set(e.clientX - rect.left);\n positionY.set(e.clientY - rect.top);\n }\n };\n\n const handleFocus = () => {\n setIsFocused(true);\n setOpacity(1);\n };\n\n const handleBlur = () => {\n setIsFocused(false);\n setOpacity(0);\n };\n\n const handleMouseEnter = () => setOpacity(1);\n const handleMouseLeave = () => setOpacity(0);\n\n const shineBorder = useTransform(\n [positionX, positionY],\n ([x, y]) =>\n `radial-gradient(30% 30px at ${x}px ${y}px, black 45%, transparent)`,\n );\n\n return (\n
\n \n\n \n {icon}\n
\n );\n};\n\nexport default ShinyTextArea;", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/counter-loader.json b/public/r/counter-loader.json index b9e826d..797dcf4 100644 --- a/public/r/counter-loader.json +++ b/public/r/counter-loader.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "counter-loader", - "type": "registry:component", "dependencies": [ "styled-components" ], @@ -18,5 +17,6 @@ "content": "\"use client\";\nimport React from \"react\";\nimport styled from \"styled-components\";\n\nconst CounterLoading = () => {\n return (\n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n );\n};\n\n\nconst StyledWrapper = styled.div`\n width: 100vw;\n height: 30rem;\n display: flex;\n justify-content: center;\n align-items: center;\n\n #timer {\n display: grid;\n grid-template-columns: repeat(3, 25px);\n grid-template-rows: repeat(5, 25px);\n gap: 10px;\n grid-template-areas:\n \"div1 div2 div3\"\n \"div4 div5 div6\"\n \"div7 div8 div9\"\n \"div10 div11 div12\"\n \"div13 div14 div15\";\n }\n\n #timer > div {\n background-color: skyblue;\n border-radius: 5px;\n }\n\n #div1 { grid-area: div1; animation: div1 10s both infinite; }\n #div2 { grid-area: div2; animation: div2 10s both infinite; }\n #div3 { grid-area: div3; }\n #div4 { grid-area: div4; animation: div4 10s both infinite; }\n #div5 { grid-area: div5; display: none; }\n #div6 { grid-area: div6; animation: div6 10s both infinite; }\n #div7 { grid-area: div7; animation: div7 10s both infinite; }\n #div8 { grid-area: div8; animation: div8 10s both infinite; }\n #div9 { grid-area: div9; }\n #div10 { grid-area: div10; animation: div10 10s both infinite; }\n #div11 { grid-area: div11; display: none; }\n #div12 { grid-area: div12; animation: div12 10s both infinite; }\n #div13 { grid-area: div13; animation: div13 10s both infinite; }\n #div14 { grid-area: div14; animation: div14 10s both infinite; }\n #div15 { grid-area: div15; }\n\n #div1 {\n grid-area: div1;\n animation: div1 10s both infinite;\n }\n\n @keyframes div1 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(70px);\n }\n\n 20% {\n transform: translateX(0);\n }\n\n 30% {\n transform: translateX(0);\n }\n\n 40% {\n transform: translateX(0);\n }\n\n 50% {\n transform: translateX(0);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(0);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div2 {\n grid-area: div2;\n animation: div2 10s both infinite;\n }\n\n @keyframes div2 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(35px);\n }\n\n 20% {\n transform: translateX(0);\n }\n\n 30% {\n transform: translateX(0);\n }\n\n 40% {\n transform: translateX(35px);\n }\n\n 50% {\n transform: translateX(0);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(0);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div3 {\n grid-area: div3;\n }\n\n #div4 {\n grid-area: div4;\n animation: div4 10s both infinite;\n }\n\n @keyframes div4 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(70px);\n }\n\n 20% {\n transform: translateX(70px);\n }\n\n 30% {\n transform: translateX(70px);\n }\n\n 40% {\n transform: translateX(0);\n }\n\n 50% {\n transform: translateX(0);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(70px);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div5 {\n grid-area: div5;\n display: none;\n }\n\n #div6 {\n grid-area: div6;\n animation: div6 10s both infinite;\n }\n\n @keyframes div6 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(0);\n }\n\n 20% {\n transform: translateX(0);\n }\n\n 30% {\n transform: translateX(0);\n }\n\n 40% {\n transform: translateX(0);\n }\n\n 50% {\n transform: translateX(-70px);\n }\n\n 60% {\n transform: translateX(-70px);\n }\n\n 70% {\n transform: translateX(0);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div7 {\n grid-area: div7;\n animation: div7 10s both infinite;\n }\n\n @keyframes div7 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(70px);\n }\n\n 20% {\n transform: translateX(0);\n }\n\n 30% {\n transform: translateX(0);\n }\n\n 40% {\n transform: translateX(0);\n }\n\n 50% {\n transform: translateX(0);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(70px);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div8 {\n grid-area: div8;\n animation: div8 10s both infinite;\n }\n\n @keyframes div8 {\n 0% {\n transform: translateX(35px);\n }\n\n 10% {\n transform: translateX(35px);\n }\n\n 20% {\n transform: translateX(0);\n }\n\n 30% {\n transform: translateX(0);\n }\n\n 40% {\n transform: translateX(0);\n }\n\n 50% {\n transform: translateX(0);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(35px);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(35px);\n }\n }\n\n #div9 {\n grid-area: div9;\n }\n\n #div10 {\n grid-area: div10;\n animation: div10 10s both infinite;\n }\n\n @keyframes div10 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(70px);\n }\n\n 20% {\n transform: translateX(0);\n }\n\n 30% {\n transform: translateX(70px);\n }\n\n 40% {\n transform: translateX(70px);\n }\n\n 50% {\n transform: translateX(70px);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(70px);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(70px);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div11 {\n grid-area: div11;\n display: none;\n }\n\n #div12 {\n grid-area: div12;\n animation: div12 10s both infinite;\n }\n\n @keyframes div12 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(0);\n }\n\n 20% {\n transform: translateX(-70px);\n }\n\n 30% {\n transform: translateX(0);\n }\n\n 40% {\n transform: translateX(0);\n }\n\n 50% {\n transform: translateX(0);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(0);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div13 {\n grid-area: div13;\n animation: div13 10s both infinite;\n }\n\n @keyframes div13 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(70px);\n }\n\n 20% {\n transform: translateX(0);\n }\n\n 30% {\n transform: translateX(0);\n }\n\n 40% {\n transform: translateX(70px);\n }\n\n 50% {\n transform: translateX(0);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(70px);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div14 {\n grid-area: div14;\n animation: div14 10s both infinite;\n }\n\n @keyframes div14 {\n 0% {\n transform: translateX(0);\n }\n\n 10% {\n transform: translateX(35px);\n }\n\n 20% {\n transform: translateX(0);\n }\n\n 30% {\n transform: translateX(0);\n }\n\n 40% {\n transform: translateX(35px);\n }\n\n 50% {\n transform: translateX(0);\n }\n\n 60% {\n transform: translateX(0);\n }\n\n 70% {\n transform: translateX(35px);\n }\n\n 80% {\n transform: translateX(0);\n }\n\n 90% {\n transform: translateX(0);\n }\n\n 100% {\n transform: translateX(0);\n }\n }\n\n #div15 {\n grid-area: div15;\n }\n`;\n\nexport default CounterLoading;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/creative-pricing.json b/public/r/creative-pricing.json index 54fd862..29155cf 100644 --- a/public/r/creative-pricing.json +++ b/public/r/creative-pricing.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "creative-pricing", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -27,5 +26,6 @@ "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n)\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes,\n VariantProps {\n asChild?: boolean\n}\n\nconst Button = React.forwardRef(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n return (\n \n )\n },\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/digital-hero.json b/public/r/digital-hero.json index de554b8..30c3e12 100644 --- a/public/r/digital-hero.json +++ b/public/r/digital-hero.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "digital-hero", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -21,5 +20,6 @@ "content": ".grow-underline {\n animation: growUnderline 1.5s ease-in-out forwards;\n}\n\n.scanline {\n animation: scanlineAnim 4s linear infinite;\n}\n\n@keyframes growUnderline {\n 0% {\n width: 0%;\n }\n 100% {\n width: 100%;\n }\n}\n\n@keyframes scanlineAnim {\n 0% {\n transform: translateY(-100vh);\n }\n 100% {\n transform: translateY(100vh);\n }\n}", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/draw-cursor.json b/public/r/draw-cursor.json index 681afdf..99cc8fd 100644 --- a/public/r/draw-cursor.json +++ b/public/r/draw-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "draw-cursor", - "type": "registry:component", "dependencies": [ "gsap" ], @@ -18,5 +17,6 @@ "content": "\"use client\";\n\nimport React, { useRef, useEffect } from \"react\";\nimport { gsap } from \"gsap\";\n\ntype DrawingType = \"drawOnHold\" | \"drawAlways\";\n\ninterface Props {\n strokeColor?: string;\n strokeWidth?: number;\n type: DrawingType;\n followEffect?: boolean;\n}\n\nconst DrawCursor: React.FC = ({\n strokeColor = \"#FF9900\",\n strokeWidth = 10,\n type = \"drawAlways\",\n followEffect = false,\n}) => {\n const containerRef = useRef(null);\n const svgRef = useRef(null);\n const isDrawing = useRef(false);\n const last = useRef<{ x: number | null; y: number | null }>({\n x: null,\n y: null,\n });\n\n useEffect(() => {\n const svgNS = \"http://www.w3.org/2000/svg\";\n\n // Create SVG\n const svg = document.createElementNS(svgNS, \"svg\");\n svg.style.position = \"fixed\";\n svg.style.top = \"0\";\n svg.style.left = \"0\";\n svg.style.width = \"100vw\";\n svg.style.height = \"100vh\";\n svg.style.pointerEvents = \"none\";\n svg.style.zIndex = \"9999\"; // high z-index to be above everything\n document.body.appendChild(svg);\n svgRef.current = svg;\n\n // Resize handler to keep SVG full screen\n const resizeSvg = () => {\n svg.setAttribute(\"width\", window.innerWidth.toString());\n svg.setAttribute(\"height\", window.innerHeight.toString());\n };\n resizeSvg();\n window.addEventListener(\"resize\", resizeSvg);\n\n const drawLine = (x1: number, y1: number, x2: number, y2: number) => {\n const line = document.createElementNS(svgNS, \"line\");\n line.setAttribute(\"x1\", `${x1}`);\n line.setAttribute(\"y1\", `${y1}`);\n line.setAttribute(\"x2\", `${x2}`);\n line.setAttribute(\"y2\", `${y2}`);\n line.setAttribute(\"stroke\", strokeColor);\n line.setAttribute(\"stroke-width\", `${strokeWidth}`);\n line.setAttribute(\"stroke-linecap\", \"round\");\n svg.appendChild(line);\n\n if (followEffect) {\n gsap.to(line, {\n opacity: 0,\n duration: 0.5,\n ease: \"power1.out\",\n onComplete: () => line.remove(),\n });\n }\n };\n\n const onMouseMove = (e: MouseEvent) => {\n if (type === \"drawOnHold\" && !isDrawing.current) return;\n\n const x = e.clientX;\n const y = e.clientY;\n\n if (last.current.x != null && last.current.y != null) {\n drawLine(last.current.x, last.current.y, x, y);\n }\n\n last.current = { x, y };\n };\n\n const onMouseDown = () => {\n if (type === \"drawOnHold\") isDrawing.current = true;\n };\n\n const onMouseUp = () => {\n if (type === \"drawOnHold\") isDrawing.current = false;\n last.current = { x: null, y: null }; // reset on mouse up\n };\n\n const onMouseLeave = () => {\n last.current = { x: null, y: null };\n isDrawing.current = false;\n };\n\n window.addEventListener(\"mousemove\", onMouseMove);\n window.addEventListener(\"mousedown\", onMouseDown);\n window.addEventListener(\"mouseup\", onMouseUp);\n window.addEventListener(\"mouseleave\", onMouseLeave);\n\n return () => {\n window.removeEventListener(\"mousemove\", onMouseMove);\n window.removeEventListener(\"mousedown\", onMouseDown);\n window.removeEventListener(\"mouseup\", onMouseUp);\n window.removeEventListener(\"mouseleave\", onMouseLeave);\n window.removeEventListener(\"resize\", resizeSvg);\n svg.remove();\n };\n }, [strokeColor, strokeWidth, type, followEffect]);\n\n return
;\n};\n\nexport default DrawCursor;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/dynamic-card.json b/public/r/dynamic-card.json index fc0cfd1..93faf4b 100644 --- a/public/r/dynamic-card.json +++ b/public/r/dynamic-card.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "dynamic-card", - "type": "registry:component", "dependencies": [ "tw-animate-css" ], @@ -23,5 +22,6 @@ "content": "/* @import \"tailwindcss\"; */\n@import \"tw-animate-css\";\n\n@keyframes float {\n 0% {\n transform: translateY(0px);\n }\n 50% {\n transform: translateY(-10px);\n }\n 100% {\n transform: translateY(0px);\n }\n}", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/electric-cursor.json b/public/r/electric-cursor.json index b495584..caa5448 100644 --- a/public/r/electric-cursor.json +++ b/public/r/electric-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "electric-cursor", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React, { useEffect, useRef } from \"react\";\n\n// Interface for Spark instance\ninterface ISpark {\n x: number;\n y: number;\n length: number;\n alpha: number;\n update: () => void;\n draw: () => void;\n}\n\nconst ElectricCursor: React.FC = () => {\n const canvasRef = useRef(null);\n\n useEffect(() => {\n const sparks: ISpark[] = [];\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n\n class Spark implements ISpark {\n x: number;\n y: number;\n length: number;\n alpha: number;\n\n constructor(x: number, y: number) {\n this.x = x;\n this.y = y;\n this.length = Math.random() * 10 + 5;\n this.alpha = 1;\n }\n\n update(): void {\n this.length -= 0.5;\n this.alpha -= 0.03;\n }\n\n draw(): void {\n if (!ctx) return;\n ctx.beginPath();\n ctx.moveTo(this.x, this.y);\n ctx.lineTo(\n this.x + Math.random() * this.length,\n this.y + Math.random() * this.length,\n );\n ctx.strokeStyle = `rgba(0, 200, 255, ${this.alpha})`;\n ctx.lineWidth = 1;\n ctx.stroke();\n }\n }\n\n const animate = (): void => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n for (let i = sparks.length - 1; i >= 0; i--) {\n sparks[i].update();\n sparks[i].draw();\n if (sparks[i].alpha <= 0) {\n sparks.splice(i, 1);\n }\n }\n\n requestAnimationFrame(animate);\n };\n\n const onMove = (e: MouseEvent): void => {\n for (let i = 0; i < 3; i++) {\n sparks.push(new Spark(e.clientX, e.clientY));\n }\n };\n\n window.addEventListener(\"mousemove\", onMove);\n animate();\n\n return () => {\n window.removeEventListener(\"mousemove\", onMove);\n };\n }, []);\n\n return (\n \n );\n};\n\nexport default ElectricCursor;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/fire-cursor.json b/public/r/fire-cursor.json index f7a40b2..3a1fca6 100644 --- a/public/r/fire-cursor.json +++ b/public/r/fire-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "fire-cursor", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React, { useEffect, useRef } from \"react\";\n\nconst FireCursor = () => {\n const canvasRef = useRef(null);\n\n useEffect(() => {\n // Particle will be defined inside useEffect, so we need to use a type assertion here\n const particles: Array<{ update: () => void; draw: () => void; alpha: number }> = [];\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n\n class Particle {\n x: number;\n y: number;\n vx: number;\n vy: number;\n alpha: number;\n size: number;\n\n constructor(x: number, y: number) {\n this.x = x;\n this.y = y;\n this.vx = (Math.random() - 0.5) * 1.5;\n this.vy = -Math.random() * 2;\n this.alpha = 1;\n this.size = Math.random() * 3 + 2;\n }\n\n update() {\n this.x += this.vx;\n this.y += this.vy;\n this.alpha -= 0.02;\n }\n\n draw() {\n if (!ctx) return;\n ctx.beginPath();\n ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);\n ctx.fillStyle = `rgba(255, ${Math.floor(Math.random() * 100)}, 0, ${this.alpha})`;\n ctx.fill();\n }\n }\n\n const animate = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n particles.forEach((p, i) => {\n p.update();\n p.draw();\n if (p.alpha <= 0) particles.splice(i, 1);\n });\n requestAnimationFrame(animate);\n };\n\n animate();\n\n const onMove = (e: MouseEvent) => {\n for (let i = 0; i < 5; i++) {\n particles.push(new Particle(e.clientX, e.clientY));\n }\n };\n\n window.addEventListener(\"mousemove\", onMove);\n\n return () => {\n window.removeEventListener(\"mousemove\", onMove);\n };\n }, []);\n\n return (\n \n );\n};\n\nexport default FireCursor;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/flow-form.json b/public/r/flow-form.json index 04b2f9a..8af2040 100644 --- a/public/r/flow-form.json +++ b/public/r/flow-form.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "flow-form", - "type": "registry:component", "dependencies": [ "@react-three/fiber", "framer-motion", @@ -21,5 +20,6 @@ "content": "\"use client\";\n\nimport React, { useState, useMemo, useRef, useEffect } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport Link from \"next/link\";\nimport { cn } from \"@/lib/utils\";\nimport { Canvas, useFrame, useThree } from \"@react-three/fiber\";\n\nimport * as THREE from \"three\";\n\ntype Uniforms = {\n [key: string]: {\n value: number[] | number[][] | number;\n type: string;\n };\n};\n\ninterface ShaderProps {\n source: string;\n uniforms: {\n [key: string]: {\n value: number[] | number[][] | number;\n type: string;\n };\n };\n maxFps?: number;\n}\n\ninterface SignInPageProps {\n className?: string;\n}\n\nexport const CanvasRevealEffect = ({\n animationSpeed = 10,\n opacities = [0.3, 0.3, 0.3, 0.5, 0.5, 0.5, 0.8, 0.8, 0.8, 1],\n colors = [[0, 255, 255]],\n containerClassName,\n dotSize,\n showGradient = true,\n reverse = false, // This controls the direction\n}: {\n animationSpeed?: number;\n opacities?: number[];\n colors?: number[][];\n containerClassName?: string;\n dotSize?: number;\n showGradient?: boolean;\n reverse?: boolean; // This prop determines the direction\n}) => {\n return (\n
\n {\" \"}\n {/* Removed bg-white */}\n
\n \n
\n {showGradient && (\n // Adjust gradient colors if needed based on background (was bg-white, now likely uses containerClassName bg)\n // Example assuming a dark background like the SignInPage uses:\n
\n )}\n
\n );\n};\n\ninterface DotMatrixProps {\n colors?: number[][];\n opacities?: number[];\n totalSize?: number;\n dotSize?: number;\n shader?: string;\n center?: (\"x\" | \"y\")[];\n}\n\nconst DotMatrix: React.FC = ({\n colors = [[0, 0, 0]],\n opacities = [0.04, 0.04, 0.04, 0.04, 0.04, 0.08, 0.08, 0.08, 0.08, 0.14],\n totalSize = 20,\n dotSize = 2,\n shader = \"\", // This shader string will now contain the animation logic\n center = [\"x\", \"y\"],\n}) => {\n // ... uniforms calculation remains the same for colors, opacities, etc.\n const uniforms = React.useMemo(() => {\n let colorsArray = [\n colors[0],\n colors[0],\n colors[0],\n colors[0],\n colors[0],\n colors[0],\n ];\n if (colors.length === 2) {\n colorsArray = [\n colors[0],\n colors[0],\n colors[0],\n colors[1],\n colors[1],\n colors[1],\n ];\n } else if (colors.length === 3) {\n colorsArray = [\n colors[0],\n colors[0],\n colors[1],\n colors[1],\n colors[2],\n colors[2],\n ];\n }\n return {\n u_colors: {\n value: colorsArray.map((color) => [\n color[0] / 255,\n color[1] / 255,\n color[2] / 255,\n ]),\n type: \"uniform3fv\",\n },\n u_opacities: {\n value: opacities,\n type: \"uniform1fv\",\n },\n u_total_size: {\n value: totalSize,\n type: \"uniform1f\",\n },\n u_dot_size: {\n value: dotSize,\n type: \"uniform1f\",\n },\n u_reverse: {\n value: shader.includes(\"u_reverse_active\") ? 1 : 0, // Convert boolean to number (1 or 0)\n type: \"uniform1i\", // Use 1i for bool in WebGL1/GLSL100, or just bool for GLSL300+ if supported\n },\n };\n }, [colors, opacities, totalSize, dotSize, shader]); // Add shader to dependencies\n\n return (\n \n );\n};\n\nconst ShaderMaterial = ({\n source,\n uniforms,\n}: {\n source: string;\n hovered?: boolean;\n maxFps?: number;\n uniforms: Uniforms;\n}) => {\n const { size } = useThree();\n const ref = useRef(null);\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n let lastFrameTime = 0;\n\n useFrame(({ clock }) => {\n if (!ref.current) return;\n const timestamp = clock.getElapsedTime();\n\n lastFrameTime = timestamp;\n\n const material = ref.current.material as THREE.ShaderMaterial;\n const timeLocation = material.uniforms.u_time;\n timeLocation.value = timestamp;\n });\n\n const getUniforms = () => {\n const preparedUniforms: Record =\n {};\n\n for (const uniformName in uniforms) {\n const uniform = uniforms[uniformName];\n\n switch (uniform.type) {\n case \"uniform1f\":\n preparedUniforms[uniformName] = { value: uniform.value, type: \"1f\" };\n break;\n case \"uniform1i\":\n preparedUniforms[uniformName] = { value: uniform.value, type: \"1i\" };\n break;\n case \"uniform3f\":\n preparedUniforms[uniformName] = {\n value: new THREE.Vector3().fromArray(uniform.value as number[]),\n type: \"3f\",\n };\n break;\n case \"uniform1fv\":\n preparedUniforms[uniformName] = { value: uniform.value, type: \"1fv\" };\n break;\n case \"uniform3fv\":\n preparedUniforms[uniformName] = {\n value: Array.isArray(uniform.value)\n ? (uniform.value as number[][]).map((v: number[]) =>\n new THREE.Vector3().fromArray(v),\n )\n : [],\n type: \"3fv\",\n };\n break;\n case \"uniform2f\":\n preparedUniforms[uniformName] = {\n value: new THREE.Vector2().fromArray(uniform.value as number[]),\n type: \"2f\",\n };\n break;\n default:\n console.error(`Invalid uniform type for '${uniformName}'.`);\n break;\n }\n }\n\n preparedUniforms[\"u_time\"] = { value: 0, type: \"1f\" };\n preparedUniforms[\"u_resolution\"] = {\n value: new THREE.Vector2(size.width * 2, size.height * 2),\n }; // Initialize u_resolution\n return preparedUniforms;\n };\n\n // Shader material\n const material = useMemo(() => {\n const materialObject = new THREE.ShaderMaterial({\n vertexShader: `\n precision mediump float;\n in vec2 coordinates;\n uniform vec2 u_resolution;\n out vec2 fragCoord;\n void main(){\n float x = position.x;\n float y = position.y;\n gl_Position = vec4(x, y, 0.0, 1.0);\n fragCoord = (position.xy + vec2(1.0)) * 0.5 * u_resolution;\n fragCoord.y = u_resolution.y - fragCoord.y;\n }\n `,\n fragmentShader: source,\n uniforms: getUniforms(),\n glslVersion: THREE.GLSL3,\n blending: THREE.CustomBlending,\n blendSrc: THREE.SrcAlphaFactor,\n blendDst: THREE.OneFactor,\n });\n\n return materialObject;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [size.width, size.height, source]);\n\n return (\n \n \n \n \n );\n};\n\nconst Shader: React.FC = ({ source, uniforms, maxFps = 60 }) => {\n return (\n \n \n \n );\n};\n\nexport const SignInPage = ({ className }: SignInPageProps) => {\n const [email, setEmail] = useState(\"\");\n const [step, setStep] = useState<\"email\" | \"code\" | \"success\">(\"email\");\n const [code, setCode] = useState([\"\", \"\", \"\", \"\", \"\", \"\"]);\n const codeInputRefs = useRef<(HTMLInputElement | null)[]>([]);\n const [initialCanvasVisible, setInitialCanvasVisible] = useState(true);\n const [reverseCanvasVisible, setReverseCanvasVisible] = useState(false);\n\n const handleEmailSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (email) {\n setStep(\"code\");\n }\n };\n\n // Focus first input when code screen appears\n useEffect(() => {\n if (step === \"code\") {\n setTimeout(() => {\n codeInputRefs.current[0]?.focus();\n }, 500);\n }\n }, [step]);\n\n const handleCodeChange = (index: number, value: string) => {\n if (value.length <= 1) {\n const newCode = [...code];\n newCode[index] = value;\n setCode(newCode);\n\n // Focus next input if value is entered\n if (value && index < 5) {\n codeInputRefs.current[index + 1]?.focus();\n }\n\n // Check if code is complete\n if (index === 5 && value) {\n const isComplete = newCode.every((digit) => digit.length === 1);\n if (isComplete) {\n // First show the new reverse canvas\n setReverseCanvasVisible(true);\n\n // Then hide the original canvas after a small delay\n setTimeout(() => {\n setInitialCanvasVisible(false);\n }, 50);\n\n // Transition to success screen after animation\n setTimeout(() => {\n setStep(\"success\");\n }, 2000);\n }\n }\n }\n };\n\n const handleKeyDown = (\n index: number,\n e: React.KeyboardEvent,\n ) => {\n if (e.key === \"Backspace\" && !code[index] && index > 0) {\n codeInputRefs.current[index - 1]?.focus();\n }\n };\n\n const handleBackClick = () => {\n setStep(\"email\");\n setCode([\"\", \"\", \"\", \"\", \"\", \"\"]);\n // Reset animations if going back\n setReverseCanvasVisible(false);\n setInitialCanvasVisible(true);\n };\n\n return (\n \n
\n {/* Initial canvas (forward animation) */}\n {initialCanvasVisible && (\n
\n \n
\n )}\n\n {/* Reverse canvas (appears when code is complete) */}\n {reverseCanvasVisible && (\n
\n \n
\n )}\n\n
\n
\n
\n\n {/* Content Layer */}\n
\n {/* Main content container */}\n
\n {/* Left side (form) */}\n
\n
\n \n {step === \"email\" ? (\n \n
\n

\n Welcome Developer\n

\n

\n Your sign in component\n

\n
\n\n
\n \n\n
\n
\n or\n
\n
\n\n
\n
\n setEmail(e.target.value)}\n className=\"w-full backdrop-blur-[1px] text-white border-1 border-white/10 rounded-full py-3 px-4 focus:outline-none focus:border focus:border-white/30 text-center\"\n required\n />\n \n \n \n →\n \n \n →\n \n \n \n
\n
\n
\n\n

\n By signing up, you agree to the{\" \"}\n \n MSA\n \n ,{\" \"}\n \n Product Terms\n \n ,{\" \"}\n \n Policies\n \n ,{\" \"}\n \n Privacy Notice\n \n , and{\" \"}\n \n Cookie Notice\n \n .\n

\n \n ) : step === \"code\" ? (\n \n
\n

\n We sent you a code\n

\n

\n Please enter it\n

\n
\n\n
\n
\n
\n {code.map((digit, i) => (\n
\n
\n {\n codeInputRefs.current[i] = el;\n }}\n type=\"text\"\n inputMode=\"numeric\"\n pattern=\"[0-9]*\"\n maxLength={1}\n value={digit}\n onChange={(e) =>\n handleCodeChange(i, e.target.value)\n }\n onKeyDown={(e) => handleKeyDown(i, e)}\n className=\"w-8 text-center text-xl bg-transparent text-white border-none focus:outline-none focus:ring-0 appearance-none\"\n style={{ caretColor: \"transparent\" }}\n />\n {!digit && (\n
\n \n 0\n \n
\n )}\n
\n {i < 5 && (\n |\n )}\n
\n ))}\n
\n
\n
\n\n
\n \n Resend code\n \n
\n\n
\n \n Back\n \n d !== \"\")\n ? \"bg-white text-black border-transparent hover:bg-white/90 cursor-pointer\"\n : \"bg-[#111] text-white/50 border-white/10 cursor-not-allowed\"\n }`}\n disabled={!code.every((d) => d !== \"\")}\n >\n Continue\n \n
\n\n
\n

\n By signing up, you agree to the{\" \"}\n \n MSA\n \n ,{\" \"}\n \n Product Terms\n \n ,{\" \"}\n \n Policies\n \n ,{\" \"}\n \n Privacy Notice\n \n , and{\" \"}\n \n Cookie Notice\n \n .\n

\n
\n \n ) : (\n \n
\n

\n You're in!\n

\n

\n Welcome\n

\n
\n\n \n
\n \n \n \n
\n \n\n \n Continue to Dashboard\n \n \n )}\n \n
\n
\n
\n
\n
\n );\n};\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/following-eye.json b/public/r/following-eye.json index c381db0..e7f351d 100644 --- a/public/r/following-eye.json +++ b/public/r/following-eye.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "following-eye", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport * as React from \"react\";\nimport { useState, useRef, useEffect } from \"react\";\n\nconst FollowingEye = ({ className }: { className?: string }) => {\n const [mousePos, setMousePos] = useState({ x: 0, y: 0 });\n const eye1Ref = useRef(null);\n const eye2Ref = useRef(null);\n\n const handleMouseMove = (e: React.MouseEvent) => {\n setMousePos({ x: e.clientX, y: e.clientY });\n };\n\n return (\n \n
\n }\n otherRef={eye2Ref as React.RefObject}\n />\n }\n otherRef={eye1Ref as React.RefObject}\n />\n
\n
\n );\n};\n\ninterface EyeProps {\n mouseX: number;\n mouseY: number;\n selfRef: React.RefObject;\n otherRef: React.RefObject;\n}\n\nconst Eye: React.FC = ({ mouseX, mouseY, selfRef, otherRef }) => {\n const pupilRef = useRef(null);\n const [center, setCenter] = useState({ x: 0, y: 0 });\n\n const updateCenter = React.useCallback(() => {\n if (!selfRef.current) return;\n const rect = selfRef.current.getBoundingClientRect();\n setCenter({\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n });\n }, [selfRef]);\n\n useEffect(() => {\n const updateCenter = () => {\n if (!selfRef.current) return;\n const rect = selfRef.current.getBoundingClientRect();\n setCenter({\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n });\n };\n\n updateCenter();\n window.addEventListener(\"resize\", updateCenter);\n return () => window.removeEventListener(\"resize\", updateCenter);\n }, [selfRef]);\n\n useEffect(() => {\n updateCenter();\n\n const isInside = (ref: React.RefObject) => {\n const rect = ref.current?.getBoundingClientRect();\n if (!rect) return false;\n return (\n mouseX >= rect.left &&\n mouseX <= rect.right &&\n mouseY >= rect.top &&\n mouseY <= rect.bottom\n );\n };\n\n if (isInside(selfRef) || isInside(otherRef)) return;\n\n const dx = mouseX - center.x;\n const dy = mouseY - center.y;\n const angle = Math.atan2(dy, dx);\n\n const maxMove = 20;\n const pupilX = Math.cos(angle) * maxMove;\n const pupilY = Math.sin(angle) * maxMove;\n\n if (pupilRef.current) {\n pupilRef.current.style.transform = `translate(${pupilX}px, ${pupilY}px)`;\n }\n }, [mouseX, mouseY, center.x, center.y, otherRef, selfRef, updateCenter]);\n\n return (\n \n \n
\n
\n
\n );\n};\n\nexport { FollowingEye };\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/future-button.json b/public/r/future-button.json index e9646c7..29f5784 100644 --- a/public/r/future-button.json +++ b/public/r/future-button.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "future-button", - "type": "registry:component", "dependencies": [ "class-variance-authority", "clsx", @@ -26,5 +25,6 @@ "content": "import { useRef, useEffect } from \"react\";\nimport { twMerge } from \"tailwind-merge\";\nimport { type Paths, setupSvgRenderer } from \"@left4code/svg-renderer\";\n\nfunction Frame({\n className,\n paths,\n enableBackdropBlur,\n enableViewBox,\n ...props\n}: {\n paths: Paths;\n enableBackdropBlur?: boolean;\n enableViewBox?: boolean;\n} & React.ComponentProps<\"svg\">) {\n const svgRef = useRef(null);\n\n useEffect(() => {\n if (svgRef.current && svgRef.current.parentElement) {\n const instance = setupSvgRenderer({\n el: svgRef.current,\n paths,\n enableBackdropBlur,\n enableViewBox,\n });\n\n return () => instance.destroy();\n }\n }, [paths, enableViewBox, enableBackdropBlur]);\n\n return (\n \n );\n}\n\nexport { Frame };\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/future-navbar.json b/public/r/future-navbar.json index 5e2b830..03450c0 100644 --- a/public/r/future-navbar.json +++ b/public/r/future-navbar.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "future-navbar", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -26,5 +25,6 @@ "content": "import { Frame } from \"@/components/nurui/frame\";\nimport { twMerge } from \"tailwind-merge\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\n// 🎨 Theme colors — no CSS variables, pure hex/rgba\nconst COLORS = {\n default: {\n stroke1: \"#4f46e5\",\n fill1: \"rgba(79,70,229,0.22)\",\n stroke2: \"#4f46e5\",\n fill2: \"rgba(79,70,229,0.1)\",\n text: \"#ffffff\",\n },\n accent: {\n stroke1: \"#f97316\",\n fill1: \"rgba(249,115,22,0.4)\",\n stroke2: \"#f97316\",\n fill2: \"rgba(249,115,22,0.2)\",\n text: \"#ffffff\",\n },\n destructive: {\n stroke1: \"#dc2626\",\n fill1: \"rgba(220,38,38,0.22)\",\n stroke2: \"#dc2626\",\n fill2: \"rgba(220,38,38,0.1)\",\n text: \"#ffffff\",\n },\n secondary: {\n stroke1: \"#64748b\",\n fill1: \"rgba(100,116,139,0.15)\",\n stroke2: \"#64748b\",\n fill2: \"rgba(100,116,139,0.1)\",\n text: \"#ffffff\",\n },\n success: {\n stroke1: \"#16a34a\",\n fill1: \"rgba(22,163,74,0.22)\",\n stroke2: \"#16a34a\",\n fill2: \"rgba(22,163,74,0.1)\",\n text: \"#ffffff\",\n },\n};\n\nconst buttonVariants = cva(\n \"group font-bold mb-2 relative px-8 py-2 cursor-pointer transition-all outline-none [&>span]:relative [&>span]:flex [&>span]:items-center [&>span]:justify-center\",\n {\n variants: {\n shape: {\n default: \"\",\n flat: \"\",\n simple: \"ps-8 pe-6\",\n },\n },\n defaultVariants: {\n shape: \"default\",\n },\n },\n);\n\nfunction FutureButton({\n className,\n children,\n shape = \"default\",\n enableBackdropBlur = false,\n enableViewBox = false,\n customPaths,\n textColor,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps & {\n customPaths?: string[];\n enableBackdropBlur?: boolean;\n enableViewBox?: boolean;\n bgColor?: string;\n textColor?: string;\n }) {\n const colors = COLORS.default;\n\n return (\n \n
\n {!customPaths && (shape === \"default\" || shape === \"flat\") && (\n \n )}\n\n {!customPaths && shape === \"simple\" && (\n \n )}\n\n {customPaths?.map((customPath, i) => (\n \n ))}\n
\n {children}\n \n );\n}\n\nexport default FutureButton;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/gaming-form.json b/public/r/gaming-form.json index c6f361d..c98f8cd 100644 --- a/public/r/gaming-form.json +++ b/public/r/gaming-form.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "gaming-form", - "type": "registry:component", "dependencies": [ "lucide-react" ], @@ -18,5 +17,6 @@ "content": "\"use client\";\nimport React, { useState, useRef, useEffect } from \"react\";\nimport {\n Eye,\n EyeOff,\n Mail,\n Lock,\n Chrome,\n Twitter,\n Gamepad2,\n} from \"lucide-react\";\n\ninterface LoginFormProps {\n onSubmit: (email: string, password: string, remember: boolean) => void;\n}\n\ninterface VideoBackgroundProps {\n videoUrl: string;\n}\n\ninterface FormInputProps {\n icon: React.ReactNode;\n type: string;\n placeholder: string;\n value: string;\n onChange: (e: React.ChangeEvent) => void;\n required?: boolean;\n}\n\ninterface SocialButtonProps {\n icon: React.ReactNode;\n name: string;\n}\n\ninterface ToggleSwitchProps {\n checked: boolean;\n onChange: () => void;\n id: string;\n}\n\n// FormInput Component\nconst FormInput: React.FC = ({\n icon,\n type,\n placeholder,\n value,\n onChange,\n required,\n}) => {\n return (\n
\n
{icon}
\n \n
\n );\n};\n\n// SocialButton Component\nconst SocialButton: React.FC = ({ icon }) => {\n return (\n \n );\n};\n\n// ToggleSwitch Component\nconst ToggleSwitch: React.FC = ({\n checked,\n onChange,\n id,\n}) => {\n return (\n
\n \n \n \n
\n
\n );\n};\n\n// VideoBackground Component\nconst VideoBackground: React.FC = ({ videoUrl }) => {\n const videoRef = useRef(null);\n\n useEffect(() => {\n if (videoRef.current) {\n videoRef.current.play().catch((error) => {\n console.error(\"Video autoplay failed:\", error);\n });\n }\n }, []);\n\n return (\n
\n
\n \n \n Your browser does not support the video tag.\n \n
\n );\n};\n\n// Main LoginForm Component\nconst LoginForm: React.FC = ({ onSubmit }) => {\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [showPassword, setShowPassword] = useState(false);\n const [remember, setRemember] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isSuccess, setIsSuccess] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setIsSubmitting(true);\n\n await new Promise((resolve) => setTimeout(resolve, 1000));\n setIsSuccess(true);\n await new Promise((resolve) => setTimeout(resolve, 500));\n\n onSubmit(email, password, remember);\n setIsSubmitting(false);\n setIsSuccess(false);\n };\n\n return (\n
\n
\n

\n \n \n NexusGate\n \n \n

\n
\n \n \n \n Your gaming universe awaits\n \n \n \n [Press Enter to join the adventure]\n \n
\n ⚔️\n 🎮\n 🏆\n
\n
\n
\n\n
\n }\n type=\"email\"\n placeholder=\"Email address\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n required\n />\n\n
\n }\n type={showPassword ? \"text\" : \"password\"}\n placeholder=\"Password\"\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n required\n />\n setShowPassword(!showPassword)}\n aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n >\n {showPassword ? : }\n \n
\n\n
\n
\n setRemember(!remember)}\n className=\"cursor-pointer\"\n >\n setRemember(!remember)}\n id=\"remember-me\"\n />\n
\n setRemember(!remember)}\n >\n Remember me\n \n
\n \n Forgot password?\n \n
\n\n \n {isSubmitting ? \"Logging in...\" : \"Enter NexusGate\"}\n \n \n\n
\n
\n
\n
\n quick access via\n
\n
\n\n
\n } name=\"Chrome\" />\n } name=\"X\" />\n } name=\"Steam\" />\n
\n
\n\n
\n Don't have an account?{\" \"}\n \n Create Account\n \n
\n
\n );\n};\n\n// Export as default components\nconst LoginPage = {\n LoginForm,\n VideoBackground,\n};\n\nexport default LoginPage;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/ghost-cursor.json b/public/r/ghost-cursor.json index b83754d..651ac18 100644 --- a/public/r/ghost-cursor.json +++ b/public/r/ghost-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "ghost-cursor", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React, { useRef, useEffect } from \"react\";\n\nconst GhostTrailCursor = () => {\n const canvasRef = useRef(null);\n // Define a Particle type to avoid using 'any'\n type ParticleType = {\n x: number;\n y: number;\n radius: number;\n alpha: number;\n color: string;\n draw: () => void;\n update: () => void;\n };\n\n useEffect(() => {\n // Move particles array inside useEffect to avoid dependency warning\n const particles: ParticleType[] = [];\n\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const resize = () => {\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n };\n\n resize();\n window.addEventListener(\"resize\", resize);\n\n class Particle {\n x: number;\n y: number;\n radius: number;\n alpha: number;\n color: string;\n\n constructor(x: number, y: number) {\n this.x = x;\n this.y = y;\n this.radius = Math.random() * 6 + 2;\n this.alpha = 1;\n this.color = \"255, 255, 255\";\n }\n\n draw() {\n if (!ctx) return;\n ctx.beginPath();\n ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);\n ctx.fillStyle = `rgba(${this.color}, ${this.alpha})`;\n ctx.fill();\n }\n\n update() {\n this.alpha -= 0.02;\n }\n }\n\n const animate = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n particles.forEach((p, index) => {\n p.update();\n p.draw();\n if (p.alpha <= 0) particles.splice(index, 1);\n });\n requestAnimationFrame(animate);\n };\n animate();\n\n const onMove = (e: MouseEvent) => {\n particles.push(new Particle(e.clientX, e.clientY));\n };\n\n window.addEventListener(\"mousemove\", onMove);\n\n return () => {\n window.removeEventListener(\"mousemove\", onMove);\n window.removeEventListener(\"resize\", resize);\n };\n }, []);\n\n return (\n \n );\n};\n\nexport default GhostTrailCursor;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/glob-map.json b/public/r/glob-map.json index ba72ac0..fc080b8 100644 --- a/public/r/glob-map.json +++ b/public/r/glob-map.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "glob-map", - "type": "registry:component", "dependencies": [ "d3", "@radix-ui/react-slot", @@ -28,5 +27,6 @@ "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n)\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes,\n VariantProps {\n asChild?: boolean\n}\n\nconst Button = React.forwardRef(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n return (\n \n )\n },\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/glowing-card.json b/public/r/glowing-card.json index 6b07604..cced730 100644 --- a/public/r/glowing-card.json +++ b/public/r/glowing-card.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "glowing-card", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge" @@ -19,5 +18,6 @@ "content": "\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport { useEffect, useState } from \"react\";\n\nexport default function GlowingCard({ className }: { className?: string }) {\n const [angle, setAngle] = useState(0);\n\n useEffect(() => {\n const interval = setInterval(() => {\n setAngle((prev) => (prev + 1) % 360);\n }, 10); // smooth rotation\n return () => clearInterval(interval);\n }, []);\n\n return (\n
\n
\n I glow :)\n \n
\n
\n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/gradient-background.json b/public/r/gradient-background.json index 4cef4ef..7eb24c1 100644 --- a/public/r/gradient-background.json +++ b/public/r/gradient-background.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "gradient-background", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge" @@ -19,5 +18,6 @@ "content": "\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { useTheme } from \"next-themes\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport const GradientBackground = ({\n firstColor = \"60, 162, 250\",\n secondColor = \"60, 162, 250\",\n thirdColor = \"60, 162, 250\",\n fourthColor = \"60, 162, 250\",\n fifthColor = \"60, 162, 250\",\n pointerColor = \"60, 162, 250\",\n size = \"50%\",\n blendingValue = \"hard-light\",\n children,\n className,\n interactive = true,\n containerClassName,\n}: {\n gradientBackgroundStart?: string;\n gradientBackgroundEnd?: string;\n firstColor?: string;\n secondColor?: string;\n thirdColor?: string;\n fourthColor?: string;\n fifthColor?: string;\n pointerColor?: string;\n size?: string;\n blendingValue?: string;\n children?: React.ReactNode;\n className?: string;\n interactive?: boolean;\n containerClassName?: string;\n}) => {\n const interactiveRef = useRef(null);\n\n // Use refs to store animation values instead of state\n const curXRef = useRef(0);\n const curYRef = useRef(0);\n const tgXRef = useRef(0);\n const tgYRef = useRef(0);\n const animationFrameRef = useRef(null);\n\n const [isSafari, setIsSafari] = useState(false);\n\n const { theme } = useTheme();\n\n // Set up gradient background colors based on theme\n const gradientBackgroundStart = theme === \"dark\" ? \"#01031333\" : \"#ffffff\";\n const gradientBackgroundEnd = theme === \"dark\" ? \"#01031333\" : \"#ffffff\";\n\n // Set up CSS variables\n useEffect(() => {\n document.body.style.setProperty(\n \"--gradient-background-start\",\n gradientBackgroundStart,\n );\n document.body.style.setProperty(\n \"--gradient-background-end\",\n gradientBackgroundEnd,\n );\n document.body.style.setProperty(\"--first-color\", firstColor);\n document.body.style.setProperty(\"--second-color\", secondColor);\n document.body.style.setProperty(\"--third-color\", thirdColor);\n document.body.style.setProperty(\"--fourth-color\", fourthColor);\n document.body.style.setProperty(\"--fifth-color\", fifthColor);\n document.body.style.setProperty(\"--pointer-color\", pointerColor);\n document.body.style.setProperty(\"--size\", size);\n document.body.style.setProperty(\"--blending-value\", blendingValue);\n }, [\n gradientBackgroundStart,\n gradientBackgroundEnd,\n firstColor,\n secondColor,\n thirdColor,\n fourthColor,\n fifthColor,\n pointerColor,\n size,\n blendingValue,\n ]);\n\n // Set up Safari detection\n useEffect(() => {\n setIsSafari(/^((?!chrome|android).)*safari/i.test(navigator.userAgent));\n }, []);\n\n // Set up animation loop\n useEffect(() => {\n if (!interactive) return;\n\n function animateMovement() {\n if (!interactiveRef.current) {\n animationFrameRef.current = requestAnimationFrame(animateMovement);\n return;\n }\n\n // Calculate new position with easing\n curXRef.current =\n curXRef.current + (tgXRef.current - curXRef.current) / 20;\n curYRef.current =\n curYRef.current + (tgYRef.current - curYRef.current) / 20;\n\n // Apply transform directly to DOM element\n interactiveRef.current.style.transform = `translate(${Math.round(curXRef.current)}px, ${Math.round(curYRef.current)}px)`;\n\n // Continue animation loop\n animationFrameRef.current = requestAnimationFrame(animateMovement);\n }\n\n // Start animation loop\n animationFrameRef.current = requestAnimationFrame(animateMovement);\n\n // Clean up animation loop on unmount\n return () => {\n if (animationFrameRef.current !== null) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n };\n }, [interactive]);\n\n // Handle mouse movement\n const handleMouseMove = (event: React.MouseEvent) => {\n if (!interactiveRef.current) return;\n\n const rect = interactiveRef.current.getBoundingClientRect();\n // Update target position directly in ref (no state update)\n tgXRef.current = event.clientX - rect.left;\n tgYRef.current = event.clientY - rect.top;\n };\n\n return (\n \n \n \n \n \n \n \n \n \n \n
{children}
\n \n
\n
\n
\n
\n
\n\n {interactive && (\n
\n )}\n
\n
\n );\n};\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/gradient-button.json b/public/r/gradient-button.json index a1ef28b..e0e6adc 100644 --- a/public/r/gradient-button.json +++ b/public/r/gradient-button.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "gradient-button", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge" @@ -24,5 +23,6 @@ "content": " @keyframes rotate-rainbow {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n\n .rainbow-btn {\n padding: var(--borderWidth);\n border-radius: var(--borderRadius);\n }\n\n .rainbow-btn::before {\n content: \"\";\n background: conic-gradient(var(--allColors));\n animation: rotate-rainbow var(--duration) linear infinite;\n filter: blur(var(--blur));\n padding: var(--borderWidth);\n position: absolute;\n inset: -200%;\n z-index: 0;\n }\n\n .btn-content {\n border-radius: var(--borderRadius);\n background-color: var(--bgColor);\n z-index: 10;\n position: relative;\n }", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/gradient-hero.json b/public/r/gradient-hero.json index 130e612..a6425be 100644 --- a/public/r/gradient-hero.json +++ b/public/r/gradient-hero.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "gradient-hero", - "type": "registry:component", "dependencies": [ "class-variance-authority", "framer-motion", @@ -28,5 +27,6 @@ "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n)\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes,\n VariantProps {\n asChild?: boolean\n}\n\nconst Button = React.forwardRef(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n return (\n \n )\n },\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/gradient-text.json b/public/r/gradient-text.json index 09f6ecc..f684cde 100644 --- a/public/r/gradient-text.json +++ b/public/r/gradient-text.json @@ -1,14 +1,13 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "gradient-text", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], "files": [ { "path": "./src/components/nurui/gradient-text-demo.tsx", - "content": "import React from \"react\";\nimport GradientText from \"@/components/nurui/gradient-text\";\n\nconst GradientTextDemo = () => {\n return (\n
\n \n Welcome to Nur/ui\n \n
\n );\n};\n\nexport default GradientTextDemo;\n", + "content": "import React from \"react\";\nimport GradientText from \"@/components/nurui/gradient-text\";\n\nconst GradientTextDemo = () => {\n return (\n
\n \n Welcome to Nur UI\n \n
\n );\n};\n\nexport default GradientTextDemo;\n", "type": "registry:component" }, { @@ -16,5 +15,6 @@ "content": "import React, { ReactNode } from \"react\";\n\ninterface GradientTextProps {\n children: ReactNode;\n className?: string;\n colors?: string[];\n animationSpeed?: number;\n showBorder?: boolean;\n}\n\nexport default function GradientText({\n children,\n className = \"\",\n colors = [\"#ffaa40\", \"#9c40ff\", \"#ffaa40\"],\n animationSpeed = 8,\n showBorder = false,\n}: GradientTextProps) {\n const gradientStyle = {\n backgroundImage: `linear-gradient(to right, ${colors.join(\", \")})`,\n animationDuration: `${animationSpeed}s`,\n };\n\n return (\n \n {showBorder && (\n \n
\n
\n )}\n \n {children}\n
\n
\n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/hacker-background.json b/public/r/hacker-background.json index 8dc1e41..f708dcf 100644 --- a/public/r/hacker-background.json +++ b/public/r/hacker-background.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "hacker-background", - "type": "registry:component", "dependencies": [ "" ], @@ -18,5 +17,6 @@ "content": "\"use client\";\nimport React, { useEffect, useRef } from \"react\";\n\ninterface HackerBackgroundProps {\n color?: string;\n fontSize?: number;\n className?: string;\n speed?: number;\n}\n\nconst HackerBackground: React.FC = ({\n color = \"#3ca2fa\",\n fontSize = 15,\n className = \"\",\n speed = 1,\n}) => {\n const canvasRef = useRef(null);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const resizeCanvas = () => {\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n };\n\n resizeCanvas();\n window.addEventListener(\"resize\", resizeCanvas);\n\n let animationFrameId: number;\n\n const columns = Math.floor(canvas.width / fontSize);\n const drops: number[] = new Array(columns).fill(1);\n\n const chars =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$%^&*()_+\";\n\n let lastTime = 0;\n const interval = 33; // ~30 fps\n\n const draw = (currentTime: number) => {\n animationFrameId = requestAnimationFrame(draw);\n\n if (currentTime - lastTime < interval) return;\n lastTime = currentTime;\n\n ctx.fillStyle = \"rgba(0, 0, 0, 0.05)\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n ctx.fillStyle = color;\n ctx.font = `${fontSize}px monospace`;\n\n for (let i = 0; i < drops.length; i++) {\n const text = chars[Math.floor(Math.random() * chars.length)];\n ctx.fillText(text, i * fontSize, drops[i] * fontSize);\n\n if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {\n drops[i] = 0;\n }\n drops[i] += speed; // Use the speed prop to control fall rate\n }\n };\n\n animationFrameId = requestAnimationFrame(draw);\n\n return () => {\n window.removeEventListener(\"resize\", resizeCanvas);\n cancelAnimationFrame(animationFrameId);\n };\n }, [color, fontSize, speed]);\n\n return (\n \n );\n};\n\nexport default HackerBackground;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/hacker-cursor.json b/public/r/hacker-cursor.json index 8158f0c..69ce0fa 100644 --- a/public/r/hacker-cursor.json +++ b/public/r/hacker-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "hacker-cursor", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React, { useRef, useEffect } from \"react\";\n\ninterface CursorTrailProps {\n trailColor?: string;\n dotSize?: number;\n fadeDuration?: number;\n className?: string;\n}\n\nconst HackerCursor: React.FC = ({\n trailColor = \"#D0FBB6\",\n dotSize = 4,\n fadeDuration = 600,\n className = \"fixed inset-0 w-full h-full pointer-events-none z-50\",\n}) => {\n const canvasRef = useRef(null);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const resizeCanvas = () => {\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n };\n\n resizeCanvas();\n window.addEventListener(\"resize\", resizeCanvas);\n\n const hexToRGB = (hex: string) => {\n const num = parseInt(hex.replace(\"#\", \"\"), 16);\n return {\n r: (num >> 16) & 255,\n g: (num >> 8) & 255,\n b: num & 255,\n };\n };\n\n const { r, g, b } = hexToRGB(trailColor);\n\n const paintDot = (x: number, y: number) => {\n ctx.fillStyle = `rgba(${r}, ${g}, ${b}, 1)`;\n ctx.fillRect(x, y, dotSize, dotSize);\n };\n\n let lastTime = performance.now();\n\n const fade = () => {\n const now = performance.now();\n const delta = now - lastTime;\n lastTime = now;\n\n const fadeAlpha = delta / fadeDuration;\n\n ctx.fillStyle = `rgba(0, 0, 0, ${fadeAlpha})`;\n ctx.globalCompositeOperation = \"destination-out\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n ctx.globalCompositeOperation = \"source-over\";\n\n requestAnimationFrame(fade);\n };\n\n requestAnimationFrame(fade);\n\n const handleMouseMove = (e: MouseEvent) => {\n const x = Math.floor(e.clientX / dotSize) * dotSize;\n const y = Math.floor(e.clientY / dotSize) * dotSize;\n paintDot(x, y);\n };\n\n window.addEventListener(\"mousemove\", handleMouseMove);\n\n return () => {\n window.removeEventListener(\"mousemove\", handleMouseMove);\n window.removeEventListener(\"resize\", resizeCanvas);\n };\n }, [trailColor, dotSize, fadeDuration]);\n\n return ;\n};\n\nexport default HackerCursor;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/hover-footer.json b/public/r/hover-footer.json index a66905c..4bd0970 100644 --- a/public/r/hover-footer.json +++ b/public/r/hover-footer.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "hover-footer", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -26,5 +25,6 @@ "content": "import React from \"react\";\n\nconst FooterBackgroundGradient = () => {\n return (\n \n );\n};\n\nexport default FooterBackgroundGradient;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/info-card.json b/public/r/info-card.json index 9635e83..2084bbf 100644 --- a/public/r/info-card.json +++ b/public/r/info-card.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "info-card", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge" @@ -24,5 +23,6 @@ "content": "@import \"tw-animate-css\";\n\n:root {\n --border-color-1: #ff5613;\n --border-color-2: #9f4eff;\n --border-color-3: #2196f3;\n --border-bg-color: #f5f5f5;\n --card-bg-color: #fff;\n --shadow-color: #e0e0e0;\n --text-color: #242424;\n --hover-text-color-1: #000;\n --hover-text-color-2: #fff;\n --hover-text-color-3: #fff;\n --font-family: \"Roboto Mono\", monospace;\n --rtl-font-family: \"Montserrat\", sans-serif;\n --pattern-color1: rgba(200, 200, 200, 0.1);\n --pattern-color2: rgba(220, 220, 220, 0.1);\n}\n\n.dark {\n --border-color-1: #daff3e;\n --border-color-2: #9f4eff;\n --border-color-3: #2196f3;\n --border-bg-color: #242424;\n --card-bg-color: #000;\n --shadow-color: #242424;\n --text-color: #f5f5f5;\n --hover-text-color-1: #242424;\n --hover-text-color-2: #000;\n --hover-text-color-3: #242424;\n --font-family: \"Roboto Mono\", monospace;\n --rtl-font-family: \"Montserrat\", sans-serif;\n --pattern-color1: rgba(230, 230, 230, 0.15);\n --pattern-color2: rgba(240, 240, 240, 0.15);\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/jump-background.json b/public/r/jump-background.json index c5299c7..45650c7 100644 --- a/public/r/jump-background.json +++ b/public/r/jump-background.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "jump-background", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -20,5 +19,6 @@ "content": "\"use client\";\n\nimport type React from \"react\";\nimport { useMemo, type HTMLAttributes } from \"react\";\nimport { motion } from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface JumpsBackgroundProps extends HTMLAttributes {\n children: React.ReactNode;\n speed?: number;\n color?: string;\n height?: number;\n line?: number;\n}\n\nconst WarpLine = ({\n angle,\n delay,\n color,\n height,\n duration,\n}: {\n angle: number;\n delay: number;\n color: string;\n height: number;\n duration: number;\n}) => {\n return (\n \n );\n};\n\nexport const JumpsBackground: React.FC = ({\n children,\n className,\n speed = 1,\n height = 1,\n color = \"#3ca2fa\",\n line = 50,\n ...props\n}) => {\n const warpLines = useMemo(() => {\n return Array.from({ length: line }, (_, i) => ({\n id: i,\n angle: (360 / line) * i + Math.random(),\n delay: Math.random() * speed * 2,\n duration: speed * 2 + Math.random(),\n }));\n }, [speed, line]);\n\n return (\n
\n {warpLines.map((line) => (\n \n ))}\n
{children}
\n
\n );\n};\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/magnet-button.json b/public/r/magnet-button.json index 8f53305..a2acebc 100644 --- a/public/r/magnet-button.json +++ b/public/r/magnet-button.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "magnet-button", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -21,5 +20,6 @@ "content": "\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport { motion, useAnimation } from \"motion/react\";\nimport { Magnet } from \"lucide-react\";\nimport { useEffect, useState, useCallback } from \"react\";\nimport { Button } from \"@/components/ui/button\";\n\ninterface AttractButtonProps\n extends React.ButtonHTMLAttributes {\n particleCount?: number;\n attractRadius?: number;\n}\n\ninterface Particle {\n id: number;\n x: number;\n y: number;\n}\n\nexport default function MagnetButton({\n className,\n particleCount = 12,\n ...props\n}: AttractButtonProps) {\n const [isAttracting, setIsAttracting] = useState(false);\n const [particles, setParticles] = useState([]);\n const particlesControl = useAnimation();\n\n useEffect(() => {\n const newParticles = Array.from({ length: particleCount }, (_, i) => ({\n id: i,\n x: Math.random() * 360 - 180,\n y: Math.random() * 360 - 180,\n }));\n setParticles(newParticles);\n }, [particleCount]);\n\n const handleInteractionStart = useCallback(async () => {\n setIsAttracting(true);\n await particlesControl.start({\n x: 0,\n y: 0,\n transition: {\n type: \"spring\",\n stiffness: 50,\n damping: 10,\n },\n });\n }, [particlesControl]);\n\n const handleInteractionEnd = useCallback(async () => {\n setIsAttracting(false);\n await particlesControl.start((i) => ({\n x: particles[i].x,\n y: particles[i].y,\n transition: {\n type: \"spring\",\n stiffness: 100,\n damping: 15,\n },\n }));\n }, [particlesControl, particles]);\n\n return (\n \n {particles.map((_, index) => (\n \n ))}\n \n \n {isAttracting ? \"Attracting\" : \"Hover me\"}\n \n \n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/marquee-testimonial.json b/public/r/marquee-testimonial.json index 8c842fa..1c8141a 100644 --- a/public/r/marquee-testimonial.json +++ b/public/r/marquee-testimonial.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "marquee-testimonial", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -35,5 +34,6 @@ "content": "import React from \"react\";\n\nconst RatingIcon = ({\n rate,\n size = \"size-6\",\n}: {\n rate?: boolean;\n size?: string;\n}) => {\n return (\n \n \n \n );\n};\n\nexport default RatingIcon;", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/matrix-cursor.json b/public/r/matrix-cursor.json index 84cdb2b..dca291b 100644 --- a/public/r/matrix-cursor.json +++ b/public/r/matrix-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "matrix-cursor", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React, { useEffect, useRef } from \"react\";\n\ninterface Particle {\n x: number;\n y: number;\n alpha: number;\n update: () => void;\n draw: () => void;\n}\n\nconst MatrixCursor = () => {\n const canvasRef = useRef(null);\n const particles = useRef([]); // useRef for persistent array\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n\n class Dot implements Particle {\n x: number;\n y: number;\n alpha: number;\n\n constructor(x: number, y: number) {\n this.x = x;\n this.y = y;\n this.alpha = 1;\n }\n\n update() {\n this.alpha -= 0.02;\n }\n\n draw() {\n if (!ctx) return;\n ctx.fillStyle = `rgba(0, 255, 0, ${this.alpha})`;\n ctx.fillRect(this.x, this.y, 4, 4);\n }\n }\n\n const animate = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n particles.current = particles.current.filter((p) => {\n p.update();\n p.draw();\n return p.alpha > 0;\n });\n\n requestAnimationFrame(animate);\n };\n\n animate();\n\n const onMove = (e: MouseEvent) => {\n particles.current.push(new Dot(e.clientX, e.clientY));\n };\n\n window.addEventListener(\"mousemove\", onMove);\n return () => {\n window.removeEventListener(\"mousemove\", onMove);\n };\n }, []);\n\n return (\n \n );\n};\n\nexport default MatrixCursor;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/money-cursor.json b/public/r/money-cursor.json index a5a5c37..4de6f07 100644 --- a/public/r/money-cursor.json +++ b/public/r/money-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "money-cursor", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React, { useEffect, useRef } from \"react\";\n\nconst symbols = [\"$\", \"💸\", \"🪙\", \"💵\"];\n\nclass MoneyParticle {\n x: number;\n y: number;\n alpha: number;\n char: string;\n\n constructor(x: number, y: number) {\n this.x = x;\n this.y = y;\n this.alpha = 1;\n this.char = symbols[Math.floor(Math.random() * symbols.length)];\n }\n\n update() {\n this.y -= 0.3;\n this.alpha -= 0.02;\n }\n\n draw(ctx: CanvasRenderingContext2D) {\n ctx.fillStyle = `rgba(255, 255, 0, ${this.alpha})`;\n ctx.font = \"18px sans-serif\";\n ctx.fillText(this.char, this.x, this.y);\n }\n}\n\nconst MoneyCursor: React.FC = () => {\n const canvasRef = useRef(null);\n const particlesRef = useRef([]);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n\n const particles = particlesRef.current;\n\n const animate = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n for (let i = particles.length - 1; i >= 0; i--) {\n const p = particles[i];\n p.update();\n p.draw(ctx);\n if (p.alpha <= 0) particles.splice(i, 1);\n }\n requestAnimationFrame(animate);\n };\n\n animate();\n\n const handleMove = (e: MouseEvent) => {\n for (let i = 0; i < 2; i++) {\n particles.push(new MoneyParticle(e.clientX, e.clientY));\n }\n };\n\n window.addEventListener(\"mousemove\", handleMove);\n\n return () => {\n window.removeEventListener(\"mousemove\", handleMove);\n };\n }, []);\n\n return (\n \n );\n};\n\nexport default MoneyCursor;", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/neobrutalism-faq.json b/public/r/neobrutalism-faq.json index 9074106..83c4e87 100644 --- a/public/r/neobrutalism-faq.json +++ b/public/r/neobrutalism-faq.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "neobrutalism-faq", - "type": "registry:component", "dependencies": [ "react-icons" ], @@ -23,5 +22,6 @@ "content": "import { FC } from \"react\";\nimport { SlArrowDown, SlArrowUp } from \"react-icons/sl\";\n\ninterface PropsType {\n question: string;\n answer: string;\n questionNumber: number;\n setOpenKey: () => void;\n openKey: number;\n}\n\nconst QuestionAnswer: FC = ({\n question,\n answer,\n questionNumber,\n openKey,\n setOpenKey,\n}) => {\n return (\n
\n setOpenKey()}\n >\n
\n {questionNumber}. {question}\n
\n \n
\n {openKey === questionNumber && (\n

\n {answer}\n

\n )}\n
\n );\n};\n\nexport default QuestionAnswer;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/neural-background.json b/public/r/neural-background.json index 9128ff7..414939d 100644 --- a/public/r/neural-background.json +++ b/public/r/neural-background.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "neural-background", - "type": "registry:component", "dependencies": [ "" ], @@ -13,5 +12,6 @@ "content": "\"use client\";\nimport React, { useEffect, useRef } from \"react\";\n\ninterface HackerBackgroundProps {\n color?: string;\n fontSize?: number;\n className?: string;\n speed?: number;\n}\n\nconst HackerBackground: React.FC = ({\n color = \"#3ca2fa\",\n fontSize = 15,\n className = \"\",\n speed = 1,\n}) => {\n const canvasRef = useRef(null);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const resizeCanvas = () => {\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n };\n\n resizeCanvas();\n window.addEventListener(\"resize\", resizeCanvas);\n\n let animationFrameId: number;\n\n const columns = Math.floor(canvas.width / fontSize);\n const drops: number[] = new Array(columns).fill(1);\n\n const chars =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$%^&*()_+\";\n\n let lastTime = 0;\n const interval = 33; // ~30 fps\n\n const draw = (currentTime: number) => {\n animationFrameId = requestAnimationFrame(draw);\n\n if (currentTime - lastTime < interval) return;\n lastTime = currentTime;\n\n ctx.fillStyle = \"rgba(0, 0, 0, 0.05)\";\n ctx.fillRect(0, 0, canvas.width, canvas.height);\n\n ctx.fillStyle = color;\n ctx.font = `${fontSize}px monospace`;\n\n for (let i = 0; i < drops.length; i++) {\n const text = chars[Math.floor(Math.random() * chars.length)];\n ctx.fillText(text, i * fontSize, drops[i] * fontSize);\n\n if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {\n drops[i] = 0;\n }\n drops[i] += speed; // Use the speed prop to control fall rate\n }\n };\n\n animationFrameId = requestAnimationFrame(draw);\n\n return () => {\n window.removeEventListener(\"resize\", resizeCanvas);\n cancelAnimationFrame(animationFrameId);\n };\n }, [color, fontSize, speed]);\n\n return (\n \n );\n};\n\nexport default HackerBackground;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/news-letter.json b/public/r/news-letter.json index 14d5661..f7c4255 100644 --- a/public/r/news-letter.json +++ b/public/r/news-letter.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "news-letter", - "type": "registry:component", "dependencies": [ "react-icons" ], @@ -15,8 +14,9 @@ }, { "path": "./src/components/nurui/animated-input.tsx", - "content": "\"use client\";\nimport { FC, useState } from \"react\";\nimport toast from \"react-hot-toast\";\n\ninterface IProps {\n className?: string;\n onBlurTitle: string;\n onFocusTitle: string;\n buttonTitle: string;\n}\n\nconst AnimatedInput: FC = ({\n className,\n onBlurTitle,\n onFocusTitle,\n buttonTitle,\n}) => {\n const [placeholder, setPlaceholder] = useState(onBlurTitle);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n const target = e.target as HTMLFormElement;\n const email = (target.email as HTMLInputElement).value;\n if (email) {\n toast.success(\"Email submitted successfully!\", {\n style: {\n background: \"#1b1d2b\",\n color: \"#fff\",\n },\n });\n target.reset();\n }\n };\n\n return (\n
\n
\n
\n \n setPlaceholder(onFocusTitle)}\n onBlur={() => setPlaceholder(onBlurTitle)}\n type=\"email\"\n name=\"email\"\n className=\"mr-2 pl-3 inline-block h-full flex-1 rounded-lg bg-transparent px-2 py-3 placeholder:text-[var(--placeholder-color)] focus:outline-none focus:ring-1 focus:ring-[var(--primary-color)]\"\n placeholder={placeholder}\n required\n />\n \n \n
\n
\n );\n};\n\nexport default AnimatedInput;\n", + "content": "\"use client\";\nimport { cn } from \"@/lib/utils\";\nimport { FC, useState } from \"react\";\nimport toast from \"react-hot-toast\";\n\ninterface IProps {\n className?: string;\n onBlurTitle: string;\n onFocusTitle: string;\n buttonTitle: string;\n buttonClassName?: string;\n}\n\nconst AnimatedInput: FC = ({\n className,\n onBlurTitle,\n onFocusTitle,\n buttonTitle,\n buttonClassName,\n}) => {\n const [placeholder, setPlaceholder] = useState(onBlurTitle);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n const target = e.target as HTMLFormElement;\n const email = (target.email as HTMLInputElement).value;\n if (email) {\n toast.success(\"Email submitted successfully!\", {\n style: {\n background: \"#1b1d2b\",\n color: \"#fff\",\n },\n });\n target.reset();\n }\n };\n\n return (\n
\n
\n
\n \n setPlaceholder(onFocusTitle)}\n onBlur={() => setPlaceholder(onBlurTitle)}\n type=\"email\"\n name=\"email\"\n className=\"mr-2 pl-3 inline-block h-full flex-1 rounded-lg bg-transparent px-2 py-3 placeholder:text-[var(--placeholder-color)] focus:outline-none focus:ring-1 focus:ring-[var(--primary-color)]\"\n placeholder={placeholder}\n required\n />\n \n {buttonTitle}\n \n \n
\n
\n );\n};\n\nexport default AnimatedInput;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/play-button.json b/public/r/play-button.json index c613237..ede248e 100644 --- a/public/r/play-button.json +++ b/public/r/play-button.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "play-button", - "type": "registry:component", "dependencies": [ "react-icons" ], @@ -15,8 +14,9 @@ }, { "path": "./src/components/nurui/play-button.tsx", - "content": "import React from 'react';\nimport { FaPlay } from 'react-icons/fa';\n\nconst PlayButton = ({ text }: { text: string }) => {\n return (\n \n );\n};\n\nexport default PlayButton;\n", + "content": "import { FaPlay } from \"react-icons/fa\";\n\nconst PlayButton = ({ text }: { text: string }) => {\n return (\n
\n
\n \n
\n
{text}
\n
\n );\n};\n\nexport default PlayButton;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/playing-card.json b/public/r/playing-card.json index 922750e..7c8faac 100644 --- a/public/r/playing-card.json +++ b/public/r/playing-card.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "playing-card", - "type": "registry:component", "dependencies": [ "three", "@react-three/fiber", @@ -26,5 +25,6 @@ "content": "@import \"tw-animate-css\";\n\n:root {\n --playingcard-bg: #18192b;\n --playingcard-fg: #f8fafc;\n --playingcard-outline-color: #3d3759;\n --playingcard-hover-outline-color: #7c6ee6;\n --playingcard-canvas-bg: #23244a;\n --playingcard-canvas-colors: \"143,108,255;99,102,241;80,115,184\";\n --playingcard-inscription-color: #00a9fe;\n --playingcard-inscription-color-hover: #8F04A7;\n}\n\n.dark {\n --playingcard-bg: #f8fafc;\n --playingcard-fg: #0f172a;\n --playingcard-outline-color: #ddd;\n --playingcard-hover-outline-color: #aaa;\n --playingcard-canvas-bg: #f8fafc;\n --playingcard-canvas-colors: \"236,72,153;232,121,249\";\n --playingcard-inscription-color: #3662f4;\n --playingcard-inscription-color-hover: #f12b30;\n}", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/premium-testimonial.json b/public/r/premium-testimonial.json index 34d8a26..aa78bc5 100644 --- a/public/r/premium-testimonial.json +++ b/public/r/premium-testimonial.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "premium-testimonial", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -22,5 +21,6 @@ "content": "\"use client\";\nimport { motion, AnimatePresence, cubicBezier } from \"framer-motion\";\nimport { useState, useEffect, useRef, FC } from \"react\";\nimport { Quote, Star, ArrowLeft, ArrowRight, Sparkles } from \"lucide-react\";\nimport Image from \"next/image\";\n\nconst testimonials = [\n {\n name: \"Sarah Chen\",\n role: \"CEO, TechFlow Solutions\",\n company: \"TechFlow\",\n avatar:\n \"https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=150&h=150&fit=crop&crop=face\",\n rating: 5,\n text: \"Lord AI transformed our entire operation. We've seen a 300% increase in efficiency and saved over $2M in operational costs. The autonomous agents work flawlessly.\",\n results: [\n \"300% efficiency increase\",\n \"$2M cost savings\",\n \"24/7 automation\",\n ],\n },\n {\n name: \"Marcus Johnson\",\n role: \"CTO, DataDrive Inc\",\n company: \"DataDrive\",\n avatar:\n \"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=150&h=150&fit=crop&crop=face\",\n rating: 5,\n text: \"The AI voice agents are revolutionary. Our customer satisfaction increased by 40% while reducing response time from hours to seconds. Incredible ROI.\",\n results: [\n \"40% satisfaction boost\",\n \"Instant responses\",\n \"Seamless integration\",\n ],\n },\n {\n name: \"Elena Rodriguez\",\n role: \"VP Operations, ScaleUp Co\",\n company: \"ScaleUp\",\n avatar:\n \"https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=150&h=150&fit=crop&crop=face\",\n rating: 5,\n text: \"From workflow automation to social media management, Lord AI handles everything. Our team can finally focus on strategy instead of repetitive tasks.\",\n results: [\"Full automation\", \"Strategic focus\", \"Team productivity\"],\n },\n {\n name: \"David Kim\",\n role: \"Founder, GrowthLab\",\n company: \"GrowthLab\",\n avatar:\n \"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=150&h=150&fit=crop&crop=face\",\n rating: 5,\n text: \"The custom AI systems delivered results beyond our expectations. Revenue increased 150% while operational overhead decreased significantly.\",\n results: [\"150% revenue growth\", \"Reduced overhead\", \"Scalable systems\"],\n },\n {\n name: \"Lisa Thompson\",\n role: \"Director, InnovateCorp\",\n company: \"InnovateCorp\",\n avatar:\n \"https://images.unsplash.com/photo-1517841905240-472988babdf9?w=150&h=150&fit=crop&crop=face\",\n rating: 5,\n text: \"Exceptional AI solutions that actually work. The implementation was smooth, and the results were immediate. Best investment we've made.\",\n results: [\"Immediate results\", \"Smooth integration\", \"High ROI\"],\n },\n];\n\ntype PremiumTestimonialProps = {\n title?: string;\n subTitle?: string;\n tagline?: string;\n des?: string;\n};\n\nexport const PremiumTestimonial: FC = ({\n title = \"Trusted by\",\n subTitle = \"Industry Leaders\",\n tagline = \"Client Success Stories\",\n des = \"Join thousands of businesses already transforming their operations with our premium AI solutions.\",\n}) => {\n const [currentIndex, setCurrentIndex] = useState(0);\n const [direction, setDirection] = useState(0);\n const containerRef = useRef(null);\n\n useEffect(() => {\n const timer = setInterval(() => {\n setDirection(1);\n setCurrentIndex((prev) => (prev + 1) % testimonials.length);\n }, 6000);\n\n return () => clearInterval(timer);\n }, []);\n\n const slideVariants = {\n enter: (direction: number) => ({\n x: direction > 0 ? 1000 : -1000,\n opacity: 0,\n scale: 0.8,\n rotateY: direction > 0 ? 45 : -45,\n }),\n center: {\n zIndex: 1,\n x: 0,\n opacity: 1,\n scale: 1,\n rotateY: 0,\n },\n exit: (direction: number) => ({\n zIndex: 0,\n x: direction < 0 ? 1000 : -1000,\n opacity: 0,\n scale: 0.8,\n rotateY: direction < 0 ? 45 : -45,\n }),\n };\n\n const fadeInUp = {\n hidden: { opacity: 0, y: 60 },\n visible: {\n opacity: 1,\n y: 0,\n transition: {\n duration: 0.8,\n ease: cubicBezier(0.23, 0.86, 0.39, 0.96),\n },\n },\n };\n\n const staggerContainer = {\n hidden: { opacity: 0 },\n visible: {\n opacity: 1,\n transition: {\n staggerChildren: 0.1,\n delayChildren: 0.3,\n },\n },\n };\n\n const nextTestimonial = () => {\n setDirection(1);\n setCurrentIndex((prev) => (prev + 1) % testimonials.length);\n };\n\n const prevTestimonial = () => {\n setDirection(-1);\n setCurrentIndex(\n (prev) => (prev - 1 + testimonials.length) % testimonials.length,\n );\n };\n\n return (\n \n {/* Enhanced Background Effects */}\n
\n {/* Animated gradient mesh */}\n \n\n {/* Moving light orbs */}\n \n \n\n {/* Floating particles */}\n {[...Array(12)].map((_, i) => (\n \n ))}\n
\n\n \n {/* Header */}\n \n \n \n \n \n \n ✨ {tagline}\n \n
\n \n\n \n \n {title}\n \n
\n \n {subTitle}\n \n \n\n \n {des}\n \n \n\n {/* Main Testimonial Display */}\n
\n
\n \n \n
\n {/* Animated background gradient */}\n \n\n {/* Quote icon */}\n \n \n \n\n
\n {/* User Info */}\n
\n \n
\n \n \n
\n\n {/* Floating ring animation */}\n \n \n\n

\n {testimonials[currentIndex].name}\n

\n

\n {testimonials[currentIndex].role}\n

\n

\n {testimonials[currentIndex].company}\n

\n\n {/* Star Rating */}\n
\n {[...Array(testimonials[currentIndex].rating)].map(\n (_, i) => (\n \n \n \n ),\n )}\n
\n
\n\n {/* Content */}\n
\n \n {testimonials[currentIndex].text}\n \n\n {/* Results */}\n
\n {testimonials[currentIndex].results.map((result, i) => (\n \n \n {result}\n \n \n ))}\n
\n
\n
\n
\n \n
\n
\n\n {/* Navigation Controls */}\n
\n \n \n \n\n {/* Dots Indicator */}\n
\n {testimonials.map((_, index) => (\n {\n setDirection(index > currentIndex ? 1 : -1);\n setCurrentIndex(index);\n }}\n className={`w-3 h-3 rounded-full transition-all ${\n index === currentIndex\n ? \"bg-indigo-400 scale-125\"\n : \"bg-white/30 hover:bg-white/50\"\n }`}\n whileHover={{ scale: 1.2 }}\n whileTap={{ scale: 0.9 }}\n />\n ))}\n
\n\n \n \n \n
\n
\n\n {/* Stats Section */}\n \n {[\n { number: \"500+\", label: \"Happy Clients\" },\n { number: \"98%\", label: \"Satisfaction Rate\" },\n { number: \"$10M+\", label: \"Cost Savings\" },\n { number: \"99.9%\", label: \"Uptime SLA\" },\n ].map((stat, index) => (\n \n \n {stat.number}\n \n
\n {stat.label}\n
\n \n ))}\n \n \n \n );\n};\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/progress-bar.json b/public/r/progress-bar.json index 6de724a..cd0219e 100644 --- a/public/r/progress-bar.json +++ b/public/r/progress-bar.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "progress-bar", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge" @@ -19,5 +18,6 @@ "content": "import { cn } from \"@/lib/utils\";\n\ninterface ProgressBarProps {\n max: number;\n value: number;\n min: number;\n gaugePrimaryColor: string;\n gaugeSecondaryColor: string;\n className?: string;\n}\n\nexport function ProgressBar({\n max = 100,\n min = 0,\n value = 0,\n gaugePrimaryColor,\n gaugeSecondaryColor,\n className,\n}: ProgressBarProps) {\n const circumference = 2 * Math.PI * 45;\n const percentPx = circumference / 100;\n const currentPercent = Math.round(((value - min) / (max - min)) * 100);\n\n return (\n \n \n {currentPercent <= 90 && currentPercent >= 0 && (\n \n )}\n \n \n \n {currentPercent}\n \n
\n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/project-showcase.json b/public/r/project-showcase.json index f66cb9c..a3c5e30 100644 --- a/public/r/project-showcase.json +++ b/public/r/project-showcase.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "project-showcase", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -18,7 +17,7 @@ }, { "path": "./src/components/nurui/project-showcase.tsx", - "content": "\"use client\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport Image from \"next/image\";\nimport { useEffect, useState, useCallback, useRef } from \"react\";\nimport { HalomotButton } from \"@/components/nurui/halomot-button\";\n\ntype Testimonial = {\n quote: string;\n name: string;\n designation: string;\n src: string;\n link?: string;\n};\n\ntype ProjectShowcaseProps = {\n testimonials: Testimonial[];\n autoplay?: boolean;\n colors?: { name?: string; position?: string; testimony?: string };\n fontSizes?: { name?: string; position?: string; testimony?: string };\n spacing?: {\n top?: string;\n bottom?: string;\n lineHeight?: string;\n nameTop?: string;\n nameBottom?: string;\n positionTop?: string;\n positionBottom?: string;\n testimonyTop?: string;\n testimonyBottom?: string;\n };\n desktopVersionBottomThreshold?: number;\n maxImageWidth?: number;\n imageWidthPercentage?: number;\n mobile?: {\n fontSizes?: { name?: string; position?: string; testimony?: string };\n spacing?: {\n top?: string;\n bottom?: string;\n lineHeight?: string;\n nameTop?: string;\n nameBottom?: string;\n positionTop?: string;\n positionBottom?: string;\n testimonyTop?: string;\n testimonyBottom?: string;\n };\n };\n imageAspectRatio?: number;\n isRTL?: boolean;\n onItemClick?: (link: string) => void;\n outerRounding?: string;\n innerRounding?: string;\n outlineColor?: string;\n hoverOutlineColor?: string;\n buttonInscriptions?: {\n previousButton: string;\n nextButton: string;\n openWebAppButton: string;\n };\n halomotButtonGradient?: string;\n halomotButtonBackground?: string;\n halomotButtonTextColor?: string;\n halomotButtonOuterBorderRadius?: string;\n halomotButtonInnerBorderRadius?: string;\n halomotButtonHoverTextColor?: string;\n};\n\nexport const ProjectShowCase = ({\n testimonials,\n autoplay = false,\n colors = { name: \"#fff\", position: \"gray-500\", testimony: \"gray-500\" },\n fontSizes = { name: \"2xl\", position: \"sm\", testimony: \"lg\" },\n spacing = {\n top: \"20\",\n bottom: \"20\",\n lineHeight: \"1.5\",\n nameTop: \"0\",\n nameBottom: \"0.5em\",\n positionTop: \"0\",\n positionBottom: \"0.25em\",\n testimonyTop: \"1em\",\n testimonyBottom: \"1em\"\n },\n desktopVersionBottomThreshold = 1024,\n mobile = {},\n imageAspectRatio = 1.37,\n isRTL = false,\n onItemClick,\n outerRounding = \"18.2px\",\n innerRounding = \"18px\",\n outlineColor = \"#33313d\",\n hoverOutlineColor = \"#403d4d\",\n buttonInscriptions = {\n previousButton: \"Previous\",\n nextButton: \"Next\",\n openWebAppButton: \"Open Web App\"\n },\n halomotButtonGradient = \"linear-gradient(to right, #a123f4, #603dec)\",\n halomotButtonBackground = \"#111014\",\n halomotButtonTextColor = \"#fff\",\n halomotButtonOuterBorderRadius = \"6.34px\",\n halomotButtonInnerBorderRadius = \"6px\",\n halomotButtonHoverTextColor\n}: ProjectShowcaseProps) => {\n const [active, setActive] = useState(0);\n const [isMobileView, setIsMobileView] = useState(false);\n const [componentWidth, setComponentWidth] = useState(0);\n const componentRef = useRef(null);\n\n // Use Mobile Config (with defaults)\n const currentFontSizes =\n isMobileView && mobile.fontSizes ? mobile.fontSizes : fontSizes;\n const currentSpacing = {\n ...spacing,\n ...(isMobileView && mobile.spacing ? mobile.spacing : {})\n };\n\n const handleNext = useCallback(() => {\n setActive((prev) => (prev + 1) % testimonials.length);\n }, [testimonials.length]);\n\n const handlePrev = () => {\n setActive((prev) => (prev - 1 + testimonials.length) % testimonials.length);\n };\n\n const isActive = (index: number) => {\n return index === active;\n };\n\n useEffect(() => {\n if (autoplay) {\n const interval = setInterval(handleNext, 5000);\n return () => clearInterval(interval);\n }\n }, [autoplay, handleNext]);\n\n const handleResize = useCallback(() => {\n if (componentRef.current) {\n setComponentWidth(componentRef.current.offsetWidth);\n setIsMobileView(\n componentRef.current.offsetWidth < desktopVersionBottomThreshold\n );\n }\n }, [desktopVersionBottomThreshold]);\n\n useEffect(() => {\n const node = componentRef.current;\n const resizeObserver = new ResizeObserver(handleResize);\n if (node) {\n resizeObserver.observe(node);\n }\n handleResize(); // Initial check\n return () => {\n if (node) {\n resizeObserver.unobserve(node);\n }\n };\n }, [handleResize]);\n\n const randomRotateY = () => {\n return Math.floor(Math.random() * 21) - 10;\n };\n\n const calculateGap = (width: number) => {\n const minWidth = 1024;\n const maxWidth = 1456;\n const minGap = 60;\n const maxGap = 86;\n if (width <= minWidth) return minGap;\n if (width >= maxWidth)\n return Math.max(minGap, maxGap + 0.06018 * (width - maxWidth));\n return (\n minGap + (maxGap - minGap) * ((width - minWidth) / (maxWidth - minWidth))\n );\n };\n\n return (\n \n \n {isRTL && !isMobileView ? (\n <>\n
\n \n \n {testimonials.map((testimonial, index) => (\n \n \n \n ))}\n \n
\n
\n
\n \n \n {testimonials[active].name}\n \n \n {testimonials[active].designation}\n

\n \n {testimonials[active].quote.split(\" \").map((word, index) => (\n \n {word} \n \n ))}\n \n \n \n \n \n \n onItemClick && onItemClick(testimonials[active].link || \"\")\n }\n fillWidth\n gradient={halomotButtonGradient}\n backgroundColor={halomotButtonBackground}\n textColor={halomotButtonTextColor}\n innerBorderRadius={halomotButtonInnerBorderRadius}\n outerBorderRadius={halomotButtonOuterBorderRadius}\n {...(halomotButtonHoverTextColor\n ? { hoverTextColor: halomotButtonHoverTextColor }\n : {})}\n href={testimonials[active].link}\n />\n
\n
\n \n ) : (\n <>\n
\n \n \n {testimonials.map((testimonial, index) => (\n \n \n \n ))}\n \n
\n
\n
\n \n \n {testimonials[active].name}\n \n \n {testimonials[active].designation}\n

\n \n {testimonials[active].quote.split(\" \").map((word, index) => (\n \n {word} \n \n ))}\n \n \n \n \n \n \n onItemClick && onItemClick(testimonials[active].link || \"\")\n }\n fillWidth\n gradient={halomotButtonGradient}\n backgroundColor={halomotButtonBackground}\n textColor={halomotButtonTextColor}\n innerBorderRadius={halomotButtonInnerBorderRadius}\n outerBorderRadius={halomotButtonOuterBorderRadius}\n {...(halomotButtonHoverTextColor\n ? { hoverTextColor: halomotButtonHoverTextColor }\n : {})}\n href={testimonials[active].link}\n />\n
\n
\n \n )}\n
\n \n );\n};\n\ntype ImageContainerProps = {\n src: string;\n alt: string;\n outerRounding: string;\n innerRounding: string;\n outlineColor: string;\n hoverOutlineColor: string;\n};\n\nconst ImageContainer = ({\n src,\n alt,\n outerRounding,\n innerRounding,\n outlineColor,\n hoverOutlineColor\n}: ImageContainerProps) => (\n \n \n \n \n \n \n);\n", + "content": "\"use client\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport Image from \"next/image\";\nimport { useEffect, useState, useCallback, useRef } from \"react\";\nimport { HalomotButton } from \"@/components/nurui/halomot-button\";\n\ntype Testimonial = {\n quote: string;\n name: string;\n designation: string;\n src: string;\n link?: string;\n};\n\ntype ProjectShowcaseProps = {\n testimonials: Testimonial[];\n autoplay?: boolean;\n colors?: { name?: string; position?: string; testimony?: string };\n fontSizes?: { name?: string; position?: string; testimony?: string };\n spacing?: {\n top?: string;\n bottom?: string;\n lineHeight?: string;\n nameTop?: string;\n nameBottom?: string;\n positionTop?: string;\n positionBottom?: string;\n testimonyTop?: string;\n testimonyBottom?: string;\n };\n desktopVersionBottomThreshold?: number;\n maxImageWidth?: number;\n imageWidthPercentage?: number;\n mobile?: {\n fontSizes?: { name?: string; position?: string; testimony?: string };\n spacing?: {\n top?: string;\n bottom?: string;\n lineHeight?: string;\n nameTop?: string;\n nameBottom?: string;\n positionTop?: string;\n positionBottom?: string;\n testimonyTop?: string;\n testimonyBottom?: string;\n };\n };\n imageAspectRatio?: number;\n isRTL?: boolean;\n onItemClick?: (link: string) => void;\n outerRounding?: string;\n innerRounding?: string;\n outlineColor?: string;\n hoverOutlineColor?: string;\n buttonInscriptions?: {\n previousButton: string;\n nextButton: string;\n openWebAppButton: string;\n };\n halomotButtonGradient?: string;\n halomotButtonBackground?: string;\n halomotButtonTextColor?: string;\n halomotButtonOuterBorderRadius?: string;\n halomotButtonInnerBorderRadius?: string;\n halomotButtonHoverTextColor?: string;\n};\n\nexport const ProjectShowCase = ({\n testimonials,\n autoplay = false,\n colors = { name: \"#fff\", position: \"gray-500\", testimony: \"gray-500\" },\n fontSizes = { name: \"2xl\", position: \"sm\", testimony: \"lg\" },\n spacing = {\n top: \"20\",\n bottom: \"20\",\n lineHeight: \"1.5\",\n nameTop: \"0\",\n nameBottom: \"0.5em\",\n positionTop: \"0\",\n positionBottom: \"0.25em\",\n testimonyTop: \"1em\",\n testimonyBottom: \"1em\"\n },\n desktopVersionBottomThreshold = 1024,\n mobile = {},\n imageAspectRatio = 1.37,\n isRTL = false,\n onItemClick,\n outerRounding = \"18.2px\",\n innerRounding = \"18px\",\n outlineColor = \"#33313d\",\n hoverOutlineColor = \"#403d4d\",\n buttonInscriptions = {\n previousButton: \"Previous\",\n nextButton: \"Next\",\n openWebAppButton: \"Open Web App\"\n },\n halomotButtonGradient = \"linear-gradient(to right, #a123f4, #603dec)\",\n halomotButtonBackground = \"#111014\",\n halomotButtonTextColor = \"#fff\",\n halomotButtonOuterBorderRadius = \"6.34px\",\n halomotButtonInnerBorderRadius = \"6px\",\n halomotButtonHoverTextColor\n}: ProjectShowcaseProps) => {\n const [active, setActive] = useState(0);\n const [isMobileView, setIsMobileView] = useState(false);\n const [componentWidth, setComponentWidth] = useState(0);\n const componentRef = useRef(null);\n\n // Use Mobile Config (with defaults)\n const currentFontSizes =\n isMobileView && mobile.fontSizes ? mobile.fontSizes : fontSizes;\n const currentSpacing = {\n ...spacing,\n ...(isMobileView && mobile.spacing ? mobile.spacing : {})\n };\n\n const handleNext = useCallback(() => {\n setActive((prev) => (prev + 1) % testimonials.length);\n }, [testimonials.length]);\n\n const handlePrev = () => {\n setActive((prev) => (prev - 1 + testimonials.length) % testimonials.length);\n };\n\n const isActive = (index: number) => {\n return index === active;\n };\n\n useEffect(() => {\n if (autoplay) {\n const interval = setInterval(handleNext, 5000);\n return () => clearInterval(interval);\n }\n }, [autoplay, handleNext]);\n\n const handleResize = useCallback(() => {\n if (componentRef.current) {\n setComponentWidth(componentRef.current.offsetWidth);\n setIsMobileView(\n componentRef.current.offsetWidth < desktopVersionBottomThreshold\n );\n }\n }, [desktopVersionBottomThreshold]);\n\n useEffect(() => {\n const node = componentRef.current;\n const resizeObserver = new ResizeObserver(handleResize);\n if (node) {\n resizeObserver.observe(node);\n }\n handleResize(); // Initial check\n return () => {\n if (node) {\n resizeObserver.unobserve(node);\n }\n };\n }, [handleResize]);\n\n const randomRotateY = () => {\n return Math.floor(Math.random() * 21) - 10;\n };\n\n const calculateGap = (width: number) => {\n const minWidth = 1024;\n const maxWidth = 1456;\n const minGap = 60;\n const maxGap = 86;\n if (width <= minWidth) return minGap;\n if (width >= maxWidth)\n return Math.max(minGap, maxGap + 0.06018 * (width - maxWidth));\n return (\n minGap + (maxGap - minGap) * ((width - minWidth) / (maxWidth - minWidth))\n );\n };\n\n return (\n \n \n {isRTL && !isMobileView ? (\n <>\n
\n \n \n {testimonials.map((testimonial, index) => (\n \n \n \n ))}\n \n
\n \n
\n \n \n {testimonials[active].name}\n \n \n {testimonials[active].designation}\n

\n \n {testimonials[active].quote.split(\" \").map((word, index) => (\n \n {word} \n \n ))}\n \n \n \n \n \n \n onItemClick && onItemClick(testimonials[active].link || \"\")\n }\n fillWidth\n gradient={halomotButtonGradient}\n backgroundColor={halomotButtonBackground}\n textColor={halomotButtonTextColor}\n innerBorderRadius={halomotButtonInnerBorderRadius}\n outerBorderRadius={halomotButtonOuterBorderRadius}\n {...(halomotButtonHoverTextColor\n ? { hoverTextColor: halomotButtonHoverTextColor }\n : {})}\n href={testimonials[active].link}\n />\n
\n \n \n ) : (\n <>\n
\n \n \n {testimonials.map((testimonial, index) => (\n \n \n \n ))}\n \n
\n \n
\n \n \n {testimonials[active].name}\n \n \n {testimonials[active].designation}\n

\n \n {testimonials[active].quote.split(\" \").map((word, index) => (\n \n {word} \n \n ))}\n \n \n \n \n \n \n onItemClick && onItemClick(testimonials[active].link || \"\")\n }\n fillWidth\n gradient={halomotButtonGradient}\n backgroundColor={halomotButtonBackground}\n textColor={halomotButtonTextColor}\n innerBorderRadius={halomotButtonInnerBorderRadius}\n outerBorderRadius={halomotButtonOuterBorderRadius}\n {...(halomotButtonHoverTextColor\n ? { hoverTextColor: halomotButtonHoverTextColor }\n : {})}\n href={testimonials[active].link}\n />\n
\n \n \n )}\n \n \n );\n};\n\ntype ImageContainerProps = {\n src: string;\n alt: string;\n outerRounding: string;\n innerRounding: string;\n outlineColor: string;\n hoverOutlineColor: string;\n};\n\nconst ImageContainer = ({\n src,\n alt,\n outerRounding,\n innerRounding,\n outlineColor,\n hoverOutlineColor\n}: ImageContainerProps) => (\n \n \n \n \n \n \n);\n", "type": "registry:component" }, { @@ -26,5 +25,6 @@ "content": "\"use client\";\nimport React, { useState } from \"react\";\n\ninterface HalomotButtonProps {\n gradient?: string; // Gradient for the button border/background\n inscription: string; // Button text\n onClick: () => void;\n fillWidth?: boolean;\n fixedWidth?: string;\n href?: string;\n backgroundColor?: string; // Solid color for the inner button (not gradient)\n icon?: React.ReactElement>;\n borderWidth?: string; // Controls the padding (thickness of the gradient border)\n padding?: string; // Custom padding for the inner button, e.g., \"1rem 4rem\"\n outerBorderRadius?: string; // Border radius for the gradient outer border\n innerBorderRadius?: string; // Border radius for the inner button\n textColor?: string; // Text color for the button, default #fff\n hoverTextColor?: string;\n}\n\nexport const HalomotButton: React.FC = ({\n gradient = \"linear-gradient(135deg, #4776cb, #a19fe5, #6cc606)\",\n inscription,\n onClick,\n fillWidth = false,\n fixedWidth,\n href,\n backgroundColor = \"#fff\",\n icon,\n borderWidth = \"1px\",\n padding,\n outerBorderRadius = \"6.34px\",\n innerBorderRadius = \"6px\",\n textColor = \"#000\",\n hoverTextColor,\n}) => {\n const [isHovered, setIsHovered] = useState(false);\n const [delayedColor, setDelayedColor] = useState(\n undefined,\n );\n\n // Container style for fixed width\n const containerStyle: React.CSSProperties = fixedWidth\n ? { width: fixedWidth, display: \"inline-block\" }\n : {};\n\n // Outer button style (gradient border)\n const buttonStyle: React.CSSProperties = {\n margin: fillWidth || fixedWidth ? \"0\" : \"auto\",\n padding: borderWidth,\n background: gradient,\n border: \"0\",\n borderRadius: outerBorderRadius,\n color: textColor,\n fontWeight: \"bold\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n textDecoration: \"none\",\n userSelect: \"none\",\n WebkitUserSelect: \"none\",\n whiteSpace: \"nowrap\",\n transition: \"all .3s\",\n width: fillWidth || fixedWidth ? \"100%\" : \"fit-content\",\n flexDirection: \"row\",\n boxSizing: \"border-box\",\n };\n\n // Inner span style (actual clickable area)\n const spanStyle: React.CSSProperties = {\n background: isHovered ? \"none\" : backgroundColor,\n padding: padding ?? (fillWidth || fixedWidth ? \"1rem 0\" : \"1rem 4rem\"),\n border: \"0\",\n borderRadius: innerBorderRadius,\n width: \"100%\",\n height: \"100%\",\n transition: hoverTextColor\n ? \"color 0.3s, background 300ms\"\n : \"background 300ms\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontWeight: \"bold\",\n color: delayedColor ? delayedColor : textColor,\n whiteSpace: \"nowrap\",\n fontFamily: \"inherit\",\n fontSize: \"1rem\",\n gap: icon ? \"0.5em\" : 0,\n flexDirection: \"row\",\n boxSizing: \"border-box\",\n cursor: \"pointer\",\n };\n\n // Icon style\n const iconStyle: React.CSSProperties = {\n display: \"inline-flex\",\n alignItems: \"center\",\n height: \"1em\",\n width: \"1em\",\n fontSize: \"1.1em\",\n verticalAlign: \"middle\",\n flexShrink: 0,\n };\n\n // No delay, just set color immediately\n const handleMouseEnter = () => {\n setIsHovered(true);\n if (hoverTextColor) {\n setDelayedColor(hoverTextColor);\n }\n };\n\n const handleMouseLeave = () => {\n setIsHovered(false);\n setDelayedColor(undefined);\n };\n\n const handleClick = (\n e: React.MouseEvent,\n ) => {\n e.preventDefault();\n onClick();\n };\n\n const ButtonContent = (\n \n {icon && React.cloneElement(icon, { style: iconStyle })}\n {inscription}\n \n );\n\n const ButtonElement = href ? (\n \n {ButtonContent}\n \n ) : (\n \n );\n\n return fixedWidth ? (\n
{ButtonElement}
\n ) : (\n ButtonElement\n );\n};\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/research-hero.json b/public/r/research-hero.json index 4b83021..2da44c6 100644 --- a/public/r/research-hero.json +++ b/public/r/research-hero.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "research-hero", - "type": "registry:component", "dependencies": [ "class-variance-authority", "framer-motion", @@ -43,5 +42,6 @@ "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n outline:\n \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-10 px-4 py-2\",\n sm: \"h-9 rounded-md px-3\",\n lg: \"h-11 rounded-md px-8\",\n icon: \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n)\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes,\n VariantProps {\n asChild?: boolean\n}\n\nconst Button = React.forwardRef(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n return (\n \n )\n },\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/retro-cursor.json b/public/r/retro-cursor.json index c99ada4..734c588 100644 --- a/public/r/retro-cursor.json +++ b/public/r/retro-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "retro-cursor", - "type": "registry:component", "dependencies": [ "framer-motion" ], @@ -18,5 +17,6 @@ "content": "\"use client\";\nimport { useEffect, useState } from \"react\";\nimport { motion } from \"framer-motion\";\n\ninterface RetroCursorProps {\n position: { x: number; y: number };\n}\n\nexport function RetroCursor({ position }: RetroCursorProps) {\n const [trail, setTrail] = useState<\n Array<{ x: number; y: number; id: number }>\n >([]);\n const [isActive, setIsActive] = useState(false);\n\n useEffect(() => {\n if (position.x === 0 && position.y === 0) return;\n\n // Only start tracking after the mouse has moved\n if (!isActive && (position.x !== 0 || position.y !== 0)) {\n setIsActive(true);\n }\n\n if (isActive) {\n setTrail((prevTrail) => {\n const newTrail = [\n { x: position.x, y: position.y, id: Date.now() },\n ...prevTrail.slice(0, 5), // Keep only 6 trail positions\n ];\n return newTrail;\n });\n }\n }, [position, isActive]);\n\n // Hide real cursor\n useEffect(() => {\n document.body.style.cursor = \"none\";\n return () => {\n document.body.style.cursor = \"auto\";\n };\n }, []);\n\n // Return if mouse hasn't moved yet\n if (!isActive) return null;\n\n return (\n
\n {/* Trail effects */}\n {trail.map((pos, index) => (\n \n ))}\n\n {/* Main cursor */}\n \n
\n );\n}", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/ripple-loader.json b/public/r/ripple-loader.json index 647012e..66132b1 100644 --- a/public/r/ripple-loader.json +++ b/public/r/ripple-loader.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "ripple-loader", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React from \"react\";\n\nconst RippleLoader = () => {\n const colors = [\n \"#cce4fc\", // very light\n \"#99c9fa\",\n \"#66afe0\",\n \"#3ca2fa\", // base color\n \"#1f8de6\",\n \"#1073d1\",\n \"#095abf\",\n \"#0347aa\",\n \"#012f82\", // darkest\n ];\n\n // Mapping the same animation delays as the original\n const delays = [\n 0, // d-0\n 100, // d-1\n 200, // d-2\n 100, // d-1\n 200, // d-2\n 200, // d-2\n 300, // d-3\n 300, // d-3\n 400, // d-4\n ];\n\n return (\n <>\n \n\n
\n {colors.map((color, index) => (\n \n ))}\n
\n \n );\n};\n\nexport default RippleLoader;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/rocket-footer.json b/public/r/rocket-footer.json index 2db2e46..d655557 100644 --- a/public/r/rocket-footer.json +++ b/public/r/rocket-footer.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "rocket-footer", - "type": "registry:component", "dependencies": [ "clsx", "tailwind-merge", @@ -22,7 +21,7 @@ }, { "path": "./src/components/nurui/nurui-logo.tsx", - "content": "import React from \"react\";\n\nconst NuruiLogo = () => {\n return (\n \n \n \n \n \n \n \n \n \n \n );\n};\n\nexport default NuruiLogo;\n", + "content": "import { cn } from \"@/lib/utils\";\n\nconst NuruiLogo = ({ className }: { className?: string }) => {\n return (\n \n \n \n \n \n \n \n \n \n \n );\n};\n\nexport default NuruiLogo;\n", "type": "registry:component" }, { @@ -30,5 +29,6 @@ "content": "\"use client\";\nimport { FC, useEffect, useRef, useState } from \"react\";\ninterface IProps {\n className?: string;\n}\nimport { cn } from \"@/lib/utils\";\n\nconst RocketScrollToTop: FC = ({ className }) => {\n const elementRef = useRef(null);\n const [scrollPosition, setScrollPosition] = useState(0);\n const [rocketLaunch, setRocketLaunch] = useState(false);\n\n const handleRocketLaunch = () => {\n setRocketLaunch(true);\n calculateButtonPosition();\n window.scrollTo({\n top: 0,\n behavior: \"smooth\", // Add smooth scrolling behavior\n });\n };\n\n useEffect(() => {\n function handleScroll() {\n const currentPosition = window.scrollY;\n if (currentPosition <= 300) {\n setRocketLaunch(false);\n }\n }\n // Attach the scroll event listener when the component mounts\n window.addEventListener(\"scroll\", handleScroll);\n return () => {\n window.removeEventListener(\"scroll\", handleScroll);\n };\n }, []);\n\n function calculateButtonPosition() {\n if (elementRef.current) {\n const rect = elementRef.current.getBoundingClientRect();\n setScrollPosition(rect.top);\n }\n }\n\n return (\n
\n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n Top\n \n
\n
\n \n );\n};\n\nexport default RocketScrollToTop;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/rotating-earth.json b/public/r/rotating-earth.json index 97a236e..312db46 100644 --- a/public/r/rotating-earth.json +++ b/public/r/rotating-earth.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "rotating-earth", - "type": "registry:component", "dependencies": [ "d3" ], @@ -18,5 +17,6 @@ "content": "/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\"use client\";\n\nimport * as d3 from \"d3\";\nimport { useEffect, useRef, useState } from \"react\";\n\ninterface RotatingEarthProps {\n width?: number;\n height?: number;\n className?: string;\n}\n\nexport default function RotatingEarth({\n width = 800,\n height = 600,\n className = \"\",\n}: RotatingEarthProps) {\n const canvasRef = useRef(null);\n const [, setIsLoading] = useState(true);\n const [error, setError] = useState(null);\n\n useEffect(() => {\n if (!canvasRef.current) return;\n\n const canvas = canvasRef.current;\n const context = canvas.getContext(\"2d\");\n if (!context) return;\n\n // Set up responsive dimensions\n const containerWidth = Math.min(width, window.innerWidth - 40);\n const containerHeight = Math.min(height, window.innerHeight - 100);\n const radius = Math.min(containerWidth, containerHeight) / 2.5;\n\n const dpr = window.devicePixelRatio || 1;\n canvas.width = containerWidth * dpr;\n canvas.height = containerHeight * dpr;\n canvas.style.width = `${containerWidth}px`;\n canvas.style.height = `${containerHeight}px`;\n context.scale(dpr, dpr);\n\n // Create projection and path generator for Canvas\n const projection = d3\n .geoOrthographic()\n .scale(radius)\n .translate([containerWidth / 2, containerHeight / 2])\n .clipAngle(90);\n\n const path = d3.geoPath().projection(projection).context(context);\n\n const pointInPolygon = (\n point: [number, number],\n polygon: number[][],\n ): boolean => {\n const [x, y] = point;\n let inside = false;\n\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const [xi, yi] = polygon[i];\n const [xj, yj] = polygon[j];\n\n if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) {\n inside = !inside;\n }\n }\n\n return inside;\n };\n\n const pointInFeature = (point: [number, number], feature: any): boolean => {\n const geometry = feature.geometry;\n\n if (geometry.type === \"Polygon\") {\n const coordinates = geometry.coordinates;\n // Check if point is in outer ring\n if (!pointInPolygon(point, coordinates[0])) {\n return false;\n }\n // Check if point is in any hole (inner rings)\n for (let i = 1; i < coordinates.length; i++) {\n if (pointInPolygon(point, coordinates[i])) {\n return false; // Point is in a hole\n }\n }\n return true;\n } else if (geometry.type === \"MultiPolygon\") {\n // Check each polygon in the MultiPolygon\n for (const polygon of geometry.coordinates) {\n // Check if point is in outer ring\n if (pointInPolygon(point, polygon[0])) {\n // Check if point is in any hole\n let inHole = false;\n for (let i = 1; i < polygon.length; i++) {\n if (pointInPolygon(point, polygon[i])) {\n inHole = true;\n break;\n }\n }\n if (!inHole) {\n return true;\n }\n }\n }\n return false;\n }\n\n return false;\n };\n\n const generateDotsInPolygon = (feature: any, dotSpacing = 16) => {\n const dots: [number, number][] = [];\n const bounds = d3.geoBounds(feature);\n const [[minLng, minLat], [maxLng, maxLat]] = bounds;\n\n const stepSize = dotSpacing * 0.08;\n let pointsGenerated = 0;\n\n for (let lng = minLng; lng <= maxLng; lng += stepSize) {\n for (let lat = minLat; lat <= maxLat; lat += stepSize) {\n const point: [number, number] = [lng, lat];\n if (pointInFeature(point, feature)) {\n dots.push(point);\n pointsGenerated++;\n }\n }\n }\n\n console.log(\n `[v0] Generated ${pointsGenerated} points for land feature:`,\n feature.properties?.featurecla || \"Land\",\n );\n return dots;\n };\n\n interface DotData {\n lng: number;\n lat: number;\n visible: boolean;\n }\n\n const allDots: DotData[] = [];\n let landFeatures: any;\n\n const render = () => {\n // Clear canvas\n context.clearRect(0, 0, containerWidth, containerHeight);\n\n const currentScale = projection.scale();\n const scaleFactor = currentScale / radius;\n\n // Draw ocean (globe background)\n context.beginPath();\n context.arc(\n containerWidth / 2,\n containerHeight / 2,\n currentScale,\n 0,\n 2 * Math.PI,\n );\n context.fillStyle = \"#00000066\";\n context.fill();\n context.strokeStyle = \"#80eeb4\";\n context.lineWidth = 2 * scaleFactor;\n context.stroke();\n\n if (landFeatures) {\n // Draw graticule\n const graticule = d3.geoGraticule();\n context.beginPath();\n path(graticule());\n context.strokeStyle = \"#80eeb4\";\n context.lineWidth = 1 * scaleFactor;\n context.globalAlpha = 0.25;\n context.stroke();\n context.globalAlpha = 1;\n\n // Draw land outlines\n context.beginPath();\n landFeatures.features.forEach((feature: any) => {\n path(feature);\n });\n context.strokeStyle = \"#80eeb4\";\n context.lineWidth = 1 * scaleFactor;\n context.stroke();\n\n // Draw halftone dots\n allDots.forEach((dot) => {\n const projected = projection([dot.lng, dot.lat]);\n if (\n projected &&\n projected[0] >= 0 &&\n projected[0] <= containerWidth &&\n projected[1] >= 0 &&\n projected[1] <= containerHeight\n ) {\n context.beginPath();\n context.arc(\n projected[0],\n projected[1],\n 1.2 * scaleFactor,\n 0,\n 2 * Math.PI,\n );\n context.fillStyle = \"#80eeb466\";\n context.fill();\n }\n });\n }\n };\n\n const loadWorldData = async () => {\n try {\n setIsLoading(true);\n\n const response = await fetch(\n \"https://raw.githubusercontent.com/martynafford/natural-earth-geojson/refs/heads/master/110m/physical/ne_110m_land.json\",\n );\n if (!response.ok) throw new Error(\"Failed to load land data\");\n\n landFeatures = await response.json();\n\n // Generate dots for all land features\n let totalDots = 0;\n landFeatures.features.forEach((feature: any) => {\n const dots = generateDotsInPolygon(feature, 16);\n dots.forEach(([lng, lat]) => {\n allDots.push({ lng, lat, visible: true });\n totalDots++;\n });\n });\n\n console.log(\n `[v0] Total dots generated: ${totalDots} across ${landFeatures.features.length} land features`,\n );\n\n render();\n setIsLoading(false);\n } catch (err) {\n setError(\"Failed to load land map data\");\n setIsLoading(false);\n }\n };\n\n // Set up rotation and interaction\n const rotation: [number, number] = [0, 0];\n let autoRotate = true;\n const rotationSpeed = 0.5;\n\n const rotate = () => {\n if (autoRotate) {\n rotation[0] += rotationSpeed;\n projection.rotate(rotation);\n render();\n }\n };\n\n // Auto-rotation timer\n const rotationTimer = d3.timer(rotate);\n\n const handleMouseDown = (event: MouseEvent) => {\n autoRotate = false;\n const startX = event.clientX;\n const startY = event.clientY;\n const startRotation: [number, number] = [rotation[0], rotation[1]];\n\n const handleMouseMove = (moveEvent: MouseEvent) => {\n const sensitivity = 0.5;\n const dx = moveEvent.clientX - startX;\n const dy = moveEvent.clientY - startY;\n\n rotation[0] = startRotation[0] + dx * sensitivity;\n rotation[1] = startRotation[1] - dy * sensitivity;\n rotation[1] = Math.max(-90, Math.min(90, rotation[1]));\n\n projection.rotate(rotation);\n render();\n };\n\n const handleMouseUp = () => {\n document.removeEventListener(\"mousemove\", handleMouseMove);\n document.removeEventListener(\"mouseup\", handleMouseUp);\n\n setTimeout(() => {\n autoRotate = true;\n }, 10);\n };\n\n document.addEventListener(\"mousemove\", handleMouseMove);\n document.addEventListener(\"mouseup\", handleMouseUp);\n };\n\n const handleWheel = (event: WheelEvent) => {\n event.preventDefault();\n const scaleFactor = event.deltaY > 0 ? 0.9 : 1.1;\n const newRadius = Math.max(\n radius * 0.5,\n Math.min(radius * 3, projection.scale() * scaleFactor),\n );\n projection.scale(newRadius);\n render();\n };\n\n canvas.addEventListener(\"mousedown\", handleMouseDown);\n canvas.addEventListener(\"wheel\", handleWheel);\n\n // Load the world data\n loadWorldData();\n\n // Cleanup\n return () => {\n rotationTimer.stop();\n canvas.removeEventListener(\"mousedown\", handleMouseDown);\n canvas.removeEventListener(\"wheel\", handleWheel);\n };\n }, [width, height]);\n\n if (error) {\n return (\n \n
\n

\n Error loading Earth visualization\n

\n

{error}

\n
\n \n );\n }\n\n return (\n
\n \n
\n Drag to rotate • Scroll to zoom\n
\n
\n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/shadow-button.json b/public/r/shadow-button.json index 2391cea..ea3a11f 100644 --- a/public/r/shadow-button.json +++ b/public/r/shadow-button.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "shadow-button", - "type": "registry:component", "dependencies": [ "react-icons", "clsx", @@ -20,5 +19,6 @@ "content": "import React from \"react\";\nimport { MdDone } from \"react-icons/md\";\n\nconst HoverShadowButton = ({ text }: { text: string }) => {\n return (\n \n );\n};\n\nexport default HoverShadowButton;\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/shiny-card.json b/public/r/shiny-card.json index 9f9eda1..49ba01c 100644 --- a/public/r/shiny-card.json +++ b/public/r/shiny-card.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "shiny-card", - "type": "registry:component", "dependencies": [ "react-icons" ], @@ -23,5 +22,6 @@ "content": ".shiny-card {\n --white: hsl(0, 0%, 100%);\n --black: hsl(240, 15%, 9%);\n --paragraph: hsl(0, 0%, 83%);\n --line: hsl(240, 9%, 17%);\n --primary: var(--primary-color);\n gap: 1rem;\n padding: 1rem;\n background-color: hsla(240, 15%, 9%, 1);\n background-image:\n radial-gradient(at 88% 40%, hsla(240, 15%, 9%, 1) 0px, transparent 85%),\n radial-gradient(at 49% 30%, hsla(240, 15%, 9%, 1) 0px, transparent 85%),\n radial-gradient(at 14% 26%, hsla(240, 15%, 9%, 1) 0px, transparent 85%),\n radial-gradient(at 0% 64%, hsl(189, 99%, 26%) 0px, transparent 85%),\n radial-gradient(at 41% 94%, hsl(189, 97%, 36%) 0px, transparent 85%),\n radial-gradient(at 100% 99%, hsl(188, 94%, 13%) 0px, transparent 85%);\n\n border-radius: 1rem;\n box-shadow: 0px -16px 24px 0px rgba(255, 255, 255, 0.25) inset;\n\n border: 2px solid var(--primary);\n animation: border-color-change 3s linear infinite;\n}\n\n@keyframes border-color-change {\n 0% {\n border-color: var(--primary);\n }\n\n 50% {\n border-color: var(--line);\n }\n\n 100% {\n border-color: var(--primary);\n }\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/singin-form.json b/public/r/singin-form.json index 0c8cde8..ca77be5 100644 --- a/public/r/singin-form.json +++ b/public/r/singin-form.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "singin-form", - "type": "registry:component", "dependencies": [ "lucide-react", "framer-motion", @@ -21,5 +20,6 @@ "content": "\"use client\";\nimport React, { useState } from \"react\";\nimport Link from \"next/link\";\nimport {\n motion,\n AnimatePresence,\n useMotionValue,\n useTransform,\n} from \"framer-motion\";\nimport { Mail, Lock, Eye, EyeClosed, ArrowRight } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nfunction Input({ className, type, ...props }: React.ComponentProps<\"input\">) {\n return (\n \n );\n}\n\nexport function SingInForm() {\n const [showPassword, setShowPassword] = useState(false);\n const [email, setEmail] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [isLoading, setIsLoading] = useState(false);\n const [focusedInput, setFocusedInput] = useState<\"email\" | \"password\" | null>(\n null,\n );\n const [rememberMe, setRememberMe] = useState(false);\n const [, setMousePosition] = useState({ x: 0, y: 0 });\n\n // For 3D card effect - increased rotation range for more pronounced 3D effect\n const mouseX = useMotionValue(0);\n const mouseY = useMotionValue(0);\n const rotateX = useTransform(mouseY, [-300, 300], [10, -10]); // Increased from 5/-5 to 10/-10\n const rotateY = useTransform(mouseX, [-300, 300], [-10, 10]); // Increased from -5/5 to -10/10\n\n const handleMouseMove = (e: React.MouseEvent) => {\n const rect = e.currentTarget.getBoundingClientRect();\n mouseX.set(e.clientX - rect.left - rect.width / 2);\n mouseY.set(e.clientY - rect.top - rect.height / 2);\n setMousePosition({ x: e.clientX, y: e.clientY });\n };\n\n const handleMouseLeave = () => {\n mouseX.set(0);\n mouseY.set(0);\n };\n\n return (\n
\n {/* Background gradient effect - matches the purple OnlyPipe style */}\n
\n\n {/* Subtle noise texture overlay */}\n \n\n {/* Top radial glow */}\n
\n \n \n\n {/* Animated glow spots */}\n
\n
\n\n \n \n
\n {/* Card glow effect - reduced intensity */}\n \n\n {/* Traveling light beam effect - reduced opacity */}\n
\n {/* Top light beam - enhanced glow */}\n \n\n {/* Right light beam - enhanced glow */}\n \n\n {/* Bottom light beam - enhanced glow */}\n \n\n {/* Left light beam - enhanced glow */}\n \n\n {/* Subtle corner glow spots - reduced opacity */}\n \n \n \n \n
\n\n {/* Card border glow - reduced opacity */}\n
\n\n {/* Glass card background */}\n
\n {/* Subtle card inner patterns */}\n \n\n {/* Logo and header */}\n
\n \n {/* Logo placeholder - would be an SVG in practice */}\n {/* */}\n \n S\n \n\n {/* Inner lighting effect */}\n
\n \n\n \n Welcome Back\n \n\n \n Sign in to continue to StyleMe\n \n
\n\n {/* Login form */}\n {\n e.preventDefault();\n setIsLoading(true);\n setTimeout(() => setIsLoading(false), 2000);\n }}\n className=\"space-y-4\"\n >\n \n {/* Email input */}\n \n
\n\n
\n \n\n setEmail(e.target.value)}\n onFocus={() => setFocusedInput(\"email\")}\n onBlur={() => setFocusedInput(null)}\n className=\"w-full bg-white/5 border-transparent focus:border-white/20 text-white placeholder:text-white/30 h-10 transition-all duration-300 pl-10 pr-3 focus:bg-white/10\"\n />\n\n {/* Input highlight effect */}\n {focusedInput === \"email\" && (\n \n )}\n
\n \n\n {/* Password input */}\n \n
\n\n
\n \n\n setPassword(e.target.value)}\n onFocus={() => setFocusedInput(\"password\")}\n onBlur={() => setFocusedInput(null)}\n className=\"w-full bg-white/5 border-transparent focus:border-white/20 text-white placeholder:text-white/30 h-10 transition-all duration-300 pl-10 pr-10 focus:bg-white/10\"\n />\n\n {/* Toggle password visibility */}\n setShowPassword(!showPassword)}\n className=\"absolute right-3 cursor-pointer\"\n >\n {showPassword ? (\n \n ) : (\n \n )}\n
\n\n {/* Input highlight effect */}\n {focusedInput === \"password\" && (\n \n )}\n
\n \n \n\n {/* Remember me & Forgot password */}\n
\n
\n
\n setRememberMe(!rememberMe)}\n className=\"appearance-none h-4 w-4 rounded border border-white/20 bg-white/5 checked:bg-white checked:border-white focus:outline-none focus:ring-1 focus:ring-white/30 transition-all duration-200\"\n />\n {rememberMe && (\n \n {/* */}\n \n \n \n \n )}\n
\n \n Remember me\n \n
\n\n
\n \n Forgot password?\n \n
\n
\n\n {/* Sign in button */}\n \n {/* Button glow effect - reduced intensity */}\n
\n\n
\n {/* Button background animation */}\n \n\n \n {isLoading ? (\n \n
\n \n ) : (\n \n Sign In\n \n \n )}\n \n
\n \n\n {/* Minimal Divider */}\n
\n
\n \n or\n \n
\n
\n\n {/* Google Sign In */}\n \n
\n\n
\n {/* */}\n
\n G\n
\n\n \n Sign in with Google\n \n\n {/* Button hover effect */}\n \n
\n \n\n {/* Sign up link */}\n \n Don't have an account?{\" \"}\n \n \n Sign up\n \n \n \n \n \n
\n
\n \n \n
\n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/splash-cursor.json b/public/r/splash-cursor.json index 6614604..cbb4cc8 100644 --- a/public/r/splash-cursor.json +++ b/public/r/splash-cursor.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "splash-cursor", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "\"use client\";\nimport React, { useEffect, useRef } from \"react\";\n\ninterface ColorRGB {\n r: number;\n g: number;\n b: number;\n}\n\ninterface SplashCursorProps {\n SIM_RESOLUTION?: number;\n DYE_RESOLUTION?: number;\n CAPTURE_RESOLUTION?: number;\n DENSITY_DISSIPATION?: number;\n VELOCITY_DISSIPATION?: number;\n PRESSURE?: number;\n PRESSURE_ITERATIONS?: number;\n CURL?: number;\n SPLAT_RADIUS?: number;\n SPLAT_FORCE?: number;\n SHADING?: boolean;\n COLOR_UPDATE_SPEED?: number;\n BACK_COLOR?: ColorRGB;\n TRANSPARENT?: boolean;\n}\n\ninterface Pointer {\n id: number;\n texcoordX: number;\n texcoordY: number;\n prevTexcoordX: number;\n prevTexcoordY: number;\n deltaX: number;\n deltaY: number;\n down: boolean;\n moved: boolean;\n color: ColorRGB;\n}\n\nfunction pointerPrototype(): Pointer {\n return {\n id: -1,\n texcoordX: 0,\n texcoordY: 0,\n prevTexcoordX: 0,\n prevTexcoordY: 0,\n deltaX: 0,\n deltaY: 0,\n down: false,\n moved: false,\n color: { r: 0, g: 0, b: 0 },\n };\n}\n\nexport default function SplashCursor({\n SIM_RESOLUTION = 128,\n DYE_RESOLUTION = 1440,\n CAPTURE_RESOLUTION = 512,\n DENSITY_DISSIPATION = 3.5,\n VELOCITY_DISSIPATION = 2,\n PRESSURE = 0.1,\n PRESSURE_ITERATIONS = 20,\n CURL = 3,\n SPLAT_RADIUS = 0.2,\n SPLAT_FORCE = 6000,\n SHADING = true,\n COLOR_UPDATE_SPEED = 10,\n BACK_COLOR = { r: 0.5, g: 0, b: 0 },\n TRANSPARENT = true,\n}: SplashCursorProps) {\n const canvasRef = useRef(null);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return; // Guard canvas early\n\n // Pointer and config setup\n const pointers: Pointer[] = [pointerPrototype()];\n\n // All these are guaranteed numbers due to destructuring defaults\n // So we cast them to remove TS warnings:\n const config = {\n SIM_RESOLUTION: SIM_RESOLUTION!,\n DYE_RESOLUTION: DYE_RESOLUTION!,\n CAPTURE_RESOLUTION: CAPTURE_RESOLUTION!,\n DENSITY_DISSIPATION: DENSITY_DISSIPATION!,\n VELOCITY_DISSIPATION: VELOCITY_DISSIPATION!,\n PRESSURE: PRESSURE!,\n PRESSURE_ITERATIONS: PRESSURE_ITERATIONS!,\n CURL: CURL!,\n SPLAT_RADIUS: SPLAT_RADIUS!,\n SPLAT_FORCE: SPLAT_FORCE!,\n SHADING,\n COLOR_UPDATE_SPEED: COLOR_UPDATE_SPEED!,\n PAUSED: false,\n BACK_COLOR,\n TRANSPARENT,\n };\n\n // Get WebGL context (WebGL1 or WebGL2)\n const { gl, ext } = getWebGLContext(canvas);\n if (!gl || !ext) return;\n\n // If no linear filtering, reduce resolution\n if (!ext.supportLinearFiltering) {\n config.DYE_RESOLUTION = 256;\n config.SHADING = false;\n }\n\n function getWebGLContext(canvas: HTMLCanvasElement) {\n const params = {\n alpha: true,\n depth: false,\n stencil: false,\n antialias: false,\n preserveDrawingBuffer: false,\n };\n\n let gl = canvas.getContext(\n \"webgl2\",\n params,\n ) as WebGL2RenderingContext | null;\n\n if (!gl) {\n gl = (canvas.getContext(\"webgl\", params) ||\n canvas.getContext(\n \"experimental-webgl\",\n params,\n )) as WebGL2RenderingContext | null;\n }\n\n if (!gl) {\n throw new Error(\"Unable to initialize WebGL.\");\n }\n\n const isWebGL2 = \"drawBuffers\" in gl;\n\n let supportLinearFiltering = false;\n let halfFloat: OES_texture_half_float | null = null;\n\n if (isWebGL2) {\n // For WebGL2\n (gl as WebGL2RenderingContext).getExtension(\"EXT_color_buffer_float\");\n supportLinearFiltering = !!(gl as WebGL2RenderingContext).getExtension(\n \"OES_texture_float_linear\",\n );\n } else {\n // For WebGL1\n halfFloat = gl.getExtension(\"OES_texture_half_float\");\n supportLinearFiltering = !!gl.getExtension(\n \"OES_texture_half_float_linear\",\n );\n }\n\n gl.clearColor(0, 0, 0, 1);\n\n const halfFloatTexType = isWebGL2\n ? (gl as WebGL2RenderingContext).HALF_FLOAT\n : halfFloat && \"HALF_FLOAT_OES\" in halfFloat\n ? (halfFloat as OES_texture_half_float).HALF_FLOAT_OES\n : 0;\n\n let formatRGBA: { internalFormat: number; format: number } | null;\n let formatRG: { internalFormat: number; format: number } | null;\n let formatR: { internalFormat: number; format: number } | null;\n\n if (isWebGL2) {\n formatRGBA = getSupportedFormat(\n gl,\n (gl as WebGL2RenderingContext).RGBA16F,\n gl.RGBA,\n halfFloatTexType,\n );\n formatRG = getSupportedFormat(\n gl,\n (gl as WebGL2RenderingContext).RG16F,\n (gl as WebGL2RenderingContext).RG,\n halfFloatTexType,\n );\n formatR = getSupportedFormat(\n gl,\n (gl as WebGL2RenderingContext).R16F,\n (gl as WebGL2RenderingContext).RED,\n halfFloatTexType,\n );\n } else {\n formatRGBA = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);\n formatRG = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);\n formatR = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);\n }\n\n return {\n gl,\n ext: {\n formatRGBA,\n formatRG,\n formatR,\n halfFloatTexType,\n supportLinearFiltering,\n },\n };\n }\n\n function getSupportedFormat(\n gl: WebGLRenderingContext | WebGL2RenderingContext,\n internalFormat: number,\n format: number,\n type: number,\n ): { internalFormat: number; format: number } | null {\n if (!supportRenderTextureFormat(gl, internalFormat, format, type)) {\n // For WebGL2 fallback:\n if (\"drawBuffers\" in gl) {\n const gl2 = gl as WebGL2RenderingContext;\n switch (internalFormat) {\n case gl2.R16F:\n return getSupportedFormat(gl2, gl2.RG16F, gl2.RG, type);\n case gl2.RG16F:\n return getSupportedFormat(gl2, gl2.RGBA16F, gl2.RGBA, type);\n default:\n return null;\n }\n }\n return null;\n }\n return { internalFormat, format };\n }\n\n function supportRenderTextureFormat(\n gl: WebGLRenderingContext | WebGL2RenderingContext,\n internalFormat: number,\n format: number,\n type: number,\n ) {\n const texture = gl.createTexture();\n if (!texture) return false;\n\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n internalFormat,\n 4,\n 4,\n 0,\n format,\n type,\n null,\n );\n\n const fbo = gl.createFramebuffer();\n if (!fbo) return false;\n\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n gl.COLOR_ATTACHMENT0,\n gl.TEXTURE_2D,\n texture,\n 0,\n );\n const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);\n return status === gl.FRAMEBUFFER_COMPLETE;\n }\n\n function hashCode(s: string) {\n if (!s.length) return 0;\n let hash = 0;\n for (let i = 0; i < s.length; i++) {\n hash = (hash << 5) - hash + s.charCodeAt(i);\n hash |= 0;\n }\n return hash;\n }\n\n function addKeywords(source: string, keywords: string[] | null) {\n if (!keywords) return source;\n let keywordsString = \"\";\n for (const keyword of keywords) {\n keywordsString += `#define ${keyword}\\n`;\n }\n return keywordsString + source;\n }\n\n function compileShader(\n type: number,\n source: string,\n keywords: string[] | null = null,\n ): WebGLShader | null {\n const shaderSource = addKeywords(source, keywords);\n const shader = gl.createShader(type);\n if (!shader) return null;\n gl.shaderSource(shader, shaderSource);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n console.trace(gl.getShaderInfoLog(shader));\n }\n return shader;\n }\n\n function createProgram(\n vertexShader: WebGLShader | null,\n fragmentShader: WebGLShader | null,\n ): WebGLProgram | null {\n if (!vertexShader || !fragmentShader) return null;\n const program = gl.createProgram();\n if (!program) return null;\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n console.trace(gl.getProgramInfoLog(program));\n }\n return program;\n }\n\n function getUniforms(program: WebGLProgram) {\n const uniforms: Record = {};\n const uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);\n for (let i = 0; i < uniformCount; i++) {\n const uniformInfo = gl.getActiveUniform(program, i);\n if (uniformInfo) {\n uniforms[uniformInfo.name] = gl.getUniformLocation(\n program,\n uniformInfo.name,\n );\n }\n }\n return uniforms;\n }\n\n class Program {\n program: WebGLProgram | null;\n uniforms: Record;\n\n constructor(\n vertexShader: WebGLShader | null,\n fragmentShader: WebGLShader | null,\n ) {\n this.program = createProgram(vertexShader, fragmentShader);\n this.uniforms = this.program ? getUniforms(this.program) : {};\n }\n\n bind() {\n if (this.program) gl.useProgram(this.program);\n }\n }\n\n class Material {\n vertexShader: WebGLShader | null;\n fragmentShaderSource: string;\n programs: Record;\n activeProgram: WebGLProgram | null;\n uniforms: Record;\n\n constructor(\n vertexShader: WebGLShader | null,\n fragmentShaderSource: string,\n ) {\n this.vertexShader = vertexShader;\n this.fragmentShaderSource = fragmentShaderSource;\n this.programs = {};\n this.activeProgram = null;\n this.uniforms = {};\n }\n\n setKeywords(keywords: string[]) {\n let hash = 0;\n for (const kw of keywords) {\n hash += hashCode(kw);\n }\n let program = this.programs[hash];\n if (program == null) {\n const fragmentShader = compileShader(\n gl.FRAGMENT_SHADER,\n this.fragmentShaderSource,\n keywords,\n );\n program = createProgram(this.vertexShader, fragmentShader);\n this.programs[hash] = program;\n }\n if (program === this.activeProgram) return;\n if (program) {\n this.uniforms = getUniforms(program);\n }\n this.activeProgram = program;\n }\n\n bind() {\n if (this.activeProgram) {\n gl.useProgram(this.activeProgram);\n }\n }\n }\n\n // -------------------- Shaders --------------------\n const baseVertexShader = compileShader(\n gl.VERTEX_SHADER,\n `\n precision highp float;\n attribute vec2 aPosition;\n varying vec2 vUv;\n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform vec2 texelSize;\n\n void main () {\n vUv = aPosition * 0.5 + 0.5;\n vL = vUv - vec2(texelSize.x, 0.0);\n vR = vUv + vec2(texelSize.x, 0.0);\n vT = vUv + vec2(0.0, texelSize.y);\n vB = vUv - vec2(0.0, texelSize.y);\n gl_Position = vec4(aPosition, 0.0, 1.0);\n }\n `,\n );\n\n const copyShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision mediump float;\n precision mediump sampler2D;\n varying highp vec2 vUv;\n uniform sampler2D uTexture;\n\n void main () {\n gl_FragColor = texture2D(uTexture, vUv);\n }\n `,\n );\n\n const clearShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision mediump float;\n precision mediump sampler2D;\n varying highp vec2 vUv;\n uniform sampler2D uTexture;\n uniform float value;\n\n void main () {\n gl_FragColor = value * texture2D(uTexture, vUv);\n }\n `,\n );\n\n const displayShaderSource = `\n precision highp float;\n precision highp sampler2D;\n varying vec2 vUv;\n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform sampler2D uTexture;\n uniform sampler2D uDithering;\n uniform vec2 ditherScale;\n uniform vec2 texelSize;\n\n vec3 linearToGamma (vec3 color) {\n color = max(color, vec3(0));\n return max(1.055 * pow(color, vec3(0.416666667)) - 0.055, vec3(0));\n }\n\n void main () {\n vec3 c = texture2D(uTexture, vUv).rgb;\n #ifdef SHADING\n vec3 lc = texture2D(uTexture, vL).rgb;\n vec3 rc = texture2D(uTexture, vR).rgb;\n vec3 tc = texture2D(uTexture, vT).rgb;\n vec3 bc = texture2D(uTexture, vB).rgb;\n\n float dx = length(rc) - length(lc);\n float dy = length(tc) - length(bc);\n\n vec3 n = normalize(vec3(dx, dy, length(texelSize)));\n vec3 l = vec3(0.0, 0.0, 1.0);\n\n float diffuse = clamp(dot(n, l) + 0.7, 0.7, 1.0);\n c *= diffuse;\n #endif\n\n float a = max(c.r, max(c.g, c.b));\n gl_FragColor = vec4(c, a);\n }\n `;\n\n const splatShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision highp float;\n precision highp sampler2D;\n varying vec2 vUv;\n uniform sampler2D uTarget;\n uniform float aspectRatio;\n uniform vec3 color;\n uniform vec2 point;\n uniform float radius;\n\n void main () {\n vec2 p = vUv - point.xy;\n p.x *= aspectRatio;\n vec3 splat = exp(-dot(p, p) / radius) * color;\n vec3 base = texture2D(uTarget, vUv).xyz;\n gl_FragColor = vec4(base + splat, 1.0);\n }\n `,\n );\n\n const advectionShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision highp float;\n precision highp sampler2D;\n varying vec2 vUv;\n uniform sampler2D uVelocity;\n uniform sampler2D uSource;\n uniform vec2 texelSize;\n uniform vec2 dyeTexelSize;\n uniform float dt;\n uniform float dissipation;\n\n vec4 bilerp (sampler2D sam, vec2 uv, vec2 tsize) {\n vec2 st = uv / tsize - 0.5;\n vec2 iuv = floor(st);\n vec2 fuv = fract(st);\n\n vec4 a = texture2D(sam, (iuv + vec2(0.5, 0.5)) * tsize);\n vec4 b = texture2D(sam, (iuv + vec2(1.5, 0.5)) * tsize);\n vec4 c = texture2D(sam, (iuv + vec2(0.5, 1.5)) * tsize);\n vec4 d = texture2D(sam, (iuv + vec2(1.5, 1.5)) * tsize);\n\n return mix(mix(a, b, fuv.x), mix(c, d, fuv.x), fuv.y);\n }\n\n void main () {\n #ifdef MANUAL_FILTERING\n vec2 coord = vUv - dt * bilerp(uVelocity, vUv, texelSize).xy * texelSize;\n vec4 result = bilerp(uSource, coord, dyeTexelSize);\n #else\n vec2 coord = vUv - dt * texture2D(uVelocity, vUv).xy * texelSize;\n vec4 result = texture2D(uSource, coord);\n #endif\n float decay = 1.0 + dissipation * dt;\n gl_FragColor = result / decay;\n }\n `,\n ext.supportLinearFiltering ? null : [\"MANUAL_FILTERING\"],\n );\n\n const divergenceShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision mediump float;\n precision mediump sampler2D;\n varying highp vec2 vUv;\n varying highp vec2 vL;\n varying highp vec2 vR;\n varying highp vec2 vT;\n varying highp vec2 vB;\n uniform sampler2D uVelocity;\n\n void main () {\n float L = texture2D(uVelocity, vL).x;\n float R = texture2D(uVelocity, vR).x;\n float T = texture2D(uVelocity, vT).y;\n float B = texture2D(uVelocity, vB).y;\n\n vec2 C = texture2D(uVelocity, vUv).xy;\n if (vL.x < 0.0) { L = -C.x; }\n if (vR.x > 1.0) { R = -C.x; }\n if (vT.y > 1.0) { T = -C.y; }\n if (vB.y < 0.0) { B = -C.y; }\n\n float div = 0.5 * (R - L + T - B);\n gl_FragColor = vec4(div, 0.0, 0.0, 1.0);\n }\n `,\n );\n\n const curlShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision mediump float;\n precision mediump sampler2D;\n varying highp vec2 vUv;\n varying highp vec2 vL;\n varying highp vec2 vR;\n varying highp vec2 vT;\n varying highp vec2 vB;\n uniform sampler2D uVelocity;\n\n void main () {\n float L = texture2D(uVelocity, vL).y;\n float R = texture2D(uVelocity, vR).y;\n float T = texture2D(uVelocity, vT).x;\n float B = texture2D(uVelocity, vB).x;\n float vorticity = R - L - T + B;\n gl_FragColor = vec4(0.5 * vorticity, 0.0, 0.0, 1.0);\n }\n `,\n );\n\n const vorticityShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision highp float;\n precision highp sampler2D;\n varying vec2 vUv;\n varying vec2 vL;\n varying vec2 vR;\n varying vec2 vT;\n varying vec2 vB;\n uniform sampler2D uVelocity;\n uniform sampler2D uCurl;\n uniform float curl;\n uniform float dt;\n\n void main () {\n float L = texture2D(uCurl, vL).x;\n float R = texture2D(uCurl, vR).x;\n float T = texture2D(uCurl, vT).x;\n float B = texture2D(uCurl, vB).x;\n float C = texture2D(uCurl, vUv).x;\n\n vec2 force = 0.5 * vec2(abs(T) - abs(B), abs(R) - abs(L));\n force /= length(force) + 0.0001;\n force *= curl * C;\n force.y *= -1.0;\n\n vec2 velocity = texture2D(uVelocity, vUv).xy;\n velocity += force * dt;\n velocity = min(max(velocity, -1000.0), 1000.0);\n gl_FragColor = vec4(velocity, 0.0, 1.0);\n }\n `,\n );\n\n const pressureShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision mediump float;\n precision mediump sampler2D;\n varying highp vec2 vUv;\n varying highp vec2 vL;\n varying highp vec2 vR;\n varying highp vec2 vT;\n varying highp vec2 vB;\n uniform sampler2D uPressure;\n uniform sampler2D uDivergence;\n\n void main () {\n float L = texture2D(uPressure, vL).x;\n float R = texture2D(uPressure, vR).x;\n float T = texture2D(uPressure, vT).x;\n float B = texture2D(uPressure, vB).x;\n float C = texture2D(uPressure, vUv).x;\n float divergence = texture2D(uDivergence, vUv).x;\n float pressure = (L + R + B + T - divergence) * 0.25;\n gl_FragColor = vec4(pressure, 0.0, 0.0, 1.0);\n }\n `,\n );\n\n const gradientSubtractShader = compileShader(\n gl.FRAGMENT_SHADER,\n `\n precision mediump float;\n precision mediump sampler2D;\n varying highp vec2 vUv;\n varying highp vec2 vL;\n varying highp vec2 vR;\n varying highp vec2 vT;\n varying highp vec2 vB;\n uniform sampler2D uPressure;\n uniform sampler2D uVelocity;\n\n void main () {\n float L = texture2D(uPressure, vL).x;\n float R = texture2D(uPressure, vR).x;\n float T = texture2D(uPressure, vT).x;\n float B = texture2D(uPressure, vB).x;\n vec2 velocity = texture2D(uVelocity, vUv).xy;\n velocity.xy -= vec2(R - L, T - B);\n gl_FragColor = vec4(velocity, 0.0, 1.0);\n }\n `,\n );\n\n // -------------------- Fullscreen Triangles --------------------\n const blit = (() => {\n const buffer = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.bufferData(\n gl.ARRAY_BUFFER,\n new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]),\n gl.STATIC_DRAW,\n );\n const elemBuffer = gl.createBuffer()!;\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elemBuffer);\n gl.bufferData(\n gl.ELEMENT_ARRAY_BUFFER,\n new Uint16Array([0, 1, 2, 0, 2, 3]),\n gl.STATIC_DRAW,\n );\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n gl.enableVertexAttribArray(0);\n\n return (target: FBO | null, doClear = false) => {\n if (!gl) return;\n if (!target) {\n gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n } else {\n gl.viewport(0, 0, target.width, target.height);\n gl.bindFramebuffer(gl.FRAMEBUFFER, target.fbo);\n }\n if (doClear) {\n gl.clearColor(0, 0, 0, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n }\n gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);\n };\n })();\n\n // Types for Framebuffers\n interface FBO {\n texture: WebGLTexture;\n fbo: WebGLFramebuffer;\n width: number;\n height: number;\n texelSizeX: number;\n texelSizeY: number;\n attach: (id: number) => number;\n }\n\n interface DoubleFBO {\n width: number;\n height: number;\n texelSizeX: number;\n texelSizeY: number;\n read: FBO;\n write: FBO;\n swap: () => void;\n }\n\n // FBO variables\n let dye: DoubleFBO;\n let velocity: DoubleFBO;\n let divergence: FBO;\n let curl: FBO;\n let pressure: DoubleFBO;\n\n // WebGL Programs\n const copyProgram = new Program(baseVertexShader, copyShader);\n const clearProgram = new Program(baseVertexShader, clearShader);\n const splatProgram = new Program(baseVertexShader, splatShader);\n const advectionProgram = new Program(baseVertexShader, advectionShader);\n const divergenceProgram = new Program(baseVertexShader, divergenceShader);\n const curlProgram = new Program(baseVertexShader, curlShader);\n const vorticityProgram = new Program(baseVertexShader, vorticityShader);\n const pressureProgram = new Program(baseVertexShader, pressureShader);\n const gradienSubtractProgram = new Program(\n baseVertexShader,\n gradientSubtractShader,\n );\n const displayMaterial = new Material(baseVertexShader, displayShaderSource);\n\n // -------------------- FBO creation --------------------\n function createFBO(\n w: number,\n h: number,\n internalFormat: number,\n format: number,\n type: number,\n param: number,\n ): FBO {\n gl.activeTexture(gl.TEXTURE0);\n const texture = gl.createTexture()!;\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, param);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, param);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n internalFormat,\n w,\n h,\n 0,\n format,\n type,\n null,\n );\n const fbo = gl.createFramebuffer()!;\n gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);\n gl.framebufferTexture2D(\n gl.FRAMEBUFFER,\n gl.COLOR_ATTACHMENT0,\n gl.TEXTURE_2D,\n texture,\n 0,\n );\n gl.viewport(0, 0, w, h);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n const texelSizeX = 1 / w;\n const texelSizeY = 1 / h;\n\n return {\n texture,\n fbo,\n width: w,\n height: h,\n texelSizeX,\n texelSizeY,\n attach(id: number) {\n gl.activeTexture(gl.TEXTURE0 + id);\n gl.bindTexture(gl.TEXTURE_2D, texture);\n return id;\n },\n };\n }\n\n function createDoubleFBO(\n w: number,\n h: number,\n internalFormat: number,\n format: number,\n type: number,\n param: number,\n ): DoubleFBO {\n const fbo1 = createFBO(w, h, internalFormat, format, type, param);\n const fbo2 = createFBO(w, h, internalFormat, format, type, param);\n return {\n width: w,\n height: h,\n texelSizeX: fbo1.texelSizeX,\n texelSizeY: fbo1.texelSizeY,\n read: fbo1,\n write: fbo2,\n swap() {\n const tmp = this.read;\n this.read = this.write;\n this.write = tmp;\n },\n };\n }\n\n function resizeFBO(\n target: FBO,\n w: number,\n h: number,\n internalFormat: number,\n format: number,\n type: number,\n param: number,\n ) {\n const newFBO = createFBO(w, h, internalFormat, format, type, param);\n copyProgram.bind();\n if (copyProgram.uniforms.uTexture)\n gl.uniform1i(copyProgram.uniforms.uTexture, target.attach(0));\n blit(newFBO, false);\n return newFBO;\n }\n\n function resizeDoubleFBO(\n target: DoubleFBO,\n w: number,\n h: number,\n internalFormat: number,\n format: number,\n type: number,\n param: number,\n ) {\n if (target.width === w && target.height === h) return target;\n target.read = resizeFBO(\n target.read,\n w,\n h,\n internalFormat,\n format,\n type,\n param,\n );\n target.write = createFBO(w, h, internalFormat, format, type, param);\n target.width = w;\n target.height = h;\n target.texelSizeX = 1 / w;\n target.texelSizeY = 1 / h;\n return target;\n }\n\n function initFramebuffers() {\n const simRes = getResolution(config.SIM_RESOLUTION!);\n const dyeRes = getResolution(config.DYE_RESOLUTION!);\n\n const texType = ext.halfFloatTexType;\n const rgba = ext.formatRGBA;\n const rg = ext.formatRG;\n const r = ext.formatR;\n const filtering = ext.supportLinearFiltering ? gl.LINEAR : gl.NEAREST;\n gl.disable(gl.BLEND);\n\n if (!rgba) {\n throw new Error(\"Required RGBA format is not supported by WebGL.\");\n }\n if (!dye) {\n dye = createDoubleFBO(\n dyeRes.width,\n dyeRes.height,\n rgba.internalFormat,\n rgba.format,\n texType,\n filtering,\n );\n } else {\n dye = resizeDoubleFBO(\n dye,\n dyeRes.width,\n dyeRes.height,\n rgba.internalFormat,\n rgba.format,\n texType,\n filtering,\n );\n }\n\n if (!rg) {\n throw new Error(\"Required RG format is not supported by WebGL.\");\n }\n if (!velocity) {\n velocity = createDoubleFBO(\n simRes.width,\n simRes.height,\n rg.internalFormat,\n rg.format,\n texType,\n filtering,\n );\n } else {\n velocity = resizeDoubleFBO(\n velocity,\n simRes.width,\n simRes.height,\n rg.internalFormat,\n rg.format,\n texType,\n filtering,\n );\n }\n\n if (!r) {\n throw new Error(\"Required R format is not supported by WebGL.\");\n }\n divergence = createFBO(\n simRes.width,\n simRes.height,\n r.internalFormat,\n r.format,\n texType,\n gl.NEAREST,\n );\n curl = createFBO(\n simRes.width,\n simRes.height,\n r.internalFormat,\n r.format,\n texType,\n gl.NEAREST,\n );\n pressure = createDoubleFBO(\n simRes.width,\n simRes.height,\n r.internalFormat,\n r.format,\n texType,\n gl.NEAREST,\n );\n }\n\n function updateKeywords() {\n const displayKeywords: string[] = [];\n if (config.SHADING) displayKeywords.push(\"SHADING\");\n displayMaterial.setKeywords(displayKeywords);\n }\n\n function getResolution(resolution: number) {\n const w = gl.drawingBufferWidth;\n const h = gl.drawingBufferHeight;\n const aspectRatio = w / h;\n const aspect = aspectRatio < 1 ? 1 / aspectRatio : aspectRatio;\n const min = Math.round(resolution);\n const max = Math.round(resolution * aspect);\n if (w > h) {\n return { width: max, height: min };\n }\n return { width: min, height: max };\n }\n\n function scaleByPixelRatio(input: number) {\n const pixelRatio = window.devicePixelRatio || 1;\n return Math.floor(input * pixelRatio);\n }\n\n // -------------------- Simulation Setup --------------------\n updateKeywords();\n initFramebuffers();\n\n let lastUpdateTime = Date.now();\n let colorUpdateTimer = 0.0;\n\n function updateFrame() {\n const dt = calcDeltaTime();\n if (resizeCanvas()) initFramebuffers();\n updateColors(dt);\n applyInputs();\n step(dt);\n render(null);\n requestAnimationFrame(updateFrame);\n }\n\n function calcDeltaTime() {\n const now = Date.now();\n let dt = (now - lastUpdateTime) / 1000;\n dt = Math.min(dt, 0.016666);\n lastUpdateTime = now;\n return dt;\n }\n\n function resizeCanvas() {\n const width = scaleByPixelRatio(canvas!.clientWidth);\n const height = scaleByPixelRatio(canvas!.clientHeight);\n if (canvas!.width !== width || canvas!.height !== height) {\n canvas!.width = width;\n canvas!.height = height;\n return true;\n }\n return false;\n }\n\n function updateColors(dt: number) {\n colorUpdateTimer += dt * config.COLOR_UPDATE_SPEED;\n if (colorUpdateTimer >= 1) {\n colorUpdateTimer = wrap(colorUpdateTimer, 0, 1);\n pointers.forEach((p) => {\n p.color = generateColor();\n });\n }\n }\n\n function applyInputs() {\n for (const p of pointers) {\n if (p.moved) {\n p.moved = false;\n splatPointer(p);\n }\n }\n }\n\n function step(dt: number) {\n gl.disable(gl.BLEND);\n\n // Curl\n curlProgram.bind();\n if (curlProgram.uniforms.texelSize) {\n gl.uniform2f(\n curlProgram.uniforms.texelSize,\n velocity.texelSizeX,\n velocity.texelSizeY,\n );\n }\n if (curlProgram.uniforms.uVelocity) {\n gl.uniform1i(curlProgram.uniforms.uVelocity, velocity.read.attach(0));\n }\n blit(curl);\n\n // Vorticity\n vorticityProgram.bind();\n if (vorticityProgram.uniforms.texelSize) {\n gl.uniform2f(\n vorticityProgram.uniforms.texelSize,\n velocity.texelSizeX,\n velocity.texelSizeY,\n );\n }\n if (vorticityProgram.uniforms.uVelocity) {\n gl.uniform1i(\n vorticityProgram.uniforms.uVelocity,\n velocity.read.attach(0),\n );\n }\n if (vorticityProgram.uniforms.uCurl) {\n gl.uniform1i(vorticityProgram.uniforms.uCurl, curl.attach(1));\n }\n if (vorticityProgram.uniforms.curl) {\n gl.uniform1f(vorticityProgram.uniforms.curl, config.CURL);\n }\n if (vorticityProgram.uniforms.dt) {\n gl.uniform1f(vorticityProgram.uniforms.dt, dt);\n }\n blit(velocity.write);\n velocity.swap();\n\n // Divergence\n divergenceProgram.bind();\n if (divergenceProgram.uniforms.texelSize) {\n gl.uniform2f(\n divergenceProgram.uniforms.texelSize,\n velocity.texelSizeX,\n velocity.texelSizeY,\n );\n }\n if (divergenceProgram.uniforms.uVelocity) {\n gl.uniform1i(\n divergenceProgram.uniforms.uVelocity,\n velocity.read.attach(0),\n );\n }\n blit(divergence);\n\n // Clear pressure\n clearProgram.bind();\n if (clearProgram.uniforms.uTexture) {\n gl.uniform1i(clearProgram.uniforms.uTexture, pressure.read.attach(0));\n }\n if (clearProgram.uniforms.value) {\n gl.uniform1f(clearProgram.uniforms.value, config.PRESSURE);\n }\n blit(pressure.write);\n pressure.swap();\n\n // Pressure\n pressureProgram.bind();\n if (pressureProgram.uniforms.texelSize) {\n gl.uniform2f(\n pressureProgram.uniforms.texelSize,\n velocity.texelSizeX,\n velocity.texelSizeY,\n );\n }\n if (pressureProgram.uniforms.uDivergence) {\n gl.uniform1i(\n pressureProgram.uniforms.uDivergence,\n divergence.attach(0),\n );\n }\n for (let i = 0; i < config.PRESSURE_ITERATIONS; i++) {\n if (pressureProgram.uniforms.uPressure) {\n gl.uniform1i(\n pressureProgram.uniforms.uPressure,\n pressure.read.attach(1),\n );\n }\n blit(pressure.write);\n pressure.swap();\n }\n\n // Gradient Subtract\n gradienSubtractProgram.bind();\n if (gradienSubtractProgram.uniforms.texelSize) {\n gl.uniform2f(\n gradienSubtractProgram.uniforms.texelSize,\n velocity.texelSizeX,\n velocity.texelSizeY,\n );\n }\n if (gradienSubtractProgram.uniforms.uPressure) {\n gl.uniform1i(\n gradienSubtractProgram.uniforms.uPressure,\n pressure.read.attach(0),\n );\n }\n if (gradienSubtractProgram.uniforms.uVelocity) {\n gl.uniform1i(\n gradienSubtractProgram.uniforms.uVelocity,\n velocity.read.attach(1),\n );\n }\n blit(velocity.write);\n velocity.swap();\n\n // Advection - velocity\n advectionProgram.bind();\n if (advectionProgram.uniforms.texelSize) {\n gl.uniform2f(\n advectionProgram.uniforms.texelSize,\n velocity.texelSizeX,\n velocity.texelSizeY,\n );\n }\n if (\n !ext.supportLinearFiltering &&\n advectionProgram.uniforms.dyeTexelSize\n ) {\n gl.uniform2f(\n advectionProgram.uniforms.dyeTexelSize,\n velocity.texelSizeX,\n velocity.texelSizeY,\n );\n }\n const velocityId = velocity.read.attach(0);\n if (advectionProgram.uniforms.uVelocity) {\n gl.uniform1i(advectionProgram.uniforms.uVelocity, velocityId);\n }\n if (advectionProgram.uniforms.uSource) {\n gl.uniform1i(advectionProgram.uniforms.uSource, velocityId);\n }\n if (advectionProgram.uniforms.dt) {\n gl.uniform1f(advectionProgram.uniforms.dt, dt);\n }\n if (advectionProgram.uniforms.dissipation) {\n gl.uniform1f(\n advectionProgram.uniforms.dissipation,\n config.VELOCITY_DISSIPATION,\n );\n }\n blit(velocity.write);\n velocity.swap();\n\n // Advection - dye\n if (\n !ext.supportLinearFiltering &&\n advectionProgram.uniforms.dyeTexelSize\n ) {\n gl.uniform2f(\n advectionProgram.uniforms.dyeTexelSize,\n dye.texelSizeX,\n dye.texelSizeY,\n );\n }\n if (advectionProgram.uniforms.uVelocity) {\n gl.uniform1i(\n advectionProgram.uniforms.uVelocity,\n velocity.read.attach(0),\n );\n }\n if (advectionProgram.uniforms.uSource) {\n gl.uniform1i(advectionProgram.uniforms.uSource, dye.read.attach(1));\n }\n if (advectionProgram.uniforms.dissipation) {\n gl.uniform1f(\n advectionProgram.uniforms.dissipation,\n config.DENSITY_DISSIPATION,\n );\n }\n blit(dye.write);\n dye.swap();\n }\n\n function render(target: FBO | null) {\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n gl.enable(gl.BLEND);\n drawDisplay(target);\n }\n\n function drawDisplay(target: FBO | null) {\n const width = target ? target.width : gl.drawingBufferWidth;\n const height = target ? target.height : gl.drawingBufferHeight;\n displayMaterial.bind();\n if (config.SHADING && displayMaterial.uniforms.texelSize) {\n gl.uniform2f(displayMaterial.uniforms.texelSize, 1 / width, 1 / height);\n }\n if (displayMaterial.uniforms.uTexture) {\n gl.uniform1i(displayMaterial.uniforms.uTexture, dye.read.attach(0));\n }\n blit(target, false);\n }\n\n // -------------------- Interaction --------------------\n function splatPointer(pointer: Pointer) {\n const dx = pointer.deltaX * config.SPLAT_FORCE;\n const dy = pointer.deltaY * config.SPLAT_FORCE;\n splat(pointer.texcoordX, pointer.texcoordY, dx, dy, pointer.color);\n }\n\n function clickSplat(pointer: Pointer) {\n const color = generateColor();\n color.r *= 10;\n color.g *= 10;\n color.b *= 10;\n const dx = 10 * (Math.random() - 0.5);\n const dy = 30 * (Math.random() - 0.5);\n splat(pointer.texcoordX, pointer.texcoordY, dx, dy, color);\n }\n\n function splat(\n x: number,\n y: number,\n dx: number,\n dy: number,\n color: ColorRGB,\n ) {\n splatProgram.bind();\n if (splatProgram.uniforms.uTarget) {\n gl.uniform1i(splatProgram.uniforms.uTarget, velocity.read.attach(0));\n }\n if (splatProgram.uniforms.aspectRatio) {\n gl.uniform1f(\n splatProgram.uniforms.aspectRatio,\n canvas!.width / canvas!.height,\n );\n }\n if (splatProgram.uniforms.point) {\n gl.uniform2f(splatProgram.uniforms.point, x, y);\n }\n if (splatProgram.uniforms.color) {\n gl.uniform3f(splatProgram.uniforms.color, dx, dy, 0);\n }\n if (splatProgram.uniforms.radius) {\n gl.uniform1f(\n splatProgram.uniforms.radius,\n correctRadius(config.SPLAT_RADIUS / 100)!,\n );\n }\n blit(velocity.write);\n velocity.swap();\n\n if (splatProgram.uniforms.uTarget) {\n gl.uniform1i(splatProgram.uniforms.uTarget, dye.read.attach(0));\n }\n if (splatProgram.uniforms.color) {\n gl.uniform3f(splatProgram.uniforms.color, color.r, color.g, color.b);\n }\n blit(dye.write);\n dye.swap();\n }\n\n function correctRadius(radius: number) {\n // Use non-null assertion (canvas can't be null here)\n const aspectRatio = canvas!.width / canvas!.height;\n if (aspectRatio > 1) radius *= aspectRatio;\n return radius;\n }\n\n function updatePointerDownData(\n pointer: Pointer,\n id: number,\n posX: number,\n posY: number,\n ) {\n pointer.id = id;\n pointer.down = true;\n pointer.moved = false;\n pointer.texcoordX = posX / canvas!.width;\n pointer.texcoordY = 1 - posY / canvas!.height;\n pointer.prevTexcoordX = pointer.texcoordX;\n pointer.prevTexcoordY = pointer.texcoordY;\n pointer.deltaX = 0;\n pointer.deltaY = 0;\n pointer.color = generateColor();\n }\n\n function updatePointerMoveData(\n pointer: Pointer,\n posX: number,\n posY: number,\n color: ColorRGB,\n ) {\n pointer.prevTexcoordX = pointer.texcoordX;\n pointer.prevTexcoordY = pointer.texcoordY;\n pointer.texcoordX = posX / canvas!.width;\n pointer.texcoordY = 1 - posY / canvas!.height;\n pointer.deltaX = correctDeltaX(\n pointer.texcoordX - pointer.prevTexcoordX,\n )!;\n pointer.deltaY = correctDeltaY(\n pointer.texcoordY - pointer.prevTexcoordY,\n )!;\n pointer.moved =\n Math.abs(pointer.deltaX) > 0 || Math.abs(pointer.deltaY) > 0;\n pointer.color = color;\n }\n\n function updatePointerUpData(pointer: Pointer) {\n pointer.down = false;\n }\n\n function correctDeltaX(delta: number) {\n const aspectRatio = canvas!.width / canvas!.height;\n if (aspectRatio < 1) delta *= aspectRatio;\n return delta;\n }\n\n function correctDeltaY(delta: number) {\n const aspectRatio = canvas!.width / canvas!.height;\n if (aspectRatio > 1) delta /= aspectRatio;\n return delta;\n }\n\n function generateColor(): ColorRGB {\n const c = HSVtoRGB(Math.random(), 1.0, 1.0);\n c.r *= 0.15;\n c.g *= 0.15;\n c.b *= 0.15;\n return c;\n }\n\n function HSVtoRGB(h: number, s: number, v: number): ColorRGB {\n let r = 0,\n g = 0,\n b = 0;\n const i = Math.floor(h * 6);\n const f = h * 6 - i;\n const p = v * (1 - s);\n const q = v * (1 - f * s);\n const t = v * (1 - (1 - f) * s);\n\n switch (i % 6) {\n case 0:\n r = v;\n g = t;\n b = p;\n break;\n case 1:\n r = q;\n g = v;\n b = p;\n break;\n case 2:\n r = p;\n g = v;\n b = t;\n break;\n case 3:\n r = p;\n g = q;\n b = v;\n break;\n case 4:\n r = t;\n g = p;\n b = v;\n break;\n case 5:\n r = v;\n g = p;\n b = q;\n break;\n }\n return { r, g, b };\n }\n\n function wrap(value: number, min: number, max: number) {\n const range = max - min;\n if (range === 0) return min;\n return ((value - min) % range) + min;\n }\n\n // -------------------- Event Listeners --------------------\n window.addEventListener(\"mousedown\", (e) => {\n const pointer = pointers[0];\n const posX = scaleByPixelRatio(e.clientX);\n const posY = scaleByPixelRatio(e.clientY);\n updatePointerDownData(pointer, -1, posX, posY);\n clickSplat(pointer);\n });\n\n // Start rendering on first mouse move\n function handleFirstMouseMove(e: MouseEvent) {\n const pointer = pointers[0];\n const posX = scaleByPixelRatio(e.clientX);\n const posY = scaleByPixelRatio(e.clientY);\n const color = generateColor();\n updateFrame();\n updatePointerMoveData(pointer, posX, posY, color);\n document.body.removeEventListener(\"mousemove\", handleFirstMouseMove);\n }\n document.body.addEventListener(\"mousemove\", handleFirstMouseMove);\n\n window.addEventListener(\"mousemove\", (e) => {\n const pointer = pointers[0];\n const posX = scaleByPixelRatio(e.clientX);\n const posY = scaleByPixelRatio(e.clientY);\n const color = pointer.color;\n updatePointerMoveData(pointer, posX, posY, color);\n });\n\n // Start rendering on first touch\n function handleFirstTouchStart(e: TouchEvent) {\n const touches = e.targetTouches;\n const pointer = pointers[0];\n for (let i = 0; i < touches.length; i++) {\n const posX = scaleByPixelRatio(touches[i].clientX);\n const posY = scaleByPixelRatio(touches[i].clientY);\n updateFrame();\n updatePointerDownData(pointer, touches[i].identifier, posX, posY);\n }\n document.body.removeEventListener(\"touchstart\", handleFirstTouchStart);\n }\n document.body.addEventListener(\"touchstart\", handleFirstTouchStart);\n\n window.addEventListener(\n \"touchstart\",\n (e) => {\n const touches = e.targetTouches;\n const pointer = pointers[0];\n for (let i = 0; i < touches.length; i++) {\n const posX = scaleByPixelRatio(touches[i].clientX);\n const posY = scaleByPixelRatio(touches[i].clientY);\n updatePointerDownData(pointer, touches[i].identifier, posX, posY);\n }\n },\n false,\n );\n\n window.addEventListener(\n \"touchmove\",\n (e) => {\n const touches = e.targetTouches;\n const pointer = pointers[0];\n for (let i = 0; i < touches.length; i++) {\n const posX = scaleByPixelRatio(touches[i].clientX);\n const posY = scaleByPixelRatio(touches[i].clientY);\n updatePointerMoveData(pointer, posX, posY, pointer.color);\n }\n },\n false,\n );\n\n window.addEventListener(\"touchend\", (e) => {\n const touches = e.changedTouches;\n const pointer = pointers[0];\n for (let i = 0; i < touches.length; i++) {\n updatePointerUpData(pointer);\n }\n });\n // ------------------------------------------------------------\n }, [\n SIM_RESOLUTION,\n DYE_RESOLUTION,\n CAPTURE_RESOLUTION,\n DENSITY_DISSIPATION,\n VELOCITY_DISSIPATION,\n PRESSURE,\n PRESSURE_ITERATIONS,\n CURL,\n SPLAT_RADIUS,\n SPLAT_FORCE,\n SHADING,\n COLOR_UPDATE_SPEED,\n BACK_COLOR,\n TRANSPARENT,\n ]);\n\n return (\n
\n \n
\n );\n}\n", "type": "registry:component" } - ] + ], + "type": "registry:component" } \ No newline at end of file diff --git a/public/r/spotlight-card.json b/public/r/spotlight-card.json index eb9e380..cfa87e0 100644 --- a/public/r/spotlight-card.json +++ b/public/r/spotlight-card.json @@ -1,7 +1,6 @@ { "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "spotlight-card", - "type": "registry:component", "dependencies": [], "devDependencies": [], "registryDependencies": [], @@ -16,5 +15,6 @@ "content": "'use client';\nimport React, { useEffect, useRef, ReactNode } from \"react\";\n\ninterface GlowCardProps {\n children?: ReactNode;\n className?: string;\n glowColor?: \"blue\" | \"purple\" | \"green\" | \"red\" | \"orange\";\n size?: \"sm\" | \"md\" | \"lg\";\n width?: string | number;\n height?: string | number;\n customSize?: boolean; // When true, ignores size prop and uses width/height or className\n}\n\nconst glowColorMap = {\n blue: { base: 220, spread: 200 },\n purple: { base: 280, spread: 300 },\n green: { base: 120, spread: 200 },\n red: { base: 0, spread: 200 },\n orange: { base: 30, spread: 200 },\n};\n\nconst sizeMap = {\n sm: \"w-48 h-64\",\n md: \"w-64 h-80\",\n lg: \"w-80 h-96\",\n};\n\nconst GlowCard: React.FC = ({\n children,\n className = \"\",\n glowColor = \"blue\",\n size = \"md\",\n width,\n height,\n customSize = false,\n}) => {\n const cardRef = useRef(null);\n const innerRef = useRef(null);\n\n useEffect(() => {\n const syncPointer = (e: PointerEvent) => {\n const { clientX: x, clientY: y } = e;\n\n if (cardRef.current) {\n cardRef.current.style.setProperty(\"--x\", x.toFixed(2));\n cardRef.current.style.setProperty(\n \"--xp\",\n (x / window.innerWidth).toFixed(2),\n );\n cardRef.current.style.setProperty(\"--y\", y.toFixed(2));\n cardRef.current.style.setProperty(\n \"--yp\",\n (y / window.innerHeight).toFixed(2),\n );\n }\n };\n\n document.addEventListener(\"pointermove\", syncPointer);\n return () => document.removeEventListener(\"pointermove\", syncPointer);\n }, []);\n\n const { base, spread } = glowColorMap[glowColor];\n\n // Determine sizing\n const getSizeClasses = () => {\n if (customSize) {\n return \"\"; // Let className or inline styles handle sizing\n }\n return sizeMap[size];\n };\n\n const getInlineStyles = (): React.CSSProperties => {\n const baseStyles: React.CSSProperties & {\n [key: string]: string | number | undefined;\n } = {\n \"--base\": base,\n \"--spread\": spread,\n \"--radius\": \"14\",\n \"--border\": \"3\",\n \"--backdrop\": \"hsl(0 0% 60% / 0.12)\",\n \"--backup-border\": \"var(--backdrop)\",\n \"--size\": \"200\",\n \"--outer\": \"1\",\n \"--border-size\": \"calc(var(--border, 2) * 1px)\",\n \"--spotlight-size\": \"calc(var(--size, 150) * 1px)\",\n \"--hue\": \"calc(var(--base) + (var(--xp, 0) * var(--spread, 0)))\",\n backgroundImage: `radial-gradient(\n var(--spotlight-size) var(--spotlight-size) at\n calc(var(--x, 0) * 1px)\n calc(var(--y, 0) * 1px),\n hsl(var(--hue, 210) calc(var(--saturation, 100) * 1%) calc(var(--lightness, 70) * 1%) / var(--bg-spot-opacity, 0.1)), transparent\n )`,\n backgroundColor: \"var(--backdrop, transparent)\",\n backgroundSize:\n \"calc(100% + (2 * var(--border-size))) calc(100% + (2 * var(--border-size)))\",\n backgroundPosition: \"50% 50%\",\n backgroundAttachment: \"fixed\",\n border: \"var(--border-size) solid var(--backup-border)\",\n position: \"relative\",\n touchAction: \"none\",\n };\n\n // Add width and height if provided\n if (width !== undefined) {\n baseStyles.width = typeof width === \"number\" ? `${width}px` : width;\n }\n if (height !== undefined) {\n baseStyles.height = typeof height === \"number\" ? `${height}px` : height;\n }\n\n return baseStyles;\n };\n\n const beforeAfterStyles = `\n [data-glow]::before,\n [data-glow]::after {\n pointer-events: none;\n content: \"\";\n position: absolute;\n inset: calc(var(--border-size) * -1);\n border: var(--border-size) solid transparent;\n border-radius: calc(var(--radius) * 1px);\n background-attachment: fixed;\n background-size: calc(100% + (2 * var(--border-size))) calc(100% + (2 * var(--border-size)));\n background-repeat: no-repeat;\n background-position: 50% 50%;\n mask: linear-gradient(transparent, transparent), linear-gradient(white, white);\n mask-clip: padding-box, border-box;\n mask-composite: intersect;\n }\n \n [data-glow]::before {\n background-image: radial-gradient(\n calc(var(--spotlight-size) * 0.75) calc(var(--spotlight-size) * 0.75) at\n calc(var(--x, 0) * 1px)\n calc(var(--y, 0) * 1px),\n hsl(var(--hue, 210) calc(var(--saturation, 100) * 1%) calc(var(--lightness, 50) * 1%) / var(--border-spot-opacity, 1)), transparent 100%\n );\n filter: brightness(2);\n }\n \n [data-glow]::after {\n background-image: radial-gradient(\n calc(var(--spotlight-size) * 0.5) calc(var(--spotlight-size) * 0.5) at\n calc(var(--x, 0) * 1px)\n calc(var(--y, 0) * 1px),\n hsl(0 100% 100% / var(--border-light-opacity, 1)), transparent 100%\n );\n }\n \n [data-glow] [data-glow] {\n position: absolute;\n inset: 0;\n will-change: filter;\n opacity: var(--outer, 1);\n border-radius: calc(var(--radius) * 1px);\n border-width: calc(var(--border-size) * 20);\n filter: blur(calc(var(--border-size) * 10));\n background: none;\n pointer-events: none;\n border: none;\n }\n \n [data-glow] > [data-glow]::before {\n inset: -10px;\n border-width: 10px;\n }\n `;\n\n return (\n <>\n