-
![YouTube Thumbnail]()
+
+
-
+
{{ selectedItem?.content || "" }}
-
+
Information
{{ row.label }}
-
-
+
+
{{ row.value }}
@@ -70,39 +43,26 @@
-
-
+
+
diff --git a/plugins/keyboard.ts b/plugins/keyboard.ts
index dfc7d44..17e8d63 100644
--- a/plugins/keyboard.ts
+++ b/plugins/keyboard.ts
@@ -1,27 +1,281 @@
+import { Key, keyboard } from "wrdu-keyboard";
import { platform } from "@tauri-apps/plugin-os";
-import { useKeyboard, Key } from "@waradu/keyboard";
+
+type KeyboardHandler = (event: KeyboardEvent) => void;
+
+const activeContexts = new Set
();
+const handlersByContext: Record<
+ string,
+ Array<{
+ keys: Key[];
+ callback: KeyboardHandler;
+ prevent: boolean;
+ priority?: number;
+ }>
+> = {};
+
+const PRIORITY = {
+ HIGH: 100,
+ MEDIUM: 50,
+ LOW: 0,
+};
+
+let currentOS = "windows";
+
+const useKeyboard = {
+ PRIORITY,
+
+ registerContext: (contextName: string) => {
+ if (!handlersByContext[contextName]) {
+ handlersByContext[contextName] = [];
+ }
+ },
+
+ enableContext: (contextName: string) => {
+ if (!handlersByContext[contextName]) {
+ useKeyboard.registerContext(contextName);
+ }
+ activeContexts.add(contextName);
+
+ initKeyboardHandlers();
+ },
+
+ disableContext: (contextName: string) => {
+ activeContexts.delete(contextName);
+
+ initKeyboardHandlers();
+ },
+
+ on: (
+ contextName: string,
+ keys: Key[],
+ callback: KeyboardHandler,
+ options: { prevent?: boolean; priority?: number } = {}
+ ) => {
+ if (!handlersByContext[contextName]) {
+ useKeyboard.registerContext(contextName);
+ }
+
+ const existingHandlerIndex = handlersByContext[contextName].findIndex(
+ (handler) =>
+ handler.keys.length === keys.length &&
+ handler.keys.every((key, i) => key === keys[i]) &&
+ handler.callback.toString() === callback.toString()
+ );
+
+ if (existingHandlerIndex !== -1) {
+ handlersByContext[contextName][existingHandlerIndex] = {
+ keys,
+ callback,
+ prevent: options.prevent ?? true,
+ priority: options.priority ?? PRIORITY.LOW,
+ };
+ } else {
+ handlersByContext[contextName].push({
+ keys,
+ callback,
+ prevent: options.prevent ?? true,
+ priority: options.priority ?? PRIORITY.LOW,
+ });
+ }
+
+ if (activeContexts.has(contextName)) {
+ initKeyboardHandlers();
+ }
+ },
+
+ clearAll: () => {
+ keyboard.clear();
+ },
+
+ setupAppShortcuts: (options: {
+ onNavigateUp?: () => void;
+ onNavigateDown?: () => void;
+ onSelect?: () => void;
+ onEscape?: () => void;
+ onToggleActions?: () => void;
+ contextName?: string;
+ priority?: number;
+ }) => {
+ const {
+ onNavigateUp,
+ onNavigateDown,
+ onSelect,
+ onEscape,
+ onToggleActions,
+ contextName = "app",
+ priority = PRIORITY.LOW,
+ } = options;
+
+ if (!handlersByContext[contextName]) {
+ useKeyboard.registerContext(contextName);
+ }
+
+ if (onNavigateUp) {
+ useKeyboard.on(contextName, [Key.UpArrow], () => onNavigateUp(), {
+ priority,
+ });
+ }
+
+ if (onNavigateDown) {
+ useKeyboard.on(contextName, [Key.DownArrow], () => onNavigateDown(), {
+ priority,
+ });
+ }
+
+ if (onSelect) {
+ useKeyboard.on(contextName, [Key.Enter], () => onSelect(), { priority });
+ }
+
+ if (onEscape) {
+ useKeyboard.on(contextName, [Key.Escape], () => onEscape(), { priority });
+ }
+
+ if (onToggleActions) {
+ const togglePriority = Math.max(priority, PRIORITY.HIGH);
+
+ if (currentOS === "macos") {
+ useKeyboard.on(
+ contextName,
+ [Key.LeftMeta, Key.K],
+ () => onToggleActions(),
+ { priority: togglePriority }
+ );
+ useKeyboard.on(
+ contextName,
+ [Key.RightMeta, Key.K],
+ () => onToggleActions(),
+ { priority: togglePriority }
+ );
+ } else {
+ useKeyboard.on(
+ contextName,
+ [Key.LeftControl, Key.K],
+ () => onToggleActions(),
+ { priority: togglePriority }
+ );
+ useKeyboard.on(
+ contextName,
+ [Key.RightControl, Key.K],
+ () => onToggleActions(),
+ { priority: togglePriority }
+ );
+ }
+ }
+ },
+
+ setupKeybindCapture: (options: {
+ onCapture: (key: string) => void;
+ onComplete: () => void;
+ }) => {
+ const { onCapture, onComplete } = options;
+
+ keyboard.prevent.down([Key.All], (event: KeyboardEvent) => {
+ if (event.code === "Escape") {
+ onComplete();
+ return;
+ }
+ onCapture(event.code);
+ });
+ },
+};
+
+const initKeyboardHandlers = () => {
+ keyboard.clear();
+
+ let allHandlers: Array<{
+ keys: Key[];
+ callback: KeyboardHandler;
+ prevent: boolean;
+ priority: number;
+ contextName: string;
+ }> = [];
+
+ for (const contextName of activeContexts) {
+ const handlers = handlersByContext[contextName] || [];
+ allHandlers = [
+ ...allHandlers,
+ ...handlers.map((handler) => ({
+ ...handler,
+ priority: handler.priority ?? PRIORITY.LOW,
+ contextName,
+ })),
+ ];
+ }
+
+ allHandlers.sort((a, b) => b.priority - a.priority);
+
+ const handlersByKeyCombination: Record<
+ string,
+ Array<(typeof allHandlers)[0]>
+ > = {};
+
+ allHandlers.forEach((handler) => {
+ const keyCombo = handler.keys.sort().join("+");
+ if (!handlersByKeyCombination[keyCombo]) {
+ handlersByKeyCombination[keyCombo] = [];
+ }
+ handlersByKeyCombination[keyCombo].push(handler);
+ });
+
+ Object.entries(handlersByKeyCombination).forEach(([_keyCombo, handlers]) => {
+ handlers.sort((a, b) => b.priority - a.priority);
+ const handler = handlers[0];
+
+ const wrappedCallback: KeyboardHandler = (event) => {
+ const isMetaCombo =
+ handler.keys.length > 1 &&
+ (handler.keys.includes(Key.LeftMeta) ||
+ handler.keys.includes(Key.RightMeta) ||
+ handler.keys.includes(Key.LeftControl) ||
+ handler.keys.includes(Key.RightControl));
+
+ const isNavigationKey =
+ event.key === "ArrowUp" ||
+ event.key === "ArrowDown" ||
+ event.key === "Enter" ||
+ event.key === "Escape";
+
+ const isInInput =
+ event.target instanceof HTMLInputElement ||
+ event.target instanceof HTMLTextAreaElement;
+
+ if (
+ (isMetaCombo || isNavigationKey || !isInInput) &&
+ activeContexts.has(handler.contextName)
+ ) {
+ handler.callback(event);
+ }
+ };
+
+ if (handler.prevent) {
+ keyboard.prevent.down(handler.keys, wrappedCallback);
+ } else {
+ keyboard.down(handler.keys, wrappedCallback);
+ }
+ });
+};
export default defineNuxtPlugin(async (nuxtApp) => {
- const keyboardInstance = useKeyboard();
- let currentOS = "windows";
try {
- const osName = await Promise.resolve(platform());
+ const osName = platform();
currentOS = osName.toLowerCase().includes("mac") ? "macos" : "windows";
} catch (error) {
console.error("Error detecting platform:", error);
}
- // Defer initialization until the app is mounted
- nuxtApp.hook('app:mounted', () => {
- keyboardInstance.init();
+ initKeyboardHandlers();
+
+ nuxtApp.hook("page:finish", () => {
+ initKeyboardHandlers();
});
- nuxtApp.provide('keyboard', {
- listen: keyboardInstance.listen.bind(keyboardInstance),
- init: keyboardInstance.init.bind(keyboardInstance),
- Key,
- currentOS,
- // Provide a clear method if users need to manually clear all listeners from the instance
- clearAll: keyboardInstance.clear ? keyboardInstance.clear.bind(keyboardInstance) : () => { console.warn('@waradu/keyboard instance does not have a clear method'); }
- });
+ return {
+ provide: {
+ keyboard: {
+ ...useKeyboard,
+ Key,
+ },
+ },
+ };
});
diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock
index add115b..356fe53 100644
--- a/src-tauri/Cargo.lock
+++ b/src-tauri/Cargo.lock
@@ -105,9 +105,9 @@ dependencies = [
[[package]]
name = "arbitrary"
-version = "1.4.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
+checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
@@ -628,13 +628,12 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.2.16"
+version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
+checksum = "504bdec147f2cc13c8b57ed9401fd8a147cc66b67ad5cb241394244f2c947549"
dependencies = [
"jobserver",
"libc",
- "shlex",
]
[[package]]
@@ -999,9 +998,9 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.21"
+version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "crunchy"
@@ -1125,9 +1124,9 @@ dependencies = [
[[package]]
name = "derive_arbitrary"
-version = "1.4.1"
+version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
+checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
@@ -2620,7 +2619,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
"hermit-abi 0.5.0",
"libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -2842,7 +2841,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -3574,9 +3573,9 @@ checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad"
[[package]]
name = "openssl"
-version = "0.10.71"
+version = "0.10.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
+checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
dependencies = [
"bitflags 2.8.0",
"cfg-if",
@@ -3606,9 +3605,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
-version = "0.9.106"
+version = "0.9.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
+checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
dependencies = [
"cc",
"libc",
@@ -4561,14 +4560,15 @@ checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
[[package]]
name = "ring"
-version = "0.17.14"
+version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
dependencies = [
"cc",
"cfg-if",
"getrandom 0.2.15",
"libc",
+ "spin",
"untrusted",
"windows-sys 0.52.0",
]
@@ -4971,12 +4971,6 @@ dependencies = [
"digest",
]
-[[package]]
-name = "shlex"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
@@ -7733,9 +7727,9 @@ dependencies = [
[[package]]
name = "zip"
-version = "2.4.1"
+version = "2.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "938cc23ac49778ac8340e366ddc422b2227ea176edb447e23fc0627608dddadd"
+checksum = "40dd8c92efc296286ce1fbd16657c5dbefff44f1b4ca01cc5f517d8b7b3d3e2e"
dependencies = [
"arbitrary",
"crc32fast",
@@ -7743,7 +7737,7 @@ dependencies = [
"displaydoc",
"indexmap 2.3.0",
"memchr",
- "thiserror 2.0.3",
+ "thiserror 1.0.63",
]
[[package]]
diff --git a/types/keyboard.d.ts b/types/keyboard.d.ts
deleted file mode 100644
index 62d26e4..0000000
--- a/types/keyboard.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-import type { Key as WaraduKey, useKeyboard } from '@waradu/keyboard';
-
-declare module '#app' {
- interface NuxtApp {
- $keyboard: {
- listen: ReturnType['listen'];
- init: ReturnType['init'];
- Key: typeof WaraduKey;
- currentOS: string;
- clearAll: () => void;
- };
- }
-}
-
-declare module 'vue' {
- interface ComponentCustomProperties {
- $keyboard: {
- listen: ReturnType['listen'];
- init: ReturnType['init'];
- Key: typeof WaraduKey;
- currentOS: string;
- clearAll: () => void;
- };
- }
-}
-
-export {};
\ No newline at end of file