* feat(settings): clock format setting (Auto / 24h / 12h)
Reported on the Psysonic Discord — the Queue side panel's ETA label
and the sleep-timer preview both render via `formatClockTime`, which
just calls `toLocaleTimeString` and so follows the user's system
locale. On en-US that means AM/PM, with no in-app way out.
Add a tri-state **Clock Format** setting under
**Settings → System → App Behavior**:
* `auto` (default) — keep the existing locale-driven behaviour, so
bestehende installs are unaffected on first launch.
* `24h` — force 24-hour wall-clock output everywhere
`formatClockTime` is used.
* `12h` — force AM/PM output.
Wired through `authStore` (`clockFormat`, `setClockFormat`), exposed
via `CustomSelect` in `SystemTab`, and threaded into the two
consumers (`QueueHeader`, `PlaybackDelayModal`) so they re-render on
change. `formatClockTime` itself stays a pure helper — it accepts the
setting as an optional second argument and maps it to `hour12`.
Locale coverage: all nine bundled locales (en, de, es, fr, nl, nb,
ru, zh, ro) get the four new settings strings. Pin tests added for
the `setClockFormat` setter and the `hour12` mapping in
`formatClockTime`.
* docs(changelog): clock format setting + contributors (PR #742)
Adds a new sub-section under Settings → Personalisation (Advanced) that
hides individual controls in the player bar: Star rating, Favorite
(heart), Last.fm love, Equalizer, Mini player. Last.fm love still only
renders when a Last.fm session exists; the overflow row in the player
collapses when both Equalizer and Mini player are hidden.
- New `playerBarLayoutStore` (Zustand + persist, items[{id, visible}] +
rehydrate sanitize) following the queueToolbar / playlistLayout
pattern; defaults to all visible.
- New `PlayerBarLayoutCustomizer` reuses the same row + toggle pattern
as the other personalisation customisers.
- Gates threaded through `PlayerTrackInfo` (3 controls), `PlayerBar`
(EQ + Mini buttons), and `PlayerOverflowMenu` (EQ + Mini in the
overflow row, with row-level conditional).
- `PersonalisationTab`: added as the last advanced sub-section so it
only appears when the global Advanced Mode toggle is on.
- Settings search index gets entries for both Playlist page layout and
Player bar (playlist row was missing).
- New i18n keys `settings.playerBar*` in all 9 locales.
Reuses kveld9's design from PR #627; not merged because the locale
split and the Advanced Mode refactor landed afterwards. Credited via
Co-Authored-By trailer + a new line in settingsCredits.ts under the
existing kveld9 entry.
Co-authored-by: Kveld. <kveld912@proton.me>
Adds a per-element visibility toggle for the playlist detail page (Add
Songs, Import CSV, Download ZIP, Cache Offline, Suggestions) and reworks
the way uncommon options are surfaced: instead of a per-tab collapsible
group, a global "Advanced" toggle in the Settings header reveals all
`advanced` sub-sections across every tab and marks each one with a small
badge. Sets the pattern up so any future advanced option lives in its
natural tab, gated by the same switch.
- New `advancedSettingsEnabled` boolean on `authStore`
(UiAppearance slice, persisted with the rest of the store).
- `SettingsSubSection` gains an `advanced?: boolean` prop. Hidden when
the toggle is off; renders an "Advanced" pill in the header when on.
- Settings header gets a Toggle-Switch next to the search lupe.
- `PersonalisationTab` flattens — Sidebar + Home stay always visible;
Artist sections, Queue Toolbar, and the new Playlist layout get
`advanced` and disappear by default. `PersonalisationAdvancedGroup`
component + CSS removed.
- New `playlistLayoutStore` (Zustand + persist, items[{id,visible}] +
rehydrate sanitize) following the queueToolbarStore pattern.
- `PlaylistHero` and `PlaylistSuggestions` gate the four toolbar buttons
and the suggestions rail on the store directly.
- One-time migration in MainApp on mount: if the user had opened the
old per-tab Advanced group (`psysonic_personalisation_advanced_open
=== 'true'`) OR already customised any of the three sub-sections,
Advanced Mode auto-enables on first launch. Idempotent via a
localStorage flag; legacy key removed afterwards.
- New i18n keys `settings.advancedMode`, `settings.advancedModeTooltip`,
`settings.advancedBadge`, `settings.playlistLayout*` in all 9 locales.
Reuses kveld9's design from PR #556; not merged because the locale split
landed afterwards. Credited under the existing kveld9 entry in
settingsCredits.ts.
Co-authored-by: Kveld. <kveld912@proton.me>
Each src/locales/<lang>.ts (~1800 LOC) becomes a folder src/locales/<lang>/
with one module per i18n namespace (44 each) plus an index.ts barrel that
reassembles <lang>Translation in the original key order.
Mechanical, script-driven split with a JSON round-trip check: every
locale object is byte-identical to its pre-split form. i18n.ts is
unchanged — './locales/<lang>' now resolves to the folder index.
The per-namespace settings.ts files land ~440-460 LOC; a single i18n
namespace is the natural, non-arbitrary split unit for a flat string
table, so they are intentionally left whole.