Commit Graph
136 Commits
Author SHA1 Message Date
vicrodh 61232c05ce fix(slint): rebuild search results view to match Tauri
The results view was bare text rows — nothing like the Tauri search.
Rebuilt it from the components the successful views already use:

- Albums: a Carousel of AlbumCard cover cards (All tab) and an AlbumCard
  grid (Albums tab).
- Artists: new ArtistCard (circular portrait) + ArtistCarousel; an
  ArtistCard grid on the Artists tab.
- Tracks: SearchTrackRow with a position number.
- The history nav pair (NavButtons) added to the view toolbar.

cc
2026-05-19 12:53:46 -06:00
vicrodh fa5f22e609 feat(slint): searchType filter dropdown for per-type tabs
The Albums / Tracks / Artists tabs get a QbzSelect filter (No filter /
Main artist / Performer / Composer / Label / Release name). Changing it
re-queries that category from offset 0 with the search_type and replaces
the list; load-more carries the active filter forward. The filter
resets on every new search. search_type_for_filter is unit-tested.

cc
2026-05-19 12:35:20 -06:00
vicrodh 6a584803f1 fix(slint): trim header nav-tab width by 6px
Drop 2px of left padding and 4px of right padding (after the caret) on
the Discover / Library / Local Library / My QBZ tabs.

cc
2026-05-19 12:30:04 -06:00
vicrodh 80f861779c fix(slint): symmetric spacing on the header sidebar toggle
The collapse toggle is a bare icon; the window-edge margin (Spacing.md)
was wider than its ~10px gap to the Discover tab. Drop the tab cluster
x to Spacing.xs so the toggle glyph sits symmetrically.

cc
2026-05-19 12:13:36 -06:00
vicrodh df2ffd2190 feat(slint): tabbed search results view
SearchResultsView is now a real results page: a five-tab strip (All /
Albums / Tracks / Artists / Playlists), an All-tab dashboard (top-result
hero plus a capped preview of each category with View more), and
per-type tabs showing the full loaded list. Album and playlist result
rows are file-local components; tracks reuse SearchTrackRow, artists
reuse SlimCard. The load-more button is in place; its callback is wired
in the next task.

cc
2026-05-19 12:01:34 -06:00
vicrodh 7a40fd660c feat(slint): SearchTrackRow with configurable artwork leading slot
A search-owned track row modelled on the album-page track row, but the
leading slot is a cover thumbnail (search tracks span many albums).
show-artwork keeps the slot configurable for a future shared component.
Compiled once SearchResultsView imports it (next task).

cc
2026-05-19 11:54:36 -06:00
vicrodh bb6fd1e0f3 feat(slint): minimal search results view, functional end to end
SearchResultsView renders the four SearchState categories; mounted in
AppShell on ContentView.search. Phase 1 is now functional end to end:
header input -> debounced search -> QbzCore::search_all -> results.
Phase 2 builds this into the tabbed dashboard.

cc
2026-05-19 11:46:16 -06:00
vicrodh 7073b6553f feat(slint): wire header search input with debounced live search
The header TextInput now submits on Enter (records history, opens the
results page) and live-searches on edit. Live search debounces 300 ms
via a Slint Timer and requires 2+ characters. A monotonic version
counter guards navigate_search so a stale load cannot overwrite newer
results.

cc
2026-05-19 11:42:12 -06:00
vicrodh b040a1d359 feat(slint): add SearchState globals and search ContentView
SearchState/SearchActions globals, SearchTrackItem/SearchPlaylistItem
structs, and a search variant on ContentView. Re-exported from app.slint
so the Rust layer can populate them. Nothing consumes them yet.

cc
2026-05-19 11:18:16 -06:00
vicrodh 862d408789 fix(slint): crisp button icons, tighter tabs, homologate nav buttons
Icon buttons (header lyrics/queue/hamburger, queue footer) centered
their glyph at a fractional offset (e.g. (36-19)/2 = 8.5px), which
renders blurry — the offset is now rounded to whole pixels. The
header tab spacing dropped from 4px to 2px. The Discover toolbar's
back/forward pair drifted 3px from where the album/artist/settings
views place it; both toolbar clusters now anchor their vertical
center to y=25 so the [<] [>] pair holds one position across views.

