-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(ui): align desktop language dropdown with mobile design #5040
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(ui): align desktop language dropdown with mobile design #5040
Conversation
✅ Deploy Preview for asyncapi-website ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
📝 WalkthroughWalkthroughThe LanguageSelect component was refactored from a standard HTML select element to a custom dropdown UI, replacing the prop interface to pass a structured language array, current language identifier, and change handler callback. NavBar was updated to use the new prop structure accordingly. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
⚡️ Lighthouse report for the changes in this PR:
Lighthouse ran on https://deploy-preview-5040--asyncapi-website.netlify.app/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@components/languageSelector/LanguageSelect.tsx`:
- Around line 1-5: Sort and reformat the import block and string quotes in
LanguageSelect so it satisfies simple-import-sort and Prettier: order imports
(external modules first like React and hooks, then config i18nextConfig, then
local icons IconLanguage and NavItemDropdown), replace all double quotes with
single quotes, and ensure spacing/line breaks match Prettier rules; then run npx
prettier --write and npx eslint --fix to apply the changes for the
LanguageSelect component and its imports.
- Around line 42-51: The JSX in the LanguageSelect button uses double quotes and
a very long className string that triggers jsx-quotes and max-len; update the
JSX to use single quotes for attribute values (e.g., className, onClick) and
break the long className into multiple concatenated strings or split
attributes/children across multiple lines to keep lines under 120 chars—apply
changes inside the component that references wrapperRef, the onClick that calls
setOpen, and the elements IconLanguage, currentLangLabel, and NavItemDropdown so
formatting stays readable and lint-compliant.
- Around line 55-76: The dropdown panel JSX has a long line (className +
template literal) causing prettier/max-len failures; split the long className
and conditional into multiple concatenated or template literal lines and/or
extract the computed classes into a small helper variable before the return to
keep each line under 120 chars. Specifically, in the map callback for
uniqueLangs (look at uniqueLangs.map, currentLanguage, isActive, changeLanguage,
setOpen, langMap) move the isActive calculation and the conditional text color
class into a const (e.g., itemClass or isActiveClass) or break the button
props/children onto separate lines so the onClick and className strings are
wrapped; ensure the displayed label still reads from
langMap[lang.text.toLowerCase() as keyof typeof langMap] || lang.text and that
formatting now satisfies prettier/max-len.
- Around line 44-77: The dropdown is missing ARIA attributes: add
aria-haspopup="menu" and aria-expanded={open} to the trigger button (the element
using setOpen and currentLangLabel) and give the dropdown panel a unique id
referenced by aria-controls on the trigger; on the panel (the JSX that renders
when open) add role="menu" and on each option button (inside uniqueLangs map
where changeLanguage and setOpen are called) add role="menuitem", tabIndex={0}
and aria-current or aria-checked for the active item based on currentLanguage,
ensuring the IDs/props use existing symbols (open, setOpen, changeLanguage,
currentLanguage, uniqueLangs, langMap) so screen readers can detect expanded
state and navigate items.
🧹 Nitpick comments (1)
components/languageSelector/LanguageSelect.tsx (1)
26-39: Consider adding keyboard support for closing the dropdown.The dropdown can be closed by clicking outside, but users should also be able to press
Escapeto close it. This improves keyboard accessibility.Proposed keyboard handler
useEffect(() => { function handleClickOutside(event: MouseEvent) { if ( wrapperRef.current && !wrapperRef.current.contains(event.target as Node) ) { setOpen(false); } } + function handleKeyDown(event: KeyboardEvent) { + if (event.key === 'Escape') { + setOpen(false); + } + } document.addEventListener('mousedown', handleClickOutside); + document.addEventListener('keydown', handleKeyDown); + return () => - document.removeEventListener('mousedown', handleClickOutside); + { + document.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('keydown', handleKeyDown); + }; }, []);
| import React, { useEffect, useRef, useState } from 'react'; | ||
| import i18nextConfig from '@/next-i18next.config.cjs'; | ||
|
|
||
| import type { SelectProps } from '../form/Select'; | ||
| import IconLanguage from '../icons/Language'; | ||
| import NavItemDropdown from '../icons/NavItemDropdown'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix import sorting and formatting to pass CI.
The pipeline reports simple-import-sort/imports and multiple prettier/prettier errors. The imports need to be sorted and double quotes replaced with single quotes throughout.
Proposed fix for imports
-import React, { useEffect, useRef, useState } from 'react';
-import i18nextConfig from '@/next-i18next.config.cjs';
-
-import IconLanguage from '../icons/Language';
-import NavItemDropdown from '../icons/NavItemDropdown';
+import React, { useEffect, useRef, useState } from 'react';
+
+import i18nextConfig from '@/next-i18next.config.cjs';
+import IconLanguage from '../icons/Language';
+import NavItemDropdown from '../icons/NavItemDropdown';Run npx prettier --write and npx eslint --fix on this file to auto-correct formatting issues.
📝 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.
| import React, { useEffect, useRef, useState } from 'react'; | |
| import i18nextConfig from '@/next-i18next.config.cjs'; | |
| import type { SelectProps } from '../form/Select'; | |
| import IconLanguage from '../icons/Language'; | |
| import NavItemDropdown from '../icons/NavItemDropdown'; | |
| import React, { useEffect, useRef, useState } from 'react'; | |
| import i18nextConfig from '@/next-i18next.config.cjs'; | |
| import IconLanguage from '../icons/Language'; | |
| import NavItemDropdown from '../icons/NavItemDropdown'; |
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project
[error] 1-1: Run autofix to sort these imports! (simple-import-sort/imports)
🤖 Prompt for AI Agents
In `@components/languageSelector/LanguageSelect.tsx` around lines 1 - 5, Sort and
reformat the import block and string quotes in LanguageSelect so it satisfies
simple-import-sort and Prettier: order imports (external modules first like
React and hooks, then config i18nextConfig, then local icons IconLanguage and
NavItemDropdown), replace all double quotes with single quotes, and ensure
spacing/line breaks match Prettier rules; then run npx prettier --write and npx
eslint --fix to apply the changes for the LanguageSelect component and its
imports.
| <div ref={wrapperRef} className="relative inline-block"> | ||
|
|
||
| <button | ||
| onClick={() => setOpen((v) => !v)} | ||
| className="flex items-center gap-x-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-800 shadow-sm transition hover:bg-gray-50" | ||
| > | ||
| <IconLanguage className="h-4 w-4 text-gray-800" /> | ||
| <span>{currentLangLabel}</span> | ||
| <NavItemDropdown /> | ||
| </button> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace double quotes with single quotes and break long lines.
The pipeline reports jsx-quotes and max-len errors. Line 46 exceeds 120 characters and uses double quotes.
Proposed fix for the button element
- <div ref={wrapperRef} className="relative inline-block">
-
- <button
- onClick={() => setOpen((v) => !v)}
- className="flex items-center gap-x-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-800 shadow-sm transition hover:bg-gray-50"
- >
- <IconLanguage className="h-4 w-4 text-gray-800" />
+ <div ref={wrapperRef} className='relative inline-block'>
+ <button
+ onClick={() => setOpen((v) => !v)}
+ className='flex items-center gap-x-2 rounded-md border border-gray-300 bg-white
+ px-3 py-2 text-sm font-medium text-gray-800 shadow-sm transition hover:bg-gray-50'
+ >
+ <IconLanguage className='h-4 w-4 text-gray-800' />🧰 Tools
🪛 GitHub Actions: PR testing - if Node project
[error] 42-42: Replace "relative·inline-block">⏎ with 'relative·inline-block'> (prettier/prettier)
[error] 42-42: Unexpected usage of doublequote. (jsx-quotes)
[error] 46-46: This line has a length of 170. Maximum allowed is 120. (max-len)
[error] 46-46: Replace "flex·items-center·gap-x-2·rounded-md·border·border-gray-300·bg-white·px-3·py-2·text-sm·font-medium·text-gray-800·shadow-sm·transition·hover:bg-gray-50" with 'flex·items-center·gap-x-2·rounded-md·border·border-gray-300·bg-white·px-3·py-2·text-sm·font-medium·text-gray-800·shadow-sm·transition·hover:bg-gray-50' (prettier/prettier)
[error] 46-46: Unexpected usage of doublequote. (jsx-quotes)
[error] 48-48: Replace "h-4·w-4·text-gray-800" with 'h-4·w-4·text-gray-800' (prettier/prettier)
[error] 48-48: Unexpected usage of doublequote. (jsx-quotes)
🤖 Prompt for AI Agents
In `@components/languageSelector/LanguageSelect.tsx` around lines 42 - 51, The JSX
in the LanguageSelect button uses double quotes and a very long className string
that triggers jsx-quotes and max-len; update the JSX to use single quotes for
attribute values (e.g., className, onClick) and break the long className into
multiple concatenated strings or split attributes/children across multiple lines
to keep lines under 120 chars—apply changes inside the component that references
wrapperRef, the onClick that calls setOpen, and the elements IconLanguage,
currentLangLabel, and NavItemDropdown so formatting stays readable and
lint-compliant.
| <button | ||
| onClick={() => setOpen((v) => !v)} | ||
| className="flex items-center gap-x-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-800 shadow-sm transition hover:bg-gray-50" | ||
| > | ||
| <IconLanguage className="h-4 w-4 text-gray-800" /> | ||
| <span>{currentLangLabel}</span> | ||
| <NavItemDropdown /> | ||
| </button> | ||
|
|
||
| {/* Dropdown panel */} | ||
| {open && ( | ||
| <div className="absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg"> | ||
| {uniqueLangs.map((lang) => { | ||
| const isActive = | ||
| currentLanguage.toLowerCase() === lang.text.toLowerCase(); | ||
|
|
||
| return ( | ||
| <button | ||
| key={lang.key} | ||
| onClick={() => { | ||
| changeLanguage(lang.value.toLowerCase(), true); | ||
| setOpen(false); | ||
| }} | ||
| className={`block w-full rounded-lg py-1 px-2 text-start text-sm font-medium leading-6 transition duration-150 ease-in-out hover:bg-gray-50 ${ | ||
| isActive ? 'text-secondary-500' : 'text-gray-700' | ||
| }`} | ||
| > | ||
| {langMap[lang.text.toLowerCase() as keyof typeof langMap] || | ||
| lang.text} | ||
| </button> | ||
| ); | ||
| })} | ||
| </div> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add accessibility attributes for the dropdown.
The custom dropdown lacks ARIA attributes needed for screen reader support. The trigger button should indicate its expanded state, and the dropdown should have appropriate roles.
Proposed accessibility improvements
<button
onClick={() => setOpen((v) => !v)}
- className="flex items-center gap-x-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-800 shadow-sm transition hover:bg-gray-50"
+ aria-expanded={open}
+ aria-haspopup='listbox'
+ className='flex items-center gap-x-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-800 shadow-sm transition hover:bg-gray-50'
> {open && (
- <div className="absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg">
+ <div
+ role='listbox'
+ aria-label='Select language'
+ className='absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg'
+ >
{uniqueLangs.map((lang) => { <button
key={lang.key}
+ role='option'
+ aria-selected={isActive}
onClick={() => {📝 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.
| <button | |
| onClick={() => setOpen((v) => !v)} | |
| className="flex items-center gap-x-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-800 shadow-sm transition hover:bg-gray-50" | |
| > | |
| <IconLanguage className="h-4 w-4 text-gray-800" /> | |
| <span>{currentLangLabel}</span> | |
| <NavItemDropdown /> | |
| </button> | |
| {/* Dropdown panel */} | |
| {open && ( | |
| <div className="absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg"> | |
| {uniqueLangs.map((lang) => { | |
| const isActive = | |
| currentLanguage.toLowerCase() === lang.text.toLowerCase(); | |
| return ( | |
| <button | |
| key={lang.key} | |
| onClick={() => { | |
| changeLanguage(lang.value.toLowerCase(), true); | |
| setOpen(false); | |
| }} | |
| className={`block w-full rounded-lg py-1 px-2 text-start text-sm font-medium leading-6 transition duration-150 ease-in-out hover:bg-gray-50 ${ | |
| isActive ? 'text-secondary-500' : 'text-gray-700' | |
| }`} | |
| > | |
| {langMap[lang.text.toLowerCase() as keyof typeof langMap] || | |
| lang.text} | |
| </button> | |
| ); | |
| })} | |
| </div> | |
| )} | |
| <button | |
| onClick={() => setOpen((v) => !v)} | |
| aria-expanded={open} | |
| aria-haspopup='listbox' | |
| className='flex items-center gap-x-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-medium text-gray-800 shadow-sm transition hover:bg-gray-50' | |
| > | |
| <IconLanguage className="h-4 w-4 text-gray-800" /> | |
| <span>{currentLangLabel}</span> | |
| <NavItemDropdown /> | |
| </button> | |
| {/* Dropdown panel */} | |
| {open && ( | |
| <div | |
| role='listbox' | |
| aria-label='Select language' | |
| className='absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg' | |
| > | |
| {uniqueLangs.map((lang) => { | |
| const isActive = | |
| currentLanguage.toLowerCase() === lang.text.toLowerCase(); | |
| return ( | |
| <button | |
| key={lang.key} | |
| role='option' | |
| aria-selected={isActive} | |
| onClick={() => { | |
| changeLanguage(lang.value.toLowerCase(), true); | |
| setOpen(false); | |
| }} | |
| className={`block w-full rounded-lg py-1 px-2 text-start text-sm font-medium leading-6 transition duration-150 ease-in-out hover:bg-gray-50 ${ | |
| isActive ? 'text-secondary-500' : 'text-gray-700' | |
| }`} | |
| > | |
| {langMap[lang.text.toLowerCase() as keyof typeof langMap] || | |
| lang.text} | |
| </button> | |
| ); | |
| })} | |
| </div> | |
| )} |
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project
[error] 46-46: This line has a length of 170. Maximum allowed is 120. (max-len)
[error] 46-46: Replace "flex·items-center·gap-x-2·rounded-md·border·border-gray-300·bg-white·px-3·py-2·text-sm·font-medium·text-gray-800·shadow-sm·transition·hover:bg-gray-50" with 'flex·items-center·gap-x-2·rounded-md·border·border-gray-300·bg-white·px-3·py-2·text-sm·font-medium·text-gray-800·shadow-sm·transition·hover:bg-gray-50' (prettier/prettier)
[error] 46-46: Unexpected usage of doublequote. (jsx-quotes)
[error] 48-48: Replace "h-4·w-4·text-gray-800" with 'h-4·w-4·text-gray-800' (prettier/prettier)
[error] 48-48: Unexpected usage of doublequote. (jsx-quotes)
[error] 55-55: Replace "absolute·right-0·top-full·z-50·mt-2·w-48·rounded-lg·bg-white·px-3·py-3·shadow-lg" with 'absolute·right-0·top-full·z-50·mt-2·w-48·rounded-lg·bg-white·px-3·py-3·shadow-lg' (prettier/prettier)
[error] 55-55: Unexpected usage of doublequote. (jsx-quotes)
[error] 57-57: Delete ⏎············· (prettier/prettier)
[error] 67-67: This line has a length of 158. Maximum allowed is 120. (max-len)
[error] 71-71: Delete ⏎················· (prettier/prettier)
🤖 Prompt for AI Agents
In `@components/languageSelector/LanguageSelect.tsx` around lines 44 - 77, The
dropdown is missing ARIA attributes: add aria-haspopup="menu" and
aria-expanded={open} to the trigger button (the element using setOpen and
currentLangLabel) and give the dropdown panel a unique id referenced by
aria-controls on the trigger; on the panel (the JSX that renders when open) add
role="menu" and on each option button (inside uniqueLangs map where
changeLanguage and setOpen are called) add role="menuitem", tabIndex={0} and
aria-current or aria-checked for the active item based on currentLanguage,
ensuring the IDs/props use existing symbols (open, setOpen, changeLanguage,
currentLanguage, uniqueLangs, langMap) so screen readers can detect expanded
state and navigate items.
| <div className="absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg"> | ||
| {uniqueLangs.map((lang) => { | ||
| const isActive = | ||
| currentLanguage.toLowerCase() === lang.text.toLowerCase(); | ||
|
|
||
| return ( | ||
| <button | ||
| key={lang.key} | ||
| onClick={() => { | ||
| changeLanguage(lang.value.toLowerCase(), true); | ||
| setOpen(false); | ||
| }} | ||
| className={`block w-full rounded-lg py-1 px-2 text-start text-sm font-medium leading-6 transition duration-150 ease-in-out hover:bg-gray-50 ${ | ||
| isActive ? 'text-secondary-500' : 'text-gray-700' | ||
| }`} | ||
| > | ||
| {langMap[lang.text.toLowerCase() as keyof typeof langMap] || | ||
| lang.text} | ||
| </button> | ||
| ); | ||
| })} | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix formatting issues in the dropdown panel.
The pipeline reports additional prettier/prettier and max-len errors in this section. Line 67 exceeds 120 characters.
Proposed fix
- <div className="absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg">
+ <div className='absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg'>
{uniqueLangs.map((lang) => {
- const isActive =
- currentLanguage.toLowerCase() === lang.text.toLowerCase();
-
+ const isActive = currentLanguage.toLowerCase() === lang.text.toLowerCase();
return (
<button
key={lang.key}
onClick={() => {
changeLanguage(lang.value.toLowerCase(), true);
setOpen(false);
}}
- className={`block w-full rounded-lg py-1 px-2 text-start text-sm font-medium leading-6 transition duration-150 ease-in-out hover:bg-gray-50 ${
- isActive ? 'text-secondary-500' : 'text-gray-700'
- }`}
+ className={`block w-full rounded-lg px-2 py-1 text-start text-sm font-medium leading-6
+ transition duration-150 ease-in-out hover:bg-gray-50
+ ${isActive ? 'text-secondary-500' : 'text-gray-700'}`}
>
- {langMap[lang.text.toLowerCase() as keyof typeof langMap] ||
- lang.text}
+ {langMap[lang.text.toLowerCase() as keyof typeof langMap] || lang.text}
</button>
);
})}📝 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.
| <div className="absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg"> | |
| {uniqueLangs.map((lang) => { | |
| const isActive = | |
| currentLanguage.toLowerCase() === lang.text.toLowerCase(); | |
| return ( | |
| <button | |
| key={lang.key} | |
| onClick={() => { | |
| changeLanguage(lang.value.toLowerCase(), true); | |
| setOpen(false); | |
| }} | |
| className={`block w-full rounded-lg py-1 px-2 text-start text-sm font-medium leading-6 transition duration-150 ease-in-out hover:bg-gray-50 ${ | |
| isActive ? 'text-secondary-500' : 'text-gray-700' | |
| }`} | |
| > | |
| {langMap[lang.text.toLowerCase() as keyof typeof langMap] || | |
| lang.text} | |
| </button> | |
| ); | |
| })} | |
| </div> | |
| <div className='absolute right-0 top-full z-50 mt-2 w-48 rounded-lg bg-white px-3 py-3 shadow-lg'> | |
| {uniqueLangs.map((lang) => { | |
| const isActive = currentLanguage.toLowerCase() === lang.text.toLowerCase(); | |
| return ( | |
| <button | |
| key={lang.key} | |
| onClick={() => { | |
| changeLanguage(lang.value.toLowerCase(), true); | |
| setOpen(false); | |
| }} | |
| className={`block w-full rounded-lg px-2 py-1 text-start text-sm font-medium leading-6 | |
| transition duration-150 ease-in-out hover:bg-gray-50 | |
| ${isActive ? 'text-secondary-500' : 'text-gray-700'}`} | |
| > | |
| {langMap[lang.text.toLowerCase() as keyof typeof langMap] || lang.text} | |
| </button> | |
| ); | |
| })} | |
| </div> |
🧰 Tools
🪛 GitHub Actions: PR testing - if Node project
[error] 55-55: Replace "absolute·right-0·top-full·z-50·mt-2·w-48·rounded-lg·bg-white·px-3·py-3·shadow-lg" with 'absolute·right-0·top-full·z-50·mt-2·w-48·rounded-lg·bg-white·px-3·py-3·shadow-lg' (prettier/prettier)
[error] 55-55: Unexpected usage of doublequote. (jsx-quotes)
[error] 57-57: Delete ⏎············· (prettier/prettier)
[error] 67-67: This line has a length of 158. Maximum allowed is 120. (max-len)
[error] 71-71: Delete ⏎················· (prettier/prettier)
🤖 Prompt for AI Agents
In `@components/languageSelector/LanguageSelect.tsx` around lines 55 - 76, The
dropdown panel JSX has a long line (className + template literal) causing
prettier/max-len failures; split the long className and conditional into
multiple concatenated or template literal lines and/or extract the computed
classes into a small helper variable before the return to keep each line under
120 chars. Specifically, in the map callback for uniqueLangs (look at
uniqueLangs.map, currentLanguage, isActive, changeLanguage, setOpen, langMap)
move the isActive calculation and the conditional text color class into a const
(e.g., itemClass or isActiveClass) or break the button props/children onto
separate lines so the onClick and className strings are wrapped; ensure the
displayed label still reads from langMap[lang.text.toLowerCase() as keyof typeof
langMap] || lang.text and that formatting now satisfies prettier/max-len.
Fixes UI inconsistency between desktop and mobile language dropdown by updating styling, spacing, colors, and icons to match the mobile design.
Closes #5038
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.