Compare commits
6 Commits
feat/v12-p
...
feat/v13-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e90a7e12ef | ||
|
|
e43ec60ecf | ||
|
|
1033099663 | ||
|
|
9bb55bc311 | ||
|
|
7ec0efdeb5 | ||
|
|
a1d6271b65 |
10
package-lock.json
generated
10
package-lock.json
generated
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^10.1.0",
|
||||
"@astrojs/vue": "^6.0.1",
|
||||
"@fontsource-variable/roboto-condensed": "^5.2.8",
|
||||
"@tailwindcss/vite": "^4.2.4",
|
||||
"@types/d3": "^7.4.3",
|
||||
"astro": "^6.3.1",
|
||||
@@ -1064,6 +1065,15 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@fontsource-variable/roboto-condensed": {
|
||||
"version": "5.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource-variable/roboto-condensed/-/roboto-condensed-5.2.8.tgz",
|
||||
"integrity": "sha512-aIZ2kYSoJHkTI4z8x/PRgKX6Zb9TTtSE/u+fUYeiwL+5trP9rhYYEEeNjRttaMqRgoDHcSueArdRZ43wf/i2Kw==",
|
||||
"license": "OFL-1.1",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ayuhito"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/colour": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz",
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^10.1.0",
|
||||
"@astrojs/vue": "^6.0.1",
|
||||
"@fontsource-variable/roboto-condensed": "^5.2.8",
|
||||
"@tailwindcss/vite": "^4.2.4",
|
||||
"@types/d3": "^7.4.3",
|
||||
"astro": "^6.3.1",
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
# statut: gestation (draft/en cours) | edite (publie)
|
||||
# nature: essai (texte politique) | projet (projet archi)
|
||||
# niveau: 0 (centre) | 1 (concepts force) | 2 (thematiques/projets)
|
||||
# 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
|
||||
|
||||
version: "1.1"
|
||||
|
||||
@@ -23,76 +26,91 @@ thematiques:
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "pratiques-collectives"
|
||||
label: "Pratiques collectives"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "art-narration"
|
||||
label: "Art & narration"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "pouvoir-domination"
|
||||
label: "Rapport au pouvoir"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "medias-critique"
|
||||
label: "Medias & pensee critique"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "justice-securite"
|
||||
label: "Justice & securite"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "sante-globale"
|
||||
label: "Sante globale"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "agriculture"
|
||||
label: "Agriculture"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "post-croissance"
|
||||
label: "Post-croissance"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "anthropocene"
|
||||
label: "Anthropocene & effondrement"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "education"
|
||||
label: "Education a la transformation"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "urbanisme"
|
||||
label: "Urbanisme"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "geopolitique"
|
||||
label: "Geopolitique & decolonisation"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "ia-technologie"
|
||||
label: "IA & technologie"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
- id: "spiritualite"
|
||||
label: "Spiritualite"
|
||||
niveau: 2
|
||||
nature: essai
|
||||
statut: gestation
|
||||
domain: "substack.com"
|
||||
|
||||
projets:
|
||||
- id: "tmip"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"version": "1.1",
|
||||
"generatedAt": "2026-05-11T16:41:21.600Z",
|
||||
"generatedAt": "2026-05-11T16:47:45.459Z",
|
||||
"nodes": [
|
||||
{
|
||||
"id": "contrat-social-medecine-corps-social",
|
||||
@@ -20,7 +20,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "pratiques-collectives",
|
||||
@@ -30,7 +31,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "art-narration",
|
||||
@@ -40,7 +42,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "pouvoir-domination",
|
||||
@@ -50,7 +53,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "medias-critique",
|
||||
@@ -60,7 +64,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "justice-securite",
|
||||
@@ -70,7 +75,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "sante-globale",
|
||||
@@ -80,7 +86,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "agriculture",
|
||||
@@ -90,7 +97,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "post-croissance",
|
||||
@@ -100,7 +108,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "anthropocene",
|
||||
@@ -110,7 +119,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "education",
|
||||
@@ -120,7 +130,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "urbanisme",
|
||||
@@ -130,7 +141,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "geopolitique",
|
||||
@@ -140,7 +152,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "ia-technologie",
|
||||
@@ -150,7 +163,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "spiritualite",
|
||||
@@ -160,7 +174,8 @@
|
||||
"statut": "gestation",
|
||||
"resume": null,
|
||||
"radius": 12,
|
||||
"family": "concept"
|
||||
"family": "concept",
|
||||
"domain": "substack.com"
|
||||
},
|
||||
{
|
||||
"id": "tmip",
|
||||
|
||||
@@ -43,7 +43,7 @@ async function main() {
|
||||
}
|
||||
|
||||
function addNode(obj) {
|
||||
nodes.push({
|
||||
const node = {
|
||||
id: obj.id,
|
||||
label: obj.label,
|
||||
niveau: obj.niveau,
|
||||
@@ -52,7 +52,10 @@ async function main() {
|
||||
resume: obj.resume || null,
|
||||
radius: getRadius(obj.niveau, obj.nature),
|
||||
family: getFamily(obj.nature),
|
||||
})
|
||||
}
|
||||
// V1.2-O : propage le champ optionnel domain (logo plateforme via Brandfetch CDN)
|
||||
if (obj.domain) node.domain = obj.domain
|
||||
nodes.push(node)
|
||||
}
|
||||
|
||||
const centreId = data.centre.id
|
||||
|
||||
@@ -1,52 +1,80 @@
|
||||
---
|
||||
// SiteHeader.astro - V1.2-M : bandeau header pleine largeur identite site
|
||||
// Palette terre figee : papier #FAFAF7, encre #0F172A, encre douce #475569
|
||||
// Composition retenue : 2 lignes hierarchique
|
||||
// ligne 1 : "Trans-Former" wordmark dominant (semibold tracking serre)
|
||||
// ligne 2 : "Jules Neny" + baseline italique cote a cote (separateur point median)
|
||||
// Rationale : le wordmark domine sans ecraser ; la baseline reste lisible ;
|
||||
// composition adaptee a un manifeste (hierarchie typographique forte).
|
||||
// Hauteur : ~64px desktop / ~48px mobile (compacte)
|
||||
// Baseline raccourcie mobile : "architecture politique du vivant"
|
||||
// SiteHeader.astro - V1.3-C : header 1 ligne fine, liens cliquables, phrase intention Roboto Condensed
|
||||
// Palette V1.3 figee : papier #FAFAF7, encre #0F172A, encre douce #475569, border #E5E7EB
|
||||
// Composition :
|
||||
// Desktop (>= md) : 1 ligne ~44px - Trans-Former | Jules Neny | architecture d'ecologie politique [phrase intention right-aligned, Roboto Condensed]
|
||||
// Mobile (< md) : 2 lignes compactes - ligne 1 Trans-Former / ligne 2 Jules Neny . AEP (cliquables) - phrase intention masquee
|
||||
// Liens :
|
||||
// Trans-Former -> /
|
||||
// Jules Neny -> /a-propos
|
||||
// architecture d'ecologie politique -> https://aep.trans-former.fr (same-tab, site frere coherent)
|
||||
// Typo phrase intention : Roboto Condensed Variable @fontsource (weight 400, font-stretch 75%)
|
||||
import '@fontsource-variable/roboto-condensed/wght.css';
|
||||
---
|
||||
<header
|
||||
class="site-header w-full border-b border-[#E5E7EB] bg-[#FAFAF7] text-[#0F172A] px-4 md:px-6 flex items-center"
|
||||
role="banner"
|
||||
>
|
||||
<!-- Bloc identite (gauche) -->
|
||||
<nav
|
||||
class="flex flex-col md:flex-row md:items-baseline gap-x-2 gap-y-0.5 flex-shrink-0"
|
||||
aria-label="identite site"
|
||||
>
|
||||
<!-- Ligne 1 desktop = wordmark inline ; mobile = ligne dediee -->
|
||||
<a
|
||||
href="/"
|
||||
class="flex flex-col md:flex-row md:items-baseline gap-x-3 gap-y-0 no-underline text-[#0F172A] hover:text-[#0F172A]"
|
||||
aria-label="trans-former.fr - retour accueil"
|
||||
>
|
||||
<!-- Ligne 1 : wordmark dominant -->
|
||||
<span
|
||||
class="font-semibold tracking-tight text-[#0F172A] text-[17px] md:text-[20px] leading-none"
|
||||
class="font-semibold tracking-tight text-[#0F172A] hover:text-[#0F172A] text-[15px] md:text-[16px] leading-none no-underline hover:underline underline-offset-2 decoration-1"
|
||||
aria-label="trans-former.fr - accueil"
|
||||
>
|
||||
Trans-Former
|
||||
</span>
|
||||
|
||||
<!-- Ligne 2 (desktop : inline ; mobile : sous wordmark) : Jules Neny + baseline -->
|
||||
<span class="flex items-baseline gap-2 text-[#475569] leading-none">
|
||||
<span class="text-[11px] md:text-[13px]">Jules Neny</span>
|
||||
<span class="text-[#94A3B8]" aria-hidden="true">·</span>
|
||||
<!-- Baseline longue : desktop / Baseline courte : mobile -->
|
||||
<span class="italic text-[11px] md:text-[13px] hidden sm:inline">
|
||||
architecture d'ecologie politique
|
||||
</span>
|
||||
<span class="italic text-[11px] inline sm:hidden">
|
||||
architecture politique du vivant
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
<!-- Bloc secondaire : Jules Neny . AEP (mobile : ligne 2 ; desktop : inline) -->
|
||||
<span class="flex items-baseline gap-1.5 text-[#475569] leading-none">
|
||||
<span class="text-[#94A3B8] hidden md:inline" aria-hidden="true">·</span>
|
||||
<a
|
||||
href="/a-propos"
|
||||
class="text-[12px] md:text-[13px] text-[#475569] hover:text-[#0F172A] no-underline hover:underline underline-offset-2 decoration-1"
|
||||
>
|
||||
Jules Neny
|
||||
</a>
|
||||
<span class="text-[#94A3B8]" aria-hidden="true">·</span>
|
||||
<a
|
||||
href="https://aep.trans-former.fr"
|
||||
class="text-[12px] md:text-[13px] text-[#475569] hover:text-[#0F172A] no-underline hover:underline underline-offset-2 decoration-1"
|
||||
>
|
||||
architecture d'écologie politique
|
||||
</a>
|
||||
</span>
|
||||
</nav>
|
||||
|
||||
<!-- Phrase intention (droite, desktop only) - Roboto Condensed allongee -->
|
||||
<p
|
||||
class="intention hidden md:block ml-auto pl-6 text-right text-[#475569] text-[11px] leading-tight max-w-[55%]"
|
||||
>
|
||||
Comment créer une pratique systémique, créative et collective de transformation sociale pour répondre à l'effondrement et restaurer notre capacité à habiter la Terre dans l'Anthropocène ?
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<style>
|
||||
.site-header {
|
||||
height: 48px;
|
||||
height: 44px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
@media (max-width: 767px) {
|
||||
.site-header {
|
||||
height: 64px;
|
||||
height: auto;
|
||||
min-height: 48px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
/* Phrase intention : Roboto Condensed Variable, font-stretch 75% (allongement vertical condense)
|
||||
Cantonnee a .intention pour eviter contagion stack Inter */
|
||||
.intention {
|
||||
font-family: 'Roboto Condensed Variable', 'Roboto Condensed', sans-serif;
|
||||
font-weight: 400;
|
||||
font-stretch: 75%;
|
||||
font-style: italic;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,8 +19,15 @@ interface CarteNode {
|
||||
slug?: string
|
||||
theme?: string
|
||||
path?: string
|
||||
domain?: string // V1.2-O : domaine plateforme source (logo Brandfetch CDN)
|
||||
}
|
||||
|
||||
// V1.2-O : logos plateforme via Brandfetch CDN (visible zoom > 1.5x seulement)
|
||||
const BRANDFETCH_CLIENT_ID = '4ae58bd85c8140eab0cee72f40656120'
|
||||
const LOGO_ZOOM_THRESHOLD = 1.5
|
||||
const logoUrl = (domain: string) =>
|
||||
`https://cdn.brandfetch.io/${domain}/w/64/h/64?c=${BRANDFETCH_CLIENT_ID}`
|
||||
|
||||
interface CarteEdge {
|
||||
source: string | CarteNode
|
||||
target: string | CarteNode
|
||||
@@ -187,6 +194,11 @@ function initSvg() {
|
||||
.scaleExtent([0.3, 4])
|
||||
.on('zoom', (event) => {
|
||||
gZoom!.attr('transform', event.transform.toString())
|
||||
// V1.2-O : toggle visibilite logos plateforme selon le niveau de zoom
|
||||
// (evite la surcharge visuelle au niveau d'ensemble, montre detail au drill-down)
|
||||
const scale = event.transform.k
|
||||
gZoom!.selectAll('.logo-overlay')
|
||||
.style('opacity', scale > LOGO_ZOOM_THRESHOLD ? 1 : 0)
|
||||
})
|
||||
|
||||
svgRoot.call(zoomBehavior as any)
|
||||
@@ -290,6 +302,32 @@ function render() {
|
||||
}
|
||||
})
|
||||
|
||||
// V1.2-O : Logo plateforme (visible zoom > 1.5x seulement)
|
||||
// Cercle blanc 14px en bas-droite du node (offset +60% x/+60% y du radius)
|
||||
// Image clip-path circle pour avatar style. Hidden par defaut (opacity 0).
|
||||
const nodeGroupsWithLogo = nodeGroups.filter(d => !!d.domain)
|
||||
|
||||
const logoOverlay = nodeGroupsWithLogo.append('g')
|
||||
.attr('class', 'logo-overlay')
|
||||
.style('opacity', 0)
|
||||
.attr('pointer-events', 'none')
|
||||
|
||||
logoOverlay.append('circle')
|
||||
.attr('cx', d => getRadius(d) * 0.6)
|
||||
.attr('cy', d => getRadius(d) * 0.6)
|
||||
.attr('r', 9)
|
||||
.attr('fill', '#FFFFFF')
|
||||
.attr('stroke', '#0F172A')
|
||||
.attr('stroke-width', 0.5)
|
||||
|
||||
logoOverlay.append('image')
|
||||
.attr('href', d => logoUrl(d.domain!))
|
||||
.attr('x', d => getRadius(d) * 0.6 - 7)
|
||||
.attr('y', d => getRadius(d) * 0.6 - 7)
|
||||
.attr('width', 14)
|
||||
.attr('height', 14)
|
||||
.attr('clip-path', d => `circle(7px at ${getRadius(d) * 0.6}px ${getRadius(d) * 0.6}px)`)
|
||||
|
||||
// Tooltip <title>
|
||||
nodeGroups.append('title')
|
||||
.text(d => `${d.label}\n[${d.family}]\n${truncate(d.resume || d.intention || '', 200)}`)
|
||||
|
||||
@@ -23,24 +23,43 @@ const iframeStyle = computed(() => ({
|
||||
transformOrigin: '0 0',
|
||||
}))
|
||||
|
||||
let fallbackTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
const revealIframe = () => {
|
||||
if (iframeRef.value) {
|
||||
iframeRef.value.classList.remove('opacity-0')
|
||||
iframeRef.value.classList.add('opacity-100')
|
||||
}
|
||||
skeletonHidden.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (wrapperRef.value && typeof ResizeObserver !== 'undefined') {
|
||||
updateScale()
|
||||
resizeObs = new ResizeObserver(updateScale)
|
||||
resizeObs.observe(wrapperRef.value)
|
||||
}
|
||||
// Fallback : si @load ne fire pas dans 2.5s (transform/scale peut bloquer l'event),
|
||||
// on revele quand meme l'iframe pour ne pas laisser le skeleton infini.
|
||||
fallbackTimer = setTimeout(() => {
|
||||
revealIframe()
|
||||
}, 2500)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
resizeObs?.disconnect()
|
||||
resizeObs = null
|
||||
if (fallbackTimer) {
|
||||
clearTimeout(fallbackTimer)
|
||||
fallbackTimer = null
|
||||
}
|
||||
})
|
||||
|
||||
const onIframeLoad = () => {
|
||||
if (iframeRef.value) {
|
||||
iframeRef.value.classList.remove('opacity-0')
|
||||
iframeRef.value.classList.add('opacity-100')
|
||||
if (fallbackTimer) {
|
||||
clearTimeout(fallbackTimer)
|
||||
fallbackTimer = null
|
||||
}
|
||||
skeletonHidden.value = true
|
||||
revealIframe()
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -51,7 +70,7 @@ const onIframeLoad = () => {
|
||||
<div
|
||||
v-if="!skeletonHidden"
|
||||
id="embed-skeleton"
|
||||
class="absolute inset-0 flex items-center justify-center bg-neutral-50 animate-pulse z-10"
|
||||
class="absolute inset-0 flex items-center justify-center bg-neutral-50 animate-pulse"
|
||||
>
|
||||
<span class="text-neutral-400 text-sm">Chargement de la carte AEP...</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user