cc
2026-05-19 05:05:17 -06:00
vicrodh 9a964477e5 fix(slint): unblock header menu hover-switch, tighten panel + tabs
The click-outside scrim was a full-window TouchArea — it covered the
tabs and intercepted their hover events, so hover-switching between
menus still did not work (same failure mode as the old PopupWindow
grab). The scrim now starts below the header, leaving the tabs
hoverable. The panel also dropped from header-height + 6px to 45px,
removing the unjustified gap between the tab and its dropdown. Header
tab labels lost another 2px of right padding.

cc
2026-05-19 04:53:03 -06:00
vicrodh 5972e8052b feat(slint): in-window overlay for nav-tab dropdowns with hover-switch
Add HeaderMenuOverlay, a plain in-window Rectangle rendered as the last
child of the AppShell root so it draws on top of the header and content
region. Unlike a PopupWindow it does not grab the pointer, so the header
tabs stay hoverable while a menu is open — hovering from one tab to
another overwrites HeaderMenuState and switches the menu instantly.

Behaviour preserved from the old PopupWindow menus:
  - hover-to-open and click-to-open
  - 1.5s idle auto-close, restarted on pointer activity over the panel
    or its rows and on every tab (re)publish via a changed handler
  - click-outside-close via a full-window transparent scrim
  - Discover home-item row still switches to ContentView.home
  - glyphs on all menus except Discover
Menu panel visuals are unchanged: surface-main bg, 1px border-muted,
Radius.sm, 24px drop shadow, 188px wide.

cc
2026-05-19 04:41:11 -06:00
vicrodh b6f5631f51 refactor(slint): publish nav-tab menus into HeaderMenuState global
The four header nav tabs each owned a PopupWindow for their dropdown.
A PopupWindow grabs the pointer while open, so hovering a sibling tab
delivered no hover event and the menus could not be hover-switched.

Add a HeaderMenuState global (open-index, anchor-x, items, home-item)
and the NavMenuEntry struct to state.slint. Tabs now write their
identity into the global on hover/click instead of showing a popup;
the menu panel itself will be rendered by a separate in-window overlay.
Move NavMenuItem into its own file so the overlay can reuse it.

cc
2026-05-19 04:37:26 -06:00
vicrodh 3aa902292e fix(slint): toolbar vertical align, header toggle, queue menu clicks
The Discover toolbar's side layouts had no explicit height, so they
filled the 56px bar and y resolved to 0 — the tab pill, genre filter
and gear stuck to the top instead of centering. Both now carry
height = preferred-height.

The header sidebar toggle dropped from a 19px to a 14px icon: it now
matches the nav-tab icon size and tint, and the 30px box centers it
on whole pixels (was 5.5px → blurry).

The queue row's click TouchArea was declared after the content, so it
sat on top and ate the context-menu button's clicks — the [...] just
skipped to the track. It is now declared before the content, so the
menu button keeps its own clicks.

cc
2026-05-19 04:32:37 -06:00
vicrodh c73e7ac767 feat(slint): add Play next to track and album context menus
Add a "Play next" ContextMenuItem above "Add to queue" in every menu
that offers queueing: the album page track menu, the artist page track
menu, and the discover album card menu. Play next uses the list-plus
icon and Add to queue switches to list-end, matching Tauri's ListPlus /
ListEnd icon mapping. The queue sidebar track menu is left untouched.

cc
2026-05-19 04:18:47 -06:00
vicrodh 6203a2db26 feat(slint): wire play-next media action for tracks and albums
Add play_track_next and enqueue_album_next to playback.rs, calling the
core's add_track_next to insert after the current track. Album play-next
inserts tracks in reverse so they land in order, mirroring Tauri's
v2_add_tracks_to_queue_next. Route ("track"/"album", "play-next")
through the on_media_action handler. Add the lucide list-end icon used
for the existing "Add to queue" item.

cc
2026-05-19 04:18:42 -06:00
vicrodh fe815318db fix(slint): center search placeholders, fix queue menu trigger
Search placeholders rode at the top of the input because the text
had no height to center within — they now span the box like the
TextInput. The queue row context-menu trigger is always visible with
a proper 32px hit area (matching the album track rows) instead of a
hover-only 24px dot cluster, so a near-miss no longer falls through
to the row and skips the queue.

cc
2026-05-19 04:13:12 -06:00
vicrodh 3134b83d72 feat(slint): move the sidebar toggle into the header
The sidebar collapse toggle is now an icon-only button at the far
left of the header, before the Discover tab. Removed from NavButtons,
which is now just the back/forward history pair.

