Skip to content
Closed
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
3 changes: 2 additions & 1 deletion frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ export default function RootLayout({
<AutoScrollToTop />
<Header isGitHubAuthEnabled={IS_GITHUB_AUTH_ENABLED} />
<BreadCrumbs />
{children}
<main className="flex min-w-0 flex-1 flex-col">{children}</main>

<Footer />
<ScrollToTop />
</Providers>
Expand Down
222 changes: 119 additions & 103 deletions frontend/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import { useEffect, useState } from 'react'
import { desktopViewMinWidth, headerLinks } from 'utils/constants'
import { cn } from 'utils/utility'
import ModeToggle from 'components/ModeToggle'
import NavButton from 'components/NavButton'
import NavDropdown from 'components/NavDropDown'
import UserMenu from 'components/UserMenu'

export default function Header({ isGitHubAuthEnabled }: { readonly isGitHubAuthEnabled: boolean }) {
Expand Down Expand Up @@ -53,60 +51,56 @@ export default function Header({ isGitHubAuthEnabled }: { readonly isGitHubAuthE
}, [mobileMenuOpen])

return (

<header className="bg-owasp-blue fixed inset-x-0 top-0 z-50 w-full shadow-md dark:bg-slate-800">

<div className="flex h-16 w-full items-center px-4 max-md:justify-between" id="navbar-sticky">
{/* Logo */}
<Link href="/" onClick={() => setMobileMenuOpen(false)}>
<div className="flex h-full items-center">
<Image
width={64}
height={64}
priority={true}
src={'/img/owasp_icon_white_sm.png'}
priority
src="/img/owasp_icon_white_sm.png"
className="hidden dark:block"
alt="OWASP Logo"
/>
<Image
width={64}
height={64}
priority={true}
src={'/img/owasp_icon_black_sm.png'}
priority
src="/img/owasp_icon_black_sm.png"
className="block dark:hidden"
alt="OWASP Logo"
/>
<div className="text-2xl text-slate-800 dark:text-slate-300 dark:hover:text-slate-200">
Nest
</div>
<span className="text-2xl text-slate-800 dark:text-slate-300">Nest</span>
</div>
</Link>
{/* Desktop Header Links */}
<div className="hidden flex-1 justify-between rounded-lg pl-6 font-medium md:block">
<div className="flex justify-start pl-6">

{/* Desktop Links */}
<nav className="hidden flex-1 justify-start pl-6 font-medium md:flex">
<div className="flex space-x-1">
{headerLinks
.filter((link) => {
if (link.requiresGitHubAuth) {
return isGitHubAuthEnabled
}
if (link.requiresGitHubAuth) return isGitHubAuthEnabled
return true
})
.map((link, i) => {
return link.submenu ? (
<NavDropdown link={link} pathname={pathname} key={i} />
) : (
<Link
key={link.text}
href={link.href || '/'}
className={cn(
'navlink px-3 py-2 text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
pathname === link.href && 'font-bold text-blue-800 dark:text-white'
)}
aria-current="page"
>
{link.text}
</Link>
)
})}
.map((link) => (
<Link
key={link.text}
href={link.href || '/'}
className={cn(
'navlink px-3 py-2 text-sm text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
pathname === link.href && 'font-bold text-blue-800 dark:text-white'
)}
aria-current={pathname === link.href ? 'page' : undefined}
>
{link.text}
</Link>
))}
Comment on lines +89 to +101
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Desktop nav regression: submenu parents link to “/”

On desktop, links with a submenu (e.g., “Community”) currently resolve to “/”, removing access to submenu pages. Use the first submenu item as the fallback href and improve active matching.

Apply this diff:

-              .map((link) => (
-                <Link
-                  key={link.text}
-                  href={link.href || '/'}
-                  className={cn(
-                    'navlink px-3 py-2 text-sm text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
-                    pathname === link.href && 'font-bold text-blue-800 dark:text-white'
-                  )}
-                  aria-current={pathname === link.href ? 'page' : undefined}
-                >
-                  {link.text}
-                </Link>
-              ))}
+              .map((link) => {
+                const href = link.href ?? link.submenu?.[0]?.href ?? '/'
+                const isActive = href !== '/' && pathname.startsWith(href)
+                return (
+                  <Link
+                    key={link.text}
+                    href={href}
+                    className={cn(
+                      'navlink px-3 py-2 text-sm text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
+                      isActive && 'font-bold text-blue-800 dark:text-white'
+                    )}
+                    aria-current={isActive ? 'page' : undefined}
+                  >
+                    {link.text}
+                  </Link>
+                )
+              })}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.map((link) => (
<Link
key={link.text}
href={link.href || '/'}
className={cn(
'navlink px-3 py-2 text-sm text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
pathname === link.href && 'font-bold text-blue-800 dark:text-white'
)}
aria-current={pathname === link.href ? 'page' : undefined}
>
{link.text}
</Link>
))}
.map((link) => {
const href = link.href ?? link.submenu?.[0]?.href ?? '/'
const isActive = href !== '/' && pathname.startsWith(href)
return (
<Link
key={link.text}
href={href}
className={cn(
'navlink px-3 py-2 text-sm text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
isActive && 'font-bold text-blue-800 dark:text-white'
)}
aria-current={isActive ? 'page' : undefined}
>
{link.text}
</Link>
)
})}
🤖 Prompt for AI Agents
In frontend/src/components/Header.tsx around lines 89 to 101, links that have
submenus currently fall back to "/" which breaks access to submenu pages; change
the fallback href to the first submenu item's href (e.g., link.href ||
link.items?.[0]?.href || '/') and update the active matching so the navitem is
considered active when the current pathname matches the link.href or any submenu
href (or startsWith the link href if appropriate) — adjust the aria-current and
className condition to use this improved check (e.g., pathname === link.href ||
link.items?.some(i => i.href === pathname) or pathname.startsWith(link.href)).

