6 changed files with 150 additions and 54 deletions
@ -1,59 +1,80 @@ |
|||||||
|
import { useCallback } from "react"; |
||||||
|
|
||||||
import { useQueryParam } from "@/hooks/useQueryParams"; |
import { useQueryParam } from "@/hooks/useQueryParams"; |
||||||
|
import { useOverlayStore } from "@/stores/overlay/store"; |
||||||
|
|
||||||
export function useOverlayRouter(id: string) { |
function splitPath(path: string, prefix?: string): string[] { |
||||||
|
const parts = [prefix ?? "", ...path.split("/")]; |
||||||
|
return parts.filter((v) => v.length > 0); |
||||||
|
} |
||||||
|
|
||||||
|
function joinPath(path: string[]): string { |
||||||
|
return `/${path.join("/")}`; |
||||||
|
} |
||||||
|
|
||||||
|
export function useInternalOverlayRouter(id: string) { |
||||||
const [route, setRoute] = useQueryParam("r"); |
const [route, setRoute] = useQueryParam("r"); |
||||||
const routeParts = (route ?? "").split("/").filter((v) => v.length > 0); |
const transition = useOverlayStore((s) => s.transition); |
||||||
const routerActive = routeParts.length > 0 && routeParts[0] === id; |
const setTransition = useOverlayStore((s) => s.setTransition); |
||||||
|
const routerActive = !!route && route.startsWith(`/${id}`); |
||||||
|
|
||||||
function navigate(path: string) { |
function navigate(path: string) { |
||||||
const newRoute = [id, ...path.split("/").filter((v) => v.length > 0)]; |
const oldRoute = route; |
||||||
setRoute(newRoute.join("/")); |
const newRoute = joinPath(splitPath(path, id)); |
||||||
|
setTransition({ |
||||||
|
from: oldRoute ?? "/", |
||||||
|
to: newRoute, |
||||||
|
}); |
||||||
|
setRoute(newRoute); |
||||||
} |
} |
||||||
|
|
||||||
function isActive(page: string) { |
function showBackwardsTransition(path: string) { |
||||||
if (page === "/") return true; |
if (!transition) return false; |
||||||
const index = routeParts.indexOf(page); |
const current = joinPath(splitPath(path, id)); |
||||||
if (index === -1) return false; // not active
|
|
||||||
if (index === routeParts.length - 1) return false; // active but latest route so shouldnt be counted as active
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
function isCurrentPage(page: string) { |
if (current === transition.to && transition.from.startsWith(transition.to)) |
||||||
return routerActive && route === `/${id}${page}`; |
return true; |
||||||
|
if ( |
||||||
|
current === transition.from && |
||||||
|
transition.to.startsWith(transition.from) |
||||||
|
) |
||||||
|
return true; |
||||||
|
return false; |
||||||
} |
} |
||||||
|
|
||||||
function isLoaded(page: string) { |
function isCurrentPage(path: string) { |
||||||
if (page === "/") return true; |
return routerActive && route === joinPath(splitPath(path, id)); |
||||||
return route.includes(page); |
|
||||||
} |
} |
||||||
|
|
||||||
function isOverlayActive() { |
function isOverlayActive() { |
||||||
return routerActive; |
return routerActive; |
||||||
} |
} |
||||||
|
|
||||||
function pageProps(page: string) { |
const close = useCallback(() => { |
||||||
return { |
setTransition(null); |
||||||
show: isCurrentPage(page), |
|
||||||
active: isActive(page), |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
function close() { |
|
||||||
setRoute(null); |
setRoute(null); |
||||||
} |
}, [setRoute, setTransition]); |
||||||
|
|
||||||
function open() { |
const open = useCallback(() => { |
||||||
|
setTransition(null); |
||||||
setRoute(`/${id}`); |
setRoute(`/${id}`); |
||||||
} |
}, [id, setRoute, setTransition]); |
||||||
|
|
||||||
return { |
return { |
||||||
|
showBackwardsTransition, |
||||||
|
isCurrentPage, |
||||||
isOverlayActive, |
isOverlayActive, |
||||||
navigate, |
navigate, |
||||||
close, |
close, |
||||||
isLoaded, |
|
||||||
isCurrentPage, |
|
||||||
pageProps, |
|
||||||
isActive, |
|
||||||
open, |
open, |
||||||
}; |
}; |
||||||
} |
} |
||||||
|
|
||||||
|
export function useOverlayRouter(id: string) { |
||||||
|
const router = useInternalOverlayRouter(id); |
||||||
|
return { |
||||||
|
open: router.open, |
||||||
|
close: router.close, |
||||||
|
navigate: router.navigate, |
||||||
|
}; |
||||||
|
} |
||||||
|
|||||||
@ -0,0 +1,23 @@ |
|||||||
|
import { create } from "zustand"; |
||||||
|
import { immer } from "zustand/middleware/immer"; |
||||||
|
|
||||||
|
export interface OverlayTransition { |
||||||
|
from: string; |
||||||
|
to: string; |
||||||
|
} |
||||||
|
|
||||||
|
interface OverlayStore { |
||||||
|
transition: null | OverlayTransition; |
||||||
|
setTransition(newTrans: OverlayTransition | null): void; |
||||||
|
} |
||||||
|
|
||||||
|
export const useOverlayStore = create( |
||||||
|
immer<OverlayStore>((set) => ({ |
||||||
|
transition: null, |
||||||
|
setTransition(newTrans) { |
||||||
|
set((s) => { |
||||||
|
s.transition = newTrans; |
||||||
|
}); |
||||||
|
}, |
||||||
|
})) |
||||||
|
); |
||||||
Loading…
Reference in new issue