// import { createApp } from 'vue' import '../scss/main.scss' import "splitting/dist/splitting.css"; import "splitting/dist/splitting-cells.css"; import Splitting from "splitting"; // import Content from './vuejs/Content.vue' // import REST from './api/rest-axios' // import LocomotiveScroll from 'locomotive-scroll'; // const scroll = new LocomotiveScroll(); // /** // * @file // * https://www.drupal.org/docs/drupal-apis/javascript-api/javascript-api-overview // */ // (function (Drupal) { // 'use strict'; // Drupal.behaviors.leshed = { // attach: function (context, settings) { // console.log('It works!'); // } // }; // } (Drupal)); (function (Drupal, drupalSettings) { const LeShedTheme = function () { const _is_front = drupalSettings.path.isFront console.log('drupalSettings', drupalSettings) // ___ _ _ // |_ _|_ _ (_) |_ // | || ' \| | _| // |___|_||_|_|\__| function init () { console.log('LeShedTheme init()') initTitles(); initBurgerMenu(); // initVues() } function onWindowResize() { _cardsForms.forEach(({card, forme, formepos}) => { // console.log(`card`, card, 'forme', forme, 'formepos', formepos); forme.style.top = `${card.offsetTop + formepos.top}px`; forme.style.left = `${card.offsetLeft + formepos.left}px`; }) } 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'); for (const txt of titles) { const splitted = Splitting({ target: txt, by: 'chars' }); for (const word of splitted[0].words) { styleWordChars(Array.from(word.getElementsByClassName('char'))); } } } /** * 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); } } 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'); }) } // function initVues(){ // console.log('initVues'); // // initVueContent(); // } // function initVueContent(){ // createApp(Content).mount('main[role="main"]'); // // processEtapeLinks(); // } // function onClickEtapeLink(e){ // e.preventDefault(); // let a = e.currentTarget; // let nid = a.dataset.nodeNid; // console.log(nid); // getNodeData(nid); // return null; // } // function processEtapeLinks(){ // let etape_link_fields = document.querySelectorAll('#etapes-liste div.views-field-title'); // etape_link_fields.forEach((field, index) => { // let nid = null; // let classList = field.classList; // classList.forEach((classe) => { // let reg = /data-node-(\d+)/; // let result = classe.match(reg); // if (result) { // nid = result[1]; // console.log(nid); // } // }) // if (nid) { // let a = field.querySelector('a'); // a.setAttribute('data-node-nid', nid); // a.addEventListener('click', onClickEtapeLink); // } // }) // } // function getNodeData(nid){ // const params = { // } // REST.get(`/node/${nid}?_format=json`, params) // .then((data) => { // console.log('user REST getUser data', data) // }) // .catch(error => { // console.warn('Issue with getNodedata', error) // Promise.reject(error) // }) // } init() } // end LeShedTheme() LeShedTheme() })(Drupal, drupalSettings)