Ordre IDENTITE-DA-5 (03/11 14h41, relayé par la session orch ; seuils confirmés par DA) : - docs/da-oiseaux.md : « Règles mesurées (liste fermée) », règles a à i avec leurs seuils, telles que le contrôle les mesure (pixels peints, ligne de base), et la phrase juste sur l'acrobate ; - UiOiseauPose : pose `bout`, une ancre sans taille dans le texte, sur sa ligne de base, pour un oiseau au bout (ou au début) d'un titre ; - au bout de leur titre : trapéziste, clown, marionnettiste, DJ (/en-musique), droneuse, vigie, alchimiste, relieur, et l'oiseau de l'intitulé au téléphone ; - authentification : le pompeur de Ğ1 perché sur la carte du projet (plus de colonne en marge) ; - accueil : l'accordéoniste au bout du titre du format (plus de paire avec la lectrice, plus de trait sur le lien) ; - soudeuse sur la ligne de base de son titre ; administrateur réseau et cartographe sortent par le côté de leur carte, pas par un coin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
307 lines
9.1 KiB
Vue
307 lines
9.1 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="relative mb-2 font-mono text-sm tracking-widest text-primary uppercase">
|
|
<!-- Phone: the title fills the width; the bird stands at the end of this line, on its baseline -->
|
|
{{ content?.kicker }}<UiOiseauPose nom="droneuse" pose="perche" bout :w="72" mobile-seul />
|
|
</p>
|
|
<h1 class="page-title relative font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
|
|
<!-- At the end of the title, on its baseline (rule e, docs/da-oiseaux.md) -->
|
|
{{ content?.title }}<UiOiseauPose nom="droneuse" pose="perche" bout left="16px" :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="40px" :w="150" />
|
|
<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[]> = {
|
|
// The cards stand 16 px apart: no room above them for a perched bird (DA rule of 03/11).
|
|
// In the margins, no strict zigzag and several sizes (DA, 03/11 07h56): two stand at the
|
|
// bottom of their card on the right, the network admin is large behind Cloud libre
|
|
'logiciel-libre': [
|
|
{ nom: 'codeuse', pose: 'marge-d', ecart: '28px', w: 84, retourne: true },
|
|
],
|
|
'authentification-wot': [
|
|
{ nom: 'cryptographe', pose: 'marge-d', ecart: '64px', w: 112, retourne: true },
|
|
],
|
|
'cloud-libre': [
|
|
// out by the side of the card, not by its corner: the card is a link, and its rounded corner
|
|
// let 5 px of the drawing show on it (rule h)
|
|
{ nom: 'admin-reseau', pose: 'derriere', left: '-150px', bottom: '20px', w: 236 },
|
|
],
|
|
}
|
|
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>
|