Backend:
- Migration 17: similar_artist_map table stores per-artist similar
artist relationships (source_mbid → similar_mbid + name + score)
- Tier 4 index build now persists similar artists to this table
- GetLibrarySimilarArtists(mbid) queries similar artists filtered
by JOIN with the artists table (library-only, no API calls)
- Added db field to explore.Service for direct queries
Frontend:
- ExploreSettingsStore with libraryOnly toggle, persisted to
localStorage
- Top bar toggle button with active/inactive styling
- Explore search: skips full MB/LB pipeline when library-only,
uses only searchLibraryCache (pure JS, instant)
- Artist detail page: in library-only mode, skips all API calls
(no top tracks, no top releases, no LB play count, no MB
artist lookup). Uses library store for discography, calls
GetLibrarySimilarArtists for similar artists.
- Similar artists section: changed from horizontal scroll to
wrapping flex layout with collapsible toggle (Show all N)
- Removed debug artist ranking log
The hidden primary view was creating a gap above the active view
because flex:0 and height:0 alone don't override min-height from
the component's shadow DOM :host styles. In flex layout, the
default min-height:auto can prevent an element from collapsing
to zero height.
Added to .view-hidden:
- min-height: 0 — overrides flex min-height:auto
- max-height: 0 — belt-and-suspenders height constraint
- padding: 0 — prevents padding from creating space
- margin: 0 — prevents margin from creating space
- border: none — prevents border from creating space
- flex: 0 0 0px — explicit flex-basis:0px (not just flex:0)
All with !important to override shadow DOM :host styles.
Three changes:
1. Added box-sizing: border-box to :host of explore-artist-details,
explore-album-details, and artist-details. The light DOM rule
.main-panel > * sets this but shadow DOM may not inherit it.
2. Changed .main-panel to display: flex; flex-direction: column.
In block layout, a height:0 hidden view could affect the
position of the detail view below it. In flex column layout,
the hidden view (flex:0) collapses completely and the active
view (flex:1) fills the remaining space.
3. Changed .main-panel > * from height:100% to flex:1; min-height:0.
In a flex column, flex:1 correctly fills available space while
min-height:0 allows the content to shrink below its intrinsic
size (needed for overflow:hidden to work).
Two layout issues:
1. Gap above content: .main-panel had padding: 0.25em which created
a visible gap above views. Removed — views control their own
internal padding.
2. Scroll cutoff at bottom: .main-panel > * had height: 100% but
no box-sizing: border-box. Views with their own padding (like
config-page) overflowed because padding added to the 100% height.
Added box-sizing: border-box to the global rule so padding is
included in the height calculation.
display:none discards scrollTop in WebKitGTK, so navigating away
from album/artist/genre grids and back reset scroll to top.
Replace inline style.display toggling with a CSS class that uses
visibility:hidden + height:0 + overflow:hidden. This collapses
the element visually while keeping the DOM alive with its scroll
state intact. contain:strict on hidden views ensures zero layout
cost while collapsed.
contain:strict includes size containment which caused a timing issue
where the flex-based main-panel height wasn't resolved before the
virtualizer measured its container, resulting in track-list rendering
at ~20% height on first load until something triggered a relayout.
- contain: layout style on .content-area to isolate main+queue from header/sidebar
- contain: strict on .main-panel for maximum layout isolation
- contain: layout style paint on .main-panel > * for paint containment per view
- contain: layout style paint on sidebar to isolate from main panel
- contain: layout style on .bottom-bar to isolate footer from content reflows