finish animations and add elevation
This commit is contained in:
@@ -346,12 +346,12 @@
|
||||
<svelte:head>
|
||||
<title>Drizz.li | {m.page_week_title()}</title>
|
||||
<link rel="canonical" href="https://drizz.li/weather/week" />
|
||||
<meta name="description" content="7-day weather forecast with detailed hourly data" />
|
||||
<meta name="description" content="Weekly weather forecast with detailed hourly data" />
|
||||
</svelte:head>
|
||||
|
||||
<!-- the model picker rides in the layout's location row (see weather/+layout) -->
|
||||
{#snippet heroActions()}
|
||||
<div class="lg:absolute lg:right-0 lg:top-0 flex w-full min-w-0 items-center gap-3 sm:w-auto">
|
||||
<div class="flex w-full min-w-0 items-center gap-3 sm:w-auto">
|
||||
<ModelSelector
|
||||
selectedModel={params.models?.[0] ?? 'best_match'}
|
||||
onModelChange={(model) => {
|
||||
|
||||
@@ -322,6 +322,10 @@
|
||||
// positioned relative to the data columns only.
|
||||
let headerColWidth = $state(0);
|
||||
let tableWidth = $state(0);
|
||||
// Measured so the centred NOW badge can be clamped fully inside the row:
|
||||
// centred on a time near midnight it would poke past the last column and
|
||||
// hand the scroller a sliver of phantom overflow.
|
||||
let nowBadgeWidth = $state(0);
|
||||
let nowLeftPx = $derived(
|
||||
nowPercent != null && tableWidth > 0
|
||||
? headerColWidth + (nowPercent / 100) * (tableWidth - headerColWidth)
|
||||
@@ -608,14 +612,17 @@
|
||||
{#if nowPercent != null}
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 w-0.5 -translate-x-1/2 bg-red-500/75"
|
||||
style="left:{nowPercent}%"
|
||||
style="left:clamp(1px, {nowPercent}%, calc(100% - 1px))"
|
||||
></div>
|
||||
{/if}
|
||||
<!-- "Now" label, aligned with the sunrise/sunset labels along the bottom -->
|
||||
<!-- "Now" label, aligned with the sunrise/sunset labels along the
|
||||
bottom; its centre is clamped so the pill never leaves the row -->
|
||||
{#if isTodaySelected && nowPercent != null}
|
||||
<span
|
||||
bind:clientWidth={nowBadgeWidth}
|
||||
class="absolute bottom-0.5 z-15 -translate-x-1/2 rounded-full bg-red-500 px-1.5 py-px text-[9px] font-bold tracking-wide whitespace-nowrap text-white uppercase shadow-sm"
|
||||
style="left:{nowPercent}%"
|
||||
style="left:clamp({nowBadgeWidth /
|
||||
2}px, {nowPercent}%, calc(100% - {nowBadgeWidth / 2}px))"
|
||||
>
|
||||
{m.table_now()}
|
||||
</span>
|
||||
@@ -904,24 +911,31 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- Hovered-column highlight, mirroring the meteogram crosshair -->
|
||||
<!-- Hovered-column highlight, mirroring the meteogram crosshair.
|
||||
max-width caps the box at the wrapper's true (fractional) right
|
||||
edge: the widths here derive from rounded clientWidth bindings, so
|
||||
on the last column left+width can land a fraction of a pixel past
|
||||
the edge - enough scrollable overflow for a phantom scrollbar. -->
|
||||
{#if hoveredCol >= 0 && tableWidth > 0}
|
||||
{@const colWidth = (tableWidth - headerColWidth) / cellData.length}
|
||||
{@const colLeft = headerColWidth + hoveredCol * colWidth}
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 z-10 border-x border-primary/40 bg-primary/10"
|
||||
style="left:{headerColWidth + hoveredCol * colWidth}px;width:{colWidth}px"
|
||||
style="left:{colLeft}px;width:{colWidth}px;max-width:calc(100% - {colLeft}px)"
|
||||
></div>
|
||||
{/if}
|
||||
|
||||
<!-- "Now" column highlight. The current-time line itself is painted per
|
||||
cell (.now-cell) so it stays under the values and icons. -->
|
||||
cell (.now-cell) so it stays under the values and icons. Same
|
||||
max-width cap as the hover highlight above. -->
|
||||
{#if nowLeftPx != null}
|
||||
{@const colWidth = (tableWidth - headerColWidth) / cellData.length}
|
||||
{@const nowIdx = cellData.findIndex((c) => c.isNow)}
|
||||
{#if nowIdx >= 0}
|
||||
{@const colLeft = headerColWidth + nowIdx * colWidth}
|
||||
<div
|
||||
class="pointer-events-none absolute inset-y-0 z-10 border-x border-red-500/30 bg-red-500/5"
|
||||
style="left:{headerColWidth + nowIdx * colWidth}px;width:{colWidth}px"
|
||||
style="left:{colLeft}px;width:{colWidth}px;max-width:calc(100% - {colLeft}px)"
|
||||
></div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -64,9 +64,13 @@
|
||||
if (val) onModelChange(val);
|
||||
}}
|
||||
>
|
||||
<!-- Fixed width from sm up (mobile stays full-width): the trigger used to hug
|
||||
its content, so its size changed with every model name and differed
|
||||
between pages. One constant footprint, sized for the longest label in
|
||||
the catalogue; anything longer truncates. -->
|
||||
<Select.Trigger
|
||||
aria-label={m.model_selector_aria({ label })}
|
||||
class="group h-auto min-h-12 min-w-0 flex-1 cursor-pointer gap-2.5 rounded-xl border-2 border-primary/35 bg-card py-1.5 ps-2.5 shadow-sm transition-colors hover:border-primary/70 hover:shadow-md data-[size=default]:h-auto data-[state=open]:border-primary sm:min-h-14 sm:gap-3 sm:py-2 sm:min-w-72 sm:flex-none"
|
||||
class="group h-auto min-h-12 min-w-0 flex-1 cursor-pointer gap-2.5 rounded-xl border-2 border-primary/35 bg-card py-1.5 ps-2.5 shadow-sm transition-colors hover:border-primary/70 hover:shadow-md data-[size=default]:h-auto data-[state=open]:border-primary sm:min-h-14 sm:w-80 sm:gap-3 sm:py-2 sm:flex-none"
|
||||
>
|
||||
<div
|
||||
class="flex size-8 shrink-0 items-center justify-center rounded-lg bg-primary/12 text-primary sm:size-9"
|
||||
|
||||
Reference in New Issue
Block a user