Compare commits
1 Commits
feat/v12-m
...
feat/v12-q
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7791054ca0 |
@@ -6,7 +6,7 @@
|
|||||||
<nav
|
<nav
|
||||||
id="mobile-tab-bar"
|
id="mobile-tab-bar"
|
||||||
aria-label="Navigation colonnes"
|
aria-label="Navigation colonnes"
|
||||||
class="fixed top-12 left-0 right-0 z-30 h-11 bg-white border-b border-neutral-200 flex items-stretch justify-around md:hidden"
|
class="fixed top-0 left-0 right-0 z-30 h-11 bg-white border-b border-neutral-200 flex items-stretch justify-around md:hidden"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
---
|
|
||||||
// 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"
|
|
||||||
---
|
|
||||||
<header
|
|
||||||
class="site-header w-full border-b border-[#E5E7EB] bg-[#FAFAF7] text-[#0F172A] px-4 md:px-6 flex items-center"
|
|
||||||
role="banner"
|
|
||||||
>
|
|
||||||
<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"
|
|
||||||
>
|
|
||||||
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>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.site-header {
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
.site-header {
|
|
||||||
height: 64px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -14,8 +14,27 @@ interface JournalItem {
|
|||||||
|
|
||||||
const selectedItem = ref<JournalItem | null>(null)
|
const selectedItem = ref<JournalItem | null>(null)
|
||||||
const iframeRef = ref<HTMLIFrameElement | null>(null)
|
const iframeRef = ref<HTMLIFrameElement | null>(null)
|
||||||
|
const wrapperRef = ref<HTMLDivElement | null>(null)
|
||||||
const skeletonHidden = ref(false)
|
const skeletonHidden = ref(false)
|
||||||
|
|
||||||
|
// Force rendu desktop de l'iframe AEP : viewport simulée 1440px + scale dynamique
|
||||||
|
const VIEWPORT_W = 1440
|
||||||
|
const iframeScale = ref(0.42)
|
||||||
|
let resizeObs: ResizeObserver | null = null
|
||||||
|
|
||||||
|
const updateScale = () => {
|
||||||
|
if (!wrapperRef.value) return
|
||||||
|
const w = wrapperRef.value.clientWidth
|
||||||
|
if (w > 0) iframeScale.value = w / VIEWPORT_W
|
||||||
|
}
|
||||||
|
|
||||||
|
const iframeStyle = computed(() => ({
|
||||||
|
width: VIEWPORT_W + 'px',
|
||||||
|
height: (100 / iframeScale.value) + '%',
|
||||||
|
transform: `scale(${iframeScale.value})`,
|
||||||
|
transformOrigin: '0 0',
|
||||||
|
}))
|
||||||
|
|
||||||
const onJournalItemClick = (e: Event) => {
|
const onJournalItemClick = (e: Event) => {
|
||||||
const ce = e as CustomEvent
|
const ce = e as CustomEvent
|
||||||
if (ce.detail?.item) selectedItem.value = ce.detail.item
|
if (ce.detail?.item) selectedItem.value = ce.detail.item
|
||||||
@@ -23,9 +42,16 @@ const onJournalItemClick = (e: Event) => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('journal-item-click', onJournalItemClick as EventListener)
|
window.addEventListener('journal-item-click', onJournalItemClick as EventListener)
|
||||||
|
if (wrapperRef.value && typeof ResizeObserver !== 'undefined') {
|
||||||
|
updateScale()
|
||||||
|
resizeObs = new ResizeObserver(updateScale)
|
||||||
|
resizeObs.observe(wrapperRef.value)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('journal-item-click', onJournalItemClick as EventListener)
|
window.removeEventListener('journal-item-click', onJournalItemClick as EventListener)
|
||||||
|
resizeObs?.disconnect()
|
||||||
|
resizeObs = null
|
||||||
})
|
})
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
@@ -89,18 +115,19 @@ const formatDate = (iso: string) => {
|
|||||||
|
|
||||||
<!-- DEFAULT : iframe AEP (aucun item selectionne) -->
|
<!-- DEFAULT : iframe AEP (aucun item selectionne) -->
|
||||||
<div v-if="!selectedItem" class="h-full">
|
<div v-if="!selectedItem" class="h-full">
|
||||||
<div class="relative h-full bg-neutral-100">
|
<div ref="wrapperRef" class="relative h-full bg-neutral-100 overflow-hidden">
|
||||||
<div
|
<div
|
||||||
v-if="!skeletonHidden"
|
v-if="!skeletonHidden"
|
||||||
id="embed-skeleton"
|
id="embed-skeleton"
|
||||||
class="absolute inset-0 flex items-center justify-center bg-neutral-50 animate-pulse"
|
class="absolute inset-0 flex items-center justify-center bg-neutral-50 animate-pulse z-10"
|
||||||
>
|
>
|
||||||
<span class="text-neutral-400 text-sm">Chargement de la carte AEP...</span>
|
<span class="text-neutral-400 text-sm">Chargement de la carte AEP...</span>
|
||||||
</div>
|
</div>
|
||||||
<iframe
|
<iframe
|
||||||
src="https://aep.trans-former.fr/agences"
|
src="https://aep.trans-former.fr/agences"
|
||||||
title="Carte AEP"
|
title="Carte AEP"
|
||||||
class="w-full h-full border-0 opacity-0 transition-opacity duration-500"
|
class="absolute top-0 left-0 border-0 opacity-0 transition-opacity duration-500"
|
||||||
|
:style="iframeStyle"
|
||||||
sandbox="allow-scripts allow-same-origin allow-popups allow-forms"
|
sandbox="allow-scripts allow-same-origin allow-popups allow-forms"
|
||||||
@load="onIframeLoad"
|
@load="onIframeLoad"
|
||||||
ref="iframeRef"
|
ref="iframeRef"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
---
|
---
|
||||||
import '../styles/global.css';
|
import '../styles/global.css';
|
||||||
import Footer from '../components/astro/Footer.astro';
|
import Footer from '../components/astro/Footer.astro';
|
||||||
import SiteHeader from '../components/astro/SiteHeader.astro';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title?: string;
|
title?: string;
|
||||||
@@ -29,11 +28,8 @@ const {
|
|||||||
<meta name="twitter:title" content={title} />
|
<meta name="twitter:title" content={title} />
|
||||||
<meta name="twitter:description" content={description} />
|
<meta name="twitter:description" content={description} />
|
||||||
</head>
|
</head>
|
||||||
<body class="m-0 bg-white text-neutral-900 antialiased min-h-screen flex flex-col">
|
<body class="m-0 bg-white text-neutral-900 antialiased">
|
||||||
<SiteHeader />
|
<slot />
|
||||||
<div class="flex-1 flex flex-col min-h-0">
|
|
||||||
<slot />
|
|
||||||
</div>
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -15,18 +15,15 @@ import PopupOnboarding from '../components/astro/PopupOnboarding.astro';
|
|||||||
<MobileTabBar />
|
<MobileTabBar />
|
||||||
<PopupOnboarding />
|
<PopupOnboarding />
|
||||||
|
|
||||||
<!-- Desktop : grid 3 colonnes (header 64px deja consommes par SiteHeader, on prend le reste) -->
|
<!-- Desktop : grid 3 colonnes -->
|
||||||
<div
|
<div class="hidden md:grid md:grid-cols-[320px_1fr_320px] h-screen overflow-hidden">
|
||||||
class="hidden md:grid md:grid-cols-[320px_1fr_320px] overflow-hidden"
|
|
||||||
style="height: calc(100vh - 64px);"
|
|
||||||
>
|
|
||||||
<aside class="border-r border-neutral-200 overflow-y-auto"><ColJournal /></aside>
|
<aside class="border-r border-neutral-200 overflow-y-auto"><ColJournal /></aside>
|
||||||
<main class="overflow-hidden"><ColCentre /></main>
|
<main class="overflow-hidden"><ColCentre /></main>
|
||||||
<aside class="border-l border-neutral-200 overflow-y-auto"><ColInsta /></aside>
|
<aside class="border-l border-neutral-200 overflow-y-auto"><ColInsta /></aside>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mobile : SwipeContainer Vue island - header 48px + tabbar 44px = 92px reserves -->
|
<!-- Mobile : SwipeContainer Vue island - decale de 44px pour la tabbar -->
|
||||||
<div class="md:hidden overflow-hidden" style="height: calc(100dvh - 48px - 44px); margin-top: 44px;">
|
<div class="md:hidden overflow-hidden" style="height: calc(100dvh - 44px); margin-top: 44px;">
|
||||||
<SwipeContainer client:load>
|
<SwipeContainer client:load>
|
||||||
<ColJournal slot="left" />
|
<ColJournal slot="left" />
|
||||||
<ColCentre slot="center" />
|
<ColCentre slot="center" />
|
||||||
|
|||||||
Reference in New Issue
Block a user