refactor(immersive): clean up controls and improve split view layout
- Remove track info (artwork, title, artist) from ImmersiveControls bottom bar - Add track title and artist below album artwork in split view mode - Change Lyrics Focus icon from MessageSquareText to Mic (microphone) - Remove unused compact mode from ImmersiveControls - Simplify props and cleanup CSS
This commit is contained in:
1 parent
0fc0723804
commit
4d5a78ff24
3 files changed
+63
-103
No files matched your search
@@ -6,10 +6,6 @@
|
||||
|
||||
interface Props {
|
||||
visible?: boolean;
|
||||
// Track info
|
||||
artwork: string;
|
||||
trackTitle: string;
|
||||
artist: string;
|
||||
// Playback state
|
||||
isPlaying: boolean;
|
||||
currentTime: number;
|
||||
@@ -32,15 +28,10 @@
|
||||
onToggleRepeat: () => void;
|
||||
onToggleFavorite: () => void;
|
||||
onVolumeChange: (volume: number) => void;
|
||||
// Compact mode (hide some elements)
|
||||
compact?: boolean;
|
||||
}
|
||||
|
||||
let {
|
||||
visible = true,
|
||||
artwork,
|
||||
trackTitle,
|
||||
artist,
|
||||
isPlaying,
|
||||
currentTime,
|
||||
duration,
|
||||
@@ -58,23 +49,11 @@
|
||||
onToggleShuffle,
|
||||
onToggleRepeat,
|
||||
onToggleFavorite,
|
||||
onVolumeChange,
|
||||
compact = false
|
||||
onVolumeChange
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="immersive-controls" class:visible class:compact>
|
||||
<!-- Left: Track Info -->
|
||||
{#if !compact}
|
||||
<div class="track-info">
|
||||
<img src={artwork} alt="" class="mini-artwork" />
|
||||
<div class="track-meta">
|
||||
<div class="track-title">{trackTitle}</div>
|
||||
<div class="track-artist">{artist}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="immersive-controls" class:visible>
|
||||
<!-- Center: Playback Controls + Progress -->
|
||||
<div class="playback-section">
|
||||
<div class="controls">
|
||||
@@ -136,31 +115,29 @@
|
||||
</div>
|
||||
|
||||
<!-- Right: Volume + Actions -->
|
||||
{#if !compact}
|
||||
<div class="right-section">
|
||||
<button
|
||||
class="action-btn"
|
||||
class:active={isFavorite}
|
||||
onclick={onToggleFavorite}
|
||||
title={isFavorite ? 'Remove from Favorites' : 'Add to Favorites'}
|
||||
>
|
||||
<Heart
|
||||
size={18}
|
||||
fill={isFavorite ? 'currentColor' : 'none'}
|
||||
/>
|
||||
</button>
|
||||
<div class="right-section">
|
||||
<button
|
||||
class="action-btn"
|
||||
class:active={isFavorite}
|
||||
onclick={onToggleFavorite}
|
||||
title={isFavorite ? 'Remove from Favorites' : 'Add to Favorites'}
|
||||
>
|
||||
<Heart
|
||||
size={18}
|
||||
fill={isFavorite ? 'currentColor' : 'none'}
|
||||
/>
|
||||
</button>
|
||||
|
||||
<div class="volume-wrapper">
|
||||
<VolumeSlider {volume} {onVolumeChange} />
|
||||
</div>
|
||||
|
||||
{#if quality}
|
||||
<div class="quality-wrapper">
|
||||
<QualityBadge {quality} {bitDepth} {samplingRate} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="volume-wrapper">
|
||||
<VolumeSlider {volume} {onVolumeChange} />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if quality}
|
||||
<div class="quality-wrapper">
|
||||
<QualityBadge {quality} {bitDepth} {samplingRate} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -193,46 +170,6 @@
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* Track Info (Left) */
|
||||
.track-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-width: 200px;
|
||||
max-width: 280px;
|
||||
}
|
||||
|
||||
.mini-artwork {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 6px;
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.track-meta {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.track-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary, white);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.track-artist {
|
||||
font-size: 12px;
|
||||
color: var(--alpha-60, rgba(255, 255, 255, 0.6));
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* Playback Section (Center) */
|
||||
.playback-section {
|
||||
flex: 1;
|
||||
@@ -351,14 +288,8 @@
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* Compact mode */
|
||||
.immersive-controls.compact .playback-section {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 900px) {
|
||||
.track-info,
|
||||
.right-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { X, Disc3, LayoutGrid, MessageSquareText, ListMusic, Music2, Info, Radio } from 'lucide-svelte';
|
||||
import { X, Disc3, LayoutGrid, Mic, ListMusic, Music2, Info, Radio } from 'lucide-svelte';
|
||||
import { t } from '$lib/i18n';
|
||||
|
||||
export type ImmersiveTab = 'lyrics' | 'credits' | 'suggestions' | 'queue';
|
||||
@@ -39,7 +39,7 @@
|
||||
const displayModes: { id: DisplayMode; icon: typeof Disc3; title: string }[] = [
|
||||
{ id: 'coverflow', icon: Disc3, title: 'Coverflow (1)' },
|
||||
{ id: 'split', icon: LayoutGrid, title: 'Split View (2)' },
|
||||
{ id: 'lyrics-focus', icon: MessageSquareText, title: 'Lyrics Focus (3)' },
|
||||
{ id: 'lyrics-focus', icon: Mic, title: 'Lyrics Focus (3)' },
|
||||
{ id: 'queue-focus', icon: ListMusic, title: 'Queue Focus (4)' },
|
||||
];
|
||||
|
||||
|
||||
@@ -271,10 +271,14 @@
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Split: Artwork + Panel side by side -->
|
||||
<div class="main-content">
|
||||
<!-- Left: Artwork -->
|
||||
<div class="immersive-main">
|
||||
<!-- Left: Artwork + Track Info -->
|
||||
<div class="artwork-section">
|
||||
<ImmersiveArtwork {artwork} {trackTitle} variant="floating" />
|
||||
<div class="split-track-info">
|
||||
<h2 class="split-track-title">{trackTitle}</h2>
|
||||
<p class="split-track-artist">{artist}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right: Active Panel -->
|
||||
@@ -307,9 +311,6 @@
|
||||
<!-- Bottom Controls -->
|
||||
<ImmersiveControls
|
||||
visible={showUI}
|
||||
{artwork}
|
||||
{trackTitle}
|
||||
{artist}
|
||||
{isPlaying}
|
||||
{currentTime}
|
||||
{duration}
|
||||
@@ -354,7 +355,7 @@
|
||||
}
|
||||
|
||||
/* Split mode layout */
|
||||
.main-content {
|
||||
.immersive-main {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
@@ -373,8 +374,36 @@
|
||||
.artwork-section {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.split-track-info {
|
||||
text-align: center;
|
||||
max-width: 380px;
|
||||
}
|
||||
|
||||
.split-track-title {
|
||||
font-size: clamp(18px, 2.5vw, 24px);
|
||||
font-weight: 700;
|
||||
color: var(--text-primary, white);
|
||||
margin: 0 0 6px 0;
|
||||
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
/* Truncate long titles */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.split-track-artist {
|
||||
font-size: clamp(14px, 1.8vw, 16px);
|
||||
color: var(--alpha-70, rgba(255, 255, 255, 0.7));
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.panel-section {
|
||||
@@ -412,7 +441,7 @@
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 1200px) {
|
||||
.main-content {
|
||||
.immersive-main {
|
||||
padding: 70px 32px 130px;
|
||||
gap: 40px;
|
||||
}
|
||||
@@ -427,7 +456,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.main-content {
|
||||
.immersive-main {
|
||||
flex-direction: column;
|
||||
padding: 70px 24px 140px;
|
||||
gap: 24px;
|
||||
@@ -454,7 +483,7 @@
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.main-content {
|
||||
.immersive-main {
|
||||
padding: 60px 16px 130px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user