feat(audio-player): gear-menu default speed + split shortcuts into Mouse/Touch (plan §12)
Release / build-and-push (push) Successful in 3m13s
Release / build-and-push (push) Successful in 3m13s
The Player settings popover gains a 'Default playback speed' row beside autoplay — a compact rate select, always visible (the Speed ▾ footer hides when current == default, which made the setting undiscoverable at 1x/1×); same setDefaultSpeed PUT. The shortcuts dialog splits its pointer section into MOUSE (click/drag/shift/wheel) and TOUCH (drag/pull-away) — the bar has two scrub systems and the sections now say so.
This commit is contained in:
1 parent
3576a4415a
commit
03c3e151dc
4 files changed
+119
-28
No files matched your search
+14
-5
@@ -215,22 +215,31 @@ export function visibleKeymap(): KeyActionSpec[] {
|
||||
|
||||
// Pointer/wheel/touch interactions (plan §9) are not key events — the
|
||||
// dispatcher never sees them — but they belong in the same dialog so
|
||||
// every scrub gesture is discoverable in one place. templ x-fors this
|
||||
// table through the component's `pointerGuide` property (same binding
|
||||
// pattern as speeds/skipChoices).
|
||||
// every scrub gesture is discoverable in one place. TWO sections,
|
||||
// because the bar really does have two scrub systems (plan §12): the
|
||||
// desktop-pointer family and the touch family. templ x-fors these
|
||||
// through the component's `mouseGuide`/`touchGuide` properties (same
|
||||
// binding pattern as speeds/skipChoices).
|
||||
export interface PointerGuideRow {
|
||||
// Badge label, e.g. "Shift + drag".
|
||||
label: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const POINTER_GUIDE: readonly PointerGuideRow[] = [
|
||||
export const MOUSE_GUIDE: readonly PointerGuideRow[] = [
|
||||
{ label: "Click", description: "Seek — lands on a chapter line within a pixel's reach" },
|
||||
{ label: "Drag", description: "Free scrub across the whole bar" },
|
||||
{ label: "Shift + click", description: "Jump to the nearest chapter line" },
|
||||
{ label: "Shift + drag", description: "Precision rail (±5 min) around the nearest line" },
|
||||
{ label: "Wheel", description: "Nudge ±5s (Shift: ±60s)" },
|
||||
{ label: "Touch + pull away", description: "Scrub, then drag off the bar for fine control" },
|
||||
];
|
||||
|
||||
export const TOUCH_GUIDE: readonly PointerGuideRow[] = [
|
||||
{ label: "Drag", description: "Free scrub across the whole bar" },
|
||||
{
|
||||
label: "Pull away",
|
||||
description: "Drag off the bar while holding — the further you pull, the finer it gets",
|
||||
},
|
||||
];
|
||||
|
||||
// resolveShortcut maps a keydown's (key, altKey) to an action, or null
|
||||
|
||||
+10
-3
@@ -15,7 +15,13 @@
|
||||
import { Alpine } from "./alpine";
|
||||
import { renderNoteHtml } from "./markdown";
|
||||
import { showToast } from "./toast";
|
||||
import { POINTER_GUIDE, resolveShortcut, visibleKeymap, type KeyAction } from "./audio-keys";
|
||||
import {
|
||||
MOUSE_GUIDE,
|
||||
resolveShortcut,
|
||||
TOUCH_GUIDE,
|
||||
visibleKeymap,
|
||||
type KeyAction,
|
||||
} from "./audio-keys";
|
||||
import {
|
||||
SLEEP_CHOICES,
|
||||
SLEEP_OFF,
|
||||
@@ -202,8 +208,9 @@ Alpine.data("audioReader", () => ({
|
||||
// Exposed for the templ dropdown's x-for — templ cannot import the
|
||||
// const directly; this property is the binding.
|
||||
speeds: SPEEDS,
|
||||
// Same binding pattern, for the dialog's Mouse & touch section.
|
||||
pointerGuide: POINTER_GUIDE,
|
||||
// Same binding pattern, for the dialog's two scrub-system sections.
|
||||
mouseGuide: MOUSE_GUIDE,
|
||||
touchGuide: TOUCH_GUIDE,
|
||||
skipSeconds: Number(localStorage.getItem("audio_skip") || 10),
|
||||
// End-label display mode (§10): total → book remaining → chapter
|
||||
// remaining, persisted per device.
|
||||
|
||||
Reference in new issue
Block a user