Second avis du studio DA (03/11, 07h56) et relecture de fb8c71f (08h14) :
- numérique : le zigzag gauche-droite à pas égal est cassé. Électricien en M,
codeuse et cryptographe au bas de leur carte, à droite, administrateur réseau
en grand derrière Cloud libre ;
- commande : un seul côté par carte. Cycliste à gauche de la première, libraire
en grand derrière la seconde ; la lectrice se tient sur le sac de l'icône.
Le cartonnier va sur la ligne qui clôt chaque chapitre, l'empileur sur le
sommaire du livre : les 61 restent rendus ;
- au moins deux tailles dès trois oiseaux (chapitre, en-musique, événement) ;
- un oiseau de marge a les pieds sur une vraie ligne, le bas ou le haut de son
bloc ou d'une carte, jamais à mi-hauteur (« posés sans flotter ») ;
- aucun oiseau sur le haut invisible de la boîte d'un titre : dj, trapéziste,
alchimiste et droneuse se tiennent sur la dernière ligne ou au bout de
l'intitulé ;
- téléphone : le pompeur de Ğ1 au bout de la ligne de l'intitulé ;
- sous-pages numériques : poses, tailles et décalages variés malgré le sommaire
à droite ; le comédien de tarifs-eau perché sur sa carte, hors du sommaire.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
95 lines
3.0 KiB
Vue
95 lines
3.0 KiB
Vue
<template>
|
|
<div v-if="chapter" class="relative">
|
|
<!-- The book's trades in the margins: the two who write keep their way, on the left -->
|
|
<UiOiseauPose nom="calligraphe" pose="libre" right="calc(100% + 40px)" top="40px" :w="112" />
|
|
<UiOiseauPose nom="typographe" pose="libre" right="calc(100% + 64px)" top="46%" :w="100" />
|
|
<UiOiseauPose nom="correcteur" pose="libre" left="calc(100% + 40px)" bottom="140px" :w="108" retourne />
|
|
<BookChapterHeader
|
|
:title="chapter.title"
|
|
:description="chapter.description"
|
|
:order="chapter.order"
|
|
:reading-time="chapter.readingTime"
|
|
:chapter-slug="slug"
|
|
/>
|
|
|
|
<BookChapterContent :content="chapter" />
|
|
|
|
<!-- Prev / Next navigation -->
|
|
<nav class="relative mt-16 flex items-center justify-between border-t border-white/8 pt-8">
|
|
<UiOiseauPose nom="cartonnier" pose="perche" left="calc(50% - 38px)" :w="76" />
|
|
<NuxtLink
|
|
v-if="prevChapter"
|
|
:to="`/economique/modele-eco/${prevChapter.stem?.split('/').pop()}`"
|
|
class="btn-ghost gap-2"
|
|
>
|
|
<div class="i-lucide-arrow-left h-4 w-4" />
|
|
<span class="text-sm">{{ prevChapter.title }}</span>
|
|
</NuxtLink>
|
|
<div v-else />
|
|
|
|
<NuxtLink
|
|
v-if="nextChapter"
|
|
:to="`/economique/modele-eco/${nextChapter.stem?.split('/').pop()}`"
|
|
class="btn-ghost gap-2"
|
|
>
|
|
<span class="text-sm">{{ nextChapter.title }}</span>
|
|
<div class="i-lucide-arrow-right h-4 w-4" />
|
|
</NuxtLink>
|
|
<div v-else />
|
|
</nav>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
definePageMeta({
|
|
layout: 'reading',
|
|
})
|
|
|
|
const route = useRoute()
|
|
const slug = route.params.slug as string
|
|
|
|
// Scroll to top when navigating between chapters (component reused by Vue Router)
|
|
watch(() => slug, () => {
|
|
if (import.meta.client) window.scrollTo({ top: 0, behavior: 'instant' })
|
|
})
|
|
|
|
// Initialize guided mode
|
|
useGuidedMode()
|
|
|
|
const { data: chapter } = await useAsyncData(`chapter-${slug}`, () =>
|
|
queryCollection('book').path(`/book/${slug}`).first(),
|
|
)
|
|
|
|
if (!chapter.value) {
|
|
throw createError({ statusCode: 404, statusMessage: 'Chapitre non trouvé' })
|
|
}
|
|
|
|
useSeoPage({
|
|
title: chapter.value?.title ?? slug,
|
|
description: chapter.value?.description as string ?? `Chapitre « ${chapter.value?.title} » — Une économie du don, enfin concevable.`,
|
|
image: '/images/Couv-Economie-du-don.jpg',
|
|
type: 'article',
|
|
})
|
|
|
|
// Get adjacent chapters for navigation
|
|
const { data: allChapters } = await useAsyncData('book-nav', () =>
|
|
queryCollection('book').order('order', 'ASC').all(),
|
|
)
|
|
|
|
const currentIndex = computed(() =>
|
|
allChapters.value?.findIndex(c => c.stem?.split('/').pop() === slug) ?? -1,
|
|
)
|
|
|
|
const prevChapter = computed(() => {
|
|
const idx = currentIndex.value
|
|
if (idx <= 0 || !allChapters.value) return null
|
|
return allChapters.value[idx - 1]
|
|
})
|
|
|
|
const nextChapter = computed(() => {
|
|
const idx = currentIndex.value
|
|
if (!allChapters.value || idx >= allChapters.value.length - 1) return null
|
|
return allChapters.value[idx + 1]
|
|
})
|
|
</script>
|