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>
87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
// 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);
|
|
}
|