- Reseed avec tous les accents français corrigés (à, é, è, ê, î, ô) - Labels type-étiquette: taille augmentée, fond accent léger, visible Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
304 lines
7.3 KiB
Vue
304 lines
7.3 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* EngagementCard — Enhanced item card with inline mini vote board,
|
|
* inertia indicator, and action buttons.
|
|
*
|
|
* Replaces the basic ItemCard for the document detail view.
|
|
*/
|
|
import type { DocumentItem } from '~/stores/documents'
|
|
|
|
const props = withDefaults(defineProps<{
|
|
item: DocumentItem
|
|
documentSlug: string
|
|
showActions?: boolean
|
|
showVoteBoard?: boolean
|
|
}>(), {
|
|
showActions: false,
|
|
showVoteBoard: true,
|
|
})
|
|
|
|
const emit = defineEmits<{
|
|
propose: [item: DocumentItem]
|
|
}>()
|
|
|
|
const isSection = computed(() => props.item.item_type === 'section')
|
|
const isPreamble = computed(() => props.item.item_type === 'preamble')
|
|
|
|
const itemTypeIcon = computed(() => {
|
|
switch (props.item.item_type) {
|
|
case 'clause': return 'i-lucide-shield-check'
|
|
case 'rule': return 'i-lucide-scale'
|
|
case 'verification': return 'i-lucide-check-circle'
|
|
case 'preamble': return 'i-lucide-scroll-text'
|
|
case 'section': return 'i-lucide-layout-list'
|
|
default: return 'i-lucide-file-text'
|
|
}
|
|
})
|
|
|
|
const itemTypeLabel = computed(() => {
|
|
switch (props.item.item_type) {
|
|
case 'clause': return 'Engagement'
|
|
case 'rule': return 'Variables'
|
|
case 'verification': return 'Application'
|
|
case 'preamble': return 'Préambule'
|
|
case 'section': return 'Titre'
|
|
default: return props.item.item_type
|
|
}
|
|
})
|
|
|
|
// Mock vote data varies by item for demo — items in "bonnes pratiques" (E8-E11) get lower/mixed votes
|
|
const mockVotes = computed(() => {
|
|
const order = props.item.sort_order
|
|
const pos = props.item.position
|
|
|
|
// Conseils et bonnes pratiques: varied votes, some non-adopted
|
|
if (pos === 'E8') return { votesFor: 4, votesAgainst: 3 } // contested
|
|
if (pos === 'E9') return { votesFor: 2, votesAgainst: 5 } // rejected
|
|
if (pos === 'E10') return { votesFor: 6, votesAgainst: 2 } // borderline
|
|
if (pos === 'E11') return { votesFor: 3, votesAgainst: 4 } // rejected
|
|
|
|
// Default: well-adopted items
|
|
const base = ((order * 7 + 13) % 5) + 8 // 8-12
|
|
const against = (order % 3) // 0-2
|
|
return { votesFor: base, votesAgainst: against }
|
|
})
|
|
|
|
function navigateToItem() {
|
|
navigateTo(`/documents/${props.documentSlug}/items/${props.item.id}`)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<!-- Section header (visual separator, not a card) -->
|
|
<div v-if="isSection" class="engagement-section">
|
|
<div class="engagement-section__line" />
|
|
<div class="engagement-section__content">
|
|
<h3 class="engagement-section__title">
|
|
{{ item.title }}
|
|
</h3>
|
|
<p class="engagement-section__text">
|
|
{{ item.current_text }}
|
|
</p>
|
|
<InertiaSlider
|
|
:preset="item.inertia_preset"
|
|
compact
|
|
class="mt-2 max-w-xs"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Regular item card -->
|
|
<div
|
|
v-else
|
|
class="engagement-card"
|
|
:class="{
|
|
'engagement-card--preamble': isPreamble,
|
|
}"
|
|
>
|
|
<!-- Card header -->
|
|
<div class="engagement-card__header" @click="navigateToItem">
|
|
<div class="flex items-center gap-2.5 min-w-0">
|
|
<div class="engagement-card__position">
|
|
{{ item.position }}
|
|
</div>
|
|
<UIcon :name="itemTypeIcon" class="text-sm shrink-0" style="color: var(--mood-accent)" />
|
|
<span v-if="item.title" class="engagement-card__title">
|
|
{{ item.title }}
|
|
</span>
|
|
<span class="engagement-card__type-label">
|
|
{{ itemTypeLabel }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Item text -->
|
|
<div class="engagement-card__body" @click="navigateToItem">
|
|
<MarkdownRenderer :content="item.current_text" />
|
|
</div>
|
|
|
|
<!-- Mini vote board -->
|
|
<div v-if="showVoteBoard" class="engagement-card__vote">
|
|
<MiniVoteBoard
|
|
:votes-for="mockVotes.votesFor"
|
|
:votes-against="mockVotes.votesAgainst"
|
|
:wot-size="7224"
|
|
:is-permanent="item.is_permanent_vote"
|
|
:inertia-preset="item.inertia_preset"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Inertia indicator -->
|
|
<div class="engagement-card__inertia">
|
|
<InertiaSlider
|
|
:preset="item.inertia_preset"
|
|
compact
|
|
/>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div v-if="showActions" class="engagement-card__actions">
|
|
<UButton
|
|
label="Proposer une alternative"
|
|
icon="i-lucide-pen-line"
|
|
variant="soft"
|
|
color="primary"
|
|
size="xs"
|
|
@click.stop="emit('propose', item)"
|
|
/>
|
|
<UButton
|
|
label="Voter"
|
|
icon="i-lucide-vote"
|
|
variant="soft"
|
|
color="success"
|
|
size="xs"
|
|
@click.stop="navigateToItem"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
/* Section separator */
|
|
.engagement-section {
|
|
display: flex;
|
|
gap: 1rem;
|
|
padding: 1.5rem 0 0.5rem;
|
|
}
|
|
|
|
.engagement-section__line {
|
|
width: 4px;
|
|
background: var(--mood-accent);
|
|
border-radius: 2px;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.engagement-section__content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
.engagement-section__title {
|
|
font-size: 1.125rem;
|
|
font-weight: 800;
|
|
color: var(--mood-text);
|
|
letter-spacing: -0.01em;
|
|
}
|
|
|
|
.engagement-section__text {
|
|
font-size: 0.8125rem;
|
|
color: var(--mood-text-muted);
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* Card */
|
|
.engagement-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: var(--mood-surface);
|
|
border-radius: 14px;
|
|
overflow: hidden;
|
|
transition: box-shadow 0.15s, transform 0.15s;
|
|
}
|
|
|
|
.engagement-card:hover {
|
|
box-shadow: 0 2px 12px color-mix(in srgb, var(--mood-accent) 12%, transparent);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.engagement-card--preamble {
|
|
border-left: 4px solid color-mix(in srgb, var(--mood-accent) 40%, transparent);
|
|
}
|
|
|
|
.engagement-card__header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 0.875rem 1rem 0;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.engagement-card__position {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-width: 2rem;
|
|
height: 1.625rem;
|
|
padding: 0 0.5rem;
|
|
border-radius: 8px;
|
|
background: var(--mood-accent);
|
|
color: white;
|
|
font-size: 0.6875rem;
|
|
font-weight: 800;
|
|
letter-spacing: 0.02em;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.engagement-card__title {
|
|
font-size: 0.875rem;
|
|
font-weight: 700;
|
|
color: var(--mood-text);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.engagement-card__type-label {
|
|
font-size: 0.625rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: var(--mood-accent);
|
|
opacity: 0.5;
|
|
flex-shrink: 0;
|
|
padding: 0.125rem 0.375rem;
|
|
border-radius: 4px;
|
|
background: color-mix(in srgb, var(--mood-accent) 8%, transparent);
|
|
}
|
|
|
|
.engagement-card__body {
|
|
padding: 0.75rem 1rem 1rem;
|
|
cursor: pointer;
|
|
font-size: 0.9375rem;
|
|
line-height: 1.7;
|
|
color: var(--mood-text);
|
|
}
|
|
|
|
@media (min-width: 640px) {
|
|
.engagement-card__body {
|
|
font-size: 1rem;
|
|
line-height: 1.75;
|
|
}
|
|
}
|
|
|
|
.engagement-card__vote {
|
|
padding: 0 1rem;
|
|
opacity: 0.7;
|
|
transform: scale(0.92);
|
|
transform-origin: left center;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
.engagement-card:hover .engagement-card__vote {
|
|
opacity: 1;
|
|
}
|
|
|
|
.engagement-card__inertia {
|
|
padding: 0.375rem 1rem;
|
|
opacity: 0.6;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
.engagement-card:hover .engagement-card__inertia {
|
|
opacity: 1;
|
|
}
|
|
|
|
.engagement-card__actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.625rem 1rem;
|
|
border-top: 1px solid color-mix(in srgb, var(--mood-text) 6%, transparent);
|
|
}
|
|
</style>
|