grid column

This commit is contained in:
Julie Blanc 2026-04-16 09:42:55 +02:00
parent 030e27bfac
commit fa738ed605
22 changed files with 183 additions and 630 deletions

View file

@ -1,8 +0,0 @@
{
"name": "FollowingNotes",
"description": "Create followingNotes with call & markers",
"author": ["Julie Blanc"],
"licence": "MIT",
"version": "1.0",
"hook": "followingNotes.js"
}

View file

@ -1,244 +0,0 @@
/**
* @name FollowingNotes
* @author Julie Blanc <contact@julie-blanc.fr>
* @see { @link https://gitlab.com/csspageweaver/plugins/followingNotes/ }
*/
import { Handler } from '/csspageweaver/lib/paged.esm.js';
export default class followingNotes extends Handler {
constructor(chunker, polisher, caller) {
super(chunker, polisher, caller);
this.parameters = cssPageWeaver.features.followingNotes.parameters;
this.notesClass = this.parameters?.selector || ".inline-note";
this.newNotesClass = this.parameters?.newNotesClass || "following-note";
this.reset = this.parameters?.reset;
this.align = this.parameters?.align;
this.followingNoteOverflow = new Set();
}
beforeParsed(content) {
let newNotesClass = this.newNotesClass;
resetCounter(content, this.reset, this.notesClass);
createCallandMarker(content, this.notesClass, newNotesClass);
const containerMap = new Map();
let notes = content.querySelectorAll(this.notesClass);
notes.forEach(function (note) {
let paragraph = note.closest("p");
if (!paragraph) return;
// Remonter au niveau direct de #section__content (ignorer blockquote et autres conteneurs)
const sectionContent = note.closest('#section__content') || content;
let topLevel = paragraph;
while (topLevel.parentElement && topLevel.parentElement !== sectionContent) {
topLevel = topLevel.parentElement;
}
// Find next boundary: heading or ol[type="1"], au niveau de #section__content
let boundary = null;
let sibling = topLevel.nextElementSibling;
while (sibling) {
if (sibling.matches('h1, h2, h3, h4, h5, h6, ol[type="1"]')) {
boundary = sibling;
break;
}
sibling = sibling.nextElementSibling;
}
const mapKey = boundary || sectionContent;
if (!containerMap.has(mapKey)) {
let container = document.createElement("div");
container.classList.add("container-following-note");
if (boundary) {
boundary.before(container);
} else {
sectionContent.appendChild(container);
}
containerMap.set(mapKey, container);
}
containerMap.get(mapKey).appendChild(note);
});
}
}
/// FUNCTIONS -----------------------------------------------------
// RESET COUNTER
function resetCounter(content, reset, notesClass){
if(reset && reset != ""){
const elements = content.querySelectorAll(reset + ", " + notesClass);
let resetEligible = false;
elements.forEach(element => {
if (element.matches(reset)) {
resetEligible = true;
} else if (resetEligible && element.matches(notesClass)) {
element.dataset.resetCounterFollowingNote = true;
resetEligible = false;
}
});
}
}
// CALL & MARKER
function createCallandMarker(content, notesClass, newNotesClass){
let notes = content.querySelectorAll(notesClass);
let resetNum = 0;
notes.forEach(function (note, index) {
if (note.dataset.resetCounterFollowingNote === "true") {
resetNum = index;
}
let num = index + 1 - resetNum;
note.classList.add(newNotesClass);
note.dataset.counterNote = num;
// call
let ref_note = document.createElement('span');
ref_note.className = newNotesClass + "_call";
ref_note.dataset.counterNote = num;
ref_note.innerHTML = num;
// wrap preceding word + call in .wrapper__note-call
let wrapper = document.createElement('span');
wrapper.className = 'wrapper__note-call';
let prevSibling = note.previousSibling;
if (prevSibling && prevSibling.nodeType === Node.TEXT_NODE) {
let text = prevSibling.textContent;
let m = text.match(/^([\s\S]*\s)(\S+\s*)$/);
if (m) {
let before = m[1];
let extracted = m[2];
// Si le dernier mot extrait est uniquement », prendre aussi le mot d'avant
if (/^»\s*$/.test(extracted)) {
let m2 = before.trimEnd().match(/^([\s\S]*\s|)(\S+)$/);
if (m2) {
let spaceBetween = before.slice(m2[1].length + m2[2].length);
before = m2[1];
extracted = m2[2] + spaceBetween + extracted;
}
}
prevSibling.textContent = before;
wrapper.appendChild(document.createTextNode(extracted));
} else {
prevSibling.textContent = '';
wrapper.appendChild(document.createTextNode(text));
}
}
wrapper.appendChild(ref_note);
note.after(wrapper);
// marker + content note wrapped in body_note
let marker_note = document.createElement('span');
marker_note.className = newNotesClass + "_marker";
//marker_note.innerHTML = num + ". ";
marker_note.innerHTML = num;
let body_note = document.createElement('div');
body_note.className = 'body_note';
while (note.firstChild) {
body_note.appendChild(note.firstChild);
}
body_note.prepend(marker_note);
note.appendChild(body_note);
});
}
// MARGINS
function marginNoteTop(elem) {
let marginTop = parseInt(window.getComputedStyle(elem).marginTop, 10)
return marginTop;
}
function marginNoteBottom(elem) {
let marginBottom = parseInt(window.getComputedStyle(elem).marginBottom, 10)
return marginBottom;
}
function biggestMargin(a, b) {
let margin;
let marginBottom = marginNoteBottom(a);
let marginTop = marginNoteTop(b);
if (marginBottom > marginTop) {
margin = marginBottom;
} else {
margin = marginTop;
}
return margin;
}
function checkOverflownote(notesClass, pageElement, maxHeight, arrayOverflow, container) {
let notes = pageElement.querySelectorAll(notesClass);
let notesHeightAll = [];
for (let n = 0; n < notes.length; ++n) {
// Add height of the notes to array notesHeightAll
let noteHeight = notes[n].offsetHeight;
notesHeightAll.push(noteHeight);
// Add margins of the notes to array notesHeightAll
if (n >= 1) {
let margins = biggestMargin(notes[n - 1], notes[n]);
notesHeightAll.push(margins);
}
}
// If notes on page
if (notesHeightAll.length > 0) {
// Calculate if all notes fit on the page;
let reducer = (accumulator, currentValue) => accumulator + currentValue;
let allHeight = notesHeightAll.reduce(reducer);
let paddingTop = getComputedStyle(container).paddingTop;
let paddingContainer = parseInt(paddingTop);
let totalHeight = allHeight + paddingContainer;
if (totalHeight > maxHeight) {
let lastNote = notes[notes.length - 1];
arrayOverflow.add(lastNote);
lastNote.remove();
checkOverflownote(notesClass, pageElement, maxHeight, arrayOverflow, container);
}
}
}

