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
171 changes: 131 additions & 40 deletions components/navigation/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,18 @@ const isMobile = isMobileDevice();
* @param {string} [props.className=''] - Additional CSS classes for styling.
* @param {boolean} [props.hideLogo=false] - Indicates whether to hide the logo.
*/
export default function NavBar({ className = '', hideLogo = false }: NavBarProps) {
export default function NavBar({
className = '',
hideLogo = false,
}: NavBarProps) {
const router: NextRouter = useRouter();
const { pathname, query, asPath } = router;
const [open, setOpen] = useState<'learning' | 'tooling' | 'community' | null>(null);
const [open, setOpen] = useState<'learning' | 'tooling' | 'community' | null>(
null,
);
Comment on lines +36 to +44
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 | 🔴 Critical

Fix formatting to match project style.

The parameter formatting and state declaration include trailing commas and line breaks that violate the project's Prettier and ESLint configuration.

Apply this diff to fix the formatting:

-export default function NavBar({
-  className = '',
-  hideLogo = false,
-}: NavBarProps) {
+export default function NavBar({ className = '', hideLogo = false }: NavBarProps) {
   const router: NextRouter = useRouter();
   const { pathname, query, asPath } = router;
-  const [open, setOpen] = useState<'learning' | 'tooling' | 'community' | null>(
-    null,
-  );
+  const [open, setOpen] = useState<'learning' | 'tooling' | 'community' | null>(null);
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 36-36: prettier/prettier: Replace ⏎··className·=·'',⏎··hideLogo·=·false,⏎ with className='' ,hideLogo=false


[error] 38-38: prettier/prettier: Unexpected trailing comma.


[error] 42-42: prettier/prettier: Replace ⏎····null,⏎·· with null


[error] 43-43: prettier/prettier: Unexpected trailing comma.

🤖 Prompt for AI Agents
In components/navigation/NavBar.tsx around lines 36 to 44, update the function
parameter and useState formatting to match project Prettier/ESLint rules: put
the props object shorthand on one line (export default function NavBar({
className = '', hideLogo = false }: NavBarProps) {), and collapse the useState
declaration to a single line without a trailing comma (const [open, setOpen] =
useState<'learning' | 'tooling' | 'community' | null>(null);). Ensure no
trailing commas or unnecessary line breaks remain.

const [mobileMenuOpen, setMobileMenuOpen] = useState<boolean>(false);
const [closeTimeout, setCloseTimeout] = useState<NodeJS.Timeout | null>(null);
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 | 🔴 Critical

Fix undefined 'NodeJS' and use proper timer type.

The NodeJS namespace is not defined in the browser environment, causing a linting error. Use ReturnType<typeof setTimeout> for cross-environment compatibility.

Apply this diff:

-  const [closeTimeout, setCloseTimeout] = useState<NodeJS.Timeout | null>(null);
+  const [closeTimeout, setCloseTimeout] = useState<ReturnType<typeof setTimeout> | null>(null);
📝 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
const [closeTimeout, setCloseTimeout] = useState<NodeJS.Timeout | null>(null);
const [closeTimeout, setCloseTimeout] = useState<ReturnType<typeof setTimeout> | null>(null);
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 46-46: no-undef: 'NodeJS' is not defined

🤖 Prompt for AI Agents
In components/navigation/NavBar.tsx around line 46, the state is typed as
NodeJS.Timeout which is undefined in browser environments; change the type to
ReturnType<typeof setTimeout> and keep the initial value as null (i.e.,
useState<ReturnType<typeof setTimeout> | null>(null)) so the timer type works
cross-environment and satisfies the linter.


const { i18n } = useTranslation();

/**
Expand All @@ -54,7 +61,9 @@ export default function NavBar({ className = '', hideLogo = false }: NavBarProps
}

// Filter unique languages based on i18nPaths that include the modified pathnameWithoutLocale
const uniqueLangs = Object.keys(i18nPaths).filter((lang) => i18nPaths[lang].includes(pathnameWithoutLocale));
const uniqueLangs = Object.keys(i18nPaths).filter((lang) =>
i18nPaths[lang].includes(pathnameWithoutLocale),
);

// If no unique languages are found, default to ['en']
return uniqueLangs.length === 0 ? ['en'] : uniqueLangs;
Expand All @@ -63,7 +72,7 @@ export default function NavBar({ className = '', hideLogo = false }: NavBarProps
const uniqueLangs = getUniqueLangs().map((lang) => ({
key: lang,
text: lang,
value: lang
value: lang,
}));

/**
Expand All @@ -72,7 +81,10 @@ export default function NavBar({ className = '', hideLogo = false }: NavBarProps
* @param {boolean} langPicker - Indicates whether the change is from the language picker.
* If true, stores the language in local storage.
*/
const changeLanguage = async (locale: string, langPicker: boolean): Promise<void> => {
const changeLanguage = async (
locale: string,
langPicker: boolean,
): Promise<void> => {
Comment on lines +84 to +87
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 | 🔴 Critical

Fix parameter formatting in changeLanguage.

The function parameters include trailing commas and line breaks that violate the project's formatting rules.

Apply this diff:

-  const changeLanguage = async (
-    locale: string,
-    langPicker: boolean,
-  ): Promise<void> => {
+  const changeLanguage = async (locale: string, langPicker: boolean): Promise<void> => {
📝 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
const changeLanguage = async (
locale: string,
langPicker: boolean,
): Promise<void> => {
const changeLanguage = async (locale: string, langPicker: boolean): Promise<void> => {
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 84-84: prettier/prettier: Replace ⏎····locale:·string,⏎····langPicker:·boolean,⏎·· with locale:·string,·langPicker:·boolean


[error] 86-86: prettier/prettier: Unexpected trailing comma.

🤖 Prompt for AI Agents
In components/navigation/NavBar.tsx around lines 84 to 87, the changeLanguage
function signature is formatted with trailing commas and unnecessary line
breaks; reformat the parameter list to follow project style by placing
parameters on a single line without trailing commas (e.g., changeLanguage =
async (locale: string, langPicker: boolean): Promise<void> => { ), ensuring
consistent spacing and removing the extra comma and line break.

// Verifies if the language change is from langPicker or the browser-api
if (langPicker) {
localStorage.setItem('i18nLang', locale);
Expand Down Expand Up @@ -121,7 +133,10 @@ export default function NavBar({ className = '', hideLogo = false }: NavBarProps
* @param {('learning' | 'tooling' | 'community' | null)} menu - The menu to show or hide.
*/
function showMenu(menu: 'learning' | 'tooling' | 'community' | null) {
if (open === menu) return;
if (closeTimeout) {
clearTimeout(closeTimeout);
setCloseTimeout(null);
}
setOpen(menu);
}

Expand All @@ -145,81 +160,157 @@ export default function NavBar({ className = '', hideLogo = false }: NavBarProps

return (
<div className={`bg-white ${className} z-50`}>
<div className='flex w-full items-center justify-between py-6 lg:justify-start lg:space-x-2'>
<div className="flex w-full items-center justify-between py-6 lg:justify-start lg:space-x-2">
{!hideLogo && (
<div className='lg:w-auto lg:flex-1'>
<div className='flex'>
<Link href='/' className='cursor-pointer' aria-label='AsyncAPI' data-testid='Navbar-logo'>
<AsyncAPILogo className='w-auto' />
<div className="lg:w-auto lg:flex-1">
<div className="flex">
<Link
href="/"
className="cursor-pointer"
aria-label="AsyncAPI"
data-testid="Navbar-logo"
>
<AsyncAPILogo className="w-auto" />
</Link>
</div>
</div>
)}

<div className='-my-2 -mr-2 flex flex-row items-center justify-center lg:hidden' data-testid='Navbar-search'>
<div
className="-my-2 -mr-2 flex flex-row items-center justify-center lg:hidden"
data-testid="Navbar-search"
>
<SearchButton
className='flex items-center space-x-2 rounded-md p-2 text-left text-gray-400 transition duration-150 ease-in-out hover:bg-gray-100 hover:text-gray-500 focus:bg-gray-100 focus:text-gray-500 focus:outline-none'
aria-label='Open Search'
className="flex items-center space-x-2 rounded-md p-2 text-left text-gray-400 transition duration-150 ease-in-out hover:bg-gray-100 hover:text-gray-500 focus:bg-gray-100 focus:text-gray-500 focus:outline-none"
aria-label="Open Search"
>
<IconLoupe />
</SearchButton>
<button
onClick={() => setMobileMenuOpen(true)}
type='button'
className='inline-flex items-center justify-center rounded-md p-2 text-gray-400 transition duration-150 ease-in-out hover:bg-gray-100 hover:text-gray-500 focus:bg-gray-100 focus:text-gray-500 focus:outline-none'
type="button"
className="inline-flex items-center justify-center rounded-md p-2 text-gray-400 transition duration-150 ease-in-out hover:bg-gray-100 hover:text-gray-500 focus:bg-gray-100 focus:text-gray-500 focus:outline-none"
>
<svg className='size-6' stroke='currentColor' fill='none' viewBox='0 0 24 24'>
<svg
className="size-6"
stroke="currentColor"
fill="none"
viewBox="0 0 24 24"
>
<title>Menu</title>
<path strokeLinecap='round' strokeLinejoin='round' strokeWidth='2' d='M4 6h16M4 12h16M4 18h16' />
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
</button>
</div>

<nav
className='hidden w-full space-x-4 lg:flex lg:items-center lg:justify-end xl:space-x-8'
data-testid='Navbar-main'
className="hidden w-full space-x-4 lg:flex lg:items-center lg:justify-end xl:space-x-8"
data-testid="Navbar-main"
Comment on lines +163 to +213
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 | 🔴 Critical

Fix extensive quote and formatting violations.

Multiple JSX attributes use double quotes instead of single quotes, violating the project's ESLint configuration. Lines also exceed maximum length.

The following violations must be fixed:

  • Line 163: Replace double quotes with single quotes
  • Line 165-173: Replace double quotes with single quotes in all Link attributes
  • Line 179-185: Replace double quotes with single quotes
  • Line 191-205: Replace double quotes with single quotes in SVG attributes
  • Line 212-213: Replace double quotes with single quotes

Apply formatting by running:

npm run format

Or apply changes manually following the pattern:

-        <div className="flex w-full items-center justify-between py-6 lg:justify-start lg:space-x-2">
+        <div className='flex w-full items-center justify-between py-6 lg:justify-start lg:space-x-2'>
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 163-163: prettier/prettier: Replace "flex·w-full·items-center·justify-between·py-6·lg:justify-start·lg:space-x-2" with 'flex w-full items-center justify-between py-6 lg:justify-start lg:space-x-2'


[error] 163-163: jsx-quotes: Unexpected usage of doublequote.


[error] 165-165: prettier/prettier: Replace "lg:w-auto·lg:flex-1" with 'lg:w-auto·lg:flex-1'


[error] 165-165: jsx-quotes: Unexpected usage of doublequote.


[error] 166-166: prettier/prettier: Replace "flex" with 'flex'


[error] 166-166: jsx-quotes: Unexpected usage of doublequote.


[error] 167-167: prettier/prettier: Replace a long line with a chained property form; see log for details.


[error] 168-168: jsx-quotes: Unexpected usage of doublequote.


[error] 169-169: jsx-quotes: Unexpected usage of doublequote.


[error] 170-170: jsx-quotes: Unexpected usage of doublequote.


[error] 171-171: jsx-quotes: Unexpected usage of doublequote.


[error] 173-173: prettier/prettier: Replace "w-auto" with 'w-auto'


[error] 173-173: jsx-quotes: Unexpected usage of doublequote.


[error] 179-179: prettier/prettier: Replace "-my-2·-mr-2·flex·flex-row·items-center·justify-center·lg:hidden" with '-my-2 -mr-2 flex flex-row items-center justify-center lg:hidden'


[error] 180-180: jsx-quotes: Unexpected usage of doublequote.


[error] 184-184: max-len: This line is too long (221). Maximum allowed is 120.


[error] 184-184: prettier/prettier: Replace long string with string literal using single quotes.


[error] 185-185: jsx-quotes: Unexpected usage of doublequote.


[error] 191-191: prettier/prettier: Replace "button" with 'button'


[error] 191-191: jsx-quotes: Unexpected usage of doublequote.


[error] 192-192: max-len: This line is too long (223). Maximum allowed is 120.


[error] 192-192: prettier/prettier: Replace long string with single-quoted literal.


[error] 194-194: prettier/prettier: Replace string with attribute-friendly form.


[error] 195-195: jsx-quotes: Unexpected usage of doublequote.


[error] 196-196: jsx-quotes: Unexpected usage of doublequote.


[error] 197-197: jsx-quotes: Unexpected usage of doublequote.


[error] 198-198: jsx-quotes: Unexpected usage of doublequote.


[error] 201-201: prettier/prettier: Replace strokeLinecap="round" with strokeLinecap='round'


[error] 202-202: prettier/prettier: Replace strokeLinejoin="round" with strokeLinejoin='round'


[error] 203-203: prettier/prettier: Replace strokeWidth="2" with strokeWidth='2'


[error] 204-204: prettier/prettier: Replace d="M4·6h16M4·12h16M4·18h16" with d='M4 6h16M4 12h16M4 18h16'


[error] 205-205: prettier/prettier: Replace "M4·6h16M4·12h16M4·18h16" with m' (invalid message placeholder)


[error] 212-212: prettier/prettier: Replace "hidden·w-full·space-x-4·lg:flex·lg:items-center·lg:justify-end·xl:space-x-8" with 'hidden w-full space-x-4 lg:flex lg:items-center lg:justify-end xl:space-x-8'


[error] 212-212: jsx-quotes: Unexpected usage of doublequote.


[error] 213-213: prettier/prettier: Replace "Navbar-main" with 'Navbar-main'


[error] 213-213: jsx-quotes: Unexpected usage of doublequote.

🤖 Prompt for AI Agents
components/navigation/NavBar.tsx lines 163-213: JSX attributes currently use
double quotes and some lines exceed max length; update all JSX attribute string
delimiters to single quotes on the specified lines (163, 165-173, 179-185,
191-205, 212-213), break long attribute or element lines into shorter
concatenated lines or wrap props onto multiple lines to satisfy max-line-length,
then run npm run format (or your project's formatter) and re-run lint to ensure
formatting and quote-style violations are resolved.

>
<div className='relative' onMouseLeave={() => showMenu(null)} ref={learningRef}>
<div
className="relative"
ref={learningRef}
onMouseEnter={() => showMenu('learning')}
onMouseLeave={() => {
const timeout = setTimeout(() => setOpen(null), 200);
setCloseTimeout(timeout);
}}
>
<NavItem
text='Docs'
href='/docs'
text="Docs"
href="/docs"
onClick={() => showOnClickMenu('learning')}
onMouseEnter={() => showMenu('learning')}
hasDropdown
/>
{open === 'learning' && <LearningPanel />}
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
${
open === 'learning'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}
`}
>
<div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
<LearningPanel />
</div>
</div>
</div>
Comment on lines +215 to 244
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 | 🟠 Major

Fix dropdown hover behavior to prevent premature closing.

The Learning dropdown sets a 200ms timeout to close on onMouseLeave (line 219-222), but the panel content (lines 231-243) doesn't have hover handlers to cancel this timeout. This causes the panel to close when the user moves their cursor from the trigger to the panel content.

Apply this diff to fix the hover behavior:

           <div
-            className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
-  ${
-    open === 'learning'
-      ? 'opacity-100 translate-y-0 scale-100 visible'
-      : 'opacity-0 -translate-y-2 scale-95 invisible'
-  }
-  `}
+            className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] ${
+              open === 'learning'
+                ? 'opacity-100 translate-y-0 scale-100 visible'
+                : 'opacity-0 -translate-y-2 scale-95 invisible'
+            }`}
+            onMouseEnter={() => showMenu('learning')}
           >
-            <div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
+            <div className='rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm'>
               <LearningPanel />
             </div>
           </div>

Note: This also fixes the quote violations in the className strings.

📝 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
<div
className="relative"
ref={learningRef}
onMouseEnter={() => showMenu('learning')}
onMouseLeave={() => {
const timeout = setTimeout(() => setOpen(null), 200);
setCloseTimeout(timeout);
}}
>
<NavItem
text='Docs'
href='/docs'
text="Docs"
href="/docs"
onClick={() => showOnClickMenu('learning')}
onMouseEnter={() => showMenu('learning')}
hasDropdown
/>
{open === 'learning' && <LearningPanel />}
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
${
open === 'learning'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}
`}
>
<div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
<LearningPanel />
</div>
</div>
</div>
<div
className="relative"
ref={learningRef}
onMouseEnter={() => showMenu('learning')}
onMouseLeave={() => {
const timeout = setTimeout(() => setOpen(null), 200);
setCloseTimeout(timeout);
}}
>
<NavItem
text="Docs"
href="/docs"
onClick={() => showOnClickMenu('learning')}
onMouseEnter={() => showMenu('learning')}
hasDropdown
/>
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] ${
open === 'learning'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}`}
onMouseEnter={() => showMenu('learning')}
>
<div className='rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm'>
<LearningPanel />
</div>
</div>
</div>
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 216-216: prettier/prettier: Replace "relative" with 'relative'


[error] 216-216: jsx-quotes: Unexpected usage of doublequote.


[error] 220-220: newline-after-var: Expected blank line after variable declarations.


[error] 221-221: padding-line-between-statements: Expected blank line before this statement.


[error] 225-225: prettier/prettier: Replace "Docs" with 'Docs'


[error] 225-225: jsx-quotes: Unexpected usage of doublequote.


[error] 226-226: prettier/prettier: Replace "/docs" with '/docs'


[error] 226-226: jsx-quotes: Unexpected usage of doublequote.


[error] 232-232: max-len: This line is too long (126). Maximum allowed is 120.


[error] 233-233: prettier/prettier: Replace long string with single-quoted literal.


[error] 233-233: jsx-quotes: Unexpected usage of doublequote.


[error] 240-240: prettier/prettier: Replace "rounded-xl·shadow-lg·border·border-gray-100·bg-white/95·backdrop-blur-sm" with 'rounded-xl·shadow-lg·border·border-gray-100·bg-white/95·backdrop-blur-sm'


[error] 240-240: jsx-quotes: Unexpected usage of doublequote.


<div className='relative' onMouseLeave={() => showMenu(null)} ref={toolingRef}>
<div
className="relative"
onMouseLeave={() => showMenu(null)}
ref={toolingRef}
>
<NavItem
text='Tools'
href='/tools'
text="Tools"
href="/tools"
onClick={() => showOnClickMenu('tooling')}
onMouseEnter={() => showMenu('tooling')}
hasDropdown
/>
{open === 'tooling' && <ToolsPanel />}
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
${
open === 'tooling'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}
`}
>
<div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
<ToolsPanel />
</div>
</div>
</div>
Comment on lines +246 to 271
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 | 🟠 Major

Fix inconsistent hover behavior and apply same pattern as Learning dropdown.

The Tooling dropdown uses onMouseLeave={() => showMenu(null)} at line 248, which closes immediately without the 200ms timeout used in the Learning dropdown. This creates an inconsistent user experience. Additionally, the panel lacks an onMouseEnter handler to keep it open when hovered.

Apply this diff to match the Learning dropdown pattern:

           <div
-            className="relative"
-            onMouseLeave={() => showMenu(null)}
+            className='relative'
             ref={toolingRef}
+            onMouseEnter={() => showMenu('tooling')}
+            onMouseLeave={() => {
+              const timeout = setTimeout(() => setOpen(null), 200);
+              setCloseTimeout(timeout);
+            }}
           >
             <NavItem
-              text="Tools"
-              href="/tools"
+              text='Tools'
+              href='/tools'
               onClick={() => showOnClickMenu('tooling')}
               onMouseEnter={() => showMenu('tooling')}
               hasDropdown
             />
             <div
-              className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
-  ${
-    open === 'tooling'
-      ? 'opacity-100 translate-y-0 scale-100 visible'
-      : 'opacity-0 -translate-y-2 scale-95 invisible'
-  }
-  `}
+              className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] ${
+                open === 'tooling'
+                  ? 'opacity-100 translate-y-0 scale-100 visible'
+                  : 'opacity-0 -translate-y-2 scale-95 invisible'
+              }`}
+              onMouseEnter={() => showMenu('tooling')}
             >
-              <div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
+              <div className='rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm'>
                 <ToolsPanel />
               </div>
             </div>
📝 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
<div
className="relative"
onMouseLeave={() => showMenu(null)}
ref={toolingRef}
>
<NavItem
text='Tools'
href='/tools'
text="Tools"
href="/tools"
onClick={() => showOnClickMenu('tooling')}
onMouseEnter={() => showMenu('tooling')}
hasDropdown
/>
{open === 'tooling' && <ToolsPanel />}
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
${
open === 'tooling'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}
`}
>
<div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
<ToolsPanel />
</div>
</div>
</div>
<div
className='relative'
ref={toolingRef}
onMouseEnter={() => showMenu('tooling')}
onMouseLeave={() => {
const timeout = setTimeout(() => setOpen(null), 200);
setCloseTimeout(timeout);
}}
>
<NavItem
text='Tools'
href='/tools'
onClick={() => showOnClickMenu('tooling')}
onMouseEnter={() => showMenu('tooling')}
hasDropdown
/>
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] ${
open === 'tooling'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}`}
onMouseEnter={() => showMenu('tooling')}
>
<div className='rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm'>
<ToolsPanel />
</div>
</div>
</div>
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 246-246: prettier/prettier: Replace long string with single-quoted literal.


[error] 246-246: jsx-quotes: Unexpected usage of doublequote.


[error] 252-252: prettier/prettier: Replace "Tools" with 'Tools'


[error] 252-252: jsx-quotes: Unexpected usage of doublequote.


[error] 253-253: prettier/prettier: Replace "/tools" with '/tools'


[error] 253-253: jsx-quotes: Unexpected usage of doublequote.


[error] 259-259: max-len: This line is too long (126). Maximum allowed is 120.


[error] 260-260: prettier/prettier: Replace long string with single-quoted literal.


[error] 260-260: jsx-quotes: Unexpected usage of doublequote.


[error] 267-267: prettier/prettier: Replace "rounded-xl·shadow-lg·border·border-gray-100·bg-white/95·backdrop-blur-sm" with 'rounded-xl·shadow-lg·border·border-gray-100·bg-white/95·backdrop-blur-sm'


[error] 267-267: jsx-quotes: Unexpected usage of doublequote.

🤖 Prompt for AI Agents
In components/navigation/NavBar.tsx around lines 246 to 271, the tooling
dropdown closes immediately because it uses onMouseLeave={() => showMenu(null)}
and the dropdown panel lacks an onMouseEnter to keep it open; update the outer
div to use the same delayed hide API as the Learning dropdown (e.g.
onMouseLeave={() => showMenu(null, 200)}) and add onMouseEnter={() =>
showMenu('tooling')} to the inner panel div (the container wrapping ToolsPanel)
so hovering the panel keeps the menu open and behavior matches the Learning
dropdown pattern.


<div className='relative' onMouseLeave={() => showMenu(null)} ref={communityRef}>
<div
className="relative"
onMouseLeave={() => showMenu(null)}
ref={communityRef}
>
<NavItem
text='Community'
href='/community'
text="Community"
href="/community"
onClick={() => showOnClickMenu('community')}
onMouseEnter={() => showMenu('community')}
hasDropdown
/>
{open === 'community' && <CommunityPanel />}
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
${
open === 'community'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}
`}
>
<div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
<CommunityPanel />
</div>
</div>
</div>
Comment on lines +273 to 298
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 | 🟠 Major

Fix inconsistent hover behavior and apply same pattern as Learning dropdown.

The Community dropdown has the same issues as the Tooling dropdown: it closes immediately without a timeout and lacks hover handlers on the panel to keep it open.

Apply this diff to match the Learning dropdown pattern:

           <div
-            className="relative"
-            onMouseLeave={() => showMenu(null)}
+            className='relative'
             ref={communityRef}
+            onMouseEnter={() => showMenu('community')}
+            onMouseLeave={() => {
+              const timeout = setTimeout(() => setOpen(null), 200);
+              setCloseTimeout(timeout);
+            }}
           >
             <NavItem
-              text="Community"
-              href="/community"
+              text='Community'
+              href='/community'
               onClick={() => showOnClickMenu('community')}
               onMouseEnter={() => showMenu('community')}
               hasDropdown
             />
             <div
-              className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
-  ${
-    open === 'community'
-      ? 'opacity-100 translate-y-0 scale-100 visible'
-      : 'opacity-0 -translate-y-2 scale-95 invisible'
-  }
-  `}
+              className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] ${
+                open === 'community'
+                  ? 'opacity-100 translate-y-0 scale-100 visible'
+                  : 'opacity-0 -translate-y-2 scale-95 invisible'
+              }`}
+              onMouseEnter={() => showMenu('community')}
             >
-              <div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
+              <div className='rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm'>
                 <CommunityPanel />
               </div>
             </div>
📝 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
<div
className="relative"
onMouseLeave={() => showMenu(null)}
ref={communityRef}
>
<NavItem
text='Community'
href='/community'
text="Community"
href="/community"
onClick={() => showOnClickMenu('community')}
onMouseEnter={() => showMenu('community')}
hasDropdown
/>
{open === 'community' && <CommunityPanel />}
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)]
${
open === 'community'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}
`}
>
<div className="rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm">
<CommunityPanel />
</div>
</div>
</div>
<div
className='relative'
ref={communityRef}
onMouseEnter={() => showMenu('community')}
onMouseLeave={() => {
const timeout = setTimeout(() => setOpen(null), 200);
setCloseTimeout(timeout);
}}
>
<NavItem
text='Community'
href='/community'
onClick={() => showOnClickMenu('community')}
onMouseEnter={() => showMenu('community')}
hasDropdown
/>
<div
className={`absolute left-0 top-full mt-3 transform transition-all duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] ${
open === 'community'
? 'opacity-100 translate-y-0 scale-100 visible'
: 'opacity-0 -translate-y-2 scale-95 invisible'
}`}
onMouseEnter={() => showMenu('community')}
>
<div className='rounded-xl shadow-lg border border-gray-100 bg-white/95 backdrop-blur-sm'>
<CommunityPanel />
</div>
</div>
</div>
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project

[error] 273-273: prettier/prettier: Replace "relative" with 'relative'


[error] 273-273: jsx-quotes: Unexpected usage of doublequote.


[error] 279-279: prettier/prettier: Replace "Community" with 'Community'


[error] 279-279: jsx-quotes: Unexpected usage of doublequote.


[error] 280-280: prettier/prettier: Replace "/community" with '/community'


[error] 280-280: jsx-quotes: Unexpected usage of doublequote.


[error] 286-286: max-len: This line is too long (126). Maximum allowed is 120.


[error] 288-288: prettier/prettier: Replace long string with single-quoted literal.


[error] 294-294: prettier/prettier: Replace "rounded-xl·shadow-lg·border·border-gray-100·bg-white/95·backdrop-blur-sm" with 'rounded-xl·shadow-lg·border·border-gray-100·bg-white/95·backdrop-blur-sm'


[error] 294-294: jsx-quotes: Unexpected usage of doublequote.

🤖 Prompt for AI Agents
In components/navigation/NavBar.tsx around lines 273-298, the Community dropdown
currently closes immediately and the panel lacks hover handlers; mirror the
Learning dropdown pattern by adding onMouseEnter={() => showMenu('community')}
and onMouseLeave={() => showMenu(null)} to the dropdown panel container (the div
that wraps CommunityPanel) so hovering the panel keeps it open, and ensure the
parent uses the same delayed-close behavior (use the same timeout-based hide
logic used by the Learning dropdown) so the menu doesn’t close instantly when
moving the pointer between trigger and panel.


{otherItems.map((item, index) => (
<NavItem href={item.href} key={index} text={item.text} target={item.target} className={item.className} />
<NavItem
href={item.href}
key={index}
text={item.text}
target={item.target}
className={item.className}
/>
))}

<div className='justify-content flex flex-row items-center'>
<div className="justify-content flex flex-row items-center">
<SearchButton
className='mr-2 flex items-center space-x-2 rounded-md p-2 text-left text-gray-400 transition duration-150 ease-in-out hover:bg-gray-100 hover:text-gray-500 focus:bg-gray-100 focus:text-gray-500 focus:outline-none'
aria-label='Open Search'
className="mr-2 flex items-center space-x-2 rounded-md p-2 text-left text-gray-400 transition duration-150 ease-in-out hover:bg-gray-100 hover:text-gray-500 focus:bg-gray-100 focus:text-gray-500 focus:outline-none"
aria-label="Open Search"
>
<IconLoupe />
</SearchButton>
Expand All @@ -230,14 +321,14 @@ export default function NavBar({ className = '', hideLogo = false }: NavBarProps
onChange={(value) => {
changeLanguage(value.toLowerCase(), true);
}}
className=''
className=""
selected={i18n.language ? i18n.language : 'en'}
/>

<GithubButton
text='Star on GitHub'
href='https://github.com/asyncapi/spec'
className='ml-2 py-2'
text="Star on GitHub"
href="https://github.com/asyncapi/spec"
className="ml-2 py-2"
inNav={true}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions website
Submodule website added at 4234dd
Loading