Files
gridpilot.gg/apps/website/ui/Link.tsx
2026-01-19 12:35:16 +01:00

107 lines
2.8 KiB
TypeScript

import React, { ReactNode, forwardRef, AnchorHTMLAttributes } from 'react';
export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
children: ReactNode;
variant?: 'primary' | 'secondary' | 'ghost' | 'inherit';
underline?: 'always' | 'hover' | 'none';
size?: string;
weight?: string;
letterSpacing?: string;
block?: boolean;
hoverColor?: string;
transition?: boolean;
pb?: number;
truncate?: boolean;
hoverTextColor?: string;
display?: string;
alignItems?: string;
gap?: number;
rounded?: string;
bg?: string;
px?: number;
py?: number;
border?: boolean;
borderColor?: string;
shadow?: string;
hoverBorderColor?: string;
}
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(({
children,
variant = 'primary',
underline = 'hover',
size,
weight,
letterSpacing,
block = false,
hoverColor,
transition = true,
pb,
truncate,
hoverTextColor,
display,
alignItems,
gap,
rounded,
bg,
px,
py,
border,
borderColor,
shadow,
hoverBorderColor,
...props
}, ref) => {
const variantClasses = {
primary: 'text-[var(--ui-color-intent-primary)] hover:opacity-80',
secondary: 'text-[var(--ui-color-text-med)] hover:text-[var(--ui-color-text-high)]',
ghost: 'text-[var(--ui-color-text-low)] hover:text-[var(--ui-color-text-high)]',
inherit: 'text-inherit',
};
const underlineClasses = {
always: 'underline',
hover: 'hover:underline',
none: 'no-underline',
};
const classes = [
transition ? 'transition-all duration-150 ease-in-out' : '',
'cursor-pointer',
block ? 'block' : 'inline',
variantClasses[variant],
underlineClasses[underline],
truncate ? 'truncate' : '',
].join(' ');
const style: React.CSSProperties = {
...(size ? { fontSize: size } : {}),
...(weight ? { fontWeight: weight } : {}),
...(letterSpacing ? { letterSpacing } : {}),
...(pb ? { paddingBottom: `${pb * 0.25}rem` } : {}),
...(display ? { display } : {}),
...(alignItems ? { alignItems } : {}),
...(gap ? { gap: `${gap * 0.25}rem` } : {}),
...(rounded ? { borderRadius: rounded === 'full' ? '9999px' : `var(--ui-radius-${rounded})` } : {}),
...(bg ? { backgroundColor: bg.startsWith('bg-') ? undefined : bg } : {}),
...(px ? { paddingLeft: `${px * 0.25}rem`, paddingRight: `${px * 0.25}rem` } : {}),
...(py ? { paddingTop: `${py * 0.25}rem`, paddingBottom: `${py * 0.25}rem` } : {}),
...(border ? { border: '1px solid var(--ui-color-border-default)' } : {}),
...(borderColor ? { borderColor: borderColor.startsWith('border-') ? undefined : borderColor } : {}),
...(shadow ? { boxShadow: shadow.startsWith('shadow-') ? undefined : shadow } : {}),
};
return (
<a
ref={ref}
className={classes}
style={style}
{...props}
>
{children}
</a>
);
});
Link.displayName = 'Link';