@@ -4,6 +4,7 @@ import Link from "next/link";
44import { usePathname } from "next/navigation" ;
55import { useTranslations } from "next-intl" ;
66import { motion } from "framer-motion" ;
7+ import { memo , useCallback , useMemo } from "react" ;
78
89function getNavItems ( t : ReturnType < typeof useTranslations > ) {
910 return [
@@ -70,7 +71,7 @@ interface SidebarProps {
7071 onMobileOpenChange : ( open : boolean ) => void ;
7172}
7273
73- function NavLinks ( {
74+ const NavLinks = memo ( function NavLinks ( {
7475 pathname,
7576 t,
7677 onNavigate,
@@ -79,7 +80,7 @@ function NavLinks({
7980 t : ReturnType < typeof useTranslations > ;
8081 onNavigate ?: ( ) => void ;
8182} ) {
82- const navItems = getNavItems ( t ) ;
83+ const navItems = useMemo ( ( ) => getNavItems ( t ) , [ t ] ) ;
8384
8485 return (
8586 < nav aria-label = "Dashboard navigation" className = "flex flex-1 flex-col gap-1 px-4 py-6" >
@@ -91,7 +92,7 @@ function NavLinks({
9192 if ( isExternal ) {
9293 return (
9394 < a key = { item . href } href = { item . href } target = "_blank" rel = "noopener noreferrer" onClick = { onNavigate }
94- className = "flex items-center gap-3 rounded-lg px-3 py-2.5 transition-all text-[#6B6B6B] hover:bg-[var(--pluto-50)] hover:text-[var(--pluto-700 )]" >
95+ className = "flex items-center gap-3 rounded-lg px-3 py-2.5 text-[#6B6B6B] transition-colors duration-150 hover:bg-[var(--pluto-50)] hover:text-[var(--pluto-800)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--pluto-300 )]" >
9596 < span className = "shrink-0" > { item . icon } </ span >
9697 < span className = "text-xs font-semibold tracking-wide" > { item . label } </ span >
9798 < svg className = "h-3 w-3 ml-auto opacity-50" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" > < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" /> </ svg >
@@ -105,12 +106,12 @@ function NavLinks({
105106 href = { item . href }
106107 prefetch = { true }
107108 onClick = { onNavigate }
108- className = { `flex items-center gap-3 rounded-lg px-3 py-2.5 transition-all ${
109+ className = { `flex items-center gap-3 rounded-lg px-3 py-2.5 transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--pluto-300)] ${
109110 isActive
110111 ? "bg-[var(--pluto-500)] text-white"
111112 : isHighlight
112- ? "border border-[var(--pluto-200)] bg-[var(--pluto-50)] text-[var(--pluto-700)] hover:bg -[var(--pluto-500)] hover:text-white hover:border- [var(--pluto-500)]"
113- : "text-[#6B6B6B] hover:bg-[var(--pluto-50 )] hover:text-[var(--pluto-700 )]"
113+ ? "border border-[var(--pluto-200)] bg-[var(--pluto-50)] text-[var(--pluto-700)] hover:border -[var(--pluto-500)] hover:bg- [var(--pluto-500)] hover:text-white "
114+ : "text-[#6B6B6B] hover:bg-[var(--pluto-100 )] hover:text-[var(--pluto-800 )]"
114115 } `}
115116 >
116117 < span className = "shrink-0" > { item . icon } </ span >
@@ -121,7 +122,7 @@ function NavLinks({
121122
122123 < div className = "mt-auto pt-4 border-t border-[#E8E8E8]" >
123124 < Link href = "/" onClick = { onNavigate }
124- className = "flex items-center gap-3 rounded-lg px-3 py-2.5 text-[#6B6B6B] transition-all hover:bg-[#F5F5F5 ] hover:text-[#0A0A0A ]"
125+ className = "flex items-center gap-3 rounded-lg px-3 py-2.5 text-[#6B6B6B] transition-colors duration-150 hover:bg-[var(--pluto-50) ] hover:text-[var(--pluto-800)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--pluto-300) ]"
125126 >
126127 < svg className = "h-4 w-4 shrink-0" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
127128 < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
@@ -131,14 +132,17 @@ function NavLinks({
131132 </ div >
132133 </ nav >
133134 ) ;
134- }
135+ } ) ;
136+
137+ NavLinks . displayName = "NavLinks" ;
135138
136139export default function Sidebar ( {
137140 mobileOpen,
138141 onMobileOpenChange,
139142} : SidebarProps ) {
140143 const t = useTranslations ( "sidebar" ) ;
141144 const pathname = usePathname ( ) ;
145+ const handleNavigate = useCallback ( ( ) => onMobileOpenChange ( false ) , [ onMobileOpenChange ] ) ;
142146
143147 // Note: Collapsible logic removed to fix linting as it's not currently used in the UI.
144148
@@ -153,7 +157,7 @@ export default function Sidebar({
153157 < NavLinks
154158 pathname = { pathname }
155159 t = { t }
156- onNavigate = { ( ) => onMobileOpenChange ( false ) }
160+ onNavigate = { handleNavigate }
157161 />
158162 </ >
159163 ) ;
0 commit comments