Pages équipe + conclusion, colonnes de page libre, réglages couverture

- Page « équipe » : roster statique du collectif (composables/useTeam),
  portraits servis depuis public/portraits, grille ≤ 3 colonnes équilibrée
  (portrait/nom/rôle/présentation), sélection + surcharges par membre
  (repliables, réordonnables, réinitialisables) dans le composeur
- Page « conclusion » : « Merci ! » centré + rappel des contacts
- Page libre : 1 à 3 colonnes texte (markdown) ou images avec sous-titres,
  réordonnables ; migration des champs body/media legacy vers columns
- Couverture : texte libre sous l'intro, adresse en bas à gauche (3 lignes),
  case « afficher les années » au niveau du document
- Sommaire : items centrés (self-center), filet en points dégradés stable
- Retrait de la dépendance morte pagedjs
- Docs à jour (CLAUDE.md, README) ; spec marquée comme archive réalisée
This commit is contained in:
2026-07-13 16:00:59 +02:00
parent ef1f14335d
commit 1c1604ea2f
29 changed files with 802 additions and 265 deletions

View File

@@ -8,6 +8,7 @@ import type { Background } from '~~/types'
const props = withDefaults(
defineProps<{
title: string // titre du portfolio — en-tête + métadonnées PDF
body?: string // HTML : texte libre sous la phrase d'intro (plus petit, centré avec elle)
subtitle?: string
recipient?: string
background: Background
@@ -15,6 +16,7 @@ const props = withDefaults(
date?: string // texte libre de l'en-tête (ex. « Juillet 2026 »)
siteUrl?: string
contactEmail?: string
address?: string // adresse postale — angle bas-gauche
renderMode?: 'preview' | 'print'
}>(),
{ renderMode: 'preview' },
@@ -41,6 +43,11 @@ const siteLabel = computed(() => siteHref.value.replace(/^https?:\/\//, '').repl
const email = computed(() => props.contactEmail?.trim() || DEFAULT_CONTACT_EMAIL)
// Laissée vide, la date affiche par défaut le mois courant (ex. « Juillet 2026 »).
const displayDate = computed(() => props.date?.trim() || formatMonthYear())
// Adresse coupée aux virgules : une ligne par segment (« Figures Libres » /
// « 55 avenue… » / « 94110 Arcueil »).
const addressLines = computed(() =>
(props.address?.trim() || DEFAULT_ADDRESS).split(',').map(s => s.trim()).filter(Boolean),
)
</script>
<template>
@@ -71,8 +78,26 @@ const displayDate = computed(() => props.date?.trim() || formatMonthYear())
<span class="fl-font-culturelle">culturelle</span>
qui œuvre sur logiciels&nbsp;libres.
</p>
<!-- Texte libre optionnel, plus petit, sous la phrase d'intro -->
<div
v-if="body"
class="fl-prose mt-12 w-[65%]"
:style="{ fontFamily: 'Lato, sans-serif', fontSize: '24px', lineHeight: '1.45' }"
v-html="body"
/>
</div>
<!-- Adresse postale dans l'angle bas-gauche (au-dessus du filet) -->
<p
v-if="addressLines.length"
class="absolute left-0"
:style="{
bottom: background.mode === 'full' ? '0' : 'var(--fl-strip)',
padding: 'var(--fl-margin)',
fontFamily: 'Syne, sans-serif', fontSize: '19px', lineHeight: '1.5',
}"
><span v-for="(line, i) in addressLines" :key="i" class="block">{{ line }}</span></p>
<!-- Filet couleur pleine largeur en bas (masqué en fond plein) -->
<div v-if="background.mode !== 'full'" class="absolute inset-x-0 bottom-0" :style="{ height: 'var(--fl-strip)', backgroundColor: strip }" />
</div>