Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 76 additions & 16 deletions src/componets/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ import { useSelector, useDispatch } from "react-redux";
import { logout } from "../Store/authSlice";
import styled from "styled-components";
import { motion, AnimatePresence } from "framer-motion";
import { FaCoffee, FaUser, FaShoppingCart, FaBars, FaTimes } from "react-icons/fa";
import { FaCoffee, FaUser, FaShoppingCart, FaBars, FaTimes, FaSun, FaMoon } from "react-icons/fa";

const NavbarContainer = styled(motion.nav)`
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem 5%;
background: linear-gradient(135deg, rgba(44, 19, 11, 0.98) 0%, rgba(66, 33, 11, 0.98) 100%);
background: var(--nav-bg);
backdrop-filter: blur(10px);
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 998;
border-bottom: 1px solid rgba(210, 105, 30, 0.3);
border-bottom: 1px solid var(--border);
transition: all 0.3s ease;

&.scrolled {
Expand Down Expand Up @@ -70,7 +70,7 @@ const NavItem = styled(motion.div)`
padding: 0.5rem 0;

a,span {
color: #e6d5b8;
color: var(--text);
font-family: 'Poppins', sans-serif;
font-weight: 500;
font-size: 1.1rem;
Expand All @@ -83,7 +83,7 @@ const NavItem = styled(motion.div)`
padding: 0.5rem 0;

&:hover {
color: #f4a460;
color: var(--accent);
}

&::after {
Expand All @@ -103,7 +103,7 @@ const NavItem = styled(motion.div)`
}

