feat: SEO complet + analytics Umami + og:image § logo
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
SEO : - composable useSeoPage() : og:*, Twitter Cards, canonical sur toutes les pages (15 pages) - app.vue : JSON-LD Organization + Book, og:image global og-default.png - og-default.png 1200×630 : logo § calligraphique + texte (Pillow) - nuxt.config.ts : @nuxtjs/sitemap avec 26 URLs statiques Analytics Umami : - useTracking() : helpers typés audio/pdf/player/scroll/cta - useScrollTracking() : scroll depth 25/50/75/100% + liens externes auto - useAudioPlayer : trackAudioPlay/Progress/Complete - BookPdfReader : trackPdfOpen/Close avec durée - BookPlayer : trackPlayerOpen/Chapter/Mode - docker-compose : variables NUXT_PUBLIC_UMAMI_* passées au container Images : - Couv-Economie-du-don.jpg ajoutée dans public/images/ - bookplayer.config.yml + home.yml : références mises à jour Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -40,8 +40,9 @@ definePageMeta({
|
||||
layout: 'default',
|
||||
})
|
||||
|
||||
useHead({
|
||||
title: 'À propos',
|
||||
useSeoPage({
|
||||
title: 'À propos — Le Librodrome',
|
||||
description: 'Le Librodrome : l\'histoire du projet, la démarche et les personnes derrière le livre et les outils d\'autonomie.',
|
||||
})
|
||||
|
||||
const { data: page } = await useAsyncData('about', () =>
|
||||
|
||||
@@ -153,7 +153,10 @@ const currentIdx = computed(() => politiqueItems.value.findIndex(i => i.to === c
|
||||
const prevItem = computed(() => currentIdx.value > 0 ? politiqueItems.value[currentIdx.value - 1] : null)
|
||||
const nextItem = computed(() => currentIdx.value < politiqueItems.value.length - 1 ? politiqueItems.value[currentIdx.value + 1] : null)
|
||||
|
||||
useHead({ title: content.value?.meta?.title ?? slug })
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? slug,
|
||||
description: content.value?.description as string ?? undefined,
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -409,8 +409,9 @@ const appConfig = useAppConfig()
|
||||
const decisionUrl = (appConfig.libredecision as { url: string })?.url ?? '#'
|
||||
const sejeteral0Url = (appConfig.sejeteral0 as { url: string })?.url ?? '#'
|
||||
|
||||
useHead({
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'Autonomie citoyenne',
|
||||
description: (content.value as Record<string, unknown> | null)?.description as string ?? 'Décision collective, gouvernance locale, outils citoyens — l\'autonomie politique à l\'échelle des bassins de vie.',
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -304,8 +304,10 @@
|
||||
<script setup lang="ts">
|
||||
const { data: content } = await usePageContent('economique/commande')
|
||||
|
||||
useHead({
|
||||
title: content.value?.meta?.title ?? 'Commander le livre',
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'Commander le livre — Une économie du don',
|
||||
description: 'Commander l\'édition papier du livre « Une économie du don — enfin concevable » d\'Yvv.',
|
||||
image: '/images/Couv-Economie-du-don.jpg',
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -452,8 +452,9 @@ definePageMeta({
|
||||
|
||||
const { data: content } = await usePageContent('economique')
|
||||
|
||||
useHead({
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'Autonomie économique',
|
||||
description: (content.value as Record<string, unknown> | null)?.description as string ?? 'Comprendre et expérimenter une économie fondée sur le don, la monnaie libre et la réciprocité.',
|
||||
})
|
||||
|
||||
const showBookPlayer = ref(false)
|
||||
|
||||
@@ -59,8 +59,11 @@ if (!chapter.value) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Chapitre non trouvé' })
|
||||
}
|
||||
|
||||
useHead({
|
||||
title: chapter.value?.title,
|
||||
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
|
||||
|
||||
@@ -424,8 +424,11 @@ definePageMeta({
|
||||
|
||||
const { data: content } = await usePageContent('economique/modele-eco')
|
||||
|
||||
useHead({
|
||||
title: content.value?.meta?.title ?? 'Table des matières',
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'Une économie du don — Table des matières',
|
||||
description: 'Onze chapitres pour explorer les fondements d\'une économie fondée sur le don, la mesure et la monnaie libre.',
|
||||
image: '/images/Couv-Economie-du-don.jpg',
|
||||
type: 'book',
|
||||
})
|
||||
|
||||
const { data: chapters } = await useAsyncData('book-toc', () =>
|
||||
|
||||
@@ -120,7 +120,10 @@ const currentIdx = computed(() => economieItems.value.findIndex(i => i.to === cu
|
||||
const prevItem = computed(() => currentIdx.value > 0 ? economieItems.value[currentIdx.value - 1] : null)
|
||||
const nextItem = computed(() => currentIdx.value < economieItems.value.length - 1 ? economieItems.value[currentIdx.value + 1] : null)
|
||||
|
||||
useHead({ title: content.value?.meta?.title ?? 'Monnaie libre' })
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'Monnaie libre — Autonomie économique',
|
||||
description: content.value?.description as string ?? 'La monnaie libre (June / G1) : comprendre la théorie relative de la monnaie et expérimenter une monnaie équitable.',
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -44,8 +44,9 @@
|
||||
<script setup lang="ts">
|
||||
const { data: content } = await usePageContent('economique/productions-collectives')
|
||||
|
||||
useHead({
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'Productions collectives',
|
||||
description: content.value?.description as string ?? 'Initiatives et productions collectives dans le cadre de l\'économie du don.',
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -166,8 +166,10 @@ definePageMeta({
|
||||
const { data: content } = await usePageContent('en-musique')
|
||||
const { data: homeContent } = await usePageContent('home')
|
||||
|
||||
useHead({
|
||||
title: content.value?.meta?.title ?? 'En musique',
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'En musique — Le Librodrome',
|
||||
description: 'Neuf chansons qui racontent le livre « Une économie du don ». Écoute libre, paroles et présentation musicale guidée.',
|
||||
image: '/images/Couv-Economie-du-don.jpg',
|
||||
})
|
||||
|
||||
const store = usePlayerStore()
|
||||
|
||||
@@ -440,8 +440,9 @@ definePageMeta({
|
||||
const { data: content } = await usePageContent('evenement')
|
||||
const evtContent = computed(() => content.value as Record<string, any> | null)
|
||||
|
||||
useHead({
|
||||
title: evtContent.value?.meta?.title ?? 'Évènement',
|
||||
useSeoPage({
|
||||
title: evtContent.value?.meta?.title ?? 'Évènement — Le Librodrome',
|
||||
description: evtContent.value?.description as string ?? 'Prochains événements du Librodrome : rencontres, lectures et ateliers autour de l\'économie du don.',
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -104,8 +104,9 @@
|
||||
<script setup lang="ts">
|
||||
const { data: content } = await usePageContent('gratewizard')
|
||||
|
||||
useHead({
|
||||
title: content.value?.meta?.title ?? 'grateWizard \u2014 Coefficients relatifs',
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'grateWizard — Coefficients relatifs',
|
||||
description: 'Calculateur de coefficients relatifs pour l\'économie du don et la monnaie libre (DU/June).',
|
||||
})
|
||||
|
||||
const { url, launch } = useGrateWizard()
|
||||
|
||||
+3
-2
@@ -9,8 +9,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
useHead({
|
||||
title: 'Accueil',
|
||||
useSeoPage({
|
||||
title: 'Le Librodrome — autonomie numérique, économique, citoyenne',
|
||||
description: 'Construire une autonomie collective à l\'échelle des bassins de vie. Un livre, des chansons et des outils pour l\'émancipation.',
|
||||
})
|
||||
|
||||
const showBookPlayer = ref(false)
|
||||
|
||||
@@ -41,8 +41,9 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
useHead({
|
||||
title: 'Messages',
|
||||
useSeoPage({
|
||||
title: 'Messages — Le Librodrome',
|
||||
description: 'Questions, retours et réactions des lecteurs et visiteurs du Librodrome.',
|
||||
})
|
||||
|
||||
const { data: messages } = await useFetch('/api/messages')
|
||||
|
||||
@@ -647,8 +647,9 @@ const currentIdx = computed(() => sectionItems.value.findIndex(i => i.to === cur
|
||||
const prevItem = computed(() => currentIdx.value > 0 ? sectionItems.value[currentIdx.value - 1] : null)
|
||||
const nextItem = computed(() => currentIdx.value < sectionItems.value.length - 1 ? sectionItems.value[currentIdx.value + 1] : null)
|
||||
|
||||
useHead({
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? slug,
|
||||
description: content.value?.description as string ?? undefined,
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -380,8 +380,9 @@ definePageMeta({
|
||||
|
||||
const { data: content } = await usePageContent('numerique')
|
||||
|
||||
useHead({
|
||||
useSeoPage({
|
||||
title: content.value?.meta?.title ?? 'Autonomie numérique',
|
||||
description: (content.value as Record<string, unknown> | null)?.description as string ?? 'Logiciel libre, authentification Web of Trust, cloud souverain — reprendre le contrôle de ses outils numériques.',
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user