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:
g
2025-12-08 00:13:40 +00:00
parent 48f1b9766d
commit 224342c410
5 changed files with 224 additions and 14 deletions

View File

@@ -241,6 +241,122 @@ body {
.bg-muted { .bg-muted {
background-color: hsl(var(--muted) / 0.8); 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 { @layer base {
@@ -270,6 +386,10 @@ body {
--chart-4: 43 74% 66%; --chart-4: 43 74% 66%;
--chart-5: 27 87% 67%; --chart-5: 27 87% 67%;
--radius: 0.5rem; --radius: 0.5rem;
/* Christmas colors */
--christmas-red: 0 84% 50%;
--christmas-green: 142 76% 36%;
--christmas-gold: 43 96% 56%;
} }
.dark { .dark {
--background: 0 0% 3.9%; --background: 0 0% 3.9%;
@@ -278,24 +398,28 @@ body {
--card-foreground: 0 0% 98%; --card-foreground: 0 0% 98%;
--popover: 0 0% 3.9%; --popover: 0 0% 3.9%;
--popover-foreground: 0 0% 98%; --popover-foreground: 0 0% 98%;
--primary: 0 0% 98%; --primary: 0 84% 50%;
--primary-foreground: 0 0% 9%; --primary-foreground: 0 0% 98%;
--secondary: 0 0% 14.9%; --secondary: 142 76% 36%;
--secondary-foreground: 0 0% 98%; --secondary-foreground: 0 0% 98%;
--muted: 0 0% 14.9%; --muted: 0 0% 14.9%;
--muted-foreground: 0 0% 63.9%; --muted-foreground: 0 0% 63.9%;
--accent: 0 0% 14.9%; --accent: 142 76% 36%;
--accent-foreground: 0 0% 98%; --accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%; --destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%; --destructive-foreground: 0 0% 98%;
--border: 0 0% 14.9%; --border: 142 76% 20%;
--input: 0 0% 14.9%; --input: 0 0% 14.9%;
--ring: 0 0% 83.1%; --ring: 0 84% 50%;
--chart-1: 220 70% 50%; --chart-1: 0 84% 50%;
--chart-2: 160 60% 45%; --chart-2: 142 76% 36%;
--chart-3: 30 80% 55%; --chart-3: 43 96% 56%;
--chart-4: 280 65% 60%; --chart-4: 0 84% 50%;
--chart-5: 340 75% 55%; --chart-5: 142 76% 36%;
/* Christmas colors */
--christmas-red: 0 84% 50%;
--christmas-green: 142 76% 36%;
--christmas-gold: 43 96% 56%;
} }
} }

View File

@@ -6,6 +6,7 @@ import type React from "react"
import { NotificationProvider } from "@/lib/notification-context" import { NotificationProvider } from "@/lib/notification-context"
import { Metadata, Viewport } from "next" import { Metadata, Viewport } from "next"
import KeepOnlineWrapper from "@/components/layout/KeepOnlineWrapper" import KeepOnlineWrapper from "@/components/layout/KeepOnlineWrapper"
import { ChristmasDecorations } from "@/components/christmas-decorations"
const inter = Inter({ subsets: ["latin"] }) const inter = Inter({ subsets: ["latin"] })
@@ -74,6 +75,7 @@ export default function RootLayout({
<body className={inter.className}> <body className={inter.className}>
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem disableTransitionOnChange> <ThemeProvider attribute="class" defaultTheme="dark" enableSystem disableTransitionOnChange>
<NotificationProvider> <NotificationProvider>
<ChristmasDecorations />
<Toaster <Toaster
theme="dark" theme="dark"
richColors richColors

View 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>
)
}

View File

@@ -1,4 +1,4 @@
{ {
"commitHash": "884574c", "commitHash": "48f1b97",
"buildTime": "2025-12-03T18:07:05.932Z" "buildTime": "2025-12-08T00:12:30.781Z"
} }

View File

@@ -29,12 +29,36 @@ const config: Config = {
shimmer: { shimmer: {
'0%': { transform: 'translateX(-100%)' }, '0%': { transform: 'translateX(-100%)' },
'100%': { 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: { animation: {
"accordion-down": "accordion-down 0.2s ease-out", "accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 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: { colors: {
background: 'hsl(var(--background))', background: 'hsl(var(--background))',