forked from yvv/decision
Lot U3 : l'interface de l'Acte d'engagement (Yvv, 03/11) — avant le texte, hors vote, « Info ouverture doc de réf. » (OpeningInfo, lib/opening.ts) : le paragraphe d'Yvv mot pour mot à la place de doc.empty.seeds (sa première phrase tant qu'aucun article n'est en vigueur, puis « entrent en vigueur » où « y » n'avait plus rien à reprendre), le cran d'ouverture des Propositions d'amorce, du titre, de l'ordre de chaque section et des autres articles (avant tout changement voté) et le quorum de chaque cran, lus dans l'API ; une séparation (un filet de la couleur de la clé de voûte, jamais une bordure) ; plus les titres « Introduction » et « Engagements fondamentaux » dans le texte. Les informations de F1, F1.1, F1.2, N1, N1.1 et O1 là où elles servent : vote.permanent, vote.rival, vote.others.rule, formula.Tprime, formula.round, formula.B.wot, formula.G, settings.share.note, settings.usual.quorum, settings.gradient, order.edit.effect ; les termes définis de T3c (« à la participation habituelle », « quorum de l'article », « part exigée », « repose sur moins de N propositions votées depuis un an »), plus de « comme d'habitude ». « Proposition d'amorce » (Starter proposal, Propuesta de arranque). Le mot d'Yvv pour qui n'est pas invité, à l'accueil sans session (à la place du bouton Ğ1 tant que la connexion Ğ1 n'est pas active) et sur « Se connecter » (signin.g1.pending sans redite). Réordonner : la ligne sous le pointeur lue dans la mise en page (offsetTop), pas là où animate:flip la montre — une poignée tirée sur plusieurs lignes ne revient plus en arrière ; le pointeur capturé par la liste. API : seedFeatured sur chaque version (seul changement sous crates/). C1, C3, C20, C27, C35, C38 suivent les mots
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -111,11 +111,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Dragging by the handle: the article takes the place of the row under the pointer.
|
||||
// Dragging by the handle: the article takes the place of the row under the pointer. The pointer
|
||||
// is captured by the list, which stays put, rather than by the handle of a row the reorder moves
|
||||
// (a guard: what lot U3 found is the measure of the rows, in `drag`).
|
||||
function grab(e: PointerEvent, id: string) {
|
||||
if (busy || e.button !== 0) return;
|
||||
e.preventDefault();
|
||||
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
|
||||
root?.setPointerCapture(e.pointerId);
|
||||
dragging = id;
|
||||
chosen = null;
|
||||
error = '';
|
||||
@@ -124,9 +126,12 @@
|
||||
function drag(e: PointerEvent) {
|
||||
const id = dragging;
|
||||
if (!id || !root) return;
|
||||
// The rows where the layout puts them, not where their animation shows them (`animate:flip`
|
||||
// moves them by a transform): a row sliding under the pointer would send the article back.
|
||||
const y = e.clientY - root.getBoundingClientRect().top;
|
||||
for (const row of root.querySelectorAll<HTMLElement>('li[data-id]')) {
|
||||
const box = row.getBoundingClientRect();
|
||||
if (e.clientY < box.top || e.clientY >= box.bottom) continue;
|
||||
const top = row.offsetTop - root.offsetTop;
|
||||
if (y < top || y >= top + row.offsetHeight) continue;
|
||||
const target = row.dataset.id;
|
||||
if (target && target !== id) list = place(list, id, target);
|
||||
return;
|
||||
@@ -164,11 +169,20 @@
|
||||
|
||||
<div class="reorder">
|
||||
<p class="faint small" id="order-help-{unit.id}">{t('order.edit.help')}</p>
|
||||
<ol class="list" aria-label={t('order.edit.label')} aria-describedby="order-help-{unit.id}" bind:this={root}>
|
||||
<ol
|
||||
class="list"
|
||||
aria-label={t('order.edit.label')}
|
||||
aria-describedby="order-help-{unit.id}"
|
||||
bind:this={root}
|
||||
onpointermove={drag}
|
||||
onpointerup={drop}
|
||||
onpointercancel={drop}
|
||||
onlostpointercapture={drop}
|
||||
>
|
||||
{#each list as id, i (id)}
|
||||
{@const name = nameOf(id)}
|
||||
<li data-id={id} class:chosen={chosen === id} class:moved={changed.has(id)} class:dragging={dragging === id} animate:flip={{ duration: reduce ? 0 : 140 }}>
|
||||
<span class="grip" aria-hidden="true" onpointerdown={(e) => grab(e, id)} onpointermove={drag} onpointerup={drop} onpointercancel={drop}>
|
||||
<span class="grip" aria-hidden="true" onpointerdown={(e) => grab(e, id)}>
|
||||
<Icon name="grip" size={18} />
|
||||
</span>
|
||||
<button type="button" class="item" data-id={id} aria-pressed={chosen === id} disabled={busy} onclick={() => pick(id)} onkeydown={(e) => key(e, id)}>
|
||||
@@ -186,7 +200,7 @@
|
||||
{/each}
|
||||
</ol>
|
||||
<p class="visually-hidden" aria-live="polite">{said}</p>
|
||||
<p class="faint small">{t('order.edit.note', { level: inertiaLevel(unit.inertia) })} {t('module.order.rule')}</p>
|
||||
<p class="faint small">{t('order.edit.note', { level: inertiaLevel(unit.inertia) })} {t('order.edit.effect')} {t('module.order.rule')}</p>
|
||||
{#if existing && !unchanged}<p class="note" role="status">{t('order.edit.exists')}</p>{/if}
|
||||
{#if error}<p class="warn" role="alert">{error}</p>{/if}
|
||||
<div class="actions">
|
||||
|
||||
Reference in New Issue
Block a user