From c2533e8a76a3ea356fc04008984ae1dfe066d20e Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 19 Feb 2026 16:51:54 +0200 Subject: [PATCH] docs: add design for 15 UI enhancements Mute toggle, fullscreen shortcut, seek feedback overlay, playlist search, scroll-to-current, PiP, timestamp insertion, keyboard help, speed shortcuts, reset confirmation, error state, double-click fullscreen, playlist stats, per-item progress bars, collapsible docks. --- .../2026-02-19-15-enhancements-design.md | 256 ++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 docs/plans/2026-02-19-15-enhancements-design.md diff --git a/docs/plans/2026-02-19-15-enhancements-design.md b/docs/plans/2026-02-19-15-enhancements-design.md new file mode 100644 index 0000000..d46da9a --- /dev/null +++ b/docs/plans/2026-02-19-15-enhancements-design.md @@ -0,0 +1,256 @@ +# TutorialVault — 15 UI Enhancements Design + +**Goal:** Add 15 real, polished enhancements to the TutorialVault frontend — all WCAG 2.2 AAA compliant. + +**Architecture:** All changes are frontend-only (TypeScript + CSS). No Rust/backend changes needed. Each enhancement is independent — no cross-dependencies between them. + +**Tech Stack:** TypeScript, CSS, HTML (Tauri v2 webview frontend) + +--- + +## Enhancement 1: Mute Toggle (M key + volume icon click) + +**What:** Press `M` to toggle mute. Click the volume icon to toggle mute. Muted state shows `fa-volume-xmark`, grays out the slider. Unmuting restores previous volume. + +**Files:** `main.ts`, `player.ts`, `player.css` + +**Behavior:** +- Store `lastVolume` before muting. Set volume to 0 on mute. +- On unmute, restore `lastVolume` (default 1.0 if none stored). +- Volume icon dynamically swaps: `fa-volume-high` (>50%), `fa-volume-low` (>0%), `fa-volume-xmark` (0/muted). +- Dragging the volume slider while muted unmutes automatically. + +**WCAG:** Volume icon gets `aria-label="Mute"/"Unmute"` dynamically. Muted visual uses icon change + reduced opacity (not color alone). + +--- + +## Enhancement 2: Fullscreen Shortcut (F key) + +**What:** Press `F` to toggle fullscreen. Mirrors the existing fullscreen button behavior. + +**Files:** `main.ts` + +**Behavior:** Add `case 'f':` to the keyboard switch. Calls the same fullscreen toggle as `fsBtn.onclick`. + +**WCAG:** No visual changes needed. + +--- + +## Enhancement 3: Seek Feedback Overlay + +**What:** Flash `−5s` / `+5s` text in the video overlay when seeking via arrow keys. Fades after 600ms. + +**Files:** `main.ts`, `player.ts`, `player.css` + +**Behavior:** +- New `showSeekFeedback(delta: number)` function in player.ts. +- Reuses the existing video overlay area. Shows text like "−5s" or "+5s" centered. +- Uses a CSS class `.seekFeedback` that fades in/out. +- Consecutive presses accumulate: pressing ArrowRight 3 times quickly shows "+15s". + +**WCAG:** Overlay area has `aria-live="assertive"` so screen readers announce "Seeked forward 5 seconds". Text meets 7:1 contrast (white on semi-transparent dark). + +--- + +## Enhancement 4: Playlist Search/Filter + +**What:** Search input above the playlist. Typing filters by video name or relative path in real-time. Shows "X of Y" while filtering. Clear button (x) resets. + +**Files:** `index.html`, `playlist.ts`, `playlist.css` + +**Behavior:** +- Add `` in the playlist `.panelHeader`. +- `renderList()` checks the filter value and skips non-matching items. +- Filter is case-insensitive, matches against `it.title`, `it.name`, `it.relpath`. +- Clear button appears only when input has text. +- Pressing Escape in the search input clears it. + +**WCAG:** `aria-label="Search playlist"`. Filtered count via `aria-live="polite"` region. Clear button has 44x44 target and `aria-label="Clear search"`. + +--- + +## Enhancement 5: Scroll-to-Current Button + +**What:** Button in playlist header that scrolls the active item into view. Only visible when the active item is off-screen. + +**Files:** `index.html`, `playlist.ts`, `playlist.css` + +**Behavior:** +- Uses `IntersectionObserver` on the `.row.active` element. +- Button appears (fades in) when active row is not visible. +- Clicking calls `activeRow.scrollIntoView({ block: 'center', behavior: 'smooth' })`. +- Icon: `fa-crosshairs` or `fa-location-dot`. + +**WCAG:** `aria-label="Scroll to current video"`. 44x44 touch target. Hidden with `display:none` when not actionable (removed from a11y tree). + +--- + +## Enhancement 6: Picture-in-Picture Button + +**What:** PiP toggle button next to the fullscreen button. Uses native `requestPictureInPicture()` API. + +**Files:** `index.html`, `player.ts` + +**Behavior:** +- New `iconBtn` after fsBtn: `