Accents FR, architecture modulaire, protocoles opérationnels
- Fix accents manquants dans 7 pages UI (décisions, boîte à outils, etc.) - Titres accueil enrichis : Décisions structurantes, Documents de référence, Mandats et nominations, Protocoles et fonctionnement - Retrait Embarquement Forgeron du seed (n'est pas une Decision) - 2 protocoles opérationnels dans Protocoles : Embarquement Forgeron (lié à l'Acte d'engagement) + Soumission Runtime Upgrade (lié à la Décision Runtime Upgrade) avec timeline et liens croisés signalétiques - Décision Runtime Upgrade : badge on-chain + lien protocole + contexte - Document [slug] : lien protocole dans la section Qualification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* Decisions — page index.
|
||||
*
|
||||
* Utilise SectionLayout avec status filters, recherche, tri,
|
||||
* et sidebar "Boite a outils" affichant les protocoles de vote.
|
||||
* et sidebar "Boîte à outils" affichant les protocoles de vote.
|
||||
*/
|
||||
const decisions = useDecisionsStore()
|
||||
const protocols = useProtocolsStore()
|
||||
@@ -28,7 +28,7 @@ onMounted(async () => {
|
||||
|
||||
/** Status filter pills with counts. */
|
||||
const statuses = computed(() => [
|
||||
{ id: 'draft', label: 'En prepa', count: decisions.list.filter(d => d.status === 'draft').length },
|
||||
{ id: 'draft', label: 'En prépa', count: decisions.list.filter(d => d.status === 'draft').length },
|
||||
{ id: 'voting', label: 'En vote', count: decisions.list.filter(d => d.status === 'voting' || d.status === 'qualification' || d.status === 'review').length },
|
||||
{ id: 'executed', label: 'En vigueur', count: decisions.list.filter(d => d.status === 'executed').length },
|
||||
{ id: 'closed', label: 'Clos', count: decisions.list.filter(d => d.status === 'closed').length },
|
||||
@@ -97,8 +97,8 @@ function formatDate(dateStr: string): string {
|
||||
|
||||
<template>
|
||||
<SectionLayout
|
||||
title="Decisions"
|
||||
subtitle="Processus de decision collectifs"
|
||||
title="Décisions"
|
||||
subtitle="Processus de décision collectifs"
|
||||
:statuses="statuses"
|
||||
:active-status="activeStatus"
|
||||
@update:active-status="activeStatus = $event"
|
||||
@@ -111,7 +111,7 @@ function formatDate(dateStr: string): string {
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
class="search-field__input"
|
||||
placeholder="Rechercher une decision..."
|
||||
placeholder="Rechercher une décision..."
|
||||
/>
|
||||
</div>
|
||||
<select v-model="sortBy" class="sort-select">
|
||||
@@ -149,7 +149,7 @@ function formatDate(dateStr: string): string {
|
||||
style="color: var(--mood-text-muted);"
|
||||
>
|
||||
<UIcon name="i-lucide-scale" class="text-4xl mb-3 block mx-auto" />
|
||||
<p>Aucune decision trouvee</p>
|
||||
<p>Aucune décision trouvée</p>
|
||||
<p v-if="searchQuery || activeStatus" class="text-sm mt-1">
|
||||
Essayez de modifier vos filtres
|
||||
</p>
|
||||
@@ -179,15 +179,33 @@ function formatDate(dateStr: string): string {
|
||||
<span class="decision-card__type-badge">
|
||||
{{ typeLabel(decision.decision_type) }}
|
||||
</span>
|
||||
<span
|
||||
v-if="decision.decision_type === 'runtime_upgrade'"
|
||||
class="decision-card__onchain-badge"
|
||||
>
|
||||
<UIcon name="i-lucide-link" class="text-xs" />
|
||||
on-chain
|
||||
</span>
|
||||
<span class="decision-card__steps">
|
||||
<UIcon name="i-lucide-layers" class="text-xs" />
|
||||
{{ decision.steps.length }} etape{{ decision.steps.length !== 1 ? 's' : '' }}
|
||||
{{ decision.steps.length }} étape{{ decision.steps.length !== 1 ? 's' : '' }}
|
||||
</span>
|
||||
<span class="decision-card__date">
|
||||
<UIcon name="i-lucide-clock" class="text-xs" />
|
||||
{{ formatDate(decision.created_at) }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- Protocol link for runtime_upgrade -->
|
||||
<NuxtLink
|
||||
v-if="decision.decision_type === 'runtime_upgrade'"
|
||||
to="/protocols"
|
||||
class="decision-card__protocol-link"
|
||||
@click.stop
|
||||
>
|
||||
<UIcon name="i-lucide-git-branch" class="text-xs" />
|
||||
<span>Protocole : Soumission Runtime Upgrade</span>
|
||||
<UIcon name="i-lucide-arrow-right" class="text-xs" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -196,21 +214,21 @@ function formatDate(dateStr: string): string {
|
||||
<template #toolbox>
|
||||
<ToolboxVignette
|
||||
title="Vote majoritaire WoT"
|
||||
:bullets="['Seuil adaptatif a la participation', 'Formule g1vote inertielle']"
|
||||
:bullets="['Seuil adaptatif à la participation', 'Formule g1vote inertielle']"
|
||||
:actions="[
|
||||
{ label: 'Simuler', icon: 'i-lucide-calculator', to: '/protocols/formulas', primary: true },
|
||||
]"
|
||||
/>
|
||||
<ToolboxVignette
|
||||
title="Vote nuance"
|
||||
:bullets="['6 niveaux de preference', 'Seuil de satisfaction 80%']"
|
||||
title="Vote nuancé"
|
||||
:bullets="['6 niveaux de préférence', 'Seuil de satisfaction 80%']"
|
||||
:actions="[
|
||||
{ label: 'Voir', icon: 'i-lucide-bar-chart-3', emit: 'nuance' },
|
||||
]"
|
||||
/>
|
||||
<ToolboxVignette
|
||||
title="Mandature"
|
||||
:bullets="['Election en binome', 'Transparence et revocation']"
|
||||
:bullets="['Élection en binôme', 'Transparence et révocation']"
|
||||
:actions="[
|
||||
{ label: 'Mandats', icon: 'i-lucide-user-check', to: '/mandates', primary: true },
|
||||
]"
|
||||
@@ -337,6 +355,40 @@ function formatDate(dateStr: string): string {
|
||||
color: var(--mood-accent);
|
||||
}
|
||||
|
||||
.decision-card__onchain-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
padding: 3px 8px;
|
||||
border-radius: 20px;
|
||||
background: color-mix(in srgb, var(--mood-success) 15%, transparent);
|
||||
color: var(--mood-success);
|
||||
}
|
||||
|
||||
.decision-card__protocol-link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
border-radius: 20px;
|
||||
text-decoration: none;
|
||||
background: color-mix(in srgb, var(--mood-tertiary, var(--mood-accent)) 10%, transparent);
|
||||
color: var(--mood-tertiary, var(--mood-accent));
|
||||
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.decision-card__protocol-link:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px var(--mood-shadow);
|
||||
}
|
||||
|
||||
/* --- Modern search / sort / action --- */
|
||||
.search-field {
|
||||
flex: 1;
|
||||
|
||||
@@ -332,6 +332,20 @@ function toggleSection(tag: string) {
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<!-- Protocol link for qualification section -->
|
||||
<NuxtLink
|
||||
v-if="section.tag === 'qualification' && !collapsedSections[section.tag]"
|
||||
to="/protocols"
|
||||
class="doc-page__protocol-link"
|
||||
>
|
||||
<UIcon name="i-lucide-git-branch" class="text-sm" />
|
||||
<div>
|
||||
<span class="doc-page__protocol-link-label">Protocole lié</span>
|
||||
<span class="doc-page__protocol-link-name">Embarquement Forgeron</span>
|
||||
</div>
|
||||
<UIcon name="i-lucide-arrow-right" class="text-sm doc-page__protocol-link-arrow" />
|
||||
</NuxtLink>
|
||||
|
||||
<!-- Items (collapsible) -->
|
||||
<Transition name="section-collapse">
|
||||
<div v-show="!collapsedSections[section.tag]" class="doc-page__section-items">
|
||||
@@ -531,6 +545,51 @@ function toggleSection(tag: string) {
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* Protocol link */
|
||||
.doc-page__protocol-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem 1rem;
|
||||
background: color-mix(in srgb, var(--mood-tertiary, var(--mood-accent)) 8%, var(--mood-surface));
|
||||
border: 1px solid color-mix(in srgb, var(--mood-tertiary, var(--mood-accent)) 15%, transparent);
|
||||
border-radius: 14px;
|
||||
text-decoration: none;
|
||||
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
||||
color: var(--mood-tertiary, var(--mood-accent));
|
||||
}
|
||||
|
||||
.doc-page__protocol-link:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px var(--mood-shadow);
|
||||
}
|
||||
|
||||
.doc-page__protocol-link-label {
|
||||
display: block;
|
||||
font-size: 0.625rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--mood-text-muted);
|
||||
}
|
||||
|
||||
.doc-page__protocol-link-name {
|
||||
display: block;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
color: var(--mood-text);
|
||||
}
|
||||
|
||||
.doc-page__protocol-link-arrow {
|
||||
margin-left: auto;
|
||||
opacity: 0.3;
|
||||
transition: opacity 0.12s;
|
||||
}
|
||||
|
||||
.doc-page__protocol-link:hover .doc-page__protocol-link-arrow {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Section collapse transition */
|
||||
.section-collapse-enter-active,
|
||||
.section-collapse-leave-active {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Documents de reference — page index.
|
||||
*
|
||||
* Utilise SectionLayout avec status filters, recherche, tri,
|
||||
* et sidebar "Boite a outils" affichant les protocoles de vote.
|
||||
* et sidebar "Boîte à outils" affichant les protocoles de vote.
|
||||
*/
|
||||
import type { DocumentCreate } from '~/stores/documents'
|
||||
|
||||
@@ -29,7 +29,7 @@ const creating = ref(false)
|
||||
const newDocTypeOptions = [
|
||||
{ label: 'Licence', value: 'licence' },
|
||||
{ label: 'Engagement', value: 'engagement' },
|
||||
{ label: 'Reglement', value: 'reglement' },
|
||||
{ label: 'Règlement', value: 'reglement' },
|
||||
{ label: 'Constitution', value: 'constitution' },
|
||||
]
|
||||
|
||||
@@ -48,7 +48,7 @@ onMounted(async () => {
|
||||
|
||||
/** Status filter pills with counts. */
|
||||
const statuses = computed(() => [
|
||||
{ id: 'draft', label: 'En prepa', count: documents.list.filter(d => d.status === 'draft').length },
|
||||
{ id: 'draft', label: 'En prépa', count: documents.list.filter(d => d.status === 'draft').length },
|
||||
{ id: 'voting', label: 'En vote', count: documents.list.filter(d => d.status === 'voting').length },
|
||||
{ id: 'active', label: 'En vigueur', count: documents.list.filter(d => d.status === 'active').length },
|
||||
{ id: 'archived', label: 'Clos', count: documents.list.filter(d => d.status === 'archived').length },
|
||||
@@ -92,7 +92,7 @@ const typeLabel = (docType: string): string => {
|
||||
switch (docType) {
|
||||
case 'licence': return 'Licence'
|
||||
case 'engagement': return 'Engagement'
|
||||
case 'reglement': return 'Reglement'
|
||||
case 'reglement': return 'Règlement'
|
||||
case 'constitution': return 'Constitution'
|
||||
default: return docType
|
||||
}
|
||||
@@ -154,8 +154,8 @@ async function createDocument() {
|
||||
|
||||
<template>
|
||||
<SectionLayout
|
||||
title="Documents de reference"
|
||||
subtitle="Textes fondateurs sous vote permanent de la communaute"
|
||||
title="Documents de référence"
|
||||
subtitle="Textes fondateurs sous vote permanent de la communauté"
|
||||
:statuses="statuses"
|
||||
:active-status="activeStatus"
|
||||
@update:active-status="activeStatus = $event"
|
||||
@@ -206,7 +206,7 @@ async function createDocument() {
|
||||
style="color: var(--mood-text-muted);"
|
||||
>
|
||||
<UIcon name="i-lucide-book-open" class="text-4xl mb-3 block mx-auto" />
|
||||
<p>Aucun document trouve</p>
|
||||
<p>Aucun document trouvé</p>
|
||||
<p v-if="searchQuery || activeStatus" class="text-sm mt-1">
|
||||
Essayez de modifier vos filtres
|
||||
</p>
|
||||
@@ -253,7 +253,7 @@ async function createDocument() {
|
||||
<template #toolbox>
|
||||
<ToolboxVignette
|
||||
title="Modules"
|
||||
:bullets="['Structurer en sections et clauses', 'Vote independant par clause']"
|
||||
:bullets="['Structurer en sections et clauses', 'Vote indépendant par clause']"
|
||||
:actions="[
|
||||
{ label: 'Voir', icon: 'i-lucide-puzzle', emit: 'modules' },
|
||||
]"
|
||||
@@ -267,7 +267,7 @@ async function createDocument() {
|
||||
/>
|
||||
<ToolboxVignette
|
||||
title="Inertie de remplacement"
|
||||
:bullets="['4 niveaux de difficulte', 'Protege les textes fondamentaux']"
|
||||
:bullets="['4 niveaux de difficulté', 'Protège les textes fondamentaux']"
|
||||
:actions="[
|
||||
{ label: 'Simuler', icon: 'i-lucide-sliders-horizontal', to: '/protocols/formulas', primary: true },
|
||||
]"
|
||||
@@ -280,7 +280,7 @@ async function createDocument() {
|
||||
<template #content>
|
||||
<div class="p-4 sm:p-6 space-y-4">
|
||||
<h3 class="text-base sm:text-lg font-semibold" style="color: var(--mood-text);">
|
||||
Nouveau document de reference
|
||||
Nouveau document de référence
|
||||
</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
@@ -335,7 +335,7 @@ async function createDocument() {
|
||||
<UTextarea
|
||||
v-model="newDoc.description"
|
||||
:rows="3"
|
||||
placeholder="Decrivez brievement ce document..."
|
||||
placeholder="Décrivez brièvement ce document..."
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
@@ -349,7 +349,7 @@ async function createDocument() {
|
||||
@click="showNewDocModal = false"
|
||||
/>
|
||||
<UButton
|
||||
label="Creer le document"
|
||||
label="Créer le document"
|
||||
icon="i-lucide-plus"
|
||||
color="primary"
|
||||
:loading="creating"
|
||||
|
||||
@@ -23,18 +23,18 @@ onMounted(async () => {
|
||||
const entryCards = computed(() => [
|
||||
{
|
||||
key: 'decisions',
|
||||
title: 'Decisions',
|
||||
title: 'Décisions structurantes',
|
||||
icon: 'i-lucide-scale',
|
||||
to: '/decisions',
|
||||
count: decisions.activeDecisions.length,
|
||||
countLabel: `${decisions.activeDecisions.length} en cours`,
|
||||
totalLabel: `${decisions.list.length} au total`,
|
||||
description: 'Processus de decision collectifs',
|
||||
description: 'Processus de décision collectifs',
|
||||
color: 'var(--mood-secondary, var(--mood-accent))',
|
||||
},
|
||||
{
|
||||
key: 'documents',
|
||||
title: 'Documents',
|
||||
title: 'Documents de référence',
|
||||
icon: 'i-lucide-book-open',
|
||||
to: '/documents',
|
||||
count: documents.activeDocuments.length,
|
||||
@@ -45,24 +45,24 @@ const entryCards = computed(() => [
|
||||
},
|
||||
{
|
||||
key: 'mandats',
|
||||
title: 'Mandats',
|
||||
title: 'Mandats et nominations',
|
||||
icon: 'i-lucide-user-check',
|
||||
to: '/mandates',
|
||||
count: null,
|
||||
countLabel: null,
|
||||
totalLabel: null,
|
||||
description: 'Missions deleguees avec nomination en binome',
|
||||
description: 'Missions déléguées avec nomination en binôme',
|
||||
color: 'var(--mood-success)',
|
||||
},
|
||||
{
|
||||
key: 'protocoles',
|
||||
title: 'Protocoles',
|
||||
title: 'Protocoles et fonctionnement',
|
||||
icon: 'i-lucide-settings',
|
||||
to: '/protocols',
|
||||
count: protocols.protocols.length,
|
||||
countLabel: `${protocols.protocols.length} modalite${protocols.protocols.length > 1 ? 's' : ''}`,
|
||||
totalLabel: 'Boite a outils de vote + workflows',
|
||||
description: 'Modalites de vote, formules, workflows',
|
||||
countLabel: `${protocols.protocols.length} modalité${protocols.protocols.length > 1 ? 's' : ''}`,
|
||||
totalLabel: 'Boîte à outils de vote + workflows',
|
||||
description: 'Modalités de vote, formules, workflows',
|
||||
color: 'var(--mood-tertiary, var(--mood-accent))',
|
||||
},
|
||||
])
|
||||
@@ -81,7 +81,7 @@ function formatDate(dateStr: string): string {
|
||||
|
||||
if (diffHours < 1) {
|
||||
const diffMinutes = Math.floor(diffMs / (1000 * 60))
|
||||
return diffMinutes <= 1 ? 'A l\'instant' : `Il y a ${diffMinutes} min`
|
||||
return diffMinutes <= 1 ? 'À l\'instant' : `Il y a ${diffMinutes} min`
|
||||
}
|
||||
if (diffHours < 24) {
|
||||
return `Il y a ${Math.floor(diffHours)}h`
|
||||
@@ -101,7 +101,7 @@ function formatDate(dateStr: string): string {
|
||||
<span class="dash__title-g">ğ</span><span class="dash__title-paren">(</span>Decision<span class="dash__title-paren">)</span>
|
||||
</h1>
|
||||
<p class="dash__subtitle">
|
||||
Decisions collectives pour la communaute Duniter / G1
|
||||
Décisions collectives pour la communauté Duniter / G1
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -141,7 +141,7 @@ function formatDate(dateStr: string): string {
|
||||
<div class="dash__connect-left">
|
||||
<UIcon name="i-lucide-key-round" class="text-lg" />
|
||||
<div>
|
||||
<p class="dash__connect-text">Connectez-vous avec votre identite Duniter pour participer.</p>
|
||||
<p class="dash__connect-text">Connectez-vous avec votre identité Duniter pour participer.</p>
|
||||
<p class="dash__connect-hint">Signature Ed25519 · aucun mot de passe</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -158,7 +158,7 @@ function formatDate(dateStr: string): string {
|
||||
<UIcon name="i-lucide-wrench" class="text-xl" />
|
||||
</div>
|
||||
<div class="dash__toolbox-card-body">
|
||||
<h3 class="dash__toolbox-card-title">Boite a outils</h3>
|
||||
<h3 class="dash__toolbox-card-title">Boîte à outils</h3>
|
||||
<p class="dash__toolbox-card-desc">
|
||||
Simulateur de formules, modules de vote, workflows
|
||||
</p>
|
||||
@@ -177,7 +177,7 @@ function formatDate(dateStr: string): string {
|
||||
<div v-if="recentDecisions.length > 0" class="dash__activity">
|
||||
<div class="dash__activity-head">
|
||||
<UIcon name="i-lucide-activity" class="text-lg" />
|
||||
<h3>Activite recente</h3>
|
||||
<h3>Activité récente</h3>
|
||||
</div>
|
||||
<div class="dash__activity-list">
|
||||
<NuxtLink
|
||||
@@ -207,7 +207,7 @@ function formatDate(dateStr: string): string {
|
||||
<template #content>
|
||||
<div class="dash__formula-body">
|
||||
<p class="dash__formula-desc">
|
||||
Le seuil s'adapte a la participation : faible = quasi-unanimite ; forte = majorite simple.
|
||||
Le seuil s'adapte à la participation : faible = quasi-unanimité ; forte = majorité simple.
|
||||
</p>
|
||||
<code class="dash__formula-code">
|
||||
Seuil = C + B^W + (M + (1-M) * (1 - (T/W)^G)) * max(0, T-C)
|
||||
@@ -217,7 +217,7 @@ function formatDate(dateStr: string): string {
|
||||
<span>B = base</span>
|
||||
<span>W = taille WoT</span>
|
||||
<span>T = votes</span>
|
||||
<span>M = majorite</span>
|
||||
<span>M = majorité</span>
|
||||
<span>G = gradient</span>
|
||||
</div>
|
||||
<NuxtLink to="/protocols/formulas" class="dash__formula-link">
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
* Mandats — page index.
|
||||
*
|
||||
* Utilise SectionLayout avec status filters, recherche,
|
||||
* et sidebar "Boite a outils" affichant les protocoles de vote.
|
||||
* Etat vide enrichi avec onboarding expliquant le concept de mandat.
|
||||
* et sidebar "Boîte à outils" affichant les protocoles de vote.
|
||||
* État vide enrichi avec onboarding expliquant le concept de mandat.
|
||||
*/
|
||||
import type { MandateCreate } from '~/stores/mandates'
|
||||
|
||||
@@ -25,9 +25,9 @@ const sortOptions = [
|
||||
// Create mandate modal state
|
||||
const showCreateModal = ref(false)
|
||||
const mandateTypeOptions = [
|
||||
{ label: 'Comite technique', value: 'techcomm' },
|
||||
{ label: 'Comité technique', value: 'techcomm' },
|
||||
{ label: 'Forgeron', value: 'smith' },
|
||||
{ label: 'Personnalise', value: 'custom' },
|
||||
{ label: 'Personnalisé', value: 'custom' },
|
||||
]
|
||||
|
||||
const newMandate = ref<MandateCreate>({
|
||||
@@ -46,7 +46,7 @@ onMounted(async () => {
|
||||
|
||||
/** Status filter pills with counts. */
|
||||
const statuses = computed(() => [
|
||||
{ id: 'draft', label: 'En prepa', count: mandates.list.filter(m => m.status === 'draft' || m.status === 'candidacy').length },
|
||||
{ id: 'draft', label: 'En prépa', count: mandates.list.filter(m => m.status === 'draft' || m.status === 'candidacy').length },
|
||||
{ id: 'voting', label: 'En vote', count: mandates.list.filter(m => m.status === 'voting').length },
|
||||
{ id: 'active', label: 'En vigueur', count: mandates.list.filter(m => m.status === 'active' || m.status === 'reporting').length },
|
||||
{ id: 'closed', label: 'Clos', count: mandates.list.filter(m => m.status === 'completed' || m.status === 'revoked').length },
|
||||
@@ -95,9 +95,9 @@ const filteredMandates = computed(() => {
|
||||
|
||||
const typeLabel = (mandateType: string) => {
|
||||
switch (mandateType) {
|
||||
case 'techcomm': return 'Comite technique'
|
||||
case 'techcomm': return 'Comité technique'
|
||||
case 'smith': return 'Forgeron'
|
||||
case 'custom': return 'Personnalise'
|
||||
case 'custom': return 'Personnalisé'
|
||||
default: return mandateType
|
||||
}
|
||||
}
|
||||
@@ -133,7 +133,7 @@ async function handleCreate() {
|
||||
<template>
|
||||
<SectionLayout
|
||||
title="Mandats"
|
||||
subtitle="Un contexte, un objectif, une duree, une ou plusieurs nominations ; par defaut : nomination d'un binome."
|
||||
subtitle="Un contexte, un objectif, une durée, une ou plusieurs nominations ; par défaut : nomination d'un binôme."
|
||||
:statuses="statuses"
|
||||
:active-status="activeStatus"
|
||||
@update:active-status="activeStatus = $event"
|
||||
@@ -189,17 +189,17 @@ async function handleCreate() {
|
||||
Qu'est-ce qu'un mandat ?
|
||||
</h3>
|
||||
<p class="mandate-onboarding__text">
|
||||
Un mandat definit un contexte, un objectif et une duree pour une mission de gouvernance.
|
||||
Il peut porter sur le comite technique, les forgerons, ou tout role specifique de la communaute.
|
||||
Un mandat définit un contexte, un objectif et une durée pour une mission de gouvernance.
|
||||
Il peut porter sur le comité technique, les forgerons, ou tout rôle spécifique de la communauté.
|
||||
</p>
|
||||
<p class="mandate-onboarding__text">
|
||||
Par defaut, un mandat nomme un binome pour assurer la continuite.
|
||||
Par défaut, un mandat nomme un binôme pour assurer la continuité.
|
||||
Le processus comprend : candidature, vote communautaire, periode active et rapport final.
|
||||
</p>
|
||||
<div class="mandate-onboarding__actions">
|
||||
<UButton
|
||||
v-if="auth.isAuthenticated"
|
||||
label="Creer un premier mandat"
|
||||
label="Créer un premier mandat"
|
||||
icon="i-lucide-plus"
|
||||
color="primary"
|
||||
size="sm"
|
||||
@@ -207,7 +207,7 @@ async function handleCreate() {
|
||||
/>
|
||||
<UButton
|
||||
to="/protocols"
|
||||
label="Decouvrir les protocoles"
|
||||
label="Découvrir les protocoles"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
icon="i-lucide-wrench"
|
||||
@@ -222,7 +222,7 @@ async function handleCreate() {
|
||||
style="color: var(--mood-text-muted);"
|
||||
>
|
||||
<UIcon name="i-lucide-user-check" class="text-4xl mb-3 block mx-auto" />
|
||||
<p>Aucun mandat trouve</p>
|
||||
<p>Aucun mandat trouvé</p>
|
||||
<p v-if="searchQuery || activeStatus" class="text-sm mt-1">
|
||||
Essayez de modifier vos filtres
|
||||
</p>
|
||||
@@ -254,7 +254,7 @@ async function handleCreate() {
|
||||
</span>
|
||||
<span class="mandate-card__steps">
|
||||
<UIcon name="i-lucide-layers" class="text-xs" />
|
||||
{{ mandate.steps.length }} etape{{ mandate.steps.length !== 1 ? 's' : '' }}
|
||||
{{ mandate.steps.length }} étape{{ mandate.steps.length !== 1 ? 's' : '' }}
|
||||
</span>
|
||||
<span v-if="mandate.mandatee_id" class="mandate-card__mandatee">
|
||||
<UIcon name="i-lucide-user" class="text-xs" />
|
||||
@@ -263,7 +263,7 @@ async function handleCreate() {
|
||||
</div>
|
||||
|
||||
<div class="mandate-card__dates">
|
||||
<span>Debut : {{ formatDate(mandate.starts_at) }}</span>
|
||||
<span>Début : {{ formatDate(mandate.starts_at) }}</span>
|
||||
<span>Fin : {{ formatDate(mandate.ends_at) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -274,28 +274,28 @@ async function handleCreate() {
|
||||
<template #toolbox>
|
||||
<ToolboxVignette
|
||||
title="Ouverture"
|
||||
:bullets="['Definir mission et perimetre', 'Duree et objectifs clairs']"
|
||||
:bullets="['Définir mission et périmètre', 'Durée et objectifs clairs']"
|
||||
:actions="[
|
||||
{ label: 'Creer', icon: 'i-lucide-door-open', emit: 'create', primary: true },
|
||||
{ label: 'Créer', icon: 'i-lucide-door-open', emit: 'create', primary: true },
|
||||
]"
|
||||
/>
|
||||
<ToolboxVignette
|
||||
title="Nomination"
|
||||
:bullets="['Election en binome', 'Titulaire + suppleant']"
|
||||
:bullets="['Élection en binôme', 'Titulaire + suppléant']"
|
||||
:actions="[
|
||||
{ label: 'Voir', icon: 'i-lucide-users', emit: 'nomination' },
|
||||
]"
|
||||
/>
|
||||
<ToolboxVignette
|
||||
title="Transparence"
|
||||
:bullets="['Rapports d\'activite', 'Soumis au vote communautaire']"
|
||||
:bullets="['Rapports d\'activité', 'Soumis au vote communautaire']"
|
||||
:actions="[
|
||||
{ label: 'Voir', icon: 'i-lucide-eye', emit: 'transparence' },
|
||||
]"
|
||||
/>
|
||||
<ToolboxVignette
|
||||
title="Cloture"
|
||||
:bullets="['Fin de mandat ou revocation', 'Bilan et transmission']"
|
||||
:bullets="['Fin de mandat ou révocation', 'Bilan et transmission']"
|
||||
:actions="[
|
||||
{ label: 'Voir', icon: 'i-lucide-lock', emit: 'cloture' },
|
||||
]"
|
||||
@@ -352,7 +352,7 @@ async function handleCreate() {
|
||||
/>
|
||||
<UButton
|
||||
type="submit"
|
||||
label="Creer"
|
||||
label="Créer"
|
||||
icon="i-lucide-plus"
|
||||
color="primary"
|
||||
:loading="creating"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* Protocoles & Fonctionnement — Boite a outils de vote.
|
||||
* Protocoles & Fonctionnement — Boîte à outils de vote.
|
||||
*
|
||||
* Liste les protocoles de vote avec SectionLayout,
|
||||
* sidebar n8n workflow + simulateur de formules.
|
||||
@@ -30,14 +30,14 @@ onMounted(async () => {
|
||||
const voteTypeLabel = (voteType: string) => {
|
||||
switch (voteType) {
|
||||
case 'binary': return 'Binaire'
|
||||
case 'nuanced': return 'Nuance'
|
||||
case 'nuanced': return 'Nuancé'
|
||||
default: return voteType
|
||||
}
|
||||
}
|
||||
|
||||
const voteTypeOptions = [
|
||||
{ label: 'Binaire (Pour/Contre)', value: 'binary' },
|
||||
{ label: 'Nuance (6 niveaux)', value: 'nuanced' },
|
||||
{ label: 'Nuancé (6 niveaux)', value: 'nuanced' },
|
||||
]
|
||||
|
||||
const formulaOptions = computed(() => {
|
||||
@@ -57,7 +57,7 @@ const statuses = computed(() => [
|
||||
},
|
||||
{
|
||||
id: 'nuanced',
|
||||
label: 'Nuance',
|
||||
label: 'Nuancé',
|
||||
count: protocols.protocols.filter(p => p.vote_type === 'nuanced').length,
|
||||
cssClass: 'status-prepa',
|
||||
},
|
||||
@@ -117,24 +117,60 @@ interface WorkflowStep {
|
||||
type: string
|
||||
}
|
||||
|
||||
const operationalProtocols = [
|
||||
interface LinkedRef {
|
||||
label: string
|
||||
icon: string
|
||||
to: string
|
||||
kind: 'document' | 'decision'
|
||||
}
|
||||
|
||||
interface OperationalProtocol {
|
||||
slug: string
|
||||
name: string
|
||||
description: string
|
||||
category: string
|
||||
icon: string
|
||||
instancesLabel: string
|
||||
linkedRefs: LinkedRef[]
|
||||
steps: WorkflowStep[]
|
||||
}
|
||||
|
||||
const operationalProtocols: OperationalProtocol[] = [
|
||||
{
|
||||
slug: 'embarquement-forgeron',
|
||||
name: 'Embarquement Forgeron',
|
||||
description: 'Processus complet d\'intégration d\'un nouveau forgeron dans le réseau Duniter.',
|
||||
description: 'Processus complet d\'intégration d\'un nouveau forgeron dans le réseau Duniter. Parcours en 5 jalons de la candidature à la mise en ligne du nœud validateur.',
|
||||
category: 'onboarding',
|
||||
icon: 'i-lucide-hammer',
|
||||
instancesLabel: '~10-50 / an',
|
||||
linkedRefs: [
|
||||
{ label: 'Acte d\'engagement forgeron', icon: 'i-lucide-book-open', to: '/documents/engagement-forgeron', kind: 'document' },
|
||||
],
|
||||
steps: [
|
||||
{ label: 'Invitation on-chain', actor: 'Smith existant', icon: 'i-lucide-send', type: 'on_chain' },
|
||||
{ label: 'Acceptation', actor: 'Candidat', icon: 'i-lucide-check', type: 'on_chain' },
|
||||
{ label: 'Session keys', actor: 'Candidat', icon: 'i-lucide-key', type: 'on_chain' },
|
||||
{ label: 'Checklist aspirant', actor: 'Candidat', icon: 'i-lucide-clipboard-check', type: 'checklist' },
|
||||
{ label: 'Certification 1', actor: 'Certificateur', icon: 'i-lucide-stamp', type: 'certification' },
|
||||
{ label: 'Certification 2', actor: 'Certificateur', icon: 'i-lucide-stamp', type: 'certification' },
|
||||
{ label: 'Certification 3', actor: 'Certificateur', icon: 'i-lucide-stamp', type: 'certification' },
|
||||
{ label: 'Candidature', actor: 'Aspirant forgeron', icon: 'i-lucide-user-plus', type: 'checklist' },
|
||||
{ label: 'Nœud miroir', actor: 'Candidat', icon: 'i-lucide-server', type: 'on_chain' },
|
||||
{ label: 'Évaluation technique', actor: 'Certificateur', icon: 'i-lucide-clipboard-check', type: 'checklist' },
|
||||
{ label: 'Certification Smith (×3)', actor: 'Certificateurs', icon: 'i-lucide-stamp', type: 'certification' },
|
||||
{ label: 'Go online', actor: 'Candidat', icon: 'i-lucide-wifi', type: 'on_chain' },
|
||||
] as WorkflowStep[],
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'soumission-runtime-upgrade',
|
||||
name: 'Soumission Runtime Upgrade',
|
||||
description: 'Protocole de soumission d\'une mise à jour du runtime Duniter V2 on-chain. Chaque upgrade suit un parcours strict en 5 étapes, de la qualification technique au suivi post-déploiement.',
|
||||
category: 'on-chain',
|
||||
icon: 'i-lucide-cpu',
|
||||
instancesLabel: '~2-6 / an',
|
||||
linkedRefs: [
|
||||
{ label: 'Décision Runtime Upgrade', icon: 'i-lucide-scale', to: '/decisions', kind: 'decision' },
|
||||
],
|
||||
steps: [
|
||||
{ label: 'Qualification', actor: 'Proposant', icon: 'i-lucide-file-check', type: 'checklist' },
|
||||
{ label: 'Revue technique', actor: 'Comité technique', icon: 'i-lucide-search', type: 'checklist' },
|
||||
{ label: 'Vote communautaire', actor: 'Communauté WoT', icon: 'i-lucide-vote', type: 'on_chain' },
|
||||
{ label: 'Exécution on-chain', actor: 'Proposant', icon: 'i-lucide-zap', type: 'on_chain' },
|
||||
{ label: 'Suivi post-upgrade', actor: 'Forgerons', icon: 'i-lucide-activity', type: 'checklist' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -142,7 +178,7 @@ const operationalProtocols = [
|
||||
const n8nWorkflows = [
|
||||
{
|
||||
name: 'Vote -> Notification',
|
||||
description: 'Notifie les membres lorsqu\'un nouveau vote demarre ou se termine.',
|
||||
description: 'Notifie les membres lorsqu\'un nouveau vote démarre ou se termine.',
|
||||
icon: 'i-lucide-bell',
|
||||
status: 'actif',
|
||||
},
|
||||
@@ -153,13 +189,13 @@ const n8nWorkflows = [
|
||||
status: 'actif',
|
||||
},
|
||||
{
|
||||
name: 'Decision -> Etape suivante',
|
||||
description: 'Avance automatiquement une decision a l\'etape suivante apres validation.',
|
||||
name: 'Décision → Étape suivante',
|
||||
description: 'Avance automatiquement une décision à l\'étape suivante après validation.',
|
||||
icon: 'i-lucide-git-branch',
|
||||
status: 'demo',
|
||||
},
|
||||
{
|
||||
name: 'Mandat expire -> Alerte',
|
||||
name: 'Mandat expiré → Alerte',
|
||||
description: 'Envoie une alerte 7 jours avant l\'expiration d\'un mandat.',
|
||||
icon: 'i-lucide-alarm-clock',
|
||||
status: 'demo',
|
||||
@@ -170,7 +206,7 @@ const n8nWorkflows = [
|
||||
<template>
|
||||
<SectionLayout
|
||||
title="Protocoles & Fonctionnement"
|
||||
subtitle="Boite a outils de vote, formules de seuil, workflows automatises"
|
||||
subtitle="Boîte à outils de vote, formules de seuil, workflows automatisés"
|
||||
:statuses="statuses"
|
||||
:active-status="activeStatus"
|
||||
@update:active-status="activeStatus = $event"
|
||||
@@ -212,7 +248,7 @@ const n8nWorkflows = [
|
||||
<template v-else>
|
||||
<div v-if="filteredProtocols.length === 0" class="proto-empty">
|
||||
<UIcon name="i-lucide-settings" class="text-2xl" />
|
||||
<p>Aucun protocole trouve</p>
|
||||
<p>Aucun protocole trouvé</p>
|
||||
</div>
|
||||
|
||||
<div v-else class="proto-list">
|
||||
@@ -262,7 +298,7 @@ const n8nWorkflows = [
|
||||
<div class="proto-ops">
|
||||
<h3 class="proto-ops__title">
|
||||
<UIcon name="i-lucide-git-branch" class="text-sm" />
|
||||
Protocoles operationnels
|
||||
Protocoles opérationnels
|
||||
<span class="proto-ops__count">{{ operationalProtocols.length }}</span>
|
||||
</h3>
|
||||
|
||||
@@ -282,6 +318,21 @@ const n8nWorkflows = [
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Linked references -->
|
||||
<div v-if="op.linkedRefs.length > 0" class="proto-ops__refs">
|
||||
<NuxtLink
|
||||
v-for="ref in op.linkedRefs"
|
||||
:key="ref.to"
|
||||
:to="ref.to"
|
||||
class="proto-ops__ref"
|
||||
:class="`proto-ops__ref--${ref.kind}`"
|
||||
>
|
||||
<UIcon :name="ref.icon" class="text-xs" />
|
||||
<span>{{ ref.label }}</span>
|
||||
<UIcon name="i-lucide-arrow-right" class="text-xs proto-ops__ref-arrow" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<!-- Step timeline -->
|
||||
<div class="proto-ops__timeline">
|
||||
<div
|
||||
@@ -314,8 +365,8 @@ const n8nWorkflows = [
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nom</th>
|
||||
<th>Duree</th>
|
||||
<th>Majorite</th>
|
||||
<th>Durée</th>
|
||||
<th>Majorité</th>
|
||||
<th>B</th>
|
||||
<th>G</th>
|
||||
<th>Smith</th>
|
||||
@@ -343,7 +394,7 @@ const n8nWorkflows = [
|
||||
<!-- Simulateur -->
|
||||
<ToolboxVignette
|
||||
title="Simulateur de formules"
|
||||
:bullets="['Testez WoT, Smith, TechComm', 'Ajustez les parametres en temps reel', 'Visualisez les seuils']"
|
||||
:bullets="['Testez WoT, Smith, TechComm', 'Ajustez les paramètres en temps réel', 'Visualisez les seuils']"
|
||||
:actions="[
|
||||
{ label: 'Tutos', icon: 'i-lucide-graduation-cap', emit: 'tutos' },
|
||||
{ label: 'Ouvrir', icon: 'i-lucide-calculator', to: '/protocols/formulas', primary: true },
|
||||
@@ -357,7 +408,7 @@ const n8nWorkflows = [
|
||||
<span>Workflows n8n</span>
|
||||
</div>
|
||||
<p class="n8n-section__desc">
|
||||
Automatisations reliees via MCP
|
||||
Automatisations reliées via MCP
|
||||
</p>
|
||||
|
||||
<div class="n8n-workflows">
|
||||
@@ -387,12 +438,12 @@ const n8nWorkflows = [
|
||||
|
||||
<!-- Meta-gouvernance -->
|
||||
<ToolboxVignette
|
||||
title="Meta-gouvernance"
|
||||
title="Méta-gouvernance"
|
||||
:bullets="['Les formules sont soumises au vote', 'Modifier les seuils collectivement', 'Transparence totale']"
|
||||
:actions="[
|
||||
{ label: 'Tutos', icon: 'i-lucide-graduation-cap', emit: 'tutos' },
|
||||
{ label: 'Formules', icon: 'i-lucide-calculator', emit: 'formules' },
|
||||
{ label: 'Demarrer', icon: 'i-lucide-play', emit: 'meta', primary: true },
|
||||
{ label: 'Démarrer', icon: 'i-lucide-play', emit: 'meta', primary: true },
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
@@ -439,7 +490,7 @@ const n8nWorkflows = [
|
||||
<USelect
|
||||
v-model="newProtocol.formula_config_id"
|
||||
:items="formulaOptions"
|
||||
placeholder="Selectionnez une formule..."
|
||||
placeholder="Sélectionnez une formule..."
|
||||
value-key="value"
|
||||
/>
|
||||
</div>
|
||||
@@ -455,7 +506,7 @@ const n8nWorkflows = [
|
||||
@click="createProtocol"
|
||||
>
|
||||
<UIcon v-if="creating" name="i-lucide-loader-2" class="animate-spin text-xs" />
|
||||
<span>Creer</span>
|
||||
<span>Créer</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -952,6 +1003,49 @@ const n8nWorkflows = [
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* Linked references */
|
||||
.proto-ops__refs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.proto-ops__ref {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
border-radius: 20px;
|
||||
text-decoration: none;
|
||||
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
||||
}
|
||||
|
||||
.proto-ops__ref:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px var(--mood-shadow);
|
||||
}
|
||||
|
||||
.proto-ops__ref--document {
|
||||
background: color-mix(in srgb, var(--mood-accent) 12%, transparent);
|
||||
color: var(--mood-accent);
|
||||
}
|
||||
|
||||
.proto-ops__ref--decision {
|
||||
background: color-mix(in srgb, var(--mood-secondary, var(--mood-accent)) 12%, transparent);
|
||||
color: var(--mood-secondary, var(--mood-accent));
|
||||
}
|
||||
|
||||
.proto-ops__ref-arrow {
|
||||
opacity: 0.4;
|
||||
transition: opacity 0.12s;
|
||||
}
|
||||
|
||||
.proto-ops__ref:hover .proto-ops__ref-arrow {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Timeline */
|
||||
.proto-ops__timeline {
|
||||
display: flex;
|
||||
|
||||
@@ -28,23 +28,23 @@ const sections: ToolSection[] = [
|
||||
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' },
|
||||
{ label: 'Votes permanents', icon: 'i-lucide-infinity', description: 'Chaque clause est sous vote permanent, modifiable à tout moment', status: 'ready' },
|
||||
{ label: 'Inertie de remplacement', icon: 'i-lucide-sliders-horizontal', description: 'Régler la difficulté de modification par section (standard, haute, très haute)', to: '/protocols/formulas', status: 'ready' },
|
||||
{ label: 'Contre-propositions', icon: 'i-lucide-pen-line', description: 'Soumettre un texte alternatif soumis au vote de la communauté', status: 'ready' },
|
||||
{ label: 'Ancrage IPFS', icon: 'i-lucide-hard-drive', description: 'Archiver les documents validés sur IPFS avec preuve on-chain', status: 'soon' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'decisions',
|
||||
title: 'Decisions',
|
||||
title: 'Décisions',
|
||||
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' },
|
||||
{ label: 'Vote quadratique', icon: 'i-lucide-square-stack', description: 'Pondération dégressive pour éviter la concentration de pouvoir', status: 'soon' },
|
||||
{ label: 'Vote nuancé 6 niveaux', icon: 'i-lucide-bar-chart-3', description: 'De Tout à fait contre à Tout à fait pour, avec seuil de satisfaction', status: 'ready' },
|
||||
{ label: 'Mandature', icon: 'i-lucide-user-check', description: 'Élection et nomination en binôme avec transparence', status: 'ready' },
|
||||
{ label: 'Multi-critères', icon: 'i-lucide-layers', description: 'Combinaison WoT + Smith + TechComm, tous doivent passer', to: '/protocols/formulas', status: 'ready' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -53,10 +53,10 @@ const sections: ToolSection[] = [
|
||||
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' },
|
||||
{ label: 'Ouverture', icon: 'i-lucide-door-open', description: 'Définir une mission, son périmètre, sa durée et ses objectifs', status: 'ready' },
|
||||
{ label: 'Nomination', icon: 'i-lucide-users', description: 'Élection en binôme : un titulaire + un suppléant', status: 'ready' },
|
||||
{ label: 'Transparence', icon: 'i-lucide-eye', description: 'Rapports d\'activité périodiques soumis au vote', status: 'ready' },
|
||||
{ label: 'Clôture', icon: 'i-lucide-lock', description: 'Fin de mandat avec bilan ou révocation anticipée par vote', status: 'ready' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -65,10 +65,10 @@ const sections: ToolSection[] = [
|
||||
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: 'Simulateur de formules', icon: 'i-lucide-calculator', description: 'Tester les paramètres de seuil WoT en temps réel', to: '/protocols/formulas', status: 'ready' },
|
||||
{ label: 'Méta-gouvernance', icon: 'i-lucide-shield', description: 'Les formules elles-mêmes 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' },
|
||||
{ label: 'Protocoles opérationnels', icon: 'i-lucide-git-branch', description: 'Processus multi-étapes réutilisables (embarquement, upgrade)', to: '/protocols', status: 'ready' },
|
||||
],
|
||||
},
|
||||
]
|
||||
@@ -83,7 +83,7 @@ const sections: ToolSection[] = [
|
||||
variant="ghost"
|
||||
color="neutral"
|
||||
icon="i-lucide-arrow-left"
|
||||
label="Retour a l'accueil"
|
||||
label="Retour à l'accueil"
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
@@ -92,10 +92,10 @@ const sections: ToolSection[] = [
|
||||
<div class="tools-page__header">
|
||||
<h1 class="tools-page__title">
|
||||
<UIcon name="i-lucide-wrench" class="tools-page__title-icon" />
|
||||
Boite a outils
|
||||
Boîte à outils
|
||||
</h1>
|
||||
<p class="tools-page__subtitle">
|
||||
Tous les outils de decision collective, organises par section
|
||||
Tous les outils de décision collective, organisés par section
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -143,7 +143,7 @@ const sections: ToolSection[] = [
|
||||
<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>
|
||||
<span v-if="tool.status === 'soon'" class="tool-card__badge">bientôt</span>
|
||||
</div>
|
||||
<p class="tool-card__desc">{{ tool.description }}</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user