Files
image-studio/commands/palette.ts
syntaxbullet c3a75cf0d6 feat: add command palette functionality and shortcuts
- Implemented command palette with keyboard shortcut (⌘K) for opening.
- Added commands for opening, closing, setting query, and selecting items in the command palette.
- Created tests for command palette commands and input handling.
- Enhanced layer actions with functions for adding, grouping, and deleting layers.
- Updated UI components to integrate command palette and shortcuts.
2026-07-05 17:15:20 +02:00

122 lines
3.2 KiB
TypeScript

import type { Command } from "./command";
import { commandIds } from "./ids";
export type CommandPaletteOpenPayload = {
query?: string;
selectedIndex?: number;
} | undefined;
export type CommandPaletteSetQueryPayload = {
query: string;
};
export type CommandPaletteSetSelectedIndexPayload = {
selectedIndex: number;
};
export const commandPaletteOpenCommand: Command<CommandPaletteOpenPayload> = {
id: commandIds.commandPaletteOpen,
name: "Open command palette",
history: { mode: "ignore" },
execute({ state }, payload) {
const commandPalette = {
open: true,
query: payload?.query ?? "",
selectedIndex: normalizeSelectedIndex(payload?.selectedIndex ?? 0),
};
if (
state.editor.commandPalette.open === commandPalette.open &&
state.editor.commandPalette.query === commandPalette.query &&
state.editor.commandPalette.selectedIndex === commandPalette.selectedIndex
) {
return state;
}
return {
...state,
editor: {
...state.editor,
commandPalette,
},
};
},
};
export const commandPaletteCloseCommand: Command = {
id: commandIds.commandPaletteClose,
name: "Close command palette",
history: { mode: "ignore" },
execute({ state }) {
const commandPalette = { open: false, query: "", selectedIndex: 0 };
if (
state.editor.commandPalette.open === commandPalette.open &&
state.editor.commandPalette.query === commandPalette.query &&
state.editor.commandPalette.selectedIndex === commandPalette.selectedIndex
) {
return state;
}
return {
...state,
editor: {
...state.editor,
commandPalette,
},
};
},
};
export const commandPaletteSetQueryCommand: Command<CommandPaletteSetQueryPayload> = {
id: commandIds.commandPaletteSetQuery,
name: "Set command palette query",
history: { mode: "ignore" },
execute({ state }, payload) {
if (state.editor.commandPalette.query === payload.query && state.editor.commandPalette.selectedIndex === 0) return state;
return {
...state,
editor: {
...state.editor,
commandPalette: {
...state.editor.commandPalette,
query: payload.query,
selectedIndex: 0,
},
},
};
},
};
export const commandPaletteSetSelectedIndexCommand: Command<CommandPaletteSetSelectedIndexPayload> = {
id: commandIds.commandPaletteSetSelectedIndex,
name: "Set command palette selected index",
history: { mode: "ignore" },
execute({ state }, payload) {
const selectedIndex = normalizeSelectedIndex(payload.selectedIndex);
if (state.editor.commandPalette.selectedIndex === selectedIndex) return state;
return {
...state,
editor: {
...state.editor,
commandPalette: {
...state.editor.commandPalette,
selectedIndex,
},
},
};
},
};
export const commandPaletteCommands = [
commandPaletteOpenCommand,
commandPaletteCloseCommand,
commandPaletteSetQueryCommand,
commandPaletteSetSelectedIndexCommand,
] satisfies Command<unknown>[];
function normalizeSelectedIndex(value: number) {
if (!Number.isFinite(value)) return 0;
return Math.max(0, Math.floor(value));
}