fix(ecommerce): zoom-hover del producto revela la imagen completa
El hover-zoom escalaba (transform:scale) la misma <Image> ya recortada por object-cover -- para fotos verticales (ej. figura de acción de pie) eso dejaba partes del producto (la cabeza) fuera del recorte desde el propio render, así que ningún nivel de zoom las mostraba. Se reemplaza por un overlay con background-image usando la foto completa (background-size en un solo valor preserva el aspect ratio real) y background-position siguiendo el cursor, que sí permite recorrer toda la imagen. De paso: las miniaturas ahora cambian la imagen principal también con hover (onMouseEnter), no solo con click. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_012Y4df3Z7odr9Cg8F2nw6uV
This commit is contained in:
1 parent
2fa404fe7b
commit
9ab779e781
1 file changed
+21
-4
@@ -14,6 +14,16 @@ interface HoverZoomOrigin { x: number; y: number }
|
||||
// continua en touch, asi que en mobile simplemente no aparece el efecto,
|
||||
// sin romper nada). Independiente del zoom interactivo del modal
|
||||
// (click -> Dialog con scale/drag), que sigue igual.
|
||||
//
|
||||
// El overlay de hover usa background-image (no transform:scale sobre el
|
||||
// <Image object-cover>) a proposito: escalar la imagen ya recortada por
|
||||
// object-cover nunca iba a revelar las partes recortadas (ej. la cabeza
|
||||
// de una figura de accion en una foto vertical) -- el recorte pasa antes
|
||||
// del zoom, en el propio render. Con background-size en un solo valor
|
||||
// (ancho%, alto en "auto") se preserva el aspect ratio real de la foto
|
||||
// completa, y background-position 0%-100% permite recorrer TODA la
|
||||
// imagen con el cursor, no solo la porcion que object-cover dejaba
|
||||
// visible en reposo.
|
||||
const HOVER_ZOOM_SCALE = 2.2;
|
||||
|
||||
export function ProductGallery({ images, name }: { images: string[]; name: string }) {
|
||||
@@ -57,7 +67,7 @@ export function ProductGallery({ images, name }: { images: string[]; name: strin
|
||||
return (
|
||||
<div className="grid gap-4 lg:grid-cols-[86px_1fr]">
|
||||
<div className="order-2 flex gap-3 overflow-x-auto lg:order-1 lg:flex-col">
|
||||
{images.map((image) => <button type="button" key={image} onClick={() => { setSelected(image); reset(); }} className={`relative aspect-square w-20 shrink-0 overflow-hidden rounded-2xl border-2 ${selected === image ? "border-fuchsia-500" : "border-transparent"}`}><Image src={image} alt="" fill sizes="80px" className="object-cover" /></button>)}
|
||||
{images.map((image) => <button type="button" key={image} onClick={() => { setSelected(image); reset(); }} onMouseEnter={() => { setSelected(image); reset(); }} className={`relative aspect-square w-20 shrink-0 overflow-hidden rounded-2xl border-2 ${selected === image ? "border-fuchsia-500" : "border-transparent"}`}><Image src={image} alt="" fill sizes="80px" className="object-cover" /></button>)}
|
||||
</div>
|
||||
<Dialog open={open} onOpenChange={changeOpen}>
|
||||
<DialogTrigger asChild>
|
||||
@@ -73,10 +83,17 @@ export function ProductGallery({ images, name }: { images: string[]; name: strin
|
||||
fill
|
||||
priority
|
||||
sizes="(max-width: 1024px) 100vw, 50vw"
|
||||
className="object-cover transition-transform duration-150 ease-out"
|
||||
className="object-cover"
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className="pointer-events-none absolute inset-0 bg-slate-50 transition-opacity duration-150 ease-out"
|
||||
style={{
|
||||
transform: `scale(${hoverZoom ? HOVER_ZOOM_SCALE : 1})`,
|
||||
transformOrigin: hoverZoom ? `${hoverZoom.x}% ${hoverZoom.y}%` : "center",
|
||||
opacity: hoverZoom ? 1 : 0,
|
||||
backgroundImage: `url(${selected})`,
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundSize: `${HOVER_ZOOM_SCALE * 100}%`,
|
||||
backgroundPosition: hoverZoom ? `${hoverZoom.x}% ${hoverZoom.y}%` : "center",
|
||||
}}
|
||||
/>
|
||||
<span className="absolute bottom-5 right-5 inline-flex items-center gap-2 rounded-full bg-white px-4 py-2 text-xs font-black shadow-xl"><ZoomIn className="size-4" />Zoom interactivo</span>
|
||||
|
||||
Reference in new issue
Block a user