@@ -13,31 +13,26 @@ import { TopNavContainer } from './container'
1313import {
1414 Server ,
1515 CloudDownload ,
16- FlaskConical ,
17- Lock ,
1816 Settings as SettingsIcon ,
1917 ArrowUpCircle ,
18+ FlaskConical ,
2019} from 'lucide-react'
2120import type { LucideIcon } from 'lucide-react'
2221import { useRouterState } from '@tanstack/react-router'
2322import { useAppVersion } from '@/common/hooks/use-app-version'
2423import { cn } from '@/common/lib/utils'
24+ import { getOsDesignVariant } from '@/common/lib/os-design'
25+ import { NavSeparator } from './nav-separator'
26+ import { NavIconButton } from './nav-icon-button'
2527
2628interface NavButtonProps {
2729 to : string
2830 icon : LucideIcon
2931 children : React . ReactNode
3032 isActive ?: boolean
31- badge ?: React . ReactNode
3233}
3334
34- function NavButton ( {
35- to,
36- icon : Icon ,
37- children,
38- isActive,
39- badge,
40- } : NavButtonProps ) {
35+ function NavButton ( { to, icon : Icon , children, isActive } : NavButtonProps ) {
4136 return (
4237 < LinkViewTransition
4338 to = { to }
@@ -50,26 +45,20 @@ function NavButton({
5045 : 'bg-transparent text-white/90 hover:bg-white/10 hover:text-white'
5146 ) }
5247 >
53- < span className = "relative" >
54- < Icon className = "size-4" />
55- { badge }
56- </ span >
48+ < Icon className = "size-4" />
5749 { children }
5850 </ LinkViewTransition >
5951 )
6052}
6153
62- function TopNavLinks ( { showUpdateBadge } : { showUpdateBadge ?: boolean } ) {
54+ function useIsActive ( ) {
6355 const pathname = useRouterState ( { select : ( s ) => s . location . pathname } )
64-
65- const isActive = ( paths : string [ ] ) =>
56+ return ( paths : string [ ] ) =>
6657 paths . some ( ( p ) => pathname . startsWith ( p ) || pathname === p )
58+ }
6759
68- const updateBadge = showUpdateBadge ? (
69- < span className = "absolute -top-1 -right-1" >
70- < ArrowUpCircle className = "size-3 fill-blue-500" />
71- </ span >
72- ) : null
60+ function TopNavLinks ( ) {
61+ const isActive = useIsActive ( )
7362
7463 return (
7564 < NavigationMenu >
@@ -101,28 +90,6 @@ function TopNavLinks({ showUpdateBadge }: { showUpdateBadge?: boolean }) {
10190 Playground
10291 </ NavButton >
10392 </ NavigationMenuItem >
104- < NavigationMenuItem >
105- < NavButton
106- to = "/secrets"
107- icon = { Lock }
108- isActive = { isActive ( [ '/secrets' ] ) }
109- >
110- Secrets
111- </ NavButton >
112- </ NavigationMenuItem >
113- < NavigationMenuItem >
114- < NavButton
115- to = "/settings"
116- icon = { SettingsIcon }
117- isActive = { isActive ( [ '/settings' ] ) }
118- badge = { updateBadge }
119- >
120- Settings
121- </ NavButton >
122- </ NavigationMenuItem >
123- < NavigationMenuItem >
124- < HelpDropdown className = "app-region-no-drag" />
125- </ NavigationMenuItem >
12693 </ NavigationMenuList >
12794 </ NavigationMenu >
12895 )
@@ -131,6 +98,8 @@ function TopNavLinks({ showUpdateBadge }: { showUpdateBadge?: boolean }) {
13198export function TopNav ( props : HTMLProps < HTMLElement > ) {
13299 const { data : appVersion } = useAppVersion ( )
133100 const isProduction = import . meta. env . MODE === 'production'
101+ const isActive = useIsActive ( )
102+ const showUpdateBadge = ! ! ( appVersion ?. isNewVersionAvailable && isProduction )
134103
135104 useEffect ( ( ) => {
136105 const cleanup = window . electronAPI . onUpdateDownloaded ( ( ) => {
@@ -163,13 +132,31 @@ export function TopNav(props: HTMLProps<HTMLElement>) {
163132 return (
164133 < TopNavContainer { ...props } >
165134 < div className = "flex h-10 items-center" >
166- < TopNavLinks
167- showUpdateBadge = {
168- ! ! ( appVersion ?. isNewVersionAvailable && isProduction )
169- }
170- />
135+ < TopNavLinks />
171136 </ div >
172- < div className = "flex items-center gap-2 justify-self-end" >
137+ < div
138+ className = "app-region-no-drag flex h-full items-center justify-self-end"
139+ >
140+ < div className = "flex h-full items-center gap-1 pl-2" >
141+ < HelpDropdown className = "app-region-no-drag" />
142+ < NavIconButton
143+ asChild
144+ isActive = { isActive ( [ '/settings' ] ) }
145+ aria-label = "Settings"
146+ className = "app-region-no-drag relative"
147+ >
148+ < LinkViewTransition to = "/settings" >
149+ < SettingsIcon className = "size-5" />
150+ { showUpdateBadge && (
151+ < span className = "absolute -top-0.5 -right-0.5" >
152+ < ArrowUpCircle className = "size-3 fill-blue-500" />
153+ </ span >
154+ ) }
155+ </ LinkViewTransition >
156+ </ NavIconButton >
157+ </ div >
158+ { /* Windows: separator between icon group and window controls */ }
159+ { getOsDesignVariant ( ) !== 'mac' && < NavSeparator /> }
173160 < WindowControls />
174161 </ div >
175162 </ TopNavContainer >
0 commit comments