From e7fcfd63a282a53f103ca5f7d9f744c11950cce5 Mon Sep 17 00:00:00 2001 From: g Date: Mon, 8 Dec 2025 00:47:57 +0000 Subject: [PATCH] Add Christmas theme and snow effects for December Introduces a Christmas theme that activates in December, including themed colors, subtle background patterns, and snowflake effects on loading screens. Adds a reusable SnowLoader component and utility for December detection. Updates layout and loading components to conditionally apply decorations and styles only during December. --- app/dashboard/analytics/loading.tsx | 4 +- app/dashboard/chats/[id]/loading.tsx | 2 + app/dashboard/loading.tsx | 4 +- app/dashboard/orders/[id]/loading.tsx | 4 +- app/globals.css | 55 +++++++++++++++++++-------- app/layout.tsx | 7 +++- components/christmas-decorations.tsx | 26 +++++++++---- components/dashboard/page-loading.tsx | 2 + components/snow-loader.tsx | 54 ++++++++++++++++++++++++++ lib/utils/christmas.ts | 9 +++++ 10 files changed, 139 insertions(+), 28 deletions(-) create mode 100644 components/snow-loader.tsx create mode 100644 lib/utils/christmas.ts diff --git a/app/dashboard/analytics/loading.tsx b/app/dashboard/analytics/loading.tsx index a2943cb..c3a1483 100644 --- a/app/dashboard/analytics/loading.tsx +++ b/app/dashboard/analytics/loading.tsx @@ -1,11 +1,13 @@ import { Skeleton } from "@/components/ui/skeleton"; import { Card, CardContent, CardHeader } from "@/components/ui/card"; import Layout from "@/components/layout/layout"; +import { SnowLoader } from "@/components/snow-loader"; export default function AnalyticsLoading() { return ( -
+
+
diff --git a/app/dashboard/chats/[id]/loading.tsx b/app/dashboard/chats/[id]/loading.tsx index 6d48584..06a3133 100644 --- a/app/dashboard/chats/[id]/loading.tsx +++ b/app/dashboard/chats/[id]/loading.tsx @@ -2,6 +2,7 @@ import Layout from "@/components/layout/layout"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import { Loader2 } from "lucide-react"; +import { SnowLoader } from "@/components/snow-loader"; export default function ChatDetailLoading() { return ( @@ -18,6 +19,7 @@ export default function ChatDetailLoading() { {/* Chat window */}
+ {/* Chat messages area */}
diff --git a/app/dashboard/loading.tsx b/app/dashboard/loading.tsx index bb6a1eb..6a55e5c 100644 --- a/app/dashboard/loading.tsx +++ b/app/dashboard/loading.tsx @@ -4,6 +4,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com import { Skeleton } from "@/components/ui/skeleton"; import Layout from "@/components/layout/layout"; import { Loader2 } from "lucide-react"; +import { SnowLoader } from "@/components/snow-loader"; export default function DashboardLoading() { return ( @@ -36,7 +37,8 @@ export default function DashboardLoading() { {/* Best selling products skeleton */} -
+ +

Loading dashboard data...

diff --git a/app/dashboard/orders/[id]/loading.tsx b/app/dashboard/orders/[id]/loading.tsx index a04f728..8fd214e 100644 --- a/app/dashboard/orders/[id]/loading.tsx +++ b/app/dashboard/orders/[id]/loading.tsx @@ -4,6 +4,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Skeleton } from "@/components/ui/skeleton"; import Layout from "@/components/layout/layout"; import { Loader2 } from "lucide-react"; +import { SnowLoader } from "@/components/snow-loader"; export default function OrderDetailsLoading() { return ( @@ -77,7 +78,8 @@ export default function OrderDetailsLoading() { {/* Loading overlay */}
-
+ +

Loading order details...

diff --git a/app/globals.css b/app/globals.css index b2a4dca..b245c5f 100644 --- a/app/globals.css +++ b/app/globals.css @@ -317,8 +317,15 @@ body { hsl(var(--christmas-gold))) 1; } - /* Subtle Christmas pattern overlay */ - body::before { + /* Christmas-themed styles - only active in December */ + .christmas-theme { + /* Subtle Christmas pattern overlay */ + --christmas-pattern: 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%); + } + + .christmas-theme body::before { content: ''; position: fixed; top: 0; @@ -334,13 +341,13 @@ body { } /* Christmas-themed card hover effects */ - .card:hover { + .christmas-theme .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 { + .christmas-theme button.bg-primary:hover { background: linear-gradient(135deg, hsl(var(--christmas-red)), hsl(var(--christmas-green))); @@ -348,13 +355,13 @@ body { } /* Christmas-themed link colors */ - a:hover { + .christmas-theme a:hover { color: hsl(var(--christmas-red)); transition: color 0.2s ease; } /* Subtle Christmas border on focus */ - *:focus-visible { + .christmas-theme *:focus-visible { outline-color: hsl(var(--christmas-red)); } } @@ -398,28 +405,46 @@ 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%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --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%; + /* Christmas colors */ + --christmas-red: 0 84% 50%; + --christmas-green: 142 76% 36%; + --christmas-gold: 43 96% 56%; + } + + /* Apply Christmas colors only in December */ + html.christmas-theme.dark, + html.christmas-theme .dark { --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: 142 76% 36%; --accent-foreground: 0 0% 98%; - --destructive: 0 62.8% 30.6%; - --destructive-foreground: 0 0% 98%; --border: 142 76% 20%; - --input: 0 0% 14.9%; --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%; } } diff --git a/app/layout.tsx b/app/layout.tsx index 5d0d9a8..ed88c38 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -7,6 +7,7 @@ import { NotificationProvider } from "@/lib/notification-context" import { Metadata, Viewport } from "next" import KeepOnlineWrapper from "@/components/layout/KeepOnlineWrapper" import { ChristmasDecorations } from "@/components/christmas-decorations" +import { isDecember } from "@/lib/utils/christmas" const inter = Inter({ subsets: ["latin"] }) @@ -70,12 +71,14 @@ export default function RootLayout({ }: { children: React.ReactNode }) { + const isDec = isDecember() + return ( - + - + {isDec && } >([]) + const [isDec, setIsDec] = useState(false) 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) + setIsDec(isDecember()) + + if (isDecember()) { + // 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) + } }, []) + if (!isDec) { + return null + } + return (
{/* Snowflakes */} diff --git a/components/dashboard/page-loading.tsx b/components/dashboard/page-loading.tsx index 8a1819b..5574836 100644 --- a/components/dashboard/page-loading.tsx +++ b/components/dashboard/page-loading.tsx @@ -3,6 +3,7 @@ import { Skeleton } from "@/components/ui/skeleton"; import { Card } from "@/components/ui/card"; import { Loader2 } from "lucide-react"; +import { SnowLoader } from "@/components/snow-loader"; interface PageLoadingProps { title?: string; @@ -30,6 +31,7 @@ export default function PageLoading({ {/* Main content skeleton */} +
diff --git a/components/snow-loader.tsx b/components/snow-loader.tsx new file mode 100644 index 0000000..ac43f56 --- /dev/null +++ b/components/snow-loader.tsx @@ -0,0 +1,54 @@ +"use client" + +import { useEffect, useState } from "react" +import { isDecember } from "@/lib/utils/christmas" + +interface SnowLoaderProps { + className?: string; + count?: number; +} + +export function SnowLoader({ className = "", count = 20 }: SnowLoaderProps) { + const [snowflakes, setSnowflakes] = useState>([]) + const [isDec, setIsDec] = useState(false) + + useEffect(() => { + setIsDec(isDecember()) + + if (isDecember()) { + // Generate snowflakes + const flakes = Array.from({ length: count }, (_, i) => ({ + id: i, + left: Math.random() * 100, + delay: Math.random() * 3, + duration: 5 + Math.random() * 3, + size: 0.5 + Math.random() * 0.5, + })) + setSnowflakes(flakes) + } + }, [count]) + + if (!isDec) { + return null + } + + return ( +
+ {snowflakes.map((flake) => ( +
+ ❄ +
+ ))} +
+ ) +} + diff --git a/lib/utils/christmas.ts b/lib/utils/christmas.ts new file mode 100644 index 0000000..92cf576 --- /dev/null +++ b/lib/utils/christmas.ts @@ -0,0 +1,9 @@ +/** + * Check if the current date is in December + * @returns true if current month is December (0-indexed, so 11 = December) + */ +export function isDecember(): boolean { + const now = new Date(); + return now.getMonth() === 11; // December is month 11 (0-indexed) +} +