v3 : les versions d'un article tiennent une seule ligne (L8)

- « Propositions en cours » : une ligne par article. Un article à plusieurs versions montre
  leur nombre et la meilleure en tête (niveau d'eau, pour / contre, « en tête » quand elle
  devance vraiment) ; la ligne se déplie (bouton à aria-expanded, clavier) sur ses versions,
  chacune avec son étiquette (variante, auteur), son niveau, ses marques, et un extrait qui
  part de là où les versions divergent ; un clic ouvre son vote comme avant.
- Règle pure dans versions.ts (vitest) : ordre du document, meilleure d'abord (niveau d'eau,
  puis pour, puis contre ; une version bloquée jamais en tête), un article reste dans un
  filtre dès qu'une de ses versions passe.
- e2e : C3 compte 30 lignes, C14 déplie « Connaissance suffisante » au clavier ; C11 passe
  par un article à une seule version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-10-30 10:42:27 +01:00
co-authored by Claude Opus 5.5
parent a5b92faa96
commit edc88111e0
10 changed files with 397 additions and 40 deletions
@@ -10,6 +10,7 @@
import { DocState, shown, type PanelState, type Tab, type View } from '$lib/doc.svelte';
import { i18n, LANGS, t } from '$lib/i18n/index.svelte';
import type { Lang, Proposal, Unit } from '$lib/types';
import { articles, type Filter } from '$lib/versions';
const doc = new DocState();
const group = $derived(page.params.group ?? '');
@@ -42,17 +43,14 @@
void goto(`${page.url.pathname}${search ? `?${search}` : ''}`, { replaceState: !!panel && !!next, noScroll: true, keepFocus: true });
}
let filter = $state<'all' | 'wellrated' | 'mine'>('all');
let filter = $state<Filter>('all');
const view = $derived(doc.view);
const source = $derived<Lang>(view?.doc.sourceLang ?? 'fr');
const lang = $derived<Lang>(doc.original ? source : i18n.lang);
const title = $derived(view ? (view.doc.title[lang] ?? view.doc.title.fr ?? '') : '');
const summary = $derived(view ? (view.doc.summary[lang] ?? view.doc.summary.fr ?? '') : '');
const deep = $derived(
doc.open.filter(({ proposal: p }) =>
filter === 'wellrated' ? p.evaluation?.wellRated : filter === 'mine' ? p.mine : true,
),
);
// One line per article; an article stays when one of its versions passes the filter.
const deep = $derived(articles(doc.open, filter));
const rivalsOf = (u: Unit) => u.proposals.filter((p) => p.status === 'open' && p.kind === 'text').length;
const VIEWS: View[] = ['inforce', 'wellrated', 'all'];
@@ -153,7 +151,7 @@
{/each}
</div>
</div>
<DeepList items={deep} selected={panel?.proposalId ?? null} onopen={onProposal} />
<DeepList articles={deep} selected={panel?.proposalId ?? null} onopen={onProposal} />
<button class="btn new" type="button" onclick={() => openPanel({ unitId: null, proposalId: null, tab: 'propose' })}><Icon name="plus" size={16} />{t('deep.new')}</button>
</section>
</div>