Skip to content

Commit 8db58b4

Browse files
committed
refactor(navbar): restructure navbar shell and menu composition
1 parent ad474b8 commit 8db58b4

1 file changed

Lines changed: 65 additions & 79 deletions

File tree

src/components/layout/Navbar/Navbar.tsx

Lines changed: 65 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
import { memo } from 'react';
22

3-
import { motion } from 'framer-motion';
4-
import { UserCircle, X } from 'lucide-react';
3+
import { UserCircle, X } from '@/assets/icons';
54

6-
import { Logo } from '@/components/layout';
7-
8-
import { NavbarDesktopDropdown } from './parts/NavbarDesktopDropdown';
9-
import { NavbarMobileMenu } from './parts/NavbarMobileMenu';
10-
11-
/** Props for the `Navbar` shell component. */
5+
import { Logo } from '@/shared/ui';
6+
import { NavbarDesktopMenu, NavbarMobileMenu } from './NavbarMenu';
127
interface NavbarProps {
138
rightSlot?: React.ReactNode;
149
isMobileMenuOpen: boolean;
1510
setIsMobileMenuOpen: React.Dispatch<React.SetStateAction<boolean>>;
1611
isAuthenticated: boolean;
17-
isDropdownOpen: boolean;
18-
setIsDropdownOpen: React.Dispatch<React.SetStateAction<boolean>>;
12+
isDesktopDropdownOpen: boolean;
13+
setIsDesktopDropdownOpen: React.Dispatch<React.SetStateAction<boolean>>;
1914
dropdownRef: React.RefObject<HTMLDivElement | null>;
2015
handleLogoClick: () => void;
2116
toggleMobileMenu: () => void;
@@ -27,89 +22,80 @@ function Navbar({
2722
isMobileMenuOpen,
2823
setIsMobileMenuOpen,
2924
isAuthenticated,
30-
isDropdownOpen,
31-
setIsDropdownOpen,
25+
isDesktopDropdownOpen,
26+
setIsDesktopDropdownOpen,
3227
dropdownRef,
3328
handleLogoClick,
3429
toggleMobileMenu,
3530
handleSignOut
3631
}: NavbarProps) {
32+
const toggleButtonClass = (isOpen: boolean) =>
33+
`p-2 min-h-11 min-w-11 flex items-center justify-center rounded-lg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent ${
34+
isOpen
35+
? 'bg-surface-elevated text-accent'
36+
: 'text-text-secondary hover:text-text-primary hover:bg-surface-hover active:bg-surface-elevated'
37+
}`;
38+
3739
return (
38-
<>
39-
<motion.nav
40-
initial={{ opacity: 0, y: -20 }}
41-
animate={{ opacity: 1, y: 0 }}
42-
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
43-
className="navbar-shell fixed top-0 left-0 right-0 z-50 transition-all duration-300"
44-
>
45-
<div className="relative z-50 bg-surface">
46-
<div className="page-container">
47-
<div className="flex justify-between items-center py-3 min-h-12 sm:min-h-14 lg:min-h-16">
48-
<button
49-
type="button"
50-
onClick={handleLogoClick}
51-
aria-label="ChessVision home"
52-
className="flex items-center gap-2 rounded-lg transition-colors duration-200 text-text-primary hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"
53-
>
54-
<div className="flex items-center gap-2">
55-
<Logo className="w-8 h-8 sm:w-10 sm:h-10 lg:w-12 lg:h-12 object-contain" />
56-
<div className="hidden lg:block">
57-
<span className="font-display font-bold text-xl xs:text-2xl sm:text-3xl leading-tight text-text-primary">
58-
Chess
59-
</span>
60-
<span className="font-display font-bold text-xl xs:text-2xl sm:text-3xl text-text-primary leading-tight ">
61-
Vision
62-
</span>
63-
</div>
40+
<nav className="fixed top-0 left-0 right-0 z-50 pt-[max(0px, env(safe-area-inset-top))] transition-all duration-300 animate-navbar-in">
41+
<div className="relative z-50 bg-surface">
42+
<div className="page-container">
43+
<div className="flex justify-between items-center py-3 min-h-12 sm:min-h-14 lg:min-h-16">
44+
<button
45+
type="button"
46+
onClick={handleLogoClick}
47+
aria-label="ChessViewer home"
48+
className="flex items-center gap-2 rounded-lg transition-colors duration-200 text-text-primary hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"
49+
>
50+
<div className="flex items-center gap-2">
51+
<Logo className="w-8 h-8 sm:w-10 sm:h-10 lg:w-12 lg:h-12 object-contain" />
52+
<div className="hidden lg:block">
53+
<span className="font-display font-bold text-xl xs:text-2xl sm:text-3xl leading-tight text-text-primary">
54+
ChessViewer
55+
</span>
6456
</div>
65-
</button>
66-
67-
<div className="hidden lg:flex items-center gap-2">
68-
{rightSlot}
69-
70-
<NavbarDesktopDropdown
71-
isAuthenticated={isAuthenticated}
72-
isDropdownOpen={isDropdownOpen}
73-
setIsDropdownOpen={setIsDropdownOpen}
74-
dropdownRef={dropdownRef}
75-
handleSignOut={handleSignOut}
76-
/>
7757
</div>
58+
</button>
7859

79-
<div className="flex lg:hidden items-center gap-2">
80-
{rightSlot}
60+
<div className="hidden lg:flex items-center gap-2">
61+
{rightSlot}
62+
<NavbarDesktopMenu
63+
isAuthenticated={isAuthenticated}
64+
isDesktopDropdownOpen={isDesktopDropdownOpen}
65+
setIsDesktopDropdownOpen={setIsDesktopDropdownOpen}
66+
dropdownRef={dropdownRef}
67+
handleSignOut={handleSignOut}
68+
/>
69+
</div>
8170

82-
<button
83-
type="button"
84-
onClick={toggleMobileMenu}
85-
className={`p-2 min-h-11 min-w-11 flex items-center justify-center rounded-lg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent ${
86-
isMobileMenuOpen
87-
? 'bg-surface-elevated text-accent'
88-
: 'text-text-secondary hover:text-text-primary hover:bg-surface-hover active:bg-surface-elevated'
89-
}`}
90-
aria-label="Account menu"
91-
aria-haspopup="menu"
92-
aria-expanded={isMobileMenuOpen}
93-
>
94-
{isMobileMenuOpen ? (
95-
<X className="w-6 h-6" aria-hidden="true" />
96-
) : (
97-
<UserCircle className="w-6 h-6" aria-hidden="true" />
98-
)}
99-
</button>
100-
</div>
71+
<div className="flex lg:hidden items-center gap-2">
72+
{rightSlot}
73+
<button
74+
type="button"
75+
onClick={toggleMobileMenu}
76+
className={toggleButtonClass(isMobileMenuOpen)}
77+
aria-label="Account menu"
78+
aria-haspopup="menu"
79+
aria-expanded={isMobileMenuOpen}
80+
>
81+
{isMobileMenuOpen ? (
82+
<X className="w-6 h-6" aria-hidden="true" />
83+
) : (
84+
<UserCircle className="w-6 h-6" aria-hidden="true" />
85+
)}
86+
</button>
10187
</div>
10288
</div>
10389
</div>
90+
</div>
10491

105-
<NavbarMobileMenu
106-
isOpen={isMobileMenuOpen}
107-
isAuthenticated={isAuthenticated}
108-
setIsMobileMenuOpen={setIsMobileMenuOpen}
109-
handleSignOut={handleSignOut}
110-
/>
111-
</motion.nav>
112-
</>
92+
<NavbarMobileMenu
93+
isOpen={isMobileMenuOpen}
94+
isAuthenticated={isAuthenticated}
95+
setIsMobileMenuOpen={setIsMobileMenuOpen}
96+
handleSignOut={handleSignOut}
97+
/>
98+
</nav>
11399
);
114100
}
115101

0 commit comments

Comments
 (0)