aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components
diff options
context:
space:
mode:
authorLibravatarLibravatar Biswa Kalyan Bhuyan <[email protected]> 2025-05-28 19:44:26 +0530
committerLibravatarLibravatar Biswa Kalyan Bhuyan <[email protected]> 2025-05-28 19:44:26 +0530
commit5e3b37288d96277a6eacb7d6464760b63f72874a (patch)
treea511f27f5bc9bc69e6ce30dbea16d7994494c837 /frontend/src/components
parent7b85f1e2c3717ddd9eee0e668e3b4d48139e2407 (diff)
downloadblcklst-5e3b37288d96277a6eacb7d6464760b63f72874a.tar.gz
blcklst-5e3b37288d96277a6eacb7d6464760b63f72874a.tar.bz2
blcklst-5e3b37288d96277a6eacb7d6464760b63f72874a.zip
feat: improved UI and added dynamic theme toggle
- improved the nav bar components - added the theme toggle button to toggle theme - fixed the button background for the nav bar - fixed the theme color issue to the ThemeToggle funtion - added more vibrant colors - fixed the theme logo render
Diffstat (limited to 'frontend/src/components')
-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
6 files changed, 248 insertions, 89 deletions
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