View file

@ -1 +0,0 @@
.DS_Store

View file

@ -1,14 +0,0 @@
{
"name": "Grid",
"description": "",
"version": "1.0",
"ui": {
"title": "Squared grid",
"description": "This Toogle a squared grid",
"template": "template.html",
"toggle": true
},
"stylesheet": "grid.css",
"script": "grid-ui.js",
"hook": "grid-hook.js"
}

View file

@ -1,17 +0,0 @@
/**
* @name Grid
* @author Julie Blanc <contact@julie-blanc.fr>
* @see { @link https://gitlab.com/csspageweaver/plugins/grid/ }
*/
import { Handler } from '/csspageweaver/lib/paged.esm.js';
export default class GridPage extends Handler {
constructor(chunker, polisher, caller) {
super(chunker, polisher, caller);
}
}

View file

@ -1,115 +0,0 @@
/**
* @name Grid
* @author Julie Blanc <contact@julie-blanc.fr>
* @see { @link https://gitlab.com/csspageweaver/plugins/grid/ }
*/
export default function gridEvents(){
let body = cssPageWeaver.ui.body;
let fileTitle = cssPageWeaver.docTitle;
let parameters = cssPageWeaver.features.grid.parameters || {};
let isParametersSet = Object.keys(parameters).length > 0;
let grid = {};
// valeur par défaut
grid.default = {
toggle: 'no-grid',
spacing: 56,
steps: 5,
positionX: 28,
positionY: 0
};
grid.toggle = {};
grid.toggle.input = cssPageWeaver.ui.grid.toggleInput;
grid.toggle.label = cssPageWeaver.ui.grid.toggleLabel;
grid.spacing = {};
grid.spacing.value = parameters.spacing || grid.default.spacing;
grid.spacing.input = document.querySelector('#spacing-grid');
grid.steps = {};
grid.steps.value = parameters.steps || grid.default.steps;
grid.steps.input = document.querySelector('#steps-grid');
grid.positionX = {};
grid.positionX.value = parameters.positionX || grid.default.positionX;
grid.positionX.input = document.querySelector('#position-x-grid');
grid.positionY = {};
grid.positionY.value = parameters.positionY || grid.default.positionY;
grid.positionY.input = document.querySelector('#position-y-grid');
/* Récupération de la session précédente */
grid.toggle.value = localStorage.getItem('gridToggle_' + fileTitle) || grid.default.toggle;
grid.spacing.value = localStorage.getItem('gridSpacing_' + fileTitle) || grid.spacing.value;
grid.steps.value = localStorage.getItem('gridSteps_' + fileTitle) || grid.steps.value;
grid.positionX.value = localStorage.getItem('gridPositionX_' + fileTitle) || grid.positionX.value;
grid.positionY.value = localStorage.getItem('gridPositionY_' + fileTitle) || grid.positionY.value;
/* DOM edit */
if(grid.toggle.value === "grid"){
body.classList.add('grid'); // on indique qu'il y a la grille
grid.toggle.input.checked = true;
} else {
body.classList.remove('grid'); // grille désactivée
grid.toggle.input.checked = false;
}
/* Set grid values on load */
grid.spacing.input.value = grid.spacing.value;
document.documentElement.style.setProperty('--grid-spacing', grid.spacing.value + 'px');
grid.steps.input.value = grid.steps.value;
document.documentElement.style.setProperty('--steps', grid.steps.value);
grid.positionX.input.value = grid.positionX.value;
document.documentElement.style.setProperty('--grid-position-x', grid.positionX.value + 'px');
grid.positionY.input.value = grid.positionY.value;
document.documentElement.style.setProperty('--grid-position-y', grid.positionY.value + 'px');
/* Event listeners */
/* Toggle event */
grid.toggle.input.addEventListener("input", (e) => {
if(e.target.checked){
body.classList.add('grid'); // grille activée
localStorage.setItem('gridToggle_' + fileTitle, 'grid');
} else {
body.classList.remove('grid'); // grille désactivée
localStorage.setItem('gridToggle_' + fileTitle, 'no-grid');
}
});
/* Change grid spacing on input */
document.querySelector("#spacing-grid").addEventListener("input", (e) => {
grid.spacing.value = e.target.value;
document.documentElement.style.setProperty('--grid-spacing', grid.spacing.value + 'px');
localStorage.setItem('gridSpacing_' + fileTitle, grid.spacing.value);
});
/* Change grid steps on input */
document.querySelector("#steps-grid").addEventListener("input", (e) => {
grid.steps.value = e.target.value;
document.documentElement.style.setProperty('--steps', grid.steps.value);
localStorage.setItem('gridSteps_' + fileTitle, grid.steps.value);
});
/* Change grid position X on input */
document.querySelector("#position-x-grid").addEventListener("input", (e) => {
grid.positionX.value = e.target.value;
document.documentElement.style.setProperty('--grid-position-x', grid.positionX.value + 'px');
localStorage.setItem('gridPositionX_' + fileTitle, grid.positionX.value);
});
/* Change grid position Y on input */
document.querySelector("#position-y-grid").addEventListener("input", (e) => {
grid.positionY.value = e.target.value;
document.documentElement.style.setProperty('--grid-position-y', grid.positionY.value + 'px');
localStorage.setItem('gridPositionY_' + fileTitle, grid.positionY.value);
});
}

