Files
librodrome/app/pages/numerique/index.vue
T
YvvandClaude Opus 5.5 d2bc0d9e46 identité : le kit du studio DA intégré, les 61 oiseaux posés sur la page
Copie du kit kit-site (empreinte vérifiée) : logotype dans l'en-tête, signe §,
favicons et icônes, og-default (?v=3), frise du pied de page, 61 oiseaux.
Les shadoks positionnés à la main (HomeShadoks et les règles des 10 pages)
cèdent la place à UiOiseauPose : chaque oiseau se pose sur une arête réelle
(perché, marge gauche ou droite, derrière une carte, libre), currentColor,
largeur 72 px au moins, opacité 0,18-0,28 près du texte et 0,10-0,14 derrière,
jamais deux fois sur une page, calligraphe et typographe jamais en miroir.
Sous 768 px, un oiseau par page au plus ; seuls ceux derrière une carte
dérivent un peu, et plus du tout en mouvement réduit.

Consignes d'Yvv du 03/11 inscrites dans docs/consignes-yvv.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 06:39:34 +01:00

301 lines
8.7 KiB
Vue

<template>
<div class="axis-scope axis-scope--num oiseaux-scene relative overflow-hidden section-padding">
<div class="container-content">
<header class="mb-12 text-center">
<p class="mb-2 font-mono text-sm tracking-widest text-primary uppercase">{{ content?.kicker }}</p>
<h1 class="page-title relative font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
{{ content?.title }}
<UiOiseauPose nom="droneuse" pose="perche" left="calc(68% - 38px)" bottom="calc(100% - 6px)" :w="76" :seuil="1200" />
</h1>
<p class="mt-4 mx-auto max-w-2xl leading-relaxed" style="color: hsl(var(--color-text-muted))">
{{ content?.description }}
</p>
</header>
<div class="mx-auto max-w-3xl flex flex-col gap-6">
<!-- LPK sert l'axe numérique -->
<NuxtLink v-if="lpk" :to="lpk.to" class="lpk-card">
<UiOiseauPose nom="electricien" pose="marge-g" ecart="46px" :w="132" />
<span class="lpk-name">{{ lpk.name }}</span>
<span class="lpk-body">
<span class="lpk-full">{{ lpk.text }}</span>
<span class="lpk-role">{{ lpk.role }}</span>
</span>
<span class="i-lucide-arrow-right h-5 w-5 lpk-arrow" aria-hidden="true" />
</NuxtLink>
<div
v-for="pillar in content?.pillars"
:key="pillar.id"
class="pillar-card"
>
<UiOiseauPose v-for="o in OISEAUX_PILIER[pillar.id] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<!-- Overlay lien — toute la carte cliquable -->
<NuxtLink v-if="pillar.to" :to="pillar.to" class="pillar-overlay" :aria-label="pillar.label" tabindex="-1" />
<!-- Corps de la carte -->
<div class="pillar-body">
<div class="pillar-header">
<div class="pillar-icon">
<div :class="`i-lucide-${pillar.icon}`" class="h-5 w-5" />
</div>
<h2 class="font-display text-xl font-bold" style="color: hsl(var(--color-text))">
{{ pillar.label }}
</h2>
<UiStatusBadge class="ml-auto" :status="pillar.status" :gestation="pillar.gestation" :since="pillar.since" />
</div>
<p class="leading-relaxed whitespace-pre-line mt-3" style="color: hsl(var(--color-text-muted))">{{ pillar.text }}</p>
<!-- Project card -->
<div v-if="pillar.project" class="project-card mt-4">
<div class="project-icon">
<div class="i-lucide-rocket h-4 w-4" />
</div>
<div>
<span class="font-display font-semibold text-sm" style="color: hsl(var(--color-text))">{{ pillar.project.name }}</span>
<span class="text-sm ml-2" style="color: hsl(var(--color-text-muted))">{{ pillar.project.text }}</span>
</div>
</div>
</div>
<!-- Zone actions — z-index au-dessus de l'overlay -->
<div v-if="(pillar as any).actions?.length" class="pillar-actions">
<a
v-for="action in (pillar as any).actions"
:key="action.label"
:href="action.href"
target="_blank"
rel="noopener noreferrer"
class="pillar-action-btn"
:class="{ 'pillar-action-btn--highlight': action.highlight }"
>
<div :class="`i-lucide-${action.icon}`" class="h-3.5 w-3.5" />
{{ action.label }}
</a>
<span v-for="action in (pillar as any).actions.filter((a: any) => a.note)" :key="`n-${action.label}`" class="pillar-action-note">{{ action.note }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type { OiseauPlace } from '~/utils/oiseauPose'
definePageMeta({
layout: 'default',
})
const { data: content } = await usePageContent('numerique')
// Birds by pillar, each next to the trade it is about (composition of 03/11)
const OISEAUX_PILIER: Record<string, OiseauPlace[]> = {
'logiciel-libre': [
{ nom: 'codeuse', pose: 'perche', right: '4px', w: 88, retourne: true },
],
'authentification-wot': [
{ nom: 'cryptographe', pose: 'perche', right: '18%', w: 76 },
],
'cloud-libre': [
{ nom: 'admin-reseau', pose: 'marge-d', ecart: '36px', bottom: '28%', w: 118, retourne: true },
{ nom: 'admin-reseau', pose: 'perche', right: '6px', w: 76, retourne: true, mobileSeul: true },
{ nom: 'porteur-de-serveur', pose: 'derriere', left: '-150px', bottom: '-40px', w: 240 },
],
}
const { data: site } = await useSiteContent()
const lpk = computed(() => site.value?.lpk)
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>
<style scoped>
.lpk-card {
position: relative;
display: flex;
align-items: center;
gap: 1.25rem;
padding: 1.25rem 1.5rem;
border-radius: 16px;
background: hsl(var(--color-primary) / 0.1);
color: hsl(var(--color-text));
transition: transform 0.12s ease;
}
.lpk-card:hover { transform: translateY(-3px); }
.lpk-card:active { transform: translateY(0); }
.lpk-name {
font-family: var(--font-display);
font-weight: 800;
font-size: 2rem;
letter-spacing: -0.03em;
color: hsl(var(--color-primary));
}
.lpk-body {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.lpk-full {
font-family: var(--font-mono);
font-size: 0.72rem;
color: hsl(var(--color-text-muted));
}
.lpk-role {
font-size: 1.02rem;
line-height: 1.45;
}
.pillar-action-note {
align-self: center;
font-family: var(--font-mono);
font-size: 0.7rem;
color: hsl(var(--axis-cit));
}
.lpk-arrow { color: hsl(var(--color-primary)); flex-shrink: 0; }
@media (prefers-reduced-motion: reduce) {
.lpk-card { transition: none; }
}
.page-title {
font-size: clamp(2rem, 5vw, 2.75rem);
}
.pillar-card {
border-radius: 16px;
border: none;
background: hsl(var(--color-surface));
transition: border-color 0.2s;
position: relative;
}
.pillar-card:hover {
border-color: hsl(var(--color-primary) / 0.2);
}
.pillar-overlay {
position: absolute;
inset: 0;
z-index: 1;
border-radius: inherit;
}
.pillar-body {
padding: 1.5rem;
}
.pillar-actions {
display: flex;
flex-wrap: wrap;
gap: 0.375rem;
padding: 0.75rem 1.5rem;
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;
position: relative;
z-index: 2;
}
.pillar-action-btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.375rem 0.75rem;
border-radius: 0.5rem;
font-size: 0.8rem;
font-weight: 500;
color: hsl(var(--color-text) / 0.7);
background: hsl(var(--color-text) / 0.05);
border: 1px solid hsl(var(--color-text) / 0.1);
transition: all 0.2s;
text-decoration: none;
cursor: pointer;
}
.pillar-action-btn:hover {
color: hsl(var(--color-text));
background: hsl(var(--color-primary) / 0.12);
border-color: hsl(var(--color-primary) / 0.3);
}
.pillar-action-btn--highlight {
color: hsl(var(--color-primary));
background: hsl(var(--color-primary) / 0.12);
border-color: hsl(var(--color-primary) / 0.25);
}
.pillar-action-btn--highlight:hover {
background: hsl(var(--color-primary) / 0.2);
border-color: hsl(var(--color-primary) / 0.4);
}
.pillar-header {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
}
.pillar-icon {
display: flex;
align-items: center;
justify-content: center;
width: 2.25rem;
height: 2.25rem;
border-radius: 0.5rem;
background: hsl(var(--color-primary) / 0.15);
color: hsl(var(--color-primary));
box-shadow: 0 0 12px hsl(var(--color-primary) / 0.12);
flex-shrink: 0;
}
.gestation-badge {
display: inline-flex;
align-items: center;
gap: 0.25rem;
margin-left: auto;
padding: 0.125rem 0.5rem;
border-radius: 9999px;
background: hsl(var(--color-accent) / 0.12);
color: hsl(var(--color-accent));
font-size: 0.7rem;
font-weight: 500;
font-family: var(--font-mono);
}
.project-card {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 0.75rem 1rem;
border-radius: 0.5rem;
background: hsl(var(--color-bg) / 0.5);
border: 1px solid hsl(var(--color-primary) / 0.1);
}
.project-icon {
display: flex;
align-items: center;
justify-content: center;
width: 1.75rem;
height: 1.75rem;
border-radius: 0.375rem;
background: hsl(var(--color-primary) / 0.1);
color: hsl(var(--color-primary));
flex-shrink: 0;
}
</style>