Compare commits

...
Author SHA1 Message Date
Jules NenyandClaude Opus 5.5 fec977a58f feat(carte-o): brouillon des 17 accroches au survol (à valider par Jules)
Champ problematique ajouté aux 17 nodes de carte-o-source.yaml (source
éditoriale), propagé par build-carte-o.js, lu en priorité par l'infobulle
de CarteO.vue. Page temporaire /apercu-accroches pour la relecture :
À SUPPRIMER avant merge. Branche partie de wip/pont-tailwind4-20260817 :
ne pas merger telle quelle dans main (elle embarque le pont non validé),
cherry-pick de ce commit seul, sans la page d'aperçu.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SHuEiSieLhPY2uZbCu6uQb
2026-09-29 14:06:25 +02:00
Jules NenyandClaude Fable 5.1 6a01db1833 wip(pont): pont Tailwind 4 câblé + pont-test.astro + carte-o.json (session défrichage 17/08, mis à l'abri le 22/09)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-22 14:05:12 +02:00
Jules NenyandClaude Sonnet 5 f642160d4b fix(insta): feed remplit toute la hauteur de colonne, Boutique collée en bas
La zone de scroll avait une max-height fixe (420px) alors que la colonne
fait toute la hauteur de la page -> gros bandeau blanc entre le feed et
le footer. Passe en flex-col (header shrink-0, feed flex-1 scrollable,
Boutique shrink-0 collée en bas), le feed occupe maintenant tout
l'espace disponible.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 17:55:43 +02:00
Jules NenyandClaude Sonnet 5 d58911a7e8 feat(insta): simplifie - 2 comptes en header, Boutique seule en bas
Retire les 3 onglets (trop petits, moches). Header : "Jules Neny"
(compte actif, lien direct) + "AEP" (lien direct vers @aep.politique,
pas encore de feed dédié). Bande du bas : uniquement "Boutique"
(placeholder désactivé).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 17:53:26 +02:00
Jules NenyandClaude Sonnet 5 5a4a8fbc2b feat(insta): 3 onglets (artistique/boutique/politique) + bande réduite
Réduit le padding de la bande d'actions (py-3->py-1, gap serré) pour
coller au feed. Ajoute un 3e onglet "Compte Insta politique" en
placeholder désactivé, à côté de "Boutique", en prévision d'une
navigation à onglets entre les comptes @julesneny (artistique, actif)
et @aep.politique (à venir).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 17:49:44 +02:00
Jules NenyandClaude Sonnet 5 aa819600f5 feat(insta): remplace la grille 3x3 par un feed scrollable (13 captures)
Empile les 13 captures d'écran du feed réel (IMG_5439..5451, plus récent
en haut, plus ancien en bas) dans une colonne overflow-y:auto avec
scrollbar fine, pour permettre de naviguer dans le feed sans quitter le
site. Petit gap 2px entre chaque capture (façon séparation Instagram).

