From ad11ce32b017311566d644b0e735ec21927d0353 Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Tue, 21 Jan 2025 23:24:36 -0600 Subject: [PATCH] Split link status/loader into two components --- src/admin/AdminNavClient.tsx | 9 +++++---- src/components/LinkWithLoader.tsx | 31 +++++++++++++++++++++++++++++++ src/components/LinkWithStatus.tsx | 31 +++++++------------------------ src/components/SwitcherItem.tsx | 20 ++++++++++---------- 4 files changed, 53 insertions(+), 38 deletions(-) create mode 100644 src/components/LinkWithLoader.tsx diff --git a/src/admin/AdminNavClient.tsx b/src/admin/AdminNavClient.tsx index 240ab4e1..3acc5e8d 100644 --- a/src/admin/AdminNavClient.tsx +++ b/src/admin/AdminNavClient.tsx @@ -1,5 +1,6 @@ 'use client'; +import LinkWithLoader from '@/components/LinkWithLoader'; import LinkWithStatus from '@/components/LinkWithStatus'; import Note from '@/components/Note'; import SiteGrid from '@/components/SiteGrid'; @@ -73,11 +74,11 @@ export default function AdminNavClient({ key={label} href={href} className={clsx( + 'flex gap-0.5', checkPathPrefix(pathname, href) ? 'font-bold' : 'text-dim', 'px-1 py-0.5 rounded-md', )} loadingClassName="bg-dim" - contentClassName="flex gap-0.5" prefetch={false} > {label} @@ -85,19 +86,19 @@ export default function AdminNavClient({ ({count})} )} - } + loader={} > - + {shouldShowBanner && }> diff --git a/src/components/LinkWithLoader.tsx b/src/components/LinkWithLoader.tsx new file mode 100644 index 00000000..af01c50b --- /dev/null +++ b/src/components/LinkWithLoader.tsx @@ -0,0 +1,31 @@ +import { ComponentProps, ReactNode } from 'react'; +import LinkWithStatus from './LinkWithStatus'; +import clsx from 'clsx/lite'; +import Link from 'next/link'; + +export default function LinkWithLoader({ + loader, + children, + ...props +}: ComponentProps & { + loader: ReactNode +}) { + return ( + + {({ isLoading }) => <> + + {children} + + {isLoading && + {loader} + } + } + + ); +} diff --git a/src/components/LinkWithStatus.tsx b/src/components/LinkWithStatus.tsx index 6b00bf2c..a2ddf0a9 100644 --- a/src/components/LinkWithStatus.tsx +++ b/src/components/LinkWithStatus.tsx @@ -20,18 +20,14 @@ const MAX_LOADING_DURATION = 15_000; export type LinkWithStatusProps = Omit< ComponentProps, 'children' > & { - loadingElement?: ReactNode loadingClassName?: string - contentClassName?: string children: ReactNode | ((props: { isLoading: boolean }) => ReactNode) } export default function LinkWithStatus({ - loadingElement, loadingClassName, - contentClassName, href, className, onClick, @@ -93,7 +89,10 @@ export default function LinkWithStatus({ {...props } href={href} className={clsx( - 'relative transition-colors', + 'relative flex transition-[colors,opacity]', + (loadingClassName || isControlled) + ? 'opacity-100' + : isLoading ? 'opacity-50' : 'opacity-100', className, isLoading && loadingClassName, )} @@ -116,24 +115,8 @@ export default function LinkWithStatus({ onClick?.(e); }} > - - {typeof children === 'function' - ? children({ isLoading }) - : children} - - {isLoading && loadingElement && - {loadingElement} - } + {typeof children === 'function' + ? children({ isLoading }) + : children} ; } diff --git a/src/components/SwitcherItem.tsx b/src/components/SwitcherItem.tsx index eb1b70be..87c01783 100644 --- a/src/components/SwitcherItem.tsx +++ b/src/components/SwitcherItem.tsx @@ -1,8 +1,8 @@ import { clsx } from 'clsx/lite'; import { SHOULD_PREFETCH_ALL_LINKS } from '@/site/config'; -import { JSX, ReactNode } from 'react'; -import LinkWithStatus from './LinkWithStatus'; +import { JSX } from 'react'; import Spinner from './Spinner'; +import LinkWithLoader from './LinkWithLoader'; export default function SwitcherItem({ icon, @@ -37,23 +37,23 @@ export default function SwitcherItem({ : 'hover:text-gray-700 dark:hover:text-gray-400', ); - const renderContent = (content: ReactNode) => noPadding - ? content + const renderIcon = () => noPadding + ? icon :
- {content} + {icon}
; return ( href - ? , + loader: , }}> - {renderContent(icon)} - - :
{renderContent(icon)}
+ {renderIcon()} + + :
{renderIcon()}
); };