fix: corrections lecteur PDF + couverture + navigation chapitres
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

- PDF viewer : suppression animation/lock isAnimating, navigation stable
- PDF reader : focus iframe au chargement → flèches actives immédiatement
- BookSection : couverture via background-image (right center) — fiable
- AxisBlock : boutons secondaires NuxtLink/button explicites (v-if/v-else)
- modele-eco/[slug] : scroll top au changement de chapitre (SPA reuse)
- router.options.ts : scrollBehavior global top/instant
- PDF mis à jour (numéros de pages chapitres 7–11)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-04-05 05:12:37 +02:00
parent f6339400fa
commit dcf64cc924
7 changed files with 56 additions and 109 deletions

View File

@@ -1,13 +1,12 @@
<template>
<Teleport to="body">
<Transition name="pdf-overlay">
<div
v-if="isOpen"
class="pdf-reader"
@keydown.escape="close"
tabindex="0"
ref="overlayRef"
>
<div
v-if="isOpen"
class="pdf-reader"
@keydown.escape="close"
tabindex="0"
ref="overlayRef"
>
<!-- Top bar -->
<div class="pdf-bar">
<div class="pdf-bar-title">
@@ -26,10 +25,11 @@
:src="pdfUrl"
class="pdf-frame"
:title="bpContent?.pdf.iframeTitle"
ref="iframeRef"
@load="iframeRef?.focus()"
/>
</div>
</div>
</Transition>
</div>
</Teleport>
</template>
@@ -42,6 +42,7 @@ const bookData = useBookData()
await bookData.init()
const overlayRef = ref<HTMLElement>()
const iframeRef = ref<HTMLIFrameElement>()
const isOpen = computed({
get: () => props.modelValue,
@@ -138,15 +139,4 @@ onUnmounted(() => {
background: white;
}
/* Overlay transitions */
.pdf-overlay-enter-active {
animation: pdf-enter 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.pdf-overlay-leave-active {
animation: pdf-enter 0.3s cubic-bezier(0.7, 0, 0.84, 0) reverse both;
}
@keyframes pdf-enter {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
</style>

View File

@@ -72,17 +72,25 @@
</div>
<!-- Secondary row -->
<div v-if="secondaryActions(item.actions).length" class="axis-actions-secondary">
<component
:is="action.to ? resolveComponent('NuxtLink') : 'button'"
v-for="action in secondaryActions(item.actions)"
:key="action.label"
:to="action.to"
class="axis-action-btn axis-action-btn--secondary"
@click.stop="!action.to && handleAction(action.id)"
>
<div :class="iconClass(action.icon)" class="h-3.5 w-3.5" />
{{ action.label }}
</component>
<template v-for="action in secondaryActions(item.actions)" :key="action.label">
<NuxtLink
v-if="action.to"
:to="action.to"
class="axis-action-btn axis-action-btn--secondary"
@click.stop
>
<div :class="iconClass(action.icon)" class="h-3.5 w-3.5" />
{{ action.label }}
</NuxtLink>
<button
v-else
class="axis-action-btn axis-action-btn--secondary"
@click.stop="handleAction(action.id)"
>
<div :class="iconClass(action.icon)" class="h-3.5 w-3.5" />
{{ action.label }}
</button>
</template>
</div>
</div>
</div>

View File

@@ -5,13 +5,12 @@
<!-- Book cover -->
<UiScrollReveal>
<div class="book-cover-wrapper relative">
<div :class="['book-cover-3d', compact && 'book-cover-3d--compact']">
<img
:src="content?.book.coverImage"
:alt="content?.book.coverAlt"
class="book-cover-img"
/>
</div>
<div
:class="['book-cover-3d', compact && 'book-cover-3d--compact']"
:style="{ backgroundImage: `url(${content?.book.coverImage})` }"
role="img"
:aria-label="content?.book.coverAlt"
/>
</div>
</UiScrollReveal>
@@ -88,7 +87,12 @@ const titleLine2 = computed(() => titleParts.value[1])
}
.book-cover-3d {
width: 100%;
max-width: 360px;
aspect-ratio: 3 / 4;
background-size: 200% auto;
background-position: right center;
background-repeat: no-repeat;
border-radius: 0.75rem;
overflow: hidden;
border: 1px solid hsl(var(--color-text) / 0.1);
@@ -97,7 +101,6 @@ const titleLine2 = computed(() => titleParts.value[1])
0 0 0 1px hsl(var(--color-text) / 0.08);
transition: transform 0.5s cubic-bezier(0.645, 0.045, 0.355, 1),
box-shadow 0.5s ease;
max-width: 360px;
}
.book-cover-3d--compact {
@@ -111,12 +114,6 @@ const titleLine2 = computed(() => titleParts.value[1])
0 0 0 1px hsl(var(--color-primary) / 0.2);
}
.book-cover-img {
width: 200%;
height: 100%;
object-fit: cover;
transform: translateX(-50%);
}
.book-heading {
font-size: clamp(1.625rem, 4vw, 2.125rem);

View File

@@ -43,6 +43,11 @@ definePageMeta({
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()

9
app/router.options.ts Normal file
View File

@@ -0,0 +1,9 @@
import type { RouterConfig } from '@nuxt/schema'
export default <RouterConfig>{
scrollBehavior(to, _from, savedPosition) {
if (savedPosition) return savedPosition
if (to.hash) return { el: to.hash, behavior: 'smooth' }
return { top: 0, behavior: 'instant' }
},
}