Switch over to WebAssembly, Rust and Yew #35

Merged
BlakeRain merged 87 commits from yew-static into main 2023-08-30 18:01:40 +00:00
7 changed files with 119 additions and 4 deletions
Showing only changes of commit e6561ec2cb - Show all commits

2
Cargo.lock generated
View File

@ -1402,8 +1402,10 @@ dependencies = [
"thiserror",
"time",
"tokio",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-logger",
"web-sys",
"yew",
"yew-hooks",
"yew-router",

View File

@ -34,6 +34,7 @@ reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
thiserror = { version = "1.0" }
wasm-bindgen = { version = "0.2" }
yew = { version = "0.20" }
yew-hooks = { version = "0.2" }
yew-router = { version = "0.17" }
@ -61,6 +62,18 @@ features = [
"LucideRss"
]
[dependencies.web-sys]
version = "0.3"
features = [
"Document",
"DomRect",
"Element",
"IntersectionObserver",
"IntersectionObserverEntry",
"ScrollToOptions",
"Window"
]
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen-futures = { version = "0.4" }
wasm-logger = { version = "0.2" }

View File

@ -1,6 +1,7 @@
use yew::{function_component, html, Children, Html, Properties};
mod footer;
pub mod goto_top;
pub mod intersperse;
mod navigation;

View File

@ -12,7 +12,7 @@ pub fn footer(_: &FooterProps) -> Html {
let year = OffsetDateTime::now_utc().year();
html! {
<div class="bg-primary text-neutral-400 text-sm mt-4">
<footer class="bg-primary text-neutral-400 text-sm mt-4">
<div class="container mx-auto flex flex-col gap-4 md:gap-0 md:flex-row md:justify-between px-4 sm:px-0 py-6">
<div>
{format!("Blake Rain © {year}")}
@ -44,7 +44,7 @@ pub fn footer(_: &FooterProps) -> Html {
</a>
</div>
</div>
</div>
</footer>
}
}

View File

@ -0,0 +1,95 @@
use wasm_bindgen::{prelude::Closure, JsCast};
use web_sys::{window, Element, IntersectionObserver, IntersectionObserverEntry, ScrollToOptions};
use yew::{classes, function_component, html, use_effect, use_state, use_state_eq, Callback, Html};
#[function_component(GotoTop)]
pub fn goto_top() -> Html {
let footer_el = use_state_eq(|| None::<Element>);
let visible = use_state_eq(|| false);
let footer_visible = use_state_eq(|| false);
let class = classes!(
"cursor-pointer",
"py-4",
"px-8",
"border",
"border-primary-dark",
"bg-primary-dark",
"hover:bg-primary",
"fixed",
"bottom-8",
"right-8",
"transition-all",
"transition-200",
if *visible { "opacity-100" } else { "opacity-0" },
);
let style = if *footer_visible {
let height = if let Some(footer) = &*footer_el {
-footer.get_bounding_client_rect().height()
} else {
-10.0
};
format!("transform: translateY({}px)", height)
} else if *visible {
"transform: translateY(0px)".to_string()
} else {
"transform: translateY(100px)".to_string()
};
let observe = {
Closure::<dyn Fn(Vec<IntersectionObserverEntry>)>::wrap(Box::new(
move |entries: Vec<IntersectionObserverEntry>| {
for entry in entries {
let tag_name = entry.target().tag_name();
if tag_name == "NAV" {
log::info!("NAV visible: {}", entry.is_intersecting());
visible.set(!entry.is_intersecting());
} else if tag_name == "FOOTER" {
log::info!("FOOTER visible: {}", entry.is_intersecting());
footer_visible.set(entry.is_intersecting());
}
}
},
))
};
{
use_effect(move || {
let document = window().expect("window").document().expect("document");
let header = document
.query_selector("nav:first-of-type")
.expect("query_selector");
let footer = document.query_selector("footer").expect("query_selector");
let observer = IntersectionObserver::new(observe.as_ref().unchecked_ref()).unwrap();
if let Some(header) = header {
observer.observe(&header);
}
if let Some(footer) = footer {
observer.observe(&footer);
footer_el.set(Some(footer));
}
move || {
observer.disconnect();
drop(observe);
}
});
}
let onclick = Callback::from(move |_| {
let mut opts = ScrollToOptions::new();
opts.top(0f64);
window()
.expect("window")
.scroll_to_with_scroll_to_options(&opts);
});
html! {
<button {class} {style} type="button" tabindex="-1" {onclick}>{"↑ Goto Top"}</button>
}
}

View File

@ -1,6 +1,9 @@
use yew::{function_component, html, Html, Properties};
use crate::{components::content::PostContent, model::ProvideTags};
use crate::{
components::{content::PostContent, layout::goto_top::GotoTop},
model::ProvideTags,
};
#[derive(Properties, PartialEq)]
pub struct PageProps {
@ -23,6 +26,7 @@ pub fn page(props: &PageProps) -> Html {
html! {
<ProvideTags>
<PostContent details={details} content={content} />
<GotoTop />
</ProvideTags>
}
}

View File

@ -77,7 +77,7 @@
}
ul {
@apply list-disc;
@apply list-disc pl-10;
}
figure {