feat: make shortcuts easier to add across the app

This commit is contained in:
Zoe
2026-02-25 19:47:33 -06:00
parent 50cb195486
commit d22d08e99f
4 changed files with 57 additions and 21 deletions
+12 -5
View File
@@ -107,13 +107,20 @@ const handleKeyDown = async (event: KeyboardEvent) => {
};
const handleWindowKeyDown = async (event: KeyboardEvent) => {
if (event.ctrlKey || event.metaKey) {
return;
}
if (event.defaultPrevented) return;
if (event.ctrlKey || event.metaKey || event.altKey) return;
if (document.activeElement === document.body) {
// redirect all standard keyboard input to the input field
inputRef.value?.focus();
const isPrintable = event.key.length === 1;
if (isPrintable) {
inputRef.value?.focus();
} else if (event.key === 'Enter') {
event.preventDefault();
handleSubmit();
inputRef.value?.focus();
}
}
};
+7 -1
View File
@@ -4,7 +4,12 @@ import Settings from './Settings.vue';
import { DialogType } from '~/composables/useDialog';
const { open, page, data, close, confirm } = useDialog();
const { open, page, data, close, confirm, openDialog } = useDialog();
const { addShortcut } = useKeyboardShortcuts();
const unbindShortcut = addShortcut(['ctrl', ','], () => {
openDialog(DialogType.Settings);
});
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
@@ -24,6 +29,7 @@ onUnmounted(() => {
if (open.value) {
document.body.removeEventListener('keydown', handleKeyDown);
}
unbindShortcut();
});
</script>
+32 -13
View File
@@ -1,23 +1,41 @@
export const useKeyboardShortcuts = () => {
const { toggle: toggleSidebar } = useSidebar();
const { toggle: openSettings, open: isSettingsOpen } = useSettings();
const shortcutsMap = new Map<string, () => void>();
const normalize = (combo: string[]) =>
combo.map(k => k.toLowerCase()).sort().join('+');
const addShortcut = (combo: string[], callback: () => void) => {
const normalizedKey = normalize(combo);
shortcutsMap.set(normalizedKey, callback);
return () => {
shortcutsMap.delete(normalizedKey);
};
};
const handleKeyDown = (event: KeyboardEvent) => {
// Ctrl+[ to collapse sidebar
if (event.ctrlKey && event.key === '[') {
event.preventDefault();
toggleSidebar();
const isInput = ['INPUT', 'TEXTAREA'].includes((event.target as HTMLElement).tagName);
if (isInput && !event.ctrlKey && !event.metaKey && event.key !== 'Escape') {
return;
}
if (event.ctrlKey && event.key === ',') {
event.preventDefault();
if (isSettingsOpen.value) {
return;
}
const keys: string[] = [];
if (event.ctrlKey) keys.push('ctrl');
if (event.metaKey) keys.push('meta');
if (event.shiftKey) keys.push('shift');
if (event.altKey) keys.push('alt');
openSettings();
return;
const mainKey = event.key.toLowerCase();
if (!['control', 'shift', 'meta', 'alt'].includes(mainKey)) {
keys.push(mainKey);
}
const pressedCombo = normalize(keys);
if (shortcutsMap.has(pressedCombo)) {
event.preventDefault();
event.stopPropagation();
shortcutsMap.get(pressedCombo)!();
}
};
@@ -30,6 +48,7 @@ export const useKeyboardShortcuts = () => {
});
return {
addShortcut,
handleKeyDown,
};
};
+6 -2
View File
@@ -2,14 +2,18 @@
import Dialog from '~/components/Dialog/index.vue';
const { colorScheme } = await useUserSettings();
const { toggle: toggleSidebar } = useSidebar();
const { addShortcut } = useKeyboardShortcuts();
addShortcut(['ctrl', '['], () => {
toggleSidebar();
});
useHead({
htmlAttrs: {
class: colorScheme.class
}
});
useKeyboardShortcuts();
</script>
<template>