Skip to content
Open
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
228 changes: 97 additions & 131 deletions web/src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,174 +9,140 @@ import { ConnectButton } from "@rainbow-me/rainbowkit";
import { useAccount } from "wagmi";
import VouchMeLogo from "../image/VouchMeLogo.png";

const NAVY_BG = "#0B1C2D";
const SHEET_HEIGHT = "100vh";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use dynamic viewport units for reliable full-screen coverage on mobile.

Using 100vh here can still produce visible layout glitches with mobile browser UI chrome. Switch both the sheet height and content calc to 100dvh (or svh fallback) to keep the overlay coverage consistent.

Suggested patch
-const SHEET_HEIGHT = "100vh";
+const SHEET_HEIGHT = "100dvh";
...
-          <div className="h-[calc(100vh-64px)] overflow-y-auto px-6 py-6 space-y-8 text-white">
+          <div className="h-[calc(100dvh-64px)] overflow-y-auto px-6 py-6 space-y-8 text-white">

Also applies to: 104-104

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/Navbar.tsx` at line 13, SHEET_HEIGHT currently uses
"100vh" which can cause mobile chrome layout glitches; update the SHEET_HEIGHT
constant and any related content height calculations (e.g., the calc that
subtracts header/footer at the content usage around the symbol referencing the
content calc near line 104) to use dynamic viewport units—prefer "100dvh" with a
safe fallback to "100svh" or "100vh" if necessary—so replace occurrences of
"100vh" and "calc(100vh - ...)" with "100dvh" (or "calc(100dvh - ...)" plus a
fallback) so the sheet and its content consistently cover the full viewport on
mobile.


const Navbar = ({
toggleWalletConfig,
useEnhancedConfig,
}: {
toggleWalletConfig: () => void;
useEnhancedConfig: boolean;
}) => {
const [isOpen, setIsOpen] = useState(false);
const [isScrolled, setIsScrolled] = useState(false);
const { address } = useAccount();
const [open, setOpen] = useState(false);
const [scrolled, setScrolled] = useState(false);

const pathname = usePathname();
const { address } = useAccount();

const isAuthenticated = !!address;
const isLandingPage = pathname === "/";
const isLanding = pathname === "/";
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const isAuth = !!address;

/* Navbar background on scroll */
useEffect(() => {
if (isLandingPage) {
const handleScroll = () => {
setIsScrolled(window.scrollY > 50);
};

window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
if (!isLanding) {
setScrolled(true);
return;
}
}, [isLandingPage]);

const scrollToSection = (sectionId: string) => {
const element = document.getElementById(sectionId);
if (element) {
element.scrollIntoView({ behavior: "smooth" });
setIsOpen(false);
}
const onScroll = () => setScrolled(window.scrollY > 40);
window.addEventListener("scroll", onScroll);
onScroll();

return () => window.removeEventListener("scroll", onScroll);
}, [isLanding]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/* Lock body scroll */
useEffect(() => {
document.body.style.overflow = open ? "hidden" : "";
return () => {
document.body.style.overflow = "";
};
}, [open]);
Comment thread
aniket866 marked this conversation as resolved.

const scrollTo = (id: string) => {
document.getElementById(id)?.scrollIntoView({ behavior: "smooth" });
setOpen(false);
};

return (
<nav
className={
isLandingPage
? `fixed top-0 w-full z-50 transition-all duration-300 ${
isScrolled
? "bg-black/80 backdrop-blur-md border-b border-gray-800/50"
: "bg-transparent"
}`
: "bg-[#171717]"
}
>
<div className="w-full px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-20">
<Link href="/" className="flex items-center space-x-3">
<div className="flex items-center justify-center w-10 h-10">
<Image
src={VouchMeLogo}
alt="VouchMe Logo"
width={40}
height={40}
className="object-contain"
/>
</div>
<span className="text-white text-2xl font-bold">VouchMe</span>
<>
{/* NAVBAR */}
<nav
className={`fixed top-0 w-full z-50 transition-all ${
!isLanding || scrolled
? "bg-black/80 backdrop-blur border-b border-gray-800"
: "bg-transparent"
}`}
>
<div className="h-20 px-4 flex items-center justify-between">
<Link href="/" className="flex items-center gap-3">
<Image src={VouchMeLogo} alt="VouchMe" width={36} height={36} />
<span className="text-white text-xl font-bold">VouchMe</span>
</Link>

{/* Desktop Navigation */}
<div className="hidden md:flex items-center space-x-8">
{isLandingPage && (
<>
<button
onClick={() => setOpen(true)}
className="md:hidden text-white p-2"
>
<Menu size={26} />
</button>
Comment thread
aniket866 marked this conversation as resolved.

<div className="hidden md:flex">
<ConnectButton />
</div>
</div>
</nav>

{/* No separate backdrop needed: the menu is full-screen and already covers the viewport */}

{/* FULL-SCREEN MENU */}
{open && (
<div
className="fixed inset-0 z-50 md:hidden"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add modal semantics and keyboard-close support for the full-screen menu.

This overlay behaves as a modal, but it lacks dialog semantics and robust keyboard handling. Add role="dialog", aria-modal, an accessible close label, and Escape-to-close.

Suggested patch
+  useEffect(() => {
+    if (!open) return;
+    const onKeyDown = (e: KeyboardEvent) => {
+      if (e.key === "Escape") setOpen(false);
+    };
+    window.addEventListener("keydown", onKeyDown);
+    return () => window.removeEventListener("keydown", onKeyDown);
+  }, [open]);
...
-        <div
-          className="fixed inset-0 z-50 md:hidden"
+        <div
+          role="dialog"
+          aria-modal="true"
+          aria-label="Navigation menu"
+          className="fixed inset-0 z-50 md:hidden"
           style={{ height: SHEET_HEIGHT, backgroundColor: NAVY_BG }}
         >
...
-            <button onClick={() => setOpen(false)} className="text-white">
+            <button
+              onClick={() => setOpen(false)}
+              className="text-white"
+              aria-label="Close menu"
+            >
As per coding guidelines, "The code adheres to best practices associated with React".

Also applies to: 98-100

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/Navbar.tsx` at line 92, The full-screen mobile menu
overlay in Navbar.tsx is missing proper dialog semantics and Escape-key
handling; update the overlay element (the div with className "fixed inset-0 z-50
md:hidden") to include role="dialog" and aria-modal="true" plus either
aria-label or aria-labelledby referencing the menu title, add an accessible
close control (a visually-hidden label or aria-label on the close button) and
wire Escape-to-close by adding a keydown listener in the Navbar component (or
the hook that manages mobileMenuOpen) which calls the existing close handler
(e.g., setMobileMenuOpen(false) or the closeMenu function) and ensure the
listener is cleaned up in useEffect; also apply the same semantic attributes to
the other overlay instance referenced around lines 98–100 so both mobile
overlays are accessible.

style={{ height: SHEET_HEIGHT, backgroundColor: NAVY_BG }}
>
{/* HEADER */}
<div className="h-16 px-5 flex items-center justify-between border-b border-white/10">
<span className="text-white text-lg font-semibold">Menu</span>
<button onClick={() => setOpen(false)} className="text-white">
<X size={24} />
</button>
Comment thread
aniket866 marked this conversation as resolved.
</div>

{/* CONTENT */}
<div className="h-[calc(100vh-64px)] overflow-y-auto px-6 py-6 space-y-8 text-white">
{isLanding && (
<div className="space-y-4">
<button
onClick={() => scrollToSection("features")}
className="text-gray-300 hover:text-white transition-colors font-semibold"
onClick={() => scrollTo("features")}
className="block w-full text-left text-base font-medium tracking-wide"
>
Why VouchMe
</button>
<button
onClick={() => scrollToSection("footer")}
className="text-gray-300 hover:text-white transition-colors font-semibold"
onClick={() => scrollTo("footer")}
className="block w-full text-left text-base font-medium tracking-wide"
>
About Us
</button>
</>
</div>
)}

{!isAuthenticated && (
<div className="border-t border-white/10 pt-6">
<div className="bg-white/5 rounded-2xl px-5 py-4 flex items-center justify-between">
<span className="text-sm opacity-80">Wallet</span>
<ConnectButton />
</div>
</div>

{!isAuth && (
<button
onClick={toggleWalletConfig}
className="bg-gray-700 hover:bg-gray-800 text-white px-4 py-2 rounded-lg font-medium transition-colors"
onClick={() => {
toggleWalletConfig();
setOpen(false);
}}
className="w-full bg-indigo-600 hover:bg-indigo-700 py-3 rounded-2xl font-semibold transition"
>
{useEnhancedConfig
? "Disable ReOwn Wallets"
: "Enable ReOwn Wallets"}
</button>
)}

<ConnectButton />
</div>

{/* Mobile Menu Button */}
<div className="md:hidden">
<button
onClick={() => setIsOpen(!isOpen)}
className="text-gray-300 hover:text-white p-2"
>
{isOpen ? (
<X className="h-6 w-6" />
) : (
<Menu className="h-6 w-6" />
)}
</button>
</div>
</div>

{/* Mobile Navigation */}
{isOpen && (
<div className="md:hidden">
<div className="px-2 pt-2 pb-3 space-y-3">
{isLandingPage && (
<>
<button
onClick={() => scrollToSection("features")}
className="block w-full text-left px-3 py-2 text-gray-300 hover:text-white transition-colors"
>
Why VouchMe
</button>
<button
onClick={() => scrollToSection("footer")}
className="block w-full text-left px-3 py-2 text-gray-300 hover:text-white transition-colors"
>
About Us
</button>
</>
)}

{!isLandingPage && isAuthenticated && (
<>
<Link
href="/dashboard"
className="block w-full text-left px-3 py-2 text-gray-300 hover:text-white transition-colors"
onClick={() => setIsOpen(false)}
>
Dashboard
</Link>
<Link
href="/profile"
className="block w-full text-left px-3 py-2 text-gray-300 hover:text-white transition-colors"
onClick={() => setIsOpen(false)}
>
Profile
</Link>
</>
)}

{!isAuthenticated && (
<button
onClick={toggleWalletConfig}
className="block w-auto text-left px-3 py-2 bg-gray-700 hover:bg-gray-800 text-white rounded-lg font-medium transition-colors"
>
{useEnhancedConfig
? "Disable ReOwn Wallets"
: "Enable ReOwn Wallets"}
</button>
)}

<div className="py-2">
<ConnectButton />
</div>
</div>
</div>
)}
</div>
</nav>
)}
</>
);
};

Expand Down