Boîtes à outils enrichies : ContextMapper, SocioElection, WorkflowMilestones

- ContextMapper : 4 questions contexte → méthode de décision optimale
  (advice process Laloux, vote inertiel WoT, consentement sociocratique, Smith…)
- SocioElection : guide élection sociocratique 6 étapes + advice process + clarté de rôle
- WorkflowMilestones : 11 jalons de protocole (7 essentiels), durées recommandées, principes Ostrom
- WorkspaceSelector : sélecteur de collectif multi-site dans le header
- SectionLayout : toolbox en USlideover droit sur mobile, sidebar sticky desktop
- Décisions : ContextMapper intégré + guide consentement
- Mandats : SocioElection intégré + cycle de mandat
- Documents : guide inertie 4 niveaux + structure + IPFS
- Protocoles : WorkflowMilestones + protocole élection sociocratique ajouté
- Renommage projet Glibredecision → libreDecision (dossier + sources)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-03-17 00:13:08 +01:00
parent 316d205593
commit 290548703d
29 changed files with 4174 additions and 168 deletions

View File

@@ -9,6 +9,31 @@ const decisions = useDecisionsStore()
const protocols = useProtocolsStore()
const auth = useAuthStore()
// Toolbox state
const showConsentModal = ref(false)
const selectedMethod = ref<string | null>(null)
const consentSteps = [
'Présenter la proposition clairement (2 min)',
'Tour de clarification — questions de compréhension uniquement',
'Tour de réaction — chacun réagit brièvement',
'Porteur amende si nécessaire',
'Tour d\'objections — silence = consentement',
'Lever les objections valides par amendement',
'Adopter ou reporter',
]
function handleMethodSelect(method: string) {
selectedMethod.value = method
if (method.toLowerCase().includes('consentement')) {
showConsentModal.value = true
}
else if (method.toLowerCase().includes('avis')) {
// Navigate to advice process guide in mandates toolbox
navigateTo('/mandates')
}
}
const activeStatus = ref<string | null>(null)
const searchQuery = ref('')
const sortBy = ref<'date' | 'title' | 'status'>('date')
@@ -212,29 +237,78 @@ function formatDate(dateStr: string): string {
<!-- Toolbox sidebar -->
<template #toolbox>
<!-- Context mapper -->
<div class="toolbox-block">
<div class="toolbox-block__head">
<UIcon name="i-lucide-compass" />
<span>Quelle méthode ?</span>
</div>
<ContextMapper @use="handleMethodSelect" />
</div>
<!-- Vote inertiel WoT -->
<ToolboxVignette
title="Vote majoritaire WoT"
:bullets="['Seuil adaptatif à la participation', 'Formule g1vote inertielle']"
title="Vote inertiel WoT"
:bullets="[
'Seuil adaptatif à la participation',
'Faible participation → quasi-unanimité',
'Formule g1vote — tracé on-chain',
]"
:actions="[
{ label: 'Simuler', icon: 'i-lucide-calculator', to: '/protocols/formulas', primary: true },
{ label: 'Protocoles', icon: 'i-lucide-settings', to: '/protocols' },
]"
/>
<!-- Consentement sociocratique -->
<ToolboxVignette
title="Vote nuancé"
:bullets="['6 niveaux de préférence', 'Seuil de satisfaction 80%']"
title="Consentement sociocratique"
:bullets="[
'Aucune objection grave = adopté',
'Rapide pour petits groupes',
'Distingue préférence et objection',
]"
:actions="[
{ label: 'Voir', icon: 'i-lucide-bar-chart-3', emit: 'nuance' },
{ label: 'Guide', icon: 'i-lucide-book-open', emit: 'consent', primary: true },
]"
/>
<!-- Advice process -->
<ToolboxVignette
title="Mandature"
:bullets="['Élection en binôme', 'Transparence et révocation']"
title="Processus d'avis (Laloux)"
:bullets="[
'Décisions urgentes : < 2h',
'Consultant experts + impactés',
'Responsabilise le porteur',
]"
:actions="[
{ label: 'Mandats', icon: 'i-lucide-user-check', to: '/mandates', primary: true },
{ label: 'Guide', icon: 'i-lucide-message-circle', emit: 'advice', primary: true },
]"
/>
</template>
</SectionLayout>
<!-- Modal consent guide -->
<UModal v-model:open="showConsentModal">
<template #content>
<div class="decision-modal">
<h3 class="decision-modal__title">Consentement sociocratique</h3>
<p class="decision-modal__text">
Une décision est adoptée par consentement quand aucun membre ne soulève d'objection grave.
Une objection grave est une raison pour laquelle la proposition nuit à la mission commune
pas une simple préférence.
</p>
<div class="decision-modal__steps">
<div v-for="(step, i) in consentSteps" :key="i" class="decision-modal__step">
<div class="decision-modal__step-num">{{ i + 1 }}</div>
<div class="decision-modal__step-text">{{ step }}</div>
</div>
</div>
<p class="decision-modal__ref">Référence : "La Sociocracie" Gerard Endenburg, Brian Robertson (Holacracy)</p>
<button class="decision-modal__close" @click="showConsentModal = false">Fermer</button>
</div>
</template>
</UModal>
</template>
<style scoped>
@@ -458,17 +532,105 @@ function formatDate(dateStr: string): string {
transform: translateY(0);
}
.toolbox-section-title {
font-size: 0.8125rem;
font-weight: 700;
color: var(--mood-text-muted);
text-transform: uppercase;
letter-spacing: 0.04em;
margin-bottom: 0.25rem;
.toolbox-block {
background: var(--mood-accent-soft);
border-radius: 14px;
padding: 0.875rem;
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.toolbox-empty-text {
.toolbox-block__head {
display: flex;
align-items: center;
gap: 0.375rem;
font-size: 0.8125rem;
color: var(--mood-text-muted);
font-weight: 800;
color: var(--mood-accent);
text-transform: uppercase;
letter-spacing: 0.04em;
}
/* Decision modal */
.decision-modal {
padding: 1.25rem;
display: flex;
flex-direction: column;
gap: 1rem;
}
@media (min-width: 640px) {
.decision-modal { padding: 2rem; gap: 1.25rem; }
}
.decision-modal__title {
font-size: 1.125rem;
font-weight: 800;
color: var(--mood-text);
margin: 0;
}
.decision-modal__text {
font-size: 0.875rem;
color: var(--mood-text-muted);
line-height: 1.6;
margin: 0;
}
.decision-modal__steps {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.decision-modal__step {
display: flex;
align-items: flex-start;
gap: 0.75rem;
}
.decision-modal__step-num {
width: 1.375rem;
height: 1.375rem;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background: var(--mood-accent);
color: var(--mood-accent-text);
font-size: 0.6875rem;
font-weight: 800;
}
.decision-modal__step-text {
font-size: 0.875rem;
color: var(--mood-text);
padding-top: 0.125rem;
line-height: 1.5;
}
.decision-modal__ref {
font-size: 0.75rem;
color: var(--mood-text-muted);
font-style: italic;
margin: 0;
}
.decision-modal__close {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.625rem 1.25rem;
font-size: 0.875rem;
font-weight: 700;
color: var(--mood-accent-text);
background: var(--mood-accent);
border-radius: 20px;
cursor: pointer;
align-self: flex-end;
transition: transform 0.1s ease;
}
.decision-modal__close:hover { transform: translateY(-1px); }
</style>