BookPlayer affiche les paroles du morceau, plus le contenu chapitre
Le BookPlayer chargeait les .md via Nuxt Content — qui contenaient avant
les paroles par erreur. Maintenant que les .md ont le vrai contenu du
livre, le BookPlayer doit afficher les lyrics depuis bookplayer.config.yml.
Supprime queryCollection('book') du BookPlayer, remplace ContentRenderer
par un rendu HTML des paroles avec tags stylisés.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -87,7 +87,13 @@
|
|||||||
ref="contentEl"
|
ref="contentEl"
|
||||||
:style="contentStyle"
|
:style="contentStyle"
|
||||||
>
|
>
|
||||||
<ContentRenderer v-if="activeChapter" :value="activeChapter" />
|
<div v-if="chapterLyrics" class="lyrics-content" v-html="chapterLyricsHtml" />
|
||||||
|
<div v-else-if="chapterSong" class="lyrics-empty">
|
||||||
|
<p class="op-40 italic">Paroles à venir pour « {{ chapterSong.title }} »</p>
|
||||||
|
</div>
|
||||||
|
<div v-else class="lyrics-empty">
|
||||||
|
<p class="op-40 italic">Aucun morceau associé à ce chapitre</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Page turn shadow overlay (paginated only) -->
|
<!-- Page turn shadow overlay (paginated only) -->
|
||||||
<div v-if="!isScrollMode" class="reader-shadow" :class="{ visible: isTurning }" />
|
<div v-if="!isScrollMode" class="reader-shadow" :class="{ visible: isTurning }" />
|
||||||
@@ -194,26 +200,13 @@ const { init: initBookData, getSongs, getPrimarySong, getChapterForSong, getPlay
|
|||||||
const audioPlayer = useAudioPlayer()
|
const audioPlayer = useAudioPlayer()
|
||||||
const playerStore = usePlayerStore()
|
const playerStore = usePlayerStore()
|
||||||
|
|
||||||
// ── Content from Nuxt Content ──
|
// ── Content loaded flag (lyrics come from bookplayer config) ──
|
||||||
const chaptersContent = ref<any[]>([])
|
|
||||||
const contentLoaded = ref(false)
|
const contentLoaded = ref(false)
|
||||||
|
|
||||||
async function loadContent() {
|
async function loadContent() {
|
||||||
if (contentLoaded.value) return
|
if (contentLoaded.value) return
|
||||||
try {
|
|
||||||
const data = await queryCollection('book').order('order', 'ASC').all()
|
|
||||||
chaptersContent.value = data
|
|
||||||
contentLoaded.value = true
|
contentLoaded.value = true
|
||||||
}
|
}
|
||||||
catch (err) {
|
|
||||||
console.error('Failed to load book content:', err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeChapter = computed(() => {
|
|
||||||
if (chapterIdx.value < 0 || !chaptersContent.value.length) return null
|
|
||||||
return chaptersContent.value[chapterIdx.value] ?? null
|
|
||||||
})
|
|
||||||
|
|
||||||
// ── Chapter metadata ──
|
// ── Chapter metadata ──
|
||||||
const chapters = [
|
const chapters = [
|
||||||
@@ -256,6 +249,23 @@ const chapterSong = computed(() => {
|
|||||||
return getPrimarySong(chapters[chapterIdx.value].slug)
|
return getPrimarySong(chapters[chapterIdx.value].slug)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const chapterLyrics = computed(() => {
|
||||||
|
return chapterSong.value?.lyrics?.trim() || ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const chapterLyricsHtml = computed(() => {
|
||||||
|
if (!chapterLyrics.value) return ''
|
||||||
|
return chapterLyrics.value
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/\[([^\]]+)\]/g, '<span class="lyrics-tag">[$1]</span>')
|
||||||
|
.replace(/\n\n/g, '</p><p>')
|
||||||
|
.replace(/\n/g, '<br>')
|
||||||
|
.replace(/^/, '<p>')
|
||||||
|
.replace(/$/, '</p>')
|
||||||
|
})
|
||||||
|
|
||||||
// ── CSS columns pagination ──
|
// ── CSS columns pagination ──
|
||||||
const contentStyle = computed(() => {
|
const contentStyle = computed(() => {
|
||||||
if (isScrollMode.value) return {}
|
if (isScrollMode.value) return {}
|
||||||
@@ -276,10 +286,9 @@ function recalcPages() {
|
|||||||
|
|
||||||
let resizeObs: ResizeObserver | null = null
|
let resizeObs: ResizeObserver | null = null
|
||||||
|
|
||||||
// Recalc when chapter content changes
|
// Recalc when chapter changes
|
||||||
watch(activeChapter, async () => {
|
watch(chapterIdx, async () => {
|
||||||
currentPage.value = 0
|
currentPage.value = 0
|
||||||
// Wait for ContentRenderer to update DOM
|
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await nextTick()
|
await nextTick()
|
||||||
setTimeout(recalcPages, 100)
|
setTimeout(recalcPages, 100)
|
||||||
@@ -357,7 +366,7 @@ function prevPage() {
|
|||||||
audioPlayer.loadAndPlay(song)
|
audioPlayer.loadAndPlay(song)
|
||||||
}
|
}
|
||||||
// After content loads, go to last page
|
// After content loads, go to last page
|
||||||
watch(activeChapter, async () => {
|
watch(chapterIdx, async () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
await nextTick()
|
await nextTick()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -809,7 +818,33 @@ onUnmounted(() => {
|
|||||||
.reader-columns :deep(ol) {
|
.reader-columns :deep(ol) {
|
||||||
break-inside: avoid;
|
break-inside: avoid;
|
||||||
}
|
}
|
||||||
/* p with pre-line (lyrics) can be taller than a column — allow break */
|
/* Lyrics content */
|
||||||
|
.lyrics-content {
|
||||||
|
white-space: pre-line;
|
||||||
|
line-height: 1.9;
|
||||||
|
font-size: clamp(0.9rem, 2vw, 1.05rem);
|
||||||
|
}
|
||||||
|
.lyrics-content :deep(.lyrics-tag) {
|
||||||
|
display: block;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
opacity: 0.35;
|
||||||
|
}
|
||||||
|
.lyrics-content :deep(p) {
|
||||||
|
break-inside: auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
.lyrics-empty {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
.reader-columns :deep(p) {
|
.reader-columns :deep(p) {
|
||||||
break-inside: auto;
|
break-inside: auto;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|||||||
Reference in New Issue
Block a user