Règle f, selon la précision de DA du 03/11 après 17h35 : au-dessus d'un oiseau perché, le vide
se mesure du haut de son dessin jusqu'à la plus basse ligne de texte ou au plus bas bloc qui
passe au-dessus de sa largeur peinte. Les lignes de son propre titre comptent, et l'en-tête
collant aussi en haut de page. Quinze perchés en défaut sur bb8fad9 changent de pose, sans
sortir de la liste fermée :
- accueil :
- le DJ se tient derrière le pupitre de la console, seule sa tête dépasse ;
- l'accordéoniste passe en S, visible à partir de 1200 px ;
- la factrice passe à 76 px ;
- la lectrice sort 20 px plus bas ;
- au téléphone, l'oiseau de l'intitulé est un oiseau plat : codeuse, maraîchère, potier, et le
cycliste livreur sur productions collectives ;
- authentification, tarifs de l'eau, commande : en marge droite, sur l'arête haute de la carte ;
- en musique : le danseur passe en S ;
- évènement :
- l'acrobate se tient avant la devise ;
- le régisseur passe en S, posé sur l'arête des cartes ;
- le clown passe en M ;
- le marionnettiste se tient sur le filet du pied de page (option 1 d'orch). Son décalage
est tiré de --seal-block, le bloc du sceau défini dans le layout ;
- chapitres : le calligraphe se tient sur le filet du titre, le typographe sur celui de la
navigation, le cartonnier en marge des boutons. Plus aucune hauteur en %.
Règle g, rectangle du bloc (décision d'orch) : le porteur de serveur et l'administrateur réseau
sortent de la découpe des coins arrondis.
La liste fermée (docs/da-oiseaux.md) reçoit les précisions d'orch :
- e vaut pour un oiseau « libre » dont le centre sort de son bloc ;
- g se mesure sur le rectangle du bloc ;
- un oiseau derrière une carte reste « derrière ».
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
99 lines
3.4 KiB
Vue
99 lines
3.4 KiB
Vue
<template>
|
|
<div v-if="chapter" class="relative">
|
|
<!-- The book's trades in the margins, each on a line of the chapter (rule e): the two who
|
|
write keep their way, on the left, the calligrapher on the title's rule (in the chapter
|
|
header), the typographer on the navigation's rule; the box maker in the right margin, by
|
|
the PDF and songs buttons (in the header); the proofreader on the right, by the last
|
|
paragraph -->
|
|
<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. The rule above it is drawn (border-t alone sets no style here):
|
|
the typographer stands on it, in the left margin. Perched in the column, the box maker had
|
|
20 to 27 px of void under the last paragraph (rule f) -->
|
|
<nav class="relative mt-16 flex items-center justify-between border-t border-t-solid border-white/8 pt-8">
|
|
<UiOiseauPose nom="typographe" pose="marge-g" ecart="64px" bottom="100%" :w="100" />
|
|
<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>
|