<script src="https://sites.super.so/snippets/v2/carousel.js"></script> <script src="https://sites.super.so/snippets/v2/lightbox.js"></script> <script> (function(){ const HOME_URL = "https://sebastien-wierinck-workshop.super.site/works/"; const SCROLL_TRIGGER = 400; // px avant d'afficher les boutons function isHome(){ return location.pathname === "/" || location.pathname === ""; // adapte si ta home est ailleurs : // return location.pathname.startsWith("/works/"); } function ensureTriangleButtons(){ if(!document.querySelector('.sw-back-triangle')){ const back = document.createElement('button'); back.className = 'sw-tri-btn sw-back-triangle'; back.setAttribute('aria-label','Retour'); back.title = 'Retour'; back.addEventListener('click', ()=>{ const ref = document.referrer || ""; const sameHost = ref.startsWith(location.origin); if (sameHost && history.length > 1) history.back(); else location.href = HOME_URL; }); document.body.appendChild(back); } if(!document.querySelector('.sw-top-triangle')){ const top = document.createElement('button'); top.className = 'sw-tri-btn sw-top-triangle'; top.setAttribute('aria-label','Haut de page'); top.title = 'Haut de page'; top.addEventListener('click', ()=>{ window.scrollTo({ top: 0, behavior: 'smooth' }); }); document.body.appendChild(top); } } function toggleButtons(){ const buttons = document.querySelectorAll('.sw-tri-btn'); if(window.scrollY > SCROLL_TRIGGER){ buttons.forEach(b => b.classList.add('visible')); } else { buttons.forEach(b => b.classList.remove('visible')); } } function init(){ // si tu gardais l'ancien bouton .sw-back, on le retire document.querySelector('.sw-back')?.remove(); if (isHome()) document.body.classList.add('is-home'); else document.body.classList.remove('is-home'); ensureTriangleButtons(); toggleButtons(); } (document.readyState === 'loading') ? document.addEventListener('DOMContentLoaded', init) : init(); window.addEventListener('scroll', toggleButtons); // Super peut réinjecter du DOM → observer et redéclencher const obs = new MutationObserver((muts)=>{ if ([...muts].some(m=>m.addedNodes && m.addedNodes.length)){ clearTimeout(window.__sw_tri_deb); window.__sw_tri_deb = setTimeout(init,120); } }); obs.observe(document.documentElement, { childList:true, subtree:true }); })(); </script> <script> /* Réorganisation sémantique des pages projet (global) / (function(){ const isProjectPage = () => document.querySelector(".notion-page__properties-layout"); // normalise du texte (pour matcher 'Type' / 'Material' / 'Matière'…) const norm = (s) => (s||"") .normalize("NFD").replace(/[\u0300-\u036f]/g,"") .toLowerCase().trim(); function buildProjectHeader(){ const article = document.querySelector("article.notion-root"); if (!article || article.classList.contains("project-upgraded")) return; const propsLayout = article.querySelector(".notion-page__properties-layout"); if (!propsLayout) return; // pas une fiche projet // Liste des propriétés visibles en haut de page const props = Array.from(propsLayout.querySelectorAll(".notion-page__property")); if (!props.length) return; // Trouver Type et Matière par leur label const byLabel = (label) => props.find(p => norm(p.querySelector(".notion-page__property-name")?.textContent) === norm(label)); const typeProp = byLabel("type") || props[0]; const materialProp = byLabel("material") || byLabel("matiere") || byLabel("materiau") || props[1] || props[0]; // Description (bloc de texte natif juste sous les propriétés) const descEl = article.querySelector(".notion-property.notion-property__text.notion-semantic-string") || article.querySelector(".notion-property.notion-semantic-string") || null; // 1. Vrai titre Notion (heading de la page) let titleText = (article.querySelector(".notion-header__title .notion-semantic-string")?.textContent || "").trim(); // 2. Si pas trouvé → fallback, mais on évite meta:title if(!titleText){ titleText = article.querySelector("h1")?.textContent?.trim() || document.querySelector('meta[property="og:title"]')?.content?.trim() || document.title.replace(/\s[–|-]\s*[^–|-]+$/,"").trim() || decodeURIComponent(location.pathname.split("/").filter(Boolean).pop() || "").replace(/[-_]+/g," "); } // Construire le header const header = document.createElement("header"); header.className = "project-header"; const h3 = document.createElement("h3"); h3.className = "project-title"; h3.textContent = titleText; header.appendChild(h3); const meta = document.createElement("div"); meta.className = "project-meta"; meta.appendChild(typeProp.cloneNode(true)); meta.appendChild(materialProp.cloneNode(true)); header.appendChild(meta); if (descEl){ const descClone = descEl.cloneNode(true); descClone.classList.add("project-desc"); header.appendChild(descClone); } // Injecter le header avant la zone des propriétés propsLayout.parentNode.insertBefore(header, propsLayout); // Masquer les originaux pour éviter les doublons propsLayout.style.display = "none"; if (descEl) descEl.style.display = "none"; // Marqueur pour ne pas rerunner inutilement article.classList.add("project-upgraded"); } // Lancer quand le DOM est prêt + si Super ré-injecte le contenu const start = () => { if (isProjectPage()) buildProjectHeader(); }; (document.readyState === "loading") ? document.addEventListener("DOMContentLoaded", start) : start(); const mo = new MutationObserver(() => start()); mo.observe(document.documentElement, {childList:true, subtree:true}); })(); </script> <script> (function () { // Liste officielle des catégories de séries et leur URL const SERIES_MAP = { 'All': '/series/all', 'OnSite': '/series/onsite', 'Panels': '/series/panels', 'Public': '/series/public-furniture', 'CraftLab': '/series/craftlab', 'Proposal': '/series/proposals', 'Proposals': '/series/proposals', 'R&D': '/series/r-d', 'Explorations': '/series/explorations' }; // Normalise un chemin pour éviter les / en trop function normalizePath(path) { return path.replace(/\/+$/, ''); } const currentPath = normalizePath(location.pathname); // Parcourt tous les .notion-pill du site document.querySelectorAll('.notion-pill').forEach(function (pill) { const label = pill.textContent.trim(); // On ne s'occupe que des labels présents dans SERIES_MAP if (!SERIES_MAP[label]) return; const url = SERIES_MAP[label]; const targetPath = normalizePath(url); // Ajoute une classe d'identification pill.classList.add('sw-series-pill'); pill.style.cursor = 'pointer'; pill.setAttribute('role', 'button'); pill.setAttribute('tabindex', '0'); // État actif si on est sur la page correspondante if (targetPath === currentPath) { pill.classList.add('is-active'); } // Fonction de navigation function go() { window.location.href = url; } // Click souris pill.addEventListener('click', function (e) { e.preventDefault(); go(); }); // Navigation clavier (Enter ou Espace) pill.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); go(); } }); }); })(); </script> <script> window.addEventListener('load', ()=>{ ['https://swws.net/series/all','https://swws.net/series/onsite'].forEach(url=>{ const link = document.createElement('link'); link.rel = 'prefetch'; link.href = url; document.head.appendChild(link); }); }); </script>
/* ===== Triangles minimalistes (monochrome) — scope SW ===== / :root{ / zone cliquable (cercle invisible) : au moins 44px / --sw-hit-size: 50px; / taille des triangles / --sw-tri-left-w: 24px; / largeur base triangle gauche / --sw-tri-left-h: 24px; / hauteur triangle gauche / --sw-tri-up-w: 24px; / largeur base triangle haut / --sw-tri-up-h: 24px; / hauteur triangle haut / / espaces au bord / --sw-gap: 16px; / couleur : on utilise currentColor (hérite du thème) / --sw-fg: currentColor; / opacité légère au repos (facultatif) / --sw-rest: .85; } @media (max-width: 768px){ :root{ --sw-hit-size: 46px; --sw-gap: 12px; } } / Bouton générique (cercle invisible) / .sw-tri-btn{ position: fixed; inline-size: var(--sw-hit-size); block-size: var(--sw-hit-size); border-radius: 999px; / hit-area circulaire / background: transparent; / invisible / color: var(--sw-fg); z-index: 9999; cursor: pointer; / caché par défaut : visible uniquement après scroll / opacity: 0; pointer-events: none; transition: opacity .25s ease, transform .15s ease; } / rendu focus clavier (a11y) / .sw-tri-btn:focus-visible{ outline: 2px solid currentColor; outline-offset: 2px; } / état visible (ajouté par JS au delà du seuil de scroll) / .sw-tri-btn.visible{ opacity: var(--sw-rest); pointer-events: auto; } @media (hover:hover){ .sw-tri-btn.visible:hover{ opacity: 1; transform: scale(1.02); } } .sw-tri-btn:active{ transform: scale(.98); } / respecte prefers-reduced-motion / @media (prefers-reduced-motion: reduce){ .sw-tri-btn{ transition: opacity .01s linear; } .sw-tri-btn:active{ transform: none; } } / ----- Triangle RETOUR (bas-gauche) : petit triangle ◄ ----- / .sw-back-triangle{ left: var(--sw-gap); bottom: var(--sw-gap); display: grid; place-items: center; } .sw-back-triangle::before{ content:""; display:block; / triangle via bordures (monochrome) / border-top: calc(var(--sw-tri-left-h)/2) solid transparent; border-bottom: calc(var(--sw-tri-left-h)/2) solid transparent; border-right: var(--sw-tri-left-w) solid currentColor; } / ----- Triangle TOP (bas-droite) : petit triangle ▲ ----- / .sw-top-triangle{ right: var(--sw-gap); bottom: var(--sw-gap); display: grid; place-items: center; } .sw-top-triangle::before{ content:""; display:block; border-left: calc(var(--sw-tri-up-w)/2) solid transparent; border-right: calc(var(--sw-tri-up-w)/2) solid transparent; border-bottom: var(--sw-tri-up-h) solid currentColor; } / Option : masquer le bouton "retour" sur la home / body.is-home .sw-back-triangle{ display: none !important; } / ==== Lightbox overlay (force overlay plein écran) ==== / #lightbox-overlay{ position: fixed !important; / clé: sortir du flux / inset: 0 !important; / top:0; right:0; bottom:0; left:0 / z-index: 100000 !important; / au-dessus de tout (triangles, header, etc.) / display: none; / caché par défaut / align-items: center; justify-content: center; background: rgba(0,0,0,.85); / fond sombre / padding: clamp(8px, 4vw, 40px); } / l'init de ton script met "display:flex" -> on accepte les 2 variantes / #lightbox-overlay[style="display: flex"], #lightbox-overlay.open{ display: flex !important; } #lightbox-image{ max-width: min(96vw, 2400px); max-height: 90vh; object-fit: contain; box-shadow: 0 10px 40px rgba(0,0,0,.5); border-radius: 6px; } /* bouton fermer / #lightbox-close{ position: absolute; top: 12px; right: 12px; width: 44px; height: 44px; border-radius: 999px; background: rgba(255,255,255,.9); border: 1px solid rgba(0,0,0,.08); display: grid; place-items: center; cursor: pointer; z-index: 100001; / au-dessus de l'image / } / empêcher le scroll de la page si le lightbox est ouvert (optionnel) / body.lightbox-open { overflow: hidden; } / ce qui marche jusqu ici grader tout / / === Works — grille stable (gauche fixe, droite fluide) === / @media (min-width:1024px){ / Colonne gauche fixe (280px) + colonne droite qui prend tout le reste / .page__works .notion-collection__header-wrapper{ display:grid !important; grid-template-columns: 280px minmax(0, 1fr) !important; gap:28px; align-items:start; } / Menu filtres = colonne 1, sticky, pas de scroll horizontal / .page__works .notion-dropdown__menu-wrapper{ grid-column:1 !important; width:280px !important; position:sticky; top:96px; max-height:calc(100vh - 120px); overflow-y:auto; overflow-x:hidden; padding-right:4px; } / Galerie (ALL + autres vues) = colonne 2, pleine largeur / .page__works .notion-collection__header-wrapper > .notion-collection-gallery, .page__works .notion-collection__header-wrapper > .notion-collection-gallery.small, .page__works .notion-collection__header-wrapper > .notion-collection-gallery.large{ grid-column:2 !important; width:100% !important; max-width:none !important; flex:1 1 auto !important; / neutralise tout 50% résiduel / min-width:0 !important; } / Sécurité : les enfants de la grille peuvent rétrécir */ .page__works .notion-collection__header-wrapper > { min-width:0; } } / === Works — pills + actif jaune (robuste <a>/<button>/<span>) === */ .page__works .notion-dropdown__option, .page__works .notion-dropdown__option { text-decoration:none !important; } .page__works .notion-dropdown__option{ display:inline-block; margin:0 0 10px 0; border:0; box-shadow:none; } .page__works .notion-dropdown__option > a, .page__works .notion-dropdown__option > button, .page__works .notion-dropdown__option > span, .page__works .notion-dropdown__option{ / fallback */ padding:8px 14px; border:1px solid var(--color-border,#dcdcdc); border-radius:9999px; background:transparent; line-height:1.2; transition:background-color .15s ease, border-color .15s ease, color .15s ease; } .page__works .notion-dropdown__option:hover, .page__works .notion-dropdown__option:hover > a, .page__works .notion-dropdown__option:hover > button, .page__works .notion-dropdown__option:hover > span{ background:rgba(255,237,207,.20); border-color:rgba(255,237,207,.60); } .page__works .notion-dropdown__option.active, .page__works .notion-dropdown__option.is-active, .page__works .notion-dropdown__option[aria-selected="true"], .page__works .notion-dropdown__option.active > *, .page__works .notion-dropdown__option.is-active > *, .page__works .notion-dropdown__option[aria-selected="true"] > { background:#FEEDCF !important; border-color:#FEEDCF !important; color:#1b1b1b !important; font-weight:600; } / Works — pills carrées (angles à 90°) / .page__works .notion-dropdown__option > a, .page__works .notion-dropdown__option > button, .page__works .notion-dropdown__option > span, .page__works .notion-dropdown__option{ / fallback si pas d'enfant direct / border-radius: 0 !important; / angles vifs / } / (optionnel) focus clavier net sur angle vif / .page__works .notion-dropdown__option:focus-visible, .page__works .notion-dropdown__option > a:focus-visible, .page__works .notion-dropdown__option > button:focus-visible, .page__works .notion-dropdown__option > span:focus-visible{ outline: 2px solid #1b1b1b; outline-offset: 2px; } / H1/h2 Notion / .notion-header__title, .notion-heading .notion-semantic-string{ font-weight:800; line-height:1.05; letter-spacing:-.012em; font-size: clamp(28px, 4.2vw, 42px); } / Paragraphe intro plus calme / .notion-text{ font-size: clamp(16px, 2.2vw, 18px); color:var(--fg); } / --- Header projet (sobre, garde les styles natifs des propriétés) --- / .project-header { margin: 24px 0 32px; } .project-header .project-title { / taille raisonnable, responsive, sans toucher à la typo du thème / font-size: clamp(3rem, 2.2vw, 1.6rem); font-weight: 600; margin: 0 0 12px; } / Ligne 2 : deux colonnes 50/50 (Type / Matière) / .project-header .project-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; margin: 0 0 12px; } / Ligne 3 : description (on garde la classe native clonée) / .project-header .project-desc { margin-top: 4px; } / Mobile : empiler Type et Matière / @media (max-width: 720px){ .project-header .project-meta { grid-template-columns: 1fr; } } / ===== Fiche projet — alignements fins ===== / / 2 colonnes (Type / Material) avec alignement haut / .project-header .project-meta{ display: grid; grid-template-columns: 1fr 1fr; gap: 18px 28px; / ligne / colonne / align-items: start; / top-aligned / margin: 6px 0 14px; } / Chaque propriété (label + valeurs) sur une seule ligne / .project-header .project-meta > .notion-page__property{ display: flex; align-items: flex-start; / top-aligned entre label et pills / gap: 10px; margin: 0; } / Neutralise la “colonne label” de Notion dans le header / .project-header .project-meta .notion-page__property-name-wrapper{ width: auto !important; min-width: 0 !important; margin: 0 !important; padding: 0 !important; flex: 0 0 auto; } / Label (Type / Material) sobre et calé / .project-header .project-meta .notion-page__property-name{ font-size: .92em; line-height: 1.3; color: #666; margin: 0; } / Valeurs (pills), sans marges parasites + wrap propre / .project-header .project-meta .notion-property{ margin: 0 !important; } .project-header .project-meta .notion-select, .project-header .project-meta .notion-multi_select{ margin: 0; } .project-header .project-meta .notion-pill{ margin: 0 8px 8px 0; } / Mobile : empile Type / Material / @media (max-width: 760px){ .project-header .project-meta{ grid-template-columns: 1fr; } } / --- Harmoniser les titres de projet avec les H2 --- / .project-title { font-family: "Space Grotesk", system-ui, -apple-system, Segoe UI, Roboto, sans-serif; font-weight: 600; / même graisse que les headings / line-height: 1.15; letter-spacing: 0; color: var(--text-color, #222); text-transform: none; margin: 0 0 0.6em 0; / Taille fluide cohérente avec H2 / font-size: clamp(1.75rem, 3.5vw, 2.25rem); } / Option : resserrer un peu sur mobile / @media (max-width: 768px) { .project-title { font-size: 1.6rem; } } / === SWWS — Titres des cartes Notion : fond blanc + hover jaune ============ / .notion-property.notion-property__title.notion-collection-card__property.title.notion-semantic-string { background: ##eee; / fond / color: #000; / texte / padding: 4px 12px; display: inline-block; border-radius: 0px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.25; box-shadow: 0 2px 8px rgba(0,0,0,0.08); transition: background 0.3s ease, color 0.3s ease, box-shadow 0.3s ease; } / OnSite — pills / / --- Effets hover & actif unifiés pour les pills --- / / Hover : fond noir, texte beige clair / .notion-pill:hover { background-color: #000000 !important; color: #feedcf !important; border-color: #000000 !important; transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease; } / Actif (catégorie courante ou clic JS) */ .notion-pill.is-active, .notion-pill.sw-series-pill.is-active { background-color: #000000 !important; color: #feedcf !important; border-color: #000000 !important; }
<link rel="stylesheet" href="https://sites.super.so/snippets/lightbox.css"/> <link href="https://evenbloom.github.io/Visu/public/css/main.css" rel="stylesheet"/> <link rel="stylesheet" href="https://sites.super.so/snippets/v2/carousel.css">