cc
2026-05-19 04:13:12 -06:00
vicrodh a65b5de535 fix(slint): group Discover history + tabs left, fix toolbar overlap
The right controls (genre filter + gear) used x = parent.width -
self.width - 32px on a width-less HorizontalLayout, which fills the
toolbar so self.width = full width and the cluster landed far left,
on top of the history arrows. Side layouts now carry an explicit
width = preferred-width. The three-tab bar is no longer centered: it
sits next to the history buttons with a 16px gap. The home-gear icon
grew 2px.

cc
2026-05-19 04:04:33 -06:00
vicrodh e822bf6601 chore(slint): add home-gear icon asset
Add the home-gear.svg icon used by the Discover toolbar sort gear
button.

cc
2026-05-19 03:20:18 -06:00
vicrodh 787973dfc3 feat(slint): make header search a real input, narrow to 80%
Replace the header search field's static placeholder text with a real
TextInput plus an empty-state placeholder, matching the album
track-search pattern so the field clearly reads as an input. Reduce the
search field width to 80% of its prior size (224/320px to 179/256px).

cc
2026-05-19 03:20:12 -06:00
vicrodh b6355dc202 feat(slint): auto-close nav-tab dropdowns on idle
Add a 1.5s idle-close timer to each header nav-tab dropdown. The timer
is armed when the menu opens and reset on any pointer hover or movement
over a menu row; on timeout the popup closes itself. Single-open is
already enforced by Slint, since only one PopupWindow can be open per
window, so sweeping across hover-to-open tabs closes the previous menu
automatically. Hover-to-open and click-to-open both remain working.

cc
2026-05-19 03:20:06 -06:00
vicrodh e48c9331e2 style(slint): center Discover tab bar and swap sort gear icon
Anchor the Discover toolbar's history buttons and genre/gear controls
to the toolbar edges and absolutely center the three-tab nav pill so it
sits at the true horizontal center. Swap the sort gear icon to the
home-gear asset.

cc
2026-05-19 03:13:36 -06:00
vicrodh 6b31abcea4 style(slint): restyle sidebar toggle and history nav buttons
Make the sidebar collapse toggle a bare icon button with no background
pill, brightest text-primary tint, and a 2px larger icon. Restyle the
back/forward history buttons to match the Discover carousel page
navigators (circular elevated buttons) instead of the tab pill style.

cc
2026-05-19 03:10:07 -06:00
vicrodh ff1ad3c619 test(slint): switch the font test to bundled Inter
Replaces the LINE Seed JP probe with Inter 18pt (Regular/Medium/
SemiBold/Bold static faces, compile-time embedded). Inter is a clean,
screen-tuned UI face; with the femtovg #5177/#11335 fixes it is the
candidate for the final look. FONT_TEST_INTER toggles back to the KDE
system font.

cc
2026-05-19 02:50:21 -06:00
vicrodh 0606826df4 feat(slint): match queue footer to Tauri and add the track menu
Footer now carries the five Tauri controls with Tauri's icons — clear
(trash-list), save (add-to-list), infinite, sleep timer (clock), and
search; the timer button is visual-only for now. Queue rows gain a
context menu 1:1 with the Tauri queue track menu (Remove from queue,
Stop after this, Remove all after, Add to playlist, Track info); only
Remove is wired, the rest are placeholders.

cc
2026-05-19 02:50:21 -06:00
vicrodh 21b0ade357 fix(slint): tighten the header right-side controls by 2px
cc
2026-05-19 02:50:05 -06:00
vicrodh e49899755a fix(qbz-slint): group and order ALSA output devices like the Tauri app
The Output Device dropdown, on the ALSA backend, listed devices flat,
unordered, with the BP badge on too many rows. Port the Tauri
DeviceDropdown.svelte ALSA behaviour:

- Regroup devices into Defaults / Bit-perfect (Hardware / Digital) /
  Plugin Hardware / Other Outputs, in that order, with a section header
  above the first row of each non-empty section.
- Align device_is_bit_perfect (the BP badge rule) with the Tauri ALSA
  bit-perfect group: hw: / front:CARD= / iec958: only. hdmi: and
  sysdefault: route through plugins and no longer get the badge.
- The regrouped ids stay index-aligned with SettingsMaps.devices, so the
  settings-select("device", i) callback still resolves to the right id
  and selected-device persistence is unaffected.

