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