feat: OG png + sentry + dept api + drom notice + registre canicule
Some checks are pending
Deploy info-canicule / deploy (push) Waiting to run
Some checks are pending
Deploy info-canicule / deploy (push) Waiting to run
Quick wins : - public/og-image.png (1200x630, via sharp depuis le SVG, build via pnpm build) SVG ne fonctionne pas pour Open Graph (Slack/Discord/X/FB). - @sentry/astro intégré conditionnellement (skip si SENTRY_DSN absent → no-op). GIT_COMMIT_SHA en var pour le release tag dans GlitchTip si voulu. - /api/vigilance/dept/[code] : JSON enrichi (phenomenon label + color name) pour J et J1, CORS *, Cache-Control 5min. 404 si code unknown. - JSON-LD enrichi : @graph WebSite + Service avec isBasedOn Dataset + license LOv2. - Lien retour vigilance.meteofrance.fr visible sous la carte. DROM (97x / 976) : - 5 entrées ajoutées dans departements.ts (région "DROM"). - /departement/[code] DROM : bannière "Vigilance Outre-mer non couverte par cette source open data" + bouton vers vigilance.meteofrance.fr. - Home : ligne sous la carte listant les 5 DROM + lien retour. - L'API /api/vigilance/dept/<DROM> retourne quand même un JSON 200 (arrays vides). Registre canicule : - Page /conseils/registre-canicule : qui, quoi, comment s'inscrire au CCAS. - Numéro vert 0 800 06 66 66. - Bannière mise en avant en haut de /conseils. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
89e48c18e4
commit
87d173684c
13 changed files with 1595 additions and 35 deletions
|
|
@ -2,6 +2,10 @@ import { defineConfig } from 'astro/config';
|
|||
import node from '@astrojs/node';
|
||||
import tailwind from '@astrojs/tailwind';
|
||||
import sitemap from '@astrojs/sitemap';
|
||||
import sentry from '@sentry/astro';
|
||||
|
||||
const sentryDsn = process.env.SENTRY_DSN;
|
||||
const release = process.env.GIT_COMMIT_SHA || 'dev';
|
||||
|
||||
export default defineConfig({
|
||||
output: 'server',
|
||||
|
|
@ -14,6 +18,19 @@ export default defineConfig({
|
|||
!page.includes('/departement/'),
|
||||
// /departement/* est dynamique pour les 96 dépts — généré dans /sitemap-departements.xml.ts à part.
|
||||
}),
|
||||
// Sentry / GlitchTip — opt-in via env. Si SENTRY_DSN absent, intégration omise (no-op).
|
||||
...(sentryDsn
|
||||
? [
|
||||
sentry({
|
||||
dsn: sentryDsn,
|
||||
environment: process.env.NODE_ENV ?? 'production',
|
||||
release,
|
||||
tracesSampleRate: 0.1,
|
||||
// GlitchTip est OK avec source maps mais on les omet pour éviter le upload.
|
||||
sourceMapsUploadOptions: { enabled: false },
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
],
|
||||
server: { host: '0.0.0.0', port: 4321 },
|
||||
site: 'https://info-canicule.nocleus.com',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"build": "node scripts/build-og-image.mjs && astro build",
|
||||
"build:og": "node scripts/build-og-image.mjs",
|
||||
"preview": "astro preview",
|
||||
"start": "node ./dist/server/entry.mjs",
|
||||
"astro": "astro",
|
||||
|
|
@ -16,6 +17,7 @@
|
|||
"@astrojs/node": "^9.2.2",
|
||||
"@astrojs/sitemap": "^3.6.0",
|
||||
"@astrojs/tailwind": "^6.0.2",
|
||||
"@sentry/astro": "^10.53.1",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"astro": "^5.7.0",
|
||||
"ioredis": "^5.6.0",
|
||||
|
|
@ -24,6 +26,7 @@
|
|||
"devDependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@types/node": "^22.10.5",
|
||||
"sharp": "^0.34.5",
|
||||
"typescript": "^5.7.2"
|
||||
},
|
||||
"packageManager": "pnpm@10.0.0"
|
||||
|
|
|
|||
1272
pnpm-lock.yaml
generated
1272
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
BIN
public/og-image.png
Normal file
BIN
public/og-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
20
scripts/build-og-image.mjs
Normal file
20
scripts/build-og-image.mjs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env node
|
||||
// Convertit public/og-image.svg en public/og-image.png (1200×630).
|
||||
// Lancé manuellement ou via `pnpm prebuild` quand le SVG bouge.
|
||||
|
||||
import sharp from 'sharp';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { resolve, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const SVG = resolve(__dirname, '../public/og-image.svg');
|
||||
const PNG = resolve(__dirname, '../public/og-image.png');
|
||||
|
||||
const buf = readFileSync(SVG);
|
||||
await sharp(buf, { density: 144 })
|
||||
.resize(1200, 630, { fit: 'fill' })
|
||||
.png({ compressionLevel: 9 })
|
||||
.toFile(PNG);
|
||||
|
||||
console.log(`Wrote ${PNG}`);
|
||||
|
|
@ -14,7 +14,7 @@ const {
|
|||
title = 'Info Canicule — Vigilance météo France en temps réel',
|
||||
description = 'Suivi gratuit et sans publicité des alertes Vigilance Météo France (canicule, orages, tempêtes), avec carte interactive par département et conseils officiels.',
|
||||
canonical,
|
||||
ogImage = '/og-image.svg',
|
||||
ogImage = '/og-image.png',
|
||||
noindex = false,
|
||||
} = Astro.props;
|
||||
|
||||
|
|
@ -25,20 +25,43 @@ const umamiSrc = process.env.UMAMI_SRC ?? 'https://analytics.nocleus.com/script.
|
|||
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebSite',
|
||||
name: 'Info Canicule',
|
||||
url: SITE,
|
||||
description,
|
||||
inLanguage: 'fr-FR',
|
||||
publisher: {
|
||||
'@type': 'Person',
|
||||
name: 'Florian Bouchet',
|
||||
},
|
||||
potentialAction: {
|
||||
'@type': 'SearchAction',
|
||||
target: `${SITE}/departement/{code}`,
|
||||
'query-input': 'required name=code',
|
||||
},
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'WebSite',
|
||||
'@id': `${SITE}/#website`,
|
||||
name: 'Info Canicule',
|
||||
url: SITE,
|
||||
description,
|
||||
inLanguage: 'fr-FR',
|
||||
publisher: { '@type': 'Person', name: 'Florian Bouchet' },
|
||||
potentialAction: {
|
||||
'@type': 'SearchAction',
|
||||
target: `${SITE}/departement/{code}`,
|
||||
'query-input': 'required name=code',
|
||||
},
|
||||
},
|
||||
{
|
||||
'@type': 'Service',
|
||||
'@id': `${SITE}/#service`,
|
||||
name: 'Info Canicule',
|
||||
serviceType: 'Service d\'information météorologique grand public',
|
||||
areaServed: { '@type': 'Country', name: 'France' },
|
||||
audience: { '@type': 'PeopleAudience', audienceType: 'Grand public, personnes fragiles' },
|
||||
provider: {
|
||||
'@type': 'Person',
|
||||
name: 'Florian Bouchet',
|
||||
url: `${SITE}/a-propos`,
|
||||
},
|
||||
isBasedOn: {
|
||||
'@type': 'Dataset',
|
||||
name: 'Vigilance Météo France',
|
||||
url: 'https://vigilance.meteofrance.fr/',
|
||||
creator: { '@type': 'Organization', name: 'Météo-France' },
|
||||
license: 'https://www.etalab.gouv.fr/licence-ouverte-open-licence/',
|
||||
},
|
||||
isAccessibleForFree: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export const ADVICE: Record<PhenomenonId, PhenomenonAdvice> = {
|
|||
title: 'Veiller sur les proches',
|
||||
items: [
|
||||
"Prendre des nouvelles des personnes isolées (voisins âgés, malades, sans-abri)",
|
||||
"S'inscrire ou inscrire un proche fragile sur le registre canicule de sa mairie",
|
||||
"Inscrire un proche fragile sur le registre canicule de sa mairie — voir page dédiée",
|
||||
'En cas de symptôme inquiétant (maux de tête, vertiges, nausées, fièvre) : alerter rapidement',
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -106,8 +106,20 @@ export const DEPARTEMENTS: Departement[] = [
|
|||
{ code: '94', name: 'Val-de-Marne', region: 'Île-de-France' },
|
||||
{ code: '95', name: "Val-d'Oise", region: 'Île-de-France' },
|
||||
{ code: '99', name: 'Andorre (zone Vigilance)', region: 'Hors France' },
|
||||
// DROM — non couverts par le dataset Opendatasoft actuel.
|
||||
// Vigilance DROM dispo via l'API Météo France officielle uniquement (TODO).
|
||||
{ code: '971', name: 'Guadeloupe', region: 'DROM' },
|
||||
{ code: '972', name: 'Martinique', region: 'DROM' },
|
||||
{ code: '973', name: 'Guyane', region: 'DROM' },
|
||||
{ code: '974', name: 'La Réunion', region: 'DROM' },
|
||||
{ code: '976', name: 'Mayotte', region: 'DROM' },
|
||||
];
|
||||
|
||||
export const DROM_CODES = new Set(['971', '972', '973', '974', '976']);
|
||||
export function isDrom(code: string): boolean {
|
||||
return DROM_CODES.has(code);
|
||||
}
|
||||
|
||||
const BY_CODE = new Map(DEPARTEMENTS.map((d) => [d.code, d]));
|
||||
|
||||
export function getDepartement(code: string): Departement | undefined {
|
||||
|
|
|
|||
62
src/pages/api/vigilance/dept/[code].ts
Normal file
62
src/pages/api/vigilance/dept/[code].ts
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import type { APIRoute } from 'astro';
|
||||
import { getVigilanceSnapshot, alertsForDepartement } from '../../../../lib/vigilance';
|
||||
import { getDepartement } from '../../../../lib/departements';
|
||||
import { PHENOMENA, COLORS } from '../../../../lib/phenomena';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
// JSON par département (J + J1) — CORS *, réutilisable sous Licence Ouverte 2.0.
|
||||
// Ex : GET /api/vigilance/dept/75 → alertes Paris
|
||||
export const GET: APIRoute = async ({ params }) => {
|
||||
const codeRaw = params.code;
|
||||
if (!codeRaw) {
|
||||
return new Response(JSON.stringify({ error: 'missing_code' }), {
|
||||
status: 400,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
const code = codeRaw.toUpperCase();
|
||||
const dept = getDepartement(code);
|
||||
if (!dept) {
|
||||
return new Response(JSON.stringify({ error: 'unknown_departement', code }), {
|
||||
status: 404,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const snap = await getVigilanceSnapshot();
|
||||
const today = alertsForDepartement(snap, code, 'J');
|
||||
const tomorrow = alertsForDepartement(snap, code, 'J1');
|
||||
const enrich = (a: ReturnType<typeof alertsForDepartement>[0]) => ({
|
||||
phenomenonId: a.phenomenonId,
|
||||
phenomenon: PHENOMENA[a.phenomenonId].label,
|
||||
colorId: a.colorId,
|
||||
color: COLORS[a.colorId].name,
|
||||
beginTime: a.beginTime,
|
||||
endTime: a.endTime,
|
||||
});
|
||||
|
||||
const body = {
|
||||
departement: { code, name: dept.name, region: dept.region },
|
||||
productDatetime: snap.productDatetime,
|
||||
fetchedAt: snap.fetchedAt,
|
||||
today: today.map(enrich),
|
||||
tomorrow: tomorrow.map(enrich),
|
||||
};
|
||||
|
||||
return new Response(JSON.stringify(body), {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8',
|
||||
'Cache-Control': 'public, max-age=300',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'fetch_failed', detail: (e as Error).message }),
|
||||
{ status: 502, headers: { 'Content-Type': 'application/json' } },
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
@ -21,6 +21,17 @@ const phenomenaList = Object.values(PHENOMENA).sort((a, b) =>
|
|||
Recommandations à appliquer en cas d'alerte Vigilance, par type de phénomène.
|
||||
Sources : Météo France, santé.gouv.fr, gouvernement.fr.
|
||||
</p>
|
||||
<div class="mt-4 rounded-lg border border-canicule-200 bg-canicule-50 p-4">
|
||||
<p class="text-sm font-semibold text-canicule-900">
|
||||
🛡️ Aider une personne fragile : <a href="/conseils/registre-canicule" class="font-bold underline">
|
||||
registre canicule de la mairie
|
||||
</a>
|
||||
</p>
|
||||
<p class="mt-1 text-sm text-canicule-800">
|
||||
Dispositif communal gratuit qui permet à un proche âgé, malade ou isolé d'être contacté en
|
||||
cas d'alerte. Inscription en quelques minutes via le CCAS.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
108
src/pages/conseils/registre-canicule.astro
Normal file
108
src/pages/conseils/registre-canicule.astro
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
import Base from '../../layouts/Base.astro';
|
||||
|
||||
export const prerender = false;
|
||||
---
|
||||
|
||||
<Base
|
||||
title="Registre canicule — s'inscrire pour soi ou un proche fragile"
|
||||
description="Le registre canicule est un dispositif communal gratuit qui permet d'être contacté par la mairie en cas d'épisode caniculaire. Comment s'y inscrire."
|
||||
>
|
||||
<section class="bg-gradient-to-b from-canicule-50 to-white">
|
||||
<div class="container-tight py-10">
|
||||
<a href="/conseils" class="text-sm text-canicule-700">← Tous les conseils</a>
|
||||
<h1 class="mt-2 text-3xl font-bold sm:text-4xl">Registre canicule</h1>
|
||||
<p class="mt-2 max-w-2xl text-slate-600">
|
||||
Un dispositif communal, gratuit et confidentiel, qui permet d'être contacté par sa mairie en
|
||||
cas d'alerte canicule. Conçu en priorité pour les personnes fragiles et isolées.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container-tight py-8 prose prose-slate max-w-none">
|
||||
<h2>À qui ça s'adresse</h2>
|
||||
<p>Le registre nominatif communal est ouvert à toute personne qui le souhaite, mais il est
|
||||
particulièrement utile pour :</p>
|
||||
<ul>
|
||||
<li>Les <strong>personnes âgées de 65 ans et plus</strong> vivant à domicile</li>
|
||||
<li>Les <strong>personnes en situation de handicap</strong></li>
|
||||
<li>Les <strong>personnes adultes isolées</strong> (sans aidant proche)</li>
|
||||
<li>Les personnes <strong>fragilisées par une maladie chronique</strong></li>
|
||||
</ul>
|
||||
<p>
|
||||
Vous pouvez inscrire un proche (parent, voisin) avec son accord, ou demander une inscription
|
||||
d'office pour une personne dont vous estimez qu'elle est en danger.
|
||||
</p>
|
||||
|
||||
<h2>Comment ça se passe en cas d'alerte</h2>
|
||||
<ul>
|
||||
<li>Quand un département passe en vigilance orange ou rouge canicule, le plan « Plan National
|
||||
Canicule » (PNC) s'enclenche en mairie.</li>
|
||||
<li>Les personnes inscrites sur le registre sont <strong>appelées</strong> ou
|
||||
<strong>visitées</strong> par des agents communaux ou bénévoles (Croix-Rouge, ADMR…).</li>
|
||||
<li>L'objectif : vérifier qu'elles vont bien, qu'elles ont de quoi s'hydrater et rester au
|
||||
frais, et alerter si besoin (médecin traitant, 15, famille).</li>
|
||||
</ul>
|
||||
|
||||
<h2>Comment s'inscrire</h2>
|
||||
<ol>
|
||||
<li>
|
||||
Contacter le <strong>CCAS</strong> (Centre Communal d'Action Sociale) de votre commune, ou
|
||||
directement la mairie. Numéros disponibles via l'annuaire officiel des mairies :
|
||||
<a href="https://lannuaire.service-public.fr/navigation/mairie" rel="noopener">
|
||||
lannuaire.service-public.fr/navigation/mairie
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
Demander le <strong>formulaire d'inscription au registre canicule</strong> (parfois appelé
|
||||
« registre des personnes vulnérables » ou « plan canicule »).
|
||||
</li>
|
||||
<li>
|
||||
Remplir le formulaire avec : nom, âge, adresse, téléphone, personne à prévenir, médecin
|
||||
traitant, éventuelles particularités (isolement, mobilité, etc.).
|
||||
</li>
|
||||
<li>
|
||||
Retourner le formulaire à la mairie. <strong>Gratuit et confidentiel</strong> — les données
|
||||
ne servent qu'au plan canicule, ne sont pas partagées commercialement.
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<h2>Bon à savoir</h2>
|
||||
<ul>
|
||||
<li>L'inscription est <strong>valable pour toute la saison estivale</strong> (juin à
|
||||
septembre), à renouveler chaque année si besoin.</li>
|
||||
<li>Vous pouvez vous <strong>désinscrire à tout moment</strong> par simple courrier ou appel.</li>
|
||||
<li>
|
||||
Cadre légal : article L121-6-1 du Code de l'action sociale et des familles + circulaire
|
||||
annuelle relative au Plan National Canicule.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="not-prose my-6 rounded-lg border border-canicule-200 bg-canicule-50 p-4">
|
||||
<p class="text-sm font-semibold text-canicule-900">📞 Plateforme téléphonique canicule</p>
|
||||
<p class="mt-1 text-sm text-canicule-800">
|
||||
Numéro vert <a href="tel:0800066666" class="font-mono font-bold">0 800 06 66 66</a> (gratuit
|
||||
depuis un poste fixe). Activé pendant les épisodes de canicule pour informer et conseiller.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h2>Pour aller plus loin</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://www.sante.gouv.fr/sante-et-environnement/risques-climatiques/article/plan-national-canicule-pnc" rel="noopener">
|
||||
Plan National Canicule (santé.gouv.fr)
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://solidarites.gouv.fr/sites/solidarite/files/migration/Brochure_canicule_grand_public_2024.pdf" rel="noopener">
|
||||
Brochure officielle Canicule grand public (PDF)
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://meteofrance.com/comprendre-meteo/temperature-et-chaleur/canicule" rel="noopener">
|
||||
Comprendre une canicule (Météo France)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</Base>
|
||||
|
|
@ -3,7 +3,7 @@ import Base from '../../layouts/Base.astro';
|
|||
import VigilanceChip from '../../components/VigilanceChip.astro';
|
||||
import VigilanceLegend from '../../components/VigilanceLegend.astro';
|
||||
import { getVigilanceSnapshot, alertsForDepartement } from '../../lib/vigilance';
|
||||
import { getDepartement } from '../../lib/departements';
|
||||
import { getDepartement, isDrom } from '../../lib/departements';
|
||||
import { PHENOMENA, COLOR_LABEL } from '../../lib/phenomena';
|
||||
import { ADVICE, EMERGENCY_NUMBERS } from '../../lib/advice';
|
||||
import { getClimatoForDepartement } from '../../lib/climato';
|
||||
|
|
@ -18,19 +18,25 @@ if (!dept) {
|
|||
return new Response('Département introuvable', { status: 404 });
|
||||
}
|
||||
|
||||
const drom = isDrom(dept.code);
|
||||
|
||||
let snapshot;
|
||||
let error: string | null = null;
|
||||
try {
|
||||
snapshot = await getVigilanceSnapshot();
|
||||
} catch (e) {
|
||||
error = (e as Error).message;
|
||||
if (!drom) {
|
||||
try {
|
||||
snapshot = await getVigilanceSnapshot();
|
||||
} catch (e) {
|
||||
error = (e as Error).message;
|
||||
}
|
||||
}
|
||||
|
||||
let climato = null;
|
||||
try {
|
||||
climato = await getClimatoForDepartement(dept.code);
|
||||
} catch (e) {
|
||||
console.warn('climato fetch failed for', dept.code, (e as Error).message);
|
||||
if (!drom) {
|
||||
try {
|
||||
climato = await getClimatoForDepartement(dept.code);
|
||||
} catch (e) {
|
||||
console.warn('climato fetch failed for', dept.code, (e as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
const today = snapshot ? alertsForDepartement(snapshot, dept.code, 'J') : [];
|
||||
|
|
@ -52,10 +58,30 @@ const adviceFor = highest && ADVICE[highest.phenomenonId];
|
|||
</section>
|
||||
|
||||
<section class="container-tight py-8">
|
||||
{error && <p class="text-red-700">Données indisponibles : {error}</p>}
|
||||
{drom && (
|
||||
<div class="rounded-lg border border-amber-200 bg-amber-50 p-4">
|
||||
<p class="font-semibold text-amber-900">Vigilance Outre-mer non couverte par cette source</p>
|
||||
<p class="mt-1 text-sm text-amber-800">
|
||||
Les départements et régions d'Outre-mer disposent de leur propre dispositif Vigilance, géré
|
||||
par les centres météorologiques locaux de Météo France. Ces données ne sont pas (encore)
|
||||
rediffusées en open data au même format que la métropole.
|
||||
</p>
|
||||
<p class="mt-3">
|
||||
<a
|
||||
href="https://vigilance.meteofrance.fr/"
|
||||
rel="noopener"
|
||||
class="inline-flex items-center gap-1 rounded bg-amber-700 px-4 py-2 text-sm font-semibold text-white no-underline hover:bg-amber-800"
|
||||
>
|
||||
Voir la Vigilance officielle Outre-mer →
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!drom && error && <p class="text-red-700">Données indisponibles : {error}</p>}
|
||||
|
||||
{
|
||||
!error && today.length === 0 && (
|
||||
!drom && !error && today.length === 0 && (
|
||||
<div class="rounded border border-green-200 bg-green-50 p-4">
|
||||
<p class="font-semibold text-green-800">Aucune vigilance particulière aujourd'hui.</p>
|
||||
<p class="text-sm text-green-700">Le département est en niveau vert pour tous les phénomènes.</p>
|
||||
|
|
@ -64,7 +90,7 @@ const adviceFor = highest && ADVICE[highest.phenomenonId];
|
|||
}
|
||||
|
||||
{
|
||||
!error && today.length > 0 && (
|
||||
!drom && !error && today.length > 0 && (
|
||||
<>
|
||||
<h2 class="mb-3 text-xl font-semibold">Alertes en cours</h2>
|
||||
<ul class="space-y-3">
|
||||
|
|
@ -100,7 +126,7 @@ const adviceFor = highest && ADVICE[highest.phenomenonId];
|
|||
}
|
||||
|
||||
{
|
||||
!error && tomorrow.length > 0 && (
|
||||
!drom && !error && tomorrow.length > 0 && (
|
||||
<div class="mt-8">
|
||||
<h2 class="mb-3 text-xl font-semibold">Prévision pour demain</h2>
|
||||
<ul class="space-y-2">
|
||||
|
|
|
|||
|
|
@ -119,6 +119,22 @@ const productDate = snapshot?.productDatetime
|
|||
<DepartementGrid colorsByDept={colorsByDept} />
|
||||
</div>
|
||||
</details>
|
||||
<p class="mt-4 text-center text-xs text-slate-500">
|
||||
Source officielle :
|
||||
<a href="https://vigilance.meteofrance.fr/" rel="noopener" class="text-canicule-700 font-medium">
|
||||
vigilance.meteofrance.fr
|
||||
</a>
|
||||
— toujours s'y référer en cas d'urgence.
|
||||
</p>
|
||||
<p class="mt-2 text-center text-xs text-slate-500">
|
||||
<strong>Outre-mer non couvert</strong> par cette source open data :
|
||||
<a href="/departement/971" class="text-canicule-700">Guadeloupe</a> ·
|
||||
<a href="/departement/972" class="text-canicule-700">Martinique</a> ·
|
||||
<a href="/departement/973" class="text-canicule-700">Guyane</a> ·
|
||||
<a href="/departement/974" class="text-canicule-700">La Réunion</a> ·
|
||||
<a href="/departement/976" class="text-canicule-700">Mayotte</a> →
|
||||
<a href="https://vigilance.meteofrance.fr/" rel="noopener" class="text-canicule-700">vigilance.meteofrance.fr</a>
|
||||
</p>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue