Commit Graph
11 Commits
Author SHA1 Message Date
logan 792e87298b fix(ui): stop the album grid eating the year it was sorted by
CI / check (push) Skipped
CI / e2e (push) Skipped
CI / check (pull_request) Successful in 2m30s
CI / e2e (pull_request) Successful in 6m5s
The year sat inside the same ellipsis box as the title, so it was the
first thing truncation took: a card wide enough for a long album name
never showed its year, and browsing the grid *by year* showed years
only for the albums with short names. The sort said one thing and the
cards showed another.

Title and year are now a flex row where only the title gives way. A
row rather than a second line, because the card's height is what the
virtualizer measures rows by.

Refs #29
2026-08-18 11:08:37 -04:00
logan 71324b561a feat(albums): draw the album dropdown that was already being computed
Search index maintenance / maintain-index (push) Successful in 6s
Build & publish Arch package / arch-package (push) Successful in 2m1s
CI / check (push) Successful in 2m27s
CI / e2e (push) Successful in 4m49s
Enter on an album card fetched the album's tracks over the IPC and ran
the whole split state machine (splitMode true, splitIndex measured
against the real container), then render() drew the single grid because
it never consulted splitMode; connectedCallback referenced
renderSplitGrid only to satisfy noUnusedLocals. perf.p2 files this as
dead code — it is the only route from the albums grid to track-details,
since a plain click navigates to the catalog page instead.

Two things it needed that the audit does not mention. The grid could
not scroll: .grid-scroll-container is the markup artists-view and
genres-view use, and cover-grid had the class with no rule for it, so
186984px of albums sat in a 772px box at 5000 albums, unreachable by
wheel, keyboard or scrollbar — and that is the element scroll-manager
saves and restores, so its scrollTop was permanently 0. And the shared
context menu was labelled 'Album actions' unconditionally, which nothing
could observe while a track menu was unreachable.

Both halves of the split grid carry the listbox semantics the single
grid gained in the ARIA pass.
2026-08-12 15:10:05 -04:00
logan b7dc368d7c feat(ui): give every primary view the same page header
Build & publish Arch package / arch-package (push) Successful in 2m0s
CI / check (push) Canceled after 14s
CI / e2e (push) Canceled after 0s
Search index maintenance / maintain-index (push) Canceled after 0s
Four views had a heading and four did not, two had a sort control and
none showed a count, so the app changed shape as you moved through it
and "how many albums have I got" could only be answered by counting.
The reason they disagreed is that each had written its own arrangement:
the sort toolbar existed three times, in track-list, cover-grid and
playlist-view, as the same twenty lines with different bugs.

<page-header> is that arrangement once - title, count, sort, actions -
and nine views adopt it. Artists and Genres gain the sort control they
never had; Artists sorts by name only, because library.Artist carries
nothing countable, so the header renders a label and a direction button
rather than a select with one option in it. The header keeps its place
while a view loads: a heading that appears only once the data does is
the shifting layout this is meant to stop. The count is omitted, not
zero, until the view has an answer.

The header search box keeps its slot on every view instead of vanishing
on the ones it cannot serve - which is what moved the library filter
and the job indicator on every navigation. It is view-scoped by
decision and now says so: "Search albums" in the placeholder, the scope
named in the header ("Showing artists matching 'tide'"), and disabled
with a reason where there is nothing to search or the page has a search
of its own.

Also fixes an e2e trap this uncovered: the view-lifecycle spec toggled
shuffle and never toggled it back, so a second run against the same app
failed playback.spec's shuffle assertion - a failure that reads exactly
like a regression in whatever you are holding.
2026-08-12 02:35:35 -04:00
yonlu 2825373c3c fix: add height:100% to all views missing it — eliminates top gap
Views with contain:layout in shadow DOM need explicit height:100%
on :host so their internal flex layout fills the parent's flex
space. Without it, the component doesn't know its height and the
internal content doesn't stretch to fill the panel.

Added height:100% to: cover-grid, artists-view, genres-view,
playlist-view, track-list, config-page (also box-sizing).
explore-view and detail views already had it.
2026-03-30 04:03:51 -04:00
yonlu a4eac394ce perf: inline SVGs, memoize grid slices, batch store notifications
- Replace wa-icon shadow DOM with inline SVG in queue-panel (xmark)
  and album-dropdown (fav icons) to eliminate per-item shadow roots
