Fix double-fire player, navigation par morceaux, admin labels morceaux

- BookPlayer : navigation par playlist (9 morceaux) au lieu de 11 chapitres
- stopPropagation clavier → plus de saut 1→3→5
- Sommaire aligné avec titres des morceaux
- Bouton back aligné avec clavier (toujours morceau précédent)
- Admin chapitres : tags morceaux cliquables avec étoile primary
- Admin liste chapitres : badges morceaux associés
- Éditeur markdown en vue split par défaut

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-02-27 14:08:58 +01:00
parent 8803087e77
commit 25bfc07b59
6 changed files with 314 additions and 162 deletions

View File

@@ -20,12 +20,21 @@
<div class="i-lucide-grip-vertical h-4 w-4" />
</div>
<span class="chapter-order">{{ String(i + 1).padStart(2, '0') }}</span>
<NuxtLink
:to="`/admin/book/${chapter.slug}`"
class="chapter-title"
>
{{ chapter.title }}
</NuxtLink>
<div class="chapter-info">
<NuxtLink
:to="`/admin/book/${chapter.slug}`"
class="chapter-title"
>
{{ chapter.title }}
</NuxtLink>
<div v-if="getChapterSongNames(chapter.slug).length" class="chapter-songs">
<span
v-for="name in getChapterSongNames(chapter.slug)"
:key="name"
class="song-badge"
>{{ name }}</span>
</div>
</div>
<button
class="delete-btn"
@click="removeChapter(chapter.slug)"
@@ -64,6 +73,19 @@ definePageMeta({
})
const { data: chapters, refresh } = await useFetch<any[]>('/api/admin/chapters')
const { data: bookConfig } = await useFetch<any>('/api/content/config')
function getChapterSongNames(chapterSlug: string): string[] {
if (!bookConfig.value) return []
const links = (bookConfig.value.chapterSongs ?? []).filter(
(cs: any) => cs.chapterSlug === chapterSlug,
)
return links.map((link: any) => {
const song = bookConfig.value.songs.find((s: any) => s.id === link.songId)
return song?.title ?? link.songId
})
}
const saving = ref(false)
const saved = ref(false)
const newTitle = ref('')
@@ -176,8 +198,13 @@ async function removeChapter(slug: string) {
width: 1.75rem;
}
.chapter-title {
.chapter-info {
flex: 1;
min-width: 0;
}
.chapter-title {
display: block;
color: white;
font-weight: 500;
text-decoration: none;
@@ -187,6 +214,22 @@ async function removeChapter(slug: string) {
color: hsl(12 76% 68%);
}
.chapter-songs {
display: flex;
flex-wrap: wrap;
gap: 0.25rem;
margin-top: 0.25rem;
}
.song-badge {
font-size: 0.65rem;
padding: 0.1rem 0.5rem;
border-radius: 9999px;
background: hsl(12 76% 48% / 0.1);
color: hsl(12 76% 60%);
border: 1px solid hsl(12 76% 48% / 0.2);
}
.delete-btn {
flex-shrink: 0;
padding: 0.375rem;