From f3cd1c2f8c93253fcfc7ba3f9ef76a3de5ef8743 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Wed, 23 Apr 2025 17:58:04 -0500 Subject: [PATCH] Add tooltips to basic view buttons --- src/admin/AdminAppMenu.tsx | 2 +- src/app/ThemeSwitcher.tsx | 6 ++-- src/app/ViewSwitcher.tsx | 23 +++++++++--- src/components/SwitcherItem.tsx | 35 ++++++++++++------- src/components/primitives/KeyCommand.tsx | 29 +++++++++++++++ .../primitives/TooltipPrimitive.tsx | 24 +++++++++++-- 6 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 src/components/primitives/KeyCommand.tsx diff --git a/src/admin/AdminAppMenu.tsx b/src/admin/AdminAppMenu.tsx index c6a09b40..8a19e63d 100644 --- a/src/admin/AdminAppMenu.tsx +++ b/src/admin/AdminAppMenu.tsx @@ -220,7 +220,7 @@ export default function AdminAppMenu({ } align="start" sideOffset={12} - alignOffset={-85} + alignOffset={-93} onOpen={refreshAdminData} className={clsx( 'border-medium', diff --git a/src/app/ThemeSwitcher.tsx b/src/app/ThemeSwitcher.tsx index 861a26bc..6ef0d021 100644 --- a/src/app/ThemeSwitcher.tsx +++ b/src/app/ThemeSwitcher.tsx @@ -22,22 +22,22 @@ export default function ThemeSwitcher () { return ( } onClick={() => setTheme('system')} active={theme === 'system'} + tooltip={{ content: 'System' }} /> } onClick={() => setTheme('light')} active={theme === 'light'} + tooltip={{ content: 'Light Mode' }} /> } onClick={() => setTheme('dark')} active={theme === 'dark'} + tooltip={{ content: 'Dark Mode' }} /> ); diff --git a/src/app/ViewSwitcher.tsx b/src/app/ViewSwitcher.tsx index 21f3322e..1d8db547 100644 --- a/src/app/ViewSwitcher.tsx +++ b/src/app/ViewSwitcher.tsx @@ -30,17 +30,25 @@ export default function ViewSwitcher({ const renderItemFeed = } + icon={} href={PATH_FEED_INFERRED} active={currentSelection === 'feed'} + tooltip={{ + content: 'Feed', + keyCommand: 'F', + }} noPadding />; const renderItemGrid = } + icon={} href={PATH_GRID_INFERRED} active={currentSelection === 'grid'} + tooltip={{ + content: 'Grid', + keyCommand: 'G', + }} noPadding />; @@ -58,18 +66,25 @@ export default function ViewSwitcher({ icon={} isInteractive={false} noPadding + tooltip={{ content: 'Admin Menu' }} />} {isUserSignedIn && } noPadding + tooltip={{ content: 'Admin Menu' }} />} } + title="Search" + icon={} onClick={() => setIsCommandKOpen?.(true)} + tooltip={{ + content: 'Search', + keyCommand: 'K', + keyCommandModifier: '⌘', + }} /> diff --git a/src/components/SwitcherItem.tsx b/src/components/SwitcherItem.tsx index 347a5475..3770cadc 100644 --- a/src/components/SwitcherItem.tsx +++ b/src/components/SwitcherItem.tsx @@ -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 }) { const className = clsx( 'flex items-center justify-center', @@ -50,18 +53,24 @@ export default function SwitcherItem({ {icon} ; + const content = href + ? , + }} /> + :
+ {renderIcon()} +
; + return ( - href - ? , - }} /> - :
- {renderIcon()} -
+ tooltip + ? + {content} + + : content ); }; diff --git a/src/components/primitives/KeyCommand.tsx b/src/components/primitives/KeyCommand.tsx new file mode 100644 index 00000000..290563f0 --- /dev/null +++ b/src/components/primitives/KeyCommand.tsx @@ -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 ( + + {keys.map((key) => ( + + {key} + + ))} + + ); +} diff --git a/src/components/primitives/TooltipPrimitive.tsx b/src/components/primitives/TooltipPrimitive.tsx index 02d19728..ddcd86d5 100644 --- a/src/components/primitives/TooltipPrimitive.tsx +++ b/src/components/primitives/TooltipPrimitive.tsx @@ -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['color'] + keyCommand?: string + keyCommandModifier?: ComponentProps['modifier'] children: ReactNode }) { const refTrigger = useRef(null); @@ -45,8 +53,18 @@ export default function TooltipPrimitive({ classNameTriggerProp, ); + const content = keyCommand + ?
+ {contentProp} + {' '} + + {keyCommand} + +
+ : contentProp; + return ( - + {includeButton