</div>

</div>
Comment on lines +81 to 104
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix missing closing tag: use instead of

This is causing the parse error Biome reported. Close the opened nav element properly.

Apply this diff:

-        </div>
+        </nav>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{/* Desktop Links */}
<nav className="hidden flex-1 justify-start pl-6 font-medium md:flex">
<div className="flex space-x-1">
{headerLinks
.filter((link) => {
if (link.requiresGitHubAuth) {
return isGitHubAuthEnabled
}
if (link.requiresGitHubAuth) return isGitHubAuthEnabled
return true
})
.map((link, i) => {
return link.submenu ? (
<NavDropdown link={link} pathname={pathname} key={i} />
) : (
<Link
key={link.text}
href={link.href || '/'}
className={cn(
'navlink px-3 py-2 text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
pathname === link.href && 'font-bold text-blue-800 dark:text-white'
)}
aria-current="page"
>
{link.text}
</Link>
)
})}
.map((link) => (
<Link
key={link.text}
href={link.href || '/'}
className={cn(
'navlink px-3 py-2 text-sm text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
pathname === link.href && 'font-bold text-blue-800 dark:text-white'
)}
aria-current={pathname === link.href ? 'page' : undefined}
>
{link.text}
</Link>
))}
</div>
</div>
{/* Desktop Links */}
<nav className="hidden flex-1 justify-start pl-6 font-medium md:flex">
<div className="flex space-x-1">
{headerLinks
.filter((link) => {
if (link.requiresGitHubAuth) return isGitHubAuthEnabled
return true
})
.map((link) => (
<Link
key={link.text}
href={link.href || '/'}
className={cn(
'navlink px-3 py-2 text-sm text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
pathname === link.href && 'font-bold text-blue-800 dark:text-white'
)}
aria-current={pathname === link.href ? 'page' : undefined}
>
{link.text}
</Link>
))}
</div>
</nav>
🧰 Tools
🪛 Biome (2.1.2)

[error] 82-82: Expected corresponding JSX closing tag for 'nav'.

Opening tag

closing tag

(parse)

🤖 Prompt for AI Agents
In frontend/src/components/Header.tsx around lines 81 to 104, the opened <nav>
element is incorrectly closed with </div>, causing an HTML/JSX parse error;
replace the incorrect closing tag with </nav> to properly close the nav element
and restore valid JSX structure.

