- Systeme de themes adaptatifs : Peps (light chaud), Zen (light calme), Chagrine (dark violet), Grave (dark ambre) avec CSS custom properties - Dashboard d'accueil orienté onboarding avec cartes-portes et teaser boite a outils - SectionLayout reutilisable : liste + sidebar toolbox + status pills cliquables (En prepa / En vote / En vigueur / Clos) - ToolboxVignette : vignettes Contexte / Tutos / Choisir / Demarrer - Seed : Acte engagement certification + forgeron, Runtime Upgrade (decision on-chain), 3 modalites de vote (majoritaire, quadratique, permanent) - Backend adapte SQLite (Uuid portable, 204 fix, pool conditionnel) - Correction noms composants (pathPrefix: false), pinia/nuxt ^0.11 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
96 lines
2.8 KiB
Vue
96 lines
2.8 KiB
Vue
<script setup lang="ts">
|
|
import type { ItemVersion } from '~/stores/documents'
|
|
|
|
const props = defineProps<{
|
|
version: ItemVersion
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
accept: [versionId: string]
|
|
reject: [versionId: string]
|
|
}>()
|
|
|
|
const auth = useAuthStore()
|
|
|
|
function formatDate(dateStr: string): string {
|
|
return new Date(dateStr).toLocaleDateString('fr-FR', {
|
|
day: 'numeric',
|
|
month: 'long',
|
|
year: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
})
|
|
}
|
|
|
|
function truncateAddress(address: string | null): string {
|
|
if (!address) return 'Inconnu'
|
|
if (address.length <= 16) return address
|
|
return address.slice(0, 8) + '...' + address.slice(-6)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<UCard>
|
|
<div class="space-y-4">
|
|
<!-- Header -->
|
|
<div class="flex items-start justify-between">
|
|
<div class="flex items-center gap-3">
|
|
<StatusBadge :status="version.status" type="version" />
|
|
<span class="text-sm text-gray-500">
|
|
Propose par
|
|
<span class="font-medium text-gray-700 dark:text-gray-300 font-mono text-xs">
|
|
{{ truncateAddress(version.proposed_by) }}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
<span class="text-xs text-gray-400">
|
|
{{ formatDate(version.created_at) }}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Rationale -->
|
|
<div v-if="version.rationale" class="bg-gray-50 dark:bg-gray-800/50 rounded-lg p-3">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase mb-1">Justification</p>
|
|
<p class="text-sm text-gray-700 dark:text-gray-300">{{ version.rationale }}</p>
|
|
</div>
|
|
|
|
<!-- Diff view -->
|
|
<div v-if="version.diff">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase mb-2">Modifications</p>
|
|
<DiffView :diff="version.diff" />
|
|
</div>
|
|
|
|
<!-- Proposed text (fallback if no diff) -->
|
|
<div v-else-if="version.proposed_text">
|
|
<p class="text-xs font-semibold text-gray-500 uppercase mb-2">Texte propose</p>
|
|
<div class="bg-green-50 dark:bg-green-900/10 border border-green-200 dark:border-green-800 rounded-lg p-3">
|
|
<MarkdownRenderer :content="version.proposed_text" />
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions for authenticated users -->
|
|
<div
|
|
v-if="auth.isAuthenticated && version.status === 'proposed'"
|
|
class="flex items-center gap-3 pt-2 border-t border-gray-100 dark:border-gray-800"
|
|
>
|
|
<UButton
|
|
label="Accepter"
|
|
icon="i-lucide-check"
|
|
color="success"
|
|
variant="soft"
|
|
size="xs"
|
|
@click="emit('accept', version.id)"
|
|
/>
|
|
<UButton
|
|
label="Rejeter"
|
|
icon="i-lucide-x"
|
|
color="error"
|
|
variant="soft"
|
|
size="xs"
|
|
@click="emit('reject', version.id)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
</template>
|