Skip to main content

flams_router_content/
components.rs

1#![allow(clippy::must_use_candidate)]
2
3use flams_router_base::maybe_lazy;
4use flams_web_utils::{client_only, components::wait_and_then_fn};
5use ftml_components::{
6    SidebarPosition,
7    components::{content::FtmlViewable, terms::inject_comp_css},
8};
9use ftml_dom::{DocumentState, FtmlViews, toc::TocSource, utils::css::CssExt};
10use ftml_uris::{
11    DocumentUri, Uri, UriKind,
12    components::{
13        DocumentUriComponentTuple, DocumentUriComponents, UriComponentTuple, UriComponents,
14        UriComponentsTrait,
15    },
16};
17use leptos::prelude::*;
18use leptos_router::hooks::use_query_map;
19
20maybe_lazy!(
21    TopDocRouter = {
22        let params = use_query_map().get_untracked();
23        if let Some(p) = params.get_str("uri") {
24            let Ok(uri) = <ftml_uris::Uri as std::str::FromStr>::from_str(p) else {
25                return view! { <leptos_router::components::Redirect path="/dashboard"/> }
26                    .into_any();
27            };
28            DocumentOfTop(DocumentOfTopProps { uri }).into_any()
29        } else {
30            view! { <leptos_router::components::Redirect path="/dashboard"/> }.into_any()
31        }
32    }
33);
34
35maybe_lazy!(
36    UriTopRouter = {
37        let works = use_query_map()
38            .with_untracked(|p| p.get_str("a").is_some() || p.get_str("uri").is_some());
39        if works {
40            URITop()
41        } else {
42            view! { <leptos_router::components::Redirect path="/dashboard"/> }.into_any()
43        }
44    }
45);
46
47#[component(transparent)]
48pub fn URITop() -> AnyView {
49    // TODO: this can be optimized!
50    ftml_dom::global_setup(move || {
51        crate::Views::top(move || {
52            use_query_map().with_untracked(|m| {
53                if let Ok(doc) = m.as_document() {
54                    return view!(<Document doc=doc.into()/>).into_any();
55                }
56                let kind = match m.kind() {
57                    Ok(k) => k,
58                    Err(e) => {
59                        return flams_web_utils::components::display_error(
60                            format!("Invalid URI: {e}").into(),
61                        )
62                        .into_any();
63                    }
64                };
65                let comps = match m.as_comps() {
66                    Ok(k) => k,
67                    Err(e) => {
68                        return flams_web_utils::components::display_error(
69                            format!("Invalid URI: {e}").into(),
70                        )
71                        .into_any();
72                    }
73                };
74                match kind {
75                    UriKind::Base => {
76                        view! { <leptos_router::components::Redirect path="/dashboard"/> }
77                            .into_any()
78                    }
79                    UriKind::Document =>
80                    // unreachable
81                    {
82                        flams_web_utils::components::display_error("Invalid URI".into()).into_any()
83                    }
84                    UriKind::DocumentElement | UriKind::Symbol => {
85                        view!(<Fragment uri=comps.into() position=SidebarPosition::Next/>)
86                            .into_any()
87                    }
88                    UriKind::Module => {
89                        let comps: UriComponents = comps.into();
90                        client_only!(view!(<DoModule comps=comps.clone()/>)).into_any()
91                    }
92                    UriKind::Archive | UriKind::Path => {
93                        let comps: UriComponents = comps.into();
94                        client_only!(
95                            view!(<super::archive_views::ArchiveView comps = comps.clone() />)
96                        )
97                        .into_any()
98                    }
99                }
100            })
101        })
102    })
103    .into_any()
104}
105
106#[component]
107fn DoModule(comps: UriComponents) -> impl IntoView {
108    let comps = UriComponentTuple::from(comps);
109    let uri = if let Some(Uri::Module(uri)) = comps.uri {
110        Some(uri)
111    } else {
112        None
113    };
114    let a = comps.a;
115    let p = comps.p;
116    let m = comps.m;
117    inject_comp_css();
118    wait_and_then_fn(
119        move || crate::server_fns::get_module(uri.clone(), a.clone(), p.clone(), m.clone()),
120        |r| DocumentState::no_document(move || r.as_view()),
121    )
122}
123
124#[component]
125pub fn DocumentOfTop(uri: Uri) -> AnyView {
126    use leptos_router::components::Redirect;
127    client_only!({
128        let uri = uri.clone();
129        wait_and_then_fn(
130            move || super::server_fns::document_of(uri.clone()),
131            |u| {
132                view!(<Redirect path=format!("/?uri={}",urlencoding::encode(&u.to_string()))/>)
133                    .into_any()
134            },
135        )
136    })
137    .into_any()
138}
139
140#[component]
141pub fn Fragment(uri: UriComponents, position: SidebarPosition) -> AnyView {
142    use ftml_dom::utils::css::CssExt;
143    let f = move || UriComponentTuple::from(uri).apply1(super::server_fns::fragment, None);
144    client_only!({
145        ftml_components::utils::wait_and_then(
146            f.clone(),
147            move |(uri, css, html)| {
148                for css in css {
149                    css.inject();
150                }
151                let (uri, src) = match uri {
152                    Uri::Document(d) => {
153                        //FtmlConfig::set_toc_source(TocSource::Get);
154                        (Some(d.into()), TocSource::Get)
155                    }
156                    Uri::DocumentElement(d) => {
157                        //FtmlConfig::set_toc_source(TocSource::None);
158                        (Some(d.into()), TocSource::None)
159                    }
160                    _ => {
161                        //FtmlConfig::set_toc_source(TocSource::None);
162                        (None, TocSource::None)
163                    }
164                };
165                crate::Views::render_fragment(uri, position, true, src, move || {
166                    crate::Views::render_ftml(html.into_string(), None).into_any()
167                })
168            },
169            |e| view!(<span style="color:red">{e.to_string()}</span>).into_any(),
170        )
171    })
172    .into_any()
173    //})
174}
175
176#[component]
177pub fn Document(doc: DocumentUriComponents) -> AnyView {
178    client_only!({
179        let doc = doc.clone();
180        ftml_components::utils::wait_and_then(
181            move || DocumentUriComponentTuple::from(doc).apply(super::server_fns::document),
182            move |(uri, css, html)| {
183                for c in css {
184                    c.inject();
185                }
186                {
187                    //FtmlConfig::set_toc_source(TocSource::Get);
188                    crate::Views::setup_document(
189                        uri,
190                        SidebarPosition::Next,
191                        true,
192                        TocSource::Get,
193                        move || crate::Views::render_ftml(html.into_string(), None).into_any(),
194                    )
195                }
196                .into_any()
197            },
198            |e| view!(<span style="color:red">{e.to_string()}</span>).into_any(),
199        )
200    })
201    .into_any()
202}
203
204#[component]
205pub fn DocumentInner(doc: DocumentUriComponents) -> AnyView {
206    let doc: UriComponents = doc.into();
207    wait_and_then_fn(
208        move || UriComponentTuple::from(doc.clone()).apply1(super::server_fns::fragment, None),
209        move |(uri, css, html)| {
210            for css in css {
211                css.inject();
212            }
213            view! {<div>{
214                crate::Views::setup_document(
215                    DocumentUri::no_doc().clone(),
216                    SidebarPosition::None,
217                    true,
218                    TocSource::None,
219                    move || crate::Views::render_ftml(html.into_string(),None).into_any()
220                )
221            }</div>}
222            .into_any()
223        },
224    )
225    .into_any()
226}