Vercel/src/components/primitives/EntityLink.tsx
2025-03-16 17:54:45 -05:00

125 lines
3.0 KiB
TypeScript

'use client';
import { ComponentProps, ReactNode } from 'react';
import LabeledIcon, { LabeledIconType } from './LabeledIcon';
import Badge from '../Badge';
import { clsx } from 'clsx/lite';
import LinkWithStatus from '../LinkWithStatus';
import Spinner from '../Spinner';
import ResponsiveText from './ResponsiveText';
export interface EntityLinkExternalProps {
type?: LabeledIconType
badged?: boolean
contrast?: ComponentProps<typeof Badge>['contrast']
prefetch?: boolean
className?: string
}
export default function EntityLink({
icon,
label,
labelSmall,
iconWide,
type,
badged,
contrast = 'medium',
href = '', // Make link optional for debugging purposes
prefetch,
title,
hoverEntity,
truncate = true,
className,
classNameIcon,
debug,
}: {
icon: ReactNode
label: ReactNode
labelSmall?: ReactNode
iconWide?: boolean
href?: string
prefetch?: boolean
title?: string
hoverEntity?: ReactNode
truncate?: boolean
className?: string
classNameIcon?: string
debug?: boolean
} & EntityLinkExternalProps) {
const classForContrast = () => {
switch (contrast) {
case 'low':
return 'text-dim';
case 'high':
return 'text-main';
case 'frosted':
return 'text-black';
default:
return 'text-medium';
}
};
const renderLabel =
<ResponsiveText shortText={labelSmall}>
{label}
</ResponsiveText>;
return (
<span className={clsx(
'group inline-flex max-w-full overflow-hidden',
className,
)}>
<LinkWithStatus
href={href}
className="inline-flex items-center gap-2 max-w-full"
>
{({ isLoading }) => <>
<LabeledIcon {...{
icon,
iconWide,
href,
prefetch,
title,
type,
className: clsx(
classForContrast(),
href && !badged && 'hover:text-gray-900 dark:hover:text-gray-100',
classNameIcon,
),
classNameIcon: 'text-dim',
debug,
}}>
{badged
? <Badge
type="small"
contrast={contrast}
className='translate-y-[-0.5px]'
uppercase
interactive
>
{renderLabel}
</Badge>
: <span className={clsx(
truncate && 'inline-flex max-w-full *:truncate',
)}>
{renderLabel}
</span>}
</LabeledIcon>
{!isLoading && hoverEntity !== undefined &&
<span className="hidden group-hover:inline text-dim">
{hoverEntity}
</span>}
{isLoading &&
<Spinner
className={clsx(
badged && 'translate-y-[0.5px]',
contrast === 'frosted' && 'text-neutral-500',
)}
color={contrast === 'frosted' ? 'text' : undefined}
/>}
</>}
</LinkWithStatus>
</span>
);
}