2727import { Link , useLocation } from '@tanstack/react-router' ;
2828import {
2929 Building2 ,
30+ Home ,
3031 Inbox ,
3132 KeyRound ,
3233 Link2 ,
@@ -57,6 +58,7 @@ import { useOrganizations } from '@/hooks/useSession';
5758
5859interface NavItem {
5960 to :
61+ | '/account'
6062 | '/account/profile'
6163 | '/account/security'
6264 | '/account/sessions'
@@ -67,9 +69,11 @@ interface NavItem {
6769 | '/organizations' ;
6870 label : string ;
6971 icon : React . ComponentType < { className ?: string } > ;
72+ exact ?: boolean ;
7073}
7174
7275const ACCOUNT_ITEMS : NavItem [ ] = [
76+ { to : '/account' , label : 'home' , icon : Home , exact : true } ,
7377 { to : '/account/profile' , label : 'profile' , icon : User } ,
7478 { to : '/account/security' , label : 'security' , icon : Shield } ,
7579 { to : '/account/sessions' , label : 'sessions' , icon : Monitor } ,
@@ -78,14 +82,30 @@ const ACCOUNT_ITEMS: NavItem[] = [
7882 { to : '/account/linked-accounts' , label : 'linkedAccounts' , icon : Link2 } ,
7983] ;
8084
85+ /**
86+ * Shared classes added to every SidebarMenuButton in the Account portal:
87+ * - left accent bar that fades in on active
88+ * - icon scale-up on hover (and gradient tint on active)
89+ * - smoother transition
90+ */
91+ const NAV_BUTTON_CLASSES = [
92+ 'group/nav relative transition-all duration-150' ,
93+ 'before:absolute before:left-0 before:top-1/2 before:h-5 before:w-[3px] before:-translate-y-1/2 before:rounded-r-full before:bg-brand-gradient before:opacity-0 before:transition-opacity' ,
94+ 'data-[active=true]:before:opacity-100' ,
95+ 'data-[active=true]:bg-sidebar-accent/80 data-[active=true]:text-sidebar-accent-foreground' ,
96+ '[&>svg]:transition-transform [&>svg]:duration-150 hover:[&>svg]:scale-110' ,
97+ 'data-[active=true]:[&>svg]:text-primary' ,
98+ ] . join ( ' ' ) ;
99+
81100export function AccountSidebar ( ) {
82101 const { t } = useObjectTranslation ( ) ;
83102 const { pathname } = useLocation ( ) ;
84103 const { organizations } = useOrganizations ( ) ;
85104
86- // /account on its own redirects to /account/profile, so treat the bare
87- // path as the profile page for active-state purposes.
88- const normalised = pathname === '/account' ? '/account/profile' : pathname ;
105+ // /account is the home dashboard now; sub-routes match by prefix and the
106+ // `exact` flag is honoured for the Home item so it doesn't light up on
107+ // every sub-route.
108+ const normalised = pathname ;
89109
90110 // Detect /organizations/<orgId>/* — used to surface the org-scoped sub-items.
91111 const orgMatch = pathname . match ( / ^ \/ o r g a n i z a t i o n s \/ ( [ ^ / ] + ) (?: \/ .* ) ? $ / ) ;
@@ -101,10 +121,12 @@ export function AccountSidebar() {
101121 < SidebarMenu >
102122 { ACCOUNT_ITEMS . map ( ( item ) => {
103123 const Icon = item . icon ;
104- const isActive = normalised === item . to || normalised . startsWith ( `${ item . to } /` ) ;
124+ const isActive = item . exact
125+ ? normalised === item . to || normalised === `${ item . to } /`
126+ : normalised === item . to || normalised . startsWith ( `${ item . to } /` ) ;
105127 return (
106128 < SidebarMenuItem key = { item . to } >
107- < SidebarMenuButton asChild isActive = { isActive } tooltip = { t ( `sidebar.items.${ item . label } ` ) } >
129+ < SidebarMenuButton asChild isActive = { isActive } tooltip = { t ( `sidebar.items.${ item . label } ` ) } className = { NAV_BUTTON_CLASSES } >
108130 < Link to = { item . to } >
109131 < Icon className = "size-4" />
110132 < span > { t ( `sidebar.items.${ item . label } ` ) } </ span >
@@ -128,6 +150,7 @@ export function AccountSidebar() {
128150 asChild
129151 isActive = { pathname === '/organizations' }
130152 tooltip = { t ( 'sidebar.items.overview' ) }
153+ className = { NAV_BUTTON_CLASSES }
131154 >
132155 < Link to = "/organizations" >
133156 < Building2 className = "size-4" />
@@ -142,6 +165,7 @@ export function AccountSidebar() {
142165 asChild
143166 isActive = { pathname === `/organizations/${ activeOrgId } /general` }
144167 tooltip = { t ( 'sidebar.items.general' ) }
168+ className = { NAV_BUTTON_CLASSES }
145169 >
146170 < Link to = "/organizations/$orgId/general" params = { { orgId : activeOrgId } } >
147171 < Settings className = "size-4" />
@@ -154,6 +178,7 @@ export function AccountSidebar() {
154178 asChild
155179 isActive = { pathname === `/organizations/${ activeOrgId } /members` }
156180 tooltip = { t ( 'sidebar.items.members' ) }
181+ className = { NAV_BUTTON_CLASSES }
157182 >
158183 < Link to = "/organizations/$orgId/members" params = { { orgId : activeOrgId } } >
159184 < Users className = "size-4" />
@@ -166,6 +191,7 @@ export function AccountSidebar() {
166191 asChild
167192 isActive = { pathname === `/organizations/${ activeOrgId } /teams` }
168193 tooltip = { t ( 'sidebar.items.teams' ) }
194+ className = { NAV_BUTTON_CLASSES }
169195 >
170196 < Link to = "/organizations/$orgId/teams" params = { { orgId : activeOrgId } } >
171197 < Users2 className = "size-4" />
@@ -190,6 +216,7 @@ export function AccountSidebar() {
190216 asChild
191217 isActive = { pathname . startsWith ( '/account/oauth-applications' ) }
192218 tooltip = { t ( 'sidebar.items.oauthApps' ) }
219+ className = { NAV_BUTTON_CLASSES }
193220 >
194221 < Link to = "/account/oauth-applications" >
195222 < KeyRound className = "size-4" />
0 commit comments