portfolio/components/MobileStack copy.tsx
2026-02-02 12:18:35 +01:00

105 lines
3.6 KiB
TypeScript

"use client";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { ArrowRight } from "lucide-react";
import { MobileFrame } from "./MobileFrame";
export default function MobileStack({ images }: { images: string[] }) {
const [currentIndex, setCurrentIndex] = useState(0);
const DRAG_THRESHOLD = -150;
const getRelativeIndex = (index: number) => {
const len = images.length;
return (index - currentIndex + len) % len;
};
const next = () => setCurrentIndex((prev) => (prev + 1) % images.length);
return (
<div className="relative h-[750px] w-full flex flex-col items-center py-20 overflow-hidden group">
<div className="relative h-[650px] w-full flex justify-center items-center">
<AnimatePresence initial={false}>
{images.map((img, index) => {
const relIndex = getRelativeIndex(index);
const isTop = relIndex === 0;
const xOffset = relIndex * 90;
if (relIndex > 5) return null;
return (
<motion.div
key={img}
style={{ zIndex: images.length - relIndex }}
initial={{ opacity: 0, x: 400 }}
animate={{
opacity: 1,
x: isTop ? 0 : xOffset,
scale: isTop ? 1 : 0.96,
filter: isTop ? "brightness(1)" : "brightness(0.4)",
pointerEvents: isTop ? "auto" : "all",
}}
exit={{
x: -1000,
opacity: 0,
transition: { duration: 0.4, ease: "easeIn" },
}}
transition={{
duration: 0.6,
ease: [0.22, 1, 0.36, 1],
}}
whileHover={
!isTop ? { scale: 0.98, filter: "brightness(0.6)" } : {}
}
drag={isTop ? "x" : false}
dragConstraints={{ left: 0, right: 0 }}
dragElastic={0.8}
onDrag={(_, info) => {
if (isTop && info.offset.x < DRAG_THRESHOLD) {
next();
}
}}
onDragEnd={(_, info) => {
// Backup check for quick flicks
if (isTop && info.offset.x < -100) {
next();
}
}}
onClick={() => !isTop && setCurrentIndex(index)}
className="absolute"
>
<div
className={`${isTop ? "cursor-grab active:cursor-grabbing" : "cursor-pointer"}`}
>
<MobileFrame>
<img
src={img}
alt="App Screenshot"
draggable="false"
className="w-full h-full object-cover select-none"
/>
</MobileFrame>
</div>
</motion.div>
);
})}
</AnimatePresence>
{/* Navigation Button */}
<div className="absolute -bottom-12 z-[100]">
<button
onClick={next}
className="flex items-center gap-3 px-6 py-3 rounded-full bg-black/40 backdrop-blur-xl border border-white/5 text-white hover:bg-white/10 transition-all opacity-0 group-hover:opacity-100 group-hover:translate-y-[-20px]"
>
<span className="text-[10px] font-mono uppercase tracking-[0.2em]">
Next Screen
</span>
<ArrowRight size={16} />
</button>
</div>
</div>
</div>
);
}