Router
use draco::router::Mode::Hash;
use draco::url::Url;
use wasm_bindgen::prelude::*;
#[derive(Default)]
struct Router {
page: Page,
}
enum Message {
Navigate(Page),
}
#[derive(Clone, Debug, PartialEq)]
enum Page {
Index,
PostIndex { sort: Option<String> },
PostShow { id: i32, hash: Option<String> },
NotFound,
}
impl Default for Page {
fn default() -> Self {
Page::Index
}
}
impl draco::router::Route for Page {
fn from_url(url: Url) -> Self {
use draco::url::parse::*;
parse(&url)
// /
.when((), |()| Page::Index)
// /posts
// /posts?sort=some-string
.when(("posts", query("sort").optional()), |((), sort)| {
Page::PostIndex { sort }
})
// /posts/123
// /posts/123#some-string
.when(("posts", param()), |((), id)| Page::PostShow {
id,
hash: url.hash().clone(),
})
.finish()
.unwrap_or(Page::NotFound)
}
fn to_url(&self) -> Url {
let root = draco::url::build();
match self {
Page::Index => root,
Page::PostIndex { sort } => root.path("posts").query_optional("sort", sort.as_ref()),
Page::PostShow { id, hash } => root.path("posts").path(id).hash(hash.as_ref()),
Page::NotFound => root,
}
.finish()
}
}
impl draco::Application for Router {
type Message = Message;
fn update(&mut self, message: Self::Message, _mailbox: &draco::Mailbox<Self::Message>) {
match message {
Message::Navigate(page) => {
self.page = page;
}
}
}
fn view(&self) -> draco::VNode<Self::Message> {
use draco::html as h;
let pages = [
Page::Index,
Page::PostIndex { sort: None },
Page::PostIndex {
sort: Some("id".into()),
},
Page::PostIndex {
sort: Some("title".into()),
},
Page::PostShow { id: 1, hash: None },
Page::PostShow {
id: 1,
hash: Some("section-1".into()),
},
Page::PostShow { id: 2, hash: None },
Page::PostShow {
id: 2,
hash: Some("section-1".into()),
},
];
h::div()
.with(h::h3().with(format!("Current Page: {:?}", &self.page)))
.append(pages.iter().map(|page| {
h::div()
.attribute(
"style",
if page == &self.page {
"padding: .25rem .75rem; background: #fefcbf; border: 1px solid #ecc94b; border-radius: 4px;"
} else {
"padding: .25rem .75rem;"
},
)
.with((
h::span().with(
draco::router::link(Hash, page.clone())
.with(format!("{:?}", page))
.attribute("style", "margin-right: .5rem;"),
),
h::button()
.with("Push")
.on_("click", {
let page = page.clone();
move |_| {
draco::router::push(Hash, &page);
None
}
})
.attribute("style", "margin-right: .5rem;"),
h::button().with("Replace").on_("click", {
let page = page.clone();
move |_| {
draco::router::replace(Hash, &page);
None
}
}),
))
}))
.into()
}
}
#[wasm_bindgen(start)]
pub fn start() {
let mailbox = draco::start(
Router::default(),
draco::select("main").expect("<main>").into(),
);
mailbox.subscribe_forever(draco::router::Router::new(Hash), Message::Navigate);
}