View file

@ -1,124 +0,0 @@
:root {
--grid-bold: #bfbfbf;
--grid-light: #efefef;
--grid-spacing: 56px;
--steps: 5;
--grid-position-x: 28px;
--grid-position-y: 0px;
--grid-subdivisions: calc(var(--grid-spacing)/var(--steps));
}
@media screen{
body.grid .pagedjs_sheet {
z-index: -1;
background-image:
/* Traits bold */
repeating-linear-gradient(
90deg,
var(--grid-bold) 0 1px,
transparent 1px var(--grid-spacing)
),
repeating-linear-gradient(
0deg,
var(--grid-bold) 0 1px,
transparent 1px var(--grid-spacing)
),
/* Traits fins (3 traits → 4 carrés) */
repeating-linear-gradient(
90deg,
var(--grid-light) 0 1px,
transparent 1px var(--grid-subdivisions)
),
repeating-linear-gradient(
0deg,
var(--grid-light) 0 1px,
transparent 1px var(--grid-subdivisions)
);
background-position:
var(--grid-position-x) var(--grid-position-y),
var(--grid-position-x) var(--grid-position-y),
var(--grid-position-x) var(--grid-position-y),
var(--grid-position-x) var(--grid-position-y);
}
.grid-page{
--nbr-columns: 8;
width: var(--pagedjs-pagebox-width);
height: var(--pagedjs-pagebox-height);
position: absolute;
top: 0;
left: 0;
display: grid;
grid-template-columns: repeat(var(--nbr-columns), calc(100%/var(--nbr-columns)));
box-shadow: 1px 0px 0px 0px var(--grid-color);
--grid-color: magenta;
z-index: -1;
}
.pagedjs_right_page .grid-page{
padding-left: var(--pagedjs-margin-left);
padding-right: var(--pagedjs-margin-right);
}
.pagedjs_left_page .grid-page{
padding-left: var(--pagedjs-margin-left);
padding-right: var(--pagedjs-margin-right);
}
.grid-page .grid-column{
box-shadow: 1px 0px 0px 0px var(--grid-color);
grid-row: 1/end;
width: 100%;
justify-self: right;
}
.grid-column-0{
grid-column: 1;
box-shadow: -1px 0px 0px 0px var(--grid-color)!important;
justify-self: left;
}
.grid-column-1{ grid-column: 1; }
.grid-column-2{ grid-column: 2; }
.grid-column-3{ grid-column: 3; }
.grid-column-4{ grid-column: 4; }
.grid-column-5{ grid-column: 5; }
.grid-column-6{ grid-column: 6; }
.grid-column-7{ grid-column: 7; }
.grid-column-8{ grid-column: 8; }
.grid-column-9{ grid-column: 9; }
.grid-column-10{ grid-column: 10; }
.grid-column-11{ grid-column: 11; }
.grid-column-12{ grid-column: 12; }
}
.no-grid .grid-page{
display: none;
}

