Files
drupal-leshed/web/themes/custom/leshed/assets/js/main.js
T
2026-08-13 11:58:27 +02:00

257 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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`
// (100900) 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)