Files
zeekay b836586a64 fix: Include all component types in registry build
- 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
2025-10-16 22:33:38 -07:00

15 lines
13 KiB
JSON

{
"name": "3d-grid",
"description": "Interactive 3D grid layout",
"dependencies": [
"motion",
"three"
],
"files": [
{
"name": "3d-grid.tsx",
"content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface Grid3DItem {\n id: string\n content: React.ReactNode\n span?: { x: number; y: number }\n elevation?: number\n}\n\ninterface Grid3DProps extends React.HTMLAttributes<HTMLDivElement> {\n items: Grid3DItem[]\n columns?: number\n rows?: number\n gap?: number\n perspective?: number\n rotateX?: number\n rotateY?: number\n cellHeight?: number\n cellWidth?: number\n isometric?: boolean\n tiltOnHover?: boolean\n staggerAnimation?: boolean\n animationDelay?: number\n elevationOnHover?: boolean\n maxElevation?: number\n className?: string\n}\n\nconst Grid3D = React.forwardRef<HTMLDivElement, Grid3DProps>(\n (\n {\n items,\n columns = 4,\n rows = 3,\n gap = 16,\n perspective = 1000,\n rotateX = 25,\n rotateY = 15,\n cellHeight = 200,\n cellWidth = 200,\n isometric = false,\n tiltOnHover = true,\n staggerAnimation = true,\n animationDelay = 100,\n elevationOnHover = true,\n maxElevation = 50,\n className,\n ...props\n },\n ref\n ) => {\n const gridRef = React.useRef<HTMLDivElement>(null)\n const [hoveredIndex, setHoveredIndex] = React.useState<number | null>(null)\n const [mousePosition, setMousePosition] = React.useState({ x: 0, y: 0 })\n const [isGridHovered, setIsGridHovered] = React.useState(false)\n\n // Calculate grid transforms based on isometric mode\n const gridTransform = React.useMemo(() => {\n if (isometric) {\n return `perspective(${perspective}px) rotateX(45deg) rotateY(45deg)`\n }\n return `perspective(${perspective}px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`\n }, [isometric, perspective, rotateX, rotateY])\n\n // Handle mouse movement for global tilt effect\n const handleMouseMove = React.useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (!tiltOnHover || !gridRef.current) return\n\n const rect = gridRef.current.getBoundingClientRect()\n const centerX = rect.left + rect.width / 2\n const centerY = rect.top + rect.height / 2\n\n const mouseX = (e.clientX - centerX) / (rect.width / 2)\n const mouseY = (e.clientY - centerY) / (rect.height / 2)\n\n setMousePosition({ x: mouseX * 10, y: mouseY * 10 })\n },\n [tiltOnHover]\n )\n\n const handleMouseEnter = React.useCallback(() => {\n setIsGridHovered(true)\n }, [])\n\n const handleMouseLeave = React.useCallback(() => {\n setIsGridHovered(false)\n setMousePosition({ x: 0, y: 0 })\n setHoveredIndex(null)\n }, [])\n\n React.useImperativeHandle(ref, () => gridRef.current!)\n\n const containerStyle: React.CSSProperties = {\n perspective: `${perspective}px`,\n transformStyle: \"preserve-3d\",\n }\n\n const gridStyle: React.CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: `repeat(${columns}, ${cellWidth}px)`,\n gridTemplateRows: `repeat(${rows}, ${cellHeight}px)`,\n gap: `${gap}px`,\n transform:\n tiltOnHover && isGridHovered\n ? `${gridTransform} rotateX(${-mousePosition.y}deg) rotateY(${mousePosition.x}deg)`\n : gridTransform,\n transition: \"transform 0.3s cubic-bezier(0.4, 0, 0.2, 1)\",\n transformStyle: \"preserve-3d\",\n }\n\n // Calculate grid position for each item\n const getGridPosition = (index: number) => {\n const x = index % columns\n const y = Math.floor(index / columns)\n return { x, y }\n }\n\n // Calculate stagger delay for animations\n const getStaggerDelay = (index: number) => {\n if (!staggerAnimation) return 0\n const { x, y } = getGridPosition(index)\n return (x + y) * animationDelay\n }\n\n return (\n <div\n ref={gridRef}\n className={cn(\"w-fit mx-auto\", className)}\n style={containerStyle}\n onMouseMove={handleMouseMove}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n {...props}\n >\n <div style={gridStyle}>\n {items.map((item, index) => {\n const isHovered = hoveredIndex === index\n const { x, y } = getGridPosition(index)\n const staggerDelay = getStaggerDelay(index)\n\n const itemStyle: React.CSSProperties = {\n gridColumn: item.span ? `span ${item.span.x}` : undefined,\n gridRow: item.span ? `span ${item.span.y}` : undefined,\n transform: `translateZ(${\n (item.elevation || 0) +\n (isHovered && elevationOnHover ? maxElevation : 0)\n }px)`,\n transition: \"all 0.3s cubic-bezier(0.4, 0, 0.2, 1)\",\n transformStyle: \"preserve-3d\",\n animationDelay: `${staggerDelay}ms`,\n }\n\n return (\n <div\n key={item.id}\n className={cn(\n \"relative rounded-lg border bg-card text-card-foreground shadow-lg\",\n \"transform-gpu will-change-transform cursor-pointer\",\n \"transition-all duration-300 hover:shadow-xl\",\n staggerAnimation &&\n \"animate-in fade-in slide-in-from-bottom-4\",\n isHovered && \"ring-2 ring-primary ring-offset-2\"\n )}\n style={itemStyle}\n onMouseEnter={() => setHoveredIndex(index)}\n onMouseLeave={() => setHoveredIndex(null)}\n >\n {/* Content container */}\n <div className=\"w-full h-full overflow-hidden rounded-lg\">\n {item.content}\n </div>\n\n {/* Elevation indicator */}\n {(item.elevation || 0) > 0 && (\n <div\n className=\"absolute inset-0 -z-10 rounded-lg bg-black/20 blur-sm\"\n style={{\n transform: `translateY(${(item.elevation || 0) / 2}px) scale(0.95)`,\n }}\n />\n )}\n </div>\n )\n })}\n </div>\n\n {/* Grid guidelines (optional overlay) */}\n {isometric && (\n <div className=\"absolute inset-0 pointer-events-none opacity-20\">\n <div\n className=\"grid border-dashed border-muted-foreground/30\"\n style={{\n gridTemplateColumns: `repeat(${columns}, ${cellWidth}px)`,\n gridTemplateRows: `repeat(${rows}, ${cellHeight}px)`,\n gap: `${gap}px`,\n transform: gridTransform,\n transformStyle: \"preserve-3d\",\n }}\n >\n {Array.from({ length: columns * rows }).map((_, index) => (\n <div\n key={index}\n className=\"border border-dashed border-muted-foreground/20 rounded-lg\"\n />\n ))}\n </div>\n </div>\n )}\n </div>\n )\n }\n)\nGrid3D.displayName = \"Grid3D\"\n\n// 3D Grid Card component optimized for the grid\nconst Grid3DCard = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & {\n title?: string\n description?: string\n image?: string\n badge?: string\n elevation?: number\n }\n>(\n (\n {\n className,\n title,\n description,\n image,\n badge,\n elevation = 0,\n children,\n ...props\n },\n ref\n ) => (\n <div\n ref={ref}\n className={cn(\n \"group relative w-full h-full flex flex-col bg-gradient-to-br from-background to-muted/20\",\n \"border rounded-lg overflow-hidden\",\n className\n )}\n style={{\n transform: `translateZ(${elevation}px)`,\n transformStyle: \"preserve-3d\",\n }}\n {...props}\n >\n {/* Image section */}\n {image && (\n <div className=\"relative h-32 overflow-hidden\">\n <img\n src={image}\n alt={title || \"\"}\n className=\"w-full h-full object-cover transition-transform duration-300 group-hover:scale-110\"\n />\n {badge && (\n <div className=\"absolute top-2 right-2 px-2 py-1 text-xs rounded-full bg-primary text-primary-foreground\">\n {badge}\n </div>\n )}\n </div>\n )}\n\n {/* Content section */}\n <div className=\"flex-1 p-4 flex flex-col justify-between\">\n {title && (\n <h3 className=\"font-semibold text-lg mb-2 line-clamp-2 group-hover:text-primary transition-colors\">\n {title}\n </h3>\n )}\n\n {description && (\n <p className=\"text-sm text-muted-foreground line-clamp-3 mb-4\">\n {description}\n </p>\n )}\n\n {children && <div className=\"mt-auto\">{children}</div>}\n </div>\n\n {/* 3D depth effect */}\n <div\n className=\"absolute inset-0 -z-10 rounded-lg bg-gradient-to-br from-muted/50 to-muted\"\n style={{\n transform: \"translateZ(-2px) scale(0.98)\",\n transformStyle: \"preserve-3d\",\n }}\n />\n </div>\n )\n)\nGrid3DCard.displayName = \"Grid3DCard\"\n\n// Preset grid layouts\nconst Grid3DPreset = {\n Dashboard: React.forwardRef<HTMLDivElement, Omit<Grid3DProps, \"items\">>(\n ({ children, ...props }, ref) => (\n <Grid3D\n ref={ref}\n columns={4}\n rows={3}\n cellWidth={250}\n cellHeight={200}\n gap={20}\n perspective={1200}\n rotateX={20}\n rotateY={10}\n tiltOnHover\n elevationOnHover\n maxElevation={30}\n items={[]}\n {...props}\n />\n )\n ),\n\n Isometric: React.forwardRef<HTMLDivElement, Omit<Grid3DProps, \"items\">>(\n ({ children, ...props }, ref) => (\n <Grid3D\n ref={ref}\n columns={3}\n rows={3}\n cellWidth={180}\n cellHeight={180}\n gap={16}\n isometric\n perspective={1000}\n staggerAnimation\n animationDelay={50}\n items={[]}\n {...props}\n />\n )\n ),\n\n Gallery: React.forwardRef<HTMLDivElement, Omit<Grid3DProps, \"items\">>(\n ({ children, ...props }, ref) => (\n <Grid3D\n ref={ref}\n columns={5}\n rows={2}\n cellWidth={200}\n cellHeight={280}\n gap={24}\n perspective={1500}\n rotateX={15}\n rotateY={5}\n tiltOnHover\n elevationOnHover\n maxElevation={40}\n items={[]}\n {...props}\n />\n )\n ),\n\n Compact: React.forwardRef<HTMLDivElement, Omit<Grid3DProps, \"items\">>(\n ({ children, ...props }, ref) => (\n <Grid3D\n ref={ref}\n columns={6}\n rows={4}\n cellWidth={120}\n cellHeight={120}\n gap={8}\n perspective={800}\n rotateX={30}\n rotateY={20}\n tiltOnHover\n staggerAnimation\n animationDelay={30}\n items={[]}\n {...props}\n />\n )\n ),\n}\n\n// Assign display names\nGrid3DPreset.Dashboard.displayName = \"Grid3DPreset.Dashboard\"\nGrid3DPreset.Isometric.displayName = \"Grid3DPreset.Isometric\"\nGrid3DPreset.Gallery.displayName = \"Grid3DPreset.Gallery\"\nGrid3DPreset.Compact.displayName = \"Grid3DPreset.Compact\"\n\n// Auto-arranging grid that adjusts based on content\nconst Grid3DAuto = React.forwardRef<\n HTMLDivElement,\n Omit<Grid3DProps, \"columns\" | \"rows\"> & {\n minCellWidth?: number\n maxCellWidth?: number\n aspectRatio?: number\n }\n>(\n (\n {\n items,\n minCellWidth = 200,\n maxCellWidth = 300,\n aspectRatio = 1,\n ...props\n },\n ref\n ) => {\n const [dimensions, setDimensions] = React.useState({ columns: 3, rows: 2 })\n\n React.useEffect(() => {\n const itemCount = items.length\n const columns = Math.ceil(Math.sqrt(itemCount))\n const rows = Math.ceil(itemCount / columns)\n setDimensions({ columns, rows })\n }, [items.length])\n\n const cellWidth = Math.min(maxCellWidth, Math.max(minCellWidth, 200))\n const cellHeight = cellWidth / aspectRatio\n\n return (\n <Grid3D\n ref={ref}\n items={items}\n columns={dimensions.columns}\n rows={dimensions.rows}\n cellWidth={cellWidth}\n cellHeight={cellHeight}\n {...props}\n />\n )\n }\n)\nGrid3DAuto.displayName = \"Grid3DAuto\"\n\nexport {\n Grid3D,\n Grid3DCard,\n Grid3DPreset,\n Grid3DAuto,\n type Grid3DItem,\n type Grid3DProps,\n}\n"
}
],
"type": "components:3d"
}