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.
This commit is contained in:
121
commands/palette.ts
Normal file
121
commands/palette.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
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));
|
||||
}
|
||||
Reference in New Issue
Block a user