diff --git a/assets/js/theme/blocks/draggableBlocks.js b/assets/js/theme/blocks/draggableBlocks.js index b653531f74784e774c107bf25032805d665a821a..4bd17eadb11ef20d213eb5a6bfc68900deb6d199 100644 --- a/assets/js/theme/blocks/draggableBlocks.js +++ b/assets/js/theme/blocks/draggableBlocks.js @@ -1,170 +1,170 @@ -const draggableBlocks = document.querySelectorAll('.block-timeline--horizontal, .block-posts--carousel'); - -class DraggableBlock { - constructor (block) { - this.block = block; - this.content = this.block.querySelector('.draggable-container'); - this.list = this.block.querySelector('ol, ul'); - this.items = this.list.querySelectorAll('.draggable-item'); - this.previous = this.block.querySelector('.previous'); - this.next = this.block.querySelector('.next'); - this.isPointerDown = false; - - this.index = 0; - - this.listen(); - this.resize(); - this.goTo(0); - } - - listen () { - window.addEventListener('resize', this.resize.bind(this)); - - this.items.forEach((item, i) => { - item.addEventListener('click', this.onClickItem.bind(this, i)); - }); - - if (this.previous && this.next) { - this.handleArrows(); - } - - this.handlePointers(); - this.handleScroll(); - } - - resize () { - let maxTitleHeight = 0; - - this.block.style = ''; - - this.itemWidth = this.items[0].offsetWidth; - - this.items.forEach((item) => { - maxTitleHeight = Math.max(item.querySelector('.title, [itemprop="headline"]').offsetHeight, maxTitleHeight); - }); - - this.block.style.setProperty('--min-title-height', maxTitleHeight + 'px'); - this.update(); - } - - onClickItem (i) { - if (!this.isManipulated) { - this.goTo(i); - } - } - - handleArrows () { - this.previous.addEventListener('click', () => { - this.goTo(this.index-1); - }); - - this.next.addEventListener('click', () => { - this.goTo(this.index+1); - }); - } - - handlePointers () { - let startX, - endX, - threshold = 30; - // j'ai initialisé isPointerDown au début du code : this.isPointerDown - // j'ai enlevé endEvents = ['pointerup'] parce qu'il était seul ? - this.block.style.touchAction = 'pan-y'; - - // on passe de this.content à this.block sur chaque événement pour grab sur tout le bloc - this.block.addEventListener('pointerdown', (event) => { - // On vérifie que l'on ne soit pas en train de cliquer sur les boutons (car on cible tout le bloc pour le grab) - if (event.target !== this.next && event.target !== this.previous) { - // on utilise partout this.isPointerDown car la navigation avec les arrow buguait - // parfois ça naviguait de 2 items - this.isPointerDown = true; - this.content.classList.add('is-grabbing'); - startX = event.clientX; - } - }); - - this.block.addEventListener('pointermove', (event) => { - endX = event.clientX; - // On vérifie que l'événement pointerdown a été activé - if (this.isPointerDown) { - event.preventDefault(); - this.items.forEach((item) => { - // on enlève le pointerevents pour que les liens ne soient pas cliquable au drag - item.style.pointerEvents = 'none'; - }); - } - }); - - // anciennement géré avec endEvents = ['pointerup'] (j'enlève le forEach) - this.block.addEventListener('pointerup', (event) => { - endX = event.clientX; - // on vérifie encore isPointerDown pour éviter le pb des arrows - if (this.isPointerDown) { - this.isPointerDown = false; - this.onManipulationEnd(startX, endX, threshold); - } - }); - } - - handleScroll () { - // On écoute le scroll sur le contenu du bloc - this.content.addEventListener('wheel', (event) => { - const deltaX = event.deltaX, - deltaY = event.deltaY; - // navigation entre les items (comme onManipulationEnd) - if (Math.abs(deltaX) > Math.abs(deltaY)) { - if (deltaX !== 0) { - if (deltaX > 0) { - this.goTo(this.index + 1); - } else { - this.goTo(this.index - 1); - } - } - } - }); - } - - onManipulationEnd (start, end, threshold) { - if (start > end + threshold) { - this.goTo(this.index+1); - } else if (start < end - threshold) { - this.goTo(this.index-1); - } - - this.content.classList.remove('is-grabbing'); - this.items.forEach((item) => { - // On rend le pointervents pour pouvoir cliquer sur le lien si on drag pas - item.style.pointerEvents = 'all'; - }); - - setTimeout(() => { - this.isManipulated = false; - }, 100); - } - - goTo (_index) { - this.index = Math.min(Math.max(_index, 0), this.items.length-1); - this.update(); - } - - update () { - this.list.style.marginLeft = `${-this.index * this.itemWidth}px`; - - this.items.forEach((item, index) => { - if (index < this.index) { - item.classList.add('is-passed'); - } else { - item.classList.remove('is-passed'); - } - }); - - if (this.previous && this.next) { - this.previous.disabled = this.index === 0; - this.next.disabled = this.index === this.items.length - 1; - } - } -} - -draggableBlocks.forEach((block) => { - new DraggableBlock(block); -}); +// const draggableBlocks = document.querySelectorAll('.block-posts--carousel'); + +// class DraggableBlock { +// constructor (block) { +// this.block = block; +// this.content = this.block.querySelector('.draggable-container'); +// this.list = this.block.querySelector('ol, ul'); +// this.items = this.list.querySelectorAll('.draggable-item'); +// this.previous = this.block.querySelector('.previous'); +// this.next = this.block.querySelector('.next'); +// this.isPointerDown = false; + +// this.index = 0; + +// this.listen(); +// this.resize(); +// this.goTo(0); +// } + +// listen () { +// window.addEventListener('resize', this.resize.bind(this)); + +// this.items.forEach((item, i) => { +// item.addEventListener('click', this.onClickItem.bind(this, i)); +// }); + +// if (this.previous && this.next) { +// this.handleArrows(); +// } + +// this.handlePointers(); +// this.handleScroll(); +// } + +// resize () { +// let maxTitleHeight = 0; + +// this.block.style = ''; + +// this.itemWidth = this.items[0].offsetWidth; + +// this.items.forEach((item) => { +// maxTitleHeight = Math.max(item.querySelector('.title, [itemprop="headline"]').offsetHeight, maxTitleHeight); +// }); + +// this.block.style.setProperty('--min-title-height', maxTitleHeight + 'px'); +// this.update(); +// } + +// onClickItem (i) { +// if (!this.isManipulated) { +// this.goTo(i); +// } +// } + +// handleArrows () { +// this.previous.addEventListener('click', () => { +// this.goTo(this.index-1); +// }); + +// this.next.addEventListener('click', () => { +// this.goTo(this.index+1); +// }); +// } + +// handlePointers () { +// let startX, +// endX, +// threshold = 30; +// // j'ai initialisé isPointerDown au début du code : this.isPointerDown +// // j'ai enlevé endEvents = ['pointerup'] parce qu'il était seul ? +// this.block.style.touchAction = 'pan-y'; + +// // on passe de this.content à this.block sur chaque événement pour grab sur tout le bloc +// this.block.addEventListener('pointerdown', (event) => { +// // On vérifie que l'on ne soit pas en train de cliquer sur les boutons (car on cible tout le bloc pour le grab) +// if (event.target !== this.next && event.target !== this.previous) { +// // on utilise partout this.isPointerDown car la navigation avec les arrow buguait +// // parfois ça naviguait de 2 items +// this.isPointerDown = true; +// this.content.classList.add('is-grabbing'); +// startX = event.clientX; +// } +// }); + +// this.block.addEventListener('pointermove', (event) => { +// endX = event.clientX; +// // On vérifie que l'événement pointerdown a été activé +// if (this.isPointerDown) { +// event.preventDefault(); +// this.items.forEach((item) => { +// // on enlève le pointerevents pour que les liens ne soient pas cliquable au drag +// item.style.pointerEvents = 'none'; +// }); +// } +// }); + +// // anciennement géré avec endEvents = ['pointerup'] (j'enlève le forEach) +// this.block.addEventListener('pointerup', (event) => { +// endX = event.clientX; +// // on vérifie encore isPointerDown pour éviter le pb des arrows +// if (this.isPointerDown) { +// this.isPointerDown = false; +// this.onManipulationEnd(startX, endX, threshold); +// } +// }); +// } + +// handleScroll () { +// // On écoute le scroll sur le contenu du bloc +// this.content.addEventListener('wheel', (event) => { +// const deltaX = event.deltaX, +// deltaY = event.deltaY; +// // navigation entre les items (comme onManipulationEnd) +// if (Math.abs(deltaX) > Math.abs(deltaY)) { +// if (deltaX !== 0) { +// if (deltaX > 0) { +// this.goTo(this.index + 1); +// } else { +// this.goTo(this.index - 1); +// } +// } +// } +// }); +// } + +// onManipulationEnd (start, end, threshold) { +// if (start > end + threshold) { +// this.goTo(this.index+1); +// } else if (start < end - threshold) { +// this.goTo(this.index-1); +// } + +// this.content.classList.remove('is-grabbing'); +// this.items.forEach((item) => { +// // On rend le pointervents pour pouvoir cliquer sur le lien si on drag pas +// item.style.pointerEvents = 'all'; +// }); + +// setTimeout(() => { +// this.isManipulated = false; +// }, 100); +// } + +// goTo (_index) { +// this.index = Math.min(Math.max(_index, 0), this.items.length-1); +// this.update(); +// } + +// update () { +// this.list.style.marginLeft = `${-this.index * this.itemWidth}px`; + +// this.items.forEach((item, index) => { +// if (index < this.index) { +// item.classList.add('is-passed'); +// } else { +// item.classList.remove('is-passed'); +// } +// }); + +// if (this.previous && this.next) { +// this.previous.disabled = this.index === 0; +// this.next.disabled = this.index === this.items.length - 1; +// } +// } +// } + +// draggableBlocks.forEach((block) => { +// new DraggableBlock(block); +// }); diff --git a/assets/js/theme/blocks/timeline.js b/assets/js/theme/blocks/timeline.js new file mode 100644 index 0000000000000000000000000000000000000000..53a9585184678d2632372f152914630200b19432 --- /dev/null +++ b/assets/js/theme/blocks/timeline.js @@ -0,0 +1,55 @@ +function Timeline(timeline) { + this.timeline = timeline; + this.eventClass = 'timeline-event' + this.init(); +} + +Timeline.prototype.init = function() { + this.updateTitleHeight(); + + // Resize + window.addEventListener('resize', this.handleResize.bind(this)); +}; + +Timeline.prototype.updateTitleHeight = function () { + var maxTitleHeight = this.getMaxTitleHeight(); + + // On met à jour la variable css qui ajoute une min-height au .title + // L'objectif est d'aligner les lignes de la timeline entre elles + this.updateCssVariable('--min-title-height', maxTitleHeight + 'px'); +}; + +Timeline.prototype.getMaxTitleHeight = function () { + var maxTitleHeight = 0; + var events = this.timeline.getElementsByClassName(this.eventClass); + + // On vient regarder dans tous les .timeline-event pour vérifier quel est le titre le plus long + Array.prototype.forEach.call(events, function(event) { + var titleHeight = this.getTitleHeight(event); + if (titleHeight > maxTitleHeight) { + maxTitleHeight = titleHeight; + } + }, this); + + return maxTitleHeight; +} + +Timeline.prototype.getTitleHeight = function (event) { + var eventTitle = event.querySelector('.title'); + return eventTitle ? eventTitle.offsetHeight : 0; +}; + +Timeline.prototype.updateCssVariable = function (variable, value) { + this.timeline.style.setProperty(variable, value); +}; + +Timeline.prototype.handleResize = function() { + this.updateTitleHeight(); +}; + +document.addEventListener('DOMContentLoaded', function() { + var timelines = document.getElementsByClassName('block-timeline--horizontal'); + for (var i = 0; i < timelines.length; i++) { + new Timeline(timelines[i]); + } +}); \ No newline at end of file diff --git a/assets/js/theme/components/carousel.js b/assets/js/theme/components/carousel.js new file mode 100644 index 0000000000000000000000000000000000000000..974eb2c9e53927aa905306ec0dea62a221a75918 --- /dev/null +++ b/assets/js/theme/components/carousel.js @@ -0,0 +1,15 @@ +// https://developers.osuny.org/docs/theme/components/carousel/ +// First +import './carousel/utils'; +// Then alphabetical +import './carousel/arrows'; +import './carousel/autoplayer'; +import './carousel/carousel'; +import './carousel/classes'; +import './carousel/config'; +import './carousel/events'; +import './carousel/manager'; +import './carousel/paginationButton'; +import './carousel/pagination'; +import './carousel/slide'; +import './carousel/slider'; \ No newline at end of file diff --git a/assets/js/theme/components/carousel/arrows.js b/assets/js/theme/components/carousel/arrows.js new file mode 100644 index 0000000000000000000000000000000000000000..9c5b32c9fc6b668953a1ba8636b91640d39edd8b --- /dev/null +++ b/assets/js/theme/components/carousel/arrows.js @@ -0,0 +1,35 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.Arrows = function (element) { + this.element = element; + if (!this.element) { return }; + this._findElement = window.osuny.carousel.utils.findElement.bind(this); + this._dispatchEvent = window.osuny.carousel.utils.dispatchEvent.bind(this); + this.counter = this._findElement('arrowsCounter'); + this.next = this._findElement('arrowsNext'); + this.previous = this._findElement('arrowsPrevious'); + this.next.addEventListener( + "click", + this._onNext.bind(this) + ); + this.previous.addEventListener( + "click", + this._onPrevious.bind(this) + ); +} +window.osuny.carousel.Arrows.prototype = { + update: function (index, total) { + if (this.element) { + this.counter.innerHTML = (index + 1) + '/' + total; + this.next.disabled = index + 1 == total; + this.previous.disabled = index == 0; + } + }, + _onNext: function () { + this._dispatchEvent('arrowsNext'); + }, + _onPrevious: function () { + this._dispatchEvent('arrowsPrevious'); + } +} \ No newline at end of file diff --git a/assets/js/theme/components/carousel/autoplayer.js b/assets/js/theme/components/carousel/autoplayer.js new file mode 100644 index 0000000000000000000000000000000000000000..a1302cfac291af5f472222ce0bf3760fe7acf8ea --- /dev/null +++ b/assets/js/theme/components/carousel/autoplayer.js @@ -0,0 +1,123 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.Autoplayer = function (element) { + this.element = element; + if (!this.element) { return }; + this.icons = { + play: this.element.getElementsByClassName(window.osuny.carousel.classes.autoplayerToggleIconPlay).item(0), + pause: this.element.getElementsByClassName(window.osuny.carousel.classes.autoplayerToggleIconPause).item(0) + } + this.ariaLiveElement = null; + // Etat de l'autoplay + this.enabled = false; + // Etat de pause (quand on rollover par exemple) + this.paused = false; + // Pause au rollover + this.softPaused = false; + // Intervalle en millisecondes entre 2 déclenhements + this.interval = 3000; + this._resetLoopValues(); + // Bouton toggle + this.classList = this.element.classList; + this.classList.add(window.osuny.carousel.classes.autoplayerPaused); + this.element.addEventListener( + "click", + this._onClick.bind(this) + ); + this._dispatchEvent = window.osuny.carousel.utils.dispatchEvent.bind(this); +} +window.osuny.carousel.Autoplayer.prototype = { + setInterval: function (interval) { + this.interval = interval; + }, + // enable() et disable() activent la boucle + enable: function () { + this.enabled = true; + this._loop(); + this._updateToggle(); + }, + disable: function () { + this.enabled = false; + this.paused = true; + this._updateToggle(); + }, + // pause() et unpause() interrompent temporairement la boucle, en gardant la position + pause: function () { + this.paused = true; + this._updateToggle(); + this._updateAriaLiveElement(); + }, + unpause: function () { + this.paused = false; + this.softPaused = false; + this._updateToggle(); + this._updateAriaLiveElement(); + }, + // Les méthodes soft se produisent quand on passe sur le carousel avec la souris. + // L'idée est de permettre aux personnes de lire une citation. + // Elles ne changent pas réellement l'état de l'autoplayer, + // mais elles l'arrêtent temporairement. + softPause: function () { + this.softPaused = true; + }, + softUnpause: function () { + this.softPaused = false; + }, + _loop: function () { + if (!this.enabled) { return } + var now = Date.now(); + if (!this.paused && !this.softPaused) { + this.elapsedSinceLastTrigger += now - this.lastLoopAt; + this.progression = this.elapsedSinceLastTrigger / this.interval; + this._dispatchProgression(); + } + if (this.elapsedSinceLastTrigger > this.interval) { + this._dispatchTrigger(); + this._resetLoopValues(); + this._dispatchProgression(); + } + // Mémoire du last loop pour la sortie de pause + this.lastLoopAt = now; + window.requestAnimationFrame(this._loop.bind(this)); + }, + _resetLoopValues: function () { + // Progression de 0 à 1, vers le prochain déclenchement + this.progression = 0; + // Temps écoulé depuis le dernier déclenchement + this.elapsedSinceLastTrigger = 0; + // Date de la dernière boucle + this.lastLoopAt = Date.now(); + }, + _dispatchTrigger: function () { + this._dispatchEvent("autoplayerTrigger"); + }, + _dispatchProgression(){ + this._dispatchEvent("autoplayerProgression", this.progression); + }, + _updateToggle: function () { + if (!this.element) { return } + this.classList.remove(window.osuny.carousel.classes.autoplayerPlaying); + this.classList.remove(window.osuny.carousel.classes.autoplayerPaused); + if (this.paused) { + this.classList.add(window.osuny.carousel.classes.autoplayerPaused); + } else { + this.classList.add(window.osuny.carousel.classes.autoplayerPlaying); + } + this.icons.play.setAttribute('aria-hidden', !this.paused); + this.icons.pause.setAttribute('aria-hidden', this.paused); + }, + _updateAriaLiveElement: function() { + if (!this.ariaLiveElement) { return } + var state = this.paused ? "off" : "polite"; + this.ariaLiveElement.setAttribute("aria-live", state); + }, + _onClick: function () { + if (this.paused) { + this.unpause(); + this.enable(); + } else { + this.pause(); + } + } +} \ No newline at end of file diff --git a/assets/js/theme/components/carousel/carousel.js b/assets/js/theme/components/carousel/carousel.js new file mode 100644 index 0000000000000000000000000000000000000000..9b931f74e86a7149a5b97624508647d1ac83004f --- /dev/null +++ b/assets/js/theme/components/carousel/carousel.js @@ -0,0 +1,178 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.Carousel = function (element) { + this.element = element; + this.slides = { + current: 0, + total: 0 + } + this.state = { + initialized: false, + visible: false, + hasMouseOver: false + }; + this.windowResizeTimeout; + this.lastScrollXTimeout; + this._findElement = window.osuny.carousel.utils.findElement.bind(this); + this._initializeConfig(); + this._initializeSlider(); + this._initializePagination(); + this._initializeArrows(); + this._initializeAutoplayer(); + this._initializeMouseEvents(); + this.showSlide(0); + this.state.initialized = true; +} +window.osuny.carousel.Carousel.prototype = { + next: function () { + var index = this.slides.current + 1; + if (index >= this.slides.total) { + index = 0; + } + this.showSlide(index); + this.arrows.next.focus(); + }, + previous: function () { + var index = this.slides.current - 1; + if (index < 0) { + // -1 parce que 0-indexed + index = this.slides.total - 1; + } + this.showSlide(index); + this.arrows.previous.focus(); + }, + showSlide: function (index) { + this.slides.current = index; + this.pagination.unselectAllButtons(); + this.pagination.selectButton(index); + this.slider.showSlide(index); + this.arrows.update(this.slides.current, this.slides.total); + }, + pause: function () { + this.autoplayer.pause(); + }, + unpause: function () { + this.autoplayer.unpause(); + }, + resize: function () { + clearTimeout(this.windowResizeTimeout); + this.windowResizeTimeout = setTimeout(function () { + this.slider.recompute(); + }.bind(this), 200); + }, + isInViewPort: function(){ + var boundingRect = this.element.getBoundingClientRect(), + screenHeight = window.innerHeight || document.documentElement.clientHeight, + elementBottomInViewport = boundingRect.bottom >= 0, + elementTopInViewport = boundingRect.top <= screenHeight; + return elementBottomInViewport || elementTopInViewport; + }, + getCenterPositionY: function () { + var boundingRect = this.element.getBoundingClientRect(); + return boundingRect.top + boundingRect.height / 2; + }, + _initializeConfig: function () { + this.config = new window.osuny.carousel.Config(this); + // Les options sont chargées depuis le data-attribute "data-carousel" + this.config.loadOptions(this.element.dataset.carousel); + }, + _initializePagination: function () { + var paginationElement = this._findElement("pagination"); + this.pagination = new window.osuny.carousel.Pagination(paginationElement); + if (paginationElement) { + paginationElement.addEventListener( + window.osuny.carousel.events.paginationButtonClicked, + this._onPaginationButtonClicked.bind(this) + ); + } + }, + _initializeArrows: function () { + var arrowsElement = this._findElement("arrows"); + this.arrows = new window.osuny.carousel.Arrows(arrowsElement); + if (arrowsElement) { + arrowsElement.addEventListener( + window.osuny.carousel.events.arrowsNext, + this.next.bind(this) + ); + arrowsElement.addEventListener( + window.osuny.carousel.events.arrowsPrevious, + this.previous.bind(this) + ); + } + }, + _initializeSlider: function () { + var sliderElement = this._findElement("slider"); + this.slider = new window.osuny.carousel.Slider(sliderElement); + this.slides.total = this.slider.length(); + sliderElement.addEventListener( + "scroll", + this._onSliderScroll.bind(this) + ); + }, + _initializeAutoplayer(){ + this.autoplayerElement = this._findElement("autoplayerToggle"); + this.autoplayer = new window.osuny.carousel.Autoplayer(this.autoplayerElement); + this.autoplayer.setInterval(this.config.autoplayinterval); + this.autoplayer.ariaLiveElement = this._findElement("container"); + if (this.autoplayerElement) { + this.autoplayerElement.addEventListener( + window.osuny.carousel.events.autoplayerTrigger, + this.next.bind(this) + ); + this.autoplayerElement.addEventListener( + window.osuny.carousel.events.autoplayerProgression, + this._onAutoplayerProgression.bind(this) + ); + if (this.config.autoplay) { + this.autoplayer.enable(); + } + } + }, + _pointerStart: function() { + this.autoplayer.softPause(); + this.state.hasMouseOver = true; + }, + _pointerEnd: function() { + this.autoplayer.softUnpause(); + this.state.hasMouseOver = false; + }, + _initializeMouseEvents: function(){ + this.element.addEventListener( + "mouseenter", this._pointerStart.bind(this) + ); + this.element.addEventListener( + "touchstart", this._pointerStart.bind(this) + ); + this.element.addEventListener( + "mouseleave", this._pointerEnd.bind(this) + ); + this.element.addEventListener( + "touchend", this._pointerEnd.bind(this) + ); + }, + + _onAutoplayerProgression: function (event) { + this.pagination.setProgression(event.value); + }, + _onPaginationButtonClicked: function (event) { + this.autoplayer.disable(); + this.showSlide(event.index); + }, + _onSliderScroll: function () { + this.autoplayer.softPause(); + clearTimeout(this.lastScrollXTimeout); + this.lastScrollXTimeout = setTimeout(function () { + if(!this.state.hasMouseOver){ + this.autoplayer.softUnpause(); + } + this._onSliderScrollend(); + }.bind(this), 100); + }, + _onSliderScrollend: function () { + var index = this.slider.currentSlideIndex(); + if (this.slides.current != index) { + this.showSlide(index); + } + } +} \ No newline at end of file diff --git a/assets/js/theme/components/carousel/classes.js b/assets/js/theme/components/carousel/classes.js new file mode 100644 index 0000000000000000000000000000000000000000..351e7aad6007ac26a215d8171066ce8439686ed8 --- /dev/null +++ b/assets/js/theme/components/carousel/classes.js @@ -0,0 +1,24 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.classes = { + arrows: "carousel__arrows", + arrowsCounter: "counter", + arrowsNext: "arrow-next", + arrowsPrevious: "arrow-prev", + autoplayerPaused: "toggle__paused", + autoplayerPlaying: "toggle__playing", + autoplayerToggle: "toggle", + autoplayerToggleIconPause: "pause", + autoplayerToggleIconPlay: "play", + carousel: "js-carousel", + container: "carousel__container", + pagination: "carousel__pagination__tabcontainer", + paginationPage: "carousel__pagination__page", + slider: "carousel__slider", + slideIsBefore: "is-before", + slideIsPrevious: "is-previous", + slideIsCurrent: "is-current", + slideIsNext: "is-next", + slideIsAfter: "is-after", +} \ No newline at end of file diff --git a/assets/js/theme/components/carousel/config.js b/assets/js/theme/components/carousel/config.js new file mode 100644 index 0000000000000000000000000000000000000000..c411931a0dcc69274b0feec338e794eba426a4f5 --- /dev/null +++ b/assets/js/theme/components/carousel/config.js @@ -0,0 +1,37 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.Config = function (instance) { + this.instance = instance; + + // Valeurs par défaut et documentation des propriétés + // L'autoplay est-il activé ou pas ? + this.autoplay = false; + + // Pagination sous forme de tabulation + this.pagination = true; + + // Controle du defilement avec les fleches + this.arrows = false; + + // Durée d'affichage d'un slide en cas d'autoplay + this.autoplayinterval = 3000; +} + +window.osuny.carousel.Config.prototype = { + valuesInOptions: [ + "autoplay", + "arrows", + "pagination", + "autoplayinterval" + ], + loadOptions: function (data) { + var options = JSON.parse(data); + for (var i = 0; i <= this.valuesInOptions.length; i += 1) { + var value = this.valuesInOptions[i]; + if (options[value] !== undefined) { + this[value] = options[value]; + } + }; + } +} \ No newline at end of file diff --git a/assets/js/theme/components/carousel/events.js b/assets/js/theme/components/carousel/events.js new file mode 100644 index 0000000000000000000000000000000000000000..c73b1c3e656f0ea82a4e5f3096f3425d4f8e9ceb --- /dev/null +++ b/assets/js/theme/components/carousel/events.js @@ -0,0 +1,10 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.events = { + autoplayerProgression: "osuny.carousel.autoplayer.progression", + autoplayerTrigger: "osuny.carousel.autoplayer.trigger", + arrowsNext: "osuny.carousel.arrows.next", + arrowsPrevious: "osuny.carousel.arrows.previous", + paginationButtonClicked: "osuny.carousel.pagination.buttonClicked" +} \ No newline at end of file diff --git a/assets/js/theme/components/carousel/manager.js b/assets/js/theme/components/carousel/manager.js new file mode 100644 index 0000000000000000000000000000000000000000..9390834ab1e28573979d9894d44a81ae925f6bc3 --- /dev/null +++ b/assets/js/theme/components/carousel/manager.js @@ -0,0 +1,95 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.manager = { + initialized: false, + elements: [], + carousels: [], + focusedCarousel: null, + carouselsInViewport: [], + windowCenterY: null, + initialize: function () { + if (!this.initialized) { + this._createCarousels(); + this._computeWindowCenterY(); + this._initializeListeners(); + this._findCarouselsInViewport(); + this.initialized = true; + } + }, + _createCarousels: function () { + this.elements = document.getElementsByClassName(window.osuny.carousel.classes.carousel); + for (var i = 0; i < this.elements.length; i += 1) { + var element = this.elements[i], + carousel = new window.osuny.carousel.Carousel(element); + this.carousels.push(carousel); + } + }, + _initializeListeners: function () { + window.addEventListener( + "resize", + this._resize.bind(this) + ); + window.addEventListener( + "scroll", + this._findCarouselsInViewport.bind(this) + ); + window.addEventListener( + "keydown", + this._onKeyPress.bind(this) + ); + }, + _resize: function () { + this._computeWindowCenterY(); + this.carousels.forEach(function (carousel) { + carousel.resize(); + }); + }, + _computeWindowCenterY: function(){ + this.windowCenterY = (window.innerHeight || document.documentElement.clientHeight) / 2; + }, + _findCarouselsInViewport: function () { + this.carouselsInViewport = []; + for (var i = 0; i < this.carousels.length; i += 1) { + var carousel = this.carousels[i]; + if (carousel.isInViewPort()) { + carousel.unpause(); + this.carouselsInViewport.push(carousel); + } else { + carousel.pause(); + } + }; + this.focusedCarousel = this._findBestCarouselFocusCandidate(); + }, + _findBestCarouselFocusCandidate: function () { + // On démarre avec la plus grande distance possible + var distance = window.innerHeight, + bestCandidate = null; + for (var i = 0; i < this.carousels.length; i += 1) { + var carousel = this.carousels[i]; + var currentDistanceToCenter = Math.abs(carousel.getCenterPositionY() - this.windowCenterY); + if (currentDistanceToCenter < distance) { + distance = currentDistanceToCenter; + bestCandidate = carousel; + } + }; + return bestCandidate; + }, + _onKeyPress: function (e) { + if (this.focusedCarousel) { + if (e.key == 'ArrowLeft') { this.focusedCarousel.previous() } + else if (e.key == 'ArrowRight') { this.focusedCarousel.next() } + } + }, + invoke: function () { + "use strict"; + return { + initialize: this.initialize.bind(this), + carousels: this.carousels, + }; + } +}.invoke(); + +window.addEventListener("load", function () { + window.osuny.carousel.manager.initialize(); +}); \ No newline at end of file diff --git a/assets/js/theme/components/carousel/pagination.js b/assets/js/theme/components/carousel/pagination.js new file mode 100644 index 0000000000000000000000000000000000000000..99386d8ad4934be904d84de9c3fd09fdc7cba567 --- /dev/null +++ b/assets/js/theme/components/carousel/pagination.js @@ -0,0 +1,33 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.Pagination = function (element) { + this.element = element; + this.buttons = []; + if (!this.element) { return }; + this.buttonElements = this.element.getElementsByClassName(window.osuny.carousel.classes.paginationPage); + for (var index = 0; index < this.buttonElements.length; index += 1) { + var buttonElement = this.buttonElements[index], + button = new window.osuny.carousel.PaginationButton(buttonElement, index, this.element); + this.buttons.push(button); + } + this.currentButton = this.buttons[0]; +} +window.osuny.carousel.Pagination.prototype = { + selectButton: function (index) { + if (this.element) { + this.currentButton = this.buttons[index]; + this.currentButton.select(); + } + }, + setProgression: function (progression) { + if (this.currentButton) { + this.currentButton.setProgression(progression); + } + }, + unselectAllButtons: function () { + this.buttons.forEach(function (button) { + button.unselect(); + }); + } +} diff --git a/assets/js/theme/components/carousel/paginationButton.js b/assets/js/theme/components/carousel/paginationButton.js new file mode 100644 index 0000000000000000000000000000000000000000..a0b60b3d08b56c1e3e44c80b5299e3c97ad62d7d --- /dev/null +++ b/assets/js/theme/components/carousel/paginationButton.js @@ -0,0 +1,41 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.PaginationButton = function PaginationButton(element, index, pagination) { + this.element = element; + this.index = index; + this.pagination = pagination; + this.progressBar = this.element.querySelector("i"); + this._setAria(); + this.setProgression(0); + this.element.addEventListener( + "click", + this._onClick.bind(this) + ); +} + +window.osuny.carousel.PaginationButton.prototype = { + setProgression: function (progression) { + this.progression = progression; + var percent = String(this.progression * 100) + "%"; + this.progressBar.style.setProperty("width", percent); + }, + select: function () { + this.setProgression(1); + this.element.setAttribute("aria-selected", "true"); + }, + unselect: function () { + this.setProgression(0); + this.element.setAttribute("aria-selected", "false"); + }, + _setAria: function () { + var ariaLabel = this.element.getAttribute("aria-label"), + ariaNewLabel = ariaLabel.replace("%s", this.index); + this.element.setAttribute("aria-label", ariaNewLabel); + }, + _onClick: function () { + var event = new Event(window.osuny.carousel.events.paginationButtonClicked); + event.index = this.index; + this.pagination.dispatchEvent(event); + } +} \ No newline at end of file diff --git a/assets/js/theme/components/carousel/slide.js b/assets/js/theme/components/carousel/slide.js new file mode 100644 index 0000000000000000000000000000000000000000..ce6a29406bd33b940541c741905ca6307ac4b26a --- /dev/null +++ b/assets/js/theme/components/carousel/slide.js @@ -0,0 +1,50 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.Slide = function (slider, container, index) { + this.slider = slider; + this.container = container; + this.index = index; + this.classList = this.container.classList; + this.computedStyle = null; + this.width = 0; + this.computeWidth(); +} + +window.osuny.carousel.Slide.prototype = { + computeWidth: function () { + this.computedStyle = getComputedStyle(this.container); + this.width = this.container.offsetWidth + + parseFloat(this.computedStyle.marginLeft) + + parseFloat(this.computedStyle.marginRight); + }, + setClasses() { + this._setState(this._isBefore(), window.osuny.carousel.classes.slideIsBefore); + this._setState(this._isPrevious(), window.osuny.carousel.classes.slideIsPrevious); + this._setState(this._isCurrent(), window.osuny.carousel.classes.slideIsCurrent); + this._setState(this._isNext(), window.osuny.carousel.classes.slideIsNext); + this._setState(this._isAfter(), window.osuny.carousel.classes.slideIsAfter); + }, + _isBefore: function () { + return this.index < this.slider.index; + }, + _isPrevious: function () { + return this.index == this.slider.index - 1; + }, + _isCurrent: function () { + return this.index == this.slider.index; + }, + _isNext: function () { + return this.index == this.slider.index + 1; + }, + _isAfter: function () { + return this.index > this.slider.index; + }, + _setState: function (active, className) { + if (active) { + this.classList.add(className); + } else { + this.classList.remove(className); + } + } +} diff --git a/assets/js/theme/components/carousel/slider.js b/assets/js/theme/components/carousel/slider.js new file mode 100644 index 0000000000000000000000000000000000000000..7ecca91227d484ac8b6e7e880b4de57f6445348c --- /dev/null +++ b/assets/js/theme/components/carousel/slider.js @@ -0,0 +1,64 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.Slider = function Slider(element) { + this.element = element; + this._findElement = window.osuny.carousel.utils.findElement.bind(this), + this.container = this._findElement("container"); + this.index = 0; + this.slides = []; + this.deltaPosition = 0; + this.drag = null; + var slidesContainers = this.container.children; + for (var i = 0; i < slidesContainers.length; i += 1) { + var slideContainer = slidesContainers.item(i); + this.slides.push(new window.osuny.carousel.Slide(this, slideContainer, i)); + } + this.showSlide(this.index); +} +window.osuny.carousel.Slider.prototype = { + showSlide: function (index) { + this.index = index; + var behavior = "smooth"; + this.element.scrollTo({ + top: 0, + left: this._slidePosition(index), + behavior: behavior + }); + this._updateSlidesClasses(); + }, + recompute: function(){ + this.slides.forEach(function(slide) { + slide.computeWidth(); + }); + this.showSlide(this.index); + }, + length: function () { + return this.slides.length; + }, + currentSlideIndex: function () { + var currentWidth = 0; + // Le seuil permet d'éviter des erreurs d'arrondis qui causent un retour en slide 1, par étapes + var threshold = 20; + for (var index = 0; index < this.slides.length; index += 1) { + var slide = this.slides[index]; + currentWidth += slide.width; + if (currentWidth > this.element.scrollLeft + threshold) { + return index; + } + } + return 0; + }, + _slidePosition: function (index) { + var position = 0; + for (var i = 0; i < index; i += 1) { + position += this.slides[i].width; + } + return position; + }, + _updateSlidesClasses: function () { + this.slides.forEach(function(slide) { + slide.setClasses(); + }); + } +} \ No newline at end of file diff --git a/assets/js/theme/components/carousel/utils.js b/assets/js/theme/components/carousel/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..73ea31ed66b9e757a50e73ddcf0db519956c03dd --- /dev/null +++ b/assets/js/theme/components/carousel/utils.js @@ -0,0 +1,16 @@ +window.osuny = window.osuny || {}; +window.osuny.carousel = window.osuny.carousel || {}; + +window.osuny.carousel.utils = { + // Méhodes ajoutées comme des traits (décorateur) aux objets qui en ont besoin + findElement: function(classKey) { + var className = window.osuny.carousel.classes[classKey]; + return this.element.getElementsByClassName(className).item(0); + }, + dispatchEvent: function (eventKey, value = null) { + var eventName = window.osuny.carousel.events[eventKey]; + var event = new Event(eventName); + event.value = value; + this.element.dispatchEvent(event); + } +} \ No newline at end of file diff --git a/assets/js/theme/index.js b/assets/js/theme/index.js index 949ab10918fcb92eec7c9d7c3d1b3d7e4886355a..3cc191d2542d24b310f90336957dca8cfdd9e3b7 100644 --- a/assets/js/theme/index.js +++ b/assets/js/theme/index.js @@ -10,5 +10,8 @@ import './design-system/toc'; import './blocks/keyFigures'; import './blocks/organizations'; import './blocks/draggableBlocks.js'; +import './blocks/timeline.js'; import './blocks/videos.js'; -import './blocks/campus.js'; \ No newline at end of file +import './blocks/campus.js'; +import './utils/utils.js'; +import './components/carousel.js'; \ No newline at end of file diff --git a/assets/js/theme/utils/utils.js b/assets/js/theme/utils/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..a87aee1e7d4ecd4b4406c4fe6ed49f58e264b7cd --- /dev/null +++ b/assets/js/theme/utils/utils.js @@ -0,0 +1,9 @@ +window.osuny = window.osuny || {}; +window.osuny.utils = window.osuny.utils || {}; +window.osuny.utils.instanciateIf = function (scope, model, condition) { + if (condition) { + return new model(scope); + } else { + return null; + } +} \ No newline at end of file diff --git a/assets/sass/_theme/blocks/gallery.sass b/assets/sass/_theme/blocks/gallery.sass index d85b11d19535fd1bc70fc58a6fb609c6f4b834e3..c66c4b95c0354b1f9df87ad846451284399cca3c 100644 --- a/assets/sass/_theme/blocks/gallery.sass +++ b/assets/sass/_theme/blocks/gallery.sass @@ -81,37 +81,14 @@ background: $block-gallery-carousel-background padding-bottom: var(--grid-gutter) padding-top: var(--grid-gutter) + .container + padding-right: var(--grid-gutter-negative) !important .block-gallery + &, .block-pages--cards + & margin-top: 0 - .splide - display: flex - flex-direction: column - @include in-page-with-sidebar - &.is-moving - .splide__slide.is-active - opacity: 0.1 - &__track - overflow: visible - margin-right: var(--grid-gutter-negative) - @include in-page-with-sidebar - .splide__slide - transition: opacity .3s ease - opacity: 0.1 - &.is-next - opacity: 0.6 - &.is-active - opacity: 1 + .carousel &__slide - flex-shrink: initial - &:last-child - padding-right: 20% - figure - margin-right: $spacing-3 - @include media-breakpoint-down(desktop) - display: flex - flex-direction: column - justify-content: end + margin-right: calc(var(--grid-gutter) / 2) picture img // FIXME Arnaud: I would like images at constant height, can't manage to get it right. @@ -123,36 +100,5 @@ height: $block-gallery-carousel-max-height width: auto max-width: none - - &__arrows - margin-left: pxToRem(-18) - order: 2 - @media (min-height: 800px) - padding-top: space(10) - &__arrow - &:disabled - cursor: default - opacity: 0.3 - &--prev, - &--next - @include button-reset - @include icon(arrow-left-line, before) - height: $spacing-4 - padding: 0 - position: static - width: $spacing-4 - svg - display: none - &--next - @include icon(arrow-right-line, before) - - @include in-page-without-sidebar - .splide - figure - margin-left: var(--grid-gutter) - margin-right: -$spacing-3 - &__slide - &:first-child - margin-left: var(--grid-gutter) - &__track - margin-left: var(--grid-gutter-negative) \ No newline at end of file + @include in-page-without-sidebar + margin-right: var(--grid-gutter) diff --git a/assets/sass/_theme/blocks/posts.sass b/assets/sass/_theme/blocks/posts.sass index 69cbcc2563f6a5b076250d655f4c19c02a767424..693446361b8af8b16dcbe9fd1625317277672c54 100644 --- a/assets/sass/_theme/blocks/posts.sass +++ b/assets/sass/_theme/blocks/posts.sass @@ -278,44 +278,35 @@ margin-top: $spacing-5 &--carousel - @include draggable-block - .container - padding-right: 0 .carousel padding-bottom: $spacing-3 - &:hover - cursor: grab - &.is-grabbing - cursor: grabbing - li + &__slider + margin-left: calc(var(--grid-gutter-negative) + calc(var(--grid-gutter) / 2)) + &__slide list-style: none - .posts - display: flex - gap: unset + word-break: break-word .post margin: 0 calc(var(--grid-gutter) / 2) - .actions-arrows + &.is-before + opacity: 0.3 + @include in-page-with-sidebar + .post + width: columns(3) + .post-title + @include h4 + @include media-breakpoint-down(desktop) + &__slider + margin-left: var(--grid-gutter-negative) + width: var(--grid-width) + &__slide + .post + margin-left: var(--grid-gutter) + margin-right: 0 + width: columns(10) + &__arrows justify-content: space-between - @include media-breakpoint-down(desktop) - .carousel - gap: half(var(--grid-gutter)) - .post - width: columns(10) - .grab-item:last-of-type - margin-right: half(var(--grid-gutter)) - .actions-arrows - margin-right: var(--grid-gutter) - @include media-breakpoint-up(desktop) - .next - margin-right: pxToRem(-27) // Marge négative pour aligner correctement le picto à la colonne - @include in-page-with-sidebar - .post - width: columns(3) - .post-title - @include h4 - .carousel - .actions-arrows - width: offset(6) + .counter + display: none @include in-page-without-sidebar .block-content display: flex @@ -326,9 +317,6 @@ width: columns(9) .post width: columns(4) - .carousel - .actions-arrows - width: offset(8) // Move this part to blocks/categories when categories block is ready .block-posts diff --git a/assets/sass/_theme/blocks/testimonials.sass b/assets/sass/_theme/blocks/testimonials.sass index 9b884e5a1de25a5a5348c99639955dcf6df3a8e0..f3edc02ff921ce3b7fb59f3c19881232b229f354 100644 --- a/assets/sass/_theme/blocks/testimonials.sass +++ b/assets/sass/_theme/blocks/testimonials.sass @@ -28,88 +28,42 @@ display: block .avatar flex-shrink: 0 - width: columns(1) - min-width: pxToRem(80) - margin-right: $spacing-2 margin-bottom: 0 - - .splide - .splide__slider - display: flex - flex-direction: column-reverse - &__toggle - border: 1px solid $block-testimonials-pagination-background - border-radius: 50% - cursor: pointer - font-size: 0 - height: pxToRem(42) - padding: 0 - position: absolute - right: 0 - top: 0 - width: pxToRem(42) - font-size: 0 - line-height: 1 - span - color: var(--color-accent) - &::before - font-size: pxToRem(22) - height: pxToRem(42) - width: pxToRem(42) - margin-left: -0.5px - margin-top: -1.5px - .splide__pagination - .is-active i - width: 100% - - .splide__play - &::before - margin-left: 2px - &__pagination - justify-content: unset - margin-right: 55px - li - flex: 1 - margin-right: 10px - button - @include button-reset - position: relative - width: 100% - &::before, - i - height: 1px - left: 0 - top: 50% - position: absolute - &::before - background-color: $block-testimonials-pagination-background - border-radius: 0 - width: 100% - i - background-color: $block-testimonials-pagination-progress-background - width: 0 + margin-right: $spacing-2 + min-width: pxToRem(80) + width: columns(1) @include in-page-without-sidebar - .top - padding-left: offset(3) - .splide__pagination - padding-left: offset(3) - padding-right: offset(1) - .splide__autoplay - margin-right: offset(1) figure - padding-right: offset(3) min-height: columns(2) + padding-right: offset(3) &.with-picture - padding-right: offset(1) padding-left: offset(3) + padding-right: offset(1) position: relative figcaption display: block margin-top: $spacing-2 .avatar - position: absolute left: columns(1) - top: 0 margin-left: var(--grid-gutter) + position: absolute + top: 0 width: columns(2) + .carousel + flex-direction: column-reverse + .toggle + border: 1px solid $block-testimonials-pagination-background + &__pagination + order: 1 + button + &::before + background-color: $block-testimonials-pagination-background + i + background-color: $block-testimonials-pagination-progress-background + &__slide + width: columns(12) + opacity: 1 + padding: 0 $spacing-1 + @include in-page-with-sidebar + width: columns(8) diff --git a/assets/sass/_theme/blocks/timeline.sass b/assets/sass/_theme/blocks/timeline.sass index cb1be7fde5adc3a16af27eeae3d81ab2de5a9804..07b2aab888349c3da26b44a41016762b50add489 100644 --- a/assets/sass/_theme/blocks/timeline.sass +++ b/assets/sass/_theme/blocks/timeline.sass @@ -69,6 +69,8 @@ padding-top: var(--block-space-y) &::before display: none + .carousel__slider + margin-left: calc(var(--grid-gutter-negative) + calc(var(--grid-gutter) / 2)) .timeline-event padding: 0 calc(var(--grid-gutter) / 2) width: columns(4) @@ -106,6 +108,9 @@ width: calc(100% + var(--grid-gutter)) @include media-breakpoint-down(desktop) + .carousel__slider + margin-left: calc(var(--grid-gutter-negative)) + width: calc(var(--grid-width) + var(--grid-gutter) * 2) .timeline-events position: relative .actions-arrows @@ -115,9 +120,14 @@ .timeline-event margin-right: 0 padding-right: 0 - width: 75% + padding-left: var(--grid-gutter) + width: columns(12) .line margin-bottom: $spacing-5 + width: calc(100% + var(--grid-gutter)) + &::before + width: 8px + height: 8px @include in-page-without-sidebar @include media-breakpoint-up(xxl) @@ -126,4 +136,4 @@ @include in-page-with-or-without-sidebar .block-title - @include h5 + @include h5 \ No newline at end of file diff --git a/assets/sass/_theme/components/carousel.sass b/assets/sass/_theme/components/carousel.sass new file mode 100644 index 0000000000000000000000000000000000000000..361f1e267d4491d752f967dfa4ec98f8a8e804da --- /dev/null +++ b/assets/sass/_theme/components/carousel.sass @@ -0,0 +1,163 @@ +.carousel + display: flex + flex-direction: column + position: relative + &__slider + overflow: scroll + scroll-snap-type: x mandatory + scrollbar-width: none + &::-webkit-scrollbar + display: none + &__container + // Si l'image est verticale, ça fonctionne tant qu'elle fait plus de 20vw + padding-right: 80vw + display: flex + justify-content: flex-start + flex-direction: row + left: 0px + position: relative + top: 0 + width: fit-content + justify-content: flex-start + + &__slide + scroll-snap-align: start + .block-timeline &.is-before + opacity: 0.3 + + button + appearance: none + background: transparent + border: 0 + + &__arrows + display: flex + flex-direction: row + align-items: center + margin-left: - $spacing-3 + margin-right: - $spacing-3 + @include media-breakpoint-up(desktop) + padding-top: $spacing-3 + .counter + min-width: $spacing-3 + text-align: center + width: fit-content + @include meta + .block-timeline & + display: none + &:empty + display: block + button + color: var(--color-text) + svg + display: none + &--prev + @include icon(arrow-left-line) + right: 100% + &--next + @include icon(arrow-right-line) + left: 100% + + &:disabled + cursor: default + opacity: 0.3 + &.arrow-prev, + &.arrow-next + @include button-reset + @include icon(arrow-left-line, before) + padding: $spacing-3 + position: static + svg + display: none + &.arrow-next + @include icon(arrow-right-line, before) + + &__pagination + &__tabcontainer + display: flex + list-style: none + margin: 0 + padding: 0 + &.has_toggle + margin: 0 50px 0 0 + li + display: block + flex: 1 + list-style: none + margin: 0 + margin-right: 10px + padding: 0 + button + display: block + height: 48px + padding: 0 + position: relative + width: 100% + cursor: pointer + &::before + -moz-transition: background .3s ease + -o-transition: background .3s ease + background-color: alphaColor($link-color, 0.3) + border-radius: 0 + content: "" + display: block + height: 1px + left: 0 + margin: auto + position: absolute + top: 50% + transition: background 0.3s ease + width: 100% + &::before, + i + height: 1px + left: 0 + position: absolute + top: 50% + i + background-color: alphaColor($link-color, 0.3) + width: 100% + + &:hover + &::before + background-color: alphaColor($link-color, 0.6) + &.is-active + &::before + background-color: $link-color + .toggle + border-radius: 50% + border: 0 + cursor: pointer + font-size: 0 + height: pxToRem(42) + line-height: 1 + padding: 0 + position: absolute + right: 0 + top: 0 + width: pxToRem(42) + span + color: var(--color-accent) + &::before + font-size: pxToRem(22) + height: pxToRem(42) + width: pxToRem(42) + margin-top: -1.5px + &.play + @include icon-block(play-fill) + margin-left: -0.5px + &.pause + @include icon-block(pause-line) + margin-left: -1.5px + &__paused + span + &.play + display: block + &.pause + display: none + &__playing + span + &.play + display: none + &.pause + display: block diff --git a/assets/sass/_theme/dependencies/splide.sass b/assets/sass/_theme/dependencies/splide.sass deleted file mode 100644 index 1a779b37e309bcfa4d01cfea2475ca01a8e567db..0000000000000000000000000000000000000000 --- a/assets/sass/_theme/dependencies/splide.sass +++ /dev/null @@ -1,52 +0,0 @@ -.splide - button - appearance: none - background: transparent - border: 0 - &__arrow - color: var(--color-text) - position: absolute - top: 50% - svg - display: none - &--prev - @include icon(arrow-left-line) - right: 100% - &--next - @include icon(arrow-right-line) - left: 100% - &__pagination - display: flex - list-style: none - margin: 0 - padding: 0 - button - display: block - height: 48px - padding: 0 - width: 48px - &::before - background-color: alphaColor($link-color, 0.3) - border-radius: 50% - content: "" - display: block - height: 10px - margin: auto - transition: background 0.3s ease - width: 10px - &:hover - &::before - background-color: alphaColor($link-color, 0.6) - &.is-active - &::before - background-color: $link-color - &__toggle - &__pause - @include icon-block(pause-line) - &__play - @include icon-block(play-fill) - padding-left: pxToRem(2) - &[data-slides-length="1"] - .splide - &__autoplay, &__pagination, &__arrow - display: none diff --git a/assets/sass/_theme/hugo-osuny.sass b/assets/sass/_theme/hugo-osuny.sass index 85c9fd8072e0087859a180d19969026288bc6c03..707b4fe42723d6deb42c8b743b5d4afe3b4f086e 100644 --- a/assets/sass/_theme/hugo-osuny.sass +++ b/assets/sass/_theme/hugo-osuny.sass @@ -13,9 +13,7 @@ // Vendors @import glightbox/dist/css/glightbox -@import @splidejs/splide/dist/css/splide-core.min @import dependencies/glightbox -@import dependencies/splide // Design System @import design-system/layout @@ -39,6 +37,9 @@ @import design-system/table @import design-system/table_of_contents +// Components +@import components/carousel + // Blocks @import blocks/base @import blocks/agenda diff --git a/config.yaml b/config.yaml index fdb8c248b20d59d4cc64529aa2e51cd98173a0a0..e041e5350ca70099eb2d9beeb7fc37130252642a 100644 --- a/config.yaml +++ b/config.yaml @@ -170,25 +170,30 @@ params: # BLOCKS blocks: gallery: - splide: + carousel: arrows: true pagination: false - autoWidth: true autoplay: false key_figures: animated: true pages: alternate: more: true + posts: + carousel: + arrows: true + pagination: false + autoplay: false testimonials: - splide: - arrows: false + carousel: + pagination: true autoplay: true - pauseOnHover: false - pauseOnFocus: true - type: loop - autoHeight: true - interval: 8000 + autoplayinterval: 3000 + timeline: + carousel: + arrows: true + pagination: false + autoplay: false image_sizes: design_system: lightbox: diff --git a/i18n/en.yml b/i18n/en.yml index bcc93e01d669e23bbe77b10edad3a56b1409132d..1ae8fbe7568d0e338c60e0f53ba6284b02aa1455 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -78,8 +78,8 @@ commons: last: Go to first slide next: Slide suivant pageX: Go to page %s - pause: Pause - play: Play + pause: Carousel playing. Pause the carousel + play: Carousel currently paused. Start the carousel prev: Slide précedent slideX: Go to slide %s click_to_copy: diff --git a/i18n/fr.yml b/i18n/fr.yml index d13d9b790fdc62f5ff34f385193e1d93ef408dc5..b3a750761ed94054fc445e415e1e6ab832ddca09 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -78,8 +78,8 @@ commons: last: Aller au dernier slide next: Aller à l'élément suivant pageX: Aller à la page %s - pause: Mettre en pause le carousel - play: Démarrer le carousel + pause: Carousel en cours de lecture. Mettre en pause le carousel + play: Carousel actuellement en pause. Démarrer le carousel prev: Aller à l'élément précédent slideX: Aller au slide %s click_to_copy: diff --git a/layouts/partials/blocks/templates/carousel.html b/layouts/partials/blocks/templates/carousel.html new file mode 100644 index 0000000000000000000000000000000000000000..c050056061d450840e59b416e8f21d567823c4de --- /dev/null +++ b/layouts/partials/blocks/templates/carousel.html @@ -0,0 +1,56 @@ +{{ $partial := .partial }} +{{ $heading_tag := .heading_tag | default 2 }} +{{ $block_options := .block_options | default "" }} + +<div class="carousel js-carousel" aria-roledescription="carousel" data-carousel="{{ .options | encoding.Jsonify }}"> + <div class="carousel__slider"> + <div id="carousel-items" class="carousel__container" aria-live="off" aria-atomic="false"> + {{ $slideRole := "group" }} + {{ if .options.pagination }} + {{ $slideRole = "tabpanel" }} + {{ end }} + {{ $totalSlides := len .content }} + {{ range $slideindex, $content := .content }} + {{ with $content }} + {{ partial $partial (dict + "is_carousel" true + "index" (add $slideindex 1) + "params" . + "role" $slideRole + "heading_tag" $heading_tag + "options" $block_options + "total" $totalSlides + ) }} + {{ end }} + {{ end }} + </div> + </div> + <div class="carousel__pagination"> + {{ if .options.pagination }} + <ul class="carousel__pagination__tabcontainer {{ if .options.autoplay }} has_toggle {{ end }}" role="tablist"> + {{ range $slideindex, $content := .content }} + <li> + <button id="carousel-tab-{{$slideindex}}" role="tab" aria-controls="carousel-item-{{$slideindex}}" aria-selected="false" class="carousel__pagination__page" type="button" aria-label='{{ safeHTML (i18n "commons.carousel.slideX") }}'> + <i></i> + </button> + </li> + {{ end }} + </ul> + {{ end }} + + {{ if .options.autoplay }} + <button class="toggle"> + <span class="play" aria-label='{{ safeHTML (i18n "commons.carousel.play") }}'></span> + <span class="pause" aria-label='{{ safeHTML (i18n "commons.carousel.pause") }}'></span> + </button> + {{ end }} + </div> + + {{ if .options.arrows }} + <div class="carousel__arrows"> + <button class="arrow-prev" aria-controls="carousel-items" type="button" aria-label='{{ safeHTML (i18n "commons.carousel.prev") }}'> </button> + <p class="counter"></p> + <button class="arrow-next" aria-controls="carousel-items" type="button" aria-label='{{ safeHTML (i18n "commons.carousel.next") }}'></button> + </div> + {{ end }} +</div> \ No newline at end of file diff --git a/layouts/partials/blocks/templates/gallery.html b/layouts/partials/blocks/templates/gallery.html index c740d848bb53ceaf2d24840787b4850df71f3d4d..157b810555ede57f562c6d0d2ef26a87a0b82d7b 100644 --- a/layouts/partials/blocks/templates/gallery.html +++ b/layouts/partials/blocks/templates/gallery.html @@ -1,6 +1,6 @@ {{- $block := .block -}} {{- $block_class := partial "GetBlockClass" .block -}} - +{{- $is_carousel := false -}} {{- with .block.data -}} {{- $layout := .layout | default "grid" }} <div class="{{ $block_class }}"> @@ -13,7 +13,24 @@ )}} {{- if eq $layout "carousel" -}} - {{ partial "blocks/templates/gallery/carousel" . }} + {{ if gt (len .images) 1 }} + {{- $is_carousel = true -}} + {{ end }} + + {{- if $is_carousel }} + {{ partial "blocks/templates/carousel.html" (dict + "content" .images + "options" site.Params.blocks.gallery.carousel + "partial" "blocks/templates/gallery/carousel-image.html" + )}} + {{ else }} + {{ range .images }} + {{ partial "blocks/templates/gallery/carousel-image.html" (dict + "is_carousel" false + "params" . + )}} + {{ end }} + {{ end -}} {{- else if eq $layout "large" -}} {{ partial "blocks/templates/gallery/large" . }} {{- else -}} @@ -22,4 +39,4 @@ </div> </div> </div> -{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/layouts/partials/blocks/templates/gallery/carousel-image.html b/layouts/partials/blocks/templates/gallery/carousel-image.html new file mode 100644 index 0000000000000000000000000000000000000000..bdc9ad857ae625b1f39283a010e5ebee2e1464e8 --- /dev/null +++ b/layouts/partials/blocks/templates/gallery/carousel-image.html @@ -0,0 +1,43 @@ +{{ $is_carousel := .is_carousel }} +{{ $index := .index }} +{{ $role := .role }} +{{ with .params }} + {{ if .file }} + {{- $image := partial "GetMedia" .file -}} + {{- if $image -}} + <figure {{ if $is_carousel }} id="carousel-item-{{$index}}" role="{{$role}}" aria-roledescription="slide" class="carousel__slide" aria-label="item-{{$index}}" {{ end }}> + {{ partial "commons/image.html" + (dict + "image" .id + "alt" .alt + "sizes" site.Params.image_sizes.blocks.gallery.carousel + )}} + {{ if not site.Params.image_sizes.design_system.lightbox.disabled }} + {{ $lightbox_text := false }} + {{ if and .text .credit }} + {{ $lightbox_text = delimit (slice .text .credit) " / " }} + {{ else }} + {{ $lightbox_text = or .text .credit }} + {{ end }} + <a class="glightbox" + role="button" + data-glightbox="type: image;{{ with $lightbox_text }}description: {{ partial "PrepareHTML" . }}{{ end }}" + href="{{ partial "GetLightboxUrl" (dict "id" .id) }}" + title="{{- i18n "commons.lightbox.link.title" -}}" + aria-label="{{- i18n "commons.lightbox.link.title" -}}"> + </a> + {{ end }} + {{ if or .text .credit }} + <figcaption> + {{ with .text }} + <p>{{ . | safeHTML }}</p> + {{ end }} + {{ with .credit }} + <div class="credit">{{ . | safeHTML }}</div> + {{ end }} + </figcaption> + {{ end }} + </figure> + {{- end -}} + {{ end }} +{{ end }} \ No newline at end of file diff --git a/layouts/partials/blocks/templates/gallery/carousel.html b/layouts/partials/blocks/templates/gallery/carousel.html deleted file mode 100644 index 0c472729dce6f6e60cab08147a476887d3266fba..0000000000000000000000000000000000000000 --- a/layouts/partials/blocks/templates/gallery/carousel.html +++ /dev/null @@ -1,57 +0,0 @@ -{{- $is_carousel := false -}} -{{ if gt (len .images) 1 }} - {{- $is_carousel = true -}} -{{ end }} - -{{- if $is_carousel }} -<div class="splide" data-splide="{{ site.Params.blocks.gallery.splide | encoding.Jsonify }}"> - <div class="splide__track"> - <div class="splide__list"> -{{ end -}} - - {{ range .images }} - {{ if .file }} - {{- $image := partial "GetMedia" .file -}} - {{- if $image -}} - <figure {{ if $is_carousel }} class="splide__slide"{{ end }}> - {{ partial "commons/image.html" - (dict - "image" .id - "alt" .alt - "sizes" site.Params.image_sizes.blocks.gallery.carousel - )}} - {{ if not site.Params.image_sizes.design_system.lightbox.disabled }} - {{ $lightbox_text := false }} - {{ if and .text .credit }} - {{ $lightbox_text = delimit (slice .text .credit) " / " }} - {{ else }} - {{ $lightbox_text = or .text .credit }} - {{ end }} - <a class="glightbox" - role="button" - data-glightbox="type: image;{{ with $lightbox_text }}description: {{ partial "PrepareHTML" . }}{{ end }}" - href="{{ partial "GetLightboxUrl" (dict "id" .id) }}" - title="{{- i18n "commons.lightbox.link.title" -}}" - aria-label="{{- i18n "commons.lightbox.link.title" -}}"> - </a> - {{ end }} - {{ if or .text .credit }} - <figcaption> - {{ with .text }} - <p>{{ . | safeHTML }}</p> - {{ end }} - {{ with .credit }} - <div class="credit">{{ . | safeHTML }}</div> - {{ end }} - </figcaption> - {{ end }} - </figure> - {{- end -}} - {{ end }} - {{ end }} - -{{- if $is_carousel }} - </div> - </div> -</div> -{{ end -}} diff --git a/layouts/partials/blocks/templates/posts/carousel.html b/layouts/partials/blocks/templates/posts/carousel.html index aa5376305a7403db3e5102d273bcc85f84d4e39a..9fca8bd25abcfcc557c4b42a307ec9ce8079ea7e 100644 --- a/layouts/partials/blocks/templates/posts/carousel.html +++ b/layouts/partials/blocks/templates/posts/carousel.html @@ -1,26 +1,16 @@ {{ $heading_level := .heading_level | default 3 }} {{ $heading := printf "h%d" $heading_level }} +{{ $heading_tag := partial "GetHeadingTag" (dict + "level" .block.ranks.children + "attributes" "class='title'" +)}} {{ $options := .options }} +{{ $template := printf "posts/post.html" }} -<div class="carousel draggable-container"> - <div class="carousel-posts draggable-content"> - <ul class="posts"> - {{ range $post := .posts -}} - {{ with site.GetPage (printf "/posts/%s" $post) }} - <li class="draggable-item"> - {{ partial "posts/post.html" (dict - "post" . - "options" $options - "heading" $heading) }} - </li> - {{ end }} - {{ end }} - </ul> - {{ if (gt (len .posts) 0) }} - <div class="actions-arrows"> - <button class="previous" disabled title="{{ i18n "blocks.timeline.previous"}}"></button> - <button class="next" title="{{ i18n "blocks.timeline.next"}}"></button> - </div> - {{ end }} - </div> -</div> +{{ partial "blocks/templates/carousel.html" (dict + "content" .posts + "options" site.Params.blocks.posts.carousel + "partial" $template + "heading_tag" $heading_tag + "block_options" $options +)}} diff --git a/layouts/partials/blocks/templates/testimonials.html b/layouts/partials/blocks/templates/testimonials.html index 37d373454aadc7612944318543abbff430906f94..e12eada0562193d8e4e1f6cab4e7c4a25db29d74 100644 --- a/layouts/partials/blocks/templates/testimonials.html +++ b/layouts/partials/blocks/templates/testimonials.html @@ -6,74 +6,35 @@ {{ if .testimonials }} {{ if gt (len .testimonials) 1 }} {{- $is_carousel = true -}} - {{ end }} + {{ end -}} {{ end }} - <div class="{{ $block_class }}{{ if $is_carousel }} with-carousel{{ end }}"> - <div class="container"> - <div class="block-content"> - {{ partial "blocks/top.html" (dict - "title" $block.title - "heading_level" $block.ranks.self - "hidden" true - )}} + +<div class="{{ $block_class }}{{ if $is_carousel }} with-carousel{{ end }}"> + <div class="container"> + <div class="block-content"> + {{ partial "blocks/top.html" (dict + "title" $block.title + "heading_level" $block.ranks.self + "hidden" true + )}} - <div class="testimonials"> - {{- if $is_carousel }} - <div class="splide" - data-splide="{{ site.Params.blocks.testimonials.splide | encoding.Jsonify }}"> - <div class="splide__slider"> - <div class="splide__track"> - <div class="splide__list"> - {{ end -}} - - {{ range .testimonials }} - {{ $is_long := gt (len .text) 150 }} - <figure class="{{ if $is_carousel }}splide__slide{{ end }} {{ if .photo }}with-picture{{ end }}"> - <blockquote {{- if $is_long }} class="is-long" {{- end }}> - <p>{{- partial "PrepareHTML" .text -}}</p> - </blockquote> - {{ if or .photo .author .job -}} - <figcaption> - {{ if .photo -}} - <div class="avatar"> - {{- partial "commons/image.html" - (dict - "image" .photo - "alt" .author - "sizes" site.Params.image_sizes.blocks.testimonials - ) -}} - </div> - {{- end }} - {{ if or .author .job -}} - <p> - {{- if .author -}} - <span class="signature">{{ partial "PrepareHTML" .author }}</span> - {{- end }} - {{- if .job -}} - <span class="meta">{{- partial "PrepareHTML" .job -}}</span> - {{- end }} - </p> - {{- end }} - </figcaption> - {{ end }} - </figure> + <div class="testimonials"> + {{- if $is_carousel }} + {{ partial "blocks/templates/carousel.html" (dict + "content" .testimonials + "options" site.Params.blocks.testimonials.carousel + "partial" "blocks/templates/testimonials/single.html" + )}} + {{ else }} + {{ range .testimonials}} + {{ partial "blocks/templates/testimonials/single.html" (dict + "is_carousel" false + "params" . + )}} {{ end }} - - {{- if $is_carousel }} - </div> - </div> - </div> - - <button class="splide__toggle"> - <span class="splide__toggle__play"></span> - <span class="splide__toggle__pause"></span> - </button> - </div> - {{ end -}} - - </div> - + {{ end }} </div> </div> </div> -{{- end -}} +</div> +{{- end -}} \ No newline at end of file diff --git a/layouts/partials/blocks/templates/testimonials/single.html b/layouts/partials/blocks/templates/testimonials/single.html new file mode 100644 index 0000000000000000000000000000000000000000..78413b78b25ba70fec953fcaa7a5f4409a422e73 --- /dev/null +++ b/layouts/partials/blocks/templates/testimonials/single.html @@ -0,0 +1,31 @@ +<figure {{- if .is_carousel }} id="carousel-item-{{.index}}" role="{{.role}}" aria-roledescription="slide" class="carousel__slide" aria-label="{{.index}} / {{ .total }}" {{ end }} class="{{ if .is_carousel }}carousel__slide{{ end }} {{ if .params.photo }}with-picture{{ end }}"> + {{ with .params }} + {{ $is_long := gt (len .text) 150 }} + <blockquote {{- if $is_long }} class="is-long" {{- end }}> + <p>{{- partial "PrepareHTML" .text -}}</p> + </blockquote> + {{ if or .photo .author .job -}} + <figcaption> + {{ if .photo -}} + <div class="avatar"> + {{- partial "commons/image.html" + (dict + "image" .photo + "sizes" site.Params.image_sizes.blocks.testimonials + ) -}} + </div> + {{- end }} + {{ if or .author .job -}} + <p> + {{- if .author -}} + <span class="signature">{{ partial "PrepareHTML" .author }}</span> + {{- end }} + {{- if .job -}} + <span class="meta">{{- partial "PrepareHTML" .job -}}</span> + {{- end }} + </p> + {{- end }} + </figcaption> + {{ end }} + {{ end }} +</figure> \ No newline at end of file diff --git a/layouts/partials/blocks/templates/timeline.html b/layouts/partials/blocks/templates/timeline.html index a26afb1f4950e7d83a2d6099467db11884780001..86774dec3bff9b87ca75960f73bef6cc56604781 100644 --- a/layouts/partials/blocks/templates/timeline.html +++ b/layouts/partials/blocks/templates/timeline.html @@ -10,9 +10,24 @@ "heading_level" $block.ranks.self )}} {{ $template := printf "blocks/templates/timeline/%s.html" $layout }} - {{ partial $template (dict - "block" $block - ) }} + {{ if eq $layout "horizontal" }} + {{- $heading_tag := partial "GetHeadingTag" (dict + "level" .block.ranks.children + "attributes" "class='title' itemprop='name'" + ) -}} + {{ with .block.data }} + {{ partial "blocks/templates/carousel.html" (dict + "content" .events + "options" site.Params.blocks.timeline.carousel + "partial" $template + "heading_tag" $heading_tag + )}} + {{ end }} + {{ else }} + {{ partial $template (dict + "block" $block + ) }} + {{ end }} </div> </div> </div> diff --git a/layouts/partials/blocks/templates/timeline/horizontal.html b/layouts/partials/blocks/templates/timeline/horizontal.html index f01f6a60a07b1f03aa4858cce20e5d0dd9165299..6dd09cb6dc88f81bc3235bb5fa86d824416aee8d 100644 --- a/layouts/partials/blocks/templates/timeline/horizontal.html +++ b/layouts/partials/blocks/templates/timeline/horizontal.html @@ -1,29 +1,13 @@ +{{ $heading_tag := .heading_tag }} +{{ $index := .index }} +{{ $role := .role }} -{{- $heading_tag := partial "GetHeadingTag" (dict - "level" .block.ranks.children - "attributes" "class='title'" - ) -}} - -<div class="timeline draggable-container"> - {{ with .block.data }} - <div class="timeline-events draggable-content"> - <ol> - {{ range .events }} - <li class="timeline-event draggable-item"> - {{ $heading_tag.open -}} - {{ .title | safeHTML }} - {{ $heading_tag.close -}} - <div class="line"></div> - <div class="description text">{{- partial "PrepareHTML" .text | markdownify -}}</div> - </li> - {{ end }} - </ol> - {{ if (gt (len .events) 0) }} - <div class="actions-arrows"> - <button class="previous" disabled title="{{ i18n "blocks.timeline.previous"}}"></button> - <button class="next" title="{{ i18n "blocks.timeline.next"}}"></button> - </div> - {{ end }} - </div> - {{ end }} -</div> +{{ with .params }} + <article class="timeline-event carousel__slide" id="carousel-item-{{$index}}" role="{{$role}}" aria-roledescription="slide" class="carousel__slide" aria-label="item-{{$index}}" itemscope itemtype="https://schema.org/Article"> + {{ $heading_tag.open -}} + {{ .title | safeHTML }} + {{ $heading_tag.close -}} + <div class="line"></div> + <div class="description text" itemprop="text">{{- partial "PrepareHTML" .text | markdownify -}}</div> + </article> +{{ end }} \ No newline at end of file diff --git a/layouts/partials/blocks/templates/timeline/vertical.html b/layouts/partials/blocks/templates/timeline/vertical.html index 1abf2727b8f18bf93d268dc7f7c57a21db7d3709..fc0c05cbe05cde51fd4c589f39171a0f3a4bb0ec 100644 --- a/layouts/partials/blocks/templates/timeline/vertical.html +++ b/layouts/partials/blocks/templates/timeline/vertical.html @@ -1,20 +1,20 @@ {{- $heading_tag := partial "GetHeadingTag" (dict "level" .block.ranks.children - "attributes" "class='title'" + "attributes" "class='title' itemprop='name'" ) -}} {{ with .block.data -}} - <div class="timeline-events"> + <div class="timeline-events" > {{ range .events -}} - <article class="timeline-event"> + <article class="timeline-event" itemscope itemtype="https://schema.org/Article"> {{ with .title }} {{ $heading_tag.open -}} {{ . | safeHTML }} {{ $heading_tag.close -}} {{ end }} {{ with .text }} - <p>{{ . | safeHTML }}</p> + <p itemprop="text">{{ . | safeHTML }}</p> {{ end }} </article> {{ end -}} diff --git a/layouts/partials/footer/js.html b/layouts/partials/footer/js.html index 5c5ee8e6eb2522c24f9f45542e452105182ee3ae..31c83e3aea0d81ff8bc57cbaff57005f4ec02d81 100644 --- a/layouts/partials/footer/js.html +++ b/layouts/partials/footer/js.html @@ -1,5 +1,5 @@ {{ $isLeafletNeeded := false }} -{{ $isSplideNeed := false }} +{{ $isCarouselNeeded := false }} {{ if .Params.contents }} {{ range .Params.contents }} @@ -14,12 +14,12 @@ {{ if eq .template "gallery"}} {{ with .data }} {{ if eq .layout "carousel" }} - {{ $isSplideNeed = true }} + {{ $isCarouselNeeded = true }} {{ end }} {{ end }} {{ end }} {{ if eq .template "testimonials"}} - {{ $isSplideNeed = true }} + {{ $isCarouselNeeded = true }} {{ end }} {{ end }} {{ end }} @@ -29,11 +29,6 @@ {{ $isLeafletNeeded = true }} {{ end }} -{{ if $isSplideNeed }} - {{ $splide_js := resources.Get "js/vendors/carousel.js" | js.Build (dict "minify" hugo.IsProduction) | fingerprint }} - <script src="{{ $splide_js.RelPermalink }}" integrity="{{ $splide_js.Data.Integrity }}"></script> -{{ end }} - {{ if $isLeafletNeeded }} <!-- CSS --> {{- $cssOpts := (dict diff --git a/layouts/partials/posts/post.html b/layouts/partials/posts/post.html index 96d2a36dee77718e60de5ef74152822ca8d566e8..014afbe268341136786d3a24a7f5bb97d83b2dfc 100644 --- a/layouts/partials/posts/post.html +++ b/layouts/partials/posts/post.html @@ -1,4 +1,8 @@ {{ $post := .post }} +{{ if .params }} + {{ $post = site.GetPage (printf "/posts/%s" .params )}} +{{ end }} + {{ $direction := "" }} {{ $heading := .heading | default "h2" }} {{ $heading_tag := (dict @@ -8,6 +12,9 @@ {{ $index := .index }} {{ $options := .options }} {{ $alternate := .alternate }} +{{ $is_carousel := .is_carousel }} +{{ $index := .index }} +{{ $role := .role }} {{ with $post }} {{ $post_class := "post" }} @@ -19,6 +26,9 @@ {{ $post_class = printf "%s %s" $post_class "without-image" }} {{ end }} + {{ if $is_carousel }} + <li class="carousel__slide" id="carousel-item-{{$index}}" role="{{$role}}" aria-roledescription="slide" aria-label="item-{{$index}}"> + {{ end }} <article class="{{ $post_class }}" itemprop="blogPosts" itemscope itemtype="http://schema.org/BlogPosting"> <div class="post-content"> {{- $title := partial "PrepareHTML" .Title -}} @@ -73,4 +83,7 @@ </div> {{- end -}} </article> + {{ if $is_carousel }} + </li> + {{ end }} {{ end }} \ No newline at end of file