player layout shenanigans

This commit is contained in:
2026-02-06 04:04:10 -08:00
parent 3418d19a57
commit 291b8d5d21
2 changed files with 398 additions and 408 deletions

View File

@@ -453,11 +453,11 @@
{/if} {/if}
</svelte:head> </svelte:head>
{#if isMobile} <!-- Mobile UI is allowed to render as an overlay even if this component is mounted
<!-- Mobile: mini bar + expandable drawer --> inside the desktop sidebar column. We hide it on lg+ via CSS, not by unmounting. -->
<div <div
class="fixed bottom-0 left-0 right-0 z-50 border-t bg-background/95 backdrop-blur shadow-2xl" class="lg:hidden fixed bottom-0 left-0 right-0 z-50 border-t bg-background/95 backdrop-blur shadow-2xl"
> >
<div class="mx-auto flex max-w-4xl items-center gap-2 px-3 py-2"> <div class="mx-auto flex max-w-4xl items-center gap-2 px-3 py-2">
<button <button
class="inline-flex h-8 w-8 items-center justify-center rounded border" class="inline-flex h-8 w-8 items-center justify-center rounded border"
@@ -623,9 +623,7 @@
step="0.01" step="0.01"
value={snap.volume} value={snap.volume}
oninput={(e) => oninput={(e) =>
setVolume( setVolume(Number((e.currentTarget as HTMLInputElement).value))}
Number((e.currentTarget as HTMLInputElement).value),
)}
/> />
</label> </label>
</div> </div>
@@ -695,12 +693,11 @@
</div> </div>
</div> </div>
{/if} {/if}
</div> </div>
{:else} <!-- Desktop UI stays in-flow in the right grid column. Hide on small screens via CSS. -->
<!-- Desktop: sticky, in-flow sidebar (sticks vertically, flows horizontally in the layout column) --> <aside
<aside class="hidden lg:flex sticky top-4 h-[calc(100dvh-2rem)] overflow-hidden bg-background flex-col"
class="sticky top-4 h-[calc(100dvh-2rem)] overflow-hidden bg-background flex flex-col" >
>
<div class="flex items-center gap-2 border-b px-3 py-3"> <div class="flex items-center gap-2 border-b px-3 py-3">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div class="truncate text-sm font-semibold">Player</div> <div class="truncate text-sm font-semibold">Player</div>
@@ -853,9 +850,7 @@
step="0.01" step="0.01"
value={snap.volume} value={snap.volume}
oninput={(e) => oninput={(e) =>
setVolume( setVolume(Number((e.currentTarget as HTMLInputElement).value))}
Number((e.currentTarget as HTMLInputElement).value),
)}
/> />
</label> </label>
</div> </div>
@@ -886,9 +881,7 @@
<span class="text-muted-foreground"></span> <span class="text-muted-foreground"></span>
{/if} {/if}
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<div <div class="flex flex-wrap items-baseline gap-x-2 gap-y-1">
class="flex flex-wrap items-baseline gap-x-2 gap-y-1"
>
{#if typeNumberLabel(item.track)} {#if typeNumberLabel(item.track)}
<span <span
class="rounded bg-muted px-2 py-0.5 text-sm text-muted-foreground" class="rounded bg-muted px-2 py-0.5 text-sm text-muted-foreground"
@@ -904,8 +897,7 @@
<div class="mt-1 text-foreground/80"> <div class="mt-1 text-foreground/80">
{(item.track.title ?? "").trim() || "Unknown title"} {(item.track.title ?? "").trim() || "Unknown title"}
<span class="text-sm text-muted-foreground"> <span class="text-sm text-muted-foreground">
{(item.track.artist ?? "").trim() || {(item.track.artist ?? "").trim() || "Unknown Artist"}
"Unknown Artist"}
</span> </span>
</div> </div>
</div> </div>
@@ -927,10 +919,8 @@
</div> </div>
</div> </div>
{/if} {/if}
</aside> </aside>
{/if}
<!-- Single global audio element (hidden but functional) -->
<audio <audio
bind:this={audioEl} bind:this={audioEl}
class="hidden" class="hidden"

View File

@@ -21,15 +21,15 @@
{@render children()} {@render children()}
</main> </main>
<!-- Desktop sidebar column (in normal flow). <!-- Desktop sidebar column (in normal flow) -->
Reserve space in the grid, but render the player only once below. --> <aside class="hidden lg:block">
<aside class="hidden lg:block"></aside> <ClientOnly showFallback={false}>
</div>
<!-- Single GlobalPlayer instance (client-only).
It renders either the desktop sidebar UI or the mobile bar/drawer internally. -->
<ClientOnly showFallback={false}>
{#snippet children()} {#snippet children()}
<GlobalPlayer /> <GlobalPlayer />
{/snippet} {/snippet}
</ClientOnly> </ClientOnly>
</aside>
</div>
<!-- Mobile player is rendered by the same GlobalPlayer instance above.
On small screens, it uses fixed positioning internally so it can overlay. -->