Files
hotschpotsh/Pottery-website/components/InstagramFeed.tsx
2026-03-23 19:00:17 -05:00

177 lines
6.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useEffect, useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
declare global {
interface Window {
instgrm?: {
Embeds: {
process: () => void;
};
};
}
}
const posts = [
'https://www.instagram.com/p/DSOFijljukL/',
'https://www.instagram.com/p/DSGh7rMjVes/',
'https://www.instagram.com/p/DRIIUECj4f6/',
'https://www.instagram.com/p/DJOvmvcIoo7/',
'https://www.instagram.com/p/DJOu5b7IL4t/',
'https://www.instagram.com/p/DIQnhO0oJgw/',
'https://www.instagram.com/p/DIJUVqbI4EH/',
'https://www.instagram.com/p/DHlvDNyIDRa/',
'https://www.instagram.com/p/DHlub_iojwv/',
'https://www.instagram.com/p/DJOvdVLIZpM/',
];
const InstagramFeed: React.FC = () => {
const [selectedPost, setSelectedPost] = useState<string | null>(null);
// Double the list for seamless infinite marquee scroll
const duplicatedPosts = [...posts, ...posts];
useEffect(() => {
// Process Instagram embeds whenever the component mounts or the lightbox opens
if (window.instgrm) {
window.instgrm.Embeds.process();
} else {
const script = document.createElement('script');
script.src = '//www.instagram.com/embed.js';
script.async = true;
document.body.appendChild(script);
}
}, [selectedPost]);
return (
<>
<section className="py-24 px-6 md:px-12 bg-stone-50 dark:bg-stone-900 overflow-hidden">
<div className="max-w-[1400px] mx-auto">
<span className="block font-body text-xs uppercase tracking-[0.3em] text-stone-400 mb-6">
Follow Along
</span>
<div className="flex items-end justify-between mb-16 px-2">
<h2 className="font-display text-4xl md:text-5xl text-text-main dark:text-white leading-none">
From the Studio
</h2>
<a
href="https://www.instagram.com/knuth.ceramics"
target="_blank"
rel="noopener noreferrer"
className="text-xs font-bold uppercase tracking-widest text-stone-500 hover:text-stone-900 dark:hover:text-white transition-colors"
>
@knuth.ceramics
</a>
</div>
{/* Infinite Carousel */}
<div className="relative group overflow-hidden">
<style>{`
@keyframes marquee {
0% { transform: translateX(0); }
100% { transform: translateX(-${posts.length * 342}px); /* 326px width + 16px gap */ }
}
.animate-marquee {
animation: marquee 50s linear infinite;
}
.animate-marquee:hover {
animation-play-state: paused;
}
`}</style>
<div className="flex gap-4 animate-marquee w-max py-4">
{duplicatedPosts.map((permalink, idx) => (
<div
key={idx}
className="relative flex-shrink-0 w-[326px] overflow-hidden rounded-[8px] group/item cursor-pointer bg-white"
>
{/* Invisible Overlay to capture clicks.
Because iframes block events, we put a div above it.
On hover it reveals a subtle mask to indicate interactivity. */}
<div
className="absolute inset-0 z-10 bg-black/0 group-hover/item:bg-black/50 transition-colors duration-300 flex flex-col items-center justify-center opacity-0 group-hover/item:opacity-100"
onClick={() => setSelectedPost(permalink)}
>
<p className="text-white font-display text-lg px-4 text-center font-bold drop-shadow-md">
View Post
</p>
</div>
{/* The Instagram Embed itself.
By omitting data-instgrm-captioned we hide the caption/hashtags directly. */}
<div className="pointer-events-none">
<blockquote
className="instagram-media"
data-instgrm-permalink={`${permalink}?utm_source=ig_embed&utm_campaign=loading`}
data-instgrm-version="14"
style={{
background: '#FFF',
border: 0,
margin: 0,
maxWidth: '540px',
minWidth: '326px',
padding: 0,
width: '100%',
}}
/>
</div>
</div>
))}
</div>
</div>
</div>
</section>
{/* Lightbox Modal */}
<AnimatePresence>
{selectedPost && (
<motion.div
className="fixed inset-0 bg-black/90 z-50 flex items-center justify-center p-4 overflow-y-auto pt-[100px]"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={() => setSelectedPost(null)}
>
<motion.div
className="relative max-w-lg w-full bg-white dark:bg-stone-900 rounded-xl overflow-hidden my-auto"
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.9, opacity: 0 }}
transition={{ type: 'spring', damping: 25, stiffness: 300 }}
onClick={(e) => e.stopPropagation()}
>
{/* Close button inside modal container */}
<button
className="absolute top-2 right-2 text-stone-500 bg-white border border-stone-200 shadow-md rounded-full w-8 h-8 flex items-center justify-center hover:bg-stone-100 transition-colors z-[60]"
onClick={() => setSelectedPost(null)}
>
<span className="font-bold">×</span>
</button>
{/* Instagram Embed WITH caption shown in the Lightbox */}
<div className="w-full bg-white mt-12 pb-4 px-2">
<blockquote
className="instagram-media"
data-instgrm-captioned
data-instgrm-permalink={`${selectedPost}?utm_source=ig_embed&utm_campaign=loading`}
data-instgrm-version="14"
style={{
background: '#FFF',
border: 0,
boxShadow: 'none',
margin: '0',
maxWidth: '540px',
minWidth: '326px',
padding: 0,
width: '100%',
}}
/>
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</>
);
};
export default InstagramFeed;