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 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 { useWorkspaces } from '../hooks/useWorkspaces';
import { fallbackRequestName } from '../lib/fallbackRequestName';
import { Input } from './core/Input';
export function CommandPalette() {
export function CommandPalette({ onClose }: { onClose: () => void }) {
const [selectedIndex, setSelectedIndex] = useState<number>(0);
const routes = useAppRoutes();
const activeEnvironmentId = useActiveEnvironmentId();
const workspaces = useWorkspaces();
const requests = useRequests();
const handleKeyDown = useCallback((e: KeyboardEvent) => {
if (e.key === 'ArrowDown') {
setSelectedIndex((prev) => prev + 1);
} else if (e.key === 'ArrowUp') {
setSelectedIndex((prev) => prev - 1);
const items = useMemo<{ label: string; onSelect: () => void; key: string }[]>(() => {
const items = [];
for (const r of requests) {
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 (
<div className="h-full grid grid-rows-[auto_minmax(0,1fr)]">
@@ -30,14 +80,13 @@ export function CommandPalette() {
/>
</div>
<div className="h-full px-1.5 overflow-y-auto">
{requests.map((r, i) => (
<CommandPaletteItem active={i === selectedIndex} key={r.id}>
Switch Request {fallbackRequestName(r)}
</CommandPaletteItem>
))}
{workspaces.map((w, i) => (
<CommandPaletteItem active={i === selectedIndex} key={w.id}>
Switch Workspace {w.name}
{items.map((v, i) => (
<CommandPaletteItem
active={i === selectedIndex}
key={v.key}
onClick={() => handleSelectAndClose(v.onSelect)}
>
{v.label}
</CommandPaletteItem>
))}
</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 (
<div
<button
onClick={onClick}
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',
)}
>
{children}
</div>
</button>
);
}

View File

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