From 1ae7ea12c364de1b42b790859e4700dd1dd2e008 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Sun, 26 May 2024 14:32:29 -0500 Subject: [PATCH] Add loading indicators to admin photo menu --- src/admin/AdminPhotoMenuClient.tsx | 2 +- src/components/MoreMenu.tsx | 108 ------------------ src/components/ShareButton.tsx | 2 +- src/components/SubmitButtonWithStatus.tsx | 2 +- src/components/more/MoreMenu.tsx | 63 ++++++++++ src/components/more/MoreMenuItem.tsx | 67 +++++++++++ src/components/primitives/LoaderButton.tsx | 27 +++-- .../primitives/PathLoaderButton.tsx | 30 +++-- src/site/SiteChecklistClient.tsx | 4 +- 9 files changed, 172 insertions(+), 133 deletions(-) delete mode 100644 src/components/MoreMenu.tsx create mode 100644 src/components/more/MoreMenu.tsx create mode 100644 src/components/more/MoreMenuItem.tsx diff --git a/src/admin/AdminPhotoMenuClient.tsx b/src/admin/AdminPhotoMenuClient.tsx index ee792f59..4ebdbc5e 100644 --- a/src/admin/AdminPhotoMenuClient.tsx +++ b/src/admin/AdminPhotoMenuClient.tsx @@ -8,7 +8,7 @@ import { Photo, deleteConfirmationTextForPhoto } from '@/photo'; import { isPathFavs, isPhotoFav } from '@/tag'; import { usePathname } from 'next/navigation'; import { BiTrash } from 'react-icons/bi'; -import MoreMenu from '@/components/MoreMenu'; +import MoreMenu from '@/components/more/MoreMenu'; import { useAppState } from '@/state/AppState'; import { RevalidatePhoto } from '@/photo/InfinitePhotoScroll'; diff --git a/src/components/MoreMenu.tsx b/src/components/MoreMenu.tsx deleted file mode 100644 index 244b7cef..00000000 --- a/src/components/MoreMenu.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { ReactNode, useState } from 'react'; -import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; -import { clsx } from 'clsx/lite'; -import { FiMoreHorizontal } from 'react-icons/fi'; -import Link from 'next/link'; - -export default function MoreMenu({ - items, - className, - buttonClassName, -}: { - items: { - label: ReactNode - icon?: ReactNode - href?: string - prefetch?: boolean - action?: () => Promise | void - }[] - className?: string - buttonClassName?: string -}){ - const [isLoading, setIsLoading] = useState(false); - - const renderItemContent = ( - label: ReactNode, - icon?: ReactNode, - ) => -
- {icon} - {label} -
; - - return ( - - - - - - - - {items.map(({ label, icon, href, prefetch = false, action }) => - { - const result = action?.(); - if (result instanceof Promise) { - e.preventDefault(); - setIsLoading(true); - result.finally(() => setIsLoading(false)); - } - }} - > - <> - {href && - - {renderItemContent(label, icon)} - } - {action && - renderItemContent(label, icon)} - - - )} - - - - ); -}; diff --git a/src/components/ShareButton.tsx b/src/components/ShareButton.tsx index 80677e80..25875e55 100644 --- a/src/components/ShareButton.tsx +++ b/src/components/ShareButton.tsx @@ -28,8 +28,8 @@ export default function ShareButton({ spinnerColor="dim" prefetch={prefetch} shouldScroll={shouldScroll} + styleAs="link" shouldReplace - styleAsLink /> ); } diff --git a/src/components/SubmitButtonWithStatus.tsx b/src/components/SubmitButtonWithStatus.tsx index 502abb22..502d714e 100644 --- a/src/components/SubmitButtonWithStatus.tsx +++ b/src/components/SubmitButtonWithStatus.tsx @@ -60,7 +60,7 @@ export default function SubmitButtonWithStatus({ )} icon={icon} spinnerColor={spinnerColor} - styleAsLink={styleAsLink} + styleAs={styleAsLink ? 'link' : undefined} isLoading={pending} {...buttonProps} > diff --git a/src/components/more/MoreMenu.tsx b/src/components/more/MoreMenu.tsx new file mode 100644 index 00000000..51625b4b --- /dev/null +++ b/src/components/more/MoreMenu.tsx @@ -0,0 +1,63 @@ +import { ReactNode } from 'react'; +import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; +import { clsx } from 'clsx/lite'; +import { FiMoreHorizontal } from 'react-icons/fi'; +import MoreMenuItem from './MoreMenuItem'; + +export default function MoreMenu({ + items, + className, + buttonClassName, +}: { + items: { + label: ReactNode + icon?: ReactNode + href?: string + action?: () => Promise | void + }[] + className?: string + buttonClassName?: string +}){ + return ( + + + + + + + + {items.map(({ label, icon, href, action }) => + + )} + + + + ); +}; diff --git a/src/components/more/MoreMenuItem.tsx b/src/components/more/MoreMenuItem.tsx new file mode 100644 index 00000000..2a36b738 --- /dev/null +++ b/src/components/more/MoreMenuItem.tsx @@ -0,0 +1,67 @@ +'use client'; + +import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; +import { clsx } from 'clsx/lite'; +import { ReactNode, useState } from 'react'; +import LoaderButton from '../primitives/LoaderButton'; +import PathLoaderButton from '../primitives/PathLoaderButton'; + +export default function MoreMenuItem({ + label, + icon, + href, + action, +}: { + label: ReactNode + icon?: ReactNode + href?: string + action?: () => Promise | void +}) { + const [isLoading, setIsLoading] = useState(false); + + return ( + + {href && + + {label} + } + {action && + { + if (!href) { + const result = action?.(); + if (result instanceof Promise) { + e.preventDefault(); + setIsLoading(true); + result.finally(() => setIsLoading(false)); + } + } + }} + > + {label} + } + + ); +} diff --git a/src/components/primitives/LoaderButton.tsx b/src/components/primitives/LoaderButton.tsx index 6011fbe7..81460ccb 100644 --- a/src/components/primitives/LoaderButton.tsx +++ b/src/components/primitives/LoaderButton.tsx @@ -5,52 +5,61 @@ import { ButtonHTMLAttributes, ReactNode } from 'react'; export default function LoaderButton(props: { children?: ReactNode isLoading?: boolean - icon?: JSX.Element + icon?: ReactNode spinnerColor?: SpinnerColor - styleAsLink?: boolean + styleAs?: 'button' | 'link' | 'link-without-hover' + hideTextOnMobile?: boolean } & ButtonHTMLAttributes) { const { children, isLoading, icon, spinnerColor, - styleAsLink, + styleAs = 'button', + hideTextOnMobile = true, type = 'button', disabled, className, ...rest } = props; + return (