more fluent design
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user