All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Structure par section : /numerique, /economique, /citoyenne (plus de /gestation) - Chaque section a index + sous-pages avec contenu YAML administrable - API content supporte les chemins imbriqués ([...path]) - Admin : liste des pages + éditeur par section - Page /economique : monnaie libre (picto Ğ1), modèle éco, productions collectives, commande livre - Page /citoyenne : decision (CTA Glibredecision), tarifs-eau (CTA SejeteralO) - BookActions : composant partagé (player, PDF, chapitres, commande) sur home, eco et modele-eco - GrateWizard remonté dans la section économique de la home - Palette été par défaut, choix persisté en localStorage - Fix lisibilité été (text-white/65 + variables CSS) - Shadoks thématiques sur toutes les pages (8-10 par page, métiers variés) - Redirections 301 : /gestation/*, /modele-eco/*, /decision, /lire/* - README, CONTRIBUTING, CLAUDE.md mis à jour Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
82 lines
2.1 KiB
Vue
82 lines
2.1 KiB
Vue
<template>
|
|
<div v-if="chapter">
|
|
<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="mt-16 flex items-center justify-between border-t border-white/8 pt-8">
|
|
<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
|
|
|
|
// 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é' })
|
|
}
|
|
|
|
useHead({
|
|
title: chapter.value?.title,
|
|
})
|
|
|
|
// 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>
|