feat(oki): fondations de la migration vers la stack souveraine OKI

Architecture décidée et documentée dans ADR.md : SvelteKit natif en
fichiers plats plutôt que Strapi (55 outils, données statiques,
souveraineté et budget performance prioritaires — doctrine §1.2, §4.4).

- frontend/ : SvelteKit 2 + Svelte 5 (runes), adapter-static, 58 pages
  prérendues, CSS natif en @layer (reset→tokens→base→layouts→components),
  tokens oklch(), container queries, typo fluide clamp(), 2 polices WOFF2
  auto-hébergées (Atkinson Hyperlegible, Fraunces), zéro CDN tiers
- i18n FR/gcf typé (clé manquante = erreur de build), bascule Kréyòl
  persistée en localStorage, micro-textes créoles (« Ou pa manké ayen »)
- Composants : ToolCard, DifficultyBadge (forme+texte+couleur, jamais la
  couleur seule), CategoryNav (≤5 entrées, divulgation progressive),
  SearchBar (raccourci /), LanguageSwitcher, EndMarker
- content/ : 55 fiches migrées depuis src/ (script frontend/scripts/
  migrate-tools.mjs, idempotent), licences SPDX reprises de directory.json
- docs/ : DESIGN_SYSTEM.md et CONTENT_GUIDE.md

