Vercel/src/components/switcher/SwitcherItem.tsx
Sam Becker 646f32e642
Rich sort controls (#283)
* Generalize app switcher menus

* Organize sort module

* Build configuration for nav sort control

* Refine sort menu styles

* Upgrade next.js

* Reset custom sort when clicking grid/full a second time

* Light up sort button when overridden
2025-07-15 22:43:36 -05:00

90 lines
2.1 KiB
TypeScript

import { clsx } from 'clsx/lite';
import { SHOULD_PREFETCH_ALL_LINKS } from '@/app/config';
import { ComponentProps, ReactNode, RefObject } from 'react';
import Spinner from '../Spinner';
import LinkWithIconLoader from '../LinkWithIconLoader';
import Tooltip from '../Tooltip';
const WIDTH_CLASS = 'w-[42px]';
const WIDTH_CLASS_NARROW = 'w-[36px]';
export default function SwitcherItem({
icon,
title,
href,
hrefRef,
className: classNameProp,
onClick,
active,
isInteractive = true,
noPadding,
prefetch = SHOULD_PREFETCH_ALL_LINKS,
tooltip,
width = 'normal',
}: {
icon: ReactNode
title?: string
href?: string
hrefRef?: RefObject<HTMLAnchorElement | null>
className?: string
onClick?: () => void
active?: boolean
isInteractive?: boolean
noPadding?: boolean
prefetch?: boolean
tooltip?: ComponentProps<typeof Tooltip>
width?: 'narrow' | 'normal'
}) {
const widthClass = width === 'narrow' ? WIDTH_CLASS_NARROW : WIDTH_CLASS;
const className = clsx(
'flex items-center justify-center',
`${widthClass} h-[28px]`,
isInteractive && 'cursor-pointer',
isInteractive && 'hover:bg-gray-100/60 active:bg-gray-100',
isInteractive && 'dark:hover:bg-gray-900/75 dark:active:bg-gray-900',
active
? 'text-black dark:text-white'
: 'text-gray-400 dark:text-gray-600',
active
? 'hover:text-black dark:hover:text-white'
: 'hover:text-gray-700 dark:hover:text-gray-400',
classNameProp,
);
const renderIcon = () => noPadding
? icon
: <div className={clsx(
'w-[28px] h-[24px]',
'flex items-center justify-center',
)}>
{icon}
</div>;
const content = href
? <LinkWithIconLoader {...{
href,
ref: hrefRef,
title,
onClick,
className,
prefetch,
icon: renderIcon(),
loader: <Spinner />,
}} />
: <div {...{ title, onClick, className }}>
{renderIcon()}
</div>;
return (
tooltip
? <Tooltip
{...tooltip}
classNameTrigger={widthClass}
delayDuration={500}
>
{content}
</Tooltip>
: content
);
};