forked from yvv/decision
- 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>
238 lines
7.6 KiB
Vue
238 lines
7.6 KiB
Vue
<script setup lang="ts">
|
|
// The three tunnel chips — Concernés / Réversible ? / Ça engage quoi ? —
|
|
// one unfolded at a time (mobile-first), plus the discreet urgency toggle,
|
|
// the never-blocking « Ce que ça engage » suggestion line and the
|
|
// « Aujourd'hui : … » status-quo line.
|
|
import type { Decision, Person, Reversibility, Weight } from '~/types/domain'
|
|
import {
|
|
BASELINE_PREFIX,
|
|
ENGAGES_LABEL,
|
|
REVERSIBILITY_LABELS,
|
|
URGENT_TOGGLE,
|
|
WEIGHT_LABELS,
|
|
} from '~/lexicon'
|
|
|
|
defineProps<{
|
|
stack: { person: Person; origin?: 'computed' | 'declared'; reason?: string }[]
|
|
engagesOpen: boolean
|
|
baselineSuggested: boolean
|
|
}>()
|
|
|
|
const scope = defineModel<Decision['scope']>('scope', { required: true })
|
|
const reversibility = defineModel<Reversibility>('reversibility', { required: true })
|
|
const weight = defineModel<Weight>('weight', { required: true })
|
|
const urgent = defineModel<boolean>('urgent', { required: true })
|
|
const resourceNote = defineModel<string>('resourceNote', { required: true })
|
|
const resourceAmount = defineModel<number | null>('resourceAmount', { required: true })
|
|
const resourceUnit = defineModel<string>('resourceUnit', { required: true })
|
|
const baselineNote = defineModel<string>('baselineNote', { required: true })
|
|
|
|
const openChip = ref<'scope' | 'rev' | 'weight' | null>(null)
|
|
const REV_OPTIONS = Object.keys(REVERSIBILITY_LABELS) as Reversibility[]
|
|
const WEIGHT_OPTIONS = Object.keys(WEIGHT_LABELS) as Weight[]
|
|
|
|
function toggle(chip: 'scope' | 'rev' | 'weight') {
|
|
openChip.value = openChip.value === chip ? null : chip
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<!-- ld-v2 -->
|
|
<div class="chips">
|
|
<div class="chips__row">
|
|
<button
|
|
class="chips__chip"
|
|
:class="{ 'chips__chip--open': openChip === 'scope' }"
|
|
type="button"
|
|
@click="toggle('scope')"
|
|
>
|
|
<span class="chips__name">Concernés</span>
|
|
<span class="chips__value">
|
|
{{ scope.selfOnly ? 'moi seul' : `${stack.length} personne${stack.length > 1 ? 's' : ''}` }}
|
|
</span>
|
|
</button>
|
|
<button
|
|
class="chips__chip"
|
|
:class="{ 'chips__chip--open': openChip === 'rev' }"
|
|
type="button"
|
|
@click="toggle('rev')"
|
|
>
|
|
<span class="chips__name">Réversible ?</span>
|
|
<span class="chips__value">{{ REVERSIBILITY_LABELS[reversibility] }}</span>
|
|
</button>
|
|
<button
|
|
class="chips__chip"
|
|
:class="{ 'chips__chip--open': openChip === 'weight' }"
|
|
type="button"
|
|
@click="toggle('weight')"
|
|
>
|
|
<span class="chips__name">Ça engage quoi ?</span>
|
|
<span class="chips__value">{{ WEIGHT_LABELS[weight] }}</span>
|
|
</button>
|
|
<label class="chips__urgent" :class="{ 'chips__urgent--on': urgent }">
|
|
<input v-model="urgent" type="checkbox">
|
|
<UIcon name="i-lucide-siren" />
|
|
<span>{{ URGENT_TOGGLE }}</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div v-if="openChip === 'scope'" class="ld-card chips__panel">
|
|
<CheminScope v-model:scope="scope" :stack="stack" />
|
|
</div>
|
|
<div v-else-if="openChip === 'rev'" class="ld-card chips__panel">
|
|
<div class="chips__options">
|
|
<button
|
|
v-for="opt in REV_OPTIONS"
|
|
:key="opt"
|
|
class="chips__option"
|
|
:class="{ 'chips__option--on': reversibility === opt }"
|
|
type="button"
|
|
@click="reversibility = opt"
|
|
>
|
|
{{ REVERSIBILITY_LABELS[opt] }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div v-else-if="openChip === 'weight'" class="ld-card chips__panel">
|
|
<div class="chips__options">
|
|
<button
|
|
v-for="opt in WEIGHT_OPTIONS"
|
|
:key="opt"
|
|
class="chips__option"
|
|
:class="{ 'chips__option--on': weight === opt }"
|
|
type="button"
|
|
@click="weight = opt"
|
|
>
|
|
{{ WEIGHT_LABELS[opt] }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- « Ce que ça engage » — suggestion dépliée, JAMAIS bloquante -->
|
|
<div v-if="engagesOpen" class="chips__engages">
|
|
<span class="chips__engages-label">{{ ENGAGES_LABEL }}</span>
|
|
<input
|
|
v-model="resourceNote"
|
|
class="chips__engages-note"
|
|
type="text"
|
|
placeholder="En une phrase — suggéré, jamais exigé ici"
|
|
>
|
|
<div class="chips__engages-amount">
|
|
<input
|
|
v-model.number="resourceAmount"
|
|
type="number"
|
|
min="0"
|
|
placeholder="Montant"
|
|
>
|
|
<select v-model="resourceUnit">
|
|
<option value="heures">heures</option>
|
|
<option value="€">€</option>
|
|
<option value="DU">DU</option>
|
|
<option value="jours">jours</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- « Aujourd'hui : … » — le statu quo, suggéré sur avis/collectif -->
|
|
<label v-if="baselineSuggested" class="chips__baseline">
|
|
<span>{{ BASELINE_PREFIX }}</span>
|
|
<input
|
|
v-model="baselineNote"
|
|
type="text"
|
|
placeholder="ce qui se passe si rien ne change"
|
|
>
|
|
</label>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.chips { display: flex; flex-direction: column; gap: 0.625rem; }
|
|
.chips__row { display: flex; flex-wrap: wrap; align-items: stretch; gap: 0.5rem; }
|
|
.chips__chip {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 0.125rem;
|
|
padding: 0.5rem 0.875rem;
|
|
border-radius: var(--r-icon);
|
|
background: var(--mood-surface);
|
|
box-shadow: var(--shadow-card);
|
|
cursor: pointer;
|
|
text-align: left;
|
|
min-height: 2.25rem;
|
|
transition: transform 0.1s ease;
|
|
}
|
|
.chips__chip:hover { transform: translateY(-1px); }
|
|
.chips__chip--open { box-shadow: 0 0 0 2px var(--mood-accent), var(--shadow-card); }
|
|
.chips__name {
|
|
font-size: 0.6875rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: var(--mood-text-muted);
|
|
}
|
|
.chips__value { font-size: 0.875rem; font-weight: 700; color: var(--mood-text); }
|
|
.chips__urgent {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
margin-left: auto;
|
|
padding: 0.4rem 0.875rem;
|
|
border-radius: var(--r-pill);
|
|
font-size: 0.8125rem;
|
|
font-weight: 600;
|
|
color: var(--mood-text-muted);
|
|
cursor: pointer;
|
|
align-self: center;
|
|
}
|
|
.chips__urgent input { position: absolute; opacity: 0; width: 1px; height: 1px; }
|
|
.chips__urgent--on {
|
|
color: var(--route-urgent);
|
|
background: color-mix(in srgb, var(--route-urgent) 12%, transparent);
|
|
}
|
|
.chips__panel { padding: 1rem; }
|
|
.chips__options { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
|
.chips__option {
|
|
padding: 0.5rem 1rem;
|
|
border-radius: var(--r-pill);
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
background: var(--mood-input-bg);
|
|
color: var(--mood-text-muted);
|
|
cursor: pointer;
|
|
min-height: 2.25rem;
|
|
}
|
|
.chips__option--on {
|
|
background: var(--mood-accent-soft);
|
|
color: var(--mood-accent);
|
|
box-shadow: 0 0 0 1.5px var(--mood-accent);
|
|
}
|
|
.chips__engages {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
padding: 0.75rem;
|
|
border-radius: var(--r-input);
|
|
background: color-mix(in srgb, var(--mood-accent) 6%, transparent);
|
|
}
|
|
.chips__engages-label { font-size: 0.8125rem; font-weight: 700; color: var(--mood-accent); }
|
|
.chips__engages-note { width: 100%; padding: 0.5rem 0.75rem; font-size: 0.9375rem; }
|
|
.chips__engages-amount { display: flex; gap: 0.5rem; }
|
|
.chips__engages-amount input { width: 7rem; padding: 0.5rem 0.75rem; font-size: 0.9375rem; }
|
|
.chips__engages-amount select { padding: 0.5rem 0.75rem; font-size: 0.9375rem; }
|
|
.chips__baseline {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
font-size: 0.9375rem;
|
|
font-weight: 700;
|
|
}
|
|
.chips__baseline input {
|
|
flex: 1;
|
|
min-width: 0;
|
|
padding: 0.5rem 0.75rem;
|
|
font-size: 0.9375rem;
|
|
font-weight: 500;
|
|
}
|
|
</style>
|