Générateur de portfolios PDF Figures Libres (app Nuxt autonome)
App Nuxt 3 + Nuxt UI qui lit les projets du CMS Grav et compose des portfolios A3 paysage exportés en PDF (gabarit book_v3) : composeur WYSIWYG, templates cover/toc/projet/grille/page libre, pipeline Playwright + Ghostscript, gel du contenu à la génération, partage public opt-in. Dépôt autonome : Dockerfile (base Playwright + Ghostscript + ffmpeg + rsync) inclus. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
// Route de rendu print : toutes les pages du portfolio empilées, imprimées
|
||||
// par Playwright/Chromium (une page CSS = une page PDF, spec §10).
|
||||
// Accès par jeton interne uniquement (?internal-token=…).
|
||||
import type { Portfolio, Project } from '~~/types'
|
||||
|
||||
definePageMeta({ layout: false })
|
||||
|
||||
const route = useRoute()
|
||||
const token = String(route.query['internal-token'] ?? '')
|
||||
const headers = { 'x-internal-token': token }
|
||||
|
||||
const { data: portfolio } = await useFetch<Portfolio>(`/api/portfolios/${route.params.id}`, { headers })
|
||||
if (!portfolio.value) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Portfolio introuvable' })
|
||||
}
|
||||
|
||||
// Contenu figé si présent (régénération à l'identique), live sinon
|
||||
const frozen = portfolio.value.frozenContent
|
||||
let projects: Record<string, Project>
|
||||
if (frozen) {
|
||||
projects = frozen.projects
|
||||
} else {
|
||||
const { data } = await useFetch<{ projects: Project[] }>('/api/projects', { headers })
|
||||
projects = Object.fromEntries((data.value?.projects ?? []).map(p => [p.id, p]))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="print-root">
|
||||
<div v-for="(page, i) in portfolio!.pages" :id="`page-${i + 1}`" :key="page.id" class="print-page">
|
||||
<PageRenderer
|
||||
:portfolio="portfolio!"
|
||||
:page="page"
|
||||
:index="i"
|
||||
:projects="projects"
|
||||
render-mode="print"
|
||||
:frozen="frozen ? portfolio!.id : undefined"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
/* Une page CSS = une page PDF — A3 paysage du gabarit :
|
||||
1190,55 × 841,89 pt ≡ 1587,4 × 1122,5 px */
|
||||
@page {
|
||||
size: 1190.55pt 841.89pt;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.print-page {
|
||||
width: 1587.4px;
|
||||
height: 1122.5px;
|
||||
overflow: hidden;
|
||||
page-break-after: always;
|
||||
break-after: page;
|
||||
}
|
||||
|
||||
.print-page:last-child {
|
||||
page-break-after: auto;
|
||||
break-after: auto;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user