aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--frontend/src/app/globals.css390
-rw-r--r--frontend/src/app/layout.tsx29
-rw-r--r--frontend/src/app/page.tsx20
-rw-r--r--frontend/src/components/footer.tsx96
-rw-r--r--frontend/src/components/header.tsx110
-rw-r--r--frontend/src/components/hero-section.tsx20
-rw-r--r--frontend/src/components/product-card.tsx52
-rw-r--r--frontend/src/components/theme-provider.tsx9
-rw-r--r--frontend/src/components/theme-toggle.tsx50
9 files changed, 672 insertions, 104 deletions
diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css
index 92fb855..89de65b 100644
--- a/frontend/src/app/globals.css
+++ b/frontend/src/app/globals.css
@@ -120,3 +120,393 @@
@apply bg-background text-foreground;
}
}
+
+/* Complete override for ghost variant default styles */
+/* This targets the specific ghost variant classes from the button component */
+.nav-button-transparent {
+ background: transparent !important;
+ background-color: transparent !important;
+ background-image: none !important;
+ border: none !important;
+ border-color: transparent !important;
+ box-shadow: none !important;
+ --tw-bg-opacity: 0 !important;
+ --accent: transparent !important;
+ --background: transparent !important;
+ --tw-border-opacity: 0 !important;
+ --tw-shadow: none !important;
+ --tw-ring-shadow: none !important;
+ --tw-ring-offset-shadow: none !important;
+ cursor: pointer !important;
+}
+
+/* Force override ghost variant styles completely */
+button[class*="nav-button-transparent"],
+[data-slot="button"][class*="nav-button-transparent"],
+[data-slot="navigation-menu-trigger"][class*="nav-button-transparent"] {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+ box-shadow: none !important;
+}
+
+/* Override ghost variant hover specifically */
+button[class*="nav-button-transparent"][class*="hover:bg-accent"],
+[data-slot="button"][class*="nav-button-transparent"][class*="hover:bg-accent"],
+[data-slot="navigation-menu-trigger"][class*="nav-button-transparent"][class*="hover:bg-accent"] {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+}
+
+/* Dark mode ghost variant overrides */
+.dark button[class*="nav-button-transparent"][class*="dark:hover:bg-accent"],
+.dark [data-slot="button"][class*="nav-button-transparent"][class*="dark:hover:bg-accent"],
+.dark [data-slot="navigation-menu-trigger"][class*="nav-button-transparent"][class*="dark:hover:bg-accent"] {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+}
+
+/* Remove focus rings and outlines for nav buttons */
+.nav-button-transparent:focus,
+.nav-button-transparent:focus-visible {
+ outline: none !important;
+ ring: none !important;
+ --tw-ring-shadow: none !important;
+ border: none !important;
+ background: transparent !important;
+ background-color: transparent !important;
+}
+
+/* Light mode subtle hover effects - only show on hover */
+.nav-button-transparent:hover {
+ background: rgba(0, 0, 0, 0.08) !important;
+ background-color: rgba(0, 0, 0, 0.08) !important;
+ --tw-bg-opacity: 1 !important;
+ border: none !important;
+ transition: background-color 0.2s ease-in-out !important;
+}
+
+/* Dark mode even more subtle hover effects */
+.dark .nav-button-transparent:hover {
+ background: rgba(255, 255, 255, 0.06) !important;
+ background-color: rgba(255, 255, 255, 0.06) !important;
+ transition: background-color 0.2s ease-in-out !important;
+}
+
+/* Override NavigationMenuTrigger specific classes with maximum specificity */
+.nav-button-transparent.bg-background {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+}
+
+/* Focus states - only subtle background, no borders or rings */
+.nav-button-transparent:focus:not(:hover) {
+ background: rgba(0, 0, 0, 0.04) !important;
+ background-color: rgba(0, 0, 0, 0.04) !important;
+ border: none !important;
+ box-shadow: none !important;
+}
+
+.dark .nav-button-transparent:focus:not(:hover) {
+ background: rgba(255, 255, 255, 0.03) !important;
+ background-color: rgba(255, 255, 255, 0.03) !important;
+ border: none !important;
+ box-shadow: none !important;
+}
+
+/* Override open states */
+.nav-button-transparent[data-state="open"] {
+ background: rgba(0, 0, 0, 0.08) !important;
+ background-color: rgba(0, 0, 0, 0.08) !important;
+ border: none !important;
+}
+
+.dark .nav-button-transparent[data-state="open"] {
+ background: rgba(255, 255, 255, 0.06) !important;
+ background-color: rgba(255, 255, 255, 0.06) !important;
+ border: none !important;
+}
+
+/* Ensure all shadcn/ui utility classes are overridden with high specificity */
+button.nav-button-transparent,
+[data-slot="button"].nav-button-transparent,
+[data-slot="navigation-menu-trigger"].nav-button-transparent {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+ border-color: transparent !important;
+ box-shadow: none !important;
+ cursor: pointer !important;
+}
+
+/* Hover states for all button types */
+button.nav-button-transparent:hover,
+[data-slot="button"].nav-button-transparent:hover,
+[data-slot="navigation-menu-trigger"].nav-button-transparent:hover {
+ background: rgba(0, 0, 0, 0.08) !important;
+ background-color: rgba(0, 0, 0, 0.08) !important;
+ border: none !important;
+ transition: background-color 0.2s ease-in-out !important;
+ cursor: pointer !important;
+}
+
+/* Focus states for all button types */
+button.nav-button-transparent:focus,
+[data-slot="button"].nav-button-transparent:focus,
+[data-slot="navigation-menu-trigger"].nav-button-transparent:focus {
+ background: rgba(0, 0, 0, 0.04) !important;
+ background-color: rgba(0, 0, 0, 0.04) !important;
+ border: none !important;
+ box-shadow: none !important;
+ outline: none !important;
+ cursor: pointer !important;
+}
+
+/* Dark mode hover and focus states */
+.dark button.nav-button-transparent:hover,
+.dark [data-slot="button"].nav-button-transparent:hover,
+.dark [data-slot="navigation-menu-trigger"].nav-button-transparent:hover {
+ background: rgba(255, 255, 255, 0.06) !important;
+ background-color: rgba(255, 255, 255, 0.06) !important;
+ border: none !important;
+ transition: background-color 0.2s ease-in-out !important;
+ cursor: pointer !important;
+}
+
+.dark button.nav-button-transparent:focus,
+.dark [data-slot="button"].nav-button-transparent:focus,
+.dark [data-slot="navigation-menu-trigger"].nav-button-transparent:focus {
+ background: rgba(255, 255, 255, 0.03) !important;
+ background-color: rgba(255, 255, 255, 0.03) !important;
+ border: none !important;
+ box-shadow: none !important;
+ outline: none !important;
+ cursor: pointer !important;
+}
+
+/* Dropdown and navigation item transparency */
+.nav-dropdown-transparent {
+ background: rgba(255, 255, 255, 0.98) !important;
+ backdrop-filter: blur(16px) saturate(180%) !important;
+ border: 1px solid rgba(255, 255, 255, 0.3) !important;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1) !important;
+}
+
+.dark .nav-dropdown-transparent {
+ background: rgba(23, 23, 23, 0.98) !important;
+ border: 1px solid rgba(82, 82, 82, 0.4) !important;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4) !important;
+}
+
+.nav-dropdown-item {
+ background: transparent !important;
+ border: none !important;
+ transition: background-color 0.2s ease-in-out !important;
+}
+
+.nav-dropdown-item:hover {
+ background: rgba(0, 0, 0, 0.08) !important;
+ border: none !important;
+}
+
+.dark .nav-dropdown-item:hover {
+ background: rgba(255, 255, 255, 0.08) !important;
+ border: none !important;
+}
+
+/* Additional overrides for complete transparency */
+/* Handle any remaining shadcn/ui styling conflicts */
+.nav-button-transparent[data-variant="ghost"] {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+ cursor: pointer !important;
+}
+
+.nav-button-transparent[data-variant="ghost"]:hover {
+ background: rgba(0, 0, 0, 0.08) !important;
+ background-color: rgba(0, 0, 0, 0.08) !important;
+ border: none !important;
+ cursor: pointer !important;
+}
+
+.dark .nav-button-transparent[data-variant="ghost"]:hover {
+ background: rgba(255, 255, 255, 0.06) !important;
+ background-color: rgba(255, 255, 255, 0.06) !important;
+ border: none !important;
+ cursor: pointer !important;
+}
+
+/* Override any remaining background utilities */
+.nav-button-transparent.bg-transparent,
+.nav-button-transparent.bg-accent,
+.nav-button-transparent.hover\:bg-accent,
+.nav-button-transparent.focus\:bg-accent {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+ cursor: pointer !important;
+}
+
+/* Ensure link elements in navigation also have transparent styling */
+a.nav-button-transparent {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+ text-decoration: none !important;
+ cursor: pointer !important;
+}
+
+a.nav-button-transparent:hover {
+ background: rgba(0, 0, 0, 0.08) !important;
+ background-color: rgba(0, 0, 0, 0.08) !important;
+ border: none !important;
+ text-decoration: none !important;
+ cursor: pointer !important;
+}
+
+.dark a.nav-button-transparent:hover {
+ background: rgba(255, 255, 255, 0.06) !important;
+ background-color: rgba(255, 255, 255, 0.06) !important;
+ border: none !important;
+ text-decoration: none !important;
+ cursor: pointer !important;
+}
+
+/* Ultra-specific overrides to ensure transparency takes precedence */
+/* Handle all possible combinations of button classes */
+button.nav-button-transparent.hover\:bg-accent,
+button.nav-button-transparent.dark\:hover\:bg-accent\/50,
+button.nav-button-transparent[class*="hover:bg"],
+[data-slot="button"].nav-button-transparent.hover\:bg-accent,
+[data-slot="button"].nav-button-transparent.dark\:hover\:bg-accent\/50,
+[data-slot="button"].nav-button-transparent[class*="hover:bg"],
+[data-slot="navigation-menu-trigger"].nav-button-transparent.hover\:bg-accent,
+[data-slot="navigation-menu-trigger"].nav-button-transparent.dark\:hover\:bg-accent\/50,
+[data-slot="navigation-menu-trigger"].nav-button-transparent[class*="hover:bg"] {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+}
+
+/* Override any CSS custom properties that might affect background */
+.nav-button-transparent {
+ --tw-bg-accent: transparent !important;
+ --tw-bg-background: transparent !important;
+ --tw-bg-muted: transparent !important;
+ --tw-bg-secondary: transparent !important;
+}
+
+/* Ensure no background on any state for nav buttons */
+.nav-button-transparent,
+.nav-button-transparent:not(:hover):not(:focus):not(:active) {
+ background: transparent !important;
+ background-color: transparent !important;
+ box-shadow: none !important;
+ border: none !important;
+}
+
+/* Maximum specificity overrides - nuclear option for transparency */
+html body header button.nav-button-transparent,
+html body header [data-slot="button"].nav-button-transparent,
+html body header [data-slot="navigation-menu-trigger"].nav-button-transparent,
+html body header div button.nav-button-transparent,
+html body header div [data-slot="button"].nav-button-transparent,
+html body header div [data-slot="navigation-menu-trigger"].nav-button-transparent {
+ background: transparent !important;
+ background-color: transparent !important;
+ background-image: none !important;
+ border: none !important;
+ border-color: transparent !important;
+ box-shadow: none !important;
+ backdrop-filter: none !important;
+}
+
+/* Override any inline styles or computed styles */
+.nav-button-transparent[style*="background"] {
+ background: transparent !important;
+ background-color: transparent !important;
+}
+
+/* Target specific button classes that might have background */
+.nav-button-transparent.inline-flex,
+.nav-button-transparent[class*="inline-flex"] {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+}
+
+/* Enhanced link element transparency for Sale button and similar nav links */
+/* Apply maximum specificity for link elements in navigation */
+html body header a.nav-button-transparent,
+html body header div a.nav-button-transparent,
+html body header nav a.nav-button-transparent,
+[data-slot="navigation-menu-link"].nav-button-transparent {
+ background: transparent !important;
+ background-color: transparent !important;
+ background-image: none !important;
+ border: none !important;
+ border-color: transparent !important;
+ box-shadow: none !important;
+ backdrop-filter: none !important;
+ cursor: pointer !important;
+}
+
+/* Override any NavigationMenuLink default styles */
+a.nav-button-transparent[data-slot="navigation-menu-link"],
+[data-slot="navigation-menu-link"].nav-button-transparent {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+ box-shadow: none !important;
+}
+
+/* Ensure link hover states maintain transparency in default state */
+a.nav-button-transparent:not(:hover):not(:focus):not(:active) {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+}
+
+/* Specific overrides for NavigationMenuLink component (Sale button) */
+[data-slot="navigation-menu-link"].nav-button-transparent {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+ box-shadow: none !important;
+ cursor: pointer !important;
+}
+
+/* Override NavigationMenuLink hover and focus states */
+[data-slot="navigation-menu-link"].nav-button-transparent.hover\:bg-accent,
+[data-slot="navigation-menu-link"].nav-button-transparent.focus\:bg-accent,
+[data-slot="navigation-menu-link"].nav-button-transparent[class*="hover:bg-accent"],
+[data-slot="navigation-menu-link"].nav-button-transparent[class*="focus:bg-accent"],
+[data-slot="navigation-menu-link"].nav-button-transparent[class*="data-[active=true]:bg-accent"] {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+}
+
+/* Override NavigationMenuLink data states */
+[data-slot="navigation-menu-link"].nav-button-transparent[data-active="true"] {
+ background: transparent !important;
+ background-color: transparent !important;
+ border: none !important;
+}
+
+/* Ensure NavigationMenuLink has proper hover effect */
+[data-slot="navigation-menu-link"].nav-button-transparent:hover {
+ background: rgba(0, 0, 0, 0.08) !important;
+ background-color: rgba(0, 0, 0, 0.08) !important;
+ border: none !important;
+ transition: background-color 0.2s ease-in-out !important;
+}
+
+.dark [data-slot="navigation-menu-link"].nav-button-transparent:hover {
+ background: rgba(255, 255, 255, 0.06) !important;
+ background-color: rgba(255, 255, 255, 0.06) !important;
+}
diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
index 50bb899..651acc8 100644
--- a/frontend/src/app/layout.tsx
+++ b/frontend/src/app/layout.tsx
@@ -1,9 +1,10 @@
import type { Metadata } from "next";
import "./globals.css";
import { Toaster } from "@/components/ui/sonner";
+import { ThemeProvider } from "@/components/theme-provider";
export const metadata: Metadata = {
- title: "blcklst - Modern Fashion Brand",
+ title: "blcklst - not everyone get blcklsted",
description: "not everyone gets blcklsted - discover carefully curated fashion pieces that define modern elegance.",
};
@@ -13,16 +14,36 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
- <html lang="en">
+ <html lang="en" suppressHydrationWarning>
<head>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"
rel="stylesheet"
/>
+ {/* Preload both logo variants for instant theme switching */}
+ <link
+ rel="preload"
+ href="/black-logo.png"
+ as="image"
+ type="image/png"
+ />
+ <link
+ rel="preload"
+ href="/white-logo.png"
+ as="image"
+ type="image/png"
+ />
</head>
<body className="font-sans antialiased">
- {children}
- <Toaster />
+ <ThemeProvider
+ attribute="class"
+ defaultTheme="system"
+ enableSystem
+ disableTransitionOnChange
+ >
+ {children}
+ <Toaster />
+ </ThemeProvider>
</body>
</html>
);
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 7a9bea6..7d6b7a2 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -93,10 +93,10 @@ export default function Home() {
<HeroSection />
{/* Featured Products Section */}
- <section className="py-16 bg-white">
+ <section className="py-16 bg-white dark:bg-neutral-950">
<div className="container mx-auto px-4">
<div className="text-center mb-12">
- <h2 className="text-3xl font-bold mb-4">Featured Products</h2>
+ <h2 className="text-3xl font-bold mb-4 text-foreground">Featured Products</h2>
<p className="text-muted-foreground max-w-2xl mx-auto">
Discover our handpicked selection of trending items that our customers love most.
</p>
@@ -117,7 +117,7 @@ export default function Home() {
</section>
{/* Categories Section */}
- <section className="py-16 bg-neutral-50">
+ <section className="py-16 bg-neutral-50 dark:bg-neutral-900">
<div className="container mx-auto px-4">
<div className="text-center mb-12">
<h2 className="text-3xl font-bold mb-4">Shop by Category</h2>
@@ -130,17 +130,15 @@ export default function Home() {
{[
{ name: "Women", image: "/api/placeholder/600/400", count: "2,345+ items" },
{ name: "Men", image: "/api/placeholder/600/400", count: "1,892+ items" },
- { name: "Kids", image: "/api/placeholder/600/400", count: "756+ items" },
+ { name: "Kids", image: "/api/placeholder/600/400", count: "956+ items" },
].map((category) => (
- <div
- key={category.name}
- className="relative group cursor-pointer overflow-hidden rounded-lg bg-gradient-to-br from-neutral-200 to-neutral-300 aspect-[4/3]"
- >
- <div className="absolute inset-0 bg-black/20 group-hover:bg-black/30 transition-colors" />
- <div className="absolute inset-0 flex flex-col justify-end p-6 text-white">
+ <div key={category.name} className="group relative overflow-hidden rounded-2xl bg-neutral-100 dark:bg-neutral-800 aspect-[4/3]">
+ <div className="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent" />
+ <div className="absolute bottom-6 left-6 text-white">
<h3 className="text-2xl font-bold mb-1">{category.name}</h3>
- <p className="text-sm opacity-90">{category.count}</p>
+ <p className="text-neutral-200">{category.count}</p>
</div>
+ <div className="absolute inset-0 bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
))}
</div>
diff --git a/frontend/src/components/footer.tsx b/frontend/src/components/footer.tsx
index d7c8ae7..d64167f 100644
--- a/frontend/src/components/footer.tsx
+++ b/frontend/src/components/footer.tsx
@@ -1,24 +1,38 @@
+"use client";
+
+import { useEffect } from "react";
import Link from "next/link";
import Image from "next/image";
-import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
-import { Separator } from "@/components/ui/separator";
+import { Input } from "@/components/ui/input";
import {
Facebook,
Instagram,
Twitter,
Youtube,
- Mail,
Phone,
+ Mail,
MapPin,
- CreditCard,
- Shield,
Truck,
RefreshCw,
+ Shield,
+ CreditCard,
} from "lucide-react";
export function Footer() {
- const currentYear = new Date().getFullYear();
+ // Preload both logo variants
+ useEffect(() => {
+ const preloadLogos = () => {
+ if (typeof window !== 'undefined') {
+ const lightLogo = new window.Image();
+ const darkLogo = new window.Image();
+ lightLogo.src = '/black-logo.png';
+ darkLogo.src = '/white-logo.png';
+ }
+ };
+
+ preloadLogos();
+ }, []);
const footerLinks = {
shop: [
@@ -53,25 +67,25 @@ export function Footer() {
};
return (
- <footer className="bg-neutral-50 border-t">
+ <footer className="bg-neutral-50 dark:bg-neutral-900 border-t dark:border-neutral-800">
{/* Newsletter Section */}
- <div className="bg-black text-white">
+ <div className="bg-black dark:bg-neutral-950 text-white">
<div className="container mx-auto px-4 py-12">
<div className="max-w-2xl mx-auto text-center">
<h2 className="text-2xl font-bold mb-4">Stay in the loop</h2>
- <p className="text-neutral-300 mb-6">
+ <p className="text-neutral-300 dark:text-neutral-400 mb-6">
Subscribe to our newsletter and be the first to know about new arrivals, sales, and exclusive offers.
</p>
<div className="flex max-w-md mx-auto gap-3">
<Input
placeholder="Enter your email"
- className="bg-white text-black placeholder:text-gray-500"
+ className="bg-white dark:bg-neutral-800 text-black dark:text-white placeholder:text-gray-500 dark:placeholder:text-gray-400 border-neutral-300 dark:border-neutral-600"
/>
- <Button variant="secondary" className="px-8">
+ <Button variant="secondary" className="px-8 bg-white dark:bg-neutral-700 text-black dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-600">
Subscribe
</Button>
</div>
- <p className="text-xs text-neutral-400 mt-3">
+ <p className="text-xs text-neutral-400 dark:text-neutral-500 mt-3">
By subscribing, you agree to our Privacy Policy and Terms of Service.
</p>
</div>
@@ -84,12 +98,23 @@ export function Footer() {
{/* Brand Info */}
<div className="lg:col-span-2">
<Link href="/" className="flex items-center space-x-2 mb-4">
+ {/* Light theme logo - visible by default, hidden in dark mode */}
<Image
src="/black-logo.png"
alt="blcklst"
width={140}
height={45}
- className="h-8 w-auto"
+ className="h-8 w-auto block dark:hidden"
+ priority
+ />
+ {/* Dark theme logo - hidden by default, visible in dark mode */}
+ <Image
+ src="/white-logo.png"
+ alt="blcklst"
+ width={140}
+ height={45}
+ className="h-8 w-auto hidden dark:block"
+ priority
/>
</Link>
<p className="text-muted-foreground mb-6 max-w-md">
@@ -98,22 +123,22 @@ export function Footer() {
{/* Contact Info */}
<div className="space-y-3 mb-6">
- <div className="flex items-center space-x-3 text-sm">
+ <div className="flex items-center space-x-3 text-sm text-foreground">
<Phone className="h-4 w-4 text-muted-foreground" />
<span>+1 (555) 123-4567</span>
</div>
- <div className="flex items-center space-x-3 text-sm">
+ <div className="flex items-center space-x-3 text-sm text-foreground">
<Mail className="h-4 w-4 text-muted-foreground" />
<span>[email protected]</span>
</div>
- <div className="flex items-center space-x-3 text-sm">
+ <div className="flex items-center space-x-3 text-sm text-foreground">
<MapPin className="h-4 w-4 text-muted-foreground" />
<span>123 Fashion St, New York, NY 10001</span>
</div>
</div>
{/* Social Media */}
- <div className="flex space-x-4">
+ <div className="flex space-x-4 mb-4">
<Link href="#" className="text-muted-foreground hover:text-foreground">
<Facebook className="h-5 w-5" />
</Link>
@@ -127,6 +152,28 @@ export function Footer() {
<Youtube className="h-5 w-5" />
</Link>
</div>
+
+ {/* Made with Love */}
+ <p className="text-xs text-muted-foreground/80 flex items-center">
+ made with ❀️ by{" "}
+ <a
+ href="https://mavvisuals.gumroad.com"
+ target="_blank"
+ rel="noopener noreferrer"
+ className="text-primary/80 hover:text-primary transition-colors mx-1 font-normal"
+ >
+ maanv
+ </a>
+ &{" "}
+ <a
+ href="https://surgot.in"
+ target="_blank"
+ rel="noopener noreferrer"
+ className="text-primary/80 hover:text-primary transition-colors ml-1 font-normal"
+ >
+ surgot
+ </a>
+ </p>
</div>
{/* Shop Links */}
@@ -225,19 +272,20 @@ export function Footer() {
</div>
{/* Bottom Footer */}
- <div className="border-t bg-neutral-100">
+ <div className="border-t dark:border-neutral-800 bg-neutral-100 dark:bg-neutral-800">
<div className="container mx-auto px-4 py-6">
- <div className="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0">
- <div className="flex flex-col md:flex-row items-center space-y-2 md:space-y-0 md:space-x-6">
+ <div className="flex flex-col lg:flex-row justify-between items-center space-y-4 lg:space-y-0 lg:gap-8">
+ {/* Left: Copyright and Legal Links */}
+ <div className="flex flex-col sm:flex-row items-center space-y-2 sm:space-y-0 sm:space-x-6 text-center sm:text-left">
<p className="text-sm text-muted-foreground">
- Β© {currentYear} blcklst. All rights reserved.
+ Β© {new Date().getFullYear()} blcklst. All rights reserved.
</p>
<div className="flex space-x-4">
{footerLinks.legal.map((link) => (
<Link
key={link.name}
href={link.href}
- className="text-xs text-muted-foreground hover:text-foreground"
+ className="text-xs text-muted-foreground hover:text-foreground transition-colors"
>
{link.name}
</Link>
@@ -245,14 +293,14 @@ export function Footer() {
</div>
</div>
- {/* Payment Methods */}
+ {/* Right: Payment Methods */}
<div className="flex items-center space-x-2">
<span className="text-xs text-muted-foreground mr-2">We accept:</span>
<div className="flex space-x-1">
{["Visa", "Mastercard", "AmEx", "PayPal", "Apple Pay"].map((method) => (
<div
key={method}
- className="bg-white border rounded px-2 py-1 text-xs font-medium"
+ className="bg-white dark:bg-neutral-700 border dark:border-neutral-600 rounded px-2 py-1 text-xs font-medium text-foreground"
>
{method}
</div>
diff --git a/frontend/src/components/header.tsx b/frontend/src/components/header.tsx
index d64061a..851f637 100644
--- a/frontend/src/components/header.tsx
+++ b/frontend/src/components/header.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useState } from "react";
+import { useState, useEffect } from "react";
import Link from "next/link";
import Image from "next/image";
import { Button } from "@/components/ui/button";
@@ -22,7 +22,7 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
-import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
+import { ThemeToggle } from "@/components/theme-toggle";
import {
Search,
ShoppingBag,
@@ -30,7 +30,6 @@ import {
User,
Menu,
Phone,
- Mail,
Truck,
RefreshCw,
Shield,
@@ -40,7 +39,7 @@ import {
export function Header() {
const [cartItems] = useState(3);
const [wishlistItems] = useState(5);
-
+
const categories = [
{
title: "Women",
@@ -73,6 +72,20 @@ export function Header() {
},
];
+ // Preload both logo variants to ensure smooth loading
+ useEffect(() => {
+ const preloadLogos = () => {
+ if (typeof window !== 'undefined') {
+ const lightLogo = new window.Image();
+ const darkLogo = new window.Image();
+ lightLogo.src = '/black-logo.png';
+ darkLogo.src = '/white-logo.png';
+ }
+ };
+
+ preloadLogos();
+ }, []);
+
return (
<header className="sticky top-0 z-50 w-full bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
{/* Top banner */}
@@ -83,20 +96,24 @@ export function Header() {
</div>
{/* Announcement bar */}
- <div className="bg-neutral-100 text-center py-2 px-4">
+ <div className="bg-neutral-100 dark:bg-neutral-800 text-center py-2 px-4">
<p className="text-sm">
πŸ”₯ <span className="font-semibold">WINTER SALE</span> - Up to 50% off on selected items
</p>
</div>
{/* Main header */}
- <div className="border-b">
+ <div className="border-b dark:border-neutral-800">
<div className="container mx-auto px-4">
<div className="flex h-16 items-center justify-between">
{/* Mobile menu */}
<Sheet>
<SheetTrigger asChild>
- <Button variant="ghost" size="icon" className="md:hidden">
+ <Button
+ variant="ghost"
+ size="icon"
+ className="md:hidden nav-button-transparent backdrop-blur-sm"
+ >
<Menu className="h-5 w-5" />
</Button>
</SheetTrigger>
@@ -128,12 +145,22 @@ export function Header() {
{/* Logo */}
<div className="flex items-center">
<Link href="/" className="flex items-center space-x-2">
+ {/* Light theme logo - visible by default, hidden in dark mode */}
<Image
src="/black-logo.png"
alt="blcklst"
width={120}
height={40}
- className="h-8 w-auto"
+ className="h-8 w-auto block dark:hidden"
+ priority
+ />
+ {/* Dark theme logo - hidden by default, visible in dark mode */}
+ <Image
+ src="/white-logo.png"
+ alt="blcklst"
+ width={120}
+ height={40}
+ className="h-8 w-auto hidden dark:block"
priority
/>
</Link>
@@ -144,16 +171,18 @@ export function Header() {
<NavigationMenuList>
{categories.map((category) => (
<NavigationMenuItem key={category.title}>
- <NavigationMenuTrigger className="font-medium">
+ <NavigationMenuTrigger
+ className="font-medium nav-button-transparent backdrop-blur-sm"
+ >
{category.title}
</NavigationMenuTrigger>
<NavigationMenuContent>
- <div className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
+ <div className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] nav-dropdown-transparent">
{category.items.map((item) => (
<NavigationMenuLink key={item.name} asChild>
<Link
href={item.href}
- className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground"
+ className="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors nav-dropdown-item backdrop-blur-sm"
>
<div className="text-sm font-medium leading-none">{item.name}</div>
</Link>
@@ -165,7 +194,7 @@ export function Header() {
))}
<NavigationMenuItem>
<NavigationMenuLink asChild>
- <Link href="/sale" className="font-medium text-red-600 hover:text-red-700">
+ <Link href="/sale" className="font-medium text-red-600 hover:text-red-700 px-4 py-2 rounded-md nav-button-transparent backdrop-blur-sm transition-colors">
Sale
</Link>
</NavigationMenuLink>
@@ -187,42 +216,57 @@ export function Header() {
{/* Action buttons */}
<div className="flex items-center space-x-2">
{/* Search icon for mobile */}
- <Button variant="ghost" size="icon" className="lg:hidden">
+ <Button
+ variant="ghost"
+ size="icon"
+ className="lg:hidden nav-button-transparent backdrop-blur-sm"
+ >
<Search className="h-5 w-5" />
</Button>
+ {/* Theme toggle */}
+ <ThemeToggle />
+
{/* User menu */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
- <Button variant="ghost" size="icon">
+ <Button
+ variant="ghost"
+ size="icon"
+ className="nav-button-transparent backdrop-blur-sm"
+ >
<User className="h-5 w-5" />
</Button>
</DropdownMenuTrigger>
- <DropdownMenuContent align="end" className="w-56">
- <DropdownMenuItem>
+ <DropdownMenuContent align="end" className="w-56 nav-dropdown-transparent">
+ <DropdownMenuItem className="nav-dropdown-item">
<User className="mr-2 h-4 w-4" />
My Account
</DropdownMenuItem>
- <DropdownMenuItem>
+ <DropdownMenuItem className="nav-dropdown-item">
<Truck className="mr-2 h-4 w-4" />
Orders
</DropdownMenuItem>
- <DropdownMenuItem>
+ <DropdownMenuItem className="nav-dropdown-item">
<Heart className="mr-2 h-4 w-4" />
Wishlist
</DropdownMenuItem>
- <DropdownMenuSeparator />
- <DropdownMenuItem>
+ <DropdownMenuSeparator className="bg-white/20 dark:bg-neutral-800/50" />
+ <DropdownMenuItem className="nav-dropdown-item">
Sign In
</DropdownMenuItem>
- <DropdownMenuItem>
+ <DropdownMenuItem className="nav-dropdown-item">
Create Account
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
{/* Wishlist */}
- <Button variant="ghost" size="icon" className="relative">
+ <Button
+ variant="ghost"
+ size="icon"
+ className="relative nav-button-transparent backdrop-blur-sm"
+ >
<Heart className="h-5 w-5" />
{wishlistItems > 0 && (
<Badge className="absolute -top-1 -right-1 h-5 w-5 rounded-full p-0 text-xs">
@@ -232,7 +276,11 @@ export function Header() {
</Button>
{/* Cart */}
- <Button variant="ghost" size="icon" className="relative">
+ <Button
+ variant="ghost"
+ size="icon"
+ className="relative nav-button-transparent backdrop-blur-sm"
+ >
<ShoppingBag className="h-5 w-5" />
{cartItems > 0 && (
<Badge className="absolute -top-1 -right-1 h-5 w-5 rounded-full p-0 text-xs">
@@ -244,14 +292,18 @@ export function Header() {
{/* Language/Currency */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
- <Button variant="ghost" size="icon">
+ <Button
+ variant="ghost"
+ size="icon"
+ className="nav-button-transparent backdrop-blur-sm"
+ >
<Globe className="h-5 w-5" />
</Button>
</DropdownMenuTrigger>
- <DropdownMenuContent align="end">
- <DropdownMenuItem>πŸ‡ΊπŸ‡Έ USD</DropdownMenuItem>
- <DropdownMenuItem>πŸ‡ͺπŸ‡Ί EUR</DropdownMenuItem>
- <DropdownMenuItem>πŸ‡¬πŸ‡§ GBP</DropdownMenuItem>
+ <DropdownMenuContent align="end" className="nav-dropdown-transparent">
+ <DropdownMenuItem className="nav-dropdown-item">πŸ‡ΊπŸ‡Έ USD</DropdownMenuItem>
+ <DropdownMenuItem className="nav-dropdown-item">πŸ‡ͺπŸ‡Ί EUR</DropdownMenuItem>
+ <DropdownMenuItem className="nav-dropdown-item">πŸ‡¬πŸ‡§ GBP</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
@@ -260,7 +312,7 @@ export function Header() {
</div>
{/* Service features */}
- <div className="hidden md:block border-b bg-neutral-50">
+ <div className="hidden md:block border-b dark:border-neutral-800 bg-neutral-50 dark:bg-neutral-900">
<div className="container mx-auto px-4">
<div className="grid grid-cols-4 gap-4 py-2 text-xs text-muted-foreground">
<div className="flex items-center justify-center space-x-1">
diff --git a/frontend/src/components/hero-section.tsx b/frontend/src/components/hero-section.tsx
index 2450365..7806cbe 100644
--- a/frontend/src/components/hero-section.tsx
+++ b/frontend/src/components/hero-section.tsx
@@ -7,7 +7,7 @@ import Link from "next/link";
export function HeroSection() {
return (
- <section className="relative overflow-hidden bg-gradient-to-br from-neutral-50 via-white to-neutral-100">
+ <section className="relative overflow-hidden bg-gradient-to-br from-neutral-50 via-white to-neutral-100 dark:from-neutral-950 dark:via-neutral-900 dark:to-neutral-800">
{/* Background decoration */}
<div className="absolute inset-0 bg-grid-pattern opacity-5"></div>
<div className="absolute top-20 right-20 w-72 h-72 bg-primary/5 rounded-full blur-3xl"></div>
@@ -89,10 +89,10 @@ export function HeroSection() {
{/* Right side - Product showcase */}
<div className="relative">
{/* Main product image */}
- <div className="relative bg-gradient-to-br from-neutral-100 to-neutral-200 rounded-2xl p-8 lg:p-12">
- <div className="aspect-[3/4] bg-gradient-to-br from-neutral-300 to-neutral-400 rounded-xl flex items-center justify-center">
- <div className="text-center text-neutral-600">
- <div className="w-16 h-16 bg-neutral-500 rounded-full mx-auto mb-4 flex items-center justify-center">
+ <div className="relative bg-gradient-to-br from-neutral-100 to-neutral-200 dark:from-neutral-800 dark:to-neutral-700 rounded-2xl p-8 lg:p-12">
+ <div className="aspect-[3/4] bg-gradient-to-br from-neutral-300 to-neutral-400 dark:from-neutral-600 dark:to-neutral-500 rounded-xl flex items-center justify-center">
+ <div className="text-center text-neutral-600 dark:text-neutral-300">
+ <div className="w-16 h-16 bg-neutral-500 dark:bg-neutral-400 rounded-full mx-auto mb-4 flex items-center justify-center">
<Sparkles className="w-8 h-8 text-white" />
</div>
<p className="font-medium">Featured Product</p>
@@ -107,9 +107,9 @@ export function HeroSection() {
</div>
{/* Floating product cards */}
- <div className="absolute -left-6 top-1/4 bg-white rounded-lg shadow-lg p-4 max-w-[200px] border">
+ <div className="absolute -left-6 top-1/4 bg-white dark:bg-neutral-800 rounded-lg shadow-lg p-4 max-w-[200px] border dark:border-neutral-700">
<div className="flex items-center space-x-3">
- <div className="w-12 h-12 bg-gradient-to-br from-pink-100 to-pink-200 rounded-lg"></div>
+ <div className="w-12 h-12 bg-gradient-to-br from-pink-100 to-pink-200 dark:from-pink-900 dark:to-pink-800 rounded-lg"></div>
<div>
<p className="font-medium text-sm">Summer Dress</p>
<p className="text-xs text-muted-foreground">$89.99</p>
@@ -121,9 +121,9 @@ export function HeroSection() {
</div>
</div>
- <div className="absolute -right-8 bottom-1/4 bg-white rounded-lg shadow-lg p-4 max-w-[200px] border">
+ <div className="absolute -right-8 bottom-1/4 bg-white dark:bg-neutral-800 rounded-lg shadow-lg p-4 max-w-[200px] border dark:border-neutral-700">
<div className="flex items-center space-x-3">
- <div className="w-12 h-12 bg-gradient-to-br from-blue-100 to-blue-200 rounded-lg"></div>
+ <div className="w-12 h-12 bg-gradient-to-br from-blue-100 to-blue-200 dark:from-blue-900 dark:to-blue-800 rounded-lg"></div>
<div>
<p className="font-medium text-sm">Casual Sneakers</p>
<p className="text-xs text-muted-foreground">$129.99</p>
@@ -150,7 +150,7 @@ export function HeroSection() {
{/* Bottom wave */}
<div className="absolute bottom-0 left-0 right-0">
<svg
- className="w-full h-12 fill-white"
+ className="w-full h-12 fill-white dark:fill-neutral-900"
viewBox="0 0 1200 120"
preserveAspectRatio="none"
>
diff --git a/frontend/src/components/product-card.tsx b/frontend/src/components/product-card.tsx
index f790c98..25717f4 100644
--- a/frontend/src/components/product-card.tsx
+++ b/frontend/src/components/product-card.tsx
@@ -71,16 +71,16 @@ export function ProductCard({
return (
<Card
- className="group relative overflow-hidden border-0 shadow-sm hover:shadow-xl transition-all duration-300 cursor-pointer"
+ className="group relative overflow-hidden border-0 shadow-sm hover:shadow-xl dark:shadow-black/30 dark:hover:shadow-black/50 transition-all duration-300 cursor-pointer bg-white dark:bg-neutral-900"
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<Link href={`/product/${id}`}>
<div className="relative overflow-hidden">
{/* Product Image */}
- <div className="aspect-[3/4] bg-neutral-100 relative overflow-hidden">
+ <div className="aspect-[3/4] bg-neutral-100 dark:bg-neutral-800 relative overflow-hidden">
<div
- className="w-full h-full bg-gradient-to-br from-neutral-200 to-neutral-300 flex items-center justify-center transition-transform duration-300 group-hover:scale-105"
+ className="w-full h-full bg-gradient-to-br from-neutral-200 to-neutral-300 dark:from-neutral-700 dark:to-neutral-800 flex items-center justify-center transition-transform duration-300 group-hover:scale-105"
style={{
backgroundImage: `url(${allImages[currentImage]})`,
backgroundSize: 'cover',
@@ -88,9 +88,9 @@ export function ProductCard({
}}
>
{/* Placeholder for actual images */}
- <div className="text-center text-neutral-500">
- <div className="w-16 h-16 bg-neutral-400 rounded-full mx-auto mb-2 flex items-center justify-center">
- <ShoppingBag className="w-8 h-8 text-white" />
+ <div className="text-center text-neutral-500 dark:text-neutral-400">
+ <div className="w-16 h-16 bg-neutral-400 dark:bg-neutral-700 rounded-full mx-auto mb-2 flex items-center justify-center">
+ <ShoppingBag className="w-8 h-8 text-white dark:text-neutral-300" />
</div>
<p className="text-sm font-medium">{name}</p>
</div>
@@ -99,12 +99,12 @@ export function ProductCard({
{/* Badges */}
<div className="absolute top-3 left-3 flex flex-col gap-2">
{isNew && (
- <Badge className="bg-blue-500 hover:bg-blue-600 text-white">
+ <Badge className="bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 text-white shadow-lg">
New
</Badge>
)}
{isSale && (
- <Badge className="bg-red-500 hover:bg-red-600 text-white">
+ <Badge className="bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 text-white shadow-lg">
-{discountPercentage}%
</Badge>
)}
@@ -114,11 +114,11 @@ export function ProductCard({
<Button
variant="ghost"
size="icon"
- className="absolute top-3 right-3 bg-white/80 hover:bg-white text-gray-600 hover:text-red-500 transition-colors"
+ className="absolute top-3 right-3 bg-white/90 dark:bg-neutral-900/90 hover:bg-white dark:hover:bg-neutral-900 text-gray-600 dark:text-gray-300 hover:text-red-500 dark:hover:text-red-400 transition-colors shadow-lg dark:shadow-black/20"
onClick={handleWishlistToggle}
>
<Heart
- className={`h-4 w-4 ${wishlisted ? 'fill-red-500 text-red-500' : ''}`}
+ className={`h-4 w-4 ${wishlisted ? 'fill-red-500 text-red-500 dark:fill-red-400 dark:text-red-400' : ''}`}
/>
</Button>
@@ -129,7 +129,7 @@ export function ProductCard({
<button
key={index}
className={`w-2 h-2 rounded-full transition-colors ${
- index === currentImage ? 'bg-white' : 'bg-white/50'
+ index === currentImage ? 'bg-white dark:bg-neutral-300' : 'bg-white/50 dark:bg-neutral-500/50'
}`}
onClick={(e) => {
e.preventDefault();
@@ -142,7 +142,7 @@ export function ProductCard({
)}
{/* Hover overlay with actions */}
- <div className={`absolute inset-0 bg-black/20 flex items-center justify-center transition-opacity duration-300 ${
+ <div className={`absolute inset-0 bg-black/30 dark:bg-black/50 flex items-center justify-center transition-opacity duration-300 ${
isHovered ? 'opacity-100' : 'opacity-0'
}`}>
<div className="flex gap-3">
@@ -150,7 +150,7 @@ export function ProductCard({
variant="secondary"
size="sm"
onClick={handleQuickView}
- className="bg-white/90 hover:bg-white text-gray-900"
+ className="bg-white/95 dark:bg-neutral-900/95 hover:bg-white dark:hover:bg-neutral-900 text-gray-900 dark:text-white shadow-lg dark:shadow-black/20"
>
<Eye className="h-4 w-4 mr-2" />
Quick View
@@ -158,7 +158,7 @@ export function ProductCard({
<Button
size="sm"
onClick={handleAddToCart}
- className="bg-primary hover:bg-primary/90"
+ className="bg-primary hover:bg-primary/90 dark:bg-primary dark:hover:bg-primary/90 shadow-lg dark:shadow-black/20"
>
<ShoppingBag className="h-4 w-4 mr-2" />
Add to Cart
@@ -168,14 +168,14 @@ export function ProductCard({
</div>
{/* Product Info */}
- <CardContent className="p-4 space-y-3">
+ <CardContent className="p-4 space-y-3 bg-white dark:bg-neutral-900">
{/* Category */}
- <p className="text-xs text-muted-foreground uppercase tracking-wide">
+ <p className="text-xs text-muted-foreground dark:text-neutral-500 uppercase tracking-wide">
{category}
</p>
{/* Product Name */}
- <h3 className="font-semibold text-sm leading-tight line-clamp-2 group-hover:text-primary transition-colors">
+ <h3 className="font-semibold text-sm leading-tight line-clamp-2 group-hover:text-primary dark:group-hover:text-primary transition-colors text-foreground dark:text-neutral-100">
{name}
</h3>
@@ -187,13 +187,13 @@ export function ProductCard({
key={star}
className={`h-3 w-3 ${
star <= rating
- ? 'fill-yellow-400 text-yellow-400'
- : 'text-gray-300'
+ ? 'fill-yellow-400 text-yellow-400 dark:fill-yellow-500 dark:text-yellow-500'
+ : 'text-gray-300 dark:text-neutral-600'
}`}
/>
))}
</div>
- <span className="text-xs text-muted-foreground">
+ <span className="text-xs text-muted-foreground dark:text-neutral-500">
({reviewCount})
</span>
</div>
@@ -204,12 +204,12 @@ export function ProductCard({
{colors.slice(0, 4).map((color, index) => (
<div
key={index}
- className="w-4 h-4 rounded-full border border-gray-300"
+ className="w-4 h-4 rounded-full border border-gray-300 dark:border-neutral-600"
style={{ backgroundColor: color }}
/>
))}
{colors.length > 4 && (
- <span className="text-xs text-muted-foreground ml-1">
+ <span className="text-xs text-muted-foreground dark:text-neutral-500 ml-1">
+{colors.length - 4}
</span>
)}
@@ -218,11 +218,11 @@ export function ProductCard({
{/* Price */}
<div className="flex items-center gap-2">
- <span className="font-bold text-lg">
+ <span className="font-bold text-lg text-foreground dark:text-neutral-100">
${price.toFixed(2)}
</span>
{originalPrice && (
- <span className="text-sm text-muted-foreground line-through">
+ <span className="text-sm text-muted-foreground dark:text-neutral-500 line-through">
${originalPrice.toFixed(2)}
</span>
)}
@@ -232,12 +232,12 @@ export function ProductCard({
{sizes.length > 0 && (
<div className="flex flex-wrap gap-1">
{sizes.slice(0, 4).map((size) => (
- <Badge key={size} variant="outline" className="text-xs px-2 py-1">
+ <Badge key={size} variant="outline" className="text-xs px-2 py-1 border-neutral-300 dark:border-neutral-600 text-neutral-700 dark:text-neutral-300">
{size}
</Badge>
))}
{sizes.length > 4 && (
- <Badge variant="outline" className="text-xs px-2 py-1">
+ <Badge variant="outline" className="text-xs px-2 py-1 border-neutral-300 dark:border-neutral-600 text-neutral-700 dark:text-neutral-300">
+{sizes.length - 4}
</Badge>
)}
diff --git a/frontend/src/components/theme-provider.tsx b/frontend/src/components/theme-provider.tsx
new file mode 100644
index 0000000..220a1f8
--- /dev/null
+++ b/frontend/src/components/theme-provider.tsx
@@ -0,0 +1,9 @@
+"use client"
+
+import * as React from "react"
+import { ThemeProvider as NextThemesProvider } from "next-themes"
+import { type ThemeProviderProps } from "next-themes/dist/types"
+
+export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>
+} \ No newline at end of file
diff --git a/frontend/src/components/theme-toggle.tsx b/frontend/src/components/theme-toggle.tsx
new file mode 100644
index 0000000..17df44e
--- /dev/null
+++ b/frontend/src/components/theme-toggle.tsx
@@ -0,0 +1,50 @@
+"use client"
+
+import * as React from "react"
+import { Moon, Sun, Monitor } from "lucide-react"
+import { useTheme } from "next-themes"
+
+import { Button } from "@/components/ui/button"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+
+export function ThemeToggle() {
+ const { setTheme, theme } = useTheme()
+
+ return (
+ <DropdownMenu>
+ <DropdownMenuTrigger asChild>
+ <Button
+ variant="ghost"
+ size="icon"
+ className="nav-button-transparent backdrop-blur-sm"
+ >
+ <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
+ <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
+ <span className="sr-only">Toggle theme</span>
+ </Button>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent align="end" className="nav-dropdown-transparent">
+ <DropdownMenuItem onClick={() => setTheme("light")} className="flex items-center gap-2 nav-dropdown-item">
+ <Sun className="h-4 w-4" />
+ Light
+ {theme === "light" && <span className="ml-auto text-xs">βœ“</span>}
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => setTheme("dark")} className="flex items-center gap-2 nav-dropdown-item">
+ <Moon className="h-4 w-4" />
+ Dark
+ {theme === "dark" && <span className="ml-auto text-xs">βœ“</span>}
+ </DropdownMenuItem>
+ <DropdownMenuItem onClick={() => setTheme("system")} className="flex items-center gap-2 nav-dropdown-item">
+ <Monitor className="h-4 w-4" />
+ System
+ {theme === "system" && <span className="ml-auto text-xs">βœ“</span>}
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
+ )
+} \ No newline at end of file