Budgets vérifiés : JS 41 Ko gzip, CSS 2,9 Ko gzip, svelte-check 0 erreur.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
sucupira
2026-07-10 12:51:17 -04:00
parent f4e09ca886
commit db5a997e50
99 changed files with 5356 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
# Guide de rédaction — fiches d'outils FR/créole
## Format d'une fiche (`content/outils/<slug>.md`)
```markdown
---
name: "Signal"
slug: "signal"
category: "messagerie" # slug d'une catégorie de content/categories.json
difficulty: "beginner" # beginner | intermediate | advanced
license: "AGPL-3.0" # identifiant SPDX exact (spdx.org/licenses)
url: "https://signal.org"
color: "#3a76f0" # couleur du monogramme (décorative)
monogram: "S"
tags: ["Remplace WhatsApp","🇺🇸 · open-source"]
lang: "fr"
---
## what
À quoi sert l'outil, en deux phrases maximum.
## why
Pourquoi il compte pour la souveraineté numérique.
## who
Pour qui, et à quel moment du parcours.
## install
<ol><li>Étapes concrètes, numérotées.</li></ol>
```
Les valeurs du frontmatter sont encodées en JSON (guillemets doubles).
Le corps accepte Markdown et HTML simple ; il est rendu au build, rien n'est
interprété côté client. **Le build échoue si une fiche est invalide** — c'est
le contrat de validation (ADR-001).
## Ton éditorial
- **Militant mais chaleureux, ancré Caraïbe.** Pas de langage corporate, pas
de peur gratuite : on explique le geste, on donne le pouvoir d'agir.
- Tutoiement. Phrases courtes. Le premier mot de chaque section porte le sens
(motif en F, doctrine §1.1).
- `what` dit le service rendu, `why` dit l'enjeu politique/technique, `who`
donne la porte d'entrée (« commence ici si… »), `install` est actionnable
sans autre lecture.
- Exemples et localisation ancrés territoire — jamais de Lorem ipsum
hexagonal (doctrine §4.2).
## Créole guadeloupéen (gcf)
- Les **micro-textes de l'interface** (boutons, filtres, états vides, marqueur
de fin) vivent dans `frontend/src/lib/i18n/gcf.json`. C'est la couche à
plus fort impact affectif pour le plus faible coût (doctrine §4.2) — elle
est traduite en premier.
- ⚠️ **Relecture par un locuteur natif requise** : les chaînes gcf actuelles
sont un premier jet à valider avant mise en production. La graphie de
référence à trancher (GEREC-F ou autre) doit être notée ici une fois choisie.
- La traduction intégrale des fiches est un chantier éditorial séparé :
le format prévu est un fichier jumeau `content/outils/gcf/<slug>.md` avec
`lang: "gcf"` (le chargeur l'ignorera tant que la locale de contenu n'est
pas activée).
- Termes fixés : « zouti » (outil), « Ou pa manké ayen » (fin de liste),
« Chwazi zouti ou » (héros), niveaux « Débitan / Entèmédia / Avansé ».
## Ajouter une catégorie
Ajouter une entrée à `content/categories.json` (`slug`, `title`, `order`,
`part`). La navigation n'affiche que 4 catégories avant la divulgation
progressive (Hick-Hyman, doctrine §1.3) : l'ordre `order` décide lesquelles.
## Vérifications avant merge
- [ ] `license` est un identifiant SPDX valide
- [ ] `difficulty` reflète l'expérience réelle d'installation (pas le prestige)
- [ ] Chaque section respecte sa question (what/why/who/install)
- [ ] `pnpm build` passe (validation du frontmatter incluse)
+72
View File
@@ -0,0 +1,72 @@
# Design system OKI — exitchatcontrol.org
Toutes les valeurs visuelles vivent dans
[`frontend/src/styles/tokens.css`](../frontend/src/styles/tokens.css).
Les composants Svelte consomment les tokens ; **jamais de valeur brute**
(couleur, taille) dans un composant (doctrine §5.2).
## Architecture CSS
Cascade explicite par `@layer` ([app.css](../frontend/src/app.css)) :
```
reset → tokens → base → layouts → components → utilities
```
- `reset.css` — reset moderne minimal (~40 lignes), inclut `prefers-reduced-motion`.
- `tokens.css` — custom properties : couleurs `oklch()`, typo fluide `clamp()`, espacements, interaction.
- `base.css` — HTML sémantique nu : typo, liens, focus visible, boutons.
- `layouts.css` — primitives Every Layout : `.stack`, `.cluster`, `.center`, `.card-grid` (container queries, pas de media queries de largeur d'écran).
- Le style propre à chaque composant vit dans son `<style>` Svelte (scopé à la compilation).
## Couleurs
En `oklch()` : la luminance perceptuelle rend les contrastes WCAG calculables
(méthode modus-vivendi, doctrine §4.3). `light-dark()` + `color-scheme` gèrent
le mode sombre sans duplication.
| Token | Rôle | Note contraste |
|---|---|---|
| `--oki-ink` / `--oki-surface` | texte / fond | ≥ 7:1 (AAA) dans les deux modes |
| `--oki-ink-2` | texte secondaire | ≥ 4.5:1 (AA) |
| `--oki-jaune` `--oki-vert` `--oki-rouge` `--oki-noir` | identité panafricaine | décoratif — jamais porteur d'information seul |
| `--accent` / `--accent-ink` | accent actif / accent texte | `--accent-ink` ≥ 4.5:1 sur `--oki-surface` |
| `--diff-*` / `--diff-*-ink` | difficulté (fond / texte) | les variantes `-ink` sont AA sur `--oki-surface` |
**Règle absolue** : la difficulté n'est jamais codée par la couleur seule —
`DifficultyBadge` = forme (●/◆/▲) + texte + couleur (doctrine §1.1, ~8 % de
déficience de vision des couleurs).
## Typographie
- Corps : **Atkinson Hyperlegible** 400 (SIL OFL, conçue pour la lisibilité).
- Display (titres, marque) : **Fraunces** 700 (SIL OFL).
- 2 fichiers WOFF2 auto-hébergés (`static/fonts/`), ~35 Ko au total,
`font-display: swap` — jamais de Google Fonts (doctrine §5.3).
- Échelle modulaire ratio 1.25, fluide par `clamp()` : `--text-0``--text-5`.
- `--measure: 65ch` sur `p, li` et `.prose` (doctrine §2.2 : 4575 caractères).
- Tout en `rem` : la taille utilisateur est respectée.
## Interaction
- `--tap-target: 48px` : tout élément interactif (boutons, liens de nav,
filtres, switcher) a une hauteur minimale de 48 px (Fitts, doctrine §1.3).
- `:focus-visible` global : anneau 3 px `--accent`, offset 2 px.
- Durées `--duration-1/2` + `--ease-out` ; annulées par `prefers-reduced-motion`.
## Composants
| Composant | Rôle | Principe doctrinal |
|---|---|---|
| `DifficultyBadge` | niveau (forme + texte + couleur) | §1.1 — jamais couleur seule |
| `ToolCard` | fiche condensée, vrai `<a>` couvrant | §4.3 — pas de div cliquable |
| `CategoryNav` | 4 catégories visibles + `<details>` | §1.3 Hick-Hyman, divulgation progressive, sans JS |
| `SearchBar` | recherche instantanée, raccourci `/` | §2.2 — le clavier est roi |
| `LanguageSwitcher` | FR / Kréyòl, persisté localStorage | §4.2 — bilinguisme |
| `EndMarker` | « Ou pa manké ayen » en fin de liste | §1.5, §3 — point d'arrêt explicite |
## Test des 50 ms (doctrine §1.1)
L'identité OKI est reconnaissable avant toute lecture : bandes panafricaines
vert/jaune/rouge dans la marque d'en-tête, soulignés et bordures jaune OKI,
titres Fraunces, créole visible dès le héros (« Chwazi zouti ou »).