Commit Graph

3 Commits

Author SHA1 Message Date
Frank Stellmacher 5231169a71 refactor(format): consolidate duration formatters into format/formatDuration (Phase L, part 2) (#690)
The mm:ss track-time formatter was hand-rolled in 11 places and the
h:mm:ss total-duration formatter in 4 — extract two tested functions:

- formatTrackTime(seconds, fallback='0:00')  — m:ss, used for track /
  playback times. fallback param covers the '–' placeholder rows.
- formatLongDuration(seconds)                — h:mm:ss when >=1h, else
  m:ss, used for album / queue totals.

Behaviour preserved per call site: the unified guard
(!seconds || !isFinite || <0 -> fallback) produces identical output to
every prior variant for all real inputs; SongRow keeps its '–' via the
fallback arg. Removes the formatter exports from 6 componentHelpers
files (playerBarHelpers / fullscreenPlayerHelpers deleted — they only
exported the formatter) and 7 inline component copies.

+ formatDuration.test.ts
2026-05-14 14:50:10 +02:00
Frank Stellmacher 7a7a9f5e6b refactor(utils): group utils/ files into topic folders (Phase L, part 1) (#689)
111 of 122 top-level src/utils/ files move into 16 topic folders (audio,
cache, cover, share, server, playback, playlist, deviceSync, waveform,
mix, format, export, changelog, ui, perf, componentHelpers). True
singletons with no cluster stay at the utils/ root.

Pure file-move: a path-aware codemod rewrote 539 relative-import
specifiers across 275 files; no logic touched. The hot-path coverage
gate list (.github/frontend-hot-path-files.txt) is updated to the new
paths for the 11 gated utils files — a mechanical consequence of the
move, not a CI change. tsc is green.
2026-05-14 14:27:44 +02:00
Frank Stellmacher 988806e6b1 refactor(player-bar): H7 — split PlayerBar.tsx 802 → 354 LOC across 10 files (#670)
* refactor(player-bar): H7 — extract PlaybackTime + RemainingTime + formatTime

The two memoized clock components (which update the DOM imperatively from
the playbackProgress store without re-rendering PlayerBar) move into
components/playerBar/PlaybackClock.tsx. formatTime helper → utils/playerBarHelpers.ts.

PlayerBar.tsx: 802 → 765 LOC.

* refactor(player-bar): H7 — extract PlayerTrackInfo

The cover-art wrap + title/artist marquees + star + last.fm love buttons
move into their own component. The new file uses PlayerState['openContextMenu']
for prop typing so the union literal type carries through.

PlayerBar.tsx: 765 → 674 LOC.

* refactor(player-bar): H7 — extract PlayerTransportControls

Stop/Prev/Play/Next/Repeat buttons (with the preview-ring + schedule-badge
overlays around play/pause) move into PlayerTransportControls.tsx. The
component uses ReturnType<...> on the source hooks to derive its
playPauseBind + scheduleRemaining prop types so the new file stays in lockstep
with usePlaybackDelayPress + usePlaybackScheduleRemaining.

PlayerBar.tsx: 674 → 621 LOC.

* refactor(player-bar): H7 — extract PlayerSeekbarSection

The waveform / radio progress / time-label block moves into its own
component. PlayerSeekbarSection branches on isRadio (AzuraCast progress
bar with elapsed+duration when available; LIVE badge otherwise) vs.
regular track (WaveformSeek or perf-flag fallback + duration ↔ remaining
toggle).

PlayerBar.tsx: 621 → 582 LOC.

* refactor(player-bar): H7 — extract PlayerVolume + PlayerOverflowMenu + 2 hooks

PlayerVolume.tsx is the reusable volume button + slider combo, used in
three layouts (inline, full menu, volume-only menu) — `inputId` /
`sectionModifier` / `wrapModifier` props handle the variants without
class duplication. PlayerOverflowMenu.tsx is the portaled Ellipsis-button
menu that hosts EQ / mini-player buttons + a PlayerVolume instance.

useFloatingPlayerBar owns the docked/floating layout computation
(ResizeObserver on sidebar + queue panel). useUtilityOverflowMenu owns
the overflow detection, menu open/mode state, close-on-outside-click /
Escape, position recompute on resize/scroll, and the wheel-menu timer.

PlayerBar.tsx: 582 → 354 LOC.
2026-05-13 23:24:57 +02:00