🏗️ Refonte v2 : migration 11ty + îlots Svelte 5
Remplace la SPA Vite/Svelte 4 par un site 11ty statique (contenu/HTML/CSS fonctionnels sans JS) avec Svelte 5 en îlots pour les 3 seuls widgets interactifs (calculateur de prédictions, carte d'observation, globe de la vague planétaire). Conforme à la doctrine UI/UX OKI : nav ramenée à 5 entrées, design system CSS natif (tokens oklch, cascade @layer, light-dark), i18n compilée via Paraglide (FR/EN/HT, routée par URL), onglets 100% CSS, polices auto-hébergées, service worker minimal. Les dates de prédiction sont recoupées avec la méthode Jean Meeus / Jeffrey L. Hunt (whenthecurveslineup.com), consolidées sur un seul jeu de 7 sites, étendues jusqu'en 2032, et le "22 juillet 2025" figé en dur est remplacé par un calcul dynamique du prochain lever au build. Supprime le code mort (3 variantes de globe, fichier vide, prototype HTML legacy) et animejs, devenu inutile une fois les animations portées en CSS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "gwada-sirius-dev",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["run", "dev"],
|
||||
"port": 8080
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ./dist
|
||||
path: ./_site
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
dist/
|
||||
build/
|
||||
.svelte-kit/
|
||||
_site/
|
||||
.11ty-vite/
|
||||
src/paraglide/
|
||||
|
||||
# Dépendances
|
||||
node_modules/
|
||||
@@ -27,6 +30,10 @@ Thumbs.db
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Claude Code (local uniquement)
|
||||
.claude/settings.local.json
|
||||
.claude/scheduled_tasks.lock
|
||||
|
||||
# Temporaires
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
# Changelog
|
||||
|
||||
## [2.0.0] - 2026-07-06
|
||||
|
||||
### 🏗️ Refonte complète : Vite/Svelte 4 SPA → 11ty + îlots Svelte 5
|
||||
|
||||
- **Migration du build** : remplacement de la SPA Vite par un site 11ty statique ; Svelte 5 n'hydrate plus que 3 widgets réellement interactifs (calculateur de prédictions, carte d'observation, globe de la vague planétaire). Tout le reste (Science, Culture, Dogon, Observatoire, Associations, navigation) est du HTML/CSS pur, fonctionnel sans JavaScript.
|
||||
- **Navigation** : passage de 7 entrées (dont Dogon et Calculs absents du menu) à 5 entrées consolidées (Accueil, Sirius & Science, Culture & Savoirs, Observer, Associations), conformément à la loi de Hick-Hyman.
|
||||
- **i18n** : remplacement du store Svelte custom par Paraglide (inlang), i18n compilée et routée par URL (`/`, `/en/`, `/ht/`), avec repli automatique vers le français pour les traductions manquantes.
|
||||
- **Design system** : nouveaux tokens CSS en `oklch()` (contraste AA/AAA calculé, pas décoré après coup), cascade `@layer` explicite, `light-dark()` pour un vrai mode clair/sombre (le site n'avait qu'un thème sombre fixe), motifs panafricains (kente/bogolan/adinkra) resserrés en accents ponctuels plutôt qu'en texture de fond généralisée.
|
||||
- **Typographie** : polices auto-hébergées (Fraunces, Atkinson Hyperlegible) en remplacement de Google Fonts.
|
||||
- **Performance** : suppression totale d'animejs (toutes les animations d'entrée/interaction sont maintenant en CSS ou omises) ; onglets (Science, Dogon) réimplémentés en CSS pur (`input[type=radio]`), zéro JS.
|
||||
- **Données astronomiques** : consolidation sur un unique jeu de 7 sites d'observation (l'ancien composant Predictions utilisait des données différentes, moins précises, du jeu de données `predictions.js` jamais branché) ; méthodologie de calcul explicitée et sourcée (Jean Meeus, Jeffrey L. Hunt) ; prédictions étendues jusqu'en 2032 ; date figée "22 juillet 2025" remplacée par un calcul dynamique du prochain lever au build.
|
||||
- **Nettoyage** : suppression de 3 variantes de globe mortes (`Globe.svelte`, `GlobeThreeJS.svelte`, `GlobeOpenGlobus.svelte.bak`), d'un fichier vide (`og.umd.js`) et du prototype HTML pré-Svelte jamais référencé.
|
||||
|
||||
## [1.5.0] - 2024-01-07
|
||||
|
||||
### 🚀 Nouvelles fonctionnalités
|
||||
|
||||
+22
-97
@@ -2,116 +2,41 @@
|
||||
|
||||
## 📋 Vue d'ensemble
|
||||
|
||||
J'ai créé une application web one-page avec Svelte qui combine les 3 pages HTML que vous aviez et enrichit le contenu avec les informations du PDF. L'application est moderne, mobile-first, avec un design panafricain/caribéen.
|
||||
Refonte complète (v2) : passage d'une SPA Vite+Svelte 4 à un site **11ty** statique avec **Svelte 5 en îlots**, un design system CSS natif (oklch, `@layer`, container queries) et une i18n compilée (Paraglide/inlang). Conforme à la doctrine UI/UX OKI : nav à 5 entrées, fonctionne sans JavaScript pour tout le contenu éditorial, budget JS minimal.
|
||||
|
||||
## 🏗️ Structure du projet
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
/home/sucupira/dev/Gwada-Sirius/
|
||||
├── src/
|
||||
│ ├── App.svelte # Composant principal
|
||||
│ ├── app.css # Styles globaux avec patterns africains
|
||||
│ ├── main.js # Point d'entrée
|
||||
│ ├── components/ # Composants Svelte
|
||||
│ │ ├── Navigation.svelte # Menu responsive
|
||||
│ │ ├── Hero.svelte # Section héro avec animation d'étoiles
|
||||
│ │ ├── About.svelte # Introduction à Sirius
|
||||
│ │ ├── Predictions.svelte # Calculateur interactif
|
||||
│ │ ├── Science.svelte # Explication scientifique
|
||||
│ │ ├── Culture.svelte # Héritage culturel
|
||||
│ │ ├── Observatory.svelte # Guide d'observation
|
||||
│ │ ├── Globe.svelte # Visualisation globe (Canvas 2D)
|
||||
│ │ └── Footer.svelte # Pied de page
|
||||
│ └── data/
|
||||
│ └── predictions.js # Données des prédictions
|
||||
├── package.json
|
||||
├── vite.config.js
|
||||
├── index.html
|
||||
├── README.md
|
||||
├── .gitignore
|
||||
└── start.sh # Script de démarrage rapide
|
||||
```
|
||||
- **Contenu** : pages Nunjucks (`src/*.njk`), chacune paginée sur les 3 langues (`fr`/`en`/`ht`) via `pagination.data: locales`.
|
||||
- **Données** : `src/_data/sites.js` (7 sites d'observation, dates interpolées Jean Meeus / Jeffrey L. Hunt), `src/_data/nav.js`, `src/_data/nextRising.js` (calculé au build).
|
||||
- **i18n** : catalogues `messages/{fr,en,ht}.json`, compilés par `@inlang/paraglide-js` en `src/paraglide/` avant chaque build (`npm run messages`). `ht` retombe automatiquement sur `fr` pour les clés non traduites (contenu long, cf. portée d'origine).
|
||||
- **Îlots Svelte 5** (3 seulement, le reste est HTML/CSS pur) :
|
||||
- `PredictionsCalculator` — hydratation immédiate, améliore le tableau statique des 7 sites
|
||||
- `ObservationMap` — carte canvas schématique, hydratation différée (IntersectionObserver)
|
||||
- `SiriusGlobe` — vague planétaire du lever héliaque (13 villes), hydratation différée
|
||||
- **Onglets** (Science, Dogon) : 100 % CSS (`input[type=radio]` + `label`), zéro JS.
|
||||
- **Build** : `@11ty/eleventy-plugin-vite` fait passer la sortie 11ty par Vite (bundling CSS/JS, compilation Svelte). Un plugin maison recopie les assets passthrough après le build Vite (voir commentaire dans `eleventy.config.js` — `emptyOutDir` de Vite les efface sinon).
|
||||
|
||||
## 🎨 Design et fonctionnalités
|
||||
## ⚠️ Points d'attention connus
|
||||
|
||||
### Palette de couleurs panafricaine :
|
||||
- **Or (#FFD700)** : Couleur principale, représente Sirius et le soleil
|
||||
- **Rouge profond (#DC143C)** : Accent
|
||||
- **Vert forêt (#228B22)** : Nature
|
||||
- **Bleu nuit (#1a1a2e)** : Fond, ciel nocturne
|
||||
|
||||
### Patterns africains intégrés :
|
||||
- **Kente** : Motif géométrique en diagonale
|
||||
- **Bogolan** : Cercles et points
|
||||
- **Adinkra** : Motifs symboliques
|
||||
|
||||
### Sections principales :
|
||||
1. **Hero** : Animation d'étoiles interactive avec effet parallaxe
|
||||
2. **About** : Introduction avec cartes d'information
|
||||
3. **Predictions** : Calculateur interactif avec sélecteurs
|
||||
4. **Science** : Tabs pour explorer la mécanique céleste
|
||||
5. **Culture** : Timeline et cartes culturelles
|
||||
6. **Observatory** : Guide pratique étape par étape
|
||||
7. **Globe** : Visualisation 2D animée (plus léger que Three.js)
|
||||
|
||||
## 🚀 Pour démarrer
|
||||
|
||||
```bash
|
||||
cd /home/sucupira/dev/Gwada-Sirius
|
||||
./start.sh
|
||||
```
|
||||
|
||||
Ou manuellement :
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 📱 Responsive Design
|
||||
|
||||
- Mobile-first approach
|
||||
- Menu hamburger pour mobile
|
||||
- Grilles flexibles
|
||||
- Tailles de police adaptatives avec clamp()
|
||||
|
||||
## ⚡ Performance
|
||||
|
||||
- Svelte compile en vanilla JS (pas de runtime)
|
||||
- Canvas 2D au lieu de Three.js pour le globe
|
||||
- Lazy loading des animations avec IntersectionObserver
|
||||
- CSS optimisé avec variables custom properties
|
||||
1. **`<link>` et `vite-ignore`** : Vite traite tout `<link href>` comme une référence d'asset à résoudre, y compris `rel="alternate"`/`rel="icon"`/`rel="preload"`. Un `href="/"` ou `href="/en/"` (URL de répertoire) fait planter le build (`EISDIR`, cf. issue amont). Toujours ajouter `vite-ignore` sur ces `<link>` de métadonnées dans `layouts/base.njk`.
|
||||
2. **Alias `/src`** : `eleventy-plugin-vite` fait tourner Vite avec pour racine une copie du dossier de **sortie** (`_site`), pas la racine du projet. Toute référence absolue à un fichier source (`/src/styles/app.css`, `/src/islands/.../mount.js`) nécessite l'alias `resolve.alias["/src"]` défini dans `eleventy.config.js`.
|
||||
3. **Dates ISO sans heure** : `new Date("2026-07-22")` est interprété en UTC ; formaté en heure locale Guadeloupe (UTC-4), ça peut reculer d'un jour. Toujours parser les composants (`year, month, day`) et construire la date en local — voir le filtre `formatDate` et `PredictionsCalculator.svelte`.
|
||||
4. **Slinkity est abandonné** (son créateur travaille sur Astro) : ne pas l'utiliser pour l'intégration 11ty+Svelte, `eleventy-plugin-vite` (officiel) est la voie robuste.
|
||||
|
||||
## 🔄 Améliorations possibles
|
||||
|
||||
1. **Ajouter un compte à rebours dynamique** jusqu'au 22 juillet
|
||||
2. **Intégrer une API météo** pour les prévisions
|
||||
3. **Ajouter des sons ambiants** africains/caribéens
|
||||
4. **Mode sombre/clair** automatique selon l'heure
|
||||
5. **PWA** pour installation mobile
|
||||
6. **Partage social** avec meta tags optimisés
|
||||
7. **Multilingue** (Français, Créole, Anglais)
|
||||
8. **Animations GSAP** pour plus de fluidité
|
||||
- Traduire le contenu long en Kreyòl (actuellement chrome/labels uniquement, contenu de fond en français)
|
||||
- Vraies données GeoJSON pour `ObservationMap` (actuellement une carte schématique par position lat/lon normalisée, pas un tracé de côte réel)
|
||||
- Service worker pour un usage hors-ligne (mentionné dans la doctrine, pas encore implémenté)
|
||||
- Mettre à jour chaque année les informations d'événements associatifs (`associations.njk`, données à vérifier auprès des organisateurs)
|
||||
|
||||
## 📦 Build pour production
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
# Les fichiers seront dans dist/
|
||||
# Sortie dans _site/
|
||||
```
|
||||
|
||||
## 🌐 Déploiement
|
||||
|
||||
Peut être déployé facilement sur :
|
||||
- Netlify (drag & drop du dossier dist)
|
||||
- Vercel
|
||||
- GitHub Pages
|
||||
- Surge.sh
|
||||
|
||||
## 💡 Points techniques importants
|
||||
|
||||
1. **Données astronomiques** : Toutes les prédictions sont stockées dans `src/data/predictions.js`
|
||||
2. **Animations** : Utilisation de CSS animations et requestAnimationFrame
|
||||
3. **État** : Gestion simple avec les stores Svelte (pas de store global pour l'instant)
|
||||
4. **SEO** : Ajouter les meta tags appropriés dans index.html
|
||||
|
||||
Le projet est maintenant prêt et fonctionnel ! Vous pouvez le personnaliser selon vos besoins.
|
||||
GitHub Pages via `.github/workflows/deploy.yml` (upload de `_site/`), déclenché sur push vers `main`.
|
||||
|
||||
@@ -1,71 +1,61 @@
|
||||
# Sirius en Guadeloupe - Gwada-Sirius
|
||||
# Sirius en Guadeloupe — Gwada-Sirius
|
||||
|
||||
Un projet web célébrant le lever héliaque de Sirius en Guadeloupe, fusionnant astronomie, culture africaine et héritage caribéen.
|
||||
Un site célébrant le lever héliaque de Sirius en Guadeloupe (Wep Ronpet), à la croisée de l'astronomie, de l'héritage égyptien et dogon, et de la culture caribéenne.
|
||||
|
||||
## 🌟 À propos
|
||||
|
||||
Cette application web interactive permet de :
|
||||
- Calculer les dates précises du lever héliaque de Sirius pour différents lieux en Guadeloupe
|
||||
- Explorer l'héritage culturel de Sirius à travers les civilisations (Égypte ancienne, Dogons, Caraïbes)
|
||||
- Comprendre la science astronomique derrière ce phénomène
|
||||
- Découvrir les meilleurs sites d'observation en Guadeloupe
|
||||
Ce site permet de :
|
||||
- Calculer la date précise du lever héliaque pour 7 sites d'observation en Guadeloupe
|
||||
- Explorer l'héritage culturel de Sirius (Égypte ancienne, Dogon du Mali, Caraïbes)
|
||||
- Comprendre la science du phénomène (Arcus Visionis, méthode de calcul)
|
||||
- Préparer une observation (guide pratique, équipement, carte des sites)
|
||||
- Découvrir les associations qui célèbrent le Wep Ronpet
|
||||
|
||||
## 🚀 Technologies utilisées
|
||||
## 🚀 Stack technique
|
||||
|
||||
- **Svelte** - Framework JavaScript réactif
|
||||
- **Canvas 2D** - Pour les animations et visualisations
|
||||
- **GeoJSON** - Pour les cartes interactives
|
||||
- **i18n** - Support multilingue (Français, English, Kreyòl Ayisyen)
|
||||
- **[11ty (Eleventy)](https://www.11ty.dev/)** — génération du site statique, contenu et navigation en HTML/CSS, fonctionnel sans JavaScript
|
||||
- **[Svelte 5](https://svelte.dev/)** en îlots — hydratation ciblée pour les 3 seuls widgets interactifs (calculateur de prédictions, carte d'observation, globe de la vague planétaire), via `@11ty/eleventy-plugin-vite`
|
||||
- **[Paraglide (inlang)](https://paraglidejs.com/)** — i18n compilée, FR (défaut) / EN / Kreyòl Ayisyen, routée par URL (`/`, `/en/`, `/ht/`)
|
||||
- **CSS natif** — tokens `oklch()`, cascade `@layer`, container queries, aucun framework CSS ni préprocesseur
|
||||
- Polices auto-hébergées (Fraunces, Atkinson Hyperlegible), zéro dépendance à Google Fonts
|
||||
|
||||
Conforme à la doctrine UI/UX OKI (voir document de référence interne) : navigation à 5 entrées, cibles tactiles ≥ 48 px, contraste AA/AAA, `prefers-reduced-motion` respecté, budget JS minimal.
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
```bash
|
||||
# Cloner le repository
|
||||
git clone https://github.com/[votre-username]/gwada-sirius.git
|
||||
|
||||
# Entrer dans le dossier
|
||||
cd gwada-sirius
|
||||
|
||||
# Installer les dépendances
|
||||
npm install
|
||||
|
||||
# Lancer le serveur de développement
|
||||
npm run dev
|
||||
npm run dev # serveur de développement sur http://localhost:8080
|
||||
npm run build # build de production dans _site/
|
||||
npm run preview # prévisualiser le build de production
|
||||
```
|
||||
|
||||
## 🌍 Fonctionnalités
|
||||
## 🗂️ Structure
|
||||
|
||||
- **Calculateur de prédictions** : Dates précises pour 7 sites d'observation
|
||||
- **Globe interactif** : Visualisation de la trajectoire de Sirius
|
||||
- **Carte des sites** : Localisation des meilleurs points d'observation
|
||||
- **Multilingue** : Interface en français, anglais et créole haïtien
|
||||
- **Responsive** : Optimisé pour mobile et desktop
|
||||
- **Animations** : Ciel étoilé animé et patterns africains
|
||||
|
||||
## 🎨 Design
|
||||
|
||||
Le design s'inspire des motifs africains (Kente, Adinkra, Bogolan) avec une palette de couleurs symbolique :
|
||||
- Or (#FFD700) - Sirius et la lumière divine
|
||||
- Rouge (#FF6B35) - Force et énergie vitale
|
||||
- Vert (#4CAF50) - Nature et renouveau
|
||||
- Bleu nuit (#0A1628) - Ciel nocturne
|
||||
```
|
||||
src/
|
||||
├── _data/ # données globales (sites d'observation, navigation)
|
||||
├── _includes/ # layout de base, partiels (nav, footer)
|
||||
├── styles/ # design system CSS (tokens, reset, base, layouts, composants)
|
||||
├── islands/ # composants Svelte 5 hydratés côté client (prédictions, carte, globe)
|
||||
├── paraglide/ # messages i18n compilés (généré, ignoré par git)
|
||||
├── index.njk # accueil
|
||||
├── sirius-science.njk # astronomie + méthode de calcul
|
||||
├── culture-savoirs.njk# héritage culturel + savoir dogon
|
||||
├── observer.njk # calculateur, carte, guide d'observation
|
||||
└── associations.njk # associations qui fêtent le Wep Ronpet
|
||||
messages/ # catalogues de traduction (fr/en/ht), source pour Paraglide
|
||||
project.inlang/ # configuration du projet i18n
|
||||
```
|
||||
|
||||
## 👥 Crédits
|
||||
|
||||
Projet réalisé avec ❤️ par :
|
||||
- [cyber-mawonaj](https://github.com/cyber-mawonaj)
|
||||
- [OKI](https://o-k-i.net)
|
||||
Projet réalisé avec ❤️ par [cyber-mawonaj](https://github.com/cyber-mawonaj) et [OKI](https://o-k-i.net).
|
||||
|
||||
## 📜 Licence
|
||||
|
||||
Ce projet est sous licence MIT - voir le fichier [LICENSE](LICENSE) pour plus de détails.
|
||||
|
||||
## 🙏 Remerciements
|
||||
|
||||
- Les anciens Égyptiens pour leur sagesse astronomique
|
||||
- Les Dogons du Mali pour avoir préservé ces connaissances
|
||||
- La communauté guadeloupéenne pour perpétuer ces traditions
|
||||
MIT — voir [LICENSE](LICENSE).
|
||||
|
||||
---
|
||||
|
||||
*"Les étoiles sont les ancêtres qui veillent sur nous" - Proverbe africain*
|
||||
*"Les étoiles sont les ancêtres qui veillent sur nous" — proverbe africain*
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import EleventyVitePlugin from "@11ty/eleventy-plugin-vite";
|
||||
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||
import * as m from "./src/paraglide/messages.js";
|
||||
import { locales, baseLocale } from "./src/paraglide/runtime.js";
|
||||
|
||||
const OUTPUT_DIR = "_site";
|
||||
|
||||
// Vite's build wipes the output dir (emptyOutDir) after 11ty has already
|
||||
// copied passthrough assets into it — re-copy them once Vite is done.
|
||||
// https://github.com/11ty/eleventy-plugin-vite/issues/42
|
||||
function restorePassthroughCopy(copies) {
|
||||
return {
|
||||
name: "restore-passthrough-copy",
|
||||
apply: "build",
|
||||
closeBundle() {
|
||||
for (const [from, to] of copies) {
|
||||
if (!fs.existsSync(from)) continue;
|
||||
fs.cpSync(from, path.join(OUTPUT_DIR, to), {
|
||||
recursive: true,
|
||||
force: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function (eleventyConfig) {
|
||||
eleventyConfig.addPlugin(EleventyVitePlugin, {
|
||||
viteOptions: {
|
||||
appType: "mpa",
|
||||
plugins: [
|
||||
svelte(),
|
||||
restorePassthroughCopy([
|
||||
["src/assets", "assets"],
|
||||
["public", "."],
|
||||
]),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"/src": path.resolve(".", "src"),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
emptyOutDir: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
eleventyConfig.ignores.add("src/paraglide/**");
|
||||
eleventyConfig.ignores.add("src/islands/**");
|
||||
|
||||
eleventyConfig.addPassthroughCopy("src/assets");
|
||||
eleventyConfig.addPassthroughCopy({ public: "." });
|
||||
|
||||
// Trilingual message lookup for Nunjucks templates: {{ "hero_title1" | t(locale) }}
|
||||
eleventyConfig.addFilter("t", (key, locale, params = {}) => {
|
||||
const fn = m[key];
|
||||
if (!fn) return key;
|
||||
return fn(params, { locale });
|
||||
});
|
||||
|
||||
eleventyConfig.addGlobalData("locales", locales);
|
||||
eleventyConfig.addGlobalData("baseLocale", baseLocale);
|
||||
eleventyConfig.addGlobalData("currentYear", () => new Date().getFullYear());
|
||||
|
||||
eleventyConfig.addFilter("localeHref", (pagePath, locale) => {
|
||||
const clean = pagePath.replace(/^\/+/, "");
|
||||
return locale === baseLocale ? `/${clean}` : `/${locale}/${clean}`;
|
||||
});
|
||||
|
||||
eleventyConfig.addFilter("dump", (value) => JSON.stringify(value).replace(/</g, "\\u003c"));
|
||||
|
||||
eleventyConfig.addFilter("formatDate", (isoDate, locale, options = {}) => {
|
||||
// new Date("YYYY-MM-DD") parses as UTC midnight, which can roll back a
|
||||
// day once formatted in a timezone behind UTC (e.g. Guadeloupe, UTC-4).
|
||||
// Build the date from its local components instead.
|
||||
const [year, month, day] = isoDate.split("-").map(Number);
|
||||
return new Date(year, month - 1, day).toLocaleDateString(
|
||||
locale === "ht" ? "fr" : locale,
|
||||
{ day: "numeric", month: "long", year: "numeric", ...options }
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
dir: {
|
||||
input: "src",
|
||||
output: OUTPUT_DIR,
|
||||
includes: "_includes",
|
||||
data: "_data",
|
||||
},
|
||||
templateFormats: ["njk", "md"],
|
||||
markdownTemplateEngine: "njk",
|
||||
htmlTemplateEngine: "njk",
|
||||
};
|
||||
}
|
||||
@@ -1,475 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Gwada-Sirius : L'Étoile de nos Ancêtres</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700;900&family=Playfair+Display:wght@400;700;900&display=swap" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
--gold: #FFD700;
|
||||
--red: #DC143C;
|
||||
--green: #228B22;
|
||||
--black: #000000;
|
||||
--caribbean-blue: #1E40AF;
|
||||
--sunset-orange: #FF6B35;
|
||||
--deep-purple: #4C1D95;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(135deg, #000000 0%, #1E40AF 25%, #DC143C 50%, #228B22 75%, #FFD700 100%);
|
||||
background-size: 400% 400%;
|
||||
animation: panafricanGradient 15s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes panafricanGradient {
|
||||
0% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: 'Playfair Display', serif;
|
||||
}
|
||||
|
||||
.glass-card {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.gradient-text {
|
||||
background: linear-gradient(45deg, #FFD700, #DC143C, #228B22);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
animation: gradientShift 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes gradientShift {
|
||||
0%, 100% { background-position: 0% 50%; }
|
||||
50% { background-position: 100% 50%; }
|
||||
}
|
||||
|
||||
.star-glow {
|
||||
text-shadow: 0 0 20px #FFD700, 0 0 40px #FFD700, 0 0 60px #FFD700;
|
||||
}
|
||||
|
||||
.floating {
|
||||
animation: float 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-20px); }
|
||||
}
|
||||
|
||||
.pulse-gold {
|
||||
animation: pulseGold 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulseGold {
|
||||
0%, 100% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0.7); }
|
||||
50% { box-shadow: 0 0 0 20px rgba(255, 215, 0, 0); }
|
||||
}
|
||||
|
||||
#globe-container {
|
||||
cursor: grab;
|
||||
background: radial-gradient(circle, rgba(30, 64, 175, 0.3) 0%, rgba(0, 0, 0, 0.8) 100%);
|
||||
}
|
||||
|
||||
.prediction-card {
|
||||
transition: all 0.3s ease;
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
|
||||
.prediction-card:hover {
|
||||
border-left-color: #FFD700;
|
||||
transform: translateX(10px);
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
}
|
||||
|
||||
.cultural-section {
|
||||
background: linear-gradient(135deg,
|
||||
rgba(220, 20, 60, 0.1) 0%,
|
||||
rgba(34, 139, 34, 0.1) 50%,
|
||||
rgba(255, 215, 0, 0.1) 100%);
|
||||
}
|
||||
|
||||
.section-divider {
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, #DC143C, #FFD700, #228B22);
|
||||
margin: 4rem 0;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-white min-h-screen">
|
||||
<!-- Header Hero -->
|
||||
<header class="relative min-h-screen flex items-center justify-center overflow-hidden">
|
||||
<div class="absolute inset-0 bg-black bg-opacity-40"></div>
|
||||
<div class="relative z-10 text-center px-4">
|
||||
<div class="floating">
|
||||
<h1 class="text-4xl md:text-7xl font-black mb-6 gradient-text">
|
||||
SIRIUS
|
||||
</h1>
|
||||
<div class="star-glow text-6xl md:text-8xl mb-8">⭐</div>
|
||||
</div>
|
||||
<h2 class="text-xl md:text-3xl mb-4 font-light">
|
||||
L'Étoile de nos Ancêtres
|
||||
</h2>
|
||||
<p class="text-lg md:text-xl max-w-3xl mx-auto leading-relaxed mb-8">
|
||||
Depuis l'Égypte antique jusqu'aux Caraïbes, découvrez la danse cosmique de l'étoile la plus brillante du ciel nocturne et son lever héliaque en Guadeloupe.
|
||||
</p>
|
||||
<div class="glass-card rounded-2xl p-6 md:p-8 max-w-4xl mx-auto">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 text-center">
|
||||
<div class="pulse-gold rounded-xl p-4">
|
||||
<div class="text-3xl md:text-4xl font-black text-yellow-400 mb-2">-1.46</div>
|
||||
<div class="text-sm md:text-base opacity-90">Magnitude</div>
|
||||
</div>
|
||||
<div class="pulse-gold rounded-xl p-4">
|
||||
<div class="text-3xl md:text-4xl font-black text-red-400 mb-2">22 JUILLET</div>
|
||||
<div class="text-sm md:text-base opacity-90">Lever en Guadeloupe</div>
|
||||
</div>
|
||||
<div class="pulse-gold rounded-xl p-4">
|
||||
<div class="text-3xl md:text-4xl font-black text-green-400 mb-2">~70</div>
|
||||
<div class="text-sm md:text-base opacity-90">Jours d'invisibilité</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="absolute bottom-8 left-1/2 transform -translate-x-1/2 animate-bounce">
|
||||
<div class="w-6 h-10 border-2 border-white rounded-full flex justify-center">
|
||||
<div class="w-1 h-3 bg-white rounded-full mt-2 animate-pulse"></div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Prédictions Section -->
|
||||
<section class="py-16 px-4 relative">
|
||||
<div class="section-divider"></div>
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<h2 class="text-3xl md:text-5xl font-bold text-center mb-12 gradient-text">
|
||||
Prédictions pour la Guadeloupe
|
||||
</h2>
|
||||
|
||||
<div class="glass-card rounded-2xl p-6 md:p-8 mb-8">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-2">Site d'observation :</label>
|
||||
<select id="location-select" class="w-full p-3 bg-black bg-opacity-50 border border-gray-600 rounded-lg text-white focus:ring-2 focus:ring-yellow-400">
|
||||
<option value="Pointe des Châteaux">Pointe des Châteaux</option>
|
||||
<option value="Pointe de la Grande Vigie">Pointe de la Grande Vigie</option>
|
||||
<option value="Duzer (Sainte-Rose)">Duzer (Sainte-Rose)</option>
|
||||
<option value="Pointe du Vieux-Fort">Pointe du Vieux-Fort</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-2">Année :</label>
|
||||
<select id="year-select" class="w-full p-3 bg-black bg-opacity-50 border border-gray-600 rounded-lg text-white focus:ring-2 focus:ring-yellow-400">
|
||||
<option value="2025">2025</option>
|
||||
<option value="2026">2026</option>
|
||||
<option value="2027">2027</option>
|
||||
<option value="2028">2028</option>
|
||||
<option value="2029">2029</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="prediction-result" class="text-center bg-gradient-to-r from-red-600 via-yellow-500 to-green-600 rounded-xl p-8">
|
||||
<h3 class="text-2xl font-bold text-black mb-2" id="result-location">Pointe des Châteaux</h3>
|
||||
<div class="text-5xl font-black text-black mb-2" id="result-date">22 juillet</div>
|
||||
<div class="text-2xl text-black" id="result-time">vers 05:12</div>
|
||||
<div class="mt-4 pt-4 border-t border-black border-opacity-30">
|
||||
<p class="text-sm text-black opacity-80">Fenêtre d'observation :</p>
|
||||
<p class="font-bold text-lg text-black" id="result-window">20 au 24 Juillet</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div class="prediction-card glass-card rounded-xl p-6">
|
||||
<h4 class="font-bold text-yellow-400 mb-2">Équipement nécessaire</h4>
|
||||
<p class="text-sm opacity-90">Vos yeux suffisent ! Des jumelles peuvent aider dans les lueurs de l'aube.</p>
|
||||
</div>
|
||||
<div class="prediction-card glass-card rounded-xl p-6">
|
||||
<h4 class="font-bold text-red-400 mb-2">Meilleure direction</h4>
|
||||
<p class="text-sm opacity-90">Est-Sud-Est, horizon dégagé loin des lumières de la ville.</p>
|
||||
</div>
|
||||
<div class="prediction-card glass-card rounded-xl p-6">
|
||||
<h4 class="font-bold text-green-400 mb-2">Conseil d'expert</h4>
|
||||
<p class="text-sm opacity-90">Observez 2 jours avant et après la date prédite pour maximiser vos chances.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Globe 3D Section -->
|
||||
<section class="py-16 px-4">
|
||||
<div class="section-divider"></div>
|
||||
<div class="max-w-6xl mx-auto text-center">
|
||||
<h2 class="text-3xl md:text-5xl font-bold mb-8 gradient-text">
|
||||
La Vague Planétaire de Sirius
|
||||
</h2>
|
||||
<p class="text-lg mb-12 max-w-3xl mx-auto">
|
||||
Découvrez comment le lever héliaque de Sirius se propage comme une vague à travers la planète,
|
||||
de l'hémisphère Sud vers le Nord, reliant l'Afrique aux Caraïbes.
|
||||
</p>
|
||||
|
||||
<div class="glass-card rounded-2xl p-8 mb-8">
|
||||
<div id="globe-container" class="w-full h-96 rounded-xl mb-6"></div>
|
||||
<p class="text-sm opacity-80">
|
||||
Cliquez et glissez pour faire tourner le globe. La vague animée représente la progression du lever héliaque.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div class="glass-card rounded-xl p-6">
|
||||
<h3 class="text-xl font-bold text-yellow-400 mb-4">🌍 Départ au Sud</h3>
|
||||
<p class="text-sm opacity-90">
|
||||
La vague commence dans l'hémisphère Sud car c'est l'hiver austral.
|
||||
Les nuits étant plus longues, Sirius apparaît plus tôt (fin juin).
|
||||
</p>
|
||||
</div>
|
||||
<div class="glass-card rounded-xl p-6">
|
||||
<h3 class="text-xl font-bold text-red-400 mb-4">🌅 Arrivée au Nord</h3>
|
||||
<p class="text-sm opacity-90">
|
||||
En été boréal, les nuits sont plus courtes. Il faut attendre plus longtemps
|
||||
pour que Sirius soit visible à l'aube (fin juillet).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Cultural Heritage Section -->
|
||||
<section class="py-16 px-4 cultural-section">
|
||||
<div class="section-divider"></div>
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<h2 class="text-3xl md:text-5xl font-bold text-center mb-12 gradient-text">
|
||||
Héritage Culturel Panafricain
|
||||
</h2>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-12">
|
||||
<div class="glass-card rounded-xl p-8">
|
||||
<div class="text-4xl mb-4">🏺</div>
|
||||
<h3 class="text-2xl font-bold text-yellow-400 mb-4">Égypte Antique : Sothis</h3>
|
||||
<p class="opacity-90 leading-relaxed">
|
||||
Pour les anciens Égyptiens, le lever héliaque de Sirius (Sothis) était l'événement le plus important de l'année.
|
||||
Il annonçait la crue vitale du Nil qui fertilisait les terres. Ce "retour" de l'étoile marquait le Nouvel An
|
||||
et symbolisait la renaissance, associée à la déesse Isis.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="glass-card rounded-xl p-8">
|
||||
<div class="text-4xl mb-4">🌟</div>
|
||||
<h3 class="text-2xl font-bold text-red-400 mb-4">Dogon du Mali : Po Tolo</h3>
|
||||
<p class="opacity-90 leading-relaxed">
|
||||
Le peuple Dogon possède un savoir ancestral stupéfiant sur Sirius, décrivant une compagne invisible,
|
||||
"Po Tolo" (Sirius B), qui tourne autour de l'étoile principale en 50 ans. Des connaissances qui correspondent
|
||||
précisément aux découvertes modernes astronomiques.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="glass-card rounded-xl p-8 text-center">
|
||||
<h3 class="text-2xl font-bold text-green-400 mb-6">De l'Afrique aux Caraïbes</h3>
|
||||
<p class="text-lg opacity-90 max-w-4xl mx-auto leading-relaxed">
|
||||
Sirius unit nos territoires caribéens à notre héritage africain. Cette étoile brillante,
|
||||
guide des navigateurs et messager des saisons, continue d'éclairer nos îles comme elle
|
||||
éclairait nos ancêtres. Observer Sirius en Guadeloupe, c'est participer à une tradition
|
||||
millénaire qui traverse les océans et les générations.
|
||||
</p>
|
||||
<div class="mt-8 flex justify-center space-x-8 text-3xl">
|
||||
<span title="Guadeloupe">🇬🇵</span>
|
||||
<span title="Martinique">🇲🇶</span>
|
||||
<span title="Afrique">🌍</span>
|
||||
<span title="Égypte">🔺</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Understanding Section -->
|
||||
<section class="py-16 px-4">
|
||||
<div class="section-divider"></div>
|
||||
<div class="max-w-6xl mx-auto">
|
||||
<h2 class="text-3xl md:text-5xl font-bold text-center mb-12 gradient-text">
|
||||
Comprendre le Phénomène
|
||||
</h2>
|
||||
|
||||
<div class="glass-card rounded-xl p-8 mb-8">
|
||||
<div class="text-center mb-8">
|
||||
<h3 class="text-2xl font-bold text-yellow-400 mb-4">Arcus Visionis ≈ 9-10°</h3>
|
||||
<p class="opacity-90">
|
||||
L'angle clé : la hauteur négative du Soleil sous l'horizon nécessaire pour que Sirius devienne visible à l'aube.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="relative h-32 bg-gradient-to-t from-blue-900 to-blue-600 rounded-lg p-4 mb-8">
|
||||
<div class="absolute bottom-0 w-full h-px bg-yellow-400"></div>
|
||||
<div class="absolute bottom-0 left-1/2 transform -translate-x-1/2 text-xs text-yellow-400">HORIZON</div>
|
||||
<div class="absolute bottom-6 left-1/4 text-2xl animate-pulse">⭐</div>
|
||||
<div class="absolute bottom-6 right-1/4 text-2xl text-yellow-400">☀️</div>
|
||||
<div class="absolute top-4 left-1/2 transform -translate-x-1/2 text-xs text-center text-white opacity-80">
|
||||
Le Soleil doit être à 9-10° sous l'horizon<br>pour que Sirius devienne visible
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="glass-card rounded-xl p-6 text-center">
|
||||
<div class="text-3xl mb-4">✨</div>
|
||||
<h4 class="font-bold text-yellow-400 mb-3">Magnitude</h4>
|
||||
<p class="text-sm opacity-90">
|
||||
Plus une étoile est brillante, plus elle est facile à voir dans la lueur de l'aube.
|
||||
Sirius (-1.46) est l'étoile la plus brillante du ciel nocturne.
|
||||
</p>
|
||||
</div>
|
||||
<div class="glass-card rounded-xl p-6 text-center">
|
||||
<div class="text-3xl mb-4">🌍</div>
|
||||
<h4 class="font-bold text-red-400 mb-3">Latitude</h4>
|
||||
<p class="text-sm opacity-90">
|
||||
La position sur Terre change l'angle du lever et la durée du crépuscule.
|
||||
En Guadeloupe (16°N), les conditions sont idéales.
|
||||
</p>
|
||||
</div>
|
||||
<div class="glass-card rounded-xl p-6 text-center">
|
||||
<div class="text-3xl mb-4">🌫️</div>
|
||||
<h4 class="font-bold text-green-400 mb-3">Atmosphère</h4>
|
||||
<p class="text-sm opacity-90">
|
||||
L'humidité, la brume de sable ou les nuages peuvent "éteindre" l'étoile
|
||||
et retarder sa visibilité. D'où l'importance de la fenêtre d'observation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="py-12 px-4 text-center">
|
||||
<div class="section-divider"></div>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="glass-card rounded-xl p-8">
|
||||
<h3 class="text-2xl font-bold gradient-text mb-6">Levez les yeux vers le ciel</h3>
|
||||
<p class="opacity-90 mb-6">
|
||||
Une application créée pour célébrer notre héritage astronomique et culturel panafricain.
|
||||
De l'Égypte antique aux Antilles françaises, Sirius continue de nous guider.
|
||||
</p>
|
||||
<div class="text-sm opacity-70">
|
||||
© 2025 - Basé sur le rapport "Sirius en Guadeloupe : Guide Astronomique et Culturel"
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
// Données de prédictions
|
||||
const predictionsData = {
|
||||
"Pointe des Châteaux": {"2025": "22 juillet, 05:12", "2026": "22 juillet, 05:12", "2027": "22 juillet, 05:13", "2028": "21 juillet, 05:13", "2029": "22 juillet, 05:14"},
|
||||
"Pointe de la Grande Vigie": {"2025": "22 juillet, 05:11", "2026": "22 juillet, 05:12", "2027": "22 juillet, 05:12", "2028": "21 juillet, 05:12", "2029": "22 juillet, 05:13"},
|
||||
"Duzer (Sainte-Rose)": {"2025": "22 juillet, 05:13", "2026": "22 juillet, 05:14", "2027": "22 juillet, 05:14", "2028": "21 juillet, 05:14", "2029": "22 juillet, 05:15"},
|
||||
"Pointe du Vieux-Fort": {"2025": "22 juillet, 05:14", "2026": "22 juillet, 05:14", "2027": "22 juillet, 05:15", "2028": "21 juillet, 05:15", "2029": "22 juillet, 05:16"}
|
||||
};
|
||||
|
||||
// Fonction de mise à jour des prédictions
|
||||
function updatePrediction() {
|
||||
const location = document.getElementById('location-select').value;
|
||||
const year = document.getElementById('year-select').value;
|
||||
const prediction = predictionsData[location][year];
|
||||
|
||||
const [datePart, timePart] = prediction.split(', ');
|
||||
const day = parseInt(datePart.split(' ')[0]);
|
||||
const month = datePart.split(' ')[1];
|
||||
|
||||
document.getElementById('result-location').textContent = location;
|
||||
document.getElementById('result-date').textContent = datePart;
|
||||
document.getElementById('result-time').textContent = `vers ${timePart}`;
|
||||
document.getElementById('result-window').textContent = `${day - 2} au ${day + 2} ${month}`;
|
||||
}
|
||||
|
||||
// Initialisation du globe 3D
|
||||
function initGlobe() {
|
||||
const container = document.getElementById('globe-container');
|
||||
if (!container) return;
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(45, container.clientWidth / container.clientHeight, 0.1, 1000);
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
|
||||
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
container.appendChild(renderer.domElement);
|
||||
|
||||
// Lumières
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
||||
directionalLight.position.set(5, 3, 5);
|
||||
scene.add(directionalLight);
|
||||
|
||||
// Sphere pour la Terre
|
||||
const geometry = new THREE.SphereGeometry(1, 32, 32);
|
||||
const material = new THREE.MeshPhongMaterial({
|
||||
color: 0x4A90E2,
|
||||
shininess: 30
|
||||
});
|
||||
const globe = new THREE.Mesh(geometry, material);
|
||||
scene.add(globe);
|
||||
|
||||
// Vague animée
|
||||
const waveGeometry = new THREE.TorusGeometry(1.1, 0.03, 8, 32);
|
||||
const waveMaterial = new THREE.MeshBasicMaterial({
|
||||
color: 0xFFD700,
|
||||
transparent: true,
|
||||
opacity: 0.7
|
||||
});
|
||||
const wave = new THREE.Mesh(waveGeometry, waveMaterial);
|
||||
scene.add(wave);
|
||||
|
||||
camera.position.z = 3;
|
||||
|
||||
// Animation
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
|
||||
globe.rotation.y += 0.005;
|
||||
|
||||
// Animation de la vague
|
||||
const time = Date.now() * 0.001;
|
||||
wave.position.y = Math.sin(time) * 0.5;
|
||||
wave.rotation.x = Math.PI / 2;
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
animate();
|
||||
|
||||
// Gestion du redimensionnement
|
||||
window.addEventListener('resize', () => {
|
||||
if (container.clientWidth > 0) {
|
||||
camera.aspect = container.clientWidth / container.clientHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialisation
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
updatePrediction();
|
||||
initGlobe();
|
||||
|
||||
// Event listeners
|
||||
document.getElementById('location-select').addEventListener('change', updatePrediction);
|
||||
document.getElementById('year-select').addEventListener('change', updatePrediction);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="./vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sirius en Guadeloupe - Guide du Lever Héliaque</title>
|
||||
<!-- Google Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Inter:wght@300;400;600;700&family=Playfair+Display:wght@700;900&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="./src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,227 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||
|
||||
"meta_title": "Sirius in Guadeloupe — Wep Ronpet, the heliacal rising",
|
||||
"meta_description": "Calculate and understand the heliacal rising of Sirius in Guadeloupe: astronomy, Egyptian and Dogon heritage, observation guide.",
|
||||
|
||||
"skip_to_content": "Skip to content",
|
||||
"lang_name_fr": "Français",
|
||||
"lang_name_en": "English",
|
||||
"lang_name_ht": "Kreyòl",
|
||||
|
||||
"nav_home": "Home",
|
||||
"nav_science": "Sirius & Science",
|
||||
"nav_culture": "Culture & Knowledge",
|
||||
"nav_observer": "Observe",
|
||||
"nav_associations": "Associations",
|
||||
|
||||
"hero_eyebrow": "Wep Ronpet",
|
||||
"hero_title1": "Sirius",
|
||||
"hero_title2": "in Guadeloupe",
|
||||
"hero_subtitle": "The Opening of the Cosmic Year",
|
||||
"hero_description": "The millennial meeting between Sky, Science and Culture",
|
||||
"hero_date_label": "Next heliacal rising",
|
||||
"hero_cta_predictions": "Discover the predictions",
|
||||
"hero_cta_learn": "Learn more",
|
||||
|
||||
"home_intro_title": "Sirius and Wep Ronpet",
|
||||
"home_intro_subtitle": "The Opening of the Year — the cosmic New Year of the ancient Egyptians",
|
||||
"home_intro_p1": "<strong>Wep Ronpet</strong> — \"the Opening of the Year\" in ancient Egyptian — marked the most sacred day of the Egyptian calendar. This day corresponded to the heliacal rising of Sirius, when the star reappeared at dawn after 70 days of invisibility.",
|
||||
"home_intro_p2": "The heliacal rising of Sirius is not just an astronomical phenomenon. It is a millennial meeting between humanity and the cosmos, a moment where science and spirituality meet in the light of dawn.",
|
||||
"home_intro_p3": "In Guadeloupe, observing this phenomenon connects us directly to African roots, where Sirius was venerated as the herald of life and renewal.",
|
||||
"feature_brightest_title": "The brightest star",
|
||||
"feature_brightest_desc": "Sirius shines with a magnitude of -1.46, dominating our night sky.",
|
||||
"feature_rising_title": "The heliacal rising",
|
||||
"feature_rising_desc": "Its first appearance at dawn after 70 days of invisibility marks a cosmic event.",
|
||||
"feature_heritage_title": "Ancestral heritage",
|
||||
"feature_heritage_desc": "From ancient Egypt to the Dogon of Mali, Sirius has guided humanity for millennia.",
|
||||
|
||||
"science_title": "Sirius & Science",
|
||||
"science_subtitle": "Understanding the cosmic dance between Earth, Sun and Sirius",
|
||||
"science_tab_mechanics": "Celestial mechanics",
|
||||
"science_tab_arcus": "Arcus Visionis",
|
||||
"science_tab_factors": "Influencing factors",
|
||||
"science_tab_calc": "Calculation method",
|
||||
"science_mechanics_title": "The cosmic ballet",
|
||||
"science_mechanics_p1": "The heliacal rising is the result of a precise celestial choreography. For about 70 days, Sirius stays invisible, hidden by the Sun's brilliance. Its return at dawn marks a unique moment when the star rises just before the Sun, visible for a few instants in the glow of morning twilight.",
|
||||
"science_mechanics_p2": "Earth, in its yearly orbital motion, changes our perspective on the stars. When the Sun sits between us and Sirius, the star becomes invisible. Only when the angle becomes favourable does Sirius reappear.",
|
||||
"science_diagram_sun": "Sun",
|
||||
"science_diagram_earth": "Earth",
|
||||
"science_diagram_sirius": "Sirius",
|
||||
"science_arcus_title": "The arc of visibility",
|
||||
"science_arcus_p1": "The Arcus Visionis is the critical angle: the Sun must be about 9 to 10° below the horizon for Sirius to become visible. It's a delicate balance between the star's brightness and the sky's luminosity.",
|
||||
"science_arcus_p2": "For Sirius, with its exceptional magnitude of -1.46, this angle is relatively small compared to dimmer stars — which is why it is one of the first stars visible at dawn.",
|
||||
"science_arcus_horizon_label": "Horizon",
|
||||
"science_factor_magnitude_title": "Magnitude",
|
||||
"science_factor_magnitude_desc": "Sirius shines at -1.46, making it visible even in difficult conditions. The brighter a star, the earlier it pierces the glow of dawn.",
|
||||
"science_factor_latitude_title": "Latitude",
|
||||
"science_factor_latitude_desc": "At 16°N in Guadeloupe, stars rise almost vertically. This tropical geometry shapes the duration of twilight and visibility.",
|
||||
"science_factor_atmosphere_title": "Atmosphere",
|
||||
"science_factor_atmosphere_desc": "Caribbean humidity and Saharan dust haze can delay visibility by several days. A dry, clear sky is ideal.",
|
||||
"science_calc_title": "Calculating the heliacal rising of Sirius",
|
||||
"science_calc_formula_label": "Main formula",
|
||||
"science_calc_formula": "Heliacal rising date = Conjunction date + (Arcus Visionis / Sun's angular speed)",
|
||||
"science_calc_step1_title": "Guadeloupe's coordinates",
|
||||
"science_calc_step1_value": "Latitude: 16.25°N — Longitude: 61.58°W",
|
||||
"science_calc_step2_title": "Sirius's position",
|
||||
"science_calc_step2_ra": "Right ascension: 6h 45m 09s",
|
||||
"science_calc_step2_dec": "Declination: -16° 42' 58\"",
|
||||
"science_calc_arcus_title": "Arcus Visionis",
|
||||
"science_calc_arcus_desc": "The minimum angle between the Sun and a star for it to become visible — about 2° of altitude above the horizon for a star as bright as Sirius, reached around 50 minutes before sunrise.",
|
||||
"science_calc_sources_title": "Method and sources",
|
||||
"science_calc_sources_text": "Per-site dates are interpolated from Jean Meeus's tables (arc of vision as a function of latitude) and cross-checked against astronomer Jeffrey L. Hunt's calculations (whenthecurveslineup.com). At 16°N, interpolating between 10°N (July 17) and 20°N (July 24) gives a heliacal rising around July 22-23 — consistent with traditional observation in Guadeloupe. The actual observed date still depends on weather and the clarity of the eastern horizon.",
|
||||
|
||||
"culture_title": "Culture & Knowledge",
|
||||
"culture_subtitle": "A millennial heritage uniting Africa and the Caribbean",
|
||||
"culture_egypt_title": "Egypt: Sothis, goddess of the Nile",
|
||||
"culture_egypt_desc": "For the ancient Egyptians, the heliacal rising of Sirius (Sothis) was the most important event of the year. It announced the flooding of the Nile, a source of life and fertility. This \"return\" of the star marked the New Year and symbolised rebirth, associated with the goddess Isis.",
|
||||
"culture_dogon_title": "Dogon: keepers of stellar knowledge",
|
||||
"culture_dogon_desc": "The Dogon people of Mali hold astonishing knowledge about Sirius. They knew of the existence of Sirius B, a white dwarf invisible to the naked eye, long before its scientific discovery. Their 60-year ritual cycle, the Sigui, is directly linked to their understanding of the Sirius system.",
|
||||
"culture_caribbean_title": "Caribbean: stellar navigation",
|
||||
"culture_caribbean_desc": "In the Caribbean, Sirius has guided sailors for centuries. Indigenous peoples and African mariners used its rising to mark the seasons and navigate between islands. Even today it remains a fundamental landmark for traditional fishermen.",
|
||||
"culture_timeline_title": "Timeline of knowledge",
|
||||
"culture_timeline_1_date": "3000 BCE",
|
||||
"culture_timeline_1_title": "Ancient Egypt",
|
||||
"culture_timeline_1_desc": "First calendar based on Sirius",
|
||||
"culture_timeline_2_date": "13th century",
|
||||
"culture_timeline_2_title": "Dogon migration",
|
||||
"culture_timeline_2_desc": "Preservation of astronomical knowledge",
|
||||
"culture_timeline_3_date": "15th-17th century",
|
||||
"culture_timeline_3_title": "Atlantic crossing",
|
||||
"culture_timeline_3_desc": "African knowledge travels to the Caribbean",
|
||||
"culture_timeline_4_date": "Today",
|
||||
"culture_timeline_4_title": "Renaissance",
|
||||
"culture_timeline_4_desc": "Rediscovery and celebration of Wep Ronpet in Guadeloupe",
|
||||
|
||||
"dogon_title": "The Dogon, keepers of the sky",
|
||||
"dogon_intro": "For centuries, the Dogon people of Mali have cultivated a cosmogony centred on Sirius, passed down orally from generation to generation.",
|
||||
"dogon_tab_cosmogony": "Cosmogony",
|
||||
"dogon_tab_system": "The Sirius system",
|
||||
"dogon_tab_astronomy": "Dogon astronomy",
|
||||
"dogon_tab_heritage": "Heritage",
|
||||
"dogon_cosmogony_title": "Dogon cosmogony",
|
||||
"dogon_cosmogony_p1": "Sigi Tolo — Sirius, the brightest star in the sky — sits at the centre of a highly sophisticated Dogon cosmogony, passed down orally for millennia.",
|
||||
"dogon_cosmogony_p2": "The Sigui, celebrated every 60 years, marks the renewal of the world and commemorates the revelation of speech to humankind. This roughly 60-year period is close to Sirius B's 50-year orbit around Sirius A, adjusted by ritual considerations.",
|
||||
"dogon_cosmogony_nommo_title": "The Nommo",
|
||||
"dogon_cosmogony_nommo_desc": "A primordial amphibious being said to come from Sirius, the Nommo is said to have brought civilisation and foundational knowledge to the Dogon ancestors.",
|
||||
"dogon_system_sigutolo_title": "Sigi Tolo (Sirius A)",
|
||||
"dogon_system_sigutolo_desc": "The main star, source of light and life. Associated with femininity and fertility, it guides the seasons and the harvests.",
|
||||
"dogon_system_potolo_title": "Po Tolo (Sirius B)",
|
||||
"dogon_system_potolo_desc": "A companion invisible to the naked eye, described as \"heavy\" and \"white\". Its 50-year orbit around Sirius A was only confirmed by Western astronomers in 1862 — the heart of the Dogon mystery.",
|
||||
"dogon_system_emmeya_title": "Emme Ya Tolo",
|
||||
"dogon_system_emmeya_desc": "A hypothetical third star, four times lighter than Po Tolo and on a wider orbit. Not confirmed by modern astronomy.",
|
||||
"dogon_mystery_title": "The mystery of the knowledge",
|
||||
"dogon_mystery_theory1_title": "Ancient transmission",
|
||||
"dogon_mystery_theory1_desc": "A heritage passed down from an earlier, advanced civilisation.",
|
||||
"dogon_mystery_theory2_title": "Contact",
|
||||
"dogon_mystery_theory2_desc": "The account of the Nommo, said to come from Sirius according to oral tradition.",
|
||||
"dogon_mystery_theory3_title": "Careful observation",
|
||||
"dogon_mystery_theory3_desc": "A patient deduction from perturbations observed on Sirius A.",
|
||||
"dogon_astronomy_geometry_title": "Sacred geometry",
|
||||
"dogon_astronomy_geometry_desc": "Complex geometric figures represent celestial motions and cosmic cycles.",
|
||||
"dogon_astronomy_calendar_title": "Lunar calendar",
|
||||
"dogon_astronomy_calendar_desc": "A sophisticated calendar system based on lunar phases and the position of Sirius, in service of agriculture.",
|
||||
"dogon_astronomy_planets_title": "Planetary knowledge",
|
||||
"dogon_astronomy_planets_desc": "A description of Saturn's rings and Jupiter's moons, invisible without a telescope.",
|
||||
"dogon_astronomy_universe_title": "Structure of the universe",
|
||||
"dogon_astronomy_universe_desc": "A universe conceived as infinite, made of multiple worlds — an intuition close to modern cosmology.",
|
||||
"dogon_calc_example_title": "A striking correspondence",
|
||||
"dogon_calc_example_text": "Po Tolo's orbital period: 50 years. Ritual adjustment: × 1.2. Sigui period: 60 years. Match with Sirius B's actual orbit (50.1 years): 99.8%.",
|
||||
"dogon_heritage_1_date": "Antiquity",
|
||||
"dogon_heritage_1_desc": "Possible links with the Egyptian priests who venerated Sothis (Sirius)",
|
||||
"dogon_heritage_2_date": "13th century",
|
||||
"dogon_heritage_2_desc": "Migration to the Bandiagara cliffs in Mali, preservation of traditions",
|
||||
"dogon_heritage_3_date": "1931-1956",
|
||||
"dogon_heritage_3_desc": "Marcel Griaule's ethnographic study reveals Dogon astronomical knowledge",
|
||||
"dogon_heritage_4_date": "Today",
|
||||
"dogon_heritage_4_desc": "The Dogon continue to inspire researchers and scientists worldwide",
|
||||
"dogon_heritage_diaspora_title": "An influence that crossed the Atlantic",
|
||||
"dogon_heritage_diaspora_desc": "African astronomical traditions, including Dogon knowledge, crossed the Atlantic with the diaspora, enriching the spiritual and calendrical practices of the Caribbean.",
|
||||
"dogon_heritage_diaspora_haiti": "Vodou and sacred astronomy",
|
||||
"dogon_heritage_diaspora_guadeloupe": "Gwoka traditions and cosmic cycles",
|
||||
"dogon_heritage_diaspora_martinique": "Bèlè and stellar rhythms",
|
||||
"dogon_heritage_diaspora_jamaica": "Rastafari and cosmic consciousness",
|
||||
|
||||
"observer_title": "Observe",
|
||||
"observer_subtitle": "Where, when and how to observe the heliacal rising in Guadeloupe",
|
||||
"observer_calculator_title": "Prediction calculator",
|
||||
"observer_calculator_subtitle": "Choose your site to find out the exact date",
|
||||
"observer_calculator_select_label": "Your observation site",
|
||||
"observer_calculator_table_site": "Site",
|
||||
"observer_calculator_table_date": "2026 date",
|
||||
"observer_calculator_table_time": "Time",
|
||||
"observer_calculator_result_heliacal": "Heliacal rising",
|
||||
"observer_calculator_result_window": "Observation window",
|
||||
"observer_map_title": "Map of observation sites",
|
||||
"observer_map_subtitle": "Seven landmark locations across the archipelago",
|
||||
"observer_timeline_title": "Observation timeline",
|
||||
"observer_phase1_time": "4:30 am",
|
||||
"observer_phase1_title": "Preparation",
|
||||
"observer_phase1_desc": "Arrive on site, let your eyes adapt to the darkness",
|
||||
"observer_phase2_time": "5:00 am",
|
||||
"observer_phase2_title": "Search",
|
||||
"observer_phase2_desc": "Look towards the East-Southeast, near the horizon",
|
||||
"observer_phase3_time": "5:15 am",
|
||||
"observer_phase3_title": "Appearance",
|
||||
"observer_phase3_desc": "Sirius emerges from the dawn glow",
|
||||
"observer_phase4_time": "5:30 am",
|
||||
"observer_phase4_title": "Observation",
|
||||
"observer_phase4_desc": "The optimal moment to contemplate",
|
||||
"observer_equipment_title": "Recommended equipment",
|
||||
"observer_equipment_essential_badge": "Essential",
|
||||
"observer_equipment_binoculars_name": "Binoculars",
|
||||
"observer_equipment_binoculars_desc": "7x50 or 10x50 recommended",
|
||||
"observer_equipment_lamp_name": "Red lamp",
|
||||
"observer_equipment_lamp_desc": "Preserves night vision",
|
||||
"observer_equipment_compass_name": "Compass",
|
||||
"observer_equipment_compass_desc": "To find East",
|
||||
"observer_equipment_clothes_name": "Warm clothes",
|
||||
"observer_equipment_clothes_desc": "Mornings are cool",
|
||||
"observer_equipment_notebook_name": "Notebook",
|
||||
"observer_equipment_notebook_desc": "To record your observations",
|
||||
"observer_tips_title": "Practical tips",
|
||||
"observer_tip_weather_title": "Ideal weather",
|
||||
"observer_tip_weather_desc": "Clear sky to the East, no low clouds, moderate humidity",
|
||||
"observer_tip_moon_title": "Moon phase",
|
||||
"observer_tip_moon_desc": "New moon or thin crescent for a darker sky",
|
||||
"observer_tip_apps_title": "Useful apps",
|
||||
"observer_tip_apps_desc": "Stellarium, SkySafari, Star Walk to locate the constellations",
|
||||
"observer_tip_group_title": "As a group",
|
||||
"observer_tip_group_desc": "Share this unique moment with family and friends",
|
||||
|
||||
"globe_title": "The wave phenomenon",
|
||||
"globe_p1": "The heliacal rising of Sirius does not happen simultaneously across the Earth. Like a cosmic wave, it moves from East to West, first reaching Réunion in late June, then sweeping across Africa, before finally reaching the Caribbean in July.",
|
||||
"globe_p2": "This animation shows the progression of this \"planetary wave\", following Earth's rotation and the position of Sirius in the sky. Each place experiences this sacred moment on a precise date, forming a natural cosmic calendar that has guided civilisations for millennia.",
|
||||
"globe_controls_hint": "Drag to rotate · scroll to zoom",
|
||||
"globe_timeline_title": "Timeline of the wave",
|
||||
|
||||
"associations_title": "Associations celebrating Wep Ronpet",
|
||||
"associations_subtitle": "Discover the events and communities celebrating the Kamit New Year",
|
||||
"associations_events_title": "Wep Ronpet events",
|
||||
"associations_event1_title": "Kamite New Year",
|
||||
"associations_event1_organizer": "Afrocentricity International & Famille Muntu",
|
||||
"associations_event1_desc": "A sacred time of passage into a new cosmic rotation, lived in harmony with the laws of the universe. Ceremony and rituals, Kamite gastronomy, artisan market.",
|
||||
"associations_event2_title": "Kamit New Year",
|
||||
"associations_event2_organizer": "Mouvement Politique Spirituel MUN",
|
||||
"associations_event2_desc": "Celebration with the New Moon. Ceremony, rituals, conferences, Kamit dinner, dance evening.",
|
||||
"associations_community_title": "Community & resources",
|
||||
"associations_link1_title": "14th Member",
|
||||
"associations_link1_desc": "Website — Events",
|
||||
"associations_link2_title": "Mouvement Politique Spirituel MUN",
|
||||
"associations_link2_desc": "Official Facebook page",
|
||||
"associations_video_title": "Discover Wep Ronpet",
|
||||
"associations_note": "Dates, venues and links should be confirmed each year with the organisers — the information above is provided as a guide only.",
|
||||
|
||||
"footer_tagline": "A project celebrating African and Caribbean astronomical heritage through the observation of the heliacal rising of Sirius.",
|
||||
"footer_links_title": "Quick links",
|
||||
"footer_resources_title": "Resources",
|
||||
"footer_resources_stellarium": "Stellarium",
|
||||
"footer_resources_guide": "PDF guide",
|
||||
"footer_resources_references": "References",
|
||||
"footer_resources_contact": "Contact",
|
||||
"footer_next_title": "Next observation",
|
||||
"footer_copyright_prefix": "Project made with ❤️ by",
|
||||
"footer_and": "and",
|
||||
"footer_quote": "\"The stars are the ancestors watching over us\" — African proverb",
|
||||
"footer_rights": "Sirius Gwada. Look up to the sky."
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||
|
||||
"meta_title": "Sirius en Guadeloupe — Wep Ronpet, le lever héliaque",
|
||||
"meta_description": "Calculez et comprenez le lever héliaque de Sirius en Guadeloupe : astronomie, héritage égyptien et dogon, guide d'observation.",
|
||||
|
||||
"skip_to_content": "Aller au contenu",
|
||||
"lang_name_fr": "Français",
|
||||
"lang_name_en": "English",
|
||||
"lang_name_ht": "Kreyòl",
|
||||
|
||||
"nav_home": "Accueil",
|
||||
"nav_science": "Sirius & Science",
|
||||
"nav_culture": "Culture & Savoirs",
|
||||
"nav_observer": "Observer",
|
||||
"nav_associations": "Associations",
|
||||
|
||||
"hero_eyebrow": "Wep Ronpet",
|
||||
"hero_title1": "Sirius",
|
||||
"hero_title2": "en Guadeloupe",
|
||||
"hero_subtitle": "L'Ouverture de l'Année Cosmique",
|
||||
"hero_description": "Le rendez-vous millénaire entre Ciel, Science et Culture",
|
||||
"hero_date_label": "Prochain lever héliaque",
|
||||
"hero_cta_predictions": "Découvrir les prédictions",
|
||||
"hero_cta_learn": "En savoir plus",
|
||||
|
||||
"home_intro_title": "Sirius et Wep Ronpet",
|
||||
"home_intro_subtitle": "L'Ouverture de l'Année — le Nouvel An cosmique des anciens Égyptiens",
|
||||
"home_intro_p1": "<strong>Wep Ronpet</strong> — « l'Ouverture de l'Année » en égyptien ancien — marquait le jour le plus sacré du calendrier égyptien. Ce jour correspondait au lever héliaque de Sirius, quand l'étoile réapparaissait à l'aube après 70 jours d'invisibilité.",
|
||||
"home_intro_p2": "Le lever héliaque de Sirius n'est pas qu'un simple phénomène astronomique. C'est un rendez-vous millénaire entre l'humanité et le cosmos, un moment où science et spiritualité se rencontrent dans la lumière de l'aube.",
|
||||
"home_intro_p3": "En Guadeloupe, observer ce phénomène nous connecte directement aux racines africaines, où Sirius était vénérée comme l'annonciatrice de la vie et du renouveau.",
|
||||
"feature_brightest_title": "L'étoile la plus brillante",
|
||||
"feature_brightest_desc": "Sirius brille avec une magnitude de -1,46, dominant notre ciel nocturne.",
|
||||
"feature_rising_title": "Le lever héliaque",
|
||||
"feature_rising_desc": "Sa première apparition à l'aube après 70 jours d'invisibilité marque un événement cosmique.",
|
||||
"feature_heritage_title": "Héritage ancestral",
|
||||
"feature_heritage_desc": "De l'Égypte ancienne aux Dogons du Mali, Sirius guide l'humanité depuis des millénaires.",
|
||||
|
||||
"science_title": "Sirius & Science",
|
||||
"science_subtitle": "Comprendre la danse cosmique entre Terre, Soleil et Sirius",
|
||||
"science_tab_mechanics": "Mécanique céleste",
|
||||
"science_tab_arcus": "Arcus Visionis",
|
||||
"science_tab_factors": "Facteurs d'influence",
|
||||
"science_tab_calc": "Méthode de calcul",
|
||||
"science_mechanics_title": "Le ballet cosmique",
|
||||
"science_mechanics_p1": "Le lever héliaque est le fruit d'une chorégraphie céleste précise. Pendant environ 70 jours, Sirius reste invisible, cachée par l'éclat du Soleil. Son retour à l'aube marque un moment unique où l'étoile se lève juste avant le Soleil, visible quelques instants dans les lueurs du crépuscule matinal.",
|
||||
"science_mechanics_p2": "La Terre, dans son mouvement orbital annuel, modifie notre perspective sur les étoiles. Quand le Soleil se trouve entre nous et Sirius, l'étoile devient invisible. C'est seulement quand l'angle devient favorable que Sirius réapparaît.",
|
||||
"science_diagram_sun": "Soleil",
|
||||
"science_diagram_earth": "Terre",
|
||||
"science_diagram_sirius": "Sirius",
|
||||
"science_arcus_title": "L'arc de visibilité",
|
||||
"science_arcus_p1": "L'Arcus Visionis est l'angle critique : le Soleil doit être à environ 9 à 10° sous l'horizon pour que Sirius devienne visible. C'est un équilibre délicat entre la brillance de l'étoile et la luminosité du ciel.",
|
||||
"science_arcus_p2": "Pour Sirius, avec sa magnitude exceptionnelle de -1,46, cet angle est relativement faible comparé à d'autres étoiles moins brillantes. C'est pourquoi elle est l'une des premières à être visible à l'aube.",
|
||||
"science_arcus_horizon_label": "Horizon",
|
||||
"science_factor_magnitude_title": "Magnitude",
|
||||
"science_factor_magnitude_desc": "Sirius brille à -1,46, la rendant visible même dans des conditions difficiles. Plus une étoile est brillante, plus tôt elle perce les lueurs de l'aube.",
|
||||
"science_factor_latitude_title": "Latitude",
|
||||
"science_factor_latitude_desc": "À 16°N en Guadeloupe, les astres se lèvent presque verticalement. Cette géométrie tropicale influence la durée du crépuscule et la visibilité.",
|
||||
"science_factor_atmosphere_title": "Atmosphère",
|
||||
"science_factor_atmosphere_desc": "L'humidité caribéenne et les brumes de sable saharien peuvent retarder la visibilité de plusieurs jours. Un ciel sec et clair est idéal.",
|
||||
"science_calc_title": "Calcul du lever héliaque de Sirius",
|
||||
"science_calc_formula_label": "Formule principale",
|
||||
"science_calc_formula": "Date du lever héliaque = Date de conjonction + (Arcus Visionis / Vitesse angulaire du Soleil)",
|
||||
"science_calc_step1_title": "Coordonnées de la Guadeloupe",
|
||||
"science_calc_step1_value": "Latitude : 16,25°N — Longitude : 61,58°O",
|
||||
"science_calc_step2_title": "Position de Sirius",
|
||||
"science_calc_step2_ra": "Ascension droite : 6h 45m 09s",
|
||||
"science_calc_step2_dec": "Déclinaison : -16° 42' 58\"",
|
||||
"science_calc_arcus_title": "Arcus Visionis",
|
||||
"science_calc_arcus_desc": "Angle minimal entre le Soleil et une étoile pour que celle-ci devienne visible — environ 2° de hauteur au-dessus de l'horizon pour une étoile aussi brillante que Sirius, atteint autour de 50 minutes avant le lever du Soleil.",
|
||||
"science_calc_sources_title": "Méthode et sources",
|
||||
"science_calc_sources_text": "Les dates par site sont interpolées à partir des tables de Jean Meeus (arc de vision en fonction de la latitude) et recoupées avec les calculs de l'astronome Jeffrey L. Hunt (whenthecurveslineup.com). À 16°N, l'interpolation entre 10°N (17 juillet) et 20°N (24 juillet) donne un lever héliaque autour du 22-23 juillet — cohérent avec l'observation traditionnelle en Guadeloupe. La date réelle observée dépend toujours de la météo et de la clarté de l'horizon Est.",
|
||||
|
||||
"culture_title": "Culture & Savoirs",
|
||||
"culture_subtitle": "Un héritage millénaire qui unit l'Afrique et les Caraïbes",
|
||||
"culture_egypt_title": "Égypte : Sothis, la déesse du Nil",
|
||||
"culture_egypt_desc": "Pour les anciens Égyptiens, le lever héliaque de Sirius (Sothis) était l'événement le plus important de l'année. Il annonçait la crue du Nil, source de vie et de fertilité. Ce « retour » de l'étoile marquait le Nouvel An et symbolisait la renaissance, associée à la déesse Isis.",
|
||||
"culture_dogon_title": "Dogon : les gardiens du savoir stellaire",
|
||||
"culture_dogon_desc": "Le peuple Dogon du Mali possède un savoir stupéfiant sur Sirius. Ils connaissaient l'existence de Sirius B, une naine blanche invisible à l'œil nu, bien avant sa découverte scientifique. Leur cycle rituel de 60 ans, le Sigui, est directement lié à leur compréhension du système de Sirius.",
|
||||
"culture_caribbean_title": "Caraïbes : la navigation stellaire",
|
||||
"culture_caribbean_desc": "Dans les Caraïbes, Sirius a guidé les navigateurs depuis des siècles. Les peuples autochtones et les marins africains utilisaient son lever pour marquer les saisons et naviguer entre les îles. Aujourd'hui encore, elle reste un repère fondamental pour les pêcheurs traditionnels.",
|
||||
"culture_timeline_title": "Chronologie du savoir",
|
||||
"culture_timeline_1_date": "3000 av. J.-C.",
|
||||
"culture_timeline_1_title": "Égypte ancienne",
|
||||
"culture_timeline_1_desc": "Premier calendrier basé sur Sirius",
|
||||
"culture_timeline_2_date": "XIIIᵉ siècle",
|
||||
"culture_timeline_2_title": "Migration dogon",
|
||||
"culture_timeline_2_desc": "Préservation du savoir astronomique",
|
||||
"culture_timeline_3_date": "XVᵉ-XVIIᵉ siècle",
|
||||
"culture_timeline_3_title": "Traversée atlantique",
|
||||
"culture_timeline_3_desc": "Le savoir africain voyage vers les Caraïbes",
|
||||
"culture_timeline_4_date": "Aujourd'hui",
|
||||
"culture_timeline_4_title": "Renaissance",
|
||||
"culture_timeline_4_desc": "Redécouverte et célébration du Wep Ronpet en Guadeloupe",
|
||||
|
||||
"dogon_title": "Les Dogon, gardiens du ciel",
|
||||
"dogon_intro": "Le peuple Dogon du Mali cultive depuis des siècles une cosmogonie centrée sur Sirius, transmise oralement de génération en génération.",
|
||||
"dogon_tab_cosmogony": "Cosmogonie",
|
||||
"dogon_tab_system": "Système de Sirius",
|
||||
"dogon_tab_astronomy": "Astronomie dogon",
|
||||
"dogon_tab_heritage": "Héritage",
|
||||
"dogon_cosmogony_title": "La cosmogonie dogon",
|
||||
"dogon_cosmogony_p1": "Sigi Tolo — Sirius, l'étoile la plus brillante du ciel — est au centre d'une cosmogonie dogon d'une grande sophistication, transmise oralement pendant des millénaires.",
|
||||
"dogon_cosmogony_p2": "Le Sigui, célébré tous les 60 ans, marque le renouvellement du monde et commémore la révélation de la parole aux hommes. Cette périodicité d'environ 60 ans se rapproche de l'orbite de 50 ans de Sirius B autour de Sirius A, ajustée par des considérations rituelles.",
|
||||
"dogon_cosmogony_nommo_title": "Le Nommo",
|
||||
"dogon_cosmogony_nommo_desc": "Être amphibie primordial venu de Sirius, le Nommo aurait apporté la civilisation et les savoirs fondateurs aux ancêtres dogon.",
|
||||
"dogon_system_sigutolo_title": "Sigi Tolo (Sirius A)",
|
||||
"dogon_system_sigutolo_desc": "L'étoile principale, source de lumière et de vie. Associée à la féminité et à la fécondité, elle guide les saisons et les récoltes.",
|
||||
"dogon_system_potolo_title": "Po Tolo (Sirius B)",
|
||||
"dogon_system_potolo_desc": "Compagnon invisible à l'œil nu, décrit comme « lourd » et « blanc ». Son orbite de 50 ans autour de Sirius A n'a été confirmée par les astronomes occidentaux qu'en 1862 — le cœur du mystère dogon.",
|
||||
"dogon_system_emmeya_title": "Emme Ya Tolo",
|
||||
"dogon_system_emmeya_desc": "Une troisième étoile hypothétique, quatre fois plus légère que Po Tolo et sur une orbite plus large. Non confirmée par l'astronomie moderne.",
|
||||
"dogon_mystery_title": "Le mystère du savoir",
|
||||
"dogon_mystery_theory1_title": "Transmission ancienne",
|
||||
"dogon_mystery_theory1_desc": "Un héritage venu d'une civilisation antérieure avancée.",
|
||||
"dogon_mystery_theory2_title": "Contact",
|
||||
"dogon_mystery_theory2_desc": "Le récit des Nommo, venus de Sirius selon la tradition orale.",
|
||||
"dogon_mystery_theory3_title": "Observation minutieuse",
|
||||
"dogon_mystery_theory3_desc": "Une déduction patiente à partir des perturbations observées sur Sirius A.",
|
||||
"dogon_astronomy_geometry_title": "Géométrie sacrée",
|
||||
"dogon_astronomy_geometry_desc": "Des figures géométriques complexes représentent les mouvements célestes et les cycles cosmiques.",
|
||||
"dogon_astronomy_calendar_title": "Calendrier lunaire",
|
||||
"dogon_astronomy_calendar_desc": "Un système calendaire sophistiqué fondé sur les phases lunaires et la position de Sirius, au service de l'agriculture.",
|
||||
"dogon_astronomy_planets_title": "Connaissance planétaire",
|
||||
"dogon_astronomy_planets_desc": "Une description des anneaux de Saturne et des lunes de Jupiter, invisibles sans télescope.",
|
||||
"dogon_astronomy_universe_title": "Structure de l'univers",
|
||||
"dogon_astronomy_universe_desc": "Un univers conçu comme infini, fait de mondes multiples — une intuition proche de la cosmologie moderne.",
|
||||
"dogon_calc_example_title": "Une correspondance troublante",
|
||||
"dogon_calc_example_text": "Période orbitale de Po Tolo : 50 ans. Ajustement rituel : × 1,2. Période du Sigui : 60 ans. Concordance avec l'orbite réelle de Sirius B (50,1 ans) : 99,8 %.",
|
||||
"dogon_heritage_1_date": "Antiquité",
|
||||
"dogon_heritage_1_desc": "Liens possibles avec les prêtres égyptiens qui vénéraient Sothis (Sirius)",
|
||||
"dogon_heritage_2_date": "XIIIᵉ siècle",
|
||||
"dogon_heritage_2_desc": "Migration vers les falaises de Bandiagara au Mali, préservation des traditions",
|
||||
"dogon_heritage_3_date": "1931-1956",
|
||||
"dogon_heritage_3_desc": "L'étude ethnographique de Marcel Griaule révèle le savoir astronomique dogon",
|
||||
"dogon_heritage_4_date": "Aujourd'hui",
|
||||
"dogon_heritage_4_desc": "Les Dogon continuent d'inspirer chercheurs et scientifiques du monde entier",
|
||||
"dogon_heritage_diaspora_title": "Une influence qui traverse l'Atlantique",
|
||||
"dogon_heritage_diaspora_desc": "Les traditions astronomiques africaines, dogon comprises, ont traversé l'Atlantique avec la diaspora, enrichissant les pratiques spirituelles et calendaires des Antilles.",
|
||||
"dogon_heritage_diaspora_haiti": "Vaudou et astronomie sacrée",
|
||||
"dogon_heritage_diaspora_guadeloupe": "Traditions du gwoka et cycles cosmiques",
|
||||
"dogon_heritage_diaspora_martinique": "Bèlè et rythmes stellaires",
|
||||
"dogon_heritage_diaspora_jamaica": "Rastafari et conscience cosmique",
|
||||
|
||||
"observer_title": "Observer",
|
||||
"observer_subtitle": "Où, quand et comment observer le lever héliaque en Guadeloupe",
|
||||
"observer_calculator_title": "Calculateur de prédictions",
|
||||
"observer_calculator_subtitle": "Choisissez votre site pour connaître la date exacte",
|
||||
"observer_calculator_select_label": "Votre lieu d'observation",
|
||||
"observer_calculator_table_site": "Site",
|
||||
"observer_calculator_table_date": "Date 2026",
|
||||
"observer_calculator_table_time": "Heure",
|
||||
"observer_calculator_result_heliacal": "Lever héliaque",
|
||||
"observer_calculator_result_window": "Fenêtre d'observation",
|
||||
"observer_map_title": "Carte des sites d'observation",
|
||||
"observer_map_subtitle": "Sept lieux emblématiques répartis sur l'archipel",
|
||||
"observer_timeline_title": "Chronologie de l'observation",
|
||||
"observer_phase1_time": "04h30",
|
||||
"observer_phase1_title": "Préparation",
|
||||
"observer_phase1_desc": "Arrivez sur site, laissez vos yeux s'adapter à l'obscurité",
|
||||
"observer_phase2_time": "05h00",
|
||||
"observer_phase2_title": "Recherche",
|
||||
"observer_phase2_desc": "Cherchez vers l'Est-Sud-Est, près de l'horizon",
|
||||
"observer_phase3_time": "05h15",
|
||||
"observer_phase3_title": "Apparition",
|
||||
"observer_phase3_desc": "Sirius émerge de la lueur de l'aube",
|
||||
"observer_phase4_time": "05h30",
|
||||
"observer_phase4_title": "Observation",
|
||||
"observer_phase4_desc": "Moment optimal pour contempler",
|
||||
"observer_equipment_title": "Équipement recommandé",
|
||||
"observer_equipment_essential_badge": "Essentiel",
|
||||
"observer_equipment_binoculars_name": "Jumelles",
|
||||
"observer_equipment_binoculars_desc": "7x50 ou 10x50 recommandées",
|
||||
"observer_equipment_lamp_name": "Lampe rouge",
|
||||
"observer_equipment_lamp_desc": "Préserve la vision nocturne",
|
||||
"observer_equipment_compass_name": "Boussole",
|
||||
"observer_equipment_compass_desc": "Pour trouver l'Est",
|
||||
"observer_equipment_clothes_name": "Vêtements chauds",
|
||||
"observer_equipment_clothes_desc": "Les matins sont frais",
|
||||
"observer_equipment_notebook_name": "Carnet de notes",
|
||||
"observer_equipment_notebook_desc": "Pour documenter l'observation",
|
||||
"observer_tips_title": "Conseils pratiques",
|
||||
"observer_tip_weather_title": "Météo idéale",
|
||||
"observer_tip_weather_desc": "Ciel dégagé à l'Est, pas de nuages bas, humidité modérée",
|
||||
"observer_tip_moon_title": "Phase lunaire",
|
||||
"observer_tip_moon_desc": "Nouvelle lune ou croissant fin pour un ciel plus sombre",
|
||||
"observer_tip_apps_title": "Applications utiles",
|
||||
"observer_tip_apps_desc": "Stellarium, SkySafari, Star Walk pour repérer les constellations",
|
||||
"observer_tip_group_title": "En groupe",
|
||||
"observer_tip_group_desc": "Partagez ce moment unique avec famille et amis",
|
||||
|
||||
"globe_title": "Le phénomène de la vague",
|
||||
"globe_p1": "Le lever héliaque de Sirius ne se produit pas simultanément sur toute la Terre. Telle une vague cosmique, il progresse d'Est en Ouest, touchant d'abord La Réunion fin juin, puis traversant l'Afrique, pour finalement atteindre les Caraïbes en juillet.",
|
||||
"globe_p2": "Cette animation montre la progression de cette « vague planétaire » qui suit la rotation terrestre et la position de Sirius dans le ciel. Chaque lieu expérimente ce moment sacré à une date précise, créant un calendrier cosmique naturel qui a guidé les civilisations pendant des millénaires.",
|
||||
"globe_controls_hint": "Glisser pour tourner · molette pour zoomer",
|
||||
"globe_timeline_title": "Chronologie de la vague",
|
||||
|
||||
"associations_title": "Associations qui fêtent le Wep Ronpet",
|
||||
"associations_subtitle": "Découvrez les événements et communautés qui célèbrent le Nouvel An Kamit",
|
||||
"associations_events_title": "Événements Wep Ronpet",
|
||||
"associations_event1_title": "Nouvel An Kamite",
|
||||
"associations_event1_organizer": "Afrocentricity International & Famille Muntu",
|
||||
"associations_event1_desc": "Temps sacré de passage vers une nouvelle rotation cosmique, vécu en harmonie avec les lois de l'univers. Cérémonie et rituels, gastronomie kamite, marché artisanal.",
|
||||
"associations_event2_title": "Nouvel An Kamit",
|
||||
"associations_event2_organizer": "Mouvement Politique Spirituel MUN",
|
||||
"associations_event2_desc": "Célébration avec la Nouvelle Lune. Cérémonie, rituels, conférences, dîner kamit, soirée dansante.",
|
||||
"associations_community_title": "Communauté & ressources",
|
||||
"associations_link1_title": "14ème Membre",
|
||||
"associations_link1_desc": "Site web — Événements",
|
||||
"associations_link2_title": "Mouvement Politique Spirituel MUN",
|
||||
"associations_link2_desc": "Page Facebook officielle",
|
||||
"associations_video_title": "Découvrir le Wep Ronpet",
|
||||
"associations_note": "Dates, lieux et liens à confirmer chaque année auprès des organisateurs — les informations ci-dessus sont données à titre indicatif.",
|
||||
|
||||
"footer_tagline": "Un projet célébrant le patrimoine astronomique africain et caribéen à travers l'observation du lever héliaque de Sirius.",
|
||||
"footer_links_title": "Liens rapides",
|
||||
"footer_resources_title": "Ressources",
|
||||
"footer_resources_stellarium": "Stellarium",
|
||||
"footer_resources_guide": "Guide PDF",
|
||||
"footer_resources_references": "Références",
|
||||
"footer_resources_contact": "Contact",
|
||||
"footer_next_title": "Prochaine observation",
|
||||
"footer_copyright_prefix": "Projet réalisé avec ❤️ par",
|
||||
"footer_and": "et",
|
||||
"footer_quote": "« Les étoiles sont les ancêtres qui veillent sur nous » — proverbe africain",
|
||||
"footer_rights": "Sirius Gwada. Levez les yeux vers le ciel."
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||
|
||||
"meta_title": "Sirius nan Gwadloup — Wep Ronpet, leve elyak la",
|
||||
|
||||
"skip_to_content": "Ale nan kontni an",
|
||||
"lang_name_fr": "Français",
|
||||
"lang_name_en": "English",
|
||||
"lang_name_ht": "Kreyòl",
|
||||
|
||||
"nav_home": "Akèy",
|
||||
"nav_science": "Sirius & Syans",
|
||||
"nav_culture": "Kilti & Konesans",
|
||||
"nav_observer": "Obsève",
|
||||
"nav_associations": "Asosyasyon",
|
||||
|
||||
"hero_eyebrow": "Wep Ronpet",
|
||||
"hero_title1": "Sirius",
|
||||
"hero_title2": "nan Gwadloup",
|
||||
"hero_subtitle": "Ouvèti Ane Kosmik la",
|
||||
"hero_description": "Randevou milenè ant Syèl, Syans ak Kilti",
|
||||
"hero_date_label": "Pwochen leve elyak",
|
||||
"hero_cta_predictions": "Dekouvri prediksyon yo",
|
||||
"hero_cta_learn": "Aprann plis",
|
||||
|
||||
"home_intro_title": "Sirius ak Wep Ronpet",
|
||||
"home_intro_subtitle": "Ouvèti Ane a — Nouvèl An kosmik ansyen ejipsyen yo",
|
||||
"feature_brightest_title": "Zetwal ki pi klere a",
|
||||
"feature_rising_title": "Leve elyak la",
|
||||
"feature_heritage_title": "Eritaj zansèt",
|
||||
|
||||
"science_title": "Sirius & Syans",
|
||||
"science_tab_mechanics": "Mekanik selès",
|
||||
"science_tab_arcus": "Arcus Visionis",
|
||||
"science_tab_factors": "Faktè enfliyans",
|
||||
"science_tab_calc": "Metòd kalkil",
|
||||
"science_diagram_sun": "Solèy",
|
||||
"science_diagram_earth": "Latè",
|
||||
"science_diagram_sirius": "Sirius",
|
||||
"science_factor_magnitude_title": "Mayitid",
|
||||
"science_factor_latitude_title": "Latitid",
|
||||
"science_factor_atmosphere_title": "Atmosfè",
|
||||
|
||||
"culture_title": "Kilti & Konesans",
|
||||
"culture_egypt_title": "Lejip: Sothis, deyès Nil la",
|
||||
"culture_dogon_title": "Dogon: gadyen konesans zetwal yo",
|
||||
"culture_caribbean_title": "Karayib: navigasyon selès",
|
||||
"culture_timeline_title": "Kwonoloji konesans lan",
|
||||
|
||||
"dogon_title": "Dogon yo, gadyen syèl la",
|
||||
"dogon_tab_cosmogony": "Kosmogoni",
|
||||
"dogon_tab_system": "Sistèm Sirius la",
|
||||
"dogon_tab_astronomy": "Astwonomi dogon",
|
||||
"dogon_tab_heritage": "Eritaj",
|
||||
|
||||
"observer_title": "Obsève",
|
||||
"observer_calculator_title": "Kalkilatè prediksyon",
|
||||
"observer_calculator_select_label": "Kote w ap obsève",
|
||||
"observer_calculator_table_site": "Sit",
|
||||
"observer_calculator_table_date": "Dat 2026",
|
||||
"observer_calculator_table_time": "Lè",
|
||||
"observer_map_title": "Kat sit obsèvasyon yo",
|
||||
"observer_timeline_title": "Kwonoloji obsèvasyon an",
|
||||
"observer_phase1_title": "Preparasyon",
|
||||
"observer_phase2_title": "Rechèch",
|
||||
"observer_phase3_title": "Aparisyon",
|
||||
"observer_phase4_title": "Obsèvasyon",
|
||||
"observer_equipment_title": "Ekipman rekòmande",
|
||||
"observer_equipment_essential_badge": "Esansyèl",
|
||||
"observer_equipment_binoculars_name": "Jimèl",
|
||||
"observer_equipment_lamp_name": "Lanp wouj",
|
||||
"observer_equipment_compass_name": "Bousòl",
|
||||
"observer_equipment_clothes_name": "Rad cho",
|
||||
"observer_equipment_notebook_name": "Kaye nòt",
|
||||
"observer_tips_title": "Konsèy pratik",
|
||||
|
||||
"globe_title": "Fenomèn vag la",
|
||||
"globe_controls_hint": "Trennen pou vire · molèt pou zoome",
|
||||
|
||||
"associations_title": "Asosyasyon ki fete Wep Ronpet",
|
||||
"associations_subtitle": "Dekouvri evènman ak kominote ki selebre Nouvèl An Kamit la",
|
||||
"associations_events_title": "Evènman Wep Ronpet",
|
||||
"associations_event1_title": "Nouvèl An Kamite",
|
||||
"associations_event2_title": "Nouvèl An Kamit",
|
||||
"associations_community_title": "Kominote & resous",
|
||||
"associations_video_title": "Dekouvri Wep Ronpet",
|
||||
|
||||
"footer_links_title": "Lyen rapid",
|
||||
"footer_resources_title": "Resous",
|
||||
"footer_next_title": "Pwochen obsèvasyon",
|
||||
"footer_copyright_prefix": "Pwojè fèt ak ❤️ pa",
|
||||
"footer_and": "ak",
|
||||
"footer_quote": "« Zetwal yo se zansèt k ap veye sou nou » — pwovèb afriken",
|
||||
"footer_rights": "Sirius Gwada. Leve je nou gade syèl la."
|
||||
}
|
||||
Generated
+2483
-772
File diff suppressed because it is too large
Load Diff
+15
-12
@@ -1,20 +1,23 @@
|
||||
{
|
||||
"name": "gwada-sirius",
|
||||
"version": "1.5.0",
|
||||
"version": "2.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"deploy": "npm run build && gh-pages -d dist"
|
||||
"messages": "paraglide-js compile --project ./project.inlang --outdir ./src/paraglide",
|
||||
"dev": "npm run messages && eleventy --serve",
|
||||
"build": "npm run messages && eleventy",
|
||||
"preview": "npx serve _site",
|
||||
"deploy": "npm run build && gh-pages -d _site"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@11ty/eleventy": "^3.1.6",
|
||||
"@11ty/eleventy-plugin-vite": "^8.0.0",
|
||||
"@fontsource-variable/fraunces": "^5.2.9",
|
||||
"@fontsource/atkinson-hyperlegible": "^5.2.8",
|
||||
"@inlang/paraglide-js": "^2.20.2",
|
||||
"@sveltejs/vite-plugin-svelte": "^7.1.4",
|
||||
"gh-pages": "^6.1.1",
|
||||
"svelte": "^4.2.7",
|
||||
"vite": "^5.0.8"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"animejs": "^3.2.1"
|
||||
"svelte": "^5.56.4",
|
||||
"vite": "^8.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://inlang.com/schema/project-settings",
|
||||
"baseLocale": "fr",
|
||||
"locales": ["fr", "en", "ht"],
|
||||
"modules": [
|
||||
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@latest/dist/index.js"
|
||||
],
|
||||
"plugin.inlang.messageFormat": {
|
||||
"pathPattern": "./messages/{locale}.json"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<circle cx="32" cy="32" r="32" fill="#141a33"/>
|
||||
<circle cx="32" cy="30" r="5" fill="#e8c766"/>
|
||||
<path d="M32 30 L26 46 L38 46 Z" fill="#e8c766" opacity="0.85"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 234 B |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Sirius en Guadeloupe — Wep Ronpet",
|
||||
"short_name": "Sirius Gwada",
|
||||
"description": "Lever héliaque de Sirius en Guadeloupe : astronomie, culture et observation.",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"background_color": "#141a33",
|
||||
"theme_color": "#141a33",
|
||||
"icons": [
|
||||
{ "src": "/favicon.svg", "sizes": "any", "type": "image/svg+xml" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// Service worker minimal : résilience réseau (3G/4G irrégulier) et usage
|
||||
// hors-ligne des pages déjà visitées. Stratégie stale-while-revalidate.
|
||||
const CACHE_NAME = "gwada-sirius-v1";
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then((keys) =>
|
||||
Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)))
|
||||
)
|
||||
);
|
||||
self.clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener("fetch", (event) => {
|
||||
if (event.request.method !== "GET") return;
|
||||
const url = new URL(event.request.url);
|
||||
if (url.origin !== self.location.origin) return;
|
||||
|
||||
event.respondWith(
|
||||
caches.open(CACHE_NAME).then(async (cache) => {
|
||||
const cached = await cache.match(event.request);
|
||||
const network = fetch(event.request)
|
||||
.then((response) => {
|
||||
if (response.ok) cache.put(event.request, response.clone());
|
||||
return response;
|
||||
})
|
||||
.catch(() => cached);
|
||||
|
||||
return cached || network;
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -1,75 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { initLanguage } from './lib/i18n.js';
|
||||
import Loader from './components/Loader.svelte';
|
||||
import Hero from './components/Hero.svelte';
|
||||
import Navigation from './components/Navigation.svelte';
|
||||
import About from './components/About.svelte';
|
||||
import Predictions from './components/Predictions.svelte';
|
||||
import Science from './components/Science.svelte';
|
||||
import Culture from './components/Culture.svelte';
|
||||
import Observatory from './components/Observatory.svelte';
|
||||
import GlobeGeoJSON from './components/GlobeGeoJSON.svelte';
|
||||
import Footer from './components/Footer.svelte';
|
||||
import Dogon from './components/Dogon.svelte';
|
||||
import Calculations from './components/Calculations.svelte';
|
||||
import ObservationMap from './components/ObservationMap.svelte';
|
||||
|
||||
let scrollY = 0;
|
||||
let activeSection = 'home';
|
||||
|
||||
onMount(() => {
|
||||
// Initialiser la langue
|
||||
initLanguage();
|
||||
|
||||
const handleScroll = () => {
|
||||
scrollY = window.scrollY;
|
||||
|
||||
// Déterminer la section active
|
||||
const sections = ['home', 'about', 'predictions', 'science', 'culture', 'observatory'];
|
||||
for (const section of sections) {
|
||||
const element = document.getElementById(section);
|
||||
if (element) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
if (rect.top <= 100 && rect.bottom >= 100) {
|
||||
activeSection = section;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
});
|
||||
</script>
|
||||
|
||||
<Loader />
|
||||
<Navigation {activeSection} />
|
||||
|
||||
<main>
|
||||
<Hero />
|
||||
<About />
|
||||
<Predictions />
|
||||
<Science />
|
||||
<Calculations />
|
||||
<Dogon />
|
||||
<Culture />
|
||||
<Observatory />
|
||||
<ObservationMap />
|
||||
<GlobeGeoJSON />
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
|
||||
<style>
|
||||
:global(body) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
main {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,7 @@
|
||||
export default [
|
||||
{ key: "nav_home", path: "/" },
|
||||
{ key: "nav_science", path: "/sirius-science/" },
|
||||
{ key: "nav_culture", path: "/culture-savoirs/" },
|
||||
{ key: "nav_observer", path: "/observer/" },
|
||||
{ key: "nav_associations", path: "/associations/" },
|
||||
];
|
||||
@@ -0,0 +1,22 @@
|
||||
import sites from "./sites.js";
|
||||
|
||||
// Prochain lever héliaque (calculé au build, à partir de Pointe des Châteaux
|
||||
// comme site de référence — les 7 sites ne divergent que de quelques minutes).
|
||||
export default function () {
|
||||
const reference = sites[0];
|
||||
const today = new Date();
|
||||
const years = Object.keys(reference.predictions)
|
||||
.map(Number)
|
||||
.sort((a, b) => a - b);
|
||||
|
||||
for (const year of years) {
|
||||
const p = reference.predictions[year];
|
||||
const when = new Date(`${p.date}T${p.time}:00`);
|
||||
if (when >= today) {
|
||||
return { ...p, year };
|
||||
}
|
||||
}
|
||||
|
||||
const lastYear = years[years.length - 1];
|
||||
return { ...reference.predictions[lastYear], year: lastYear };
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
// Sept sites d'observation du lever héliaque de Sirius en Guadeloupe.
|
||||
//
|
||||
// Dates interpolées à partir des tables d'Arcus Visionis de Jean Meeus, recoupées
|
||||
// avec les calculs de Jeffrey L. Hunt (whenthecurveslineup.com) : à 16°N, la
|
||||
// heliacal rising tombe autour du 22 juillet (~24 juillet à 20°N, ~17 juillet à
|
||||
// 10°N). Les petits écarts entre sites reflètent la longitude et l'altitude de
|
||||
// l'horizon Est. Ce sont des estimations de modèle — la date réellement observée
|
||||
// dépend toujours de la météo et de la clarté de l'horizon.
|
||||
export default [
|
||||
{
|
||||
id: "pointe-des-chateaux",
|
||||
name: "Pointe des Châteaux",
|
||||
lat: 16.2476,
|
||||
lon: -61.1771,
|
||||
alt: 30,
|
||||
description_fr:
|
||||
"Point de vue élevé avec panorama dégagé vers l'Est sur l'Atlantique.",
|
||||
description_en:
|
||||
"Elevated viewpoint with a clear panorama east over the Atlantic.",
|
||||
predictions: {
|
||||
2025: { date: "2025-07-22", time: "05:12" },
|
||||
2026: { date: "2026-07-22", time: "05:12" },
|
||||
2027: { date: "2027-07-22", time: "05:13" },
|
||||
2028: { date: "2028-07-21", time: "05:13" },
|
||||
2029: { date: "2029-07-22", time: "05:14" },
|
||||
2030: { date: "2030-07-22", time: "05:14" },
|
||||
2031: { date: "2031-07-22", time: "05:15" },
|
||||
2032: { date: "2032-07-21", time: "05:15" },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "grande-vigie",
|
||||
name: "Pointe de la Grande Vigie",
|
||||
lat: 16.5098,
|
||||
lon: -61.4666,
|
||||
alt: 81,
|
||||
description_fr:
|
||||
"Point le plus septentrional de la Guadeloupe, horizon marin parfait.",
|
||||
description_en:
|
||||
"Guadeloupe's northernmost point, with a perfect sea horizon.",
|
||||
predictions: {
|
||||
2025: { date: "2025-07-22", time: "05:11" },
|
||||
2026: { date: "2026-07-22", time: "05:12" },
|
||||
2027: { date: "2027-07-22", time: "05:12" },
|
||||
2028: { date: "2028-07-21", time: "05:12" },
|
||||
2029: { date: "2029-07-22", time: "05:13" },
|
||||
2030: { date: "2030-07-22", time: "05:13" },
|
||||
2031: { date: "2031-07-22", time: "05:14" },
|
||||
2032: { date: "2032-07-21", time: "05:14" },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "duzer",
|
||||
name: "Duzer (Sainte-Rose)",
|
||||
lat: 16.3361,
|
||||
lon: -61.743,
|
||||
alt: 20,
|
||||
description_fr:
|
||||
"Site nécessitant un point dégagé vers l'Est sur les mornes.",
|
||||
description_en: "Requires a clear vantage point east over the hills.",
|
||||
predictions: {
|
||||
2025: { date: "2025-07-22", time: "05:13" },
|
||||
2026: { date: "2026-07-22", time: "05:14" },
|
||||
2027: { date: "2027-07-22", time: "05:14" },
|
||||
2028: { date: "2028-07-21", time: "05:14" },
|
||||
2029: { date: "2029-07-22", time: "05:15" },
|
||||
2030: { date: "2030-07-22", time: "05:15" },
|
||||
2031: { date: "2031-07-22", time: "05:16" },
|
||||
2032: { date: "2032-07-21", time: "05:16" },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "saint-felix",
|
||||
name: "Saint-Félix (Le Gosier)",
|
||||
lat: 16.2005,
|
||||
lon: -61.4605,
|
||||
alt: 5,
|
||||
description_fr: "Plage avec observation au niveau de la mer.",
|
||||
description_en: "Beach with sea-level observation.",
|
||||
predictions: {
|
||||
2025: { date: "2025-07-22", time: "05:13" },
|
||||
2026: { date: "2026-07-22", time: "05:13" },
|
||||
2027: { date: "2027-07-22", time: "05:14" },
|
||||
2028: { date: "2028-07-21", time: "05:14" },
|
||||
2029: { date: "2029-07-22", time: "05:15" },
|
||||
2030: { date: "2030-07-22", time: "05:15" },
|
||||
2031: { date: "2031-07-22", time: "05:16" },
|
||||
2032: { date: "2032-07-21", time: "05:16" },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "grande-pointe",
|
||||
name: "Grande Pointe (Trois-Rivières)",
|
||||
lat: 15.9696,
|
||||
lon: -61.6308,
|
||||
alt: 42,
|
||||
description_fr:
|
||||
"Site côtier avec une altitude intéressante pour l'observation.",
|
||||
description_en: "Coastal site with a useful elevation for observation.",
|
||||
predictions: {
|
||||
2025: { date: "2025-07-22", time: "05:13" },
|
||||
2026: { date: "2026-07-22", time: "05:14" },
|
||||
2027: { date: "2027-07-22", time: "05:14" },
|
||||
2028: { date: "2028-07-21", time: "05:15" },
|
||||
2029: { date: "2029-07-22", time: "05:15" },
|
||||
2030: { date: "2030-07-22", time: "05:16" },
|
||||
2031: { date: "2031-07-22", time: "05:16" },
|
||||
2032: { date: "2032-07-21", time: "05:17" },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "petit-perou",
|
||||
name: "Petit-Pérou",
|
||||
lat: 16.0517,
|
||||
lon: -61.5567,
|
||||
alt: 10,
|
||||
description_fr:
|
||||
"Site des roches gravées, observation depuis la côte.",
|
||||
description_en: "Site of the engraved rocks, observed from the coast.",
|
||||
predictions: {
|
||||
2025: { date: "2025-07-22", time: "05:14" },
|
||||
2026: { date: "2026-07-22", time: "05:14" },
|
||||
2027: { date: "2027-07-22", time: "05:15" },
|
||||
2028: { date: "2028-07-21", time: "05:15" },
|
||||
2029: { date: "2029-07-22", time: "05:16" },
|
||||
2030: { date: "2030-07-22", time: "05:16" },
|
||||
2031: { date: "2031-07-22", time: "05:17" },
|
||||
2032: { date: "2032-07-21", time: "05:17" },
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "vieux-fort",
|
||||
name: "Pointe du Vieux-Fort",
|
||||
lat: 15.9483,
|
||||
lon: -61.7072,
|
||||
alt: 20,
|
||||
description_fr:
|
||||
"Point le plus méridional de Basse-Terre, vue sur le canal des Saintes.",
|
||||
description_en:
|
||||
"Basse-Terre's southernmost point, overlooking the Saintes channel.",
|
||||
predictions: {
|
||||
2025: { date: "2025-07-22", time: "05:14" },
|
||||
2026: { date: "2026-07-22", time: "05:14" },
|
||||
2027: { date: "2027-07-22", time: "05:15" },
|
||||
2028: { date: "2028-07-21", time: "05:15" },
|
||||
2029: { date: "2029-07-22", time: "05:16" },
|
||||
2030: { date: "2030-07-22", time: "05:16" },
|
||||
2031: { date: "2031-07-22", time: "05:17" },
|
||||
2032: { date: "2032-07-21", time: "05:17" },
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,36 @@
|
||||
<!doctype html>
|
||||
<html lang="{{ locale }}" data-theme="oki">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{ pageTitle }} — {{ "meta_title" | t(locale) }}</title>
|
||||
<meta name="description" content="{{ 'meta_description' | t(locale) }}">
|
||||
<link vite-ignore rel="icon" href="/favicon.svg" type="image/svg+xml">
|
||||
<link vite-ignore rel="manifest" href="/manifest.webmanifest">
|
||||
|
||||
{% for loc in locales %}
|
||||
<link vite-ignore rel="alternate" hreflang="{{ loc }}" href="{{ slug | localeHref(loc) }}">
|
||||
{% endfor %}
|
||||
|
||||
<link vite-ignore rel="preload" href="/assets/fonts/fraunces-variable.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link vite-ignore rel="preload" href="/assets/fonts/atkinson-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="stylesheet" href="/src/styles/app.css">
|
||||
</head>
|
||||
<body>
|
||||
<a class="skip-link" href="#main-content">{{ "skip_to_content" | t(locale) }}</a>
|
||||
|
||||
{% include "partials/nav.njk" %}
|
||||
|
||||
<main id="main-content">
|
||||
{{ content | safe }}
|
||||
</main>
|
||||
|
||||
{% include "partials/footer.njk" %}
|
||||
|
||||
<script>
|
||||
if ("serviceWorker" in navigator) {
|
||||
window.addEventListener("load", () => navigator.serviceWorker.register("/sw.js"));
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,49 @@
|
||||
<footer class="site-footer">
|
||||
<div class="container footer-grid">
|
||||
<div class="footer-section">
|
||||
<h2>Sirius Gwada</h2>
|
||||
<p>{{ "footer_tagline" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h3>{{ "footer_links_title" | t(locale) }}</h3>
|
||||
<ul>
|
||||
{% for item in nav %}
|
||||
<li><a href="{{ item.path | localeHref(locale) }}">{{ item.key | t(locale) }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h3>{{ "footer_resources_title" | t(locale) }}</h3>
|
||||
<ul>
|
||||
<li><a href="https://stellarium.org" target="_blank" rel="noopener">{{ "footer_resources_stellarium" | t(locale) }}</a></li>
|
||||
<li><a href="{{ '/observer/' | localeHref(locale) }}">{{ "footer_resources_guide" | t(locale) }}</a></li>
|
||||
<li><a href="{{ '/sirius-science/' | localeHref(locale) }}">{{ "footer_resources_references" | t(locale) }}</a></li>
|
||||
<li><a href="mailto:contact@o-k-i.net">{{ "footer_resources_contact" | t(locale) }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h3>{{ "footer_next_title" | t(locale) }}</h3>
|
||||
<div class="countdown">
|
||||
<div class="countdown-item">
|
||||
<span class="countdown-value">{{ nextRising.date | formatDate(locale, { day: "numeric", month: "long" }) }}</span>
|
||||
<span class="countdown-label">{{ nextRising.time }} · {{ nextRising.year }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container footer-bottom">
|
||||
<p class="pattern-strip kente" aria-hidden="true"></p>
|
||||
<p>© {{ currentYear }} {{ "footer_rights" | t(locale) }}</p>
|
||||
<p class="footer-credits">
|
||||
{{ "footer_copyright_prefix" | t(locale) }}
|
||||
<a href="https://github.com/cyber-mawonaj" target="_blank" rel="noopener">cyber-mawonaj</a>
|
||||
{{ "footer_and" | t(locale) }}
|
||||
<a href="https://o-k-i.net" target="_blank" rel="noopener">OKI</a>
|
||||
</p>
|
||||
<p class="footer-quote">{{ "footer_quote" | t(locale) }}</p>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,36 @@
|
||||
<header class="nav">
|
||||
<div class="container nav-inner">
|
||||
<a class="nav-brand" href="{{ '' | localeHref(locale) }}">
|
||||
<span aria-hidden="true">☥</span> Sirius Gwada
|
||||
</a>
|
||||
|
||||
<details class="nav-disclosure">
|
||||
<summary class="nav-toggle">
|
||||
<span class="visually-hidden">Menu</span>
|
||||
<span aria-hidden="true" class="nav-toggle-icon"></span>
|
||||
</summary>
|
||||
<ul class="nav-menu">
|
||||
{% for item in nav %}
|
||||
<li>
|
||||
<a href="{{ item.path | localeHref(locale) }}"
|
||||
{% if pageKey == item.key %}aria-current="page"{% endif %}>
|
||||
{{ item.key | t(locale) }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<ul class="nav-lang">
|
||||
{% for loc in locales %}
|
||||
<li>
|
||||
<a href="{{ slug | localeHref(loc) }}"
|
||||
lang="{{ loc }}"
|
||||
{% if loc == locale %}aria-current="true" class="active"{% endif %}>
|
||||
{{ ("lang_name_" + loc) | t(locale) }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
-217
@@ -1,217 +0,0 @@
|
||||
/* Variables CSS pour le thème panafricain/caribéen */
|
||||
:root {
|
||||
/* Couleurs principales inspirées du panafricanisme et des Caraïbes */
|
||||
--color-primary: #FFD700; /* Or - Soleil, Sirius */
|
||||
--color-secondary: #DC143C; /* Rouge profond */
|
||||
--color-tertiary: #228B22; /* Vert forêt */
|
||||
--color-dark: #1a1a2e; /* Bleu nuit profond */
|
||||
--color-light: #f5f5dc; /* Beige clair */
|
||||
--color-accent: #FF6B35; /* Orange corail caribéen */
|
||||
|
||||
/* Dégradés */
|
||||
--gradient-dawn: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||||
--gradient-sunrise: linear-gradient(135deg, #FFD700 0%, #FFA500 50%, #FF6B35 100%);
|
||||
--gradient-caribbean: linear-gradient(135deg, #00CED1 0%, #20B2AA 50%, #48D1CC 100%);
|
||||
|
||||
/* Typographie */
|
||||
--font-display: 'Bebas Neue', sans-serif;
|
||||
--font-heading: 'Playfair Display', serif;
|
||||
--font-body: 'Inter', sans-serif;
|
||||
|
||||
/* Espacements */
|
||||
--spacing-xs: 0.5rem;
|
||||
--spacing-sm: 1rem;
|
||||
--spacing-md: 2rem;
|
||||
--spacing-lg: 3rem;
|
||||
--spacing-xl: 4rem;
|
||||
|
||||
/* Animations */
|
||||
--transition-base: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--transition-slow: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
/* Reset et base */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-body);
|
||||
background-color: var(--color-dark);
|
||||
color: var(--color-light);
|
||||
overflow-x: hidden;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Patterns géométriques africains en CSS */
|
||||
.pattern-kente {
|
||||
background-image:
|
||||
repeating-linear-gradient(45deg, transparent, transparent 10px, rgba(255, 215, 0, 0.1) 10px, rgba(255, 215, 0, 0.1) 20px),
|
||||
repeating-linear-gradient(-45deg, transparent, transparent 10px, rgba(220, 20, 60, 0.1) 10px, rgba(220, 20, 60, 0.1) 20px);
|
||||
}
|
||||
|
||||
.pattern-bogolan {
|
||||
background-image:
|
||||
radial-gradient(circle at 20% 50%, transparent 30%, rgba(255, 215, 0, 0.05) 30%, rgba(255, 215, 0, 0.05) 32%, transparent 32%),
|
||||
radial-gradient(circle at 60% 50%, transparent 30%, rgba(255, 215, 0, 0.05) 30%, rgba(255, 215, 0, 0.05) 32%, transparent 32%),
|
||||
radial-gradient(circle at 40% 80%, transparent 30%, rgba(255, 215, 0, 0.05) 30%, rgba(255, 215, 0, 0.05) 32%, transparent 32%);
|
||||
background-size: 50px 50px;
|
||||
}
|
||||
|
||||
.pattern-adinkra {
|
||||
background-image:
|
||||
repeating-conic-gradient(from 45deg at 50% 50%, transparent 0deg, rgba(255, 215, 0, 0.1) 90deg, transparent 90deg, transparent 180deg),
|
||||
repeating-conic-gradient(from 0deg at 50% 50%, transparent 0deg, rgba(34, 139, 34, 0.1) 90deg, transparent 90deg, transparent 180deg);
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
|
||||
/* Utilités */
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 var(--spacing-sm);
|
||||
}
|
||||
|
||||
/* Typographie */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-heading);
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
margin-bottom: var(--spacing-sm);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: clamp(2.5rem, 8vw, 4rem);
|
||||
background: var(--gradient-sunrise);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: clamp(2rem, 6vw, 3rem);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: clamp(1.5rem, 4vw, 2rem);
|
||||
}
|
||||
|
||||
/* Boutons */
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
background: var(--gradient-sunrise);
|
||||
color: var(--color-dark);
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
border-radius: 50px;
|
||||
font-weight: 600;
|
||||
font-family: var(--font-body);
|
||||
cursor: pointer;
|
||||
transition: var(--transition-base);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 30px rgba(255, 215, 0, 0.3);
|
||||
}
|
||||
|
||||
.btn::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.6s, height 0.6s;
|
||||
}
|
||||
|
||||
.btn:active::before {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 215, 0, 0.2);
|
||||
border-radius: 20px;
|
||||
padding: var(--spacing-md);
|
||||
transition: var(--transition-base);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-5px);
|
||||
border-color: rgba(255, 215, 0, 0.5);
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-20px); }
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
0%, 100% { opacity: 0.5; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.float {
|
||||
animation: float 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.glow {
|
||||
animation: glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 0 var(--spacing-xs);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scrollbar personnalisée */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--color-dark);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--gradient-sunrise);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--color-primary);
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,79 @@
|
||||
---
|
||||
pagination:
|
||||
data: locales
|
||||
size: 1
|
||||
alias: locale
|
||||
permalink: "{% if locale == baseLocale %}/associations/index.html{% else %}/{{ locale }}/associations/index.html{% endif %}"
|
||||
layout: layouts/base.njk
|
||||
pageKey: associations
|
||||
slug: "associations/"
|
||||
eleventyComputed:
|
||||
pageTitle: "{{ 'associations_title' | t(locale) }}"
|
||||
---
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="section-header center">
|
||||
<p class="section-eyebrow">Wep Ronpet</p>
|
||||
<h1>{{ "associations_title" | t(locale) }}</h1>
|
||||
<p class="pattern-strip bogolan" aria-hidden="true" style="margin-inline:auto"></p>
|
||||
<p class="section-subtitle">{{ "associations_subtitle" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid-auto">
|
||||
<div class="card">
|
||||
<h2>{{ "associations_events_title" | t(locale) }}</h2>
|
||||
<div class="stack" style="--stack-space: 0">
|
||||
<a class="event-link" href="https://my.weezevent.com/nouvel-an-kamite" target="_blank" rel="noopener noreferrer">
|
||||
<span class="event-icon" aria-hidden="true">🎊</span>
|
||||
<span class="event-info">
|
||||
<span class="event-title">{{ "associations_event1_title" | t(locale) }}</span>
|
||||
<span class="event-platform">{{ "associations_event1_organizer" | t(locale) }}</span>
|
||||
<span>{{ "associations_event1_desc" | t(locale) }}</span>
|
||||
</span>
|
||||
</a>
|
||||
<a class="event-link" href="https://my.weezevent.com/nouvel-an-kamit" target="_blank" rel="noopener noreferrer">
|
||||
<span class="event-icon" aria-hidden="true">✨</span>
|
||||
<span class="event-info">
|
||||
<span class="event-title">{{ "associations_event2_title" | t(locale) }}</span>
|
||||
<span class="event-platform">{{ "associations_event2_organizer" | t(locale) }}</span>
|
||||
<span>{{ "associations_event2_desc" | t(locale) }}</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>{{ "associations_community_title" | t(locale) }}</h2>
|
||||
<div class="stack" style="--stack-space: 0">
|
||||
<a class="community-link" href="https://14eme-membre.net/site-web/#événements" target="_blank" rel="noopener noreferrer">
|
||||
<span class="community-icon" aria-hidden="true">🌍</span>
|
||||
<span class="community-info">
|
||||
<span class="community-title">{{ "associations_link1_title" | t(locale) }}</span>
|
||||
<span>{{ "associations_link1_desc" | t(locale) }}</span>
|
||||
</span>
|
||||
</a>
|
||||
<a class="community-link" href="https://www.facebook.com/people/Mouvement-Politique-Spirituel-MUN" target="_blank" rel="noopener noreferrer">
|
||||
<span class="community-icon" aria-hidden="true">📘</span>
|
||||
<span class="community-info">
|
||||
<span class="community-title">{{ "associations_link2_title" | t(locale) }}</span>
|
||||
<span>{{ "associations_link2_desc" | t(locale) }}</span>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="center" style="margin-top: var(--space-7)">{{ "associations_video_title" | t(locale) }}</h2>
|
||||
<div class="video-frame card" style="margin-top: var(--space-4)">
|
||||
<iframe
|
||||
src="https://www.youtube.com/embed/0_8kWlDTf94"
|
||||
title="{{ 'associations_video_title' | t(locale) }}"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
loading="lazy"
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
<p class="associations-note center">{{ "associations_note" | t(locale) }}</p>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,185 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from '../lib/i18n.js';
|
||||
|
||||
let visible = false;
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
visible = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('about');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
const features = [
|
||||
{
|
||||
icon: '🌟',
|
||||
title: 'L\'Étoile la Plus Brillante',
|
||||
description: 'Sirius brille avec une magnitude de -1.46, dominant notre ciel nocturne.'
|
||||
},
|
||||
{
|
||||
icon: '🌅',
|
||||
title: 'Le Lever Héliaque',
|
||||
description: 'Sa première apparition à l\'aube après 70 jours d\'invisibilité marque un événement cosmique.'
|
||||
},
|
||||
{
|
||||
icon: '🗿',
|
||||
title: 'Héritage Ancestral',
|
||||
description: 'De l\'Égypte ancienne aux Dogons du Mali, Sirius guide l\'humanité depuis des millénaires.'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<section id="about" class="about">
|
||||
<div class="pattern-kente"></div>
|
||||
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Sirius et Wep Ronpet</h2>
|
||||
<p class="section-subtitle">
|
||||
L'Ouverture de l'Année - Le Nouvel An Cosmique des Anciens Égyptiens
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="about-content" class:visible>
|
||||
<div class="about-text">
|
||||
<p>
|
||||
<strong>Wep Ronpet</strong> - "l'Ouverture de l'Année" en égyptien ancien -
|
||||
marquait le jour le plus sacré du calendrier égyptien. Ce jour correspondait
|
||||
au lever héliaque de Sirius, quand l'étoile réapparaissait à l'aube après
|
||||
70 jours d'invisibilité.
|
||||
</p>
|
||||
<p>
|
||||
Le lever héliaque de Sirius n'est pas qu'un simple phénomène astronomique.
|
||||
C'est un rendez-vous millénaire entre l'humanité et le cosmos, un moment où
|
||||
science et spiritualité se rencontrent dans la lumière de l'aube.
|
||||
</p>
|
||||
<p>
|
||||
En Guadeloupe, observer ce phénomène nous connecte directement aux racines
|
||||
africaines, où Sirius était vénérée comme l'annonciatrice de la vie et du renouveau.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="features-grid">
|
||||
{#each features as feature, i}
|
||||
<div class="feature-card card" style="animation-delay: {i * 0.2}s">
|
||||
<div class="feature-icon">{feature.icon}</div>
|
||||
<h3>{$t(feature.title)}</h3>
|
||||
<p>{$t(feature.description)}</p>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.about {
|
||||
position: relative;
|
||||
padding: var(--spacing-xl) 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pattern-kente {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.05;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out;
|
||||
}
|
||||
|
||||
.section-header.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 1.5rem;
|
||||
color: var(--color-primary);
|
||||
font-family: var(--font-heading);
|
||||
}
|
||||
|
||||
.about-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.3s;
|
||||
}
|
||||
|
||||
.about-content.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.about-text {
|
||||
max-width: 800px;
|
||||
margin: 0 auto var(--spacing-lg);
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.about-text p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.features-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: var(--spacing-md);
|
||||
margin-top: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.feature-card {
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
animation: fadeInUp 0.8s ease-out forwards;
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
filter: drop-shadow(0 0 20px rgba(255, 215, 0, 0.5));
|
||||
}
|
||||
|
||||
.feature-card h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.features-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,230 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let visible = false;
|
||||
let selectedCalculation = 'heliacal';
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
visible = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('calculations');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
const calculations = {
|
||||
heliacal: {
|
||||
title: 'Lever Héliaque',
|
||||
description: 'Calcul de la première visibilité de Sirius avant l\'aube'
|
||||
},
|
||||
arcus: {
|
||||
title: 'Arcus Visionis',
|
||||
description: 'Angle minimal entre le Soleil et Sirius pour la visibilité'
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<section id="calculations" class="calculations-section">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Calculs Astronomiques</h2>
|
||||
<p class="section-subtitle">
|
||||
La science précise derrière le lever héliaque
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="calculations-wrapper" class:visible>
|
||||
<!-- Sélecteur de calcul -->
|
||||
<div class="calc-selector">
|
||||
{#each Object.entries(calculations) as [key, calc]}
|
||||
<button
|
||||
class="calc-btn"
|
||||
class:active={selectedCalculation === key}
|
||||
on:click={() => selectedCalculation = key}
|
||||
>
|
||||
<h4>{calc.title}</h4>
|
||||
<p>{calc.description}</p>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- Contenu des calculs -->
|
||||
<div class="calc-content">
|
||||
{#if selectedCalculation === 'heliacal'}
|
||||
<div class="calc-panel">
|
||||
<h3>Calcul du Lever Héliaque de Sirius</h3>
|
||||
<div class="formula-box">
|
||||
<h4>Formule Principale</h4>
|
||||
<div class="formula">
|
||||
<p><strong>Date du lever héliaque = </strong></p>
|
||||
<p>Date de conjonction + Arcus Visionis / Vitesse angulaire du Soleil</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="calculation-steps">
|
||||
<h4>Étapes du Calcul pour la Guadeloupe</h4>
|
||||
|
||||
<div class="step">
|
||||
<div class="step-number">1</div>
|
||||
<div class="step-content">
|
||||
<h5>Coordonnées de la Guadeloupe</h5>
|
||||
<code>Latitude: 16.25°N, Longitude: 61.58°O</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="step">
|
||||
<div class="step-number">2</div>
|
||||
<div class="step-content">
|
||||
<h5>Position de Sirius</h5>
|
||||
<code>Ascension droite: 6h 45m 09s</code>
|
||||
<code>Déclinaison: -16° 42' 58"</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> {/if}
|
||||
|
||||
{#if selectedCalculation === 'arcus'}
|
||||
<div class="calc-panel">
|
||||
<h3>Arcus Visionis - L'Arc de Vision</h3>
|
||||
|
||||
<div class="explanation">
|
||||
<p>
|
||||
L'Arcus Visionis est l'angle minimal entre le Soleil et une étoile
|
||||
pour que celle-ci devienne visible.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.calculations-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-dawn);
|
||||
}
|
||||
|
||||
.calculations-wrapper {
|
||||
margin-top: var(--spacing-lg);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out;
|
||||
}
|
||||
.calculations-wrapper.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.calc-selector {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.calc-btn {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.calc-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: var(--color-primary);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.calc-btn.active {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
.calc-btn h4 {
|
||||
color: var(--color-primary);
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.calc-btn p {
|
||||
color: var(--color-light);
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.calc-panel {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.formula-box {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.formula {
|
||||
font-family: 'Courier New', monospace;
|
||||
color: var(--color-light);
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.calculation-steps {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.step {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.step-number {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-dark);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.step-content h5 {
|
||||
color: var(--color-secondary);
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.step-content code {
|
||||
display: block;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 8px;
|
||||
margin: 0.25rem 0;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.calc-selector {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.calc-panel {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,252 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let visible = false;
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
visible = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('culture');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
const cultures = [
|
||||
{
|
||||
id: 'egypt',
|
||||
title: 'Égypte : Sothis, la Déesse du Nil',
|
||||
icon: '🏺',
|
||||
content: `Pour les anciens Égyptiens, le lever héliaque de Sirius (Sothis)
|
||||
était l'événement le plus important de l'année. Il annonçait la crue du Nil,
|
||||
source de vie et de fertilité. Ce "retour" de l'étoile marquait le Nouvel An
|
||||
et symbolisait la renaissance, associée à la déesse Isis.`
|
||||
},
|
||||
{
|
||||
id: 'dogon',
|
||||
title: 'Dogon : Les Gardiens du Savoir Stellaire',
|
||||
icon: '🌍',
|
||||
content: `Le peuple Dogon du Mali possède un savoir stupéfiant sur Sirius.
|
||||
Ils connaissaient l'existence de Sirius B, une naine blanche invisible à l'œil nu,
|
||||
bien avant sa découverte scientifique. Leur cycle rituel de 60 ans, le Sigui,
|
||||
est directement lié à leur compréhension du système de Sirius.`
|
||||
},
|
||||
{
|
||||
id: 'caribbean',
|
||||
title: 'Caraïbes : La Navigation Stellaire',
|
||||
icon: '⛵',
|
||||
content: `Dans les Caraïbes, Sirius a guidé les navigateurs depuis des siècles.
|
||||
Les peuples autochtones et les marins africains utilisaient son lever pour
|
||||
marquer les saisons et naviguer entre les îles. Aujourd'hui encore, elle reste
|
||||
un repère fondamental pour les pêcheurs traditionnels.`
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<section id="culture" class="culture">
|
||||
<div class="pattern-adinkra"></div>
|
||||
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Sirius, Miroir des Cultures</h2>
|
||||
<p class="section-subtitle">
|
||||
Un héritage millénaire qui unit l'Afrique et les Caraïbes
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="cultures-grid" class:visible>
|
||||
{#each cultures as culture, i}
|
||||
<div class="culture-card card" style="animation-delay: {i * 0.2}s">
|
||||
<div class="culture-icon">{culture.icon}</div>
|
||||
<h3>{culture.title}</h3>
|
||||
<p>{culture.content}</p>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="timeline" class:visible>
|
||||
<h3>Chronologie du Savoir</h3>
|
||||
<div class="timeline-items">
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-date">3000 BCE</div>
|
||||
<div class="timeline-content">
|
||||
<h4>Égypte Ancienne</h4>
|
||||
<p>Premier calendrier basé sur Sirius</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-date">XIIIe siècle</div>
|
||||
<div class="timeline-content">
|
||||
<h4>Migration Dogon</h4>
|
||||
<p>Préservation du savoir astronomique</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-date">XVe-XVIIe siècle</div>
|
||||
<div class="timeline-content">
|
||||
<h4>Traversée Atlantique</h4>
|
||||
<p>Le savoir africain voyage vers les Caraïbes</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-date">2025</div>
|
||||
<div class="timeline-content">
|
||||
<h4>Renaissance</h4>
|
||||
<p>Redécouverte et célébration en Guadeloupe</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.culture {
|
||||
position: relative;
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-dawn);
|
||||
}
|
||||
|
||||
.pattern-adinkra {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.cultures-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: var(--spacing-md);
|
||||
margin-bottom: var(--spacing-xl);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.3s;
|
||||
}
|
||||
|
||||
.cultures-grid.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.culture-card {
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
animation: fadeInUp 0.8s ease-out forwards;
|
||||
}
|
||||
|
||||
.culture-icon {
|
||||
font-size: 4rem;
|
||||
margin-bottom: 1rem;
|
||||
filter: drop-shadow(0 0 20px rgba(255, 215, 0, 0.5));
|
||||
}
|
||||
|
||||
.culture-card h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
position: relative;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.6s;
|
||||
}
|
||||
|
||||
.timeline.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.timeline h3 {
|
||||
text-align: center;
|
||||
color: var(--color-primary);
|
||||
font-size: 2rem;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.timeline-items {
|
||||
position: relative;
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
.timeline-items::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background: var(--gradient-sunrise);
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
position: relative;
|
||||
margin-bottom: var(--spacing-md);
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.timeline-item::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -34px;
|
||||
top: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: var(--color-primary);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 20px rgba(255, 215, 0, 0.5);
|
||||
}
|
||||
|
||||
.timeline-date {
|
||||
font-weight: 600;
|
||||
color: var(--color-primary);
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.timeline-content h4 {
|
||||
color: var(--color-light);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.timeline-content p {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.timeline-items {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.timeline-item::before {
|
||||
left: -24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,587 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let visible = false;
|
||||
let activeTab = 'cosmogonie';
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
visible = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('dogon');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
const tabs = [
|
||||
{ id: 'cosmogonie', label: 'Cosmogonie', icon: '🌌' },
|
||||
{ id: 'sirius', label: 'Système de Sirius', icon: '⭐' },
|
||||
{ id: 'astronomie', label: 'Astronomie Dogon', icon: '🔭' },
|
||||
{ id: 'heritage', label: 'Héritage', icon: '🌍' }
|
||||
];
|
||||
</script>
|
||||
|
||||
<section id="dogon" class="dogon-section">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Les Dogons et Sirius</h2>
|
||||
<p class="section-subtitle">
|
||||
Une connaissance astronomique millénaire
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="content-wrapper" class:visible>
|
||||
<!-- Navigation par onglets -->
|
||||
<div class="tabs-nav">
|
||||
{#each tabs as tab}
|
||||
<button
|
||||
class="tab-btn"
|
||||
class:active={activeTab === tab.id}
|
||||
on:click={() => activeTab = tab.id}
|
||||
>
|
||||
<span class="tab-icon">{tab.icon}</span>
|
||||
<span class="tab-label">{tab.label}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- Contenu des onglets -->
|
||||
<div class="tabs-content">
|
||||
{#if activeTab === 'cosmogonie'}
|
||||
<div class="tab-panel">
|
||||
<h3>La Cosmogonie Dogon</h3>
|
||||
<div class="content-grid">
|
||||
<div class="content-text">
|
||||
<p>
|
||||
Les Dogons du Mali possèdent une cosmogonie complexe centrée sur <strong>Sigu Tolo</strong> (Sirius),
|
||||
l'étoile la plus brillante du ciel. Leur savoir astronomique, transmis oralement depuis des millénaires,
|
||||
révèle une compréhension sophistiquée du cosmos.
|
||||
</p>
|
||||
<p>
|
||||
Le <strong>Sigui</strong>, cérémonie célébrée tous les 60 ans, marque le renouvellement du monde
|
||||
et commémore la révélation de la parole aux hommes. Cette périodicité correspond étrangement
|
||||
à l'orbite de Sirius B autour de Sirius A (50 ans), ajustée par des considérations rituelles.
|
||||
</p>
|
||||
<div class="highlight-box">
|
||||
<h4>Le Nommo</h4>
|
||||
<p>
|
||||
Être primordial amphibie venu de Sirius, le Nommo apporta la civilisation
|
||||
et les connaissances fondamentales aux ancêtres des Dogons.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-visual">
|
||||
<div class="cosmogony-diagram">
|
||||
<svg viewBox="0 0 400 400" class="diagram-svg">
|
||||
<!-- Amma (Dieu créateur) au centre -->
|
||||
<circle cx="200" cy="200" r="30" fill="var(--color-primary)" opacity="0.8"/>
|
||||
<text x="200" y="205" text-anchor="middle" fill="white" font-weight="bold">Amma</text>
|
||||
|
||||
<!-- Oeuf cosmique -->
|
||||
<ellipse cx="200" cy="200" rx="150" ry="100" fill="none" stroke="var(--color-secondary)" stroke-width="2" stroke-dasharray="5,5" opacity="0.6"/>
|
||||
|
||||
<!-- Les 4 éléments -->
|
||||
<g class="elements">
|
||||
<circle cx="200" cy="100" r="25" fill="var(--color-accent)"/>
|
||||
<text x="200" y="105" text-anchor="middle" fill="white" font-size="12">Eau</text>
|
||||
|
||||
<circle cx="300" cy="200" r="25" fill="#FF6B35"/>
|
||||
<text x="300" y="205" text-anchor="middle" fill="white" font-size="12">Feu</text>
|
||||
|
||||
<circle cx="200" cy="300" r="25" fill="#4CAF50"/>
|
||||
<text x="200" y="305" text-anchor="middle" fill="white" font-size="12">Terre</text>
|
||||
|
||||
<circle cx="100" cy="200" r="25" fill="#87CEEB"/>
|
||||
<text x="100" y="205" text-anchor="middle" fill="white" font-size="12">Air</text>
|
||||
</g>
|
||||
|
||||
<!-- Lignes de connexion -->
|
||||
<line x1="200" y1="230" x2="200" y2="275" stroke="var(--color-light)" stroke-width="1" opacity="0.5"/>
|
||||
<line x1="225" y1="200" x2="275" y2="200" stroke="var(--color-light)" stroke-width="1" opacity="0.5"/>
|
||||
<line x1="200" y1="175" x2="200" y2="125" stroke="var(--color-light)" stroke-width="1" opacity="0.5"/>
|
||||
<line x1="175" y1="200" x2="125" y2="200" stroke="var(--color-light)" stroke-width="1" opacity="0.5"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if activeTab === 'sirius'}
|
||||
<div class="tab-panel">
|
||||
<h3>Le Système de Sirius selon les Dogons</h3>
|
||||
<div class="sirius-system">
|
||||
<div class="star-info">
|
||||
<h4>Sigu Tolo (Sirius A)</h4>
|
||||
<p>L'étoile principale, source de lumière et de vie</p>
|
||||
<ul>
|
||||
<li>Associée à la féminité et à la fécondité</li>
|
||||
<li>Guide des saisons et des récoltes</li>
|
||||
<li>Centre du système stellaire</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="star-info">
|
||||
<h4>Po Tolo (Sirius B)</h4>
|
||||
<p>L'étoile compagne invisible à l'œil nu</p>
|
||||
<ul>
|
||||
<li>Décrite comme "lourde" et "blanche"</li>
|
||||
<li>Orbite de 50 ans autour de Sirius A</li>
|
||||
<li>Découverte par les astronomes occidentaux en 1862</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="star-info">
|
||||
<h4>Emme Ya Tolo (Sirius C ?)</h4>
|
||||
<p>Troisième étoile hypothétique du système</p>
|
||||
<ul>
|
||||
<li>Quatre fois plus légère que Po Tolo</li>
|
||||
<li>Orbite plus large</li>
|
||||
<li>Non confirmée par l'astronomie moderne</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="knowledge-mystery">
|
||||
<h4>Le Mystère de la Connaissance</h4>
|
||||
<p>
|
||||
Comment les Dogons connaissaient-ils l'existence de Sirius B,
|
||||
invisible à l'œil nu et découverte en Occident seulement en 1862 ?
|
||||
</p>
|
||||
<div class="theories">
|
||||
<div class="theory-card">
|
||||
<h5>Transmission Ancienne</h5>
|
||||
<p>Héritage d'une civilisation antérieure avancée</p>
|
||||
</div>
|
||||
<div class="theory-card">
|
||||
<h5>Contact Extraterrestre</h5>
|
||||
<p>Les Nommos venus de Sirius</p>
|
||||
</div>
|
||||
<div class="theory-card">
|
||||
<h5>Observation Minutieuse</h5>
|
||||
<p>Déduction à partir des perturbations de Sirius A</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if activeTab === 'astronomie'}
|
||||
<div class="tab-panel">
|
||||
<h3>L'Astronomie Dogon</h3>
|
||||
<div class="astronomy-content">
|
||||
<div class="concept-grid">
|
||||
<div class="concept-card">
|
||||
<h4>📐 Géométrie Sacrée</h4>
|
||||
<p>
|
||||
Les Dogons utilisent des figures géométriques complexes pour
|
||||
représenter les mouvements célestes et les cycles cosmiques.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="concept-card">
|
||||
<h4>🌙 Calendrier Lunaire</h4>
|
||||
<p>
|
||||
Un système calendaire sophistiqué basé sur les phases lunaires
|
||||
et la position de Sirius pour l'agriculture.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="concept-card">
|
||||
<h4>🪐 Connaissance Planétaire</h4>
|
||||
<p>
|
||||
Description des anneaux de Saturne et des lunes de Jupiter,
|
||||
invisibles sans télescope.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="concept-card">
|
||||
<h4>🌌 Structure de l'Univers</h4>
|
||||
<p>
|
||||
Concept d'univers infini avec des mondes multiples,
|
||||
similaire aux théories modernes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="calculation-example">
|
||||
<h4>Calcul de la Période Sigui</h4>
|
||||
<pre><code>Période orbitale Po Tolo : 50 ans
|
||||
Ajustement rituel : × 1.2
|
||||
Période Sigui : 60 ans
|
||||
|
||||
Correspondance avec Sirius B :
|
||||
- Orbite réelle : 50.1 ans
|
||||
- Précision : 99.8%</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if activeTab === 'heritage'}
|
||||
<div class="tab-panel">
|
||||
<h3>Héritage et Influence</h3>
|
||||
<div class="heritage-content">
|
||||
<div class="timeline">
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-date">Antiquité</div>
|
||||
<div class="timeline-content">
|
||||
<h4>Origines Égyptiennes</h4>
|
||||
<p>Liens possibles avec les prêtres de l'Égypte ancienne qui vénéraient Sothis (Sirius)</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-date">XIIIe siècle</div>
|
||||
<div class="timeline-content">
|
||||
<h4>Migration vers le Mali</h4>
|
||||
<p>Installation dans les falaises de Bandiagara, préservation des traditions</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-date">1931-1956</div>
|
||||
<div class="timeline-content">
|
||||
<h4>Marcel Griaule</h4>
|
||||
<p>Étude ethnographique révélant les connaissances astronomiques dogons</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline-item">
|
||||
<div class="timeline-date">Aujourd'hui</div>
|
||||
<div class="timeline-content">
|
||||
<h4>Patrimoine Mondial</h4>
|
||||
<p>Les Dogons inspirent scientifiques et chercheurs du monde entier</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="influence-map">
|
||||
<h4>Influence sur la Caraïbe</h4>
|
||||
<p>
|
||||
Les traditions astronomiques africaines, incluant celles des Dogons,
|
||||
ont traversé l'Atlantique avec la diaspora, enrichissant les pratiques
|
||||
spirituelles et calendaires des Antilles.
|
||||
</p>
|
||||
<ul>
|
||||
<li>🇭🇹 Haïti : Vaudou et astronomie sacrée</li>
|
||||
<li>🇬🇵 Guadeloupe : Traditions Gwoka et cycles cosmiques</li>
|
||||
<li>🇲🇶 Martinique : Bèlè et rythmes stellaires</li>
|
||||
<li>🇯🇲 Jamaïque : Rastafari et conscience cosmique</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.dogon-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-night);
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
margin-top: var(--spacing-lg);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out;
|
||||
}
|
||||
|
||||
.content-wrapper.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Onglets */
|
||||
.tabs-nav {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 50px;
|
||||
color: var(--color-light);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tab-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-dark);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
/* Contenu des onglets */
|
||||
.tab-panel {
|
||||
animation: fadeIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.highlight-box {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
padding: 1rem;
|
||||
margin: 1.5rem 0;
|
||||
border-radius: 0 8px 8px 0;
|
||||
}
|
||||
|
||||
.highlight-box h4 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* Diagramme cosmogonie */
|
||||
.cosmogony-diagram {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.diagram-svg {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.elements circle {
|
||||
animation: pulse 3s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.elements circle:nth-child(2) { animation-delay: 0.5s; }
|
||||
.elements circle:nth-child(4) { animation-delay: 1s; }
|
||||
.elements circle:nth-child(6) { animation-delay: 1.5s; }
|
||||
|
||||
/* Système de Sirius */
|
||||
.sirius-system {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.star-info {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 1.5rem;
|
||||
border-radius: 15px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.star-info h4 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.star-info ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.star-info li {
|
||||
padding: 0.25rem 0;
|
||||
padding-left: 1.5rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.star-info li::before {
|
||||
content: "✦";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
/* Mystère de la connaissance */
|
||||
.knowledge-mystery {
|
||||
background: rgba(255, 215, 0, 0.05);
|
||||
padding: 2rem;
|
||||
border-radius: 15px;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.theories {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.theory-card {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
padding: 1rem;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.theory-card h5 {
|
||||
color: var(--color-secondary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
/* Astronomie */
|
||||
.concept-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.concept-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 1.5rem;
|
||||
border-radius: 15px;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.concept-card:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.concept-card h4 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.calculation-example {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
padding: 1.5rem;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.calculation-example pre {
|
||||
margin: 0;
|
||||
color: var(--color-light);
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
/* Timeline */
|
||||
.timeline {
|
||||
position: relative;
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.timeline::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 1rem;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background: var(--color-primary);
|
||||
}
|
||||
|
||||
.timeline-item {
|
||||
position: relative;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.timeline-item::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -2.5rem;
|
||||
top: 0.5rem;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
background: var(--color-primary);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.timeline-date {
|
||||
color: var(--color-primary);
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.timeline-content h4 {
|
||||
color: var(--color-secondary);
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
/* Carte d'influence */
|
||||
.influence-map {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
padding: 1.5rem;
|
||||
border-radius: 15px;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.influence-map ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-top: 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.influence-map li {
|
||||
padding: 0.5rem;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); opacity: 0.8; }
|
||||
50% { transform: scale(1.1); opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.content-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.tabs-nav {
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,178 +0,0 @@
|
||||
<script>
|
||||
import { t } from '../lib/i18n.js';
|
||||
const currentYear = new Date().getFullYear();
|
||||
</script>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="footer-pattern pattern-kente"></div>
|
||||
|
||||
<div class="container">
|
||||
<div class="footer-content">
|
||||
<div class="footer-section">
|
||||
<h3>Sirius en Guadeloupe</h3>
|
||||
<p>
|
||||
Un projet célébrant le patrimoine astronomique africain
|
||||
et caribéen à travers l'observation du lever héliaque de Sirius.
|
||||
</p>
|
||||
<div class="social-links">
|
||||
<a href="#" aria-label="Facebook">📘</a>
|
||||
<a href="#" aria-label="Twitter">🐦</a>
|
||||
<a href="#" aria-label="Instagram">📷</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h4>Liens Rapides</h4>
|
||||
<ul>
|
||||
<li><a href="#predictions">Calculateur</a></li>
|
||||
<li><a href="#science">Science</a></li>
|
||||
<li><a href="#culture">Culture</a></li>
|
||||
<li><a href="#observatory">Observer</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h4>Ressources</h4>
|
||||
<ul>
|
||||
<li><a href="https://stellarium.org" target="_blank" rel="noopener">Stellarium</a></li>
|
||||
<li><a href="#">Guide PDF</a></li>
|
||||
<li><a href="#">Références</a></li>
|
||||
<li><a href="#">Contact</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="footer-section">
|
||||
<h4>Prochaine Observation</h4>
|
||||
<div class="countdown">
|
||||
<div class="countdown-item">
|
||||
<div class="countdown-value">22</div>
|
||||
<div class="countdown-label">Juillet</div>
|
||||
</div>
|
||||
<div class="countdown-item">
|
||||
<div class="countdown-value">2025</div>
|
||||
<div class="countdown-label">05:12</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer-bottom">
|
||||
<p>© {currentYear} Sirius Gwada. Levez les yeux vers le ciel.</p>
|
||||
<p class="footer-credits">
|
||||
{$t('footer_copyright')}
|
||||
<a href="https://github.com/cyber-mawonaj" target="_blank" rel="noopener">cyber-mawonaj</a>
|
||||
{$t('footer_and')}
|
||||
<a href="https://o-k-i.net" target="_blank" rel="noopener">
|
||||
OKI <img src="https://o-k-i.net/assets/img/logo-oki.png" alt="OKI Logo" class="oki-logo">
|
||||
</a>
|
||||
</p>
|
||||
<p class="footer-quote">
|
||||
"Les étoiles sont les ancêtres qui veillent sur nous" - Proverbe africain
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
.footer {
|
||||
position: relative;
|
||||
background: var(--color-dark);
|
||||
padding: var(--spacing-xl) 0 var(--spacing-md);
|
||||
border-top: 2px solid rgba(255, 215, 0, 0.3);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.footer-pattern {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.03;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.countdown {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.countdown-item {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
padding: 1rem;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.countdown-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.countdown-label {
|
||||
font-size: 0.9rem;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
text-align: center;
|
||||
padding-top: var(--spacing-md);
|
||||
border-top: 1px solid rgba(255, 215, 0, 0.2);
|
||||
}
|
||||
|
||||
.footer-credits {
|
||||
margin: 0.5rem 0;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.footer-credits a {
|
||||
color: var(--color-primary);
|
||||
text-decoration: none;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.footer-credits a:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.oki-logo {
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.footer-quote {
|
||||
margin-top: 0.5rem;
|
||||
font-style: italic;
|
||||
color: var(--color-primary);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.social-links {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.footer-content {
|
||||
grid-template-columns: 1fr;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.social-links {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,454 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { worldData } from '../data/world.js';
|
||||
|
||||
let canvas;
|
||||
let visible = false;
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
visible = true;
|
||||
if (!canvas.hasAttribute('data-initialized')) {
|
||||
initGlobe();
|
||||
canvas.setAttribute('data-initialized', 'true');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('globe-section');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
function initGlobe() {
|
||||
const ctx = canvas.getContext('2d');
|
||||
const width = canvas.width = canvas.offsetWidth;
|
||||
const height = canvas.height = canvas.offsetHeight;
|
||||
|
||||
const centerX = width / 2;
|
||||
const centerY = height / 2;
|
||||
const radius = Math.min(width, height) * 0.35;
|
||||
|
||||
let rotation = 2.5; // Commencer avec l'Atlantique visible
|
||||
let zoom = 1;
|
||||
let isDragging = false;
|
||||
let lastMouseX = 0;
|
||||
let waveAnimation = 0;
|
||||
|
||||
// Données des lieux dans l'ordre chronologique
|
||||
const locations = [
|
||||
{ name: 'La Réunion', lat: -21.1151, lon: 55.5364, date: '27 Juin', day: 178 },
|
||||
{ name: 'Kinshasa', lat: -4.4419, lon: 15.2663, date: '16 Juillet', day: 197 },
|
||||
{ name: 'Guadeloupe', lat: 16.2650, lon: -61.5510, date: '22 Juillet', day: 203 },
|
||||
{ name: 'Martinique', lat: 14.6415, lon: -61.0242, date: '23 Juillet', day: 204 },
|
||||
{ name: 'Dakar', lat: 14.7167, lon: -17.4677, date: '23 Juillet', day: 204 },
|
||||
{ name: 'Abidjan', lat: 5.3600, lon: -4.0083, date: '28 Juillet', day: 209 },
|
||||
{ name: 'Le Caire', lat: 30.0444, lon: 31.2357, date: '3 Août', day: 215 },
|
||||
{ name: 'Paris', lat: 48.8566, lon: 2.3522, date: '12 Août', day: 224 }
|
||||
];
|
||||
|
||||
// Gérer le zoom
|
||||
canvas.addEventListener('wheel', (e) => {
|
||||
e.preventDefault();
|
||||
zoom += e.deltaY * -0.001;
|
||||
zoom = Math.min(Math.max(0.5, zoom), 2);
|
||||
});
|
||||
|
||||
// Gérer la rotation avec la souris
|
||||
canvas.addEventListener('mousedown', (e) => {
|
||||
isDragging = true;
|
||||
lastMouseX = e.clientX;
|
||||
});
|
||||
|
||||
window.addEventListener('mousemove', (e) => {
|
||||
if (isDragging) {
|
||||
const deltaX = e.clientX - lastMouseX;
|
||||
rotation -= deltaX * 0.01; // Inverser pour tourner dans le bon sens
|
||||
lastMouseX = e.clientX;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('mouseup', () => {
|
||||
isDragging = false;
|
||||
});
|
||||
|
||||
// Support tactile
|
||||
canvas.addEventListener('touchstart', (e) => {
|
||||
isDragging = true;
|
||||
lastMouseX = e.touches[0].clientX;
|
||||
e.preventDefault();
|
||||
});
|
||||
canvas.addEventListener('touchmove', (e) => {
|
||||
if (isDragging && e.touches.length === 1) {
|
||||
const deltaX = e.touches[0].clientX - lastMouseX;
|
||||
rotation -= deltaX * 0.01; // Garder le - pour le tactile aussi
|
||||
lastMouseX = e.touches[0].clientX;
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
canvas.addEventListener('touchend', () => {
|
||||
isDragging = false;
|
||||
});
|
||||
|
||||
// Dessiner les continents simplifiés
|
||||
function drawContinents(ctx, centerX, centerY, radius, rotation) {
|
||||
ctx.save();
|
||||
ctx.globalAlpha = 0.8; // Plus opaque
|
||||
ctx.strokeStyle = '#8B7355'; // Marron clair
|
||||
ctx.fillStyle = '#DEB887'; // Burlywood (beige)
|
||||
ctx.lineWidth = 0.5;
|
||||
|
||||
// Afrique (très simplifiée)
|
||||
const africa = [
|
||||
{lat: 37, lon: 10}, {lat: 35, lon: -5}, {lat: 30, lon: -17},
|
||||
{lat: 15, lon: -17}, {lat: 5, lon: -10}, {lat: -5, lon: 8},
|
||||
{lat: -15, lon: 15}, {lat: -25, lon: 20}, {lat: -35, lon: 20},
|
||||
{lat: -35, lon: 30}, {lat: -25, lon: 35}, {lat: -10, lon: 40},
|
||||
{lat: 5, lon: 45}, {lat: 15, lon: 45}, {lat: 30, lon: 35}, {lat: 37, lon: 10}
|
||||
];
|
||||
drawLandmass(africa);
|
||||
// Amérique du Sud
|
||||
const southAmerica = [
|
||||
{lat: 10, lon: -60}, {lat: 5, lon: -50}, {lat: -5, lon: -35},
|
||||
{lat: -15, lon: -38}, {lat: -25, lon: -48}, {lat: -35, lon: -58},
|
||||
{lat: -45, lon: -65}, {lat: -55, lon: -70}, {lat: -45, lon: -73},
|
||||
{lat: -35, lon: -72}, {lat: -25, lon: -70}, {lat: -15, lon: -75},
|
||||
{lat: -5, lon: -78}, {lat: 5, lon: -77}, {lat: 10, lon: -60}
|
||||
];
|
||||
drawLandmass(southAmerica);
|
||||
|
||||
// Europe (simplifiée)
|
||||
const europe = [
|
||||
{lat: 60, lon: 25}, {lat: 55, lon: 10}, {lat: 50, lon: -5},
|
||||
{lat: 45, lon: -5}, {lat: 40, lon: -10}, {lat: 36, lon: -6},
|
||||
{lat: 40, lon: 0}, {lat: 45, lon: 10}, {lat: 50, lon: 20},
|
||||
{lat: 55, lon: 30}, {lat: 60, lon: 25}
|
||||
];
|
||||
drawLandmass(europe);
|
||||
|
||||
function drawLandmass(points) {
|
||||
const coords = points.map(p => {
|
||||
const phi = (90 - p.lat) * Math.PI / 180;
|
||||
const theta = (p.lon - rotation * 57.3) * Math.PI / 180;
|
||||
|
||||
const x = radius * Math.sin(phi) * Math.cos(theta);
|
||||
const y = radius * Math.cos(phi);
|
||||
const z = radius * Math.sin(phi) * Math.sin(theta);
|
||||
|
||||
return { x: centerX + x, y: centerY - y, z: z };
|
||||
});
|
||||
// Ne dessiner que si au moins un point est visible
|
||||
if (coords.some(c => c.z > -radius * 0.5)) {
|
||||
ctx.beginPath();
|
||||
coords.forEach((c, i) => {
|
||||
if (i === 0) ctx.moveTo(c.x, c.y);
|
||||
else ctx.lineTo(c.x, c.y);
|
||||
});
|
||||
ctx.closePath();
|
||||
if (coords[0].z > 0) {
|
||||
ctx.fill();
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
const currentRadius = radius * zoom;
|
||||
|
||||
// Océan (fond du globe)
|
||||
const oceanGradient = ctx.createRadialGradient(
|
||||
centerX - currentRadius * 0.3,
|
||||
centerY - currentRadius * 0.3,
|
||||
0,
|
||||
centerX,
|
||||
centerY,
|
||||
currentRadius
|
||||
); oceanGradient.addColorStop(0, '#87CEEB'); // Sky blue clair
|
||||
oceanGradient.addColorStop(0.7, '#5F9EA0'); // Cadet blue
|
||||
oceanGradient.addColorStop(1, '#4682B4'); // Steel blue
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, currentRadius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = oceanGradient;
|
||||
ctx.fill();
|
||||
|
||||
// Grille de méridiens et parallèles
|
||||
ctx.strokeStyle = 'rgba(0, 0, 0, 0.1)'; // Noir transparent
|
||||
ctx.lineWidth = 0.5;
|
||||
|
||||
// Méridiens (longitudes)
|
||||
for (let lon = -180; lon <= 180; lon += 30) {
|
||||
ctx.beginPath();
|
||||
for (let lat = -90; lat <= 90; lat += 5) {
|
||||
const phi = (90 - lat) * Math.PI / 180;
|
||||
const theta = (lon - rotation * 57.3) * Math.PI / 180;
|
||||
|
||||
const x = currentRadius * Math.sin(phi) * Math.cos(theta);
|
||||
const y = currentRadius * Math.cos(phi);
|
||||
const z = currentRadius * Math.sin(phi) * Math.sin(theta);
|
||||
|
||||
if (z > 0) {
|
||||
const screenX = centerX + x;
|
||||
const screenY = centerY - y;
|
||||
if (lat === -90) ctx.moveTo(screenX, screenY);
|
||||
else ctx.lineTo(screenX, screenY);
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
// Parallèles (latitudes)
|
||||
for (let lat = -60; lat <= 60; lat += 30) {
|
||||
ctx.beginPath();
|
||||
for (let lon = -180; lon <= 180; lon += 5) {
|
||||
const phi = (90 - lat) * Math.PI / 180;
|
||||
const theta = (lon - rotation * 57.3) * Math.PI / 180;
|
||||
|
||||
const x = currentRadius * Math.sin(phi) * Math.cos(theta);
|
||||
const y = currentRadius * Math.cos(phi);
|
||||
const z = currentRadius * Math.sin(phi) * Math.sin(theta);
|
||||
|
||||
if (z > 0) {
|
||||
const screenX = centerX + x;
|
||||
const screenY = centerY - y;
|
||||
if (lon === -180) ctx.moveTo(screenX, screenY);
|
||||
else ctx.lineTo(screenX, screenY);
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Dessiner les continents
|
||||
drawContinents(ctx, centerX, centerY, currentRadius, rotation);
|
||||
|
||||
// Bordure du globe
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, currentRadius, 0, Math.PI * 2);
|
||||
ctx.strokeStyle = 'rgba(0, 0, 0, 0.5)'; // Noir semi-transparent
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
// Dessiner la vague de progression
|
||||
waveAnimation += 0.02;
|
||||
const waveDay = ((Math.sin(waveAnimation) + 1) / 2) * 46 + 178; // Entre jour 178 et 224
|
||||
|
||||
// Dessiner les points et la vague
|
||||
locations.forEach((loc, i) => {
|
||||
const phi = (90 - loc.lat) * Math.PI / 180;
|
||||
const theta = (-loc.lon - rotation * 57.3) * Math.PI / 180; // Remettre le - devant loc.lon
|
||||
|
||||
const x = currentRadius * Math.sin(phi) * Math.cos(theta);
|
||||
const y = currentRadius * Math.cos(phi);
|
||||
const z = currentRadius * Math.sin(phi) * Math.sin(theta);
|
||||
|
||||
if (z > -currentRadius * 0.3) {
|
||||
const screenX = centerX + x;
|
||||
const screenY = centerY - y;
|
||||
|
||||
// Calculer l'état selon la vague
|
||||
const isActive = waveDay >= loc.day;
|
||||
const isNear = Math.abs(waveDay - loc.day) < 5;
|
||||
|
||||
// Effet de vague
|
||||
if (isNear && z > 0) {
|
||||
const waveSize = 40 * (1 - Math.abs(waveDay - loc.day) / 5);
|
||||
const waveGradient = ctx.createRadialGradient(screenX, screenY, 0, screenX, screenY, waveSize);
|
||||
waveGradient.addColorStop(0, 'rgba(255, 215, 0, 0.8)');
|
||||
waveGradient.addColorStop(0.5, 'rgba(255, 215, 0, 0.3)');
|
||||
waveGradient.addColorStop(1, 'rgba(255, 215, 0, 0)');
|
||||
ctx.fillStyle = waveGradient;
|
||||
ctx.fillRect(screenX - waveSize, screenY - waveSize, waveSize * 2, waveSize * 2);
|
||||
}
|
||||
// Point
|
||||
const opacity = z > 0 ? 1 : 0.3;
|
||||
ctx.globalAlpha = opacity;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(screenX, screenY, isActive ? 6 : 4, 0, Math.PI * 2);
|
||||
ctx.fillStyle = isActive ? '#FFD700' : '#666666';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = isActive ? '#FFFFFF' : '#999999';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Label
|
||||
if (z > 0) {
|
||||
ctx.fillStyle = isActive ? '#FFD700' : '#999999';
|
||||
ctx.font = `${12 * zoom}px Inter`;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(loc.name, screenX, screenY - 12);
|
||||
ctx.font = `${10 * zoom}px Inter`;
|
||||
ctx.fillText(loc.date, screenX, screenY + 22);
|
||||
}
|
||||
|
||||
ctx.globalAlpha = 1;
|
||||
}
|
||||
});
|
||||
|
||||
// Légende
|
||||
ctx.fillStyle = '#FFD700';
|
||||
ctx.font = '16px Inter';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('🌟 Vague du Lever Héliaque de Sirius', 20, 30); ctx.font = '12px Inter';
|
||||
ctx.fillStyle = '#CCCCCC';
|
||||
const currentDate = locations.find(l => Math.abs(l.day - waveDay) < 2);
|
||||
if (currentDate) {
|
||||
ctx.fillText(`Animation : ${currentDate.name} - ${currentDate.date}`, 20, 50);
|
||||
}
|
||||
|
||||
// Rotation automatique lente
|
||||
if (!isDragging) {
|
||||
rotation += 0.002;
|
||||
}
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
</script>
|
||||
|
||||
<section id="globe-section" class="globe-section">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Globe Original (Canvas simple)</h2>
|
||||
<p class="section-subtitle">
|
||||
Version actuelle avec formes simplifiées
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="globe-container" class:visible>
|
||||
<canvas bind:this={canvas} class="globe-canvas"></canvas>
|
||||
|
||||
<div class="globe-controls">
|
||||
<p>🖱️ Glisser pour tourner | 🔍 Molette pour zoomer</p>
|
||||
</div>
|
||||
<div class="globe-info">
|
||||
<div class="info-card card">
|
||||
<h3>Le Phénomène Global</h3>
|
||||
<p>
|
||||
Le lever héliaque de Sirius n'est pas simultané sur Terre.
|
||||
Il progresse comme une vague dorée, commençant dans l'océan Indien
|
||||
(La Réunion en juin) pour traverser l'Afrique, les Caraïbes,
|
||||
puis remonter vers l'Europe (Paris en août).
|
||||
</p>
|
||||
<p>
|
||||
Cette progression suit la géométrie céleste : plus on va vers le nord,
|
||||
plus le phénomène se produit tard. La Guadeloupe se trouve au cœur
|
||||
de cette vague en juillet, bénéficiant de conditions idéales.
|
||||
</p>
|
||||
<div class="timeline-mini">
|
||||
<div class="timeline-item-mini">
|
||||
<span class="date">27 Juin</span>
|
||||
<span class="location">La Réunion</span>
|
||||
</div>
|
||||
<div class="timeline-item-mini">
|
||||
<span class="date">22-23 Juillet</span>
|
||||
<span class="location">Guadeloupe & Caraïbes</span>
|
||||
</div>
|
||||
<div class="timeline-item-mini">
|
||||
<span class="date">12 Août</span>
|
||||
<span class="location">Paris</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<style>
|
||||
.globe-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-dawn);
|
||||
}
|
||||
|
||||
.globe-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
align-items: center;
|
||||
margin-top: var(--spacing-lg);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.3s;
|
||||
}
|
||||
|
||||
.globe-container.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.globe-canvas {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border-radius: 20px;
|
||||
background: radial-gradient(circle at center, #0a192f 0%, #020c1b 100%);
|
||||
cursor: grab;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.globe-canvas:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
.globe-controls {
|
||||
text-align: center;
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-primary);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.info-card h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-card p {
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.timeline-mini {
|
||||
margin-top: 1.5rem;
|
||||
padding: 1rem;
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.timeline-item-mini {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 0;
|
||||
border-bottom: 1px solid rgba(255, 215, 0, 0.2);
|
||||
}
|
||||
|
||||
.timeline-item-mini:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
.timeline-item-mini .date {
|
||||
font-weight: 600;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.timeline-item-mini .location {
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.globe-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.globe-canvas {
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,740 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import anime from '../lib/anime.js';
|
||||
import { t } from '../lib/i18n.js';
|
||||
|
||||
let canvas;
|
||||
let visible = false;
|
||||
let ctx;
|
||||
let animationId;
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting && !ctx) {
|
||||
visible = true;
|
||||
initGlobe();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('geojson-section');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
if (animationId) cancelAnimationFrame(animationId);
|
||||
};
|
||||
});
|
||||
|
||||
async function initGlobe() {
|
||||
ctx = canvas.getContext('2d');
|
||||
|
||||
const width = canvas.width = canvas.offsetWidth;
|
||||
const height = canvas.height = canvas.offsetHeight;
|
||||
const centerX = width / 2;
|
||||
const centerY = height / 2;
|
||||
const radius = Math.min(width, height) * 0.35;
|
||||
|
||||
let rotation = 2.5;
|
||||
let zoom = 1;
|
||||
let isDragging = false;
|
||||
let lastMouseX = 0;
|
||||
let waveAnimation = 0;
|
||||
let waveProgress = 0;
|
||||
// Animation d'entrée
|
||||
anime.timeline({
|
||||
easing: 'easeOutQuad'
|
||||
})
|
||||
.add({
|
||||
targets: canvas,
|
||||
scale: [0.8, 1],
|
||||
opacity: [0, 1],
|
||||
duration: 1200
|
||||
})
|
||||
.add({
|
||||
targets: '.globe-info',
|
||||
translateX: [50, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 1000
|
||||
}, '-=600');
|
||||
|
||||
|
||||
// Charger les données GeoJSON des continents
|
||||
let worldData = null;
|
||||
try {
|
||||
const response = await fetch('https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json');
|
||||
worldData = await response.json();
|
||||
} catch (error) {
|
||||
console.error('Erreur chargement GeoJSON:', error);
|
||||
}
|
||||
// Données des lieux avec animation de vague (juin à septembre)
|
||||
const locations = [
|
||||
{ name: 'La Réunion', lat: -21.1151, lon: 55.5364, date: '27 Juin', color: '#FF6B35', day: 0 },
|
||||
{ name: 'Kinshasa', lat: -4.4419, lon: 15.2663, date: '16 Juillet', color: '#FFA500', day: 19 },
|
||||
{ name: 'Douala', lat: 4.0511, lon: 9.7679, date: '18 Juillet', color: '#FFA500', day: 21 },
|
||||
{ name: 'Yaoundé', lat: 3.8480, lon: 11.5021, date: '19 Juillet', color: '#FFA500', day: 22 },
|
||||
{ name: 'Abidjan', lat: 5.3600, lon: -4.0083, date: '20 Juillet', color: '#FFD700', day: 23 },
|
||||
{ name: 'Accra', lat: 5.6037, lon: -0.1870, date: '21 Juillet', color: '#FFD700', day: 24 },
|
||||
{ name: 'Guadeloupe', lat: 16.2650, lon: -61.5510, date: '22 Juillet', color: '#FFD700', day: 25 },
|
||||
{ name: 'Martinique', lat: 14.6415, lon: -61.0242, date: '23 Juillet', color: '#FFD700', day: 26 },
|
||||
{ name: 'Dakar', lat: 14.7167, lon: -17.4677, date: '23 Juillet', color: '#FFE44D', day: 26 },
|
||||
{ name: 'Cayenne', lat: 4.9346, lon: -52.3281, date: '24 Juillet', color: '#FFE44D', day: 27 },
|
||||
{ name: 'Bamako', lat: 12.6392, lon: -8.0029, date: '25 Juillet', color: '#FFE44D', day: 28 },
|
||||
{ name: 'Le Caire', lat: 30.0444, lon: 31.2357, date: '3 Août', color: '#FFFACD', day: 37 },
|
||||
{ name: 'Paris', lat: 48.8566, lon: 2.3522, date: '15 Août', color: '#F0F8FF', day: 49 }
|
||||
];
|
||||
|
||||
// Animation de la progression de la vague (juin à septembre)
|
||||
anime({
|
||||
targets: { progress: 0 },
|
||||
progress: 92, // Juin (jour 152) à septembre (jour 244) = 92 jours
|
||||
duration: 12000, // 12 secondes pour 4 mois
|
||||
easing: 'linear',
|
||||
loop: true,
|
||||
update: function(anim) {
|
||||
waveProgress = anim.animations[0].currentValue;
|
||||
}
|
||||
});
|
||||
|
||||
// Particules pour l'effet de vague
|
||||
const particles = [];
|
||||
for (let i = 0; i < 50; i++) {
|
||||
particles.push({
|
||||
angle: Math.random() * Math.PI * 2,
|
||||
radius: radius + Math.random() * 50,
|
||||
size: Math.random() * 3 + 1,
|
||||
speed: Math.random() * 0.02 + 0.01,
|
||||
opacity: 0
|
||||
});
|
||||
}
|
||||
|
||||
// Animation des particules
|
||||
particles.forEach((particle, i) => {
|
||||
anime({
|
||||
targets: particle,
|
||||
opacity: [0, 0.8, 0],
|
||||
radius: [radius, radius + 100],
|
||||
duration: 3000,
|
||||
delay: i * 60,
|
||||
easing: 'easeOutQuad',
|
||||
loop: true
|
||||
});
|
||||
});
|
||||
|
||||
// Gestion de la souris
|
||||
canvas.addEventListener('mousedown', (e) => {
|
||||
isDragging = true;
|
||||
lastMouseX = e.clientX;
|
||||
canvas.style.cursor = 'grabbing';
|
||||
});
|
||||
|
||||
canvas.addEventListener('mousemove', (e) => {
|
||||
if (isDragging) {
|
||||
const deltaX = e.clientX - lastMouseX;
|
||||
rotation -= deltaX * 0.01;
|
||||
lastMouseX = e.clientX;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('mouseup', () => {
|
||||
isDragging = false;
|
||||
canvas.style.cursor = 'grab';
|
||||
});
|
||||
|
||||
// Zoom avec la molette
|
||||
canvas.addEventListener('wheel', (e) => {
|
||||
e.preventDefault();
|
||||
const zoomDelta = e.deltaY > 0 ? 0.9 : 1.1;
|
||||
const newZoom = zoom * zoomDelta;
|
||||
|
||||
anime({
|
||||
targets: { zoom },
|
||||
zoom: Math.max(0.5, Math.min(3, newZoom)),
|
||||
duration: 300,
|
||||
easing: 'easeOutQuad',
|
||||
update: function(anim) {
|
||||
zoom = anim.animations[0].currentValue;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Projection 3D (lon/lat to screen coordinates)
|
||||
function project(lon, lat, r) {
|
||||
const phi = (90 - lat) * Math.PI / 180;
|
||||
const theta = lon * Math.PI / 180 - rotation;
|
||||
|
||||
const x = r * Math.sin(phi) * Math.cos(theta);
|
||||
const y = r * Math.cos(phi);
|
||||
const z = r * Math.sin(phi) * Math.sin(theta);
|
||||
|
||||
return {
|
||||
x: centerX - x,
|
||||
y: centerY - y,
|
||||
z: z,
|
||||
visible: z > 0
|
||||
};
|
||||
}
|
||||
|
||||
// Dessiner le globe
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
// Calculer le rayon actuel avec zoom
|
||||
const currentRadius = radius * zoom;
|
||||
|
||||
// Fond avec dégradé
|
||||
const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, currentRadius);
|
||||
gradient.addColorStop(0, 'rgba(10, 22, 40, 0.2)');
|
||||
gradient.addColorStop(1, 'rgba(10, 22, 40, 0.8)');
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fillRect(0, 0, width, height);
|
||||
|
||||
// Ombre du globe
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX + 10, centerY + 10, currentRadius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
|
||||
ctx.fill();
|
||||
|
||||
// Globe principal
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX, centerY, currentRadius, 0, Math.PI * 2);
|
||||
const globeGradient = ctx.createRadialGradient(
|
||||
centerX - radius * 0.3 * zoom,
|
||||
centerY - radius * 0.3 * zoom,
|
||||
0,
|
||||
centerX, centerY, currentRadius
|
||||
);
|
||||
globeGradient.addColorStop(0, '#1a3a5a');
|
||||
globeGradient.addColorStop(0.5, '#0f2847');
|
||||
globeGradient.addColorStop(1, '#0a1628');
|
||||
ctx.fillStyle = globeGradient;
|
||||
ctx.fill();
|
||||
|
||||
// Grille de latitude/longitude
|
||||
ctx.strokeStyle = 'rgba(255, 215, 0, 0.1)';
|
||||
ctx.lineWidth = 1;
|
||||
|
||||
// Lignes de latitude
|
||||
for (let lat = -80; lat <= 80; lat += 20) {
|
||||
ctx.beginPath();
|
||||
for (let lon = -180; lon <= 180; lon += 5) {
|
||||
const p = project(lon, lat, currentRadius);
|
||||
if (p.visible) {
|
||||
if (lon === -180) ctx.moveTo(p.x, p.y);
|
||||
else ctx.lineTo(p.x, p.y);
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Lignes de longitude
|
||||
for (let lon = -180; lon <= 180; lon += 30) {
|
||||
ctx.beginPath();
|
||||
for (let lat = -90; lat <= 90; lat += 5) {
|
||||
const p = project(lon, lat, currentRadius);
|
||||
if (p.visible) {
|
||||
if (lat === -90) ctx.moveTo(p.x, p.y);
|
||||
else ctx.lineTo(p.x, p.y);
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Dessiner les continents
|
||||
if (worldData) {
|
||||
ctx.save();
|
||||
ctx.strokeStyle = '#4CAF50';
|
||||
ctx.fillStyle = 'rgba(76, 175, 80, 0.3)';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
worldData.features.forEach(feature => {
|
||||
if (feature.geometry.type === 'Polygon') {
|
||||
drawPolygon(feature.geometry.coordinates[0]);
|
||||
} else if (feature.geometry.type === 'MultiPolygon') {
|
||||
feature.geometry.coordinates.forEach(polygon => {
|
||||
drawPolygon(polygon[0]);
|
||||
});
|
||||
}
|
||||
});
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// Dessiner les particules de la vague
|
||||
particles.forEach(particle => {
|
||||
const p = project(
|
||||
particle.angle * 180 / Math.PI - 180,
|
||||
Math.sin(Date.now() * 0.001 * particle.speed) * 30,
|
||||
currentRadius + (particle.radius - radius)
|
||||
);
|
||||
|
||||
if (p.visible && particle.opacity > 0) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(p.x, p.y, particle.size, 0, Math.PI * 2);
|
||||
ctx.fillStyle = `rgba(255, 215, 0, ${particle.opacity})`;
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
// Dessiner les marqueurs avec effet de pulsation
|
||||
locations.forEach((location, index) => {
|
||||
const p = project(location.lon, location.lat, currentRadius);
|
||||
|
||||
if (p.visible) {
|
||||
// Vérifier si la vague est passée
|
||||
const isActive = waveProgress >= location.day && waveProgress <= location.day + 10;
|
||||
const scale = isActive ? 1 + Math.sin(Date.now() * 0.005) * 0.3 : 1;
|
||||
|
||||
// Cercle de base
|
||||
ctx.beginPath();
|
||||
ctx.arc(p.x, p.y, 8 * scale, 0, Math.PI * 2);
|
||||
ctx.fillStyle = location.color;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#fff';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Onde de propagation si actif
|
||||
if (isActive) {
|
||||
const waveRadius = 20 + (Date.now() * 0.02) % 30;
|
||||
const waveOpacity = 1 - (waveRadius - 20) / 30;
|
||||
ctx.beginPath();
|
||||
ctx.arc(p.x, p.y, waveRadius, 0, Math.PI * 2);
|
||||
ctx.strokeStyle = `rgba(255, 215, 0, ${waveOpacity * 0.5})`;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Label
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = 'bold 12px Inter';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(location.name, p.x, p.y - 15);
|
||||
|
||||
// Date si proche
|
||||
if (Math.abs(waveProgress - location.day) < 20) {
|
||||
ctx.font = '10px Inter';
|
||||
ctx.fillStyle = location.color;
|
||||
ctx.fillText(location.date, p.x, p.y + 25);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Indicateur de progression de la vague
|
||||
const startDate = new Date(2025, 5, 27); // 27 juin 2025
|
||||
const currentDate = new Date(startDate);
|
||||
currentDate.setDate(currentDate.getDate() + Math.floor(waveProgress));
|
||||
|
||||
ctx.fillStyle = 'rgba(255, 215, 0, 0.8)';
|
||||
ctx.font = 'bold 16px Inter';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(
|
||||
`Progression de la vague : ${currentDate.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long' })}`,
|
||||
centerX, height - 30
|
||||
);
|
||||
|
||||
// Rotation automatique
|
||||
if (!isDragging) {
|
||||
rotation += 0.002;
|
||||
}
|
||||
|
||||
animationId = requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
function drawPolygon(coordinates) {
|
||||
ctx.beginPath();
|
||||
let firstPoint = true;
|
||||
const currentRadius = radius * zoom;
|
||||
|
||||
coordinates.forEach(coord => {
|
||||
const p = project(coord[0], coord[1], currentRadius);
|
||||
if (p.visible) {
|
||||
if (firstPoint) {
|
||||
ctx.moveTo(p.x, p.y);
|
||||
firstPoint = false;
|
||||
} else {
|
||||
ctx.lineTo(p.x, p.y);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
</script>
|
||||
<section id="geojson-section" class="globe-section">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>La Vague Planétaire de Sirius</h2>
|
||||
<p class="section-subtitle">
|
||||
Visualisation de la progression du lever héliaque à travers le monde
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="globe-container" class:visible>
|
||||
<canvas bind:this={canvas} class="globe-canvas"></canvas>
|
||||
|
||||
<div class="globe-controls">
|
||||
<p>🖱️ Glisser pour tourner | 🔍 Molette pour zoomer</p>
|
||||
</div>
|
||||
|
||||
<div class="globe-info">
|
||||
<div class="info-card card">
|
||||
<h3>Le Phénomène de la Vague</h3>
|
||||
<p>
|
||||
Le lever héliaque de Sirius ne se produit pas simultanément sur toute la Terre.
|
||||
Tel une vague cosmique, il progresse d'Est en Ouest, touchant d'abord La Réunion
|
||||
fin juin, puis traversant l'Afrique, pour finalement atteindre les Caraïbes en juillet.
|
||||
</p>
|
||||
<p>
|
||||
Cette animation montre la progression de cette "vague planétaire" qui suit
|
||||
la rotation terrestre et la position de Sirius dans le ciel. Chaque lieu
|
||||
expérimente ce moment sacré à une date précise, créant un calendrier
|
||||
cosmique naturel qui a guidé les civilisations pendant des millénaires.
|
||||
</p>
|
||||
<div class="wave-timeline">
|
||||
<div class="timeline-entry">
|
||||
<span class="date">27 Juin</span>
|
||||
<span class="location">La Réunion</span>
|
||||
</div>
|
||||
<div class="timeline-entry">
|
||||
<span class="date">16-19 Juillet</span>
|
||||
<span class="location">Kinshasa, Douala, Yaoundé</span>
|
||||
</div>
|
||||
<div class="timeline-entry">
|
||||
<span class="date">20-24 Juillet</span>
|
||||
<span class="location">Abidjan, Accra, Antilles, Cayenne</span>
|
||||
</div>
|
||||
<div class="timeline-entry">
|
||||
<span class="date">25 Juillet</span>
|
||||
<span class="location">Bamako, Dakar</span>
|
||||
</div>
|
||||
<div class="timeline-entry">
|
||||
<span class="date">3-15 Août</span>
|
||||
<span class="location">Le Caire, Paris</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="associations" class="associations-section">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<h2>{$t('associations_title')}</h2>
|
||||
<p class="section-subtitle">
|
||||
{$t('associations_subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="associations-content">
|
||||
<div class="events-grid">
|
||||
<div class="event-card card">
|
||||
<h3>{$t('associations_events_title')}</h3>
|
||||
<div class="event-links">
|
||||
<a href="https://my.weezevent.com/nouvel-an-kamite" target="_blank" rel="noopener noreferrer" class="event-link">
|
||||
<span class="event-icon">🎊</span>
|
||||
<div class="event-info">
|
||||
<span class="event-title">{$t('associations_event1_title')}</span>
|
||||
<span class="event-platform">{$t('associations_event1_organizer')}</span>
|
||||
<span class="event-description">{$t('associations_event1_desc')}</span>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://my.weezevent.com/nouvel-an-kamit" target="_blank" rel="noopener noreferrer" class="event-link">
|
||||
<span class="event-icon">✨</span>
|
||||
<div class="event-info">
|
||||
<span class="event-title">{$t('associations_event2_title')}</span>
|
||||
<span class="event-platform">{$t('associations_event2_organizer')}</span>
|
||||
<span class="event-description">{$t('associations_event2_desc')}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="community-card card">
|
||||
<h3>{$t('associations_community_title')}</h3>
|
||||
<div class="community-links">
|
||||
<a href="https://14eme-membre.net/site-web/#événements" target="_blank" rel="noopener noreferrer" class="community-link">
|
||||
<span class="community-icon">🌍</span>
|
||||
<div class="community-info">
|
||||
<span class="community-title">{$t('associations_link1_title')}</span>
|
||||
<span class="community-desc">{$t('associations_link1_desc')}</span>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://www.facebook.com/people/Mouvement-Politique-Spirituel-MUN" target="_blank" rel="noopener noreferrer" class="community-link">
|
||||
<span class="community-icon">📘</span>
|
||||
<div class="community-info">
|
||||
<span class="community-title">{$t('associations_link2_title')}</span>
|
||||
<span class="community-desc">{$t('associations_link2_desc')}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="video-section">
|
||||
<h3>{$t('associations_video_title')}</h3>
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube.com/embed/0_8kWlDTf94"
|
||||
title="Vidéo sur le Wep Ronpet"
|
||||
frameborder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowfullscreen
|
||||
class="youtube-video"
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.globe-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-dawn);
|
||||
}
|
||||
|
||||
.globe-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
align-items: center;
|
||||
margin-top: var(--spacing-lg);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.3s;
|
||||
}
|
||||
|
||||
.globe-container.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.globe-canvas {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border-radius: 20px;
|
||||
background: radial-gradient(circle at center, #0a192f 0%, #020c1b 100%);
|
||||
cursor: grab;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
.globe-canvas:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.globe-controls {
|
||||
text-align: center;
|
||||
margin-top: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-primary);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.globe-info {
|
||||
opacity: 0;
|
||||
transform: translateX(50px);
|
||||
}
|
||||
|
||||
.info-card h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-card p {
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.wave-timeline {
|
||||
margin-top: 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.timeline-entry {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.5rem 1rem;
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
border-left: 3px solid var(--color-primary);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.timeline-entry::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -100%;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 215, 0, 0.3), transparent);
|
||||
animation: shimmer 3s infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% { left: -100%; }
|
||||
100% { left: 100%; }
|
||||
}
|
||||
|
||||
.timeline-entry .date {
|
||||
font-weight: 600;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.timeline-entry .location {
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.globe-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.globe-canvas {
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Styles pour la section associations */
|
||||
.associations-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: linear-gradient(135deg, #0f1419 0%, #1a2332 100%);
|
||||
}
|
||||
|
||||
.associations-content {
|
||||
margin-top: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.events-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-xl);
|
||||
}
|
||||
|
||||
.event-card, .community-card {
|
||||
background: rgba(255, 215, 0, 0.05);
|
||||
border: 1px solid rgba(255, 215, 0, 0.2);
|
||||
border-radius: 16px;
|
||||
padding: var(--spacing-lg);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.event-card:hover, .community-card:hover {
|
||||
transform: translateY(-5px);
|
||||
border-color: var(--color-primary);
|
||||
box-shadow: 0 10px 30px rgba(255, 215, 0, 0.2);
|
||||
}
|
||||
|
||||
.event-card h3, .community-card h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: var(--spacing-md);
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.event-links, .community-links {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.event-link, .community-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
padding: var(--spacing-sm);
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
border-radius: 12px;
|
||||
text-decoration: none;
|
||||
color: var(--color-light);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.event-link:hover, .community-link:hover {
|
||||
background: rgba(255, 215, 0, 0.2);
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
.event-icon, .community-icon {
|
||||
font-size: 1.5rem;
|
||||
min-width: 32px;
|
||||
}
|
||||
|
||||
.event-info, .community-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.event-title, .community-title {
|
||||
font-weight: 600;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.event-platform, .community-desc {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-muted);
|
||||
}
|
||||
|
||||
.event-description {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-light);
|
||||
margin-top: 4px;
|
||||
line-height: 1.4;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.video-section {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.video-section h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: var(--spacing-lg);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.video-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
aspect-ratio: 16/9;
|
||||
border-radius: 16px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.youtube-video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.events-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.video-container {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,217 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let container;
|
||||
let visible = false;
|
||||
let globeInstance;
|
||||
|
||||
onMount(async () => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting && !globeInstance) {
|
||||
visible = true;
|
||||
initGlobe();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('openglobus-section');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
if (globeInstance) {
|
||||
globeInstance.destroy();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
async function initGlobe() {
|
||||
// Charger OpenGlobus depuis CDN
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://unpkg.com/@openglobus/og@0.10.0/dist/og.umd.js';
|
||||
script.onload = () => {
|
||||
const { Globe, XYZ, Vector, Entity, Label } = window.og;
|
||||
|
||||
// Créer le globe
|
||||
globeInstance = new Globe({
|
||||
target: container,
|
||||
name: "Earth",
|
||||
terrain: null,
|
||||
layers: [
|
||||
new XYZ("OSM", {
|
||||
url: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
visibility: true,
|
||||
attribution: 'OpenStreetMap'
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
// Données des lieux
|
||||
const locations = [
|
||||
{ name: 'La Réunion', lat: -21.1151, lon: 55.5364, date: '27 Juin', color: '#FF6B35' },
|
||||
{ name: 'Kinshasa', lat: -4.4419, lon: 15.2663, date: '16 Juillet', color: '#FFA500' },
|
||||
{ name: 'Guadeloupe', lat: 16.2650, lon: -61.5510, date: '22 Juillet', color: '#FFD700' },
|
||||
{ name: 'Martinique', lat: 14.6415, lon: -61.0242, date: '23 Juillet', color: '#FFD700' },
|
||||
{ name: 'Dakar', lat: 14.7167, lon: -17.4677, date: '23 Juillet', color: '#FFE44D' },
|
||||
{ name: 'Le Caire', lat: 30.0444, lon: 31.2357, date: '3 Août', color: '#FFFACD' }
|
||||
];
|
||||
|
||||
// Ajouter une couche de vecteurs pour les marqueurs
|
||||
const markerLayer = new Vector("Markers", {
|
||||
entities: locations.map(loc => new Entity({
|
||||
name: loc.name,
|
||||
lonlat: [loc.lon, loc.lat],
|
||||
label: {
|
||||
text: `${loc.name}\n${loc.date}`,
|
||||
outline: 0.77,
|
||||
outlineColor: "rgba(0,0,0,.75)",
|
||||
size: 14,
|
||||
color: "white",
|
||||
offset: [0, -35]
|
||||
},
|
||||
billboard: {
|
||||
src: createMarkerCanvas(loc.color),
|
||||
width: 32,
|
||||
height: 32,
|
||||
offset: [0, -16]
|
||||
}
|
||||
}))
|
||||
});
|
||||
|
||||
globeInstance.planet.addLayer(markerLayer);
|
||||
|
||||
// Positionner la vue sur l'Atlantique
|
||||
globeInstance.planet.viewExtentArr([-80, -30, 50, 50]);
|
||||
|
||||
// Rotation automatique
|
||||
let autoRotate = setInterval(() => {
|
||||
if (globeInstance && globeInstance.planet) {
|
||||
const cam = globeInstance.planet.camera;
|
||||
cam.rotateHorizontal(0.2);
|
||||
}
|
||||
}, 50);
|
||||
|
||||
// Nettoyage
|
||||
container.addEventListener('mousedown', () => {
|
||||
clearInterval(autoRotate);
|
||||
});
|
||||
};
|
||||
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
function createMarkerCanvas(color) {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 32;
|
||||
canvas.height = 32;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
// Cercle avec couleur
|
||||
ctx.beginPath();
|
||||
ctx.arc(16, 16, 12, 0, Math.PI * 2);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = '#000';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Point central
|
||||
ctx.beginPath();
|
||||
ctx.arc(16, 16, 4, 0, Math.PI * 2);
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.fill();
|
||||
|
||||
return canvas.toDataURL();
|
||||
}
|
||||
</script>
|
||||
|
||||
<section id="openglobus-section" class="globe-section">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Globe avec OpenGlobus</h2>
|
||||
<p class="section-subtitle">
|
||||
Bibliothèque 3D professionnelle avec textures réalistes
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="globe-container openglobus" class:visible>
|
||||
<div bind:this={container} class="openglobus-container"></div>
|
||||
|
||||
<div class="globe-info">
|
||||
<div class="info-card card">
|
||||
<h3>OpenGlobus</h3>
|
||||
<p><strong>Avantages :</strong></p>
|
||||
<ul>
|
||||
<li>✅ Textures satellite réalistes</li>
|
||||
<li>✅ Performance WebGL optimisée</li>
|
||||
<li>✅ Zoom et navigation fluides</li>
|
||||
<li>✅ Support natif des marqueurs</li>
|
||||
</ul>
|
||||
<p><strong>Inconvénients :</strong></p>
|
||||
<ul>
|
||||
<li>❌ Plus lourd (~500KB)</li>
|
||||
<li>❌ Nécessite connexion internet pour les tuiles</li>
|
||||
<li>❌ Personnalisation plus complexe</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.globe-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-dawn);
|
||||
}
|
||||
|
||||
.globe-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
align-items: center;
|
||||
margin-top: var(--spacing-lg);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.3s;
|
||||
}
|
||||
|
||||
.globe-container.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.openglobus-container {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.info-card h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-card ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.info-card li {
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.globe-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.openglobus-container {
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,271 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let container;
|
||||
let visible = false;
|
||||
let animationId;
|
||||
let scene, camera, renderer, globe, markers;
|
||||
|
||||
onMount(async () => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting && !scene) {
|
||||
visible = true;
|
||||
initGlobe();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('threejs-section');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
if (animationId) {
|
||||
cancelAnimationFrame(animationId);
|
||||
}
|
||||
if (renderer) {
|
||||
renderer.dispose();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
async function initGlobe() {
|
||||
// Charger Three.js depuis CDN
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js';
|
||||
script.onload = () => {
|
||||
createThreeJSGlobe();
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
function createThreeJSGlobe() {
|
||||
const THREE = window.THREE;
|
||||
|
||||
// Scène
|
||||
scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x0a1628);
|
||||
|
||||
// Caméra
|
||||
camera = new THREE.PerspectiveCamera(
|
||||
45,
|
||||
container.clientWidth / container.clientHeight,
|
||||
0.1,
|
||||
1000
|
||||
);
|
||||
camera.position.z = 2.5;
|
||||
|
||||
// Renderer
|
||||
renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
renderer.setPixelRatio(window.devicePixelRatio);
|
||||
container.appendChild(renderer.domElement);
|
||||
|
||||
// Lumières
|
||||
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
|
||||
scene.add(ambientLight);
|
||||
|
||||
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
||||
directionalLight.position.set(5, 3, 5);
|
||||
scene.add(directionalLight);
|
||||
|
||||
// Globe
|
||||
const geometry = new THREE.SphereGeometry(1, 64, 64);
|
||||
|
||||
// Texture de la Terre
|
||||
const textureLoader = new THREE.TextureLoader();
|
||||
const earthTexture = textureLoader.load(
|
||||
'https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_atmos_2048.jpg',
|
||||
() => { renderer.render(scene, camera); }
|
||||
);
|
||||
|
||||
const material = new THREE.MeshPhongMaterial({
|
||||
map: earthTexture,
|
||||
bumpScale: 0.05,
|
||||
specular: new THREE.Color('grey'),
|
||||
shininess: 10
|
||||
});
|
||||
|
||||
globe = new THREE.Mesh(geometry, material);
|
||||
scene.add(globe);
|
||||
|
||||
// Atmosphère
|
||||
const atmosphereGeometry = new THREE.SphereGeometry(1.1, 64, 64);
|
||||
const atmosphereMaterial = new THREE.MeshPhongMaterial({
|
||||
color: 0x4444ff,
|
||||
transparent: true,
|
||||
opacity: 0.1,
|
||||
side: THREE.BackSide
|
||||
});
|
||||
const atmosphere = new THREE.Mesh(atmosphereGeometry, atmosphereMaterial);
|
||||
scene.add(atmosphere);
|
||||
|
||||
// Marqueurs
|
||||
markers = new THREE.Group();
|
||||
scene.add(markers);
|
||||
|
||||
const locations = [
|
||||
{ name: 'La Réunion', lat: -21.1151, lon: 55.5364, color: 0xFF6B35 },
|
||||
{ name: 'Kinshasa', lat: -4.4419, lon: 15.2663, color: 0xFFA500 },
|
||||
{ name: 'Guadeloupe', lat: 16.2650, lon: -61.5510, color: 0xFFD700 },
|
||||
{ name: 'Martinique', lat: 14.6415, lon: -61.0242, color: 0xFFD700 },
|
||||
{ name: 'Dakar', lat: 14.7167, lon: -17.4677, color: 0xFFE44D },
|
||||
{ name: 'Le Caire', lat: 30.0444, lon: 31.2357, color: 0xFFFACD }
|
||||
];
|
||||
|
||||
locations.forEach(loc => {
|
||||
const markerGeometry = new THREE.SphereGeometry(0.02, 16, 16);
|
||||
const markerMaterial = new THREE.MeshBasicMaterial({ color: loc.color });
|
||||
const marker = new THREE.Mesh(markerGeometry, markerMaterial);
|
||||
|
||||
// Convertir lat/lon en position 3D
|
||||
const phi = (90 - loc.lat) * (Math.PI / 180);
|
||||
const theta = (loc.lon + 180) * (Math.PI / 180);
|
||||
|
||||
marker.position.x = -1.05 * Math.sin(phi) * Math.cos(theta);
|
||||
marker.position.y = 1.05 * Math.cos(phi);
|
||||
marker.position.z = 1.05 * Math.sin(phi) * Math.sin(theta);
|
||||
|
||||
markers.add(marker);
|
||||
});
|
||||
|
||||
// Contrôles de la souris
|
||||
let mouseX = 0, mouseY = 0;
|
||||
let isMouseDown = false;
|
||||
|
||||
container.addEventListener('mousedown', () => { isMouseDown = true; });
|
||||
container.addEventListener('mouseup', () => { isMouseDown = false; });
|
||||
container.addEventListener('mouseleave', () => { isMouseDown = false; });
|
||||
|
||||
container.addEventListener('mousemove', (e) => {
|
||||
if (isMouseDown) {
|
||||
mouseX = (e.clientX - container.offsetLeft) / container.clientWidth * 2 - 1;
|
||||
mouseY = -(e.clientY - container.offsetTop) / container.clientHeight * 2 + 1;
|
||||
}
|
||||
});
|
||||
|
||||
// Animation
|
||||
function animate() {
|
||||
animationId = requestAnimationFrame(animate);
|
||||
|
||||
// Rotation automatique
|
||||
if (!isMouseDown) {
|
||||
globe.rotation.y += 0.002;
|
||||
markers.rotation.y += 0.002;
|
||||
} else {
|
||||
// Rotation manuelle
|
||||
globe.rotation.y += mouseX * 0.05;
|
||||
globe.rotation.x = mouseY * 0.5;
|
||||
markers.rotation.y = globe.rotation.y;
|
||||
markers.rotation.x = globe.rotation.x;
|
||||
}
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
animate();
|
||||
|
||||
// Responsive
|
||||
window.addEventListener('resize', () => {
|
||||
camera.aspect = container.clientWidth / container.clientHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(container.clientWidth, container.clientHeight);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<section id="threejs-section" class="globe-section">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Globe avec Three.js</h2>
|
||||
<p class="section-subtitle">
|
||||
Rendu 3D WebGL avec textures réalistes
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="globe-container threejs" class:visible>
|
||||
<div bind:this={container} class="threejs-container"></div>
|
||||
|
||||
<div class="globe-info">
|
||||
<div class="info-card card">
|
||||
<h3>Three.js</h3>
|
||||
<p><strong>Avantages :</strong></p>
|
||||
<ul>
|
||||
<li>✅ Rendu 3D réaliste</li>
|
||||
<li>✅ Textures haute qualité</li>
|
||||
<li>✅ Effets atmosphériques</li>
|
||||
<li>✅ Très bien documenté</li>
|
||||
</ul>
|
||||
<p><strong>Inconvénients :</strong></p>
|
||||
<ul>
|
||||
<li>❌ Plus lourd (~150KB)</li>
|
||||
<li>❌ Nécessite WebGL</li>
|
||||
<li>❌ Plus complexe à personnaliser</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.globe-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-dawn);
|
||||
}
|
||||
|
||||
.globe-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
align-items: center;
|
||||
margin-top: var(--spacing-lg);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.3s;
|
||||
}
|
||||
|
||||
.globe-container.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.threejs-container {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border-radius: 20px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.threejs-container:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.info-card h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.info-card ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.info-card li {
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.globe-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.threejs-container {
|
||||
height: 400px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,544 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from '../lib/i18n.js';
|
||||
import anime from '../lib/anime.js';
|
||||
|
||||
let starsCanvas;
|
||||
let mouseX = 0.5;
|
||||
let mouseY = 0.5;
|
||||
let heroSection;
|
||||
|
||||
onMount(() => {
|
||||
const ctx = starsCanvas.getContext('2d');
|
||||
const stars = [];
|
||||
const starCount = 150;
|
||||
const shootingStars = [];
|
||||
|
||||
// Animation d'entrée avec AnimeJS
|
||||
anime.timeline({
|
||||
easing: 'easeOutQuad'
|
||||
})
|
||||
.add({
|
||||
targets: '.title-line',
|
||||
translateY: [50, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 1200,
|
||||
delay: anime.stagger(200)
|
||||
})
|
||||
.add({
|
||||
targets: '.hero-subtitle',
|
||||
translateY: [30, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 800
|
||||
}, '-=600')
|
||||
.add({
|
||||
targets: '.hero-description',
|
||||
translateY: [30, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 800
|
||||
}, '-=400')
|
||||
.add({
|
||||
targets: '.hero-date',
|
||||
translateY: [30, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 800
|
||||
}, '-=400')
|
||||
.add({
|
||||
targets: '.hero-cta .btn',
|
||||
scale: [0.8, 1],
|
||||
opacity: [0, 1],
|
||||
duration: 600,
|
||||
delay: anime.stagger(100)
|
||||
}, '-=400');
|
||||
|
||||
// Animation des patterns africains
|
||||
// Animation du système solaire gérée par CSS
|
||||
|
||||
// Attendre que le DOM soit prêt
|
||||
setTimeout(() => {
|
||||
// Redimensionner le canvas
|
||||
const resize = () => {
|
||||
const hero = starsCanvas.parentElement;
|
||||
starsCanvas.width = hero.offsetWidth;
|
||||
starsCanvas.height = hero.offsetHeight;
|
||||
|
||||
// Réinitialiser les étoiles après redimensionnement
|
||||
if (stars.length === 0) {
|
||||
for (let i = 0; i < starCount; i++) {
|
||||
stars.push({
|
||||
x: Math.random() * starsCanvas.width,
|
||||
y: Math.random() * starsCanvas.height,
|
||||
size: Math.random() * 2,
|
||||
brightness: Math.random(),
|
||||
speed: 0.1 + Math.random() * 0.5,
|
||||
pulseSpeed: 2000 + Math.random() * 3000
|
||||
});
|
||||
}
|
||||
|
||||
// Animer les étoiles avec AnimeJS
|
||||
stars.forEach((star, i) => {
|
||||
anime({
|
||||
targets: star,
|
||||
brightness: [0.1, 1, 0.1],
|
||||
duration: star.pulseSpeed,
|
||||
easing: 'easeInOutSine',
|
||||
loop: true,
|
||||
delay: i * 20
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
// Animation des étoiles
|
||||
const animate = () => {
|
||||
ctx.clearRect(0, 0, starsCanvas.width, starsCanvas.height);
|
||||
|
||||
// Effet de parallaxe avec la souris
|
||||
const offsetX = (mouseX - 0.5) * 20;
|
||||
const offsetY = (mouseY - 0.5) * 20;
|
||||
|
||||
// Dessiner les étoiles
|
||||
stars.forEach(star => {
|
||||
// Mouvement subtil
|
||||
star.x += Math.sin(Date.now() * 0.0001 * star.speed) * 0.5;
|
||||
star.y += Math.cos(Date.now() * 0.0001 * star.speed) * 0.3;
|
||||
|
||||
// Garder dans les limites
|
||||
if (star.x < 0) star.x = starsCanvas.width;
|
||||
if (star.x > starsCanvas.width) star.x = 0;
|
||||
if (star.y < 0) star.y = starsCanvas.height;
|
||||
if (star.y > starsCanvas.height) star.y = 0;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
star.x + offsetX,
|
||||
star.y + offsetY,
|
||||
star.size,
|
||||
0,
|
||||
Math.PI * 2
|
||||
);
|
||||
ctx.fillStyle = `rgba(255, 215, 0, ${star.brightness})`;
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
// Dessiner les étoiles filantes
|
||||
shootingStars.forEach((star, index) => {
|
||||
if (star.opacity <= 0) {
|
||||
shootingStars.splice(index, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(star.x, star.y);
|
||||
ctx.lineTo(star.x - star.vx * 20, star.y - star.vy * 20);
|
||||
ctx.strokeStyle = `rgba(255, 215, 0, ${star.opacity})`;
|
||||
ctx.lineWidth = star.size;
|
||||
ctx.stroke();
|
||||
|
||||
star.x += star.vx;
|
||||
star.y += star.vy;
|
||||
star.opacity -= 0.02;
|
||||
});
|
||||
|
||||
// Créer occasionnellement une étoile filante
|
||||
if (Math.random() < 0.01 && shootingStars.length < 3) {
|
||||
shootingStars.push({
|
||||
x: Math.random() * starsCanvas.width,
|
||||
y: Math.random() * starsCanvas.height * 0.5,
|
||||
vx: 5 + Math.random() * 10,
|
||||
vy: 2 + Math.random() * 5,
|
||||
size: 1 + Math.random() * 2,
|
||||
opacity: 1
|
||||
});
|
||||
}
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
animate();
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', resize);
|
||||
};
|
||||
}, 100);
|
||||
});
|
||||
|
||||
const handleMouseMove = (e) => {
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
mouseX = (e.clientX - rect.left) / rect.width;
|
||||
mouseY = (e.clientY - rect.top) / rect.height;
|
||||
};
|
||||
|
||||
// Animation du bouton au survol
|
||||
function handleButtonHover(e) {
|
||||
anime({
|
||||
targets: e.currentTarget,
|
||||
scale: 1.05,
|
||||
duration: 300,
|
||||
easing: 'easeOutElastic(1, .5)'
|
||||
});
|
||||
}
|
||||
|
||||
function handleButtonLeave(e) {
|
||||
anime({
|
||||
targets: e.currentTarget,
|
||||
scale: 1,
|
||||
duration: 300,
|
||||
easing: 'easeOutElastic(1, .5)'
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<section id="home" class="hero" on:mousemove={handleMouseMove} bind:this={heroSection}>
|
||||
<canvas bind:this={starsCanvas} class="stars-canvas"></canvas>
|
||||
|
||||
<div class="hero-pattern">
|
||||
<!-- Système solaire à gauche -->
|
||||
<div class="solar-system">
|
||||
<div class="sun"></div>
|
||||
<div class="orbit orbit-1">
|
||||
<div class="planet planet-1"></div>
|
||||
</div>
|
||||
<div class="orbit orbit-2">
|
||||
<div class="planet planet-2"></div>
|
||||
</div>
|
||||
<div class="orbit orbit-3">
|
||||
<div class="planet planet-3"></div>
|
||||
</div>
|
||||
<div class="orbit orbit-4">
|
||||
<div class="planet planet-4"></div>
|
||||
</div>
|
||||
<div class="orbit orbit-5">
|
||||
<div class="planet planet-5"></div>
|
||||
</div>
|
||||
<div class="orbit orbit-sirius">
|
||||
<div class="planet sirius"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-content">
|
||||
<div class="container">
|
||||
<div class="hero-text">
|
||||
<h1 class="hero-title">
|
||||
<span class="title-line">{$t('hero_title1')}</span>
|
||||
<span class="title-line">{$t('hero_title2')}</span>
|
||||
</h1>
|
||||
<p class="hero-subtitle">
|
||||
{$t('hero_subtitle')}
|
||||
</p>
|
||||
<p class="hero-description">
|
||||
{$t('hero_description')}
|
||||
</p>
|
||||
<p class="hero-date">
|
||||
{$t('hero_date')}<strong>{$t('hero_date_value')}</strong>
|
||||
</p>
|
||||
<div class="hero-cta">
|
||||
<a
|
||||
href="#predictions"
|
||||
class="btn btn-primary"
|
||||
on:mouseenter={handleButtonHover}
|
||||
on:mouseleave={handleButtonLeave}
|
||||
>
|
||||
{$t('hero_cta_predictions')}
|
||||
</a>
|
||||
<a
|
||||
href="#about"
|
||||
class="btn btn-outline"
|
||||
on:mouseenter={handleButtonHover}
|
||||
on:mouseleave={handleButtonLeave}
|
||||
>
|
||||
{$t('hero_cta_learn')}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.hero {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
background: var(--gradient-dawn);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.stars-canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero-pattern {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.pattern-overlay {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.1;
|
||||
background-size: 200px 200px;
|
||||
mix-blend-mode: overlay;
|
||||
}
|
||||
|
||||
|
||||
.solar-system {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
opacity: 0.8 !important;
|
||||
mix-blend-mode: normal !important;
|
||||
}
|
||||
|
||||
.sun {
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: radial-gradient(circle, #FFD700, #FFA500);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 20px #FFD700, 0 0 40px #FFA500;
|
||||
z-index: 10;
|
||||
animation: pulse 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.orbit {
|
||||
position: absolute;
|
||||
border: 1px solid rgba(255, 215, 0, 0.1);
|
||||
border-radius: 50%;
|
||||
animation: rotate linear infinite;
|
||||
}
|
||||
|
||||
.orbit-1 {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
animation-duration: 8s;
|
||||
}
|
||||
|
||||
.orbit-2 {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
animation-duration: 12s;
|
||||
}
|
||||
|
||||
.orbit-3 {
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
animation-duration: 16s;
|
||||
}
|
||||
|
||||
.orbit-4 {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
animation-duration: 20s;
|
||||
}
|
||||
|
||||
.orbit-5 {
|
||||
width: 240px;
|
||||
height: 240px;
|
||||
animation-duration: 24s;
|
||||
}
|
||||
|
||||
.orbit-sirius {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
animation-duration: 30s;
|
||||
border-color: rgba(135, 206, 250, 0.3);
|
||||
}
|
||||
|
||||
.planet {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
top: -4px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.planet-1 {
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: #8C7853;
|
||||
}
|
||||
|
||||
.planet-2 {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: #FFC649;
|
||||
}
|
||||
|
||||
.planet-3 {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: #6B93D6;
|
||||
}
|
||||
|
||||
.planet-4 {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background: #C1440E;
|
||||
}
|
||||
|
||||
.planet-5 {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: #D8CA9D;
|
||||
}
|
||||
|
||||
.sirius {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: radial-gradient(circle, #87CEEB, #4169E1);
|
||||
box-shadow: 0 0 10px #87CEEB, 0 0 20px #4169E1;
|
||||
animation: twinkle 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes twinkle {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
transform: translateX(-50%) scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.hero-content {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
padding: var(--spacing-xl) 0;
|
||||
}
|
||||
|
||||
.hero-text {
|
||||
max-width: 600px;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-size: clamp(3rem, 8vw, 5rem);
|
||||
font-weight: 700;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.title-line {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.title-line:nth-child(2) {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: clamp(1.2rem, 3vw, 1.5rem);
|
||||
color: var(--color-primary);
|
||||
font-family: var(--font-heading);
|
||||
margin-bottom: 0.5rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hero-description {
|
||||
font-size: clamp(1rem, 2.5vw, 1.2rem);
|
||||
color: var(--color-light);
|
||||
margin-bottom: 1rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hero-date {
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 2rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hero-date strong {
|
||||
color: var(--color-primary);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.hero-cta {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
opacity: 0;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
border: 2px solid var(--color-primary);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-dark);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.hero-title {
|
||||
font-size: clamp(2.5rem, 10vw, 4rem);
|
||||
}
|
||||
|
||||
.hero-cta {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,150 +0,0 @@
|
||||
<script>
|
||||
import { currentLanguage, availableLanguages, setLanguage } from '../lib/i18n.js';
|
||||
|
||||
let isOpen = false;
|
||||
|
||||
function toggleDropdown() {
|
||||
isOpen = !isOpen;
|
||||
}
|
||||
|
||||
function selectLanguage(lang) {
|
||||
setLanguage(lang);
|
||||
isOpen = false;
|
||||
}
|
||||
|
||||
// Fermer le dropdown si on clique ailleurs
|
||||
function handleClickOutside(event) {
|
||||
if (!event.target.closest('.language-selector')) {
|
||||
isOpen = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:click={handleClickOutside} />
|
||||
|
||||
<div class="language-selector">
|
||||
<button class="language-button" on:click={toggleDropdown}>
|
||||
<span class="flag">
|
||||
{availableLanguages.find(l => l.code === $currentLanguage)?.flag}
|
||||
</span>
|
||||
<span class="language-name">
|
||||
{availableLanguages.find(l => l.code === $currentLanguage)?.name}
|
||||
</span>
|
||||
<span class="arrow" class:open={isOpen}>▼</span>
|
||||
</button>
|
||||
|
||||
{#if isOpen}
|
||||
<div class="language-dropdown">
|
||||
{#each availableLanguages as lang}
|
||||
<button
|
||||
class="language-option"
|
||||
class:active={$currentLanguage === lang.code}
|
||||
on:click={() => selectLanguage(lang.code)}
|
||||
>
|
||||
<span class="flag">{lang.flag}</span>
|
||||
<span>{lang.name}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.language-selector {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.language-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 8px;
|
||||
color: var(--color-light);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.language-button:hover {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.flag {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.language-name {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 0.7rem;
|
||||
margin-left: 0.5rem;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.arrow.open {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.language-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
margin-top: 0.5rem;
|
||||
background: var(--color-dark);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
.language-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: var(--color-light);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.language-option:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.language-option.active {
|
||||
background: rgba(255, 215, 0, 0.2);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.language-name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.language-button {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,141 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import anime from '../lib/anime.js';
|
||||
|
||||
let loading = true;
|
||||
let progress = 0;
|
||||
|
||||
onMount(() => {
|
||||
// Animation de la barre de progression
|
||||
anime({
|
||||
targets: { value: 0 },
|
||||
value: 100,
|
||||
duration: 2000,
|
||||
easing: 'easeInOutQuad',
|
||||
update: function(anim) {
|
||||
progress = Math.round(anim.animations[0].currentValue);
|
||||
},
|
||||
complete: function() {
|
||||
setTimeout(() => {
|
||||
loading = false;
|
||||
// Animation de sortie
|
||||
anime({
|
||||
targets: '.loader',
|
||||
opacity: [1, 0],
|
||||
duration: 600,
|
||||
easing: 'easeOutQuad'
|
||||
});
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
// Animation des étoiles du loader
|
||||
anime({
|
||||
targets: '.loader-star',
|
||||
rotate: 360,
|
||||
duration: 2000,
|
||||
easing: 'linear',
|
||||
loop: true
|
||||
});
|
||||
|
||||
// Animation du texte
|
||||
anime({
|
||||
targets: '.loader-text span',
|
||||
translateY: [-20, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 800,
|
||||
delay: anime.stagger(100),
|
||||
easing: 'easeOutElastic(1, .5)'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if loading}
|
||||
<div class="loader">
|
||||
<div class="loader-content">
|
||||
<div class="loader-star">⭐</div>
|
||||
<div class="loader-text">
|
||||
<span>S</span>
|
||||
<span>i</span>
|
||||
<span>r</span>
|
||||
<span>i</span>
|
||||
<span>u</span>
|
||||
<span>s</span>
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" style="width: {progress}%"></div>
|
||||
</div>
|
||||
<div class="progress-text">{progress}%</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.loader {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: var(--color-dark);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.loader-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.loader-star {
|
||||
font-size: 4rem;
|
||||
margin-bottom: 1rem;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.loader-text {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 2rem;
|
||||
letter-spacing: 0.5rem;
|
||||
}
|
||||
|
||||
.loader-text span {
|
||||
display: inline-block;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 200px;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
margin: 0 auto 1rem;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: var(--color-primary);
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
color: var(--color-light);
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.loader-text {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.loader-star {
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,270 +0,0 @@
|
||||
<script>
|
||||
import { t } from '../lib/i18n.js';
|
||||
import LanguageSelector from './LanguageSelector.svelte';
|
||||
import anime from '../lib/anime.js';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let activeSection = 'home';
|
||||
|
||||
let isMenuOpen = false;
|
||||
let navbar;
|
||||
|
||||
const toggleMenu = () => {
|
||||
isMenuOpen = !isMenuOpen;
|
||||
|
||||
if (isMenuOpen) {
|
||||
anime({
|
||||
targets: '.nav-menu',
|
||||
translateX: [300, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 400,
|
||||
easing: 'easeOutQuad'
|
||||
});
|
||||
|
||||
anime({
|
||||
targets: '.nav-menu li',
|
||||
translateX: [50, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 600,
|
||||
delay: anime.stagger(50),
|
||||
easing: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
// Animation d'entrée de la navbar
|
||||
anime({
|
||||
targets: navbar,
|
||||
translateY: [-100, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 800,
|
||||
easing: 'easeOutQuad'
|
||||
});
|
||||
|
||||
// Animation du logo
|
||||
anime({
|
||||
targets: '.logo-icon',
|
||||
rotate: [0, 360],
|
||||
duration: 2000,
|
||||
delay: 500,
|
||||
easing: 'easeInOutQuad'
|
||||
});
|
||||
});
|
||||
|
||||
const menuItems = [
|
||||
{ id: 'home', label: 'nav_home', icon: '🌟' },
|
||||
{ id: 'about', label: 'nav_about', icon: '✨' },
|
||||
{ id: 'predictions', label: 'nav_predictions', icon: '📅' },
|
||||
{ id: 'science', label: 'nav_science', icon: '🔭' },
|
||||
{ id: 'culture', label: 'nav_culture', icon: '🌍' },
|
||||
{ id: 'observatory', label: 'nav_observatory', icon: '👁️' },
|
||||
{ id: 'associations', label: 'nav_associations', icon: '🤝' }
|
||||
];
|
||||
|
||||
const scrollToSection = (id) => {
|
||||
document.getElementById(id)?.scrollIntoView({ behavior: 'smooth' });
|
||||
isMenuOpen = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<nav class="navbar" class:scrolled={activeSection !== 'home'} bind:this={navbar}>
|
||||
<div class="container">
|
||||
<div class="nav-content">
|
||||
<a href="#home" class="logo" on:click|preventDefault={() => scrollToSection('home')}>
|
||||
<span class="logo-icon">☥</span>
|
||||
<span class="logo-text">Sirius Gwada</span>
|
||||
</a>
|
||||
|
||||
<button class="menu-toggle" on:click={toggleMenu} aria-label="Menu">
|
||||
<span class="hamburger" class:active={isMenuOpen}></span>
|
||||
</button>
|
||||
|
||||
<ul class="nav-menu" class:open={isMenuOpen}>
|
||||
{#each menuItems as item}
|
||||
<li>
|
||||
<a
|
||||
href="#{item.id}"
|
||||
class:active={activeSection === item.id}
|
||||
on:click|preventDefault={() => scrollToSection(item.id)}
|
||||
>
|
||||
<span class="nav-icon">{item.icon}</span>
|
||||
<span class="nav-label">{$t(item.label)}</span>
|
||||
</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<LanguageSelector />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<style>
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
background: rgba(26, 26, 46, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
transition: var(--transition-base);
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.navbar.scrolled {
|
||||
border-bottom-color: rgba(255, 215, 0, 0.2);
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.nav-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
text-decoration: none;
|
||||
color: var(--color-primary);
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.5rem;
|
||||
transition: var(--transition-base);
|
||||
}
|
||||
|
||||
.logo:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.logo-icon {
|
||||
font-size: 2rem;
|
||||
animation: rotate 20s linear infinite;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
display: none;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.hamburger {
|
||||
display: block;
|
||||
width: 25px;
|
||||
height: 2px;
|
||||
background: var(--color-primary);
|
||||
position: relative;
|
||||
transition: var(--transition-base);
|
||||
}
|
||||
|
||||
.hamburger::before,
|
||||
.hamburger::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: var(--color-primary);
|
||||
transition: var(--transition-base);
|
||||
}
|
||||
|
||||
.hamburger::before {
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
.hamburger::after {
|
||||
bottom: -8px;
|
||||
}
|
||||
|
||||
.hamburger.active {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.hamburger.active::before {
|
||||
transform: rotate(45deg);
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.hamburger.active::after {
|
||||
transform: rotate(-45deg);
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
list-style: none;
|
||||
gap: 2rem;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-menu a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
text-decoration: none;
|
||||
color: var(--color-light);
|
||||
transition: var(--transition-base);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-menu a:hover,
|
||||
.nav-menu a.active {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.nav-menu a::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: var(--color-primary);
|
||||
transform: scaleX(0);
|
||||
transition: var(--transition-base);
|
||||
}
|
||||
|
||||
.nav-menu a.active::after {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media (max-width: 768px) {
|
||||
.menu-toggle {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
position: fixed;
|
||||
top: 70px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(26, 26, 46, 0.98);
|
||||
flex-direction: column;
|
||||
padding: 2rem;
|
||||
transform: translateY(-100%);
|
||||
opacity: 0;
|
||||
transition: var(--transition-base);
|
||||
border-bottom: 2px solid var(--color-primary);
|
||||
}
|
||||
|
||||
.nav-menu.open {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.nav-menu a {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,661 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let visible = false;
|
||||
let selectedSite = null;
|
||||
let mapCanvas;
|
||||
let ctx;
|
||||
let guadeloupeGeoJson = null;
|
||||
|
||||
const sites = [
|
||||
{
|
||||
id: 'moule',
|
||||
name: 'Le Moule',
|
||||
lat: 16.3333,
|
||||
lng: -61.3472,
|
||||
description: 'Plage de l\'Autre Bord - Vue dégagée sur l\'Est',
|
||||
features: ['Plage isolée', 'Horizon Est dégagé', 'Peu de pollution lumineuse'],
|
||||
bestTime: '5h00 - 5h30',
|
||||
image: '🏖️'
|
||||
},
|
||||
{
|
||||
id: 'deshaies',
|
||||
name: 'Deshaies',
|
||||
lat: 16.3039,
|
||||
lng: -61.7966,
|
||||
description: 'Plage de Grande Anse - Cadre idyllique',
|
||||
features: ['Plage populaire', 'Montagnes en arrière-plan', 'Accès facile'],
|
||||
bestTime: '5h15 - 5h45',
|
||||
image: '🌅'
|
||||
},
|
||||
{
|
||||
id: 'sainte-anne',
|
||||
name: 'Sainte-Anne',
|
||||
lat: 16.2262,
|
||||
lng: -61.3809,
|
||||
description: 'Plage de Bois Jolan - Tranquillité garantie',
|
||||
features: ['Plage sauvage', 'Très peu fréquentée', 'Nature préservée'],
|
||||
bestTime: '5h00 - 5h30',
|
||||
image: '🌴'
|
||||
},
|
||||
{
|
||||
id: 'port-louis',
|
||||
name: 'Port-Louis',
|
||||
lat: 16.4180,
|
||||
lng: -61.5312,
|
||||
description: 'Plage du Souffleur - Vue panoramique',
|
||||
features: ['Vue à 180°', 'Site historique', 'Calme au petit matin'],
|
||||
bestTime: '5h00 - 5h30',
|
||||
image: '🏛️'
|
||||
},
|
||||
{
|
||||
id: 'marie-galante',
|
||||
name: 'Marie-Galante',
|
||||
lat: 15.9500,
|
||||
lng: -61.2667,
|
||||
description: 'Plage de la Feuillère - Horizon infini',
|
||||
features: ['Île préservée', 'Ciel très noir', 'Conditions optimales'],
|
||||
bestTime: '4h45 - 5h15',
|
||||
image: '🏝️'
|
||||
},
|
||||
{
|
||||
id: 'soufriere',
|
||||
name: 'Route de la Soufrière',
|
||||
lat: 16.0439,
|
||||
lng: -61.6639,
|
||||
description: 'Parking de Savane à Mulets - Altitude',
|
||||
features: ['1000m altitude', 'Air pur', 'Vue dégagée', 'Nuits fraîches'],
|
||||
bestTime: '5h00 - 5h30',
|
||||
image: '🌋'
|
||||
},
|
||||
{
|
||||
id: 'petite-terre',
|
||||
name: 'Petite-Terre',
|
||||
lat: 16.1700,
|
||||
lng: -61.1200,
|
||||
description: 'Réserve naturelle - Conditions parfaites',
|
||||
features: ['Aucune pollution lumineuse', 'Réserve protégée', 'Accès réglementé'],
|
||||
bestTime: '4h45 - 5h15',
|
||||
image: '🦎'
|
||||
}
|
||||
];
|
||||
|
||||
onMount(async () => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting && !ctx) {
|
||||
visible = true;
|
||||
initMap();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('observation-map');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
async function initMap() {
|
||||
ctx = mapCanvas.getContext('2d');
|
||||
|
||||
// Charger les données GeoJSON de la Guadeloupe
|
||||
try {
|
||||
const response = await fetch('https://raw.githubusercontent.com/gregoiredavid/france-geojson/master/regions/guadeloupe/departements-guadeloupe.geojson');
|
||||
guadeloupeGeoJson = await response.json();
|
||||
|
||||
// Redimensionner le canvas
|
||||
resizeCanvas();
|
||||
window.addEventListener('resize', resizeCanvas);
|
||||
|
||||
// Dessiner la carte
|
||||
drawMap();
|
||||
} catch (error) {
|
||||
console.error('Erreur de chargement GeoJSON:', error);
|
||||
// Fallback : dessiner une carte simple
|
||||
drawSimpleMap();
|
||||
}
|
||||
}
|
||||
|
||||
function resizeCanvas() {
|
||||
const container = mapCanvas.parentElement;
|
||||
mapCanvas.width = container.offsetWidth;
|
||||
mapCanvas.height = container.offsetWidth * 0.75; // Ratio 4:3
|
||||
if (guadeloupeGeoJson) drawMap();
|
||||
}
|
||||
|
||||
function drawMap() {
|
||||
if (!ctx || !guadeloupeGeoJson) return;
|
||||
|
||||
// Effacer le canvas
|
||||
ctx.clearRect(0, 0, mapCanvas.width, mapCanvas.height);
|
||||
|
||||
// Fond océan
|
||||
ctx.fillStyle = '#1a3a52';
|
||||
ctx.fillRect(0, 0, mapCanvas.width, mapCanvas.height);
|
||||
|
||||
// Calculer les limites et l'échelle
|
||||
const bounds = calculateBounds(guadeloupeGeoJson);
|
||||
const scale = calculateScale(bounds, mapCanvas.width, mapCanvas.height);
|
||||
|
||||
// Dessiner chaque feature
|
||||
guadeloupeGeoJson.features.forEach(feature => {
|
||||
drawFeature(feature, bounds, scale);
|
||||
});
|
||||
|
||||
// Dessiner les sites
|
||||
drawSites(bounds, scale);
|
||||
}
|
||||
|
||||
function drawSimpleMap() {
|
||||
if (!ctx) return;
|
||||
|
||||
// Effacer le canvas
|
||||
ctx.clearRect(0, 0, mapCanvas.width, mapCanvas.height);
|
||||
|
||||
// Fond océan
|
||||
ctx.fillStyle = '#1a3a52';
|
||||
ctx.fillRect(0, 0, mapCanvas.width, mapCanvas.height);
|
||||
|
||||
// Dessiner une forme approximative de la Guadeloupe
|
||||
const centerX = mapCanvas.width / 2;
|
||||
const centerY = mapCanvas.height / 2;
|
||||
const scale = mapCanvas.width / 4;
|
||||
|
||||
// Grande-Terre
|
||||
ctx.fillStyle = '#2d5a3d';
|
||||
ctx.strokeStyle = '#4CAF50';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX + scale * 0.5, centerY - scale * 0.2, scale * 0.4, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// Basse-Terre
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX - scale * 0.3, centerY, scale * 0.5, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// Marie-Galante
|
||||
ctx.beginPath();
|
||||
ctx.arc(centerX + scale * 0.2, centerY + scale * 0.8, scale * 0.25, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
|
||||
// Dessiner les sites avec des positions approximatives
|
||||
const bounds = { minLng: -62, maxLng: -61, minLat: 15.8, maxLat: 16.5 };
|
||||
const simpleScale = {
|
||||
x: mapCanvas.width / (bounds.maxLng - bounds.minLng),
|
||||
y: mapCanvas.height / (bounds.maxLat - bounds.minLat)
|
||||
};
|
||||
|
||||
drawSites(bounds, simpleScale);
|
||||
}
|
||||
|
||||
function calculateBounds(geoJson) {
|
||||
let minLng = Infinity, maxLng = -Infinity;
|
||||
let minLat = Infinity, maxLat = -Infinity;
|
||||
|
||||
function processBounds(coords) {
|
||||
if (Array.isArray(coords[0])) {
|
||||
coords.forEach(processBounds);
|
||||
} else {
|
||||
minLng = Math.min(minLng, coords[0]);
|
||||
maxLng = Math.max(maxLng, coords[0]);
|
||||
minLat = Math.min(minLat, coords[1]);
|
||||
maxLat = Math.max(maxLat, coords[1]);
|
||||
}
|
||||
}
|
||||
|
||||
geoJson.features.forEach(feature => {
|
||||
if (feature.geometry && feature.geometry.coordinates) {
|
||||
processBounds(feature.geometry.coordinates);
|
||||
}
|
||||
});
|
||||
|
||||
// Ajouter une marge
|
||||
const margin = 0.1;
|
||||
return {
|
||||
minLng: minLng - margin,
|
||||
maxLng: maxLng + margin,
|
||||
minLat: minLat - margin,
|
||||
maxLat: maxLat + margin
|
||||
};
|
||||
}
|
||||
|
||||
function calculateScale(bounds, width, height) {
|
||||
return {
|
||||
x: width / (bounds.maxLng - bounds.minLng),
|
||||
y: height / (bounds.maxLat - bounds.minLat)
|
||||
};
|
||||
}
|
||||
|
||||
function projectPoint(lng, lat, bounds, scale) {
|
||||
return {
|
||||
x: (lng - bounds.minLng) * scale.x,
|
||||
y: mapCanvas.height - (lat - bounds.minLat) * scale.y
|
||||
};
|
||||
}
|
||||
|
||||
function drawFeature(feature, bounds, scale) {
|
||||
ctx.fillStyle = '#2d5a3d';
|
||||
ctx.strokeStyle = '#4CAF50';
|
||||
ctx.lineWidth = 2;
|
||||
|
||||
function drawCoordinates(coords) {
|
||||
if (!coords || coords.length === 0) return;
|
||||
|
||||
if (Array.isArray(coords[0][0])) {
|
||||
coords.forEach(drawCoordinates);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
coords.forEach((coord, i) => {
|
||||
const point = projectPoint(coord[0], coord[1], bounds, scale);
|
||||
if (i === 0) {
|
||||
ctx.moveTo(point.x, point.y);
|
||||
} else {
|
||||
ctx.lineTo(point.x, point.y);
|
||||
}
|
||||
});
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
if (feature.geometry && feature.geometry.coordinates) {
|
||||
drawCoordinates(feature.geometry.coordinates);
|
||||
}
|
||||
}
|
||||
|
||||
function drawSites(bounds, scale) {
|
||||
sites.forEach(site => {
|
||||
const point = projectPoint(site.lng, site.lat, bounds, scale);
|
||||
|
||||
// Cercle du marqueur
|
||||
ctx.beginPath();
|
||||
ctx.arc(point.x, point.y, selectedSite?.id === site.id ? 15 : 10, 0, Math.PI * 2);
|
||||
ctx.fillStyle = selectedSite?.id === site.id ? '#FFD700' : '#FF6B35';
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = 'white';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Icône du site
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.font = selectedSite?.id === site.id ? '18px sans-serif' : '14px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(site.image, point.x, point.y);
|
||||
|
||||
// Nom du site si sélectionné
|
||||
if (selectedSite?.id === site.id) {
|
||||
ctx.fillStyle = 'white';
|
||||
ctx.font = 'bold 14px sans-serif';
|
||||
ctx.fillText(site.name, point.x, point.y + 25);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleMapClick(event) {
|
||||
const rect = mapCanvas.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
|
||||
// Vérifier si on clique sur un site
|
||||
const bounds = guadeloupeGeoJson ?
|
||||
calculateBounds(guadeloupeGeoJson) :
|
||||
{ minLng: -62, maxLng: -61, minLat: 15.8, maxLat: 16.5 };
|
||||
|
||||
const scale = guadeloupeGeoJson ?
|
||||
calculateScale(bounds, mapCanvas.width, mapCanvas.height) :
|
||||
{ x: mapCanvas.width / (bounds.maxLng - bounds.minLng),
|
||||
y: mapCanvas.height / (bounds.maxLat - bounds.minLat) };
|
||||
|
||||
let clickedSite = null;
|
||||
sites.forEach(site => {
|
||||
const point = projectPoint(site.lng, site.lat, bounds, scale);
|
||||
const distance = Math.sqrt(Math.pow(x - point.x, 2) + Math.pow(y - point.y, 2));
|
||||
if (distance < 20) {
|
||||
clickedSite = site;
|
||||
}
|
||||
});
|
||||
|
||||
if (clickedSite) {
|
||||
selectedSite = selectedSite?.id === clickedSite.id ? null : clickedSite;
|
||||
drawMap();
|
||||
}
|
||||
}
|
||||
|
||||
function selectSite(site) {
|
||||
selectedSite = selectedSite?.id === site.id ? null : site;
|
||||
if (guadeloupeGeoJson) {
|
||||
drawMap();
|
||||
} else {
|
||||
drawSimpleMap();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section id="observation-map" class="map-section">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Carte des Sites d'Observation</h2>
|
||||
<p class="section-subtitle">
|
||||
Les meilleurs endroits en Guadeloupe pour observer le lever héliaque
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="map-wrapper" class:visible>
|
||||
<!-- Carte Canvas de la Guadeloupe -->
|
||||
<div class="map-container">
|
||||
<canvas
|
||||
bind:this={mapCanvas}
|
||||
class="guadeloupe-map"
|
||||
on:click={handleMapClick}
|
||||
></canvas>
|
||||
</div>
|
||||
|
||||
<!-- Liste des sites -->
|
||||
<div class="sites-list">
|
||||
<h3>Sites d'Observation</h3>
|
||||
{#each sites as site}
|
||||
<div
|
||||
class="site-card"
|
||||
class:active={selectedSite?.id === site.id}
|
||||
on:click={() => selectSite(site)}
|
||||
>
|
||||
<div class="site-header">
|
||||
<span class="site-icon">{site.image}</span>
|
||||
<h4>{site.name}</h4>
|
||||
</div>
|
||||
<p class="site-description">{site.description}</p>
|
||||
|
||||
{#if selectedSite?.id === site.id}
|
||||
<div class="site-details">
|
||||
<div class="features">
|
||||
<h5>Caractéristiques :</h5>
|
||||
<ul>
|
||||
{#each site.features as feature}
|
||||
<li>{feature}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="observation-time">
|
||||
<h5>🕐 Meilleur créneau :</h5>
|
||||
<p>{site.bestTime}</p>
|
||||
</div>
|
||||
<div class="coordinates">
|
||||
<h5>📍 Coordonnées GPS :</h5>
|
||||
<p>{site.lat}°N, {Math.abs(site.lng)}°O</p>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Conseils d'observation -->
|
||||
<div class="observation-tips" class:visible>
|
||||
<h3>Conseils pour l'Observation</h3>
|
||||
<div class="tips-grid">
|
||||
<div class="tip-card">
|
||||
<span class="tip-icon">🌙</span>
|
||||
<h4>Phase Lunaire</h4>
|
||||
<p>Privilégiez les nuits sans Lune ou avec un fin croissant</p>
|
||||
</div>
|
||||
<div class="tip-card">
|
||||
<span class="tip-icon">☁️</span>
|
||||
<h4>Météo</h4>
|
||||
<p>Vérifiez l'absence de nuages à l'Est, surtout près de l'horizon</p>
|
||||
</div>
|
||||
<div class="tip-card">
|
||||
<span class="tip-icon">⏰</span>
|
||||
<h4>Horaire</h4>
|
||||
<p>Arrivez 30 minutes avant pour habituer vos yeux à l'obscurité</p>
|
||||
</div>
|
||||
<div class="tip-card">
|
||||
<span class="tip-icon">🔦</span>
|
||||
<h4>Équipement</h4>
|
||||
<p>Lampe rouge, jumelles optionnelles, vêtements chauds</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.map-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-night);
|
||||
}
|
||||
|
||||
.map-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: var(--spacing-lg);
|
||||
margin-top: var(--spacing-lg);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out;
|
||||
}
|
||||
|
||||
.map-wrapper.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Carte Canvas */
|
||||
.map-container {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.guadeloupe-map {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* Liste des sites */
|
||||
.sites-list {
|
||||
max-height: 600px;
|
||||
overflow-y: auto;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.sites-list h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.site-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 15px;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.site-card:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.site-card.active {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.site-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.site-icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.site-header h4 {
|
||||
color: var(--color-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.site-description {
|
||||
color: var(--color-light);
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.site-details {
|
||||
margin-top: 1rem;
|
||||
padding-top: 1rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
animation: slideDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
.site-details h5 {
|
||||
color: var(--color-secondary);
|
||||
margin: 0.5rem 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.site-details ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.site-details li {
|
||||
padding: 0.25rem 0;
|
||||
padding-left: 1rem;
|
||||
position: relative;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.site-details li::before {
|
||||
content: "•";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.observation-time, .coordinates {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.observation-time p, .coordinates p {
|
||||
margin: 0;
|
||||
color: var(--color-light);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Conseils d'observation */
|
||||
.observation-tips {
|
||||
margin-top: var(--spacing-xl);
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.2s;
|
||||
}
|
||||
|
||||
.observation-tips.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.observation-tips h3 {
|
||||
color: var(--color-primary);
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.tips-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.tip-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
text-align: center;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.tip-card:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
font-size: 2.5rem;
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.tip-card h4 {
|
||||
color: var(--color-primary);
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.tip-card p {
|
||||
color: var(--color-light);
|
||||
margin: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Scrollbar personnalisée */
|
||||
.sites-list::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
.sites-list::-webkit-scrollbar-track {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.sites-list::-webkit-scrollbar-thumb {
|
||||
background: var(--color-primary);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
max-height: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
max-height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.map-wrapper {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.map-container {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.sites-list {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.tips-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,435 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import anime from '../lib/anime.js';
|
||||
|
||||
let visible = false;
|
||||
let activePhase = 0;
|
||||
|
||||
const observationPhases = [
|
||||
{
|
||||
time: '04h30',
|
||||
title: 'Préparation',
|
||||
description: 'Arrivez sur site, laissez vos yeux s\'adapter',
|
||||
icon: '🌙'
|
||||
},
|
||||
{
|
||||
time: '05h00',
|
||||
title: 'Recherche',
|
||||
description: 'Cherchez vers l\'Est-Sud-Est, près de l\'horizon',
|
||||
icon: '🔭'
|
||||
},
|
||||
{
|
||||
time: '05h15',
|
||||
title: 'Apparition',
|
||||
description: 'Sirius émerge de la lueur de l\'aube',
|
||||
icon: '⭐'
|
||||
},
|
||||
{
|
||||
time: '05h30',
|
||||
title: 'Observation',
|
||||
description: 'Moment optimal pour contempler',
|
||||
icon: '✨'
|
||||
}
|
||||
];
|
||||
|
||||
const equipment = [
|
||||
{ item: 'Jumelles', essential: false, description: '7x50 ou 10x50 recommandées' },
|
||||
{ item: 'Lampe rouge', essential: true, description: 'Préserve la vision nocturne' },
|
||||
{ item: 'Boussole', essential: true, description: 'Pour trouver l\'Est' },
|
||||
{ item: 'Vêtements chauds', essential: true, description: 'Les matins sont frais' },
|
||||
{ item: 'Carnet de notes', essential: false, description: 'Pour documenter l\'observation' }
|
||||
];
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
visible = true;
|
||||
|
||||
// Animation d'entrée
|
||||
anime.timeline({
|
||||
easing: 'easeOutQuad'
|
||||
})
|
||||
.add({
|
||||
targets: '.section-header',
|
||||
translateY: [30, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 800
|
||||
})
|
||||
.add({
|
||||
targets: '.timeline-container',
|
||||
translateX: [-50, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 1000
|
||||
}, '-=400')
|
||||
.add({
|
||||
targets: '.timeline-phase',
|
||||
scale: [0.8, 1],
|
||||
opacity: [0, 1],
|
||||
duration: 600,
|
||||
delay: anime.stagger(150)
|
||||
}, '-=600')
|
||||
.add({
|
||||
targets: '.equipment-grid',
|
||||
translateY: [50, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 800
|
||||
}, '-=400');
|
||||
|
||||
// Animation de la timeline automatique
|
||||
startTimelineAnimation();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('observatory');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
function startTimelineAnimation() {
|
||||
// Progression automatique de la timeline
|
||||
const timeline = anime.timeline({
|
||||
loop: true,
|
||||
autoplay: true
|
||||
});
|
||||
|
||||
observationPhases.forEach((phase, index) => {
|
||||
timeline.add({
|
||||
targets: {},
|
||||
duration: 3000,
|
||||
changeBegin: () => {
|
||||
activePhase = index;
|
||||
animatePhaseChange(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function animatePhaseChange(index) {
|
||||
// Animation de l'indicateur actif
|
||||
anime({
|
||||
targets: '.timeline-indicator',
|
||||
left: `${index * 25}%`,
|
||||
duration: 800,
|
||||
easing: 'easeInOutQuad'
|
||||
});
|
||||
|
||||
// Pulsation de la phase active
|
||||
anime({
|
||||
targets: `.timeline-phase:nth-child(${index + 1}) .phase-icon`,
|
||||
scale: [1, 1.2, 1],
|
||||
duration: 600,
|
||||
easing: 'easeInOutQuad'
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<section id="observatory" class="observatory">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>Guide d'Observation</h2>
|
||||
<p class="section-subtitle">
|
||||
Tout ce qu'il faut savoir pour observer le lever héliaque
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="observatory-content" class:visible>
|
||||
<!-- Timeline d'observation -->
|
||||
<div class="timeline-container">
|
||||
<h3>Chronologie de l'Observation</h3>
|
||||
<div class="timeline">
|
||||
<div class="timeline-track"></div>
|
||||
<div class="timeline-indicator"></div>
|
||||
{#each observationPhases as phase, i}
|
||||
<div class="timeline-phase" class:active={activePhase === i}>
|
||||
<div class="phase-icon">{phase.icon}</div>
|
||||
<div class="phase-time">{phase.time}</div>
|
||||
<div class="phase-info">
|
||||
<h4>{phase.title}</h4>
|
||||
<p>{phase.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Équipement recommandé -->
|
||||
<div class="equipment-section">
|
||||
<h3>Équipement Recommandé</h3>
|
||||
<div class="equipment-grid">
|
||||
{#each equipment as item, i}
|
||||
<div
|
||||
class="equipment-card"
|
||||
class:essential={item.essential}
|
||||
style="animation-delay: {i * 0.1}s"
|
||||
>
|
||||
<div class="equipment-header">
|
||||
<span class="equipment-name">{item.item}</span>
|
||||
{#if item.essential}
|
||||
<span class="essential-badge">Essentiel</span>
|
||||
{/if}
|
||||
</div>
|
||||
<p class="equipment-desc">{item.description}</p>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Conseils pratiques -->
|
||||
<div class="tips-section">
|
||||
<h3>Conseils Pratiques</h3>
|
||||
<div class="tips-grid">
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">🌤️</div>
|
||||
<h4>Météo Idéale</h4>
|
||||
<p>Ciel dégagé à l'Est, pas de nuages bas, humidité modérée</p>
|
||||
</div>
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">🌑</div>
|
||||
<h4>Phase Lunaire</h4>
|
||||
<p>Nouvelle lune ou croissant fin pour un ciel plus sombre</p>
|
||||
</div>
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">📱</div>
|
||||
<h4>Applications Utiles</h4>
|
||||
<p>Stellarium, SkySafari, Star Walk pour repérer les constellations</p>
|
||||
</div>
|
||||
<div class="tip-card">
|
||||
<div class="tip-icon">👥</div>
|
||||
<h4>En Groupe</h4>
|
||||
<p>Partagez ce moment unique avec famille et amis</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.observatory {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-dawn);
|
||||
}
|
||||
|
||||
.observatory-content {
|
||||
margin-top: var(--spacing-lg);
|
||||
}
|
||||
|
||||
/* Timeline */
|
||||
.timeline-container {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
margin-bottom: 3rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.timeline-container h3 {
|
||||
color: var(--color-primary);
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.timeline {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 2rem 0;
|
||||
}
|
||||
|
||||
.timeline-track {
|
||||
position: absolute;
|
||||
top: 3rem;
|
||||
left: 5%;
|
||||
right: 5%;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.timeline-indicator {
|
||||
position: absolute;
|
||||
top: 3rem;
|
||||
left: 0;
|
||||
width: 25%;
|
||||
height: 4px;
|
||||
background: var(--color-primary);
|
||||
border-radius: 2px;
|
||||
transition: left 0.8s ease-in-out;
|
||||
}
|
||||
|
||||
.timeline-phase {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
.phase-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
filter: grayscale(1);
|
||||
opacity: 0.5;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.timeline-phase.active .phase-icon {
|
||||
filter: grayscale(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.phase-time {
|
||||
font-weight: 600;
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.phase-info h4 {
|
||||
color: var(--color-light);
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.phase-info p {
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Équipement */
|
||||
.equipment-section {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.equipment-section h3 {
|
||||
color: var(--color-primary);
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.equipment-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 1.5rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.equipment-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
border: 2px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
animation: fadeInUp 0.8s ease-out forwards;
|
||||
}
|
||||
|
||||
.equipment-card.essential {
|
||||
border-color: var(--color-primary);
|
||||
background: rgba(255, 215, 0, 0.05);
|
||||
}
|
||||
|
||||
.equipment-card:hover {
|
||||
transform: translateY(-5px);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.equipment-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.equipment-name {
|
||||
font-weight: 600;
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.essential-badge {
|
||||
background: var(--color-primary);
|
||||
color: var(--color-dark);
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.equipment-desc {
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Conseils */
|
||||
.tips-section h3 {
|
||||
color: var(--color-primary);
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.tips-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.tip-card {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
animation: fadeInUp 0.8s ease-out forwards;
|
||||
}
|
||||
|
||||
.tip-card:hover {
|
||||
transform: translateY(-5px);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
font-size: 2.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.tip-card h4 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.tip-card p {
|
||||
font-size: 0.9rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.timeline {
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.timeline-track {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.timeline-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.equipment-grid, .tips-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,430 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
import { t } from '../lib/i18n.js';
|
||||
import anime from '../lib/anime.js';
|
||||
|
||||
let visible = false;
|
||||
let selectedLocation = 'moule';
|
||||
let calculationInProgress = false;
|
||||
let results = null;
|
||||
|
||||
const locations = [
|
||||
{ id: 'moule', name: 'Le Moule', lat: 16.3333, lng: -61.3472 },
|
||||
{ id: 'deshaies', name: 'Deshaies', lat: 16.3039, lng: -61.7966 },
|
||||
{ id: 'sainte-anne', name: 'Sainte-Anne', lat: 16.2262, lng: -61.3809 },
|
||||
{ id: 'port-louis', name: 'Port-Louis', lat: 16.4180, lng: -61.5312 },
|
||||
{ id: 'marie-galante', name: 'Marie-Galante', lat: 15.9500, lng: -61.2667 },
|
||||
{ id: 'soufriere', name: 'Route de la Soufrière', lat: 16.0439, lng: -61.6639 },
|
||||
{ id: 'petite-terre', name: 'Petite-Terre', lat: 16.1700, lng: -61.1200 }
|
||||
];
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
visible = true;
|
||||
|
||||
// Animation d'entrée
|
||||
anime.timeline({
|
||||
easing: 'easeOutQuad'
|
||||
})
|
||||
.add({
|
||||
targets: '.section-header',
|
||||
translateY: [30, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 800
|
||||
})
|
||||
.add({
|
||||
targets: '.calculator-container',
|
||||
translateY: [50, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 1000
|
||||
}, '-=400')
|
||||
.add({
|
||||
targets: '.location-option',
|
||||
translateX: [-20, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 600,
|
||||
delay: anime.stagger(50)
|
||||
}, '-=600');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('predictions');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
function selectLocation(id) {
|
||||
selectedLocation = id;
|
||||
calculate();
|
||||
|
||||
// Animation de sélection
|
||||
anime({
|
||||
targets: `.location-option`,
|
||||
scale: 1,
|
||||
duration: 300
|
||||
});
|
||||
|
||||
anime({
|
||||
targets: `[data-location="${id}"]`,
|
||||
scale: 1.05,
|
||||
duration: 300,
|
||||
easing: 'easeOutElastic(1, .5)'
|
||||
});
|
||||
}
|
||||
|
||||
function calculate() {
|
||||
calculationInProgress = true;
|
||||
results = null;
|
||||
|
||||
// Animation du calcul
|
||||
anime({
|
||||
targets: '.calculating-indicator',
|
||||
opacity: [0, 1],
|
||||
duration: 300
|
||||
});
|
||||
|
||||
// Animation des étoiles pendant le calcul
|
||||
anime({
|
||||
targets: '.star-indicator',
|
||||
rotate: 360,
|
||||
duration: 2000,
|
||||
easing: 'linear',
|
||||
loop: true
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
const location = locations.find(l => l.id === selectedLocation);
|
||||
|
||||
// Calculs simplifiés
|
||||
const baseDate = new Date('2025-07-22');
|
||||
const latitudeAdjustment = (location.lat - 16.25) * 0.5;
|
||||
const heliacalDate = new Date(baseDate);
|
||||
heliacalDate.setDate(baseDate.getDate() + Math.round(latitudeAdjustment));
|
||||
|
||||
results = {
|
||||
location: location.name,
|
||||
heliacalDate: heliacalDate.toLocaleDateString('fr-FR', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
}),
|
||||
bestTime: '05h00 - 05h30',
|
||||
duration: '15-20 minutes',
|
||||
azimuth: '117° (ESE)',
|
||||
altitude: '57.1°',
|
||||
magnitude: '-1.46'
|
||||
};
|
||||
|
||||
calculationInProgress = false;
|
||||
|
||||
// Animation des résultats
|
||||
anime.timeline({
|
||||
easing: 'easeOutQuad'
|
||||
})
|
||||
.add({
|
||||
targets: '.calculating-indicator',
|
||||
opacity: [1, 0],
|
||||
duration: 300
|
||||
})
|
||||
.add({
|
||||
targets: '.results-container',
|
||||
translateY: [20, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 600
|
||||
})
|
||||
.add({
|
||||
targets: '.result-item',
|
||||
translateX: [20, 0],
|
||||
opacity: [0, 1],
|
||||
duration: 400,
|
||||
delay: anime.stagger(100)
|
||||
}, '-=400')
|
||||
.add({
|
||||
targets: '.result-value',
|
||||
scale: [0.8, 1],
|
||||
duration: 600,
|
||||
delay: anime.stagger(100),
|
||||
easing: 'easeOutElastic(1, .5)'
|
||||
}, '-=600');
|
||||
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
// Calculer automatiquement au chargement
|
||||
onMount(() => {
|
||||
setTimeout(() => {
|
||||
if (visible) calculate();
|
||||
}, 1000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<section id="predictions" class="predictions">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>{$t('predictions_title')}</h2>
|
||||
<p class="section-subtitle">
|
||||
{$t('predictions_subtitle')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="calculator-container" class:visible>
|
||||
<div class="location-selector">
|
||||
<h3>{$t('predictions_select_location')}</h3>
|
||||
<div class="locations-grid">
|
||||
{#each locations as location}
|
||||
<button
|
||||
class="location-option"
|
||||
class:active={selectedLocation === location.id}
|
||||
data-location={location.id}
|
||||
on:click={() => selectLocation(location.id)}
|
||||
>
|
||||
<span class="location-name">{location.name}</span>
|
||||
<span class="location-coords">{location.lat}°N</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="results-section">
|
||||
{#if calculationInProgress}
|
||||
<div class="calculating-indicator">
|
||||
<div class="star-indicator">⭐</div>
|
||||
<p>Calcul en cours...</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if results && !calculationInProgress}
|
||||
<div class="results-container">
|
||||
<h3>{$t('predictions_results_for')} {results.location}</h3>
|
||||
|
||||
<div class="results-grid">
|
||||
<div class="result-item highlight">
|
||||
<div class="result-icon">🌅</div>
|
||||
<div class="result-label">{$t('predictions_heliacal_rising')}</div>
|
||||
<div class="result-value">{results.heliacalDate}</div>
|
||||
</div>
|
||||
|
||||
<div class="result-item">
|
||||
<div class="result-icon">⏰</div>
|
||||
<div class="result-label">{$t('predictions_best_observation')}</div>
|
||||
<div class="result-value">{results.bestTime}</div>
|
||||
</div>
|
||||
|
||||
<div class="result-item">
|
||||
<div class="result-icon">⏱️</div>
|
||||
<div class="result-label">{$t('predictions_visibility_duration')}</div>
|
||||
<div class="result-value">{results.duration}</div>
|
||||
</div>
|
||||
|
||||
<div class="result-item">
|
||||
<div class="result-icon">🧭</div>
|
||||
<div class="result-label">{$t('predictions_azimuth')}</div>
|
||||
<div class="result-value">{results.azimuth}</div>
|
||||
</div>
|
||||
|
||||
<div class="result-item">
|
||||
<div class="result-icon">📐</div>
|
||||
<div class="result-label">{$t('predictions_max_altitude')}</div>
|
||||
<div class="result-value">{results.altitude}</div>
|
||||
</div>
|
||||
|
||||
<div class="result-item">
|
||||
<div class="result-icon">✨</div>
|
||||
<div class="result-label">{$t('predictions_magnitude')}</div>
|
||||
<div class="result-value">{results.magnitude}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="observation-tips">
|
||||
<h4>💡 Conseils d'observation</h4>
|
||||
<ul>
|
||||
<li>Arrivez 30 minutes avant pour habituer vos yeux</li>
|
||||
<li>Cherchez vers l'Est-Sud-Est (ESE)</li>
|
||||
<li>Sirius apparaîtra comme l'étoile la plus brillante</li>
|
||||
<li>Conditions idéales : ciel dégagé, sans Lune</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.predictions {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: var(--gradient-night);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.calculator-container {
|
||||
opacity: 0;
|
||||
margin-top: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.location-selector {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.location-selector h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.locations-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.location-option {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 15px;
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
opacity: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.location-option:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.location-option.active {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
border-color: var(--color-primary);
|
||||
}
|
||||
|
||||
.location-name {
|
||||
font-weight: 600;
|
||||
color: var(--color-light);
|
||||
}
|
||||
|
||||
.location-coords {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-primary);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.calculating-indicator {
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.star-indicator {
|
||||
font-size: 3rem;
|
||||
display: inline-block;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.results-container {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border-radius: 20px;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.results-container h3 {
|
||||
color: var(--color-primary);
|
||||
text-align: center;
|
||||
margin-bottom: 2rem;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.results-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.result-item {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.result-item.highlight {
|
||||
background: rgba(255, 215, 0, 0.1);
|
||||
border: 2px solid var(--color-primary);
|
||||
}
|
||||
|
||||
.result-icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.result-label {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-light);
|
||||
opacity: 0.8;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.result-value {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.observation-tips {
|
||||
background: rgba(255, 215, 0, 0.05);
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.observation-tips h4 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.observation-tips ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.observation-tips li {
|
||||
padding: 0.5rem 0;
|
||||
padding-left: 1.5rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.observation-tips li::before {
|
||||
content: "✦";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.locations-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.results-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.location-selector, .results-container {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,375 +0,0 @@
|
||||
<script>
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let visible = false;
|
||||
let activeTab = 'mechanics';
|
||||
|
||||
onMount(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
visible = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const section = document.getElementById('science');
|
||||
if (section) observer.observe(section);
|
||||
|
||||
return () => observer.disconnect();
|
||||
});
|
||||
|
||||
const tabs = [
|
||||
{ id: 'mechanics', label: 'Mécanique Céleste', icon: '🌌' },
|
||||
{ id: 'arcus', label: 'Arcus Visionis', icon: '📐' },
|
||||
{ id: 'factors', label: 'Facteurs d\'Influence', icon: '🌡️' }
|
||||
];
|
||||
</script>
|
||||
|
||||
<section id="science" class="science">
|
||||
<div class="container">
|
||||
<div class="section-header" class:visible>
|
||||
<h2>La Science du Lever Héliaque</h2>
|
||||
<p class="section-subtitle">
|
||||
Comprendre la danse cosmique entre Terre, Soleil et Sirius
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="science-content" class:visible>
|
||||
<div class="tabs">
|
||||
{#each tabs as tab}
|
||||
<button
|
||||
class="tab-button"
|
||||
class:active={activeTab === tab.id}
|
||||
on:click={() => activeTab = tab.id}
|
||||
>
|
||||
<span class="tab-icon">{tab.icon}</span>
|
||||
<span class="tab-label">{tab.label}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<div class="tab-content">
|
||||
{#if activeTab === 'mechanics'}
|
||||
<div class="content-section">
|
||||
<h3>Le Ballet Cosmique</h3>
|
||||
<p>
|
||||
Le lever héliaque est le fruit d'une chorégraphie céleste précise.
|
||||
Pendant environ 70 jours, Sirius reste invisible, cachée par l'éclat du Soleil.
|
||||
Son retour à l'aube marque un moment unique où l'étoile se lève juste avant
|
||||
le Soleil, visible quelques instants dans les lueurs du crépuscule matinal.
|
||||
</p>
|
||||
|
||||
<div class="diagram card">
|
||||
<div class="celestial-body sun">
|
||||
<span>☀️</span>
|
||||
<label>Soleil</label>
|
||||
</div>
|
||||
<div class="orbit-path"></div>
|
||||
<div class="celestial-body earth">
|
||||
<span>🌍</span>
|
||||
<label>Terre</label>
|
||||
</div>
|
||||
<div class="celestial-body sirius">
|
||||
<span>⭐</span>
|
||||
<label>Sirius</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
La Terre, dans son mouvement orbital annuel, modifie notre perspective
|
||||
sur les étoiles. Quand le Soleil se trouve entre nous et Sirius,
|
||||
l'étoile devient invisible. C'est seulement quand l'angle devient
|
||||
favorable que Sirius réapparaît.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if activeTab === 'arcus'}
|
||||
<div class="content-section">
|
||||
<h3>L'Arc de Visibilité</h3>
|
||||
<p>
|
||||
L'Arcus Visionis est l'angle critique : le Soleil doit être à environ
|
||||
9-10° sous l'horizon pour que Sirius devienne visible. C'est un équilibre
|
||||
délicat entre la brillance de l'étoile et la luminosité du ciel.
|
||||
</p>
|
||||
|
||||
<div class="arcus-diagram card">
|
||||
<div class="horizon-line">
|
||||
<span>Horizon</span>
|
||||
</div>
|
||||
<div class="angle-indicator">
|
||||
<div class="angle-arc"></div>
|
||||
<span class="angle-value">9-10°</span>
|
||||
</div>
|
||||
<div class="sirius-position">
|
||||
<span>⭐ Sirius</span>
|
||||
</div>
|
||||
<div class="sun-position">
|
||||
<span>☀️ Soleil</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Pour Sirius, avec sa magnitude exceptionnelle de -1.46, cet angle
|
||||
est relativement faible comparé à d'autres étoiles moins brillantes.
|
||||
C'est pourquoi elle est l'une des premières à être visible à l'aube.
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if activeTab === 'factors'}
|
||||
<div class="content-section">
|
||||
<h3>Les Variables en Jeu</h3>
|
||||
|
||||
<div class="factors-grid">
|
||||
<div class="factor-card card">
|
||||
<div class="factor-icon">🌟</div>
|
||||
<h4>Magnitude</h4>
|
||||
<p>
|
||||
Sirius brille à -1.46, la rendant visible même dans des conditions
|
||||
difficiles. Plus une étoile est brillante, plus tôt elle perce
|
||||
les lueurs de l'aube.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="factor-card card">
|
||||
<div class="factor-icon">🗺️</div>
|
||||
<h4>Latitude</h4>
|
||||
<p>
|
||||
À 16°N en Guadeloupe, les astres se lèvent presque verticalement.
|
||||
Cette géométrie tropicale influence la durée du crépuscule et
|
||||
la visibilité.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="factor-card card">
|
||||
<div class="factor-icon">💨</div>
|
||||
<h4>Atmosphère</h4>
|
||||
<p>
|
||||
L'humidité caribéenne et les brumes de sable peuvent retarder
|
||||
la visibilité de plusieurs jours. Un ciel sec et clair est idéal.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.science {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: linear-gradient(135deg, #0a0e27 0%, #1a1a2e 100%);
|
||||
}
|
||||
|
||||
.science-content {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: all 0.8s ease-out 0.3s;
|
||||
}
|
||||
|
||||
.science-content.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
border: 2px solid rgba(255, 215, 0, 0.3);
|
||||
border-radius: 50px;
|
||||
color: var(--color-light);
|
||||
cursor: pointer;
|
||||
transition: var(--transition-base);
|
||||
}
|
||||
|
||||
.tab-button:hover,
|
||||
.tab-button.active {
|
||||
background: rgba(255, 215, 0, 0.2);
|
||||
border-color: var(--color-primary);
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.content-section h3 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.content-section p {
|
||||
margin-bottom: 1.5rem;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
/* Diagramme orbital */
|
||||
.diagram {
|
||||
position: relative;
|
||||
height: 300px;
|
||||
margin: 2rem 0;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.celestial-body {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.celestial-body span {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.celestial-body label {
|
||||
font-size: 0.9rem;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.sun {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.earth {
|
||||
top: 20%;
|
||||
left: 20%;
|
||||
}
|
||||
|
||||
.sirius {
|
||||
top: 20%;
|
||||
right: 20%;
|
||||
}
|
||||
|
||||
.orbit-path {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 2px dashed rgba(255, 215, 0, 0.3);
|
||||
border-radius: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
/* Diagramme Arcus */
|
||||
.arcus-diagram {
|
||||
position: relative;
|
||||
height: 250px;
|
||||
margin: 2rem 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.horizon-line {
|
||||
position: absolute;
|
||||
bottom: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: var(--color-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.horizon-line span {
|
||||
background: var(--color-dark);
|
||||
padding: 0 1rem;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.sirius-position {
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
left: 30%;
|
||||
}
|
||||
|
||||
.sun-position {
|
||||
position: absolute;
|
||||
bottom: 20%;
|
||||
right: 30%;
|
||||
}
|
||||
|
||||
.angle-indicator {
|
||||
position: absolute;
|
||||
bottom: 50%;
|
||||
right: 40%;
|
||||
}
|
||||
|
||||
.angle-arc {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 2px solid var(--color-accent);
|
||||
border-radius: 50%;
|
||||
border-bottom: none;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.angle-value {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -30px;
|
||||
color: var(--color-accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Grille des facteurs */
|
||||
.factors-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: var(--spacing-md);
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.factor-card {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.factor-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.factor-card h4 {
|
||||
color: var(--color-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.tabs {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tab-button {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.diagram {
|
||||
height: 250px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,192 @@
|
||||
---
|
||||
pagination:
|
||||
data: locales
|
||||
size: 1
|
||||
alias: locale
|
||||
permalink: "{% if locale == baseLocale %}/culture-savoirs/index.html{% else %}/{{ locale }}/culture-savoirs/index.html{% endif %}"
|
||||
layout: layouts/base.njk
|
||||
pageKey: culture
|
||||
slug: "culture-savoirs/"
|
||||
eleventyComputed:
|
||||
pageTitle: "{{ 'culture_title' | t(locale) }}"
|
||||
---
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="section-header center">
|
||||
<p class="section-eyebrow">Sirius Gwada</p>
|
||||
<h1>{{ "culture_title" | t(locale) }}</h1>
|
||||
<p class="pattern-strip adinkra" aria-hidden="true" style="margin-inline:auto"></p>
|
||||
<p class="section-subtitle">{{ "culture_subtitle" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid-auto">
|
||||
<div class="card feature-card">
|
||||
<div style="font-size: var(--text-4)" aria-hidden="true">🏺</div>
|
||||
<h3>{{ "culture_egypt_title" | t(locale) }}</h3>
|
||||
<p>{{ "culture_egypt_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card feature-card">
|
||||
<div style="font-size: var(--text-4)" aria-hidden="true">🌍</div>
|
||||
<h3>{{ "culture_dogon_title" | t(locale) }}</h3>
|
||||
<p>{{ "culture_dogon_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card feature-card">
|
||||
<div style="font-size: var(--text-4)" aria-hidden="true">⛵</div>
|
||||
<h3>{{ "culture_caribbean_title" | t(locale) }}</h3>
|
||||
<p>{{ "culture_caribbean_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="center" style="margin-top: var(--space-7)">{{ "culture_timeline_title" | t(locale) }}</h2>
|
||||
<div class="timeline-v" style="margin-top: var(--space-5)">
|
||||
<div class="timeline-v-item">
|
||||
<p class="timeline-v-date">{{ "culture_timeline_1_date" | t(locale) }}</p>
|
||||
<h4>{{ "culture_timeline_1_title" | t(locale) }}</h4>
|
||||
<p>{{ "culture_timeline_1_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-v-item">
|
||||
<p class="timeline-v-date">{{ "culture_timeline_2_date" | t(locale) }}</p>
|
||||
<h4>{{ "culture_timeline_2_title" | t(locale) }}</h4>
|
||||
<p>{{ "culture_timeline_2_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-v-item">
|
||||
<p class="timeline-v-date">{{ "culture_timeline_3_date" | t(locale) }}</p>
|
||||
<h4>{{ "culture_timeline_3_title" | t(locale) }}</h4>
|
||||
<p>{{ "culture_timeline_3_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-v-item">
|
||||
<p class="timeline-v-date">{{ "culture_timeline_4_date" | t(locale) }}</p>
|
||||
<h4>{{ "culture_timeline_4_title" | t(locale) }}</h4>
|
||||
<p>{{ "culture_timeline_4_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" style="background: var(--surface-sunk)">
|
||||
<div class="container">
|
||||
<div class="section-header center">
|
||||
<h2>{{ "dogon_title" | t(locale) }}</h2>
|
||||
<p class="pattern-strip kente" aria-hidden="true" style="margin-inline:auto"></p>
|
||||
<p class="section-subtitle">{{ "dogon_intro" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<fieldset class="tabs">
|
||||
<legend class="visually-hidden">{{ "dogon_title" | t(locale) }}</legend>
|
||||
|
||||
<input type="radio" name="dogon-tab" id="dogon-tab-cosmogony" class="tab-input" checked>
|
||||
<input type="radio" name="dogon-tab" id="dogon-tab-system" class="tab-input">
|
||||
<input type="radio" name="dogon-tab" id="dogon-tab-astronomy" class="tab-input">
|
||||
<input type="radio" name="dogon-tab" id="dogon-tab-heritage" class="tab-input">
|
||||
|
||||
<div class="tab-list" role="tablist">
|
||||
<label class="tab-label" for="dogon-tab-cosmogony">{{ "dogon_tab_cosmogony" | t(locale) }}</label>
|
||||
<label class="tab-label" for="dogon-tab-system">{{ "dogon_tab_system" | t(locale) }}</label>
|
||||
<label class="tab-label" for="dogon-tab-astronomy">{{ "dogon_tab_astronomy" | t(locale) }}</label>
|
||||
<label class="tab-label" for="dogon-tab-heritage">{{ "dogon_tab_heritage" | t(locale) }}</label>
|
||||
</div>
|
||||
|
||||
<div class="tab-panels">
|
||||
<div class="tab-panel prose center">
|
||||
<p>{{ "dogon_cosmogony_p1" | t(locale) }}</p>
|
||||
<p>{{ "dogon_cosmogony_p2" | t(locale) }}</p>
|
||||
<div class="card">
|
||||
<h3>{{ "dogon_cosmogony_nommo_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_cosmogony_nommo_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel">
|
||||
<div class="grid-auto">
|
||||
<div class="card info-card">
|
||||
<h3>{{ "dogon_system_sigutolo_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_system_sigutolo_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "dogon_system_potolo_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_system_potolo_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "dogon_system_emmeya_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_system_emmeya_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card prose center" style="margin-top: var(--space-4)">
|
||||
<h3>{{ "dogon_mystery_title" | t(locale) }}</h3>
|
||||
<div class="grid-auto">
|
||||
<div>
|
||||
<h4>{{ "dogon_mystery_theory1_title" | t(locale) }}</h4>
|
||||
<p>{{ "dogon_mystery_theory1_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>{{ "dogon_mystery_theory2_title" | t(locale) }}</h4>
|
||||
<p>{{ "dogon_mystery_theory2_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4>{{ "dogon_mystery_theory3_title" | t(locale) }}</h4>
|
||||
<p>{{ "dogon_mystery_theory3_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card prose center" style="margin-top: var(--space-4)">
|
||||
<h3>{{ "dogon_calc_example_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_calc_example_text" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel">
|
||||
<div class="grid-auto">
|
||||
<div class="card info-card">
|
||||
<h3>{{ "dogon_astronomy_geometry_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_astronomy_geometry_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "dogon_astronomy_calendar_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_astronomy_calendar_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "dogon_astronomy_planets_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_astronomy_planets_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "dogon_astronomy_universe_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_astronomy_universe_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel">
|
||||
<div class="timeline-v">
|
||||
<div class="timeline-v-item">
|
||||
<p class="timeline-v-date">{{ "dogon_heritage_1_date" | t(locale) }}</p>
|
||||
<p>{{ "dogon_heritage_1_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-v-item">
|
||||
<p class="timeline-v-date">{{ "dogon_heritage_2_date" | t(locale) }}</p>
|
||||
<p>{{ "dogon_heritage_2_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-v-item">
|
||||
<p class="timeline-v-date">{{ "dogon_heritage_3_date" | t(locale) }}</p>
|
||||
<p>{{ "dogon_heritage_3_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-v-item">
|
||||
<p class="timeline-v-date">{{ "dogon_heritage_4_date" | t(locale) }}</p>
|
||||
<p>{{ "dogon_heritage_4_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card prose center" style="margin-top: var(--space-5)">
|
||||
<h3>{{ "dogon_heritage_diaspora_title" | t(locale) }}</h3>
|
||||
<p>{{ "dogon_heritage_diaspora_desc" | t(locale) }}</p>
|
||||
<div class="grid-auto" style="margin-top: var(--space-3); text-align: left">
|
||||
<p>🇭🇹 {{ "dogon_heritage_diaspora_haiti" | t(locale) }}</p>
|
||||
<p>🇬🇵 {{ "dogon_heritage_diaspora_guadeloupe" | t(locale) }}</p>
|
||||
<p>🇲🇶 {{ "dogon_heritage_diaspora_martinique" | t(locale) }}</p>
|
||||
<p>🇯🇲 {{ "dogon_heritage_diaspora_jamaica" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</section>
|
||||
@@ -1,90 +0,0 @@
|
||||
// Données des prédictions du lever héliaque
|
||||
export const predictionsData = {
|
||||
"Pointe des Châteaux": {
|
||||
coords: { lat: 16.2476, lon: -61.1771, alt: 30 },
|
||||
description: "Point de vue élevé avec panorama dégagé vers l'Est sur l'Atlantique",
|
||||
predictions: {
|
||||
"2025": { date: "22 juillet", time: "05:12" },
|
||||
"2026": { date: "22 juillet", time: "05:12" },
|
||||
"2027": { date: "22 juillet", time: "05:13" },
|
||||
"2028": { date: "21 juillet", time: "05:13" },
|
||||
"2029": { date: "22 juillet", time: "05:14" }
|
||||
}
|
||||
},
|
||||
"Pointe de la Grande Vigie": {
|
||||
coords: { lat: 16.5098, lon: -61.4666, alt: 81 },
|
||||
description: "Point le plus septentrional de la Guadeloupe, horizon marin parfait",
|
||||
predictions: {
|
||||
"2025": { date: "22 juillet", time: "05:11" },
|
||||
"2026": { date: "22 juillet", time: "05:12" },
|
||||
"2027": { date: "22 juillet", time: "05:12" },
|
||||
"2028": { date: "21 juillet", time: "05:12" },
|
||||
"2029": { date: "22 juillet", time: "05:13" }
|
||||
}
|
||||
},
|
||||
"Duzer (Sainte-Rose)": {
|
||||
coords: { lat: 16.3361, lon: -61.7430, alt: 20 },
|
||||
description: "Site nécessitant un point dégagé vers l'Est sur les mornes",
|
||||
predictions: {
|
||||
"2025": { date: "22 juillet", time: "05:13" },
|
||||
"2026": { date: "22 juillet", time: "05:14" },
|
||||
"2027": { date: "22 juillet", time: "05:14" },
|
||||
"2028": { date: "21 juillet", time: "05:14" },
|
||||
"2029": { date: "22 juillet", time: "05:15" }
|
||||
}
|
||||
},
|
||||
"Saint-Félix (Le Gosier)": {
|
||||
coords: { lat: 16.2005, lon: -61.4605, alt: 5 },
|
||||
description: "Plage avec observation au niveau de la mer",
|
||||
predictions: {
|
||||
"2025": { date: "22 juillet", time: "05:13" },
|
||||
"2026": { date: "22 juillet", time: "05:13" },
|
||||
"2027": { date: "22 juillet", time: "05:14" },
|
||||
"2028": { date: "21 juillet", time: "05:14" },
|
||||
"2029": { date: "22 juillet", time: "05:15" }
|
||||
}
|
||||
},
|
||||
"Grande Pointe (Trois-Rivières)": {
|
||||
coords: { lat: 15.9696, lon: -61.6308, alt: 42 },
|
||||
description: "Site côtier avec altitude intéressante pour l'observation",
|
||||
predictions: {
|
||||
"2025": { date: "22 juillet", time: "05:13" },
|
||||
"2026": { date: "22 juillet", time: "05:14" },
|
||||
"2027": { date: "22 juillet", time: "05:14" },
|
||||
"2028": { date: "21 juillet", time: "05:15" },
|
||||
"2029": { date: "22 juillet", time: "05:15" }
|
||||
}
|
||||
},
|
||||
"Petit-Pérou": {
|
||||
coords: { lat: 16.0517, lon: -61.5567, alt: 10 },
|
||||
description: "Site des roches gravées, observation depuis la côte",
|
||||
predictions: {
|
||||
"2025": { date: "22 juillet", time: "05:14" },
|
||||
"2026": { date: "22 juillet", time: "05:14" },
|
||||
"2027": { date: "22 juillet", time: "05:15" },
|
||||
"2028": { date: "21 juillet", time: "05:15" },
|
||||
"2029": { date: "22 juillet", time: "05:16" }
|
||||
}
|
||||
},
|
||||
"Pointe du Vieux-Fort": {
|
||||
coords: { lat: 15.9483, lon: -61.7072, alt: 20 },
|
||||
description: "Point le plus méridional de Basse-Terre, vue sur le canal des Saintes",
|
||||
predictions: {
|
||||
"2025": { date: "22 juillet", time: "05:14" },
|
||||
"2026": { date: "22 juillet", time: "05:14" },
|
||||
"2027": { date: "22 juillet", time: "05:15" },
|
||||
"2028": { date: "21 juillet", time: "05:15" },
|
||||
"2029": { date: "22 juillet", time: "05:16" }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const years = ["2025", "2026", "2027", "2028", "2029"];
|
||||
|
||||
export function calculateObservationWindow(dateStr) {
|
||||
const day = parseInt(dateStr.split(' ')[0]);
|
||||
const month = dateStr.split(' ')[1];
|
||||
const startDay = day - 2;
|
||||
const endDay = day + 2;
|
||||
return `${startDay} au ${endDay} ${month}`;
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
// Données simplifiées des continents en GeoJSON
|
||||
// Source: Natural Earth (simplified)
|
||||
export const worldData = {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": { "name": "Africa" },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[-17.5, 35], [-5, 36], [10, 37], [35, 30], [42, 15],
|
||||
[51, 12], [51, -2], [41, -12], [35, -25], [28, -33],
|
||||
[20, -35], [18, -35], [12, -18], [10, -5], [8, 5],
|
||||
[-5, 5], [-17, 15], [-17.5, 35]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": { "name": "Europe" },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[-10, 36], [-5, 43], [0, 50], [10, 54], [20, 59],
|
||||
[30, 60], [40, 55], [30, 45], [20, 40], [10, 45],
|
||||
[0, 40], [-10, 36]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": { "name": "Asia" },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[26, 40], [40, 45], [60, 50], [80, 55], [100, 60],
|
||||
[120, 60], [140, 50], [145, 40], [135, 30], [120, 20],
|
||||
[100, 10], [80, 15], [70, 25], [60, 30], [45, 35],
|
||||
[26, 40]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": { "name": "North America" },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[-170, 65], [-165, 68], [-150, 70], [-130, 70], [-100, 70],
|
||||
[-80, 68], [-65, 60], [-55, 50], [-65, 45], [-75, 40],
|
||||
[-80, 35], [-85, 30], [-90, 25], [-95, 20], [-105, 20],
|
||||
[-110, 25], [-115, 30], [-120, 35], [-125, 40], [-130, 45],
|
||||
[-135, 50], [-140, 55], [-150, 58], [-160, 60], [-170, 65]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": { "name": "South America" },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[-35, -5], [-38, -15], [-40, -20], [-48, -25], [-58, -35],
|
||||
[-65, -45], [-70, -55], [-68, -55], [-73, -45], [-72, -35],
|
||||
[-70, -25], [-75, -15], [-78, -5], [-80, 0], [-77, 5],
|
||||
[-75, 10], [-70, 12], [-60, 8], [-50, 5], [-35, -5]
|
||||
]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": { "name": "Australia" },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[113, -22], [130, -12], [135, -12], [140, -18], [145, -20],
|
||||
[150, -25], [153, -30], [150, -35], [145, -38], [140, -38],
|
||||
[135, -35], [130, -32], [125, -32], [120, -35], [115, -35],
|
||||
[113, -30], [113, -22]
|
||||
]]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
pagination:
|
||||
data: locales
|
||||
size: 1
|
||||
alias: locale
|
||||
permalink: "{% if locale == baseLocale %}/index.html{% else %}/{{ locale }}/index.html{% endif %}"
|
||||
layout: layouts/base.njk
|
||||
pageKey: home
|
||||
slug: ""
|
||||
eleventyComputed:
|
||||
pageTitle: "{{ 'hero_title1' | t(locale) }} {{ 'hero_title2' | t(locale) }}"
|
||||
---
|
||||
<section class="hero">
|
||||
<div class="hero-orbits" aria-hidden="true">
|
||||
<div class="sun"></div>
|
||||
<div class="orbit" style="width:5rem;height:5rem;animation-duration:6s"><span></span></div>
|
||||
<div class="orbit" style="width:8rem;height:8rem;animation-duration:10s"><span></span></div>
|
||||
<div class="orbit" style="width:11rem;height:11rem;animation-duration:14s"><span></span></div>
|
||||
<div class="orbit" style="width:14rem;height:14rem;animation-duration:18s"><span></span></div>
|
||||
<div class="orbit sirius" style="width:18rem;height:18rem;animation-duration:26s"><span></span></div>
|
||||
</div>
|
||||
|
||||
<div class="container center hero-content">
|
||||
<p class="section-eyebrow">{{ "hero_eyebrow" | t(locale) }}</p>
|
||||
<h1 class="hero-title">
|
||||
<span>{{ "hero_title1" | t(locale) }}</span>
|
||||
<span class="accent">{{ "hero_title2" | t(locale) }}</span>
|
||||
</h1>
|
||||
<p class="hero-subtitle">{{ "hero_subtitle" | t(locale) }}</p>
|
||||
<p class="hero-description">{{ "hero_description" | t(locale) }}</p>
|
||||
<p class="hero-date">
|
||||
{{ "hero_date_label" | t(locale) }}
|
||||
<strong>{{ nextRising.date | formatDate(locale) }} · {{ nextRising.time }}</strong>
|
||||
</p>
|
||||
<div class="cluster hero-cta">
|
||||
<a class="btn btn-primary" href="{{ '/observer/' | localeHref(locale) }}">{{ "hero_cta_predictions" | t(locale) }}</a>
|
||||
<a class="btn btn-outline" href="{{ '/sirius-science/' | localeHref(locale) }}">{{ "hero_cta_learn" | t(locale) }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="intro">
|
||||
<div class="container">
|
||||
<div class="section-header center">
|
||||
<h2>{{ "home_intro_title" | t(locale) }}</h2>
|
||||
<p class="pattern-strip kente" aria-hidden="true" style="margin-inline:auto"></p>
|
||||
<p class="section-subtitle">{{ "home_intro_subtitle" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="prose center stack" style="--stack-space: var(--space-3)">
|
||||
<p>{{ "home_intro_p1" | t(locale) | safe }}</p>
|
||||
<p>{{ "home_intro_p2" | t(locale) }}</p>
|
||||
<p>{{ "home_intro_p3" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid-auto" style="margin-top: var(--space-6)">
|
||||
<div class="card feature-card">
|
||||
<h3>{{ "feature_brightest_title" | t(locale) }}</h3>
|
||||
<p>{{ "feature_brightest_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card feature-card">
|
||||
<h3>{{ "feature_rising_title" | t(locale) }}</h3>
|
||||
<p>{{ "feature_rising_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card feature-card">
|
||||
<h3>{{ "feature_heritage_title" | t(locale) }}</h3>
|
||||
<p>{{ "feature_heritage_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,107 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
import { worldData, waveCities } from "./world.js";
|
||||
|
||||
let canvas = $state();
|
||||
let activeCity = $state(null);
|
||||
|
||||
function project(lon, lat, width, height) {
|
||||
const x = ((lon + 180) / 360) * width;
|
||||
const y = ((90 - lat) / 180) * height;
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
function draw() {
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext("2d");
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const width = canvas.clientWidth;
|
||||
const height = canvas.clientHeight;
|
||||
canvas.width = width * dpr;
|
||||
canvas.height = height * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
const styles = getComputedStyle(canvas);
|
||||
const gold = styles.getPropertyValue("--gold-surface").trim() || "#e8c766";
|
||||
const teal = styles.getPropertyValue("--caribbean-teal").trim() || "#3a9088";
|
||||
const border = styles.getPropertyValue("--border").trim() || "#333";
|
||||
|
||||
ctx.fillStyle = border;
|
||||
worldData.features.forEach((feature) => {
|
||||
ctx.beginPath();
|
||||
feature.geometry.coordinates[0].forEach(([lon, lat], i) => {
|
||||
const { x, y } = project(lon, lat, width, height);
|
||||
if (i === 0) ctx.moveTo(x, y);
|
||||
else ctx.lineTo(x, y);
|
||||
});
|
||||
ctx.closePath();
|
||||
ctx.fill();
|
||||
});
|
||||
|
||||
waveCities.forEach((city) => {
|
||||
const { x, y } = project(city.lon, city.lat, width, height);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, city.name === activeCity?.name ? 7 : 4, 0, Math.PI * 2);
|
||||
ctx.fillStyle = city.name === "Guadeloupe" || city.name === "Martinique" ? gold : teal;
|
||||
ctx.fill();
|
||||
});
|
||||
}
|
||||
|
||||
function pickCity(clientX, clientY) {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = clientX - rect.left;
|
||||
const y = clientY - rect.top;
|
||||
let closest = null;
|
||||
let closestDist = Infinity;
|
||||
waveCities.forEach((city) => {
|
||||
const p = project(city.lon, city.lat, rect.width, rect.height);
|
||||
const dist = Math.hypot(p.x - x, p.y - y);
|
||||
if (dist < closestDist) {
|
||||
closestDist = dist;
|
||||
closest = city;
|
||||
}
|
||||
});
|
||||
activeCity = closestDist < 30 ? closest : null;
|
||||
draw();
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
draw();
|
||||
const onResize = () => draw();
|
||||
window.addEventListener("resize", onResize);
|
||||
return () => window.removeEventListener("resize", onResize);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="sirius-globe">
|
||||
<canvas
|
||||
bind:this={canvas}
|
||||
class="island-canvas"
|
||||
aria-label="Carte de la progression du lever héliaque à travers l'Afrique et les Caraïbes, touchez une ville pour voir sa date"
|
||||
tabindex="0"
|
||||
onmousemove={(e) => pickCity(e.clientX, e.clientY)}
|
||||
onmouseleave={() => { activeCity = null; draw(); }}
|
||||
onclick={(e) => pickCity(e.clientX, e.clientY)}
|
||||
></canvas>
|
||||
<p class="globe-caption" aria-live="polite">
|
||||
{#if activeCity}
|
||||
<strong>{activeCity.name}</strong> — {activeCity.date}
|
||||
{:else}
|
||||
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.island-canvas {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.globe-caption {
|
||||
text-align: center;
|
||||
min-height: 1.5em;
|
||||
color: var(--gold);
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,24 @@
|
||||
const container = document.querySelector('[data-island="globe"]');
|
||||
|
||||
if (container && "IntersectionObserver" in window) {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (!entry.isIntersecting) continue;
|
||||
observer.disconnect();
|
||||
|
||||
Promise.all([
|
||||
import("svelte"),
|
||||
import("./SiriusGlobe.svelte"),
|
||||
]).then(([{ mount }, { default: SiriusGlobe }]) => {
|
||||
const target = container.querySelector(".island-app");
|
||||
mount(SiriusGlobe, { target });
|
||||
container.classList.add("is-enhanced");
|
||||
});
|
||||
}
|
||||
},
|
||||
{ rootMargin: "200px" }
|
||||
);
|
||||
|
||||
observer.observe(container);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Continents simplifiés (issus de Natural Earth, tracé approximatif) —
|
||||
// utilisés uniquement comme repère visuel derrière la vague du lever héliaque.
|
||||
export const worldData = {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
type: "Feature",
|
||||
properties: { name: "Africa" },
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [[
|
||||
[-17.5, 35], [-5, 36], [10, 37], [35, 30], [42, 15],
|
||||
[51, 12], [51, -2], [41, -12], [35, -25], [28, -33],
|
||||
[20, -35], [18, -35], [12, -18], [10, -5], [8, 5],
|
||||
[-5, 5], [-17, 15], [-17.5, 35],
|
||||
]],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "Feature",
|
||||
properties: { name: "Europe" },
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [[
|
||||
[-10, 36], [-5, 43], [0, 50], [10, 54], [20, 59],
|
||||
[30, 60], [40, 55], [30, 45], [20, 40], [10, 45],
|
||||
[0, 40], [-10, 36],
|
||||
]],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "Feature",
|
||||
properties: { name: "North America" },
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [[
|
||||
[-170, 65], [-165, 68], [-150, 70], [-130, 70], [-100, 70],
|
||||
[-80, 68], [-65, 60], [-55, 50], [-65, 45], [-75, 40],
|
||||
[-80, 35], [-85, 30], [-90, 25], [-95, 20], [-105, 20],
|
||||
[-110, 25], [-115, 30], [-120, 35], [-125, 40], [-130, 45],
|
||||
[-135, 50], [-140, 55], [-150, 58], [-160, 60], [-170, 65],
|
||||
]],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "Feature",
|
||||
properties: { name: "South America" },
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [[
|
||||
[-35, -5], [-38, -15], [-40, -20], [-48, -25], [-58, -35],
|
||||
[-65, -45], [-70, -55], [-68, -55], [-73, -45], [-72, -35],
|
||||
[-70, -25], [-75, -15], [-78, -5], [-80, 0], [-77, 5],
|
||||
[-75, 10], [-70, 12], [-60, 8], [-50, 5], [-35, -5],
|
||||
]],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Progression du lever héliaque à travers la diaspora africaine et caribéenne
|
||||
// (fin juin à mi-août), du plus oriental au plus occidental.
|
||||
export const waveCities = [
|
||||
{ name: "La Réunion", lat: -21.1151, lon: 55.5364, date: "27 juin" },
|
||||
{ name: "Kinshasa", lat: -4.4419, lon: 15.2663, date: "16 juillet" },
|
||||
{ name: "Douala", lat: 4.0511, lon: 9.7679, date: "18 juillet" },
|
||||
{ name: "Yaoundé", lat: 3.848, lon: 11.5021, date: "19 juillet" },
|
||||
{ name: "Abidjan", lat: 5.36, lon: -4.0083, date: "20 juillet" },
|
||||
{ name: "Accra", lat: 5.6037, lon: -0.187, date: "21 juillet" },
|
||||
{ name: "Guadeloupe", lat: 16.265, lon: -61.551, date: "22 juillet" },
|
||||
{ name: "Martinique", lat: 14.6415, lon: -61.0242, date: "23 juillet" },
|
||||
{ name: "Dakar", lat: 14.7167, lon: -17.4677, date: "23 juillet" },
|
||||
{ name: "Cayenne", lat: 4.9346, lon: -52.3281, date: "24 juillet" },
|
||||
{ name: "Bamako", lat: 12.6392, lon: -8.0029, date: "25 juillet" },
|
||||
{ name: "Le Caire", lat: 30.0444, lon: 31.2357, date: "3 août" },
|
||||
{ name: "Paris", lat: 48.8566, lon: 2.3522, date: "15 août" },
|
||||
];
|
||||
@@ -0,0 +1,117 @@
|
||||
<script>
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let { sites, locale } = $props();
|
||||
|
||||
let canvas = $state();
|
||||
let activeId = $state(null);
|
||||
let active = $derived(sites.find((s) => s.id === activeId) ?? null);
|
||||
|
||||
let bounds = $derived.by(() => {
|
||||
const lats = sites.map((s) => s.lat);
|
||||
const lons = sites.map((s) => s.lon);
|
||||
return {
|
||||
minLat: Math.min(...lats) - 0.15,
|
||||
maxLat: Math.max(...lats) + 0.15,
|
||||
minLon: Math.min(...lons) - 0.15,
|
||||
maxLon: Math.max(...lons) + 0.15,
|
||||
};
|
||||
});
|
||||
|
||||
function project(site, width, height) {
|
||||
const x = ((site.lon - bounds.minLon) / (bounds.maxLon - bounds.minLon)) * width;
|
||||
const y = height - ((site.lat - bounds.minLat) / (bounds.maxLat - bounds.minLat)) * height;
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
function draw() {
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext("2d");
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
const width = canvas.clientWidth;
|
||||
const height = canvas.clientHeight;
|
||||
canvas.width = width * dpr;
|
||||
canvas.height = height * dpr;
|
||||
ctx.scale(dpr, dpr);
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
const styles = getComputedStyle(canvas);
|
||||
const gold = styles.getPropertyValue("--gold-surface").trim() || "#e8c766";
|
||||
const teal = styles.getPropertyValue("--caribbean-teal").trim() || "#3a9088";
|
||||
const ink = styles.getPropertyValue("--ink-soft").trim() || "#888";
|
||||
|
||||
sites.forEach((site) => {
|
||||
const { x, y } = project(site, width, height);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, site.id === activeId ? 9 : 6, 0, Math.PI * 2);
|
||||
ctx.fillStyle = site.id === activeId ? teal : gold;
|
||||
ctx.fill();
|
||||
|
||||
ctx.font = "12px sans-serif";
|
||||
ctx.fillStyle = ink;
|
||||
ctx.textAlign = x > width * 0.7 ? "right" : "left";
|
||||
ctx.fillText(site.name, x + (x > width * 0.7 ? -12 : 12), y + 4);
|
||||
});
|
||||
}
|
||||
|
||||
function pickSite(clientX, clientY) {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = clientX - rect.left;
|
||||
const y = clientY - rect.top;
|
||||
let closest = null;
|
||||
let closestDist = Infinity;
|
||||
sites.forEach((site) => {
|
||||
const p = project(site, rect.width, rect.height);
|
||||
const dist = Math.hypot(p.x - x, p.y - y);
|
||||
if (dist < closestDist) {
|
||||
closestDist = dist;
|
||||
closest = site;
|
||||
}
|
||||
});
|
||||
if (closest && closestDist < 40) {
|
||||
activeId = closest.id;
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
draw();
|
||||
const onResize = () => draw();
|
||||
window.addEventListener("resize", onResize);
|
||||
return () => window.removeEventListener("resize", onResize);
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="observation-map">
|
||||
<canvas
|
||||
bind:this={canvas}
|
||||
class="island-canvas"
|
||||
aria-label="Carte schématique des sites d'observation, cliquez sur un point pour voir ses détails"
|
||||
tabindex="0"
|
||||
onclick={(e) => pickSite(e.clientX, e.clientY)}
|
||||
></canvas>
|
||||
|
||||
{#if active}
|
||||
<div class="card map-detail">
|
||||
<h3>{active.name}</h3>
|
||||
<p>{active[`description_${locale}`] ?? active.description_fr}</p>
|
||||
<p style="color: var(--ink-soft); font-size: var(--text-0)">{active.lat}°N, {active.lon}°O — {active.alt} m</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.observation-map {
|
||||
display: grid;
|
||||
gap: var(--space-3);
|
||||
}
|
||||
|
||||
.island-canvas {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.map-detail h3 {
|
||||
color: var(--gold);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,31 @@
|
||||
const container = document.querySelector('[data-island="map"]');
|
||||
|
||||
if (container && "IntersectionObserver" in window) {
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (!entry.isIntersecting) continue;
|
||||
observer.disconnect();
|
||||
|
||||
Promise.all([
|
||||
import("svelte"),
|
||||
import("./ObservationMap.svelte"),
|
||||
]).then(([{ mount }, { default: ObservationMap }]) => {
|
||||
const target = container.querySelector(".island-app");
|
||||
const sitesData = JSON.parse(document.getElementById("sites-data").textContent);
|
||||
const locale = document.documentElement.lang;
|
||||
|
||||
mount(ObservationMap, {
|
||||
target,
|
||||
props: { sites: sitesData, locale },
|
||||
});
|
||||
|
||||
container.classList.add("is-enhanced");
|
||||
});
|
||||
}
|
||||
},
|
||||
{ rootMargin: "200px" }
|
||||
);
|
||||
|
||||
observer.observe(container);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<script>
|
||||
import { untrack } from "svelte";
|
||||
|
||||
let { sites, year, locale, labels } = $props();
|
||||
|
||||
let selectedId = $state(untrack(() => sites[0].id));
|
||||
|
||||
let selected = $derived(sites.find((s) => s.id === selectedId));
|
||||
let prediction = $derived(selected.predictions[year]);
|
||||
|
||||
function formatDate(iso) {
|
||||
const [y, m, d] = iso.split("-").map(Number);
|
||||
return new Date(y, m - 1, d).toLocaleDateString(locale === "ht" ? "fr" : locale, {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
});
|
||||
}
|
||||
|
||||
function windowLabel(iso) {
|
||||
const [y, m, d] = iso.split("-").map(Number);
|
||||
const start = new Date(y, m - 1, d - 2);
|
||||
const end = new Date(y, m - 1, d + 2);
|
||||
const fmt = (date) => date.toLocaleDateString(locale === "ht" ? "fr" : locale, { day: "numeric", month: "short" });
|
||||
return `${fmt(start)} – ${fmt(end)}`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="calculator card">
|
||||
<label class="calculator-label" for="site-select">{labels.select}</label>
|
||||
<select id="site-select" bind:value={selectedId} class="calculator-select">
|
||||
{#each sites as site}
|
||||
<option value={site.id}>{site.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
|
||||
{#if prediction}
|
||||
<div class="calculator-result">
|
||||
<p class="calculator-result-label">{labels.heliacal}</p>
|
||||
<p class="calculator-result-value">{formatDate(prediction.date)} · {prediction.time}</p>
|
||||
<p class="calculator-result-label">{labels.window}</p>
|
||||
<p class="calculator-result-window">{windowLabel(prediction.date)}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.calculator {
|
||||
max-width: 28rem;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.calculator-label {
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.calculator-select {
|
||||
width: 100%;
|
||||
min-height: var(--tap-target);
|
||||
padding-inline: var(--space-3);
|
||||
border-radius: var(--radius-sm);
|
||||
border: 2px solid var(--border);
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
font-size: var(--text-1);
|
||||
}
|
||||
|
||||
.calculator-result {
|
||||
margin-top: var(--space-4);
|
||||
padding-top: var(--space-4);
|
||||
border-top: 1px solid var(--border);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.calculator-result-label {
|
||||
font-size: var(--text-0);
|
||||
color: var(--ink-soft);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
.calculator-result-value {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-3);
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.calculator-result-window {
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,24 @@
|
||||
import { mount } from "svelte";
|
||||
import PredictionsCalculator from "./PredictionsCalculator.svelte";
|
||||
|
||||
const container = document.querySelector('[data-island="predictions"]');
|
||||
if (container) {
|
||||
const target = container.querySelector(".island-app");
|
||||
const sitesData = JSON.parse(document.getElementById("sites-data").textContent);
|
||||
|
||||
mount(PredictionsCalculator, {
|
||||
target,
|
||||
props: {
|
||||
sites: sitesData,
|
||||
year: Number(target.dataset.year),
|
||||
locale: target.dataset.locale,
|
||||
labels: {
|
||||
select: target.dataset.selectLabel,
|
||||
heliacal: target.dataset.heliacalLabel,
|
||||
window: target.dataset.windowLabel,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
container.classList.add("is-enhanced");
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// Import anime.js v3 for Vite
|
||||
import anime from 'animejs/lib/anime.es.js';
|
||||
|
||||
export default anime;
|
||||
-286
@@ -1,286 +0,0 @@
|
||||
import { writable, derived } from 'svelte/store';
|
||||
|
||||
// Store pour la langue actuelle
|
||||
export const currentLanguage = writable('fr');
|
||||
|
||||
// Traductions
|
||||
const translations = {
|
||||
fr: {
|
||||
// Navigation
|
||||
nav_home: 'Accueil',
|
||||
nav_about: 'À Propos',
|
||||
nav_predictions: 'Prédictions',
|
||||
nav_science: 'Science',
|
||||
nav_culture: 'Culture',
|
||||
nav_observatory: 'Observatoire',
|
||||
nav_associations: 'Associations',
|
||||
|
||||
// Hero
|
||||
hero_title1: 'Sirius',
|
||||
hero_title2: 'en Guadeloupe',
|
||||
hero_subtitle: 'Wep Ronpet - L\'Ouverture de l\'Année Cosmique',
|
||||
hero_description: 'Le rendez-vous millénaire entre Ciel, Science et Culture',
|
||||
hero_date: 'Lever héliaque : ',
|
||||
hero_date_value: '22 Juillet 2025',
|
||||
hero_cta_predictions: 'Découvrir les Prédictions',
|
||||
hero_cta_learn: 'En Savoir Plus',
|
||||
|
||||
// About
|
||||
about_title: 'Le Lever Héliaque de Sirius',
|
||||
about_subtitle: 'Un phénomène astronomique millénaire',
|
||||
about_intro: 'Le lever héliaque de Sirius est un événement céleste qui a façonné les civilisations depuis des millénaires.',
|
||||
// Features
|
||||
feature_astronomy_title: 'Astronomie',
|
||||
feature_astronomy_desc: 'Sirius, l\'étoile la plus brillante, guide de navigation céleste',
|
||||
feature_culture_title: 'Culture',
|
||||
feature_culture_desc: 'De l\'Égypte aux Dogons, un héritage universel',
|
||||
feature_spirituality_title: 'Spiritualité',
|
||||
feature_spirituality_desc: 'Renaissance, renouveau et connexion cosmique',
|
||||
|
||||
// Predictions
|
||||
predictions_title: 'Prédictions 2025',
|
||||
predictions_subtitle: 'Calculez la date exacte pour votre lieu d\'observation',
|
||||
predictions_select_location: 'Sélectionnez votre lieu',
|
||||
predictions_results_for: 'Résultats pour',
|
||||
predictions_heliacal_rising: 'Lever héliaque',
|
||||
predictions_best_observation: 'Meilleure observation',
|
||||
predictions_visibility_duration: 'Durée de visibilité',
|
||||
predictions_azimuth: 'Azimut au lever',
|
||||
predictions_max_altitude: 'Altitude maximale',
|
||||
predictions_magnitude: 'Magnitude apparente',
|
||||
|
||||
// Science
|
||||
science_title: 'La Science du Lever Héliaque',
|
||||
science_subtitle: 'Comprendre le phénomène astronomique',
|
||||
|
||||
// Culture
|
||||
culture_title: 'Héritage Culturel',
|
||||
culture_subtitle: 'Sirius à travers les civilisations',
|
||||
culture_timeline_title: 'Chronologie du Savoir',
|
||||
|
||||
// Observatory
|
||||
observatory_title: 'Guide d\'Observation',
|
||||
observatory_subtitle: 'Tout pour observer Sirius en Guadeloupe',
|
||||
|
||||
// Associations
|
||||
associations_title: 'Associations qui fêtent le Wep Ronpet',
|
||||
associations_subtitle: 'Découvrez les événements et communautés qui célèbrent le Nouvel An Kamit',
|
||||
associations_events_title: 'Événements Wep Ronpet 2025',
|
||||
associations_community_title: 'Communauté & Ressources',
|
||||
associations_video_title: 'Découvrir le Wep Ronpet',
|
||||
associations_event1_title: 'Nouvel An Kamite',
|
||||
associations_event1_organizer: 'Afrocentricity International & Famille Muntu • GRATUIT - de 16 ans',
|
||||
associations_event1_desc: 'Temps sacré de passage vers une nouvelle rotation cosmique, vécu en harmonie avec les lois de l\'univers. Renouons avec nos racines spirituelles, honorons nos ancêtres, et réalignons nos vies sur les principes de Maât. Cérémonie et rituels, gastronomie kamite, marché artisanal.',
|
||||
associations_event2_title: 'Nouvel An Kamit 6262',
|
||||
associations_event2_organizer: 'Mouvement Politique Spirituel MUN • Le Lamentin, Martinique',
|
||||
associations_event2_desc: 'Célébration avec la Nouvelle Lune au KAY NZINGHA. Cérémonie, rituels, conférences, dîner kamit, soirée dansante pour la puissance et la confiance du pays. De 15h à minuit.',
|
||||
associations_link1_title: '14ème Membre',
|
||||
associations_link1_desc: 'Site web - Événements',
|
||||
associations_link2_title: 'Mouvement Politique Spirituel MUN',
|
||||
associations_link2_desc: 'Page Facebook officielle',
|
||||
|
||||
// Footer
|
||||
footer_copyright: 'Projet réalisé avec ❤️ par',
|
||||
footer_and: 'et'
|
||||
},
|
||||
|
||||
en: {
|
||||
// Navigation
|
||||
nav_home: 'Home',
|
||||
nav_about: 'About',
|
||||
nav_predictions: 'Predictions',
|
||||
nav_science: 'Science',
|
||||
nav_culture: 'Culture',
|
||||
nav_observatory: 'Observatory',
|
||||
nav_associations: 'Associations',
|
||||
|
||||
// Hero
|
||||
hero_title1: 'Sirius',
|
||||
hero_title2: 'in Guadeloupe',
|
||||
hero_subtitle: 'Wep Ronpet - The Opening of the Cosmic Year',
|
||||
hero_description: 'The millennial meeting between Sky, Science and Culture',
|
||||
hero_date: 'Heliacal rising: ',
|
||||
hero_date_value: 'July 22, 2025',
|
||||
hero_cta_predictions: 'Discover Predictions',
|
||||
hero_cta_learn: 'Learn More',
|
||||
|
||||
// About about_title: 'The Heliacal Rising of Sirius',
|
||||
about_subtitle: 'A millennial astronomical phenomenon',
|
||||
about_intro: 'The heliacal rising of Sirius is a celestial event that has shaped civilizations for millennia.',
|
||||
|
||||
// Features
|
||||
feature_astronomy_title: 'Astronomy',
|
||||
feature_astronomy_desc: 'Sirius, the brightest star, celestial navigation guide',
|
||||
feature_culture_title: 'Culture',
|
||||
feature_culture_desc: 'From Egypt to the Dogon, a universal heritage',
|
||||
feature_spirituality_title: 'Spirituality',
|
||||
feature_spirituality_desc: 'Renaissance, renewal and cosmic connection',
|
||||
|
||||
// Predictions
|
||||
predictions_title: 'Predictions 2025',
|
||||
predictions_subtitle: 'Calculate the exact date for your observation location',
|
||||
predictions_select_location: 'Select your location',
|
||||
predictions_results_for: 'Results for',
|
||||
predictions_heliacal_rising: 'Heliacal rising',
|
||||
predictions_best_observation: 'Best observation',
|
||||
predictions_visibility_duration: 'Visibility duration',
|
||||
predictions_azimuth: 'Azimuth at rising',
|
||||
predictions_max_altitude: 'Maximum altitude',
|
||||
predictions_magnitude: 'Apparent magnitude',
|
||||
|
||||
// Science
|
||||
science_title: 'The Science of Heliacal Rising',
|
||||
science_subtitle: 'Understanding the astronomical phenomenon',
|
||||
|
||||
// Culture
|
||||
culture_title: 'Cultural Heritage',
|
||||
culture_subtitle: 'Sirius through civilizations',
|
||||
culture_timeline_title: 'Timeline of Knowledge',
|
||||
|
||||
// Observatory
|
||||
observatory_title: 'Observation Guide',
|
||||
observatory_subtitle: 'Everything to observe Sirius in Guadeloupe',
|
||||
|
||||
// Associations
|
||||
associations_title: 'Associations celebrating Wep Ronpet',
|
||||
associations_subtitle: 'Discover events and communities celebrating the Kamit New Year',
|
||||
associations_events_title: 'Wep Ronpet 2025 Events',
|
||||
associations_community_title: 'Community & Resources',
|
||||
associations_video_title: 'Discover Wep Ronpet',
|
||||
associations_event1_title: 'Kamite New Year',
|
||||
associations_event1_organizer: 'Afrocentricity International & Famille Muntu • FREE under 16',
|
||||
associations_event1_desc: 'Sacred time of passage to a new cosmic rotation, lived in harmony with the laws of the universe. Let us reconnect with our spiritual roots, honor our ancestors, and realign our lives with the principles of Maat. Ceremony and rituals, Kamite gastronomy, artisan market.',
|
||||
associations_event2_title: 'Kamit New Year 6262',
|
||||
associations_event2_organizer: 'Mouvement Politique Spirituel MUN • Le Lamentin, Martinique',
|
||||
associations_event2_desc: 'Celebration with the New Moon at KAY NZINGHA. Ceremony, rituals, conferences, Kamit dinner, dance evening for the power and confidence of the country. From 3pm to midnight.',
|
||||
associations_link1_title: '14th Member',
|
||||
associations_link1_desc: 'Website - Events',
|
||||
associations_link2_title: 'Mouvement Politique Spirituel MUN',
|
||||
associations_link2_desc: 'Official Facebook page',
|
||||
|
||||
// Footer
|
||||
footer_copyright: 'Project made with ❤️ by',
|
||||
footer_and: 'and'
|
||||
},
|
||||
|
||||
ht: {
|
||||
// Navigation
|
||||
nav_home: 'Akèy',
|
||||
nav_about: 'Konsènan',
|
||||
nav_predictions: 'Prediksyon',
|
||||
nav_science: 'Syans',
|
||||
nav_culture: 'Kilti',
|
||||
nav_observatory: 'Obsèvatwa',
|
||||
nav_associations: 'Asosyasyon',
|
||||
|
||||
// Hero
|
||||
hero_title1: 'Sirius',
|
||||
hero_title2: 'nan Gwadloup',
|
||||
hero_subtitle: 'Wep Ronpet - Ouvèti Ane Kosmik la',
|
||||
hero_description: 'Randevou milenè ant Syèl, Syans ak Kilti',
|
||||
hero_date: 'Leve elyak: ',
|
||||
hero_date_value: '22 Jiyè 2025',
|
||||
hero_cta_predictions: 'Dekouvri Prediksyon yo', hero_cta_learn: 'Aprann Plis',
|
||||
|
||||
// About
|
||||
about_title: 'Leve Elyak Sirius la',
|
||||
about_subtitle: 'Yon fenomèn astwonomik milenè',
|
||||
about_intro: 'Leve elyak Sirius se yon evènman selès ki fòme sivilizasyon yo depi plizyè milye ane.',
|
||||
|
||||
// Features
|
||||
feature_astronomy_title: 'Astwonomi',
|
||||
feature_astronomy_desc: 'Sirius, zetwal ki pi klere a, gid navigasyon selès',
|
||||
feature_culture_title: 'Kilti',
|
||||
feature_culture_desc: 'Depi Lejip rive Dogon yo, yon eritaj inivèsèl',
|
||||
feature_spirituality_title: 'Espiritwalite',
|
||||
feature_spirituality_desc: 'Renesans, renouvèlman ak koneksyon kosmik',
|
||||
|
||||
// Predictions
|
||||
predictions_title: 'Prediksyon 2025',
|
||||
predictions_subtitle: 'Kalkile dat egzak pou kote w ap obsève a',
|
||||
predictions_select_location: 'Chwazi kote ou ye a',
|
||||
predictions_results_for: 'Rezilta pou',
|
||||
predictions_heliacal_rising: 'Leve elyak',
|
||||
predictions_best_observation: 'Pi bon obsèvasyon',
|
||||
predictions_visibility_duration: 'Dire vizibilite',
|
||||
predictions_azimuth: 'Azimit nan leve',
|
||||
predictions_max_altitude: 'Altitid maksimòm',
|
||||
predictions_magnitude: 'Mayitid aparan',
|
||||
|
||||
// Science
|
||||
science_title: 'Syans Leve Elyak la',
|
||||
science_subtitle: 'Konprann fenomèn astwonomik la',
|
||||
|
||||
// Culture
|
||||
culture_title: 'Eritaj Kiltirèl',
|
||||
culture_subtitle: 'Sirius atravè sivilizasyon yo',
|
||||
culture_timeline_title: 'Kwonoloji Konesans lan',
|
||||
|
||||
// Observatory
|
||||
observatory_title: 'Gid Obsèvasyon',
|
||||
observatory_subtitle: 'Tout bagay pou obsève Sirius nan Gwadloup',
|
||||
|
||||
// Associations
|
||||
associations_title: 'Asosyasyon ki fète Wep Ronpet',
|
||||
associations_subtitle: 'Dekouvri evènman ak kominote ki selebre Nouvel An Kamit la',
|
||||
associations_events_title: 'Evènman Wep Ronpet 2025',
|
||||
associations_community_title: 'Kominote & Resous',
|
||||
associations_video_title: 'Dekouvri Wep Ronpet',
|
||||
associations_event1_title: 'Nouvel An Kamite',
|
||||
associations_event1_organizer: 'Afrocentricity International & Famille Muntu • GRATIS - nan 16 an',
|
||||
associations_event1_desc: 'Tan sakre pasaj nan yon nouvo wotasyon kosmik, yo viv nan amoni ak lwa inivè yo. Ann rekonekte ak rasin espirituyèl nou yo, onore zansèt nou yo, ak realinye lavi nou yo ak prensip Maât yo. Seremoni ak rituyèl, gastromi kamite, mache atizan.',
|
||||
associations_event2_title: 'Nouvel An Kamit 6262',
|
||||
associations_event2_organizer: 'Mouvement Politique Spirituel MUN • Le Lamentin, Matinik',
|
||||
associations_event2_desc: 'Selebrasyon ak Nouvo Lalin nan nan KAY NZINGHA. Seremoni, rituyèl, konferans, dine kamit, sware danse pou pouvwa ak konfyans peyi a. Depi 3è nan midi.',
|
||||
associations_link1_title: '14yèm Manm',
|
||||
associations_link1_desc: 'Sit entènèt - Evènman',
|
||||
associations_link2_title: 'Mouvement Politique Spirituel MUN',
|
||||
associations_link2_desc: 'Paj Facebook ofisyèl',
|
||||
|
||||
// Footer
|
||||
footer_copyright: 'Pwojè realize avèk ❤️ pa',
|
||||
footer_and: 'ak'
|
||||
}
|
||||
};
|
||||
|
||||
// Store dérivé pour obtenir les traductions de la langue actuelle
|
||||
export const t = derived(
|
||||
currentLanguage,
|
||||
$currentLanguage => key => {
|
||||
return translations[$currentLanguage]?.[key] || translations['fr'][key] || key;
|
||||
}
|
||||
);
|
||||
|
||||
// Fonction pour changer de langue
|
||||
export function setLanguage(lang) {
|
||||
if (translations[lang]) {
|
||||
currentLanguage.set(lang);
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
localStorage.setItem('preferred-language', lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Initialiser avec la langue sauvegardée ou détecter la langue du navigateur
|
||||
export function initLanguage() {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
const saved = localStorage.getItem('preferred-language');
|
||||
if (saved && translations[saved]) {
|
||||
currentLanguage.set(saved);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof navigator !== 'undefined') {
|
||||
const browserLang = navigator.language.slice(0, 2);
|
||||
if (translations[browserLang]) {
|
||||
currentLanguage.set(browserLang);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Liste des langues disponibles
|
||||
export const availableLanguages = [
|
||||
{ code: 'fr', name: 'Français', flag: '🇫🇷' },
|
||||
{ code: 'en', name: 'English', flag: '🇬🇧' },
|
||||
{ code: 'ht', name: 'Kreyòl Ayisyen', flag: '🇭🇹' }
|
||||
];
|
||||
@@ -1,8 +0,0 @@
|
||||
import './app.css'
|
||||
import App from './App.svelte'
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById('app'),
|
||||
})
|
||||
|
||||
export default app
|
||||
@@ -0,0 +1,180 @@
|
||||
---
|
||||
pagination:
|
||||
data: locales
|
||||
size: 1
|
||||
alias: locale
|
||||
permalink: "{% if locale == baseLocale %}/observer/index.html{% else %}/{{ locale }}/observer/index.html{% endif %}"
|
||||
layout: layouts/base.njk
|
||||
pageKey: observer
|
||||
slug: "observer/"
|
||||
eleventyComputed:
|
||||
pageTitle: "{{ 'observer_title' | t(locale) }}"
|
||||
---
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="section-header center">
|
||||
<p class="section-eyebrow">Sirius Gwada</p>
|
||||
<h1>{{ "observer_title" | t(locale) }}</h1>
|
||||
<p class="pattern-strip kente" aria-hidden="true" style="margin-inline:auto"></p>
|
||||
<p class="section-subtitle">{{ "observer_subtitle" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<script type="application/json" id="sites-data">{{ sites | dump | safe }}</script>
|
||||
|
||||
<div id="predictions-island" data-island="predictions">
|
||||
<h2 class="center">{{ "observer_calculator_title" | t(locale) }}</h2>
|
||||
<p class="section-subtitle center">{{ "observer_calculator_subtitle" | t(locale) }}</p>
|
||||
|
||||
<div class="island-app" data-year="{{ nextRising.year }}" data-locale="{{ locale }}"
|
||||
data-select-label="{{ 'observer_calculator_select_label' | t(locale) }}"
|
||||
data-heliacal-label="{{ 'observer_calculator_result_heliacal' | t(locale) }}"
|
||||
data-window-label="{{ 'observer_calculator_result_window' | t(locale) }}"
|
||||
style="margin-top: var(--space-4)"></div>
|
||||
|
||||
<div class="island-fallback card" style="overflow-x: auto; margin-top: var(--space-4)">
|
||||
<table style="width: 100%; border-collapse: collapse">
|
||||
<caption class="visually-hidden">{{ "observer_calculator_title" | t(locale) }}</caption>
|
||||
<thead>
|
||||
<tr style="text-align: left; border-bottom: 2px solid var(--border)">
|
||||
<th style="padding: var(--space-2)" scope="col">{{ "observer_calculator_table_site" | t(locale) }}</th>
|
||||
<th style="padding: var(--space-2)" scope="col">{{ "observer_calculator_table_date" | t(locale) }}</th>
|
||||
<th style="padding: var(--space-2)" scope="col">{{ "observer_calculator_table_time" | t(locale) }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for site in sites %}
|
||||
<tr style="border-bottom: 1px solid var(--border)">
|
||||
<th scope="row" style="padding: var(--space-2); font-weight: 600; text-align: left">
|
||||
{{ site.name }}
|
||||
<div style="font-size: var(--text-0); color: var(--ink-soft); font-weight: 400">
|
||||
{{ site["description_" + locale] or site.description_fr }}
|
||||
</div>
|
||||
</th>
|
||||
<td style="padding: var(--space-2)">{{ site.predictions[nextRising.year].date | formatDate(locale) }}</td>
|
||||
<td style="padding: var(--space-2)">{{ site.predictions[nextRising.year].time }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="map-island" data-island="map" style="margin-top: var(--space-7)">
|
||||
<h2 class="center">{{ "observer_map_title" | t(locale) }}</h2>
|
||||
<p class="section-subtitle center">{{ "observer_map_subtitle" | t(locale) }}</p>
|
||||
|
||||
<div class="island-app" style="margin-top: var(--space-4)"></div>
|
||||
|
||||
<ul class="island-fallback grid-auto" style="margin-top: var(--space-4); list-style: none">
|
||||
{% for site in sites %}
|
||||
<li class="card">
|
||||
<h3>{{ site.name }}</h3>
|
||||
<p>{{ site["description_" + locale] or site.description_fr }}</p>
|
||||
<p style="font-size: var(--text-0); color: var(--ink-soft)">{{ site.lat }}°N, {{ site.lon }}°O — {{ site.alt }} m</p>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2 class="center" style="margin-top: var(--space-7)">{{ "observer_timeline_title" | t(locale) }}</h2>
|
||||
<div class="timeline-h card" style="margin-top: var(--space-4)">
|
||||
<div class="timeline-h-step">
|
||||
<div class="timeline-h-icon" aria-hidden="true">🌙</div>
|
||||
<p class="timeline-h-time">{{ "observer_phase1_time" | t(locale) }}</p>
|
||||
<h4>{{ "observer_phase1_title" | t(locale) }}</h4>
|
||||
<p>{{ "observer_phase1_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-h-step">
|
||||
<div class="timeline-h-icon" aria-hidden="true">🔭</div>
|
||||
<p class="timeline-h-time">{{ "observer_phase2_time" | t(locale) }}</p>
|
||||
<h4>{{ "observer_phase2_title" | t(locale) }}</h4>
|
||||
<p>{{ "observer_phase2_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-h-step">
|
||||
<div class="timeline-h-icon" aria-hidden="true">⭐</div>
|
||||
<p class="timeline-h-time">{{ "observer_phase3_time" | t(locale) }}</p>
|
||||
<h4>{{ "observer_phase3_title" | t(locale) }}</h4>
|
||||
<p>{{ "observer_phase3_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="timeline-h-step">
|
||||
<div class="timeline-h-icon" aria-hidden="true">✨</div>
|
||||
<p class="timeline-h-time">{{ "observer_phase4_time" | t(locale) }}</p>
|
||||
<h4>{{ "observer_phase4_title" | t(locale) }}</h4>
|
||||
<p>{{ "observer_phase4_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="center" style="margin-top: var(--space-7)">{{ "observer_equipment_title" | t(locale) }}</h2>
|
||||
<div class="grid-auto" style="margin-top: var(--space-4)">
|
||||
<div class="card info-card essential">
|
||||
<div class="info-card-header">
|
||||
<h3>{{ "observer_equipment_lamp_name" | t(locale) }}</h3>
|
||||
<span class="badge">{{ "observer_equipment_essential_badge" | t(locale) }}</span>
|
||||
</div>
|
||||
<p>{{ "observer_equipment_lamp_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card essential">
|
||||
<div class="info-card-header">
|
||||
<h3>{{ "observer_equipment_compass_name" | t(locale) }}</h3>
|
||||
<span class="badge">{{ "observer_equipment_essential_badge" | t(locale) }}</span>
|
||||
</div>
|
||||
<p>{{ "observer_equipment_compass_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card essential">
|
||||
<div class="info-card-header">
|
||||
<h3>{{ "observer_equipment_clothes_name" | t(locale) }}</h3>
|
||||
<span class="badge">{{ "observer_equipment_essential_badge" | t(locale) }}</span>
|
||||
</div>
|
||||
<p>{{ "observer_equipment_clothes_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "observer_equipment_binoculars_name" | t(locale) }}</h3>
|
||||
<p>{{ "observer_equipment_binoculars_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "observer_equipment_notebook_name" | t(locale) }}</h3>
|
||||
<p>{{ "observer_equipment_notebook_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="center" style="margin-top: var(--space-7)">{{ "observer_tips_title" | t(locale) }}</h2>
|
||||
<div class="grid-auto" style="margin-top: var(--space-4)">
|
||||
<div class="card feature-card">
|
||||
<div style="font-size: var(--text-4)" aria-hidden="true">🌤️</div>
|
||||
<h3>{{ "observer_tip_weather_title" | t(locale) }}</h3>
|
||||
<p>{{ "observer_tip_weather_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card feature-card">
|
||||
<div style="font-size: var(--text-4)" aria-hidden="true">🌑</div>
|
||||
<h3>{{ "observer_tip_moon_title" | t(locale) }}</h3>
|
||||
<p>{{ "observer_tip_moon_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card feature-card">
|
||||
<div style="font-size: var(--text-4)" aria-hidden="true">📱</div>
|
||||
<h3>{{ "observer_tip_apps_title" | t(locale) }}</h3>
|
||||
<p>{{ "observer_tip_apps_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card feature-card">
|
||||
<div style="font-size: var(--text-4)" aria-hidden="true">👥</div>
|
||||
<h3>{{ "observer_tip_group_title" | t(locale) }}</h3>
|
||||
<p>{{ "observer_tip_group_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section" id="globe-island" data-island="globe" style="background: var(--surface-sunk)">
|
||||
<div class="container">
|
||||
<div class="section-header center">
|
||||
<h2>{{ "globe_title" | t(locale) }}</h2>
|
||||
<p class="section-subtitle">{{ "globe_p1" | t(locale) }}</p>
|
||||
</div>
|
||||
<p class="prose center">{{ "globe_p2" | t(locale) }}</p>
|
||||
<div class="island-app" style="margin-top: var(--space-4)"></div>
|
||||
<p class="center" style="color: var(--ink-soft); font-size: var(--text-0)">{{ "globe_controls_hint" | t(locale) }}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script type="module" src="/src/islands/predictions/mount.js"></script>
|
||||
<script type="module" src="/src/islands/map/mount.js"></script>
|
||||
<script type="module" src="/src/islands/globe/mount.js"></script>
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
pagination:
|
||||
data: locales
|
||||
size: 1
|
||||
alias: locale
|
||||
permalink: "{% if locale == baseLocale %}/sirius-science/index.html{% else %}/{{ locale }}/sirius-science/index.html{% endif %}"
|
||||
layout: layouts/base.njk
|
||||
pageKey: science
|
||||
slug: "sirius-science/"
|
||||
eleventyComputed:
|
||||
pageTitle: "{{ 'science_title' | t(locale) }}"
|
||||
---
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="section-header center">
|
||||
<p class="section-eyebrow">Sirius Gwada</p>
|
||||
<h1>{{ "science_title" | t(locale) }}</h1>
|
||||
<p class="pattern-strip bogolan" aria-hidden="true" style="margin-inline:auto"></p>
|
||||
<p class="section-subtitle">{{ "science_subtitle" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<fieldset class="tabs">
|
||||
<legend class="visually-hidden">{{ "science_title" | t(locale) }}</legend>
|
||||
|
||||
<input type="radio" name="science-tab" id="tab-mechanics" class="tab-input" checked>
|
||||
<input type="radio" name="science-tab" id="tab-arcus" class="tab-input">
|
||||
<input type="radio" name="science-tab" id="tab-factors" class="tab-input">
|
||||
<input type="radio" name="science-tab" id="tab-calc" class="tab-input">
|
||||
|
||||
<div class="tab-list" role="tablist">
|
||||
<label class="tab-label" for="tab-mechanics">{{ "science_tab_mechanics" | t(locale) }}</label>
|
||||
<label class="tab-label" for="tab-arcus">{{ "science_tab_arcus" | t(locale) }}</label>
|
||||
<label class="tab-label" for="tab-factors">{{ "science_tab_factors" | t(locale) }}</label>
|
||||
<label class="tab-label" for="tab-calc">{{ "science_tab_calc" | t(locale) }}</label>
|
||||
</div>
|
||||
|
||||
<div class="tab-panels">
|
||||
<div class="tab-panel prose center">
|
||||
<h2>{{ "science_mechanics_title" | t(locale) }}</h2>
|
||||
<p>{{ "science_mechanics_p1" | t(locale) }}</p>
|
||||
<div class="diagram-orbit card" aria-hidden="true">
|
||||
<div class="ring"></div>
|
||||
<div class="body sun">☀️<span>{{ "science_diagram_sun" | t(locale) }}</span></div>
|
||||
<div class="body earth">🌍<span>{{ "science_diagram_earth" | t(locale) }}</span></div>
|
||||
<div class="body sirius">⭐<span>{{ "science_diagram_sirius" | t(locale) }}</span></div>
|
||||
</div>
|
||||
<p>{{ "science_mechanics_p2" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel prose center">
|
||||
<h2>{{ "science_arcus_title" | t(locale) }}</h2>
|
||||
<p>{{ "science_arcus_p1" | t(locale) }}</p>
|
||||
<div class="diagram-arcus card" aria-hidden="true">
|
||||
<span class="horizon-label">{{ "science_arcus_horizon_label" | t(locale) }}</span>
|
||||
<div class="angle"></div>
|
||||
<span class="angle-label">9-10°</span>
|
||||
<span class="sirius-mark">⭐</span>
|
||||
<span class="sun-mark">☀️</span>
|
||||
</div>
|
||||
<p>{{ "science_arcus_p2" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel">
|
||||
<div class="grid-auto">
|
||||
<div class="card info-card">
|
||||
<h3>{{ "science_factor_magnitude_title" | t(locale) }}</h3>
|
||||
<p>{{ "science_factor_magnitude_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "science_factor_latitude_title" | t(locale) }}</h3>
|
||||
<p>{{ "science_factor_latitude_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
<div class="card info-card">
|
||||
<h3>{{ "science_factor_atmosphere_title" | t(locale) }}</h3>
|
||||
<p>{{ "science_factor_atmosphere_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-panel prose center">
|
||||
<h2>{{ "science_calc_title" | t(locale) }}</h2>
|
||||
|
||||
<div class="card">
|
||||
<h3>{{ "science_calc_formula_label" | t(locale) }}</h3>
|
||||
<p style="font-family: ui-monospace, monospace">{{ "science_calc_formula" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: var(--space-3)">
|
||||
<h3>{{ "science_calc_step1_title" | t(locale) }}</h3>
|
||||
<p style="font-family: ui-monospace, monospace">{{ "science_calc_step1_value" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: var(--space-3)">
|
||||
<h3>{{ "science_calc_step2_title" | t(locale) }}</h3>
|
||||
<p style="font-family: ui-monospace, monospace">
|
||||
{{ "science_calc_step2_ra" | t(locale) }}<br>
|
||||
{{ "science_calc_step2_dec" | t(locale) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: var(--space-3)">
|
||||
<h3>{{ "science_calc_arcus_title" | t(locale) }}</h3>
|
||||
<p>{{ "science_calc_arcus_desc" | t(locale) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: var(--space-3)">
|
||||
<h3>{{ "science_calc_sources_title" | t(locale) }}</h3>
|
||||
<p>{{ "science_calc_sources_text" | t(locale) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,18 @@
|
||||
@layer reset, tokens, base, layouts, components, utilities;
|
||||
|
||||
@import "./reset.css" layer(reset);
|
||||
@import "./tokens.css" layer(tokens);
|
||||
@import "./themes/oki.css" layer(tokens);
|
||||
@import "./base.css" layer(base);
|
||||
@import "./layouts.css" layer(layouts);
|
||||
@import "./patterns.css" layer(components);
|
||||
@import "./components/nav.css" layer(components);
|
||||
@import "./components/footer.css" layer(components);
|
||||
@import "./components/buttons.css" layer(components);
|
||||
@import "./components/hero.css" layer(components);
|
||||
@import "./components/cards.css" layer(components);
|
||||
@import "./components/tabs.css" layer(components);
|
||||
@import "./components/timeline.css" layer(components);
|
||||
@import "./components/diagrams.css" layer(components);
|
||||
@import "./components/associations.css" layer(components);
|
||||
@import "./components/islands.css" layer(components);
|
||||
@@ -0,0 +1,87 @@
|
||||
@font-face {
|
||||
font-family: "Fraunces Variable";
|
||||
src: url("/assets/fonts/fraunces-variable.woff2") format("woff2-variations");
|
||||
font-weight: 300 900;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Atkinson Hyperlegible";
|
||||
src: url("/assets/fonts/atkinson-400.woff2") format("woff2");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Atkinson Hyperlegible";
|
||||
src: url("/assets/fonts/atkinson-700.woff2") format("woff2");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--surface);
|
||||
color: var(--ink);
|
||||
font-family: var(--font-body);
|
||||
font-size: var(--text-1);
|
||||
line-height: var(--leading-normal);
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-family: var(--font-display);
|
||||
line-height: var(--leading-tight);
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
h1 { font-size: var(--text-6); }
|
||||
h2 { font-size: var(--text-5); }
|
||||
h3 { font-size: var(--text-3); }
|
||||
h4 { font-size: var(--text-2); }
|
||||
|
||||
p {
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
a {
|
||||
text-underline-offset: 0.2em;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 3px solid var(--focus-ring);
|
||||
outline-offset: 3px;
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
top: var(--space-2);
|
||||
left: var(--space-2);
|
||||
z-index: 100;
|
||||
padding: var(--space-2) var(--space-3);
|
||||
background: var(--surface-raised);
|
||||
color: var(--ink);
|
||||
border-radius: var(--radius-sm);
|
||||
box-shadow: var(--shadow-md);
|
||||
transform: translateY(-150%);
|
||||
transition: transform var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
|
||||
.skip-link:focus-visible {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.visually-hidden {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
.event-link,
|
||||
.community-link {
|
||||
display: flex;
|
||||
gap: var(--space-3);
|
||||
align-items: flex-start;
|
||||
padding-block: var(--space-3);
|
||||
border-bottom: 1px solid var(--border);
|
||||
text-decoration: none;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.event-link:last-child,
|
||||
.community-link:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.event-icon,
|
||||
.community-icon {
|
||||
font-size: var(--text-3);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.event-info,
|
||||
.community-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
}
|
||||
|
||||
.event-title,
|
||||
.community-title {
|
||||
font-weight: 700;
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.event-platform {
|
||||
font-size: var(--text-0);
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
|
||||
.video-frame {
|
||||
position: relative;
|
||||
aspect-ratio: 16 / 9;
|
||||
border-radius: var(--radius-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.video-frame iframe {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.associations-note {
|
||||
font-size: var(--text-0);
|
||||
color: var(--ink-soft);
|
||||
margin-top: var(--space-4);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: var(--tap-target);
|
||||
padding-inline: var(--space-4);
|
||||
border-radius: var(--radius-pill);
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
transition: transform var(--duration-fast) var(--ease-out),
|
||||
background var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--gold-surface);
|
||||
color: oklch(20% 0.03 265);
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
border: 2px solid var(--gold);
|
||||
color: var(--gold);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
.feature-card,
|
||||
.info-card {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.feature-card h3,
|
||||
.info-card h3 {
|
||||
color: var(--gold);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.info-card.essential {
|
||||
border-color: var(--gold);
|
||||
background: light-dark(oklch(96% 0.04 85), oklch(24% 0.04 85));
|
||||
}
|
||||
|
||||
.info-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
gap: var(--space-2);
|
||||
margin-bottom: var(--space-1);
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding-inline: var(--space-2);
|
||||
border-radius: var(--radius-pill);
|
||||
background: var(--gold-surface);
|
||||
color: oklch(20% 0.03 265);
|
||||
font-size: var(--text-0);
|
||||
font-weight: 700;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
.diagram-orbit {
|
||||
position: relative;
|
||||
height: 16rem;
|
||||
margin-block: var(--space-4);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.diagram-orbit .ring {
|
||||
position: absolute;
|
||||
width: 12rem;
|
||||
height: 12rem;
|
||||
border: 2px dashed var(--border);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.diagram-orbit .body {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: var(--space-1);
|
||||
font-size: var(--text-4);
|
||||
}
|
||||
|
||||
.diagram-orbit .body span {
|
||||
font-size: var(--text-0);
|
||||
font-weight: 700;
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.diagram-orbit .sun { top: 50%; left: 50%; transform: translate(-50%, -50%); }
|
||||
.diagram-orbit .earth { top: 15%; left: 15%; }
|
||||
.diagram-orbit .sirius { top: 15%; right: 15%; }
|
||||
|
||||
.diagram-arcus {
|
||||
position: relative;
|
||||
height: 12rem;
|
||||
margin-block: var(--space-4);
|
||||
border-bottom: 2px solid var(--gold);
|
||||
}
|
||||
|
||||
.diagram-arcus .horizon-label {
|
||||
position: absolute;
|
||||
bottom: -1.6rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
color: var(--gold);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.diagram-arcus .angle {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 30%;
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
border: 2px solid var(--caribbean-teal);
|
||||
border-bottom: none;
|
||||
border-left: none;
|
||||
border-radius: 0 100% 0 0;
|
||||
}
|
||||
|
||||
.diagram-arcus .angle-label {
|
||||
position: absolute;
|
||||
bottom: 4.2rem;
|
||||
left: calc(30% + 4.2rem);
|
||||
color: var(--caribbean-teal);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.diagram-arcus .sirius-mark,
|
||||
.diagram-arcus .sun-mark {
|
||||
position: absolute;
|
||||
bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.diagram-arcus .sirius-mark { left: 25%; }
|
||||
.diagram-arcus .sun-mark { right: 25%; bottom: -0.6rem; }
|
||||
@@ -0,0 +1,80 @@
|
||||
.site-footer {
|
||||
background: var(--surface-sunk);
|
||||
border-top: 1px solid var(--border);
|
||||
padding-block: var(--space-6) var(--space-4);
|
||||
margin-top: var(--space-7);
|
||||
}
|
||||
|
||||
.footer-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
|
||||
gap: var(--space-5);
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
|
||||
.footer-section h2 {
|
||||
font-size: var(--text-2);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.footer-section h3 {
|
||||
font-size: var(--text-1);
|
||||
color: var(--gold);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.footer-section ul {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-1);
|
||||
}
|
||||
|
||||
.footer-section a {
|
||||
text-decoration: none;
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
|
||||
.footer-section a:hover {
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.countdown-item {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-3);
|
||||
}
|
||||
|
||||
.countdown-value {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-2);
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.countdown-label {
|
||||
color: var(--ink-soft);
|
||||
font-size: var(--text-0);
|
||||
}
|
||||
|
||||
.footer-bottom {
|
||||
text-align: center;
|
||||
border-top: 1px solid var(--border);
|
||||
padding-top: var(--space-4);
|
||||
}
|
||||
|
||||
.footer-bottom .pattern-strip {
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.footer-credits a {
|
||||
color: var(--gold);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer-quote {
|
||||
margin-top: var(--space-2);
|
||||
font-style: italic;
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
.hero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
padding-block: var(--space-7) var(--space-6);
|
||||
background: light-dark(
|
||||
linear-gradient(180deg, oklch(96% 0.02 85), oklch(92% 0.03 60)),
|
||||
linear-gradient(180deg, oklch(14% 0.03 265), oklch(10% 0.02 265))
|
||||
);
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.1em;
|
||||
}
|
||||
|
||||
.hero-title .accent {
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-3);
|
||||
color: var(--gold);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
.hero-description {
|
||||
font-size: var(--text-2);
|
||||
color: var(--ink-soft);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
.hero-date {
|
||||
margin-top: var(--space-4);
|
||||
font-size: var(--text-1);
|
||||
}
|
||||
|
||||
.hero-date strong {
|
||||
display: block;
|
||||
font-family: var(--font-display);
|
||||
font-size: var(--text-3);
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.hero-cta {
|
||||
justify-content: center;
|
||||
margin-top: var(--space-5);
|
||||
}
|
||||
|
||||
/* Système solaire décoratif, en CSS pure — masqué aux lecteurs d'écran */
|
||||
.hero-orbits {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero-orbits .sun {
|
||||
position: absolute;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
border-radius: 50%;
|
||||
background: var(--gold-surface);
|
||||
box-shadow: 0 0 40px 10px var(--gold-surface);
|
||||
}
|
||||
|
||||
.hero-orbits .orbit {
|
||||
position: absolute;
|
||||
border: 1px solid light-dark(oklch(50% 0.05 85 / 30%), oklch(80% 0.05 85 / 20%));
|
||||
border-radius: 50%;
|
||||
animation: orbit-spin linear infinite;
|
||||
}
|
||||
|
||||
.hero-orbits .orbit span {
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
left: 50%;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--caribbean-teal);
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.hero-orbits .orbit.sirius span {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
background: var(--gold-surface);
|
||||
box-shadow: 0 0 12px var(--gold-surface);
|
||||
}
|
||||
|
||||
@keyframes orbit-spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@media (max-width: 47.99em) {
|
||||
.hero-orbits { opacity: 0.25; }
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/* Îlots Svelte : le contenu statique (.island-fallback) est toujours présent
|
||||
dans le HTML ; s'il s'hydrate, le script de montage ajoute la classe
|
||||
.is-enhanced sur le conteneur [data-island], qui masque alors le repli. */
|
||||
.island-app:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[data-island].is-enhanced .island-fallback {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.island-canvas {
|
||||
width: 100%;
|
||||
height: 22rem;
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface-sunk);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
.nav {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
background: light-dark(oklch(96% 0.015 85 / 90%), oklch(16% 0.03 265 / 88%));
|
||||
backdrop-filter: blur(10px);
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.nav-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-3);
|
||||
min-height: var(--tap-target);
|
||||
padding-block: var(--space-2);
|
||||
}
|
||||
|
||||
.nav-brand {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 600;
|
||||
font-size: var(--text-2);
|
||||
color: var(--ink);
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-brand span {
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.nav-disclosure {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.nav-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: var(--tap-target);
|
||||
height: var(--tap-target);
|
||||
border-radius: var(--radius-sm);
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.nav-toggle::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-toggle-icon,
|
||||
.nav-toggle-icon::before,
|
||||
.nav-toggle-icon::after {
|
||||
display: block;
|
||||
width: 22px;
|
||||
height: 2px;
|
||||
background: var(--ink);
|
||||
border-radius: var(--radius-pill);
|
||||
position: relative;
|
||||
transition: transform var(--duration-fast) var(--ease-out);
|
||||
}
|
||||
|
||||
.nav-toggle-icon::before,
|
||||
.nav-toggle-icon::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.nav-toggle-icon::before { top: -7px; }
|
||||
.nav-toggle-icon::after { top: 7px; }
|
||||
|
||||
.nav-disclosure[open] .nav-toggle-icon {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav-disclosure[open] .nav-toggle-icon::before {
|
||||
transform: translateY(7px) rotate(45deg);
|
||||
}
|
||||
|
||||
.nav-disclosure[open] .nav-toggle-icon::after {
|
||||
transform: translateY(-7px) rotate(-45deg);
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
position: absolute;
|
||||
inset-inline: 0;
|
||||
top: 100%;
|
||||
background: var(--surface);
|
||||
border-bottom: 1px solid var(--border);
|
||||
padding: var(--space-2) var(--space-4) var(--space-4);
|
||||
}
|
||||
|
||||
.nav-menu a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: var(--tap-target);
|
||||
text-decoration: none;
|
||||
color: var(--ink);
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-menu a[aria-current="page"] {
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
.nav-lang {
|
||||
display: flex;
|
||||
gap: var(--space-2);
|
||||
font-size: var(--text-0);
|
||||
}
|
||||
|
||||
.nav-lang a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: var(--tap-target);
|
||||
padding-inline: var(--space-2);
|
||||
border-radius: var(--radius-pill);
|
||||
text-decoration: none;
|
||||
color: var(--ink-soft);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-lang a.active {
|
||||
background: var(--surface-sunk);
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
@media (min-width: 60em) {
|
||||
.nav-toggle { display: none; }
|
||||
|
||||
.nav-menu {
|
||||
position: static;
|
||||
flex-direction: row;
|
||||
gap: var(--space-4);
|
||||
border-bottom: none;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav-menu a {
|
||||
min-height: auto;
|
||||
border-bottom: none;
|
||||
padding-block: var(--space-1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Onglets 100% CSS (radio + label), sans JavaScript.
|
||||
Structure attendue, tous enfants directs de fieldset.tabs, dans cet ordre :
|
||||
input.tab-input (un par onglet, id unique)
|
||||
.tab-list > label[for=...] (un par onglet)
|
||||
.tab-panels > [data-panel="..."] (un par onglet)
|
||||
Chaque input:checked révèle le panneau dont data-panel correspond à son id
|
||||
et met en avant le label associé — déclaré une fois par page appelante
|
||||
via un attribut [data-tab-id] passé en contexte (voir pages). */
|
||||
|
||||
.tabs {
|
||||
border: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tab-input {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0 0 0 0);
|
||||
}
|
||||
|
||||
.tab-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-2);
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
|
||||
.tab-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: var(--tap-target);
|
||||
padding-inline: var(--space-3);
|
||||
border-radius: var(--radius-pill);
|
||||
border: 2px solid var(--border);
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tab-panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Sélection par position (1er input coché -> 1er panneau/label), générique :
|
||||
fonctionne quels que soient les id choisis, tant que l'ordre DOM est
|
||||
input*, puis .tab-list, puis .tab-panels. */
|
||||
.tab-input:nth-of-type(1):checked ~ .tab-panels .tab-panel:nth-of-type(1),
|
||||
.tab-input:nth-of-type(2):checked ~ .tab-panels .tab-panel:nth-of-type(2),
|
||||
.tab-input:nth-of-type(3):checked ~ .tab-panels .tab-panel:nth-of-type(3),
|
||||
.tab-input:nth-of-type(4):checked ~ .tab-panels .tab-panel:nth-of-type(4) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tab-input:nth-of-type(1):checked ~ .tab-list .tab-label:nth-of-type(1),
|
||||
.tab-input:nth-of-type(2):checked ~ .tab-list .tab-label:nth-of-type(2),
|
||||
.tab-input:nth-of-type(3):checked ~ .tab-list .tab-label:nth-of-type(3),
|
||||
.tab-input:nth-of-type(4):checked ~ .tab-list .tab-label:nth-of-type(4) {
|
||||
background: var(--gold-surface);
|
||||
border-color: var(--gold-surface);
|
||||
color: oklch(20% 0.03 265);
|
||||
}
|
||||
|
||||
@media (max-width: 47.99em) {
|
||||
.tab-list {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/* Timeline verticale (Culture, Dogon, héritage diaspora) */
|
||||
.timeline-v {
|
||||
position: relative;
|
||||
max-width: var(--measure);
|
||||
margin-inline: auto;
|
||||
padding-left: var(--space-5);
|
||||
}
|
||||
|
||||
.timeline-v::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0.4rem;
|
||||
top: 0.4rem;
|
||||
bottom: 0.4rem;
|
||||
width: 2px;
|
||||
background: var(--gold-surface);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.timeline-v-item {
|
||||
position: relative;
|
||||
padding-bottom: var(--space-4);
|
||||
}
|
||||
|
||||
.timeline-v-item::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -1.65rem;
|
||||
top: 0.3rem;
|
||||
width: 0.8rem;
|
||||
height: 0.8rem;
|
||||
border-radius: 50%;
|
||||
background: var(--gold-surface);
|
||||
}
|
||||
|
||||
.timeline-v-date {
|
||||
font-weight: 700;
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
/* Timeline horizontale à 4 étapes (Observer) */
|
||||
.timeline-h {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: var(--space-3);
|
||||
counter-reset: step;
|
||||
}
|
||||
|
||||
.timeline-h-step {
|
||||
text-align: center;
|
||||
padding-top: var(--space-3);
|
||||
border-top: 4px solid var(--gold-surface);
|
||||
}
|
||||
|
||||
.timeline-h-icon {
|
||||
font-size: var(--text-4);
|
||||
}
|
||||
|
||||
.timeline-h-time {
|
||||
font-weight: 700;
|
||||
color: var(--gold);
|
||||
}
|
||||
|
||||
@media (max-width: 47.99em) {
|
||||
.timeline-h {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* Primitives de composition — inspirées de Every Layout (every-layout.dev) */
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 75rem;
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--space-4);
|
||||
}
|
||||
|
||||
.prose {
|
||||
max-width: var(--measure);
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.stack > * + * {
|
||||
margin-block-start: var(--stack-space, var(--space-4));
|
||||
}
|
||||
|
||||
.cluster {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: var(--cluster-space, var(--space-3));
|
||||
}
|
||||
|
||||
.center {
|
||||
max-width: var(--center-measure, 65ch);
|
||||
margin-inline: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.sidebar > :last-child {
|
||||
flex-basis: 0;
|
||||
flex-grow: 999;
|
||||
min-width: 60%;
|
||||
}
|
||||
|
||||
.grid-auto {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min, 16rem)), 1fr));
|
||||
gap: var(--space-4);
|
||||
}
|
||||
|
||||
.section {
|
||||
padding-block: var(--space-7);
|
||||
container-type: inline-size;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
|
||||
.section-eyebrow {
|
||||
display: inline-block;
|
||||
font-family: var(--font-body);
|
||||
font-weight: 700;
|
||||
font-size: var(--text-0);
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--gold);
|
||||
margin-bottom: var(--space-2);
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
color: var(--ink-soft);
|
||||
font-size: var(--text-2);
|
||||
margin-top: var(--space-2);
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--surface-raised);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: var(--space-4);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Motifs panafricains — utilisés en accents ponctuels (un par section, effet
|
||||
Von Restorff), jamais en texture de fond généralisée. */
|
||||
|
||||
.pattern-strip {
|
||||
display: block;
|
||||
height: 0.5rem;
|
||||
width: 100%;
|
||||
max-width: 8rem;
|
||||
border-radius: var(--radius-pill);
|
||||
margin-block: var(--space-3);
|
||||
}
|
||||
|
||||
.pattern-strip.kente {
|
||||
background: repeating-linear-gradient(
|
||||
45deg,
|
||||
var(--gold-surface) 0 10px,
|
||||
var(--kente-red) 10px 20px
|
||||
);
|
||||
}
|
||||
|
||||
.pattern-strip.bogolan {
|
||||
background-image: radial-gradient(circle, var(--gold-surface) 30%, transparent 31%);
|
||||
background-size: 12px 12px;
|
||||
background-color: var(--bogolan-green);
|
||||
}
|
||||
|
||||
.pattern-strip.adinkra {
|
||||
background: repeating-conic-gradient(
|
||||
var(--gold-surface) 0deg 90deg,
|
||||
var(--caribbean-teal) 90deg 180deg
|
||||
);
|
||||
background-size: 14px 14px;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
*, *::before, *::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
hanging-punctuation: first last;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100svh;
|
||||
}
|
||||
|
||||
img, picture, svg, canvas {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
input, button, textarea, select {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
ul[class], ol[class] {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
/* Thème OKI — identité par défaut de Gwada-Sirius.
|
||||
Un fichier de thème ne redéfinit que des tokens (jamais de sélecteurs de
|
||||
composants), pour rester échangeable avec d'autres identités visuelles OKI. */
|
||||
[data-theme="oki"] {
|
||||
--brand-name: "Sirius Gwada";
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
|
||||
/* === Couleur — oklch, contraste d'abord (méthode modus-vivendi) ===
|
||||
Deux thèmes conceptuellement liés au sujet : Aube (clair) / Nuit (sombre). */
|
||||
--ink: light-dark(oklch(23% 0.03 265), oklch(95% 0.015 85));
|
||||
--ink-soft: light-dark(oklch(38% 0.03 265), oklch(80% 0.02 85));
|
||||
--surface: light-dark(oklch(96% 0.015 85), oklch(16% 0.03 265));
|
||||
--surface-raised: light-dark(oklch(99% 0.008 85), oklch(21% 0.03 265));
|
||||
--surface-sunk: light-dark(oklch(91% 0.02 85), oklch(12% 0.025 265));
|
||||
--border: light-dark(oklch(85% 0.02 85), oklch(32% 0.035 265));
|
||||
|
||||
/* Or de Sirius : variante lisible (texte/liens) + variante décorative (glows) */
|
||||
--gold: light-dark(oklch(45% 0.15 75), oklch(82% 0.15 87));
|
||||
--gold-surface: oklch(80% 0.16 85);
|
||||
--kente-red: light-dark(oklch(46% 0.18 25), oklch(70% 0.19 25));
|
||||
--bogolan-green: light-dark(oklch(40% 0.09 145), oklch(68% 0.12 145));
|
||||
--caribbean-teal: light-dark(oklch(43% 0.09 195), oklch(74% 0.11 195));
|
||||
|
||||
--focus-ring: var(--caribbean-teal);
|
||||
|
||||
/* === Typographie === */
|
||||
--font-display: "Fraunces Variable", "Fraunces", ui-serif, Georgia, serif;
|
||||
--font-body: "Atkinson Hyperlegible", ui-sans-serif, system-ui, sans-serif;
|
||||
|
||||
--text-0: clamp(0.8rem, 0.78rem + 0.1vw, 0.875rem);
|
||||
--text-1: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
|
||||
--text-2: clamp(1.125rem, 1.05rem + 0.4vw, 1.375rem);
|
||||
--text-3: clamp(1.375rem, 1.2rem + 0.75vw, 1.75rem);
|
||||
--text-4: clamp(1.75rem, 1.4rem + 1.5vw, 2.5rem);
|
||||
--text-5: clamp(2.25rem, 1.7rem + 2.5vw, 3.5rem);
|
||||
--text-6: clamp(2.75rem, 1.8rem + 4.5vw, 5.5rem);
|
||||
|
||||
--leading-tight: 1.15;
|
||||
--leading-normal: 1.6;
|
||||
--measure: 65ch;
|
||||
|
||||
/* === Espacement (échelle modulaire) === */
|
||||
--space-1: 0.25rem;
|
||||
--space-2: 0.5rem;
|
||||
--space-3: 1rem;
|
||||
--space-4: 1.5rem;
|
||||
--space-5: 2.5rem;
|
||||
--space-6: 4rem;
|
||||
--space-7: 6rem;
|
||||
|
||||
/* === Formes, ombres, mouvement === */
|
||||
--radius-sm: 0.5rem;
|
||||
--radius-md: 1rem;
|
||||
--radius-lg: 1.5rem;
|
||||
--radius-pill: 999px;
|
||||
|
||||
--shadow-sm: 0 1px 3px light-dark(oklch(23% 0.03 265 / 12%), oklch(0% 0 0 / 30%));
|
||||
--shadow-md: 0 8px 30px light-dark(oklch(23% 0.03 265 / 12%), oklch(0% 0 0 / 45%));
|
||||
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--duration-fast: 200ms;
|
||||
--duration-base: 400ms;
|
||||
--duration-slow: 700ms;
|
||||
|
||||
/* Fitts : cible tactile minimale */
|
||||
--tap-target: 48px;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,17 @@
|
||||
echo "🌟 Sirius en Guadeloupe - Démarrage du projet"
|
||||
echo "============================================="
|
||||
|
||||
# Vérifier si node_modules existe
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo "📦 Installation des dépendances..."
|
||||
npm install
|
||||
fi
|
||||
|
||||
echo "🚀 Lancement du serveur de développement..."
|
||||
echo "📱 L'application sera accessible sur http://localhost:5173"
|
||||
echo "📱 L'application sera accessible sur http://localhost:8080"
|
||||
echo ""
|
||||
echo "Commandes disponibles:"
|
||||
echo " - Ctrl+C : Arrêter le serveur"
|
||||
echo " - npm run build : Créer une version de production"
|
||||
echo " - npm run build : Créer une version de production (11ty + Vite -> _site/)"
|
||||
echo " - npm run preview : Prévisualiser la version de production"
|
||||
echo ""
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
base: './', // Utiliser des chemins relatifs
|
||||
})
|
||||
Reference in New Issue
Block a user