feat(09-02): add frontend keyboard shortcut service, store, and controller

- Create keyboard-shortcut-service.ts singleton with keydown listener
- Shadow DOM active element resolution for scope detection
- Text input suppression (only Escape passes through)
- Scope resolution: text-input > panel-specific > global
- Action dispatch to player/queue stores and Wails bindings
- Create shortcuts-store.ts with Wails persistence and event sync
- Create shortcuts-controller.ts for Lit component integration
- Export store and controller from store/index.ts
- Replace hardcoded Ctrl+F handler in index.ts with service
- Initialize service via import in frontend/index.ts
This commit is contained in:
2026-03-06 21:48:52 -05:00
parent 6285ca9dc4
commit 40d48151dd
5 changed files with 610 additions and 18 deletions
@@ -0,0 +1,60 @@
import type { ReactiveController, ReactiveControllerHost } from 'lit';
import type { ShortcutsState } from '../shortcuts-store';
import { shortcutsStore } from '../shortcuts-store';
/**
* ShortcutsController connects a Lit component to the ShortcutsStore.
*
* Use this controller in components that need to read or change
* shortcut bindings (e.g. the shortcut settings UI in config-page).
*/
export class ShortcutsController implements ReactiveController {
private host: ReactiveControllerHost;
private unsubscribe?: () => void;
constructor(host: ReactiveControllerHost) {
this.host = host;
host.addController(this);
}
// ===================================================================
// LIFECYCLE HOOKS
// ===================================================================
hostConnected(): void {
this.unsubscribe = shortcutsStore.subscribe(() => {
this.host.requestUpdate();
});
}
hostDisconnected(): void {
this.unsubscribe?.();
}
// ===================================================================
// STATE ACCESSORS
// ===================================================================
get state(): Readonly<ShortcutsState> {
return shortcutsStore.getState();
}
get bindings(): Map<string, string> {
return shortcutsStore.getBindings();
}
// ===================================================================
// ACTIONS
// ===================================================================
async updateBinding(
action: string,
key: string,
): Promise<void> {
await shortcutsStore.updateBinding(action, key);
}
async resetAll(): Promise<void> {
await shortcutsStore.resetAll();
}
}