Refactor button loader behavior

This commit is contained in:
Sam Becker 2023-10-21 16:27:07 -05:00
parent eae78d2194
commit 655f91b336
6 changed files with 43 additions and 53 deletions

View File

@ -21,21 +21,26 @@ export default function IconButton({
return ( return (
<span className={cc( <span className={cc(
className, className,
'relative inline-flex items-center justify-center', 'relative inline-flex items-center',
'min-w-[1.2rem] min-h-[1.3rem]', 'w-[1rem] h-[1.1rem]',
)}> )}>
{!isLoading {!isLoading
? <span ? <button
onClick={onClick} onClick={onClick}
className={cc( className={cc(
'inline-flex items-center justify-center',
'p-0 border-none shadow-none',
'active:bg-transparent bg-transparent',
'translate-x-[-1px]',
onClick !== undefined && 'cursor-pointer', onClick !== undefined && 'cursor-pointer',
'active:opacity-50', 'active:opacity-50',
)} )}
> >
{icon} {icon}
</span> </button>
: <span className={cc( : <span className={cc(
'inline-block translate-y-[1.5px]', 'inline-flex items-center justify-center',
'h-full w-full',
)}> )}>
<Spinner <Spinner
color={spinnerColor} color={spinnerColor}

View File

@ -4,6 +4,7 @@ import { useRouter } from 'next/navigation';
import IconButton from './IconButton'; import IconButton from './IconButton';
import { useEffect, useState, useTransition } from 'react'; import { useEffect, useState, useTransition } from 'react';
import { cc } from '@/utility/css'; import { cc } from '@/utility/css';
import { SpinnerColor } from './Spinner';
export default function IconPathButton({ export default function IconPathButton({
icon, icon,
@ -12,6 +13,7 @@ export default function IconPathButton({
loaderDelay = 250, loaderDelay = 250,
shouldScroll = true, shouldScroll = true,
shouldReplace, shouldReplace,
spinnerColor,
}: { }: {
icon: JSX.Element icon: JSX.Element
path: string path: string
@ -19,6 +21,7 @@ export default function IconPathButton({
loaderDelay?: number loaderDelay?: number
shouldScroll?: boolean shouldScroll?: boolean
shouldReplace?: boolean shouldReplace?: boolean
spinnerColor?: SpinnerColor
}) { }) {
const router = useRouter(); const router = useRouter();
@ -60,7 +63,7 @@ export default function IconPathButton({
'text-gray-500 active:text-gray-600', 'text-gray-500 active:text-gray-600',
'dark:text-gray-400 dark:active:text-gray-300', 'dark:text-gray-400 dark:active:text-gray-300',
)} )}
spinnerColor="text" spinnerColor={spinnerColor ?? 'text'}
/> />
); );
} }

View File

@ -21,6 +21,7 @@ export default function ShareButton({
prefetch, prefetch,
shouldScroll, shouldScroll,
shouldReplace: true, shouldReplace: true,
spinnerColor: 'dim',
}} /> }} />
); );
} }

View File

@ -1,25 +1,33 @@
import { cc } from '@/utility/css';
const SIZE_DEFAULT = 12; const SIZE_DEFAULT = 12;
export type SpinnerColor = 'text' | 'light-gray'; export type SpinnerColor = 'text' | 'dim' | 'light-gray';
export default function Spinner({ export default function Spinner({
size = SIZE_DEFAULT, size = SIZE_DEFAULT,
color = 'light-gray', color = 'light-gray',
className,
}: { }: {
size?: number size?: number
color?: SpinnerColor color?: SpinnerColor
className?: string
}) { }) {
return ( return (
<span {...{ <span
...color === 'light-gray' && { className={cc(
className: 'text-gray-300 dark:text-gray-600', className,
}, color === 'light-gray' &&
style: { 'text-gray-300 dark:text-gray-600',
color === 'dim' &&
'text-dim',
)}
style={{
display: 'inline-flex', display: 'inline-flex',
width: size, width: size,
height: size, height: size,
}, }}
}}> >
<svg <svg
width={size} width={size}
height={size} height={size}

View File

@ -31,12 +31,12 @@ export default function PhotoLarge({
const camera = cameraFromPhoto(photo); const camera = cameraFromPhoto(photo);
const renderMiniGrid = (children: JSX.Element) => const renderMiniGrid = (children: JSX.Element, rightPadding = true) =>
<div className={cc( <div className={cc(
'flex gap-y-4', 'flex gap-y-4',
'flex-col sm:flex-row md:flex-col', 'flex-col sm:flex-row md:flex-col',
'[&>*]:sm:flex-grow', '[&>*]:sm:flex-grow',
'pr-2', rightPadding && 'pr-2',
)}> )}>
{children} {children}
</div>; </div>;
@ -114,19 +114,17 @@ export default function PhotoLarge({
)}> )}>
{photo.takenAtNaiveFormatted} {photo.takenAtNaiveFormatted}
</div> </div>
<div className="-translate-x-0.5"> <ShareButton
<ShareButton path={pathForPhotoShare(
path={pathForPhotoShare( photo,
photo, tag,
tag, shareCamera ? camera : undefined,
shareCamera ? camera : undefined, )}
)} prefetch={prefetchShare}
prefetch={prefetchShare} shouldScroll={shouldScrollOnShare}
shouldScroll={shouldScrollOnShare} />
/>
</div>
</div> </div>
</>)} </>, false)}
</div>} </div>}
/> />
); );

View File

@ -1,25 +0,0 @@
import { Photo } from '.';
import { pathForPhotoShare } from '@/site/paths';
import { TbPhotoShare } from 'react-icons/tb';
import IconPathButton from '@/components/IconPathButton';
export default function SharePhotoButton({
photo,
tag,
prefetch,
shouldScroll,
}: {
photo: Photo
tag?: string
prefetch?: boolean
shouldScroll?: boolean
}) {
return (
<IconPathButton
icon={<TbPhotoShare size={17} />}
path={pathForPhotoShare(photo, tag)}
prefetch={prefetch}
shouldScroll={shouldScroll}
/>
);
}