Explorar el Código

Layout update per il video player

Sviluppo_Carrello_Immagini
Lorenzo Pollutri hace 2 días
padre
commit
0b83447024
Se han modificado 1 ficheros con 61 adiciones y 17 borrados
  1. +61
    -17
      components/PublicGrid.tsx

+ 61
- 17
components/PublicGrid.tsx Ver fichero

@@ -12,9 +12,20 @@ function MediaCarousel({
onMediaClick?: (index: number) => void; onMediaClick?: (index: number) => void;
}) { }) {
const [current, setCurrent] = useState(0); const [current, setCurrent] = useState(0);
const [playing, setPlaying] = useState<Set<number>>(new Set());
const touchStartX = useRef<number | null>(null); const touchStartX = useRef<number | null>(null);
const videoRefs = useRef<Record<number, HTMLVideoElement | null>>({}); const videoRefs = useRef<Record<number, HTMLVideoElement | null>>({});


const markPlaying = (i: number) => setPlaying(p => { const n = new Set(p); n.add(i); return n; });
const markPaused = (i: number) => setPlaying(p => { const n = new Set(p); n.delete(i); return n; });

const togglePlay = (i: number) => {
const v = videoRefs.current[i];
if (!v) return;
if (v.paused) v.play().catch(() => {});
else v.pause();
};

const prev = useCallback(() => setCurrent(i => (i - 1 + items.length) % items.length), [items.length]); const prev = useCallback(() => setCurrent(i => (i - 1 + items.length) % items.length), [items.length]);
const next = useCallback(() => setCurrent(i => (i + 1) % items.length), [items.length]); const next = useCallback(() => setCurrent(i => (i + 1) % items.length), [items.length]);


@@ -70,18 +81,28 @@ function MediaCarousel({
className={`absolute inset-0 transition-opacity duration-300 ${isActive ? 'opacity-100' : 'opacity-0 pointer-events-none'}`} className={`absolute inset-0 transition-opacity duration-300 ${isActive ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
> >
{video ? ( {video ? (
<>
<div
className="relative w-full h-full cursor-pointer"
onClick={(e) => { e.stopPropagation(); togglePlay(i); }}
>
<video <video
ref={el => { videoRefs.current[i] = el; }} ref={el => { videoRefs.current[i] = el; }}
src={item.url} src={item.url}
className="w-full h-full object-contain bg-black"
controls
controlsList="nofullscreen"
disablePictureInPicture
className="w-full h-full object-contain bg-black pointer-events-none"
playsInline playsInline
muted={!!item.autoplay} muted={!!item.autoplay}
preload="metadata" preload="metadata"
onPlay={() => markPlaying(i)}
onPause={() => markPaused(i)}
onEnded={() => markPaused(i)}
/> />
{/* Custom play overlay (shown when paused) */}
{!playing.has(i) && (
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<span className="bg-black/60 text-white w-20 h-20 rounded-full flex items-center justify-center text-4xl shadow-2xl pl-1">▶</span>
</div>
)}
{/* Custom expand button */}
<button <button
onClick={(e) => { e.stopPropagation(); onMediaClick?.(i); }} onClick={(e) => { e.stopPropagation(); onMediaClick?.(i); }}
className="absolute top-3 left-3 bg-black/60 hover:bg-black/80 text-white w-9 h-9 rounded-full flex items-center justify-center transition-colors shadow-lg z-10" className="absolute top-3 left-3 bg-black/60 hover:bg-black/80 text-white w-9 h-9 rounded-full flex items-center justify-center transition-colors shadow-lg z-10"
@@ -92,7 +113,7 @@ function MediaCarousel({
<path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" /> <path d="M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5" />
</svg> </svg>
</button> </button>
</>
</div>
) : ( ) : (
<img <img
src={item.url} src={item.url}
@@ -149,7 +170,19 @@ function FullscreenViewer({
onClose: () => void; onClose: () => void;
}) { }) {
const [current, setCurrent] = useState(startIndex); const [current, setCurrent] = useState(startIndex);
const [playing, setPlaying] = useState<Set<number>>(new Set());
const touchStartX = useRef<number | null>(null); const touchStartX = useRef<number | null>(null);
const videoRefs = useRef<Record<number, HTMLVideoElement | null>>({});

const markPlaying = (i: number) => setPlaying(p => { const n = new Set(p); n.add(i); return n; });
const markPaused = (i: number) => setPlaying(p => { const n = new Set(p); n.delete(i); return n; });

const togglePlay = (i: number) => {
const v = videoRefs.current[i];
if (!v) return;
if (v.paused) v.play().catch(() => {});
else v.pause();
};


const prev = useCallback(() => setCurrent(i => (i - 1 + items.length) % items.length), [items.length]); const prev = useCallback(() => setCurrent(i => (i - 1 + items.length) % items.length), [items.length]);
const next = useCallback(() => setCurrent(i => (i + 1) % items.length), [items.length]); const next = useCallback(() => setCurrent(i => (i + 1) % items.length), [items.length]);
@@ -188,16 +221,27 @@ function FullscreenViewer({
className={`absolute inset-0 flex items-center justify-center p-4 pb-28 transition-opacity duration-200 ${isActive ? 'opacity-100' : 'opacity-0 pointer-events-none'}`} className={`absolute inset-0 flex items-center justify-center p-4 pb-28 transition-opacity duration-200 ${isActive ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
> >
{video ? ( {video ? (
<video
src={item.url}
className="max-w-full max-h-full"
controls
controlsList="nofullscreen"
disablePictureInPicture
playsInline
autoPlay={!!item.autoplay}
muted={!!item.autoplay}
/>
<div
className="relative flex items-center justify-center max-w-full max-h-full cursor-pointer"
onClick={(e) => { e.stopPropagation(); togglePlay(i); }}
>
<video
ref={el => { videoRefs.current[i] = el; }}
src={item.url}
className="max-w-full max-h-full pointer-events-none"
playsInline
autoPlay={!!item.autoplay}
muted={!!item.autoplay}
onPlay={() => markPlaying(i)}
onPause={() => markPaused(i)}
onEnded={() => markPaused(i)}
/>
{!playing.has(i) && (
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
<span className="bg-black/60 text-white w-24 h-24 rounded-full flex items-center justify-center text-5xl shadow-2xl pl-1">▶</span>
</div>
)}
</div>
) : ( ) : (
<img <img
src={item.url} src={item.url}
@@ -304,7 +348,7 @@ export default function PublicGrid({ cards, maxCols = 5 }: { cards: Card[], maxC
<div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-blue-100 to-gray-200 text-gray-400">No Image</div> <div className="absolute inset-0 flex items-center justify-center bg-gradient-to-br from-blue-100 to-gray-200 text-gray-400">No Image</div>
)} )}
{galleryCount > 1 && ( {galleryCount > 1 && (
<div className="absolute top-2 right-2 bg-black/60 text-white text-xs font-semibold px-1.5 py-0.5 rounded-full flex items-center gap-1">
<div className="absolute top-2 left-2 bg-black/60 text-white text-xs font-semibold px-1.5 py-0.5 rounded-full flex items-center gap-1 z-10">
<span>⊞</span> <span>⊞</span>
<span>{galleryCount}</span> <span>{galleryCount}</span>
</div> </div>


Cargando…
Cancelar
Guardar