v2 : les 14 écrans — le tour complet de la démocratie d'exercice
- Aujourd'hui (Fil 13 sections + capture sticky) + Le chemin (tunnel 2 gestes, Q0 inline, 3 chips, dérogation asymétrique, alternatives réglage/consignation) - Registre + fiche décision (timeline, périmètre premier/second lieu auditable, affluence non-ignorable, S'instruire condensé, éléments + cartographie de clôture, épreuve du réel, Remettre en question, PV A4, gravure) - Salle de vote 5 modalités (consentement, nuancé+histogramme, binaire hérité avec jauge inertielle, Réglage collectif complet — faisceau, médiane basse, Pour moi, Explorer, cristallisation-geste —, élection à départage humain) - Textes (Pacte en clair, document vivant, diff, vue projetée, Atelier des formules porté du v1 sur le moteur unique) + Mandats (faits comptés, feux de la rampe, wizard 3 étapes) + Observatoire (consigner→observer→protocoliser) - Onboarding 7 gabarits + Données locales (export/import, attributs, atelier) - voting→framing gardé (Reformuler d'un réglage figé non cristallisé) - Pages v1 supprimées (login, documents, mandates, protocols, sanctuary, tools, decisions/new) — 342 tests verts, build zéro erreur Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
<script setup lang="ts">
|
||||
// <!-- ld-v2 --> Mini-démo interactive du Réglage collectif : cinq curseurs-votes
|
||||
// jouets, la médiane basse recalculée en direct par ~/engine (medianByElement),
|
||||
// et la règle de cristallisation — l'agrégat éclaire, le geste cristallise.
|
||||
import { medianByElement } from '~/engine'
|
||||
import { CRYSTALLIZE_ACTION, MEDIAN_EXPLANATION } from '~/lexicon'
|
||||
|
||||
const TOY_VOTERS = ['Ana', 'Brice', 'Chloé', 'Dado', 'Elsa'] as const
|
||||
|
||||
const votes = ref<number[]>([20, 35, 40, 65, 80])
|
||||
|
||||
const median = computed(() => {
|
||||
const result = medianByElement(votes.value.map(v => [v]))
|
||||
return result[0] ?? 0
|
||||
})
|
||||
|
||||
/** La médiane est toujours une valeur réellement votée — on la nomme. */
|
||||
const medianVoters = computed(() =>
|
||||
TOY_VOTERS.filter((_, i) => votes.value[i] === median.value))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- ld-v2 -->
|
||||
<div class="median-demo">
|
||||
<div class="median-demo__sliders">
|
||||
<label v-for="(name, i) in TOY_VOTERS" :key="name" class="median-demo__vote">
|
||||
<span class="median-demo__voter">{{ name }}</span>
|
||||
<input
|
||||
v-model.number="votes[i]"
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
step="5"
|
||||
:aria-label="`Curseur-vote de ${name}`"
|
||||
>
|
||||
<span class="median-demo__value">{{ votes[i] }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Le faisceau : chaque point est un vote, le trait épais est la médiane -->
|
||||
<div class="median-demo__strip" aria-hidden="true">
|
||||
<span
|
||||
v-for="(vote, i) in votes"
|
||||
:key="i"
|
||||
class="median-demo__dot"
|
||||
:style="{ left: `${vote}%` }"
|
||||
/>
|
||||
<span class="median-demo__median-mark" :style="{ left: `${median}%` }" />
|
||||
</div>
|
||||
|
||||
<p class="median-demo__readout">
|
||||
Médiane basse : <strong>{{ median }}</strong>
|
||||
<span v-if="medianVoters.length" class="median-demo__who">
|
||||
— c'est la position de {{ medianVoters.join(' et ') }}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p class="median-demo__explain">{{ MEDIAN_EXPLANATION }}</p>
|
||||
|
||||
<div class="median-demo__rule">
|
||||
<UIcon name="i-lucide-stamp" class="median-demo__rule-icon" />
|
||||
<div>
|
||||
<p class="median-demo__rule-title">L'agrégat éclaire, le geste cristallise.</p>
|
||||
<p class="median-demo__rule-body">
|
||||
À la clôture, les votes sont figés et la médiane s'affiche — mais rien n'est
|
||||
adopté tant qu'un·e garant·e n'a pas fait le geste « {{ CRYSTALLIZE_ACTION }} »,
|
||||
daté et signé. Jamais d'adoption automatique.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.median-demo { display: flex; flex-direction: column; gap: 0.9rem; }
|
||||
|
||||
.median-demo__sliders { display: flex; flex-direction: column; gap: 0.45rem; }
|
||||
.median-demo__vote {
|
||||
display: grid;
|
||||
grid-template-columns: 3.4rem 1fr 2.4rem;
|
||||
align-items: center;
|
||||
gap: 0.6rem;
|
||||
}
|
||||
.median-demo__voter { font-size: 0.8125rem; font-weight: 700; color: var(--mood-text-muted); }
|
||||
.median-demo__vote input[type='range'] {
|
||||
width: 100%;
|
||||
accent-color: var(--mood-tertiary);
|
||||
background: transparent;
|
||||
min-height: 1.3rem;
|
||||
}
|
||||
.median-demo__value {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
text-align: right;
|
||||
color: var(--mood-text);
|
||||
}
|
||||
|
||||
.median-demo__strip {
|
||||
position: relative;
|
||||
height: 2rem;
|
||||
margin: 0 0.3rem;
|
||||
border-radius: var(--r-input);
|
||||
background: color-mix(in srgb, var(--mood-text) 5%, transparent);
|
||||
}
|
||||
.median-demo__dot {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background: var(--mood-tertiary);
|
||||
opacity: 0.55;
|
||||
transition: left 0.15s ease;
|
||||
}
|
||||
.median-demo__median-mark {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
bottom: 3px;
|
||||
transform: translateX(-50%);
|
||||
width: 4px;
|
||||
border-radius: 2px;
|
||||
background: var(--mood-accent);
|
||||
transition: left 0.15s ease;
|
||||
}
|
||||
|
||||
.median-demo__readout { font-size: 0.9375rem; color: var(--mood-text); }
|
||||
.median-demo__readout strong {
|
||||
color: var(--mood-accent);
|
||||
font-size: 1.1rem;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.median-demo__who { font-size: 0.8125rem; color: var(--mood-text-muted); }
|
||||
|
||||
.median-demo__explain {
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.6;
|
||||
color: var(--mood-text-muted);
|
||||
}
|
||||
|
||||
.median-demo__rule {
|
||||
display: flex;
|
||||
gap: 0.7rem;
|
||||
align-items: flex-start;
|
||||
padding: 0.8rem 0.95rem;
|
||||
border-radius: var(--r-input);
|
||||
background: var(--mood-accent-soft);
|
||||
}
|
||||
.median-demo__rule-icon {
|
||||
font-size: 1.2rem;
|
||||
color: var(--mood-accent);
|
||||
margin-top: 2px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.median-demo__rule-title { font-size: 0.875rem; font-weight: 800; color: var(--mood-text); }
|
||||
.median-demo__rule-body {
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.55;
|
||||
color: var(--mood-text-muted);
|
||||
margin-top: 2px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user