design : accueil en trois variantes (console, parcours, établi) + couleur par axe

- typo : Bricolage Grotesque (titres) + Atkinson Hyperlegible (texte),
  Syne gardée pour le logo seul ; une seule source de polices (Bunny)
- palettes : teinte propre à chaque axe dans les 4 ambiances ;
  pages d'axe en axis-scope, cartes sans bordure (canon design)
- accueil : console des trois curseurs (tablist clavier), boîte à outils,
  bloc format éditorial + événement + reproduction ; ?v=a|b|c|0
- numérique : carte LPK ; bouquet rendu avec statut et légende
- messages : sans bordure, deux colonnes en grand écran

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-09-28 10:15:46 +02:00
co-authored by Claude Opus 5.5
parent c3ada04e52
commit e9fce4be8f
29 changed files with 2901 additions and 56 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<div class="section-padding">
<div class="axis-scope axis-scope--cit section-padding">
<div class="container-content">
<!-- Header -->
+3 -3
View File
@@ -1,5 +1,5 @@
<template>
<div class="relative overflow-hidden section-padding">
<div class="axis-scope axis-scope--cit relative overflow-hidden section-padding">
<!-- 1. Shadok Capitaine (top-left, profile — at ship's wheel, telescope) -->
<svg class="shadok shadok-capitaine" viewBox="0 0 170 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
@@ -421,8 +421,8 @@ useSeoPage({
}
.item-card {
border-radius: 0.75rem;
border: 1px solid hsl(var(--color-text) / 0.08);
border-radius: 16px;
border: none;
background: hsl(var(--color-surface));
transition: border-color 0.2s;
overflow: hidden;
+5 -5
View File
@@ -1,5 +1,5 @@
<template>
<div class="relative overflow-hidden section-padding">
<div class="axis-scope axis-scope--eco relative overflow-hidden section-padding">
<!-- Shadok boulangère (top-left, walking profile, carrying bread tray) -->
<svg class="shadok shadok-boulangere" viewBox="0 0 160 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -469,8 +469,8 @@ const showPdfReader = ref(false)
.item-card {
display: block;
padding: 1.5rem;
border-radius: 0.75rem;
border: 1px solid hsl(var(--color-text) / 0.08);
border-radius: 16px;
border: none;
background: hsl(var(--color-surface));
transition: border-color 0.2s, transform 0.12s ease;
text-decoration: none;
@@ -524,8 +524,8 @@ const showPdfReader = ref(false)
.book-block {
padding: 1.25rem;
border-radius: 0.75rem;
border: 1px solid hsl(var(--color-text) / 0.08);
border-radius: 16px;
border: none;
background: hsl(var(--color-surface));
}
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<div class="section-padding">
<div class="axis-scope axis-scope--eco section-padding">
<div class="container-content">
<!-- Header -->
@@ -1,5 +1,5 @@
<template>
<div class="section-padding">
<div class="axis-scope axis-scope--eco section-padding">
<div class="container-content">
<div class="mx-auto max-w-2xl">
<div class="section-icon mx-auto mb-6">
+30 -2
View File
@@ -1,8 +1,27 @@
<template>
<div>
<HomeHeroSection />
<HomeAxisGrid @open-player="showBookPlayer = true" @open-pdf="showPdfReader = true" />
<HomeVariantParcours
v-if="variant === 'b'"
@open-player="showBookPlayer = true"
@open-pdf="showPdfReader = true"
/>
<HomeVariantEtabli
v-else-if="variant === 'c'"
@open-player="showBookPlayer = true"
@open-pdf="showPdfReader = true"
/>
<template v-else-if="variant === '0'">
<HomeHeroSection />
<HomeAxisGrid @open-player="showBookPlayer = true" @open-pdf="showPdfReader = true" />
</template>
<HomeVariantConsole
v-else
@open-player="showBookPlayer = true"
@open-pdf="showPdfReader = true"
/>
<HomeMessages />
<HomeVariantSwitch v-if="showSwitch" :current="variant" />
<BookPlayer v-model="showBookPlayer" />
<BookPdfReader v-model="showPdfReader" />
</div>
@@ -14,6 +33,15 @@ useSeoPage({
description: 'Construire une autonomie collective à l\'échelle des bassins de vie. Un livre, des chansons et des outils pour l\'émancipation.',
})
// Home variants under review: ?v=a (console, default) · ?v=b (parcours) · ?v=c (établi) · ?v=0 (previous home)
const route = useRoute()
const VARIANTS = ['a', 'b', 'c', '0'] as const
const variant = computed(() => {
const v = String(route.query.v ?? 'a')
return (VARIANTS as readonly string[]).includes(v) ? v : 'a'
})
const showSwitch = computed(() => route.query.v !== undefined)
const showBookPlayer = ref(false)
const showPdfReader = ref(false)
</script>
+92 -2
View File
@@ -1,5 +1,5 @@
<template>
<div class="page-outer section-padding">
<div class="axis-scope axis-scope--num page-outer section-padding">
<!-- Shadok pinguin — tenant une clé USB, petit Tux à ses pieds -->
<svg class="shadok-dl shadok-dl-pinguin" viewBox="0 0 170 210" fill="none" aria-hidden="true">
@@ -483,6 +483,12 @@
<div class="i-lucide-package h-4 w-4" />
{{ section.bouquet.title }}
</h3>
<p v-if="section.bouquet.provider" class="territoire-bouquet-provider">{{ section.bouquet.provider }}</p>
<ul v-if="section.bouquet.statuses" class="bouquet-legend" aria-label="Légende des statuts">
<li v-for="(label, key) in section.bouquet.statuses" :key="key">
<span class="bouquet-dot" :class="`bouquet-dot--${key}`" aria-hidden="true" />{{ label }}
</li>
</ul>
<div class="territoire-bouquet-grid">
<div
v-for="(cat, ci) in section.bouquet.categories"
@@ -494,8 +500,24 @@
<span>{{ cat.label }}</span>
</div>
<ul class="territoire-bouquet-items">
<li v-for="(item, ii) in cat.items" :key="ii">{{ item }}</li>
<template v-for="(item, ii) in cat.items" :key="ii">
<li v-if="typeof item === 'string'">{{ item }}</li>
<li v-else class="bouquet-item">
<span
class="bouquet-dot"
:class="`bouquet-dot--${item.status}`"
:title="section.bouquet.statuses?.[item.status]"
/>
<span class="bouquet-role">{{ item.role }}</span>
<template v-if="item.name">
<a v-if="item.url" :href="item.url" target="_blank" rel="noopener" class="bouquet-name">{{ item.name }}</a>
<span v-else class="bouquet-name">{{ item.name }}</span>
</template>
<span class="sr-only">— {{ section.bouquet.statuses?.[item.status] }}</span>
</li>
</template>
</ul>
<p v-if="cat.note" class="bouquet-note">{{ cat.note }}</p>
</div>
</div>
</div>
@@ -1628,6 +1650,74 @@ useSeoPage({
color: hsl(var(--color-primary) / 0.5);
}
/* Bouquet — status of each stack */
.territoire-bouquet-provider {
font-size: 0.8rem;
color: hsl(var(--color-text-muted));
margin: -0.25rem 0 0.75rem;
}
.bouquet-legend {
list-style: none;
display: flex;
flex-wrap: wrap;
gap: 0.35rem 1rem;
padding: 0;
margin: 0 0 1rem;
font-family: var(--font-mono);
font-size: 0.7rem;
color: hsl(var(--color-text-muted));
}
.bouquet-legend li {
display: inline-flex;
align-items: center;
gap: 0.4rem;
}
.territoire-bouquet-items li.bouquet-item {
padding-left: 0;
display: grid;
grid-template-columns: 0.5rem minmax(0, 1fr);
column-gap: 0.45rem;
align-items: baseline;
}
.bouquet-item > .bouquet-dot { grid-row: 1; align-self: center; }
.bouquet-item > .bouquet-role { grid-column: 2; }
.bouquet-item > .bouquet-name { grid-column: 2; }
.territoire-bouquet-items li.bouquet-item::before { content: none; }
.bouquet-dot {
display: inline-block;
flex-shrink: 0;
width: 0.5rem;
height: 0.5rem;
border-radius: 50%;
align-self: center;
}
.bouquet-dot--service { background: hsl(var(--axis-num)); }
.bouquet-dot--catalogue { box-shadow: inset 0 0 0 1.5px hsl(var(--axis-num)); }
.bouquet-dot--avenir { box-shadow: inset 0 0 0 1px hsl(var(--color-text) / 0.3); }
.bouquet-role { color: hsl(var(--color-text-muted)); }
.bouquet-name {
color: hsl(var(--color-text));
font-weight: 600;
}
a.bouquet-name:hover { color: hsl(var(--axis-num)); }
.bouquet-note {
margin: 0.4rem 0 0;
font-size: 0.72rem;
font-style: italic;
color: hsl(var(--color-text-muted));
}
/* Estimation toggled */
.territoire-estimate {
border-top: 1px solid hsl(var(--color-text) / 0.06);
+61 -3
View File
@@ -1,5 +1,5 @@
<template>
<div class="relative overflow-hidden section-padding">
<div class="axis-scope axis-scope--num relative overflow-hidden section-padding">
<!-- Shadok codeuse — sitting at desk, typing on laptop, glasses -->
<svg class="shadok-codeuse" viewBox="0 0 170 200" fill="none" aria-hidden="true">
<!-- Desk -->
@@ -315,6 +315,16 @@
</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">
<span class="lpk-name">{{ lpk.name }}</span>
<span class="lpk-body">
<span class="lpk-full">{{ lpk.fullName }} — {{ 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"
@@ -379,6 +389,8 @@ definePageMeta({
})
const { data: content } = await usePageContent('numerique')
const { data: site } = await useSiteContent()
const lpk = computed(() => site.value?.lpk)
useSeoPage({
title: content.value?.meta?.title ?? 'Autonomie numérique',
@@ -387,13 +399,59 @@ useSeoPage({
</script>
<style scoped>
.lpk-card {
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;
}
.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: 0.75rem;
border: 1px solid hsl(var(--color-text) / 0.08);
border-radius: 16px;
border: none;
background: hsl(var(--color-surface));
transition: border-color 0.2s;
position: relative;