1use log::*;
2use sauron::{prelude::*, Cmd, Component, Node, Program};
3use std::collections::BTreeMap;
4use url_path::UrlPath;
5use wasm_bindgen::prelude::*;
6
7#[global_allocator]
9static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
10
11#[derive(Clone)]
12pub enum Msg {
13 UrlChanged(String),
14 FileReady(Result<String, JsValue>),
15}
16
17pub struct App {
18 raw: String,
19 content: String,
20 title: Option<String>,
21 current_file: UrlPath,
22}
23
24impl App {
25 fn new() -> Self {
26 let hash = Browser::get_hash();
27 let current_file = UrlPath::new(Self::clean_link(&hash));
28 App {
29 raw: String::new(),
30 content: String::new(),
31 title: None,
32 current_file,
33 }
34 }
35
36 fn clean_link(url: &str) -> &str {
37 let url = url.trim_start_matches("#/");
38 let url = url.trim_start_matches("#");
39 if url.trim().is_empty(){
40 "index.md"
41 }else{
42 url
43 }
44 }
45
46 fn fetch_current_file(&self) -> Cmd<App, Msg> {
47 let url = self.current_file.normalize();
48 trace!("fetching {}", url);
49 Http::fetch_with_text_response_decoder(&url, |v| v, Msg::FileReady)
50 }
51
52 fn markdown_to_html(&mut self) {
53 let embed_files = BTreeMap::new();
54 if let Ok(html) = spongedown::parse_with_base_dir(
55 &self.raw,
56 &self.current_file.parent().unwrap_or("/".to_string()),
57 &Some(embed_files),
58 ) {
59 self.title = html.title;
60 self.content = html.content;
61 if let Some(title) = &self.title{
62 Window::set_title(&title);
63 }
64 }
65 }
66}
67
68impl Component<Msg> for App {
69 fn init(&self) -> Cmd<App, Msg> {
70 Cmd::batch(vec![
71 Browser::onhashchange(Msg::UrlChanged),
72 self.fetch_current_file(),
73 ])
74 }
75 fn update(&mut self, msg: Msg) -> Cmd<App, Msg> {
76 match msg {
77 Msg::UrlChanged(url) => {
78 let url = Self::clean_link(&url);
79 trace!("url changed: {}", url);
80 self.current_file = UrlPath::new(url);
81 self.fetch_current_file()
82 }
83 Msg::FileReady(file) => {
84 Browser::scroll_to_top();
85 match file {
86 Ok(raw) => {
87 trace!("ok got file");
88 self.raw = raw;
89 self.markdown_to_html();
90 }
91 Err(_e) => {
92 error!("display 404 here")
95 }
96 }
97 Cmd::none()
98 }
99 }
100 }
101
102 fn view(&self) -> Node<Msg> {
103 div(
104 vec![],
105 vec![
106 nav(vec![], vec![a(vec![href("/")], vec![text("Home")])]),
107 article(vec![inner_html(&self.content)], vec![]),
108 ],
109 )
110 }
111}
112
113#[wasm_bindgen(start)]
114pub fn main() {
115 console_error_panic_hook::set_once();
116 console_log::init_with_level(log::Level::Trace).unwrap();
117 Program::mount_to_body(App::new());
118}