feat(immersive): create unified ImmersivePlayer component

New component architecture:
- ImmersivePlayer.svelte: Main container with tab system
- ImmersiveHeader.svelte: Tabs (lyrics/credits/suggestions/visualizer)
- ImmersiveControls.svelte: Bottom bar with all playback controls
- ImmersiveArtwork.svelte: Album art with floating/vinyl variants
- ImmersiveBackground.svelte: Optimized blur background (from Phase 1)

Panel components:
- LyricsPanel: Wrapper for existing LyricsLines
- CreditsPanel: Placeholder (Phase 3)
- SuggestionsPanel: Placeholder (Phase 4)
- VisualizerPanel: Placeholder (Phase 5)

Shared components:
- ProgressBar: Reusable seek bar with keyboard support
- VolumeSlider: Reusable volume control

Features:
- Tab-based navigation (L/C/S/V keyboard shortcuts)
- Auto-hide UI after 4 seconds of inactivity
- Full keyboard control (Space, Arrows, Escape)
- Responsive layout (desktop/tablet/mobile)
- Accessibility: ARIA roles, focus management
This commit is contained in:
vicrodh committed 2026-01-30 16:11:03 -06:00
1 parent 513614466e
commit 7c9f1820f8
11 files changed
+1730

No files matched your search

@@ -0,0 +1,58 @@
<script lang="ts">
import { t } from '$lib/i18n';
interface Props {
trackId?: number;
artistId?: number;
}
let { trackId, artistId }: Props = $props();
// TODO: Implement suggestions fetching in Phase 4
let isLoading = $state(false);
</script>
<div class="suggestions-panel">
<div class="placeholder">
<span class="placeholder-icon">📻</span>
<span class="placeholder-text">{$t('player.suggestionsComingSoon') || 'Suggestions coming soon'}</span>
<span class="placeholder-hint">Artist Radio, Track Radio, Similar Tracks...</span>
</div>
</div>
<style>
.suggestions-panel {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
overflow-y: auto;
padding: 24px;
}
.placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
height: 100%;
min-height: 200px;
color: var(--alpha-40, rgba(255, 255, 255, 0.4));
}
.placeholder-icon {
font-size: 32px;
opacity: 0.5;
}
.placeholder-text {
font-size: 16px;
font-weight: 500;
}
.placeholder-hint {
font-size: 13px;
color: var(--alpha-30, rgba(255, 255, 255, 0.3));
}
</style>