Dédoublonnage pixel des zones de chevauchement tenté (corrélation de
luminance par ligne) mais abandonné : signal pas assez discriminant sur
ce contenu (fonds crème uniformes). Chevauchement naturel accepté.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 17:45:13 +02:00
Jules NenyandClaude Sonnet 5 11499a147c feat(insta): remplace Behold (jamais configuré) par galerie statique @julesneny
ColInsta n'affichait que le fallback bio depuis PC5 (feed IDs Behold jamais
renseignés, login Facebook Business trop lourd). Retire le bloc @aep.politique
(jugé insatisfaisant) et remplace InstaFeed par une galerie 3x3 statique de
9 vignettes réelles (croppées depuis le dernier screenshot du feed), avec
boutons Compte Insta + Boutique (placeholder désactivé, en attente d'URL).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-07 17:05:41 +02:00
24 changed files with 193 additions and 111 deletions
+6
View File
@@ -13,6 +13,7 @@
"@astrojs/vue": "^6.0.1",
"@fontsource-variable/roboto-condensed": "^5.2.8",
"@tailwindcss/vite": "^4.2.4",
"@transformer/ui": "git+https://git.trans-former.fr/jules/design-system.git",
"@types/d3": "^7.4.3",
"astro": "^6.3.1",
"d3": "^7.9.0",
@@ -2366,6 +2367,11 @@
"vite": "^5.2.0 || ^6 || ^7 || ^8"
}
},
"node_modules/@transformer/ui": {
"version": "0.1.0",
"resolved": "git+https://git.trans-former.fr/jules/design-system.git#b7f4f21b7c41258d976a878a8a3c2d4ce45a2ede",
"license": "UNLICENSED"
},
"node_modules/@types/d3": {
"version": "7.4.3",
"resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz",
+1
View File
@@ -20,6 +20,7 @@
"@astrojs/vue": "^6.0.1",
"@fontsource-variable/roboto-condensed": "^5.2.8",
"@tailwindcss/vite": "^4.2.4",
"@transformer/ui": "git+https://git.trans-former.fr/jules/design-system.git",
"@types/d3": "^7.4.3",
"astro": "^6.3.1",
"d3": "^7.9.0",
+19
View File
@@ -4,6 +4,8 @@
# statut: gestation (draft/en cours) | edite (publie)
# nature: essai (texte politique) | projet (projet archi)
# niveau: 0 (centre) | 1 (concepts force) | 2 (thematiques/projets)
# problematique (optionnel) : accroche affichee au survol du node (une tension, pas une definition)
# BROUILLON MOE 29/09 : les 17 textes sont a valider par Jules
# domain (optionnel) : domaine plateforme source pour logo Brandfetch CDN
# - affiche logo en bas-droite du node si zoom > 1.5x
# - V1.2 par defaut : substack.com pour tous les essais AEP
@@ -16,6 +18,7 @@ centre:
niveau: 0
nature: essai
statut: gestation
problematique: "Diagnostiquer avant de prescrire : où le corps social bloque-t-il, et quelle aiguille le débloque ?"
resume: "Manifeste central AEP : inventer un nouveau contrat social et diagnostiquer/soigner les pathologies du corps social."
concepts_force: []
@@ -26,90 +29,105 @@ thematiques:
niveau: 2
nature: essai
statut: gestation
problematique: "Tout se tient : c'est pour ça qu'on ne répare rien en traitant les problèmes un par un."
domain: "substack.com"
- id: "pratiques-collectives"
label: "Pratiques collectives"
niveau: 2
nature: essai
statut: gestation
problematique: "Seul, chacun a raison et reste impuissant. Qu'est-ce qui fait passer du « je » au « nous » ?"
domain: "substack.com"
- id: "art-narration"
label: "Art & narration"
niveau: 2
nature: essai
statut: gestation
problematique: "On ne quitte pas un monde qu'on n'arrive pas à raconter autrement."
domain: "substack.com"
- id: "pouvoir-domination"
label: "Rapport au pouvoir"
niveau: 2
nature: essai
statut: gestation
problematique: "Le pouvoir des pires n'est pas un accident : c'est une mécanique. Laquelle démonter ?"
domain: "substack.com"
- id: "medias-critique"
label: "Medias & pensee critique"
niveau: 2
nature: essai
statut: gestation
problematique: "S'informer tous les jours et comprendre de moins en moins : à qui profite le bruit ?"
domain: "substack.com"
- id: "justice-securite"
label: "Justice & securite"
niveau: 2
nature: essai
statut: gestation
problematique: "Dure pour les faibles, douce pour les puissants : punir plus, ou réparer mieux ?"
domain: "substack.com"
- id: "sante-globale"
label: "Sante globale"
niveau: 2
nature: essai
statut: gestation
problematique: "Le burn-out est-il une maladie à soigner, ou le symptôme d'un travail à changer ?"
domain: "substack.com"
- id: "agriculture"
label: "Agriculture"
niveau: 2
nature: essai
statut: gestation
problematique: "Le sol vivant est une infrastructure à entretenir, pas un stock à vider."
domain: "substack.com"
- id: "post-croissance"
label: "Post-croissance"
niveau: 2
nature: essai
statut: gestation
problematique: "Performants jusqu'à casser : et si la robustesse valait mieux que la croissance ?"
domain: "substack.com"
- id: "anthropocene"
label: "Anthropocene & effondrement"
niveau: 2
nature: essai
statut: gestation
problematique: "Quand tout se dérègle en même temps, que protège-t-on en premier ?"
domain: "substack.com"
- id: "education"
label: "Education a la transformation"
niveau: 2
nature: essai
statut: gestation
problematique: "Former des esprits qui doutent, ou des rouages qui tiennent le rang ?"
domain: "substack.com"
- id: "urbanisme"
label: "Urbanisme"
niveau: 2
nature: essai
statut: gestation
problematique: "Couler du béton neuf, ou transformer ce qui est déjà là ?"
domain: "substack.com"
- id: "geopolitique"
label: "Geopolitique & decolonisation"
niveau: 2
nature: essai
statut: gestation
problematique: "Notre confort repose sur un empire qui n'a jamais vraiment pris fin. Qui paie l'addition ?"
domain: "substack.com"
- id: "ia-technologie"
label: "IA & technologie"
niveau: 2
nature: essai
statut: gestation
problematique: "Un outil qui pense à notre place nous rend-il plus libres, ou plus dépendants ?"
domain: "substack.com"
- id: "spiritualite"
label: "Spiritualite"
niveau: 2
nature: essai
statut: gestation
problematique: "Retrouver du sens sans retomber dans le dogme, ni dans le développement personnel."
domain: "substack.com"
projets:
@@ -118,6 +136,7 @@ projets:
niveau: 2
nature: projet
statut: gestation
problematique: "7,6 millions de maisons périurbaines : une impasse, ou le plus grand chantier de transformation du pays ?"
resume: "Transport, mobilite, industrie, politique - projet archi. Exemple de projet archi relie aux thematiques AEP."
# V1.3-D : lien explicite au noeud central (pont vision <-> pratique)
lien_central: true
+35 -18
View File
@@ -1,6 +1,6 @@
{
"version": "1.1",
"generatedAt": "2026-05-12T09:28:20.972Z",
"generatedAt": "2026-09-29T12:05:12.880Z",
"nodes": [
{
"id": "contrat-social-medecine-corps-social",
@@ -10,7 +10,8 @@
"statut": "gestation",
"resume": "Manifeste central AEP : inventer un nouveau contrat social et diagnostiquer/soigner les pathologies du corps social.",
"radius": 30,
"family": "concept"
"family": "concept",
"problematique": "Diagnostiquer avant de prescrire : où le corps social bloque-t-il, et quelle aiguille le débloque ?"
},
{
"id": "systemique",
@@ -21,7 +22,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Tout se tient : c'est pour ça qu'on ne répare rien en traitant les problèmes un par un."
},
{
"id": "pratiques-collectives",
@@ -32,7 +34,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Seul, chacun a raison et reste impuissant. Qu'est-ce qui fait passer du « je » au « nous » ?"
},
{
"id": "art-narration",
@@ -43,7 +46,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "On ne quitte pas un monde qu'on n'arrive pas à raconter autrement."
},
{
"id": "pouvoir-domination",
@@ -54,7 +58,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Le pouvoir des pires n'est pas un accident : c'est une mécanique. Laquelle démonter ?"
},
{
"id": "medias-critique",
@@ -65,7 +70,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "S'informer tous les jours et comprendre de moins en moins : à qui profite le bruit ?"
},
{
"id": "justice-securite",
@@ -76,7 +82,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Dure pour les faibles, douce pour les puissants : punir plus, ou réparer mieux ?"
},
{
"id": "sante-globale",
@@ -87,7 +94,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Le burn-out est-il une maladie à soigner, ou le symptôme d'un travail à changer ?"
},
{
"id": "agriculture",
@@ -98,7 +106,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Le sol vivant est une infrastructure à entretenir, pas un stock à vider."
},
{
"id": "post-croissance",
@@ -109,7 +118,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Performants jusqu'à casser : et si la robustesse valait mieux que la croissance ?"
},
{
"id": "anthropocene",
@@ -120,7 +130,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Quand tout se dérègle en même temps, que protège-t-on en premier ?"
},
{
"id": "education",
@@ -131,7 +142,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Former des esprits qui doutent, ou des rouages qui tiennent le rang ?"
},
{
"id": "urbanisme",
@@ -142,7 +154,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Couler du béton neuf, ou transformer ce qui est déjà là ?"
},
{
"id": "geopolitique",
@@ -153,7 +166,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Notre confort repose sur un empire qui n'a jamais vraiment pris fin. Qui paie l'addition ?"
},
{
"id": "ia-technologie",
@@ -164,7 +178,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Un outil qui pense à notre place nous rend-il plus libres, ou plus dépendants ?"
},
{
"id": "spiritualite",
@@ -175,7 +190,8 @@
"resume": null,
"radius": 12,
"family": "concept",
"domain": "substack.com"
"domain": "substack.com",
"problematique": "Retrouver du sens sans retomber dans le dogme, ni dans le développement personnel."
},
{
"id": "tmip",
@@ -185,7 +201,8 @@
"statut": "gestation",
"resume": "Transport, mobilite, industrie, politique - projet archi. Exemple de projet archi relie aux thematiques AEP.",
"radius": 18,
"family": "ressource"
"family": "ressource",
"problematique": "7,6 millions de maisons périurbaines : une impasse, ou le plus grand chantier de transformation du pays ?"
}
],
"edges": [
Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

+2
View File
@@ -59,6 +59,8 @@ async function main() {
}
// V1.2-O : propage le champ optionnel domain (logo plateforme via Brandfetch CDN)
if (obj.domain) node.domain = obj.domain
// P3 §3 : accroche problematisee affichee au survol (une tension, pas une definition)
if (obj.problematique) node.problematique = obj.problematique
nodes.push(node)
}
+9 -15
View File
@@ -1,24 +1,18 @@
---
import InstaFeed from '../vue/InstaFeed.vue';
// Feed IDs Behold a remplir apres inscription Behold (voir docs/BEHOLD-SETUP.md)
const FEED_AEP = import.meta.env.PUBLIC_BEHOLD_AEP || 'PLACEHOLDER_AEP';
const FEED_JULESNENY = import.meta.env.PUBLIC_BEHOLD_JULESNENY || 'PLACEHOLDER_JULESNENY';
const JULESNENY_FEED = Array.from(
{ length: 13 },
(_, i) => `/images/instagram/feed/feed-${String(i + 1).padStart(2, '0')}.jpg`
);
---
<div class="h-full overflow-y-auto">
<div class="h-full overflow-hidden">
<InstaFeed
client:visible
feedId={FEED_AEP}
account="@aep.politique"
accountUrl="https://www.instagram.com/aep.politique/"
fallbackBio="Carrousels manifeste AEP ; pensee politique eco-architecture"
/>
<InstaFeed
client:visible
feedId={FEED_JULESNENY}
account="@julesneny"
account="Jules Neny"
accountUrl="https://www.instagram.com/julesneny/"
fallbackBio="Peinture, poesie, Corse ; archives visuelles personnelles"
secondAccount="AEP"
secondAccountUrl="https://www.instagram.com/aep.politique/"
feedImages={JULESNENY_FEED}
/>
</div>
+2 -1
View File
@@ -20,6 +20,7 @@ interface CarteNode {
theme?: string
path?: string
domain?: string // V1.2-O : domaine plateforme source (logo Brandfetch CDN)
problematique?: string // P3 §3 : accroche au survol (brouillon MOE 29/09, a valider)
}
// V1.2-O : logos plateforme via Brandfetch CDN (visible zoom > 1.5x seulement)
@@ -364,7 +365,7 @@ function render() {
// Tooltip <title>
nodeGroups.append('title')
.text(d => `${d.label}\n[${d.family}]\n${truncate(d.resume || d.intention || '', 200)}`)
.text(d => `${d.label}\n[${d.family}]\n${truncate(d.problematique || d.resume || d.intention || '', 200)}`)
// V1.3-D : Simulation force-directed fit-cadre + animation continue subtile
// - link distance/strength differencies : TMIP (central) court/fort, autres essais souples
+50 -77
View File
@@ -1,57 +1,16 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
interface BeholdPost {
id: string;
permalink: string;
mediaUrl: string;
thumbnailUrl?: string;
caption?: string;
mediaType: 'IMAGE' | 'VIDEO' | 'CAROUSEL_ALBUM';
timestamp: string;
}
const props = defineProps<{
feedId: string;
defineProps<{
account: string;
accountUrl: string;
fallbackBio?: string;
secondAccount: string;
secondAccountUrl: string;
feedImages: string[]; // ordonné du plus récent (haut) au plus ancien (bas)
}>();
const posts = ref<BeholdPost[]>([]);
const loading = ref(true);
const error = ref<string | null>(null);
const isPlaceholder = (id: string) => !id || id.startsWith('PLACEHOLDER_');
onMounted(async () => {
if (isPlaceholder(props.feedId)) {
loading.value = false;
error.value = 'no-feed-id';
return;
}
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
const res = await fetch(`https://feeds.behold.so/${props.feedId}`, {
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!res.ok) throw new Error(`Behold returned ${res.status}`);
const data = await res.json();
const items: BeholdPost[] = Array.isArray(data) ? data : (data.posts ?? []);
posts.value = items.slice(0, 6);
} catch (e) {
error.value = (e as Error).message || 'fetch-error';
} finally {
loading.value = false;
}
});
</script>
<template>
<section class="border-b border-neutral-200 last:border-b-0">
<header class="px-4 py-3 flex items-center justify-between">
<section class="h-full flex flex-col border-b border-neutral-200 last:border-b-0">
<header class="shrink-0 px-4 py-2 flex items-center justify-between gap-3">
<a
:href="accountUrl"
target="_blank"
@@ -60,48 +19,62 @@ onMounted(async () => {
>
{{ account }}
</a>
<span v-if="loading" class="text-xs text-neutral-400">...</span>
</header>
<div v-if="loading" class="grid grid-cols-2 gap-1 p-1">
<div
v-for="i in 4"
:key="i"
class="aspect-square bg-neutral-100 animate-pulse"
/>
</div>
<div
v-else-if="posts.length"
class="grid grid-cols-2 gap-1 p-1"
>
<a
v-for="post in posts"
:key="post.id"
:href="post.permalink"
:href="secondAccountUrl"
target="_blank"
rel="noopener"
class="block aspect-square overflow-hidden group"
class="font-medium text-sm text-neutral-500 hover:underline hover:text-neutral-800"
>
<img
:src="post.thumbnailUrl || post.mediaUrl"
:alt="post.caption?.slice(0, 80) || account"
loading="lazy"
class="w-full h-full object-cover group-hover:scale-105 transition-transform"
/>
{{ secondAccount }}
</a>
</div>
</header>
<div v-else class="p-4 text-sm text-neutral-600">
<p v-if="fallbackBio" class="mb-3">{{ fallbackBio }}</p>
<div class="insta-feed-scroll flex-1 min-h-0">
<a
:href="accountUrl"
target="_blank"
rel="noopener"
class="inline-block px-3 py-2 bg-neutral-900 text-white rounded-lg text-sm"
:aria-label="`Voir le compte Instagram ${account}`"
>
Voir sur Instagram &rarr;
<img
v-for="(src, i) in feedImages"
:key="i"
:src="src"
alt=""
loading="lazy"
class="block w-full feed-img"
/>
</a>
</div>
<div class="shrink-0 px-2 py-1">
<span
class="block text-center px-3 py-1 bg-neutral-200 text-neutral-400 rounded text-xs cursor-not-allowed"
aria-disabled="true"
title="Boutique — bientôt disponible"
>
Boutique
</span>
</div>
</section>
</template>
<style scoped>
.insta-feed-scroll {
overflow-y: auto;
scrollbar-width: thin;
}
.insta-feed-scroll::-webkit-scrollbar {
width: 6px;
}
.insta-feed-scroll::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.25);
border-radius: 3px;
}
.insta-feed-scroll::-webkit-scrollbar-track {
background: transparent;
}
.feed-img + .feed-img {
margin-top: 2px;
}
</style>
+44
View File
@@ -0,0 +1,44 @@
---
// Page TEMPORAIRE d'apercu des 17 accroches de la Carte O (P3 §3, brouillon MOE 29/09).
// Sert a la relecture de Jules : chaque node avec l'accroche qui s'affichera au survol.
// A SUPPRIMER avant tout merge dans main.
import carte from '../../public/data/carte-o.json';
export const prerender = true;
const nodes = carte.nodes as Array<{ id: string; label: string; problematique?: string; niveau?: number }>;
---
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>apercu-accroches</title>
<style>
body { font-family: system-ui, sans-serif; background: #f7f4ee; color: #1d1d1b; margin: 0; padding: 32px 16px; }
main { max-width: 760px; margin: 0 auto; }
h1 { font-size: 1.1rem; font-weight: 600; margin: 0 0 4px; }
p.note { margin: 0 0 24px; color: #5b5a55; font-size: .9rem; }
ol { list-style: none; padding: 0; margin: 0; display: grid; gap: 10px; }
li { background: #fff; border: 1px solid #e3ded3; border-radius: 8px; padding: 12px 14px; }
li.centre { border-color: #1d1d1b; }
.label { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; color: #6b6a64; }
.id { font-family: ui-monospace, monospace; font-size: .7rem; color: #9a978f; margin-left: 6px; text-transform: none; }
.acc { font-size: 1.05rem; line-height: 1.4; margin-top: 4px; }
.manque { color: #b3261e; }
</style>
</head>
<body>
<main>
<h1>Carte O : accroches au survol (brouillon, à valider)</h1>
<p class="note">{nodes.filter((n) => n.problematique).length} accroches sur {nodes.length} nodes, lues dans <code>public/data/carte-o.json</code>.</p>
<ol>
{nodes.map((n, i) => (
<li class={n.niveau === 0 ? 'centre' : ''}>
<div class="label">{i + 1}. {n.label}<span class="id">{n.id}</span></div>
<div class={n.problematique ? 'acc' : 'acc manque'}>{n.problematique ?? 'aucune accroche'}</div>
</li>
))}
</ol>
</main>
</body>
</html>
+20
View File
@@ -0,0 +1,20 @@
---
// Page TEMPORAIRE de test du pont Tailwind 4 (@transformer/ui) — P3 §1.
// Sert a verifier que le pont compile les utilitaires et que les tokens
// se resolvent en vraies valeurs. A supprimer apres validation.
export const prerender = true;
---
<!doctype html>
<html lang="fr">
<head><meta charset="utf-8" /><title>pont-test</title></head>
<body class="bg-bg text-text">
<div class="bg-surface text-text-muted border-border">surface / muted / border</div>
<div class="bg-primary text-on-primary">primary / on-primary</div>
<div class="bg-accent text-on-accent">accent / on-accent</div>
<div class="text-link hover:text-link-hover">lien</div>
<div class="bg-success bg-warning bg-danger">etats</div>
<div class="font-(family-name:--font-heading) rounded-(--radius-md) shadow-(--shadow-md) ease-(--ease-out)">
syntaxe var arbitraire (namespaces non mappes)
</div>
</body>
</html>
+5
View File
@@ -1,4 +1,9 @@
@import "tailwindcss";
/* Pont design system (P3 §1) : tokens + mappings @theme Tailwind 4.
Pas de reset.css ni theme/*.css tant que la palette racine n'est pas tranchee —
le bridge seul ne change aucun rendu (il ne definit que des variables). */
@import "@transformer/ui/tokens.css";
@import "@transformer/ui/tailwind.css";
/* Typographie monospace - labels editoriaux (V1.1-G.1) */
.font-mono-editorial,