&.active a {
color: #d2691e;
color: var(--primary);
font-weight: 600;

&::after {
Expand All @@ -121,7 +121,7 @@ const DropdownMenu = styled(motion.div)`
padding: 1rem;
min-width: 200px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(210, 105, 30, 0.3);
border: 1px solid var(--border);
display: none;
flex-direction: column;
gap: 0.8rem;
Expand All @@ -133,7 +133,7 @@ const DropdownMenu = styled(motion.div)`
transition: all 0.3s ease;

&:hover {
background: rgba(210, 105, 30, 0.2);
background: rgba(210, 105, 30, 0.12);
transform: translateX(5px);
}
}
Expand Down Expand Up @@ -168,17 +168,17 @@ const AuthButton = styled(motion.button)`

&.login {
background: transparent;
color: #e6d5b8;
border: 1px solid #d2691e;
color: var(--text);
border: 1px solid var(--primary);

&:hover {
background: rgba(210, 105, 30, 0.2);
background: rgba(210, 105, 30, 0.12);
}
}

&.register {
background: linear-gradient(to right, #d2691e, #cd853f);
color: white;
background: linear-gradient(to right, var(--primary), #cd853f);
color: var(--surface);
box-shadow: 0 4px 15px rgba(210, 105, 30, 0.4);

&:hover {
Expand All @@ -189,15 +189,29 @@ const AuthButton = styled(motion.button)`

&.logout {
background: transparent;
color: #e6d5b8;
border: 1px solid #8b0000;
color: var(--text);
border: 1px solid rgba(139, 0, 0, 0.25);

&:hover {
background: rgba(139, 0, 0, 0.2);
background: rgba(139, 0, 0, 0.08);
}
}
`;

const ThemeToggleButton = styled(motion.button)`
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 8px;
border: 1px solid var(--border);
background: transparent;
color: var(--text);
cursor: pointer;
padding: 0;
`;

const MobileMenuButton = styled(motion.button)`
display: none;
background: transparent;
Expand Down Expand Up @@ -291,6 +305,14 @@ function Navbar() {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);
const [activeDropdown, setActiveDropdown] = useState(null);
// Theme state: we reflect the presence of the `.dark` class on the <html> element
const [isDark, setIsDark] = useState(() => {
try {
return document.documentElement.classList.contains('dark');
} catch (e) {
return false;
}
});

useEffect(() => {
const handleScroll = () => {
Expand All @@ -309,6 +331,22 @@ function Navbar() {
}
}, [isMobileMenuOpen]);

// Toggle theme and persist preference
const toggleTheme = () => {
try {
const willBeDark = !document.documentElement.classList.contains('dark');
if (willBeDark) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
localStorage.setItem('themeMode', willBeDark ? 'dark' : 'light');
setIsDark(willBeDark);
} catch (e) {
// ignore
}
};

const handleLogout = () => {
dispatch(logout());
navigate("/");
Expand Down Expand Up @@ -407,6 +445,16 @@ function Navbar() {
</NavLinks>

<AuthButtons>
<ThemeToggleButton
onClick={toggleTheme}
aria-label="Toggle theme"
aria-pressed={isDark}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
title={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
>
{isDark ? <FaSun /> : <FaMoon />}
</ThemeToggleButton>
{isLoggedIn ? (
<>
<NavItem>
Expand Down Expand Up @@ -470,6 +518,18 @@ function Navbar() {
exit={{ opacity: 0, x: "100%" }}
transition={{ type: "tween", duration: 0.3 }}
>
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '1rem' }}>
<ThemeToggleButton
onClick={() => { toggleTheme(); setIsMobileMenuOpen(false); }}
aria-label="Toggle theme"
aria-pressed={isDark}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
title={isDark ? 'Switch to light mode' : 'Switch to dark mode'}
>
{isDark ? <FaSun /> : <FaMoon />}
</ThemeToggleButton>
</div>
{navItems.map((item) => (
<React.Fragment key={item.path || item.title}>
<MobileNavItem
Expand Down
42 changes: 38 additions & 4 deletions src/index.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,47 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
/* Theme variables: light defaults, dark overrides below */
:root {
/* Backgrounds and surfaces */
--bg: #FAF9F6; /* off-white */
--surface: #FFFFFF;

/* Text */
--text: #111827; /* very dark gray */
--muted: #6B7280;

/* Accent / brand */
--primary: #d2691e; /* coffee brown */
--accent: #f4a460;

/* Borders and UI */
--border: rgba(0,0,0,0.08);
--nav-bg: linear-gradient(135deg, rgba(44, 19, 11, 0.98) 0%, rgba(66, 33, 11, 0.98) 100%);
--nav-surface: rgba(44, 19, 11, 0.98);
}

/* Dark theme overrides */
.dark {
--bg: #0b1220; /* dark navy */
--surface: #0f1724;
--text: #E6E6E6;
--muted: #9CA3AF;
--primary: #D9A15A; /* lighter accent for dark */
--accent: #f4a460;
--border: rgba(255,255,255,0.06);
--nav-bg: linear-gradient(135deg, rgba(6, 7, 14, 0.85) 0%, rgba(16, 20, 30, 0.85) 100%);
--nav-surface: rgba(6, 7, 14, 0.9);
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: var(--bg);
color: var(--text);
}

code {
Expand All @@ -22,8 +56,8 @@ code {
bottom: 20px;
right: 20px;
z-index: 99;
background-color: #6F4E37; /* Coffee Brown */
color: #FAF9F6; /* Off-White */
background-color: var(--primary);
color: var(--surface);
border: none;
outline: none;
cursor: pointer;
Expand All @@ -36,8 +70,8 @@ code {

/* Hover effect */
#scrollToTop:hover {
background-color: #D4A373; /* Golden Yellow */
color: #4B4B4B; /* Charcoal Gray */
background-color: var(--accent);
color: var(--text);
transform: scale(1.1); /* Slightly enlarge the button */
}

12 changes: 12 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";

// Apply saved theme (light/dark) from localStorage before React mounts.
// Requirement: default theme remains unchanged unless user toggles.
try {
const saved = localStorage.getItem('themeMode');
if (saved === 'dark') {
document.documentElement.classList.add('dark');
} else if (saved === 'light') {
document.documentElement.classList.remove('dark');
}
} catch (e) {
// ignore (e.g. SSR or restricted env)
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
Expand Down