feat: toon vandaag ook in de 5-daagse verwachting (nu 6 dagen)
ForecastMapper mapt voortaan index 0 t/m 5 van Open-Meteo (was 1 t/m 5), zodat vandaag als eerste kolom in de verwachtingsstrook verschijnt naast de bestaande 5 dagen erna. Verwachtingskolommen gaan van 5 naar 6 breed (103px i.p.v. 124px), weericoon iets verkleind (58 -> 50px) om te passen. Spec bijgewerkt om de wijziging vast te leggen. Service-worker-versie naar v4 zodat het scherm dit zelf binnen enkele minuten oppikt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Weerscherm: bouwspecificatie v1
|
||||
|
||||
Opdracht voor Claude Code: bouw een PWA die fullscreen draait op een iPad mini (liggend) in de woonkamer. Het scherm toont actuele gegevens van een Netatmo-weerstation en een weersverwachting voor 5 dagen.
|
||||
Opdracht voor Claude Code: bouw een PWA die fullscreen draait op een iPad mini (liggend) in de woonkamer. Het scherm toont actuele gegevens van een Netatmo-weerstation en een weersverwachting voor 6 dagen.
|
||||
|
||||
**Ontwerp A** in `docs/design/weerscherm-layouts.html` is leidend voor de layout. Dat bestand is een statische mockup met voorbeelddata. De CSS van ontwerp A (klasse `.da` en alle `.a-*`-klassen) is getest op 1133 × 744 punten en dient als uitgangspunt. De tabbladen B en C zijn niet in scope.
|
||||
|
||||
@@ -26,7 +26,8 @@ Werkwijze: lees eerst dit document en de mockup. Stel daarna een plan voor per f
|
||||
- Buitentemperatuur, met de laagste en hoogste temperatuur van vandaag (inclusief tijdstippen) en de trend.
|
||||
- De 3 binnensensoren, elk met huidige, laagste en hoogste temperatuur van vandaag.
|
||||
- Regen: vandaag, de afgelopen 3 dagen per dag, en het totaal van de huidige maand.
|
||||
- Verwachting voor de komende 5 dagen (vanaf morgen): max/min-temperatuur, neerslag in mm, neerslagkans en een weericoon.
|
||||
- Verwachting voor 6 dagen (vandaag t/m 5 dagen verder): max/min-temperatuur, neerslag in mm, neerslagkans en een weericoon.
|
||||
_Wijziging 2026-09-13: was oorspronkelijk 5 dagen vanaf morgen; op verzoek van Theo toegevoegd: vandaag als eerste kolom._
|
||||
- Installeerbaar als PWA op het beginscherm, blijft werken met de laatst bekende data als de verbinding wegvalt.
|
||||
|
||||
**Niet in v1:** nachtmodus (ontwerp C), andere meetwaarden (CO₂, luchtvochtigheid, wind), meerdere stations, een instellingenscherm, pushmeldingen.
|
||||
@@ -255,7 +256,7 @@ De iconen `sun`, `partly`, `rain` en `showers` staan in de mockup. Maak `cloud`,
|
||||
- "Vandaag" groot, in mm met 1 decimaal.
|
||||
- Daarnaast 4 staafjes: de 3 vorige dagen (labels "Di", "Wo", "Do") en vandaag, uitgelicht. De hoogte is `mm / max(4 waarden) × 70px`, met een minimum van 2px. Zijn alle waarden 0, dan zijn alle staafjes 2px.
|
||||
- Daaronder "September 38,5 mm".
|
||||
- **Verwachting (rechtsonder):** 5 kolommen met dagafkorting ("Za"), icoon (58px), "max° min°" als hele getallen (min in `--muted`) en "x,x mm" plus neerslagkans in %. Geen neerslag toont "0 mm".
|
||||
- **Verwachting (rechtsonder):** 6 kolommen met dagafkorting ("Za"), icoon (50px), "max° min°" als hele getallen (min in `--muted`) en "x,x mm" plus neerslagkans in %. Geen neerslag toont "0 mm". Eerste kolom is vandaag.
|
||||
|
||||
### 6.4 Verversen
|
||||
|
||||
@@ -342,7 +343,7 @@ Hangt af van de iPadOS-versie in §0:
|
||||
|
||||
- [ ] Op de iPad mini, gestart vanaf het beginscherm, draait de app fullscreen zonder Safari-balken en klopt de layout visueel met ontwerp A.
|
||||
- [ ] Alle waarden komen overeen met de Netatmo-app: buiten, 3× binnen, min/max met tijdstippen, regen vandaag en de afgelopen 3 dagen, en het maandtotaal.
|
||||
- [ ] De verwachting toont 5 dagen vanaf morgen met het juiste icoon per WMO-code.
|
||||
- [ ] De verwachting toont 6 dagen (vandaag t/m 5 dagen verder) met het juiste icoon per WMO-code.
|
||||
- [ ] De data ververst zichzelf. Na middernacht staat de nieuwe datum er binnen 5 minuten.
|
||||
- [ ] Wifi uit: de laatste data blijft staan, met een melding "geen verbinding sinds". Wifi aan: herstelt vanzelf.
|
||||
- [ ] De Netatmo-token ververst meerdere dagen achter elkaar zonder handmatig ingrijpen.
|
||||
|
||||
+2
-2
@@ -129,11 +129,11 @@ html, body {
|
||||
.a-bar.now span { color: var(--ink); font-weight: 600; }
|
||||
|
||||
/* Verwachting */
|
||||
.a-fc { display: grid; grid-template-columns: repeat(5, 1fr); text-align: center; }
|
||||
.a-fc { display: grid; grid-template-columns: repeat(6, 1fr); text-align: center; }
|
||||
.a-day { display: flex; flex-direction: column; align-items: center; gap: 6px; border-left: 1px solid var(--line); }
|
||||
.a-day:first-child { border-left: 0; }
|
||||
.a-dname { font-size: 19px; font-weight: 600; }
|
||||
.a-icon { width: 58px; height: 58px; }
|
||||
.a-icon { width: 50px; height: 50px; }
|
||||
.a-hl { font-size: 28px; font-weight: 500; }
|
||||
.a-hl span { font-size: 22px; color: var(--muted); font-weight: 400; margin-left: 6px; }
|
||||
.a-fr { font-size: 16px; color: var(--rain); }
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* Service worker: app-shell cache-first, API network-first met timeout en fallback op de laatste response. */
|
||||
|
||||
const VERSION = 'weerscherm-v3';
|
||||
const VERSION = 'weerscherm-v4';
|
||||
const SHELL = [
|
||||
'./',
|
||||
'./index.html',
|
||||
|
||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Weerscherm;
|
||||
|
||||
/** Zet het "daily"-blok van Open-Meteo om naar 5 dagen vanaf morgen (index 0 is vandaag). */
|
||||
/** Zet het "daily"-blok van Open-Meteo om naar 6 dagen, inclusief vandaag (index 0). */
|
||||
final class ForecastMapper
|
||||
{
|
||||
private const DAYS = 5;
|
||||
private const DAYS = 6;
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $daily
|
||||
@@ -17,7 +17,7 @@ final class ForecastMapper
|
||||
{
|
||||
$dates = is_array($daily['time'] ?? null) ? $daily['time'] : [];
|
||||
$out = [];
|
||||
for ($i = 1; $i <= self::DAYS && isset($dates[$i]); $i++) {
|
||||
for ($i = 0; $i < self::DAYS && isset($dates[$i]); $i++) {
|
||||
if (!is_string($dates[$i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ final class DashboardServiceTest extends TestCase
|
||||
self::assertSame(['2026-09-08', '2026-09-09', '2026-09-10'], array_column($p['rain']['previous_days'], 'date'));
|
||||
self::assertEqualsWithDelta(38.5, $p['rain']['month_total'], 0.0001);
|
||||
self::assertFalse($p['rain']['stale']);
|
||||
self::assertCount(5, $p['forecast']);
|
||||
self::assertSame('2026-09-12', $p['forecast'][0]['date']);
|
||||
self::assertCount(6, $p['forecast']);
|
||||
self::assertSame('2026-09-11', $p['forecast'][0]['date']);
|
||||
self::assertFalse($p['forecast_stale']);
|
||||
self::assertSame([], $p['errors']);
|
||||
}
|
||||
|
||||
@@ -15,16 +15,16 @@ final class ForecastMapperTest extends TestCase
|
||||
return json_decode((string) file_get_contents(__DIR__ . '/fixtures/forecast.json'), true)['daily'];
|
||||
}
|
||||
|
||||
public function testSkipsTodayAndReturnsFiveDays(): void
|
||||
public function testIncludesTodayAndReturnsSixDays(): void
|
||||
{
|
||||
$f = ForecastMapper::map($this->daily());
|
||||
|
||||
self::assertCount(5, $f);
|
||||
self::assertCount(6, $f);
|
||||
self::assertSame([
|
||||
'date' => '2026-09-12', 'weather_code' => 2, 'temp_max' => 18.3, 'temp_min' => 10.1,
|
||||
'precip_mm' => 0.4, 'precip_prob' => 20,
|
||||
'date' => '2026-09-11', 'weather_code' => 3, 'temp_max' => 17.9, 'temp_min' => 11.0,
|
||||
'precip_mm' => 0.0, 'precip_prob' => 10,
|
||||
], $f[0]);
|
||||
self::assertSame('2026-09-16', $f[4]['date']);
|
||||
self::assertSame('2026-09-16', $f[5]['date']);
|
||||
}
|
||||
|
||||
public function testNullValuesStayNull(): void
|
||||
@@ -35,9 +35,9 @@ final class ForecastMapperTest extends TestCase
|
||||
|
||||
$f = ForecastMapper::map($daily);
|
||||
|
||||
self::assertNull($f[2]['weather_code']);
|
||||
self::assertNull($f[2]['precip_prob']);
|
||||
self::assertSame(17.4, $f[2]['temp_max']);
|
||||
self::assertNull($f[3]['weather_code']);
|
||||
self::assertNull($f[3]['precip_prob']);
|
||||
self::assertSame(17.4, $f[3]['temp_max']);
|
||||
}
|
||||
|
||||
public function testShorterResponseGivesFewerDays(): void
|
||||
@@ -47,7 +47,7 @@ final class ForecastMapperTest extends TestCase
|
||||
$daily[$key] = array_slice($values, 0, 3);
|
||||
}
|
||||
|
||||
self::assertCount(2, ForecastMapper::map($daily));
|
||||
self::assertCount(3, ForecastMapper::map($daily));
|
||||
}
|
||||
|
||||
public function testMissingTimeArrayGivesEmptyList(): void
|
||||
|
||||
Reference in New Issue
Block a user