fix(linebed): size artwork off the live measured column height

CSS-only flex stretch + aspect-ratio collapsed instead of sizing the
thumb against the track-meta column — the previous two attempts
landed with no visible change (the thumb stayed near its old fixed
72px or fell back to image-intrinsic). aspect-ratio interacts poorly
with align-self: stretch when the item has no natural width to drive
the stretched dimension off.

Drops the CSS-only attempt. Binds clientHeight on .track-meta with
Svelte's bind:clientHeight, derives 98% of that into artworkSize, and
applies the result as inline width/height on the thumb. Reactive —
when the badge or text lines re-flow, the column height changes and
the thumb resizes with it. No fallback fixed size needed because the
{#if artwork && artworkSize > 0} guard avoids the first-paint flash
before the bind resolves.

cc
This commit is contained in:
vicrodh committed 2026-05-13 19:19:58 -06:00
1 parent c715475d10
commit 7bb1047283
1 file changed
+25 -17
@@ -48,6 +48,15 @@
let unlisten: UnlistenFn | null = null; let unlisten: UnlistenFn | null = null;
let isInitialized = false; let isInitialized = false;
// Live height of the track-meta column (3 text lines + quality badge).
// The artwork thumb sizes off this so it visually matches the column,
// which CSS-only flex stretch + aspect-ratio couldn't deliver reliably
// (aspect-ratio interacts poorly with align-self: stretch on items
// whose natural width is auto). 98% of this gives a small breathing
// gutter that reads as deliberate.
let metaHeight = $state(0);
const artworkSize = $derived(Math.max(0, Math.floor(metaHeight * 0.98)));
const INPUT_BANDS = 512; const INPUT_BANDS = 512;
const VISUAL_BANDS = 256; const VISUAL_BANDS = 256;
const NUM_LINES = 200; const NUM_LINES = 200;
@@ -423,7 +432,7 @@
<canvas bind:this={canvasRef} class="linebed-canvas"></canvas> <canvas bind:this={canvasRef} class="linebed-canvas"></canvas>
<div class="bottom-info"> <div class="bottom-info">
<div class="track-meta"> <div class="track-meta" bind:clientHeight={metaHeight}>
<span class="track-title">{trackTitle}</span> <span class="track-title">{trackTitle}</span>
{#if explicit} {#if explicit}
<span class="explicit-badge" title="{ $t('library.explicit') }"></span> <span class="explicit-badge" title="{ $t('library.explicit') }"></span>
@@ -434,8 +443,12 @@
<span class="track-artist">{artist}</span> <span class="track-artist">{artist}</span>
<QualityBadgeStatic {quality} {bitDepth} {samplingRate} {format} /> <QualityBadgeStatic {quality} {bitDepth} {samplingRate} {format} />
</div> </div>
{#if artwork} {#if artwork && artworkSize > 0}
<div class="artwork-thumb"> <div
class="artwork-thumb"
style:width="{artworkSize}px"
style:height="{artworkSize}px"
>
<img src={artwork} alt={trackTitle} /> <img src={artwork} alt={trackTitle} />
</div> </div>
{/if} {/if}
@@ -470,11 +483,11 @@
bottom: 24px; bottom: 24px;
z-index: 10; z-index: 10;
display: flex; display: flex;
/* Stretch so the artwork thumb matches the height of the track-meta /* center keeps the artwork vertically centered against the
column (title + album + artist + quality badge). The artwork's track-meta column (3 lines + badge). The artwork's width/height
intrinsic dimensions are no longer fixed — it scales to fill the are set inline from the live measured column height, so flex
column height with a 1px top/bottom margin (~98% of the column). */ just needs to position it — no stretch shenanigans. */
align-items: stretch; align-items: center;
gap: 12px; gap: 12px;
} }
@@ -515,16 +528,11 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
/* The thumb stretches to the height of the track-meta column (3 /* width / height come from inline style (computed as 98% of the
text lines + quality badge) via the parent's align-items: stretch. measured track-meta column height in the script). The .thumb
aspect-ratio: 1 keeps it square (width derives from the stretched itself just carries the chrome (rounded corners, drop shadow). */
height). margin-block: 1px gives the 2px gap that reads as a
deliberate breathing room around the column instead of a flush
edge match. */
.artwork-thumb { .artwork-thumb {
align-self: stretch; flex-shrink: 0;
aspect-ratio: 1;
margin-block: 1px;
border-radius: 6px; border-radius: 6px;
overflow: hidden; overflow: hidden;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);