diff --git a/docs/assets/trainingify-dashboard-0.9.1.png b/docs/assets/trainingify-dashboard-0.9.1.png new file mode 100644 index 0000000..4acb0ef Binary files /dev/null and b/docs/assets/trainingify-dashboard-0.9.1.png differ diff --git a/docs/assets/trainingify-device-control-0.9.1.png b/docs/assets/trainingify-device-control-0.9.1.png new file mode 100644 index 0000000..5623cda Binary files /dev/null and b/docs/assets/trainingify-device-control-0.9.1.png differ diff --git a/docs/assets/trainingify-super-col-detail-0.9.1.png b/docs/assets/trainingify-super-col-detail-0.9.1.png new file mode 100644 index 0000000..67401d7 Binary files /dev/null and b/docs/assets/trainingify-super-col-detail-0.9.1.png differ diff --git a/docs/assets/trainingify-super-cols-0.9.1.png b/docs/assets/trainingify-super-cols-0.9.1.png new file mode 100644 index 0000000..0753fc9 Binary files /dev/null and b/docs/assets/trainingify-super-cols-0.9.1.png differ diff --git a/docs/assets/trainingify-training-plan-0.9.1.png b/docs/assets/trainingify-training-plan-0.9.1.png new file mode 100644 index 0000000..8ae2bd8 Binary files /dev/null and b/docs/assets/trainingify-training-plan-0.9.1.png differ diff --git a/docs/assets/trainingify-workouts-0.9.1.png b/docs/assets/trainingify-workouts-0.9.1.png new file mode 100644 index 0000000..27ce186 Binary files /dev/null and b/docs/assets/trainingify-workouts-0.9.1.png differ diff --git a/docs/css/site.css b/docs/css/site.css index d331ad2..558fa07 100644 --- a/docs/css/site.css +++ b/docs/css/site.css @@ -871,6 +871,153 @@ a { } /* SCREENSHOTS SECTION */ +.screenshot-carousel { + position: relative; + max-width: 1280px; + margin: 0 auto 48px; +} + +.screenshot-carousel-viewport { + overflow: hidden; + margin: 0; + background: var(--color-bg-alt); + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 14px; + box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28); +} + +.screenshot-carousel-track { + display: flex; + transition: transform 0.45s ease; + will-change: transform; +} + +.carousel-slide { + min-width: 100%; + margin: 0; + display: flex; + flex-direction: column; +} + +.carousel-slide .actual-screenshot-caption { + flex: 1; +} + +.actual-screenshot-frame { + padding: 10px; + background: #07080b; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); +} + +.actual-screenshot-frame img { + display: block; + width: 100%; + height: auto; + border-radius: 8px; +} + +.actual-screenshot-caption { + padding: 22px 24px 24px; +} + +.actual-screenshot-caption h3 { + margin: 12px 0 8px; + font-size: 1.25rem; +} + +.actual-screenshot-caption p { + margin: 0; + color: var(--color-text-muted); + font-size: 0.9rem; + line-height: 1.6; +} + +.carousel-control { + position: absolute; + top: 34%; + z-index: 2; + width: 46px; + height: 46px; + border: 1px solid rgba(255, 255, 255, 0.16); + border-radius: 50%; + background: rgba(10, 11, 15, 0.88); + color: #fff; + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: var(--transition-smooth); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.32); +} + +.carousel-control:hover, +.carousel-control:focus-visible { + background: var(--gradient-orange-red); + border-color: transparent; + transform: scale(1.06); + outline: none; +} + +.carousel-control-prev { + left: -23px; +} + +.carousel-control-next { + right: -23px; +} + +.carousel-footer { + display: flex; + align-items: center; + justify-content: center; + gap: 18px; + margin-top: 18px; +} + +.carousel-dots { + display: flex; + align-items: center; + gap: 8px; +} + +.carousel-dot { + width: 9px; + height: 9px; + padding: 0; + border: 0; + border-radius: 999px; + background: rgba(255, 255, 255, 0.22); + cursor: pointer; + transition: var(--transition-smooth); +} + +.carousel-dot:hover, +.carousel-dot:focus-visible { + background: rgba(255, 255, 255, 0.65); + outline: none; +} + +.carousel-dot.is-active { + width: 28px; + background: var(--gradient-orange-red); +} + +.carousel-counter { + min-width: 42px; + color: var(--color-text-muted); + font-size: 0.78rem; + font-weight: 700; + letter-spacing: 0.06em; +} + +@media (prefers-reduced-motion: reduce) { + .screenshot-carousel-track, + .carousel-control, + .carousel-dot { + transition: none; + } +} + .screenshots-grid { display: flex; justify-content: center; @@ -1553,6 +1700,7 @@ a { flex-direction: column; align-items: center; } + } @media (max-width: 768px) { @@ -1611,4 +1759,22 @@ a { .device-simulator-row { grid-template-columns: 1fr; } + + .carousel-control { + top: 31%; + width: 38px; + height: 38px; + } + + .carousel-control-prev { + left: 10px; + } + + .carousel-control-next { + right: 10px; + } + + .actual-screenshot-caption { + padding: 20px; + } } diff --git a/docs/index.html b/docs/index.html index 7e3b2f3..cfdd2dd 100644 --- a/docs/index.html +++ b/docs/index.html @@ -286,70 +286,91 @@

L'interface au cœur de la - - -
-
- - - - TRAININGIFY DASHBOARD -
-
- -
- SÉANCE ACTIVE : PMA BURST 5x5 - 00:34:12 -
- -
-
- PUISSANCE - 380 - WATTS + + +
diff --git a/docs/js/main.js b/docs/js/main.js index a08c613..ce16a1c 100644 --- a/docs/js/main.js +++ b/docs/js/main.js @@ -251,7 +251,131 @@ document.addEventListener('DOMContentLoaded', () => { }, duration * 1000); } - // 4. SCROLL REVEAL ANIMATIONS (Intersection Observer) + // 4. SCREENSHOT CAROUSEL + const screenshotCarousel = document.querySelector('[data-screenshot-carousel]'); + + if (screenshotCarousel) { + const carouselTrack = screenshotCarousel.querySelector('[data-carousel-track]'); + const carouselSlides = Array.from(screenshotCarousel.querySelectorAll('.carousel-slide')); + const previousButton = screenshotCarousel.querySelector('[data-carousel-prev]'); + const nextButton = screenshotCarousel.querySelector('[data-carousel-next]'); + const dotsContainer = screenshotCarousel.querySelector('[data-carousel-dots]'); + const counter = screenshotCarousel.querySelector('[data-carousel-counter]'); + const reducedMotion = window.matchMedia?.('(prefers-reduced-motion: reduce)').matches ?? false; + + let currentSlide = 0; + let autoPlayTimer = null; + let touchStartX = null; + + carouselSlides.forEach((slide, index) => { + slide.setAttribute('aria-hidden', index === 0 ? 'false' : 'true'); + }); + + const dots = carouselSlides.map((_, index) => { + const dot = document.createElement('button'); + dot.type = 'button'; + dot.className = 'carousel-dot'; + dot.setAttribute('role', 'tab'); + dot.setAttribute('aria-label', `Afficher la capture ${index + 1}`); + dot.addEventListener('click', () => goToSlide(index)); + dotsContainer.appendChild(dot); + return dot; + }); + + function renderCarousel() { + carouselTrack.style.transform = `translateX(-${currentSlide * 100}%)`; + + carouselSlides.forEach((slide, index) => { + const isActive = index === currentSlide; + slide.classList.toggle('is-active', isActive); + slide.setAttribute('aria-hidden', isActive ? 'false' : 'true'); + }); + + dots.forEach((dot, index) => { + const isActive = index === currentSlide; + dot.classList.toggle('is-active', isActive); + dot.setAttribute('aria-selected', isActive ? 'true' : 'false'); + dot.tabIndex = isActive ? 0 : -1; + }); + + if (counter) { + counter.textContent = `${currentSlide + 1} / ${carouselSlides.length}`; + } + } + + function stopAutoPlay() { + if (autoPlayTimer) { + window.clearInterval(autoPlayTimer); + autoPlayTimer = null; + } + } + + function startAutoPlay() { + stopAutoPlay(); + + if (!reducedMotion && carouselSlides.length > 1) { + autoPlayTimer = window.setInterval(() => { + goToSlide(currentSlide + 1, false); + }, 6000); + } + } + + function goToSlide(index, restartAutoPlay = true) { + currentSlide = (index + carouselSlides.length) % carouselSlides.length; + renderCarousel(); + + if (restartAutoPlay) { + startAutoPlay(); + } + } + + previousButton?.addEventListener('click', () => goToSlide(currentSlide - 1)); + nextButton?.addEventListener('click', () => goToSlide(currentSlide + 1)); + + screenshotCarousel.addEventListener('mouseenter', stopAutoPlay); + screenshotCarousel.addEventListener('mouseleave', startAutoPlay); + screenshotCarousel.addEventListener('focusin', stopAutoPlay); + screenshotCarousel.addEventListener('focusout', event => { + if (!screenshotCarousel.contains(event.relatedTarget)) { + startAutoPlay(); + } + }); + + screenshotCarousel.addEventListener('keydown', event => { + if (event.key === 'ArrowLeft') { + event.preventDefault(); + goToSlide(currentSlide - 1); + } else if (event.key === 'ArrowRight') { + event.preventDefault(); + goToSlide(currentSlide + 1); + } + }); + + screenshotCarousel.addEventListener('touchstart', event => { + touchStartX = event.changedTouches[0]?.clientX ?? null; + stopAutoPlay(); + }, { passive: true }); + + screenshotCarousel.addEventListener('touchend', event => { + if (touchStartX === null) return; + + const touchEndX = event.changedTouches[0]?.clientX ?? touchStartX; + const swipeDistance = touchEndX - touchStartX; + + if (Math.abs(swipeDistance) > 45) { + goToSlide(currentSlide + (swipeDistance < 0 ? 1 : -1)); + } else { + startAutoPlay(); + } + + touchStartX = null; + }, { passive: true }); + + renderCarousel(); + startAutoPlay(); + } + + // 5. SCROLL REVEAL ANIMATIONS (Intersection Observer) const revealElements = document.querySelectorAll('.feature-card, .ecosystem-content, .ecosystem-visual, .playground-card, .screenshot-card'); if ('IntersectionObserver' in window && revealElements.length > 0) {