From 492f25f6295f409087d29e2edaf05af39cc7da42 Mon Sep 17 00:00:00 2001 From: th Date: Sat, 25 Apr 2026 09:55:16 +0200 Subject: [PATCH] 1.1.7: TAB hides the asset + properties asides for a full-width stage Press TAB to slide the asset sidebar and the properties aside off-screen and let the stage absorb their grid columns; press again to bring them back. Skipped while typing in inputs so form-field focus traversal keeps working. --- package.json | 2 +- src/App.vue | 49 ++++++++++++++++++++++++++++++++++++++++++- src/devtools/tests.ts | 42 +++++++++++++++++++++++++++++++++++++ src/version.ts | 2 +- 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 63435e0..1313ff9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "ruwio", "private": true, - "version": "1.1.6", + "version": "1.1.7", "type": "module", "scripts": { "dev": "vite", diff --git a/src/App.vue b/src/App.vue index abf23c5..cd3a57f 100644 --- a/src/App.vue +++ b/src/App.vue @@ -85,6 +85,12 @@ function readStoredTimelineHeight(): number { const timelineHeight = ref(readStoredTimelineHeight()) +// Hide the asset sidebar + properties aside on TAB so the stage +// gets the full width. Toggled, not held — press TAB again to bring +// them back. Session-only state; we don't persist this so reopening +// the app always starts with the panels visible. +const panelsHidden = ref(false) + function maxTimelineHeight(): number { return Math.max(MIN_TIMELINE_HEIGHT, window.innerHeight - MAX_TIMELINE_HEIGHT_MARGIN) } @@ -93,6 +99,8 @@ const appStyle = computed(() => ({ '--timeline-height': `${timelineHeight.value}px`, })) +const appClass = computed(() => ({ 'panels-hidden': panelsHidden.value })) + let resizeStartY = 0 let resizeStartHeight = 0 let resizePointerId = -1 @@ -366,6 +374,22 @@ function onKeyDown(e: KeyboardEvent) { testsOpen.value = true return } + // TAB toggles the side panels (asset sidebar + properties aside) + // so the user can give the stage the full window width on demand. + // Skipped while typing — TAB still has to walk between form fields + // inside dialogs / inputs as expected. + if ( + e.key === 'Tab' && + !e.ctrlKey && + !e.metaKey && + !e.altKey && + !e.shiftKey && + !isEditable(e.target) + ) { + e.preventDefault() + panelsHidden.value = !panelsHidden.value + return + } // Arrow-key nudge: 1px step, 10px with Shift. Intercepted before // any other key handler so the stage steals the event from browser // scroll / selectable regions. Skipped when the user is typing in @@ -499,7 +523,7 @@ onBeforeUnmount(() => {
-
+
@@ -691,6 +715,15 @@ onBeforeUnmount(() => { min-width: 0; height: 100%; position: relative; + transition: grid-template-columns 220ms var(--ease, ease); +} + +/* TAB-toggle: collapse the side columns so the stage takes the + full width. The asides themselves slide off via the .sidebar / + .properties transform rules below for a pop-out feel; the grid + transition smooths the stage's resize. */ +.app.panels-hidden { + grid-template-columns: 0 1fr 0; } .topbar { @@ -856,6 +889,13 @@ onBeforeUnmount(() => { flex-direction: column; min-height: 0; overflow: hidden; + transition: transform 220ms var(--ease, ease), opacity 180ms var(--ease, ease); +} + +.app.panels-hidden .sidebar { + transform: translateX(-100%); + opacity: 0; + pointer-events: none; } .sidebar-scroll { @@ -920,6 +960,13 @@ onBeforeUnmount(() => { background: var(--panel); border-left: 1px solid var(--border); overflow: auto; + transition: transform 220ms var(--ease, ease), opacity 180ms var(--ease, ease); +} + +.app.panels-hidden .properties { + transform: translateX(100%); + opacity: 0; + pointer-events: none; } .timeline { diff --git a/src/devtools/tests.ts b/src/devtools/tests.ts index 1a2fdf3..3dbaa4b 100644 --- a/src/devtools/tests.ts +++ b/src/devtools/tests.ts @@ -4621,6 +4621,48 @@ export function registerAllTests(): void { const btn = document.querySelector('button[aria-label="Create a new track group"]') expect(btn).toBeTruthy() }) + + test('TAB toggles .panels-hidden on the .app grid', async () => { + // Pressing TAB from the document root flips a class on .app + // that collapses the side / props grid columns. A second TAB + // restores them. Skipped while the user is typing in an input. + const app = document.querySelector('.app') as HTMLElement + expect(app).toBeTruthy() + // Reset to a known baseline — preceding tests may have left + // the panels in either state. + while (app.classList.contains('panels-hidden')) { + document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })) + await nextTick() + } + document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })) + await nextTick() + expect(app.classList.contains('panels-hidden')).toBe(true) + document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })) + await nextTick() + expect(app.classList.contains('panels-hidden')).toBe(false) + }) + + test('TAB inside an input does not toggle the panels', async () => { + // Typed-text inputs need TAB for focus traversal; the global + // toggle bails out via isEditable(). + const app = document.querySelector('.app') as HTMLElement + while (app.classList.contains('panels-hidden')) { + document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', bubbles: true })) + await nextTick() + } + const input = document.createElement('input') + input.type = 'text' + document.body.appendChild(input) + try { + input.dispatchEvent( + new KeyboardEvent('keydown', { key: 'Tab', bubbles: true }), + ) + await nextTick() + expect(app.classList.contains('panels-hidden')).toBe(false) + } finally { + document.body.removeChild(input) + } + }) }) suite('app — arrow-key nudge', () => { diff --git a/src/version.ts b/src/version.ts index 660b842..a221450 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,2 +1,2 @@ -export const APP_VERSION = '1.1.6' +export const APP_VERSION = '1.1.7' export const APP_NAME = 'RUWIO'