portfolio : animation horizontale — toggle panel + composant
All checks were successful
Deploy / Deploy to Production (push) Successful in 19s
All checks were successful
Deploy / Deploy to Production (push) Successful in 19s
Ajout du mode horizontal dans GalleryAnimation (5 rangées, scrollLeft/scrollRight) avec toggle vertical/horizontal dans le panel projet. refs #21 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
347ccd33eb
commit
133651c35d
5 changed files with 116 additions and 21 deletions
|
|
@ -103,6 +103,18 @@ columns:
|
|||
uploads:
|
||||
template: image
|
||||
help: Petite image carrée représentant le jeu
|
||||
galleryAnimationMode:
|
||||
label: Mode d'animation de la galerie
|
||||
type: toggles
|
||||
default: vertical
|
||||
options:
|
||||
- value: vertical
|
||||
text: Vertical
|
||||
icon: arrow-up-down
|
||||
- value: horizontal
|
||||
text: Horizontal
|
||||
icon: arrow-left-right
|
||||
help: "Direction du défilement des images dans la galerie animée"
|
||||
galleryBackgroundColor:
|
||||
label: Couleur d'arrière-plan de la galerie animée
|
||||
type: color
|
||||
|
|
|
|||
|
|
@ -5,5 +5,9 @@ panel.plugin("adrienpayet/world-game-icons", {
|
|||
stack:
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M20.0833 10.4999L21.2854 11.2212C21.5221 11.3633 21.5989 11.6704 21.4569 11.9072C21.4146 11.9776 21.3557 12.0365 21.2854 12.0787L11.9999 17.6499L2.71451 12.0787C2.47772 11.9366 2.40093 11.6295 2.54301 11.3927C2.58523 11.3223 2.64413 11.2634 2.71451 11.2212L3.9166 10.4999L11.9999 15.3499L20.0833 10.4999ZM20.0833 15.1999L21.2854 15.9212C21.5221 16.0633 21.5989 16.3704 21.4569 16.6072C21.4146 16.6776 21.3557 16.7365 21.2854 16.7787L12.5144 22.0412C12.1977 22.2313 11.8021 22.2313 11.4854 22.0412L2.71451 16.7787C2.47772 16.6366 2.40093 16.3295 2.54301 16.0927C2.58523 16.0223 2.64413 15.9634 2.71451 15.9212L3.9166 15.1999L11.9999 20.0499L20.0833 15.1999ZM12.5144 1.30864L21.2854 6.5712C21.5221 6.71327 21.5989 7.0204 21.4569 7.25719C21.4146 7.32757 21.3557 7.38647 21.2854 7.42869L11.9999 12.9999L2.71451 7.42869C2.47772 7.28662 2.40093 6.97949 2.54301 6.7427C2.58523 6.67232 2.64413 6.61343 2.71451 6.5712L11.4854 1.30864C11.8021 1.11864 12.1977 1.11864 12.5144 1.30864Z"></path></svg>',
|
||||
blog: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M2 4C2 3.44772 2.44772 3 3 3H21C21.5523 3 22 3.44772 22 4V20C22 20.5523 21.5523 21 21 21H3C2.44772 21 2 20.5523 2 20V4ZM4 5V19H20V5H4ZM6 7H12V13H6V7ZM8 9V11H10V9H8ZM14 9H18V7H14V9ZM18 13H14V11H18V13ZM6 15V17L18 17V15L6 15Z"></path></svg>',
|
||||
"arrow-up-down":
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M11.9498 7.94975L10.5356 9.36396L8.00079 6.828L8.00004 20H6.00004L6.00079 6.828L3.46451 9.36396L2.05029 7.94975L7.00004 3L11.9498 7.94975ZM21.9498 16.0503L17 21L12.0503 16.0503L13.4645 14.636L16.0008 17.172L16 4H18L18.0008 17.172L20.5356 14.636L21.9498 16.0503Z"></path></svg>',
|
||||
"arrow-left-right":
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M16 16V12L21 17L16 22V18H4V16H16ZM8 2V5.999L20 6V8H8V12L3 7L8 2Z"></path></svg>',
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ $specificData = [
|
|||
'mockup' => $project->mockup()->toFile()?->url(),
|
||||
'mockupSrcset' => $project->mockup()->toFile()?->srcset('mockup'),
|
||||
'mockupWebp' => $project->mockup()->toFile()?->srcset('mockup-webp'),
|
||||
'galleryAnimationMode' => $project->galleryAnimationMode()->value() ?: 'vertical',
|
||||
'galleryBackgroundColor' => $project->galleryBackgroundColor()->value(),
|
||||
'galleryBackgroundImage' => $project->galleryBackgroundImage()->isNotEmpty() ? $project->galleryBackgroundImage()->toFile()->url() : null,
|
||||
'keywords' => $project->keywords()->toStructure()->map(fn($i) => [
|
||||
|
|
|
|||
|
|
@ -1,19 +1,32 @@
|
|||
<script>
|
||||
/**
|
||||
* GalleryAnimation — animation CSS de galerie en 3 colonnes défilantes.
|
||||
* GalleryAnimation — animation CSS de galerie défilante.
|
||||
* Mode vertical : 3 colonnes (haut/bas)
|
||||
* Mode horizontal : 5 rangées (gauche/droite)
|
||||
* @prop {Array<{src: string, srcset: string, webp: string}>} images
|
||||
* @prop {number} secondsPerImage — durée par image (défaut: 8s)
|
||||
* @prop {'vertical'|'horizontal'} mode — direction du défilement
|
||||
*/
|
||||
let { images = [], secondsPerImage = 8, backgroundColor = null, backgroundImage = null } = $props()
|
||||
let { images = [], secondsPerImage = 8, backgroundColor = null, backgroundImage = null, mode = 'vertical' } = $props()
|
||||
|
||||
const columns = $derived.by(() => {
|
||||
const count = images.length
|
||||
const duration = count * secondsPerImage
|
||||
const defs = [
|
||||
{ offset: 0, delay: 0 },
|
||||
{ offset: Math.floor(count / 3), delay: duration / 4 },
|
||||
{ offset: 0, delay: duration / 2 },
|
||||
]
|
||||
|
||||
const defs = mode === 'horizontal'
|
||||
? [
|
||||
{ offset: 0, delay: 0 },
|
||||
{ offset: Math.floor(count / 5), delay: duration / 5 },
|
||||
{ offset: Math.floor(2 * count / 5), delay: 2 * duration / 5 },
|
||||
{ offset: Math.floor(count / 5), delay: 3 * duration / 5 },
|
||||
{ offset: 0, delay: 4 * duration / 5 },
|
||||
]
|
||||
: [
|
||||
{ offset: 0, delay: 0 },
|
||||
{ offset: Math.floor(count / 3), delay: duration / 4 },
|
||||
{ offset: 0, delay: duration / 2 },
|
||||
]
|
||||
|
||||
return defs.map(({ offset, delay }) => ({
|
||||
images: shiftImages(images, offset),
|
||||
delay,
|
||||
|
|
@ -28,7 +41,7 @@
|
|||
</script>
|
||||
|
||||
<div
|
||||
class="gallery-animation gallery-animation--vertical"
|
||||
class="gallery-animation gallery-animation--{mode}"
|
||||
style="--gallery-duration: {columns[0]?.duration ?? 24}s{backgroundColor ? `; --background-color: ${backgroundColor}` : ''}{backgroundImage ? `; --gallery-background-image: url(${backgroundImage})` : ''}"
|
||||
>
|
||||
<div class="gallery-animation__overlay"></div>
|
||||
|
|
@ -72,7 +85,22 @@
|
|||
opacity: .8;
|
||||
}
|
||||
|
||||
/* Vertical mode (Portfolio) */
|
||||
.gallery-animation__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: #000;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
:global(.gallery-animation__image) {
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
MODE VERTICAL — 3 colonnes
|
||||
========================================================================== */
|
||||
|
||||
.gallery-animation--vertical {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
@ -105,18 +133,9 @@
|
|||
animation-duration: var(--gallery-duration);
|
||||
}
|
||||
|
||||
.gallery-animation__overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: #000;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
:global(.gallery-animation__image) {
|
||||
.gallery-animation--vertical :global(.gallery-animation__image) {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
@keyframes galleryScrollDown {
|
||||
|
|
@ -129,6 +148,65 @@
|
|||
to { transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
MODE HORIZONTAL — 5 rangées
|
||||
========================================================================== */
|
||||
|
||||
.gallery-animation--horizontal {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.gallery-animation--horizontal :global(.gallery-animation__column) {
|
||||
--inner-height: 100vh;
|
||||
height: clamp(calc(var(--inner-height) / 5), 20%, calc(var(--inner-height) / 3));
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gallery-animation--horizontal :global(.gallery-animation__track) {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: stretch;
|
||||
height: 100%;
|
||||
column-gap: 1rem;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.gallery-animation--horizontal :global(.gallery-animation__column:nth-child(odd) .gallery-animation__track) {
|
||||
animation-name: galleryScrollRight;
|
||||
animation-duration: var(--gallery-duration);
|
||||
}
|
||||
|
||||
.gallery-animation--horizontal :global(.gallery-animation__column:nth-child(even) .gallery-animation__track) {
|
||||
animation-name: galleryScrollLeft;
|
||||
animation-duration: var(--gallery-duration);
|
||||
}
|
||||
|
||||
.gallery-animation--horizontal :global(.gallery-animation__image) {
|
||||
height: 100%;
|
||||
width: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@keyframes galleryScrollRight {
|
||||
from { transform: translateX(-50%); }
|
||||
to { transform: translateX(0); }
|
||||
}
|
||||
|
||||
@keyframes galleryScrollLeft {
|
||||
from { transform: translateX(0); }
|
||||
to { transform: translateX(-50%); }
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
REDUCED MOTION
|
||||
========================================================================== */
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
:global(.gallery-animation__track) {
|
||||
animation: none;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@
|
|||
</script>
|
||||
|
||||
<div class="portfolio-gallery mobile-only" aria-hidden="true">
|
||||
<GalleryAnimation images={currentProject.imagesGallery} backgroundColor={currentProject.galleryBackgroundColor} backgroundImage={currentProject.galleryBackgroundImage} />
|
||||
<GalleryAnimation images={currentProject.imagesGallery} backgroundColor={currentProject.galleryBackgroundColor} backgroundImage={currentProject.galleryBackgroundImage} mode={currentProject.galleryAnimationMode} />
|
||||
</div>
|
||||
|
||||
<section
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
{#if currentProject}
|
||||
<!-- Galerie animation (gauche desktop / plein écran mobile) -->
|
||||
<div class="portfolio-gallery desktop-only" aria-hidden="true">
|
||||
<GalleryAnimation images={currentProject.imagesGallery} backgroundColor={currentProject.galleryBackgroundColor} backgroundImage={currentProject.galleryBackgroundImage} />
|
||||
<GalleryAnimation images={currentProject.imagesGallery} backgroundColor={currentProject.galleryBackgroundColor} backgroundImage={currentProject.galleryBackgroundImage} mode={currentProject.galleryAnimationMode} />
|
||||
</div>
|
||||
|
||||
<!-- Mockup device (centre) -->
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue