Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Router use anchor tags #128

Merged
merged 2 commits into from
Jun 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions docs/src/header.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use sycamore::prelude::*;
use sycamore_router::Link;

#[component(Nav<G>)]
fn nav() -> Template<G> {
Expand All @@ -11,12 +10,10 @@ fn nav() -> Template<G> {
// Brand section
div(class="flex-initial") {
div(class="flex space-x-4 text-white") {
Link(("/", template! {
span(class="py-2 px-3 text-sm font-medium \
bg-gray-500 hover:bg-gray-600 transition-colors rounded", href="/#") {
"Sycamore"
}
}))
a(href="/#", class="py-2 px-3 text-sm font-medium \
bg-gray-500 hover:bg-gray-600 transition-colors rounded") {
"Sycamore"
}
}
}
// Links section
Expand Down
15 changes: 7 additions & 8 deletions docs/src/index.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use sycamore::prelude::*;
use sycamore_router::Link;

#[component(Index<G>)]
pub fn index() -> Template<G> {
Expand All @@ -12,13 +11,13 @@ pub fn index() -> Template<G> {
p(class="mb-10") {
"Pure Rust + WASM web-apps"
}

Link(("/getting_started/installation", template! {
span(class="py-2 px-3 bg-white hover:bg-yellow-500 border-2 border-yellow-500 \
rounded font-medium transition") {
"Read the Book"
}
}))
a(
href="/getting_started/installation",
class="py-2 px-3 bg-white hover:bg-yellow-500 border-2 border-yellow-500 \
rounded font-medium transition",
) {
"Read the Book"
}
}
}
}
110 changes: 6 additions & 104 deletions docs/src/sidebar.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use sycamore::prelude::*;
use sycamore_router::Link;

static PAGES: &[(&str, &[(&str, &str)])] = &[
(
Expand Down Expand Up @@ -60,11 +59,12 @@ pub fn sidebar() -> Template<G> {
.map(|page| {
template! {
li {
Link((page.1, template! {
span(class="pl-4 hover:bg-gray-300 w-full inline-block rounded transition") {
(page.0)
}
}))
a(
href=page.1,
class="pl-4 hover:bg-gray-300 w-full inline-block rounded transition",
) {
(page.0)
}
}
}
})
Expand All @@ -90,104 +90,6 @@ pub fn sidebar() -> Template<G> {
ul(class="text-black") {
(sections)
}
// ul(class="list-unstyled ps-0") {
// li(class="mb-1") {
// h5 {
// "Getting Started"
// }
// div(class="d-grid gap-1") {
// a(class="btn btn-sm btn-light btn-block", href="/getting_started/installation") {
// "Installation"
// }

// a(class="btn btn-sm btn-light btn-block", href="/getting_started/hello_world") {
// "Hello, World!"
// }
// }
// }
// li(class="mb-1") {
// h5 {
// "Basics"
// }
// div(class="d-grid gap-1") {
// a(class="btn btn-sm btn-light btn-block", href="/basics/template") {
// "template!"
// }
// a(class="btn btn-sm btn-light btn-block", href="/basics/reactivity") {
// "Reactivity"
// }
// a(class="btn btn-sm btn-light btn-block", href="/basics/components") {
// "Components"
// }
// a(class="btn btn-sm btn-light btn-block", href="/basics/control_flow") {
// "Control Flow"
// }
// a(class="btn btn-sm btn-light btn-block", href="/basics/iteration") {
// "Iteration"
// }
// a(class="btn btn-sm btn-light btn-block", href="/basics/data_binding") {
// "Data binding"
// }
// }
// }
// li(class="mb-1") {
// h5 {
// "Advanced Guides"
// }
// div(class="d-grid gap-1") {
// a(class="btn btn-sm btn-light btn-block", href="/advanced/noderef") {
// "NodeRef"
// }
// a(class="btn btn-sm btn-light btn-block", href="/advanced/tweened") {
// "Tweened"
// }
// a(class="btn btn-sm btn-light btn-block", href="/advanced/advanced_reactivity") {
// "Advanced Reactivity"
// }
// a(class="btn btn-sm btn-light btn-block", href="/advanced/css") {
// "CSS"
// }
// a(class="btn btn-sm btn-light btn-block", href="/advanced/testing") {
// "Testing"
// }
// a(class="btn btn-sm btn-light btn-block", href="/advanced/routing") {
// "Routing"
// }
// a(class="btn btn-sm btn-light btn-block", href="/advanced/ssr") {
// "SSR"
// }
// a(class="btn btn-sm btn-light btn-block", href="/advanced/js_interop") {
// "JS Interop"
// }
// }
// }
// li(class="mb-1") {
// h5 {
// "Optimizations"
// }
// div(class="d-grid gap-1") {
// a(class="btn btn-sm btn-light btn-block", href="/optimizations/code_size") {
// "Code Size"
// }
// a(class="btn btn-sm btn-light btn-block", href="/optimizations/speed") {
// "Speed"
// }
// }
// }
// li(class="mb-1") {
// h5 {
// "Contribute"
// }
// div(class="d-grid gap-1") {
// a(class="btn btn-sm btn-light btn-block", href="/contribute/architecture") {
// "Architecture"
// }
// a(class="btn btn-sm btn-light btn-block", href="/contribute/development") {
// "Development"
// }
// }
// }
// }
}
}
}
1 change: 1 addition & 0 deletions packages/sycamore-router/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ features = [
"Event",
"EventTarget",
"History",
"HtmlAnchorElement",
"Location",
"PopStateEvent",
"Window",
Expand Down
75 changes: 47 additions & 28 deletions packages/sycamore-router/src/router.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::cell::RefCell;
use std::rc::Rc;

use sycamore::prelude::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use web_sys::{Element, HtmlAnchorElement};

use crate::Route;

Expand All @@ -24,32 +24,6 @@ thread_local! {
static PATHNAME: RefCell<Option<Signal<String>>> = RefCell::new(None);
}

#[component(Link<G>)]
pub fn link((to, body): (impl ToString, Template<G>)) -> Template<G> {
let href = Rc::new(to.to_string());
let handle_click = cloned!((href) => move |ev: web_sys::Event| {
ev.prevent_default();

PATHNAME.with(|pathname| {
if let Some(pathname) = pathname.borrow().as_ref() {
pathname.set(href.to_string());

// Update History API.
let history = web_sys::window().unwrap().history().unwrap();
history.push_state_with_url(&JsValue::UNDEFINED, "", Some(pathname.get().as_str())).unwrap();
} else {
panic!("Link can only be used inside a BrowserRouter");
}

});
});
template! {
a(href=href, on:click=handle_click) {
(body)
}
}
}

#[component(BrowserRouter<G>)]
pub fn browser_router<R: Route>(render: impl Fn(R) -> Template<G> + 'static) -> Template<G> {
PATHNAME.with(|pathname| {
Expand Down Expand Up @@ -88,6 +62,51 @@ pub fn browser_router<R: Route>(render: impl Fn(R) -> Template<G> + 'static) ->
.collect::<Vec<_>>()
.as_slice(),
);
untrack(|| render(route))
// Delegate click events from child <a> tags.
let template = untrack(|| render(route));
if let Some(node) = template.as_node() {
node.event(
"click",
Box::new(|ev| {
if let Some(a) = ev
.target()
.unwrap()
.unchecked_into::<Element>()
.closest("a[href]")
.unwrap()
{
let location = web_sys::window().unwrap().location();

let a = a.unchecked_into::<HtmlAnchorElement>();
let origin = a.origin();
let href = a.href();
let path = a.pathname();
if origin == location.origin().unwrap() {
ev.prevent_default();
if href != location.href().unwrap() {
PATHNAME.with(|pathname| {
let pathname = pathname.borrow().clone().unwrap();
pathname.set(path.to_string());

// Update History API.
let history = web_sys::window().unwrap().history().unwrap();
history
.push_state_with_url(
&JsValue::UNDEFINED,
"",
Some(pathname.get().as_str()),
)
.unwrap();
});
}
}
}
}),
);
} else {
todo!();
}

template
})
}
2 changes: 1 addition & 1 deletion packages/sycamore/src/generic_node/dom_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ impl GenericNode for DomNode {
fn event(&self, name: &str, handler: Box<EventListener>) {
let closure = Closure::wrap(handler);
self.node
.add_event_listener_with_callback(name, closure.as_ref().unchecked_ref())
.add_event_listener_with_callback(intern(name), closure.as_ref().unchecked_ref())
.unwrap();

on_cleanup(move || {
Expand Down