| import { useEffect, useState } from "react"; |
|
|
| |
| export type Route = { kind: "home" } | { kind: "graph" } | { kind: "free-label"; slug: string }; |
|
|
| |
| export function parseRoute(pathname: string): Route { |
| const segments = pathname.split("/").filter((segment) => segment !== ""); |
| if (segments[0] !== "graph") return { kind: "home" }; |
| const slug = segments[1]; |
| if (slug === undefined) return { kind: "graph" }; |
| try { |
| return { kind: "free-label", slug: decodeURIComponent(slug) }; |
| } catch { |
| return { kind: "graph" }; |
| } |
| } |
|
|
| |
| export function navigate(path: string): void { |
| window.history.pushState(null, "", path); |
| window.dispatchEvent(new PopStateEvent("popstate")); |
| } |
|
|
| |
| export function isPlainLeftClick(event: { |
| defaultPrevented: boolean; |
| button: number; |
| metaKey: boolean; |
| ctrlKey: boolean; |
| shiftKey: boolean; |
| altKey: boolean; |
| }): boolean { |
| if (event.defaultPrevented || event.button !== 0) return false; |
| return !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey; |
| } |
|
|
| |
| export function useRoute(): Route { |
| const [pathname, setPathname] = useState(() => window.location.pathname); |
| useEffect(() => { |
| const onPopState = (): void => { |
| setPathname(window.location.pathname); |
| }; |
| window.addEventListener("popstate", onPopState); |
| return (): void => { |
| window.removeEventListener("popstate", onPopState); |
| }; |
| }, []); |
| return parseRoute(pathname); |
| } |
|
|