Files
gong.gp/src/lib/server/actualites.ts
T
sucupiraandClaude Opus 4.8 cd9b9b093c 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>
2026-07-24 23:57:37 -04:00

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);
}