Implement select for command palette

This commit is contained in:
Gregory Schier
2024-03-19 17:24:57 -07:00
parent 829d10d7b9
commit ab6cef064c
2 changed files with 79 additions and 21 deletions

View File

@@ -1,22 +1,72 @@
import classNames from 'classnames'; import classNames from 'classnames';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { useCallback, useState } from 'react'; import { useMemo, useCallback, useState } from 'react';
import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
import { useAppRoutes } from '../hooks/useAppRoutes';
import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
import { useRequests } from '../hooks/useRequests'; import { useRequests } from '../hooks/useRequests';
import { useWorkspaces } from '../hooks/useWorkspaces'; import { useWorkspaces } from '../hooks/useWorkspaces';
import { fallbackRequestName } from '../lib/fallbackRequestName'; import { fallbackRequestName } from '../lib/fallbackRequestName';
import { Input } from './core/Input'; import { Input } from './core/Input';
export function CommandPalette() { export function CommandPalette({ onClose }: { onClose: () => void }) {
const [selectedIndex, setSelectedIndex] = useState<number>(0); const [selectedIndex, setSelectedIndex] = useState<number>(0);
const routes = useAppRoutes();
const activeEnvironmentId = useActiveEnvironmentId();
const workspaces = useWorkspaces(); const workspaces = useWorkspaces();
const requests = useRequests(); const requests = useRequests();
const handleKeyDown = useCallback((e: KeyboardEvent) => {
if (e.key === 'ArrowDown') { const items = useMemo<{ label: string; onSelect: () => void; key: string }[]>(() => {
setSelectedIndex((prev) => prev + 1); const items = [];
} else if (e.key === 'ArrowUp') { for (const r of requests) {
setSelectedIndex((prev) => prev - 1); items.push({
key: `switch-request-${r.id}`,
label: `Switch Request → ${fallbackRequestName(r)}`,
onSelect: () => {
return routes.navigate('request', {
workspaceId: r.workspaceId,
requestId: r.id,
environmentId: activeEnvironmentId ?? undefined,
});
},
});
} }
}, []); for (const w of workspaces) {
items.push({
key: `switch-workspace-${w.id}`,
label: `Switch Workspace → ${w.name}`,
onSelect: async () => {
const environmentId = (await getRecentEnvironments(w.id))[0];
return routes.navigate('workspace', {
workspaceId: w.id,
environmentId,
});
},
});
}
return items;
}, [activeEnvironmentId, requests, routes, workspaces]);
const handleSelectAndClose = (cb: () => void) => {
onClose();
cb();
};
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (e.key === 'ArrowDown') {
setSelectedIndex((prev) => prev + 1);
} else if (e.key === 'ArrowUp') {
setSelectedIndex((prev) => prev - 1);
} else if (e.key === 'Enter') {
const item = items[selectedIndex];
if (item) {
handleSelectAndClose(item.onSelect);
}
}
},
[items, onClose, selectedIndex],
);
return ( return (
<div className="h-full grid grid-rows-[auto_minmax(0,1fr)]"> <div className="h-full grid grid-rows-[auto_minmax(0,1fr)]">
@@ -30,14 +80,13 @@ export function CommandPalette() {
/> />
</div> </div>
<div className="h-full px-1.5 overflow-y-auto"> <div className="h-full px-1.5 overflow-y-auto">
{requests.map((r, i) => ( {items.map((v, i) => (
<CommandPaletteItem active={i === selectedIndex} key={r.id}> <CommandPaletteItem
Switch Request {fallbackRequestName(r)} active={i === selectedIndex}
</CommandPaletteItem> key={v.key}
))} onClick={() => handleSelectAndClose(v.onSelect)}
{workspaces.map((w, i) => ( >
<CommandPaletteItem active={i === selectedIndex} key={w.id}> {v.label}
Switch Workspace {w.name}
</CommandPaletteItem> </CommandPaletteItem>
))} ))}
</div> </div>
@@ -45,15 +94,24 @@ export function CommandPalette() {
); );
} }
function CommandPaletteItem({ children, active }: { children: ReactNode; active: boolean }) { function CommandPaletteItem({
children,
active,
onClick,
}: {
children: ReactNode;
active: boolean;
onClick: () => void;
}) {
return ( return (
<div <button
onClick={onClick}
className={classNames( className={classNames(
'h-xs flex items-center rounded px-1.5 text-gray-600', 'w-full h-xs flex items-center rounded px-1.5 text-gray-600',
active && 'bg-highlightSecondary text-gray-800', active && 'bg-highlightSecondary text-gray-800',
)} )}
> >
{children} {children}
</div> </button>
); );
} }

View File

@@ -18,7 +18,7 @@ export function useCommandPalette() {
hideX: true, hideX: true,
noPadding: true, noPadding: true,
noScroll: true, noScroll: true,
render: () => <CommandPalette />, render: ({ hide }) => <CommandPalette onClose={hide} />,
}); });
}); });
} }