FEATURE Introducing timeline and timline-step blocks

This commit is contained in:
Antoine M 2025-12-04 16:54:40 +01:00
parent 33ff9faa0d
commit d3095286b7
17 changed files with 402 additions and 0 deletions

View File

@ -0,0 +1,28 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "carhop-blocks/highlight-timeline-step",
"version": "0.1.0",
"title": "Étape de timeline",
"category": "carhop-blocks",
"icon": "calendar",
"description": "Étape de timeline pour la mise en forme d'une étape de timeline",
"example": {},
"parent": [
"carhop-blocks/highlight-timeline"
],
"supports": {
"html": false
},
"textdomain": "carhop-blocks",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js",
"attributes": {
"year": {
"type": "number",
"default": 2025
}
}
}

View File

@ -0,0 +1,81 @@
import { __ } from "@wordpress/i18n";
import { useBlockProps, InnerBlocks } from "@wordpress/block-editor";
import "./editor.scss";
import {
PanelBody,
Card,
CardBody,
CardHeader,
TextControl,
Button,
__experimentalNumberControl as NumberControl,
} from "@wordpress/components";
import { InspectorControls } from "@wordpress/block-editor";
import { RichText } from "@wordpress/block-editor";
import TimelineYearBackground from "./timelineYearBackground";
export default function Edit({ attributes, setAttributes, ...props }) {
const { year } = attributes;
return (
<>
<InspectorControls>
<PanelBody title={__("Étape de timeline", "carhop-blocks")}>
<NumberControl
label={__("Année", "carhop-blocks")}
value={year}
onChange={(value) => {
const n = parseInt(value, 10);
setAttributes({ year: Number.isFinite(n) ? n : undefined });
}}
/>
</PanelBody>
</InspectorControls>
<div
{...useBlockProps({
className: `highlight-timeline-step`,
id: `year-${year}`,
})}
>
<div className="highlight-timeline-step__year">
<p className="highlight-timeline-step__year-text">{year}</p>
<TimelineYearBackground />
</div>
<div className="highlight-timeline-step__innerblocks">
<InnerBlocks
allowedBlocks={[
"core/heading",
"core/paragraph",
"core/group",
"core/list",
"core/button",
"core/image",
"core/buttons",
"core/columns",
"core/post-title",
"core/embed",
"core/quote",
"core/pullquote",
"core/media-text",
"core/table",
"carhop-blocks/image-stack",
"carhop-blocks/heading",
"carhop-blocks/decorative-shapes",
"carhop-blocks/scroll-highlight-block",
"carhop-blocks/cta-group",
"carhop-blocks/audio-player",
"carhop-blocks/localisation-map",
"carhop-blocks/notice-panel",
"acf/statistics-datas",
"ninja-forms/form",
"gravityforms/form",
"dynamiques-blocks/sitemap",
"mailpoet/subscription-form-block",
"shortcode",
]}
/>
</div>
</div>
</>
);
}

View File

@ -0,0 +1,24 @@
import { registerBlockType } from "@wordpress/blocks";
import "./style.scss";
import Edit from "./edit";
import save from "./save";
import metadata from "./block.json";
registerBlockType(metadata.name, {
icon: {
foreground: "#136f63",
src: (
<svg width="100" height="100" viewBox="0 0 100 100">
<g stroke="null" id="svg_10" class="fills">
<path
stroke="null"
d="m3.74998,19.74151c0,-8.82607 7.16546,-15.99153 15.99153,-15.99153l60.51698,0c8.82607,0 15.99153,7.16546 15.99153,15.99153l0,60.51698c0,8.82607 -7.16546,15.99153 -15.99153,15.99153l-60.51698,0c-8.82607,0 -15.99153,-7.16546 -15.99153,-15.99153l0,-60.51698zm22.57628,3.44915l0,53.61867l23.67374,-18.7148l23.67374,18.7148l0,-53.61867l-47.34748,0z"
/>
</g>
</svg>
),
},
edit: Edit,
save,
});

View File

@ -0,0 +1,21 @@
import { useBlockProps, InnerBlocks } from "@wordpress/block-editor";
import TimelineYearBackground from "./timelineYearBackground";
export default function save({ attributes }) {
const { year } = attributes;
return (
<div
{...useBlockProps.save({
className: `highlight-timeline-step swiper-slide`,
id: `year-${year}`,
})}
>
<div className="highlight-timeline-step__year">
<p className="highlight-timeline-step__year-text">{year}</p>
<TimelineYearBackground />
</div>
<div className="highlight-timeline-step__innerblocks">
<InnerBlocks.Content />
</div>
</div>
);
}

View File

@ -0,0 +1,34 @@
.highlight-timeline-step__year {
position: relative;
> * {
z-index: 1;
}
.highlight-timeline-step__year-background {
position: absolute;
top: 10px;
right: 10px;
bottom: 10px;
left: 10px;
z-index: 0;
overflow: visible;
svg {
overflow: visible;
width: 100%;
height: 100%;
polygon {
overflow: visible;
fill: #efe8ff;
stroke: white;
stroke-width: 20px;
vector-effect: non-scaling-stroke;
}
}
}
.highlight-timeline-step__year-text {
line-height: 1 !important;
}
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" width="772.1" height="653.3" viewBox="0 0 772.1 653.3">
<polygon points="14.2 10.6 762.1 53.5 757.9 642.7 10.1 599.8 14.2 10.6" style="fill: #efe8ff; stroke: #fff; stroke-width: 20px;"/>
</svg>

After

Width:  |  Height:  |  Size: 309 B

View File

@ -0,0 +1,21 @@
import React from "react";
export default function ShapeA({}) {
return (
<div className="highlight-timeline-step__year-background">
<svg
xmlns="http://www.w3.org/2000/svg"
width="772.1"
height="653.3"
viewBox="0 0 772.1 653.3"
preserveAspectRatio="none"
>
<polygon
preserveAspectRatio="none"
points="14.2 10.6 762.1 53.5 757.9 642.7 10.1 599.8 14.2 10.6"
vectorEffect="non-scaling-stroke"
/>
</svg>
</div>
);
}

View File

@ -0,0 +1,20 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "carhop-blocks/highlight-timeline",
"version": "0.1.0",
"title": "Highlight Timeline",
"category": "carhop-blocks",
"icon": "smiley",
"description": "Highlight Timeline pour la mise en forme d'une timeline avec des éléments en surbrillance",
"example": {},
"supports": {
"html": false
},
"textdomain": "highlight-timeline",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js",
"render": "file:./render.php"
}

