Make cmd-k item visible while loading

This commit is contained in:
Sam Becker 2024-06-05 20:33:54 -05:00
parent cf3e6c1300
commit 3ae500f93e
2 changed files with 40 additions and 27 deletions

View File

@ -91,12 +91,16 @@ export default function CommandKClient({
const isOpenRef = useRef(isOpen);
const [isPending, startTransition] = useTransition();
const [keyPending, setKeyPending] = useState<string>();
const shouldCloseAfterPending = useRef(false);
useEffect(() => {
if (!isPending && shouldCloseAfterPending.current) {
setIsOpen?.(false);
shouldCloseAfterPending.current = false;
if (!isPending) {
setKeyPending(undefined);
if (shouldCloseAfterPending.current) {
setIsOpen?.(false);
shouldCloseAfterPending.current = false;
}
}
}, [isPending, setIsOpen]);
@ -312,7 +316,7 @@ export default function CommandKClient({
onClose={() => setIsOpen?.(false)}
fast
>
<div className={clsx('space-y-1.5', isPending && 'opacity-30')}>
<div className="space-y-1.5">
<div className="relative">
<Command.Input
onChangeCapture={(e) => setQueryLive(e.currentTarget.value)}
@ -324,6 +328,7 @@ export default function CommandKClient({
'focus:border-gray-200 focus:dark:border-gray-800',
'placeholder:text-gray-400/80',
'placeholder:dark:text-gray-700',
isPending && 'opacity-20',
)}
placeholder="Search photos, views, settings ..."
disabled={isPending}
@ -356,6 +361,7 @@ export default function CommandKClient({
heading={<div className={clsx(
'flex items-center',
'px-2',
isPending && 'opacity-20',
)}>
{accessory &&
<div className="w-5">{accessory}</div>}
@ -379,15 +385,17 @@ export default function CommandKClient({
annotationAria,
path,
action,
}) =>
<CommandKItem
key={`${heading} ${label}`}
}) => {
const key = `${heading} ${label}`;
return <CommandKItem
key={key}
label={label}
value={`${heading} ${label}`}
value={key}
keywords={keywords}
onSelect={() => {
if (path) {
startTransition(() => {
setKeyPending(key);
startTransition(async () => {
shouldCloseAfterPending.current = true;
router.push(path, { scroll: true });
});
@ -399,8 +407,10 @@ export default function CommandKClient({
accessory={accessory}
annotation={annotation}
annotationAria={annotationAria}
showSpinner={Boolean(path)}
/>)}
loading={key === keyPending}
disabled={isPending && key !== keyPending}
/>;
})}
</Command.Group>)}
{footer && !queryLive &&
<div className="text-center text-dim pt-3 sm:pt-4">

View File

@ -1,6 +1,6 @@
import { clsx } from 'clsx/lite';
import { Command } from 'cmdk';
import { ReactNode, useState } from 'react';
import { ReactNode } from 'react';
import Spinner from '../Spinner';
export default function CommandKItem({
@ -11,7 +11,8 @@ export default function CommandKItem({
accessory,
annotation,
annotationAria,
showSpinner,
loading,
disabled,
}: {
label: string
value: string
@ -20,10 +21,9 @@ export default function CommandKItem({
accessory?: ReactNode
annotation?: ReactNode
annotationAria?: string
showSpinner?: boolean
loading?: boolean
disabled?: boolean
}) {
const [isLoading, setIsLoading] = useState(false);
return (
<Command.Item
value={value}
@ -32,23 +32,26 @@ export default function CommandKItem({
'px-2',
accessory ? 'py-2' : 'py-1',
'rounded-md cursor-pointer tracking-wide',
'data-[selected=true]:bg-gray-100',
'data-[selected=true]:dark:bg-gray-900/75',
'active:!bg-gray-200/75 active:dark:!bg-gray-800/55',
...loading
? [
'data-[selected=true]:dark:bg-gray-900/50',
'data-[selected=true]:bg-gray-100/50',
] : [
'data-[selected=true]:dark:bg-gray-900/75',
'data-[selected=true]:bg-gray-100',
],
disabled && 'opacity-15',
)}
onSelect={() => {
onSelect?.();
if (showSpinner) {
setIsLoading(true);
}
}}
onSelect={onSelect}
disabled={loading || disabled}
>
<div className="flex items-center gap-2 sm:gap-3">
{accessory}
<span className="grow text-ellipsis truncate">
{label}
</span>
{annotation && !isLoading &&
{annotation && !loading &&
<span
className="text-dim whitespace-nowrap"
aria-label={annotationAria}
@ -57,8 +60,8 @@ export default function CommandKItem({
{annotation}
</span>
</span>}
{isLoading &&
<Spinner color="text" />}
{loading &&
<Spinner color="dim" />}
</div>
</Command.Item>
);