v3 : modules d'ordre et de titre — l'interface, restes mineurs (L11, C25–C27)

Chaque section du lecteur finit par l'ordre de ses articles (inertie 2) : ses
articles numérotés, son vote déplié, « Proposer un autre ordre » — une liste où
l'on clique un article puis sa place, ses flèches, ou le clavier. Le titre du
document (inertie 4) se vote et se propose sous le titre, « traduction à
revoir » quand il a changé. Les deux sont dans la liste des propositions, le
panier et la chaîne Ğ1 ; un nouvel article se propose dans une section, à sa fin.
La liste du groupe compte les propositions ouvertes des modules.

Restes mineurs : la participation ramenée se dit en deux temps (la mesure, puis
ce que le groupe demande), les lignes « habituelle » des réglages resserrées, le
sélecteur d'inertie se parcourt aux flèches (le cran actuel atteignable, jamais
choisi), la marque « seed a minima » porte le vrai nombre de votes.

Contrôles : C25 (ordre, dont la chaîne et le téléphone), C26 (titre), C27
(participation ramenée) ; C3, C17 (41 modules), C20 mis à jour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-10-31 05:35:02 +01:00
co-authored by Claude Opus 5.5
parent 3831ddb1bf
commit 785580c78f
31 changed files with 1480 additions and 136 deletions
+14 -3
View File
@@ -6,12 +6,14 @@
import { t } from '$lib/i18n/index.svelte';
import { relationOf, titleOf } from '$lib/labels';
import type { BasketState } from '$lib/picks.svelte';
import type { Lang } from '$lib/types';
import type { Lang, Proposal } from '$lib/types';
import type { Line } from '$lib/vote';
import BallotPanel from './BallotPanel.svelte';
import FormulaSettings from './FormulaSettings.svelte';
import Icon from './Icon.svelte';
import OrderEditor from './OrderEditor.svelte';
import ProposeView from './ProposeView.svelte';
import TitlePropose from './TitlePropose.svelte';
import VersionDetails from './VersionDetails.svelte';
import WaterLevel from './WaterLevel.svelte';
@@ -43,6 +45,11 @@
const versions = $derived(
unit ? [unit.inForce, ...unit.proposals.filter((p) => p.status === 'open')].filter((p) => p !== null) : [],
);
// A module (ADR 0009) is proposed with its own gesture: another order, another title.
const proposeLabel = $derived(unit?.kind === 'order' ? t('order.propose') : unit?.kind === 'title' ? t('title.propose') : t('doc.action.propose'));
const nameOf = (id: string) => doc.articleTitle(id, lang, doc.view?.doc.sourceLang ?? 'fr');
/** A version in the list: an order reads as its articles, in its order. */
const nameOfVersion = (v: Proposal) => (v.kind === 'order' && v.order ? v.order.ids.map(nameOf).join(' · ') : titleOf(v, unit));
const voteId = $derived(panel.proposalId ?? unit?.inForce?.id ?? unit?.proposals.find((p) => p.status === 'open')?.id ?? null);
const tabs = $derived(
(
@@ -102,14 +109,18 @@
<WaterLevel tally={v.tally} evaluation={v.evaluation} blocked={v.blocked} />
<span class="text">
<span class="eyebrow">{v.status === 'in_force' ? t('panel.inforce') : t('panel.proposal')}</span>
<span class="title">{titleOf(v, unit)}</span>
<span class="title">{nameOfVersion(v)}</span>
<span class="faint small">{v.status === 'in_force' ? (v.seedMinimal ? t('doc.seed') : '') : relationOf(v, unit)} · {t('tally.short', { for: v.tally.for, against: v.tally.against })}{#if v.myVote && !v.myVoteStale} · {t('basket.mine', { choice: t(`vote.choice.${v.myVote}`) })}{/if}</span>
</span>
</button>
</li>
{/each}
</ul>
<button class="btn small" type="button" onclick={() => onchange({ ...panel, tab: 'propose', prefill: null, draftId: null })}><Icon name="plus" size={16} />{t('doc.action.propose')}</button>
<button class="btn small" type="button" onclick={() => onchange({ ...panel, tab: 'propose', prefill: null, draftId: null })}><Icon name="plus" size={16} />{proposeLabel}</button>
{:else if panel.tab === 'propose' && unit?.kind === 'order'}
<OrderEditor {doc} {unit} {nameOf} ondone={(id) => onvote(id, true)} oncancel={onclose} />
{:else if panel.tab === 'propose' && unit?.kind === 'title'}
<TitlePropose {doc} {unit} ondone={(id) => onvote(id, true)} />
{:else if panel.tab === 'propose'}
<ProposeView
{doc}