Fortura/apps/www/public/r/icon-button.json
2025-08-20 04:12:49 -06:00

18 lines
4.5 KiB
JSON

{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "icon-button",
"type": "registry:ui",
"title": "Icon Button",
"description": "An icon button that displays particles when clicked.",
"dependencies": [
"motion"
],
"files": [
{
"path": "registry/buttons/icon/index.tsx",
"content": "'use client';\n\nimport * as React from 'react';\nimport {\n motion,\n AnimatePresence,\n type HTMLMotionProps,\n type Transition,\n} from 'motion/react';\n\nimport { cn } from '@/lib/utils';\n\nconst sizes = {\n default: 'size-8 [&_svg]:size-5',\n sm: 'size-6 [&_svg]:size-4',\n md: 'size-10 [&_svg]:size-6',\n lg: 'size-12 [&_svg]:size-7',\n};\n\ntype IconButtonProps = Omit<HTMLMotionProps<'button'>, 'color'> & {\n icon: React.ElementType;\n active?: boolean;\n className?: string;\n animate?: boolean;\n size?: keyof typeof sizes;\n color?: [number, number, number];\n transition?: Transition;\n};\n\nfunction IconButton({\n icon: Icon,\n className,\n active = false,\n animate = true,\n size = 'default',\n color = [59, 130, 246],\n transition = { type: 'spring', stiffness: 300, damping: 15 },\n ...props\n}: IconButtonProps) {\n return (\n <motion.button\n data-slot=\"icon-button\"\n className={cn(\n `group/icon-button cursor-pointer relative inline-flex size-10 shrink-0 rounded-full hover:bg-[var(--icon-button-color)]/10 active:bg-[var(--icon-button-color)]/20 text-[var(--icon-button-color)]`,\n sizes[size],\n className,\n )}\n whileHover={{ scale: 1.05 }}\n whileTap={{ scale: 0.95 }}\n style={\n {\n '--icon-button-color': `rgb(${color[0]}, ${color[1]}, ${color[2]})`,\n } as React.CSSProperties\n }\n {...props}\n >\n <motion.div\n className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 stroke-muted-foreground group-hover/icon-button:stroke-[var(--icon-button-color)]\"\n aria-hidden=\"true\"\n >\n <Icon\n className={\n active ? 'fill-[var(--icon-button-color)]' : 'fill-transparent'\n }\n />\n </motion.div>\n\n <AnimatePresence mode=\"wait\">\n {active && (\n <motion.div\n className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 text-[var(--icon-button-color)] fill-[var(--icon-button-color)]\"\n aria-hidden=\"true\"\n initial={{ opacity: 0, scale: 0 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0 }}\n transition={transition}\n >\n <Icon />\n </motion.div>\n )}\n </AnimatePresence>\n\n <AnimatePresence>\n {animate && active && (\n <>\n <motion.div\n className=\"absolute inset-0 z-10 rounded-full \"\n style={{\n background: `radial-gradient(circle, rgba(${color[0]}, ${color[1]}, ${color[2]}, 0.4) 0%, rgba(${color[0]}, ${color[1]}, ${color[2]}, 0) 70%)`,\n }}\n initial={{ scale: 1.2, opacity: 0 }}\n animate={{ scale: [1.2, 1.8, 1.2], opacity: [0, 0.3, 0] }}\n transition={{ duration: 1.2, ease: 'easeInOut' }}\n />\n <motion.div\n className=\"absolute inset-0 z-10 rounded-full\"\n style={{\n boxShadow: `0 0 10px 2px rgba(${color[0]}, ${color[1]}, ${color[2]}, 0.6)`,\n }}\n initial={{ scale: 1, opacity: 0 }}\n animate={{ scale: [1, 1.5], opacity: [0.8, 0] }}\n transition={{ duration: 0.8, ease: 'easeOut' }}\n />\n {[...Array(6)].map((_, i) => (\n <motion.div\n key={i}\n className=\"absolute w-1 h-1 rounded-full bg-[var(--icon-button-color)]\"\n initial={{ x: '50%', y: '50%', scale: 0, opacity: 0 }}\n animate={{\n x: `calc(50% + ${Math.cos((i * Math.PI) / 3) * 30}px)`,\n y: `calc(50% + ${Math.sin((i * Math.PI) / 3) * 30}px)`,\n scale: [0, 1, 0],\n opacity: [0, 1, 0],\n }}\n transition={{ duration: 0.8, delay: i * 0.05, ease: 'easeOut' }}\n />\n ))}\n </>\n )}\n </AnimatePresence>\n </motion.button>\n );\n}\n\nexport { IconButton, sizes, type IconButtonProps };\n",
"type": "registry:ui",
"target": "components/animate-ui/buttons/icon.tsx"
}
]
}