woedii/components/cards/HoverCards.tsx

161 lines
5.7 KiB
TypeScript
Raw Normal View History

2025-04-28 00:47:36 +00:00
'use client'
import React, { useState, useEffect, useRef } from 'react'
import Image from 'next/image'
2025-04-28 00:47:36 +00:00
import Link from 'next/link'
2025-04-28 00:47:36 +00:00
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
import { useContextMenuTriggers } from "@/hooks/useContextMenuTriggers"
2025-04-28 00:47:36 +00:00
export interface HoverCardsProps {
triggerText: string
videourl: string
description: string
linkText?: string
link?: string,
isImage?: boolean,
2025-04-28 00:47:36 +00:00
}
export default function HoverCards({
triggerText,
videourl,
description,
link = '#',
linkText = 'Purchase & Read More',
isImage
2025-04-28 00:47:36 +00:00
}: HoverCardsProps) {
const [isTooltipOpen, setIsTooltipOpen] = useState(false);
const [isMobile, setIsMobile] = useState(false);
const tooltipRef = useRef<HTMLDivElement>(null);
// Check if device is mobile
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 768);
};
// Set initial value
checkMobile();
// Add event listener for window resize
window.addEventListener('resize', checkMobile);
// Cleanup
return () => window.removeEventListener('resize', checkMobile);
}, []);
// Add click outside listener when tooltip is open
useEffect(() => {
if (isTooltipOpen && isMobile) {
const handleOutsideClick = (e: MouseEvent) => {
if (tooltipRef.current && !tooltipRef.current.contains(e.target as Node)) {
setIsTooltipOpen(false);
}
};
// Add a slight delay before adding the event listener to prevent immediate closing
const timeoutId = setTimeout(() => {
document.addEventListener('click', handleOutsideClick);
}, 100);
return () => {
clearTimeout(timeoutId);
document.removeEventListener('click', handleOutsideClick);
};
}
}, [isTooltipOpen, isMobile]);
// Custom handlers for mobile interactions
const { handlers } = useContextMenuTriggers({
longPressDelay: 500,
doubleClickDelay: 300,
onLongPress: () => {
if (isMobile) {
console.log("Long press triggered tooltip");
setIsTooltipOpen(true);
}
},
onDoubleTap: () => {
if (isMobile) {
console.log("Double tap toggling tooltip");
setIsTooltipOpen(!isTooltipOpen);
}
}
});
// Close tooltip function
const handleCloseTooltip = (e: React.MouseEvent) => {
e.stopPropagation();
setIsTooltipOpen(false);
};
2025-04-28 00:47:36 +00:00
return (
<TooltipProvider>
<Tooltip
open={isMobile ? isTooltipOpen : undefined}
onOpenChange={!isMobile ? setIsTooltipOpen : undefined}
>
<TooltipTrigger asChild>
<span
className={`text-blue-400 cursor-pointer underline inline relative ${
isMobile ? 'after:content-[""] after:absolute after:bottom-[-3px] after:left-0 after:w-full after:h-[2px] after:bg-blue-400 after:opacity-70' : ''
}`}
{...(isMobile ? handlers : {})}
title={isMobile ? "Double tap or long press to view details" : "Hover to view details"}
>
{triggerText}
</span>
</TooltipTrigger>
<TooltipContent className="w-80 tooltip-content p-0" ref={tooltipRef}>
<div className="max-w-xs bg-white rounded-lg overflow-hidden shadow-lg relative">
{isMobile && (
<button
className="absolute top-2 right-2 z-10 bg-gray-800 text-white rounded-full w-6 h-6 flex items-center justify-center"
onClick={handleCloseTooltip}
aria-label="Close"
>
</button>
)}
<div className="relative h-48 w-full">
{isImage ? (
<Image
src={videourl}
alt="Content preview"
layout="fill"
objectFit="cover"
/>
) : (
<video
className="absolute top-0 left-0 w-full h-full object-cover"
muted
loop
playsInline
autoPlay
src={videourl}
/>
)}
</div>
2025-04-28 00:47:36 +00:00
<div className="p-4">
<p className="text-gray-700 text-sm mb-4">
{description}
</p>
2025-04-28 00:47:36 +00:00
<Link href={link}>
<span className="text-purple-700 font-medium text-sm hover:text-purple-900 transition-colors">
{linkText}
</span>
</Link>
</div>
2025-04-28 00:47:36 +00:00
</div>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
}