Add loading indicator to share button

This commit is contained in:
Sam Becker 2023-09-10 16:07:28 -05:00
parent f4e4a2f0a4
commit 2e3dc8a47e
5 changed files with 63 additions and 22 deletions

View File

@ -79,7 +79,7 @@ export default async function PhotoPage({
key={photo.id}
photo={photo}
priority
showShare
prefetchShare
/>]}
/>
<SiteGrid

View File

@ -7,13 +7,19 @@ export default function IconButton({
children,
onClick,
isLoading,
className,
}: {
children: React.ReactNode
onClick?: () => void
isLoading?: boolean
className?: string
}) {
return (
<span className="min-w-[1.1rem]">
<span className={cc(
className,
'relative inline-flex items-center justify-center',
'min-w-[1.2rem] min-h-[1.3rem]',
)}>
{!isLoading
? <span
onClick={onClick}
@ -25,7 +31,7 @@ export default function IconButton({
{children}
</span>
: <span className={cc(
'inline-block translate-x-[2px] translate-y-[1px]',
'inline-block translate-y-[1.5px]',
)}>
<Spinner size={12} />
</span>}

View File

@ -3,17 +3,17 @@ import SiteGrid from '@/components/SiteGrid';
import ImageLarge from '@/components/ImageLarge';
import { cc } from '@/utility/css';
import Link from 'next/link';
import { TbPhotoShare } from 'react-icons/tb';
import { routeForPhoto } from '@/site/routes';
import SharePhotoButton from './SharePhotoButton';
export default function PhotoLarge({
photo,
priority,
showShare,
prefetchShare,
}: {
photo: Photo
priority?: boolean
showShare?: boolean
prefetchShare?: boolean
}) {
const renderMiniGrid = (children: JSX.Element) =>
<div className={cc(
@ -83,21 +83,12 @@ export default function PhotoLarge({
)}>
{photo.takenAtNaiveFormatted}
</div>
{showShare &&
<Link
href={routeForPhoto(photo, true)}
className={cc(
'active:translate-y-[1px]',
'text-gray-500 active:text-gray-600',
'dark:text-gray-400 dark:active:text-gray-300',
)}
prefetch
>
<TbPhotoShare
className="translate-x-[-1.5px]"
size={17}
/>
</Link>}
<div className="-translate-x-1">
<SharePhotoButton
photo={photo}
prefetch={prefetchShare}
/>
</div>
</>)}
</div>}
/>

View File

@ -0,0 +1,44 @@
'use client';
import { useRouter } from 'next/navigation';
import { useEffect, useTransition } from 'react';
import { Photo } from '.';
import { routeForPhoto } from '@/site/routes';
import IconButton from '@/components/IconButton';
import { TbPhotoShare } from 'react-icons/tb';
import { cc } from '@/utility/css';
export default function SharePhotoButton({
photo,
prefetch,
}: {
photo: Photo
prefetch?: boolean
}) {
const router = useRouter();
const shareRoute = routeForPhoto(photo, true);
const [isPending, startTransition] = useTransition();
useEffect(() => {
if (prefetch) {
router.prefetch(shareRoute);
}
}, [prefetch, router, shareRoute]);
return (
<IconButton
onClick={() => startTransition(() =>
router.push(shareRoute))}
isLoading={isPending}
className={cc(
'active:translate-y-[1px]',
'text-gray-500 active:text-gray-600',
'dark:text-gray-400 dark:active:text-gray-300',
)}
>
<TbPhotoShare size={17} />
</IconButton>
);
}

View File

@ -136,7 +136,7 @@ export default function SiteChecklistClient({
<InfoBlock className="my-1.5" padding="tight">
<div className="flex items-center gap-4">
<span>{secret}</span>
<div className="flex items-center gap-1">
<div className="flex items-center gap-0.5">
<IconButton
onClick={() => {
navigator.clipboard.writeText(secret);