404 fallback routes
This commit is contained in:
		
							parent
							
								
									fadb797c55
								
							
						
					
					
						commit
						11359a906f
					
				
							
								
								
									
										24
									
								
								app.tsx
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								app.tsx
									
									
									
									
									
								
							@ -2,8 +2,8 @@ import {Route, useRoute} from ">able/iso-router.tsx";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const Tracer =()=>
 | 
					const Tracer =()=>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const {nestedDepth, pathIndex} = useRoute();
 | 
					    const {nestedDepth, pathIndex, blocked} = useRoute();
 | 
				
			||||||
    return <div>Depth: {nestedDepth}, Index:{pathIndex}</div>
 | 
					    return <div>Depth: {nestedDepth}, Index:{pathIndex}, Match:{blocked.value}</div>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default ()=><div>
 | 
					export default ()=><div>
 | 
				
			||||||
@ -11,23 +11,17 @@ export default ()=><div>
 | 
				
			|||||||
    <nav class="flex gap-10 p-6">
 | 
					    <nav class="flex gap-10 p-6">
 | 
				
			||||||
        <a href="/">Home</a>
 | 
					        <a href="/">Home</a>
 | 
				
			||||||
        <a href="/about">About</a>
 | 
					        <a href="/about">About</a>
 | 
				
			||||||
 | 
					        <a href="/404">404</a>
 | 
				
			||||||
    </nav>
 | 
					    </nav>
 | 
				
			||||||
    <Route path={[]}>
 | 
					    <Route path={[]}><p>home page!</p></Route>
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        <p>home page! <Tracer/></p>
 | 
					 | 
				
			||||||
    </Route>
 | 
					 | 
				
			||||||
    <Route path={["about"]}>
 | 
					    <Route path={["about"]}>
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        <nav class="flex gap-10 p-6">
 | 
					        <nav class="flex gap-10 p-6">
 | 
				
			||||||
            <a href="/about/more">more</a>
 | 
					            <a href="/about/more">more</a>
 | 
				
			||||||
 | 
					            <a href="/about/404">more 404</a>
 | 
				
			||||||
        </nav>
 | 
					        </nav>
 | 
				
			||||||
        <Route path={[]}>
 | 
					        <Route path={[]}><p>About page!</p></Route>
 | 
				
			||||||
            
 | 
					        <Route path={["more"]}><p>more!</p></Route>
 | 
				
			||||||
            <p>About page! <Tracer/></p>
 | 
					        <Route><span>couldnt find it</span></Route>
 | 
				
			||||||
        </Route>
 | 
					 | 
				
			||||||
        <Route path={["more"]}>
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            <p>more!<Tracer/></p>
 | 
					 | 
				
			||||||
        </Route>
 | 
					 | 
				
			||||||
    </Route>
 | 
					    </Route>
 | 
				
			||||||
 | 
					    <Route><p>404 :(</p></Route>
 | 
				
			||||||
</div>;
 | 
					</div>;
 | 
				
			||||||
@ -22,10 +22,21 @@ export const Meta =(props:MetaFields)=> { useMeta(props); return null; }
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//////// Router
 | 
					//////// Router
 | 
				
			||||||
 | 
					type RouteContextData = {
 | 
				
			||||||
 | 
					    /** Current nested depth of the router */ nestedDepth:number,
 | 
				
			||||||
 | 
					    /** Index into the page path to start matching routes */ pathIndex:number,
 | 
				
			||||||
 | 
					    /** Collection of keys from matched routes ("page/:key/") */ keys: Record<string, string>,
 | 
				
			||||||
 | 
					    blocked: Signal.Signal<string | false>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const context = React.createContext({nestedDepth:0, pathIndex:0, keys:{}, blocked:Signal.signal(false as false|string)} as RouteContextData);
 | 
				
			||||||
//// Create Signals
 | 
					//// Create Signals
 | 
				
			||||||
export const pageURL = Signal.signal(new URL(globalThis?.location.href || ""));
 | 
					export const pageURL = Signal.signal(new URL(globalThis?.location.href || ""));
 | 
				
			||||||
export const pagePath = Signal.signal([] as string[]);
 | 
					export const pagePath = Signal.signal([] as string[]);
 | 
				
			||||||
Signal.effect(()=> pagePath.value = pageURL.value.pathname.split("/").filter(part=>part!=""));
 | 
					Signal.effect(()=>{
 | 
				
			||||||
 | 
					    //@ts-ignore 1337 hax
 | 
				
			||||||
 | 
					    if(context){context.__.blocked.value = false;}
 | 
				
			||||||
 | 
					    pagePath.value = pageURL.value.pathname.split("/").filter(part=>part!="");
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
//// Add handlers
 | 
					//// Add handlers
 | 
				
			||||||
globalThis.addEventListener("click", e=>
 | 
					globalThis.addEventListener("click", e=>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -44,14 +55,7 @@ globalThis.addEventListener("click", e=>
 | 
				
			|||||||
    })
 | 
					    })
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
globalThis.addEventListener("popstate", _=> pageURL.value = new URL(globalThis.location.href) );
 | 
					globalThis.addEventListener("popstate", _=> pageURL.value = new URL(globalThis.location.href) );
 | 
				
			||||||
/// Rendering context
 | 
					//// Rendering context
 | 
				
			||||||
type RouteContextData = {
 | 
					 | 
				
			||||||
    /** Current nested depth of the router */ nestedDepth:number,
 | 
					 | 
				
			||||||
    /** Index into the page path to start matching routes */ pathIndex:number,
 | 
					 | 
				
			||||||
    /** Collection of keys from matched routes ("page/:key/") */ keys: Record<string, string>,
 | 
					 | 
				
			||||||
    blocked: Signal.Signal<string | false>
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
const context = React.createContext({nestedDepth:0, pathIndex:0, keys:{}, blocked:Signal.signal(false as false|string)} as RouteContextData);
 | 
					 | 
				
			||||||
type PathFields = {pathAfter:string[], pathBefore:[], compare:typeof compare}
 | 
					type PathFields = {pathAfter:string[], pathBefore:[], compare:typeof compare}
 | 
				
			||||||
const compare =(pathA:string[], pathB:string[])=>
 | 
					const compare =(pathA:string[], pathB:string[])=>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -88,21 +92,21 @@ export const useRoute =()=> {
 | 
				
			|||||||
    const pathBefore = pathFull.slice(0, Math.max(0, routeContext.pathIndex-1));
 | 
					    const pathBefore = pathFull.slice(0, Math.max(0, routeContext.pathIndex-1));
 | 
				
			||||||
    return { ...routeContext, pathAfter, pathBefore, compare } as PathFields&RouteContextData;
 | 
					    return { ...routeContext, pathAfter, pathBefore, compare } as PathFields&RouteContextData;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
export const Route =(props:{path:string[], children:React.ReactNode|React.ReactNode[]}):React.JSX.Element|null=>
 | 
					export const Route =(props:{path?:string[], children:React.ReactNode|React.ReactNode[]}):React.JSX.Element|null=>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const {nestedDepth, pathIndex, pathAfter, compare, keys} = useRoute();
 | 
					    const {nestedDepth, pathIndex, pathAfter, compare, keys, blocked} = useRoute();
 | 
				
			||||||
    const check = compare(props.path, pathAfter);
 | 
					
 | 
				
			||||||
    if (check)
 | 
					    if(blocked.peek()){ return null; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const passOn:RouteContextData = { nestedDepth:nestedDepth+1, pathIndex, keys, blocked:Signal.signal(false) }
 | 
				
			||||||
 | 
					    if(props.path)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return <context.Provider value={{
 | 
					        const check = compare(props.path, pathAfter);
 | 
				
			||||||
            nestedDepth:nestedDepth+1,
 | 
					        if (!check){ return null; }
 | 
				
			||||||
            pathIndex:pathIndex+check.comparisonSize,
 | 
					    
 | 
				
			||||||
            keys: {...keys, ...check.keys},
 | 
					        blocked.value = "/"+props.path.join("/");
 | 
				
			||||||
            blocked:Signal.signal(false)
 | 
					        passOn.pathIndex += check.comparisonSize;
 | 
				
			||||||
        }}>{props.children}</context.Provider>;
 | 
					        passOn.keys = {...keys, ...check.keys};
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return null;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return <context.Provider value={passOn}>{props.children}</context.Provider>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user