mirror of
https://github.com/Nutomic/ibis.git
synced 2024-11-25 21:41:10 +00:00
fmt
This commit is contained in:
parent
bb892571cb
commit
3e1d2a1d4a
19 changed files with 689 additions and 673 deletions
|
@ -90,30 +90,30 @@ pub fn App() -> impl IntoView {
|
|||
provide_context(create_rw_signal(global_state));
|
||||
|
||||
view! {
|
||||
<>
|
||||
<Stylesheet id="simple" href="/assets/simple.css"/>
|
||||
<Stylesheet id="ibis" href="/assets/ibis.css"/>
|
||||
<Router>
|
||||
<Nav/>
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="/" view=ReadArticle/>
|
||||
<Route path="/article/:title" view=ReadArticle/>
|
||||
<Route path="/article/:title/history" view=ArticleHistory/>
|
||||
<Route path="/article/:title/edit/:conflict_id?" view=EditArticle/>
|
||||
<Route path="/article/:title/actions" view=ArticleActions/>
|
||||
<Route path="/article/:title/diff/:hash" view=EditDiff/>
|
||||
<Route path="/article/create" view=CreateArticle/>
|
||||
<Route path="/article/list" view=ListArticles/>
|
||||
<Route path="/instance/:hostname" view=InstanceDetails/>
|
||||
<Route path="/user/:name" view=UserProfile/>
|
||||
<Route path="/login" view=Login/>
|
||||
<Route path="/register" view=Register/>
|
||||
<Route path="/search" view=Search/>
|
||||
<Route path="/conflicts" view=Conflicts/>
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
</>
|
||||
<>
|
||||
<Stylesheet id="simple" href="/assets/simple.css" />
|
||||
<Stylesheet id="ibis" href="/assets/ibis.css" />
|
||||
<Router>
|
||||
<Nav />
|
||||
<main>
|
||||
<Routes>
|
||||
<Route path="/" view=ReadArticle />
|
||||
<Route path="/article/:title" view=ReadArticle />
|
||||
<Route path="/article/:title/history" view=ArticleHistory />
|
||||
<Route path="/article/:title/edit/:conflict_id?" view=EditArticle />
|
||||
<Route path="/article/:title/actions" view=ArticleActions />
|
||||
<Route path="/article/:title/diff/:hash" view=EditDiff />
|
||||
<Route path="/article/create" view=CreateArticle />
|
||||
<Route path="/article/list" view=ListArticles />
|
||||
<Route path="/instance/:hostname" view=InstanceDetails />
|
||||
<Route path="/user/:name" view=UserProfile />
|
||||
<Route path="/login" view=Login />
|
||||
<Route path="/register" view=Register />
|
||||
<Route path="/search" view=Search />
|
||||
<Route path="/conflicts" view=Conflicts />
|
||||
</Routes>
|
||||
</main>
|
||||
</Router>
|
||||
</>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,61 +12,65 @@ use leptos_router::*;
|
|||
#[component]
|
||||
pub fn ArticleNav(article: Resource<Option<String>, ArticleView>) -> impl IntoView {
|
||||
view! {
|
||||
<Suspense>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article_| {
|
||||
let instance = create_local_resource(
|
||||
move || article_.article.instance_id,
|
||||
move |instance_id| async move {
|
||||
let form = GetInstance {
|
||||
id: Some(instance_id),
|
||||
};
|
||||
GlobalState::api_client().get_instance(&form).await.unwrap()
|
||||
},
|
||||
);
|
||||
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
|
||||
let article_link = article_link(&article_.article);
|
||||
let article_link_ = article_link.clone();
|
||||
let protected = article_.article.protected;
|
||||
view! {
|
||||
<nav class="inner">
|
||||
<A href=article_link.clone()>"Read"</A>
|
||||
<A href=format!("{article_link}/history")>"History"</A>
|
||||
<Show when=move || {
|
||||
global_state
|
||||
.with(|state| {
|
||||
let is_admin = state
|
||||
.my_profile
|
||||
.as_ref()
|
||||
.map(|p| p.local_user.admin)
|
||||
.unwrap_or(false);
|
||||
state.my_profile.is_some()
|
||||
&& can_edit_article(&article_.article, is_admin).is_ok()
|
||||
})
|
||||
}>
|
||||
<A href=format!("{article_link}/edit")>"Edit"</A>
|
||||
</Show>
|
||||
<Show when=move || global_state.with(|state| state.my_profile.is_some())>
|
||||
<A href=format!("{article_link_}/actions")>"Actions"</A>
|
||||
{instance
|
||||
.get()
|
||||
.map(|i| {
|
||||
view! { <InstanceFollowButton instance=i.instance.clone()/> }
|
||||
})}
|
||||
<Suspense>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article_| {
|
||||
let instance = create_local_resource(
|
||||
move || article_.article.instance_id,
|
||||
move |instance_id| async move {
|
||||
let form = GetInstance {
|
||||
id: Some(instance_id),
|
||||
};
|
||||
GlobalState::api_client().get_instance(&form).await.unwrap()
|
||||
},
|
||||
);
|
||||
let global_state = use_context::<RwSignal<GlobalState>>().unwrap();
|
||||
let article_link = article_link(&article_.article);
|
||||
let article_link_ = article_link.clone();
|
||||
let protected = article_.article.protected;
|
||||
view! {
|
||||
<nav class="inner">
|
||||
<A href=article_link.clone()>"Read"</A>
|
||||
<A href=format!("{article_link}/history")>"History"</A>
|
||||
<Show when=move || {
|
||||
global_state
|
||||
.with(|state| {
|
||||
let is_admin = state
|
||||
.my_profile
|
||||
.as_ref()
|
||||
.map(|p| p.local_user.admin)
|
||||
.unwrap_or(false);
|
||||
state.my_profile.is_some()
|
||||
&& can_edit_article(&article_.article, is_admin).is_ok()
|
||||
})
|
||||
}>
|
||||
<A href=format!("{article_link}/edit")>"Edit"</A>
|
||||
</Show>
|
||||
<Show when=move || {
|
||||
global_state.with(|state| state.my_profile.is_some())
|
||||
}>
|
||||
<A href=format!("{article_link_}/actions")>"Actions"</A>
|
||||
{instance
|
||||
.get()
|
||||
.map(|i| {
|
||||
view! {
|
||||
<InstanceFollowButton instance=i.instance.clone() />
|
||||
}
|
||||
})}
|
||||
|
||||
</Show>
|
||||
<Show when=move || protected>
|
||||
<span title="Article can only be edited by local admins">
|
||||
"Protected"
|
||||
</span>
|
||||
</Show>
|
||||
</nav>
|
||||
}
|
||||
})
|
||||
}}
|
||||
</Show>
|
||||
<Show when=move || protected>
|
||||
<span title="Article can only be edited by local admins">
|
||||
"Protected"
|
||||
</span>
|
||||
</Show>
|
||||
</nav>
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,63 +18,63 @@ pub fn CredentialsForm(
|
|||
});
|
||||
|
||||
view! {
|
||||
<form on:submit=|ev| ev.prevent_default()>
|
||||
<p>{title}</p>
|
||||
{move || {
|
||||
error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
<form on:submit=|ev| ev.prevent_default()>
|
||||
<p>{title}</p>
|
||||
{move || {
|
||||
error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Username"
|
||||
prop:disabled=move || disabled.get()
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
let val = event_target_value(&ev);
|
||||
set_username.update(|v| *v = val);
|
||||
}
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Username"
|
||||
prop:disabled=move || disabled.get()
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
let val = event_target_value(&ev);
|
||||
set_username.update(|v| *v = val);
|
||||
}
|
||||
|
||||
on:change=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_username.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
on:change=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_username.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
|
||||
<input
|
||||
type="password"
|
||||
required
|
||||
placeholder="Password"
|
||||
prop:disabled=move || disabled.get()
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
match &*ev.key() {
|
||||
"Enter" => {
|
||||
dispatch_action();
|
||||
}
|
||||
_ => {
|
||||
let val = event_target_value(&ev);
|
||||
set_password.update(|p| *p = val);
|
||||
}
|
||||
}
|
||||
}
|
||||
<input
|
||||
type="password"
|
||||
required
|
||||
placeholder="Password"
|
||||
prop:disabled=move || disabled.get()
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
match &*ev.key() {
|
||||
"Enter" => {
|
||||
dispatch_action();
|
||||
}
|
||||
_ => {
|
||||
let val = event_target_value(&ev);
|
||||
set_password.update(|p| *p = val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
on:change=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_password.update(|p| *p = val);
|
||||
}
|
||||
/>
|
||||
on:change=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_password.update(|p| *p = val);
|
||||
}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<button
|
||||
prop:disabled=move || button_is_disabled.get()
|
||||
on:click=move |_| dispatch_action()
|
||||
>
|
||||
{action_label}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<button
|
||||
prop:disabled=move || button_is_disabled.get()
|
||||
on:click=move |_| dispatch_action()
|
||||
>
|
||||
{action_label}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,12 +30,12 @@ pub fn InstanceFollowButton(instance: DbInstance) -> impl IntoView {
|
|||
};
|
||||
|
||||
view! {
|
||||
<button
|
||||
on:click=move |_| follow_action.dispatch(instance.id)
|
||||
prop:disabled=move || is_following
|
||||
prop:hidden=move || instance.local
|
||||
>
|
||||
{follow_text}
|
||||
</button>
|
||||
<button
|
||||
on:click=move |_| follow_action.dispatch(instance.id)
|
||||
prop:disabled=move || is_following
|
||||
prop:hidden=move || instance.local
|
||||
>
|
||||
{follow_text}
|
||||
</button>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,77 +22,77 @@ pub fn Nav() -> impl IntoView {
|
|||
|
||||
let (search_query, set_search_query) = create_signal(String::new());
|
||||
view! {
|
||||
<nav class="inner" style="min-width: 250px;">
|
||||
<li>
|
||||
<A href="/">"Main Page"</A>
|
||||
</li>
|
||||
<li>
|
||||
<A href="/article/list">"List Articles"</A>
|
||||
</li>
|
||||
<Show when=move || global_state.with(|state| state.my_profile.is_some())>
|
||||
<li>
|
||||
<A href="/article/create">"Create Article"</A>
|
||||
</li>
|
||||
<li>
|
||||
<A href="/conflicts">"Edit Conflicts"</A>
|
||||
</li>
|
||||
</Show>
|
||||
<li>
|
||||
<form on:submit=move |ev| {
|
||||
ev.prevent_default();
|
||||
let navigate = leptos_router::use_navigate();
|
||||
let query = search_query.get();
|
||||
if !query.is_empty() {
|
||||
navigate(&format!("/search?query={query}"), Default::default());
|
||||
}
|
||||
}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
prop:value=search_query
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
let val = event_target_value(&ev);
|
||||
set_search_query.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
|
||||
<button>Go</button>
|
||||
</form>
|
||||
</li>
|
||||
<Show
|
||||
when=move || global_state.with(|state| state.my_profile.is_some())
|
||||
fallback=move || {
|
||||
view! {
|
||||
<nav class="inner" style="min-width: 250px;">
|
||||
<li>
|
||||
<A href="/">"Main Page"</A>
|
||||
</li>
|
||||
<li>
|
||||
<A href="/article/list">"List Articles"</A>
|
||||
</li>
|
||||
<Show when=move || global_state.with(|state| state.my_profile.is_some())>
|
||||
<li>
|
||||
<A href="/login">"Login"</A>
|
||||
<A href="/article/create">"Create Article"</A>
|
||||
</li>
|
||||
<Show when=move || registration_open.get().unwrap_or_default()>
|
||||
<li>
|
||||
<A href="/register">"Register"</A>
|
||||
</li>
|
||||
</Show>
|
||||
}
|
||||
}
|
||||
>
|
||||
<li>
|
||||
<A href="/conflicts">"Edit Conflicts"</A>
|
||||
</li>
|
||||
</Show>
|
||||
<li>
|
||||
<form on:submit=move |ev| {
|
||||
ev.prevent_default();
|
||||
let navigate = leptos_router::use_navigate();
|
||||
let query = search_query.get();
|
||||
if !query.is_empty() {
|
||||
navigate(&format!("/search?query={query}"), Default::default());
|
||||
}
|
||||
}>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search"
|
||||
prop:value=search_query
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
let val = event_target_value(&ev);
|
||||
set_search_query.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
|
||||
{
|
||||
let my_profile = global_state.with(|state| state.my_profile.clone().unwrap());
|
||||
let profile_link = format!("/user/{}", my_profile.person.username);
|
||||
view! {
|
||||
<p>
|
||||
"Logged in as "
|
||||
<a
|
||||
href=profile_link
|
||||
style="border: none; padding: 0; color: var(--accent) !important;"
|
||||
>
|
||||
{my_profile.person.username}
|
||||
</a>
|
||||
</p>
|
||||
<button on:click=move |_| logout_action.dispatch(())>Logout</button>
|
||||
}
|
||||
}
|
||||
<button>Go</button>
|
||||
</form>
|
||||
</li>
|
||||
<Show
|
||||
when=move || global_state.with(|state| state.my_profile.is_some())
|
||||
fallback=move || {
|
||||
view! {
|
||||
<li>
|
||||
<A href="/login">"Login"</A>
|
||||
</li>
|
||||
<Show when=move || registration_open.get().unwrap_or_default()>
|
||||
<li>
|
||||
<A href="/register">"Register"</A>
|
||||
</li>
|
||||
</Show>
|
||||
}
|
||||
}
|
||||
>
|
||||
|
||||
</Show>
|
||||
</nav>
|
||||
{
|
||||
let my_profile = global_state.with(|state| state.my_profile.clone().unwrap());
|
||||
let profile_link = format!("/user/{}", my_profile.person.username);
|
||||
view! {
|
||||
<p>
|
||||
"Logged in as "
|
||||
<a
|
||||
href=profile_link
|
||||
style="border: none; padding: 0; color: var(--accent) !important;"
|
||||
>
|
||||
{my_profile.person.username}
|
||||
</a>
|
||||
</p>
|
||||
<button on:click=move |_| logout_action.dispatch(())>Logout</button>
|
||||
}
|
||||
}
|
||||
|
||||
</Show>
|
||||
</nav>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,73 +52,73 @@ pub fn ArticleActions() -> impl IntoView {
|
|||
}
|
||||
});
|
||||
view! {
|
||||
<ArticleNav article=article/>
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article| {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article_title(&article.article)}</h1>
|
||||
{move || {
|
||||
error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
<ArticleNav article=article />
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article| {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article_title(&article.article)}</h1>
|
||||
{move || {
|
||||
error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
|
||||
<Show when=move || {
|
||||
global_state
|
||||
.with(|state| {
|
||||
state
|
||||
.my_profile
|
||||
.as_ref()
|
||||
.map(|p| p.local_user.admin)
|
||||
.unwrap_or_default() && article.article.local
|
||||
})
|
||||
}>
|
||||
<button on:click=move |_| {
|
||||
protect_action
|
||||
.dispatch((article.article.id, article.article.protected))
|
||||
}>Toggle Article Protection</button>
|
||||
<p>"Protect a local article so that only admins can edit it"</p>
|
||||
</Show>
|
||||
<Show when=move || !article.article.local>
|
||||
<input
|
||||
placeholder="New Title"
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
let val = event_target_value(&ev);
|
||||
set_new_title.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
<Show when=move || {
|
||||
global_state
|
||||
.with(|state| {
|
||||
state
|
||||
.my_profile
|
||||
.as_ref()
|
||||
.map(|p| p.local_user.admin)
|
||||
.unwrap_or_default() && article.article.local
|
||||
})
|
||||
}>
|
||||
<button on:click=move |_| {
|
||||
protect_action
|
||||
.dispatch((article.article.id, article.article.protected))
|
||||
}>Toggle Article Protection</button>
|
||||
<p>"Protect a local article so that only admins can edit it"</p>
|
||||
</Show>
|
||||
<Show when=move || !article.article.local>
|
||||
<input
|
||||
placeholder="New Title"
|
||||
on:keyup=move |ev: ev::KeyboardEvent| {
|
||||
let val = event_target_value(&ev);
|
||||
set_new_title.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
|
||||
<button
|
||||
disabled=move || new_title.get().is_empty()
|
||||
on:click=move |_| {
|
||||
fork_action.dispatch((article.article.id, new_title.get()))
|
||||
}
|
||||
>
|
||||
<button
|
||||
disabled=move || new_title.get().is_empty()
|
||||
on:click=move |_| {
|
||||
fork_action.dispatch((article.article.id, new_title.get()))
|
||||
}
|
||||
>
|
||||
|
||||
Fork Article
|
||||
</button>
|
||||
<p>
|
||||
"You can fork a remote article to the local instance. This is useful if the original
|
||||
instance is dead, or if there are disagreements how the article should be written."
|
||||
</p>
|
||||
</Show>
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
Fork Article
|
||||
</button>
|
||||
<p>
|
||||
"You can fork a remote article to the local instance. This is useful if the original
|
||||
instance is dead, or if there are disagreements how the article should be written."
|
||||
</p>
|
||||
</Show>
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
<Show when=move || fork_response.get().is_some()>
|
||||
<Redirect path=article_link(&fork_response.get().unwrap())/>
|
||||
</Show>
|
||||
<p>"TODO: add option for admin to delete article etc"</p>
|
||||
</Suspense>
|
||||
<Show when=move || fork_response.get().is_some()>
|
||||
<Redirect path=article_link(&fork_response.get().unwrap()) />
|
||||
</Show>
|
||||
<p>"TODO: add option for admin to delete article etc"</p>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,66 +40,67 @@ pub fn CreateArticle() -> impl IntoView {
|
|||
});
|
||||
|
||||
view! {
|
||||
<h1>Create new Article</h1>
|
||||
<Show
|
||||
when=move || create_response.get().is_some()
|
||||
fallback=move || {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Title"
|
||||
prop:disabled=move || wait_for_response.get()
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_title.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
<h1>Create new Article</h1>
|
||||
<Show
|
||||
when=move || create_response.get().is_some()
|
||||
fallback=move || {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
placeholder="Title"
|
||||
prop:disabled=move || wait_for_response.get()
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_title.update(|v| *v = val);
|
||||
}
|
||||
/>
|
||||
|
||||
<textarea
|
||||
placeholder="Article text..."
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_text.update(|p| *p = val);
|
||||
}
|
||||
>
|
||||
</textarea>
|
||||
<div>
|
||||
<a href="https://commonmark.org/help/" target="blank_">
|
||||
Markdown
|
||||
</a>
|
||||
" formatting is supported"
|
||||
</div>
|
||||
{move || {
|
||||
create_error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
<textarea
|
||||
placeholder="Article text..."
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_text.update(|p| *p = val);
|
||||
}
|
||||
></textarea>
|
||||
<div>
|
||||
<a href="https://commonmark.org/help/" target="blank_">
|
||||
Markdown
|
||||
</a>
|
||||
" formatting is supported"
|
||||
</div>
|
||||
{move || {
|
||||
create_error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Edit summary"
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_summary.update(|p| *p = val);
|
||||
}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Edit summary"
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_summary.update(|p| *p = val);
|
||||
}
|
||||
/>
|
||||
|
||||
<button
|
||||
prop:disabled=move || button_is_disabled.get()
|
||||
on:click=move |_| submit_action.dispatch((title.get(), text.get(), summary.get()))
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
prop:disabled=move || button_is_disabled.get()
|
||||
on:click=move |_| {
|
||||
submit_action.dispatch((title.get(), text.get(), summary.get()))
|
||||
}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
>
|
||||
|
||||
<Redirect path=format!("/article/{}", title.get().replace(' ', "_"))/>
|
||||
</Show>
|
||||
<Redirect path=format!("/article/{}", title.get().replace(' ', "_")) />
|
||||
</Show>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,82 +100,82 @@ pub fn EditArticle() -> impl IntoView {
|
|||
);
|
||||
|
||||
view! {
|
||||
<ArticleNav article=article/>
|
||||
<Show
|
||||
when=move || edit_response.get() == EditResponse::Success
|
||||
fallback=move || {
|
||||
view! {
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|mut article| {
|
||||
if let EditResponse::Conflict(conflict) = edit_response.get() {
|
||||
article.article.text = conflict.three_way_merge;
|
||||
set_summary.set(conflict.summary);
|
||||
}
|
||||
set_text.set(article.article.text.clone());
|
||||
let article_ = article.clone();
|
||||
view! {
|
||||
// set initial text, otherwise submit with no changes results in empty text
|
||||
<div class="item-view">
|
||||
<h1>{article_title(&article.article)}</h1>
|
||||
{move || {
|
||||
edit_error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
<ArticleNav article=article />
|
||||
<Show
|
||||
when=move || edit_response.get() == EditResponse::Success
|
||||
fallback=move || {
|
||||
view! {
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|mut article| {
|
||||
if let EditResponse::Conflict(conflict) = edit_response.get() {
|
||||
article.article.text = conflict.three_way_merge;
|
||||
set_summary.set(conflict.summary);
|
||||
}
|
||||
set_text.set(article.article.text.clone());
|
||||
let article_ = article.clone();
|
||||
view! {
|
||||
// set initial text, otherwise submit with no changes results in empty text
|
||||
<div class="item-view">
|
||||
<h1>{article_title(&article.article)}</h1>
|
||||
{move || {
|
||||
edit_error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
|
||||
<textarea on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_text.update(|p| *p = val);
|
||||
}>{article.article.text.clone()}</textarea>
|
||||
<div>
|
||||
<a href="https://commonmark.org/help/" target="blank_">
|
||||
Markdown
|
||||
</a>
|
||||
" formatting is supported"
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Edit summary"
|
||||
value=summary.get_untracked()
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_summary.update(|p| *p = val);
|
||||
}
|
||||
/>
|
||||
<textarea on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_text.update(|p| *p = val);
|
||||
}>{article.article.text.clone()}</textarea>
|
||||
<div>
|
||||
<a href="https://commonmark.org/help/" target="blank_">
|
||||
Markdown
|
||||
</a>
|
||||
" formatting is supported"
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Edit summary"
|
||||
value=summary.get_untracked()
|
||||
on:keyup=move |ev| {
|
||||
let val = event_target_value(&ev);
|
||||
set_summary.update(|p| *p = val);
|
||||
}
|
||||
/>
|
||||
|
||||
<button
|
||||
prop:disabled=move || button_is_disabled.get()
|
||||
on:click=move |_| {
|
||||
submit_action
|
||||
.dispatch((
|
||||
text.get(),
|
||||
summary.get(),
|
||||
article_.clone(),
|
||||
edit_response.get(),
|
||||
))
|
||||
}
|
||||
>
|
||||
<button
|
||||
prop:disabled=move || button_is_disabled.get()
|
||||
on:click=move |_| {
|
||||
submit_action
|
||||
.dispatch((
|
||||
text.get(),
|
||||
summary.get(),
|
||||
article_.clone(),
|
||||
edit_response.get(),
|
||||
))
|
||||
}
|
||||
>
|
||||
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
>
|
||||
|
||||
Edit successful!
|
||||
</Show>
|
||||
Edit successful!
|
||||
</Show>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,49 +12,49 @@ pub fn ArticleHistory() -> impl IntoView {
|
|||
let article = article_resource();
|
||||
|
||||
view! {
|
||||
<ArticleNav article=article/>
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article| {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article_title(&article.article)}</h1>
|
||||
<ArticleNav article=article />
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article| {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article_title(&article.article)}</h1>
|
||||
|
||||
{article
|
||||
.edits
|
||||
.into_iter()
|
||||
.rev()
|
||||
.map(|edit| {
|
||||
let path = format!(
|
||||
"/article/{}@{}/diff/{}",
|
||||
article.article.title,
|
||||
extract_domain(&article.article.ap_id),
|
||||
edit.edit.hash.0,
|
||||
);
|
||||
let label = format!(
|
||||
"{} ({})",
|
||||
edit.edit.summary,
|
||||
edit.edit.created.to_rfc2822(),
|
||||
);
|
||||
view! {
|
||||
<li>
|
||||
<a href=path>{label}</a>
|
||||
" by "
|
||||
{user_link(&edit.creator)}
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()}
|
||||
{article
|
||||
.edits
|
||||
.into_iter()
|
||||
.rev()
|
||||
.map(|edit| {
|
||||
let path = format!(
|
||||
"/article/{}@{}/diff/{}",
|
||||
article.article.title,
|
||||
extract_domain(&article.article.ap_id),
|
||||
edit.edit.hash.0,
|
||||
);
|
||||
let label = format!(
|
||||
"{} ({})",
|
||||
edit.edit.summary,
|
||||
edit.edit.created.to_rfc2822(),
|
||||
);
|
||||
view! {
|
||||
<li>
|
||||
<a href=path>{label}</a>
|
||||
" by "
|
||||
{user_link(&edit.creator)}
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()}
|
||||
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,36 +21,36 @@ pub fn ListArticles() -> impl IntoView {
|
|||
);
|
||||
|
||||
view! {
|
||||
<h1>Most recently edited Articles</h1>
|
||||
<Suspense fallback=|| view! { "Loading..." }>
|
||||
<fieldset on:input=move |ev| {
|
||||
let val = ev.target().unwrap().unchecked_into::<web_sys::HtmlInputElement>().id();
|
||||
let is_local_only = val == "only-local";
|
||||
set_only_local.update(|p| *p = is_local_only);
|
||||
}>
|
||||
<input type="radio" name="listing-type" id="only-local"/>
|
||||
<label for="only-local">Only Local</label>
|
||||
<input type="radio" name="listing-type" id="all" checked/>
|
||||
<label for="all">All</label>
|
||||
</fieldset>
|
||||
<ul>
|
||||
{move || {
|
||||
articles
|
||||
.get()
|
||||
.map(|a| {
|
||||
a.into_iter()
|
||||
.map(|a| {
|
||||
view! {
|
||||
<li>
|
||||
<a href=article_link(&a)>{article_title(&a)}</a>
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
}}
|
||||
<h1>Most recently edited Articles</h1>
|
||||
<Suspense fallback=|| view! { "Loading..." }>
|
||||
<fieldset on:input=move |ev| {
|
||||
let val = ev.target().unwrap().unchecked_into::<web_sys::HtmlInputElement>().id();
|
||||
let is_local_only = val == "only-local";
|
||||
set_only_local.update(|p| *p = is_local_only);
|
||||
}>
|
||||
<input type="radio" name="listing-type" id="only-local" />
|
||||
<label for="only-local">Only Local</label>
|
||||
<input type="radio" name="listing-type" id="all" checked />
|
||||
<label for="all">All</label>
|
||||
</fieldset>
|
||||
<ul>
|
||||
{move || {
|
||||
articles
|
||||
.get()
|
||||
.map(|a| {
|
||||
a.into_iter()
|
||||
.map(|a| {
|
||||
view! {
|
||||
<li>
|
||||
<a href=article_link(&a)>{article_title(&a)}</a>
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
}}
|
||||
|
||||
</ul>
|
||||
</Suspense>
|
||||
</ul>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,27 +11,29 @@ pub fn ReadArticle() -> impl IntoView {
|
|||
let article = article_resource();
|
||||
|
||||
view! {
|
||||
<ArticleNav article=article/>
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
<ArticleNav article=article />
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
|
||||
{
|
||||
let parser = markdown_parser();
|
||||
move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article| {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article_title(&article.article)}</h1>
|
||||
<div inner_html=parser.parse(&article.article.text).render()></div>
|
||||
</div>
|
||||
}
|
||||
})
|
||||
{
|
||||
let parser = markdown_parser();
|
||||
move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article| {
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article_title(&article.article)}</h1>
|
||||
<div inner_html=parser
|
||||
.parse(&article.article.text)
|
||||
.render()></div>
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</Suspense>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,27 +9,33 @@ pub fn Conflicts() -> impl IntoView {
|
|||
);
|
||||
|
||||
view! {
|
||||
<h1>Your unresolved edit conflicts</h1>
|
||||
<Suspense fallback=|| view! { "Loading..." }>
|
||||
<ul>
|
||||
{move || {
|
||||
conflicts
|
||||
.get()
|
||||
.map(|c| {
|
||||
c.into_iter()
|
||||
.map(|c| {
|
||||
let link = format!("{}/edit/{}", article_link(&c.article), c.id);
|
||||
view! {
|
||||
<li>
|
||||
<a href=link>{article_title(&c.article)} " - " {c.summary}</a>
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
}}
|
||||
<h1>Your unresolved edit conflicts</h1>
|
||||
<Suspense fallback=|| view! { "Loading..." }>
|
||||
<ul>
|
||||
{move || {
|
||||
conflicts
|
||||
.get()
|
||||
.map(|c| {
|
||||
c.into_iter()
|
||||
.map(|c| {
|
||||
let link = format!(
|
||||
"{}/edit/{}",
|
||||
article_link(&c.article),
|
||||
c.id,
|
||||
);
|
||||
view! {
|
||||
<li>
|
||||
<a href=link>
|
||||
{article_title(&c.article)} " - " {c.summary}
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
}}
|
||||
|
||||
</ul>
|
||||
</Suspense>
|
||||
</ul>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,36 +8,36 @@ pub fn EditDiff() -> impl IntoView {
|
|||
let article = article_resource();
|
||||
|
||||
view! {
|
||||
<ArticleNav article=article/>
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article| {
|
||||
let hash = params.get_untracked().get("hash").cloned().unwrap();
|
||||
let edit = article
|
||||
.edits
|
||||
.iter()
|
||||
.find(|e| e.edit.hash.0.to_string() == hash)
|
||||
.unwrap();
|
||||
let label = format!(
|
||||
"{} ({})",
|
||||
edit.edit.summary,
|
||||
edit.edit.created.to_rfc2822(),
|
||||
);
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article.article.title.replace('_', " ")}</h1>
|
||||
<h2>{label}</h2>
|
||||
<p>"by " {user_link(&edit.creator)}</p>
|
||||
<pre>{edit.edit.diff.clone()}</pre>
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
<ArticleNav article=article />
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
article
|
||||
.get()
|
||||
.map(|article| {
|
||||
let hash = params.get_untracked().get("hash").cloned().unwrap();
|
||||
let edit = article
|
||||
.edits
|
||||
.iter()
|
||||
.find(|e| e.edit.hash.0.to_string() == hash)
|
||||
.unwrap();
|
||||
let label = format!(
|
||||
"{} ({})",
|
||||
edit.edit.summary,
|
||||
edit.edit.created.to_rfc2822(),
|
||||
);
|
||||
view! {
|
||||
<div class="item-view">
|
||||
<h1>{article.article.title.replace('_', " ")}</h1>
|
||||
<h2>{label}</h2>
|
||||
<p>"by " {user_link(&edit.creator)}</p>
|
||||
<pre>{edit.edit.diff.clone()}</pre>
|
||||
</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,32 +20,36 @@ pub fn InstanceDetails() -> impl IntoView {
|
|||
});
|
||||
|
||||
view! {
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
instance_profile
|
||||
.get()
|
||||
.map(|instance: DbInstance| {
|
||||
let instance_ = instance.clone();
|
||||
view! {
|
||||
<h1>{instance.domain}</h1>
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
instance_profile
|
||||
.get()
|
||||
.map(|instance: DbInstance| {
|
||||
let instance_ = instance.clone();
|
||||
view! {
|
||||
<h1>{instance.domain}</h1>
|
||||
|
||||
<Show when=move || global_state.with(|state| state.my_profile.is_some())>
|
||||
<InstanceFollowButton instance=instance_.clone()/>
|
||||
</Show>
|
||||
<p>Follow the instance so that new edits are federated to your instance.</p>
|
||||
<p>
|
||||
"TODO: show a list of articles from the instance. For now you can use the "
|
||||
<a href="/article/list">Article list</a> .
|
||||
</p>
|
||||
<hr/>
|
||||
<h2>"Description:"</h2>
|
||||
<div>{instance.description}</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
<Show when=move || {
|
||||
global_state.with(|state| state.my_profile.is_some())
|
||||
}>
|
||||
<InstanceFollowButton instance=instance_.clone() />
|
||||
</Show>
|
||||
<p>
|
||||
Follow the instance so that new edits are federated to your instance.
|
||||
</p>
|
||||
<p>
|
||||
"TODO: show a list of articles from the instance. For now you can use the "
|
||||
<a href="/article/list">Article list</a>.
|
||||
</p>
|
||||
<hr />
|
||||
<h2>"Description:"</h2>
|
||||
<div>{instance.description}</div>
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,22 +38,22 @@ pub fn Login() -> impl IntoView {
|
|||
let disabled = Signal::derive(move || wait_for_response.get());
|
||||
|
||||
view! {
|
||||
<Show
|
||||
when=move || login_response.get().is_some()
|
||||
fallback=move || {
|
||||
view! {
|
||||
<CredentialsForm
|
||||
title="Please enter the desired credentials"
|
||||
action_label="Login"
|
||||
action=login_action
|
||||
error=login_error.into()
|
||||
disabled
|
||||
/>
|
||||
<Show
|
||||
when=move || login_response.get().is_some()
|
||||
fallback=move || {
|
||||
view! {
|
||||
<CredentialsForm
|
||||
title="Please enter the desired credentials"
|
||||
action_label="Login"
|
||||
action=login_action
|
||||
error=login_error.into()
|
||||
disabled
|
||||
/>
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
>
|
||||
|
||||
<Redirect path="/"/>
|
||||
</Show>
|
||||
<Redirect path="/" />
|
||||
</Show>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,22 +39,22 @@ pub fn Register() -> impl IntoView {
|
|||
let disabled = Signal::derive(move || wait_for_response.get());
|
||||
|
||||
view! {
|
||||
<Show
|
||||
when=move || register_response.get().is_some()
|
||||
fallback=move || {
|
||||
view! {
|
||||
<CredentialsForm
|
||||
title="Please enter the desired credentials"
|
||||
action_label="Register"
|
||||
action=register_action
|
||||
error=register_error.into()
|
||||
disabled
|
||||
/>
|
||||
<Show
|
||||
when=move || register_response.get().is_some()
|
||||
fallback=move || {
|
||||
view! {
|
||||
<CredentialsForm
|
||||
title="Please enter the desired credentials"
|
||||
action_label="Register"
|
||||
action=register_action
|
||||
error=register_error.into()
|
||||
disabled
|
||||
/>
|
||||
}
|
||||
}
|
||||
}
|
||||
>
|
||||
>
|
||||
|
||||
<p>"You have successfully registered."</p>
|
||||
</Show>
|
||||
<p>"You have successfully registered."</p>
|
||||
</Show>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,67 +52,66 @@ pub fn Search() -> impl IntoView {
|
|||
});
|
||||
|
||||
view! {
|
||||
<h1>"Search results for " {query}</h1>
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
search_results
|
||||
.get()
|
||||
.map(move |search_results| {
|
||||
let is_empty = search_results.is_empty();
|
||||
view! {
|
||||
<Show
|
||||
when=move || !is_empty
|
||||
fallback=move || {
|
||||
let error_view = move || {
|
||||
error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
};
|
||||
view! {
|
||||
{error_view}
|
||||
<p>No results found</p>
|
||||
}
|
||||
<h1>"Search results for " {query}</h1>
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
search_results
|
||||
.get()
|
||||
.map(move |search_results| {
|
||||
let is_empty = search_results.is_empty();
|
||||
view! {
|
||||
<Show
|
||||
when=move || !is_empty
|
||||
fallback=move || {
|
||||
let error_view = move || {
|
||||
error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
};
|
||||
view! {
|
||||
{error_view}
|
||||
<p>No results found</p>
|
||||
}
|
||||
}
|
||||
>
|
||||
|
||||
<ul>
|
||||
|
||||
// render resolved instance
|
||||
{if let Some(instance) = &search_results.instance {
|
||||
let domain = &instance.domain;
|
||||
vec![
|
||||
view! {
|
||||
<li>
|
||||
<a href=format!("/instance/{domain}")>{domain}</a>
|
||||
</li>
|
||||
},
|
||||
]
|
||||
} else {
|
||||
vec![]
|
||||
}} // render articles from resolve/search
|
||||
{search_results
|
||||
.articles
|
||||
.iter()
|
||||
.map(|a| {
|
||||
view! {
|
||||
<li>
|
||||
<a href=article_link(a)>{article_title(a)}</a>
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()}
|
||||
|
||||
</ul>
|
||||
</Show>
|
||||
}
|
||||
>
|
||||
})
|
||||
}}
|
||||
|
||||
<ul>
|
||||
|
||||
// render resolved instance
|
||||
{if let Some(instance) = &search_results.instance {
|
||||
let domain = &instance.domain;
|
||||
vec![
|
||||
view! {
|
||||
<li>
|
||||
<a href=format!("/instance/{domain}")>{domain}</a>
|
||||
</li>
|
||||
},
|
||||
]
|
||||
} else {
|
||||
vec![]
|
||||
}}
|
||||
// render articles from resolve/search
|
||||
{search_results
|
||||
.articles
|
||||
.iter()
|
||||
.map(|a| {
|
||||
view! {
|
||||
<li>
|
||||
<a href=article_link(a)>{article_title(a)}</a>
|
||||
</li>
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()}
|
||||
|
||||
</ul>
|
||||
</Show>
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,28 +22,28 @@ pub fn UserProfile() -> impl IntoView {
|
|||
});
|
||||
|
||||
view! {
|
||||
{move || {
|
||||
error
|
||||
.get()
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
user_profile
|
||||
error
|
||||
.get()
|
||||
.map(|person: DbPerson| {
|
||||
view! {
|
||||
<h1>{user_title(&person)}</h1>
|
||||
<p>TODO: create actual user profile</p>
|
||||
}
|
||||
.map(|err| {
|
||||
view! { <p style="color:red;">{err}</p> }
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
<Suspense fallback=|| {
|
||||
view! { "Loading..." }
|
||||
}>
|
||||
{move || {
|
||||
user_profile
|
||||
.get()
|
||||
.map(|person: DbPerson| {
|
||||
view! {
|
||||
<h1>{user_title(&person)}</h1>
|
||||
<p>TODO: create actual user profile</p>
|
||||
}
|
||||
})
|
||||
}}
|
||||
|
||||
</Suspense>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,6 @@ fn main() {
|
|||
_ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
mount_to_body(|| {
|
||||
view! { <App/> }
|
||||
view! { <App /> }
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue