- Remove problematic $effect that ran loadPlaybackPreferences() on every
render, causing a state update loop and visual flicker
- The function is already called in onMount, so the duplicate was redundant
- Add ViewTransition wrapper for consistent subtle animation (200ms fade+slide)
- Only navigate to search page after 3 characters typed
- Sync still happens immediately from 1st character
- Remove auto-navigate on focus (let user type first)
- Add ViewTransition component for reusable subtle animations
- Apply 200ms fade+slide transition to SearchView
cc
- Replace search button with actual text input in sidebar
- Add X button to clear search when text is present
- Sync sidebar input 1:1 with SearchView input (bidirectional)
- Typing in sidebar navigates to search page and triggers search
- Clearing sidebar input resets search page to standby state
- Add subscribeSearchQuery and setSearchQuery to searchState store
cc
Redesigned dropdown architecture:
- Menu uses position:fixed instead of absolute
- Menu rendered outside dropdown container (sibling, not child)
- Position calculated in pixels before menu opens
- Completely removes menu from document flow
This eliminates the momentary scroll flash that occurred when
dropdowns opened and temporarily expanded the page.
cc
- Header now outside .track-sections.virtualized (like LocalLibraryView)
- Use calc() height for virtualized section to give explicit dimensions
- Removes complex flex/absolute positioning that was breaking layout
- Add track list header with columns: #, Title, Album, Duration,
Quality, Favorite icon, Download icon
- Album column is hidden when grouping by album (redundant)
- Add getTrackAlbum and showAlbum props to VirtualizedTrackList
- Style matches PlaylistDetailView for consistency
Previously, streaming tracks could not be resumed after pause timeout
because current_audio_data was never set for streaming playback.
Changes:
- Store BufferedMediaSource in current_streaming_source for streaming tracks
- On resume, check if streaming source has complete data and use it
- Clear streaming source on Stop and when switching to non-streaming play
- Log buffered bytes when streaming not complete yet
This allows users to pause streaming tracks and resume them after the
download completes, instead of getting "no audio data available" error.
- Add z-index: 1000 to dropdown-container to appear above sidebar
- Change dropdown alignment from right: 0 to left: 0 for natural
left-to-right opening
- Affects all tabs: Albums, Tracks, Artists
- Fix Favorites Albums group dropdown appearing behind sidebar
(z-index 10 -> 100)
- Persist volume level to localStorage between sessions
- Allow changing volume when nothing is playing (volume
applies when playback starts)
- Add fade/slide transitions when tracks are added or dismissed
- Show success state (checkmark + green highlight) before fade out
- Add track to local state without page reload
- Update sidebar counts via callbacks
- Disable buttons during adding animation
- Add extractAdaptiveArtists() for dynamic seed artist count based on playlist size
- Mix 60% top artists (coherence) + 40% random (discovery) for variety
- Filter duplicates by title+artist, not just track ID
- Catches same song from compilations, live albums, remasters, etc.
- Deduplicate within suggestion pool itself
- Add compact prop to QualityBadge for inline usage in track lists
- Compact mode shows simple text (24bit/96kHz or CD Quality)
- Use golden gradient for hires badges in compact mode
- Update ArtistDetailView to use QualityBadge compact
- Update FavoritesView to use QualityBadge compact
- Update SearchView to use QualityBadge compact
- Remove duplicate CSS and getQualityLabel functions
- LocalLibrary views keep custom format showing codec (FLAC 24/96)
- Use golden gradient (#fbbf24 to #b8860b) with dark text for hires badges
- Increase min-width to 90px for consistent sizing across all badges
- Rename track-row favorite button to avoid CSS conflict with header button
- Header favorite button now properly circular like radio and network buttons
1. Search: Re-clicking Search button in sidebar scrolls to top and focuses input
- Added triggerSearchFocus mechanism in searchState store
- SearchView subscribes to focus trigger for scroll + focus
2. ArtistDetailView: Added quality badge and favorite button to Popular Tracks
- Added getQualityLabel function with bit depth/sample rate
- Added quality-badge element with hires styling
- Added favorite button in track actions
3. FavoritesView: Fixed getAlbumQualityLabel to show detailed format
- Now shows "24bit/96kHz" instead of generic "Hi-Res"
- Change overflow-y to scroll to always reserve scrollbar space
- Fix sticky header top position to -24px to eliminate gap with window edge
- Add proper padding-top compensation when scrolled
- Add scrollbar-gutter: stable to prevent layout shift when content scrolls
- Create sticky header that activates on scroll with:
- Compact search input (bottom border only, muted accent, smaller height)
- Tabs and filters remain visible
- Title hidden when scrolled to save space
- Box-shadow for visual separation
- Increased menu min-width to 200px with width: max-content
to prevent word wrap on options
- Added padding: 4px 0 to menu (matches context menus)
- Changed box-shadow to match context menu (0 8px 24px)
- Reduced option padding to 10px 16px (was 12px 16px)
- Changed font-size to 13px (was 14px) to match context menus
- Added color transition on hover to match context menus
- Removed overflow/text-overflow from options (no wrap needed)
- Added smooth scroll CSS optimizations to artist list:
- webkit-overflow-scrolling: touch
- scroll-behavior: smooth
- overscroll-behavior: contain
- will-change: scroll-position
- contain: strict
- Added contain: layout style to artist cards for better rendering
- Added same optimizations to albums grid
- Memory: selectedArtistAlbums is a derived value that auto-updates
when switching artists, old arrays are garbage collected
- Note: VirtualizedArtistList exists for future use with large libraries
- Removed early return that blocked Various Artists clicks
(album header already protected via HTML condition)
- Added special case in selectedArtistAlbums: when user selects
"Various Artists", show all albums with that artist name
- Remove background from artist column, integrate with main background
- Add vertical border line separating artist list from albums view
- Wrap artists tab content in flex container for proper height
- Artist list now fills full available height (no gaps at top/bottom)
- Adjusted padding and margins for better visual integration
- Adjusted artist two-column layout height to account for NowPlayingBar
(was calc(100vh - 320px), now calc(100vh - 424px))
- Added 100ms delay before scrolling to artist card to ensure content
is fully rendered after tab switch
- Artist name in album header now clickable (except for Various Artists)
- Clicking artist navigates to Artists tab, scrolls to artist card,
and shows their albums
- Track artist links (when different from album artist) work the same
- Added IDs to artist cards for scroll targeting
- Navigation history updated so back button returns to album view
- Handle undefined/null values in cache stats with nullish coalescing
- Show "No cached artwork" when both counts are 0
- Use outlined style for Clear All button (consistent with others)
- Simplified description text
1. Play button fix: After resuming on cast device, update playerStore.isPlaying
so the UI shows the correct playing state immediately.
2. Disconnect handoff: When disconnecting from Chromecast/DLNA while playing:
- Captures current track and position from cast state
- Shows confirm dialog asking if user wants to continue locally
- If yes, starts local playback and seeks to saved position
- If no, just resets player state
This provides seamless transitions in both directions:
- Local → Cast: auto-resumes with position
- Cast → Local: asks user, then resumes with position
When user connects to a Chromecast/DLNA device while local playback is
active, the local stream was conflicting with the cast stream.
Now connectToDevice():
1. Captures current track info and position
2. Stops local playback completely
3. Establishes the cast connection
4. Automatically resumes the track on the cast device
5. Seeks to the saved position (if > 5 seconds)
This provides seamless handoff from local to cast playback.
- Added artwork thumbnails cache stats and clear button
- Shows legacy artwork files count if old cache exists
- Added "Clear All Caches" button that clears all cached data at once
- Danger button styling for destructive action
- metadata.rs now creates 500px thumbnails instead of copying full images
- Added cache management commands: library_get_cache_stats,
library_clear_artwork_cache, library_clear_thumbnails_cache
- Thumbnails stored in ~/.local/share/qbz/thumbnails/ (was ~/.cache/qbz/artwork)
- Reduces cache size from GB to MB for large libraries