Français soigné, labels signalétiques, formule N1.1 visuelle, F1.2 lisible

- Accents français partout (seed + composants Vue)
- Labels discrets: Engagements, Préambule, Application, Variables
- N1.1: présentation visuelle des niveaux d'inertie avec formule
- F1.2: paramètres + lecture du curseur d'inertie
- MarkdownRenderer: espacement resserré, support code inline
- Toutes descriptions et meta en bon français

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-03-02 09:29:50 +01:00
parent 0b230483d9
commit 21ceae4866
8 changed files with 372 additions and 298 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,9 @@ const renderedHtml = computed(() => {
// Convert *italic* to <em>
html = html.replace(/\*(.+?)\*/g, '<em>$1</em>')
// Convert `code` to <code>
html = html.replace(/`([^`]+)`/g, '<code class="md-code">$1</code>')
// Process lines for list items
const lines = html.split('\n')
const result: string[] = []
@@ -34,7 +37,7 @@ const renderedHtml = computed(() => {
if (trimmed.startsWith('- ')) {
if (!inList) {
result.push('<ul class="list-disc list-inside space-y-1 my-2">')
result.push('<ul class="md-list">')
inList = true
}
result.push(`<li>${trimmed.slice(2)}</li>`)
@@ -46,7 +49,7 @@ const renderedHtml = computed(() => {
if (trimmed === '') {
result.push('<br>')
} else {
result.push(`<p class="my-1">${line}</p>`)
result.push(`<p class="md-para">${line}</p>`)
}
}
}
@@ -61,7 +64,49 @@ const renderedHtml = computed(() => {
<template>
<div
class="prose prose-sm dark:prose-invert max-w-none text-gray-700 dark:text-gray-300 leading-relaxed"
class="md-rendered"
v-html="renderedHtml"
/>
</template>
<style scoped>
.md-rendered {
color: var(--mood-text);
line-height: 1.65;
}
.md-rendered :deep(.md-list) {
list-style-type: disc;
padding-left: 1.25em;
margin: 0.25em 0;
}
.md-rendered :deep(.md-list li) {
padding: 0.05em 0;
line-height: 1.5;
}
.md-rendered :deep(.md-para) {
margin: 0.2em 0;
}
.md-rendered :deep(.md-code) {
font-family: monospace;
font-size: 0.875em;
padding: 0.1em 0.35em;
border-radius: 4px;
background: color-mix(in srgb, var(--mood-accent) 8%, var(--mood-bg));
color: var(--mood-text);
}
.md-rendered :deep(strong) {
font-weight: 700;
color: var(--mood-text);
}
.md-rendered :deep(em) {
font-style: italic;
color: var(--mood-text-muted);
font-size: 0.875em;
}
</style>

View File

@@ -9,27 +9,27 @@ const steps = [
{
icon: 'i-lucide-infinity',
title: 'Vote permanent',
text: 'Chaque engagement est sous vote permanent. A tout moment, vous pouvez proposer une alternative ou voter pour/contre le texte en vigueur.',
text: 'Chaque engagement est sous vote permanent. À tout moment, vous pouvez proposer une alternative ou voter pour/contre le texte en vigueur.',
},
{
icon: 'i-lucide-sliders-horizontal',
title: 'Inertie variable',
text: 'Les engagements fondamentaux ont une inertie standard (difficulte de remplacement moderee). Les annexes sont plus faciles a modifier. La formule et ses reglages sont tres proteges.',
text: 'Les engagements fondamentaux ont une inertie standard (difficulté de remplacement modérée). Les annexes sont plus faciles à modifier. La formule et ses réglages sont très protégés.',
},
{
icon: 'i-lucide-scale',
title: 'Seuil adaptatif',
text: 'La formule WoT adapte le seuil a la participation : peu de votants = quasi-unanimite requise ; beaucoup de votants = majorite simple suffit.',
text: 'La formule WoT adapte le seuil à la participation : peu de votants = quasi-unanimité requise ; beaucoup de votants = majorité simple suffit.',
},
{
icon: 'i-lucide-pen-line',
title: 'Contre-propositions',
text: 'Cliquez sur "Proposer une alternative" pour soumettre un texte de remplacement. Il sera soumis au vote et devra atteindre le seuil d\'adoption pour remplacer le texte en vigueur.',
text: 'Cliquez sur « Proposer une alternative » pour soumettre un texte de remplacement. Il sera soumis au vote et devra atteindre le seuil d\'adoption pour remplacer le texte en vigueur.',
},
{
icon: 'i-lucide-git-branch',
title: 'Depot automatique',
text: 'Quand une alternative est adoptee, le document officiel est mis a jour, ancre sur IPFS et on-chain, puis deploye dans les applications (Cesium, Gecko).',
title: 'Dépôt automatique',
text: 'Quand une alternative est adoptée, le document officiel est mis à jour, ancré sur IPFS et on-chain, puis déployé dans les applications (Cesium, Gecko).',
},
]
</script>
@@ -37,7 +37,7 @@ const steps = [
<template>
<div>
<UButton
label="Comment ca marche ?"
label="Comment ça marche ?"
icon="i-lucide-circle-help"
variant="ghost"
color="neutral"
@@ -50,7 +50,7 @@ const steps = [
<div class="p-6">
<div class="flex items-center justify-between mb-5">
<h2 class="text-lg font-bold" style="color: var(--mood-text)">
Comment ca marche ?
Comment ça marche ?
</h2>
<UButton
icon="i-lucide-x"
@@ -83,7 +83,7 @@ const steps = [
<div class="mt-5 pt-4 border-t" style="border-color: color-mix(in srgb, var(--mood-text) 8%, transparent)">
<p class="text-xs text-center" style="color: var(--mood-text-muted)">
Reference : formule g1vote
Référence : formule g1vote
<a
href="https://g1vote-view-237903.pages.duniter.org/"
target="_blank"

View File

@@ -38,9 +38,9 @@ const itemTypeIcon = computed(() => {
const itemTypeLabel = computed(() => {
switch (props.item.item_type) {
case 'clause': return 'Engagement'
case 'rule': return 'Regle'
case 'verification': return 'Verification'
case 'preamble': return 'Preambule'
case 'rule': return 'Variables'
case 'verification': return 'Application'
case 'preamble': return 'Préambule'
case 'section': return 'Titre'
default: return props.item.item_type
}
@@ -105,9 +105,9 @@ function navigateToItem() {
<span v-if="item.title" class="engagement-card__title">
{{ item.title }}
</span>
<UBadge variant="subtle" color="neutral" size="xs" class="shrink-0">
<span class="engagement-card__type-label">
{{ itemTypeLabel }}
</UBadge>
</span>
</div>
</div>
@@ -243,6 +243,16 @@ function navigateToItem() {
text-overflow: ellipsis;
}
.engagement-card__type-label {
font-size: 0.5625rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--mood-text-muted);
opacity: 0.6;
flex-shrink: 0;
}
.engagement-card__body {
padding: 0.75rem 1rem 1rem;
cursor: pointer;

View File

@@ -61,9 +61,9 @@ const statusColor = (status: string) => {
const statusLabel = (status: string) => {
switch (status) {
case 'rejected': return 'Rejetee'
case 'rejected': return 'Rejetée'
case 'in_progress': return 'En cours'
case 'reference': return 'Reference'
case 'reference': return 'Référence'
default: return status
}
}
@@ -82,10 +82,10 @@ const statusLabel = (status: string) => {
</div>
<div class="text-left">
<h3 class="text-sm font-bold uppercase tracking-wide" style="color: var(--mood-accent)">
Bloc de genese
Bloc de genèse
</h3>
<p class="text-xs" style="color: var(--mood-text-muted)">
Sources, references et formule de depot
Sources, références et formule de dépôt
</p>
</div>
</div>
@@ -134,7 +134,7 @@ const statusLabel = (status: string) => {
class="genesis-link"
>
<UIcon name="i-lucide-git-branch" class="text-xs" />
Depot git
Dépôt git
</a>
</div>
</div>
@@ -146,7 +146,7 @@ const statusLabel = (status: string) => {
<button class="genesis-section__toggle" @click="toggleSection('tools')">
<h4 class="genesis-section__title">
<UIcon name="i-lucide-wrench" />
Outils de reference
Outils de référence
</h4>
<UIcon
:name="sectionOpen.tools ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
@@ -178,7 +178,7 @@ const statusLabel = (status: string) => {
<button class="genesis-section__toggle" @click="toggleSection('forum')">
<h4 class="genesis-section__title">
<UIcon name="i-lucide-messages-square" />
Synthese des discussions
Synthèse des discussions
</h4>
<UIcon
:name="sectionOpen.forum ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
@@ -222,7 +222,7 @@ const statusLabel = (status: string) => {
<button class="genesis-section__toggle" @click="toggleSection('process')">
<h4 class="genesis-section__title">
<UIcon name="i-lucide-zap" />
Processus de depot
Processus de dépôt
</h4>
<UIcon
:name="sectionOpen.process ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"

View File

@@ -27,7 +27,7 @@ const LEVELS: Record<string, InertiaLevel> = {
majority: 50,
color: '#22c55e',
position: 10,
description: 'Majorite simple suffit, meme a faible participation',
description: 'Majorité simple suffit, même à faible participation',
},
standard: {
label: 'Inertie pour le remplacement',
@@ -35,7 +35,7 @@ const LEVELS: Record<string, InertiaLevel> = {
majority: 50,
color: '#3b82f6',
position: 37,
description: 'Equilibre : consensus croissant avec la participation',
description: 'Équilibre : consensus croissant avec la participation',
},
high: {
label: 'Remplacement difficile',
@@ -43,15 +43,15 @@ const LEVELS: Record<string, InertiaLevel> = {
majority: 60,
color: '#f59e0b',
position: 63,
description: 'Forte mobilisation et super-majorite requises',
description: 'Forte mobilisation et super-majorité requises',
},
very_high: {
label: 'Remplacement tres difficile',
label: 'Remplacement très difficile',
gradient: 0.6,
majority: 66,
color: '#ef4444',
position: 90,
description: 'Quasi-unanimite requise a toute participation',
description: 'Quasi-unanimité requise à toute participation',
},
}
@@ -205,9 +205,9 @@ const allCurves = computed(() => {
<code class="inertia__formula-code">Seuil = M + (1-M) × (1 - (T/W)<sup>G</sup>)</code>
</div>
<div class="inertia__formula-legend">
<span><strong>T</strong> = votes exprimes</span>
<span><strong>T</strong> = votes exprimés</span>
<span><strong>W</strong> = taille WoT</span>
<span><strong>M</strong> = majorite cible</span>
<span><strong>M</strong> = majorité cible</span>
<span><strong>G</strong> = gradient d'inertie</span>
</div>
</div>

View File

@@ -100,7 +100,7 @@ function formatDate(d: string): string {
:variant="isPassing ? 'solid' : 'subtle'"
size="xs"
>
{{ isPassing ? 'Adopte' : 'En attente' }}
{{ isPassing ? 'Adopté' : 'En attente' }}
</UBadge>
</div>
</div>

View File

@@ -48,7 +48,7 @@ const SECTION_META: Record<string, { label: string; icon: string }> = {
conclusion: { label: 'Conclusion', icon: 'i-lucide-bookmark' },
annexe: { label: 'Annexes', icon: 'i-lucide-paperclip' },
formule: { label: 'Formule de vote', icon: 'i-lucide-calculator' },
inertie: { label: 'Reglage de l\'inertie', icon: 'i-lucide-sliders-horizontal' },
inertie: { label: 'Réglage de l\'inertie', icon: 'i-lucide-sliders-horizontal' },
ordonnancement: { label: 'Ordonnancement', icon: 'i-lucide-list-ordered' },
}
@@ -106,7 +106,7 @@ const typeLabel = (docType: 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
}
@@ -231,11 +231,11 @@ function scrollToSection(tag: string) {
<div class="doc-page__meta">
<div class="doc-page__meta-grid">
<div>
<p class="doc-page__meta-label">Cree le</p>
<p class="doc-page__meta-label">Créé le</p>
<p class="doc-page__meta-value">{{ formatDate(documents.current.created_at) }}</p>
</div>
<div>
<p class="doc-page__meta-label">Mis a jour le</p>
<p class="doc-page__meta-label">Mis à jour le</p>
<p class="doc-page__meta-value">{{ formatDate(documents.current.updated_at) }}</p>
</div>
<div>