Make cmd-k item visible while loading
This commit is contained in:
parent
cf3e6c1300
commit
3ae500f93e
@ -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">
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user