@@ -68,14 +68,34 @@ type RouterContextValue = [
68
68
69
69
const RouterContext = createContext < RouterContextValue | undefined > ( undefined ) ;
70
70
71
- const parse = ( search : string ) : RouterState => {
71
+ const parse = ( pathname : string , search : string ) : RouterState => {
72
72
const params = new URLSearchParams ( search ) ;
73
- return {
74
- tab : params . get ( "tab" ) ?? undefined ,
75
- api : anchorForParam ( params . get ( "api" ) ) ,
76
- reference : anchorForParam ( params . get ( "reference" ) ) ,
77
- idea : anchorForParam ( params . get ( "idea" ) ) ,
78
- } ;
73
+ if ( params . get ( "tab" ) ) {
74
+ // Legacy
75
+ return {
76
+ tab : params . get ( "tab" ) ?? undefined ,
77
+ api : anchorForParam ( params . get ( "api" ) ) ,
78
+ reference : anchorForParam ( params . get ( "reference" ) ) ,
79
+ idea : anchorForParam ( params . get ( "idea" ) ) ,
80
+ } ;
81
+ }
82
+ const base = process . env . PUBLIC_URL ?? "/" ;
83
+ pathname = pathname . slice ( base . length ) ;
84
+ if ( pathname ) {
85
+ const parts = pathname . split ( "/" ) ;
86
+ const tab = parts [ 0 ] ;
87
+ switch ( tab ) {
88
+ case "api" :
89
+ return { tab : "api" , api : anchorForParam ( parts [ 1 ] ) } ;
90
+ case "reference" :
91
+ return { tab : "reference" , api : anchorForParam ( parts [ 1 ] ) } ;
92
+ case "idea" :
93
+ return { tab : "ideas" , api : anchorForParam ( parts [ 1 ] ) } ;
94
+ default :
95
+ return { } ;
96
+ }
97
+ }
98
+ return { } ;
79
99
} ;
80
100
81
101
/**
@@ -95,28 +115,29 @@ export const useRouterState = (): RouterContextValue => {
95
115
} ;
96
116
97
117
export const toUrl = ( state : RouterState ) : string => {
98
- const query = Object . entries ( state )
99
- . filter ( ( [ k , v ] ) => k !== "focus" && ! ! v )
100
- . map ( ( [ k , v ] ) => {
101
- return `${ encodeURIComponent ( k ) } =${ encodeURIComponent (
102
- serializeValue ( v )
103
- ) } `;
104
- } )
105
- . join ( "&" ) ;
106
- return window . location . toString ( ) . split ( "?" ) [ 0 ] + ( query ? "?" + query : "" ) ;
118
+ // This could be cleaned up if we always set the tab.
119
+ const parts = [
120
+ state . tab ??
121
+ ( state . tab === "api" || state . api ? "api" : undefined ) ??
122
+ ( state . reference ? "reference" : undefined ) ??
123
+ ( state . idea ? "ideas" : undefined ) ,
124
+ state . api ?. id ?? state . reference ?. id ?? state . idea ?. id ,
125
+ ] ;
126
+ const base = process . env . PUBLIC_URL ?? "/" ;
127
+ const pathname = base + parts . filter ( ( x ) : x is string => ! ! x ) . join ( "/" ) ;
128
+ return window . location . toString ( ) . split ( "/" , 1 ) [ 0 ] + pathname ;
107
129
} ;
108
130
109
- const serializeValue = ( value : Anchor | string ) =>
110
- typeof value === "string" ? value : value . id ;
111
-
112
131
export const RouterProvider = ( { children } : { children : ReactNode } ) => {
113
132
const logging = useLogging ( ) ;
114
- const [ state , setState ] = useState ( parse ( window . location . search ) ) ;
133
+ const [ state , setState ] = useState (
134
+ parse ( window . location . pathname , window . location . search )
135
+ ) ;
115
136
useEffect ( ( ) => {
116
137
// This detects browser navigation but not our programatic changes,
117
138
// so we need to update state there ourselves.
118
139
const listener = ( _ : PopStateEvent ) => {
119
- const newState = parse ( window . location . search ) ;
140
+ const newState = parse ( window . location . pathname , window . location . search ) ;
120
141
setState ( newState ) ;
121
142
} ;
122
143
window . addEventListener ( "popstate" , listener ) ;
0 commit comments