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
150 changes: 69 additions & 81 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,68 @@
import { Link } from "react-router-dom";
import { Link, useLocation } from "react-router-dom";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use NavLink to simplify active state and improve a11y (aria-current).

You can drop manual pathname checks and get correct exact/partial matching + aria-current for free.

- import { Link, useLocation } from "react-router-dom";
+ import { Link, NavLink } from "react-router-dom";
@@
- const location = useLocation();
@@
-          {navLinks.map((link) => (
-            <Link
-              key={link.to}
-              to={link.to}
-              className={`relative text-lg font-medium px-3 py-2 rounded-lg transition-all duration-300 group
-                ${
-                  location.pathname === link.to
-                    ? "text-indigo-500 dark:text-indigo-400 font-semibold bg-indigo-50 dark:bg-indigo-900"
-                    : "hover:text-indigo-400 dark:hover:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-gray-800"
-                }`}
-            >
+          {navLinks.map((link) => (
+            <NavLink
+              key={link.to}
+              to={link.to}
+              end={link.to === "/"}
+              className={({ isActive }) =>
+                `relative text-lg font-medium px-3 py-2 rounded-lg transition-all duration-300 group ${
+                  isActive
+                    ? "text-indigo-500 dark:text-indigo-400 font-semibold bg-indigo-50 dark:bg-indigo-900"
+                    : "hover:text-indigo-400 dark:hover:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-gray-800"
+                }`
+              }
+            >
@@
-            </Link>
+            </NavLink>
@@
-          {navLinks.map((link) => (
-            <Link
-              key={link.to}
-              to={link.to}
-              onClick={() => setIsOpen(false)}
-              className={`block text-lg font-medium px-3 py-2 rounded-lg transition-all duration-300
-                ${
-                  location.pathname === link.to
-                    ? "text-indigo-500 dark:text-indigo-400 font-semibold bg-indigo-50 dark:bg-indigo-900"
-                    : "hover:text-indigo-400 dark:hover:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-gray-800"
-                }`}
-            >
+          {navLinks.map((link) => (
+            <NavLink
+              key={link.to}
+              to={link.to}
+              end={link.to === "/"}
+              onClick={() => setIsOpen(false)}
+              className={({ isActive }) =>
+                `block text-lg font-medium px-3 py-2 rounded-lg transition-all duration-300 ${
+                  isActive
+                    ? "text-indigo-500 dark:text-indigo-400 font-semibold bg-indigo-50 dark:bg-indigo-900"
+                    : "hover:text-indigo-400 dark:hover:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-gray-800"
+                }`
+              }
+            >
@@
-            </Link>
+            </NavLink>

Also applies to: 9-9, 39-54, 101-115

🤖 Prompt for AI Agents
In src/components/Navbar.tsx around lines 1 (and also apply to ranges 9-9,
39-54, 101-115), you are using Link and manual pathname checks to set an active
state and ARIA attributes; replace Link with React Router's NavLink (update the
import) and remove the manual pathname comparisons, relying on NavLink's
built-in active matching (use exact where needed or the end prop for exact
matching) which automatically sets aria-current="page"; update any active
className logic to use NavLink's className callback (or style callback) to
return the correct classes based on isActive.

import { useState, useContext } from "react";
import { ThemeContext } from "../context/ThemeContext";
import { Moon, Sun } from 'lucide-react';

import { Moon, Sun } from "lucide-react";

const Navbar: React.FC = () => {

const [isOpen, setIsOpen] = useState<boolean>(false);
const themeContext = useContext(ThemeContext);
const location = useLocation();

if (!themeContext)
return null;
if (!themeContext) return null;

const { toggleTheme, mode } = themeContext;

const navLinks = [
{ to: "/", label: "Home" },
{ to: "/track", label: "Tracker" },
{ to: "/contributors", label: "Contributors" },
{ to: "/login", label: "Login" },
];

return (
<nav className="sticky top-0 z-50 bg-white dark:bg-gray-900 text-black dark:text-white border-b border-gray-100 dark:border-gray-800 transition-colors duration-300">
<nav className="sticky top-0 z-50 bg-white/70 dark:bg-gray-900/70 backdrop-blur-lg text-black dark:text-white border-b border-gray-200 dark:border-gray-800 shadow-md transition-colors duration-300">
<div className="container mx-auto px-6 py-4 flex justify-between items-center">
{/* Logo Section */}
<Link
to="/"
className="text-2xl font-bold hover:text-gray-300 cursor-pointer flex items-center"
className="text-2xl font-extrabold tracking-wide flex items-center group"
>
<img src="/crl-icon.png" alt="CRL Icon" className="h-8 mr-2" />
GitHub Tracker
<img src="/crl-icon.png" alt="CRL Icon" className="h-9 mr-2" />
<span className="relative">
GitHub Tracker
<span className="absolute -bottom-1 left-0 w-0 h-[3px] bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 transition-all duration-500 group-hover:w-full rounded"></span>
</span>
</Link>

{/* Desktop Links */}
<div className="hidden md:flex space-x-6">
<Link
to="/"
className="text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
>
Home
</Link>
<Link
to="/track"
className="text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
>
Tracker
</Link>
<Link
to="/contributors"
className="text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
>
Contributors
</Link>
<Link
to="/login"
className="text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
>
Login
</Link>
{navLinks.map((link) => (
<Link
key={link.to}
to={link.to}
className={`relative text-lg font-medium px-3 py-2 rounded-lg transition-all duration-300 group
${
location.pathname === link.to
? "text-indigo-500 dark:text-indigo-400 font-semibold bg-indigo-50 dark:bg-indigo-900"
: "hover:text-indigo-400 dark:hover:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-gray-800"
}`}
>
{link.label}
{/* Gradient underline hover */}
<span className="absolute bottom-0 left-0 w-0 h-[2px] bg-gradient-to-r from-indigo-500 via-purple-500 to-pink-500 transition-all duration-500 group-hover:w-full"></span>
</Link>
))}

{/* Theme Toggle */}
<button
onClick={toggleTheme}
className="text-sm font-semibold px-3 py-1 rounded border border-gray-500 hover:text-gray-300 hover:border-gray-300 transition duration-200"
className="ml-4 p-2 rounded-full border border-gray-400 dark:border-gray-600 hover:scale-110 hover:border-indigo-400 transition-all duration-500 transform hover:rotate-12"
>
{mode === "dark" ? <Sun className="h-5 w-5" /> : <Moon className="h-5 w-5" />}
{mode === "dark" ? (
<Sun className="h-5 w-5 text-yellow-400 drop-shadow-glow" />
) : (
<Moon className="h-5 w-5 text-indigo-500 drop-shadow-glow" />
)}
</button>
</div>

Expand Down Expand Up @@ -86,56 +92,38 @@ const Navbar: React.FC = () => {
</div>

{/* Mobile Links */}
{isOpen && (
<div className="md:hidden bg-white dark:bg-gray-800 text-black dark:text-white">
<div className="space-y-4 px-6 py-4">
<Link
to="/"
className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
onClick={() => setIsOpen(false)}
>
Home
</Link>
<Link
to="/about"
className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
onClick={() => setIsOpen(false)}
>
About
</Link>
<Link
to="/contact"
className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
onClick={() => setIsOpen(false)}
>
Contact
</Link>
<Link
to="/contributors"
className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
onClick={() => setIsOpen(false)}
>
Contributors
</Link>
<div
className={`md:hidden overflow-hidden transition-all duration-500 ${
isOpen ? "max-h-96 opacity-100" : "max-h-0 opacity-0"
}`}
>
<div className="bg-white/90 dark:bg-gray-800/90 backdrop-blur-md text-black dark:text-white border-t border-gray-200 dark:border-gray-700 px-6 py-4 space-y-4">
{navLinks.map((link) => (
<Link
to="/login"
className="block text-lg font-medium hover:text-gray-300 transition-all px-2 py-1 border border-transparent hover:border-gray-400 rounded"
key={link.to}
to={link.to}
onClick={() => setIsOpen(false)}
className={`block text-lg font-medium px-3 py-2 rounded-lg transition-all duration-300
${
location.pathname === link.to
? "text-indigo-500 dark:text-indigo-400 font-semibold bg-indigo-50 dark:bg-indigo-900"
: "hover:text-indigo-400 dark:hover:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-gray-800"
}`}
>
Login
{link.label}
</Link>
<button
onClick={() => {
toggleTheme();
setIsOpen(false);
}}
className="text-sm font-semibold px-3 py-1 rounded border border-gray-500 hover:text-gray-300 hover:border-gray-300 transition duration-200 w-full text-left"
>
{mode === "dark" ? "🌞 Light" : "🌙 Dark"}
</button>
</div>
))}
<button
onClick={() => {
toggleTheme();
setIsOpen(false);
}}
className="w-full text-left text-sm font-semibold px-3 py-2 rounded-lg border border-gray-500 hover:border-indigo-400 hover:text-indigo-400 dark:hover:text-indigo-300 transition duration-300"
>
{mode === "dark" ? "🌞 Light Mode" : "🌙 Dark Mode"}
</button>
</div>
)}
</div>
</nav>
);
};
Expand Down
21 changes: 12 additions & 9 deletions tailwind.config.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: 'class',
content: [
"./index.html", // For any HTML files in the root
"./src/**/*.{js,jsx,ts,tsx}", // For all JS/JSX/TS/TSX files inside src folder
],
theme: {
extend: {},
content: [
"./index.html",
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {
dropShadow: {
glow: "0 0 8px rgba(255, 255, 255, 0.6)", // white glow
},
},
plugins: [],
}
},
plugins: [],
}