View file

@ -1,16 +0,0 @@
<div class="panel-group-values">
<label for="spacing-grid">Spacing (px)</label>
<input type="number" id="spacing-grid" name="spacing-grid" min="1" max="200" value="56">
</div>
<div class="panel-group-values">
<label for="steps-grid">Steps</label>
<input type="number" id="steps-grid" name="steps-grid" min="1" max="20" value="5">
</div>
<div class="panel-group-values">
<label for="position-x-grid">Position X (px)</label>
<input type="number" id="position-x-grid" name="position-x-grid" value="28">
</div>
<div class="panel-group-values">
<label for="position-y-grid">Position Y (px)</label>
<input type="number" id="position-y-grid" name="position-y-grid" value="0">
</div>

View file

@ -0,0 +1,13 @@
{
"name": "Column grid",
"description": "",
"version": "1.0",
"ui": {
"title": "Column grid",
"description": "This Toogle a column grid",
"template": "template.html",
"toggle": true
},
"stylesheet": "grid.css",
"script": "grid-ui.js"
}

View file

@ -0,0 +1,73 @@
/**
* @name Grid
* @author Julie Blanc <contact@julie-blanc.fr>
* @see { @link https://gitlab.com/csspageweaver/plugins/grid/ }
*/
export default function gridEvents(id){
let body = cssPageWeaver.ui.body;
let fileTitle = cssPageWeaver.docTitle;
let parameters = cssPageWeaver.features[id].parameters || {};
let isParametersSet = Object.keys(parameters).length > 0;
let grid = {};
// valeur par défaut
grid.default = {
steps: 7,
};
grid.toggle = {};
grid.toggle.value = localStorage.getItem('gridColToggle_' + fileTitle) || 'no-grid-col';
grid.toggle.input = document.querySelector(`#${id}-toggle`);
grid.steps = {};
grid.steps.value = parameters.steps || grid.default.steps;
grid.steps.input = document.querySelector('#steps-grid-col');
/* Récupération de la session précédente si elle existe */
grid.steps.value = localStorage.getItem('gridColSteps_' + fileTitle) || grid.steps.value;
grid.steps.input.value = grid.steps.value;
document.documentElement.style.setProperty('--grid-col-steps', grid.steps.value);
/* DOM edit */
if(grid.toggle.value === "grid-col"){
body.classList.add('grid-col'); // on indique qu'il y a la grille
grid.toggle.input.checked = true;
} else {
body.classList.remove('grid-col'); // grille désactivée
grid.toggle.input.checked = false;
}
/* Toggle event */
grid.toggle.input.addEventListener("input", (e) => {
if(e.target.checked){
body.classList.add('grid-col'); // grille activée
localStorage.setItem('gridColToggle_' + fileTitle, 'grid-col');
} else {
body.classList.remove('grid-col'); // grille désactivée
localStorage.setItem('gridColToggle_' + fileTitle, 'no-grid-col');
}
});
/* Change grid steps on input */
document.querySelector("#steps-grid-col").addEventListener("input", (e) => {
grid.steps.value = e.target.value;
document.documentElement.style.setProperty('--grid-col-steps', grid.steps.value);
localStorage.setItem('gridColSteps_' + fileTitle, grid.steps.value);
});
}

View file

@ -0,0 +1,36 @@
:root {
--grid-col-color: #ee33d2;
--grid-light: #efefef;
--grid-spacing: 56px;
--steps: 5;
--grid-position-x: 28px;
--grid-position-y: 0px;
--grid-subdivisions: calc(var(--grid-spacing)/var(--steps));
}
@media screen{
body.grid-col .pagedjs_area {
z-index: -1;
box-shadow: 0px 0px 1px 0px var(--grid-col-color);
background-image: repeating-linear-gradient(to right, var(--grid-col-color), var(--grid-col-color) 0.5px, transparent 0.5px, transparent);
background-size: calc(100%/var(--grid-col-steps));
}
}

View file

@ -0,0 +1,4 @@
<div class="panel-group-values">
<label for="steps-grid-col">Steps</label>
<input type="number" id="steps-grid-col" name="steps-grid" min="1" max="22" value="6">
</div>