cc
2026-05-19 02:28:24 -06:00
vicrodh 9f86197f60 feat(qbz-slint): add optional section headers to QbzSelect
QbzSelect gains an optional `groups` property parallel to `options`: a
non-empty entry renders a non-selectable, muted-caps section-header row
above that option in the open list. The header is plain text, no pill
background, matching the QBZ design rule.

The popup now self-sizes from the list layout's preferred height so the
extra header rows are accounted for. `groups` defaults to empty, so the
backend and sample-rate selects (which never set it) render unchanged.

cc
2026-05-19 02:28:14 -06:00
vicrodh b17cb5de71 test(slint): bundle LINE Seed JP for a font-rendering comparison
Slint 1.14 has no public register_font API, so the .ttf is imported
in app.slint (compile-time embed + registration) and selected via the
FONT_TEST_LINESEED toggle in main.rs. Flip the toggle to false to
restore the KDE system font.

cc
2026-05-19 02:08:13 -06:00
vicrodh 095888a269 feat(slint): open header tab menus on hover
The nav-tab dropdowns now open when the pointer enters the tab, no
click required. NavTab gained a hovered callback fired from a
changed has-hover handler; click-to-open still works.

cc
2026-05-19 02:08:13 -06:00
vicrodh 25ac4a0e35 feat(slint): build out the queue sidebar UI
Port the Tauri QueuePanel into QueueSidebar.slint: a Queue/History tab
switch, a highlighted NOW PLAYING card with a favorite heart toggle, a
paginated UP NEXT list with a Tauri-style counter (UP NEXT (N of M, K
left)) and prev/next page controls, four footer actions (clear, save as
playlist, infinite play, search) plus an inline queue search field.

Tabs and actions are plain text / plain icon buttons with no pill
backgrounds, per the QBZ design rule. All strings go through @tr. The
panel-open width animation is preserved; opening the panel fires
panel-opened so the controller pulls a fresh snapshot.

cc
2026-05-19 01:49:56 -06:00
vicrodh 747ae6082c feat(slint): extend QueueState model for the queue sidebar
Restructure the QueueState global so the sidebar can render two tabs and
a paginated upcoming list: separate now-playing / upcoming-page / history
properties, paginator counters, tab and search state, and callbacks for
every control. QueueItem gains duration and explicit fields. Adds a
favorite semantic color token and the heart-filled, infinity and list-x
icons the sidebar needs.

cc
2026-05-19 01:49:32 -06:00
vicrodh e80df21cfe feat(slint): render with the desktop UI font
The app now resolves the KDE Plasma general font from kdeglobals and
sets it as the window default-font-family, so the UI matches the
desktop instead of the bundled Slint default. Falls back cleanly off
KDE. A full font picker lands later with Settings > Appearance.

cc
2026-05-19 00:03:06 -06:00
vicrodh 9dd7002c5d fix(slint): center header tab labels, brighten and shrink them
Tab labels rode high against their glyph and the header because a
bare Text box sits high on its descender space. They now use an
explicit row-height box with vertical-alignment, drop one point to
11px, and take the brightest text color.

cc
2026-05-19 00:03:06 -06:00
vicrodh 87cf74764c fix(slint): correct BP marking and widen the output-device list
The BP badge marked every ALSA device; it now marks only the direct
hardware PCMs (hw:/front:/iec958:/hdmi:), matching Tauri — sysdefault
and plug devices are not bit-perfect. The device list also opens at
480px (right-anchored) so the full card + PCM id name is readable
instead of being elided in a 300px control.

cc
2026-05-19 00:03:06 -06:00
vicrodh 9cf2c5588f feat(slint): mark bit-perfect-capable devices in the output select
The output-device select now shows an accent BP marker on devices
able to deliver bit-perfect audio: every ALSA hw card, hardware nodes
on PipeWire, none under PulseAudio. QbzSelect gained an optional
parallel badges array so other selects are unaffected.

cc
2026-05-18 23:40:11 -06:00
vicrodh 5ae303157a feat(slint): wire volume mute toggle in the player bar
The volume icon now toggles mute: it stashes the current level, drops
the player to zero, and swaps to the volume-x glyph. Unmute restores
the level, and any non-zero set-volume (slider drag or step) clears
the mute so the two controls stay consistent.

