v3 : interface Svelte — accueil, groupes, lecteur du texte en vigueur, panneau contextuel, éditeur à assistant, trustinWallet

- Accueil sobre, menu complet à gauche (Décisions, Docs de référence, Mandats,
  Protocoles), intro demandée, quatre sections, connexion Ğ1.
- Lecteur : texte en vigueur en Literata, actions contextuelles par article
  (le vote, propositions, proposer), propositions en cours sous la « surface »
  avec leur niveau d'eau, aperçus « si les bien cotées passent » / « si tout
  passe », langue du texte fr/en/es (traductions éditoriales).
- Panneau : vote pour/contre, seuil et formule (MathML), inertie et son
  changement (voté en inertie +), coquille sans vote, traduction, signalement
  de contradiction, historique des corrections.
- trustinWallet (/acces) : groupes et membres, invitations à usage unique,
  administrateurs, retours d'usage.
- Contrôles : vitest (markdown, catalogues, anti-lexique), Playwright C1–C10 + M1.
- Sections du seed portées jusqu'à l'écran.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-10-21 02:58:34 +02:00
co-authored by Claude Opus 5.5
parent 67ddee28b2
commit 7a022dd35e
66 changed files with 7771 additions and 15 deletions
+47
View File
@@ -0,0 +1,47 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { onMount } from 'svelte';
import { api } from '$lib/api';
import { t } from '$lib/i18n/index.svelte';
import { session } from '$lib/session.svelte';
import type { Me } from '$lib/types';
let state = $state<'working' | 'invalid' | 'missing'>('working');
onMount(async () => {
// The token travels in the fragment: it never reaches a server log.
const token = location.hash.slice(1).trim();
history.replaceState(null, '', '/invitation');
if (!/^[0-9a-f]{64}$/.test(token)) {
state = 'missing';
return;
}
try {
const r = await api.post<{ me: Me }>('/auth/invitation', { token });
session.me = r.me;
await goto('/groupes', { replaceState: true });
} catch {
state = 'invalid';
}
});
</script>
<div class="page">
<h1>{t('invite.title')}</h1>
<p class="muted" role="status">{t(`invite.${state}`)}</p>
</div>
<style>
.page {
max-width: 34rem;
margin: 0 auto;
padding: clamp(2.5rem, 9vh, 6rem) 1.4rem;
display: grid;
gap: 1rem;
}
h1 {
font-family: var(--font-text);
font-weight: 500;
font-size: 2.2rem;
}
</style>