Skip to content

Commit

Permalink
feat(examples): update rdom-router demo
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Jul 2, 2024
1 parent 8ea075e commit b117a28
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 16 deletions.
6 changes: 1 addition & 5 deletions examples/rdom-router/css/style.mcss
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,4 @@ main { mv4 }
grid grid-cols-3 m:grid-cols-4 l:grid-cols-5 gap4 mv3
}

#controls {
{
button { dib mr2 }
}
}
#controls button { dib mr2 }
59 changes: 48 additions & 11 deletions examples/rdom-router/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { pickRandom } from "@thi.ng/random";
import { $compile, $list, $switch } from "@thi.ng/rdom";
import {
EVENT_ROUTE_CHANGED,
EVENT_ROUTE_FAILED,
HTMLRouter,
type Route,
type RouteMatch,
Expand All @@ -24,9 +25,21 @@ interface AppState {

// route definitions for router
const ROUTES: Route[] = [
{ id: "home", match: ["home"] },
{ id: "gallery", match: ["gallery"] },
{ id: "image", match: ["gallery", "?id"] },
{ id: "home", match: "/home" },
{ id: "gallery", match: "/gallery" },
// parametric route with param coercion & validation
{
id: "image",
match: "gallery/?id",
validate: {
id: {
coerce: (x) => parseInt(x),
check: (x) => x >= 0 && x < IMAGES.length,
},
},
},
// fallback route
{ id: "missing", match: "/404" },
];

// list of image URLs
Expand All @@ -44,14 +57,19 @@ const db = defAtom<AppState>({
// define & initialize router w/ basic config (see thi.ng/router)
const router = new HTMLRouter({
routes: ROUTES,
default: "home",
initial: "home",
default: "missing",
useFragment: true,
});

// the router will emit an event each time the route has changed
// we'll store the new route in the atom, which then will trigger an UI update
router.addListener(EVENT_ROUTE_CHANGED, (e) => db.resetIn(["route"], e.value));

// optional event listener for failed/unknown routes
// (these routes will be redirected to configured default route)
router.addListener(EVENT_ROUTE_FAILED, console.log);

// start the router
router.start();

Expand Down Expand Up @@ -104,23 +122,42 @@ const thumbnail = (src: string) =>
const image = async ({ params: { id } }: RouteMatch) =>
container("Single image", img(".fullsize", { src: IMAGES[id] }));

const missing = async () => container("404", "Route doesn't exist...");

// compile & mount main UI/DOM
$compile(
div(
{},
nav(
{},
// build SPA navigation links using the router's format() feature to form URLs
...["home", "gallery"].map((id) =>
anchor({ href: router.format(id) }, id)
)
),
// unknown route (will trigger configured fallback/default route)
anchor({ href: "#/foo" }, "todo")
),
$switch(fromView(db, { path: ["route"] }), (route) => route.id, {
home,
gallery,
image,
})
// helper component to dynamically switch out its body based on given
// reactive subscription value (here the app state's `route` info)
$switch(
// reactive value
fromView(db, { path: ["route"] }),
// key function to extract the actual dispatch/switch value
(route) => route.id,
// an object mapping keys to component functions. e.g. if the new
// route ID is `gallery`, then the `gallery()` function defined
// above will be called and its result used as new body of the
// $switch() component. before that, the current component body will
// be unmounted first....
{
home,
gallery,
image,
missing,
}
)
)
).mount(document.getElementById("app")!);

// expose app state atom in browser console
// debug only: expose app state atom in browser console
exposeGlobal("db", db);

0 comments on commit b117a28

Please sign in to comment.