Refine tooltip/more menu interactions

This commit is contained in:
Sam Becker 2025-04-24 09:18:27 -05:00
parent f3cd1c2f8c
commit 99a3fb7ad2
7 changed files with 59 additions and 30 deletions

View File

@ -34,10 +34,14 @@ import MoreMenuItem from '@/components/more/MoreMenuItem';
export default function AdminAppMenu({
active,
animateMenuClose,
isOpen,
setIsOpen,
className,
}: {
active?: boolean
animateMenuClose?: boolean
isOpen?: boolean
setIsOpen?: (isOpen: boolean) => void
className?: string
}) {
const {
@ -80,7 +84,7 @@ export default function AdminAppMenu({
annotation: `${uploadsCount}`,
icon: <IconFolder
size={16}
className="translate-x-[1px] translate-y-[0.5px]"
className="translate-x-[1px] translate-y-[1px]"
/>,
href: PATH_ADMIN_UPLOADS,
});
@ -93,13 +97,13 @@ export default function AdminAppMenu({
{photosCountNeedSync}
</span>
<InsightsIndicatorDot
className="inline-block translate-y-[-0.5px]"
className="inline-block translate-y-[1px]"
size="small"
/>
</>,
icon: <IconBroom
size={17}
className="translate-y-[0.5px]"
size={18}
className="translate-y-[-0.5px]"
/>,
href: PATH_ADMIN_PHOTOS_UPDATES,
});
@ -112,7 +116,7 @@ export default function AdminAppMenu({
},
icon: <IconPhoto
size={15}
className="translate-x-[-0.5px] translate-y-[0.5px]"
className="translate-x-[-0.5px] translate-y-[1px]"
/>,
href: PATH_ADMIN_PHOTOS,
});
@ -123,7 +127,7 @@ export default function AdminAppMenu({
annotation: `${tagsCount}`,
icon: <IconTag
size={15}
className="translate-y-[0.5px]"
className="translate-y-[1.5px]"
/>,
href: PATH_ADMIN_TAGS,
});
@ -134,7 +138,7 @@ export default function AdminAppMenu({
annotation: `${recipesCount}`,
icon: <IconRecipe
size={17}
className="translate-x-[-0.5px] translate-y-[0.5px]"
className="translate-x-[-0.5px] translate-y-[1px]"
/>,
href: PATH_ADMIN_RECIPES,
});
@ -147,7 +151,7 @@ export default function AdminAppMenu({
icon: isSelecting
? <IoCloseSharp
size={18}
className="translate-x-[-1px] translate-y-[0.5px]"
className="translate-x-[-1px] translate-y-[1px]"
/>
: <IoMdCheckboxOutline
size={16}
@ -174,7 +178,7 @@ export default function AdminAppMenu({
: 'App Configuration',
icon: <AdminAppInfoIcon
size="small"
className="translate-x-[-0.5px] translate-y-[-0.5px]"
className="translate-x-[-0.5px] translate-y-[0.5px]"
/>,
href: showAppInsightsLink
? PATH_ADMIN_INSIGHTS
@ -189,6 +193,7 @@ export default function AdminAppMenu({
return (
<MoreMenu
{...{ isOpen, setIsOpen }}
header={<div className="flex items-center select-none">
<span className="inline-flex items-center justify-center w-5 mr-2">
{!hasAdminData && isLoadingAdminData
@ -226,7 +231,7 @@ export default function AdminAppMenu({
'border-medium',
className,
)}
buttonClassName={clsx(
classNameButton={clsx(
'p-0!',
'w-full h-full',
'flex items-center justify-center',
@ -237,7 +242,7 @@ export default function AdminAppMenu({
? 'text-black dark:text-white'
: 'text-gray-400 dark:text-gray-600',
)}
buttonClassNameOpen={clsx(
classNameButtonOpen={clsx(
'bg-dim text-main!',
'[&>*>*]:translate-y-[6px]',
!animateMenuClose && '[&>*>*]:duration-300',

View File

@ -48,7 +48,7 @@ export default function AdminPhotoMenu({
label: 'Edit',
icon: <IconEdit
size={15}
className="translate-x-[0.5px] translate-y-[-0.5px]"
className="translate-x-[0.5px]"
/>,
href: pathForAdminPhotoEdit(photo.id),
}];
@ -57,7 +57,7 @@ export default function AdminPhotoMenu({
label: isFav ? 'Unfavorite' : 'Favorite',
icon: <IconFavs
size={14}
className="translate-x-[-1px]"
className="translate-x-[-1px] translate-y-[0.5px]"
highlight={isFav}
/>,
action: () => toggleFavoritePhotoAction(
@ -70,7 +70,7 @@ export default function AdminPhotoMenu({
label: 'Download',
icon: <MdOutlineFileDownload
size={17}
className="translate-x-[-1px] translate-y-[-0.5px]"
className="translate-x-[-1px]"
/>,
href: photo.url,
hrefDownloadName: downloadFileNameForPhoto(photo),
@ -86,7 +86,9 @@ export default function AdminPhotoMenu({
size="small"
/>}
</span>,
icon: <IconGrSync className="translate-x-[-1px]" />,
icon: <IconGrSync
className="translate-x-[-1px] translate-y-[0.5px]"
/>,
action: () => syncPhotoAction(photo.id)
.then(() => revalidatePhoto?.(photo.id)),
});

View File

@ -12,6 +12,7 @@ import { GRID_HOMEPAGE_ENABLED } from './config';
import AdminAppMenu from '@/admin/AdminAppMenu';
import Spinner from '@/components/Spinner';
import clsx from 'clsx/lite';
import { useState } from 'react';
export type SwitcherSelection = 'feed' | 'grid' | 'admin';
@ -28,6 +29,8 @@ export default function ViewSwitcher({
setIsCommandKOpen,
} = useAppState();
const [isAdminMenuOpen, setIsAdminMenuOpen] = useState(false);
const renderItemFeed =
<SwitcherItem
icon={<IconFeed includeTitle={false} />}
@ -70,9 +73,12 @@ export default function ViewSwitcher({
/>}
{isUserSignedIn &&
<SwitcherItem
icon={<AdminAppMenu />}
noPadding
icon={<AdminAppMenu
isOpen={isAdminMenuOpen}
setIsOpen={setIsAdminMenuOpen}
/>}
tooltip={{ content: 'Admin Menu' }}
noPadding
/>}
</Switcher>
<Switcher type="borderless">

View File

@ -30,8 +30,7 @@ export default function SwitcherItem({
}) {
const className = clsx(
'flex items-center justify-center',
'w-[42px] h-full',
'py-0.5 px-1.5',
'w-[42px] 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',
@ -68,7 +67,10 @@ export default function SwitcherItem({
return (
tooltip
? <Tooltip {...tooltip}>
? <Tooltip
{...tooltip}
delayDuration={500}
>
{content}
</Tooltip>
: content

View File

@ -15,12 +15,14 @@ export default function MoreMenu({
icon,
header,
className,
buttonClassName,
buttonClassNameOpen,
classNameButton,
classNameButtonOpen,
ariaLabel,
align = 'end',
// Prevent errant clicks from trigger being too close to menu
sideOffset = 6,
isOpen: isOpenProp,
setIsOpen: setIsOpenProp,
onOpen,
...props
}: {
@ -28,12 +30,17 @@ export default function MoreMenu({
icon?: ReactNode
header?: ReactNode
className?: string
buttonClassName?: string
buttonClassNameOpen?: string
classNameButton?: string
classNameButtonOpen?: string
ariaLabel: string
isOpen?: boolean
setIsOpen?: (isOpen: boolean) => void
onOpen?: () => void
} & ComponentProps<typeof DropdownMenu.Content>){
const [isOpen, setIsOpen] = useState(false);
const [isOpenInternal, setIsOpenInternal] = useState(isOpenProp ?? false);
const isOpen = isOpenProp ?? isOpenInternal;
const setIsOpen = setIsOpenProp ?? setIsOpenInternal;
const dismissMenu = useCallback(() => {
setIsOpen(false);
@ -44,7 +51,10 @@ export default function MoreMenu({
}, [isOpen, onOpen]);
return (
<DropdownMenu.Root open={isOpen} onOpenChange={setIsOpen}>
<DropdownMenu.Root
open={isOpen}
onOpenChange={setIsOpen}
>
<DropdownMenu.Trigger asChild>
<button
className={clsx(
@ -54,8 +64,8 @@ export default function MoreMenu({
'dark:hover:bg-gray-800/75 dark:active:bg-gray-900',
'text-dim',
'outline-none',
buttonClassName,
isOpen && buttonClassNameOpen,
classNameButton,
isOpen && classNameButtonOpen,
)}
aria-label={ariaLabel}
>

View File

@ -51,7 +51,7 @@ export default function MoreMenuItem({
<DropdownMenu.Item
disabled={isLoading}
className={clsx(
'flex items-center h-9',
'flex items-center h-8.5',
'pl-2 pr-3 py-2 rounded-sm',
'select-none hover:outline-hidden',
'hover:bg-gray-100/90 active:bg-gray-200/75',
@ -108,7 +108,8 @@ export default function MoreMenuItem({
isLoading={isLoading || isPending}
hideTextOnMobile={false}
styleAs="link-without-hover"
className="translate-y-[1px]"
className="translate-y-[0.5px] text-sm"
classNameIcon="translate-y-[-0.5px]!"
>
<span>
{labelComplex ?? label}

View File

@ -13,6 +13,7 @@ import Tooltip from '../Tooltip';
export default function LoaderButton({
ref,
children,
classNameIcon,
isLoading,
icon,
spinnerColor,
@ -32,6 +33,7 @@ export default function LoaderButton({
...rest
}: {
ref?: RefObject<HTMLButtonElement | null>
classNameIcon?: string
isLoading?: boolean
icon?: ReactNode
spinnerColor?: SpinnerColor
@ -79,6 +81,7 @@ export default function LoaderButton({
'min-w-[1.25rem] max-h-5',
styleAs === 'button' ? 'translate-y-[-0.5px]' : 'translate-y-[0.5px]',
'inline-flex justify-center shrink-0',
classNameIcon,
)}>
{isLoading
? <Spinner