* feat(settings): per-user date and time display format settings
Add ui.date_format (auto, DD/MM/YYYY, MM/DD/YYYY, YYYY-MM-DD) and
ui.time_format (auto, 12h, 24h) as validated user-scoped settings, a
shared preference-aware formatter module (web/src/lib/datetime.ts)
synced via DateTimeFormatProvider, a Date & time section in Appearance
settings, and convert all absolute date/time display call sites to the
shared formatters.
Closes#303
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(settings): make loaded API settings authoritative for date/time formats
Address adversarial review: once the authenticated settings request
resolves, a missing ui.date_format/ui.time_format key means "auto"
instead of falling back to device-wide localStorage (which could carry
another user's preference), and failed saves roll back through the
query cache. Layout and AdminLayout subscribe to the format store so
all routed pages re-render live when the preference changes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(settings): reliable re-render and rollback for date/time format changes
ReactiveAppRoutes re-renders the routed page tree when the format
preference changes (a Layout-level subscription cannot re-render stable
children elements); memoized AdminLogs rows and the out-of-route
PlayingNextScreen subscribe directly. useSetSetting now rolls back only
the mutated key on error and invalidates the settings list on settle so
overlapping saves cannot resurrect stale values.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(settings): guard same-key rollback against newer optimistic saves
Roll back a failed setting save only while its optimistic value is
still current in the cache, invalidate the detail query on settle, and
add a regression test for overlapping same-key mutations.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(settings): owner-bind the datetime format warm start, pad 24h hours
Address PR review: the localStorage warm start is now tagged with the
user id that mirrored it and is ignored for a different authenticated
user, so a failed settings request can no longer leak another account's
format on a shared browser. The 24h branch of formatTime defaults to
2-digit hours ("09:04") since h23 alone does not guarantee padding in
every locale.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Brings the web audiobook player to parity with best-in-class audiobook
apps (Audiobookshelf, Audible, BookPlayer) on the quality-of-life axis,
per docs/superpowers/plans/audiobook-player-qol.md:
- Keyboard shortcuts active on every route while the player is mounted
(space/K, arrow skips, volume, M, N/P chapters, shift+./, speed,
E expand, Esc collapse), inert while a video session exists.
- Configurable skip intervals with asymmetric defaults (back 10s,
forward 30s) via a new player settings popover.
- Speed control expanded to 0.5x-3x with a 0.05 stepper, presets, and
per-book memory (LRU-capped, device-local).
- Chapter prev/next transport buttons (prev restarts the chapter when
more than 3s in, the universal player convention).
- Volume/mute via the shared VolumeControl with a new theme-token
"surface" tone; persistence shared with the video player.
- Smart rewind: backs up 3-30s on resume scaled by pause length, plus a
flat 10s on cold resume from the detail page; explicit seeks are never
second-guessed. Toggleable in player settings.
- Now Listening time label cycles total / remaining / remaining at
current speed.
Chapter flattening is deduplicated into lib/audiobooks/chapters.ts, the
SkipIcon is shared between both player views, and new pure modules
(smartRewind, chapter nav, prefs) come with unit tests.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- Extract hardcoded trending snapshot source/window to named constants.
- Collapse the three identical personal-preset nil-checks into one case.
- Persist the selected preset through the shared storage util (try/catch
wrapped) instead of raw localStorage with manual SSR guards.
- Derive KNOWN_FILTERS from PRESET_OPTIONS so the lists can't drift.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>