Compare commits
15
Commits
fc621923d1
..
prod
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6627a63805 | ||
|
|
b1ad60e76e | ||
|
|
edec95abbf | ||
|
|
9f9a2501ee | ||
|
|
d3799fb3b3 | ||
|
|
c19b5899e4 | ||
|
|
914f5fd9d1 | ||
|
|
612896d2c6 | ||
|
|
6a190effab | ||
|
|
a2cb5f9dcf | ||
|
|
829653a9e9 | ||
|
|
0e1b0158d7 | ||
|
|
8bf17caf19 | ||
|
|
45458cdbb8 | ||
|
|
30ca6320f4 |
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,631 @@
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'html' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ html--node--570.html.twig
|
||||
▪️ html--node--%.html.twig
|
||||
▪️ html--node.html.twig
|
||||
✅ html.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/html.html.twig' -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="Generator" content="Drupal 10 (https://www.drupal.org)" />
|
||||
<meta name="MobileOptimized" content="width" />
|
||||
<meta name="HandheldFriendly" content="true" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" href="/core/misc/favicon.ico" type="image/vnd.microsoft.icon" />
|
||||
<link rel="alternate" hreflang="fr" href="http://dev.leshed.fr/node/570" />
|
||||
<link rel="canonical" href="http://dev.leshed.fr/node/570" />
|
||||
<link rel="shortlink" href="http://dev.leshed.fr/node/570" />
|
||||
|
||||
<title>FAGO | Le Shed</title>
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/align.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/fieldgroup.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/container-inline.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/clearfix.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/details.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/hidden.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/item-list.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/js.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/nowrap.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/position-container.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/reset-appearance.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/resize.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/system-status-counter.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/system-status-report-counters.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/system-status-report-general-info.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/core/modules/system/css/components/tablesort.module.css?tjtjpd" />
|
||||
<link rel="stylesheet" media="all" href="/modules/contrib/extlink/css/extlink.css?tjtjpd" />
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<a href="#main-content" class="visually-hidden focusable">
|
||||
Aller au contenu principal
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'off_canvas_page_wrapper' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/off-canvas-page-wrapper.html.twig' -->
|
||||
<div class="dialog-off-canvas-main-canvas" data-off-canvas-main-canvas>
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'page' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ page--node--570.html.twig
|
||||
▪️ page--node--%.html.twig
|
||||
▪️ page--node.html.twig
|
||||
✅ page.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/page.html.twig' -->
|
||||
<div class="layout-container">
|
||||
|
||||
<header role="banner">
|
||||
<section class="header-top"></section>
|
||||
<section class="header-middle">
|
||||
<section class="header-left">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'region' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ region--header-left.html.twig
|
||||
✅ region.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/region.html.twig' -->
|
||||
<div class="wrapper">
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'block' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ block--leshed-identitedusite.html.twig
|
||||
✅ block--system-branding-block.html.twig
|
||||
▪️ block--system.html.twig
|
||||
▪️ block.html.twig
|
||||
-->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/block--system-branding-block.html.twig' -->
|
||||
<div id="block-leshed-identitedusite">
|
||||
|
||||
|
||||
<a href="/" rel="home">Le Shed</a>
|
||||
Centre d'art en Normandie
|
||||
</div>
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/block--system-branding-block.html.twig' -->
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/region.html.twig' -->
|
||||
|
||||
</section>
|
||||
<section class="header-center"></section>
|
||||
<section class="header-right">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'region' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
✅ region--header-right.html.twig
|
||||
▪️ region.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/region--header-right.html.twig' -->
|
||||
<div id="burger-btn"></div>
|
||||
<div class="wrapper">
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'block' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ block--leshed-navigationprincipale.html.twig
|
||||
▪️ block--menu-block--main.html.twig
|
||||
▪️ block--menu-block.html.twig
|
||||
✅ block--system-menu-block.html.twig
|
||||
▪️ block.html.twig
|
||||
-->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/block--system-menu-block.html.twig' -->
|
||||
<nav role="navigation" aria-labelledby="block-leshed-navigationprincipale-menu" id="block-leshed-navigationprincipale">
|
||||
|
||||
<h2 class="visually-hidden" id="block-leshed-navigationprincipale-menu">Navigation principale</h2>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'menu' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ menu--main.html.twig
|
||||
✅ menu.html.twig
|
||||
-->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/menu.html.twig' -->
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/" data-drupal-link-system-path="<front>">Accueil</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/menu.html.twig' -->
|
||||
|
||||
|
||||
</nav>
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/block--system-menu-block.html.twig' -->
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/region--header-right.html.twig' -->
|
||||
|
||||
</section>
|
||||
</section>
|
||||
<section class="header-bottom"></section>
|
||||
</header>
|
||||
|
||||
|
||||
|
||||
|
||||
<nav role="breadcrumb">
|
||||
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<main role="main">
|
||||
<a id="main-content" tabindex="-1"></a>
|
||||
<div class="layout-content">
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'region' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ region--content.html.twig
|
||||
✅ region.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/region.html.twig' -->
|
||||
<div class="wrapper">
|
||||
<div data-drupal-messages-fallback class="hidden"></div>
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'node' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ node--570--full.html.twig
|
||||
▪️ node--570.html.twig
|
||||
✅ node--projet--full.html.twig
|
||||
▪️ node--projet.html.twig
|
||||
▪️ node--full.html.twig
|
||||
▪️ node.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/node--projet--full.html.twig' -->
|
||||
<article class="node-type-projet view-mode-full">
|
||||
|
||||
<div class="cols">
|
||||
<div class="col left">
|
||||
<h2>
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'field' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ field--node--title--projet.html.twig
|
||||
✅ field--node--title.html.twig
|
||||
▪️ field--node--projet.html.twig
|
||||
▪️ field--title.html.twig
|
||||
▪️ field--string.html.twig
|
||||
▪️ field.html.twig
|
||||
-->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/node/templates/field--node--title.html.twig' -->
|
||||
|
||||
<span class="title">FAGO</span>
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/node/templates/field--node--title.html.twig' -->
|
||||
|
||||
|
||||
</h2>
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'field' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ field--node--field-artiste-s-invite-s--projet.html.twig
|
||||
▪️ field--node--field-artiste-s-invite-s.html.twig
|
||||
▪️ field--node--projet.html.twig
|
||||
▪️ field--field-artiste-s-invite-s.html.twig
|
||||
▪️ field--entity-reference.html.twig
|
||||
✅ field.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
<div class="field_artiste_s_invite_s field-items multiple">
|
||||
<div class="field-item"><a href="/node/569" hreflang="fr">Géraldine Longueville</a></div>
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'field' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ field--node--field-invite-accompagne-curate-p--projet.html.twig
|
||||
▪️ field--node--field-invite-accompagne-curate-p.html.twig
|
||||
▪️ field--node--projet.html.twig
|
||||
▪️ field--field-invite-accompagne-curate-p.html.twig
|
||||
▪️ field--entity-reference.html.twig
|
||||
✅ field.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
<div class="field_invite_accompagne_curate_p">
|
||||
<div class="field-label">invite/accompagné/curaté par</div>
|
||||
<div class="field-items multiple">
|
||||
<div class="field-item"><a href="/node/508" hreflang="fr">Virginie Bobin</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'field' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ field--node--field-dates--projet.html.twig
|
||||
▪️ field--node--field-dates.html.twig
|
||||
▪️ field--node--projet.html.twig
|
||||
▪️ field--field-dates.html.twig
|
||||
▪️ field--daterange.html.twig
|
||||
✅ field.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
<div class="field_dates field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'time' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/time.html.twig' -->
|
||||
<time datetime="2026-06-28T12:00:00Z">28 juin 2026</time>
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/time.html.twig' -->
|
||||
|
||||
-
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'time' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/time.html.twig' -->
|
||||
<time datetime="2026-09-27T12:00:00Z">27 Sep 2026</time>
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/time.html.twig' -->
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'field' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ field--node--body--projet.html.twig
|
||||
▪️ field--node--body.html.twig
|
||||
▪️ field--node--projet.html.twig
|
||||
▪️ field--body.html.twig
|
||||
▪️ field--text-with-summary.html.twig
|
||||
✅ field.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
<div class="body field-item"><p>De l’Algérie à la Normandie en passant par le Japon, l’artiste et cueilleuse Géraldine Longueville retrace les trajectoires entremêlées de plantes et de corps pris dans les mailles de récits intimes et politiques, notamment liés à l’histoire coloniale. Spécialement produites pour l’exposition, les œuvres présentées (installations, film, pièce sonore) composent un jardin à la fois mémoriel et fabuleux, fruit de gestes, de processus et d’histoires transmises par l’artiste lors d’ateliers et de performances. Cueillies, séchées, nouées, consumées ou macérées, les plantes déposées dans les pièces de La maison accueillant le Shed à Maromme en appellent à tous nos sens. Entre amertume et guérison, elles invitent à se rassembler autour d’elles le temps d’une boisson ou d’une chanson.</p>
|
||||
<p><em>Fago</em> est l’ultime étape des recherches menées par Géraldine Longueville dans le cadre du programme doctoral RADIAN (ésam Caen-Cherbourg, ésadhar, ENSA Normandie et Normandie-Université).</p>
|
||||
<p>Une exposition curatée par Virginie Bobin Dans le cadre de Normandie Impressionniste</p>
|
||||
<p>Assistant artistique : Alioun Abderrahmane</p>
|
||||
<h1>Géraldine Longueville</h1>
|
||||
<p>Diplômée d’un Master Fine Arts de Sandberg Institute à Amsterdam et d’un Master Histoire de l’Art de la Sorbonne Université Paris, elle poursuit actuellement une thèse en Recherche et Créationu sein du programme Radian (ésam Caen-Cherbourg, ésadhar, ENSA Normandie et Normandie-Université). Elle a travaillé dans des centres d’art contemporains franciliens (Emba Manet Gennevilliers, La Galerie Noisy-le-Sec) et à l’école nationale d’arts Paris-Cergy (ENSAPC). Depuis 2016, elle enseigne la performance et l’écriture à l’Ecole Européenne Supérieure de l’Image de Poitiers (EESI).</p>
|
||||
<p>Sa pratique artistique est transversale, mêlant écriture, chant, musique, comestible et installation. Elle se déploie à travers différentes formes de collaborations et de partage tant avec les artistes que le public. La circulation des savoirs écologiques et leurs transmissions sensorielles sur site sont au cœur de ses productions. En 2019, elle se forme aux jardins des plantes médicinales au Potager du Roi à l'École nationale supérieure du paysage à Versailles et elle suit la formation du cueilleur.euse.s Le chemin de la nature de Christophe de Hody.<br>
|
||||
Pendant une vingtaine d'années, elle a mené de nombreux projets collectifs : membre de Glassbox en 2002, elle a monté la galerie extérieure en 2005, projet d'intervention artistique dans l’espace public à Paris et aux Etats-Unis. En 2011, avec les artistes David Bersntein et Jurgis Paskevicius, elle crée le trio Jugedamos avec lequel elle réalise de nombreuses performances à Amsterdam (De Appel), New-York (Sculpture Center) ou Rome (Nomas Foundation). De retour à Paris en 2014, avec la cheffe Virginie Galan et les designers graphiques Commune, elle cofonde Black Garlic, un atelier en art et gastronomie qui organise des dîners dans des brasseries et des lieux d’arts.<br>
|
||||
Depuis 2017, elle travaille sur des projets personnels incluants des invitations collaboratives qui sont exposés au Cac Bretigny, Bétonsalon Paris, galerie gb agency Paris, Goethe Institut Nancy, Kyoto art center, galerie Jocelyn Wolff Paris et la Grande Galerie de l’ésam de Caen.<br>
|
||||
Elle mène depuis 2019 une recherche sur l’amertume, goût et sentiment qui selon elle traduisent la persistance du colonialisme et la résistance à la colonialité. Elle travaille actuellement sur les différentes modalités d’exposition de cette recherche qui seront présentées à partir de 2026.</p>
|
||||
<h1>Virginie Bobin</h1>
|
||||
<p>Virginie Bobin travaille de manière indépendante et souvent collective au croisement des pratiques curatoriales et éditoriales, de l'écriture, de la pédagogie et de la traduction. Après avoir œuvré pendant près de dix ans au sein de centres d'art et lieux de résidence en France et à l'international (Bétonsalon - Centre d'art et de recherche, la Villa Vassilieff, le Witte de With, Les Laboratoires d'Aubervilliers, Performa), elle s'efforce aujourd'hui d'instaurer des pratiques collectives d'apprentissage, d'écoute et de soin dans différents contextes, en s'appuyant sur des méthodologies féministes.<br>
|
||||
En 2024, elle rejoint l'ésadhar de Rouen en tant que Professeure en Art et Pratiques sociales. Docteure en recherche artistique (PhD-in-Practice de l’Académie des Beaux-Arts de Vienne, 2023), elle est membre co-fondatrice de la plateforme Qalqalah قلقلة (<a href="http://www.qalqalah.org">www.qalqalah.org</a>), avec laquelle elle a mené des projets à la Ferme du Buisson, au CRAC-Occitanie à Sète, à La Kunsthalle Mulhouse, au Tanzquartier (Vienne), à Buda (Courtrai), la Fondazione Pistoletto (Biella), l'Atelier de l'Observatoire (Casablanca) ou encore au Master exerce à l'ICI-CCN (Montpellier). Traductrice, elle collabore notamment avec le magazine The Funambulist.<br>
|
||||
Ses projets curatoriaux et de recherche ont été présentés dans des institutions françaises et internationales telles que le CAC Brétigny, Bétonsalon - Centre d'art et de recherche, Museion (Bolzano), CentroCentro (Madrid), MoMA PS1 et e-flux space (New York) ou Tabakalera (San Sebastian). Elle a dirigé plusieurs ouvrages collectifs : Bestiario de Lengüitas (fruit d'une collaboration au long cours avec l'artiste Mercedes Azpilicueta, k.verlag, 2024), Composing Differences (Les Presses du Réel, 2015) et Re-publications (en collaboration avec Mathilde Villeneuve, Archive Books, 2015). Sont parus en 2025 : Désapprendre en traduisant : une pratique critique et collective (Villa Arson / Sternberg Press) et L'interprète dis/paraît (Scriptings).<br>
|
||||
Vivant dans une commune rurale de Normandie, Virginie Bobin est membre des conseils d'administration du réseau RN13BIS et de l'association Kit de Survie.</p>
|
||||
<h1>Fago</h1>
|
||||
<p><strong>Ecouter</strong> des récits déracinés...<br>
|
||||
<strong>Goûter</strong> une boisson d'accueil...<br>
|
||||
<strong>Humer</strong> un paysage en mouvement...<br>
|
||||
<strong>Toucher</strong> des gestes de réparation...<br>
|
||||
<strong>Percevoir</strong> des jeux d'ombre et de lumière...</p>
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'field' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ field--node--field-partenaire-s--projet.html.twig
|
||||
▪️ field--node--field-partenaire-s.html.twig
|
||||
▪️ field--node--projet.html.twig
|
||||
▪️ field--field-partenaire-s.html.twig
|
||||
▪️ field--entity-reference.html.twig
|
||||
✅ field.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
<div class="field_partenaire_s">
|
||||
<div class="field-label">Partenaire(s) Associé(s)</div>
|
||||
<div class="field-items multiple">
|
||||
<div class="field-item"><a href="/node/57" hreflang="fr">Normandie Impressionniste</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col right">
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'field' -->
|
||||
<!-- FILE NAME SUGGESTIONS:
|
||||
▪️ field--node--field-images--projet.html.twig
|
||||
▪️ field--node--field-images.html.twig
|
||||
▪️ field--node--projet.html.twig
|
||||
▪️ field--field-images.html.twig
|
||||
▪️ field--image.html.twig
|
||||
✅ field.html.twig
|
||||
-->
|
||||
<!-- 💡 BEGIN CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
<div class="field_images field-items multiple">
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG917.jpg" width="1920" height="1419" alt="Fago, Géraldine Longueville, 2026, sculpture en bambou, organza,treuil mécanique, corse, plantes. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG1715.jpg" width="1920" height="1280" alt="Sharab, Géraldine Longueville, 2026, installation, mobilier, boisson d'accueil, céramiques de Nina Safaïnia, bouteilles en grès, cuir. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG1729.jpg" width="1280" height="1920" alt="Sharab, Géraldine Longueville, 2026, installation, mobilier, boisson d'accueil, céramiques de Nina Safaïnia, bouteilles en grès, cuir. Performance de service réalisée par Morane Remaud. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG2010.jpg" width="1920" height="1221" alt="Fago, Géraldine Longueville, 2026, sculpture en bambou, organza, treuil mécanique, corde, plantes. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG2025.jpg" width="1920" height="1280" alt="Fago, Géraldine Longueville, 2026, sculpture en bambou, organza, treuil mécanique, corde, plantes. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG2051.jpg" width="1920" height="1280" alt="Fago, Géraldine Longueville, 2026, sculpture en bambou, organza, treuil mécanique, corde, plantes. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG2064.jpg" width="1920" height="1391" alt="Vous la rappelez-vous ?, Géraldine Longueville, 2026, installation en bambou, numérisation de cartes postales imprimées sur papier, aquarelle. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG2070.jpg" width="1920" height="1280" alt="kinakina, Géraldine Longueville, 2024, vidéo (durée : 25min), images, composition, voix : Géraldine Longueville ; Darbouka ; Olivier Longueville ; Dobro : John Molan et Elie Godard ; Arrangement sonore et mixage : Thomas Schmahl. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG2075.jpg" width="1280" height="1920" alt="Fuma, Géraldine Longueville, 2026, performance et sculpture de plantes consumées, collier à vis. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
<div class="field-item">
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image_formatter' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
|
||||
<!-- THEME DEBUG -->
|
||||
<!-- THEME HOOK: 'image' -->
|
||||
<!-- BEGIN OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
<img loading="lazy" src="/sites/default/files/projets/103/103_IMG2088.jpg" width="1920" height="1280" alt="Vous la rappelez-vous ?, Géraldine Longueville, 2026, installation en bambou, numérisation de cartes postales imprimées sur papier, aquarelle. Crédits photographiques : © Marc Domage" />
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/image.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/image/templates/image-formatter.html.twig' -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/field.html.twig' -->
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/node--projet--full.html.twig' -->
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/region.html.twig' -->
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</main>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/page.html.twig' -->
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END OUTPUT from 'core/modules/system/templates/off-canvas-page-wrapper.html.twig' -->
|
||||
|
||||
|
||||
|
||||
<script type="application/json" data-drupal-selector="drupal-settings-json">{"path":{"baseUrl":"\/","pathPrefix":"","currentPath":"node\/570","currentPathIsAdmin":false,"isFront":false,"currentLanguage":"fr"},"pluralDelimiter":"\u0003","suppressDeprecationErrors":true,"data":{"extlink":{"extTarget":false,"extTargetAppendNewWindowDisplay":false,"extTargetAppendNewWindowLabel":"(opens in a new window)","extTargetNoOverride":false,"extNofollow":false,"extTitleNoOverride":false,"extNoreferrer":false,"extFollowNoOverride":false,"extClass":"ext","extLabel":"(le lien est externe)","extImgClass":false,"extSubdomains":true,"extExclude":"","extInclude":"","extCssExclude":"","extCssInclude":"","extCssExplicit":"","extAlert":false,"extAlertText":"Ce lien vous dirige vers un site externe. Nous ne sommes pas responsables de son contenu.","extHideIcons":false,"mailtoClass":"mailto","telClass":"tel","mailtoLabel":"(link sends email)","telLabel":"(link is a phone number)","extUseFontAwesome":false,"extIconPlacement":"append","extPreventOrphan":false,"extFaLinkClasses":"fa fa-external-link","extFaMailtoClasses":"fa fa-envelope-o","extAdditionalLinkClasses":"","extAdditionalMailtoClasses":"","extAdditionalTelClasses":"","extFaTelClasses":"fa fa-phone","allowedDomains":null,"extExcludeNoreferrer":""}},"user":{"uid":0,"permissionsHash":"ec925e94d2171db34f4a2e24795940b32ebbfae3c8882b3c70d7f1931d114517"}}</script>
|
||||
<script src="/sites/default/files/languages/fr_CrdT4JHfBTSbUhzO9RLz5imL3dFblqGqJOpzKqtwZGA.js?tjtjpd"></script>
|
||||
<script src="/core/misc/drupalSettingsLoader.js?v=10.6.10"></script>
|
||||
<script src="/core/misc/drupal.js?v=10.6.10"></script>
|
||||
<script src="/core/misc/drupal.init.js?v=10.6.10"></script>
|
||||
<script src="/modules/contrib/extlink/js/extlink.js?tjtjpd"></script>
|
||||
<script src="http://localhost:5173/@vite/client" type="module"></script>
|
||||
<script src="http://localhost:5173/assets/js/main.js" type="module"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- END CUSTOM TEMPLATE OUTPUT from 'themes/custom/leshed/templates/html.html.twig' -->
|
||||
|
||||
@@ -16,15 +16,20 @@
|
||||
],
|
||||
"require": {
|
||||
"composer/installers": "^2.0",
|
||||
"drupal/auto_entitylabel": "^3.4",
|
||||
"drupal/cer": "^5.0@beta",
|
||||
"drupal/config_ignore": "^3.4",
|
||||
"drupal/core-composer-scaffold": "^10.6",
|
||||
"drupal/core-project-message": "^10.6",
|
||||
"drupal/core-recommended": "^10.6",
|
||||
"drupal/image_delta_formatter": "^1.3",
|
||||
"drupal/image_field_caption": "^3.0",
|
||||
"drupal/migrate_google_sheets": "^2.3",
|
||||
"drupal/migrate_tools": "^6.1",
|
||||
"drupal/page_manager": "^4.0@RC",
|
||||
"drupal/shield": "^1.8",
|
||||
"drupal/structure_sync": "^2.0",
|
||||
"league/commonmark": "^2.8",
|
||||
"wikimedia/composer-merge-plugin": "^2.1"
|
||||
},
|
||||
"conflict": {
|
||||
|
||||
Generated
+719
-1
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "0b0b3210b893eaaa833b27f1e6fae4c9",
|
||||
"content-hash": "b6910aa746da9a58dfcadde6f45bdad8",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
@@ -1868,6 +1868,87 @@
|
||||
"issues": "https://www.drupal.org/project/issues/audiofield"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drupal/auto_entitylabel",
|
||||
"version": "3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://git.drupalcode.org/project/auto_entitylabel.git",
|
||||
"reference": "8.x-3.4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://ftp.drupal.org/files/projects/auto_entitylabel-8.x-3.4.zip",
|
||||
"reference": "8.x-3.4",
|
||||
"shasum": "9b3d7bc8e450ae008b3f48fed0dd9dace03ddbb5"
|
||||
},
|
||||
"require": {
|
||||
"drupal/core": "^10.1 || ^11"
|
||||
},
|
||||
"require-dev": {
|
||||
"drupal/book": "^1.0",
|
||||
"drupal/token": "^1.0"
|
||||
},
|
||||
"type": "drupal-module",
|
||||
"extra": {
|
||||
"drupal": {
|
||||
"version": "8.x-3.4",
|
||||
"datestamp": "1736308389",
|
||||
"security-coverage": {
|
||||
"status": "covered",
|
||||
"message": "Covered by Drupal's security advisory policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||
"license": [
|
||||
"GPL-2.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "bforchhammer",
|
||||
"homepage": "https://www.drupal.org/user/216396"
|
||||
},
|
||||
{
|
||||
"name": "colan",
|
||||
"homepage": "https://www.drupal.org/user/58704"
|
||||
},
|
||||
{
|
||||
"name": "dqd",
|
||||
"homepage": "https://www.drupal.org/user/1001934"
|
||||
},
|
||||
{
|
||||
"name": "japerry",
|
||||
"homepage": "https://www.drupal.org/user/45640"
|
||||
},
|
||||
{
|
||||
"name": "mandclu",
|
||||
"homepage": "https://www.drupal.org/user/52136"
|
||||
},
|
||||
{
|
||||
"name": "pravin ajaaz",
|
||||
"homepage": "https://www.drupal.org/user/2910049"
|
||||
},
|
||||
{
|
||||
"name": "purushotam.rai",
|
||||
"homepage": "https://www.drupal.org/user/3193859"
|
||||
},
|
||||
{
|
||||
"name": "renatog",
|
||||
"homepage": "https://www.drupal.org/user/3326031"
|
||||
},
|
||||
{
|
||||
"name": "vladimiraus",
|
||||
"homepage": "https://www.drupal.org/user/673120"
|
||||
}
|
||||
],
|
||||
"description": "Allows hiding of entity label fields and automatic label creation.",
|
||||
"homepage": "https://www.drupal.org/project/auto_entitylabel",
|
||||
"support": {
|
||||
"source": "https://git.drupalcode.org/project/auto_entitylabel",
|
||||
"issues": "https://www.drupal.org/project/issues/auto_entitylabel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drupal/autocomplete_deluxe",
|
||||
"version": "2.1.2",
|
||||
@@ -4243,6 +4324,131 @@
|
||||
"issues": "https://www.drupal.org/project/issues/honeypot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drupal/image_delta_formatter",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://git.drupalcode.org/project/image_delta_formatter.git",
|
||||
"reference": "8.x-1.3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://ftp.drupal.org/files/projects/image_delta_formatter-8.x-1.3.zip",
|
||||
"reference": "8.x-1.3",
|
||||
"shasum": "6ec48166cb04eda57915dbe28f97fa32c1e77b75"
|
||||
},
|
||||
"require": {
|
||||
"drupal/core": "^10 || ^11"
|
||||
},
|
||||
"type": "drupal-module",
|
||||
"extra": {
|
||||
"drupal": {
|
||||
"version": "8.x-1.3",
|
||||
"datestamp": "1738516937",
|
||||
"security-coverage": {
|
||||
"status": "covered",
|
||||
"message": "Covered by Drupal's security advisory policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||
"license": [
|
||||
"GPL-2.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "bojanz",
|
||||
"homepage": "https://www.drupal.org/user/86106"
|
||||
},
|
||||
{
|
||||
"name": "fgm",
|
||||
"homepage": "https://www.drupal.org/user/27985"
|
||||
},
|
||||
{
|
||||
"name": "jsacksick",
|
||||
"homepage": "https://www.drupal.org/user/972218"
|
||||
}
|
||||
],
|
||||
"description": "Provides a formatter that displays a specific delta of a multi-value image or media field.",
|
||||
"homepage": "https://www.drupal.org/project/image_delta_formatter",
|
||||
"support": {
|
||||
"source": "https://git.drupalcode.org/project/image_delta_formatter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drupal/image_field_caption",
|
||||
"version": "3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://git.drupalcode.org/project/image_field_caption.git",
|
||||
"reference": "3.0.1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://ftp.drupal.org/files/projects/image_field_caption-3.0.1.zip",
|
||||
"reference": "3.0.1",
|
||||
"shasum": "e84c3b9534d5824b6a67885187b1c24d4eccaf60"
|
||||
},
|
||||
"require": {
|
||||
"drupal/core": "^10 || ^11"
|
||||
},
|
||||
"type": "drupal-module",
|
||||
"extra": {
|
||||
"drupal": {
|
||||
"version": "3.0.1",
|
||||
"datestamp": "1739400507",
|
||||
"security-coverage": {
|
||||
"status": "covered",
|
||||
"message": "Covered by Drupal's security advisory policy"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||
"license": [
|
||||
"GPL-2.0+"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "awm",
|
||||
"homepage": "https://www.drupal.org/user/1059398"
|
||||
},
|
||||
{
|
||||
"name": "foxy-vikvik",
|
||||
"homepage": "https://www.drupal.org/user/3706169"
|
||||
},
|
||||
{
|
||||
"name": "hanoii",
|
||||
"homepage": "https://www.drupal.org/user/23157"
|
||||
},
|
||||
{
|
||||
"name": "ironsizide",
|
||||
"homepage": "https://www.drupal.org/user/787980"
|
||||
},
|
||||
{
|
||||
"name": "istryker",
|
||||
"homepage": "https://www.drupal.org/user/303676"
|
||||
},
|
||||
{
|
||||
"name": "kksandr",
|
||||
"homepage": "https://www.drupal.org/user/3710922"
|
||||
},
|
||||
{
|
||||
"name": "robloach",
|
||||
"homepage": "https://www.drupal.org/user/61114"
|
||||
},
|
||||
{
|
||||
"name": "tyler.frankenstein",
|
||||
"homepage": "https://www.drupal.org/user/150680"
|
||||
}
|
||||
],
|
||||
"description": "Add caption to image field.",
|
||||
"homepage": "https://www.drupal.org/project/image_field_caption",
|
||||
"support": {
|
||||
"source": "https://git.drupalcode.org/project/image_field_caption",
|
||||
"issues": "https://www.drupal.org/project/issues/image_field_caption"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drupal/imagemagick",
|
||||
"version": "3.7.0",
|
||||
@@ -6506,6 +6712,87 @@
|
||||
"source": "https://git.drupalcode.org/project/sophron"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drupal/structure_sync",
|
||||
"version": "2.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://git.drupalcode.org/project/structure_sync.git",
|
||||
"reference": "2.0.8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://ftp.drupal.org/files/projects/structure_sync-2.0.8.zip",
|
||||
"reference": "2.0.8",
|
||||
"shasum": "3f1bd24d7f048cdd9f49e178af9fa47d291d3525"
|
||||
},
|
||||
"require": {
|
||||
"drupal/core": "^8 || ^9 || ^10 || ^11",
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"drush/drush": "^9 || ^10 || ^11 || ^12 || ^13"
|
||||
},
|
||||
"type": "drupal-module",
|
||||
"extra": {
|
||||
"drupal": {
|
||||
"version": "2.0.8",
|
||||
"datestamp": "1728580642",
|
||||
"security-coverage": {
|
||||
"status": "covered",
|
||||
"message": "Covered by Drupal's security advisory policy"
|
||||
}
|
||||
},
|
||||
"drush": {
|
||||
"services": {
|
||||
"drush.services.yml": "^9 || ^10 || ^11 || ^12 || ^13"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packages.drupal.org/8/downloads",
|
||||
"license": [
|
||||
"GPL-2.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "colan",
|
||||
"homepage": "https://www.drupal.org/user/58704"
|
||||
},
|
||||
{
|
||||
"name": "fidovdbos",
|
||||
"homepage": "https://www.drupal.org/user/1494332"
|
||||
},
|
||||
{
|
||||
"name": "joachim",
|
||||
"homepage": "https://www.drupal.org/user/107701"
|
||||
},
|
||||
{
|
||||
"name": "louis-cuny",
|
||||
"homepage": "https://www.drupal.org/user/3606332"
|
||||
},
|
||||
{
|
||||
"name": "mparker17",
|
||||
"homepage": "https://www.drupal.org/user/536298"
|
||||
},
|
||||
{
|
||||
"name": "spiderman",
|
||||
"homepage": "https://www.drupal.org/user/1631"
|
||||
},
|
||||
{
|
||||
"name": "timkruijsen",
|
||||
"homepage": "https://www.drupal.org/user/3513437"
|
||||
},
|
||||
{
|
||||
"name": "vinlaurens",
|
||||
"homepage": "https://www.drupal.org/user/2945689"
|
||||
}
|
||||
],
|
||||
"description": "Tool for syncing structural data that is stored as content.",
|
||||
"homepage": "https://www.drupal.org/project/structure_sync",
|
||||
"support": {
|
||||
"source": "https://git.drupalcode.org/project/structure_sync"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drupal/synonyms",
|
||||
"version": "2.1.4",
|
||||
@@ -7864,6 +8151,195 @@
|
||||
},
|
||||
"time": "2026-06-26T00:11:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
"version": "2.8.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/commonmark.git",
|
||||
"reference": "1902f60f984235023acbe03db6ad614a37b3c3e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/1902f60f984235023acbe03db6ad614a37b3c3e7",
|
||||
"reference": "1902f60f984235023acbe03db6ad614a37b3c3e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"league/config": "^1.1.1",
|
||||
"php": "^7.4 || ^8.0",
|
||||
"psr/event-dispatcher": "^1.0",
|
||||
"symfony/deprecation-contracts": "^2.1 || ^3.0",
|
||||
"symfony/polyfill-php80": "^1.16"
|
||||
},
|
||||
"require-dev": {
|
||||
"cebe/markdown": "^1.0",
|
||||
"commonmark/cmark": "0.31.1",
|
||||
"commonmark/commonmark.js": "0.31.1",
|
||||
"composer/package-versions-deprecated": "^1.8",
|
||||
"embed/embed": "^4.4",
|
||||
"erusev/parsedown": "^1.0",
|
||||
"ext-json": "*",
|
||||
"github/gfm": "0.29.0",
|
||||
"michelf/php-markdown": "^1.4 || ^2.0",
|
||||
"nyholm/psr7": "^1.5",
|
||||
"phpstan/phpstan": "^2.0.0",
|
||||
"phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0 || ^12.0.0 || ^13.0.0",
|
||||
"scrutinizer/ocular": "^1.8.1",
|
||||
"symfony/finder": "^5.3 | ^6.0 | ^7.0 || ^8.0",
|
||||
"symfony/process": "^5.4 | ^6.0 | ^7.0 || ^8.0",
|
||||
"symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0 || ^8.0",
|
||||
"unleashedtech/php-coding-standard": "^3.1.1",
|
||||
"vimeo/psalm": "^4.24.0 || ^5.0.0 || ^6.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/yaml": "v2.3+ required if using the Front Matter extension"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "2.9-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\CommonMark\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Colin O'Dell",
|
||||
"email": "colinodell@gmail.com",
|
||||
"homepage": "https://www.colinodell.com",
|
||||
"role": "Lead Developer"
|
||||
}
|
||||
],
|
||||
"description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)",
|
||||
"homepage": "https://commonmark.thephpleague.com",
|
||||
"keywords": [
|
||||
"commonmark",
|
||||
"flavored",
|
||||
"gfm",
|
||||
"github",
|
||||
"github-flavored",
|
||||
"markdown",
|
||||
"md",
|
||||
"parser"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://commonmark.thephpleague.com/",
|
||||
"forum": "https://github.com/thephpleague/commonmark/discussions",
|
||||
"issues": "https://github.com/thephpleague/commonmark/issues",
|
||||
"rss": "https://github.com/thephpleague/commonmark/releases.atom",
|
||||
"source": "https://github.com/thephpleague/commonmark"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.colinodell.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.paypal.me/colinpodell/10.00",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/colinodell",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/league/commonmark",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-07-12T15:29:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/config",
|
||||
"version": "v1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/config.git",
|
||||
"reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3",
|
||||
"reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dflydev/dot-access-data": "^3.0.1",
|
||||
"nette/schema": "^1.2",
|
||||
"php": "^7.4 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.8.2",
|
||||
"phpunit/phpunit": "^9.5.5",
|
||||
"scrutinizer/ocular": "^1.8.1",
|
||||
"unleashedtech/php-coding-standard": "^3.1",
|
||||
"vimeo/psalm": "^4.7.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "1.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Config\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Colin O'Dell",
|
||||
"email": "colinodell@gmail.com",
|
||||
"homepage": "https://www.colinodell.com",
|
||||
"role": "Lead Developer"
|
||||
}
|
||||
],
|
||||
"description": "Define configuration arrays with strict schemas and access values with dot notation",
|
||||
"homepage": "https://config.thephpleague.com",
|
||||
"keywords": [
|
||||
"array",
|
||||
"config",
|
||||
"configuration",
|
||||
"dot",
|
||||
"dot-access",
|
||||
"nested",
|
||||
"schema"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://config.thephpleague.com/",
|
||||
"issues": "https://github.com/thephpleague/config/issues",
|
||||
"rss": "https://github.com/thephpleague/config/releases.atom",
|
||||
"source": "https://github.com/thephpleague/config"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.colinodell.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://www.paypal.me/colinpodell/10.00",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/colinodell",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2022-12-11T20:36:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/container",
|
||||
"version": "4.2.5",
|
||||
@@ -8062,6 +8538,164 @@
|
||||
},
|
||||
"time": "2026-04-24T08:04:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/schema",
|
||||
"version": "v1.3.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/schema.git",
|
||||
"reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/schema/zipball/f0ab1a3cda782dbc5da270d28545236aa80c4002",
|
||||
"reference": "f0ab1a3cda782dbc5da270d28545236aa80c4002",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nette/utils": "^4.0",
|
||||
"php": "8.1 - 8.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"nette/phpstan-rules": "^1.0",
|
||||
"nette/tester": "^2.6",
|
||||
"phpstan/extension-installer": "^1.4@stable",
|
||||
"phpstan/phpstan": "^2.1.39@stable",
|
||||
"tracy/tracy": "^2.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Nette\\": "src"
|
||||
},
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause",
|
||||
"GPL-2.0-only",
|
||||
"GPL-3.0-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Grudl",
|
||||
"homepage": "https://davidgrudl.com"
|
||||
},
|
||||
{
|
||||
"name": "Nette Community",
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"description": "📐 Nette Schema: validating data structures against a given Schema.",
|
||||
"homepage": "https://nette.org",
|
||||
"keywords": [
|
||||
"config",
|
||||
"nette"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/schema/issues",
|
||||
"source": "https://github.com/nette/schema/tree/v1.3.5"
|
||||
},
|
||||
"time": "2026-02-23T03:47:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v4.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "b043439dbdf954e6c28b5ea7e34b0100f83165e0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/b043439dbdf954e6c28b5ea7e34b0100f83165e0",
|
||||
"reference": "b043439dbdf954e6c28b5ea7e34b0100f83165e0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "8.2 - 8.5"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/finder": "<3",
|
||||
"nette/schema": "<1.2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"jetbrains/phpstorm-attributes": "^1.2",
|
||||
"nette/phpstan-rules": "^1.0",
|
||||
"nette/tester": "^2.5",
|
||||
"phpstan/extension-installer": "^1.4@stable",
|
||||
"phpstan/phpstan": "^2.1@stable",
|
||||
"tracy/tracy": "^2.9"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gd": "to use Image",
|
||||
"ext-iconv": "to use Strings::chr(), ord() and reverse()",
|
||||
"ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
|
||||
"ext-json": "to use Nette\\Utils\\Json",
|
||||
"ext-mbstring": "to use Strings::lower() etc...",
|
||||
"ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Nette\\": "src"
|
||||
},
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause",
|
||||
"GPL-2.0-only",
|
||||
"GPL-3.0-only"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "David Grudl",
|
||||
"homepage": "https://davidgrudl.com"
|
||||
},
|
||||
{
|
||||
"name": "Nette Community",
|
||||
"homepage": "https://nette.org/contributors"
|
||||
}
|
||||
],
|
||||
"description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
|
||||
"homepage": "https://nette.org",
|
||||
"keywords": [
|
||||
"array",
|
||||
"core",
|
||||
"datetime",
|
||||
"images",
|
||||
"json",
|
||||
"nette",
|
||||
"paginator",
|
||||
"password",
|
||||
"slugify",
|
||||
"string",
|
||||
"unicode",
|
||||
"utf-8",
|
||||
"utility",
|
||||
"validation"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.1.5"
|
||||
},
|
||||
"time": "2026-07-17T23:02:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.8.0",
|
||||
@@ -10687,6 +11321,90 @@
|
||||
],
|
||||
"time": "2026-04-10T17:25:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php80",
|
||||
"version": "v1.37.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-php80.git",
|
||||
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
|
||||
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"url": "https://github.com/symfony/polyfill",
|
||||
"name": "symfony/polyfill"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"bootstrap.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Symfony\\Polyfill\\Php80\\": ""
|
||||
},
|
||||
"classmap": [
|
||||
"Resources/stubs"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ion Bazan",
|
||||
"email": "ion.bazan@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"compatibility",
|
||||
"polyfill",
|
||||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-04-10T16:19:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"version": "v1.38.1",
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
status: 1
|
||||
pattern: '[node:field_prenom] [node:field_nom]'
|
||||
escape: false
|
||||
preserve_titles: false
|
||||
save: true
|
||||
chunk: 50
|
||||
dependencies:
|
||||
config:
|
||||
- node.type.personne
|
||||
new_content_behavior: 0
|
||||
@@ -0,0 +1,23 @@
|
||||
uuid: e2f0e1c7-b805-4c1d-8988-760ebfe8fa7d
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- system
|
||||
theme:
|
||||
- leshed
|
||||
id: leshed_identitedusite
|
||||
theme: leshed
|
||||
region: header_left
|
||||
weight: 0
|
||||
provider: null
|
||||
plugin: system_branding_block
|
||||
settings:
|
||||
id: system_branding_block
|
||||
label: 'Identité du site'
|
||||
label_display: '0'
|
||||
provider: system
|
||||
use_site_logo: false
|
||||
use_site_name: true
|
||||
use_site_slogan: true
|
||||
visibility: { }
|
||||
@@ -0,0 +1,34 @@
|
||||
uuid: 372f96d2-3992-45b6-9335-b1359d3382e2
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- system.menu.main
|
||||
module:
|
||||
- menu_block
|
||||
theme:
|
||||
- leshed
|
||||
id: leshed_navigationprincipale
|
||||
theme: leshed
|
||||
region: header_right
|
||||
weight: 0
|
||||
provider: null
|
||||
plugin: 'menu_block:main'
|
||||
settings:
|
||||
id: 'menu_block:main'
|
||||
label: 'Navigation principale'
|
||||
label_display: '0'
|
||||
provider: menu_block
|
||||
follow: false
|
||||
follow_parent: child
|
||||
display_empty: false
|
||||
label_link: false
|
||||
label_type: block
|
||||
level: 1
|
||||
depth: 0
|
||||
expand_all_items: false
|
||||
parent: 'main:'
|
||||
render_parent: false
|
||||
suggestion: main
|
||||
hide_on_nonactive: false
|
||||
visibility: { }
|
||||
@@ -0,0 +1,29 @@
|
||||
uuid: 013d1fb2-1c81-4b8b-93ca-0da2e401fd88
|
||||
langcode: fr
|
||||
status: false
|
||||
dependencies:
|
||||
module:
|
||||
- ctools_block
|
||||
theme:
|
||||
- leshed
|
||||
id: leshed_titre
|
||||
theme: leshed
|
||||
region: content
|
||||
weight: 0
|
||||
provider: null
|
||||
plugin: 'entity_field:node:title'
|
||||
settings:
|
||||
id: 'entity_field:node:title'
|
||||
label: Titre
|
||||
label_display: '0'
|
||||
provider: ctools_block
|
||||
context_mapping:
|
||||
entity: '@node.node_route_context:node'
|
||||
formatter:
|
||||
type: string
|
||||
weight: 0
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
visibility: { }
|
||||
@@ -6,7 +6,7 @@ id: projet_curateur
|
||||
label: 'Projet - Curateur'
|
||||
enabled: true
|
||||
first_field: field_invite_accompagne_curate_p
|
||||
second_field: field_projet_s_lie_s
|
||||
second_field: field_projets_curates
|
||||
add_direction: append
|
||||
bundles:
|
||||
node:
|
||||
|
||||
@@ -8,7 +8,7 @@ id: node.personne.title
|
||||
field_name: title
|
||||
entity_type: node
|
||||
bundle: personne
|
||||
label: Nom
|
||||
label: Title
|
||||
description: ''
|
||||
required: true
|
||||
translatable: true
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
uuid: 177f93c8-cb82-4d48-a9f0-ba1f88df350b
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies: { }
|
||||
id: d_m_y
|
||||
label: 'd M Y'
|
||||
locked: false
|
||||
pattern: 'd M Y'
|
||||
@@ -162,4 +162,9 @@ content:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
url_redirects:
|
||||
weight: 50
|
||||
region: content
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
hidden: { }
|
||||
|
||||
@@ -89,4 +89,9 @@ content:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
url_redirects:
|
||||
weight: 50
|
||||
region: content
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
hidden: { }
|
||||
|
||||
@@ -4,8 +4,10 @@ status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.node.personne.body
|
||||
- field.field.node.personne.field_nom
|
||||
- field.field.node.personne.field_prenom
|
||||
- field.field.node.personne.field_projet_s_lie_s
|
||||
- field.field.node.personne.field_projets_curates
|
||||
- field.field.node.personne.field_type_de_personne
|
||||
- node.type.personne
|
||||
module:
|
||||
@@ -23,7 +25,7 @@ third_party_settings:
|
||||
label: Details
|
||||
region: content
|
||||
parent_name: ''
|
||||
weight: 4
|
||||
weight: 5
|
||||
format_type: details_sidebar
|
||||
format_settings:
|
||||
classes: ''
|
||||
@@ -41,7 +43,7 @@ mode: default
|
||||
content:
|
||||
body:
|
||||
type: text_textarea_with_summary
|
||||
weight: 2
|
||||
weight: 3
|
||||
region: content
|
||||
settings:
|
||||
rows: 9
|
||||
@@ -49,6 +51,14 @@ content:
|
||||
placeholder: ''
|
||||
show_summary: false
|
||||
third_party_settings: { }
|
||||
field_nom:
|
||||
type: string_textfield
|
||||
weight: 2
|
||||
region: content
|
||||
settings:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_prenom:
|
||||
type: string_textfield
|
||||
weight: 1
|
||||
@@ -59,7 +69,17 @@ content:
|
||||
third_party_settings: { }
|
||||
field_projet_s_lie_s:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 3
|
||||
weight: 4
|
||||
region: content
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
match_limit: 10
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
field_projets_curates:
|
||||
type: entity_reference_autocomplete
|
||||
weight: 26
|
||||
region: content
|
||||
settings:
|
||||
match_operator: CONTAINS
|
||||
|
||||
@@ -6,6 +6,7 @@ dependencies:
|
||||
- field.field.node.projet.body
|
||||
- field.field.node.projet.field_artiste_s_invite_s
|
||||
- field.field.node.projet.field_dates
|
||||
- field.field.node.projet.field_fichiers
|
||||
- field.field.node.projet.field_images
|
||||
- field.field.node.projet.field_invite_accompagne_curate_p
|
||||
- field.field.node.projet.field_partenaire_s
|
||||
@@ -18,6 +19,7 @@ dependencies:
|
||||
- autocomplete_deluxe
|
||||
- datetime_range
|
||||
- field_group
|
||||
- file
|
||||
- image
|
||||
- path
|
||||
- text
|
||||
@@ -101,6 +103,7 @@ third_party_settings:
|
||||
group_media:
|
||||
children:
|
||||
- field_images
|
||||
- field_fichiers
|
||||
label: Media
|
||||
region: content
|
||||
parent_name: group_tabs
|
||||
@@ -161,6 +164,13 @@ content:
|
||||
region: content
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
field_fichiers:
|
||||
type: file_generic
|
||||
weight: 8
|
||||
region: content
|
||||
settings:
|
||||
progress_indicator: throbber
|
||||
third_party_settings: { }
|
||||
field_images:
|
||||
type: image_image
|
||||
weight: 7
|
||||
@@ -257,6 +267,11 @@ content:
|
||||
size: 60
|
||||
placeholder: ''
|
||||
third_party_settings: { }
|
||||
url_redirects:
|
||||
weight: 50
|
||||
region: content
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
hidden:
|
||||
created: true
|
||||
sticky: true
|
||||
|
||||
@@ -4,8 +4,10 @@ status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.field.node.personne.body
|
||||
- field.field.node.personne.field_nom
|
||||
- field.field.node.personne.field_prenom
|
||||
- field.field.node.personne.field_projet_s_lie_s
|
||||
- field.field.node.personne.field_projets_curates
|
||||
- field.field.node.personne.field_type_de_personne
|
||||
- node.type.personne
|
||||
module:
|
||||
@@ -23,6 +25,14 @@ content:
|
||||
third_party_settings: { }
|
||||
weight: 101
|
||||
region: content
|
||||
field_nom:
|
||||
type: string
|
||||
label: above
|
||||
settings:
|
||||
link_to_entity: false
|
||||
third_party_settings: { }
|
||||
weight: 109
|
||||
region: content
|
||||
field_prenom:
|
||||
type: string
|
||||
label: above
|
||||
@@ -39,6 +49,14 @@ content:
|
||||
third_party_settings: { }
|
||||
weight: 108
|
||||
region: content
|
||||
field_projets_curates:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 110
|
||||
region: content
|
||||
field_type_de_personne:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
|
||||
@@ -5,34 +5,26 @@ dependencies:
|
||||
config:
|
||||
- core.entity_view_mode.node.teaser
|
||||
- field.field.node.personne.body
|
||||
- field.field.node.personne.field_nom
|
||||
- field.field.node.personne.field_prenom
|
||||
- field.field.node.personne.field_projet_s_lie_s
|
||||
- field.field.node.personne.field_projets_curates
|
||||
- field.field.node.personne.field_type_de_personne
|
||||
- node.type.personne
|
||||
module:
|
||||
- text
|
||||
- user
|
||||
id: node.personne.teaser
|
||||
targetEntityType: node
|
||||
bundle: personne
|
||||
mode: teaser
|
||||
content:
|
||||
body:
|
||||
type: text_summary_or_trimmed
|
||||
label: hidden
|
||||
settings:
|
||||
trim_length: 600
|
||||
third_party_settings: { }
|
||||
weight: 101
|
||||
region: content
|
||||
links:
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 100
|
||||
region: content
|
||||
content: { }
|
||||
hidden:
|
||||
body: true
|
||||
field_nom: true
|
||||
field_prenom: true
|
||||
field_projet_s_lie_s: true
|
||||
field_projets_curates: true
|
||||
field_type_de_personne: true
|
||||
langcode: true
|
||||
links: true
|
||||
search_api_excerpt: true
|
||||
|
||||
@@ -6,6 +6,7 @@ dependencies:
|
||||
- field.field.node.projet.body
|
||||
- field.field.node.projet.field_artiste_s_invite_s
|
||||
- field.field.node.projet.field_dates
|
||||
- field.field.node.projet.field_fichiers
|
||||
- field.field.node.projet.field_images
|
||||
- field.field.node.projet.field_invite_accompagne_curate_p
|
||||
- field.field.node.projet.field_partenaire_s
|
||||
@@ -15,6 +16,7 @@ dependencies:
|
||||
- node.type.projet
|
||||
module:
|
||||
- datetime_range
|
||||
- file
|
||||
- image
|
||||
- options
|
||||
- text
|
||||
@@ -29,7 +31,7 @@ content:
|
||||
label: hidden
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 101
|
||||
weight: 1
|
||||
region: content
|
||||
field_artiste_s_invite_s:
|
||||
type: entity_reference_label
|
||||
@@ -37,18 +39,26 @@ content:
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 105
|
||||
weight: 6
|
||||
region: content
|
||||
field_dates:
|
||||
type: daterange_default
|
||||
label: above
|
||||
label: visually_hidden
|
||||
settings:
|
||||
timezone_override: ''
|
||||
format_type: medium
|
||||
from_to: both
|
||||
separator: '-'
|
||||
third_party_settings: { }
|
||||
weight: 102
|
||||
weight: 2
|
||||
region: content
|
||||
field_fichiers:
|
||||
type: file_default
|
||||
label: above
|
||||
settings:
|
||||
use_description_as_link_text: true
|
||||
third_party_settings: { }
|
||||
weight: 9
|
||||
region: content
|
||||
field_images:
|
||||
type: image
|
||||
@@ -59,7 +69,7 @@ content:
|
||||
image_loading:
|
||||
attribute: lazy
|
||||
third_party_settings: { }
|
||||
weight: 109
|
||||
weight: 10
|
||||
region: content
|
||||
field_invite_accompagne_curate_p:
|
||||
type: entity_reference_label
|
||||
@@ -67,7 +77,7 @@ content:
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 106
|
||||
weight: 4
|
||||
region: content
|
||||
field_partenaire_s:
|
||||
type: entity_reference_label
|
||||
@@ -75,14 +85,14 @@ content:
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 104
|
||||
weight: 5
|
||||
region: content
|
||||
field_portage:
|
||||
type: list_default
|
||||
label: above
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 107
|
||||
weight: 7
|
||||
region: content
|
||||
field_projet_s_lie_s:
|
||||
type: entity_reference_label
|
||||
@@ -90,20 +100,20 @@ content:
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 108
|
||||
weight: 8
|
||||
region: content
|
||||
field_type_de_projet:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
label: visually_hidden
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 103
|
||||
weight: 3
|
||||
region: content
|
||||
links:
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 100
|
||||
weight: 0
|
||||
region: content
|
||||
hidden:
|
||||
langcode: true
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
uuid: 3e27c55e-5165-4118-bd03-5c0433642e42
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- core.entity_view_mode.node.full
|
||||
- field.field.node.projet.body
|
||||
- field.field.node.projet.field_artiste_s_invite_s
|
||||
- field.field.node.projet.field_dates
|
||||
- field.field.node.projet.field_fichiers
|
||||
- field.field.node.projet.field_images
|
||||
- field.field.node.projet.field_invite_accompagne_curate_p
|
||||
- field.field.node.projet.field_partenaire_s
|
||||
- field.field.node.projet.field_portage
|
||||
- field.field.node.projet.field_projet_s_lie_s
|
||||
- field.field.node.projet.field_type_de_projet
|
||||
- image.style.large
|
||||
- node.type.projet
|
||||
module:
|
||||
- datetime_range
|
||||
- file
|
||||
- image_field_caption
|
||||
- layout_builder
|
||||
- options
|
||||
- text
|
||||
- user
|
||||
third_party_settings:
|
||||
layout_builder:
|
||||
enabled: false
|
||||
allow_custom: false
|
||||
id: node.projet.full
|
||||
targetEntityType: node
|
||||
bundle: projet
|
||||
mode: full
|
||||
content:
|
||||
body:
|
||||
type: text_default
|
||||
label: hidden
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 3
|
||||
region: content
|
||||
field_artiste_s_invite_s:
|
||||
type: entity_reference_label
|
||||
label: hidden
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 0
|
||||
region: content
|
||||
field_dates:
|
||||
type: daterange_default
|
||||
label: hidden
|
||||
settings:
|
||||
timezone_override: ''
|
||||
format_type: d_m_y
|
||||
from_to: both
|
||||
separator: '-'
|
||||
third_party_settings: { }
|
||||
weight: 2
|
||||
region: content
|
||||
field_fichiers:
|
||||
type: file_default
|
||||
label: above
|
||||
settings:
|
||||
use_description_as_link_text: true
|
||||
third_party_settings: { }
|
||||
weight: 7
|
||||
region: content
|
||||
field_images:
|
||||
type: image_caption
|
||||
label: hidden
|
||||
settings:
|
||||
image_style: large
|
||||
image_link: file
|
||||
image_loading:
|
||||
attribute: lazy
|
||||
third_party_settings: { }
|
||||
weight: 8
|
||||
region: content
|
||||
field_invite_accompagne_curate_p:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 1
|
||||
region: content
|
||||
field_partenaire_s:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 4
|
||||
region: content
|
||||
field_portage:
|
||||
type: list_default
|
||||
label: above
|
||||
settings: { }
|
||||
third_party_settings: { }
|
||||
weight: 5
|
||||
region: content
|
||||
field_projet_s_lie_s:
|
||||
type: entity_reference_label
|
||||
label: above
|
||||
settings:
|
||||
link: true
|
||||
third_party_settings: { }
|
||||
weight: 6
|
||||
region: content
|
||||
hidden:
|
||||
field_type_de_projet: true
|
||||
langcode: true
|
||||
links: true
|
||||
search_api_excerpt: true
|
||||
@@ -7,14 +7,17 @@ dependencies:
|
||||
- field.field.node.projet.body
|
||||
- field.field.node.projet.field_artiste_s_invite_s
|
||||
- field.field.node.projet.field_dates
|
||||
- field.field.node.projet.field_fichiers
|
||||
- field.field.node.projet.field_images
|
||||
- field.field.node.projet.field_invite_accompagne_curate_p
|
||||
- field.field.node.projet.field_partenaire_s
|
||||
- field.field.node.projet.field_portage
|
||||
- field.field.node.projet.field_projet_s_lie_s
|
||||
- field.field.node.projet.field_type_de_projet
|
||||
- image.style.medium
|
||||
- node.type.projet
|
||||
module:
|
||||
- image_delta_formatter
|
||||
- text
|
||||
- user
|
||||
id: node.projet.teaser
|
||||
@@ -26,23 +29,40 @@ content:
|
||||
type: text_summary_or_trimmed
|
||||
label: hidden
|
||||
settings:
|
||||
trim_length: 600
|
||||
trim_length: 100
|
||||
third_party_settings: { }
|
||||
weight: 101
|
||||
weight: 2
|
||||
region: content
|
||||
links:
|
||||
settings: { }
|
||||
field_artiste_s_invite_s:
|
||||
type: entity_reference_label
|
||||
label: hidden
|
||||
settings:
|
||||
link: false
|
||||
third_party_settings: { }
|
||||
weight: 100
|
||||
weight: 1
|
||||
region: content
|
||||
field_images:
|
||||
type: image_delta_formatter
|
||||
label: hidden
|
||||
settings:
|
||||
deltas:
|
||||
- 1
|
||||
deltas_reversed: false
|
||||
image_link: content
|
||||
image_style: medium
|
||||
image_loading:
|
||||
attribute: lazy
|
||||
third_party_settings: { }
|
||||
weight: 0
|
||||
region: content
|
||||
hidden:
|
||||
field_artiste_s_invite_s: true
|
||||
field_dates: true
|
||||
field_images: true
|
||||
field_fichiers: true
|
||||
field_invite_accompagne_curate_p: true
|
||||
field_partenaire_s: true
|
||||
field_portage: true
|
||||
field_projet_s_lie_s: true
|
||||
field_type_de_projet: true
|
||||
langcode: true
|
||||
links: true
|
||||
search_api_excerpt: true
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
_core:
|
||||
default_config_hash: 4GIX5Esnc_umpXUBj4IIocRX7Mt5fPhm4AgXfE3E56E
|
||||
module:
|
||||
auto_entitylabel: -100
|
||||
actions_permissions: 0
|
||||
address: 0
|
||||
admin_toolbar: 0
|
||||
@@ -52,6 +53,8 @@ module:
|
||||
help: 0
|
||||
honeypot: 0
|
||||
image: 0
|
||||
image_delta_formatter: 0
|
||||
image_field_caption: 0
|
||||
inline_entity_form: 0
|
||||
language: 0
|
||||
layout_builder: 0
|
||||
@@ -90,6 +93,7 @@ module:
|
||||
shield: 0
|
||||
smart_trim: 0
|
||||
smtp: 0
|
||||
structure_sync: 0
|
||||
system: 0
|
||||
taxonomy: 0
|
||||
telephone: 0
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
uuid: 7f1a16d3-57ea-4861-ad4f-1312ceadd1e7
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_nom
|
||||
- node.type.personne
|
||||
id: node.personne.field_nom
|
||||
field_name: field_nom
|
||||
entity_type: node
|
||||
bundle: personne
|
||||
label: Nom
|
||||
description: ''
|
||||
required: true
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings: { }
|
||||
field_type: string
|
||||
@@ -11,7 +11,7 @@ entity_type: node
|
||||
bundle: personne
|
||||
label: Prenom
|
||||
description: ''
|
||||
required: false
|
||||
required: true
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
uuid: 75b15206-7946-48cb-b7b9-17c27ad00c25
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_projets_curates
|
||||
- node.type.personne
|
||||
- node.type.projet
|
||||
id: node.personne.field_projets_curates
|
||||
field_name: field_projets_curates
|
||||
entity_type: node
|
||||
bundle: personne
|
||||
label: projets_curates
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:node'
|
||||
handler_settings:
|
||||
target_bundles:
|
||||
projet: projet
|
||||
sort:
|
||||
field: _none
|
||||
direction: ASC
|
||||
auto_create: false
|
||||
auto_create_bundle: ''
|
||||
field_type: entity_reference
|
||||
@@ -0,0 +1,27 @@
|
||||
uuid: 01cf5142-1617-4b0a-afbe-46bed19f3a75
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_fichiers
|
||||
- node.type.projet
|
||||
module:
|
||||
- file
|
||||
id: node.projet.field_fichiers
|
||||
field_name: field_fichiers
|
||||
entity_type: node
|
||||
bundle: projet
|
||||
label: Fichiers
|
||||
description: ''
|
||||
required: false
|
||||
translatable: false
|
||||
default_value: { }
|
||||
default_value_callback: ''
|
||||
settings:
|
||||
handler: 'default:file'
|
||||
handler_settings: { }
|
||||
file_directory: '[date:custom:Y]-[date:custom:m]'
|
||||
file_extensions: 'pdf doc docx odt zip txt'
|
||||
max_filesize: ''
|
||||
description_field: true
|
||||
field_type: file
|
||||
@@ -35,4 +35,7 @@ settings:
|
||||
title: ''
|
||||
width: null
|
||||
height: null
|
||||
caption: ''
|
||||
caption_field: 1
|
||||
caption_field_required: 0
|
||||
field_type: image
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
uuid: 9a9ebb54-2e2f-46bd-9586-60ebedfc95d8
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- file
|
||||
- node
|
||||
id: node.field_fichiers
|
||||
field_name: field_fichiers
|
||||
entity_type: node
|
||||
type: file
|
||||
settings:
|
||||
target_type: file
|
||||
display_field: true
|
||||
display_default: false
|
||||
uri_scheme: public
|
||||
module: file
|
||||
locked: false
|
||||
cardinality: -1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,21 @@
|
||||
uuid: 14aa5aef-0840-4e3d-a78a-027e2c61844f
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
id: node.field_nom
|
||||
field_name: field_nom
|
||||
entity_type: node
|
||||
type: string
|
||||
settings:
|
||||
max_length: 255
|
||||
case_sensitive: false
|
||||
is_ascii: false
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: 1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -0,0 +1,19 @@
|
||||
uuid: c5d97546-10d2-46e0-9324-1164bdd04cbb
|
||||
langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
module:
|
||||
- node
|
||||
id: node.field_projets_curates
|
||||
field_name: field_projets_curates
|
||||
entity_type: node
|
||||
type: entity_reference
|
||||
settings:
|
||||
target_type: node
|
||||
module: core
|
||||
locked: false
|
||||
cardinality: -1
|
||||
translatable: true
|
||||
indexes: { }
|
||||
persist_with_no_fields: false
|
||||
custom_storage: false
|
||||
@@ -15,6 +15,8 @@ source:
|
||||
plugin: projet_node
|
||||
data_fetcher_plugin: http
|
||||
data_parser_plugin: google_sheets
|
||||
constants:
|
||||
images_destination: 'public://projets/'
|
||||
urls: 'https://sheets.googleapis.com/v4/spreadsheets/1561Gv1C-IlCTmg64Z8HnznvOeLbvwhA_k1l6aq95zFA/values/Projets'
|
||||
fields:
|
||||
-
|
||||
@@ -56,7 +58,43 @@ process:
|
||||
type:
|
||||
plugin: default_value
|
||||
default_value: projet
|
||||
title: title
|
||||
title:
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
source: title
|
||||
message: 'Projet ignoré : « Nom du projet » vide.'
|
||||
body/value: body_html
|
||||
body/format:
|
||||
plugin: default_value
|
||||
default_value: wysiwyg
|
||||
field_images:
|
||||
plugin: sub_process
|
||||
source: images
|
||||
process:
|
||||
target_id:
|
||||
plugin: image_resize_import
|
||||
source: uri
|
||||
destination: destination
|
||||
max_width: 1920
|
||||
max_height: 1920
|
||||
reuse: true
|
||||
skip_on_missing_source: true
|
||||
alt: alt
|
||||
image_field_caption/value: caption
|
||||
image_field_caption/format:
|
||||
plugin: default_value
|
||||
default_value: wysiwyg
|
||||
field_fichiers:
|
||||
plugin: sub_process
|
||||
source: pdfs
|
||||
process:
|
||||
target_id:
|
||||
plugin: file_import
|
||||
source: uri
|
||||
destination: destination
|
||||
reuse: true
|
||||
skip_on_missing_source: true
|
||||
description: description
|
||||
field_dates/value:
|
||||
plugin: leshed_date
|
||||
source: date_start
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
langcode: fr
|
||||
_core:
|
||||
default_config_hash: R7HmKRbuDsDQNpqEWt7wWcf0ygaE3u-NQQr-w_LhHJk
|
||||
auto_redirect: true
|
||||
@@ -7,4 +8,3 @@ warning: false
|
||||
ignore_admin_path: false
|
||||
access_check: false
|
||||
route_normalizer_enabled: true
|
||||
langcode: fr
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
menus:
|
||||
-
|
||||
menu_name: main
|
||||
title: Accueil
|
||||
parent: null
|
||||
uri: 'internal:/'
|
||||
link_title: ''
|
||||
description: null
|
||||
enabled: true
|
||||
expanded: false
|
||||
weight: 0
|
||||
langcode: fr
|
||||
uuid: 75910d9e-f8a0-4dbd-930f-e37fb47de597
|
||||
options: { }
|
||||
@@ -4,7 +4,7 @@ langcode: fr
|
||||
uuid: e53d1b41-902a-4030-a476-ad2d5f3e5070
|
||||
name: 'Le Shed'
|
||||
mail: dev@figureslibres.io
|
||||
slogan: ''
|
||||
slogan: "Centre d'art en Normandie"
|
||||
page:
|
||||
403: ''
|
||||
404: ''
|
||||
|
||||
@@ -3,7 +3,8 @@ langcode: fr
|
||||
status: true
|
||||
dependencies:
|
||||
config:
|
||||
- field.storage.node.field_prenom
|
||||
- field.storage.node.field_projet_s_lie_s
|
||||
- field.storage.node.field_projets_curates
|
||||
- field.storage.node.field_type_de_projet
|
||||
module:
|
||||
- node
|
||||
@@ -107,69 +108,6 @@ display:
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
field_prenom:
|
||||
id: field_prenom
|
||||
table: node__field_prenom
|
||||
field: field_prenom
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: field
|
||||
label: ''
|
||||
exclude: true
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: false
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: value
|
||||
type: string
|
||||
settings:
|
||||
link_to_entity: true
|
||||
group_column: value
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
title:
|
||||
id: title
|
||||
table: node_field_data
|
||||
@@ -183,7 +121,7 @@ display:
|
||||
label: Titre
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: true
|
||||
alter_text: false
|
||||
text: '{{ field_prenom }} {{ title }}'
|
||||
make_link: false
|
||||
path: ''
|
||||
@@ -298,25 +236,132 @@ display:
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
name:
|
||||
id: name
|
||||
table: users_field_data
|
||||
field: name
|
||||
relationship: uid
|
||||
entity_type: user
|
||||
entity_field: name
|
||||
field_projet_s_lie_s:
|
||||
id: field_projet_s_lie_s
|
||||
table: node__field_projet_s_lie_s
|
||||
field: field_projet_s_lie_s
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: field
|
||||
label: Auteur
|
||||
label: 'Projet(s) lié(s)'
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
type: user_name
|
||||
click_sort_column: target_id
|
||||
type: entity_reference_label
|
||||
settings:
|
||||
link: true
|
||||
group_column: target_id
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
field_projets_curates:
|
||||
id: field_projets_curates
|
||||
table: node__field_projets_curates
|
||||
field: field_projets_curates
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: field
|
||||
label: projets_curates
|
||||
exclude: false
|
||||
alter:
|
||||
alter_text: false
|
||||
text: ''
|
||||
make_link: false
|
||||
path: ''
|
||||
absolute: false
|
||||
external: false
|
||||
replace_spaces: false
|
||||
path_case: none
|
||||
trim_whitespace: false
|
||||
alt: ''
|
||||
rel: ''
|
||||
link_class: ''
|
||||
prefix: ''
|
||||
suffix: ''
|
||||
target: ''
|
||||
nl2br: false
|
||||
max_length: 0
|
||||
word_boundary: true
|
||||
ellipsis: true
|
||||
more_link: false
|
||||
more_link_text: ''
|
||||
more_link_path: ''
|
||||
strip_tags: false
|
||||
trim: false
|
||||
preserve_tags: ''
|
||||
html: false
|
||||
element_type: ''
|
||||
element_class: ''
|
||||
element_label_type: ''
|
||||
element_label_class: ''
|
||||
element_label_colon: true
|
||||
element_wrapper_type: ''
|
||||
element_wrapper_class: ''
|
||||
element_default_classes: true
|
||||
empty: ''
|
||||
hide_empty: false
|
||||
empty_zero: false
|
||||
hide_alter_empty: true
|
||||
click_sort_column: target_id
|
||||
type: entity_reference_label
|
||||
settings:
|
||||
link: true
|
||||
group_column: target_id
|
||||
group_columns: { }
|
||||
group_rows: true
|
||||
delta_limit: 0
|
||||
delta_offset: 0
|
||||
delta_reversed: false
|
||||
delta_first_last: false
|
||||
multi_type: separator
|
||||
separator: ', '
|
||||
field_api_classes: false
|
||||
status:
|
||||
id: status
|
||||
table: node_field_data
|
||||
@@ -658,9 +703,10 @@ display:
|
||||
columns:
|
||||
node_bulk_form: node_bulk_form
|
||||
type: title
|
||||
field_prenom: title
|
||||
title: title
|
||||
name: name
|
||||
field_type_de_projet: field_type_de_projet
|
||||
field_projets_curates: field_projet_s_lie_s
|
||||
field_projet_s_lie_s: field_projet_s_lie_s
|
||||
status: status
|
||||
changed: changed
|
||||
operations: operations
|
||||
@@ -678,13 +724,6 @@ display:
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
field_prenom:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
title:
|
||||
sortable: true
|
||||
default_sort_order: asc
|
||||
@@ -692,13 +731,21 @@ display:
|
||||
separator: '<br/>'
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
name:
|
||||
sortable: false
|
||||
default_sort_order: asc
|
||||
field_type_de_projet:
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: priority-low
|
||||
responsive: ''
|
||||
field_projets_curates:
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
field_projet_s_lie_s:
|
||||
align: ''
|
||||
separator: ''
|
||||
empty_column: false
|
||||
responsive: ''
|
||||
status:
|
||||
sortable: true
|
||||
default_sort_order: asc
|
||||
@@ -737,6 +784,17 @@ display:
|
||||
plugin_id: standard
|
||||
required: true
|
||||
show_admin_links: false
|
||||
header:
|
||||
result:
|
||||
id: result
|
||||
table: views
|
||||
field: result
|
||||
relationship: none
|
||||
group_type: group
|
||||
admin_label: ''
|
||||
plugin_id: result
|
||||
empty: false
|
||||
content: 'Affichage de @start à @end sur @total'
|
||||
display_extenders: { }
|
||||
cache_metadata:
|
||||
max-age: 0
|
||||
@@ -749,7 +807,8 @@ display:
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags:
|
||||
- 'config:field.storage.node.field_prenom'
|
||||
- 'config:field.storage.node.field_projet_s_lie_s'
|
||||
- 'config:field.storage.node.field_projets_curates'
|
||||
- 'config:field.storage.node.field_type_de_projet'
|
||||
page_1:
|
||||
id: page_1
|
||||
@@ -783,5 +842,6 @@ display:
|
||||
- 'user.node_grants:view'
|
||||
- user.permissions
|
||||
tags:
|
||||
- 'config:field.storage.node.field_prenom'
|
||||
- 'config:field.storage.node.field_projet_s_lie_s'
|
||||
- 'config:field.storage.node.field_projets_curates'
|
||||
- 'config:field.storage.node.field_type_de_projet'
|
||||
|
||||
+41
-1
@@ -10,6 +10,10 @@ source:
|
||||
plugin: projet_node
|
||||
data_fetcher_plugin: http
|
||||
data_parser_plugin: google_sheets
|
||||
constants:
|
||||
# Trailing slash: file_import keeps the original filename and copies the
|
||||
# image into this directory.
|
||||
images_destination: 'public://projets/'
|
||||
# The feed file for the spreadsheet. The Google Spreadsheet should be either “Public” or set to “Anyone with link can
|
||||
# view” in order for the feed to work.
|
||||
# Template: 'https://sheets.googleapis.com/v4/spreadsheets/<SHEET>/values/<TAB>?key=<KEY>'
|
||||
@@ -68,7 +72,43 @@ process:
|
||||
type:
|
||||
plugin: default_value
|
||||
default_value: projet
|
||||
title: title
|
||||
title:
|
||||
plugin: skip_on_empty
|
||||
method: row
|
||||
source: title
|
||||
message: 'Projet ignoré : « Nom du projet » vide.'
|
||||
body/value: body_html
|
||||
body/format:
|
||||
plugin: default_value
|
||||
default_value: wysiwyg
|
||||
field_images:
|
||||
plugin: sub_process
|
||||
source: images
|
||||
process:
|
||||
target_id:
|
||||
plugin: image_resize_import
|
||||
source: uri
|
||||
destination: destination
|
||||
max_width: 1920
|
||||
max_height: 1920
|
||||
reuse: true
|
||||
skip_on_missing_source: true
|
||||
alt: alt
|
||||
image_field_caption/value: caption
|
||||
image_field_caption/format:
|
||||
plugin: default_value
|
||||
default_value: wysiwyg
|
||||
field_fichiers:
|
||||
plugin: sub_process
|
||||
source: pdfs
|
||||
process:
|
||||
target_id:
|
||||
plugin: file_import
|
||||
source: uri
|
||||
destination: destination
|
||||
reuse: true
|
||||
skip_on_missing_source: true
|
||||
description: description
|
||||
field_dates/value:
|
||||
plugin: leshed_date
|
||||
source: date_start
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\migrate_leshed\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\File\FileExists;
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Attribute\MigrateProcess;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Copies a local file into the file system as a managed File entity.
|
||||
*
|
||||
* The source value is a readable file path/URI. The file is copied into the
|
||||
* destination directory and registered as a managed file; the file id is
|
||||
* returned.
|
||||
*
|
||||
* Configuration:
|
||||
* - destination: (required) destination directory URI, e.g. 'public://2026-08/'.
|
||||
* - uid: owner uid of the created file (default 0).
|
||||
* - reuse: reuse an existing managed file at the destination URI (default TRUE).
|
||||
* - skip_on_missing_source: skip the value when the source is missing
|
||||
* (default TRUE) instead of failing.
|
||||
*
|
||||
* @code
|
||||
* field_fichiers/target_id:
|
||||
* plugin: file_import
|
||||
* source: uri
|
||||
* destination: destination
|
||||
* @endcode
|
||||
*/
|
||||
#[MigrateProcess(id: 'file_import')]
|
||||
final class FileImport extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* Per-run cache of already resolved destination URIs to file ids.
|
||||
*
|
||||
* @var array<string, int>
|
||||
*/
|
||||
private array $fidCache = [];
|
||||
|
||||
public function __construct(
|
||||
array $configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
private readonly FileSystemInterface $fileSystem,
|
||||
private readonly EntityTypeManagerInterface $entityTypeManager,
|
||||
) {
|
||||
$configuration += [
|
||||
'uid' => 0,
|
||||
'reuse' => TRUE,
|
||||
'skip_on_missing_source' => TRUE,
|
||||
];
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
|
||||
return new self(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('file_system'),
|
||||
$container->get('entity_type.manager'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property): ?int {
|
||||
$source = is_string($value) ? trim($value) : '';
|
||||
if ($source === '') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!is_file($source) && !is_file($this->fileSystem->realpath($source) ?: $source)) {
|
||||
return $this->skipFile($migrate_executable, "Source file '$source' is missing.");
|
||||
}
|
||||
|
||||
$directory = $this->getPropertyValue($this->configuration['destination'], $row);
|
||||
if (!is_string($directory) || $directory === '') {
|
||||
return $this->skipFile($migrate_executable, "Missing 'destination' for file '$source'.");
|
||||
}
|
||||
$directory = rtrim($directory, '/') . '/';
|
||||
$destination = $directory . $this->fileSystem->basename($source);
|
||||
|
||||
// Reuse an already imported file to keep the migration idempotent.
|
||||
if ($this->configuration['reuse']) {
|
||||
if (isset($this->fidCache[$destination])) {
|
||||
return $this->fidCache[$destination];
|
||||
}
|
||||
$existing = $this->entityTypeManager->getStorage('file')
|
||||
->loadByProperties(['uri' => $destination]);
|
||||
if ($existing) {
|
||||
return $this->fidCache[$destination] = (int) reset($existing)->id();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if (!$this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
|
||||
return $this->skipFile($migrate_executable, "Cannot prepare directory '$directory'.");
|
||||
}
|
||||
$this->fileSystem->copy($source, $destination, FileExists::Replace);
|
||||
|
||||
$file = $this->entityTypeManager->getStorage('file')->create([
|
||||
'uri' => $destination,
|
||||
'uid' => (int) $this->getPropertyValue($this->configuration['uid'], $row),
|
||||
'status' => 1,
|
||||
]);
|
||||
$file->save();
|
||||
}
|
||||
catch (\Throwable $e) {
|
||||
return $this->skipFile($migrate_executable, "Import of file '$source' failed: " . $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->fidCache[$destination] = (int) $file->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message and skips the current file item.
|
||||
*
|
||||
* @throws \Drupal\migrate\MigrateSkipRowException
|
||||
*/
|
||||
private function skipFile(MigrateExecutableInterface $migrate_executable, string $message): never {
|
||||
$migrate_executable->saveMessage($message);
|
||||
throw new MigrateSkipRowException($message, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a configuration value, supporting destination (@) references.
|
||||
*/
|
||||
private function getPropertyValue(mixed $key, Row $row): mixed {
|
||||
if (is_string($key) && str_starts_with($key, '@')) {
|
||||
return $row->get(substr($key, 1));
|
||||
}
|
||||
if (is_string($key) && $row->hasSourceProperty($key)) {
|
||||
return $row->getSourceProperty($key);
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\migrate_leshed\Plugin\migrate\process;
|
||||
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\Image\ImageFactory;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\migrate\Attribute\MigrateProcess;
|
||||
use Drupal\migrate\MigrateExecutableInterface;
|
||||
use Drupal\migrate\MigrateSkipRowException;
|
||||
use Drupal\migrate\ProcessPluginBase;
|
||||
use Drupal\migrate\Row;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Copies a local image, downscaling it to a web-friendly size, as a File.
|
||||
*
|
||||
* The source value is a readable file path/URI. The image is scaled down
|
||||
* (aspect ratio preserved, never upscaled) to fit within max_width x
|
||||
* max_height, saved into the destination directory and registered as a
|
||||
* managed file. Returns the file id.
|
||||
*
|
||||
* Configuration:
|
||||
* - destination: (required) destination directory URI, e.g. 'public://projets/1/'.
|
||||
* - max_width: maximum width in pixels (default 1920).
|
||||
* - max_height: maximum height in pixels (default 1920).
|
||||
* - uid: owner uid of the created file (default 0).
|
||||
* - reuse: reuse an existing managed file at the destination URI (default TRUE).
|
||||
* - skip_on_missing_source: skip the value when the source is missing
|
||||
* (default TRUE) instead of failing.
|
||||
*
|
||||
* @code
|
||||
* field_images/target_id:
|
||||
* plugin: image_resize_import
|
||||
* source: uri
|
||||
* destination: destination
|
||||
* max_width: 1920
|
||||
* max_height: 1920
|
||||
* @endcode
|
||||
*/
|
||||
#[MigrateProcess(id: 'image_resize_import')]
|
||||
final class ImageResizeImport extends ProcessPluginBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* Per-run cache of already resolved destination URIs to file ids.
|
||||
*
|
||||
* @var array<string, int>
|
||||
*/
|
||||
private array $fidCache = [];
|
||||
|
||||
public function __construct(
|
||||
array $configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
private readonly FileSystemInterface $fileSystem,
|
||||
private readonly ImageFactory $imageFactory,
|
||||
private readonly EntityTypeManagerInterface $entityTypeManager,
|
||||
) {
|
||||
$configuration += [
|
||||
'max_width' => 1920,
|
||||
'max_height' => 1920,
|
||||
'uid' => 0,
|
||||
'reuse' => TRUE,
|
||||
'skip_on_missing_source' => TRUE,
|
||||
];
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): self {
|
||||
return new self(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('file_system'),
|
||||
$container->get('image.factory'),
|
||||
$container->get('entity_type.manager'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property): ?int {
|
||||
$source = is_string($value) ? trim($value) : '';
|
||||
if ($source === '') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Stream wrappers support is_file() directly; realpath() is only needed as
|
||||
// a fallback for schemes it cannot resolve.
|
||||
if (!is_file($source) && !is_file($this->fileSystem->realpath($source) ?: $source)) {
|
||||
// Skipping throws MigrateSkipRowException because, inside a sub_process,
|
||||
// only that exception drops the whole image item cleanly (SubProcess
|
||||
// catches it and `continue`s); MigrateSkipProcessException would instead
|
||||
// leave a broken delta with alt/caption but no target_id.
|
||||
return $this->skipImage($migrate_executable, "Source image '$source' is missing.");
|
||||
}
|
||||
|
||||
$directory = $this->getPropertyValue($this->configuration['destination'], $row);
|
||||
if (!is_string($directory) || $directory === '') {
|
||||
return $this->skipImage($migrate_executable, "Missing 'destination' for image '$source'.");
|
||||
}
|
||||
$directory = rtrim($directory, '/') . '/';
|
||||
$destination = $directory . $this->fileSystem->basename($source);
|
||||
|
||||
// Reuse an already imported file (idempotency), memoized for the run.
|
||||
if ($this->configuration['reuse']) {
|
||||
if (isset($this->fidCache[$destination])) {
|
||||
return $this->fidCache[$destination];
|
||||
}
|
||||
$existing = $this->entityTypeManager->getStorage('file')
|
||||
->loadByProperties(['uri' => $destination]);
|
||||
if ($existing) {
|
||||
return $this->fidCache[$destination] = (int) reset($existing)->id();
|
||||
}
|
||||
}
|
||||
|
||||
// Any infrastructure failure only drops the current image (logged), so a
|
||||
// single unreadable/oversized file never aborts the whole batch.
|
||||
try {
|
||||
if (!$this->fileSystem->prepareDirectory($directory, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
|
||||
return $this->skipImage($migrate_executable, "Cannot prepare directory '$directory'.");
|
||||
}
|
||||
|
||||
$image = $this->imageFactory->get($source);
|
||||
if (!$image->isValid()) {
|
||||
return $this->skipImage($migrate_executable, "Source '$source' is not a valid image.");
|
||||
}
|
||||
// Downscale only: scale() never upscales when upscale is FALSE.
|
||||
$image->scale((int) $this->configuration['max_width'], (int) $this->configuration['max_height']);
|
||||
if (!$image->save($destination)) {
|
||||
return $this->skipImage($migrate_executable, "Failed to write resized image to '$destination'.");
|
||||
}
|
||||
|
||||
$file = $this->entityTypeManager->getStorage('file')->create([
|
||||
'uri' => $destination,
|
||||
'uid' => (int) $this->getPropertyValue($this->configuration['uid'], $row),
|
||||
'status' => 1,
|
||||
]);
|
||||
$file->save();
|
||||
}
|
||||
catch (\Throwable $e) {
|
||||
return $this->skipImage($migrate_executable, "Import of image '$source' failed: " . $e->getMessage());
|
||||
}
|
||||
|
||||
return $this->fidCache[$destination] = (int) $file->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs a message and skips the current image item.
|
||||
*
|
||||
* @throws \Drupal\migrate\MigrateSkipRowException
|
||||
*/
|
||||
private function skipImage(MigrateExecutableInterface $migrate_executable, string $message): never {
|
||||
$migrate_executable->saveMessage($message);
|
||||
throw new MigrateSkipRowException($message, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a configuration value, supporting destination (@) references.
|
||||
*/
|
||||
private function getPropertyValue(mixed $key, Row $row): mixed {
|
||||
if (is_string($key) && str_starts_with($key, '@')) {
|
||||
return $row->get(substr($key, 1));
|
||||
}
|
||||
if (is_string($key) && $row->hasSourceProperty($key)) {
|
||||
return $row->getSourceProperty($key);
|
||||
}
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,8 +18,9 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
* Input: a string such as "Julie Faitot et Jonathan Loppin" or
|
||||
* "Sonja Beaudouin, Alexandre Delabrière". Names are split on "et" and
|
||||
* commas. For each name, the first word is used as 'field_prenom' and the
|
||||
* rest as the node title. An existing node with the same title and prenom
|
||||
* is reused, otherwise it is created. Returns an array of node IDs.
|
||||
* rest as 'field_nom'. The node title is generated from those two fields by
|
||||
* the auto_entitylabel module on save. An existing node with the same nom and
|
||||
* prenom is reused, otherwise it is created. Returns an array of node IDs.
|
||||
*
|
||||
* When 'type_de_personne' is set in the configuration, a taxonomy term with
|
||||
* that name is found or created (without duplicates) in the
|
||||
@@ -103,7 +104,7 @@ final class PersonneGenerate extends ProcessPluginBase implements ContainerFacto
|
||||
|
||||
$query = $storage->getQuery()
|
||||
->condition('type', 'personne')
|
||||
->condition('title', $nom)
|
||||
->condition('field_nom', $nom)
|
||||
->accessCheck(FALSE)
|
||||
->range(0, 1);
|
||||
if ($prenom !== '') {
|
||||
@@ -121,9 +122,11 @@ final class PersonneGenerate extends ProcessPluginBase implements ContainerFacto
|
||||
return $nid;
|
||||
}
|
||||
|
||||
// The node title is generated from field_prenom + field_nom by
|
||||
// auto_entitylabel on save; it is intentionally not set here.
|
||||
$values = [
|
||||
'type' => 'personne',
|
||||
'title' => $nom,
|
||||
'field_nom' => $nom,
|
||||
'field_prenom' => $prenom === '' ? NULL : $prenom,
|
||||
'status' => 1,
|
||||
'uid' => $this->configuration['author_uid'] ?? 3,
|
||||
|
||||
@@ -4,11 +4,33 @@ declare(strict_types=1);
|
||||
|
||||
namespace Drupal\migrate_leshed\Plugin\migrate\source;
|
||||
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\File\FileSystemInterface;
|
||||
use Drupal\Core\Utility\Token;
|
||||
use Drupal\migrate\Attribute\MigrateSource;
|
||||
use Drupal\migrate_plus\Plugin\migrate\source\Url;
|
||||
use Drupal\migrate\Plugin\MigrationInterface;
|
||||
use Drupal\migrate\Row;
|
||||
use Drupal\migrate_plus\DataParserPluginManager;
|
||||
use Drupal\migrate_plus\Plugin\migrate\source\Url;
|
||||
use League\CommonMark\CommonMarkConverter;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Source plugin for projects, enriched with body and images from the drive.
|
||||
*
|
||||
* On top of the Google Sheets columns, this source reads the local files
|
||||
* synced from the shared Google Drive (see the `sync_leshed_drive` Makefile
|
||||
* target) that live under public://drive_shared_leshed. Files are grouped in
|
||||
* per-project folders named "Page{UID}" (optionally suffixed, e.g.
|
||||
* "Page1_Complet"), where {UID} matches the sheet UID column:
|
||||
* - "{UID}_texte_*.md": the body, written in Markdown, converted to HTML.
|
||||
* - "{UID}_images|Images/": one folder of images, each "{name}.jpg" paired
|
||||
* with a "{name}_legende.md" caption used as the (required) alt text.
|
||||
*
|
||||
* These are exposed as two extra source properties consumed by the migration:
|
||||
* - body_html: the converted HTML string (or NULL).
|
||||
* - images: a list of ['uri' => string, 'alt' => string] items.
|
||||
*
|
||||
* @MigrateSource(
|
||||
* id = "projet_node"
|
||||
* )
|
||||
@@ -16,18 +38,80 @@ use Drupal\migrate\Row;
|
||||
#[MigrateSource(id: 'projet_node')]
|
||||
final class ProjetNode extends Url {
|
||||
|
||||
/**
|
||||
* Stream wrapper URI of the synced drive folder.
|
||||
*/
|
||||
private const DRIVE_URI = 'public://drive_shared_leshed';
|
||||
|
||||
/**
|
||||
* Image file extensions to import into field_images.
|
||||
*/
|
||||
private const IMAGE_EXTENSIONS = ['png', 'gif', 'jpg', 'jpeg', 'webp'];
|
||||
|
||||
/**
|
||||
* File extensions to import into field_fichiers.
|
||||
*/
|
||||
private const FILE_EXTENSIONS = ['pdf'];
|
||||
|
||||
/**
|
||||
* Default destination directory when no constant is configured.
|
||||
*/
|
||||
private const DEFAULT_IMAGE_DESTINATION = 'public://projets/';
|
||||
|
||||
/**
|
||||
* Lazily instantiated Markdown converter.
|
||||
*/
|
||||
private ?CommonMarkConverter $markdownConverter = NULL;
|
||||
|
||||
/**
|
||||
* Memoized map of UID => project folder URI, built once from the drive root.
|
||||
*
|
||||
* @var array<string, string>|null
|
||||
*/
|
||||
private ?array $folderMap = NULL;
|
||||
|
||||
/**
|
||||
* Memoized destination directory for field_fichiers (from field settings).
|
||||
*/
|
||||
private ?string $filesDestination = NULL;
|
||||
|
||||
public function __construct(
|
||||
array $configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
MigrationInterface $migration,
|
||||
DataParserPluginManager $parserPluginManager,
|
||||
private readonly FileSystemInterface $fileSystem,
|
||||
private readonly EntityFieldManagerInterface $entityFieldManager,
|
||||
private readonly Token $token,
|
||||
) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration, $parserPluginManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create($container, array $configuration, $plugin_id, $plugin_definition, ?MigrationInterface $migration = NULL): self {
|
||||
return new self(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$migration,
|
||||
$container->get('plugin.manager.migrate_plus.data_parser'),
|
||||
$container->get('file_system'),
|
||||
$container->get('entity_field.manager'),
|
||||
$container->get('token'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function fields(): array {
|
||||
// theese are source fields
|
||||
return [
|
||||
'id' => $this->t('Project ID'),
|
||||
'title' => $this->t('Project Title'),
|
||||
'date_start' => $this->t('Project date start'),
|
||||
'date_end' => $this->t('Project date end'),
|
||||
'projet_type' => $this->t('Type de projet'),
|
||||
'curator' => $this->t('Commissaria')
|
||||
return parent::fields() + [
|
||||
'body_html' => $this->t('Project body (HTML converted from Markdown)'),
|
||||
'images' => $this->t('Project images with captions'),
|
||||
'pdfs' => $this->t('Project PDF files'),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -45,16 +129,331 @@ final class ProjetNode extends Url {
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prepareRow(Row $row) {
|
||||
// $nid = $row->getSourceProperty('entity_id');
|
||||
// $vid = $row->getSourceProperty('revision_id');
|
||||
// $type = $row->getSourceProperty('type');
|
||||
// $language = $row->getSourceProperty('language');
|
||||
// $title = $row->getSourceProperty('title');
|
||||
// // drush_print('-- '.$nid."\t".$title."\t".$language);
|
||||
public function prepareRow(Row $row): bool {
|
||||
// Let the parent (and prepare-row event subscribers) decide first: no need
|
||||
// to hit the filesystem for a row that will be skipped.
|
||||
if (!parent::prepareRow($row)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Always define both properties so the process pipeline never references
|
||||
// an undefined source key, even when no drive folder exists yet.
|
||||
$row->setSourceProperty('body_html', NULL);
|
||||
$row->setSourceProperty('images', []);
|
||||
$row->setSourceProperty('pdfs', []);
|
||||
|
||||
$uid = trim((string) $row->getSourceProperty('id'));
|
||||
$folder = $uid !== '' ? $this->findProjectFolder($uid) : NULL;
|
||||
if ($folder !== NULL) {
|
||||
$row->setSourceProperty('body_html', $this->readBody($folder, $uid));
|
||||
$row->setSourceProperty('images', $this->readImages($folder, $uid, (string) $row->getSourceProperty('title')));
|
||||
$row->setSourceProperty('pdfs', $this->readPdfs($folder, $uid));
|
||||
}
|
||||
|
||||
return parent::prepareRow($row);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public:// URI of the project folder, or NULL when missing.
|
||||
*/
|
||||
private function findProjectFolder(string $uid): ?string {
|
||||
return $this->getFolderMap()[$uid] ?? NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds (once) the UID => project folder URI map from the drive root.
|
||||
*
|
||||
* @return array<string, string>
|
||||
* Map keyed by the numeric part of each "Page{UID}[_suffix]" folder.
|
||||
*/
|
||||
private function getFolderMap(): array {
|
||||
if ($this->folderMap !== NULL) {
|
||||
return $this->folderMap;
|
||||
}
|
||||
|
||||
$this->folderMap = [];
|
||||
$base = $this->fileSystem->realpath(self::DRIVE_URI);
|
||||
if ($base === FALSE || !is_dir($base)) {
|
||||
return $this->folderMap;
|
||||
}
|
||||
// Match "Page{N}" exactly or with a suffix ("_Complet", ...). Sorting keeps
|
||||
// the resolution deterministic when e.g. "Page5" and "Page5_Complet"
|
||||
// coexist (the plain, longer-suffixed folder wins consistently).
|
||||
$entries = scandir($base) ?: [];
|
||||
sort($entries, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
foreach ($entries as $entry) {
|
||||
if ($entry === '.' || $entry === '..' || !is_dir($base . '/' . $entry)) {
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^Page(\d+)(_.*)?$/', $entry, $matches)) {
|
||||
$this->folderMap[$matches[1]] = self::DRIVE_URI . '/' . $entry;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->folderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the Markdown body file and converts it to HTML.
|
||||
*/
|
||||
private function readBody(string $folderUri, string $uid): ?string {
|
||||
$dir = $this->fileSystem->realpath($folderUri);
|
||||
if ($dir === FALSE) {
|
||||
return NULL;
|
||||
}
|
||||
// Prefer "{UID}_texte*.md", fall back to any Markdown file at the root.
|
||||
$preferred = '/^' . preg_quote($uid, '/') . '_texte.*\.md$/i';
|
||||
$entries = scandir($dir) ?: [];
|
||||
sort($entries, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
$markdown = NULL;
|
||||
foreach ($entries as $entry) {
|
||||
if (!is_file($dir . '/' . $entry) || !preg_match('/\.md$/i', $entry)) {
|
||||
continue;
|
||||
}
|
||||
if (preg_match($preferred, $entry)) {
|
||||
$markdown = $dir . '/' . $entry;
|
||||
break;
|
||||
}
|
||||
$markdown ??= $dir . '/' . $entry;
|
||||
}
|
||||
if ($markdown === NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$contents = file_get_contents($markdown);
|
||||
if ($contents === FALSE || trim($contents) === '') {
|
||||
return NULL;
|
||||
}
|
||||
$contents = $this->cleanBodyMarkdown($contents);
|
||||
if ($contents === '') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (string) $this->getMarkdownConverter()->convert($contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the raw source Markdown before conversion.
|
||||
*
|
||||
* Removes redundant content already present elsewhere: raw HTML wrappers,
|
||||
* invisible characters, and the leading title block (H1 title + H2/H3
|
||||
* artists/subtitle, redundant with the sheet). Headings located *inside* the
|
||||
* body (e.g. artist/curator bios) are preserved. Idempotent: running it on an
|
||||
* already-cleaned text has no effect.
|
||||
*/
|
||||
private function cleanBodyMarkdown(string $md): string {
|
||||
// 1. Strip HTML tags (<div>, <br>, </div>, ...).
|
||||
$md = (string) preg_replace('/<[^>]+>/', '', $md);
|
||||
// 2. Strip zero-width/BOM characters and turn NBSP into a normal space.
|
||||
$md = (string) preg_replace('/[\x{200B}\x{200E}\x{200F}\x{FEFF}]/u', '', $md);
|
||||
$md = (string) preg_replace('/\x{00A0}/u', ' ', $md);
|
||||
// 3. Drop only the leading heading block: skip leading blank and heading
|
||||
// lines until the first body line.
|
||||
$lines = preg_split('/\R/u', $md) ?: [];
|
||||
$i = 0;
|
||||
$count = count($lines);
|
||||
while ($i < $count && (trim($lines[$i]) === '' || preg_match('/^\s*#{1,6}\s/u', $lines[$i]))) {
|
||||
$i++;
|
||||
}
|
||||
$md = implode("\n", array_slice($lines, $i));
|
||||
// 4. Collapse blank lines and trim.
|
||||
$md = (string) preg_replace('/\n{3,}/', "\n\n", $md);
|
||||
|
||||
return trim($md);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the list of images (URI + alt) for the project.
|
||||
*
|
||||
* @return array<int, array{uri: string, alt: string, caption: string, destination: string}>
|
||||
* The images to import.
|
||||
*/
|
||||
private function readImages(string $folderUri, string $uid, string $title): array {
|
||||
$dir = $this->fileSystem->realpath($folderUri);
|
||||
if ($dir === FALSE) {
|
||||
return [];
|
||||
}
|
||||
// The destination is passed through each item because a sub_process row
|
||||
// cannot read the parent migration's `constants`. It is namespaced per
|
||||
// project (UID) so identically-named files from different projects never
|
||||
// collide when file_import reuses existing files (reuse: true).
|
||||
$base = $this->configuration['constants']['images_destination']
|
||||
?? self::DEFAULT_IMAGE_DESTINATION;
|
||||
$destination = rtrim($base, '/') . '/' . $uid . '/';
|
||||
// Locate the images subfolder ("{UID}_images", case-insensitive).
|
||||
$imagesDirUri = NULL;
|
||||
$pattern = '/^' . preg_quote($uid, '/') . '_images$/i';
|
||||
foreach (scandir($dir) ?: [] as $entry) {
|
||||
if (preg_match($pattern, $entry) && is_dir($dir . '/' . $entry)) {
|
||||
$imagesDirUri = $folderUri . '/' . $entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($imagesDirUri === NULL) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$imagesDir = $this->fileSystem->realpath($imagesDirUri);
|
||||
if ($imagesDir === FALSE) {
|
||||
return [];
|
||||
}
|
||||
$images = [];
|
||||
$files = scandir($imagesDir) ?: [];
|
||||
sort($files, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
foreach ($files as $file) {
|
||||
$extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
||||
if (!in_array($extension, self::IMAGE_EXTENSIONS, TRUE)) {
|
||||
continue;
|
||||
}
|
||||
$name = pathinfo($file, PATHINFO_FILENAME);
|
||||
$legende = $this->readCaptionFile($imagesDir . '/' . $name . '_legende.md');
|
||||
// Plain text (required alt), falling back to the project title. Capped to
|
||||
// the image field's alt column length (varchar 512).
|
||||
$alt = $legende !== '' ? $this->toPlainText($legende) : $title;
|
||||
$alt = mb_substr($alt, 0, 512);
|
||||
// Rich caption (image_field_caption): Markdown converted to HTML.
|
||||
$caption = $legende !== '' ? (string) $this->getMarkdownConverter()->convert($legende) : '';
|
||||
$images[] = [
|
||||
'uri' => $imagesDirUri . '/' . $file,
|
||||
'alt' => $alt,
|
||||
'caption' => $caption,
|
||||
'destination' => $destination,
|
||||
];
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the list of PDF files for the project.
|
||||
*
|
||||
* Collects PDFs both at the project folder root and inside the "{UID}_pdf"
|
||||
* subfolder. Each item carries the destination directory (from the
|
||||
* field_fichiers settings) and a human-readable description.
|
||||
*
|
||||
* @return array<int, array{uri: string, destination: string, description: string}>
|
||||
* The files to import.
|
||||
*/
|
||||
private function readPdfs(string $folderUri, string $uid): array {
|
||||
$dir = $this->fileSystem->realpath($folderUri);
|
||||
if ($dir === FALSE) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Directories to scan: the project folder root and its "{UID}_pdf" subfolder.
|
||||
$sources = [$folderUri];
|
||||
$pattern = '/^' . preg_quote($uid, '/') . '_pdf$/i';
|
||||
foreach (scandir($dir) ?: [] as $entry) {
|
||||
if (preg_match($pattern, $entry) && is_dir($dir . '/' . $entry)) {
|
||||
$sources[] = $folderUri . '/' . $entry;
|
||||
}
|
||||
}
|
||||
|
||||
$destination = $this->filesDestination();
|
||||
$pdfs = [];
|
||||
foreach ($sources as $sourceUri) {
|
||||
$sourceDir = $this->fileSystem->realpath($sourceUri);
|
||||
if ($sourceDir === FALSE) {
|
||||
continue;
|
||||
}
|
||||
$files = scandir($sourceDir) ?: [];
|
||||
sort($files, SORT_NATURAL | SORT_FLAG_CASE);
|
||||
foreach ($files as $file) {
|
||||
if (!is_file($sourceDir . '/' . $file)) {
|
||||
continue;
|
||||
}
|
||||
if (!in_array(strtolower(pathinfo($file, PATHINFO_EXTENSION)), self::FILE_EXTENSIONS, TRUE)) {
|
||||
continue;
|
||||
}
|
||||
$pdfs[] = [
|
||||
'uri' => $sourceUri . '/' . $file,
|
||||
'destination' => $destination,
|
||||
'description' => $this->humanizeFilename($file),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $pdfs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves (once) the field_fichiers destination directory from its settings.
|
||||
*/
|
||||
private function filesDestination(): string {
|
||||
if ($this->filesDestination !== NULL) {
|
||||
return $this->filesDestination;
|
||||
}
|
||||
$scheme = 'public';
|
||||
$directory = '';
|
||||
$definitions = $this->entityFieldManager->getFieldDefinitions('node', 'projet');
|
||||
$field = $definitions['field_fichiers'] ?? NULL;
|
||||
if ($field !== NULL) {
|
||||
$scheme = $field->getFieldStorageDefinition()->getSetting('uri_scheme') ?: 'public';
|
||||
$directory = (string) $this->token->replace((string) $field->getSetting('file_directory'));
|
||||
}
|
||||
|
||||
return $this->filesDestination = $scheme . '://' . trim($directory, '/') . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a file name into a readable label (drops UID prefix and extension).
|
||||
*/
|
||||
private function humanizeFilename(string $file): string {
|
||||
$name = pathinfo($file, PATHINFO_FILENAME);
|
||||
// Drop a leading "{UID}_" numeric prefix.
|
||||
$name = preg_replace('/^\d+[_-]/', '', $name) ?? $name;
|
||||
// Separators to spaces, collapse, trim.
|
||||
$name = (string) preg_replace('/[_\-]+/u', ' ', $name);
|
||||
|
||||
return trim((string) preg_replace('/\s+/u', ' ', $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw contents of a caption (legende) file, or '' when missing.
|
||||
*/
|
||||
private function readCaptionFile(string $captionPath): string {
|
||||
if (!is_file($captionPath)) {
|
||||
return '';
|
||||
}
|
||||
$contents = file_get_contents($captionPath);
|
||||
if ($contents === FALSE) {
|
||||
return '';
|
||||
}
|
||||
// Drive exports are occasionally Windows-1252 rather than UTF-8.
|
||||
if (!mb_check_encoding($contents, 'UTF-8')) {
|
||||
$contents = mb_convert_encoding($contents, 'UTF-8', 'Windows-1252');
|
||||
}
|
||||
|
||||
return trim($contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces Markdown/HTML text to a single trimmed plain-text line (for alt).
|
||||
*/
|
||||
private function toPlainText(string $text): string {
|
||||
$text = html_entity_decode(strip_tags($text), ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
// Drop Markdown emphasis/heading markers left after tag stripping.
|
||||
$text = preg_replace('/[*_#`>]+/u', '', $text) ?? $text;
|
||||
|
||||
return trim((string) preg_replace('/\s+/u', ' ', $text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared Markdown converter.
|
||||
*
|
||||
* Raw HTML embedded in the source Markdown (alignment <div>, <br>, ...) is
|
||||
* stripped: only the Markdown itself is converted to HTML, keeping the body
|
||||
* clean and safe for the wysiwyg format.
|
||||
*/
|
||||
private function getMarkdownConverter(): CommonMarkConverter {
|
||||
if ($this->markdownConverter === NULL) {
|
||||
$this->markdownConverter = new CommonMarkConverter([
|
||||
'html_input' => 'strip',
|
||||
'allow_unsafe_links' => FALSE,
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->markdownConverter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
+30
-1
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Epilogue Project Authors (https://github.com/Etcetera-Type-Co/Epilogue)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,81 @@
|
||||
Epilogue Variable Font
|
||||
======================
|
||||
|
||||
This download contains Epilogue as both variable fonts and static fonts.
|
||||
|
||||
Epilogue is a variable font with this axis:
|
||||
wght
|
||||
|
||||
This means all the styles are contained in these files:
|
||||
Epilogue-VariableFont_wght.ttf
|
||||
Epilogue-Italic-VariableFont_wght.ttf
|
||||
|
||||
If your app fully supports variable fonts, you can now pick intermediate styles
|
||||
that aren’t available as static fonts. Not all apps support variable fonts, and
|
||||
in those cases you can use the static font files for Epilogue:
|
||||
static/Epilogue-Thin.ttf
|
||||
static/Epilogue-ExtraLight.ttf
|
||||
static/Epilogue-Light.ttf
|
||||
static/Epilogue-Regular.ttf
|
||||
static/Epilogue-Medium.ttf
|
||||
static/Epilogue-SemiBold.ttf
|
||||
static/Epilogue-Bold.ttf
|
||||
static/Epilogue-ExtraBold.ttf
|
||||
static/Epilogue-Black.ttf
|
||||
static/Epilogue-ThinItalic.ttf
|
||||
static/Epilogue-ExtraLightItalic.ttf
|
||||
static/Epilogue-LightItalic.ttf
|
||||
static/Epilogue-Italic.ttf
|
||||
static/Epilogue-MediumItalic.ttf
|
||||
static/Epilogue-SemiBoldItalic.ttf
|
||||
static/Epilogue-BoldItalic.ttf
|
||||
static/Epilogue-ExtraBoldItalic.ttf
|
||||
static/Epilogue-BlackItalic.ttf
|
||||
|
||||
Get started
|
||||
-----------
|
||||
|
||||
1. Install the font files you want to use
|
||||
|
||||
2. Use your app's font picker to view the font family and all the
|
||||
available styles
|
||||
|
||||
Learn more about variable fonts
|
||||
-------------------------------
|
||||
|
||||
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
|
||||
https://variablefonts.typenetwork.com
|
||||
https://medium.com/variable-fonts
|
||||
|
||||
In desktop apps
|
||||
|
||||
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
|
||||
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
|
||||
|
||||
Online
|
||||
|
||||
https://developers.google.com/fonts/docs/getting_started
|
||||
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
|
||||
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
|
||||
|
||||
Installing fonts
|
||||
|
||||
MacOS: https://support.apple.com/en-us/HT201749
|
||||
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
|
||||
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
|
||||
|
||||
Android Apps
|
||||
|
||||
https://developers.google.com/fonts/docs/android
|
||||
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
|
||||
|
||||
License
|
||||
-------
|
||||
Please read the full license text (OFL.txt) to understand the permissions,
|
||||
restrictions and requirements for usage, redistribution, and modification.
|
||||
|
||||
You can use them in your products & projects – print or digital,
|
||||
commercial or otherwise.
|
||||
|
||||
This isn't legal advice, please consider consulting a lawyer and see the full
|
||||
license for all details.
|
||||
@@ -0,0 +1,221 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, noarchive">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<title>Transfonter demo</title>
|
||||
<link href="stylesheet.css" rel="stylesheet">
|
||||
<style>
|
||||
/*
|
||||
http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
/* demo styles */
|
||||
body {
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
}
|
||||
.page {
|
||||
background: #fff;
|
||||
width: 920px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 20px 0 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.font-container {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-bottom: 40px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
h1 {
|
||||
position: relative;
|
||||
background: #444;
|
||||
font-size: 32px;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
margin: 0 -20px 12px -20px;
|
||||
}
|
||||
.letters {
|
||||
font-size: 25px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.s10:before {
|
||||
content: '10px';
|
||||
}
|
||||
.s11:before {
|
||||
content: '11px';
|
||||
}
|
||||
.s12:before {
|
||||
content: '12px';
|
||||
}
|
||||
.s14:before {
|
||||
content: '14px';
|
||||
}
|
||||
.s18:before {
|
||||
content: '18px';
|
||||
}
|
||||
.s24:before {
|
||||
content: '24px';
|
||||
}
|
||||
.s30:before {
|
||||
content: '30px';
|
||||
}
|
||||
.s36:before {
|
||||
content: '36px';
|
||||
}
|
||||
.s48:before {
|
||||
content: '48px';
|
||||
}
|
||||
.s60:before {
|
||||
content: '60px';
|
||||
}
|
||||
.s72:before {
|
||||
content: '72px';
|
||||
}
|
||||
.s10:before, .s11:before, .s12:before, .s14:before,
|
||||
.s18:before, .s24:before, .s30:before, .s36:before,
|
||||
.s48:before, .s60:before, .s72:before {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
color: #999;
|
||||
padding-right: 6px;
|
||||
}
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9px;
|
||||
margin: 0 0 12px;
|
||||
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.428571429;
|
||||
color: #333;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ccc;
|
||||
overflow-x: auto;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* responsive */
|
||||
@media (max-width: 959px) {
|
||||
.page {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="demo">
|
||||
<h1 style="font-family: 'Epilogue'; font-weight: normal; font-style: italic;">Epilogue Italic</h1>
|
||||
<pre title="Usage">.your-style {
|
||||
font-family: 'Epilogue';
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}</pre>
|
||||
<pre title="Preload (optional)">
|
||||
<link rel="preload" href="Epilogue-Italic.woff2" as="font" type="font/woff2" crossorigin></pre>
|
||||
<div class="font-container" style="font-family: 'Epilogue'; font-weight: normal; font-style: italic;">
|
||||
<p class="letters">
|
||||
abcdefghijklmnopqrstuvwxyz<br>
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||
</p>
|
||||
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="demo">
|
||||
<h1 style="font-family: 'Epilogue'; font-weight: normal; font-style: normal;">Epilogue Regular</h1>
|
||||
<pre title="Usage">.your-style {
|
||||
font-family: 'Epilogue';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}</pre>
|
||||
<pre title="Preload (optional)">
|
||||
<link rel="preload" href="Epilogue-Regular.woff2" as="font" type="font/woff2" crossorigin></pre>
|
||||
<div class="font-container" style="font-family: 'Epilogue'; font-weight: normal; font-style: normal;">
|
||||
<p class="letters">
|
||||
abcdefghijklmnopqrstuvwxyz<br>
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||
</p>
|
||||
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'Epilogue';
|
||||
src: url('Epilogue-Italic-VariableFont_wght.ttf') format('woff2');
|
||||
src: url('Epilogue-Italic-VariableFont_wght.ttf') format('woff2') tech(variations);
|
||||
font-weight: 100 900;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Epilogue';
|
||||
src: url('Epilogue-VariableFont_wght.ttf') format('woff2');
|
||||
src: url('Epilogue-VariableFont_wght.ttf') format('woff2') tech(variations);
|
||||
font-weight: 100 900;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
// import { createApp } from 'vue'
|
||||
import '../scss/main.scss'
|
||||
|
||||
import "splitting/dist/splitting.css";
|
||||
import "splitting/dist/splitting-cells.css";
|
||||
import Splitting from "splitting";
|
||||
import { hyphenateSync } from "hyphen/fr";
|
||||
import { gsap, Power1 } from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
import Lenis from 'lenis';
|
||||
import 'fslightbox';
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
// import Content from './vuejs/Content.vue'
|
||||
|
||||
// import REST from './api/rest-axios'
|
||||
@@ -29,13 +41,22 @@ import '../scss/main.scss'
|
||||
const _is_front = drupalSettings.path.isFront
|
||||
console.log('drupalSettings', drupalSettings)
|
||||
|
||||
const scroller = document.querySelector('main[role="main"]');
|
||||
const gsap_mm = gsap.matchMedia();
|
||||
console.log('gsap_mm', gsap_mm);
|
||||
|
||||
// ___ _ _
|
||||
// |_ _|_ _ (_) |_
|
||||
// | || ' \| | _|
|
||||
// |___|_||_|_|\__|
|
||||
function init () {
|
||||
console.log('LeShedTheme init()')
|
||||
console.log('LeShedTheme init()');
|
||||
|
||||
initTitles();
|
||||
initBurgerMenu();
|
||||
initSmoothScroll();
|
||||
initColumnScrollSync();
|
||||
initFsLightbox();
|
||||
// initVues()
|
||||
}
|
||||
|
||||
@@ -48,6 +69,291 @@ import '../scss/main.scss'
|
||||
})
|
||||
}
|
||||
|
||||
function randomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
||||
|
||||
// Rendu typographique des titres. Police Epilogue = axe variable `wght`
|
||||
// (100–900) uniquement ; l'italique est un fichier séparé (font-style).
|
||||
const TITLE_STYLE = {
|
||||
// 3 groupes de graisse : thin = majorité (défaut), medium = quelques,
|
||||
// bold = les pics. Les fines ne sont pas comptées (c'est le reste).
|
||||
wghtThin: { min: 100, max: 200 }, // majorité (défaut)
|
||||
wghtMedium: { min: 200, max: 400 }, // quelques
|
||||
wghtBold: { min: 800, max: 900 }, // pics
|
||||
boldRatio: 0.28, // proportion de pics gras par mot
|
||||
mediumRatio: 0.12, // proportion de medium par mot
|
||||
italicOnBold: 0.6, // proba d'italique sur un pic
|
||||
italicOnMedium: 0.4, // proba d'italique sur un medium
|
||||
italicOnThin: 0.30, // proba d'italique sur une fine
|
||||
};
|
||||
|
||||
function initTitles() {
|
||||
const titles = document.querySelectorAll('#block-leshed-identitedusite>a, article.node-type-projet>header>h2, article.node-type-projet>.cols>.left>h2');
|
||||
for (const txt of titles) {
|
||||
txt.classList.add("variable-title");
|
||||
const splitted = Splitting({ target: txt, by: 'chars' });
|
||||
for (const word of splitted[0].words) {
|
||||
const chars = Array.from(word.getElementsByClassName('char'));
|
||||
styleWordChars(chars);
|
||||
hyphenateWord(chars);
|
||||
}
|
||||
}
|
||||
|
||||
const pageTitle = document.querySelector('article.node-type-projet.view-mode-full h2.node-title');
|
||||
console.log('pageTitle', pageTitle);
|
||||
|
||||
|
||||
if (pageTitle) {
|
||||
// needs requestAnimationFrame to get the real titleHeight after splitting
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
|
||||
const initTitleH = pageTitle.offsetHeight;
|
||||
// console.log(`initTitleH: ${initTitleH}`);
|
||||
const titleScaleTarget = 0.4;
|
||||
const end = initTitleH - initTitleH * titleScaleTarget;
|
||||
// console.log(`end: ${end}`);
|
||||
|
||||
gsap_mm.add('(min-width: 768px)', () => {
|
||||
gsap.to(pageTitle, {
|
||||
scale: titleScaleTarget,
|
||||
y: end,
|
||||
ease: 'none',
|
||||
scrollTrigger: {
|
||||
scroller: scroller,
|
||||
start: 0,
|
||||
end: end, // scroll maximum du conteneur (robuste au resize)
|
||||
scrub: true,
|
||||
invalidateOnRefresh: true,
|
||||
},
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tire k positions réparties régulièrement dans [0, n[ : le mot est découpé
|
||||
* en k cases contiguës, une position au hasard par case (aléa contrôlé, pas
|
||||
* de paquets). Les positions déjà prises par un autre groupe sont évitées.
|
||||
*/
|
||||
function spreadPositions(n, k, exclude = new Set()) {
|
||||
const set = new Set();
|
||||
for (let i = 0; i < k; i++) {
|
||||
const start = Math.floor((i * n) / k);
|
||||
const end = Math.floor(((i + 1) * n) / k); // borne exclue
|
||||
const span = Math.max(1, end - start);
|
||||
let pos = randomInt(start, start + span);
|
||||
let guard = 0;
|
||||
while ((exclude.has(pos) || set.has(pos)) && guard < span) {
|
||||
pos = start + ((pos - start + 1) % span);
|
||||
guard++;
|
||||
}
|
||||
set.add(pos);
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applique graisse + italique caractère par caractère.
|
||||
*
|
||||
* Majorité de fines ; quelques medium et quelques pics gras, chacun réparti
|
||||
* régulièrement dans le mot. L'italique est corrélé à la graisse.
|
||||
*/
|
||||
function styleWordChars(chars) {
|
||||
const n = chars.length;
|
||||
if (!n) return;
|
||||
|
||||
// Accents répartis régulièrement : d'abord les pics gras, puis les medium
|
||||
// (en évitant les positions déjà grasses). Le reste sera fin.
|
||||
const bold = spreadPositions(n, Math.round(n * TITLE_STYLE.boldRatio));
|
||||
const medium = spreadPositions(n, Math.round(n * TITLE_STYLE.mediumRatio), bold);
|
||||
|
||||
// 1) Décide graisse + italique pour chaque caractère.
|
||||
const decisions = chars.map((char, i) => {
|
||||
let range, pItal;
|
||||
if (bold.has(i)) {
|
||||
range = TITLE_STYLE.wghtBold;
|
||||
pItal = TITLE_STYLE.italicOnBold;
|
||||
}
|
||||
else if (medium.has(i)) {
|
||||
range = TITLE_STYLE.wghtMedium;
|
||||
pItal = TITLE_STYLE.italicOnMedium;
|
||||
}
|
||||
else {
|
||||
range = TITLE_STYLE.wghtThin;
|
||||
pItal = TITLE_STYLE.italicOnThin;
|
||||
}
|
||||
return {
|
||||
char,
|
||||
wght: randomInt(range.min, range.max + 1),
|
||||
ital: Math.random() < pItal,
|
||||
};
|
||||
});
|
||||
|
||||
// 2) Au moins une italique par mot : si aucune, on en force une, de
|
||||
// préférence sur un pic gras ou un medium, sinon sur une lettre au hasard.
|
||||
if (!decisions.some((d) => d.ital)) {
|
||||
const accents = [...bold, ...medium];
|
||||
const idx = accents.length ? accents[randomInt(0, accents.length)] : randomInt(0, n);
|
||||
decisions[idx].ital = true;
|
||||
}
|
||||
|
||||
// 3) Pas plus de 2 italiques consécutives : on casse les séries de 3+.
|
||||
let run = 0;
|
||||
for (const d of decisions) {
|
||||
if (d.ital) {
|
||||
run += 1;
|
||||
if (run > 2) {
|
||||
d.ital = false;
|
||||
run = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
run = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 4) Applique.
|
||||
for (const { char, wght, ital } of decisions) {
|
||||
char.style.fontVariationSettings = `'wght' ${wght}`;
|
||||
char.style.fontStyle = ital ? 'italic' : 'normal';
|
||||
char.classList.toggle('italic', ital);
|
||||
char.classList.toggle('normal', !ital);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insère des césures logicielles (U+00AD) aux points de coupure valides.
|
||||
*
|
||||
* Comme chaque lettre est un span (display:inline) sans « run » de texte
|
||||
* continu, `hyphens: auto` est inopérant : on calcule donc les points de
|
||||
* césure (motifs FR) et on insère un soft hyphen — en nœud texte, entre les
|
||||
* lettres concernées — qui n'autorise une coupure (avec tiret) qu'à ces
|
||||
* endroits. Les mots trop longs coupent proprement au lieu de casser
|
||||
* n'importe où.
|
||||
*/
|
||||
function hyphenateWord(chars) {
|
||||
if (chars.length < 5) return;
|
||||
const SOFT = '\u00AD';
|
||||
const text = chars.map((c) => c.textContent).join('');
|
||||
const hyphenated = hyphenateSync(text);
|
||||
if (!hyphenated.includes(SOFT)) return;
|
||||
|
||||
let letter = 0;
|
||||
for (const ch of hyphenated) {
|
||||
if (ch === SOFT) {
|
||||
const target = chars[letter];
|
||||
if (letter > 0 && target && target.parentNode) {
|
||||
target.parentNode.insertBefore(document.createTextNode(SOFT), target);
|
||||
}
|
||||
}
|
||||
else {
|
||||
letter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initBurgerMenu() {
|
||||
let header_right = document.getElementById('burger-btn');
|
||||
header_right.parentElement.addEventListener('click', function(e){
|
||||
// console.log('click header_right', this);
|
||||
this.firstElementChild.toggleAttribute('opened');
|
||||
this.firstElementChild.nextElementSibling.toggleAttribute('opened');
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll lissé (Lenis) sur le conteneur `main` — et non la fenêtre, car
|
||||
* c'est `main[role="main"]` qui porte l'overflow. Lenis est branché sur le
|
||||
* ticker GSAP (une seule boucle RAF) et pousse ses updates à ScrollTrigger
|
||||
* pour que la synchro des colonnes reste calée sur le scroll lissé.
|
||||
*/
|
||||
function initSmoothScroll() {
|
||||
const scroller = document.querySelector('main[role="main"]');
|
||||
const content = scroller && scroller.querySelector('.layout-content');
|
||||
if (!scroller || !content) return;
|
||||
|
||||
const lenis = new Lenis({
|
||||
wrapper: scroller, // conteneur scrollable custom
|
||||
content: content, // contenu réel (le 1er enfant est l'ancre skip-link)
|
||||
duration: 1.2,
|
||||
smoothWheel: true,
|
||||
});
|
||||
|
||||
lenis.on('scroll', ScrollTrigger.update);
|
||||
gsap.ticker.add((time) => lenis.raf(time * 1000));
|
||||
gsap.ticker.lagSmoothing(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronise le scroll des deux colonnes du layout 50/50 : la colonne la
|
||||
* plus courte est ralentie (translateY décroissant) pour que son bas soit
|
||||
* atteint en même temps que celui de la colonne la plus haute, qui défile
|
||||
* nativement (flux normal, pas de pin). Le scroll réel a lieu dans
|
||||
* `main[role="main"]`, pas dans la fenêtre : GSAP utilise donc ce conteneur
|
||||
* comme `scroller`.
|
||||
*/
|
||||
function initColumnScrollSync() {
|
||||
console.log('initColumnScrollSync');
|
||||
|
||||
const firstColumn = document.querySelector('.layout--twocol-section--50-50 .layout__region--first');
|
||||
const secondColumn = document.querySelector('.layout--twocol-section--50-50 .layout__region--second');
|
||||
console.log(scroller, firstColumn, secondColumn);
|
||||
|
||||
if (!scroller || !firstColumn || !secondColumn) return;
|
||||
|
||||
|
||||
gsap_mm.add('(min-width: 768px)', () => {
|
||||
[firstColumn, secondColumn].forEach((column) => {
|
||||
gsap.to(column, {
|
||||
// Distance à parcourir pour que le bas de la colonne arrive en
|
||||
// bas du viewport en même temps que la colonne la plus haute.
|
||||
y: () => {
|
||||
const visibleHeight = scroller.clientHeight;
|
||||
const scrollRange = scroller.scrollHeight - scroller.clientHeight;
|
||||
const columnRevealRange = Math.max(0, column.offsetHeight - visibleHeight);
|
||||
return scrollRange - columnRevealRange;
|
||||
},
|
||||
ease: 'none',
|
||||
scrollTrigger: {
|
||||
scroller: scroller,
|
||||
start: 0,
|
||||
end: 'max', // scroll maximum du conteneur (robuste au resize)
|
||||
// Valeur numérique = easing : l'animation met ~0.6s à rattraper la
|
||||
// position de scroll au lieu de la suivre au pixel près → lisse les
|
||||
// à-coups de la colonne lente. Monter la valeur = plus d'inertie.
|
||||
scrub: true,
|
||||
invalidateOnRefresh: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Nettoyage automatique des tweens/triggers quand on repasse sous 768px.
|
||||
return () => {};
|
||||
});
|
||||
|
||||
// Les images chargent après coup et changent la hauteur des colonnes.
|
||||
window.addEventListener('load', () => ScrollTrigger.refresh());
|
||||
}
|
||||
|
||||
function initFsLightbox(){
|
||||
console.log('initFsLightbox');
|
||||
// console.log(window.FsLightbox);
|
||||
let imgs_links = document.querySelectorAll('article.node-type-projet.view-mode-full .field_images.multiple .field-item a');
|
||||
for (const link of imgs_links) {
|
||||
link.setAttribute("data-fslightbox", "gallery")
|
||||
}
|
||||
// window.FsLightbox
|
||||
window.refreshFsLightbox();
|
||||
}
|
||||
|
||||
// function initVues(){
|
||||
// console.log('initVues');
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@import "partials/variables";
|
||||
@import "partials/colors";
|
||||
@import "partials/fonts";
|
||||
@import "partials/mixins";
|
||||
@@ -11,5 +12,380 @@ a, a:visited{
|
||||
body{
|
||||
margin: 0;
|
||||
// background-color: green;
|
||||
font-weight: $default_fwght;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// Splitting met .word ET .char en inline-block :
|
||||
// - inline-block sur .char crée une opportunité de coupure entre CHAQUE lettre ;
|
||||
// - inline-block sur .word (dimensionné en max-content) empêche tout retour à la
|
||||
// ligne interne, donc les soft hyphens ne peuvent jamais couper le mot.
|
||||
// On repasse les deux en inline : le mot redevient un flux de texte qui ne coupe
|
||||
// qu'aux césures logicielles (U+00AD) insérées par le JS.
|
||||
// Spécificité (0,2,1) pour battre `.splitting .word/.char` de Splitting.
|
||||
.splitting span.word,
|
||||
.splitting span.char{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
// _ _
|
||||
// | | | |
|
||||
// | | __ _ _ _ ___ _ _| |_
|
||||
// | | / _` | | | |/ _ \| | | | __|
|
||||
// | |___| (_| | |_| | (_) | |_| | |_
|
||||
// \_____/\__,_|\__, |\___/ \__,_|\__|
|
||||
// __/ |
|
||||
// |___/
|
||||
|
||||
div.layout-container{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
max-width:1080px;
|
||||
margin: 0 auto;
|
||||
header[role="banner"]{
|
||||
display: block;
|
||||
position: relative;
|
||||
padding: 0.5em 0;
|
||||
flex: 1 1 $header_height;
|
||||
z-index: 100;
|
||||
// position: fixed;
|
||||
// top:0;
|
||||
// width: 100%;
|
||||
height: $header_height;
|
||||
min-height: $header_height;
|
||||
}
|
||||
main[role="main"]{
|
||||
flex: 1 1 auto;
|
||||
// padding:5em 0;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
// footer[role="contentinfo"]{
|
||||
// // flex: 0 1 content;
|
||||
// z-index: 100;
|
||||
// position: fixed;
|
||||
// bottom: 0;
|
||||
// width: 100%;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
||||
// _ _ _
|
||||
// | | | | | |
|
||||
// | |_| | ___ __ _ __| | ___ _ __
|
||||
// | _ |/ _ \/ _` |/ _` |/ _ \ '__|
|
||||
// | | | | __/ (_| | (_| | __/ |
|
||||
// \_| |_/\___|\__,_|\__,_|\___|_|
|
||||
|
||||
|
||||
header[role="banner"]{
|
||||
background-color: #fff;
|
||||
// box-shadow: 0 -5px 15px #000;
|
||||
|
||||
.header-middle{
|
||||
display: flex;
|
||||
justify-content:space-between;
|
||||
align-items: center;
|
||||
padding: 0.2em 0;
|
||||
}
|
||||
|
||||
#block-leshed-identitedusite{
|
||||
a{
|
||||
// color: ;
|
||||
text-decoration: none;
|
||||
font-size: 2em;
|
||||
font-weight: 500;
|
||||
margin-right: 0.5em;
|
||||
// &:hover{
|
||||
// color: $rose;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
.header-right{
|
||||
// position: relative;
|
||||
height:20px; width:20px;
|
||||
cursor: pointer;
|
||||
// background-color: green;
|
||||
|
||||
>div#burger-btn{
|
||||
position:relative;
|
||||
transition-duration: 0.5s;
|
||||
transition-property: transform;
|
||||
top: 8.5px;
|
||||
&, &::before, &::after{
|
||||
// position: absolute;
|
||||
width:20px; height:3px;
|
||||
background-color: #000;
|
||||
|
||||
}
|
||||
&:hover{
|
||||
&, &::before, &::after{
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
&::before, &::after{
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
// background-color: red;
|
||||
}
|
||||
&::before{
|
||||
top:6px;
|
||||
}
|
||||
&::after{
|
||||
bottom: 6px;
|
||||
}
|
||||
&[opened]{
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&>div.wrapper{
|
||||
position:absolute;
|
||||
top:$header_height; left:0;
|
||||
// z-index: 99;
|
||||
background-color: rgba(0,0,0,0.75);
|
||||
|
||||
width:100vw;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
transition-duration: 0.5s;
|
||||
&[opened]{
|
||||
height: calc(100vh - $header_height);
|
||||
}
|
||||
&>nav{
|
||||
padding-top: 10px;
|
||||
background-color: #fff;
|
||||
>ul{
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
nav#block-mathallo-navigationprincipale{
|
||||
padding: 2em 1em;
|
||||
ul{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
list-style: none;
|
||||
li{
|
||||
margin-right: 1em;
|
||||
// background-color: $bleu_site;
|
||||
color: #fff;
|
||||
padding:0.5em 1em;
|
||||
&:not(:last-child){
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // end of header[role="banner"]{
|
||||
|
||||
|
||||
.variable-title{
|
||||
margin: 0;
|
||||
font-weight: 200;
|
||||
text-transform:lowercase;
|
||||
line-height: 1;
|
||||
// margin-left: -0.04em;
|
||||
filter: drop-shadow(0 0 5px #fff) drop-shadow(0 0 15px #fff);
|
||||
span.word{
|
||||
span.char{
|
||||
letter-spacing:-0.1em;
|
||||
}
|
||||
}
|
||||
// span.whitespace{
|
||||
// letter-spacing: 0.5em;
|
||||
// }
|
||||
}
|
||||
|
||||
// _____ _____ __ ____ ___ _ ____
|
||||
// |_ _/ _ \ \ / / / ___/ _ \| | / ___|
|
||||
// | || | | \ \ /\ / / | | | | | | | \___ \
|
||||
// | || |_| |\ V V / | |__| |_| | |___ ___) |
|
||||
// |_| \___/ \_/\_/ \____\___/|_____|____/
|
||||
|
||||
div.layout.layout--twocol-section--50-50{
|
||||
flex-wrap: nowrap;
|
||||
// Sans ça, `align-items: stretch` (défaut flex) étire les deux colonnes à la
|
||||
// même hauteur : la synchro de scroll ne verrait aucune différence de hauteur.
|
||||
// flex-start = chaque colonne prend la hauteur de son contenu.
|
||||
align-items: flex-start;
|
||||
|
||||
column-gap: $colsgap;
|
||||
div.layout__region{
|
||||
max-width: calc(50% - $colsgap / 2);
|
||||
flex: 1 0 calc(50% - $colsgap / 2);
|
||||
.views-row{
|
||||
// border: 1px solid red;
|
||||
// box-sizing: border-box;
|
||||
margin-bottom: 2em;
|
||||
max-width: 100%;
|
||||
article.node-type-projet{
|
||||
>header{
|
||||
>h2{
|
||||
font-size: 5em;
|
||||
}
|
||||
}
|
||||
>div{
|
||||
// margin-top: 3em;
|
||||
}
|
||||
// only with images, title overlap the image
|
||||
&.has-image{
|
||||
>header{
|
||||
>h2{
|
||||
position: relative;
|
||||
max-height: 1em;
|
||||
overflow: visible;
|
||||
z-index: 10;
|
||||
// text-shadow: 0 0 10px #fff;
|
||||
// box-shadow: 0 0 15px #f00;
|
||||
// filter: drop-shadow(0 0 5px #fff);
|
||||
}
|
||||
div.field_images{
|
||||
position:relative;
|
||||
// width: 100%;
|
||||
z-index: 5;
|
||||
a{
|
||||
display:block;
|
||||
img{
|
||||
width:100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ____ _ _
|
||||
// | _ \ _ __ ___ (_) ___| |_
|
||||
// | |_) | '__/ _ \| |/ _ \ __|
|
||||
// | __/| | | (_) | | __/ |_
|
||||
// |_| |_| \___// |\___|\__|
|
||||
// |__/
|
||||
article.node-type-projet.view-mode-full{
|
||||
div.cols{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: $colsgap;
|
||||
// column-gap: 2em;
|
||||
div.col{
|
||||
flex:0 0 calc(50% - $colsgap / 2);
|
||||
max-width: calc(50% - $colsgap / 2);
|
||||
|
||||
&.left{
|
||||
>h2.node-title{
|
||||
position: relative;
|
||||
font-size: 12em;
|
||||
margin: 0;
|
||||
z-index: 100;
|
||||
width: 205%;//calc(50% - $colsgap / 2);
|
||||
pointer-events: none;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
|
||||
.field_artiste_s_invite_s{
|
||||
font-size: 1.8em;
|
||||
font-weight: 300;
|
||||
}
|
||||
.field_invite_accompagne_curate_p{
|
||||
font-weight: 400;
|
||||
.field-label{
|
||||
font-weight: $default_fwght;
|
||||
}
|
||||
>div{
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
.field_dates{
|
||||
time{
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.right{
|
||||
// Étire .field_images sur toute la hauteur de la colonne (= colonne la
|
||||
// plus haute, via le stretch de .cols) : le contexte de collage sticky
|
||||
// couvre alors tout le scroll, donc les cartes restent figées tant que
|
||||
// la colonne gauche défile encore (cf. point 6).
|
||||
display: flex;
|
||||
.field_images{
|
||||
flex: 1;
|
||||
// .field-items{
|
||||
&:after{
|
||||
display: block;
|
||||
position: relative;
|
||||
content: "";
|
||||
// border: 1px solid red;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
// }
|
||||
.field-item{
|
||||
position: relative;
|
||||
// Empilement "cartes" : chaque image se fige au même endroit (haut) et
|
||||
// est recouverte par la suivante (l'ordre du DOM fait que la dernière
|
||||
// passe au-dessus). La 1re image ne bouge pas. Desktop uniquement.
|
||||
@media (min-width: 768px){
|
||||
position: sticky;
|
||||
top: 0;
|
||||
// &:last-child:after{
|
||||
// content: "";
|
||||
// // position: relative;
|
||||
// display:block;
|
||||
// // blockquote.image-field-caption{
|
||||
// height: 100vh;
|
||||
// width:100%;
|
||||
// border: 1px solid red;
|
||||
// // }
|
||||
// }
|
||||
}
|
||||
|
||||
img{
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
blockquote.image-field-caption{
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
bottom: 0; left: 0;
|
||||
width: 100%;
|
||||
background-color: rgba(0,0,0,0.65);
|
||||
color: #fff;
|
||||
p{
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
font-weight: 300;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
}
|
||||
&:hover{
|
||||
z-index:200;
|
||||
blockquote.image-field-caption{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
// @import "/assets/fonts/fredoka/stylesheet.css";
|
||||
// @import "/assets/fonts/Schibsted_Grotesk/stylesheet.css";
|
||||
@import "/assets/fonts/epilogue/stylesheet.css";
|
||||
|
||||
|
||||
// body{
|
||||
// font-family: "Schibsted Grotesk";
|
||||
// font-weight: normal;
|
||||
// font-style: normal;
|
||||
// color: $bleu_typo;
|
||||
// }
|
||||
body{
|
||||
font-family: 'Epilogue';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@mixin titre{
|
||||
|
||||
}
|
||||
|
||||
// @mixin titre_h2{
|
||||
// font-family: 'Fredoka';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
$default_fwght: 200;
|
||||
$header_height: 70px;
|
||||
$colsgap: 2em;
|
||||
@@ -74,15 +74,27 @@ function parse_menu_item(&$items, $key){
|
||||
* Implements hook_preprocess_HOOK() for node.html.twig.
|
||||
*/
|
||||
function leshed_preprocess_node(&$variables) {
|
||||
$node_type = $variables['node']->getType();
|
||||
/** @var \Drupal\node\Entity\Node $node */
|
||||
$node = $variables['node'];
|
||||
$node_type = $node->getType();
|
||||
if (!isset($variables["attributes"]['class'])) {
|
||||
$variables["attributes"]['class'] = [];
|
||||
}
|
||||
$variables["attributes"]['class'][] = "node-type-{$node_type}";
|
||||
|
||||
$variables["attributes"]['class'][] = "view-mode-{$variables['view_mode']}";
|
||||
|
||||
if ($variables['view_mode'] === "teaser") {
|
||||
/** @var \Drupal\file\Plugin\\Field\FieldType\FileFieldItemList $field_images */
|
||||
$field_images = $node->get('field_images');
|
||||
if (!$field_images->isEmpty()) {
|
||||
$variables["attributes"]['class'][] = "has-image";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function leshed_preprocess_contanier(&$variables) {
|
||||
function leshed_preprocess_container(&$variables) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
+53
@@ -9,7 +9,11 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
"fslightbox": "^3.7.5",
|
||||
"gsap": "^3.14.1",
|
||||
"hyphen": "^1.14.1",
|
||||
"lenis": "^1.3.26",
|
||||
"splitting": "^1.1.0",
|
||||
"vue": "^3.4.29"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -1580,6 +1584,12 @@
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fslightbox": {
|
||||
"version": "3.7.5",
|
||||
"resolved": "https://registry.npmjs.org/fslightbox/-/fslightbox-3.7.5.tgz",
|
||||
"integrity": "sha512-swEUrwMOyiBhdkPf3GXj4nxARX5d8/9yfVCdxgPLl9+ZMiacUTub9O2wxLI0Y2G2jI85Qxfqpv2I24vlbx0zfg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@@ -1696,6 +1706,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/hyphen": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/hyphen/-/hyphen-1.14.1.tgz",
|
||||
"integrity": "sha512-kvL8xYl5QMTh+LwohVN72ciOxC0OEV79IPdJSTwEXok9y9QHebXGdFgrED4sWfiax/ODx++CAMk3hMy4XPJPOw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.1.9",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz",
|
||||
@@ -1728,6 +1744,37 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lenis": {
|
||||
"version": "1.3.26",
|
||||
"resolved": "https://registry.npmjs.org/lenis/-/lenis-1.3.26.tgz",
|
||||
"integrity": "sha512-s/xTCZCxTFvHbAN1OzuhNaN5YPJH2ail0XAkctKW1b+RUAG4nUL5UHLXwNko1h8aEeT2jspBXegMgPJd8zcuag==",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"playground",
|
||||
"playground/*"
|
||||
],
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/darkroomengineering"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nuxt/kit": ">=3.0.0",
|
||||
"react": ">=17.0.0",
|
||||
"vue": ">=3.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@nuxt/kit": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"vue": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.21",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
|
||||
@@ -1945,6 +1992,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/splitting": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/splitting/-/splitting-1.1.0.tgz",
|
||||
"integrity": "sha512-6Tj+4mvlSti4DUu1yl0PnkHIIoLchFYJHqz2DnwYkvEehXbjrR2epa4ds/xdto6ZdZsC+NP5IOOehi9VGjNlMQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.21",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
"fslightbox": "^3.7.5",
|
||||
"gsap": "^3.14.1",
|
||||
"hyphen": "^1.14.1",
|
||||
"lenis": "^1.3.26",
|
||||
"splitting": "^1.1.0",
|
||||
"vue": "^3.4.29"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation for a field.
|
||||
*
|
||||
* To override output, copy the "field.html.twig" from the templates directory
|
||||
* to your theme's directory and customize it, just like customizing other
|
||||
* Drupal templates such as page.html.twig or node.html.twig.
|
||||
*
|
||||
* Instead of overriding the theming for all fields, you can also just override
|
||||
* theming for a subset of fields using
|
||||
* @link themeable Theme hook suggestions. @endlink For example,
|
||||
* here are some theme hook suggestions that can be used for a field_foo field
|
||||
* on an article node type:
|
||||
* - field--node--field-foo--article.html.twig
|
||||
* - field--node--field-foo.html.twig
|
||||
* - field--node--article.html.twig
|
||||
* - field--field-foo.html.twig
|
||||
* - field--text-with-summary.html.twig
|
||||
* - field.html.twig
|
||||
*
|
||||
* Available variables:
|
||||
* - attributes: HTML attributes for the containing element.
|
||||
* - label_hidden: Whether to show the field label or not.
|
||||
* - title_attributes: HTML attributes for the title.
|
||||
* - label: The label for the field.
|
||||
* - multiple: TRUE if a field can contain multiple items.
|
||||
* - items: List of all the field items. Each item contains:
|
||||
* - attributes: List of HTML attributes for each item.
|
||||
* - content: The field item's content.
|
||||
* - entity_type: The entity type to which the field belongs.
|
||||
* - field_name: The name of the field.
|
||||
* - field_type: The type of the field.
|
||||
* - label_display: The display settings for the label.
|
||||
*
|
||||
* @see template_preprocess_field()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
{%
|
||||
set title_classes = [
|
||||
label_display == 'visually_hidden' ? 'visually-hidden',
|
||||
]
|
||||
%}
|
||||
|
||||
{% if label_hidden %}
|
||||
{% if multiple %}
|
||||
<div{{ attributes.addClass("field-items").addClass("multiple") }}>
|
||||
{% for item in items %}
|
||||
<div{{ item.attributes.addClass("field-item") }}>{{ item.content }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% for item in items %}
|
||||
<div{{ attributes.addClass("field-item") }}>{{ item.content }}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div{{ attributes }}>
|
||||
<div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>
|
||||
{% if multiple %}
|
||||
<div class="field-items multiple">
|
||||
{% endif %}
|
||||
{% for item in items %}
|
||||
<div{{ item.attributes.addClass("field-item") }}>{{ item.content }}</div>
|
||||
{% endfor %}
|
||||
{% if multiple %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,89 @@
|
||||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display a node.
|
||||
*
|
||||
* Available variables:
|
||||
* - node: The node entity with limited access to object properties and methods.
|
||||
* Only method names starting with "get", "has", or "is" and a few common
|
||||
* methods such as "id", "label", and "bundle" are available. For example:
|
||||
* - node.getCreatedTime() will return the node creation timestamp.
|
||||
* - node.hasField('field_example') returns TRUE if the node bundle includes
|
||||
* field_example. (This does not indicate the presence of a value in this
|
||||
* field.)
|
||||
* - node.isPublished() will return whether the node is published or not.
|
||||
* Calling other methods, such as node.delete(), will result in an exception.
|
||||
* See \Drupal\node\Entity\Node for a full list of public properties and
|
||||
* methods for the node object.
|
||||
* - label: (optional) The title of the node.
|
||||
* - content: All node items. Use {{ content }} to print them all,
|
||||
* or print a subset such as {{ content.field_example }}. Use
|
||||
* {{ content|without('field_example') }} to temporarily suppress the printing
|
||||
* of a given child element.
|
||||
* - author_picture: The node author user entity, rendered using the "compact"
|
||||
* view mode.
|
||||
* - metadata: Metadata for this node.
|
||||
* - date: (optional) Themed creation date field.
|
||||
* - author_name: (optional) Themed author name field.
|
||||
* - url: Direct URL of the current node.
|
||||
* - display_submitted: Whether submission information should be displayed.
|
||||
* - attributes: HTML attributes for the containing element.
|
||||
* The attributes.class element may contain one or more of the following
|
||||
* classes:
|
||||
* - node: The current template type (also known as a "theming hook").
|
||||
* - node--type-[type]: The current node type. For example, if the node is an
|
||||
* "Article" it would result in "node--type-article". Note that the machine
|
||||
* name will often be in a short form of the human readable label.
|
||||
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
|
||||
* teaser would result in: "node--view-mode-teaser", and
|
||||
* full: "node--view-mode-full".
|
||||
* The following are controlled through the node publishing options.
|
||||
* - node--promoted: Appears on nodes promoted to the front page.
|
||||
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
|
||||
* teaser listings.
|
||||
* - node--unpublished: Appears on unpublished nodes visible only to site
|
||||
* admins.
|
||||
* - title_attributes: Same as attributes, except applied to the main title
|
||||
* tag that appears in the template.
|
||||
* - content_attributes: Same as attributes, except applied to the main
|
||||
* content tag that appears in the template.
|
||||
* - author_attributes: Same as attributes, except applied to the author of
|
||||
* the node tag that appears in the template.
|
||||
* - title_prefix: Additional output populated by modules, intended to be
|
||||
* displayed in front of the main title tag that appears in the template.
|
||||
* - title_suffix: Additional output populated by modules, intended to be
|
||||
* displayed after the main title tag that appears in the template.
|
||||
* - view_mode: View mode; for example, "teaser" or "full".
|
||||
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
|
||||
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
|
||||
*
|
||||
* @see template_preprocess_node()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<article{{ attributes }}>
|
||||
|
||||
{{ title_prefix }}
|
||||
{% if label and not page %}
|
||||
<h2{{ title_attributes }}>
|
||||
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
|
||||
</h2>
|
||||
{% endif %}
|
||||
{{ title_suffix }}
|
||||
|
||||
{% if display_submitted %}
|
||||
<footer>
|
||||
{{ author_picture }}
|
||||
<div{{ author_attributes }}>
|
||||
{% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}
|
||||
{{ metadata }}
|
||||
</div>
|
||||
</footer>
|
||||
{% endif %}
|
||||
|
||||
<div{{ content_attributes }}>
|
||||
{{ content }}
|
||||
</div>
|
||||
|
||||
</article>
|
||||
@@ -0,0 +1,79 @@
|
||||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display a node.
|
||||
*
|
||||
* Available variables:
|
||||
* - node: The node entity with limited access to object properties and methods.
|
||||
* Only method names starting with "get", "has", or "is" and a few common
|
||||
* methods such as "id", "label", and "bundle" are available. For example:
|
||||
* - node.getCreatedTime() will return the node creation timestamp.
|
||||
* - node.hasField('field_example') returns TRUE if the node bundle includes
|
||||
* field_example. (This does not indicate the presence of a value in this
|
||||
* field.)
|
||||
* - node.isPublished() will return whether the node is published or not.
|
||||
* Calling other methods, such as node.delete(), will result in an exception.
|
||||
* See \Drupal\node\Entity\Node for a full list of public properties and
|
||||
* methods for the node object.
|
||||
* - label: (optional) The title of the node.
|
||||
* - content: All node items. Use {{ content }} to print them all,
|
||||
* or print a subset such as {{ content.field_example }}. Use
|
||||
* {{ content|without('field_example') }} to temporarily suppress the printing
|
||||
* of a given child element.
|
||||
* - author_picture: The node author user entity, rendered using the "compact"
|
||||
* view mode.
|
||||
* - metadata: Metadata for this node.
|
||||
* - date: (optional) Themed creation date field.
|
||||
* - author_name: (optional) Themed author name field.
|
||||
* - url: Direct URL of the current node.
|
||||
* - display_submitted: Whether submission information should be displayed.
|
||||
* - attributes: HTML attributes for the containing element.
|
||||
* The attributes.class element may contain one or more of the following
|
||||
* classes:
|
||||
* - node: The current template type (also known as a "theming hook").
|
||||
* - node--type-[type]: The current node type. For example, if the node is an
|
||||
* "Article" it would result in "node--type-article". Note that the machine
|
||||
* name will often be in a short form of the human readable label.
|
||||
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
|
||||
* teaser would result in: "node--view-mode-teaser", and
|
||||
* full: "node--view-mode-full".
|
||||
* The following are controlled through the node publishing options.
|
||||
* - node--promoted: Appears on nodes promoted to the front page.
|
||||
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
|
||||
* teaser listings.
|
||||
* - node--unpublished: Appears on unpublished nodes visible only to site
|
||||
* admins.
|
||||
* - title_attributes: Same as attributes, except applied to the main title
|
||||
* tag that appears in the template.
|
||||
* - content_attributes: Same as attributes, except applied to the main
|
||||
* content tag that appears in the template.
|
||||
* - author_attributes: Same as attributes, except applied to the author of
|
||||
* the node tag that appears in the template.
|
||||
* - title_prefix: Additional output populated by modules, intended to be
|
||||
* displayed in front of the main title tag that appears in the template.
|
||||
* - title_suffix: Additional output populated by modules, intended to be
|
||||
* displayed after the main title tag that appears in the template.
|
||||
* - view_mode: View mode; for example, "teaser" or "full".
|
||||
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
|
||||
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
|
||||
*
|
||||
* @see template_preprocess_node()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<article{{ attributes }}>
|
||||
|
||||
<div class="cols">
|
||||
<div class="col left">
|
||||
<h2{{ title_attributes.addClass('node-title') }}>
|
||||
{{ label }}
|
||||
</h2>
|
||||
{{ content|without('field_images') }}
|
||||
</div>
|
||||
<div class="col right">
|
||||
{{ content.field_images }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</article>
|
||||
@@ -0,0 +1,89 @@
|
||||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display a node.
|
||||
*
|
||||
* Available variables:
|
||||
* - node: The node entity with limited access to object properties and methods.
|
||||
* Only method names starting with "get", "has", or "is" and a few common
|
||||
* methods such as "id", "label", and "bundle" are available. For example:
|
||||
* - node.getCreatedTime() will return the node creation timestamp.
|
||||
* - node.hasField('field_example') returns TRUE if the node bundle includes
|
||||
* field_example. (This does not indicate the presence of a value in this
|
||||
* field.)
|
||||
* - node.isPublished() will return whether the node is published or not.
|
||||
* Calling other methods, such as node.delete(), will result in an exception.
|
||||
* See \Drupal\node\Entity\Node for a full list of public properties and
|
||||
* methods for the node object.
|
||||
* - label: (optional) The title of the node.
|
||||
* - content: All node items. Use {{ content }} to print them all,
|
||||
* or print a subset such as {{ content.field_example }}. Use
|
||||
* {{ content|without('field_example') }} to temporarily suppress the printing
|
||||
* of a given child element.
|
||||
* - author_picture: The node author user entity, rendered using the "compact"
|
||||
* view mode.
|
||||
* - metadata: Metadata for this node.
|
||||
* - date: (optional) Themed creation date field.
|
||||
* - author_name: (optional) Themed author name field.
|
||||
* - url: Direct URL of the current node.
|
||||
* - display_submitted: Whether submission information should be displayed.
|
||||
* - attributes: HTML attributes for the containing element.
|
||||
* The attributes.class element may contain one or more of the following
|
||||
* classes:
|
||||
* - node: The current template type (also known as a "theming hook").
|
||||
* - node--type-[type]: The current node type. For example, if the node is an
|
||||
* "Article" it would result in "node--type-article". Note that the machine
|
||||
* name will often be in a short form of the human readable label.
|
||||
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
|
||||
* teaser would result in: "node--view-mode-teaser", and
|
||||
* full: "node--view-mode-full".
|
||||
* The following are controlled through the node publishing options.
|
||||
* - node--promoted: Appears on nodes promoted to the front page.
|
||||
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
|
||||
* teaser listings.
|
||||
* - node--unpublished: Appears on unpublished nodes visible only to site
|
||||
* admins.
|
||||
* - title_attributes: Same as attributes, except applied to the main title
|
||||
* tag that appears in the template.
|
||||
* - content_attributes: Same as attributes, except applied to the main
|
||||
* content tag that appears in the template.
|
||||
* - author_attributes: Same as attributes, except applied to the author of
|
||||
* the node tag that appears in the template.
|
||||
* - title_prefix: Additional output populated by modules, intended to be
|
||||
* displayed in front of the main title tag that appears in the template.
|
||||
* - title_suffix: Additional output populated by modules, intended to be
|
||||
* displayed after the main title tag that appears in the template.
|
||||
* - view_mode: View mode; for example, "teaser" or "full".
|
||||
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
|
||||
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
|
||||
*
|
||||
* @see template_preprocess_node()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
|
||||
{#
|
||||
{% if content.field_images.getvalue|length %}
|
||||
{% set attributes = attributes.addClass('has-image') %}
|
||||
{% endif %} #}
|
||||
|
||||
<article{{ attributes }}>
|
||||
|
||||
{# {{ title_prefix }} #}
|
||||
{# {% if label and not page %} #}
|
||||
<header>
|
||||
<h2{{ title_attributes }}>
|
||||
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
|
||||
</h2>
|
||||
{{ content.field_images }}
|
||||
</header>
|
||||
{# {% endif %} #}
|
||||
{# {{ title_suffix }} #}
|
||||
|
||||
|
||||
<div{{ content_attributes }}>
|
||||
{{ content|without('field_images') }}
|
||||
</div>
|
||||
|
||||
</article>
|
||||
@@ -0,0 +1,93 @@
|
||||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display a node.
|
||||
*
|
||||
* Available variables:
|
||||
* - node: The node entity with limited access to object properties and methods.
|
||||
* Only method names starting with "get", "has", or "is" and a few common
|
||||
* methods such as "id", "label", and "bundle" are available. For example:
|
||||
* - node.getCreatedTime() will return the node creation timestamp.
|
||||
* - node.hasField('field_example') returns TRUE if the node bundle includes
|
||||
* field_example. (This does not indicate the presence of a value in this
|
||||
* field.)
|
||||
* - node.isPublished() will return whether the node is published or not.
|
||||
* Calling other methods, such as node.delete(), will result in an exception.
|
||||
* See \Drupal\node\Entity\Node for a full list of public properties and
|
||||
* methods for the node object.
|
||||
* - label: (optional) The title of the node.
|
||||
* - content: All node items. Use {{ content }} to print them all,
|
||||
* or print a subset such as {{ content.field_example }}. Use
|
||||
* {{ content|without('field_example') }} to temporarily suppress the printing
|
||||
* of a given child element.
|
||||
* - author_picture: The node author user entity, rendered using the "compact"
|
||||
* view mode.
|
||||
* - metadata: Metadata for this node.
|
||||
* - date: (optional) Themed creation date field.
|
||||
* - author_name: (optional) Themed author name field.
|
||||
* - url: Direct URL of the current node.
|
||||
* - display_submitted: Whether submission information should be displayed.
|
||||
* - attributes: HTML attributes for the containing element.
|
||||
* The attributes.class element may contain one or more of the following
|
||||
* classes:
|
||||
* - node: The current template type (also known as a "theming hook").
|
||||
* - node--type-[type]: The current node type. For example, if the node is an
|
||||
* "Article" it would result in "node--type-article". Note that the machine
|
||||
* name will often be in a short form of the human readable label.
|
||||
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
|
||||
* teaser would result in: "node--view-mode-teaser", and
|
||||
* full: "node--view-mode-full".
|
||||
* The following are controlled through the node publishing options.
|
||||
* - node--promoted: Appears on nodes promoted to the front page.
|
||||
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
|
||||
* teaser listings.
|
||||
* - node--unpublished: Appears on unpublished nodes visible only to site
|
||||
* admins.
|
||||
* - title_attributes: Same as attributes, except applied to the main title
|
||||
* tag that appears in the template.
|
||||
* - content_attributes: Same as attributes, except applied to the main
|
||||
* content tag that appears in the template.
|
||||
* - author_attributes: Same as attributes, except applied to the author of
|
||||
* the node tag that appears in the template.
|
||||
* - title_prefix: Additional output populated by modules, intended to be
|
||||
* displayed in front of the main title tag that appears in the template.
|
||||
* - title_suffix: Additional output populated by modules, intended to be
|
||||
* displayed after the main title tag that appears in the template.
|
||||
* - view_mode: View mode; for example, "teaser" or "full".
|
||||
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
|
||||
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
|
||||
*
|
||||
* @see template_preprocess_node()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<article{{ attributes }}>
|
||||
|
||||
{{ title_prefix }}
|
||||
{% if label %}
|
||||
<h2{{ title_attributes }}>
|
||||
{% if not page %}
|
||||
<a href="{{ url }}" rel="bookmark">{{ label }}</a>
|
||||
{% else %}
|
||||
{{ label }}
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% endif %}
|
||||
{{ title_suffix }}
|
||||
|
||||
{% if display_submitted %}
|
||||
<footer>
|
||||
{{ author_picture }}
|
||||
<div{{ author_attributes }}>
|
||||
{% trans %}Submitted by {{ author_name }} on {{ date }}{% endtrans %}
|
||||
{{ metadata }}
|
||||
</div>
|
||||
</footer>
|
||||
{% endif %}
|
||||
|
||||
<div{{ content_attributes }}>
|
||||
{{ content }}
|
||||
</div>
|
||||
|
||||
</article>
|
||||
@@ -0,0 +1,98 @@
|
||||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display a single page.
|
||||
*
|
||||
* The doctype, html, head and body tags are not in this template. Instead they
|
||||
* can be found in the html.html.twig template in this directory.
|
||||
*
|
||||
* Available variables:
|
||||
*
|
||||
* General utility variables:
|
||||
* - base_path: The base URL path of the Drupal installation. Will usually be
|
||||
* "/" unless you have installed Drupal in a sub-directory.
|
||||
* - is_front: A flag indicating if the current page is the front page.
|
||||
* - logged_in: A flag indicating if the user is registered and signed in.
|
||||
* - is_admin: A flag indicating if the user has permission to access
|
||||
* administration pages.
|
||||
*
|
||||
* Site identity:
|
||||
* - front_page: The URL of the front page. Use this instead of base_path when
|
||||
* linking to the front page. This includes the language domain or prefix.
|
||||
*
|
||||
* Page content (in order of occurrence in the default page.html.twig):
|
||||
* - messages: Status and error messages. Should be displayed prominently.
|
||||
* - node: Fully loaded node, if there is an automatically-loaded node
|
||||
* associated with the page and the node ID is the second argument in the
|
||||
* page's path (e.g. node/12345 and node/12345/revisions, but not
|
||||
* comment/reply/12345).
|
||||
*
|
||||
* Regions:
|
||||
* - page.header: Items for the header region.
|
||||
* - page.primary_menu: Items for the primary menu region.
|
||||
* - page.secondary_menu: Items for the secondary menu region.
|
||||
* - page.highlighted: Items for the highlighted content region.
|
||||
* - page.help: Dynamic help text, mostly for admin pages.
|
||||
* - page.content: The main content of the current page.
|
||||
* - page.sidebar_first: Items for the first sidebar.
|
||||
* - page.sidebar_second: Items for the second sidebar.
|
||||
* - page.footer: Items for the footer region.
|
||||
* - page.breadcrumb: Items for the breadcrumb region.
|
||||
*
|
||||
* @see template_preprocess_page()
|
||||
* @see html.html.twig
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
<div class="layout-container">
|
||||
|
||||
<header role="banner">
|
||||
<section class="header-top">{{ page.header_top }}</section>
|
||||
<section class="header-middle">
|
||||
<section class="header-left">{{ page.header_left }}</section>
|
||||
<section class="header-center">{{ page.header_center }}</section>
|
||||
<section class="header-right">{{ page.header_right }}</section>
|
||||
</section>
|
||||
<section class="header-bottom">{{ page.header_bottom }}</section>
|
||||
</header>
|
||||
|
||||
{{ page.primary_menu }}
|
||||
{{ page.secondary_menu }}
|
||||
|
||||
<nav role="breadcrumb">
|
||||
{{ page.breadcrumb }}
|
||||
</nav>
|
||||
|
||||
{{ page.highlighted }}
|
||||
|
||||
{{ page.help }}
|
||||
|
||||
<main role="main">
|
||||
<a id="main-content" tabindex="-1"></a>{# link is in html.html.twig #}
|
||||
|
||||
<div class="layout-content">
|
||||
{{ page.content }}
|
||||
</div>{# /.layout-content #}
|
||||
|
||||
{% if page.sidebar_first %}
|
||||
<aside class="layout-sidebar-first" role="complementary">
|
||||
{{ page.sidebar_first }}
|
||||
</aside>
|
||||
{% endif %}
|
||||
|
||||
{% if page.sidebar_second %}
|
||||
<aside class="layout-sidebar-second" role="complementary">
|
||||
{{ page.sidebar_second }}
|
||||
</aside>
|
||||
{% endif %}
|
||||
|
||||
</main>
|
||||
|
||||
{% if page.footer %}
|
||||
<footer role="contentinfo">
|
||||
{{ page.footer }}
|
||||
</footer>
|
||||
{% endif %}
|
||||
|
||||
</div>{# /.layout-container #}
|
||||
@@ -0,0 +1,22 @@
|
||||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display a region.
|
||||
*
|
||||
* Available variables:
|
||||
* - content: The content for this region, typically blocks.
|
||||
* - attributes: HTML attributes for the region <div>.
|
||||
* - region: The name of the region variable as defined in the theme's
|
||||
* .info.yml file.
|
||||
*
|
||||
* @see template_preprocess_region()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
{% if content %}
|
||||
<div id="burger-btn"></div>
|
||||
<div{{ attributes }}>
|
||||
{{ content }}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,21 @@
|
||||
{#
|
||||
/**
|
||||
* @file
|
||||
* Default theme implementation to display a region.
|
||||
*
|
||||
* Available variables:
|
||||
* - content: The content for this region, typically blocks.
|
||||
* - attributes: HTML attributes for the region <div>.
|
||||
* - region: The name of the region variable as defined in the theme's
|
||||
* .info.yml file.
|
||||
*
|
||||
* @see template_preprocess_region()
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
#}
|
||||
{% if content %}
|
||||
<div{{ attributes }}>
|
||||
{{ content }}
|
||||
</div>
|
||||
{% endif %}
|
||||
Reference in New Issue
Block a user