Files
gridpilot.gg/apps/website/ui/Icon.tsx
2026-01-18 17:55:04 +01:00

81 lines
2.1 KiB
TypeScript

import React from 'react';
import { LucideIcon } from 'lucide-react';
import { Box, BoxProps } from './primitives/Box';
export interface IconProps extends Omit<BoxProps<'div'>, 'children'> {
icon: LucideIcon | React.ReactNode;
size?: number | string;
color?: string;
strokeWidth?: number;
animate?: string;
transition?: boolean;
groupHoverTextColor?: string;
groupHoverScale?: boolean;
}
export function Icon({
icon: IconProp,
size = 4,
color,
className = '',
style,
animate,
transition,
groupHoverTextColor,
groupHoverScale,
...props
}: IconProps) {
const sizeMap: Record<string | number, string> = {
3: 'w-3 h-3',
3.5: 'w-3.5 h-3.5',
4: 'w-4 h-4',
5: 'w-5 h-5',
6: 'w-6 h-6',
7: 'w-7 h-7',
8: 'w-8 h-8',
10: 'w-10 h-10',
12: 'w-12 h-12',
16: 'w-16 h-16',
'full': 'w-full h-full'
};
const sizeClass = sizeMap[size] || 'w-4 h-4';
// If color starts with 'text-', it's a tailwind class, so pass it as color prop to Box
const isTailwindColor = typeof color === 'string' && color.startsWith('text-');
const combinedStyle = color && !isTailwindColor ? { color, ...style } : style;
const boxColor = isTailwindColor ? color : undefined;
const classes = [
sizeClass,
animate === 'spin' ? 'animate-spin' : '',
transition ? 'transition-all duration-150' : '',
groupHoverTextColor ? `group-hover:text-${groupHoverTextColor}` : '',
groupHoverScale ? 'group-hover:scale-110 transition-transform' : '',
className
].filter(Boolean).join(' ');
const renderIcon = () => {
if (!IconProp) return null;
if (typeof IconProp === 'function' || (typeof IconProp === 'object' && 'render' in IconProp)) {
const LucideIconComponent = IconProp as LucideIcon;
return <LucideIconComponent size="100%" strokeWidth={props.strokeWidth} />;
}
return IconProp;
};
return (
<Box
className={classes}
style={combinedStyle}
color={boxColor}
display="inline-flex"
alignItems="center"
justifyContent="center"
{...props}
>
{renderIcon()}
</Box>
);
}