variables titles are ok
This commit is contained in:
@@ -59,46 +59,119 @@ import Splitting from "splitting";
|
|||||||
return Math.floor(Math.random() * (max - min)) + min;
|
return Math.floor(Math.random() * (max - min)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
function initTitles(){
|
// Rendu typographique des titres. Police Epilogue = axe variable `wght`
|
||||||
let titles = document.querySelectorAll('#block-leshed-identitedusite>a, article.node-type-projet>h2');
|
// (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) {
|
for (const txt of titles) {
|
||||||
console.log(txt.innerText, '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -');
|
const splitted = Splitting({ target: txt, by: 'chars' });
|
||||||
let splitted = Splitting({ target: txt, by: 'chars'});
|
|
||||||
console.log("splitted", splitted);
|
|
||||||
|
|
||||||
for (const word of splitted[0].words) {
|
for (const word of splitted[0].words) {
|
||||||
let chars = word.getElementsByClassName('char');
|
styleWordChars(Array.from(word.getElementsByClassName('char')));
|
||||||
console.log("chars", chars);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const char of chars) {
|
/**
|
||||||
console.log(char.innerText);
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
// Weight
|
/**
|
||||||
let wght = randomInt(150, 600);//200 + Math.random() * 800;
|
* 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;
|
||||||
|
|
||||||
// Ital
|
// Accents répartis régulièrement : d'abord les pics gras, puis les medium
|
||||||
let ital = Math.random() > 0.7 ? 1 : 0;
|
// (en évitant les positions déjà grasses). Le reste sera fin.
|
||||||
// char.style.fontVariationSettings = `'wght' ${wght}, 'wdth' ${wdth}, 'ital' ${ital}`;
|
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.fontVariationSettings = `'wght' ${wght}`;
|
||||||
char.style.fontStyle = ital ? 'italic' : 'normal';
|
char.style.fontStyle = ital ? 'italic' : 'normal';
|
||||||
|
char.classList.toggle('italic', ital);
|
||||||
// // Letter spacing
|
char.classList.toggle('normal', !ital);
|
||||||
// let wdth_wght_ratio = wdth*wght / 10000;
|
|
||||||
// console.log('wdth_wght_ratio',wdth_wght_ratio);
|
|
||||||
|
|
||||||
// char.style.letterSpacing = wdth_wght_ratio < 1 ? "0.5em" : ital ? "0.05em" : 0;
|
|
||||||
// if (ital) {
|
|
||||||
// let prev_char = char.previousSibling;
|
|
||||||
// if (prev_char) {
|
|
||||||
// char.style.letterSpacing = prev_char.style.letterSpacing = "0.03em";
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ header[role="banner"]{
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content:space-between;
|
justify-content:space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0.2em 2em;
|
padding: 0.2em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#block-leshed-identitedusite{
|
#block-leshed-identitedusite{
|
||||||
@@ -170,3 +170,76 @@ header[role="banner"]{
|
|||||||
}
|
}
|
||||||
} // end of header[role="banner"]{
|
} // end of header[role="banner"]{
|
||||||
|
|
||||||
|
|
||||||
|
// _____ _____ __ ____ ___ _ ____
|
||||||
|
// |_ _/ _ \ \ / / / ___/ _ \| | / ___|
|
||||||
|
// | || | | \ \ /\ / / | | | | | | | \___ \
|
||||||
|
// | || |_| |\ V V / | |__| |_| | |___ ___) |
|
||||||
|
// |_| \___/ \_/\_/ \____\___/|_____|____/
|
||||||
|
|
||||||
|
div.layout.layout--twocol-section--50-50{
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
column-gap: 1em;
|
||||||
|
div.layout__region{
|
||||||
|
.views-row{
|
||||||
|
// border: 1px solid red;
|
||||||
|
// box-sizing: border-box;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
article.node-type-projet{
|
||||||
|
>header{
|
||||||
|
>h2{
|
||||||
|
margin: 0;
|
||||||
|
font-size: 5em;
|
||||||
|
text-transform:lowercase;
|
||||||
|
filter: drop-shadow(0 0 5px #fff) drop-shadow(0 0 15px #fff);
|
||||||
|
span.word{
|
||||||
|
hyphens: auto;
|
||||||
|
|
||||||
|
// $bgcolor:rgba(255,255,255,0.8);
|
||||||
|
// // background-color: $bgcolor;
|
||||||
|
// border-radius: 0.8em;
|
||||||
|
// box-shadow: 0 0 20px #fff;
|
||||||
|
|
||||||
|
span.char{
|
||||||
|
letter-spacing:-0.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// span.whitespace{
|
||||||
|
// letter-spacing: 0.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,15 +74,25 @@ function parse_menu_item(&$items, $key){
|
|||||||
* Implements hook_preprocess_HOOK() for node.html.twig.
|
* Implements hook_preprocess_HOOK() for node.html.twig.
|
||||||
*/
|
*/
|
||||||
function leshed_preprocess_node(&$variables) {
|
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'])) {
|
if (!isset($variables["attributes"]['class'])) {
|
||||||
$variables["attributes"]['class'] = [];
|
$variables["attributes"]['class'] = [];
|
||||||
}
|
}
|
||||||
$variables["attributes"]['class'][] = "node-type-{$node_type}";
|
$variables["attributes"]['class'][] = "node-type-{$node_type}";
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,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>
|
||||||
Reference in New Issue
Block a user