Backend: - CRUD complet documents/items/versions (update, delete, accept, reject, reorder) - Service IPFS (upload/retrieve/pin via kubo HTTP API) - Service sanctuaire : pipeline SHA-256 + IPFS + on-chain (system.remark) - Verification integrite des entrees sanctuaire - Recherche par reference (document -> entrees sanctuaire) - Serialisation deterministe des documents pour archivage - 14 tests unitaires supplementaires (document service) Frontend: - 9 composants : StatusBadge, MarkdownRenderer, DiffView, ItemCard, ItemVersionDiff, DocumentList, SanctuaryEntry, IPFSLink, ChainAnchor - Page detail item avec historique des versions et diff - Page detail sanctuaire avec verification integrite - Modal de creation de document + proposition de version - Archivage document vers sanctuaire depuis la page detail Documentation: - API reference mise a jour (9 nouveaux endpoints) - Guides utilisateur documents et sanctuaire enrichis Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
90 lines
2.3 KiB
Vue
90 lines
2.3 KiB
Vue
<script setup lang="ts">
|
|
import type { DocumentItem } from '~/stores/documents'
|
|
|
|
const props = withDefaults(defineProps<{
|
|
item: DocumentItem
|
|
documentSlug: string
|
|
showActions?: boolean
|
|
}>(), {
|
|
showActions: false,
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
propose: [item: DocumentItem]
|
|
}>()
|
|
|
|
const itemTypeLabel = (itemType: string): string => {
|
|
switch (itemType) {
|
|
case 'clause': return 'Clause'
|
|
case 'rule': return 'Regle'
|
|
case 'verification': return 'Verification'
|
|
case 'preamble': return 'Preambule'
|
|
case 'section': return 'Section'
|
|
default: return itemType
|
|
}
|
|
}
|
|
|
|
function navigateToItem() {
|
|
navigateTo(`/documents/${props.documentSlug}/items/${props.item.id}`)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<UCard
|
|
class="cursor-pointer hover:ring-2 hover:ring-primary/50 transition-all"
|
|
@click="navigateToItem"
|
|
>
|
|
<div class="space-y-3">
|
|
<!-- Item header -->
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center gap-3">
|
|
<UBadge variant="solid" color="primary" size="xs">
|
|
{{ item.position }}
|
|
</UBadge>
|
|
<span v-if="item.title" class="text-sm font-semibold text-gray-900 dark:text-white">
|
|
{{ item.title }}
|
|
</span>
|
|
<UBadge variant="subtle" color="neutral" size="xs">
|
|
{{ itemTypeLabel(item.item_type) }}
|
|
</UBadge>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<UBadge
|
|
v-if="item.voting_protocol_id"
|
|
color="info"
|
|
variant="subtle"
|
|
size="xs"
|
|
>
|
|
Sous vote
|
|
</UBadge>
|
|
<UBadge
|
|
v-else
|
|
color="neutral"
|
|
variant="subtle"
|
|
size="xs"
|
|
>
|
|
Pas de vote
|
|
</UBadge>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Item text -->
|
|
<div class="pl-2">
|
|
<CommonMarkdownRenderer :content="item.current_text" />
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div v-if="showActions" class="flex justify-end pt-2 border-t border-gray-100 dark:border-gray-800">
|
|
<UButton
|
|
label="Proposer une modification"
|
|
icon="i-lucide-pen-line"
|
|
variant="soft"
|
|
color="primary"
|
|
size="xs"
|
|
@click.stop="emit('propose', item)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
</template>
|