View File

@ -0,0 +1,40 @@
import { __ } from "@wordpress/i18n";
import { useBlockProps, InnerBlocks } from "@wordpress/block-editor";
import "./editor.scss";
import { useSelect } from "@wordpress/data";
export default function Edit({ attributes, setAttributes, ...props }) {
const years = useSelect(
(select) => {
const { getBlocks } = select("core/block-editor");
const childBlocks = getBlocks(props.clientId) || [];
return childBlocks
.filter((b) => b.name === "carhop-blocks/highlight-timeline-step")
.map((b) => b.attributes?.year)
.filter((y) => y !== undefined && y !== null && y !== "");
},
[props.clientId]
);
return (
<div
{...useBlockProps({
className: "highlight-timeline",
})}
>
<div className="highlight-timeline__innerblocks">
<InnerBlocks
allowedBlocks={["carhop-blocks/highlight-timeline-step"]}
/>
</div>
<ul className="highlight-timeline__years">
{years.map((y, idx) => (
<li key={idx} className="story-timeline__year">
{y}
</li>
))}
</ul>
</div>
);
}

View File

@ -0,0 +1,18 @@
import { registerBlockType } from "@wordpress/blocks";
import "./style.scss";
import Edit from "./edit";
import save from "./save";
import metadata from "./block.json";
registerBlockType(metadata.name, {
icon: {
src: (
<svg width="32" height="32" viewBox="0 0 32 32">
<path d="M16 24L8 16L16 8L24 16L16 24Z" />
</svg>
),
},
edit: Edit,
save,
});

View File

@ -0,0 +1,33 @@
<?php
$wrapper_attributes = get_block_wrapper_attributes(array('class' => 'highlight-timeline'));
$years = array();
if (isset($block) && is_object($block) && ! empty($block->inner_blocks)) {
foreach ($block->inner_blocks as $inner_block) {
if (isset($inner_block->name) && $inner_block->name === 'carhop-blocks/highlight-timeline-step') {
$y = isset($inner_block->attributes['year']) ? $inner_block->attributes['year'] : null;
if ($y !== null && $y !== '') {
$years[] = $y;
}
}
}
}
?>
<section <?php echo $wrapper_attributes; ?>>
<div class="highlight-timeline__innerblocks swiper highlight-timeline-swiper" id="<?php echo esc_attr($years[0]); ?>">
<div class="swiper-wrapper">
<?php echo $content; ?>
</div>
</div>
<div class="swiper-pagination"></div>
<div class="swiper-controls">
<div class="swiper-button-prev"></div>
<div class="swiper-button-next"></div>
</div>
</section>

View File

@ -0,0 +1,5 @@
import { useBlockProps, InnerBlocks } from "@wordpress/block-editor";
export default function save({ attributes }) {
return <InnerBlocks.Content />;
}

View File

@ -0,0 +1,16 @@
.highlight-timeline {
&__years {
width: 100%;
display: flex;
gap: 20px;
li {
color: #fff;
flex-grow: 1;
text-align: center;
list-style: none !important;
border-bottom: 1px solid #fff;
}
}
}

View File

@ -0,0 +1,56 @@
function initiateSwiper() {
const currentBlock = document.querySelector(
".wp-block-carhop-blocks-highlight-timeline"
);
if (!currentBlock) return;
// const swiperFraction = currentBlock.querySelector(
// ".swiper-pagination-fraction"
// );
const slides = currentBlock.querySelectorAll(".swiper-slide");
const slideCount = slides.length;
const years = Array.from(slides).map((slide) => {
const yearEl = slide.querySelector(".highlight-timeline-step__year");
if (yearEl && yearEl.textContent) {
return yearEl.textContent.trim();
}
const id = slide.id || "";
const match = id.match(/^year-(.+)$/);
return match ? match[1] : "";
});
highlightTimelineSwiper = new Swiper(".highlight-timeline-swiper", {
slidesPerView: 1,
spaceBetween: 30,
loop: true,
grabCursor: true,
keyboard: {
enabled: true,
onlyInViewport: true,
},
navigation: {
nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev",
},
mousewheel: {
enabled: true,
forceToAxis: true, // Force le scroll dans l'axe du slider
sensitivity: 1, // Sensibilité du scroll (1 = normal)
releaseOnEdges: false, // Continue le scroll même aux bords
},
pagination: {
el: ".swiper-pagination",
clickable: true,
renderBullet: function (index, className) {
return `<button class="${className}">${years[index] ?? ""}</button>`;
},
},
});
}
window.addEventListener("DOMContentLoaded", (event) => {
initiateSwiper();
// swiperCheckBreakpoints();
// window.addEventListener("resize", swiperCheckBreakpoints);
});