<div className="flex items-center justify-normal gap-4">
<NavButton
Expand All @@ -119,17 +113,32 @@ export default function Header({ isGitHubAuthEnabled }: { readonly isGitHubAuthE
className="hidden"
/>

<NavButton

{/* Desktop Actions */}
<div className="flex items-center space-x-4">
<Button
as="a"
href="https://github.com/OWASP/Nest"
variant="secondary"
size="sm"
className="hidden text-yellow-300 hover:text-yellow-200 md:flex"
>
<FontAwesomeIcon icon={faRegularStar} className="mr-1" />
Star
</Button>
<Button
as="a"
href="https://owasp.org/donate/?reponame=www-project-nest&title=OWASP+Nest"
defaultIcon={faRegularHeart}
hoverIcon={faSolidHeart}
defaultIconColor="#b55f95"
hoverIconColor="#d9156c"
text="Sponsor"
className="hidden"
/>
variant="secondary"
size="sm"
className="hidden text-pink-300 hover:text-pink-200 md:flex"
>
<FontAwesomeIcon icon={faRegularHeart} className="mr-1" />
Sponsor
</Button>
<UserMenu isGitHubAuthEnabled={isGitHubAuthEnabled} />
<ModeToggle />

<div className="md:hidden">
<Button
onPress={toggleMobileMenu}
Expand Down Expand Up @@ -176,73 +185,80 @@ export default function Header({ isGitHubAuthEnabled }: { readonly isGitHubAuthE
Nest
</div>
</div>

</Link>
{headerLinks
.filter((link) => {
if (link.requiresGitHubAuth) {
return isGitHubAuthEnabled
}
return true
})
.map((link) =>
link.submenu ? (
<div key={link.text} className="flex flex-col">
<div className="block px-3 py-2 font-medium text-slate-700 dark:text-slate-300">
{link.text}
</div>
<div className="ml-4">
{link.submenu.map((sub, i) => (
<Link
key={i}
href={sub.href || '/'}
className={cn(
'block w-full px-4 py-2 text-left text-sm text-slate-700 transition duration-150 ease-in-out first:rounded-t-md last:rounded-b-md hover:bg-slate-100 hover:text-slate-900 dark:text-slate-300 dark:hover:bg-slate-700 dark:hover:text-white',
pathname === sub.href &&
'bg-blue-50 font-medium text-blue-600 dark:bg-blue-900/20 dark:text-blue-200'
)}
onClick={toggleMobileMenu}
>
{sub.text}
</Link>
))}

{/* Mobile Navigation */}
<nav className="flex flex-col space-y-1">
{headerLinks
.filter((link) => {
if (link.requiresGitHubAuth) return isGitHubAuthEnabled
return true
})
.map((link) =>
link.submenu ? (
<div key={link.text} className="flex flex-col">
<span className="px-3 py-2 font-medium text-slate-700 dark:text-slate-300">
{link.text}
</span>
<div className="ml-4 space-y-1">
{link.submenu.map((sub) => (
<Link
key={sub.text}
href={sub.href || '/'}
className={cn(
'block rounded px-4 py-2 text-sm text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-300 dark:hover:bg-slate-700 dark:hover:text-white',
pathname === sub.href && 'bg-blue-50 font-medium text-blue-600 dark:bg-blue-900/20'
)}
onClick={toggleMobileMenu}
>
{sub.text}
</Link>
))}
</div>
</div>
</div>
) : (
<Link
key={link.text}
href={link.href || '/'}
className={cn(
'navlink block px-3 py-2 text-slate-700 hover:text-slate-800 dark:text-slate-300 dark:hover:text-slate-200',
pathname === link.href && 'font-bold text-blue-800 dark:text-white'
)}
onClick={toggleMobileMenu}
>
{link.text}
</Link>
)
)}
</div>
) : (
<Link
key={link.text}
href={link.href || '/'}
className={cn(
'block rounded px-3 py-2 text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:text-slate-300 dark:hover:bg-slate-700 dark:hover:text-white',
pathname === link.href && 'font-bold text-blue-800 dark:text-white'
)}
onClick={toggleMobileMenu}
>
{link.text}
</Link>
)
)}
</nav>

<div className="flex flex-col gap-y-2">
<NavButton
href="https://github.com/OWASP/Nest"
defaultIcon={faRegularStar}
hoverIcon={faSolidStar}
defaultIconColor="#FDCE2D"
hoverIconColor="#FDCE2D"
text="Star On Github"
/>
<NavButton
href="https://owasp.org/donate/?reponame=www-project-nest&title=OWASP+Nest"
defaultIcon={faRegularHeart}
hoverIcon={faSolidHeart}
defaultIconColor="#b55f95"
hoverIconColor="#d9156c"
text="Sponsor Us"
/>
{/* Mobile Actions */}
<div className="flex flex-col space-y-3">
<Button
as="a"
href="https://github.com/OWASP/Nest"
variant="secondary"
size="md"
className="w-full justify-center"
>
<FontAwesomeIcon icon={faRegularStar} className="mr-2" />
Star On Github
</Button>
<Button
as="a"
href="https://owasp.org/donate/?reponame=www-project-nest&title=OWASP+Nest"
variant="secondary"
size="md"
className="w-full justify-center"
>
<FontAwesomeIcon icon={faRegularHeart} className="mr-2" />
Sponsor Us
</Button>
</div>
</div>
</div>
</div>
)}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove stray “)}” after the mobile drawer

This unmatched token breaks parsing/compilation.

Apply this diff:

-      )}
+      
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
)}
🧰 Tools
🪛 Biome (2.1.2)

[error] 261-261: Unexpected token. Did you mean {'}'} or &rbrace;?

(parse)

🤖 Prompt for AI Agents
In frontend/src/components/Header.tsx around line 261, there is a stray closing
token ")}" left after the mobile drawer which breaks compilation; remove that
unmatched ")}" so the JSX/TSX returns and component structure remain balanced,
then run TypeScript/JSX compile to verify no other mismatched braces remain.

</header>
)
}
}