Add loading indicator to share button
This commit is contained in:
parent
f4e4a2f0a4
commit
2e3dc8a47e
@ -79,7 +79,7 @@ export default async function PhotoPage({
|
|||||||
key={photo.id}
|
key={photo.id}
|
||||||
photo={photo}
|
photo={photo}
|
||||||
priority
|
priority
|
||||||
showShare
|
prefetchShare
|
||||||
/>]}
|
/>]}
|
||||||
/>
|
/>
|
||||||
<SiteGrid
|
<SiteGrid
|
||||||
|
|||||||
@ -7,13 +7,19 @@ export default function IconButton({
|
|||||||
children,
|
children,
|
||||||
onClick,
|
onClick,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
className,
|
||||||
}: {
|
}: {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
isLoading?: boolean
|
isLoading?: boolean
|
||||||
|
className?: string
|
||||||
}) {
|
}) {
|
||||||
return (
|
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
|
{!isLoading
|
||||||
? <span
|
? <span
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
@ -25,7 +31,7 @@ export default function IconButton({
|
|||||||
{children}
|
{children}
|
||||||
</span>
|
</span>
|
||||||
: <span className={cc(
|
: <span className={cc(
|
||||||
'inline-block translate-x-[2px] translate-y-[1px]',
|
'inline-block translate-y-[1.5px]',
|
||||||
)}>
|
)}>
|
||||||
<Spinner size={12} />
|
<Spinner size={12} />
|
||||||
</span>}
|
</span>}
|
||||||
|
|||||||
@ -3,17 +3,17 @@ import SiteGrid from '@/components/SiteGrid';
|
|||||||
import ImageLarge from '@/components/ImageLarge';
|
import ImageLarge from '@/components/ImageLarge';
|
||||||
import { cc } from '@/utility/css';
|
import { cc } from '@/utility/css';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { TbPhotoShare } from 'react-icons/tb';
|
|
||||||
import { routeForPhoto } from '@/site/routes';
|
import { routeForPhoto } from '@/site/routes';
|
||||||
|
import SharePhotoButton from './SharePhotoButton';
|
||||||
|
|
||||||
export default function PhotoLarge({
|
export default function PhotoLarge({
|
||||||
photo,
|
photo,
|
||||||
priority,
|
priority,
|
||||||
showShare,
|
prefetchShare,
|
||||||
}: {
|
}: {
|
||||||
photo: Photo
|
photo: Photo
|
||||||
priority?: boolean
|
priority?: boolean
|
||||||
showShare?: boolean
|
prefetchShare?: boolean
|
||||||
}) {
|
}) {
|
||||||
const renderMiniGrid = (children: JSX.Element) =>
|
const renderMiniGrid = (children: JSX.Element) =>
|
||||||
<div className={cc(
|
<div className={cc(
|
||||||
@ -83,21 +83,12 @@ export default function PhotoLarge({
|
|||||||
)}>
|
)}>
|
||||||
{photo.takenAtNaiveFormatted}
|
{photo.takenAtNaiveFormatted}
|
||||||
</div>
|
</div>
|
||||||
{showShare &&
|
<div className="-translate-x-1">
|
||||||
<Link
|
<SharePhotoButton
|
||||||
href={routeForPhoto(photo, true)}
|
photo={photo}
|
||||||
className={cc(
|
prefetch={prefetchShare}
|
||||||
'active:translate-y-[1px]',
|
/>
|
||||||
'text-gray-500 active:text-gray-600',
|
</div>
|
||||||
'dark:text-gray-400 dark:active:text-gray-300',
|
|
||||||
)}
|
|
||||||
prefetch
|
|
||||||
>
|
|
||||||
<TbPhotoShare
|
|
||||||
className="translate-x-[-1.5px]"
|
|
||||||
size={17}
|
|
||||||
/>
|
|
||||||
</Link>}
|
|
||||||
</>)}
|
</>)}
|
||||||
</div>}
|
</div>}
|
||||||
/>
|
/>
|
||||||
|
|||||||
44
src/photo/SharePhotoButton.tsx
Normal file
44
src/photo/SharePhotoButton.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -136,7 +136,7 @@ export default function SiteChecklistClient({
|
|||||||
<InfoBlock className="my-1.5" padding="tight">
|
<InfoBlock className="my-1.5" padding="tight">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<span>{secret}</span>
|
<span>{secret}</span>
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-0.5">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(secret);
|
navigator.clipboard.writeText(secret);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user