v2 : les 14 écrans — le tour complet de la démocratie d'exercice
- Aujourd'hui (Fil 13 sections + capture sticky) + Le chemin (tunnel 2 gestes, Q0 inline, 3 chips, dérogation asymétrique, alternatives réglage/consignation) - Registre + fiche décision (timeline, périmètre premier/second lieu auditable, affluence non-ignorable, S'instruire condensé, éléments + cartographie de clôture, épreuve du réel, Remettre en question, PV A4, gravure) - Salle de vote 5 modalités (consentement, nuancé+histogramme, binaire hérité avec jauge inertielle, Réglage collectif complet — faisceau, médiane basse, Pour moi, Explorer, cristallisation-geste —, élection à départage humain) - Textes (Pacte en clair, document vivant, diff, vue projetée, Atelier des formules porté du v1 sur le moteur unique) + Mandats (faits comptés, feux de la rampe, wizard 3 étapes) + Observatoire (consigner→observer→protocoliser) - Onboarding 7 gabarits + Données locales (export/import, attributs, atelier) - voting→framing gardé (Reformuler d'un réglage figé non cristallisé) - Pages v1 supprimées (login, documents, mandates, protocols, sanctuary, tools, decisions/new) — 342 tests verts, build zéro erreur Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
<script setup lang="ts">
|
||||
// <!-- ld-v2 --> Carte d'un document de la bibliothèque : titre, rôle,
|
||||
// nombre de clauses, mini-jauges des sessions en cours sur ses clauses,
|
||||
// provenance résumée (version, vote d'origine), badge 井 si gravures.
|
||||
import type { TextDoc } from '~/types/domain'
|
||||
import { PACT_BADGE } from '~/lexicon'
|
||||
import type { ClauseSessionGauge } from './textsModel'
|
||||
import { formatInt } from './textsModel'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
doc: TextDoc
|
||||
clauseCount: number
|
||||
gauges?: ClauseSessionGauge[]
|
||||
engraved?: number
|
||||
/** Carte épinglée du Pacte — mise en avant. */
|
||||
pinned?: boolean
|
||||
}>(), { gauges: () => [], engraved: 0, pinned: false })
|
||||
|
||||
const roleLabel = computed(() => (props.doc.role === 'pact' ? PACT_BADGE : 'document de référence'))
|
||||
|
||||
const version = computed(() =>
|
||||
props.doc.provenance?.sources.find(s => s.version)?.version)
|
||||
|
||||
const voteSummary = computed(() => {
|
||||
const r = props.doc.provenance?.voteRecord?.result
|
||||
if (!r) return null
|
||||
return `${formatInt(r.for)} pour · ${formatInt(r.against)} contre — toile de ${formatInt(r.wotSize)}`
|
||||
})
|
||||
|
||||
const visibleGauges = computed(() => props.gauges.slice(0, 3))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- ld-v2 -->
|
||||
<NuxtLink
|
||||
:to="`/textes/${doc.slug}`"
|
||||
class="doc-card ld-card ld-card--hover"
|
||||
:class="{ 'doc-card--pinned': pinned }"
|
||||
>
|
||||
<header class="doc-card__head">
|
||||
<span class="doc-card__role" :class="{ 'doc-card__role--pact': doc.role === 'pact' }">
|
||||
<UIcon :name="doc.role === 'pact' ? 'i-lucide-scroll' : 'i-lucide-book-open'" />
|
||||
{{ roleLabel }}
|
||||
</span>
|
||||
<span v-if="engraved > 0" class="doc-card__engraved" title="Décisions gravées sur ce texte">
|
||||
井 {{ engraved }}
|
||||
</span>
|
||||
</header>
|
||||
|
||||
<h3 class="doc-card__title">{{ doc.title }}</h3>
|
||||
<p class="doc-card__desc">{{ doc.description }}</p>
|
||||
|
||||
<div class="doc-card__meta">
|
||||
<span class="doc-card__chip">
|
||||
<UIcon name="i-lucide-list" />
|
||||
{{ clauseCount }} clause{{ clauseCount > 1 ? 's' : '' }}
|
||||
</span>
|
||||
<span v-if="version" class="doc-card__chip doc-card__chip--mono">v{{ version }}</span>
|
||||
<span v-if="voteSummary" class="doc-card__chip doc-card__chip--vote">
|
||||
<UIcon name="i-lucide-vote" />
|
||||
{{ voteSummary }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="visibleGauges.length" class="doc-card__sessions">
|
||||
<p class="doc-card__sessions-heading">
|
||||
{{ gauges.length > 1 ? `${gauges.length} sessions en cours` : 'Une session en cours' }}
|
||||
</p>
|
||||
<div class="doc-card__gauges">
|
||||
<SessionMiniGauge
|
||||
v-for="gauge in visibleGauges"
|
||||
:key="gauge.decisionId"
|
||||
:gauge="gauge"
|
||||
@click.stop
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.doc-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.6rem;
|
||||
padding: clamp(1rem, 3vw, 1.35rem);
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
.doc-card--pinned {
|
||||
background:
|
||||
linear-gradient(140deg, var(--mood-accent-soft), transparent 55%),
|
||||
var(--mood-surface);
|
||||
}
|
||||
|
||||
.doc-card__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.doc-card__role {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
padding: 3px 10px;
|
||||
border-radius: var(--r-pill);
|
||||
background: color-mix(in srgb, var(--mood-text) 7%, transparent);
|
||||
color: var(--mood-text-muted);
|
||||
}
|
||||
.doc-card__role--pact { background: var(--mood-accent-soft); color: var(--mood-accent); }
|
||||
.doc-card__engraved {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 800;
|
||||
color: var(--mood-status-vigueur);
|
||||
}
|
||||
|
||||
.doc-card__title {
|
||||
font-size: clamp(1rem, 2.5vw, 1.15rem);
|
||||
font-weight: 800;
|
||||
color: var(--mood-text);
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 1.25;
|
||||
}
|
||||
.doc-card__desc {
|
||||
font-size: 0.8125rem;
|
||||
color: var(--mood-text-muted);
|
||||
line-height: 1.55;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.doc-card__meta { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.15rem; }
|
||||
.doc-card__chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
font-size: 0.71875rem;
|
||||
font-weight: 700;
|
||||
padding: 3px 9px;
|
||||
border-radius: var(--r-pill);
|
||||
background: color-mix(in srgb, var(--mood-text) 6%, transparent);
|
||||
color: var(--mood-text-muted);
|
||||
}
|
||||
.doc-card__chip--mono { font-family: monospace; }
|
||||
.doc-card__chip--vote {
|
||||
background: var(--mood-status-vigueur-bg);
|
||||
color: var(--mood-status-vigueur);
|
||||
}
|
||||
|
||||
.doc-card__sessions {
|
||||
margin-top: 0.35rem;
|
||||
padding-top: 0.6rem;
|
||||
box-shadow: 0 -1px 0 color-mix(in srgb, var(--mood-text) 7%, transparent);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
.doc-card__sessions-heading {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
color: var(--mood-status-vote);
|
||||
}
|
||||
.doc-card__gauges { display: flex; flex-direction: column; gap: 0.3rem; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user