diff --git a/src/lib/components/Ledger.svelte b/src/lib/components/Ledger.svelte index 26c155c..ba7ce51 100644 --- a/src/lib/components/Ledger.svelte +++ b/src/lib/components/Ledger.svelte @@ -75,17 +75,22 @@ const crowded = $derived(duel.others.length >= 3); - // The focused wizard's columns slide in just past the pinned ones. + // The focused wizard's columns slide in just past the pinned ones. Sticky cells + // report where they are stuck, not where they lie, so the sums are done in + // viewport coordinates: the header's distance from the scroller's edge plus + // the current scroll, less the width the pinned columns always cover. $effect(() => { const who = duel.focus; void duel.focusTick; if (!who || !scroller) return; const th = scroller.querySelector(`th[data-who="${who}"]`); - const pinned = scroller.querySelector('thead th.pin-right'); if (!th) return; - const left = pinned ? pinned.offsetLeft + pinned.offsetWidth : 0; + const pinnedWidth = ['th.turn', 'thead tr.hands th.pin-left', 'thead tr.hands th.pin-right'] + .map((sel) => scroller!.querySelector(sel)?.getBoundingClientRect().width ?? 0) + .reduce((a, b) => a + b, 0); + const left = th.getBoundingClientRect().left - scroller.getBoundingClientRect().left + scroller.scrollLeft - pinnedWidth; const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; - scroller.scrollTo({ left: th.offsetLeft - left, behavior: reduce ? 'auto' : 'smooth' }); + scroller.scrollTo({ left: Math.max(0, left), behavior: reduce ? 'auto' : 'smooth' }); }); @@ -110,7 +115,7 @@ {/each} - + {#each columns as who (who)} left right diff --git a/src/lib/components/MobileBar.svelte b/src/lib/components/MobileBar.svelte index 66bfb00..19d20ff 100644 --- a/src/lib/components/MobileBar.svelte +++ b/src/lib/components/MobileBar.svelte @@ -4,16 +4,28 @@ import { MAX_HP } from '$lib/game/state'; let { duel }: { duel: Duel } = $props(); + + /** Past three wizards the bar names you, the wizard in focus, and the count; the roster is a tap away. */ + const crowded = $derived(duel.others.length >= 3); + const shown = $derived(crowded ? [duel.focus ?? duel.foeId].filter((id) => id !== duel.me) : duel.others); + + function toRoster() { + const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + document.getElementById('roster')?.scrollIntoView({ behavior: reduce ? 'auto' : 'smooth', block: 'start' }); + } {#if !duel.state.over}
1}> {#if !duel.spectating}{duel.you.name} {duel.you.hp}/{MAX_HP}{/if} - {#each duel.others as id (id)} + {#each shown as id (id)} {@const w = duel.state.wizards[id]} {w.name} {w.hp}/{MAX_HP} {/each} + {#if crowded} + + {/if}
{#if duel.spectating} the gallery @@ -88,6 +100,15 @@ opacity: 0.6; } + .count { + background: none; + border: 0; + padding: 0; + font: inherit; + color: var(--frost); + text-decoration: underline dotted; + } + .gestures { display: flex; gap: 0.5rem; diff --git a/src/lib/components/Roster.svelte b/src/lib/components/Roster.svelte index 3c2b25d..9e77fee 100644 --- a/src/lib/components/Roster.svelte +++ b/src/lib/components/Roster.svelte @@ -26,7 +26,7 @@ } -
+

At the table

    {#each duel.others as id (id)} @@ -53,6 +53,7 @@