2024-04-17 22:07:47 +02:00
use apb ::{ Actor , Base , Collection , Object } ;
use leptos ::* ;
use leptos_router ::* ;
use crate ::prelude ::* ;
#[ component ]
pub fn AboutPage ( ) -> impl IntoView {
view! {
< div >
< Breadcrumb > about < / Breadcrumb >
< div class = " mt-s mb-s " >
< p > < code > μ pub < / code > " is a micro social network powered by " < a href = " " > ActivityPub < / a > < / p >
2024-04-17 23:07:56 +02:00
< p > < i > " the " < a href = " https://en.wikipedia.org/wiki/Fediverse " > fediverse < / a > " is an ensemble of social networks, which, while independently hosted, can communicate with each other " < / i > < / p >
< p > content is aggregated in timelines , logged out users can only access global server timeline < / p >
< / div >
< / div >
}
}
#[ component ]
pub fn ConfigPage ( ) -> impl IntoView {
view! {
< div >
< Breadcrumb > config < / Breadcrumb >
< div class = " mt-s mb-s " >
< p > < code > " not implemented :( " < / code > < / p >
2024-04-17 22:07:47 +02:00
< / div >
< / div >
}
}
#[ component ]
pub fn UserPage ( ) -> impl IntoView {
let params = use_params_map ( ) ;
let auth = use_context ::< Auth > ( ) . expect ( " missing auth context " ) ;
2024-04-18 03:34:41 +02:00
let id = params . get ( ) . get ( " id " ) . cloned ( ) . unwrap_or_default ( ) ;
let _id = id . clone ( ) ; // wtf triple clone??? TODO!!
let actor = create_local_resource ( move | | _id . clone ( ) , move | id | {
2024-04-17 22:07:47 +02:00
async move {
match CACHE . get ( & Uri ::full ( " users " , & id ) ) {
Some ( x ) = > Some ( x . clone ( ) ) ,
None = > {
2024-04-18 05:00:44 +02:00
let user : serde_json ::Value = Http ::fetch ( & Uri ::api ( " users " , & id , true ) , auth ) . await . ok ( ) ? ;
2024-04-17 22:07:47 +02:00
CACHE . put ( Uri ::full ( " users " , & id ) , user . clone ( ) ) ;
Some ( user )
} ,
}
}
} ) ;
view! {
< div >
< Breadcrumb back = true > users ::view < / Breadcrumb >
< div >
{ move | | match actor . get ( ) {
None = > view! { < p > loading .. . < / p > } . into_view ( ) ,
Some ( None ) = > view! { < p > < code > error loading < / code > < / p > } . into_view ( ) ,
2024-04-18 03:34:41 +02:00
Some ( Some ( object ) ) = > {
let uid = object . id ( ) . unwrap_or_default ( ) . to_string ( ) ;
let avatar_url = object . icon ( ) . get ( ) . map ( | x | x . url ( ) . id ( ) . unwrap_or_default ( ) ) . unwrap_or_default ( ) ;
let background_url = object . image ( ) . get ( ) . map ( | x | x . url ( ) . id ( ) . unwrap_or_default ( ) ) . unwrap_or_default ( ) ;
let display_name = object . name ( ) . unwrap_or_default ( ) . to_string ( ) ;
let username = object . preferred_username ( ) . unwrap_or_default ( ) . to_string ( ) ;
let summary = object . summary ( ) . unwrap_or_default ( ) . to_string ( ) ;
let domain = object . id ( ) . unwrap_or_default ( ) . replace ( " https:// " , " " ) . split ( '/' ) . next ( ) . unwrap_or_default ( ) . to_string ( ) ;
let actor_type = object . actor_type ( ) . unwrap_or ( apb ::ActorType ::Person ) ;
let actor_type_tag = if actor_type = = apb ::ActorType ::Person { None } else {
Some ( view! { < sup class = " ml-s " > < small > " [ " { actor_type . as_ref ( ) . to_lowercase ( ) } " ] " < / small > < / sup > } )
} ;
let created = object . published ( ) ;
let following = object . following ( ) . get ( ) . map ( | x | x . total_items ( ) . unwrap_or ( 0 ) ) . unwrap_or_default ( ) ;
let followers = object . followers ( ) . get ( ) . map ( | x | x . total_items ( ) . unwrap_or ( 0 ) ) . unwrap_or_default ( ) ;
view! {
< div class = " ml-3 mr-3 " >
< div
class = " banner "
style = { format! ( " background: center / cover url( {background_url} ); " ) }
>
// <table class="align w-100">
// <tr><td rowspan=3>
// <img src=
// </table>
< div style = " height: 10em " > < / div >
< / div >
< div class = " overlap " >
< table class = " pl-2 pr-2 align w-100 " style = " table-layout: fixed " >
< tr >
< td rowspan = 4 style = " width: 8em " >
< img class = " avatar-circle avatar-border mr-s " src = { avatar_url } style = " height: 7em; width: 7em " / >
< / td >
< td rowspan = 2 class = " bottom " >
< b class = " big " > { display_name } < / b > { actor_type_tag }
< / td >
< td rowspan = 2 class = " bottom rev " > < span class = " emoji " title = " statuses " > " \u{1f582} " < / span > " : " 0 < / td >
< / tr >
< tr > < / tr >
< tr >
< td class = " top " >
< small > < a class = " clean hover " href = { uid } target = " _blank " > { username . clone ( ) } @ { domain } < / a > < / small >
< / td >
< td class = " rev " > < span class = " emoji " title = " following " > " 👥 " < / span > " : " { following } < / td >
< / tr >
< tr >
< td >
< DateTime t = created / >
< / td >
< td class = " rev " > < span class = " emoji " title = " followers " > " 📢 " < / span > " : " { followers } < / td >
< / tr >
< / table >
< blockquote class = " ml-2 mt-1 " > {
dissolve ::strip_html_tags ( & summary )
2024-04-17 22:07:47 +02:00
. into_iter ( )
2024-04-18 03:34:41 +02:00
. map ( | x | view! { < div > { x } < / div > } )
2024-04-17 22:07:47 +02:00
. collect_view ( )
2024-04-18 03:34:41 +02:00
} < / blockquote >
< / div >
< / div >
2024-04-18 05:00:44 +02:00
< TimelineFeed tl = Timeline ::new ( format! ( " {} /outbox/page " , Uri ::api ( " users " , & id . clone ( ) , false ) ) ) / >
2024-04-18 03:34:41 +02:00
} . into_view ( )
} ,
2024-04-17 22:07:47 +02:00
} }
< / div >
< / div >
}
}
#[ component ]
pub fn ObjectPage ( ) -> impl IntoView {
let params = use_params_map ( ) ;
let auth = use_context ::< Auth > ( ) . expect ( " missing auth context " ) ;
let object = create_local_resource ( move | | params . get ( ) . get ( " id " ) . cloned ( ) . unwrap_or_default ( ) , move | oid | {
async move {
match CACHE . get ( & Uri ::full ( " objects " , & oid ) ) {
Some ( x ) = > Some ( x . clone ( ) ) ,
None = > {
2024-04-18 05:00:44 +02:00
let obj = Http ::fetch ::< serde_json ::Value > ( & Uri ::api ( " objects " , & oid , true ) , auth ) . await . ok ( ) ? ;
2024-04-17 22:07:47 +02:00
CACHE . put ( Uri ::full ( " objects " , & oid ) , obj . clone ( ) ) ;
Some ( obj )
}
}
}
} ) ;
view! {
< div >
< Breadcrumb back = true > objects ::view < / Breadcrumb >
< div class = " ma-2 " >
{ move | | match object . get ( ) {
Some ( Some ( o ) ) = > view! { < Object object = o / > } . into_view ( ) ,
Some ( None ) = > view! { < p > < code > loading failed < / code > < / p > } . into_view ( ) ,
None = > view! { < p > loading .. . < / p > } . into_view ( ) ,
} }
< / div >
< / div >
}
}
#[ component ]
pub fn TimelinePage ( name : & 'static str , tl : Timeline ) -> impl IntoView {
let auth = use_context ::< Auth > ( ) . expect ( " missing auth context " ) ;
view! {
< div >
< Breadcrumb back = false >
{ name }
< a class = " clean ml-1 " href = " # " on :click = move | _ | {
tl . reset ( tl . next . get ( ) . split ( '?' ) . next ( ) . unwrap_or_default ( ) . to_string ( ) ) ;
spawn_local ( async move {
if let Err ( e ) = tl . more ( auth ) . await {
tracing ::error! ( " error fetching more items for timeline: {e} " ) ;
}
} )
} > < span class = " emoji " >
" \u{1f5d8} "
< / span > < / a >
< / Breadcrumb >
< div class = " mt-s mb-s " >
< TimelineFeed tl = tl / >
< / div >
< / div >
}
}