more fluent design

This commit is contained in:
Vincent van der Wal
2026-07-25 11:10:14 +02:00
parent 562d545c7a
commit d78ac84a12
8 changed files with 90 additions and 73 deletions
@@ -101,11 +101,11 @@
<style>
.chart-bleed {
/* Bleed exactly into the page padding on mobile (main has p-5 =
1.25rem) for edge-to-edge charts, and a bit past the content
/* Bleed exactly into the page padding on mobile (main has p-3 =
0.75rem) for edge-to-edge charts, and a bit past the content
column on md+ (main has 2rem padding) for extra readability. */
margin-left: -1.25rem;
margin-right: -1.25rem;
margin-left: -0.75rem;
margin-right: -0.75rem;
overflow-x: auto;
}
+1 -1
View File
@@ -92,7 +92,7 @@ export interface ChartPanel {
export const defaultChartLayout: ChartPanel[] = [
{ id: 'panel-1', variables: ['weather_icons', 'temperature', 'cloud_cover'] },
{ id: 'panel-2', variables: ['precipitation', 'precipitation_probability'] },
{ id: 'panel-3', variables: ['wind', 'humidity'] }
{ id: 'panel-3', variables: ['wind', 'wind_direction', 'humidity'] }
];
export const storedChartLayout = persisted<ChartPanel[]>('chart_layout_v1', defaultChartLayout);
+1 -1
View File
@@ -83,7 +83,7 @@
<Header onMenuToggle={toggleMobileMenu} />
<main
class={fullBleed ? 'flex-1 overflow-hidden' : 'flex-1 overflow-y-auto p-5 md:px-8 md:py-6'}
class={fullBleed ? 'flex-1 overflow-hidden' : 'flex-1 overflow-y-auto p-3 md:px-8 md:py-6'}
>
{#if fullBleed}
{@render children()}
@@ -281,7 +281,8 @@
<!-- ─── Page hero: location (matches the other forecast pages) ──────────────── -->
<div class="mb-5 flex min-w-0 items-center gap-3">
<div class="mb-5 flex flex-wrap items-center justify-between gap-x-6 gap-y-3">
<div class="flex min-w-0 items-center gap-3">
<img
class="h-10 w-10 shrink-0 rounded-full shadow-sm ring-2 ring-border"
src="/images/country-flags/{(location.country_code || 'united_nations').toLowerCase()}.svg"
@@ -298,23 +299,14 @@
>Model comparison
</p>
</div>
</div>
<!-- ─── Chart Area ─────────────────────────────────────────────────────────── -->
{#if loadError}
<div
class="mb-4 rounded-md border border-destructive/50 bg-destructive/10 px-4 py-3 text-sm text-destructive"
>
Failed to load weather data: {loadError}
</div>
{/if}
<!-- Range / zoom controls (same as the 7-day meteograms) -->
<div class="mb-3 flex flex-wrap items-center justify-end gap-3">
<span class="hidden text-xs text-muted-foreground md:inline">
<!-- Range / zoom controls, aligned with the title like the other pages -->
<div class="flex flex-wrap items-center gap-3">
<span class="hidden text-xs text-muted-foreground lg:inline">
drag or
<kbd class="rounded border border-border bg-muted px-1 py-0.5 font-sans text-[10px]">Ctrl</kbd>
<kbd class="rounded border border-border bg-muted px-1 py-0.5 font-sans text-[10px]">Ctrl</kbd
>
+ scroll to zoom
</span>
{#if zoomActive}
@@ -351,8 +343,19 @@
</button>
{/each}
</div>
</div>
</div>
<!-- ─── Chart Area ─────────────────────────────────────────────────────────── -->
{#if loadError}
<div
class="mb-4 rounded-md border border-destructive/50 bg-destructive/10 px-4 py-3 text-sm text-destructive"
>
Failed to load weather data: {loadError}
</div>
{/if}
<!-- chart count derives from the selected variables (not the fetched data),
so the reserved height is right even before the response arrives -->
<ChartContainer
@@ -119,7 +119,7 @@
</defs>
</svg>
<div in:fade out:fade class="mb-6 min-h-[260px]">
<div transition:fade={{ duration: 200 }} class="mb-6 min-h-[260px]">
<!-- negative margin + matching padding: the scroll box gains room so a
lifted/scaled/shadowed card is never clipped, while the first card still
lines up with the page content edge -->
@@ -1,4 +1,6 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import { storedVariablePrefs } from '$lib/stores/settings';
import { formatUtcOffset, formatZoned, getZonedHour, isSameDayInZone } from '$lib/utils/date';
@@ -236,10 +238,11 @@
{#if cellData.length > 0}
{@const hourly = data.hourly}
{@const iconPx = is3h ? 38 : 33}
<!-- Full-bleed to the viewport edges on mobile (main has p-5 = 1.25rem);
<!-- Full-bleed to the viewport edges on mobile (main has p-3 = 0.75rem);
a contained rounded card on md+ -->
<section
class="-mx-5 overflow-hidden border-y border-border/70 bg-card shadow-sm md:mx-0 md:rounded-2xl md:border"
transition:fade={{ duration: 200 }}
class="-mx-3 overflow-hidden border-y border-border/70 bg-card shadow-sm md:mx-0 md:rounded-2xl md:border"
>
<!-- Card toolbar -->
<div
@@ -153,7 +153,7 @@
);
</script>
<section class="mt-8" in:fade={{ duration: 200 }}>
<section class="mt-8" transition:fade={{ duration: 200 }}>
<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
<h3 class="text-lg font-bold">
Meteograms
@@ -239,7 +239,7 @@
{:else}
<!-- one full-bleed card on mobile / contained card on md+, graphs stacked
tightly so they read as one fluent meteogram -->
<div class="-mx-5 border-y border-border/70 bg-card shadow-sm md:mx-0 md:rounded-2xl md:border">
<div class="-mx-3 border-y border-border/70 bg-card shadow-sm md:mx-0 md:rounded-2xl md:border">
{#each renderPanels as panel, i (panel.id)}
<div
class="px-0 pt-2 pb-1 md:px-4 {i > 0 ? 'border-t border-border/50' : 'md:pt-4'} {i ===
@@ -201,8 +201,19 @@ export const CHART_VARIABLES: ChartVariableDef[] = [
color: '#26a69a',
width: 2,
fill: true,
fillOpacity: 0.15,
windArrows: true
fillOpacity: 0.15
},
{
key: 'wind_direction',
label: 'Wind direction',
short: 'Dir',
field: 'winddirection_10m',
api: 'wind_direction_10m',
type: 'line',
kind: 'wind',
color: '#14b8a6',
windArrows: true,
marker: true
},
{
key: 'wind_gusts',
@@ -325,7 +336,7 @@ export function neededHourlyApiVars(
if (!def) continue;
s.add(apiNameOf(def));
if (def.pictograms) s.add('weather_code');
if (def.key === 'wind') s.add('wind_direction_10m');
if (def.windArrows || def.key === 'wind') s.add('wind_direction_10m');
}
return [...s];