Refonte complète en SvelteKit (méthode OKI, AI-Overview ready)
Reconstruit le site statique mono-page (Bulma + htmx + Strapi) en SvelteKit 2 + Svelte 5 (runes) + TypeScript, 100 % statique (adapter-static), auto-hébergé. - Contenu enrichi à partir du dossier documentaire sourcé : 28 pages (histoire, Mé 67, procès 1968, 9 fiches militants, idéologie, héritage, publications, charte, orientation, sources, FAQ, actualités, contact, mentions légales). - Souveraineté : retrait de Bulma/htmx/mustache/ionicons/Plausible/Google Fonts et de l'API Strapi. Polices Archivo/Inter et sprite SVG auto-hébergés (zéro emoji). - Identité GONG (drapeau vert/blanc/rouge), thème sombre par défaut + clair AA, cadences motion gwoka, KineticText, timeline, 404 kréyòl, PWA hors-ligne. - SEO/AI-Overview : HTML sémantique, JSON-LD (Organization, Person, Event, FAQPage, Article...), hreflang, sitemap dynamique, robots/humans.txt. - Sécurité : CSP hachée + en-têtes (.htaccess o2switch + _headers Cloudflare), HSTS. - Actualités éditées via Sveltia CMS (git-based) ; Strapi retiré. npm run build : vert · npm run check : 0 erreur / 0 warning · JS 97 Ko gzip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b89c1a80b7
commit
cd9b9b093c
@@ -0,0 +1,86 @@
|
||||
// Chargement des actualités depuis content/actualites/*.md (éditées via Sveltia CMS).
|
||||
// $lib/server → garanti côté serveur : `marked` ne part jamais dans le bundle client.
|
||||
// Le site étant prérendu, ce code s'exécute au build ; les pages sont ensuite 100 % statiques.
|
||||
import { marked } from 'marked';
|
||||
|
||||
const files = import.meta.glob('/content/actualites/*.md', {
|
||||
query: '?raw',
|
||||
import: 'default',
|
||||
eager: true
|
||||
}) as Record<string, string>;
|
||||
|
||||
export interface Actualite {
|
||||
slug: string;
|
||||
titre: string;
|
||||
date: string; // affichage libre (ex. « 26 mai 2026 »)
|
||||
iso: string; // ISO pour <time datetime> / schema
|
||||
chapeau: string;
|
||||
couverture?: string;
|
||||
couvertureAlt?: string;
|
||||
top: boolean;
|
||||
html: string; // corps rendu (first-party, Sveltia)
|
||||
texte: string; // corps brut (pour description/estimation de lecture)
|
||||
}
|
||||
|
||||
/** Parse un front-matter YAML simple (clés scalaires, valeurs entre guillemets optionnelles). */
|
||||
function parseFrontmatter(raw: string): { data: Record<string, string>; body: string } {
|
||||
const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
||||
if (!m) return { data: {}, body: raw };
|
||||
const data: Record<string, string> = {};
|
||||
for (const line of m[1].split(/\r?\n/)) {
|
||||
const kv = line.match(/^([A-Za-z0-9_]+)\s*:\s*(.*)$/);
|
||||
if (!kv) continue;
|
||||
let val = kv[2].trim();
|
||||
if (
|
||||
(val.startsWith('"') && val.endsWith('"')) ||
|
||||
(val.startsWith("'") && val.endsWith("'"))
|
||||
) {
|
||||
val = val.slice(1, -1);
|
||||
}
|
||||
data[kv[1]] = val;
|
||||
}
|
||||
return { data, body: m[2] };
|
||||
}
|
||||
|
||||
function frToIso(date: string): string {
|
||||
// Accepte déjà l'ISO ; sinon renvoie tel quel (Sveltia écrit du YYYY-MM-DD).
|
||||
return /^\d{4}-\d{2}-\d{2}/.test(date) ? date : date;
|
||||
}
|
||||
|
||||
function frDisplay(iso: string): string {
|
||||
const d = new Date(iso);
|
||||
if (Number.isNaN(d.getTime())) return iso;
|
||||
return d.toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' });
|
||||
}
|
||||
|
||||
let cache: Actualite[] | null = null;
|
||||
|
||||
export function getActualites(): Actualite[] {
|
||||
if (cache) return cache;
|
||||
const out: Actualite[] = [];
|
||||
for (const [path, raw] of Object.entries(files)) {
|
||||
const slug = path.split('/').pop()!.replace(/\.md$/, '');
|
||||
const { data, body } = parseFrontmatter(raw);
|
||||
if (!data.titre) continue;
|
||||
const iso = frToIso(data.date ?? '');
|
||||
out.push({
|
||||
slug,
|
||||
titre: data.titre,
|
||||
iso,
|
||||
date: data.date ? frDisplay(iso) : '',
|
||||
chapeau: data.chapeau ?? '',
|
||||
couverture: data.couverture || undefined,
|
||||
couvertureAlt: data.couvertureAlt || data.titre,
|
||||
top: data.top === 'true',
|
||||
html: marked.parse(body.trim(), { async: false }) as string,
|
||||
texte: body.trim()
|
||||
});
|
||||
}
|
||||
out.sort((a, b) => (a.iso < b.iso ? 1 : a.iso > b.iso ? -1 : 0));
|
||||
cache = out;
|
||||
return out;
|
||||
}
|
||||
|
||||
export function getActualite(slug: string): Actualite | undefined {
|
||||
return getActualites().find((a) => a.slug === slug);
|
||||
}
|
||||
Reference in New Issue
Block a user