- 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>
419 lines
12 KiB
Vue
419 lines
12 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* Genesis block: displays source documents, repos, forum synthesis, and formula trigger
|
|
* for a reference document. Main block collapsible, each sub-section independently collapsible.
|
|
*/
|
|
const props = defineProps<{
|
|
genesisJson: string
|
|
}>()
|
|
|
|
const expanded = ref(false)
|
|
|
|
// Individual section toggles
|
|
const sectionOpen = reactive<Record<string, boolean>>({
|
|
source: true,
|
|
tools: false,
|
|
forum: true,
|
|
process: false,
|
|
contributors: false,
|
|
})
|
|
|
|
function toggleSection(key: string) {
|
|
sectionOpen[key] = !sectionOpen[key]
|
|
}
|
|
|
|
interface GenesisData {
|
|
source_document: {
|
|
title: string
|
|
url: string
|
|
repo: string
|
|
}
|
|
reference_tools: Record<string, string>
|
|
forum_synthesis: Array<{
|
|
title: string
|
|
url: string
|
|
status: string
|
|
posts?: number
|
|
}>
|
|
formula_trigger: string
|
|
contributors: Array<{
|
|
name: string
|
|
role: string
|
|
}>
|
|
}
|
|
|
|
const genesis = computed((): GenesisData | null => {
|
|
try {
|
|
return JSON.parse(props.genesisJson)
|
|
} catch {
|
|
return null
|
|
}
|
|
})
|
|
|
|
const statusColor = (status: string) => {
|
|
switch (status) {
|
|
case 'rejected': return 'error'
|
|
case 'in_progress': return 'warning'
|
|
case 'reference': return 'info'
|
|
default: return 'neutral'
|
|
}
|
|
}
|
|
|
|
const statusLabel = (status: string) => {
|
|
switch (status) {
|
|
case 'rejected': return 'Rejetée'
|
|
case 'in_progress': return 'En cours'
|
|
case 'reference': return 'Référence'
|
|
default: return status
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div v-if="genesis" class="genesis-block">
|
|
<!-- Header (always visible) -->
|
|
<button
|
|
class="genesis-block__header"
|
|
@click="expanded = !expanded"
|
|
>
|
|
<div class="flex items-center gap-3">
|
|
<div class="genesis-block__icon">
|
|
<UIcon name="i-lucide-file-archive" class="text-lg" />
|
|
</div>
|
|
<div class="text-left">
|
|
<h3 class="text-sm font-bold uppercase tracking-wide" style="color: var(--mood-accent)">
|
|
Bloc de genèse
|
|
</h3>
|
|
<p class="text-xs" style="color: var(--mood-text-muted)">
|
|
Sources, références et formule de dépôt
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<UIcon
|
|
:name="expanded ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
|
|
class="text-lg"
|
|
style="color: var(--mood-text-muted)"
|
|
/>
|
|
</button>
|
|
|
|
<!-- Expandable content -->
|
|
<Transition name="genesis-expand">
|
|
<div v-if="expanded" class="genesis-block__body">
|
|
<!-- Source document -->
|
|
<div class="genesis-section">
|
|
<button class="genesis-section__toggle" @click="toggleSection('source')">
|
|
<h4 class="genesis-section__title">
|
|
<UIcon name="i-lucide-file-text" />
|
|
Document source
|
|
</h4>
|
|
<UIcon
|
|
:name="sectionOpen.source ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
|
|
class="text-sm"
|
|
style="color: var(--mood-text-muted)"
|
|
/>
|
|
</button>
|
|
<div v-if="sectionOpen.source" class="genesis-section__content">
|
|
<div class="genesis-card">
|
|
<p class="font-medium text-sm" style="color: var(--mood-text)">
|
|
{{ genesis.source_document.title }}
|
|
</p>
|
|
<div class="flex flex-col gap-1 mt-2">
|
|
<a
|
|
:href="genesis.source_document.url"
|
|
target="_blank"
|
|
rel="noopener"
|
|
class="genesis-link"
|
|
>
|
|
<UIcon name="i-lucide-external-link" class="text-xs" />
|
|
Texte officiel
|
|
</a>
|
|
<a
|
|
:href="genesis.source_document.repo"
|
|
target="_blank"
|
|
rel="noopener"
|
|
class="genesis-link"
|
|
>
|
|
<UIcon name="i-lucide-git-branch" class="text-xs" />
|
|
Dépôt git
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Reference tools -->
|
|
<div class="genesis-section">
|
|
<button class="genesis-section__toggle" @click="toggleSection('tools')">
|
|
<h4 class="genesis-section__title">
|
|
<UIcon name="i-lucide-wrench" />
|
|
Outils de référence
|
|
</h4>
|
|
<UIcon
|
|
:name="sectionOpen.tools ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
|
|
class="text-sm"
|
|
style="color: var(--mood-text-muted)"
|
|
/>
|
|
</button>
|
|
<div v-if="sectionOpen.tools" class="genesis-section__content">
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<a
|
|
v-for="(url, name) in genesis.reference_tools"
|
|
:key="name"
|
|
:href="url"
|
|
target="_blank"
|
|
rel="noopener"
|
|
class="genesis-card genesis-card--tool"
|
|
>
|
|
<span class="text-xs font-semibold capitalize" style="color: var(--mood-text)">
|
|
{{ name.replace(/_/g, ' ') }}
|
|
</span>
|
|
<UIcon name="i-lucide-external-link" class="text-xs" style="color: var(--mood-text-muted)" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Forum synthesis -->
|
|
<div class="genesis-section">
|
|
<button class="genesis-section__toggle" @click="toggleSection('forum')">
|
|
<h4 class="genesis-section__title">
|
|
<UIcon name="i-lucide-messages-square" />
|
|
Synthèse des discussions
|
|
</h4>
|
|
<UIcon
|
|
:name="sectionOpen.forum ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
|
|
class="text-sm"
|
|
style="color: var(--mood-text-muted)"
|
|
/>
|
|
</button>
|
|
<div v-if="sectionOpen.forum" class="genesis-section__content">
|
|
<div class="flex flex-col gap-2">
|
|
<a
|
|
v-for="topic in genesis.forum_synthesis"
|
|
:key="topic.url"
|
|
:href="topic.url"
|
|
target="_blank"
|
|
rel="noopener"
|
|
class="genesis-card genesis-card--forum"
|
|
>
|
|
<div class="flex items-start justify-between gap-2">
|
|
<span class="text-xs font-medium" style="color: var(--mood-text)">
|
|
{{ topic.title }}
|
|
</span>
|
|
<UBadge
|
|
:color="statusColor(topic.status)"
|
|
variant="subtle"
|
|
size="xs"
|
|
class="shrink-0"
|
|
>
|
|
{{ statusLabel(topic.status) }}
|
|
</UBadge>
|
|
</div>
|
|
<span v-if="topic.posts" class="text-xs" style="color: var(--mood-text-muted)">
|
|
{{ topic.posts }} messages
|
|
</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Formula trigger -->
|
|
<div class="genesis-section">
|
|
<button class="genesis-section__toggle" @click="toggleSection('process')">
|
|
<h4 class="genesis-section__title">
|
|
<UIcon name="i-lucide-zap" />
|
|
Processus de dépôt
|
|
</h4>
|
|
<UIcon
|
|
:name="sectionOpen.process ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
|
|
class="text-sm"
|
|
style="color: var(--mood-text-muted)"
|
|
/>
|
|
</button>
|
|
<div v-if="sectionOpen.process" class="genesis-section__content">
|
|
<div class="genesis-card">
|
|
<p class="text-xs leading-relaxed" style="color: var(--mood-text)">
|
|
{{ genesis.formula_trigger }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Contributors -->
|
|
<div class="genesis-section">
|
|
<button class="genesis-section__toggle" @click="toggleSection('contributors')">
|
|
<h4 class="genesis-section__title">
|
|
<UIcon name="i-lucide-users" />
|
|
Contributeurs
|
|
</h4>
|
|
<UIcon
|
|
:name="sectionOpen.contributors ? 'i-lucide-chevron-up' : 'i-lucide-chevron-down'"
|
|
class="text-sm"
|
|
style="color: var(--mood-text-muted)"
|
|
/>
|
|
</button>
|
|
<div v-if="sectionOpen.contributors" class="genesis-section__content">
|
|
<div class="flex flex-wrap gap-2">
|
|
<div
|
|
v-for="c in genesis.contributors"
|
|
:key="c.name"
|
|
class="genesis-contributor"
|
|
>
|
|
<span class="font-semibold text-xs" style="color: var(--mood-text)">{{ c.name }}</span>
|
|
<span class="text-xs" style="color: var(--mood-text-muted)">{{ c.role }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.genesis-block {
|
|
background: var(--mood-surface);
|
|
border-radius: 16px;
|
|
overflow: hidden;
|
|
border: 1px solid color-mix(in srgb, var(--mood-accent) 15%, transparent);
|
|
}
|
|
|
|
.genesis-block__header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
width: 100%;
|
|
padding: 1rem 1.25rem;
|
|
cursor: pointer;
|
|
background: none;
|
|
transition: background 0.15s;
|
|
}
|
|
|
|
.genesis-block__header:hover {
|
|
background: color-mix(in srgb, var(--mood-accent) 5%, transparent);
|
|
}
|
|
|
|
.genesis-block__icon {
|
|
width: 2.25rem;
|
|
height: 2.25rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 10px;
|
|
background: color-mix(in srgb, var(--mood-accent) 12%, transparent);
|
|
color: var(--mood-accent);
|
|
}
|
|
|
|
.genesis-block__body {
|
|
padding: 0 1.25rem 1.25rem;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.genesis-section {
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
background: color-mix(in srgb, var(--mood-accent) 2%, transparent);
|
|
}
|
|
|
|
.genesis-section__toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
width: 100%;
|
|
padding: 0.5rem 0.75rem;
|
|
cursor: pointer;
|
|
background: none;
|
|
border: none;
|
|
transition: background 0.15s;
|
|
}
|
|
|
|
.genesis-section__toggle:hover {
|
|
background: color-mix(in srgb, var(--mood-accent) 5%, transparent);
|
|
}
|
|
|
|
.genesis-section__title {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
font-size: 0.6875rem;
|
|
font-weight: 700;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
color: var(--mood-accent);
|
|
margin: 0;
|
|
}
|
|
|
|
.genesis-section__content {
|
|
padding: 0 0.75rem 0.75rem;
|
|
}
|
|
|
|
.genesis-card {
|
|
padding: 0.75rem;
|
|
border-radius: 10px;
|
|
background: color-mix(in srgb, var(--mood-accent) 4%, var(--mood-bg));
|
|
}
|
|
|
|
.genesis-card--tool {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
text-decoration: none;
|
|
transition: background 0.15s;
|
|
}
|
|
|
|
.genesis-card--tool:hover {
|
|
background: color-mix(in srgb, var(--mood-accent) 10%, var(--mood-bg));
|
|
}
|
|
|
|
.genesis-card--forum {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.25rem;
|
|
text-decoration: none;
|
|
transition: background 0.15s;
|
|
}
|
|
|
|
.genesis-card--forum:hover {
|
|
background: color-mix(in srgb, var(--mood-accent) 10%, var(--mood-bg));
|
|
}
|
|
|
|
.genesis-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.375rem;
|
|
font-size: 0.75rem;
|
|
color: var(--mood-accent);
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.genesis-link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.genesis-contributor {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 0.5rem 0.75rem;
|
|
border-radius: 8px;
|
|
background: color-mix(in srgb, var(--mood-accent) 4%, var(--mood-bg));
|
|
}
|
|
|
|
/* Expand/collapse transition */
|
|
.genesis-expand-enter-active,
|
|
.genesis-expand-leave-active {
|
|
transition: all 0.25s ease;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.genesis-expand-enter-from,
|
|
.genesis-expand-leave-to {
|
|
opacity: 0;
|
|
max-height: 0;
|
|
padding-top: 0;
|
|
padding-bottom: 0;
|
|
}
|
|
</style>
|