Add tooltips to basic view buttons

This commit is contained in:
Sam Becker 2025-04-23 17:58:04 -05:00
parent 9cd5a0f74f
commit f3cd1c2f8c
6 changed files with 95 additions and 24 deletions

View File

@ -220,7 +220,7 @@ export default function AdminAppMenu({
</div>}
align="start"
sideOffset={12}
alignOffset={-85}
alignOffset={-93}
onOpen={refreshAdminData}
className={clsx(
'border-medium',

View File

@ -22,22 +22,22 @@ export default function ThemeSwitcher () {
return (
<Switcher>
<SwitcherItem
title="System"
icon={<BiDesktop size={16} />}
onClick={() => setTheme('system')}
active={theme === 'system'}
tooltip={{ content: 'System' }}
/>
<SwitcherItem
title="Light"
icon={<BiSun size={18} />}
onClick={() => setTheme('light')}
active={theme === 'light'}
tooltip={{ content: 'Light Mode' }}
/>
<SwitcherItem
title="Dark"
icon={<BiMoon size={16} />}
onClick={() => setTheme('dark')}
active={theme === 'dark'}
tooltip={{ content: 'Dark Mode' }}
/>
</Switcher>
);

View File

@ -30,17 +30,25 @@ export default function ViewSwitcher({
const renderItemFeed =
<SwitcherItem
icon={<IconFeed />}
icon={<IconFeed includeTitle={false} />}
href={PATH_FEED_INFERRED}
active={currentSelection === 'feed'}
tooltip={{
content: 'Feed',
keyCommand: 'F',
}}
noPadding
/>;
const renderItemGrid =
<SwitcherItem
icon={<IconGrid />}
icon={<IconGrid includeTitle={false} />}
href={PATH_GRID_INFERRED}
active={currentSelection === 'grid'}
tooltip={{
content: 'Grid',
keyCommand: 'G',
}}
noPadding
/>;
@ -58,18 +66,25 @@ export default function ViewSwitcher({
icon={<Spinner />}
isInteractive={false}
noPadding
tooltip={{ content: 'Admin Menu' }}
/>}
{isUserSignedIn &&
<SwitcherItem
className="p-0!"
icon={<AdminAppMenu />}
noPadding
tooltip={{ content: 'Admin Menu' }}
/>}
</Switcher>
<Switcher type="borderless">
<SwitcherItem
icon={<IconSearch />}
title="Search"
icon={<IconSearch includeTitle={false} />}
onClick={() => setIsCommandKOpen?.(true)}
tooltip={{
content: 'Search',
keyCommand: 'K',
keyCommandModifier: '⌘',
}}
/>
</Switcher>
</div>

View File

@ -1,8 +1,9 @@
import { clsx } from 'clsx/lite';
import { SHOULD_PREFETCH_ALL_LINKS } from '@/app/config';
import { ReactNode } from 'react';
import { ComponentProps, ReactNode } from 'react';
import Spinner from './Spinner';
import LinkWithIconLoader from './LinkWithIconLoader';
import Tooltip from './Tooltip';
export default function SwitcherItem({
icon,
@ -14,6 +15,7 @@ export default function SwitcherItem({
isInteractive = true,
noPadding,
prefetch = SHOULD_PREFETCH_ALL_LINKS,
tooltip,
}: {
icon: ReactNode
title?: string
@ -24,6 +26,7 @@ export default function SwitcherItem({
isInteractive?: boolean
noPadding?: boolean
prefetch?: boolean
tooltip?: ComponentProps<typeof Tooltip>
}) {
const className = clsx(
'flex items-center justify-center',
@ -50,18 +53,24 @@ export default function SwitcherItem({
{icon}
</div>;
const content = href
? <LinkWithIconLoader {...{
href,
title,
className,
prefetch,
icon: renderIcon(),
loader: <Spinner />,
}} />
: <div {...{ title, onClick, className }}>
{renderIcon()}
</div>;
return (
href
? <LinkWithIconLoader {...{
title,
href,
className,
prefetch,
icon: renderIcon(),
loader: <Spinner />,
}} />
: <div {...{ title, onClick, className }}>
{renderIcon()}
</div>
tooltip
? <Tooltip {...tooltip}>
{content}
</Tooltip>
: content
);
};

View File

@ -0,0 +1,29 @@
import clsx from 'clsx/lite';
import { useMemo } from 'react';
export default function KeyCommand({
children,
modifier,
className,
}: {
children: string
modifier?: '⌘' | '⌥' | '⇧' | '⌃' | '⏎'
className?: string
}) {
const keys = useMemo(() =>
modifier ? [modifier, ...children] : [...children],
[modifier, children]);
return (
<span className={clsx('inline-flex items-center gap-0.5', className)}>
{keys.map((key) => (
<span
key={key}
className="text-gray-600 bg-gray-200/75 px-1 rounded-sm"
>
{key}
</span>
))}
</span>
);
}

View File

@ -6,22 +6,30 @@ import MenuSurface from './MenuSurface';
import useSupportsHover from '@/utility/useSupportsHover';
import clsx from 'clsx/lite';
import useClickInsideOutside from '@/utility/useClickInsideOutside';
import KeyCommand from './KeyCommand';
export default function TooltipPrimitive({
content,
content: contentProp,
className,
classNameTrigger: classNameTriggerProp,
sideOffset = 10,
delayDuration = 100,
skipDelayDuration = 300,
supportMobile,
color,
keyCommand,
keyCommandModifier,
children,
}: {
content?: ReactNode
className?: string
classNameTrigger?: string
sideOffset?: number
delayDuration?: number
skipDelayDuration?: number
supportMobile?: boolean
color?: ComponentProps<typeof MenuSurface>['color']
keyCommand?: string
keyCommandModifier?: ComponentProps<typeof KeyCommand>['modifier']
children: ReactNode
}) {
const refTrigger = useRef<HTMLButtonElement>(null);
@ -45,8 +53,18 @@ export default function TooltipPrimitive({
classNameTriggerProp,
);
const content = keyCommand
? <div className="-mr-0.5">
{contentProp}
{' '}
<KeyCommand {...{ modifier: keyCommandModifier }}>
{keyCommand}
</KeyCommand>
</div>
: contentProp;
return (
<Tooltip.Provider delayDuration={100}>
<Tooltip.Provider {...{ delayDuration, skipDelayDuration }}>
<Tooltip.Root open={includeButton ? isOpen : undefined}>
<Tooltip.Trigger asChild>
{includeButton