Files
decision/frontend/app/pages/tools.vue
Yvv c19c1aa55e Restructure Engagement Forgeron + fix GenesisBlock + InertiaSlider
- Seed: restructure Engagement Forgeron (51→59 items) avec 3 nouvelles
  sections: Engagements fondamentaux (EF1-EF3), Engagements techniques
  (ET1-ET3), Qualification (Q0-Q1) liée au protocole Embarquement
- Seed: ajout protocole Embarquement Forgeron (5 jalons: candidature,
  miroir, évaluation, certification Smith, mise en ligne)
- GenesisBlock: fix lisibilité — fond mood-surface teinté accent au lieu
  de mood-text inversé, texte mood-aware au lieu de rgba blanc hardcodé
- InertiaSlider: mini affiche "Inertie" sous le curseur, compact en
  width:fit-content pour s'adapter au label
- Frontend: ajout section qualification dans SECTION_META/SECTION_ORDER
- Pages, composants et tests des sprints précédents

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:44:33 +01:00

333 lines
9.3 KiB
Vue

<script setup lang="ts">
/**
* Tools page — lists tools grouped by main section.
* Each section shows relevant tools for Documents, Decisions, Mandates, Protocols.
*/
interface Tool {
label: string
icon: string
description: string
to?: string
status: 'ready' | 'soon'
}
interface ToolSection {
key: string
title: string
icon: string
color: string
tools: Tool[]
}
const sections: ToolSection[] = [
{
key: 'documents',
title: 'Documents',
icon: 'i-lucide-book-open',
color: 'var(--mood-accent)',
tools: [
{ label: 'Modules', icon: 'i-lucide-puzzle', description: 'Structurer un document en sections et clauses modulaires', to: '/documents', status: 'ready' },
{ label: 'Votes permanents', icon: 'i-lucide-infinity', description: 'Chaque clause est sous vote permanent, modifiable a tout moment', status: 'ready' },
{ label: 'Inertie de remplacement', icon: 'i-lucide-sliders-horizontal', description: 'Regler la difficulte de modification par section (standard, haute, tres haute)', to: '/protocols/formulas', status: 'ready' },
{ label: 'Contre-propositions', icon: 'i-lucide-pen-line', description: 'Soumettre un texte alternatif soumis au vote de la communaute', status: 'ready' },
{ label: 'Ancrage IPFS', icon: 'i-lucide-hard-drive', description: 'Archiver les documents valides sur IPFS avec preuve on-chain', status: 'soon' },
],
},
{
key: 'decisions',
title: 'Decisions',
icon: 'i-lucide-scale',
color: 'var(--mood-secondary, var(--mood-accent))',
tools: [
{ label: 'Vote majoritaire WoT', icon: 'i-lucide-check-circle', description: 'Seuil adaptatif par la toile de confiance, formule g1vote', to: '/protocols/formulas', status: 'ready' },
{ label: 'Vote quadratique', icon: 'i-lucide-square-stack', description: 'Ponderation degresssive pour eviter la concentration de pouvoir', status: 'soon' },
{ label: 'Vote nuance 6 niveaux', icon: 'i-lucide-bar-chart-3', description: 'De Tout a fait contre a Tout a fait pour, avec seuil de satisfaction', status: 'ready' },
{ label: 'Mandature', icon: 'i-lucide-user-check', description: 'Election et nomination en binome avec transparence', status: 'ready' },
{ label: 'Multi-criteres', icon: 'i-lucide-layers', description: 'Combinaison WoT + Smith + TechComm, tous doivent passer', to: '/protocols/formulas', status: 'ready' },
],
},
{
key: 'mandats',
title: 'Mandats',
icon: 'i-lucide-user-check',
color: 'var(--mood-success)',
tools: [
{ label: 'Ouverture', icon: 'i-lucide-door-open', description: 'Definir une mission, son perimetre, sa duree et ses objectifs', status: 'ready' },
{ label: 'Nomination', icon: 'i-lucide-users', description: 'Election en binome : un titulaire + un suppleant', status: 'ready' },
{ label: 'Transparence', icon: 'i-lucide-eye', description: 'Rapports d\'activite periodiques soumis au vote', status: 'ready' },
{ label: 'Cloture', icon: 'i-lucide-lock', description: 'Fin de mandat avec bilan ou revocation anticipee par vote', status: 'ready' },
],
},
{
key: 'protocoles',
title: 'Protocoles',
icon: 'i-lucide-settings',
color: 'var(--mood-tertiary, var(--mood-accent))',
tools: [
{ label: 'Simulateur de formules', icon: 'i-lucide-calculator', description: 'Tester les parametres de seuil WoT en temps reel', to: '/protocols/formulas', status: 'ready' },
{ label: 'Meta-gouvernance', icon: 'i-lucide-shield', description: 'Les formules elles-memes sont soumises au vote', status: 'ready' },
{ label: 'Workflows n8n', icon: 'i-lucide-workflow', description: 'Automatisations optionnelles (notifications, alertes, relances)', status: 'soon' },
{ label: 'Protocoles operationnels', icon: 'i-lucide-git-branch', description: 'Processus multi-etapes reutilisables (embarquement, upgrade)', to: '/protocols', status: 'ready' },
],
},
]
</script>
<template>
<div class="tools-page">
<!-- Back link -->
<div class="tools-page__nav">
<UButton
to="/"
variant="ghost"
color="neutral"
icon="i-lucide-arrow-left"
label="Retour a l'accueil"
size="sm"
/>
</div>
<!-- Header -->
<div class="tools-page__header">
<h1 class="tools-page__title">
<UIcon name="i-lucide-wrench" class="tools-page__title-icon" />
Boite a outils
</h1>
<p class="tools-page__subtitle">
Tous les outils de decision collective, organises par section
</p>
</div>
<!-- Tool sections -->
<div class="tools-page__sections">
<div
v-for="section in sections"
:key="section.key"
class="tools-section"
:style="{ '--section-color': section.color }"
>
<div class="tools-section__header">
<UIcon :name="section.icon" class="tools-section__icon" />
<h2 class="tools-section__title">{{ section.title }}</h2>
<span class="tools-section__count">{{ section.tools.length }}</span>
</div>
<div class="tools-section__grid">
<NuxtLink
v-for="tool in section.tools.filter(t => t.to)"
:key="tool.label"
:to="tool.to!"
class="tool-card"
>
<div class="tool-card__icon">
<UIcon :name="tool.icon" />
</div>
<div class="tool-card__body">
<div class="tool-card__head">
<span class="tool-card__label">{{ tool.label }}</span>
</div>
<p class="tool-card__desc">{{ tool.description }}</p>
</div>
<UIcon name="i-lucide-chevron-right" class="tool-card__arrow" />
</NuxtLink>
<div
v-for="tool in section.tools.filter(t => !t.to)"
:key="tool.label"
class="tool-card"
:class="{ 'tool-card--soon': tool.status === 'soon' }"
>
<div class="tool-card__icon">
<UIcon :name="tool.icon" />
</div>
<div class="tool-card__body">
<div class="tool-card__head">
<span class="tool-card__label">{{ tool.label }}</span>
<span v-if="tool.status === 'soon'" class="tool-card__badge">bientot</span>
</div>
<p class="tool-card__desc">{{ tool.description }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.tools-page {
display: flex;
flex-direction: column;
gap: 1.5rem;
max-width: 56rem;
margin: 0 auto;
padding-bottom: 4rem;
}
.tools-page__nav {
margin-bottom: -0.5rem;
}
.tools-page__header {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.tools-page__title {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.5rem;
font-weight: 800;
color: var(--mood-text);
letter-spacing: -0.02em;
}
@media (min-width: 640px) {
.tools-page__title {
font-size: 1.875rem;
}
}
.tools-page__title-icon {
color: var(--mood-accent);
}
.tools-page__subtitle {
font-size: 0.9375rem;
color: var(--mood-text-muted);
font-weight: 500;
}
/* Sections */
.tools-page__sections {
display: flex;
flex-direction: column;
gap: 2rem;
}
.tools-section__header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.tools-section__icon {
font-size: 1.125rem;
color: var(--section-color);
}
.tools-section__title {
font-size: 1.125rem;
font-weight: 800;
color: var(--mood-text);
margin: 0;
}
.tools-section__count {
font-size: 0.6875rem;
font-weight: 700;
background: color-mix(in srgb, var(--section-color) 12%, transparent);
color: var(--section-color);
padding: 2px 8px;
border-radius: 20px;
}
/* Tool cards */
.tools-section__grid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.tool-card {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.875rem 1rem;
background: var(--mood-surface);
border-radius: 14px;
text-decoration: none;
cursor: pointer;
transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.tool-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 16px var(--mood-shadow);
}
.tool-card--soon {
opacity: 0.6;
cursor: default;
}
.tool-card--soon:hover {
transform: none;
box-shadow: none;
}
.tool-card__icon {
width: 2rem;
height: 2rem;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
background: color-mix(in srgb, var(--section-color) 12%, transparent);
color: var(--section-color);
font-size: 0.875rem;
}
.tool-card__body {
flex: 1;
min-width: 0;
}
.tool-card__head {
display: flex;
align-items: center;
gap: 0.375rem;
}
.tool-card__label {
font-size: 0.875rem;
font-weight: 700;
color: var(--mood-text);
}
.tool-card__badge {
font-size: 0.5625rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
padding: 2px 6px;
border-radius: 20px;
background: var(--mood-accent-soft);
color: var(--mood-text-muted);
}
.tool-card__desc {
font-size: 0.75rem;
color: var(--mood-text-muted);
line-height: 1.4;
margin: 0.125rem 0 0;
}
.tool-card__arrow {
flex-shrink: 0;
color: var(--mood-text-muted);
opacity: 0.3;
margin-top: 0.375rem;
transition: all 0.12s;
}
.tool-card:hover .tool-card__arrow {
opacity: 1;
color: var(--section-color);
}
</style>