cc
2026-05-18 23:31:44 -06:00
vicrodh c0490175f7 feat(slint): homologate menu surfaces with a defined muted border
Dropdown and context menus now sit on the content background
(surface-main) with a more defined border (border-muted, ~22% white)
instead of the elevated surface plus hairline border, so the popover
edge reads cleanly against the content instead of looking coarse.

cc
2026-05-18 23:06:29 -06:00
vicrodh 4636194043 fix(slint): album description fills the band right of the artwork
The header description wrapped at its natural width and left the
space to the right unused. It now spans the full width to the page
edge (bound to root.width to avoid a layout binding loop), and the
truncation grew from 200 to 360 chars so the wider band reads full.

cc
2026-05-18 23:06:29 -06:00
vicrodh c273506800 feat(slint): wire shuffle, repeat and volume buttons in player bar
Shuffle toggles via core; repeat cycles off/all/one and swaps to the
repeat-1 glyph for one-track mode. Volume minus/plus step the level
by 5%. State flows back through NowPlayingState.

cc
2026-05-18 22:43:31 -06:00
vicrodh f283de57e3 feat(slint): match header dropdown icons, align tab text, tighten menus
Header nav tabs now use the same icons as Tauri (compass, music
library, hard drive, cassette) and the dropdown sub-items carry
leading glyphs everywhere except Discover, which stays text-only.
Tab label text is centered vertically against its glyph and the
header. Dropdown and context menus drop from Radius.md to Radius.sm
so their corners match buttons and album cards.

cc
2026-05-18 22:43:31 -06:00
vicrodh 10d4dc5738 fix(slint): tint AlbumCard cd-tier badge icon light
The cd.svg quality badge rendered black/transparent; switched the
Image to QbzIcon with a light tint so it matches the Tauri look.

cc
2026-05-18 22:43:13 -06:00
vicrodh 1f6159f3ba feat(slint): split sidebar toggle from nav buttons, animate side panels
NavButtons now renders the collapse toggle and history buttons as two
spaced pills instead of separating them with a bar. Queue and Lyrics
sidebars animate their own width open/closed (160ms ease-in-out) so
they slide in like the main sidebar instead of appearing abruptly.

cc
2026-05-18 22:43:13 -06:00
vicrodh 7e6e548598 feat(slint): minimal playback wiring + Queue, plus detail/Settings fixes
Playback (minimal, album-focused):
- playback.rs controller: play an album (set queue + start audio),
  play a single track, enqueue, play a queue index, transport
  (play/pause, next, previous, seek, volume)
- the audible step uses Player::play_track (fetch -> download -> play);
  the protected audio backend is untouched
- a 450ms poll loop pushes position/progress/times/playing onto
  NowPlayingState and auto-advances at end of track
- NowPlayingState / QueueState globals; NowPlayingBar bound to real
  state (song card, seek bar, transport, volume); QueueSidebar lists
  the queue and rows play on click
- a played track is recorded into the recently-played store

Detail views:
- album description and artist biography stay with the metadata,
  filling the width to the right of the artwork (not below the header)
- header nav tabs gained a dropdown caret and 2px side padding

Settings > Playback defaults are now opt-out: show context icon,
restore session, resume position and stream-uncached default on;
streaming-only stays opt-in; initial buffer defaults to 2s.

Known gaps: queue/now-playing artwork not yet threaded (Image is not
Send); autoplay-mode preference not consulted by auto-advance; buffer
progress line stays at 0.

cc
2026-05-18 22:16:13 -06:00
vicrodh 33df7bce76 feat(slint): collapsible sidebar, Queue/Lyrics panels, nav menus
Shell chrome (steps 1-3):
- Left sidebar is collapsible — a toggle in the nav cluster (left of the
  [<] [>] pair) and a draggable right edge that resizes 200-420px and
  collapses below 160px. ShellState global drives it.
- Queue and Lyrics right sidebars: 320px panels rendered as layout
  siblings, so opening one pushes the content area narrower rather than
  overlaying it. The header captions/queue buttons toggle them
  (mutually exclusive) and light up when active.
- The four nav tabs (Discover/Library/Local Library/My QBZ) open
  dropdown menus listing their sub-sections; Discover -> Home is wired.

Detail views (steps 4-5):
- Track rows: the even-row tint is now clearly fainter than the hover
  tint so the two states no longer look identical.
- The favorite and offline-cache glyphs in album track rows are real
  buttons (hover state, emit media-action).
