Refactor showcase cards to use absolute grid overlay expansion system
This commit is contained in:
parent
a1626a5c20
commit
9646309a0a
@ -100,8 +100,13 @@ const TwitterEmbed: React.FC<{ url: string }> = ({ url }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ── Collapsible Video Description Component ──
|
// ── Collapsible Video Description Component ──
|
||||||
const VideoDescription: React.FC<{ text: string }> = ({ text }) => {
|
interface VideoDescriptionProps {
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
text: string;
|
||||||
|
isExpanded: boolean;
|
||||||
|
onToggleExpand: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VideoDescription: React.FC<VideoDescriptionProps> = ({ text, isExpanded, onToggleExpand }) => {
|
||||||
const shouldCollapse = text.length > 180 || text.includes('\n');
|
const shouldCollapse = text.length > 180 || text.includes('\n');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -118,7 +123,7 @@ const VideoDescription: React.FC<{ text: string }> = ({ text }) => {
|
|||||||
<button
|
<button
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsExpanded(!isExpanded);
|
onToggleExpand();
|
||||||
}}
|
}}
|
||||||
className="inline-flex items-center text-[10px] font-black uppercase tracking-wider text-blue-600 hover:text-blue-800 transition-colors focus:outline-none cursor-pointer"
|
className="inline-flex items-center text-[10px] font-black uppercase tracking-wider text-blue-600 hover:text-blue-800 transition-colors focus:outline-none cursor-pointer"
|
||||||
>
|
>
|
||||||
@ -133,6 +138,7 @@ export const ShowcasePage: React.FC = () => {
|
|||||||
const [items, setItems] = useState<ContentShowcase[]>([]);
|
const [items, setItems] = useState<ContentShowcase[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [playingVideoId, setPlayingVideoId] = useState<string | null>(null);
|
const [playingVideoId, setPlayingVideoId] = useState<string | null>(null);
|
||||||
|
const [expandedItemId, setExpandedItemId] = useState<string | null>(null);
|
||||||
|
|
||||||
// Resizable Lightbox state: compact | theater | cinema
|
// Resizable Lightbox state: compact | theater | cinema
|
||||||
const [lightboxSize, setLightboxSize] = useState<'compact' | 'theater' | 'cinema'>('compact');
|
const [lightboxSize, setLightboxSize] = useState<'compact' | 'theater' | 'cinema'>('compact');
|
||||||
@ -189,20 +195,27 @@ export const ShowcasePage: React.FC = () => {
|
|||||||
<p className="text-xs text-ink-500 mt-1 max-w-sm">There are no featured videos available in the showcase right now. Check back later!</p>
|
<p className="text-xs text-ink-500 mt-1 max-w-sm">There are no featured videos available in the showcase right now. Check back later!</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6 animate-fadeIn">
|
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6 items-start animate-fadeIn">
|
||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
const ytId = extractYouTubeVideoId(item.youtubeUrl);
|
const ytId = extractYouTubeVideoId(item.youtubeUrl);
|
||||||
const isIg = item.youtubeUrl.includes('instagram.com');
|
const isIg = item.youtubeUrl.includes('instagram.com');
|
||||||
const isTw = item.youtubeUrl.includes('twitter.com') || item.youtubeUrl.includes('x.com');
|
const isTw = item.youtubeUrl.includes('twitter.com') || item.youtubeUrl.includes('x.com');
|
||||||
const thumbnail = item.thumbnailUrl || (ytId ? `https://img.youtube.com/vi/${ytId}/hqdefault.jpg` : null);
|
const thumbnail = item.thumbnailUrl || (ytId ? `https://img.youtube.com/vi/${ytId}/hqdefault.jpg` : null);
|
||||||
|
const isExpanded = expandedItemId === item.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div key={item.id} className="relative min-h-[400px]">
|
||||||
key={item.id}
|
<motion.div
|
||||||
className="group flex flex-col bg-ink-0 border border-ink-200 hover:border-ink-350 rounded-2xl overflow-hidden hover:shadow-xl transition-all duration-500"
|
layout
|
||||||
|
transition={{ type: "spring", stiffness: 320, damping: 28 }}
|
||||||
|
className={`group flex flex-col bg-ink-0 border rounded-2xl overflow-hidden transition-all duration-300 ${
|
||||||
|
isExpanded
|
||||||
|
? 'absolute z-20 top-0 left-0 right-0 h-auto shadow-2xl border-ink-350 bg-ink-0'
|
||||||
|
: 'relative w-full h-full border-ink-200 hover:border-ink-350 hover:shadow-xl'
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{/* Video Player / Thumbnail */}
|
{/* Video Player / Thumbnail */}
|
||||||
<div className="relative aspect-video bg-ink-900 overflow-hidden">
|
<div className="relative aspect-video bg-ink-900 overflow-hidden shrink-0">
|
||||||
{thumbnail ? (
|
{thumbnail ? (
|
||||||
<img
|
<img
|
||||||
src={thumbnail}
|
src={thumbnail}
|
||||||
@ -256,13 +269,17 @@ export const ShowcasePage: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content Info */}
|
{/* Content Info */}
|
||||||
<div className="p-5 flex-1 flex flex-col justify-between space-y-4">
|
<div className="p-5 flex-grow flex flex-col justify-between space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<h3 className="text-sm font-black tracking-tight text-ink-900 leading-snug">
|
<h3 className="text-sm font-black tracking-tight text-ink-900 leading-snug">
|
||||||
{item.title}
|
{item.title}
|
||||||
</h3>
|
</h3>
|
||||||
{item.description && (
|
{item.description && (
|
||||||
<VideoDescription text={item.description} />
|
<VideoDescription
|
||||||
|
text={item.description}
|
||||||
|
isExpanded={isExpanded}
|
||||||
|
onToggleExpand={() => setExpandedItemId(isExpanded ? null : item.id)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -281,6 +298,7 @@ export const ShowcasePage: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user