149 lines
6.1 KiB
TypeScript
149 lines
6.1 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useRef } from "react";
|
|
import { motion } from "framer-motion";
|
|
import { Star, Quote, Sparkles } from "lucide-react";
|
|
|
|
export default function Testimonials() {
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
|
|
// Testimonials database
|
|
const reviews = [
|
|
{
|
|
name: "Aishwarya Krishnan",
|
|
role: "Culinary Critic, Madras Digest",
|
|
quote: "My Dosa Place is not merely a restaurant; it is a culinary sanctuary. The ghee roast dosa had the exact golden ghee crunch that I've only ever tasted in heritage kitchens. The visual focus onto our set table completes this extraordinary sensory theatre.",
|
|
rating: 5,
|
|
},
|
|
{
|
|
name: "Dr. Raghavan Pillai",
|
|
role: "Heritage Historian",
|
|
quote: "Dining here felt like attending a grand royal feast in a Chola palace. The attention to traditional serving etiquette, the stone-paved floor, and the hand-ground masalas are a testament to true preservation of culture.",
|
|
rating: 5,
|
|
},
|
|
{
|
|
name: "Siddharth Malhotra",
|
|
role: "Luxury Connoisseur",
|
|
quote: "The WebGL 3D interface was impressive, but the real-life experience surpassed it. The Chef's storytelling through spices, the live flute tunes, and the incredible banana-leaf thali is unmatched. A true 5-star experience.",
|
|
rating: 5,
|
|
},
|
|
];
|
|
|
|
// 3D Card Hover Tilt logic (programmatic per card)
|
|
const Card = ({ review }: { review: typeof reviews[0] }) => {
|
|
const cardRef = useRef<HTMLDivElement>(null);
|
|
const [rotateX, setRotateX] = useState(0);
|
|
const [rotateY, setRotateY] = useState(0);
|
|
|
|
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
const card = cardRef.current;
|
|
if (!card) return;
|
|
const rect = card.getBoundingClientRect();
|
|
const width = rect.width;
|
|
const height = rect.height;
|
|
const mouseX = e.clientX - rect.left - width / 2;
|
|
const mouseY = e.clientY - rect.top - height / 2;
|
|
|
|
// Calculate rotation angles (max 12 degrees)
|
|
const rX = -(mouseY / (height / 2)) * 10;
|
|
const rY = (mouseX / (width / 2)) * 10;
|
|
|
|
setRotateX(rX);
|
|
setRotateY(rY);
|
|
};
|
|
|
|
const handleMouseLeave = () => {
|
|
setRotateX(0);
|
|
setRotateY(0);
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={cardRef}
|
|
onMouseMove={handleMouseMove}
|
|
onMouseLeave={handleMouseLeave}
|
|
className="w-full flex-shrink-0 lg:flex-1 h-full perspective-[1000px] z-10"
|
|
>
|
|
<motion.div
|
|
animate={{ rotateX, rotateY }}
|
|
transition={{ type: "spring", stiffness: 300, damping: 25 }}
|
|
className="clickable h-full flex flex-col justify-between p-8 rounded-xl glass border border-gold/15 shadow-[0_20px_50px_rgba(0,0,0,0.6)] relative overflow-hidden group"
|
|
style={{ transformStyle: "preserve-3d" }}
|
|
>
|
|
{/* Decorative Corner Borders */}
|
|
<div className="absolute top-2 left-2 w-3 h-3 border-t border-l border-gold/30" />
|
|
<div className="absolute top-2 right-2 w-3 h-3 border-t border-r border-gold/30" />
|
|
<div className="absolute bottom-2 left-2 w-3 h-3 border-b border-l border-gold/30" />
|
|
<div className="absolute bottom-2 right-2 w-3 h-3 border-b border-r border-gold/30" />
|
|
|
|
{/* Background Ambient Glow */}
|
|
<div className="absolute inset-0 bg-gradient-to-br from-gold/5 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none" />
|
|
|
|
{/* Quote Icon */}
|
|
<div className="flex justify-between items-center mb-6">
|
|
<div className="flex gap-1">
|
|
{Array.from({ length: review.rating }).map((_, i) => (
|
|
<Star
|
|
key={i}
|
|
size={14}
|
|
className="text-gold fill-gold drop-shadow-[0_0_5px_rgba(212,175,55,0.6)] animate-pulse"
|
|
style={{ animationDelay: `${i * 0.2}s` }}
|
|
/>
|
|
))}
|
|
</div>
|
|
<Quote size={24} className="text-gold/25 group-hover:text-gold/50 transition-colors duration-300" />
|
|
</div>
|
|
|
|
{/* Review Text */}
|
|
<p className="font-sans text-xs md:text-sm text-stone-700 leading-relaxed tracking-wider mb-8 italic">
|
|
"{review.quote}"
|
|
</p>
|
|
|
|
{/* Reviewer Details */}
|
|
<div className="border-t border-gold/15 pt-4 flex flex-col">
|
|
<span className="font-serif text-sm font-bold text-stone-900 tracking-widest uppercase">
|
|
{review.name}
|
|
</span>
|
|
<span className="font-sans text-[10px] text-gold-dark font-bold tracking-widest uppercase mt-0.5">
|
|
{review.role}
|
|
</span>
|
|
</div>
|
|
</motion.div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<section
|
|
ref={containerRef}
|
|
className="relative min-h-screen py-24 px-6 md:px-12 flex flex-col justify-center overflow-hidden bg-darkbg border-b border-gold/10"
|
|
>
|
|
{/* Background Graphic elements */}
|
|
<div className="absolute top-[20%] right-[-10%] w-96 h-96 rounded-full bg-maroon/10 blur-[150px] pointer-events-none" />
|
|
<div className="absolute bottom-[20%] left-[-10%] w-96 h-96 rounded-full bg-gold/5 blur-[150px] pointer-events-none" />
|
|
|
|
<div className="container max-w-6xl mx-auto relative z-10">
|
|
|
|
{/* Title */}
|
|
<div className="mb-16 flex flex-col items-center text-center">
|
|
<span className="font-sans text-[10px] tracking-[0.4em] uppercase text-gold font-semibold flex items-center gap-2 mb-3">
|
|
<Sparkles size={12} className="animate-pulse" /> H O N O R E D P A T R O N S
|
|
</span>
|
|
<h2 className="font-serif text-4xl md:text-6xl font-bold tracking-wide text-foreground uppercase text-glow">
|
|
GUEST CRITICS & DIARIES
|
|
</h2>
|
|
<div className="w-20 h-[1.5px] bg-gold mt-4" />
|
|
</div>
|
|
|
|
{/* Reviews Cards Grid */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8 items-stretch min-h-[380px]">
|
|
{reviews.map((review, idx) => (
|
|
<Card key={idx} review={review} />
|
|
))}
|
|
</div>
|
|
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|