- Album header artist link uses the metadata text color, bold, instead
  of the accent blue.
- Album description and artist biography span the full content width
  below the header block.

cc
2026-05-18 21:54:31 -06:00
vicrodh 99e3513d68 feat(slint): NowPlayingBar rebuild, Settings constraints, Discover fixes
NowPlayingBar (start of the playback-bar work):
- height raised to 110px
- SeekBar component: three-line track (total / cached / progress), a
  hover thumb, elapsed/remaining times, and a hover time bubble with a
  downward caret marking the seek position
- song card: background and border dropped, gains the extra height,
  album/artist links and the context icon kept (context icon now
  always shown)
- transport + secondary buttons copied from Tauri (shuffle, prev,
  play, next, repeat, add, favorite; cast, picture-in-picture,
  fullscreen, normalization; volume cluster). Queue/Lyrics stay in the
  header — and the header now orders them lyrics-then-queue.

Settings constraints (1:1 with Tauri):
- Exclusive Mode enabled only on ALSA; DAC Passthrough only on
  PipeWire; Lock Output Device disabled while DAC Passthrough is on;
  Gapless disabled while Streaming Only is on
- backend change cascades: forces off DAC passthrough / force-bit-
  perfect / exclusive / gapless as appropriate; DAC-passthrough and
  streaming-only cascades; initial-buffer slider right-aligned

Discover fixes:
- navigation [<] [>] pair homologated to the same top/left margin
  across every view
- album/artist description moved back into the metadata column (it now
  fills the width there) with uniform secondary text color
- genre filter button hugs its label instead of stretching
- Recently Played Albums and Tracks modules always render, with a
  placeholder until the play history has data
- wider spacing between Discover rows; the Discover gear is no longer
  a Settings shortcut (it is the per-tab sort/show-hide control)

cc
2026-05-18 21:22:40 -06:00
vicrodh edca636a16 feat(slint): Settings Audio/Playback 1:1 with Tauri
Rebuild both Settings panels to match the Tauri app — every option
present, on the correct tab, and fully functional (persisted and
applied to the live player).

Audio: streaming quality, limit-quality-to-device, maximum sample rate,
backend, output device, ALSA plugin, hardware volume, exclusive mode,
reserve DAC, DAC passthrough, force bit-perfect, allow quality
fallback, sync-on-startup, lock output device, and a reset button.
Conditional rows (ALSA plugin, hardware volume, max sample rate, force
bit-perfect, lock output device) are gated on Rust-computed flags.

Playback: continue-after-track, show context icon, gapless, restore
session, resume position, stream uncached, initial buffer size (slider),
streaming only, quality-retry behavior. Note gapless and the streaming
options live on the Playback tab though the qbz-audio struct stores them.

- ui_prefs.rs: JSON store for the frontend-only streaming-quality pref
- QbzSlider primitive for the integer buffer-size control
- volume normalization row removed (Tauri hides it)

Caveat: toggling reserve-DAC persists and is read live, but re-arming
the device reservation guard mid-session needs a player-side API that
does not exist yet; it takes effect on next launch.

cc
2026-05-18 20:47:12 -06:00
vicrodh 1089761e74 fix(slint): widen the album/artist description area
Move the album description and the artist biography out of the metadata
column to span the full content width below the header block, so the
text is no longer cramped into the narrow column beside the artwork.

cc
2026-05-18 20:36:04 -06:00
vicrodh 12ed5a7c4a feat(slint): browser-like back/forward navigation history
Add a navigation history so pages can be walked back and forward.

- nav.rs: a back/forward stack of NavEntry (home, album, artist,
  settings); record() on fresh navigation, go_back/go_forward to walk it
- NavButtons: a [<] [>] pair styled like the Discover tab group; inline
  beside the Discover tabs and in place of the per-page Back button on
  album, artist and settings views
- All navigation routes through Rust (open-album/-artist record entries;
  the gear and header menu use NavState.request-settings) so the history
  stays accurate; back/forward re-apply entries, re-loading entity pages
- AppShell listens for the mouse back/forward buttons
- can-back / can-forward drive the buttons' enabled state

Also in this round:

- Album header description: render a pre-truncated short string so it
  wraps to a couple of lines instead of overflowing the header; the full
  text stays in the Read-more modal
- Header queue button uses an ordered-list icon (the previous one read
  as a playlist)

cc
2026-05-18 20:17:54 -06:00