Merge version_2 into main #2

Merged
bender merged 3 commits from version_2 into main 2026-03-20 19:12:08 +00:00
3 changed files with 462 additions and 8 deletions

320
src/app/birthday/page.tsx Normal file
View 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>
);
}

View File

@@ -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"

View File

@@ -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);