@@ -5,71 +5,61 @@ import { t } from "./i18n/index.ts";
55
66export type NavigationRouteId = RouteId ;
77
8- type SidebarSection = {
9- label : string ;
10- routes : readonly NavigationRouteId [ ] ;
11- } ;
12-
138type NavigationItem = {
149 [ TRouteId in NavigationRouteId ] : IconName ;
1510} ;
1611
17- export const SIDEBAR_SECTIONS = [
18- { label : "chat" , routes : [ "chat" ] } ,
19- {
20- label : "control" ,
21- routes : [
22- "overview" ,
23- "activity" ,
24- "workboard" ,
25- "worktrees" ,
26- "instances" ,
27- "sessions" ,
28- "usage" ,
29- "cron" ,
30- ] ,
31- } ,
32- { label : "agent" , routes : [ "agents" , "skills" , "skill-workshop" , "nodes" , "dreams" ] } ,
33- { label : "settings" , routes : [ "config" ] } ,
34- ] as const satisfies readonly SidebarSection [ ] ;
35-
36- type SidebarSectionRouteId = ( typeof SIDEBAR_SECTIONS ) [ number ] [ "routes" ] [ number ] ;
37-
38- export type SidebarNavRoute = Exclude < SidebarSectionRouteId , "chat" | "config" > ;
12+ // The sidebar shows a small user-customizable pinned set; every other nav route
13+ // lives in the collapsed "More" section. Chat is reachable through the session
14+ // list and Settings/Docs live in the sidebar footer, so neither is listed here.
15+ export const SIDEBAR_NAV_ROUTES = [
16+ "overview" ,
17+ "activity" ,
18+ "workboard" ,
19+ "worktrees" ,
20+ "instances" ,
21+ "sessions" ,
22+ "usage" ,
23+ "cron" ,
24+ "agents" ,
25+ "skills" ,
26+ "skill-workshop" ,
27+ "nodes" ,
28+ "dreams" ,
29+ ] as const satisfies readonly NavigationRouteId [ ] ;
3930
40- export const SIDEBAR_NAV_ROUTES = SIDEBAR_SECTIONS . flatMap ( ( section ) =>
41- section . label === "control" || section . label === "agent" ? section . routes : [ ] ,
42- ) as readonly SidebarNavRoute [ ] ;
31+ export type SidebarNavRoute = ( typeof SIDEBAR_NAV_ROUTES ) [ number ] ;
4332
33+ // Sessions are the sidebar's core content; Overview is the only page pinned by
34+ // default. Users pin more via the customize menu.
4435export const DEFAULT_SIDEBAR_PINNED_ROUTES = [
4536 "overview" ,
4637] as const satisfies readonly SidebarNavRoute [ ] ;
4738
48- const SIDEBAR_NAV_ROUTE_SET = new Set < NavigationRouteId > ( SIDEBAR_NAV_ROUTES ) ;
49-
50- function isSidebarNavRoute ( value : unknown ) : value is SidebarNavRoute {
51- return typeof value === "string" && SIDEBAR_NAV_ROUTE_SET . has ( value as NavigationRouteId ) ;
52- }
53-
54- export function normalizeSidebarPinnedRoutes ( value : unknown ) : SidebarNavRoute [ ] | undefined {
39+ /**
40+ * Normalize a persisted pinned-route list. Returns null when the value is not a
41+ * list (caller falls back to defaults); unknown or duplicate entries are dropped
42+ * so prefs survive route renames/removals without a migration.
43+ */
44+ export function normalizeSidebarPinnedRoutes ( value : unknown ) : SidebarNavRoute [ ] | null {
5545 if ( ! Array . isArray ( value ) ) {
56- return undefined ;
46+ return null ;
5747 }
58- const seen = new Set < SidebarNavRoute > ( ) ;
59- const routes : SidebarNavRoute [ ] = [ ] ;
60- for ( const routeId of value ) {
61- if ( ! isSidebarNavRoute ( routeId ) || seen . has ( routeId ) ) {
62- continue ;
48+ const pinned : SidebarNavRoute [ ] = [ ] ;
49+ for ( const entry of value ) {
50+ if (
51+ typeof entry === "string" &&
52+ ( SIDEBAR_NAV_ROUTES as readonly string [ ] ) . includes ( entry ) &&
53+ ! pinned . includes ( entry as SidebarNavRoute )
54+ ) {
55+ pinned . push ( entry as SidebarNavRoute ) ;
6356 }
64- seen . add ( routeId ) ;
65- routes . push ( routeId ) ;
6657 }
67- return routes ;
58+ return pinned ;
6859}
6960
70- export function sidebarMoreRoutes ( pinnedRoutes : readonly SidebarNavRoute [ ] ) : SidebarNavRoute [ ] {
71- const pinned = new Set ( pinnedRoutes ) ;
72- return SIDEBAR_NAV_ROUTES . filter ( ( routeId ) => ! pinned . has ( routeId ) ) ;
61+ export function sidebarMoreRoutes ( pinned : readonly SidebarNavRoute [ ] ) : SidebarNavRoute [ ] {
62+ return SIDEBAR_NAV_ROUTES . filter ( ( routeId ) => ! pinned . includes ( routeId ) ) ;
7363}
7464
7565export const SETTINGS_NAVIGATION_ROUTES = [
@@ -117,16 +107,6 @@ export function isSettingsNavigationRoute(routeId: NavigationRouteId): boolean {
117107 return ( SETTINGS_NAVIGATION_ROUTES as readonly NavigationRouteId [ ] ) . includes ( routeId ) ;
118108}
119109
120- export function isRouteInSidebarSection (
121- section : SidebarSection ,
122- routeId : NavigationRouteId ,
123- ) : boolean {
124- if ( section . label === "settings" ) {
125- return isSettingsNavigationRoute ( routeId ) ;
126- }
127- return section . routes . includes ( routeId ) ;
128- }
129-
130110export function navigationIconForRoute ( routeId : NavigationRouteId ) : IconName {
131111 return NAVIGATION_ICONS [ routeId ] ?? "folder" ;
132112}
0 commit comments