feat: implement keyboard context management and shortcuts for improved user interaction

This commit is contained in:
pandadev 2025-03-16 20:33:40 +01:00
parent af64b77b74
commit b946b6455f
No known key found for this signature in database
GPG key ID: C39629DACB8E762F
3 changed files with 353 additions and 109 deletions

View file

@ -49,9 +49,12 @@
onClick: pasteSelectedItem,
}" :secondary-action="{
text: 'Actions',
icon: IconsK,
icon: IconsKey,
input: 'K',
showModifier: true,
onClick: toggleActionsMenu,
}" />
<ActionsMenu :selected-item="selectedItem" :is-visible="isActionsMenuVisible" @close="closeActionsMenu" />
</main>
</template>
@ -73,22 +76,17 @@ import type {
InfoColor,
InfoCode,
} from "~/types/types";
import { Key, keyboard } from "wrdu-keyboard";
import {
selectedGroupIndex,
selectedItemIndex,
selectedElement,
useSelectedResult,
} from "~/lib/selectedResult";
import IconsEnter from "~/components/Icons/Enter.vue";
import IconsK from "~/components/Icons/K.vue";
import IconsKey from "~/components/Icons/Key.vue";
import ActionsMenu from "~/components/ActionsMenu.vue";
interface GroupedHistory {
label: string;
items: HistoryItem[];
}
const { $history } = useNuxtApp();
const { $history, $keyboard, $selectedResult } = useNuxtApp();
const { selectedGroupIndex, selectedItemIndex, selectedElement, useSelectedResult } = $selectedResult;
const CHUNK_SIZE = 50;
const SCROLL_THRESHOLD = 100;
@ -113,9 +111,24 @@ const imageLoadError = ref<boolean>(false);
const imageLoading = ref<boolean>(false);
const pageTitle = ref<string>("");
const pageOgImage = ref<string>("");
const isActionsMenuVisible = ref<boolean>(false);
const topBar = ref<{ searchInput: HTMLInputElement | null } | null>(null);
const toggleActionsMenu = () => {
nextTick(() => {
isActionsMenuVisible.value = !isActionsMenuVisible.value;
if (isActionsMenuVisible.value) {
$keyboard.enableContext('actionsMenu');
}
});
};
const closeActionsMenu = () => {
isActionsMenuVisible.value = false;
$keyboard.disableContext('actionsMenu');
};
const isSameDay = (date1: Date, date2: Date): boolean => {
return (
date1.getFullYear() === date2.getFullYear() &&
@ -527,70 +540,47 @@ const setupEventListeners = async (): Promise<void> => {
}
focusSearchInput();
keyboard.clear();
keyboard.prevent.down([Key.DownArrow], () => {
selectNext();
$keyboard.clearAll();
$keyboard.setupAppShortcuts({
onNavigateDown: selectNext,
onNavigateUp: selectPrevious,
onSelect: pasteSelectedItem,
onEscape: () => {
if (isActionsMenuVisible.value) {
closeActionsMenu();
} else {
hideApp();
}
},
onToggleActions: toggleActionsMenu,
contextName: 'main',
priority: $keyboard.PRIORITY.LOW
});
keyboard.prevent.down([Key.UpArrow], () => {
selectPrevious();
});
keyboard.prevent.down([Key.Enter], () => {
pasteSelectedItem();
});
keyboard.prevent.down([Key.Escape], () => {
hideApp();
});
switch (os.value) {
case "macos":
keyboard.prevent.down([Key.LeftMeta, Key.K], () => { });
keyboard.prevent.down([Key.RightMeta, Key.K], () => { });
break;
case "linux":
case "windows":
keyboard.prevent.down([Key.LeftControl, Key.K], () => { });
keyboard.prevent.down([Key.RightControl, Key.K], () => { });
break;
}
$keyboard.enableContext('main');
});
await listen("tauri://blur", () => {
searchInput.value?.blur();
keyboard.clear();
$keyboard.clearAll();
$keyboard.disableContext('main');
});
keyboard.prevent.down([Key.DownArrow], () => {
selectNext();
$keyboard.setupAppShortcuts({
onNavigateDown: selectNext,
onNavigateUp: selectPrevious,
onSelect: pasteSelectedItem,
onEscape: () => {
if (isActionsMenuVisible.value) {
closeActionsMenu();
} else {
hideApp();
}
},
onToggleActions: toggleActionsMenu,
contextName: 'main',
priority: $keyboard.PRIORITY.LOW
});
keyboard.prevent.down([Key.UpArrow], () => {
selectPrevious();
});
keyboard.prevent.down([Key.Enter], () => {
pasteSelectedItem();
});
keyboard.prevent.down([Key.Escape], () => {
hideApp();
});
switch (os.value) {
case "macos":
keyboard.prevent.down([Key.LeftMeta, Key.K], () => { });
keyboard.prevent.down([Key.RightMeta, Key.K], () => { });
break;
case "linux":
case "windows":
keyboard.prevent.down([Key.LeftControl, Key.K], () => { });
keyboard.prevent.down([Key.RightControl, Key.K], () => { });
break;
}
$keyboard.enableContext('main');
};
const hideApp = async (): Promise<void> => {

View file

@ -79,7 +79,7 @@ import { platform } from "@tauri-apps/plugin-os";
import { useRouter } from "vue-router";
import { KeyValues, KeyLabels } from "../types/keys";
import { disable, enable } from "@tauri-apps/plugin-autostart";
import { Key, keyboard } from "wrdu-keyboard";
import { useNuxtApp } from "#app";
import BottomBar from "../components/BottomBar.vue";
import IconsEnter from "~/components/Icons/Enter.vue";
@ -92,7 +92,7 @@ const os = ref("");
const router = useRouter();
const showEmptyKeybindError = ref(false);
const autostart = ref(false);
const { $settings } = useNuxtApp();
const { $settings, $keyboard } = useNuxtApp();
const modifierKeySet = new Set([
KeyValues.AltLeft,
@ -174,56 +174,71 @@ const toggleAutostart = async () => {
os.value = platform();
onMounted(async () => {
keyboard.prevent.down([Key.All], (event: KeyboardEvent) => {
if (isKeybindInputFocused.value) {
onKeyDown(event);
$keyboard.setupKeybindCapture({
onCapture: (key: string) => {
if (isKeybindInputFocused.value) {
const keyValue = key as KeyValues;
if (isModifier(keyValue)) {
activeModifiers.add(keyValue);
} else if (!keybind.value.includes(keyValue)) {
keybind.value = keybind.value.filter((k) => isModifier(k));
keybind.value.push(keyValue);
}
updateKeybind();
showEmptyKeybindError.value = false;
}
},
onComplete: () => {
if (isKeybindInputFocused.value) {
keybindInput.value?.blur();
} else {
router.push("/");
}
}
});
keyboard.prevent.down([Key.Escape], () => {
if (isKeybindInputFocused.value) {
keybindInput.value?.blur();
} else {
router.push("/");
}
});
switch (os.value) {
case "macos":
keyboard.prevent.down([Key.LeftMeta, Key.Enter], () => {
if (!isKeybindInputFocused.value) {
saveKeybind();
}
});
keyboard.prevent.down([Key.RightMeta, Key.Enter], () => {
if (!isKeybindInputFocused.value) {
saveKeybind();
}
});
break;
case "linux":
case "windows":
keyboard.prevent.down([Key.LeftControl, Key.Enter], () => {
if (!isKeybindInputFocused.value) {
saveKeybind();
}
});
keyboard.prevent.down([Key.RightControl, Key.Enter], () => {
if (!isKeybindInputFocused.value) {
saveKeybind();
}
});
break;
if (os.value === "macos") {
$keyboard.on("settings", [$keyboard.Key.LeftMeta, $keyboard.Key.Enter], () => {
if (!isKeybindInputFocused.value) {
saveKeybind();
}
}, { priority: $keyboard.PRIORITY.MEDIUM });
$keyboard.on("settings", [$keyboard.Key.RightMeta, $keyboard.Key.Enter], () => {
if (!isKeybindInputFocused.value) {
saveKeybind();
}
}, { priority: $keyboard.PRIORITY.MEDIUM });
} else {
$keyboard.on("settings", [$keyboard.Key.LeftControl, $keyboard.Key.Enter], () => {
if (!isKeybindInputFocused.value) {
saveKeybind();
}
}, { priority: $keyboard.PRIORITY.MEDIUM });
$keyboard.on("settings", [$keyboard.Key.RightControl, $keyboard.Key.Enter], () => {
if (!isKeybindInputFocused.value) {
saveKeybind();
}
}, { priority: $keyboard.PRIORITY.MEDIUM });
}
$keyboard.on("settings", [$keyboard.Key.Escape], () => {
if (!isKeybindInputFocused.value) {
router.push("/");
}
}, { priority: $keyboard.PRIORITY.MEDIUM });
$keyboard.enableContext("settings");
autostart.value = (await $settings.getSetting("autostart")) === "true";
});
onUnmounted(() => {
keyboard.clear();
$keyboard.disableContext("settings");
$keyboard.clearAll();
});
</script>