Files
qbz/src/lib/components/immersive/panels/LyricsPanel.svelte
T
vicrodh c0242356a1 fix(lyrics): show user-friendly message when lyrics unavailable
Replace technical error 'LRCLIB search request failed...' with
'No lyrics available' in both LyricsPanel and LyricsFocusPanel.
2026-01-31 12:31:02 -06:00

132 lines
2.7 KiB
Svelte

<script lang="ts">
import LyricsLines from '../../lyrics/LyricsLines.svelte';
import { t } from '$lib/i18n';
interface LyricsLine {
text: string;
}
interface Props {
lines: LyricsLine[];
activeIndex?: number;
activeProgress?: number;
isSynced?: boolean;
isLoading?: boolean;
error?: string | null;
}
let {
lines = [],
activeIndex = -1,
activeProgress = 0,
isSynced = false,
isLoading = false,
error = null
}: Props = $props();
const hasLyrics = $derived(lines.length > 0);
</script>
<div class="lyrics-panel">
{#if isLoading}
<div class="lyrics-state">
<div class="spinner"></div>
<span>{$t('player.fetchingLyrics')}</span>
</div>
{:else if error}
<div class="lyrics-state">
<span class="no-lyrics">{$t('player.noLyrics') || 'No lyrics available'}</span>
</div>
{:else if hasLyrics}
<div class="lyrics-container">
<LyricsLines
{lines}
{activeIndex}
{activeProgress}
{isSynced}
center={false}
compact={false}
immersive={true}
/>
</div>
{:else}
<div class="lyrics-state">
<span class="no-lyrics">{$t('player.noLyrics') || 'No lyrics available'}</span>
</div>
{/if}
</div>
<style>
.lyrics-panel {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
overflow: hidden;
}
.lyrics-container {
flex: 1;
min-height: 0;
overflow: hidden;
mask-image: linear-gradient(
to bottom,
transparent 0%,
black 8%,
black 85%,
transparent 100%
);
-webkit-mask-image: linear-gradient(
to bottom,
transparent 0%,
black 8%,
black 85%,
transparent 100%
);
}
.lyrics-container :global(.lyrics-lines) {
--text-primary: var(--alpha-95, rgba(255, 255, 255, 0.95));
--text-secondary: var(--alpha-50, rgba(255, 255, 255, 0.5));
--text-muted: var(--alpha-25, rgba(255, 255, 255, 0.25));
--bg-tertiary: var(--alpha-8, rgba(255, 255, 255, 0.08));
padding: 0;
height: 100%;
}
.lyrics-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 12px;
height: 100%;
min-height: 200px;
color: var(--alpha-50, rgba(255, 255, 255, 0.5));
font-size: 14px;
}
.error-text {
color: var(--alpha-40, rgba(255, 255, 255, 0.4));
}
.no-lyrics {
font-style: italic;
}
.spinner {
width: 24px;
height: 24px;
border: 2px solid var(--alpha-20, rgba(255, 255, 255, 0.2));
border-top-color: var(--alpha-80, rgba(255, 255, 255, 0.8));
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
</style>