use std::sync::Arc; use leptos::*; use crate::{prelude::*, URL_SENSITIVE}; use apb::{target::Addressed, ActivityMut, Base, Collection, Object, ObjectMut}; #[component] pub fn Attachment( object: serde_json::Value, #[prop(optional)] sensitive: bool ) -> impl IntoView { let (expand, set_expand) = create_signal(false); let href = object.url().id().unwrap_or_default(); let media_type = object.media_type() .unwrap_or("image/png") // TODO weird defaulting to png????? .to_string(); let kind = media_type .split('/') .next() .unwrap_or("image") .to_string(); match kind.as_str() { "image" => view! {

}.into_view(), "video" => view! {
}.into_view(), "audio" => view! {

}.into_view(), _ => view! {

{media_type}

{object.name().unwrap_or_default().to_string()}

}.into_view(), } } #[component] pub fn Object(object: crate::Object) -> impl IntoView { let oid = object.id().unwrap_or_default().to_string(); let content = dissolve::strip_html_tags(object.content().unwrap_or_default()); let author_id = object.attributed_to().id().unwrap_or_default(); let author = CACHE.get_or(&author_id, serde_json::Value::String(author_id.clone()).into()); let sensitive = object.sensitive().unwrap_or_default(); let addressed = object.addressed(); let public = addressed.iter().any(|x| x.as_str() == apb::target::PUBLIC); let attachments = object.attachment() .map(|x| view! { }) .collect_view(); let comments = object.replies().get() .map_or(0, |x| x.total_items().unwrap_or(0)); let shares = object.generator().get() .map_or(0, |x| x.total_items().unwrap_or(0)); let likes = object.audience().get() .map_or(0, |x| x.total_items().unwrap_or(0)); let already_liked = object.audience().get() .map_or(false, |x| !x.ordered_items().is_empty()); let attachments_padding = if object.attachment().is_empty() { None } else { Some(view! {
}) }; view! {
{object.in_reply_to().id().map(|reply| view! { reply })} "↗"
{content.into_iter().map(|x| view! {

{x}

}).collect_view()} {attachments_padding} {attachments}
} } #[component] pub fn Summary(summary: Option, open: bool, children: Children) -> impl IntoView { match summary.filter(|x| !x.is_empty()) { None => children().into_view(), Some(summary) => view! {
{summary} {children()}
}.into_view(), } } #[component] pub fn LikeButton( n: u64, target: String, liked: bool, author: String, #[prop(optional)] private: bool, ) -> impl IntoView { let (count, set_count) = create_signal(n); let (clicked, set_clicked) = create_signal(!liked); let auth = use_context::().expect("missing auth context"); view! { { set_clicked.set(false); set_count.set(count.get() + 1); }, Err(e) => tracing::error!("failed sending like: {e}"), } }); } > {move || if count.get() > 0 { Some(view! { {count} })} else { None }} " ⭐" } } #[component] pub fn ReplyButton(n: u64) -> impl IntoView { let comments = if n > 0 { Some(view! { {n} }) } else { None }; view! { {comments}" 📨" } } #[component] pub fn RepostButton(n: u64, target: String) -> impl IntoView { let (count, set_count) = create_signal(n); let (clicked, set_clicked) = create_signal(true); let auth = use_context::().expect("missing auth context"); view! { set_count.set(count.get() + 1), Err(e) => tracing::error!("failed sending like: {e}"), } set_clicked.set(true); }); } > {move || if count.get() > 0 { Some(view! { {count} })} else { None }} " 🚀" } }