Add Christmas decorations and theme styles
Introduced a ChristmasDecorations component with animated snowflakes, twinkling stars, and festive emojis. Updated global CSS and Tailwind config to include Christmas-themed animations, colors, and effects. Integrated the decorations into the main layout for a seasonal appearance.
This commit is contained in:
146
app/globals.css
146
app/globals.css
@@ -241,6 +241,122 @@ body {
|
||||
.bg-muted {
|
||||
background-color: hsl(var(--muted) / 0.8);
|
||||
}
|
||||
|
||||
/* Christmas-themed animations */
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.3; transform: scale(0.8); }
|
||||
}
|
||||
|
||||
@keyframes snowflake {
|
||||
0% {
|
||||
transform: translateY(-100vh) rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(100vh) rotate(360deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sparkle {
|
||||
0%, 100% {
|
||||
opacity: 0;
|
||||
transform: scale(0) rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(1) rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 5px hsl(var(--christmas-red)), 0 0 10px hsl(var(--christmas-red)), 0 0 15px hsl(var(--christmas-red));
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 10px hsl(var(--christmas-green)), 0 0 20px hsl(var(--christmas-green)), 0 0 30px hsl(var(--christmas-green));
|
||||
}
|
||||
}
|
||||
|
||||
/* Christmas decorative elements */
|
||||
.christmas-twinkle {
|
||||
animation: twinkle 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.christmas-snowflake {
|
||||
position: absolute;
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
animation: snowflake 10s linear infinite;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.christmas-sparkle {
|
||||
animation: sparkle 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.christmas-glow {
|
||||
animation: glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Subtle Christmas gradient backgrounds */
|
||||
.christmas-gradient {
|
||||
background: linear-gradient(135deg,
|
||||
hsl(var(--christmas-red) / 0.1) 0%,
|
||||
hsl(var(--christmas-green) / 0.1) 50%,
|
||||
hsl(var(--christmas-gold) / 0.1) 100%);
|
||||
}
|
||||
|
||||
/* Christmas-themed borders */
|
||||
.christmas-border {
|
||||
border: 2px solid;
|
||||
border-image: linear-gradient(45deg,
|
||||
hsl(var(--christmas-red)),
|
||||
hsl(var(--christmas-green)),
|
||||
hsl(var(--christmas-gold))) 1;
|
||||
}
|
||||
|
||||
/* Subtle Christmas pattern overlay */
|
||||
body::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
radial-gradient(circle at 20% 50%, hsl(var(--christmas-red) / 0.03) 0%, transparent 50%),
|
||||
radial-gradient(circle at 80% 80%, hsl(var(--christmas-green) / 0.03) 0%, transparent 50%),
|
||||
radial-gradient(circle at 40% 20%, hsl(var(--christmas-gold) / 0.03) 0%, transparent 50%);
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
/* Christmas-themed card hover effects */
|
||||
.card:hover {
|
||||
border-color: hsl(var(--christmas-red) / 0.3);
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Christmas-themed button hover effects */
|
||||
button.bg-primary:hover {
|
||||
background: linear-gradient(135deg,
|
||||
hsl(var(--christmas-red)),
|
||||
hsl(var(--christmas-green)));
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
/* Christmas-themed link colors */
|
||||
a:hover {
|
||||
color: hsl(var(--christmas-red));
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
/* Subtle Christmas border on focus */
|
||||
*:focus-visible {
|
||||
outline-color: hsl(var(--christmas-red));
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
@@ -270,6 +386,10 @@ body {
|
||||
--chart-4: 43 74% 66%;
|
||||
--chart-5: 27 87% 67%;
|
||||
--radius: 0.5rem;
|
||||
/* Christmas colors */
|
||||
--christmas-red: 0 84% 50%;
|
||||
--christmas-green: 142 76% 36%;
|
||||
--christmas-gold: 43 96% 56%;
|
||||
}
|
||||
.dark {
|
||||
--background: 0 0% 3.9%;
|
||||
@@ -278,24 +398,28 @@ body {
|
||||
--card-foreground: 0 0% 98%;
|
||||
--popover: 0 0% 3.9%;
|
||||
--popover-foreground: 0 0% 98%;
|
||||
--primary: 0 0% 98%;
|
||||
--primary-foreground: 0 0% 9%;
|
||||
--secondary: 0 0% 14.9%;
|
||||
--primary: 0 84% 50%;
|
||||
--primary-foreground: 0 0% 98%;
|
||||
--secondary: 142 76% 36%;
|
||||
--secondary-foreground: 0 0% 98%;
|
||||
--muted: 0 0% 14.9%;
|
||||
--muted-foreground: 0 0% 63.9%;
|
||||
--accent: 0 0% 14.9%;
|
||||
--accent: 142 76% 36%;
|
||||
--accent-foreground: 0 0% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 0% 98%;
|
||||
--border: 0 0% 14.9%;
|
||||
--border: 142 76% 20%;
|
||||
--input: 0 0% 14.9%;
|
||||
--ring: 0 0% 83.1%;
|
||||
--chart-1: 220 70% 50%;
|
||||
--chart-2: 160 60% 45%;
|
||||
--chart-3: 30 80% 55%;
|
||||
--chart-4: 280 65% 60%;
|
||||
--chart-5: 340 75% 55%;
|
||||
--ring: 0 84% 50%;
|
||||
--chart-1: 0 84% 50%;
|
||||
--chart-2: 142 76% 36%;
|
||||
--chart-3: 43 96% 56%;
|
||||
--chart-4: 0 84% 50%;
|
||||
--chart-5: 142 76% 36%;
|
||||
/* Christmas colors */
|
||||
--christmas-red: 0 84% 50%;
|
||||
--christmas-green: 142 76% 36%;
|
||||
--christmas-gold: 43 96% 56%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import type React from "react"
|
||||
import { NotificationProvider } from "@/lib/notification-context"
|
||||
import { Metadata, Viewport } from "next"
|
||||
import KeepOnlineWrapper from "@/components/layout/KeepOnlineWrapper"
|
||||
import { ChristmasDecorations } from "@/components/christmas-decorations"
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] })
|
||||
|
||||
@@ -74,6 +75,7 @@ export default function RootLayout({
|
||||
<body className={inter.className}>
|
||||
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem disableTransitionOnChange>
|
||||
<NotificationProvider>
|
||||
<ChristmasDecorations />
|
||||
<Toaster
|
||||
theme="dark"
|
||||
richColors
|
||||
|
||||
60
components/christmas-decorations.tsx
Normal file
60
components/christmas-decorations.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
"use client"
|
||||
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
export function ChristmasDecorations() {
|
||||
const [snowflakes, setSnowflakes] = useState<Array<{ id: number; left: number; delay: number; duration: number }>>([])
|
||||
|
||||
useEffect(() => {
|
||||
// Generate snowflakes
|
||||
const flakes = Array.from({ length: 30 }, (_, i) => ({
|
||||
id: i,
|
||||
left: Math.random() * 100,
|
||||
delay: Math.random() * 5,
|
||||
duration: 8 + Math.random() * 4,
|
||||
}))
|
||||
setSnowflakes(flakes)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 pointer-events-none z-50 overflow-hidden">
|
||||
{/* Snowflakes */}
|
||||
{snowflakes.map((flake) => (
|
||||
<div
|
||||
key={flake.id}
|
||||
className="absolute top-0 text-white/60 text-xs animate-snowflake"
|
||||
style={{
|
||||
left: `${flake.left}%`,
|
||||
animationDelay: `${flake.delay}s`,
|
||||
animationDuration: `${flake.duration}s`,
|
||||
}}
|
||||
>
|
||||
❄
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Twinkling stars in corners */}
|
||||
<div className="absolute top-4 left-4 text-yellow-300 animate-twinkle text-lg">
|
||||
✨
|
||||
</div>
|
||||
<div className="absolute top-4 right-4 text-yellow-300 animate-twinkle text-lg" style={{ animationDelay: '0.5s' }}>
|
||||
✨
|
||||
</div>
|
||||
<div className="absolute bottom-4 left-4 text-yellow-300 animate-twinkle text-lg" style={{ animationDelay: '1s' }}>
|
||||
✨
|
||||
</div>
|
||||
<div className="absolute bottom-4 right-4 text-yellow-300 animate-twinkle text-lg" style={{ animationDelay: '1.5s' }}>
|
||||
✨
|
||||
</div>
|
||||
|
||||
{/* Christmas tree emoji decorations */}
|
||||
<div className="absolute top-8 left-1/4 text-green-500/40 animate-sparkle text-xl" style={{ animationDelay: '2s' }}>
|
||||
🎄
|
||||
</div>
|
||||
<div className="absolute top-8 right-1/4 text-green-500/40 animate-sparkle text-xl" style={{ animationDelay: '3s' }}>
|
||||
🎄
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"commitHash": "884574c",
|
||||
"buildTime": "2025-12-03T18:07:05.932Z"
|
||||
"commitHash": "48f1b97",
|
||||
"buildTime": "2025-12-08T00:12:30.781Z"
|
||||
}
|
||||
@@ -29,12 +29,36 @@ const config: Config = {
|
||||
shimmer: {
|
||||
'0%': { transform: 'translateX(-100%)' },
|
||||
'100%': { transform: 'translateX(100%)' }
|
||||
},
|
||||
twinkle: {
|
||||
'0%, 100%': { opacity: '1', transform: 'scale(1)' },
|
||||
'50%': { opacity: '0.3', transform: 'scale(0.8)' }
|
||||
},
|
||||
snowflake: {
|
||||
'0%': { transform: 'translateY(-100vh) rotate(0deg)', opacity: '1' },
|
||||
'100%': { transform: 'translateY(100vh) rotate(360deg)', opacity: '0' }
|
||||
},
|
||||
sparkle: {
|
||||
'0%, 100%': { opacity: '0', transform: 'scale(0) rotate(0deg)' },
|
||||
'50%': { opacity: '1', transform: 'scale(1) rotate(180deg)' }
|
||||
},
|
||||
glow: {
|
||||
'0%, 100%': {
|
||||
boxShadow: '0 0 5px hsl(0 84% 50%), 0 0 10px hsl(0 84% 50%), 0 0 15px hsl(0 84% 50%)'
|
||||
},
|
||||
'50%': {
|
||||
boxShadow: '0 0 10px hsl(142 76% 36%), 0 0 20px hsl(142 76% 36%), 0 0 30px hsl(142 76% 36%)'
|
||||
}
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
"shimmer": "shimmer 2s infinite"
|
||||
"shimmer": "shimmer 2s infinite",
|
||||
"twinkle": "twinkle 2s ease-in-out infinite",
|
||||
"snowflake": "snowflake 10s linear infinite",
|
||||
"sparkle": "sparkle 1.5s ease-in-out infinite",
|
||||
"glow": "glow 2s ease-in-out infinite"
|
||||
},
|
||||
colors: {
|
||||
background: 'hsl(var(--background))',
|
||||
|
||||
Reference in New Issue
Block a user