portfolio : galerie horizontale 3 rangées + mockup conditionnel
All checks were successful
Deploy / Deploy to Production (push) Successful in 25s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
isUnknown 2026-03-24 18:53:27 +01:00
parent 133651c35d
commit cb51e050e4
2 changed files with 42 additions and 32 deletions

View file

@ -2,7 +2,7 @@
/** /**
* GalleryAnimation — animation CSS de galerie défilante. * GalleryAnimation — animation CSS de galerie défilante.
* Mode vertical : 3 colonnes (haut/bas) * Mode vertical : 3 colonnes (haut/bas)
* Mode horizontal : 5 rangées (gauche/droite) * Mode horizontal : 3 rangées (gauche/droite)
* @prop {Array<{src: string, srcset: string, webp: string}>} images * @prop {Array<{src: string, srcset: string, webp: string}>} images
* @prop {number} secondsPerImage — durée par image (défaut: 8s) * @prop {number} secondsPerImage — durée par image (défaut: 8s)
* @prop {'vertical'|'horizontal'} mode — direction du défilement * @prop {'vertical'|'horizontal'} mode — direction du défilement
@ -16,10 +16,8 @@
const defs = mode === 'horizontal' const defs = mode === 'horizontal'
? [ ? [
{ offset: 0, delay: 0 }, { offset: 0, delay: 0 },
{ offset: Math.floor(count / 5), delay: duration / 5 }, { offset: Math.floor(count / 3), delay: duration / 3 },
{ offset: Math.floor(2 * count / 5), delay: 2 * duration / 5 }, { offset: 0, delay: 2 * duration / 3 },
{ offset: Math.floor(count / 5), delay: 3 * duration / 5 },
{ offset: 0, delay: 4 * duration / 5 },
] ]
: [ : [
{ offset: 0, delay: 0 }, { offset: 0, delay: 0 },
@ -92,7 +90,7 @@
opacity: .5; opacity: .5;
} }
:global(.gallery-animation__image) { .gallery-animation__image {
display: block; display: block;
object-fit: contain; object-fit: contain;
} }
@ -108,14 +106,14 @@
transform: scale(1.2); transform: scale(1.2);
} }
.gallery-animation--vertical :global(.gallery-animation__column) { .gallery-animation--vertical .gallery-animation__column {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
} }
.gallery-animation--vertical :global(.gallery-animation__track) { .gallery-animation--vertical .gallery-animation__track {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
row-gap: 1rem; row-gap: 1rem;
@ -123,17 +121,17 @@
animation-iteration-count: infinite; animation-iteration-count: infinite;
} }
.gallery-animation--vertical :global(.gallery-animation__column:nth-child(odd) .gallery-animation__track) { .gallery-animation--vertical .gallery-animation__column:nth-child(odd) .gallery-animation__track {
animation-name: galleryScrollDown; animation-name: galleryScrollDown;
animation-duration: var(--gallery-duration); animation-duration: var(--gallery-duration);
} }
.gallery-animation--vertical :global(.gallery-animation__column:nth-child(even) .gallery-animation__track) { .gallery-animation--vertical .gallery-animation__column:nth-child(even) .gallery-animation__track {
animation-name: galleryScrollUp; animation-name: galleryScrollUp;
animation-duration: var(--gallery-duration); animation-duration: var(--gallery-duration);
} }
.gallery-animation--vertical :global(.gallery-animation__image) { .gallery-animation--vertical .gallery-animation__image {
width: 100%; width: 100%;
height: auto; height: auto;
} }
@ -149,48 +147,48 @@
} }
/* ========================================================================== /* ==========================================================================
MODE HORIZONTAL — 5 rangées MODE HORIZONTAL — 3 rangées
========================================================================== */ ========================================================================== */
.gallery-animation--horizontal { .gallery-animation--horizontal {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
transform: scale(1.2); justify-content: space-evenly;
} }
.gallery-animation--horizontal :global(.gallery-animation__column) { .gallery-animation--horizontal .gallery-animation__column {
--inner-height: 100vh;
height: clamp(calc(var(--inner-height) / 5), 20%, calc(var(--inner-height) / 3));
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: stretch; align-items: stretch;
overflow: hidden; overflow: hidden;
} }
.gallery-animation--horizontal :global(.gallery-animation__track) { .gallery-animation--horizontal .gallery-animation__track {
display: flex; display: flex;
flex-direction: row;
align-items: stretch;
height: 100%; height: 100%;
column-gap: 1rem; column-gap: 1.8vh;
animation-timing-function: linear; animation-timing-function: linear;
animation-iteration-count: infinite; animation-iteration-count: infinite;
} }
.gallery-animation--horizontal :global(.gallery-animation__column:nth-child(odd) .gallery-animation__track) { .gallery-animation--horizontal .gallery-animation__column:nth-child(odd) .gallery-animation__track {
animation-name: galleryScrollRight; animation-name: galleryScrollRight;
animation-duration: var(--gallery-duration); animation-duration: var(--gallery-duration);
} }
.gallery-animation--horizontal :global(.gallery-animation__column:nth-child(even) .gallery-animation__track) { .gallery-animation--horizontal .gallery-animation__column:nth-child(even) .gallery-animation__track {
animation-name: galleryScrollLeft; animation-name: galleryScrollLeft;
animation-duration: var(--gallery-duration); animation-duration: var(--gallery-duration);
} }
.gallery-animation--horizontal :global(.gallery-animation__image) { .gallery-animation--horizontal picture {
height: 100%; width: 56vh;
width: auto; }
flex-shrink: 0;
.gallery-animation--horizontal .gallery-animation__image {
width: 100%;
border-radius: 2vh;
overflow: hidden;
} }
@keyframes galleryScrollRight { @keyframes galleryScrollRight {
@ -208,7 +206,7 @@
========================================================================== */ ========================================================================== */
@media (prefers-reduced-motion: reduce) { @media (prefers-reduced-motion: reduce) {
:global(.gallery-animation__track) { .gallery-animation__track {
animation: none; animation: none;
} }
} }

View file

@ -103,7 +103,7 @@
</div> </div>
<!-- Mockup device (centre) --> <!-- Mockup device (centre) -->
<div class="portfolio-mockup"> <div class="portfolio-mockup portfolio-mockup--{currentProject.galleryAnimationMode}">
<ResponsivePicture <ResponsivePicture
src={currentProject.mockup} src={currentProject.mockup}
srcset={currentProject.mockupSrcset} srcset={currentProject.mockupSrcset}
@ -195,13 +195,21 @@
} }
.portfolio-mockup { .portfolio-mockup {
grid-area: 6/7 / span 10 / span 4; grid-area: 6/7 / span 10 / span 5;
z-index: var(--z-content); z-index: var(--z-content);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.portfolio-mockup--horizontal {
grid-area: 6/1 / span 10 / span 7;
}
.portfolio-mockup--horizontal :global(picture) {
transform: scale(1.25);
}
.portfolio-mockup :global(picture), .portfolio-mockup :global(picture),
.portfolio-mockup :global(.portfolio-mockup-img) { .portfolio-mockup :global(.portfolio-mockup-img) {
width: 100%; width: 100%;
@ -397,13 +405,17 @@
z-index: var(--z-content); z-index: var(--z-content);
} }
.portfolio-mockup--vertical {
transform: scale(.8);
}
.portfolio-mockup :global(.portfolio-mockup-img) { .portfolio-mockup :global(.portfolio-mockup-img) {
height: auto; height: auto;
} }
/* Text — over mockup, centered */ /* Text — over mockup, centered */
.portfolio-text { .portfolio-text {
grid-area: 9/4/span 8/span 14; grid-area: 10/4/span 8/span 14;
z-index: var(--z-content); z-index: var(--z-content);
gap: .5rem; gap: .5rem;
text-align: center; text-align: center;
@ -464,8 +476,8 @@
} }
.portfolio-nav-item img { .portfolio-nav-item img {
width: 3.75rem; width: 3rem;
height: 3.75rem; height: 3rem;
} }
.portfolio-nav-number { .portfolio-nav-number {