mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-24 01:28:35 +02:00
Implement select for command palette
This commit is contained in:
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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} />,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user