- Memoize getBeforeEntries/getAfterEntries in cover-grid to prevent
  .slice() creating new array refs that trigger virtualizer relayout
- Remove transition: scale and border-radius from album cards to
  avoid per-frame repaints and anti-aliased path clipping
- Add queueMicrotask batching to player-store and favorites-store
  notify() to coalesce rapid-fire updates into single renders
2026-03-15 09:29:40 -04:00
yonlu 199c91013f perf: reduce software rendering overhead for NVIDIA+Wayland
Targeted optimizations for the DMABuf-disabled rendering path where
every frame is software-composited:

- Replace infinite CSS scroll-text animation with transition-based
  cycle that only repaints during active scroll, not during pauses
- Remove CSS mask-image on scrolling text (mask + animation was the
  single most expensive continuous repaint)
- Replace wa-icon in track rows with inline SVG — eliminates 30-50
  shadow DOM trees (each with SVG fetch/parse) during scroll
- Remove hover transitions on album cards, artist cards, genre cards,
  fav icons, queue remove buttons — each transition was causing
  per-frame software repaints
- Use visibility:hidden instead of opacity:0 for queue remove button
  (binary switch vs per-frame alpha blend)
- Add decoding=async to now-playing cover art images (prevents
  main-thread blocking during image decode on track change)
- Add contain:strict to fixed-height track rows (33px) and queue
  items (49px) — browser skips size contribution calculations
2026-03-15 09:00:59 -04:00
yonlu 3b2e189e7d fix(14-perf): fix scroll jumping and input latency
Root causes addressed:
- track-list had no _itemSize hint for flow layout — virtualizer
  defaulted to 100px, measured actual ~33px rows, then called
  _correctScrollError/scrollTo on every scroll causing visible jumps
- will-change:transform on virtualizer elements caused nested GPU
  layers (virtualizer positions children with transforms internally)
  adding compositor overhead instead of helping
- content-visibility:auto on album cards conflicted with virtualizer's
  own DOM recycling, causing redundant layout recalculation
- track-list visibilityChanged handler wrote to store synchronously
  on every event (per-item during scroll) without any throttling
- IIFE closure in renderTrackRow created a new function per row per render

Fixes applied:
- Add _itemSize:{height:33} + fixed height:33px on .track-row (matches
  queue-panel pattern that already worked smoothly)
- Add overflow-anchor:none on track-list virtualizer
- Remove will-change:transform from all 6 scroll containers
- Remove content-visibility:auto from album cards
- RAF-throttle visibilityChanged scroll position saves
- Replace IIFE with direct cols.map() in template
2026-03-14 14:46:38 -04:00
yonlu ac8a52e110 perf(14-01): add GPU promotion and containment to all scroll containers
- contain: layout style on :host of all 6 scroll-heavy components
- contain: paint + will-change: transform on all scroll containers for GPU compositing
- content-visibility: auto + contain-intrinsic-size on .album-card for off-screen skip
- cover-grid, track-list, queue-panel, artists-view, genres-view, playlist-view
2026-03-14 13:46:08 -04:00
yonlu a29137b2ba fix(frontend): reposition search indicator into toolbar and fix album cover art lookup
Move search indicator from absolute-positioned overlay into sort toolbar
(or dedicated search-bar-row for artists/genres views). Shows indicator
on empty-state screens. Fix cover art not displaying for expanded album
tracks by checking expandedAlbumId before the albumName guard. Add
ScanWarning model bindings.
2026-03-05 16:07:54 -05:00
yonlu 1303422e69 feat(08-04): apply design tokens to cover-grid, track-list, queue-panel, and detail components
- cover-grid dynamic text tiers use --yj-text-xs/sm/md/lg tokens
- track-list sort toolbar, row text, and fav icon use design tokens
- queue-panel header and track text use type scale tokens
- track-details, track-info, artist-details, genre-details use tokens
- designTokens imported and prepended to static styles in all 8 files
2026-03-04 23:30:29 -05:00
yonlu 1221a403cf cover grid refactor
-split component into several files
2026-02-24 09:49:34 -05:00