import {createContext} from "@/utils/context" import {Topic} from "@/contexts/topics"; type Route = { name: keyof typeof routes, args: any[], location: string, } const matchers: {[key: string]: (location: string) => any[] | null} = {}; function constructRoute( name: keyof typeof routes, generateLocation: (...args: A) => string, matcher: (location: string) => A | null, ): (...args: A) => Route { matchers[name] = matcher; return (...args) => ({ name, args, location: generateLocation(...args), } satisfies Route); } export const routes = { home: constructRoute( "home", (page: number) => { // console.log(page) if(page < 0) { throw new Error("Page not found"); } return page ? `/${page + 1}` : "/" }, (location) => { // console.log(location) if(location === "/") { return [0]; } const match = location.match(/^\/(\d+)/); // console.log([Math.max(parseInt(match[1]) - 1, 0)]); return match ? [Math.max(parseInt(match[1]) - 1, 0)] : null; }, // (location) => location === "/" ? [] : null, ), topic: constructRoute( "topic", (id: string, page: number) => `/topic/${id}/${page}`, (location) => { const match = location.match(/^\/topic\/(.+)\/(\d+)/); return match ? [match[1], Math.max(parseInt(match[2]) - 1, 1)] : null; }, ), settings: constructRoute( "settings", () => "/settings", (location) => location === "/settings" ? [] : null, ), } as const satisfies { [key: string]: (...args: any[]) => Route }; function matchBrowserLocation(): Route { for (const [name, matcher] of Object.entries(matchers)) { const location = window.location.pathname + window.location.search; const args = matcher(location); if (args !== null) { return routes[name as keyof typeof routes](...args); } } return routes.home(0); } const history: Route[] = []; let historyIndex = 0; export const routeCtx = createContext({ initialValue: matchBrowserLocation, controllers: (route: Route, setRoute) => ({ onMount: () => { // console.log("add listener") // Add initial route to history history.push(route); historyIndex = history.length - 1; window.addEventListener('popstate', () => { setRoute(matchBrowserLocation()); }); }, effect: () => { const location = route.location; if (location !== `${window.location.pathname}${window.location.search}`) { history.push(route); historyIndex = history.length - 1; window.history.pushState({}, "", location); } }, actions: { goBack: () => { // console.log(history); // console.log(historyIndex); if (historyIndex > 0) { historyIndex--; setRoute(history[historyIndex]); } else { setRoute(routes.home(0)); } }, getHistoryIndex: () => historyIndex, // goBack: (route: Route, setRoute) => { // if (historyIndex > 0) { // historyIndex--; // // } // } // goForward: () => { // if (historyIndex < history.length - 1) {} // } } }) })