feat: pages contenu + SEO + Umami + sitemap
Some checks are pending
Deploy info-canicule / deploy (push) Waiting to run
Some checks are pending
Deploy info-canicule / deploy (push) Waiting to run
- Pages /a-propos, /mentions-legales, /dependances, /soutenir (Ko-fi) - Header/footer enrichis (lien Soutenir, mentions, API publique) - @astrojs/sitemap + /sitemap-departements.xml.ts (96 dépts) - robots.txt + og-image.svg + JSON-LD Schema.org - Meta tags Open Graph + Twitter Card + canonical - Umami snippet conditionnel (UMAMI_WEBSITE_ID env) - Slot SENTRY_DSN dans .env.tmpl (GlitchTip — SDK à wire ultérieurement) - @tailwindcss/typography pour les pages contenu Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e075d963bc
commit
86352eb436
14 changed files with 727 additions and 23 deletions
|
|
@ -12,3 +12,7 @@ VIGILANCE_PROVIDER=opendatasoft
|
||||||
|
|
||||||
# TTL du cache Vigilance en secondes (Vigilance se met à jour 2x/jour, 15min raisonnable)
|
# TTL du cache Vigilance en secondes (Vigilance se met à jour 2x/jour, 15min raisonnable)
|
||||||
VIGILANCE_CACHE_TTL=900
|
VIGILANCE_CACHE_TTL=900
|
||||||
|
|
||||||
|
# Umami analytics (optionnel — laisser vide pour désactiver)
|
||||||
|
UMAMI_WEBSITE_ID=
|
||||||
|
UMAMI_SRC=https://analytics.nocleus.com/script.js
|
||||||
|
|
|
||||||
|
|
@ -7,3 +7,10 @@ REDIS_URL=redis://info-canicule:{{ pass://Infra/Valkey — info-canicule/passwor
|
||||||
|
|
||||||
VIGILANCE_PROVIDER=opendatasoft
|
VIGILANCE_PROVIDER=opendatasoft
|
||||||
VIGILANCE_CACHE_TTL=900
|
VIGILANCE_CACHE_TTL=900
|
||||||
|
|
||||||
|
# Umami analytics (RGPD, auto-hébergé — analytics.nocleus.com)
|
||||||
|
UMAMI_WEBSITE_ID={{ pass://Infra/Umami — info-canicule/website_id }}
|
||||||
|
UMAMI_SRC=https://analytics.nocleus.com/script.js
|
||||||
|
|
||||||
|
# GlitchTip (optionnel — si vide, pas d'envoi Sentry)
|
||||||
|
SENTRY_DSN={{ pass://Infra/Info Canicule — secrets/SENTRY_DSN }}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,20 @@
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
import node from '@astrojs/node';
|
import node from '@astrojs/node';
|
||||||
import tailwind from '@astrojs/tailwind';
|
import tailwind from '@astrojs/tailwind';
|
||||||
|
import sitemap from '@astrojs/sitemap';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
output: 'server',
|
output: 'server',
|
||||||
adapter: node({ mode: 'standalone' }),
|
adapter: node({ mode: 'standalone' }),
|
||||||
integrations: [tailwind({ applyBaseStyles: false })],
|
integrations: [
|
||||||
|
tailwind({ applyBaseStyles: false }),
|
||||||
|
sitemap({
|
||||||
|
filter: (page) =>
|
||||||
|
!page.includes('/api/') &&
|
||||||
|
!page.includes('/departement/'),
|
||||||
|
// /departement/* est dynamique pour les 96 dépts — généré dans /sitemap-departements.xml.ts à part.
|
||||||
|
}),
|
||||||
|
],
|
||||||
server: { host: '0.0.0.0', port: 4321 },
|
server: { host: '0.0.0.0', port: 4321 },
|
||||||
site: 'https://info-canicule.nocleus.com',
|
site: 'https://info-canicule.nocleus.com',
|
||||||
vite: {
|
vite: {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/node": "^9.2.2",
|
"@astrojs/node": "^9.2.2",
|
||||||
|
"@astrojs/sitemap": "^3.6.0",
|
||||||
"@astrojs/tailwind": "^6.0.2",
|
"@astrojs/tailwind": "^6.0.2",
|
||||||
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"astro": "^5.7.0",
|
"astro": "^5.7.0",
|
||||||
"ioredis": "^5.6.0",
|
"ioredis": "^5.6.0",
|
||||||
"tailwindcss": "^3.4.17"
|
"tailwindcss": "^3.4.17"
|
||||||
|
|
|
||||||
75
pnpm-lock.yaml
generated
75
pnpm-lock.yaml
generated
|
|
@ -11,9 +11,15 @@ importers:
|
||||||
'@astrojs/node':
|
'@astrojs/node':
|
||||||
specifier: ^9.2.2
|
specifier: ^9.2.2
|
||||||
version: 9.5.5(astro@5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0))
|
version: 9.5.5(astro@5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0))
|
||||||
|
'@astrojs/sitemap':
|
||||||
|
specifier: ^3.6.0
|
||||||
|
version: 3.7.2
|
||||||
'@astrojs/tailwind':
|
'@astrojs/tailwind':
|
||||||
specifier: ^6.0.2
|
specifier: ^6.0.2
|
||||||
version: 6.0.2(astro@5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0))(tailwindcss@3.4.19(yaml@2.9.0))
|
version: 6.0.2(astro@5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0))(tailwindcss@3.4.19(yaml@2.9.0))
|
||||||
|
'@tailwindcss/typography':
|
||||||
|
specifier: ^0.5.16
|
||||||
|
version: 0.5.19(tailwindcss@3.4.19(yaml@2.9.0))
|
||||||
astro:
|
astro:
|
||||||
specifier: ^5.7.0
|
specifier: ^5.7.0
|
||||||
version: 5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0)
|
version: 5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0)
|
||||||
|
|
@ -76,6 +82,9 @@ packages:
|
||||||
resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==}
|
resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==}
|
||||||
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
|
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
|
||||||
|
|
||||||
|
'@astrojs/sitemap@3.7.2':
|
||||||
|
resolution: {integrity: sha512-PqkzkcZTb5ICiyIR8VoKbIAP/laNRXi5tw616N1Ckk+40oNB8Can1AzVV56lrbC5GKSZFCyJYUVYqVivMisvpA==}
|
||||||
|
|
||||||
'@astrojs/tailwind@6.0.2':
|
'@astrojs/tailwind@6.0.2':
|
||||||
resolution: {integrity: sha512-j3mhLNeugZq6A8dMNXVarUa8K6X9AW+QHU9u3lKNrPLMHhOQ0S7VeWhHwEeJFpEK1BTKEUY1U78VQv2gN6hNGg==}
|
resolution: {integrity: sha512-j3mhLNeugZq6A8dMNXVarUa8K6X9AW+QHU9u3lKNrPLMHhOQ0S7VeWhHwEeJFpEK1BTKEUY1U78VQv2gN6hNGg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -769,6 +778,11 @@ packages:
|
||||||
'@shikijs/vscode-textmate@10.0.2':
|
'@shikijs/vscode-textmate@10.0.2':
|
||||||
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==}
|
||||||
|
|
||||||
|
'@tailwindcss/typography@0.5.19':
|
||||||
|
resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==}
|
||||||
|
peerDependencies:
|
||||||
|
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
|
||||||
|
|
||||||
'@types/debug@4.1.13':
|
'@types/debug@4.1.13':
|
||||||
resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==}
|
resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==}
|
||||||
|
|
||||||
|
|
@ -793,6 +807,12 @@ packages:
|
||||||
'@types/node@22.19.19':
|
'@types/node@22.19.19':
|
||||||
resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==}
|
resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==}
|
||||||
|
|
||||||
|
'@types/node@24.12.4':
|
||||||
|
resolution: {integrity: sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==}
|
||||||
|
|
||||||
|
'@types/sax@1.2.7':
|
||||||
|
resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
|
||||||
|
|
||||||
'@types/unist@3.0.3':
|
'@types/unist@3.0.3':
|
||||||
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
||||||
|
|
||||||
|
|
@ -1721,6 +1741,10 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
postcss: ^8.2.14
|
postcss: ^8.2.14
|
||||||
|
|
||||||
|
postcss-selector-parser@6.0.10:
|
||||||
|
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
postcss-selector-parser@6.1.2:
|
postcss-selector-parser@6.1.2:
|
||||||
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
|
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
@ -1890,6 +1914,11 @@ packages:
|
||||||
sisteransi@1.0.5:
|
sisteransi@1.0.5:
|
||||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||||
|
|
||||||
|
sitemap@9.0.1:
|
||||||
|
resolution: {integrity: sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==}
|
||||||
|
engines: {node: '>=20.19.5', npm: '>=10.8.2'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
smol-toml@1.6.1:
|
smol-toml@1.6.1:
|
||||||
resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==}
|
resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
|
|
@ -1908,6 +1937,9 @@ packages:
|
||||||
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
stream-replace-string@2.0.0:
|
||||||
|
resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==}
|
||||||
|
|
||||||
string-width@4.2.3:
|
string-width@4.2.3:
|
||||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -2021,6 +2053,9 @@ packages:
|
||||||
undici-types@6.21.0:
|
undici-types@6.21.0:
|
||||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||||
|
|
||||||
|
undici-types@7.16.0:
|
||||||
|
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
|
||||||
|
|
||||||
unified@11.0.5:
|
unified@11.0.5:
|
||||||
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==}
|
||||||
|
|
||||||
|
|
@ -2348,6 +2383,9 @@ packages:
|
||||||
zod@3.25.76:
|
zod@3.25.76:
|
||||||
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||||
|
|
||||||
|
zod@4.4.3:
|
||||||
|
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
|
||||||
|
|
||||||
zwitch@2.0.4:
|
zwitch@2.0.4:
|
||||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||||
|
|
||||||
|
|
@ -2434,6 +2472,12 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
prismjs: 1.30.0
|
prismjs: 1.30.0
|
||||||
|
|
||||||
|
'@astrojs/sitemap@3.7.2':
|
||||||
|
dependencies:
|
||||||
|
sitemap: 9.0.1
|
||||||
|
stream-replace-string: 2.0.0
|
||||||
|
zod: 4.4.3
|
||||||
|
|
||||||
'@astrojs/tailwind@6.0.2(astro@5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0))(tailwindcss@3.4.19(yaml@2.9.0))':
|
'@astrojs/tailwind@6.0.2(astro@5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0))(tailwindcss@3.4.19(yaml@2.9.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
astro: 5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0)
|
astro: 5.18.1(@types/node@22.19.19)(ioredis@5.10.1)(jiti@1.21.7)(rollup@4.60.4)(typescript@5.9.3)(yaml@2.9.0)
|
||||||
|
|
@ -2904,6 +2948,11 @@ snapshots:
|
||||||
|
|
||||||
'@shikijs/vscode-textmate@10.0.2': {}
|
'@shikijs/vscode-textmate@10.0.2': {}
|
||||||
|
|
||||||
|
'@tailwindcss/typography@0.5.19(tailwindcss@3.4.19(yaml@2.9.0))':
|
||||||
|
dependencies:
|
||||||
|
postcss-selector-parser: 6.0.10
|
||||||
|
tailwindcss: 3.4.19(yaml@2.9.0)
|
||||||
|
|
||||||
'@types/debug@4.1.13':
|
'@types/debug@4.1.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/ms': 2.1.0
|
'@types/ms': 2.1.0
|
||||||
|
|
@ -2930,6 +2979,14 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.21.0
|
undici-types: 6.21.0
|
||||||
|
|
||||||
|
'@types/node@24.12.4':
|
||||||
|
dependencies:
|
||||||
|
undici-types: 7.16.0
|
||||||
|
|
||||||
|
'@types/sax@1.2.7':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 22.19.19
|
||||||
|
|
||||||
'@types/unist@3.0.3': {}
|
'@types/unist@3.0.3': {}
|
||||||
|
|
||||||
'@ungap/structured-clone@1.3.1': {}
|
'@ungap/structured-clone@1.3.1': {}
|
||||||
|
|
@ -4148,6 +4205,11 @@ snapshots:
|
||||||
postcss: 8.5.15
|
postcss: 8.5.15
|
||||||
postcss-selector-parser: 6.1.2
|
postcss-selector-parser: 6.1.2
|
||||||
|
|
||||||
|
postcss-selector-parser@6.0.10:
|
||||||
|
dependencies:
|
||||||
|
cssesc: 3.0.0
|
||||||
|
util-deprecate: 1.0.2
|
||||||
|
|
||||||
postcss-selector-parser@6.1.2:
|
postcss-selector-parser@6.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
cssesc: 3.0.0
|
cssesc: 3.0.0
|
||||||
|
|
@ -4418,6 +4480,13 @@ snapshots:
|
||||||
|
|
||||||
sisteransi@1.0.5: {}
|
sisteransi@1.0.5: {}
|
||||||
|
|
||||||
|
sitemap@9.0.1:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 24.12.4
|
||||||
|
'@types/sax': 1.2.7
|
||||||
|
arg: 5.0.2
|
||||||
|
sax: 1.6.0
|
||||||
|
|
||||||
smol-toml@1.6.1: {}
|
smol-toml@1.6.1: {}
|
||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
@ -4428,6 +4497,8 @@ snapshots:
|
||||||
|
|
||||||
statuses@2.0.2: {}
|
statuses@2.0.2: {}
|
||||||
|
|
||||||
|
stream-replace-string@2.0.0: {}
|
||||||
|
|
||||||
string-width@4.2.3:
|
string-width@4.2.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
emoji-regex: 8.0.0
|
emoji-regex: 8.0.0
|
||||||
|
|
@ -4557,6 +4628,8 @@ snapshots:
|
||||||
|
|
||||||
undici-types@6.21.0: {}
|
undici-types@6.21.0: {}
|
||||||
|
|
||||||
|
undici-types@7.16.0: {}
|
||||||
|
|
||||||
unified@11.0.5:
|
unified@11.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/unist': 3.0.3
|
'@types/unist': 3.0.3
|
||||||
|
|
@ -4839,4 +4912,6 @@ snapshots:
|
||||||
|
|
||||||
zod@3.25.76: {}
|
zod@3.25.76: {}
|
||||||
|
|
||||||
|
zod@4.4.3: {}
|
||||||
|
|
||||||
zwitch@2.0.4: {}
|
zwitch@2.0.4: {}
|
||||||
|
|
|
||||||
15
public/og-image.svg
Normal file
15
public/og-image.svg
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 630">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="0%" stop-color="#fff7ed"/>
|
||||||
|
<stop offset="100%" stop-color="#ffedd5"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<rect width="1200" height="630" fill="url(#bg)"/>
|
||||||
|
<text x="80" y="200" font-family="system-ui,-apple-system,sans-serif" font-size="120" font-weight="800" fill="#c2410c">🌡️ Info</text>
|
||||||
|
<text x="80" y="340" font-family="system-ui,-apple-system,sans-serif" font-size="120" font-weight="800" fill="#c2410c">Canicule</text>
|
||||||
|
<text x="80" y="440" font-family="system-ui,-apple-system,sans-serif" font-size="38" fill="#7c2d12">Vigilance Météo France en temps réel</text>
|
||||||
|
<text x="80" y="495" font-family="system-ui,-apple-system,sans-serif" font-size="28" fill="#9a3412">Carte interactive · 96 départements · conseils officiels</text>
|
||||||
|
<text x="80" y="570" font-family="system-ui,-apple-system,sans-serif" font-size="22" fill="#a16207">Gratuit · sans publicité · non lucratif · données ouvertes</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
5
public/robots.txt
Normal file
5
public/robots.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
Disallow: /api/
|
||||||
|
|
||||||
|
Sitemap: https://info-canicule.nocleus.com/sitemap-index.xml
|
||||||
|
|
@ -4,12 +4,43 @@ import '../styles/global.css';
|
||||||
interface Props {
|
interface Props {
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
canonical?: string;
|
||||||
|
ogImage?: string;
|
||||||
|
noindex?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SITE = 'https://info-canicule.nocleus.com';
|
||||||
const {
|
const {
|
||||||
title = 'Info Canicule — Vigilance météo en temps réel',
|
title = 'Info Canicule — Vigilance météo France en temps réel',
|
||||||
description = 'Suivi en temps réel des alertes Vigilance Météo France et conseils officiels en cas de canicule, orages, tempêtes.',
|
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',
|
||||||
|
noindex = false,
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
|
const canonicalUrl = canonical ?? new URL(Astro.url.pathname, SITE).toString();
|
||||||
|
const fullOgImage = ogImage.startsWith('http') ? ogImage : `${SITE}${ogImage}`;
|
||||||
|
const umamiId = import.meta.env.UMAMI_WEBSITE_ID;
|
||||||
|
const umamiSrc = import.meta.env.UMAMI_SRC ?? 'https://analytics.nocleus.com/script.js';
|
||||||
|
|
||||||
|
const jsonLd = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'WebSite',
|
||||||
|
name: 'Info Canicule',
|
||||||
|
url: SITE,
|
||||||
|
description,
|
||||||
|
inLanguage: 'fr-FR',
|
||||||
|
publisher: {
|
||||||
|
'@type': 'Person',
|
||||||
|
name: 'Florian Bouchet',
|
||||||
|
url: 'https://nocleus.com',
|
||||||
|
},
|
||||||
|
potentialAction: {
|
||||||
|
'@type': 'SearchAction',
|
||||||
|
target: `${SITE}/departement/{code}`,
|
||||||
|
'query-input': 'required name=code',
|
||||||
|
},
|
||||||
|
};
|
||||||
---
|
---
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
@ -18,24 +49,46 @@ const {
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<meta name="description" content={description} />
|
<meta name="description" content={description} />
|
||||||
<meta name="robots" content="index, follow" />
|
{noindex ? <meta name="robots" content="noindex, nofollow" /> : <meta name="robots" content="index, follow, max-image-preview:large" />}
|
||||||
|
<link rel="canonical" href={canonicalUrl} />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="alternate" type="application/rss+xml" title="Info Canicule" href={`${SITE}/sitemap-index.xml`} />
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
|
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:title" content={title} />
|
<meta property="og:title" content={title} />
|
||||||
<meta property="og:description" content={description} />
|
<meta property="og:description" content={description} />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:url" content={canonicalUrl} />
|
||||||
|
<meta property="og:image" content={fullOgImage} />
|
||||||
|
<meta property="og:locale" content="fr_FR" />
|
||||||
|
<meta property="og:site_name" content="Info Canicule" />
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={title} />
|
||||||
|
<meta name="twitter:description" content={description} />
|
||||||
|
<meta name="twitter:image" content={fullOgImage} />
|
||||||
|
|
||||||
<meta name="theme-color" content="#ea580c" />
|
<meta name="theme-color" content="#ea580c" />
|
||||||
|
<meta name="format-detection" content="telephone=yes" />
|
||||||
|
|
||||||
|
<script type="application/ld+json" set:html={JSON.stringify(jsonLd)} />
|
||||||
|
|
||||||
|
{umamiId && (
|
||||||
|
<script defer src={umamiSrc} data-website-id={umamiId} data-do-not-track="true"></script>
|
||||||
|
)}
|
||||||
</head>
|
</head>
|
||||||
<body class="min-h-screen flex flex-col">
|
<body class="min-h-screen flex flex-col">
|
||||||
<header class="border-b border-slate-200 bg-white">
|
<header class="border-b border-slate-200 bg-white">
|
||||||
<div class="container-tight flex items-center justify-between py-4">
|
<div class="container-tight flex flex-wrap items-center justify-between gap-3 py-4">
|
||||||
<a href="/" class="flex items-center gap-2 no-underline">
|
<a href="/" class="flex items-center gap-2 no-underline">
|
||||||
<span class="text-2xl">🌡️</span>
|
<span class="text-2xl">🌡️</span>
|
||||||
<span class="text-lg font-bold text-canicule-700">Info Canicule</span>
|
<span class="text-lg font-bold text-canicule-700">Info Canicule</span>
|
||||||
</a>
|
</a>
|
||||||
<nav class="flex items-center gap-6 text-sm font-medium text-slate-600">
|
<nav class="flex flex-wrap items-center gap-x-5 gap-y-1 text-sm font-medium text-slate-600">
|
||||||
<a href="/">Carte Vigilance</a>
|
<a href="/">Carte</a>
|
||||||
<a href="/conseils">Conseils</a>
|
<a href="/conseils">Conseils</a>
|
||||||
|
<a href="/a-propos">À propos</a>
|
||||||
|
<a href="/soutenir" class="text-canicule-700">☕ Soutenir</a>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
@ -44,22 +97,37 @@ const {
|
||||||
</main>
|
</main>
|
||||||
<footer class="border-t border-slate-200 bg-white">
|
<footer class="border-t border-slate-200 bg-white">
|
||||||
<div class="container-tight py-6 text-sm text-slate-500">
|
<div class="container-tight py-6 text-sm text-slate-500">
|
||||||
<p>
|
<div class="grid gap-4 sm:grid-cols-3">
|
||||||
Données :
|
<div>
|
||||||
<a href="https://meteo.data.gouv.fr/" class="text-canicule-700" rel="noopener">Météo France</a>
|
<p class="font-semibold text-slate-700">Info Canicule</p>
|
||||||
via
|
<p class="mt-1 text-xs">
|
||||||
<a href="https://public.opendatasoft.com/" class="text-canicule-700" rel="noopener">Opendatasoft</a>
|
Service d'information publique gratuit, sans publicité, non lucratif.
|
||||||
— Licence Ouverte 2.0.
|
</p>
|
||||||
</p>
|
</div>
|
||||||
<p class="mt-1">
|
<div>
|
||||||
Service d'information publique sans valeur officielle. En cas de doute, suivre les consignes de
|
<p class="font-semibold text-slate-700">Liens</p>
|
||||||
la Préfecture (
|
<ul class="mt-1 space-y-0.5">
|
||||||
<a href="tel:112" class="text-canicule-700">112</a>
|
<li><a href="/a-propos">À propos</a></li>
|
||||||
en urgence).
|
<li><a href="/mentions-legales">Mentions légales</a></li>
|
||||||
</p>
|
<li><a href="/dependances">Dépendances</a></li>
|
||||||
<p class="mt-2 text-xs text-slate-400">
|
<li><a href="/soutenir">Soutenir</a></li>
|
||||||
|
<li><a href="/api/vigilance">API JSON publique</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="font-semibold text-slate-700">Données</p>
|
||||||
|
<p class="mt-1 text-xs">
|
||||||
|
<a href="https://meteo.data.gouv.fr/" rel="noopener">Météo France</a>
|
||||||
|
— <a href="https://www.etalab.gouv.fr/licence-ouverte-open-licence/" rel="noopener">Licence Ouverte 2.0</a>.
|
||||||
|
En urgence : <a href="tel:112" class="text-canicule-700 font-semibold">112</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="mt-4 text-xs text-slate-400">
|
||||||
Un projet
|
Un projet
|
||||||
<a href="https://nocleus.com" class="text-canicule-700" rel="noopener">Nocleus</a>.
|
<a href="https://nocleus.com" class="text-canicule-700" rel="noopener">Nocleus</a>.
|
||||||
|
Code source :
|
||||||
|
<a href="https://git.nocleus.com/florian/info-canicule" class="text-canicule-700" rel="noopener">git.nocleus.com</a>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
91
src/pages/a-propos.astro
Normal file
91
src/pages/a-propos.astro
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
---
|
||||||
|
import Base from '../layouts/Base.astro';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base
|
||||||
|
title="À propos — Info Canicule"
|
||||||
|
description="Info Canicule est un site d'information publique gratuit, non lucratif, qui agrège les alertes Vigilance Météo France et les conseils officiels."
|
||||||
|
>
|
||||||
|
<section class="bg-gradient-to-b from-canicule-50 to-white">
|
||||||
|
<div class="container-tight py-10">
|
||||||
|
<h1 class="text-3xl font-bold sm:text-4xl">À propos d'Info Canicule</h1>
|
||||||
|
<p class="mt-2 text-slate-600">
|
||||||
|
Pourquoi ce site existe, comment il fonctionne, ce qu'il ne fait pas.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="container-tight py-8 prose prose-slate max-w-none">
|
||||||
|
<h2>Pourquoi ce site ?</h2>
|
||||||
|
<p>
|
||||||
|
Les épisodes de canicule, d'orages violents ou de fortes pluies tuent des dizaines de personnes
|
||||||
|
chaque année en France. Les informations existent — Météo France publie des bulletins Vigilance
|
||||||
|
détaillés, le gouvernement diffuse des conseils — mais elles sont éparpillées, parfois difficiles
|
||||||
|
à trouver, souvent enfouies sous des bannières publicitaires sur les sites grand public.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Info Canicule</strong> est un site d'utilité publique qui ne fait qu'une chose :
|
||||||
|
afficher clairement, gratuitement, sans publicité ni traceurs commerciaux, la Vigilance Météo
|
||||||
|
France en temps réel et les conseils officiels à appliquer.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Comment ça marche</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Données Vigilance</strong> : récupérées toutes les 15 minutes depuis le portail
|
||||||
|
Opendatasoft qui rediffuse les bulletins Météo France. Bulletin officiel mis à jour deux fois
|
||||||
|
par jour (matin et après-midi).
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Données climatologiques</strong> : températures journalières des 30 derniers jours,
|
||||||
|
récupérées depuis <a href="https://meteo.data.gouv.fr/" rel="noopener">meteo.data.gouv.fr</a>
|
||||||
|
(jeu de données <em>Données climatologiques de base — quotidiennes</em>), agrégées en moyenne
|
||||||
|
sur toutes les stations du département.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Conseils officiels</strong> : repris des publications de
|
||||||
|
<a href="https://www.meteofrance.fr/" rel="noopener">Météo France</a>,
|
||||||
|
<a href="https://sante.gouv.fr/" rel="noopener">santé.gouv.fr</a> et
|
||||||
|
<a href="https://www.gouvernement.fr/" rel="noopener">gouvernement.fr</a>.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Ce que ce site n'est pas</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Pas un service officiel</strong>. En cas d'urgence, suivre les consignes de la Préfecture (
|
||||||
|
<a href="tel:112">112</a>).</li>
|
||||||
|
<li><strong>Pas un site commercial</strong>. Aucune publicité, aucune monétisation, aucun affiliation,
|
||||||
|
aucune vente de données.</li>
|
||||||
|
<li><strong>Pas un outil de prévision</strong>. Les prévisions affichées sont celles de Météo France,
|
||||||
|
pas un modèle indépendant.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>Statut juridique</h2>
|
||||||
|
<p>
|
||||||
|
Info Canicule est édité <strong>à titre personnel, sans but lucratif</strong>, sur fonds propres
|
||||||
|
par un développeur indépendant. Le site n'est pas une association loi 1901, pas une entreprise,
|
||||||
|
pas un service public. Les données affichées sont publiques et réutilisables sous
|
||||||
|
<a href="https://www.etalab.gouv.fr/licence-ouverte-open-licence/" rel="noopener">Licence Ouverte 2.0</a>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Voir aussi : <a href="/mentions-legales">mentions légales</a>,
|
||||||
|
<a href="/dependances">dépendances logicielles</a>,
|
||||||
|
<a href="/soutenir">soutenir le projet</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Code source</h2>
|
||||||
|
<p>
|
||||||
|
Le site est entièrement open source. Le code est disponible sur
|
||||||
|
<a href="https://git.nocleus.com/florian/info-canicule" rel="noopener">git.nocleus.com/florian/info-canicule</a>
|
||||||
|
(instance Forgejo personnelle). Contributions, signalements de bugs et améliorations bienvenus.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Contact</h2>
|
||||||
|
<p>
|
||||||
|
Mail : <a href="mailto:florian@nocleus.com">florian@nocleus.com</a> — pour toute question,
|
||||||
|
remarque ou correction (typo, erreur dans un conseil, donnée incohérente).
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</Base>
|
||||||
215
src/pages/dependances.astro
Normal file
215
src/pages/dependances.astro
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
---
|
||||||
|
import Base from '../layouts/Base.astro';
|
||||||
|
import pkg from '../../package.json';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
|
||||||
|
const deps = Object.entries(pkg.dependencies as Record<string, string>).sort(([a], [b]) =>
|
||||||
|
a.localeCompare(b),
|
||||||
|
);
|
||||||
|
const devDeps = Object.entries(pkg.devDependencies as Record<string, string>).sort(([a], [b]) =>
|
||||||
|
a.localeCompare(b),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Catalogue manuel : description + license + URL pour chaque dépendance principale.
|
||||||
|
const META: Record<string, { desc: string; license: string; url: string }> = {
|
||||||
|
astro: {
|
||||||
|
desc: "Framework web orienté contenu (rendu serveur, île d'interactivité).",
|
||||||
|
license: 'MIT',
|
||||||
|
url: 'https://astro.build/',
|
||||||
|
},
|
||||||
|
'@astrojs/node': {
|
||||||
|
desc: 'Adapter Astro pour exécution sur Node.js (mode standalone).',
|
||||||
|
license: 'MIT',
|
||||||
|
url: 'https://docs.astro.build/en/guides/integrations-guide/node/',
|
||||||
|
},
|
||||||
|
'@astrojs/tailwind': {
|
||||||
|
desc: 'Intégration TailwindCSS pour Astro.',
|
||||||
|
license: 'MIT',
|
||||||
|
url: 'https://docs.astro.build/en/guides/integrations-guide/tailwind/',
|
||||||
|
},
|
||||||
|
tailwindcss: {
|
||||||
|
desc: 'Framework CSS utility-first.',
|
||||||
|
license: 'MIT',
|
||||||
|
url: 'https://tailwindcss.com/',
|
||||||
|
},
|
||||||
|
ioredis: {
|
||||||
|
desc: 'Client Redis/Valkey performant pour Node.js (cache du snapshot Vigilance).',
|
||||||
|
license: 'MIT',
|
||||||
|
url: 'https://github.com/redis/ioredis',
|
||||||
|
},
|
||||||
|
'@astrojs/check': {
|
||||||
|
desc: 'Type checker officiel Astro (utilisé en CI / dev).',
|
||||||
|
license: 'MIT',
|
||||||
|
url: 'https://docs.astro.build/en/reference/cli-reference/#astro-check',
|
||||||
|
},
|
||||||
|
'@types/node': {
|
||||||
|
desc: 'Types TypeScript pour les API Node.js.',
|
||||||
|
license: 'MIT',
|
||||||
|
url: 'https://www.npmjs.com/package/@types/node',
|
||||||
|
},
|
||||||
|
typescript: {
|
||||||
|
desc: 'Compilateur TypeScript (vérification de types).',
|
||||||
|
license: 'Apache-2.0',
|
||||||
|
url: 'https://www.typescriptlang.org/',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const DATA_SOURCES = [
|
||||||
|
{
|
||||||
|
name: 'France GeoJSON',
|
||||||
|
desc: "Polygones des départements français (utilisés pour la carte SVG).",
|
||||||
|
license: 'Licence Ouverte 2.0',
|
||||||
|
url: 'https://github.com/gregoiredavid/france-geojson',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Météo France — Vigilance',
|
||||||
|
desc: 'Bulletin Vigilance en temps réel via Opendatasoft.',
|
||||||
|
license: 'Licence Ouverte 2.0',
|
||||||
|
url: 'https://public.opendatasoft.com/explore/dataset/weatherref-france-vigilance-meteo-departement/',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Météo France — Climatologie',
|
||||||
|
desc: 'Données climatologiques de base quotidiennes (températures, précipitations).',
|
||||||
|
license: 'Licence Ouverte 2.0',
|
||||||
|
url: 'https://www.data.gouv.fr/datasets/donnees-climatologiques-de-base-quotidiennes',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const INFRA = [
|
||||||
|
{ name: 'Node.js 22', desc: "Runtime serveur.", license: 'MIT', url: 'https://nodejs.org/' },
|
||||||
|
{ name: 'Docker', desc: 'Containerisation.', license: 'Apache-2.0', url: 'https://www.docker.com/' },
|
||||||
|
{ name: 'Caddy', desc: 'Reverse proxy + TLS automatique.', license: 'Apache-2.0', url: 'https://caddyserver.com/' },
|
||||||
|
{ name: 'Valkey', desc: 'Fork ouvert de Redis (cache).', license: 'BSD-3-Clause', url: 'https://valkey.io/' },
|
||||||
|
{ name: 'Umami', desc: 'Analytics RGPD-friendly (auto-hébergé).', license: 'MIT', url: 'https://umami.is/' },
|
||||||
|
{ name: 'Forgejo', desc: 'Forge git auto-hébergée + CI/CD.', license: 'MIT', url: 'https://forgejo.org/' },
|
||||||
|
];
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base
|
||||||
|
title="Dépendances — Info Canicule"
|
||||||
|
description="Liste complète des bibliothèques logicielles, sources de données et services utilisés par Info Canicule."
|
||||||
|
>
|
||||||
|
<section class="bg-gradient-to-b from-canicule-50 to-white">
|
||||||
|
<div class="container-tight py-10">
|
||||||
|
<h1 class="text-3xl font-bold sm:text-4xl">Dépendances</h1>
|
||||||
|
<p class="mt-2 max-w-2xl text-slate-600">
|
||||||
|
Transparence sur ce qui fait tourner Info Canicule : code, données, infrastructure.
|
||||||
|
Tout est open source ou en données ouvertes.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="container-tight py-8 space-y-10">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-xl font-semibold">Sources de données</h2>
|
||||||
|
<table class="mt-3 w-full text-sm">
|
||||||
|
<thead class="bg-slate-100 text-left text-slate-700">
|
||||||
|
<tr>
|
||||||
|
<th class="px-3 py-2">Source</th>
|
||||||
|
<th class="px-3 py-2">Description</th>
|
||||||
|
<th class="px-3 py-2">Licence</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{DATA_SOURCES.map((s) => (
|
||||||
|
<tr class="border-t border-slate-200">
|
||||||
|
<td class="px-3 py-2 font-medium">
|
||||||
|
<a href={s.url} rel="noopener">{s.name}</a>
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-2 text-slate-700">{s.desc}</td>
|
||||||
|
<td class="px-3 py-2 text-slate-600">{s.license}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 class="text-xl font-semibold">Bibliothèques applicatives</h2>
|
||||||
|
<table class="mt-3 w-full text-sm">
|
||||||
|
<thead class="bg-slate-100 text-left text-slate-700">
|
||||||
|
<tr>
|
||||||
|
<th class="px-3 py-2">Package</th>
|
||||||
|
<th class="px-3 py-2">Version</th>
|
||||||
|
<th class="px-3 py-2">Description</th>
|
||||||
|
<th class="px-3 py-2">Licence</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{deps.map(([name, version]) => {
|
||||||
|
const m = META[name];
|
||||||
|
return (
|
||||||
|
<tr class="border-t border-slate-200">
|
||||||
|
<td class="px-3 py-2 font-mono">
|
||||||
|
{m ? <a href={m.url} rel="noopener">{name}</a> : name}
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-2 text-slate-600">{version}</td>
|
||||||
|
<td class="px-3 py-2 text-slate-700">{m?.desc ?? '—'}</td>
|
||||||
|
<td class="px-3 py-2 text-slate-600">{m?.license ?? '—'}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 class="text-xl font-semibold">Outillage de développement</h2>
|
||||||
|
<table class="mt-3 w-full text-sm">
|
||||||
|
<thead class="bg-slate-100 text-left text-slate-700">
|
||||||
|
<tr>
|
||||||
|
<th class="px-3 py-2">Package</th>
|
||||||
|
<th class="px-3 py-2">Version</th>
|
||||||
|
<th class="px-3 py-2">Licence</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{devDeps.map(([name, version]) => {
|
||||||
|
const m = META[name];
|
||||||
|
return (
|
||||||
|
<tr class="border-t border-slate-200">
|
||||||
|
<td class="px-3 py-2 font-mono">
|
||||||
|
{m ? <a href={m.url} rel="noopener">{name}</a> : name}
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-2 text-slate-600">{version}</td>
|
||||||
|
<td class="px-3 py-2 text-slate-600">{m?.license ?? '—'}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 class="text-xl font-semibold">Infrastructure</h2>
|
||||||
|
<table class="mt-3 w-full text-sm">
|
||||||
|
<thead class="bg-slate-100 text-left text-slate-700">
|
||||||
|
<tr>
|
||||||
|
<th class="px-3 py-2">Composant</th>
|
||||||
|
<th class="px-3 py-2">Description</th>
|
||||||
|
<th class="px-3 py-2">Licence</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{INFRA.map((i) => (
|
||||||
|
<tr class="border-t border-slate-200">
|
||||||
|
<td class="px-3 py-2 font-medium">
|
||||||
|
<a href={i.url} rel="noopener">{i.name}</a>
|
||||||
|
</td>
|
||||||
|
<td class="px-3 py-2 text-slate-700">{i.desc}</td>
|
||||||
|
<td class="px-3 py-2 text-slate-600">{i.license}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-sm text-slate-500">
|
||||||
|
Code source du site :
|
||||||
|
<a href="https://git.nocleus.com/florian/info-canicule" rel="noopener">
|
||||||
|
git.nocleus.com/florian/info-canicule
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</Base>
|
||||||
113
src/pages/mentions-legales.astro
Normal file
113
src/pages/mentions-legales.astro
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
---
|
||||||
|
import Base from '../layouts/Base.astro';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base
|
||||||
|
title="Mentions légales — Info Canicule"
|
||||||
|
description="Mentions légales, éditeur, hébergeur, traitement des données personnelles d'Info Canicule."
|
||||||
|
>
|
||||||
|
<section class="bg-gradient-to-b from-canicule-50 to-white">
|
||||||
|
<div class="container-tight py-10">
|
||||||
|
<h1 class="text-3xl font-bold sm:text-4xl">Mentions légales</h1>
|
||||||
|
<p class="mt-2 text-slate-600">Conformes à la LCEN (loi pour la confiance dans l'économie numérique).</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="container-tight py-8 prose prose-slate max-w-none">
|
||||||
|
<h2>Éditeur du site</h2>
|
||||||
|
<p>
|
||||||
|
Site édité à titre personnel, <strong>sans but lucratif</strong>, par :
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Florian Bouchet — développeur indépendant</li>
|
||||||
|
<li>Contact : <a href="mailto:florian@nocleus.com">florian@nocleus.com</a></li>
|
||||||
|
<li>Statut : personne physique (pas d'entreprise immatriculée, pas d'association)</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Le site n'a aucune vocation commerciale. Aucun chiffre d'affaires, aucune publicité, aucune
|
||||||
|
collecte de données à des fins de monétisation.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Hébergement</h2>
|
||||||
|
<p>
|
||||||
|
<strong>OVH SAS</strong> — 2 rue Kellermann, 59100 Roubaix, France.
|
||||||
|
<br />
|
||||||
|
Téléphone : 1007 (numéro non surtaxé) — <a href="https://www.ovh.com/" rel="noopener">ovh.com</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Serveur VPS mutualisé hébergeant plusieurs projets personnels du même éditeur.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Données personnelles</h2>
|
||||||
|
<p>
|
||||||
|
Info Canicule <strong>ne collecte aucune donnée personnelle</strong> de ses visiteurs.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Pas de compte utilisateur, pas de formulaire de contact direct (mail uniquement).</li>
|
||||||
|
<li>Pas de cookies de session ni de tracking.</li>
|
||||||
|
<li>
|
||||||
|
<strong>Statistiques de fréquentation</strong> : assurées par
|
||||||
|
<a href="https://umami.is/" rel="noopener">Umami</a>, solution d'analytics auto-hébergée,
|
||||||
|
RGPD-compatible et sans cookies. Les données collectées (pays, navigateur, page visitée) sont
|
||||||
|
agrégées et anonymes. Aucun identifiant individuel n'est stocké.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Logs serveur</strong> : adresses IP conservées 14 jours dans les logs Caddy pour des
|
||||||
|
raisons techniques (debug, détection d'abus via CrowdSec). Pas d'exploitation au-delà.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Vos droits RGPD (accès, rectification, suppression, opposition) peuvent être exercés en écrivant à
|
||||||
|
<a href="mailto:florian@nocleus.com">florian@nocleus.com</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Sources des données</h2>
|
||||||
|
<p>
|
||||||
|
Les alertes Vigilance et données climatologiques affichées proviennent de :
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Météo France</strong> via le portail
|
||||||
|
<a href="https://meteo.data.gouv.fr/" rel="noopener">meteo.data.gouv.fr</a>
|
||||||
|
et la rediffusion
|
||||||
|
<a href="https://public.opendatasoft.com/" rel="noopener">Opendatasoft</a>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Diffusées sous
|
||||||
|
<a href="https://www.etalab.gouv.fr/licence-ouverte-open-licence/" rel="noopener">Licence Ouverte 2.0</a>
|
||||||
|
(Etalab).
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Les conseils officiels sont repris des publications de Météo France, santé.gouv.fr et
|
||||||
|
gouvernement.fr (informations publiques).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Limitation de responsabilité</h2>
|
||||||
|
<p>
|
||||||
|
Info Canicule est un service d'information à titre indicatif. Il ne remplace en aucun cas les
|
||||||
|
sources officielles. En cas d'événement météorologique dangereux, suivre les consignes de la
|
||||||
|
<strong>Préfecture</strong> et appeler les services d'urgence si nécessaire (
|
||||||
|
<a href="tel:15">15</a>, <a href="tel:18">18</a>, <a href="tel:112">112</a>).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
L'éditeur ne saurait être tenu responsable d'un retard ou d'une indisponibilité de
|
||||||
|
l'information, ni de toute conséquence directe ou indirecte de l'usage des informations affichées
|
||||||
|
sur ce site.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Propriété intellectuelle</h2>
|
||||||
|
<p>
|
||||||
|
Le code source du site est sous licence libre (
|
||||||
|
<a href="https://git.nocleus.com/florian/info-canicule" rel="noopener">repo Forgejo</a>
|
||||||
|
). Les données affichées sont sous Licence Ouverte 2.0 et réutilisables librement, y compris
|
||||||
|
commercialement, à condition de citer Météo France et la licence.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
L'endpoint <code>/api/vigilance</code> diffuse le snapshot courant en JSON (CORS *), pour
|
||||||
|
réutilisation par tout site ou application qui le souhaite.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</Base>
|
||||||
23
src/pages/sitemap-departements.xml.ts
Normal file
23
src/pages/sitemap-departements.xml.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import type { APIRoute } from 'astro';
|
||||||
|
import { DEPARTEMENTS } from '../lib/departements';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
|
||||||
|
const SITE = 'https://info-canicule.nocleus.com';
|
||||||
|
|
||||||
|
export const GET: APIRoute = () => {
|
||||||
|
const today = new Date().toISOString().split('T')[0];
|
||||||
|
const urls = DEPARTEMENTS.map(
|
||||||
|
(d) =>
|
||||||
|
` <url><loc>${SITE}/departement/${d.code}</loc><lastmod>${today}</lastmod><changefreq>daily</changefreq><priority>0.7</priority></url>`,
|
||||||
|
).join('\n');
|
||||||
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${urls}
|
||||||
|
</urlset>
|
||||||
|
`;
|
||||||
|
return new Response(xml, {
|
||||||
|
status: 200,
|
||||||
|
headers: { 'Content-Type': 'application/xml; charset=utf-8', 'Cache-Control': 'public, max-age=3600' },
|
||||||
|
});
|
||||||
|
};
|
||||||
74
src/pages/soutenir.astro
Normal file
74
src/pages/soutenir.astro
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
---
|
||||||
|
import Base from '../layouts/Base.astro';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base
|
||||||
|
title="Soutenir le projet — Info Canicule"
|
||||||
|
description="Info Canicule est un service gratuit, sans publicité, à but non lucratif. Si le site vous est utile, vous pouvez soutenir son hébergement via Ko-fi."
|
||||||
|
>
|
||||||
|
<section class="bg-gradient-to-b from-canicule-50 to-white">
|
||||||
|
<div class="container-tight py-10">
|
||||||
|
<h1 class="text-3xl font-bold sm:text-4xl">Soutenir Info Canicule</h1>
|
||||||
|
<p class="mt-2 max-w-2xl text-slate-600">
|
||||||
|
Le site est gratuit, sans publicité et sans traceurs commerciaux. Si vous le trouvez utile,
|
||||||
|
vous pouvez aider à couvrir l'hébergement (~7 €/mois mutualisés sur plusieurs projets perso).
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="container-tight py-8 prose prose-slate max-w-none">
|
||||||
|
<h2>Don libre via Ko-fi</h2>
|
||||||
|
<p>
|
||||||
|
Le moyen le plus simple : un don libre, sans inscription, par carte bancaire ou PayPal, via
|
||||||
|
<a href="https://ko-fi.com/daelwizhit" rel="noopener" class="font-semibold">ko-fi.com/daelwizhit</a>.
|
||||||
|
Les dons sont anonymes par défaut et entièrement optionnels.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="not-prose my-6">
|
||||||
|
<a
|
||||||
|
href="https://ko-fi.com/daelwizhit"
|
||||||
|
rel="noopener"
|
||||||
|
class="inline-flex items-center gap-2 rounded-lg bg-canicule-600 px-6 py-3 text-base font-semibold text-white no-underline hover:bg-canicule-700"
|
||||||
|
>
|
||||||
|
☕ Soutenir sur Ko-fi
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Ce que les dons financent</h2>
|
||||||
|
<ul>
|
||||||
|
<li>Location du VPS OVH qui héberge le site (~7 €/mois, mutualisés avec d'autres projets perso).</li>
|
||||||
|
<li>Nom de domaine annuel.</li>
|
||||||
|
<li>Café pour les soirées de maintenance 🥲.</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<strong>Ce site n'a aucune vocation commerciale.</strong> Aucun chiffre d'affaires, aucun salaire
|
||||||
|
versé. Les dons couvrent les frais techniques ou, en cas d'excédent, financent d'autres petits
|
||||||
|
projets d'utilité publique du même développeur.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Autres manières d'aider</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<strong>Signaler un bug ou une typo</strong> : par mail à
|
||||||
|
<a href="mailto:florian@nocleus.com">florian@nocleus.com</a> ou via une issue sur le
|
||||||
|
<a href="https://git.nocleus.com/florian/info-canicule" rel="noopener">repo Forgejo</a>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Partager le site</strong> autour de vous, en particulier auprès de personnes fragiles
|
||||||
|
(proches âgés, personnes isolées) pour qui les conseils canicule peuvent faire une vraie
|
||||||
|
différence.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<strong>Réutiliser les données</strong> : l'endpoint <code>/api/vigilance</code> diffuse le
|
||||||
|
snapshot en JSON (CORS *), réutilisable librement sous Licence Ouverte 2.0.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p class="text-sm text-slate-500">
|
||||||
|
Pour les questions juridiques (mention de l'éditeur, statut), voir les
|
||||||
|
<a href="/mentions-legales">mentions légales</a>.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</Base>
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
|
content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
|
||||||
|
|
@ -24,5 +27,5 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [require('@tailwindcss/typography')],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue