Add loading status to all entity links

This commit is contained in:
Sam Becker 2025-02-05 09:15:57 -06:00
parent 8548fee089
commit 95e11c70bc
3 changed files with 78 additions and 75 deletions

View File

@ -9,7 +9,7 @@ import EntityLink, {
export default function PhotoCamera({
camera,
hideAppleIcon,
type = 'icon-first',
type,
badged,
contrast,
prefetch,
@ -36,7 +36,7 @@ export default function PhotoCamera({
size={12}
className="translate-x-[-1px]"
/>}
type={showAppleIcon && isCameraApple ? 'icon-first' : type}
type={type}
badged={badged}
contrast={contrast}
prefetch={prefetch}

View File

@ -1,7 +1,11 @@
'use client';
import { 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';
export interface EntityLinkExternalProps {
type?: LabeledIconType
@ -18,7 +22,7 @@ export default function EntityLink({
type,
badged,
contrast = 'medium',
href,
href = '', // Make link optional for debugging purposes
prefetch,
title,
hoverEntity,
@ -59,43 +63,53 @@ export default function EntityLink({
</>;
return (
<span className={clsx(
'group inline-flex gap-2 w-full',
className,
)}>
<LabeledIcon {...{
icon,
iconWide,
href,
prefetch,
title,
type,
className: clsx(
classForContrast(),
href && !badged && 'hover:text-gray-900 dark:hover:text-gray-100',
),
debug,
}}>
{badged
? <Badge
type="small"
highContrast={contrast === 'high'}
className='translate-y-[-0.5px]'
uppercase
interactive
>
{renderLabel()}
</Badge>
: <span className={clsx(
truncate && 'inline-flex max-w-full [&>*]:truncate',
)}>
{renderLabel()}
</span>}
</LabeledIcon>
{hoverEntity !== undefined &&
<span className="hidden group-hover:inline">
{hoverEntity}
</span>}
<span className="group inline-flex w-full">
<LinkWithStatus
href={href}
className={clsx(
'inline-flex items-center gap-2',
className,
)}
>
{({ isLoading }) => <>
<LabeledIcon {...{
icon,
iconWide,
href,
prefetch,
title,
type,
className: clsx(
classForContrast(),
href && !badged && 'hover:text-gray-900 dark:hover:text-gray-100',
),
debug,
}}>
{badged
? <Badge
type="small"
highContrast={contrast === 'high'}
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]',
)} />}
</>}
</LinkWithStatus>
</span>
);
}

View File

@ -1,7 +1,6 @@
import { ComponentProps, ReactNode } from 'react';
import { ReactNode } from 'react';
import Icon from './Icon';
import { clsx } from 'clsx/lite';
import Link from 'next/link';
export type LabeledIconType =
'icon-first' |
@ -15,8 +14,6 @@ export default function LabeledIcon({
className: classNameProp,
children,
iconWide,
href,
prefetch,
debug,
}: {
icon?: ReactNode,
@ -25,36 +22,28 @@ export default function LabeledIcon({
children: ReactNode,
iconWide?:boolean,
debug?: boolean,
} & Partial<ComponentProps<typeof Link>>) {
const className = clsx(
'inline-flex gap-x-1 md:gap-x-1.5 min-w-0',
classNameProp,
debug && 'border border-green-500 m-[-1px]',
}) {
return (
<span className={ clsx(
'inline-flex gap-x-1 md:gap-x-1.5 min-w-0',
classNameProp,
debug && 'border border-green-500 m-[-1px]',
)}>
{icon && type !== 'text-only' &&
<Icon {...{
className: clsx(type === 'icon-last' && 'order-1'),
wide: iconWide,
debug,
}}>
{icon}
</Icon>}
{children && type !== 'icon-only' &&
<span className={clsx(
'uppercase overflow-hidden',
debug && 'bg-gray-300 dark:bg-gray-700',
)}>
{children}
</span>}
</span>
);
const renderContent = () => <>
{icon && type !== 'text-only' &&
<Icon {...{
className: clsx(type === 'icon-last' && 'order-1'),
wide: iconWide,
debug,
}}>
{icon}
</Icon>}
{children && type !== 'icon-only' &&
<span className={clsx(
'uppercase overflow-hidden',
debug && 'bg-gray-300 dark:bg-gray-700',
)}>
{children}
</span>}
</>;
return href
? <Link {...{ href, prefetch, className }}>
{renderContent()}
</Link>
: <div {...{ className }}>
{renderContent()}
</div>;
}