fixed typographic traitment, moved js alog to header defer script for speed, no more flickering
This commit is contained in:
+1
-1
File diff suppressed because one or more lines are too long
+6
-6
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,17 +2,19 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Epilogue';
|
font-family: 'Epilogue';
|
||||||
src: url('Epilogue-Italic-VariableFont_wght.ttf') format('woff2');
|
src: url('Epilogue-Italic-VariableFont_wght.ttf') format('truetype');
|
||||||
src: url('Epilogue-Italic-VariableFont_wght.ttf') format('woff2') tech(variations);
|
src: url('Epilogue-Italic-VariableFont_wght.ttf') format('truetype') tech(variations);
|
||||||
font-weight: 100 900;
|
font-weight: 100 900;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
font-display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Epilogue';
|
font-family: 'Epilogue';
|
||||||
src: url('Epilogue-VariableFont_wght.ttf') format('woff2');
|
src: url('Epilogue-VariableFont_wght.ttf') format('truetype');
|
||||||
src: url('Epilogue-VariableFont_wght.ttf') format('woff2') tech(variations);
|
src: url('Epilogue-VariableFont_wght.ttf') format('truetype') tech(variations);
|
||||||
font-weight: 100 900;
|
font-weight: 100 900;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
font-display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import '../scss/main.scss'
|
|||||||
|
|
||||||
import "splitting/dist/splitting.css";
|
import "splitting/dist/splitting.css";
|
||||||
import "splitting/dist/splitting-cells.css";
|
import "splitting/dist/splitting-cells.css";
|
||||||
import Splitting from "splitting";
|
|
||||||
import { hyphenateSync } from "hyphen/fr";
|
|
||||||
import { gsap, Power1 } from 'gsap';
|
import { gsap, Power1 } from 'gsap';
|
||||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||||
import Lenis from 'lenis';
|
import Lenis from 'lenis';
|
||||||
@@ -53,7 +51,6 @@ gsap.registerPlugin(ScrollTrigger);
|
|||||||
console.log('LeShedTheme init()');
|
console.log('LeShedTheme init()');
|
||||||
console.log('deploy test to delete');
|
console.log('deploy test to delete');
|
||||||
|
|
||||||
initTitles();
|
|
||||||
initBurgerMenu();
|
initBurgerMenu();
|
||||||
initSmoothScroll();
|
initSmoothScroll();
|
||||||
initHomeColumnScrollSync();
|
initHomeColumnScrollSync();
|
||||||
@@ -71,170 +68,6 @@ gsap.registerPlugin(ScrollTrigger);
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
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,\
|
|
||||||
article.node-type-projet.view-mode-full h2.node-title,\
|
|
||||||
article.node-type-evenement>header>h2,\
|
|
||||||
article.node-type-evenement>header>.field_dates>time,\
|
|
||||||
article.node-type-evenement.view-mode-full h2.node-title,\
|
|
||||||
article.node-type-evenement.view-mode-full .field_dates.digit-dates span.date-part\
|
|
||||||
');
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {
|
function initBurgerMenu() {
|
||||||
let header_right = document.getElementById('burger-btn');
|
let header_right = document.getElementById('burger-btn');
|
||||||
header_right.parentElement.addEventListener('click', function(e){
|
header_right.parentElement.addEventListener('click', function(e){
|
||||||
@@ -373,7 +206,7 @@ gsap.registerPlugin(ScrollTrigger);
|
|||||||
const leftFreezeStart = () => {
|
const leftFreezeStart = () => {
|
||||||
const overflow = leftColumn.offsetHeight - scroller.clientHeight;
|
const overflow = leftColumn.offsetHeight - scroller.clientHeight;
|
||||||
if (overflow > 0) return overflow;
|
if (overflow > 0) return overflow;
|
||||||
return pageTitle ? pageTitle.offsetHeight * (1 - titleScaleTarget) : 0;
|
return initheaderH ? initheaderH.offsetHeight * (1 - titleScaleTarget) : 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
gsap_mm.add('(min-width: 768px)', () => {
|
gsap_mm.add('(min-width: 768px)', () => {
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
// Chargé en defer dans le <head> : s'exécute avant main.js (defer, fin de body).
|
||||||
|
import Splitting from "splitting";
|
||||||
|
import { hyphenateSync } from "hyphen/fr";
|
||||||
|
|
||||||
|
// À garder identique à $variable-title-selectors (main.scss), qui masque ces
|
||||||
|
// titres jusqu'à `is-ready`.
|
||||||
|
const TITLE_SELECTORS = '\
|
||||||
|
#block-leshed-identitedusite>a, \
|
||||||
|
article.node-type-projet>header>h2,\
|
||||||
|
article.node-type-projet>.cols>.left>h2,\
|
||||||
|
article.node-type-projet.view-mode-full h2.node-title,\
|
||||||
|
article.node-type-evenement>header>h2,\
|
||||||
|
article.node-type-evenement>header>.field_dates>time,\
|
||||||
|
article.node-type-evenement.view-mode-full h2.node-title,\
|
||||||
|
article.node-type-evenement.view-mode-full .field_dates.digit-dates span.date-part\
|
||||||
|
';
|
||||||
|
|
||||||
|
// 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 randomInt(min, max) {
|
||||||
|
return Math.floor(Math.random() * (max - min)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initTitles() {
|
||||||
|
const titles = document.querySelectorAll(TITLE_SELECTORS);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
txt.classList.add("is-ready");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initTitles();
|
||||||
@@ -237,6 +237,39 @@ header[role="banner"]{
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Titres traités par assets/js/titles.js : garder identique à TITLE_SELECTORS.
|
||||||
|
$variable-title-selectors: (
|
||||||
|
'#block-leshed-identitedusite>a',
|
||||||
|
'article.node-type-projet>header>h2',
|
||||||
|
'article.node-type-projet>.cols>.left>h2',
|
||||||
|
'article.node-type-projet.view-mode-full h2.node-title',
|
||||||
|
'article.node-type-evenement>header>h2',
|
||||||
|
'article.node-type-evenement>header>.field_dates>time',
|
||||||
|
'article.node-type-evenement.view-mode-full h2.node-title',
|
||||||
|
'article.node-type-evenement.view-mode-full .field_dates.digit-dates span.date-part',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Avant le split : même métrique qu'après, pour éviter un saut de mise en page.
|
||||||
|
:where(#{$variable-title-selectors}):not(.splitting){
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 200;
|
||||||
|
text-transform: lowercase;
|
||||||
|
line-height: 1;
|
||||||
|
letter-spacing: -0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Masqués (place conservée) jusqu'au split ; réaffichés après 3 s si le JS échoue.
|
||||||
|
@media (scripting: enabled){
|
||||||
|
:where(#{$variable-title-selectors}):not(.is-ready){
|
||||||
|
visibility: hidden;
|
||||||
|
animation: leshed-title-failsafe 0s 3s forwards;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes leshed-title-failsafe{
|
||||||
|
to{ visibility: visible; }
|
||||||
|
}
|
||||||
|
|
||||||
@mixin nodeListe{
|
@mixin nodeListe{
|
||||||
>header{
|
>header{
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,32 @@
|
|||||||
# Main theme library.
|
# Main theme library.
|
||||||
global:
|
global:
|
||||||
js:
|
js:
|
||||||
assets/dist/main.js: {}
|
# defer : s'exécute après titles.js (defer dans le head), ordre du document.
|
||||||
|
assets/dist/main.js:
|
||||||
|
attributes:
|
||||||
|
defer: true
|
||||||
# assets/js/main.js: {}
|
# assets/js/main.js: {}
|
||||||
css:
|
css:
|
||||||
theme:
|
theme:
|
||||||
assets/dist/main.css: {}
|
assets/dist/main.css: {}
|
||||||
# assets/scss/main.css: {}
|
# assets/scss/main.css: {}
|
||||||
|
|
||||||
|
# Rendu typographique des titres, au plus tôt (voir assets/js/titles.js).
|
||||||
|
titles:
|
||||||
|
header: true
|
||||||
|
js:
|
||||||
|
assets/dist/titles.js:
|
||||||
|
attributes:
|
||||||
|
defer: true
|
||||||
|
|
||||||
|
titles_hmr:
|
||||||
|
header: true
|
||||||
|
js:
|
||||||
|
http://localhost:5173/assets/js/titles.js:
|
||||||
|
type: external
|
||||||
|
attributes:
|
||||||
|
type: module
|
||||||
|
|
||||||
vitehmr:
|
vitehmr:
|
||||||
js:
|
js:
|
||||||
http://localhost:5173/@vite/client:
|
http://localhost:5173/@vite/client:
|
||||||
|
|||||||
@@ -12,8 +12,29 @@ function leshed_page_attachments_alter(&$page) {
|
|||||||
// $attachments['#attached']['html_head'][] = [['src' => 'http://localhost:5173/assets/js/main.js', 'type' => 'module'],'vite-main'];
|
// $attachments['#attached']['html_head'][] = [['src' => 'http://localhost:5173/assets/js/main.js', 'type' => 'module'],'vite-main'];
|
||||||
// $page['#attached']['library'][] = 'http://localhost:5173/assets/js/main.js';
|
// $page['#attached']['library'][] = 'http://localhost:5173/assets/js/main.js';
|
||||||
$page['#attached']['library'][] = 'leshed/vitehmr';
|
$page['#attached']['library'][] = 'leshed/vitehmr';
|
||||||
|
$page['#attached']['library'][] = 'leshed/titles_hmr';
|
||||||
}else{
|
}else{
|
||||||
$page['#attached']['library'][] = 'leshed/global';
|
$page['#attached']['library'][] = 'leshed/global';
|
||||||
|
$page['#attached']['library'][] = 'leshed/titles';
|
||||||
|
|
||||||
|
// Must match exactly the url() resolved from assets/dist/main.css, or the
|
||||||
|
// font is downloaded twice.
|
||||||
|
$fonts_path = base_path() . \Drupal::service('extension.list.theme')->getPath('leshed') . '/assets/dist/fonts/';
|
||||||
|
foreach (['Epilogue-VariableFont_wght.ttf', 'Epilogue-Italic-VariableFont_wght.ttf'] as $font) {
|
||||||
|
$page['#attached']['html_head'][] = [
|
||||||
|
[
|
||||||
|
'#tag' => 'link',
|
||||||
|
'#attributes' => [
|
||||||
|
'rel' => 'preload',
|
||||||
|
'href' => $fonts_path . $font,
|
||||||
|
'as' => 'font',
|
||||||
|
'type' => 'font/ttf',
|
||||||
|
'crossorigin' => 'anonymous',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'leshed_preload_' . $font,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -31,9 +31,13 @@ export default defineConfig({
|
|||||||
build: {
|
build: {
|
||||||
outDir: 'assets/dist',
|
outDir: 'assets/dist',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: 'assets/js/main.js',
|
// titles.js est chargé à part dans le <head> (librairie leshed/titles).
|
||||||
|
input: {
|
||||||
|
main: 'assets/js/main.js',
|
||||||
|
titles: 'assets/js/titles.js',
|
||||||
|
},
|
||||||
output: {
|
output: {
|
||||||
entryFileNames: 'main.js',
|
entryFileNames: '[name].js',
|
||||||
// Sans distinction d'extension, tous les assets émis (CSS mais aussi
|
// Sans distinction d'extension, tous les assets émis (CSS mais aussi
|
||||||
// les polices référencées en url() dans fonts.scss) écrasaient le
|
// les polices référencées en url() dans fonts.scss) écrasaient le
|
||||||
// même fichier main.css au hasard de l'ordre de build.
|
// même fichier main.css au hasard de l'ordre de build.
|
||||||
|
|||||||
Reference in New Issue
Block a user