feat(web): per-user timeline, proper scrollboxes
This commit is contained in:
parent
5de3e6622f
commit
964b45e50b
2 changed files with 82 additions and 67 deletions
143
web/src/lib.rs
143
web/src/lib.rs
|
@ -213,31 +213,37 @@ pub fn UserPage() -> impl IntoView {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
view! {
|
view! {
|
||||||
<div class="tl-header w-100 center mb-s ml-1" >view::user</div>
|
<div class="ml-1">
|
||||||
{move || match actor.get() {
|
<div class="tl-header w-100 center mb-s" >view::user</div>
|
||||||
None => view! { <p>loading...</p> }.into_view(),
|
<div class="boxscroll" >
|
||||||
Some(None) => view! { <p><code>error loading</code></p> }.into_view(),
|
{move || match actor.get() {
|
||||||
Some(Some(x)) => view! {
|
None => view! { <p>loading...</p> }.into_view(),
|
||||||
<div class="ml-3 mr-3 mt-3">
|
Some(None) => view! { <p><code>error loading</code></p> }.into_view(),
|
||||||
<ActorBanner object=x.clone() />
|
Some(Some(x)) => view! {
|
||||||
<p
|
<div class="ml-3 mr-3 mt-3">
|
||||||
class="pb-2 pt-2 pr-2 pl-2"
|
<ActorBanner object=x.clone() />
|
||||||
style={format!(
|
<p
|
||||||
"background-image: url({}); background-size: cover;",
|
class="pb-2 pt-2 pr-2 pl-2"
|
||||||
x.image().get().map(|x| x.url().id().unwrap_or_default()).unwrap_or_default()
|
style={format!(
|
||||||
)}
|
"background-image: url({}); background-size: cover;",
|
||||||
>
|
x.image().get().map(|x| x.url().id().unwrap_or_default()).unwrap_or_default()
|
||||||
{x.summary().unwrap_or("").to_string()}
|
)}
|
||||||
</p>
|
>
|
||||||
<ul>
|
{x.summary().unwrap_or("").to_string()}
|
||||||
<li><code>type</code>" "<b>{x.actor_type().unwrap_or(apb::ActorType::Person).as_ref().to_string()}</b></li>
|
</p>
|
||||||
<li><code>following</code>" "<b>{x.following().get().map(|x| x.total_items().unwrap_or(0))}</b></li>
|
<ul>
|
||||||
<li><code>followers</code>" "<b>{x.followers().get().map(|x| x.total_items().unwrap_or(0))}</b></li>
|
<li><code>type</code>" "<b>{x.actor_type().unwrap_or(apb::ActorType::Person).as_ref().to_string()}</b></li>
|
||||||
<li><code>created</code>" "{x.published().map(|x| x.to_rfc3339())}</li>
|
<li><code>following</code>" "<b>{x.following().get().map(|x| x.total_items().unwrap_or(0))}</b></li>
|
||||||
</ul>
|
<li><code>followers</code>" "<b>{x.followers().get().map(|x| x.total_items().unwrap_or(0))}</b></li>
|
||||||
</div>
|
<li><code>created</code>" "{x.published().map(|x| x.to_rfc3339())}</li>
|
||||||
}.into_view(),
|
</ul>
|
||||||
}}
|
</div>
|
||||||
|
<hr />
|
||||||
|
<TimelineFeed tl=Timeline::new(format!("{}/outbox/page", Uri::api("users", x.id().unwrap_or_default()))) />
|
||||||
|
}.into_view(),
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,13 +264,15 @@ pub fn ObjectPage() -> impl IntoView {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
view! {
|
view! {
|
||||||
<div class="tl-header w-100 center mb-s ml-1" >view::object</div>
|
<div class="ml-1">
|
||||||
<div class="ma-2" >
|
<div class="tl-header w-100 center mb-s" >view::object</div>
|
||||||
{move || match object.get() {
|
<div class="boxscroll ma-2" >
|
||||||
Some(Some(o)) => view!{ <Object object=o /> }.into_view(),
|
{move || match object.get() {
|
||||||
Some(None) => view! { <p><code>loading failed</code></p> }.into_view(),
|
Some(Some(o)) => view!{ <Object object=o /> }.into_view(),
|
||||||
None => view! { <p> loading ... </p> }.into_view(),
|
Some(None) => view! { <p><code>loading failed</code></p> }.into_view(),
|
||||||
}}
|
None => view! { <p> loading ... </p> }.into_view(),
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,43 +373,50 @@ pub fn About() -> impl IntoView {
|
||||||
struct OmgReqwestErrorIsNotClonable(String);
|
struct OmgReqwestErrorIsNotClonable(String);
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn TimelineFeed(name: &'static str, tl: Timeline) -> impl IntoView {
|
pub fn TimelinePage(name: &'static str, tl: Timeline) -> impl IntoView {
|
||||||
let auth = use_context::<Signal<Option<Auth>>>().expect("missing auth context");
|
|
||||||
view! {
|
view! {
|
||||||
<div class="ml-1">
|
<div class="ml-1">
|
||||||
<div class="tl-header w-100 center mb-s" >{name}</div>
|
<div class="tl-header w-100 center mb-s" >{name}</div>
|
||||||
<div class="boxscroll mt-s mb-s" >
|
<div class="boxscroll mt-s mb-s" >
|
||||||
<For
|
<TimelineFeed tl=tl />
|
||||||
each=move || tl.feed.get()
|
|
||||||
key=|k| k.to_string()
|
|
||||||
children=move |id: String| {
|
|
||||||
match CACHE.get(&id) {
|
|
||||||
Some(object) => {
|
|
||||||
view! {
|
|
||||||
<div class="ml-1 mr-1 mt-1">
|
|
||||||
<InlineActivity activity=object />
|
|
||||||
</div>
|
|
||||||
<hr/ >
|
|
||||||
}.into_view()
|
|
||||||
},
|
|
||||||
None => view! {
|
|
||||||
<p><code>{id}</code>" "[<a href={uri}>go</a>]</p>
|
|
||||||
}.into_view(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/ >
|
|
||||||
<div class="center" >
|
|
||||||
<button type="button"
|
|
||||||
on:click=move |_| {
|
|
||||||
spawn_local(async move {
|
|
||||||
if let Err(e) = tl.more(auth).await {
|
|
||||||
console_error(&format!("error fetching more items for timeline: {e}"));
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>more</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn TimelineFeed(tl: Timeline) -> impl IntoView {
|
||||||
|
let auth = use_context::<Signal<Option<Auth>>>().expect("missing auth context");
|
||||||
|
view! {
|
||||||
|
<For
|
||||||
|
each=move || tl.feed.get()
|
||||||
|
key=|k| k.to_string()
|
||||||
|
children=move |id: String| {
|
||||||
|
match CACHE.get(&id) {
|
||||||
|
Some(object) => {
|
||||||
|
view! {
|
||||||
|
<div class="ml-1 mr-1 mt-1">
|
||||||
|
<InlineActivity activity=object />
|
||||||
|
</div>
|
||||||
|
<hr/ >
|
||||||
|
}.into_view()
|
||||||
|
},
|
||||||
|
None => view! {
|
||||||
|
<p><code>{id}</code>" "[<a href={uri}>go</a>]</p>
|
||||||
|
}.into_view(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/ >
|
||||||
|
<div class="center" >
|
||||||
|
<button type="button"
|
||||||
|
on:click=move |_| {
|
||||||
|
spawn_local(async move {
|
||||||
|
if let Err(e) = tl.more(auth).await {
|
||||||
|
console_error(&format!("error fetching more items for timeline: {e}"));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>more</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use leptos_router::*;
|
||||||
use leptos_use::{use_cookie, utils::JsonCodec};
|
use leptos_use::{use_cookie, utils::JsonCodec};
|
||||||
use upub_web::{
|
use upub_web::{
|
||||||
URL_BASE, context::Timeline, About, Auth, LoginBox, MaybeToken, ObjectPage, PostBox,
|
URL_BASE, context::Timeline, About, Auth, LoginBox, MaybeToken, ObjectPage, PostBox,
|
||||||
TimelineFeed, TimelineNavigation, UserPage
|
TimelinePage, TimelineNavigation, UserPage
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -72,8 +72,8 @@ fn main() {
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/web" view=About />
|
<Route path="/web" view=About />
|
||||||
|
|
||||||
<Route path="/web/home" view=move || view! { <TimelineFeed name="home" tl=home_tl /> } />
|
<Route path="/web/home" view=move || view! { <TimelinePage name="home" tl=home_tl /> } />
|
||||||
<Route path="/web/server" view=move || view! { <TimelineFeed name="server" tl=server_tl /> } />
|
<Route path="/web/server" view=move || view! { <TimelinePage name="server" tl=server_tl /> } />
|
||||||
|
|
||||||
<Route path="/web/users/:id" view=UserPage />
|
<Route path="/web/users/:id" view=UserPage />
|
||||||
<Route path="/web/objects/:id" view=ObjectPage />
|
<Route path="/web/objects/:id" view=ObjectPage />
|
||||||
|
|
Loading…
Reference in a new issue