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:
@@ -1,3 +1,16 @@
|
||||
# Admin authentication
|
||||
NUXT_ADMIN_PASSWORD=changeme
|
||||
NUXT_ADMIN_SECRET=change-this-to-a-random-secret-at-least-32-chars
|
||||
|
||||
# Umami analytics — instance Docker (docker-compose.umami.yml)
|
||||
# UMAMI_DB_PASSWORD et UMAMI_APP_SECRET : générer avec `openssl rand -hex 32`
|
||||
UMAMI_DB_PASSWORD=
|
||||
UMAMI_APP_SECRET=
|
||||
UMAMI_DOMAIN=stats.librodrome.org
|
||||
|
||||
# Variables injectées dans Nuxt (tracking frontend + API stats)
|
||||
# NUXT_PUBLIC_UMAMI_WEBSITE_ID : Settings → Websites dans l'interface Umami
|
||||
# NUXT_UMAMI_API_KEY : Settings → API Keys dans l'interface Umami
|
||||
NUXT_PUBLIC_UMAMI_URL=https://stats.librodrome.org
|
||||
NUXT_PUBLIC_UMAMI_WEBSITE_ID=
|
||||
NUXT_UMAMI_API_KEY=
|
||||
|
||||
@@ -83,3 +83,49 @@ PORT=3099 node .output/server/index.mjs # Test build prod (toujours avant commi
|
||||
- Shadoks SVG inline thématiques sur chaque page (hidden mobile, opacity 0.18–0.28)
|
||||
- Hexagramme 益 (#42 Yi, Augmentation) dans `layouts/default.vue`
|
||||
- Signature § (logo calligraphique SVG gradient) dans `TheHeader.vue` — ne pas modifier sans demander
|
||||
|
||||
## SEO & Recherche IA — Checklist permanente
|
||||
|
||||
### À chaque nouvelle page Vue
|
||||
|
||||
1. **Appeler `useSeoPage()`** — jamais `useHead({ title })` seul
|
||||
```ts
|
||||
useSeoPage({
|
||||
title: 'Titre page — Le Librodrome', // 50–60 chars
|
||||
description: 'Description...', // 120–155 chars
|
||||
image: '/images/og-specifique.jpg', // optionnel, sinon og-default.png (logo §)
|
||||
type: 'website' | 'article' | 'book', // défaut: website
|
||||
})
|
||||
```
|
||||
2. **og:image** : utiliser la couverture `/images/Couv-Economie-du-don.jpg` pour les pages livre/musique ; `og-default.png` (logo §) pour les pages site générales
|
||||
3. **type: 'article'** pour les chapitres du modele-eco ; **type: 'book'** pour les index livre
|
||||
|
||||
### À chaque nouveau fichier YAML dans `site/pages/`
|
||||
|
||||
Ajouter le bloc `seo:` en tête :
|
||||
```yaml
|
||||
seo:
|
||||
title: "Titre SEO — 50-60 chars max"
|
||||
description: "Description 120-155 chars, avec mots-clés naturels"
|
||||
# image: /images/og-specifique.jpg # optionnel
|
||||
# keywords: [monnaie libre, TRM, économie du don]
|
||||
```
|
||||
|
||||
### Règles description SEO
|
||||
|
||||
- Commence par un verbe d'action ou une affirmation forte
|
||||
- Contient les mots-clés : économie du don, monnaie libre, TRM, June, bassin de vie, autonomie
|
||||
- 120–155 caractères (ni trop court, ni tronqué)
|
||||
- Différente du titre et du H1
|
||||
|
||||
### JSON-LD automatique
|
||||
|
||||
- JSON-LD `Organization` + `Book` : injecté globalement dans `app.vue` — ne pas redupliquer
|
||||
- Chapitres → og:type `article` via `useSeoPage({ type: 'article' })`
|
||||
- Sitemap : géré par `@nuxtjs/sitemap` — ajouter manuellement les nouvelles routes statiques dans `nuxt.config.ts > sitemap.urls`
|
||||
|
||||
### Analytics — Nouveaux composants
|
||||
|
||||
- Tout bouton CTA externe : `trackCta(label, url)` depuis `useTracking()`
|
||||
- Tout `<a target="_blank">` : capturé automatiquement par `useScrollTracking()` dans `default.vue`
|
||||
- Tout nouveau lecteur média : appeler `trackAudioPlay` / `trackPdfOpen` depuis `useTracking()`
|
||||
|
||||
+56
-9
@@ -17,24 +17,71 @@
|
||||
const paletteStore = usePaletteStore()
|
||||
onMounted(() => paletteStore.applyToDOM())
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
const siteUrl = (config.public.siteUrl as string) || 'https://librodrome.org'
|
||||
|
||||
// Umami analytics — inject script only when configured
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
if (runtimeConfig.public.umamiWebsiteId && runtimeConfig.public.umamiUrl) {
|
||||
if (config.public.umamiWebsiteId && config.public.umamiUrl) {
|
||||
useHead({
|
||||
script: [{
|
||||
src: `${runtimeConfig.public.umamiUrl}/script.js`,
|
||||
src: `${config.public.umamiUrl}/script.js`,
|
||||
defer: true,
|
||||
'data-website-id': runtimeConfig.public.umamiWebsiteId,
|
||||
'data-website-id': config.public.umamiWebsiteId,
|
||||
}],
|
||||
})
|
||||
}
|
||||
|
||||
// Global SEO defaults — surchargeables page par page via useSeoPage()
|
||||
useHead({
|
||||
titleTemplate: (title) => {
|
||||
return title ? `${title} — Le Librodrome` : 'Le librodrome'
|
||||
},
|
||||
meta: [
|
||||
{ name: 'description', content: 'Une économie du don — enfin concevable. Un livre et des chansons, lecture guidée et écoute libre.' },
|
||||
titleTemplate: (title) => title ? `${title} — Le Librodrome` : 'Le Librodrome',
|
||||
})
|
||||
|
||||
useSeoMeta({
|
||||
ogSiteName: 'Le Librodrome',
|
||||
ogType: 'website',
|
||||
ogLocale: 'fr_FR',
|
||||
ogImage: `${siteUrl}/og-default.png`,
|
||||
ogImageWidth: 1200,
|
||||
ogImageHeight: 630,
|
||||
twitterCard: 'summary_large_image',
|
||||
twitterSite: '@librodrome',
|
||||
})
|
||||
|
||||
// JSON-LD — Organisation + Livre
|
||||
useHead({
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
innerHTML: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@graph': [
|
||||
{
|
||||
'@type': 'Organization',
|
||||
'@id': `${siteUrl}/#organization`,
|
||||
name: 'Le Librodrome',
|
||||
url: siteUrl,
|
||||
logo: {
|
||||
'@type': 'ImageObject',
|
||||
url: `${siteUrl}/images/og-default.png`,
|
||||
},
|
||||
description: 'Plateforme d\'autonomie numérique, économique et citoyenne à l\'échelle des bassins de vie.',
|
||||
},
|
||||
{
|
||||
'@type': 'Book',
|
||||
'@id': `${siteUrl}/economique/modele-eco#book`,
|
||||
name: 'Une économie du don — enfin concevable',
|
||||
author: { '@type': 'Person', name: 'Yvv' },
|
||||
publisher: { '@id': `${siteUrl}/#organization` },
|
||||
isbn: '979-1-042-45206-3',
|
||||
inLanguage: 'fr',
|
||||
image: `${siteUrl}/images/Couv-Economie-du-don.jpg`,
|
||||
url: `${siteUrl}/economique/modele-eco`,
|
||||
description: 'Un livre et 9 chansons pour explorer les fondements d\'une économie fondée sur le don.',
|
||||
license: 'https://creativecommons.org/licenses/by-nc/4.0/',
|
||||
},
|
||||
],
|
||||
}),
|
||||
},
|
||||
],
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -40,6 +40,7 @@ const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>()
|
||||
const { data: bpContent } = await usePageContent('book-player')
|
||||
const bookData = useBookData()
|
||||
await bookData.init()
|
||||
const { trackPdfOpen, trackPdfClose } = useTracking()
|
||||
|
||||
const overlayRef = ref<HTMLElement>()
|
||||
const iframeRef = ref<HTMLIFrameElement>()
|
||||
@@ -60,9 +61,18 @@ function close() {
|
||||
isOpen.value = false
|
||||
}
|
||||
|
||||
// Tracking state
|
||||
let pdfOpenedAt = 0
|
||||
|
||||
watch(isOpen, (open) => {
|
||||
if (open) {
|
||||
nextTick(() => overlayRef.value?.focus())
|
||||
trackPdfOpen(props.page ? `chapter-p${props.page}` : 'direct')
|
||||
pdfOpenedAt = Date.now()
|
||||
}
|
||||
else if (pdfOpenedAt > 0) {
|
||||
trackPdfClose(0, Date.now() - pdfOpenedAt)
|
||||
pdfOpenedAt = 0
|
||||
}
|
||||
if (import.meta.client) {
|
||||
document.body.style.overflow = open ? 'hidden' : ''
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
<!-- Song disc -->
|
||||
<div v-if="currentSong" class="reader-song">
|
||||
<div class="reader-disc" :class="{ spinning: playerStore.isPlaying }">
|
||||
<img src="/images/book-cover-spread.jpg" alt="" class="reader-disc-img" />
|
||||
<img src="/images/Couv-Economie-du-don.jpg" alt="" class="reader-disc-img" />
|
||||
<div class="reader-disc-hole" />
|
||||
</div>
|
||||
<span class="reader-song-name">{{ currentSong.title }}</span>
|
||||
@@ -138,6 +138,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
const { data: bpContent } = await usePageContent('book-player')
|
||||
const { trackPlayerOpen, trackPlayerChapter, trackPlayerMode } = useTracking()
|
||||
|
||||
const COL_GAP = 80
|
||||
|
||||
@@ -167,6 +168,7 @@ const scrollPercent = ref(0)
|
||||
|
||||
// When switching back to paginated, recalc pages
|
||||
watch(readingMode, async (mode) => {
|
||||
trackPlayerMode(mode === 'scroll' ? 'scroll' : 'guided')
|
||||
if (mode === 'paginated') {
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
@@ -288,6 +290,7 @@ function goToTrack(idx: number) {
|
||||
// Play the song
|
||||
const song = tracks.value[idx]?.song
|
||||
if (song) {
|
||||
trackPlayerChapter(song.id)
|
||||
_skipSongWatch = true
|
||||
audioPlayer.loadAndPlay(song)
|
||||
}
|
||||
@@ -378,6 +381,7 @@ function onTouchEnd(e: TouchEvent) {
|
||||
watch(isOpen, async (open) => {
|
||||
if (open) {
|
||||
showSommaire.value = false
|
||||
trackPlayerOpen()
|
||||
await initBookData()
|
||||
await nextTick()
|
||||
overlayRef.value?.focus()
|
||||
|
||||
@@ -2,9 +2,12 @@ import type { Song } from '~/types/song'
|
||||
|
||||
let audio: HTMLAudioElement | null = null
|
||||
let animationFrameId: number | null = null
|
||||
// Track which milestones have been fired for the current song
|
||||
const firedMilestones = new Set<number>()
|
||||
|
||||
export function useAudioPlayer() {
|
||||
const store = usePlayerStore()
|
||||
const { trackAudioPlay, trackAudioComplete, trackAudioProgress } = useTracking()
|
||||
|
||||
function getAudio(): HTMLAudioElement {
|
||||
if (!audio) {
|
||||
@@ -17,6 +20,10 @@ export function useAudioPlayer() {
|
||||
})
|
||||
|
||||
audio.addEventListener('ended', () => {
|
||||
if (store.currentSong) {
|
||||
trackAudioComplete(store.currentSong.id, store.currentSong.title)
|
||||
}
|
||||
firedMilestones.clear()
|
||||
const next = store.nextSong()
|
||||
if (next) {
|
||||
loadAndPlay(next)
|
||||
@@ -36,6 +43,16 @@ export function useAudioPlayer() {
|
||||
const update = () => {
|
||||
if (audio && !audio.paused) {
|
||||
store.setCurrentTime(audio.currentTime)
|
||||
// Track progress milestones (25 / 50 / 75 %)
|
||||
if (audio.duration > 0 && store.currentSong) {
|
||||
const pct = (audio.currentTime / audio.duration) * 100
|
||||
for (const milestone of [25, 50, 75] as const) {
|
||||
if (pct >= milestone && !firedMilestones.has(milestone)) {
|
||||
firedMilestones.add(milestone)
|
||||
trackAudioProgress(store.currentSong.id, milestone)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
animationFrameId = requestAnimationFrame(update)
|
||||
}
|
||||
@@ -52,6 +69,7 @@ export function useAudioPlayer() {
|
||||
async function loadAndPlay(song: Song) {
|
||||
const el = getAudio()
|
||||
store.setSong(song)
|
||||
firedMilestones.clear()
|
||||
|
||||
// Try OGG first, fall back to MP3
|
||||
const oggPath = song.file.replace(/\.mp3$/, '.ogg')
|
||||
@@ -64,6 +82,7 @@ export function useAudioPlayer() {
|
||||
await el.play()
|
||||
store.play()
|
||||
startTimeUpdate()
|
||||
trackAudioPlay(song.id, song.title)
|
||||
}
|
||||
catch {
|
||||
// If OGG failed, try MP3
|
||||
@@ -73,6 +92,7 @@ export function useAudioPlayer() {
|
||||
await el.play()
|
||||
store.play()
|
||||
startTimeUpdate()
|
||||
trackAudioPlay(song.id, song.title)
|
||||
}
|
||||
catch (err) {
|
||||
console.error('Playback failed:', err)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Tracks scroll depth milestones (25 / 50 / 75 / 100 %) on each page.
|
||||
* Also intercepts external link clicks and tracks them.
|
||||
*
|
||||
* Usage: call once in default.vue layout.
|
||||
*/
|
||||
export function useScrollTracking() {
|
||||
const route = useRoute()
|
||||
const { trackScrollDepth, trackExternalLink } = useTracking()
|
||||
|
||||
// ── Scroll depth ────────────────────────────────────────────────────────
|
||||
const fired = new Set<number>()
|
||||
|
||||
function onScroll() {
|
||||
const el = document.documentElement
|
||||
const scrolled = el.scrollTop + el.clientHeight
|
||||
const total = el.scrollHeight
|
||||
if (total <= el.clientHeight) return
|
||||
const pct = (scrolled / total) * 100
|
||||
|
||||
for (const milestone of [25, 50, 75, 100] as const) {
|
||||
if (pct >= milestone && !fired.has(milestone)) {
|
||||
fired.add(milestone)
|
||||
trackScrollDepth(route.path, milestone)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset fired milestones on route change
|
||||
watch(() => route.path, () => fired.clear())
|
||||
|
||||
// ── External link tracking ───────────────────────────────────────────────
|
||||
function onLinkClick(e: MouseEvent) {
|
||||
const target = (e.target as HTMLElement).closest('a')
|
||||
if (!target) return
|
||||
const href = target.getAttribute('href') || ''
|
||||
if (!href.startsWith('http') && !href.startsWith('//')) return
|
||||
try {
|
||||
const url = new URL(href)
|
||||
if (url.hostname === 'librodrome.org') return
|
||||
trackExternalLink(href, target.textContent?.trim() || '')
|
||||
}
|
||||
catch { /* invalid URL, ignore */ }
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('scroll', onScroll, { passive: true })
|
||||
document.addEventListener('click', onLinkClick)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('scroll', onScroll)
|
||||
document.removeEventListener('click', onLinkClick)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Applique toutes les balises SEO (og:*, Twitter Cards, canonical, description)
|
||||
* à partir du contenu YAML d'une page.
|
||||
*
|
||||
* Usage dans les pages :
|
||||
* useSeoPage({ title: content.value?.meta?.title, description: content.value?.description })
|
||||
*
|
||||
* L'og:image par défaut est /og-default.png (logo §).
|
||||
* Chaque section peut surcharger avec son propre image via le champ seo.image du YAML.
|
||||
*/
|
||||
export function useSeoPage(opts: {
|
||||
title?: string | null
|
||||
description?: string | null
|
||||
image?: string | null
|
||||
type?: 'website' | 'article' | 'book'
|
||||
}) {
|
||||
const config = useRuntimeConfig()
|
||||
const route = useRoute()
|
||||
const siteUrl = (config.public.siteUrl as string) || 'https://librodrome.org'
|
||||
|
||||
const title = opts.title || 'Le Librodrome'
|
||||
const description = opts.description
|
||||
|| 'Autonomie numérique, économique et citoyenne. Un livre et des chansons sur l\'économie du don.'
|
||||
const rawImage = opts.image || '/og-default.png'
|
||||
const image = rawImage.startsWith('http') ? rawImage : `${siteUrl}${rawImage}`
|
||||
const canonical = `${siteUrl}${route.path}`
|
||||
const type = opts.type || 'website'
|
||||
|
||||
useSeoMeta({
|
||||
// Open Graph
|
||||
ogTitle: title,
|
||||
ogDescription: description,
|
||||
ogImage: image,
|
||||
ogImageWidth: 1200,
|
||||
ogImageHeight: 630,
|
||||
ogUrl: canonical,
|
||||
ogType: type,
|
||||
ogSiteName: 'Le Librodrome',
|
||||
ogLocale: 'fr_FR',
|
||||
// Twitter Cards
|
||||
twitterCard: 'summary_large_image',
|
||||
twitterTitle: title,
|
||||
twitterDescription: description,
|
||||
twitterImage: image,
|
||||
// Standard
|
||||
description,
|
||||
})
|
||||
|
||||
useHead({
|
||||
link: [{ rel: 'canonical', href: canonical }],
|
||||
})
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
/**
|
||||
* Umami analytics wrapper — safe server-side, no-op when not configured.
|
||||
* Usage: const { track } = useTracking()
|
||||
* track('player:open')
|
||||
* track('axis:navigate', { axis: 'numerique' })
|
||||
*
|
||||
* Events convention:
|
||||
* audio:play | audio:pause | audio:complete | audio:progress
|
||||
* pdf:open | pdf:close
|
||||
* player:open | player:chapter | player:mode
|
||||
* scroll:depth
|
||||
* link:external
|
||||
* cta:click
|
||||
*/
|
||||
export function useTracking() {
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const enabled = !!runtimeConfig.public.umamiWebsiteId
|
||||
|
||||
// ── Core ────────────────────────────────────────────────────────────────
|
||||
function track(event: string, data?: Record<string, unknown>) {
|
||||
if (!import.meta.client || !enabled) return
|
||||
const umami = (window as Record<string, unknown>).umami as
|
||||
@@ -16,5 +22,75 @@ export function useTracking() {
|
||||
umami?.track(event, data)
|
||||
}
|
||||
|
||||
return { track, enabled }
|
||||
// ── Audio ────────────────────────────────────────────────────────────────
|
||||
function trackAudioPlay(songId: string, songTitle: string, context?: string) {
|
||||
track('audio:play', { song_id: songId, song_title: songTitle, context })
|
||||
}
|
||||
|
||||
function trackAudioPause(songId: string, progressPct: number) {
|
||||
track('audio:pause', { song_id: songId, progress_pct: progressPct })
|
||||
}
|
||||
|
||||
function trackAudioComplete(songId: string, songTitle: string) {
|
||||
track('audio:complete', { song_id: songId, song_title: songTitle })
|
||||
}
|
||||
|
||||
/** Fired at 25 / 50 / 75 % milestones */
|
||||
function trackAudioProgress(songId: string, milestone: 25 | 50 | 75) {
|
||||
track('audio:progress', { song_id: songId, milestone })
|
||||
}
|
||||
|
||||
// ── PDF ──────────────────────────────────────────────────────────────────
|
||||
function trackPdfOpen(trigger?: string) {
|
||||
track('pdf:open', { trigger })
|
||||
}
|
||||
|
||||
function trackPdfClose(pagesVisited: number, durationMs: number) {
|
||||
track('pdf:close', { pages_visited: pagesVisited, duration_ms: durationMs })
|
||||
}
|
||||
|
||||
// ── BookPlayer ───────────────────────────────────────────────────────────
|
||||
function trackPlayerOpen(trigger?: string) {
|
||||
track('player:open', { trigger })
|
||||
}
|
||||
|
||||
function trackPlayerChapter(chapterSlug: string) {
|
||||
track('player:chapter', { chapter_slug: chapterSlug })
|
||||
}
|
||||
|
||||
function trackPlayerMode(mode: 'guided' | 'scroll') {
|
||||
track('player:mode', { mode })
|
||||
}
|
||||
|
||||
// ── Navigation & UX ──────────────────────────────────────────────────────
|
||||
function trackScrollDepth(page: string, depth: 25 | 50 | 75 | 100) {
|
||||
track('scroll:depth', { page, depth })
|
||||
}
|
||||
|
||||
function trackExternalLink(url: string, label?: string) {
|
||||
const route = useRoute()
|
||||
track('link:external', { url, label, from_page: route.path })
|
||||
}
|
||||
|
||||
function trackCta(label: string, target?: string) {
|
||||
const route = useRoute()
|
||||
track('cta:click', { label, target, from_page: route.path })
|
||||
}
|
||||
|
||||
return {
|
||||
track,
|
||||
enabled,
|
||||
trackAudioPlay,
|
||||
trackAudioPause,
|
||||
trackAudioComplete,
|
||||
trackAudioProgress,
|
||||
trackPdfOpen,
|
||||
trackPdfClose,
|
||||
trackPlayerOpen,
|
||||
trackPlayerChapter,
|
||||
trackPlayerMode,
|
||||
trackScrollDepth,
|
||||
trackExternalLink,
|
||||
trackCta,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
useScrollTracking()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-layout {
|
||||
grid-template-rows: auto 1fr auto;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
## Usage : docker compose -f docker-compose.yml -f docker-compose.umami.yml up -d
|
||||
##
|
||||
## Variables à définir dans .env :
|
||||
## UMAMI_DB_PASSWORD — mot de passe PostgreSQL Umami (générer avec openssl rand -hex 32)
|
||||
## UMAMI_APP_SECRET — secret applicatif (générer avec openssl rand -hex 32)
|
||||
## UMAMI_DOMAIN — ex: stats.librodrome.org
|
||||
## UMAMI_DB_PASSWORD — mot de passe PostgreSQL Umami (générer avec openssl rand -hex 32)
|
||||
## UMAMI_APP_SECRET — secret applicatif (générer avec openssl rand -hex 32)
|
||||
## UMAMI_DOMAIN — ex: stats.librodrome.org
|
||||
## NUXT_PUBLIC_UMAMI_URL — ex: https://stats.librodrome.org
|
||||
## NUXT_PUBLIC_UMAMI_WEBSITE_ID — ID du site dans Umami (Settings → Websites)
|
||||
## NUXT_UMAMI_API_KEY — clé API Umami (Settings → API Keys)
|
||||
|
||||
name: librodrome
|
||||
|
||||
@@ -48,5 +51,6 @@ volumes:
|
||||
umami-db-data:
|
||||
|
||||
networks:
|
||||
default:
|
||||
traefik:
|
||||
external: true
|
||||
|
||||
@@ -11,6 +11,9 @@ services:
|
||||
NUXT_ADMIN_PASSWORD: ${NUXT_ADMIN_PASSWORD}
|
||||
NUXT_ADMIN_SECRET: ${NUXT_ADMIN_SECRET}
|
||||
ADMIN_GIT_SYNC: ${ADMIN_GIT_SYNC:-false}
|
||||
NUXT_PUBLIC_UMAMI_URL: ${NUXT_PUBLIC_UMAMI_URL:-}
|
||||
NUXT_PUBLIC_UMAMI_WEBSITE_ID: ${NUXT_PUBLIC_UMAMI_WEBSITE_ID:-}
|
||||
NUXT_UMAMI_API_KEY: ${NUXT_UMAMI_API_KEY:-}
|
||||
ports:
|
||||
- 3000
|
||||
volumes:
|
||||
|
||||
@@ -14,8 +14,48 @@ export default defineNuxtConfig({
|
||||
'@unocss/nuxt',
|
||||
'@vueuse/nuxt',
|
||||
'@nuxt/image',
|
||||
'@nuxtjs/sitemap',
|
||||
],
|
||||
|
||||
site: {
|
||||
url: 'https://librodrome.org',
|
||||
name: 'Le Librodrome',
|
||||
},
|
||||
|
||||
sitemap: {
|
||||
strictNuxtContentPaths: false,
|
||||
sources: ['/api/__sitemap__/urls'],
|
||||
urls: [
|
||||
{ loc: '/', changefreq: 'weekly', priority: 1.0 },
|
||||
{ loc: '/economique', changefreq: 'monthly', priority: 0.9 },
|
||||
{ loc: '/economique/modele-eco', changefreq: 'monthly', priority: 0.9 },
|
||||
{ loc: '/economique/monnaie-libre', changefreq: 'monthly', priority: 0.8 },
|
||||
{ loc: '/economique/productions-collectives', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/commande', changefreq: 'monthly', priority: 0.8 },
|
||||
{ loc: '/numerique', changefreq: 'monthly', priority: 0.8 },
|
||||
{ loc: '/numerique/logiciel-libre', changefreq: 'monthly', priority: 0.8 },
|
||||
{ loc: '/numerique/authentification-wot', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/numerique/cloud-libre', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/citoyenne', changefreq: 'monthly', priority: 0.8 },
|
||||
{ loc: '/citoyenne/decision', changefreq: 'monthly', priority: 0.8 },
|
||||
{ loc: '/citoyenne/tarifs-eau', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/en-musique', changefreq: 'monthly', priority: 0.8 },
|
||||
{ loc: '/a-propos', changefreq: 'yearly', priority: 0.5 },
|
||||
// Chapitres modele-eco
|
||||
{ loc: '/economique/modele-eco/01-introduction', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/02-don', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/03-mesure', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/04-monnaie', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/05-trm', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/06-produire', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/07-echanger', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/08-institution', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/09-greffes', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/10-maintenant', changefreq: 'monthly', priority: 0.7 },
|
||||
{ loc: '/economique/modele-eco/11-annexes', changefreq: 'monthly', priority: 0.6 },
|
||||
],
|
||||
},
|
||||
|
||||
unocss: {
|
||||
safelist: [
|
||||
// Axis block icons (dynamic from YAML)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"@nuxt/content": "^3.11.2",
|
||||
"@nuxt/image": "^2.0.0",
|
||||
"@nuxtjs/sitemap": "^8.0.12",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"@unocss/nuxt": "^66.6.0",
|
||||
"@vueuse/nuxt": "^14.2.1",
|
||||
|
||||
Generated
+278
@@ -14,6 +14,9 @@ importers:
|
||||
'@nuxt/image':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)
|
||||
'@nuxtjs/sitemap':
|
||||
specifier: ^8.0.12
|
||||
version: 8.0.12(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76)
|
||||
'@pinia/nuxt':
|
||||
specifier: ^0.11.3
|
||||
version: 0.11.3(magicast@0.5.2)(pinia@3.0.4(typescript@5.9.3)(vue@3.5.28(typescript@5.9.3)))
|
||||
@@ -210,9 +213,15 @@ packages:
|
||||
'@clack/core@1.0.1':
|
||||
resolution: {integrity: sha512-WKeyK3NOBwDOzagPR5H08rFk9D/WuN705yEbuZvKqlkmoLM2woKtXb10OO2k1NoSU4SFG947i2/SCYh+2u5e4g==}
|
||||
|
||||
'@clack/core@1.2.0':
|
||||
resolution: {integrity: sha512-qfxof/3T3t9DPU/Rj3OmcFyZInceqj/NVtO9rwIuJqCUgh32gwPjpFQQp/ben07qKlhpwq7GzfWpST4qdJ5Drg==}
|
||||
|
||||
'@clack/prompts@1.0.1':
|
||||
resolution: {integrity: sha512-/42G73JkuYdyWZ6m8d/CJtBrGl1Hegyc7Fy78m5Ob+jF85TOUmLR5XLce/U3LxYAw0kJ8CT5aI99RIvPHcGp/Q==}
|
||||
|
||||
'@clack/prompts@1.2.0':
|
||||
resolution: {integrity: sha512-4jmztR9fMqPMjz6H/UZXj0zEmE43ha1euENwkckKKel4XpSfokExPo5AiVStdHSAlHekz4d0CA/r45Ok1E4D3w==}
|
||||
|
||||
'@cloudflare/kv-asset-handler@0.4.2':
|
||||
resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
@@ -733,6 +742,11 @@ packages:
|
||||
peerDependencies:
|
||||
vite: '>=6.0'
|
||||
|
||||
'@nuxt/devtools-kit@4.0.0-alpha.3':
|
||||
resolution: {integrity: sha512-ymp4jqS3hFfwRw8uDkv8cpu4kWvhQrX+S4jnA/oOc76s4AXf2HCZZJgrncKxh+txqi1NJj8nsQNBbaqRAo3g4w==}
|
||||
peerDependencies:
|
||||
vite: '>=6.0'
|
||||
|
||||
'@nuxt/devtools-wizard@3.2.1':
|
||||
resolution: {integrity: sha512-NKUg54cLQSDeBWaNwAPkVIpwXtd1CrxLr0inl9Z7OdLwsidqMrncNObO6K3HgV0PEdAcqY4IwE2hkON2dlRLYw==}
|
||||
hasBin: true
|
||||
@@ -755,6 +769,10 @@ packages:
|
||||
resolution: {integrity: sha512-UjBFt72dnpc+83BV3OIbCT0YHLevJtgJCHpxMX0YRKWLDhhbcDdUse87GtsQBrjvOzK7WUNUYLDS/hQLYev5rA==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
|
||||
'@nuxt/kit@4.4.2':
|
||||
resolution: {integrity: sha512-5+IPRNX2CjkBhuWUwz0hBuLqiaJPRoKzQ+SvcdrQDbAyE+VDeFt74VpSFr5/R0ujrK4b+XnSHUJWdS72w6hsog==}
|
||||
engines: {node: '>=18.12.0'}
|
||||
|
||||
'@nuxt/nitro-server@4.3.1':
|
||||
resolution: {integrity: sha512-4aNiM69Re02gI1ywnDND0m6QdVKXhWzDdtvl/16veytdHZj3FSq57ZCwOClNJ7HQkEMqXgS+bi6S2HmJX+et+g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -786,6 +804,15 @@ packages:
|
||||
'@nuxtjs/mdc@0.20.1':
|
||||
resolution: {integrity: sha512-fGmtLDQAmmDHF5Z37Apfc3k806rb2XWDOQFhb5xlDSL7+HiiUjyFy3ctx3qWdlC08dRzfAetmsGOYbfDqYsB/w==}
|
||||
|
||||
'@nuxtjs/sitemap@8.0.12':
|
||||
resolution: {integrity: sha512-1lFrk7FW/+3vtWRNnAyVjhyEsQN3xwau9hQI/cTmUKyxbImY0d10ZXeicR+amCU4wSnayVeaysBjM2KREAODTA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
zod: '>=3'
|
||||
peerDependenciesMeta:
|
||||
zod:
|
||||
optional: true
|
||||
|
||||
'@oxc-minify/binding-android-arm-eabi@0.112.0':
|
||||
resolution: {integrity: sha512-m7TGBR2hjsBJIN9UJ909KBoKsuogo6CuLsHKvUIBXdjI0JVHP8g4ZHeB+BJpGn5LJdeSGDfz9MWiuXrZDRzunw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -1906,6 +1933,11 @@ packages:
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
acorn@8.16.0:
|
||||
resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
|
||||
agent-base@7.1.4:
|
||||
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -2215,6 +2247,9 @@ packages:
|
||||
cookie-es@1.2.2:
|
||||
resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==}
|
||||
|
||||
cookie-es@1.2.3:
|
||||
resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==}
|
||||
|
||||
cookie-es@2.0.0:
|
||||
resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==}
|
||||
|
||||
@@ -2372,6 +2407,9 @@ packages:
|
||||
defu@6.1.4:
|
||||
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
||||
|
||||
defu@6.1.7:
|
||||
resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==}
|
||||
|
||||
denque@2.1.0:
|
||||
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
|
||||
engines: {node: '>=0.10'}
|
||||
@@ -2587,9 +2625,25 @@ packages:
|
||||
fast-npm-meta@1.2.1:
|
||||
resolution: {integrity: sha512-vTHOCEbzcbQEfYL0sPzcz+HF5asxoy60tPBVaiYzsCfuyhbXZCSqXL+LgPGV22nuAYimoGMeDpywMQB4aOw8HQ==}
|
||||
|
||||
fast-string-truncated-width@1.2.1:
|
||||
resolution: {integrity: sha512-Q9acT/+Uu3GwGj+5w/zsGuQjh9O1TyywhIwAxHudtWrgF09nHOPrvTLhQevPbttcxjr/SNN7mJmfOw/B1bXgow==}
|
||||
|
||||
fast-string-width@1.1.0:
|
||||
resolution: {integrity: sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ==}
|
||||
|
||||
fast-uri@3.1.0:
|
||||
resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==}
|
||||
|
||||
fast-wrap-ansi@0.1.6:
|
||||
resolution: {integrity: sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w==}
|
||||
|
||||
fast-xml-builder@1.1.4:
|
||||
resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==}
|
||||
|
||||
fast-xml-parser@5.5.11:
|
||||
resolution: {integrity: sha512-QL0eb0YbSTVWF6tTf1+LEMSgtCEjBYPpnAjoLC8SscESlAjXEIRJ7cHtLG0pLeDFaZLa4VKZLArtA/60ZS7vyA==}
|
||||
hasBin: true
|
||||
|
||||
fastq@1.20.1:
|
||||
resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==}
|
||||
|
||||
@@ -2733,6 +2787,9 @@ packages:
|
||||
resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
h3@1.15.11:
|
||||
resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==}
|
||||
|
||||
h3@1.15.5:
|
||||
resolution: {integrity: sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==}
|
||||
|
||||
@@ -3338,6 +3395,9 @@ packages:
|
||||
mlly@1.8.0:
|
||||
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
||||
|
||||
mlly@1.8.2:
|
||||
resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==}
|
||||
|
||||
mocked-exports@0.1.1:
|
||||
resolution: {integrity: sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==}
|
||||
|
||||
@@ -3444,6 +3504,12 @@ packages:
|
||||
resolution: {integrity: sha512-5pVCzWXqg9HP159JDhdfQJtFvgmS/KouEVpyYLPEBXWMrQoJBwujsczmLeIKXKI2BTy4RqfXy8N1GfGTZNb57g==}
|
||||
hasBin: true
|
||||
|
||||
nuxt-site-config-kit@4.0.8:
|
||||
resolution: {integrity: sha512-7g3giKXt0M2vssCUg8XFfR6+u4U0zywQ8p8i4msy4p+9etteFNrkrCmVHZ83xiWGFbnoTgiaymPjbaQH3KZqAg==}
|
||||
|
||||
nuxt-site-config@4.0.8:
|
||||
resolution: {integrity: sha512-H7wHoOJ5Z6ZnTqD5vUugaKkWZbejZ9kGmzpr2dheOaC6RdT8JafCfMrmJG7W+cyJiJJ3YmzL+bzPBW2bW6MExA==}
|
||||
|
||||
nuxt@4.3.1:
|
||||
resolution: {integrity: sha512-bl+0rFcT5Ax16aiWFBFPyWcsTob19NTZaDL5P6t0MQdK63AtgS6fN6fwvwdbXtnTk6/YdCzlmuLzXhSM22h0OA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
@@ -3457,6 +3523,20 @@ packages:
|
||||
'@types/node':
|
||||
optional: true
|
||||
|
||||
nuxtseo-shared@5.1.2:
|
||||
resolution: {integrity: sha512-L8nYZCmdFh2w9wNf4dxQy5Vzv2JTWd661zAg3D0h9HRm3chUkMZNgWQbodE7rK6jpitydONyvi7uHXOEHbGIuA==}
|
||||
peerDependencies:
|
||||
'@nuxt/schema': ^3.16.0 || ^4.0.0
|
||||
nuxt: ^3.16.0 || ^4.0.0
|
||||
nuxt-site-config: ^3.2.0 || ^4.0.0
|
||||
vue: ^3.5.0
|
||||
zod: ^3.23.0 || ^4.0.0
|
||||
peerDependenciesMeta:
|
||||
nuxt-site-config:
|
||||
optional: true
|
||||
zod:
|
||||
optional: true
|
||||
|
||||
nypm@0.6.5:
|
||||
resolution: {integrity: sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -3552,6 +3632,10 @@ packages:
|
||||
path-browserify@1.0.1:
|
||||
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
|
||||
|
||||
path-expression-matcher@1.5.0:
|
||||
resolution: {integrity: sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
path-key@3.1.1:
|
||||
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -4085,6 +4169,11 @@ packages:
|
||||
sisteransi@1.0.5:
|
||||
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
|
||||
|
||||
site-config-stack@4.0.8:
|
||||
resolution: {integrity: sha512-Su+57p7CGqd3QSMmaDV+qU9EqWmgAT3SGX4Wurb5VsEBMFC3oXvai8BlrXVUnH1ay9hA1WOn0g0i6+y/RJX5Yw==}
|
||||
peerDependencies:
|
||||
vue: ^3.5.30
|
||||
|
||||
skin-tone@2.0.0:
|
||||
resolution: {integrity: sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -4146,6 +4235,9 @@ packages:
|
||||
std-env@3.10.0:
|
||||
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
|
||||
|
||||
std-env@4.0.0:
|
||||
resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==}
|
||||
|
||||
streamx@2.23.0:
|
||||
resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==}
|
||||
|
||||
@@ -4185,6 +4277,9 @@ packages:
|
||||
strip-literal@3.1.0:
|
||||
resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
|
||||
|
||||
strnum@2.2.3:
|
||||
resolution: {integrity: sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==}
|
||||
|
||||
structured-clone-es@1.0.0:
|
||||
resolution: {integrity: sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==}
|
||||
|
||||
@@ -4272,6 +4367,10 @@ packages:
|
||||
resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
tinyexec@1.1.1:
|
||||
resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
tinyglobby@0.2.15:
|
||||
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
@@ -5007,12 +5106,24 @@ snapshots:
|
||||
picocolors: 1.1.1
|
||||
sisteransi: 1.0.5
|
||||
|
||||
'@clack/core@1.2.0':
|
||||
dependencies:
|
||||
fast-wrap-ansi: 0.1.6
|
||||
sisteransi: 1.0.5
|
||||
|
||||
'@clack/prompts@1.0.1':
|
||||
dependencies:
|
||||
'@clack/core': 1.0.1
|
||||
picocolors: 1.1.1
|
||||
sisteransi: 1.0.5
|
||||
|
||||
'@clack/prompts@1.2.0':
|
||||
dependencies:
|
||||
'@clack/core': 1.2.0
|
||||
fast-string-width: 1.1.0
|
||||
fast-wrap-ansi: 0.1.6
|
||||
sisteransi: 1.0.5
|
||||
|
||||
'@cloudflare/kv-asset-handler@0.4.2': {}
|
||||
|
||||
'@dxup/nuxt@0.3.2(magicast@0.5.2)':
|
||||
@@ -5474,6 +5585,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
'@nuxt/devtools-kit@4.0.0-alpha.3(magicast@0.5.2)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))':
|
||||
dependencies:
|
||||
'@nuxt/kit': 4.4.2(magicast@0.5.2)
|
||||
tinyexec: 1.1.1
|
||||
vite: 7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2)
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
'@nuxt/devtools-wizard@3.2.1':
|
||||
dependencies:
|
||||
consola: 3.4.2
|
||||
@@ -5587,6 +5706,31 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
'@nuxt/kit@4.4.2(magicast@0.5.2)':
|
||||
dependencies:
|
||||
c12: 3.3.3(magicast@0.5.2)
|
||||
consola: 3.4.2
|
||||
defu: 6.1.7
|
||||
destr: 2.0.5
|
||||
errx: 0.1.0
|
||||
exsolve: 1.0.8
|
||||
ignore: 7.0.5
|
||||
jiti: 2.6.1
|
||||
klona: 2.0.6
|
||||
mlly: 1.8.2
|
||||
ohash: 2.0.11
|
||||
pathe: 2.0.3
|
||||
pkg-types: 2.3.0
|
||||
rc9: 3.0.0
|
||||
scule: 1.3.0
|
||||
semver: 7.7.4
|
||||
tinyglobby: 0.2.15
|
||||
ufo: 1.6.3
|
||||
unctx: 2.5.0
|
||||
untyped: 2.0.0
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
'@nuxt/nitro-server@4.3.1(better-sqlite3@12.6.2)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@nuxt/devalue': 2.0.2
|
||||
@@ -5776,6 +5920,29 @@ snapshots:
|
||||
- magicast
|
||||
- supports-color
|
||||
|
||||
'@nuxtjs/sitemap@8.0.12(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@nuxt/kit': 4.4.2(magicast@0.5.2)
|
||||
consola: 3.4.2
|
||||
defu: 6.1.7
|
||||
fast-xml-parser: 5.5.11
|
||||
nuxt-site-config: 4.0.8(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76)
|
||||
nuxtseo-shared: 5.1.2(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt-site-config@4.0.8(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76))(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76)
|
||||
ofetch: 1.5.1
|
||||
pathe: 2.0.3
|
||||
pkg-types: 2.3.0
|
||||
radix3: 1.1.2
|
||||
ufo: 1.6.3
|
||||
ultrahtml: 1.6.0
|
||||
optionalDependencies:
|
||||
zod: 3.25.76
|
||||
transitivePeerDependencies:
|
||||
- '@nuxt/schema'
|
||||
- magicast
|
||||
- nuxt
|
||||
- vite
|
||||
- vue
|
||||
|
||||
'@oxc-minify/binding-android-arm-eabi@0.112.0':
|
||||
optional: true
|
||||
|
||||
@@ -6814,6 +6981,8 @@ snapshots:
|
||||
|
||||
acorn@8.15.0: {}
|
||||
|
||||
acorn@8.16.0: {}
|
||||
|
||||
agent-base@7.1.4: {}
|
||||
|
||||
ajv-formats@2.1.1(ajv@8.18.0):
|
||||
@@ -7111,6 +7280,8 @@ snapshots:
|
||||
|
||||
cookie-es@1.2.2: {}
|
||||
|
||||
cookie-es@1.2.3: {}
|
||||
|
||||
cookie-es@2.0.0: {}
|
||||
|
||||
copy-anything@4.0.5:
|
||||
@@ -7260,6 +7431,8 @@ snapshots:
|
||||
|
||||
defu@6.1.4: {}
|
||||
|
||||
defu@6.1.7: {}
|
||||
|
||||
denque@2.1.0: {}
|
||||
|
||||
depd@2.0.0: {}
|
||||
@@ -7471,8 +7644,28 @@ snapshots:
|
||||
|
||||
fast-npm-meta@1.2.1: {}
|
||||
|
||||
fast-string-truncated-width@1.2.1: {}
|
||||
|
||||
fast-string-width@1.1.0:
|
||||
dependencies:
|
||||
fast-string-truncated-width: 1.2.1
|
||||
|
||||
fast-uri@3.1.0: {}
|
||||
|
||||
fast-wrap-ansi@0.1.6:
|
||||
dependencies:
|
||||
fast-string-width: 1.1.0
|
||||
|
||||
fast-xml-builder@1.1.4:
|
||||
dependencies:
|
||||
path-expression-matcher: 1.5.0
|
||||
|
||||
fast-xml-parser@5.5.11:
|
||||
dependencies:
|
||||
fast-xml-builder: 1.1.4
|
||||
path-expression-matcher: 1.5.0
|
||||
strnum: 2.2.3
|
||||
|
||||
fastq@1.20.1:
|
||||
dependencies:
|
||||
reusify: 1.1.0
|
||||
@@ -7611,6 +7804,18 @@ snapshots:
|
||||
dependencies:
|
||||
duplexer: 0.1.2
|
||||
|
||||
h3@1.15.11:
|
||||
dependencies:
|
||||
cookie-es: 1.2.3
|
||||
crossws: 0.3.5
|
||||
defu: 6.1.7
|
||||
destr: 2.0.5
|
||||
iron-webcrypto: 1.2.1
|
||||
node-mock-http: 1.0.4
|
||||
radix3: 1.1.2
|
||||
ufo: 1.6.3
|
||||
uncrypto: 0.1.3
|
||||
|
||||
h3@1.15.5:
|
||||
dependencies:
|
||||
cookie-es: 1.2.2
|
||||
@@ -8500,6 +8705,13 @@ snapshots:
|
||||
pkg-types: 1.3.1
|
||||
ufo: 1.6.3
|
||||
|
||||
mlly@1.8.2:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
pathe: 2.0.3
|
||||
pkg-types: 1.3.1
|
||||
ufo: 1.6.3
|
||||
|
||||
mocked-exports@0.1.1: {}
|
||||
|
||||
mrmime@2.0.1: {}
|
||||
@@ -8682,6 +8894,34 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
nuxt-site-config-kit@4.0.8(magicast@0.5.2)(vue@3.5.28(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@nuxt/kit': 4.4.2(magicast@0.5.2)
|
||||
site-config-stack: 4.0.8(vue@3.5.28(typescript@5.9.3))
|
||||
std-env: 4.0.0
|
||||
ufo: 1.6.3
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
- vue
|
||||
|
||||
nuxt-site-config@4.0.8(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76):
|
||||
dependencies:
|
||||
'@nuxt/kit': 4.4.2(magicast@0.5.2)
|
||||
h3: 1.15.11
|
||||
nuxt-site-config-kit: 4.0.8(magicast@0.5.2)(vue@3.5.28(typescript@5.9.3))
|
||||
nuxtseo-shared: 5.1.2(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt-site-config@4.0.8(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76))(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76)
|
||||
pathe: 2.0.3
|
||||
pkg-types: 2.3.0
|
||||
site-config-stack: 4.0.8(vue@3.5.28(typescript@5.9.3))
|
||||
ufo: 1.6.3
|
||||
transitivePeerDependencies:
|
||||
- '@nuxt/schema'
|
||||
- magicast
|
||||
- nuxt
|
||||
- vite
|
||||
- vue
|
||||
- zod
|
||||
|
||||
nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2):
|
||||
dependencies:
|
||||
'@dxup/nuxt': 0.3.2(magicast@0.5.2)
|
||||
@@ -8805,6 +9045,31 @@ snapshots:
|
||||
- xml2js
|
||||
- yaml
|
||||
|
||||
nuxtseo-shared@5.1.2(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt-site-config@4.0.8(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76))(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76):
|
||||
dependencies:
|
||||
'@clack/prompts': 1.2.0
|
||||
'@nuxt/devtools-kit': 4.0.0-alpha.3(magicast@0.5.2)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))
|
||||
'@nuxt/kit': 4.4.2(magicast@0.5.2)
|
||||
'@nuxt/schema': 4.3.1
|
||||
birpc: 4.0.0
|
||||
consola: 3.4.2
|
||||
defu: 6.1.7
|
||||
nuxt: 4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2)
|
||||
ofetch: 1.5.1
|
||||
pathe: 2.0.3
|
||||
pkg-types: 2.3.0
|
||||
radix3: 1.1.2
|
||||
sirv: 3.0.2
|
||||
std-env: 4.0.0
|
||||
ufo: 1.6.3
|
||||
vue: 3.5.28(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
nuxt-site-config: 4.0.8(@nuxt/schema@4.3.1)(magicast@0.5.2)(nuxt@4.3.1(@parcel/watcher@2.5.6)(@types/node@25.2.3)(@vue/compiler-sfc@3.5.28)(better-sqlite3@12.6.2)(cac@6.7.14)(db0@0.3.4(better-sqlite3@12.6.2))(ioredis@5.9.3)(magicast@0.5.2)(rollup@4.57.1)(terser@5.46.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(yaml@2.8.2))(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(vue@3.5.28(typescript@5.9.3))(zod@3.25.76)
|
||||
zod: 3.25.76
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
- vite
|
||||
|
||||
nypm@0.6.5:
|
||||
dependencies:
|
||||
citty: 0.2.1
|
||||
@@ -8971,6 +9236,8 @@ snapshots:
|
||||
|
||||
path-browserify@1.0.1: {}
|
||||
|
||||
path-expression-matcher@1.5.0: {}
|
||||
|
||||
path-key@3.1.1: {}
|
||||
|
||||
path-key@4.0.0: {}
|
||||
@@ -9633,6 +9900,11 @@ snapshots:
|
||||
|
||||
sisteransi@1.0.5: {}
|
||||
|
||||
site-config-stack@4.0.8(vue@3.5.28(typescript@5.9.3)):
|
||||
dependencies:
|
||||
ufo: 1.6.3
|
||||
vue: 3.5.28(typescript@5.9.3)
|
||||
|
||||
skin-tone@2.0.0:
|
||||
dependencies:
|
||||
unicode-emoji-modifier-base: 1.0.0
|
||||
@@ -9684,6 +9956,8 @@ snapshots:
|
||||
|
||||
std-env@3.10.0: {}
|
||||
|
||||
std-env@4.0.0: {}
|
||||
|
||||
streamx@2.23.0:
|
||||
dependencies:
|
||||
events-universal: 1.0.1
|
||||
@@ -9734,6 +10008,8 @@ snapshots:
|
||||
dependencies:
|
||||
js-tokens: 9.0.1
|
||||
|
||||
strnum@2.2.3: {}
|
||||
|
||||
structured-clone-es@1.0.0: {}
|
||||
|
||||
stylehacks@7.0.7(postcss@8.5.6):
|
||||
@@ -9828,6 +10104,8 @@ snapshots:
|
||||
|
||||
tinyexec@1.0.2: {}
|
||||
|
||||
tinyexec@1.1.1: {}
|
||||
|
||||
tinyglobby@0.2.15:
|
||||
dependencies:
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 327 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
@@ -3,7 +3,7 @@ book:
|
||||
author: Yvv
|
||||
pdfFile: /pdf/une-economie-du-don.pdf
|
||||
description: Un livre et 9 chansons pour explorer ensemble les fondements d'une économie fondée sur le don.
|
||||
coverImage: /images/book-cover.jpg
|
||||
coverImage: /images/Couv-Economie-du-don.jpg
|
||||
license: CC-BY-NC
|
||||
isbn: 979-1-042-45206-3
|
||||
songs:
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ book:
|
||||
title: Une économie du don — enfin concevable
|
||||
description: Un livre et quelques chansons pour une proposition de modèle économique fondé sur le don. Le livre est
|
||||
accompagné de chansons qui le racontent, un peu autrement.
|
||||
coverImage: /images/book-cover-spread.jpg
|
||||
coverImage: /images/Couv-Economie-du-don.jpg
|
||||
coverAlt: Couverture — Une économie du don, enfin concevable
|
||||
cta:
|
||||
player: Présentation musicale
|
||||
|
||||
Reference in New Issue
Block a user