fix(immersive): improve background quality and polish UI

- Increase canvas blur size from 64x64 to 256x256 for smoother background
- Fix lyrics horizontal scroll by adding word-wrap and overflow-x: hidden
- Remove queue button from controls (use header tab instead)
- Add queue sync effect when immersive player is open

Addresses visual quality issues with pixelated background and long
German lyrics causing horizontal overflow.
This commit is contained in:
vicrodh committed 2026-01-30 16:40:20 -06:00
1 parent 07b7228538
commit 223a7f5e1d
5 files changed
+20 -23

No files matched your search

@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { Shuffle, SkipBack, Play, Pause, SkipForward, Repeat, Heart, List } from 'lucide-svelte'; import { Shuffle, SkipBack, Play, Pause, SkipForward, Repeat, Heart } from 'lucide-svelte';
import ProgressBar from './shared/ProgressBar.svelte'; import ProgressBar from './shared/ProgressBar.svelte';
import VolumeSlider from './shared/VolumeSlider.svelte'; import VolumeSlider from './shared/VolumeSlider.svelte';
import QualityBadge from '../QualityBadge.svelte'; import QualityBadge from '../QualityBadge.svelte';
@@ -32,7 +32,6 @@
onToggleRepeat: () => void; onToggleRepeat: () => void;
onToggleFavorite: () => void; onToggleFavorite: () => void;
onVolumeChange: (volume: number) => void; onVolumeChange: (volume: number) => void;
onOpenQueue?: () => void;
// Compact mode (hide some elements) // Compact mode (hide some elements)
compact?: boolean; compact?: boolean;
} }
@@ -60,7 +59,6 @@
onToggleRepeat, onToggleRepeat,
onToggleFavorite, onToggleFavorite,
onVolumeChange, onVolumeChange,
onOpenQueue,
compact = false compact = false
}: Props = $props(); }: Props = $props();
</script> </script>
@@ -152,12 +150,6 @@
/> />
</button> </button>
{#if onOpenQueue}
<button class="action-btn" onclick={onOpenQueue} title="Queue">
<List size={18} />
</button>
{/if}
<div class="volume-wrapper"> <div class="volume-wrapper">
<VolumeSlider {volume} {onVolumeChange} /> <VolumeSlider {volume} {onVolumeChange} />
</div> </div>
@@ -53,7 +53,6 @@
onToggleShuffle: () => void; onToggleShuffle: () => void;
onToggleRepeat: () => void; onToggleRepeat: () => void;
onToggleFavorite: () => void; onToggleFavorite: () => void;
onOpenQueue?: () => void;
// Lyrics // Lyrics
lyricsLines?: LyricsLine[]; lyricsLines?: LyricsLine[];
lyricsActiveIndex?: number; lyricsActiveIndex?: number;
@@ -99,7 +98,6 @@
onToggleShuffle, onToggleShuffle,
onToggleRepeat, onToggleRepeat,
onToggleFavorite, onToggleFavorite,
onOpenQueue,
lyricsLines = [], lyricsLines = [],
lyricsActiveIndex = -1, lyricsActiveIndex = -1,
lyricsActiveProgress = 0, lyricsActiveProgress = 0,
@@ -289,7 +287,6 @@
{onToggleRepeat} {onToggleRepeat}
{onToggleFavorite} {onToggleFavorite}
{onVolumeChange} {onVolumeChange}
{onOpenQueue}
/> />
</div> </div>
{/if} {/if}
@@ -134,6 +134,7 @@
gap: 16px; gap: 16px;
padding: 16px 20px; padding: 16px 20px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden;
height: 100%; height: 100%;
scrollbar-width: thin; scrollbar-width: thin;
scrollbar-color: var(--bg-tertiary) transparent; scrollbar-color: var(--bg-tertiary) transparent;
@@ -213,6 +214,9 @@
font-size 150ms ease-out, font-size 150ms ease-out,
color 250ms ease-out; color 250ms ease-out;
transform-origin: left center; transform-origin: left center;
/* Prevent horizontal overflow with long lyrics */
word-wrap: break-word;
overflow-wrap: break-word;
/* will-change removed from all lines - only active line gets GPU layer */ /* will-change removed from all lines - only active line gets GPU layer */
} }
+6 -6
View File
@@ -2,8 +2,8 @@
* Optimized Image Blur Utility * Optimized Image Blur Utility
* *
* Pre-computes blurred background images for the immersive player. * Pre-computes blurred background images for the immersive player.
* Uses a tiny canvas (64x64) which, when scaled up, produces the same * Uses a small canvas (256x256) with blur which, when scaled up, produces
* visual effect as CSS blur(100px) but with near-zero GPU cost. * a smooth background effect with minimal GPU cost.
* *
* Performance comparison: * Performance comparison:
* - CSS blur(100px) on 600x600 image: ~15-30% GPU, constant * - CSS blur(100px) on 600x600 image: ~15-30% GPU, constant
@@ -19,14 +19,14 @@ const MAX_CACHE_SIZE = 20;
* Returns a data URL that can be used as background-image. * Returns a data URL that can be used as background-image.
* *
* @param artworkUrl - The original artwork URL * @param artworkUrl - The original artwork URL
* @param size - Output canvas size (default 64, higher = sharper blur edges) * @param size - Output canvas size (default 256, higher = smoother result)
* @param blurRadius - Canvas blur radius (default 8, effective ~100px at fullscreen) * @param blurRadius - Canvas blur radius (default 20, effective ~80px at fullscreen)
* @returns Promise<string> - Data URL of blurred image * @returns Promise<string> - Data URL of blurred image
*/ */
export async function generateBlurredBackground( export async function generateBlurredBackground(
artworkUrl: string, artworkUrl: string,
size: number = 64, size: number = 256,
blurRadius: number = 8 blurRadius: number = 20
): Promise<string> { ): Promise<string> {
// Check cache first // Check cache first
const cacheKey = `${artworkUrl}-${size}-${blurRadius}`; const cacheKey = `${artworkUrl}-${size}-${blurRadius}`;
+9 -5
View File
@@ -2587,6 +2587,15 @@
} }
}); });
// Sync queue state when immersive player is open and track changes
$effect(() => {
const trackId = currentTrack?.id;
const immersiveOpen = isFullScreenOpen || isFocusModeOpen;
if (immersiveOpen && trackId !== undefined) {
syncQueueState();
}
});
// Helper function to fetch and update queue counts and history // Helper function to fetch and update queue counts and history
async function updateQueueCounts() { async function updateQueueCounts() {
const state = await getBackendQueueState(); const state = await getBackendQueueState();
@@ -3095,11 +3104,6 @@
onToggleRepeat={toggleRepeat} onToggleRepeat={toggleRepeat}
{isFavorite} {isFavorite}
onToggleFavorite={toggleFavorite} onToggleFavorite={toggleFavorite}
onOpenQueue={() => {
closeFullScreen();
closeFocusMode();
toggleQueue();
}}
lyricsLines={lyricsLines.map(l => ({ text: l.text }))} lyricsLines={lyricsLines.map(l => ({ text: l.text }))}
lyricsActiveIndex={lyricsActiveIndex} lyricsActiveIndex={lyricsActiveIndex}
lyricsActiveProgress={lyricsActiveProgress} lyricsActiveProgress={lyricsActiveProgress}