Pages détail numérique : sommaire flottant, nav ctx, shadoks geek, contenu enrichi
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- [slug].vue : sommaire sticky (overflow:clip sur parent), prev/next en haut, 6 shadoks geek (pinguin+USB, web-of-trust, rubber-duck, caféine, debugger loupe, rack serveur) - Nouveaux types de sections : territoire (bouquet sweethomeCloud, 2 modèles éco, tableau matériel dépliable), projet (carte gestation) - cloud-libre.yml : section sweethomeCloud complète avec infra 50 000 hab. (~2€/an/hab) - authentification-wot.yml : trustWallet, correction WoT Duniter (Ed25519+Scrypt, sigQty=5, stepMax=3), DID/VC standards - logiciel-libre.yml : carte projet wishBounty - home.yml + numerique.yml : cloud-libre → sweethomeCloud, description RGPD/local-first - AxisBlock.vue : bulles de présentation inline dans les cards (plus de tooltip absolu) - Analytics : useTracking.ts (Umami), docker-compose.umami.yml, /api/stats fédération - nuxt.config.ts : config Umami runtime Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
12
app/app.vue
12
app/app.vue
@@ -17,6 +17,18 @@
|
||||
const paletteStore = usePaletteStore()
|
||||
onMounted(() => paletteStore.applyToDOM())
|
||||
|
||||
// Umami analytics — inject script only when configured
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
if (runtimeConfig.public.umamiWebsiteId && runtimeConfig.public.umamiUrl) {
|
||||
useHead({
|
||||
script: [{
|
||||
src: `${runtimeConfig.public.umamiUrl}/script.js`,
|
||||
defer: true,
|
||||
'data-website-id': runtimeConfig.public.umamiWebsiteId,
|
||||
}],
|
||||
})
|
||||
}
|
||||
|
||||
useHead({
|
||||
titleTemplate: (title) => {
|
||||
return title ? `${title} — Le Librodrome` : 'Le librodrome'
|
||||
|
||||
@@ -37,6 +37,15 @@
|
||||
</h3>
|
||||
|
||||
<p class="text-sm text-white/60 leading-relaxed">{{ item.description }}</p>
|
||||
|
||||
<!-- Presentation inline (projet en gestation) -->
|
||||
<div v-if="item.presentation" class="axis-presentation-inline">
|
||||
<div class="axis-pi-header">
|
||||
<div class="i-lucide-sparkles h-3 w-3" />
|
||||
<span class="axis-pi-title">{{ item.presentation.title }}</span>
|
||||
</div>
|
||||
<p class="axis-pi-text">{{ item.presentation.text }}</p>
|
||||
</div>
|
||||
</component>
|
||||
|
||||
<!-- Actions zone (separate from card link) -->
|
||||
@@ -173,7 +182,7 @@ function itemAttrs(item: AxisItem) {
|
||||
border: 1px solid hsl(var(--color-text) / 0.08);
|
||||
background: hsl(var(--color-surface));
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
overflow: hidden;
|
||||
/* overflow: visible pour laisser le tooltip sortir du cadre */
|
||||
}
|
||||
|
||||
.axis-item:hover {
|
||||
@@ -248,6 +257,8 @@ function itemAttrs(item: AxisItem) {
|
||||
gap: 0;
|
||||
border-top: 1px solid hsl(var(--color-text) / 0.06);
|
||||
background: hsl(var(--color-bg) / 0.4);
|
||||
border-bottom-left-radius: 0.75rem;
|
||||
border-bottom-right-radius: 0.75rem;
|
||||
}
|
||||
|
||||
.axis-actions-row {
|
||||
@@ -309,4 +320,34 @@ function itemAttrs(item: AxisItem) {
|
||||
background: hsl(var(--color-accent) / 0.08);
|
||||
border-color: hsl(var(--color-accent) / 0.2);
|
||||
}
|
||||
|
||||
/* Presentation inline — projet en gestation, affiché dans la card */
|
||||
.axis-presentation-inline {
|
||||
margin-top: 0.75rem;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 8px;
|
||||
background: hsl(var(--color-accent) / 0.07);
|
||||
border: 1px solid hsl(var(--color-accent) / 0.18);
|
||||
}
|
||||
|
||||
.axis-pi-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
margin-bottom: 0.2rem;
|
||||
color: hsl(var(--color-accent));
|
||||
}
|
||||
|
||||
.axis-pi-title {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.axis-pi-text {
|
||||
font-size: 0.72rem;
|
||||
color: hsl(var(--color-text) / 0.55);
|
||||
line-height: 1.45;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
20
app/composables/useTracking.ts
Normal file
20
app/composables/useTracking.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Umami analytics wrapper — safe server-side, no-op when not configured.
|
||||
* Usage: const { track } = useTracking()
|
||||
* track('player:open')
|
||||
* track('axis:navigate', { axis: 'numerique' })
|
||||
*/
|
||||
export function useTracking() {
|
||||
const runtimeConfig = useRuntimeConfig()
|
||||
const enabled = !!runtimeConfig.public.umamiWebsiteId
|
||||
|
||||
function track(event: string, data?: Record<string, unknown>) {
|
||||
if (!import.meta.client || !enabled) return
|
||||
const umami = (window as Record<string, unknown>).umami as
|
||||
| { track: (event: string, data?: unknown) => void }
|
||||
| undefined
|
||||
umami?.track(event, data)
|
||||
}
|
||||
|
||||
return { track, enabled }
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user