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 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 }
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}