Merge version_2 into main #2
320
src/app/birthday/page.tsx
Normal file
320
src/app/birthday/page.tsx
Normal file
@@ -0,0 +1,320 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import NavbarLayoutFloatingInline from "@/components/navbar/NavbarLayoutFloatingInline";
|
||||
|
||||
export default function BirthdayPage() {
|
||||
const [gameStarted, setGameStarted] = useState(false);
|
||||
const [countdown, setCountdown] = useState<number | null>(null);
|
||||
const [showCelebration, setShowCelebration] = useState(false);
|
||||
const audioRef = useRef<HTMLAudioElement>(null);
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
const startCountdown = () => {
|
||||
setGameStarted(true);
|
||||
setCountdown(3);
|
||||
|
||||
// Play birthday song
|
||||
if (audioRef.current) {
|
||||
audioRef.current.play();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (countdown === null || countdown < 0) return;
|
||||
|
||||
if (countdown === 0) {
|
||||
setShowCelebration(true);
|
||||
triggerCelebration();
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
setCountdown(countdown - 1);
|
||||
}, 1000);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [countdown]);
|
||||
|
||||
const triggerCelebration = () => {
|
||||
// Trigger cake animation and lighting effects
|
||||
if (canvasRef.current) {
|
||||
const ctx = canvasRef.current.getContext("2d");
|
||||
if (ctx) {
|
||||
animateConfetti(ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const animateConfetti = (ctx: CanvasRenderingContext2D) => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
const particles: Array<{
|
||||
x: number;
|
||||
y: number;
|
||||
vx: number;
|
||||
vy: number;
|
||||
life: number;
|
||||
size: number;
|
||||
color: string;
|
||||
}> = [];
|
||||
|
||||
// Create confetti particles
|
||||
for (let i = 0; i < 100; i++) {
|
||||
particles.push({
|
||||
x: Math.random() * canvas.width,
|
||||
y: -10,
|
||||
vx: (Math.random() - 0.5) * 8,
|
||||
vy: Math.random() * 8 + 4,
|
||||
life: 1,
|
||||
size: Math.random() * 4 + 2,
|
||||
color: `hsl(${Math.random() * 60 + 0}, 100%, 60%)`
|
||||
});
|
||||
}
|
||||
|
||||
const animate = () => {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
for (let i = particles.length - 1; i >= 0; i--) {
|
||||
const p = particles[i];
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
p.vy += 0.2; // gravity
|
||||
p.life -= 0.01;
|
||||
|
||||
if (p.life <= 0) {
|
||||
particles.splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx.fillStyle = p.color;
|
||||
ctx.globalAlpha = p.life;
|
||||
ctx.fillRect(p.x, p.y, p.size, p.size);
|
||||
}
|
||||
|
||||
ctx.globalAlpha = 1;
|
||||
if (particles.length > 0) {
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
};
|
||||
|
||||
animate();
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="directional-hover"
|
||||
defaultTextAnimation="reveal-blur"
|
||||
borderRadius="rounded"
|
||||
contentWidth="mediumSmall"
|
||||
sizing="mediumLarge"
|
||||
background="circleGradient"
|
||||
cardStyle="glass-elevated"
|
||||
primaryButtonStyle="double-inset"
|
||||
secondaryButtonStyle="radial-glow"
|
||||
headingFontWeight="extrabold"
|
||||
>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarLayoutFloatingInline
|
||||
brandName="Birthday Celebration"
|
||||
navItems={[
|
||||
{ name: "Celebrate", id: "celebrate" },
|
||||
{ name: "Gallery", id: "gallery" },
|
||||
{ name: "Home", id: "home" }
|
||||
]}
|
||||
button={{
|
||||
text: "Back Home", href: "/"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
className="fixed top-0 left-0 w-full h-full pointer-events-none"
|
||||
style={{
|
||||
position: "fixed", top: 0,
|
||||
left: 0,
|
||||
zIndex: 50
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
className="relative w-full min-h-screen flex flex-col items-center justify-center"
|
||||
style={{
|
||||
backgroundColor: "#000000", overflow: "hidden"
|
||||
}}
|
||||
>
|
||||
{/* Lighting effects background */}
|
||||
<div
|
||||
className="absolute inset-0 opacity-30"
|
||||
style={{
|
||||
background: "radial-gradient(circle at 50% 50%, rgba(255, 215, 0, 0.3) 0%, rgba(255, 105, 180, 0.2) 25%, rgba(0, 191, 255, 0.1) 50%, transparent 100%)", animation: gameStarted ? "pulse 1s infinite" : "none"
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Main content */}
|
||||
<div className="relative z-10 text-center px-4 md:px-8">
|
||||
{!gameStarted ? (
|
||||
<>
|
||||
<h1
|
||||
className="text-4xl md:text-6xl lg:text-7xl font-bold mb-6"
|
||||
style={{
|
||||
color: "#FFD700", textShadow: "0 0 20px rgba(255, 215, 0, 0.8), 0 0 40px rgba(255, 105, 180, 0.6)", animation: "glow 2s ease-in-out infinite"
|
||||
}}
|
||||
>
|
||||
Happy Birthday Papa 47th Birthday
|
||||
</h1>
|
||||
|
||||
<p
|
||||
className="text-lg md:text-2xl mb-12"
|
||||
style={{
|
||||
color: "#FFFFFF", textShadow: "0 0 10px rgba(255, 215, 0, 0.6)"
|
||||
}}
|
||||
>
|
||||
Let's celebrate 40 seconds of pure joy!
|
||||
</p>
|
||||
|
||||
<button
|
||||
onClick={startCountdown}
|
||||
className="px-8 py-4 text-xl font-bold rounded-lg transition-all duration-300"
|
||||
style={{
|
||||
backgroundColor: "#FFD700", color: "#000000", boxShadow: "0 0 30px rgba(255, 215, 0, 0.8)", cursor: "pointer", transform: "scale(1)", transition: "all 0.3s ease"
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
(e.target as HTMLElement).style.transform = "scale(1.1)";
|
||||
(e.target as HTMLElement).style.boxShadow = "0 0 50px rgba(255, 215, 0, 1)";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
(e.target as HTMLElement).style.transform = "scale(1)";
|
||||
(e.target as HTMLElement).style.boxShadow = "0 0 30px rgba(255, 215, 0, 0.8)";
|
||||
}}
|
||||
>
|
||||
Start Celebration
|
||||
</button>
|
||||
</>
|
||||
) : countdown !== null && countdown >= 0 ? (
|
||||
<div className="text-center">
|
||||
<div
|
||||
className="text-9xl md:text-10xl font-bold mb-8"
|
||||
style={{
|
||||
color: "#FFD700", textShadow: "0 0 40px rgba(255, 215, 0, 0.8), 0 0 80px rgba(255, 105, 180, 0.6)", animation: "bounce 0.5s ease-in-out infinite"
|
||||
}}
|
||||
>
|
||||
{countdown}
|
||||
</div>
|
||||
<p
|
||||
className="text-2xl"
|
||||
style={{
|
||||
color: "#FFFFFF", textShadow: "0 0 10px rgba(255, 215, 0, 0.6)"
|
||||
}}
|
||||
>
|
||||
Get ready to celebrate!
|
||||
</p>
|
||||
</div>
|
||||
) : showCelebration ? (
|
||||
<>
|
||||
<h2
|
||||
className="text-5xl md:text-7xl font-bold mb-8"
|
||||
style={{
|
||||
color: "#FFD700", textShadow: "0 0 40px rgba(255, 215, 0, 0.8), 0 0 80px rgba(255, 105, 180, 0.6)", animation: "glow 1s ease-in-out infinite"
|
||||
}}
|
||||
>
|
||||
🎂 HAPPY BIRTHDAY PAPA! 🎂
|
||||
</h2>
|
||||
|
||||
<div
|
||||
className="mt-12 text-3xl font-bold animate-bounce"
|
||||
style={{
|
||||
color: "#FFD700", textShadow: "0 0 30px rgba(255, 215, 0, 0.8)"
|
||||
}}
|
||||
>
|
||||
47 Years of Celebration!
|
||||
</div>
|
||||
|
||||
{/* Cake animation */}
|
||||
<div className="mt-16 flex justify-center">
|
||||
<div
|
||||
className="text-9xl"
|
||||
style={{
|
||||
animation: "cakeFloat 3s ease-in-out infinite"
|
||||
}}
|
||||
>
|
||||
🎂
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-12">
|
||||
<button
|
||||
onClick={() => {
|
||||
setGameStarted(false);
|
||||
setCountdown(null);
|
||||
setShowCelebration(false);
|
||||
}}
|
||||
className="px-8 py-4 text-xl font-bold rounded-lg"
|
||||
style={{
|
||||
backgroundColor: "#FFD700", color: "#000000", boxShadow: "0 0 30px rgba(255, 215, 0, 0.8)", cursor: "pointer"
|
||||
}}
|
||||
>
|
||||
Celebrate Again
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Birthday song audio */}
|
||||
<audio
|
||||
ref={audioRef}
|
||||
src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3"
|
||||
loop={false}
|
||||
/>
|
||||
|
||||
<style jsx>{`
|
||||
@keyframes glow {
|
||||
0%, 100% {
|
||||
text-shadow: 0 0 20px rgba(255, 215, 0, 0.8), 0 0 40px rgba(255, 105, 180, 0.6);
|
||||
}
|
||||
50% {
|
||||
text-shadow: 0 0 40px rgba(255, 215, 0, 1), 0 0 80px rgba(255, 105, 180, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes bounce {
|
||||
0%, 100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.2);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes cakeFloat {
|
||||
0%, 100% {
|
||||
transform: translateY(0px) rotate(0deg);
|
||||
}
|
||||
25% {
|
||||
transform: translateY(-20px) rotate(5deg);
|
||||
}
|
||||
75% {
|
||||
transform: translateY(-20px) rotate(-5deg);
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
136
src/app/page.tsx
136
src/app/page.tsx
@@ -7,9 +7,64 @@ import InlineImageSplitTextAbout from "@/components/sections/about/InlineImageSp
|
||||
import FeatureBento from "@/components/sections/feature/FeatureBento";
|
||||
import TestimonialCardTwo from "@/components/sections/testimonial/TestimonialCardTwo";
|
||||
import FooterLogoEmphasis from "@/components/sections/footer/FooterLogoEmphasis";
|
||||
import { Gift, Sparkles, Image, BookOpen, Heart } from "lucide-react";
|
||||
import { Gift, Sparkles, Image, BookOpen, Heart, ChevronLeft, ChevronRight } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function LandingPage() {
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
|
||||
const bookPages = [
|
||||
{
|
||||
title: "Papa's 47th Birthday", subtitle: "A Celebration of Love and Family", images: [
|
||||
"http://img.b2bpic.net/free-photo/medium-shot-people-celebrating-birthday_52683-88947.jpg", "http://img.b2bpic.net/free-photo/family-generations-looking-camera_23-2148314901.jpg?_wi=1"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Cherished Moments", subtitle: "Family Through the Years", images: [
|
||||
"http://img.b2bpic.net/free-photo/lifestyle-queer-couples-celebrating-birthday_23-2149668049.jpg?_wi=1", "http://img.b2bpic.net/free-photo/smiling-family-lying-autumn-park_23-2147888337.jpg"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Forever Together", subtitle: "Memories That Last a Lifetime", images: [
|
||||
"http://img.b2bpic.net/free-photo/happy-family-spending-time-together-green-nature_1098-1063.jpg", "http://img.b2bpic.net/free-photo/family-generations-looking-camera_23-2148314901.jpg?_wi=1"
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "A Father's Heart", subtitle: "The Greatest Gift of All", fullPageImage: "http://img.b2bpic.net/free-photo/family-generations-looking-camera_23-2148314901.jpg?_wi=1", content: "With endless gratitude and heartfelt love, we celebrate you today."
|
||||
},
|
||||
{
|
||||
title: "Thank You, Papa", subtitle: "For All the Love You've Given", isClosing: true,
|
||||
poem: `Your hands have guided us through every season,
|
||||
Your heart has been our reason.
|
||||
Your wisdom, our compass true,
|
||||
Our strength found always in you.
|
||||
|
||||
Seventy-seven rings around the sun,
|
||||
Each one a battle valiantly won.
|
||||
But greater than years is the love you give,
|
||||
The way you teach us all to live.
|
||||
|
||||
Happy 47th, dear Papa dear,
|
||||
We celebrate you, year after year.
|
||||
With the Patel family, strong and true,
|
||||
We honor and cherish all that is you."`
|
||||
}
|
||||
];
|
||||
|
||||
const handleNextPage = () => {
|
||||
if (currentPage < bookPages.length - 1) {
|
||||
setCurrentPage(currentPage + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePreviousPage = () => {
|
||||
if (currentPage > 0) {
|
||||
setCurrentPage(currentPage - 1);
|
||||
}
|
||||
};
|
||||
|
||||
const currentBookPage = bookPages[currentPage];
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="directional-hover"
|
||||
@@ -102,6 +157,85 @@ export default function LandingPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div id="book" data-section="book" className="min-h-screen flex flex-col items-center justify-center p-8 bg-amber-50" style={{ backgroundColor: "#f6f0e9" }}>
|
||||
<div className="max-w-4xl w-full">
|
||||
{/* Book Cover Design */}
|
||||
<div className="bg-gradient-to-br from-amber-900 to-amber-700 rounded-lg shadow-2xl p-12 text-center text-white mb-8 relative overflow-hidden" style={{
|
||||
backgroundImage: "url('data:image/svg+xml,%3Csvg width=\"100\" height=\"100\" xmlns=\"http://www.w3.org/2000/svg\"%3E%3Ctext x=\"10\" y=\"50\" font-size=\"40\" opacity=\"0.1\" font-family=\"serif\"%3E✦%3C/text%3E%3C/svg%3E')", backgroundBlendMode: "overlay"
|
||||
}}>
|
||||
{/* Stickers decoration */}
|
||||
<div className="absolute top-4 right-4 text-4xl">🎉</div>
|
||||
<div className="absolute bottom-4 left-4 text-4xl">💝</div>
|
||||
<div className="absolute top-8 left-6 text-3xl">⭐</div>
|
||||
|
||||
{currentBookPage.isClosing ? (
|
||||
<div>
|
||||
<h1 className="text-5xl font-bold mb-4">Thank You, Papa</h1>
|
||||
<p className="text-xl opacity-90 mb-8">{currentBookPage.subtitle}</p>
|
||||
<div className="whitespace-pre-line text-base leading-relaxed font-serif italic">
|
||||
{currentBookPage.poem}
|
||||
</div>
|
||||
</div>
|
||||
) : currentBookPage.fullPageImage ? (
|
||||
<div className="flex flex-col items-center justify-center h-96">
|
||||
<img src={currentBookPage.fullPageImage} alt="Full page" className="w-full h-full object-cover rounded-lg mb-4" />
|
||||
<p className="text-lg italic mt-4">{currentBookPage.content}</p>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<h1 className="text-5xl font-bold mb-2">{currentBookPage.title}</h1>
|
||||
<p className="text-2xl opacity-90 mb-8">{currentBookPage.subtitle}</p>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{currentBookPage.images?.map((img, idx) => (
|
||||
<img key={idx} src={img} alt={`Page ${idx + 1}`} className="w-full h-48 object-cover rounded-lg" />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Page Navigation */}
|
||||
<div className="flex items-center justify-between mt-8">
|
||||
<button
|
||||
onClick={handlePreviousPage}
|
||||
disabled={currentPage === 0}
|
||||
className="flex items-center justify-center w-12 h-12 rounded-full bg-amber-200 hover:bg-amber-300 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
aria-label="Previous page"
|
||||
>
|
||||
<ChevronLeft className="w-6 h-6 text-amber-900" />
|
||||
</button>
|
||||
|
||||
<div className="text-center">
|
||||
<p className="text-amber-900 font-semibold">Patel Family</p>
|
||||
<p className="text-sm text-amber-700">Page {currentPage + 1} of {bookPages.length}</p>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleNextPage}
|
||||
disabled={currentPage === bookPages.length - 1}
|
||||
className="flex items-center justify-center w-12 h-12 rounded-full bg-amber-200 hover:bg-amber-300 disabled:opacity-50 disabled:cursor-not-allowed transition-all"
|
||||
aria-label="Next page"
|
||||
>
|
||||
<ChevronRight className="w-6 h-6 text-amber-900" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Page Indicators */}
|
||||
<div className="flex justify-center gap-2 mt-6">
|
||||
{bookPages.map((_, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
onClick={() => setCurrentPage(idx)}
|
||||
className={`w-2 h-2 rounded-full transition-all ${
|
||||
idx === currentPage ? "bg-amber-900 w-6" : "bg-amber-300"
|
||||
}`}
|
||||
aria-label={`Go to page ${idx + 1}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="testimonials" data-section="testimonials">
|
||||
<TestimonialCardTwo
|
||||
title="Wishes from Heart"
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
--accent: #ffffff;
|
||||
--background-accent: #ffffff; */
|
||||
|
||||
--background: #f5f4ef;
|
||||
--card: #dad6cd;
|
||||
--foreground: #2a2928;
|
||||
--primary-cta: #2a2928;
|
||||
--background: #0a0a0a;
|
||||
--card: #1a1a1a;
|
||||
--foreground: #ffffffe6;
|
||||
--primary-cta: #FFD700;
|
||||
--primary-cta-text: #f5f4ef;
|
||||
--secondary-cta: #ecebea;
|
||||
--secondary-cta: #1a1a1a;
|
||||
--secondary-cta-text: #2a2928;
|
||||
--accent: #ffffff;
|
||||
--background-accent: #c6b180;
|
||||
--accent: #FF69B4;
|
||||
--background-accent: #00BFFF;
|
||||
|
||||
/* text sizing - set by ThemeProvider */
|
||||
/* --text-2xs: clamp(0.465rem, 0.62vw, 0.62rem);
|
||||
|
||||
Reference in New Issue
Block a user