mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-22 20:26:42 +02:00
feat(mana-web): keyboard shortcuts for workbench + nav bars
- 1–9 scroll to the Nth open app on the workbench homepage; 0 opens the app picker. - q/w/e toggle the bottom bars (workbench tabs / search / tags); r opens the user-menu PillDropdownBar (expanding the PillNav first if needed); t toggles the PillNav visibility. Adds a `data-user-menu-trigger` hook on the user pill so the layout can drive the menu bar programmatically without duplicating its config. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4be5e29bd3
commit
4d6e6e61b4
3 changed files with 174 additions and 37 deletions
|
|
@ -2,7 +2,7 @@
|
|||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import type { Component, Snippet } from 'svelte';
|
||||
import { onDestroy, setContext } from 'svelte';
|
||||
import { onDestroy, setContext, tick } from 'svelte';
|
||||
import { createReminderScheduler } from '@mana/shared-stores';
|
||||
import { todoReminderSource } from '$lib/modules/todo/reminder-source';
|
||||
import { startEventStore, stopEventStore } from '$lib/data/events/event-store';
|
||||
|
|
@ -261,7 +261,7 @@
|
|||
const bottomChromeHeight = $derived(
|
||||
isFullscreen
|
||||
? 0
|
||||
: (isCollapsed ? 0 : 80) +
|
||||
: (isCollapsed ? 0 : 56) +
|
||||
(activeBar ? 64 : 0) +
|
||||
(isTagStripVisible ? 64 : 0) +
|
||||
(isQuickInputVisible ? 64 : 0) +
|
||||
|
|
@ -311,7 +311,7 @@
|
|||
{
|
||||
href: '/',
|
||||
label: 'Workbench-Tabs',
|
||||
icon: 'columns',
|
||||
icon: 'tabs',
|
||||
iconOnly: true,
|
||||
onClick: handleBottomBarToggle,
|
||||
active: isBottomBarVisible,
|
||||
|
|
@ -372,6 +372,40 @@
|
|||
const route = navRoutes[num - 1];
|
||||
if (route) goto(route);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (event.ctrlKey || event.metaKey || event.altKey) return;
|
||||
switch (event.key) {
|
||||
case 'q':
|
||||
case 'Q':
|
||||
event.preventDefault();
|
||||
handleBottomBarToggle();
|
||||
return;
|
||||
case 'w':
|
||||
case 'W':
|
||||
event.preventDefault();
|
||||
handleQuickInputToggle();
|
||||
return;
|
||||
case 'e':
|
||||
case 'E':
|
||||
event.preventDefault();
|
||||
handleTagStripToggle();
|
||||
return;
|
||||
case 'r':
|
||||
case 'R':
|
||||
event.preventDefault();
|
||||
(async () => {
|
||||
if (isCollapsed) handleCollapsedChange(false);
|
||||
await tick();
|
||||
document.querySelector<HTMLButtonElement>('[data-user-menu-trigger]')?.click();
|
||||
})();
|
||||
return;
|
||||
case 't':
|
||||
case 'T':
|
||||
event.preventDefault();
|
||||
if (!isCollapsed) closeAllBars();
|
||||
handleCollapsedChange(!isCollapsed);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -872,15 +906,6 @@
|
|||
{/if}
|
||||
</button>
|
||||
{/snippet}
|
||||
{#snippet rightAction()}
|
||||
<button
|
||||
class="pill-nav-toggle"
|
||||
onclick={() => handleCollapsedChange(!isCollapsed)}
|
||||
title={isCollapsed ? 'Navigation einblenden' : 'Navigation ausblenden'}
|
||||
>
|
||||
<span class="pill-nav-toggle-icon" class:collapsed={isCollapsed}>▼</span>
|
||||
</button>
|
||||
{/snippet}
|
||||
</QuickInputBar>
|
||||
{/if}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,6 +120,35 @@
|
|||
if (el) el.scrollIntoView({ behavior: 'smooth', inline: 'center', block: 'nearest' });
|
||||
}
|
||||
|
||||
// ── Keyboard shortcuts 1-9 / 0 ─────────────────────────
|
||||
// 1-9 scroll to the Nth open app in the active scene.
|
||||
// 0 opens the new-app picker (which scrolls itself into view).
|
||||
onMount(() => {
|
||||
function onKeydown(e: KeyboardEvent) {
|
||||
if (e.metaKey || e.ctrlKey || e.altKey) return;
|
||||
const target = e.target as HTMLElement | null;
|
||||
if (target) {
|
||||
const tag = target.tagName;
|
||||
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || target.isContentEditable)
|
||||
return;
|
||||
}
|
||||
if (e.key === '0') {
|
||||
e.preventDefault();
|
||||
showPicker = true;
|
||||
return;
|
||||
}
|
||||
if (e.key >= '1' && e.key <= '9') {
|
||||
const idx = Number(e.key) - 1;
|
||||
const page = carouselPages[idx];
|
||||
if (!page) return;
|
||||
e.preventDefault();
|
||||
scrollToPage(page.id);
|
||||
}
|
||||
}
|
||||
window.addEventListener('keydown', onKeydown);
|
||||
return () => window.removeEventListener('keydown', onKeydown);
|
||||
});
|
||||
|
||||
// ── Register SceneAppBar in the layout's bottom-stack ───
|
||||
// Split into two effects so prop churn (carouselPages re-deriving on
|
||||
// every openApps change) doesn't re-write barComponent. The first
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue