Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb61a4654a |
@@ -262,90 +262,101 @@
|
||||
ontouchend={onTouchEnd}
|
||||
>
|
||||
|
||||
<!-- ── Full-bleed cover hero (top ~50% of screen) ────────────────────── -->
|
||||
<div class="relative w-full shrink-0" style="height: 52svh; min-height: 220px; max-height: 380px;">
|
||||
{#if audioStore.cover}
|
||||
<!-- Full-bleed cover image -->
|
||||
<img
|
||||
src={audioStore.cover}
|
||||
alt=""
|
||||
class="absolute inset-0 w-full h-full object-cover"
|
||||
/>
|
||||
{:else}
|
||||
<!-- Fallback when no cover -->
|
||||
<div class="absolute inset-0 flex items-center justify-center bg-(--color-surface-2)">
|
||||
<svg class="w-20 h-20 text-(--color-muted)/30" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 14H8v-2h8v2zm0-4H8v-2h8v2zm0-4H8V6h8v2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- Top gradient: surface → transparent (for header legibility) -->
|
||||
<div
|
||||
class="absolute inset-x-0 top-0 h-28 pointer-events-none"
|
||||
style="background: linear-gradient(to bottom, var(--color-surface) 0%, transparent 100%);"
|
||||
<!-- ── Blurred background (full-screen atmospheric layer) ───────────── -->
|
||||
{#if audioStore.cover}
|
||||
<img
|
||||
src={audioStore.cover}
|
||||
alt=""
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<!-- Bottom gradient: transparent → surface (seamless blend into controls) -->
|
||||
<div
|
||||
class="absolute inset-x-0 bottom-0 h-40 pointer-events-none"
|
||||
style="background: linear-gradient(to top, var(--color-surface) 0%, transparent 100%);"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
class="absolute inset-0 w-full h-full object-cover pointer-events-none select-none"
|
||||
style="filter: blur(40px) brightness(0.25) saturate(1.4); transform: scale(1.15); z-index: 0;"
|
||||
/>
|
||||
{:else}
|
||||
<div class="absolute inset-0 pointer-events-none" style="background: var(--color-surface-2); z-index: 0;"></div>
|
||||
{/if}
|
||||
<!-- Subtle vignette overlay for depth -->
|
||||
<div
|
||||
class="absolute inset-0 pointer-events-none"
|
||||
style="background: radial-gradient(ellipse at center, transparent 40%, rgba(0,0,0,0.55) 100%); z-index: 1;"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
|
||||
<!-- Header bar (sits over the top gradient) -->
|
||||
<div class="relative z-10 flex items-center justify-between px-4 pt-3 pb-2">
|
||||
<button
|
||||
type="button"
|
||||
onclick={onclose}
|
||||
class="p-2 rounded-full text-(--color-text)/70 hover:text-(--color-text) hover:bg-black/20 transition-colors"
|
||||
aria-label="Close listening mode"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
||||
</svg>
|
||||
</button>
|
||||
<span class="text-xs font-semibold text-(--color-text)/60 uppercase tracking-wider">Now Playing</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- Chapters button -->
|
||||
{#if audioStore.chapters.length > 0}
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => { showChapterModal = !showChapterModal; showVoiceModal = false; voiceSearch = ''; }}
|
||||
class={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium border transition-colors',
|
||||
showChapterModal
|
||||
? 'border-(--color-brand) bg-(--color-brand)/15 text-(--color-brand)'
|
||||
: 'border-white/20 bg-black/25 text-(--color-text)/70 hover:text-(--color-text) backdrop-blur-sm'
|
||||
)}
|
||||
aria-label="Browse chapters"
|
||||
>
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h10"/>
|
||||
</svg>
|
||||
Chapters
|
||||
</button>
|
||||
{/if}
|
||||
<!-- Voice selector button -->
|
||||
<!-- ── Header bar ─────────────────────────────────────────────────────── -->
|
||||
<div class="relative flex items-center justify-between px-4 pt-3 pb-2 shrink-0" style="z-index: 2;">
|
||||
<button
|
||||
type="button"
|
||||
onclick={onclose}
|
||||
class="p-2 rounded-full text-(--color-text)/70 hover:text-(--color-text) hover:bg-white/10 transition-colors"
|
||||
aria-label="Close listening mode"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
|
||||
</svg>
|
||||
</button>
|
||||
<span class="text-xs font-semibold text-(--color-text)/60 uppercase tracking-wider">Now Playing</span>
|
||||
<div class="flex items-center gap-2">
|
||||
<!-- Chapters button -->
|
||||
{#if audioStore.chapters.length > 0}
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => { showVoiceModal = !showVoiceModal; showChapterModal = false; }}
|
||||
onclick={() => { showChapterModal = !showChapterModal; showVoiceModal = false; voiceSearch = ''; }}
|
||||
class={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium border transition-colors',
|
||||
showVoiceModal
|
||||
showChapterModal
|
||||
? 'border-(--color-brand) bg-(--color-brand)/15 text-(--color-brand)'
|
||||
: 'border-white/20 bg-black/25 text-(--color-text)/70 hover:text-(--color-text) backdrop-blur-sm'
|
||||
)}
|
||||
aria-label="Browse chapters"
|
||||
>
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h10"/>
|
||||
</svg>
|
||||
<span class="max-w-[80px] truncate">{voiceLabel(audioStore.voice)}</span>
|
||||
Chapters
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
<!-- Voice selector button -->
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => { showVoiceModal = !showVoiceModal; showChapterModal = false; }}
|
||||
class={cn(
|
||||
'flex items-center gap-1.5 px-3 py-1.5 rounded-full text-xs font-medium border transition-colors',
|
||||
showVoiceModal
|
||||
? 'border-(--color-brand) bg-(--color-brand)/15 text-(--color-brand)'
|
||||
: 'border-white/20 bg-black/25 text-(--color-text)/70 hover:text-(--color-text) backdrop-blur-sm'
|
||||
)}
|
||||
>
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"/>
|
||||
</svg>
|
||||
<span class="max-w-[80px] truncate">{voiceLabel(audioStore.voice)}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Portrait cover card + track info ───────────────────────────────── -->
|
||||
<div class="relative flex flex-col items-center gap-4 px-8 pt-2 pb-4 shrink-0" style="z-index: 2;">
|
||||
<!-- Cover card -->
|
||||
<div
|
||||
class="rounded-2xl overflow-hidden shadow-2xl"
|
||||
style="height: 38svh; min-height: 180px; max-height: 320px; aspect-ratio: 2/3;"
|
||||
>
|
||||
{#if audioStore.cover}
|
||||
<img
|
||||
src={audioStore.cover}
|
||||
alt=""
|
||||
class="w-full h-full object-cover"
|
||||
/>
|
||||
{:else}
|
||||
<div class="w-full h-full bg-(--color-surface-2) flex items-center justify-center">
|
||||
<svg class="w-16 h-16 text-(--color-muted)/30" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M18 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 14H8v-2h8v2zm0-4H8v-2h8v2zm0-4H8V6h8v2z"/>
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Track info (sits over the bottom gradient) -->
|
||||
<div class="absolute inset-x-0 bottom-0 z-10 px-6 pb-3 text-center">
|
||||
<!-- Track info -->
|
||||
<div class="text-center w-full">
|
||||
{#if audioStore.chapter > 0}
|
||||
<p class="text-[10px] font-bold uppercase tracking-widest text-(--color-brand) mb-0.5">
|
||||
Chapter {audioStore.chapter}
|
||||
@@ -499,7 +510,7 @@
|
||||
{/if}
|
||||
|
||||
<!-- ── Controls area (bottom half) ───────────────────────────────────── -->
|
||||
<div class="flex-1 flex flex-col justify-end px-6 pb-6 gap-0 shrink-0 overflow-hidden">
|
||||
<div class="flex-1 flex flex-col justify-end px-6 pb-6 gap-0 shrink-0 overflow-hidden" style="z-index: 2; position: relative;">
|
||||
|
||||
<!-- Seek bar -->
|
||||
<div class="shrink-0 mb-1">
|
||||
|
||||
Reference in New Issue
Block a user