forked from yvv/decision
v3 : le vote déplié sous l'article, le panier, la signature par le portefeuille Ğ1
- Le vote se déplie sous l'article, façon accordéon, l'URL pour état (?vote=) :
niveau d'eau, totaux, seuil et voix manquantes, ton vote et où il en est
(enregistré, inscrit sur la chaîne, en attente, à reconfirmer, non compté),
inertie et formule. Le reste d'une version (coquilles, traductions,
signalements, historique) passe dans l'onglet « Détails » du panneau.
- Le panier : article par article, « tout pour / tout contre » par section ou
pour tout le document, jamais pour un article à plusieurs versions ; un seul
geste (une écriture, ou une transaction).
- La signature : le portefeuille de la page (injectedWeb3), polkadot-api chargé
au moment de signer ; sans portefeuille, Ğecko par lien et QR ; la page
attend la confirmation. Un bulletin que le portefeuille n'a pas signé est
lâché aussitôt (DELETE /api/ballots/{id}).
- Pastilles d'ambiance : flèches dans le groupe, anneau de focus pointillé à
la couleur d'accent de la page (3:1 au moins), distinct du choix.
- e2e : chaîne simulée (indexeur et nœud), faux portefeuille ; C21–C24, et
C4, C5, C6, C11, C17, C19, C20, M1 mis à jour.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<script lang="ts">
|
||||
// One choice of the basket: for, against, or withdraw one's vote (when there is
|
||||
// one). Pressing the chosen one again takes the version out of the basket.
|
||||
import { t } from '$lib/i18n/index.svelte';
|
||||
import type { Choice } from '$lib/types';
|
||||
|
||||
let {
|
||||
value,
|
||||
voted,
|
||||
label,
|
||||
disabled = false,
|
||||
onpick,
|
||||
}: { value: Choice | undefined; voted: boolean; label: string; disabled?: boolean; onpick: (c: Choice) => void } = $props();
|
||||
</script>
|
||||
|
||||
<span class="picker" role="group" aria-label={label}>
|
||||
<button type="button" class="for" aria-pressed={value === 'for'} {disabled} onclick={() => onpick('for')}>{t('vote.for')}</button>
|
||||
<button type="button" class="against" aria-pressed={value === 'against'} {disabled} onclick={() => onpick('against')}>{t('vote.against')}</button>
|
||||
{#if voted || value === 'none'}
|
||||
<button type="button" class="none" aria-pressed={value === 'none'} {disabled} onclick={() => onpick('none')}>{t('basket.pick.retract')}</button>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<style>
|
||||
.picker {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
background: var(--surface-2);
|
||||
padding: 3px;
|
||||
border-radius: var(--r-pill);
|
||||
}
|
||||
button {
|
||||
border: 0;
|
||||
background: transparent;
|
||||
border-radius: var(--r-pill);
|
||||
padding: 0.3rem 0.75rem;
|
||||
min-height: 2.25rem;
|
||||
min-width: 2.75rem;
|
||||
font-weight: 750;
|
||||
font-size: 0.84rem;
|
||||
color: var(--ink-soft);
|
||||
transition: background-color 0.15s var(--ease), color 0.15s var(--ease);
|
||||
}
|
||||
button:hover:not(:disabled) {
|
||||
color: var(--ink);
|
||||
background: var(--surface);
|
||||
}
|
||||
.for[aria-pressed='true'],
|
||||
.for[aria-pressed='true']:hover {
|
||||
background: var(--moss);
|
||||
color: var(--on-water);
|
||||
}
|
||||
.against[aria-pressed='true'],
|
||||
.against[aria-pressed='true']:hover {
|
||||
background: var(--ochre);
|
||||
color: var(--on-water);
|
||||
}
|
||||
.none[aria-pressed='true'],
|
||||
.none[aria-pressed='true']:hover {
|
||||
background: var(--ink-soft);
|
||||
color: var(--surface);
|
||||
}
|
||||
button:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
button {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user