mirror of
https://github.com/hanzoai/shadcn.git
synced 2026-11-03 03:18:52 +00:00
- Updated build-registry.mts to include all component types (ui, ai, 3d, animation, code, etc.) - Fixed missing components issue by processing all components that start with 'components:' - Now properly handles components that only exist in one theme variant - Registry now contains 363 components (up from 117) - AI, 3D, animation, and code components are now accessible via the registry
14 lines
15 KiB
JSON
14 lines
15 KiB
JSON
{
|
|
"name": "animated-background",
|
|
"description": "Animated background patterns and effects",
|
|
"dependencies": [
|
|
"motion"
|
|
],
|
|
"files": [
|
|
{
|
|
"name": "animated-background.tsx",
|
|
"content": "\"use client\"\n\nimport React, { useEffect, useMemo, useRef, useState } from \"react\"\nimport {\n motion,\n useAnimation,\n useMotionValue,\n useTransform,\n} from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/**\n * Custom hook to detect prefers-reduced-motion\n */\nfunction usePrefersReducedMotion(): boolean {\n const [prefersReducedMotion, setPrefersReducedMotion] = useState(false)\n\n useEffect(() => {\n if (typeof window === \"undefined\") return\n\n const mediaQuery = window.matchMedia(\"(prefers-reduced-motion: reduce)\")\n setPrefersReducedMotion(mediaQuery.matches)\n\n const handleChange = (event: MediaQueryListEvent) => {\n setPrefersReducedMotion(event.matches)\n }\n\n mediaQuery.addEventListener(\"change\", handleChange)\n return () => mediaQuery.removeEventListener(\"change\", handleChange)\n }, [])\n\n return prefersReducedMotion\n}\n\nexport interface AnimatedBackgroundProps {\n /**\n * Background animation type\n */\n animation?: \"gradient\" | \"blob\" | \"wave\" | \"mesh\" | \"parallax\" | \"particles\"\n /**\n * Animation speed (0.1 - 2.0)\n */\n speed?: number\n /**\n * Color palette for the animation\n */\n colors?: string[]\n /**\n * Whether animation is paused\n */\n paused?: boolean\n /**\n * Custom CSS class\n */\n className?: string\n /**\n * Custom styling\n */\n style?: React.CSSProperties\n /**\n * Children to render on top\n */\n children?: React.ReactNode\n /**\n * Intensity of the animation (0-1)\n */\n intensity?: number\n /**\n * Whether to blur the background\n */\n blur?: boolean\n /**\n * Blur amount in pixels\n */\n blurAmount?: number\n /**\n * Opacity of the background\n */\n opacity?: number\n /**\n * Number of elements (for blob, particles, etc.)\n */\n elementCount?: number\n /**\n * Custom dimensions\n */\n width?: number | string\n height?: number | string\n /**\n * Whether to cover entire viewport\n */\n fullscreen?: boolean\n /**\n * Parallax layers (for parallax animation)\n */\n parallaxLayers?: Array<{\n speed: number\n color: string\n opacity: number\n }>\n}\n\n/**\n * Gradient shifting background\n */\nfunction GradientBackground({\n colors,\n speed,\n intensity,\n paused,\n}: {\n colors: string[]\n speed: number\n intensity: number\n paused: boolean\n}) {\n const gradientColors =\n colors.length >= 2 ? colors : [\"#ff6b6b\", \"#4ecdc4\", \"#45b7d1\", \"#96ceb4\"]\n\n return (\n <motion.div\n className=\"absolute inset-0\"\n style={{\n background: `linear-gradient(-45deg, ${gradientColors.join(\", \")})`,\n backgroundSize: \"400% 400%\",\n }}\n animate={\n paused\n ? {}\n : {\n x: [\"0%\", \"100%\", \"0%\"],\n }\n }\n transition={{\n duration: 10 / speed,\n repeat: Infinity,\n ease: \"linear\",\n }}\n />\n )\n}\n\n/**\n * Blob animation background\n */\nfunction BlobBackground({\n colors,\n speed,\n elementCount,\n intensity,\n paused,\n}: {\n colors: string[]\n speed: number\n elementCount: number\n intensity: number\n paused: boolean\n}) {\n const blobs = useMemo(\n () =>\n Array.from({ length: elementCount }, (_, i) => ({\n id: i,\n color: colors[i % colors.length],\n size: Math.random() * 200 + 100,\n x: Math.random() * 100,\n y: Math.random() * 100,\n duration: (Math.random() * 10 + 10) / speed,\n })),\n [elementCount, colors, speed]\n )\n\n return (\n <div className=\"absolute inset-0 overflow-hidden\">\n {blobs.map((blob) => (\n <motion.div\n key={blob.id}\n className=\"absolute rounded-full\"\n style={{\n background: `radial-gradient(circle, ${blob.color}40, transparent)`,\n width: blob.size * intensity,\n height: blob.size * intensity,\n filter: \"blur(40px)\",\n }}\n initial={{\n x: `${blob.x}%`,\n y: `${blob.y}%`,\n }}\n animate={\n paused\n ? {}\n : {\n x: [`${blob.x}%`, `${(blob.x + 50) % 100}%`, `${blob.x}%`],\n y: [`${blob.y}%`, `${(blob.y + 30) % 100}%`, `${blob.y}%`],\n scale: [1, 1.2, 1],\n }\n }\n transition={{\n duration: blob.duration,\n repeat: Infinity,\n ease: \"easeInOut\",\n }}\n />\n ))}\n </div>\n )\n}\n\n/**\n * Wave pattern background\n */\nfunction WaveBackground({\n colors,\n speed,\n intensity,\n paused,\n}: {\n colors: string[]\n speed: number\n intensity: number\n paused: boolean\n}) {\n const waveColor = colors[0] || \"#4ecdc4\"\n\n return (\n <div className=\"absolute inset-0 overflow-hidden\">\n {[0, 1, 2].map((index) => (\n <motion.div\n key={index}\n className=\"absolute inset-0\"\n style={{\n background: `radial-gradient(ellipse 100% 50% at center ${50 + index * 20}%, ${waveColor}${Math.round(\n 30 * intensity\n )\n .toString(16)\n .padStart(2, \"0\")}, transparent)`,\n }}\n animate={\n paused\n ? {}\n : {\n y: [index * 10, index * 10 + 20 * intensity, index * 10],\n }\n }\n transition={{\n duration: (3 + index) / speed,\n repeat: Infinity,\n ease: \"easeInOut\",\n }}\n />\n ))}\n </div>\n )\n}\n\n/**\n * Mesh gradient background\n */\nfunction MeshBackground({\n colors,\n speed,\n intensity,\n paused,\n}: {\n colors: string[]\n speed: number\n intensity: number\n paused: boolean\n}) {\n const meshColors =\n colors.length >= 4\n ? colors.slice(0, 4)\n : [\"#ff6b6b\", \"#4ecdc4\", \"#45b7d1\", \"#96ceb4\"]\n\n return (\n <div className=\"absolute inset-0 overflow-hidden\">\n {meshColors.map((color, index) => (\n <motion.div\n key={index}\n className=\"absolute rounded-full\"\n style={{\n background: `radial-gradient(circle, ${color}60, transparent)`,\n width: `${60 + index * 20}%`,\n height: `${60 + index * 20}%`,\n filter: \"blur(60px)\",\n mixBlendMode: \"multiply\",\n }}\n initial={{\n x: `${25 + index * 15}%`,\n y: `${25 + index * 15}%`,\n }}\n animate={\n paused\n ? {}\n : {\n x: [\n `${25 + index * 15}%`,\n `${35 + index * 15}%`,\n `${25 + index * 15}%`,\n ],\n y: [\n `${25 + index * 15}%`,\n `${15 + index * 15}%`,\n `${25 + index * 15}%`,\n ],\n rotate: [0, 180, 360],\n }\n }\n transition={{\n duration: (8 + index * 2) / speed,\n repeat: Infinity,\n ease: \"easeInOut\",\n }}\n />\n ))}\n </div>\n )\n}\n\n/**\n * Parallax layers background\n */\nfunction ParallaxBackground({\n layers,\n speed,\n paused,\n}: {\n layers: Array<{ speed: number; color: string; opacity: number }>\n speed: number\n paused: boolean\n}) {\n const mouseX = useMotionValue(0)\n const mouseY = useMotionValue(0)\n\n useEffect(() => {\n const handleMouseMove = (e: MouseEvent) => {\n const { clientX, clientY } = e\n const { innerWidth, innerHeight } = window\n mouseX.set((clientX / innerWidth - 0.5) * 100)\n mouseY.set((clientY / innerHeight - 0.5) * 100)\n }\n\n window.addEventListener(\"mousemove\", handleMouseMove)\n return () => window.removeEventListener(\"mousemove\", handleMouseMove)\n }, [mouseX, mouseY])\n\n return (\n <div className=\"absolute inset-0 overflow-hidden\">\n {layers.map((layer, index) => {\n const x = useTransform(\n mouseX,\n [-50, 50],\n [-layer.speed * 10, layer.speed * 10]\n )\n const y = useTransform(\n mouseY,\n [-50, 50],\n [-layer.speed * 10, layer.speed * 10]\n )\n\n return (\n <motion.div\n key={index}\n className=\"absolute inset-0\"\n style={{\n background: `radial-gradient(circle, ${layer.color}, transparent)`,\n opacity: layer.opacity,\n x: paused ? 0 : x,\n y: paused ? 0 : y,\n }}\n />\n )\n })}\n </div>\n )\n}\n\n/**\n * Floating particles background\n */\nfunction ParticlesBackground({\n colors,\n speed,\n elementCount,\n intensity,\n paused,\n}: {\n colors: string[]\n speed: number\n elementCount: number\n intensity: number\n paused: boolean\n}) {\n const particles = useMemo(\n () =>\n Array.from({ length: elementCount }, (_, i) => ({\n id: i,\n color: colors[i % colors.length],\n size: Math.random() * 4 + 2,\n x: Math.random() * 100,\n y: Math.random() * 100,\n duration: (Math.random() * 20 + 20) / speed,\n delay: Math.random() * 5,\n })),\n [elementCount, colors, speed]\n )\n\n return (\n <div className=\"absolute inset-0 overflow-hidden\">\n {particles.map((particle) => (\n <motion.div\n key={particle.id}\n className=\"absolute rounded-full\"\n style={{\n backgroundColor: particle.color,\n width: particle.size * intensity,\n height: particle.size * intensity,\n opacity: 0.6,\n }}\n initial={{\n x: `${particle.x}%`,\n y: `${particle.y}%`,\n }}\n animate={\n paused\n ? {}\n : {\n y: [`${particle.y}%`, `${particle.y - 100}%`],\n opacity: [0, 0.6, 0],\n }\n }\n transition={{\n duration: particle.duration,\n repeat: Infinity,\n delay: particle.delay,\n ease: \"linear\",\n }}\n />\n ))}\n </div>\n )\n}\n\n/**\n * Animated background component with multiple animation types\n */\nexport function AnimatedBackground({\n animation = \"gradient\",\n speed = 1,\n colors = [\"#ff6b6b\", \"#4ecdc4\", \"#45b7d1\", \"#96ceb4\", \"#ffeaa7\"],\n paused = false,\n className,\n style,\n children,\n intensity = 1,\n blur = false,\n blurAmount = 20,\n opacity = 1,\n elementCount = 5,\n width = \"100%\",\n height = \"100%\",\n fullscreen = false,\n parallaxLayers = [\n { speed: 0.5, color: \"#ff6b6b50\", opacity: 0.3 },\n { speed: 1, color: \"#4ecdc450\", opacity: 0.4 },\n { speed: 1.5, color: \"#45b7d150\", opacity: 0.3 },\n ],\n}: AnimatedBackgroundProps) {\n const prefersReducedMotion = usePrefersReducedMotion()\n const isAnimationPaused = paused || prefersReducedMotion\n\n const containerStyle = useMemo(\n () => ({\n width: fullscreen ? \"100vw\" : width,\n height: fullscreen ? \"100vh\" : height,\n opacity,\n filter: blur ? `blur(${blurAmount}px)` : undefined,\n ...style,\n }),\n [fullscreen, width, height, opacity, blur, blurAmount, style]\n )\n\n const renderAnimation = () => {\n const props = { colors, speed, intensity, paused: isAnimationPaused }\n\n switch (animation) {\n case \"blob\":\n return <BlobBackground {...props} elementCount={elementCount} />\n case \"wave\":\n return <WaveBackground {...props} />\n case \"mesh\":\n return <MeshBackground {...props} />\n case \"parallax\":\n return (\n <ParallaxBackground\n layers={parallaxLayers}\n speed={speed}\n paused={isAnimationPaused}\n />\n )\n case \"particles\":\n return <ParticlesBackground {...props} elementCount={elementCount} />\n default:\n return <GradientBackground {...props} />\n }\n }\n\n return (\n <div\n className={cn(\n \"relative overflow-hidden\",\n fullscreen && \"fixed inset-0 z-0\",\n className\n )}\n style={containerStyle}\n >\n {renderAnimation()}\n\n {children && (\n <div className=\"relative z-10 h-full w-full\">{children}</div>\n )}\n </div>\n )\n}\n\n/**\n * Preset animated background variations\n */\nexport const AnimatedBackgroundPresets = {\n /**\n * Calm gradient flow\n */\n CalmGradient: (\n props: Omit<AnimatedBackgroundProps, \"animation\" | \"colors\" | \"speed\">\n ) => (\n <AnimatedBackground\n animation=\"gradient\"\n colors={[\"#667eea\", \"#764ba2\", \"#f093fb\", \"#f5576c\"]}\n speed={0.5}\n {...props}\n />\n ),\n\n /**\n * Ocean waves\n */\n OceanWaves: (\n props: Omit<AnimatedBackgroundProps, \"animation\" | \"colors\">\n ) => (\n <AnimatedBackground\n animation=\"wave\"\n colors={[\"#0093E9\", \"#80D0C7\"]}\n {...props}\n />\n ),\n\n /**\n * Floating bubbles\n */\n FloatingBubbles: (\n props: Omit<\n AnimatedBackgroundProps,\n \"animation\" | \"colors\" | \"elementCount\"\n >\n ) => (\n <AnimatedBackground\n animation=\"blob\"\n colors={[\"#667eea\", \"#764ba2\", \"#f093fb\"]}\n elementCount={8}\n {...props}\n />\n ),\n\n /**\n * Cosmic mesh\n */\n CosmicMesh: (\n props: Omit<AnimatedBackgroundProps, \"animation\" | \"colors\">\n ) => (\n <AnimatedBackground\n animation=\"mesh\"\n colors={[\"#667eea\", \"#764ba2\", \"#f093fb\", \"#f5576c\"]}\n {...props}\n />\n ),\n\n /**\n * Starfield particles\n */\n Starfield: (\n props: Omit<\n AnimatedBackgroundProps,\n \"animation\" | \"colors\" | \"elementCount\"\n >\n ) => (\n <AnimatedBackground\n animation=\"particles\"\n colors={[\"#ffffff\", \"#f0f0f0\", \"#e0e0e0\"]}\n elementCount={50}\n intensity={0.5}\n {...props}\n />\n ),\n\n /**\n * Aurora parallax\n */\n Aurora: (\n props: Omit<AnimatedBackgroundProps, \"animation\" | \"parallaxLayers\">\n ) => (\n <AnimatedBackground\n animation=\"parallax\"\n parallaxLayers={[\n { speed: 0.3, color: \"#00ff8850\", opacity: 0.4 },\n { speed: 0.6, color: \"#0080ff50\", opacity: 0.3 },\n { speed: 0.9, color: \"#8000ff50\", opacity: 0.3 },\n { speed: 1.2, color: \"#ff008050\", opacity: 0.2 },\n ]}\n {...props}\n />\n ),\n}\n\nexport default AnimatedBackground\n"
|
|
}
|
|
],
|
|
"type": "components:animation"
|
|
} |