fracter/
lib.rs

1use wasm_bindgen::prelude::*;
2use sycamore::prelude::*;
3pub use seoul::Isomorphism;
4
5
6impl<T: Isomorphism + Default + PartialEq + Clone> Fracter for T {
7  fn name(&self) -> Option<String> {
8    if self==&Self::default() {
9      None
10    } else {
11      Some(self.title().to_lowercase())
12    }
13  }
14
15  fn from(name: &str) -> Self {
16    let name = name.to_lowercase();
17    for x in Self::list().iter() {
18      if let Some(t) = x.name() {
19        if name==t {
20          return x.clone();
21        }
22      }
23    }
24    Self::default()
25  }
26}
27
28pub trait Fracter: Default + PartialEq {
29
30  /// default -> None
31  fn name(&self) -> Option<String>;
32
33  fn from(name: &str) -> Self;
34
35  fn get_hash() -> String {
36    let x = gloo_utils::window().location().hash().unwrap_throw();
37    x.replace("#", "")
38  }
39
40  fn from_hash() -> Self {
41    Self::from(&Self::get_hash())
42  }
43  
44  fn set_hash(x: &str) {
45    gloo_utils::window().location().set_hash(x).unwrap_throw()
46  }
47
48  fn init() -> Signal<Self> {
49
50    let fracter = create_signal(Self::default());
51    provide_context(fracter);
52
53    on_mount(move || {
54
55      let f = Self::from_hash();
56      if fracter.with(|x| x!=&f) {
57        fracter.set(f);
58      }
59
60      create_effect(on(fracter, move || {
61        if let Some(name) = fracter.with(|x| x.name()) {
62          if Self::get_hash() != name {
63            Self::set_hash(&name);
64            // No need to update history
65            // let history = gloo_utils::window().history().unwrap_throw();
66            // history.push_state_with_url(&JsValue::NULL, &name, Some(&format!("#{}", name))).unwrap_throw();
67          }
68        } else {
69          Self::set_hash("");
70        }
71      }));
72
73      let cb = Closure::<dyn FnMut(_)>::new(move |_: web_sys::PopStateEvent| {
74        let f = Self::from_hash();
75        if fracter.with(|x| x!=&f) {
76          fracter.set(f);
77        }
78      });
79      let window = gloo_utils::window();
80      window.add_event_listener_with_callback("popstate", cb.as_ref().unchecked_ref()).unwrap_throw();
81  
82      on_cleanup(move || {
83        window.remove_event_listener_with_callback("popstate", cb.as_ref().unchecked_ref()).unwrap_throw();
84      });
85    });
86
87    fracter
88  }
89}