use apb::{ActivityMut, Base, BaseMut, Object, ObjectMut}; use leptos::*; use crate::{prelude::*, WEBFINGER}; #[derive(Debug, Clone, Copy, Default)] pub struct ReplyControls { pub context: RwSignal>, pub reply_to: RwSignal>, } impl ReplyControls { pub fn reply(&self, oid: &str) { if let Some(obj) = CACHE.get(oid) { self.context.set(obj.context().id()); self.reply_to.set(obj.id().ok().map(|x| x.to_string())); } } pub fn clear(&self) { self.context.set(None); self.reply_to.set(None); } } fn post_author(post_id: &str) -> Option { let usr = CACHE.get(post_id)?.attributed_to().id()?; CACHE.get(&usr) } #[component] pub fn PostBox(advanced: WriteSignal) -> impl IntoView { let auth = use_context::().expect("missing auth context"); let reply = use_context::().expect("missing reply controls"); let (posting, set_posting) = create_signal(false); let (error, set_error) = create_signal(None); let (content, set_content) = create_signal("".to_string()); let summary_ref: NodeRef = create_node_ref(); let public_ref: NodeRef = create_node_ref(); let followers_ref: NodeRef = create_node_ref(); let private_ref: NodeRef = create_node_ref(); // TODO is this too abusive with resources? im even checking if TLD exists... let mentions = create_local_resource( move || content.get(), move |c| async move { let mut out = Vec::new(); for word in c.split(' ') { if !word.starts_with('@') { break }; let stripped = word.replacen('@', "", 1); if let Some((user, domain)) = stripped.split_once('@') { if let Some(tld) = domain.split('.').last() { if tld::exist(tld) { if let Some(uid) = WEBFINGER.blocking_resolve(user, domain).await { out.push(uid); } } } } } out }, ); view! {
{move || reply.reply_to.get().map(|r| { let actor_strip = post_author(&r).map(|x| view! { }); view! { {r} | ctx: {}", reply.context.get().unwrap_or_default())} > "✒️" {actor_strip} "["reply"]" } }) } {move || mentions.get() .map(|x| x.into_iter().map(|u| match CACHE.get(&u) { Some(u) => view! { "📨" }.into_view(), None => view! { "📨"{u} }.into_view(), }) .collect_view()) }
{PRIVACY_PUBLIC}
{PRIVACY_FOLLOWERS}
{PRIVACY_PRIVATE}
{move|| error.get().map(|x| view! {
{x}
})}
} } #[component] pub fn AdvancedPostBox(advanced: WriteSignal) -> impl IntoView { let auth = use_context::().expect("missing auth context"); let (posting, set_posting) = create_signal(false); let (error, set_error) = create_signal(None); let (value, set_value) = create_signal("Like".to_string()); let (embedded, set_embedded) = create_signal(false); let sensitive_ref: NodeRef = create_node_ref(); let summary_ref: NodeRef = create_node_ref(); let content_ref: NodeRef = create_node_ref(); let context_ref: NodeRef = create_node_ref(); let name_ref: NodeRef = create_node_ref(); let reply_ref: NodeRef = create_node_ref(); let to_ref: NodeRef = create_node_ref(); let object_id_ref: NodeRef = create_node_ref(); let bto_ref: NodeRef = create_node_ref(); let cc_ref: NodeRef = create_node_ref(); let bcc_ref: NodeRef = create_node_ref(); view! {
{move|| error.get().map(|x| view! {
{x}
})}
} } fn get_if_some(node: NodeRef) -> Option { node.get() .map(|x| x.value()) .filter(|x| !x.is_empty()) } fn get_vec_if_some(node: NodeRef) -> Vec { node.get() .map(|x| x.value()) .filter(|x| !x.is_empty()) .map(|x| x.split(',') .map(|x| x.to_string()) .collect() ).unwrap_or_default() } fn get_checked(node: NodeRef) -> bool { node.get() .map(|x| x.checked()) .unwrap_or_default() } #[component] fn SelectOption(is: &'static str, value: ReadSignal) -> impl IntoView { view! { } }