Thème Paris.fr
@cImg permet de générer des éléments img avec un texte alternatif et une description optionnelle pour l'accessibilité
Paris map.
<@cImg src='images/pexels-picjumbocom-196645.jpg' class='img-fluid p-4' alt='Sketch for new website' title='Sketch for new website' />
<@cImg src='images/carte.png' alt='Paris map' labelDescribedBy='Paris map.' showLabelDescribedBy=true />
<img src="images/pexels-picjumbocom-196645.jpg" alt="Sketch for new website" title="Sketch for new website" class="img-fluid p-4" id="sketch_for_new_website">
<img src="images/carte.png" alt="Paris map" title="" class="img-fluid" aria-descridedby="descridedby_paris_map" id="paris_map">
<p id="descridedby_paris_map">Paris map.</p>
Génère un élément img HTML avec une mise en forme responsive et une description accessible optionnelle. Prend en charge aria-describedby pour une accessibilité renforcée sur les pages skin.
La macro @cImg est conçue pour créer des images responsives dotées de fonctionnalités d'accessibilité. Elle permet de spécifier une source d'image, un texte alternatif et une description optionnelle qui peut être masquée visuellement ou affichée pour les lecteurs d'écran.
Le paramètre "alt" est désormais obligatoire !
@cFigure permet de générer des éléments figure HTML5 avec un texte alternatif et une description optionnelle pour l'accessibilité
<@cFigure caption='City hall at sunset'>
<@cImg src='images/city-hall.jpg' alt='City hall' />
</@cFigure>
<@cFigure class='figure text-center'>
<@cImg src='images/banner.jpg' alt='Welcome banner' />
</@cFigure>
<figure class="figure">
<img src="images/image-filter-map-01.png" alt="Kiosk" title="" class="img-fluid w-25" id="kiosk">
<figcaption class="figure-caption">kiosk in a small parc</figcaption>
</figure>
<figure class="figure text-center">
<img src="images/banner_v.jpg" alt="Welcome banner" title="" class="img-fluid" id="welcome_banner">
</figure>
Génère un élément figure HTML avec une légende optionnelle. Encapsule des images ou des illustrations dans un conteneur sémantique sur les pages skin.
@cPicture permet de générer des éléments picture HTML5 avec des sources d'image responsives et un texte alternatif pour l'accessibilité
<@cPicture>
<@cPictureSrc srcset='images/banner_v-large.webp' media='(min-width: 768px)' type='image/webp' />
<@cPictureSrc srcset='images/banner_v-small.webp' type='image/webp' />
<@cImg src='images/banner_v.jpg' alt='Welcome banner' />
</@cPicture>
<picture>
<source srcset="images/banner_large.webp" media="(min-width: 768px)" type="image/webp">
<source srcset="images/banner_small.webp" type="image/webp">
<img src="images/banner_v.jpg" alt="Welcome banner" title="" class="img-fluid" id="welcome_banner">
</picture>
Génère un élément picture HTML pour le rendu d'images responsives. Encapsule des éléments source et img afin de servir différentes images selon les media queries.
La macro cCarousel permet de générer un carrousel d'images ou de vidéos avec des contrôles de navigation, une pagination et des boutons lecture/pause optionnels.
<@cTitle level=4>Example 1</@cTitle>
<@cCarousel id='manege1' items='' labelPrev='' labelNext=''>
<@cCarouselItem img='images/alexander-kagan-t9Td0zfDTwI-unsplash.png' active=true title='Chance' />
<@cCarouselItem img='images/adrien-xplr-wAScP0OY-yM-unsplash.png' title='Does it well' subtitle='But not only...' />
<@cCarouselItem img='images/paul-dufour-5XndD3FhH-w-unsplash.png' title='Things' />
</@cCarousel>
<@cTitle level=4>Example 2</@cTitle>
<@cCarousel id='manege2' items='' controls=true labelPrev='' labelNext=''>
<@cCarouselItem img='images/paul-dufour-5XndD3FhH-w-unsplash.png' active=true title='Chance' />
<@cCarouselItem img='images/adrien-xplr-wAScP0OY-yM-unsplash.png' title='Does it well' subtitle='But not only...' />
<@cCarouselItem img='images/alexander-kagan-t9Td0zfDTwI-unsplash.png' title='Things' />
</@cCarousel>
<@cTitle level=4>Example 3</@cTitle>
<@cCarousel id='manege3' items='' controls=true pagination=true indicatorSize=3 labelPrev='' labelNext=''>
<@cCarouselItem img='images/adrien-xplr-wAScP0OY-yM-unsplash.png' active=true title='Chance' />
<@cCarouselItem img='images/alexander-kagan-t9Td0zfDTwI-unsplash.png' title='Does it well' subtitle='But not only...' />
<@cCarouselItem img='images/paul-dufour-5XndD3FhH-w-unsplash.png' title='Things' />
</@cCarousel>
<@cTitle level=4>Example 4</@cTitle>
<@cCarousel id='manege4' items='' slideControls=true labelPrev='' labelNext=''>
<@cCarouselItem img='images/adrien-xplr-wAScP0OY-yM-unsplash.png' active=true title='Chance' />
<@cCarouselItem img='images/paul-dufour-5XndD3FhH-w-unsplash.png' title='Does it well' subtitle='But not only...' />
<@cCarouselItem img='images/alexander-kagan-t9Td0zfDTwI-unsplash.png' title='Things' />
</@cCarousel>
<h4>
Example 1</h4>
<div id="manege1" class="carousel slide carousel-themed show-neighbors" data-bs-ride="carousel" aria-roledescription="carousel" aria-label="Carousel">
<div class="carousel-inner">
<div class="carousel-item active" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/alexander-kagan-t9Td0zfDTwI-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Chance</h3>
<p></p>
</div>
</div>
</div>
<div class="carousel-item" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/adrien-xplr-wAScP0OY-yM-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Does it well</h3>
<p>But not only...</p>
</div>
</div>
</div>
<div class="carousel-item" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/paul-dufour-5XndD3FhH-w-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Things</h3>
<p></p>
</div>
</div>
</div>
</div>
</div>
<script type="module" src="themes/skin/parisfr/js//modules/theme-carousel.js"></script>
<h4>
Example 2</h4>
<div id="manege2" class="carousel slide carousel-themed show-neighbors" data-bs-ride="carousel" aria-roledescription="carousel" aria-label="Carousel">
<div class="carousel-inner">
<div class="carousel-item active" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/paul-dufour-5XndD3FhH-w-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Chance</h3>
<p></p>
</div>
</div>
</div>
<div class="carousel-item" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/adrien-xplr-wAScP0OY-yM-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Does it well</h3>
<p>But not only...</p>
</div>
</div>
</div>
<div class="carousel-item" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/alexander-kagan-t9Td0zfDTwI-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Things</h3>
<p></p>
</div>
</div>
</div>
</div>
<button class="carousel-control-prev" data-bs-target="#manege2" data-bs-slide="prev" aria-label="élément précédent">
<span class="carousel-bg-control">
<svg class="paris-icon paris-icon-arrow-left decorative" data-mce-svg="paris-icon paris-icon-arrow-left" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-arrow-left"></use>
</svg> <span class="visually-hidden"></span>
</span>
</button>
<button class="carousel-control-next" data-bs-target="#manege2" data-bs-slide="next" aria-label="élément suivant">
<span class="carousel-bg-control">
<svg class="paris-icon paris-icon-arrow-right decorative" data-mce-svg="paris-icon paris-icon-arrow-right" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-arrow-right"></use>
</svg> <span class="visually-hidden"></span>
</span>
</button>
</div>
<script type="module" src="themes/skin/parisfr/js//modules/theme-carousel.js"></script>
<h4>
Example 3</h4>
<div id="manege3" class="carousel slide carousel-themed show-neighbors" data-bs-ride="carousel" aria-roledescription="carousel" aria-label="Carousel">
<ol class="carousel-indicators pagination">
<li class="page-item active" data-bs-target="#manege3" data-bs-slide-to="0" aria-label="Slide 0" aria-selected="false" aria-controls="carousel-item-0" tabindex="0"><span class="page-link">1</span></li>
<li class="page-item" data-bs-target="#manege3" data-bs-slide-to="1" aria-label="Slide 1" aria-selected="false" aria-controls="carousel-item-1" tabindex="0"><span class="page-link">2</span></li>
<li class="page-item" data-bs-target="#manege3" data-bs-slide-to="2" aria-label="Slide 2" aria-selected="false" aria-controls="carousel-item-2" tabindex="0"><span class="page-link">3</span></li>
</ol>
<div class="carousel-inner">
<div class="carousel-item active" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/adrien-xplr-wAScP0OY-yM-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Chance</h3>
<p></p>
</div>
</div>
</div>
<div class="carousel-item" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/alexander-kagan-t9Td0zfDTwI-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Does it well</h3>
<p>But not only...</p>
</div>
</div>
</div>
<div class="carousel-item" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/paul-dufour-5XndD3FhH-w-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Things</h3>
<p></p>
</div>
</div>
</div>
</div>
<button class="carousel-control-prev" data-bs-target="#manege3" data-bs-slide="prev" aria-label="élément précédent">
<span class="carousel-bg-control">
<svg class="paris-icon paris-icon-arrow-left decorative" data-mce-svg="paris-icon paris-icon-arrow-left" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-arrow-left"></use>
</svg> <span class="visually-hidden"></span>
</span>
</button>
<button class="carousel-control-next" data-bs-target="#manege3" data-bs-slide="next" aria-label="élément suivant">
<span class="carousel-bg-control">
<svg class="paris-icon paris-icon-arrow-right decorative" data-mce-svg="paris-icon paris-icon-arrow-right" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-arrow-right"></use>
</svg> <span class="visually-hidden"></span>
</span>
</button>
</div>
<script type="module" src="themes/skin/parisfr/js//modules/theme-carousel.js"></script>
<h4>
Example 4</h4>
<div id="carouselButtons-manege4" class="d-flex justify-content-center py-2">
<button id="playButton-manege4" type="button" class="btn btn-tertiary" size="mini" aria-label="Démarrer la lecture du carrousel">
<svg class="paris-icon paris-icon-play decorative" data-mce-svg="paris-icon paris-icon-play" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-play"></use>
</svg> </button>
<button id="pauseButton-manege4" type="button" class="btn btn-tertiary" size="mini" aria-label="Mettre le carrousel en pause">
<svg class="paris-icon paris-icon-refresh decorative" data-mce-svg="paris-icon paris-icon-refresh" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-refresh"></use>
</svg> </button>
<button id="stopButton-manege4" type="button" class="btn btn-tertiary" size="mini" aria-label="Arrêter le carrousel et revenir à la première diapositive">
<svg class="paris-icon paris-icon-close decorative" data-mce-svg="paris-icon paris-icon-close" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-close"></use>
</svg> </button>
</div>
<div id="manege4" class="carousel slide carousel-themed show-neighbors" data-bs-ride="carousel" aria-roledescription="carousel" aria-label="Carousel">
<div class="carousel-inner">
<div class="carousel-item active" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/adrien-xplr-wAScP0OY-yM-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Chance</h3>
<p></p>
</div>
</div>
</div>
<div class="carousel-item" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/paul-dufour-5XndD3FhH-w-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Does it well</h3>
<p>But not only...</p>
</div>
</div>
</div>
<div class="carousel-item" id="manege-item-1" role="group" aria-roledescription="slide" aria-label="1 of 1">
<div class="item__third">
<img src="images/alexander-kagan-t9Td0zfDTwI-unsplash.png" class="d-block w-100" alt="">
<div class="carousel-caption">
<h3>
Things</h3>
<p></p>
</div>
</div>
</div>
</div>
</div>
<script type="module" src="themes/skin/parisfr/js//modules/theme-carousel.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function (event) {
var carouselElement = document.getElementById('manege4');
var carousel = bootstrap.Carousel.getOrCreateInstance(carouselElement);
document.getElementById('playButton-manege4').addEventListener('click', function () {
carousel.cycle();
});
document.getElementById('pauseButton-manege4').addEventListener('click', function () {
carousel.pause();
});
document.getElementById('stopButton-manege4').addEventListener('click', function () {
carousel.pause();
carousel.to(0);
});
});
</script>
Génère un carrousel d'images ou de vidéos avec des contrôles de navigation, une pagination et des boutons lecture/pause optionnels.
Génère un slider/carrousel horizontal de cartes avec boutons de navigation et lien optionnel "voir tout" pour parcourir du contenu sur les pages du skin.
<#assign mySlides = [
{"content":"Content 1","linkLabel":"Title 1", "img":"images/adrien-xplr-wAScP0OY-yM-unsplash.png", "link":"https://paris.fr"},
{"content":"Content 2", "linkLabel":"Title 2", "img":"images/alexander-kagan-t9Td0zfDTwI-unsplash.png", "link":"https://paris.fr"},
{"content":"Content 3", "linkLabel":"Title 3", "img":"images/paul-dufour-5XndD3FhH-w-unsplash.png", "link":"https://paris.fr"},
{"content":"Content 4", "linkLabel":"Title 4", "img":"images/adrien-xplr-wAScP0OY-yM-unsplash.png", "link":"https://paris.fr"},
{"content":"Content 5", "linkLabel":"Title 5", "img":"images/alexander-kagan-t9Td0zfDTwI-unsplash.png", "link":"https://paris.fr"},
{"content":"Content 6", "linkLabel":"Title 6", "img":"images/paul-dufour-5XndD3FhH-w-unsplash.png", "link":"https://paris.fr"}
]>
<@cSlider id='myslider' sliderLabel='Miscellaneous links' slides=mySlides />
<section class="themeparisfr-slider-wrapper" id="myslider" aria-roledescription="slide" aria-label="Miscellaneous links" data-reload-on-show>
<div class="row themeparisfr-slider row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4" id="myslider-theme-slider" aria-live="off">
<div class="card slide p-0" role="group" aria-roledescription="slide" aria-label="1 sur 6" >
<figure class="card-figure ">
<img src="images/paul-dufour-5XndD3FhH-w-unsplash.png" alt="" title="" class="card-img-top">
</figure>
<div class="card-body ">
<h3 class="card-title">
Title 1</h3>
<p class="card-text">Content 1</p>
</div>
</div>
<div class="card slide p-0" role="group" aria-roledescription="slide" aria-label="2 sur 6" >
<figure class="card-figure ">
<img src="images/adrien-xplr-wAScP0OY-yM-unsplash.png" alt="" title="" class="card-img-top">
</figure>
<div class="card-body ">
<h3 class="card-title">
Title 2</h3>
<p class="card-text">Content 2</p>
</div>
</div>
<div class="card slide p-0" role="group" aria-roledescription="slide" aria-label="3 sur 6" >
<figure class="card-figure ">
<img src="images/alexander-kagan-t9Td0zfDTwI-unsplash.png" alt="" title="" class="card-img-top">
</figure>
<div class="card-body ">
<h3 class="card-title">
Title 3</h3>
<p class="card-text">Content 3</p>
</div>
</div>
<div class="card slide p-0" role="group" aria-roledescription="slide" aria-label="4 sur 6" >
<figure class="card-figure ">
<img src="images/paul-dufour-5XndD3FhH-w-unsplash.png" alt="" title="" class="card-img-top">
</figure>
<div class="card-body ">
<h3 class="card-title">
Title 4</h3>
<p class="card-text">Content 4</p>
</div>
</div>
<div class="card slide p-0" role="group" aria-roledescription="slide" aria-label="5 sur 6" >
<figure class="card-figure ">
<img src="images/adrien-xplr-wAScP0OY-yM-unsplash.png" alt="" title="" class="card-img-top">
</figure>
<div class="card-body ">
<h3 class="card-title">
Title 5</h3>
<p class="card-text">Content 5</p>
</div>
</div>
<div class="card slide p-0" role="group" aria-roledescription="slide" aria-label="6 sur 6" >
<figure class="card-figure ">
<img src="images/alexander-kagan-t9Td0zfDTwI-unsplash.png" alt="" title="" class="card-img-top">
</figure>
<div class="card-body ">
<h3 class="card-title">
Title 6</h3>
<p class="card-text">Content 6</p>
</div>
</div>
</div>
<div class="slider-buttons">
<div class="container ">
<div class="d-flex justify-content-end pt-4 pb-md-5 mb-md-5">
<div class="d-flex align-items-center justify-content-end gap-1 test">
<button class="btn btn-light rounded-circle disabled prev-slide" type="button"tabindex="0" aria-controls="myslider-theme-slider" aria-label="Previous slide">
<svg class="paris-icon paris-icon-arrow-left decorative" data-mce-svg="paris-icon paris-icon-arrow-left" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-arrow-left"></use>
</svg>
</button>
<button class="btn btn-light rounded-circle ms-sm next-slide" type="button"tabindex="0" aria-controls="myslider-theme-slider" aria-label="Next slide">
<svg class="paris-icon paris-icon-arrow-right decorative" data-mce-svg="paris-icon paris-icon-arrow-right" aria-hidden="true" focusable="false" role="img">
<use href="#paris-icon-arrow-right"></use>
</svg>
</button>
</div>
</div>
</div>
</div>
</section>
<script>
document.addEventListener('DOMContentLoaded', function (){
const wrapper = document.getElementById('myslider');
if (!wrapper) return;
const slider = wrapper.querySelector('.themeparisfr-slider');
const btnPrev = wrapper.querySelector('.slider-buttons .prev-slide');
const btnNext = wrapper.querySelector('.slider-buttons .next-slide');
const nbSlides = slider ? slider.querySelectorAll('.slide').length : 0;
if (!slider || !btnPrev || !btnNext || nbSlides <= 1) return;
// Calculate scroll amount based on first slide width
function getScrollAmount() {
const firstSlide = slider.querySelector('.slide');
return firstSlide ? firstSlide.offsetWidth + 16 : 305; // 16 = gap
}
function updateButtons() {
const atStart = slider.scrollLeft <= 1;
const hasOverflow = slider.scrollWidth > slider.clientWidth + 1;
const atEnd = !hasOverflow || (slider.scrollLeft + slider.clientWidth >= slider.scrollWidth - 1);
btnPrev.classList.toggle('disabled', atStart);
btnNext.classList.toggle('disabled', atEnd);
}
function scrollSlider(direction) {
const scrollAmount = getScrollAmount();
const target = slider.scrollLeft + (direction * scrollAmount);
slider.scrollTo({ left: target, behavior: 'smooth' });
}
// Initial state: prev disabled, next enabled (will be updated after layout)
btnPrev.classList.add('disabled');
btnNext.classList.remove('disabled');
// Wait for layout to be complete before checking actual overflow
requestAnimationFrame(function() {
requestAnimationFrame(updateButtons);
});
btnPrev.addEventListener('click', function(e) {
e.preventDefault();
if (!this.classList.contains('disabled')) {
scrollSlider(-1);
}
});
btnNext.addEventListener('click', function(e) {
e.preventDefault();
if (!this.classList.contains('disabled')) {
scrollSlider(1);
}
});
// Update buttons after scroll animation
slider.addEventListener('scroll', function() {
clearTimeout(slider._scrollTimeout);
slider._scrollTimeout = setTimeout(updateButtons, 50);
});
// Keyboard accessibility (spacebar + enter)
[btnPrev, btnNext].forEach(function(btn) {
btn.setAttribute('tabindex', '0');
btn.setAttribute('role', 'button');
btn.removeAttribute('disabled');
btn.addEventListener('keydown', function(event) {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
btn.click();
}
});
});
// Also update when images load (changes scrollWidth)
slider.querySelectorAll('img').forEach(function(img) {
if (!img.complete) {
img.addEventListener('load', updateButtons);
}
});
});
</script>
Génère un slider/carrousel horizontal de cartes avec boutons de navigation et lien optionnel "voir tout" pour parcourir du contenu sur les pages du skin.