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
58 changes: 26 additions & 32 deletions client/package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions client/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import MindMapEditor from "./pages/MindMapEditor";
import Profile from "./pages/Profile.js";
import SubmitFeedback from "./pages/SubmitFeedback";
import Todo from "./pages/Todo";
import HomeNew from "./pages/HomeNew";


const App = () => {
Expand All @@ -29,6 +30,7 @@ const App = () => {
<ScrollToTop />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/homenew" element={<HomeNew />} />
<Route path="/tasks" element={<Todo />} />
<Route path="/syllabus" element={<Syllabus />} />
<Route path="/notes" element={<Notes />} />
Expand Down
130 changes: 96 additions & 34 deletions client/src/components/Navbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ html[data-theme="dark"] .navbar {
.navbar-links {
display: flex;
align-items: center;
gap: 0.1rem;
gap: 0.25rem;
list-style: none;
margin: 0;
padding: 0;
Expand All @@ -77,30 +77,49 @@ html[data-theme="dark"] .navbar {
color: var(--muted);
text-decoration: none;
font-weight: 500;
font-size: 0.875rem;
padding: 0.35rem 0.6rem;
border-radius: 6px;
font-size: 1.05rem; /* Increased font size for legibility */
padding: 0.4rem 0.95rem; /* Adjusted slightly for 3px double border height parity */
border-radius: 10px; /* Beautiful rounded rect box */
border: 3px double transparent; /* Concentric double border layout standard */
white-space: nowrap;
transition: background 0.18s ease, color 0.18s ease;
transition: background 0.25s cubic-bezier(0.4, 0, 0.2, 1),
border-color 0.25s cubic-bezier(0.4, 0, 0.2, 1),
color 0.25s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.22s ease;
letter-spacing: 0.01em;
}

.navbar-link:hover {
background: rgba(99, 102, 241, 0.08);
background: rgba(99, 102, 241, 0.04);
color: #4f46e5;
border-color: rgba(99, 102, 241, 0.16); /* Two concentric active hover lines */
transform: translateY(-1px);
}

/* Active pill highlight */
/* Active "double border lines one after another" rounded rectangular highlight */
.navbar-link.active {
background: rgba(99, 102, 241, 0.12);
color: #4f46e5;
background: rgba(226, 232, 240, 0.45) !important; /* Soft premium grey-blue pill background */
border-color: rgba(15, 23, 42, 0.22) !important; /* Two thin concentric border lines */
color: #0f172a !important; /* Premium dark color text */
font-weight: 600;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
}

html[data-theme="dark"] .navbar-link:hover,
html[data-theme="dark"] .navbar-link.active {
background: rgba(139, 180, 255, 0.12);
html[data-theme="dark"] .navbar-link {
color: #cbd5e1;
}

html[data-theme="dark"] .navbar-link:hover {
background: rgba(139, 180, 255, 0.06);
color: #8ab4ff;
border-color: rgba(139, 180, 255, 0.25); /* Dark mode concentric hover */
}

html[data-theme="dark"] .navbar-link.active {
background: rgba(255, 255, 255, 0.05) !important; /* Semi-transparent in dark theme */
border-color: rgba(255, 255, 255, 0.22) !important; /* Two thin white concentric border lines */
color: #ffffff !important; /* Premium bright white active text */
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);
}

/* ── Dropdown "More" menu ── */
Expand All @@ -114,21 +133,52 @@ html[data-theme="dark"] .navbar-link.active {
gap: 0.3rem;
color: var(--muted);
background: none;
border: none;
border: 3px double transparent; /* Concentric double border layout standard */
font-family: inherit;
font-weight: 500;
font-size: 0.875rem;
padding: 0.35rem 0.6rem;
border-radius: 6px;
font-size: 1.05rem; /* Match increased link font size */
padding: 0.4rem 0.95rem; /* Match link padding */
border-radius: 10px; /* Match link border-radius */
cursor: pointer;
white-space: nowrap;
transition: background 0.18s ease, color 0.18s ease;
transition: background 0.25s cubic-bezier(0.4, 0, 0.2, 1),
border-color 0.25s cubic-bezier(0.4, 0, 0.2, 1),
color 0.25s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.22s ease;
letter-spacing: 0.01em;
}

.navbar-dropdown-btn:hover {
background: rgba(99, 102, 241, 0.08);
background: rgba(99, 102, 241, 0.04);
color: #4f46e5;
border-color: rgba(99, 102, 241, 0.16);
transform: translateY(-1px);
}

/* Active box highlight for More dropdown when its children routes are active */
.navbar-dropdown-btn.active {
background: rgba(226, 232, 240, 0.45) !important;
border-color: rgba(15, 23, 42, 0.22) !important; /* Two thin concentric border lines */
color: #0f172a !important;
font-weight: 600;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
}

html[data-theme="dark"] .navbar-dropdown-btn {
color: #cbd5e1;
}

html[data-theme="dark"] .navbar-dropdown-btn:hover {
background: rgba(139, 180, 255, 0.06);
color: #8ab4ff;
border-color: rgba(139, 180, 255, 0.25);
}

html[data-theme="dark"] .navbar-dropdown-btn.active {
background: rgba(255, 255, 255, 0.05) !important;
border-color: rgba(255, 255, 255, 0.22) !important; /* Two thin white concentric border lines */
color: #ffffff !important;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);
}

.navbar-dropdown-btn svg,
Expand Down Expand Up @@ -169,11 +219,11 @@ html[data-theme="dark"] .navbar-link.active {

.navbar-dropdown-menu a {
display: block;
padding: 0.55rem 0.9rem;
padding: 0.6rem 1rem;
border-radius: 8px;
color: var(--muted);
text-decoration: none;
font-size: 0.875rem;
font-size: 0.96rem; /* Increased size */
font-weight: 500;
transition: background 0.15s ease, color 0.15s ease;
}
Expand Down Expand Up @@ -235,31 +285,42 @@ html[data-theme="dark"] .navbar-theme-toggle:hover {

/* ── Profile avatar ── */
.navbar-profile-link {
display: flex;
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: 50%;
background: var(--card, #f8fafc);
border: 1px solid var(--border, #e2e8f0);
cursor: pointer;
flex-shrink: 0;
transition: transform 0.2s ease;
overflow: hidden;
transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.navbar-profile-link:hover {
transform: scale(1.08);
background: rgba(99, 102, 241, 0.08);
border-color: #4f46e5;
transform: scale(1.05);
}

html[data-theme="dark"] .navbar-profile-link {
background: #101826;
border-color: #263243;
}

html[data-theme="dark"] .navbar-profile-link:hover {
background: rgba(139, 180, 255, 0.12);
border-color: #8ab4ff;
}

.navbar-profile-img {
width: 34px;
height: 34px;
width: 100%;
height: 100%;
border-radius: 50%;
object-fit: cover;
border: 2px solid transparent;
background-clip: padding-box;
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0);
transition: box-shadow 0.2s ease;
}

.navbar-profile-link:hover .navbar-profile-img {
box-shadow: 0 0 0 2px #6366f1;
display: block;
}

/* ── Mobile hamburger ── */
Expand Down Expand Up @@ -360,7 +421,8 @@ html[data-theme="dark"] .navbar-link-mobile.active {
margin-top: 0.25rem;
}

.navbar-mobile-controls .navbar-theme-toggle {
.navbar-mobile-controls .navbar-theme-toggle,
.navbar-mobile-controls .navbar-profile-link {
width: 38px;
height: 38px;
}
Expand Down
72 changes: 40 additions & 32 deletions client/src/components/Navbar.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import React, { useState, useEffect, useRef } from "react";
import { Link, NavLink } from "react-router-dom";
import { Link, NavLink, useLocation } from "react-router-dom";
import "./Navbar.css";
import { useTheme } from "../theme/ThemeProvider";
import { FaMoon, FaSun, FaChevronDown } from "react-icons/fa";

const DEFAULT_AVATAR = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><defs><linearGradient id='avatarGrad' x1='0%25' y1='0%25' x2='100%25' y2='100%25'><stop offset='0%25' stop-color='%23818cf8'/><stop offset='100%25' stop-color='%234f46e5'/></linearGradient></defs><circle cx='16' cy='16' r='16' fill='url(%23avatarGrad)'/><circle cx='16' cy='13' r='5' fill='%23ffffff'/><path d='M7 26.5c0-4.5 3.5-8 8-8h2c4.5 0 8 3.5 8 8' fill='none' stroke='%23ffffff' stroke-width='2.5' stroke-linecap='round'/></svg>";

const user = {
avatar: "https://avatar.iran.liara.run/public/boy",
avatar: null, // Set to null by default to showcase our beautiful default SVG profile image
};


// Primary links always visible in the bar
const primaryLinks = [
{ to: "/", label: "Home" },
Expand All @@ -34,6 +37,11 @@ const Navbar = () => {
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const dropdownRef = useRef(null);
const location = useLocation();

const currentPath = location.pathname;
const isHomeActive = currentPath === "/" || currentPath === "/homenew";
const isMoreActive = moreLinks.some(({ to }) => currentPath === to || currentPath.startsWith(to + "/"));

const toggleMobileMenu = () => setIsMobileMenuOpen((prev) => !prev);
const closeMobileMenu = () => setIsMobileMenuOpen(false);
Expand Down Expand Up @@ -72,27 +80,27 @@ const Navbar = () => {

{/* Primary nav links */}
<ul className="navbar-links">
{primaryLinks.map(({ to, label }) => (
<li key={to}>
<NavLink
to={to}
end={to === "/"}
className={({ isActive }) =>
"navbar-link" + (isActive ? " active" : "")
}
>
{label}
</NavLink>
</li>
))}
{primaryLinks.map(({ to, label }) => {
const isActive = to === "/" ? isHomeActive : (currentPath === to || currentPath.startsWith(to + "/"));
return (
<li key={to}>
<NavLink
to={to}
className={`navbar-link${isActive ? " active" : ""}`}
>
{label}
</NavLink>
</li>
);
})}

{/* "More" dropdown */}
<li
className={`navbar-dropdown${isDropdownOpen ? " open" : ""}`}
ref={dropdownRef}
>
<button
className="navbar-dropdown-btn"
className={`navbar-dropdown-btn${isMoreActive ? " active" : ""}`}
onClick={() => setIsDropdownOpen((prev) => !prev)}
aria-expanded={isDropdownOpen}
aria-haspopup="true"
Expand Down Expand Up @@ -131,7 +139,7 @@ const Navbar = () => {

{/* Profile */}
<Link to="/profile" className="navbar-profile-link" aria-label="User profile">
<img src={user.avatar} alt="User Profile" className="navbar-profile-img" />
<img src={user.avatar || DEFAULT_AVATAR} alt="User Profile" className="navbar-profile-img" />
</Link>

{/* Hamburger β€” mobile only */}
Expand All @@ -149,20 +157,20 @@ const Navbar = () => {
{/* Mobile slide-down menu */}
<div className={`navbar-menu-mobile${isMobileMenuOpen ? " active" : ""}`}>
<ul className="navbar-links-mobile">
{allLinks.map(({ to, label }) => (
<li key={to}>
<NavLink
to={to}
end={to === "/"}
className={({ isActive }) =>
"navbar-link-mobile" + (isActive ? " active" : "")
}
onClick={closeMobileMenu}
>
{label}
</NavLink>
</li>
))}
{allLinks.map(({ to, label }) => {
const isActive = to === "/" ? isHomeActive : (currentPath === to || currentPath.startsWith(to + "/"));
return (
<li key={to}>
<NavLink
to={to}
className={`navbar-link-mobile${isActive ? " active" : ""}`}
onClick={closeMobileMenu}
>
{label}
</NavLink>
</li>
);
})}
</ul>

{/* Mobile bottom controls */}
Expand All @@ -180,7 +188,7 @@ const Navbar = () => {
onClick={closeMobileMenu}
aria-label="User profile"
>
<img src={user.avatar} alt="User Profile" className="navbar-profile-img" />
<img src={user.avatar || DEFAULT_AVATAR} alt="User Profile" className="navbar-profile-img" />
</Link>
</div>
</div>
Expand Down
Loading