- Champ Présentation prérempli avec le texte Grav, suivi modifié/synchro (textOverride undefined = suit Grav, sinon figé ; bouton Réinitialiser) - Fix génération PDF : savePortfolio écrit en atomique (temp+rename) pour éviter la corruption de lecture par l'autosave concurrent du rendu print - Toast d'échec de génération explicite (message serveur) - Refonte architecture visuelle, fond unifié white/tint/full, dispositions couverture bandeau/colonne, instantané public complet, index 3 lignes
80 lines
3.7 KiB
Vue
80 lines
3.7 KiB
Vue
<script setup lang="ts">
|
|
// Couverture du portfolio — reprend l'accueil du site figureslibres.cc
|
|
// (docs/portfolios-examples/screenshot-site-figures-libres.png) : la phrase
|
|
// d'intro seule, bloc centré à 65 % de large, chaque keyword dans sa fonte
|
|
// (sans soulignement, contrairement au site), flèche vers le bas. Rien d'autre.
|
|
import type { Background } from '~~/types'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
title: string // titre du portfolio — en-tête + métadonnées PDF
|
|
subtitle?: string
|
|
recipient?: string
|
|
background: Background
|
|
bandColor?: string // filet couleur en bas (définit aussi celui du sommaire)
|
|
date?: string // texte libre de l'en-tête (ex. « Juillet 2026 »)
|
|
siteUrl?: string
|
|
contactEmail?: string
|
|
renderMode?: 'preview' | 'print'
|
|
}>(),
|
|
{ renderMode: 'preview' },
|
|
)
|
|
|
|
const strip = computed(() => props.bandColor || FL_INK)
|
|
|
|
// Fond : « Plein » = couleur du filet ; « Blanc » rend le gris charte du site
|
|
// (l'intro y est présentée sur gris clair) ; « Teinté » = aplat beige.
|
|
const pageStyle = computed(() => {
|
|
const base
|
|
= props.background.mode === 'full'
|
|
? strip.value
|
|
: props.background.mode === 'tint'
|
|
? TINT_COLOR
|
|
: FL_BASE
|
|
return { backgroundColor: base, color: inkOn(base) }
|
|
})
|
|
|
|
// En-tête : coordonnées en liens actifs (le PDF et l'aperçu partagent le
|
|
// template ; Chromium convertit les <a href> en liens cliquables du PDF).
|
|
const siteHref = computed(() => props.siteUrl?.trim() || DEFAULT_SITE_URL)
|
|
const siteLabel = computed(() => siteHref.value.replace(/^https?:\/\//, '').replace(/\/$/, ''))
|
|
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())
|
|
</script>
|
|
|
|
<template>
|
|
<div class="fl-page" :style="pageStyle">
|
|
<!-- En-tête : titre du portfolio + date, site et mail (liens actifs PDF/viewer) -->
|
|
<header
|
|
class="absolute inset-x-0 top-0 flex items-start justify-between gap-8"
|
|
:style="{ padding: 'var(--fl-margin)', fontFamily: 'Syne, sans-serif' }"
|
|
>
|
|
<div class="max-w-[60%]">
|
|
<h1 :style="{ fontSize: '30px', lineHeight: '1.2' }">{{ title }}</h1>
|
|
<p class="opacity-70" :style="{ fontSize: '19px', lineHeight: '1.5' }">{{ displayDate }}</p>
|
|
</div>
|
|
<div class="flex shrink-0 flex-col items-end" :style="{ fontSize: '19px', lineHeight: '1.5' }">
|
|
<a :href="siteHref" target="_blank" rel="noopener" class="text-current no-underline">{{ siteLabel }}</a>
|
|
<a :href="`mailto:${email}`" class="text-current no-underline">{{ email }}</a>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="absolute inset-0 flex flex-col items-center justify-center">
|
|
<!-- Phrase d'intro du site (pages/01.home) — Lato, keywords dans les
|
|
fontes d'« utilité » du thème Grav, non soulignés -->
|
|
<p class="w-[65%]" :style="{ fontFamily: 'Lato, sans-serif', fontSize: '54px', lineHeight: '1.35' }">
|
|
<span class="font-bold" style="font-family: 'Syne', sans-serif">Figures Libres</span>
|
|
est un collectif de design graphique et interactif porteur de messages d'utilité
|
|
<span class="fl-font-publique">publique</span>,
|
|
<span class="fl-font-sociale">sociale</span> et
|
|
<span class="fl-font-culturelle">culturelle</span>
|
|
qui œuvre sur logiciels libres.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- 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>
|
|
</template>
|