use std::sync::Arc; use apb::{target::Addressed, Activity, ActivityMut, Actor, Base, Collection, Object, ObjectMut}; use dashmap::DashMap; use leptos::{leptos_dom::logging::console_log, *}; pub const BASE_URL: &str = "https://feditest.alemi.dev"; #[derive(Debug, serde::Serialize)] struct LoginForm { email: String, password: String, } #[component] pub fn LoginBox( rx: Signal>, tx: WriteSignal>, ) -> impl IntoView { let username_ref: NodeRef = create_node_ref(); let password_ref: NodeRef = create_node_ref(); view! { () .await.unwrap(); tx.set(Some(auth)); }); } /> } } #[component] pub fn PostBox(token: Signal>) -> impl IntoView { let summary_ref: NodeRef = create_node_ref(); let content_ref: NodeRef = create_node_ref(); view! { post } } #[component] pub fn TimelinePicker( tx: WriteSignal, rx: ReadSignal, ) -> impl IntoView { let targets = ( "https://feditest.alemi.dev/users/test/inbox/page".to_string(), "https://feditest.alemi.dev/users/test/outbox/page".to_string(), "https://feditest.alemi.dev/inbox/page".to_string(), "https://feditest.alemi.dev/outbox/page".to_string(), ); let (my_in, my_out, our_in, our_out) = targets.clone(); let (my_in_, my_out_, our_in_, our_out_) = targets; view! { } } #[component] pub fn Actor(object: serde_json::Value) -> impl IntoView { match object { serde_json::Value::String(id) => view! { {id} }, serde_json::Value::Object(_) => { let avatar_url = object.icon().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 domain = object.id().unwrap_or_default().replace("https://", "").split('/').next().unwrap_or_default().to_string(); view! { {display_name} {username}@{domain} } }, _ => view! { invalid actor } } } #[component] pub fn Activity(activity: serde_json::Value) -> impl IntoView { let object = activity.clone().object().extract().unwrap_or_else(|| serde_json::Value::String(activity.object().id().unwrap_or_default()) ); let object_id = object.id().unwrap_or_default().to_string(); let content = dissolve::strip_html_tags(object.content().unwrap_or_default()); let addressed = activity.addressed(); let audience = format!("[ {} ]", addressed.join(", ")); let privacy = if addressed.iter().any(|x| x == apb::target::PUBLIC) { "[public]" } else if addressed.iter().any(|x| x.ends_with("/followers")) { "[followers]" } else { "[private]" }; let title = object.summary().unwrap_or_default().to_string(); let date = object.published().map(|x| x.to_rfc3339()).unwrap_or_default(); let kind = activity.activity_type().unwrap_or(apb::ActivityType::Activity); view! { {match kind { // post apb::ActivityType::Create => view! { {title} {x} } /> }, kind => view! { {kind.as_ref().to_string()}" >> "{object_id} }, }} {privacy}" "{date} } } #[component] pub fn Timeline( token: Signal>, ) -> impl IntoView { let (timeline, set_timeline) = create_signal(format!("{BASE_URL}/inbox/page")); let users : Arc> = Arc::new(DashMap::new()); let _users = users.clone(); // TODO i think there is syntactic sugar i forgot? let items = create_resource(move || timeline.get(), move |feed_url| { let __users = _users.clone(); // TODO lmao this is meme tier async move { let mut req = reqwest::Client::new().get(feed_url); if let Some(token) = token.get() { req = req.header("Authorization", format!("Bearer {token}")); } let activities : Vec = req .send() .await.unwrap() .json::() .await.unwrap() .ordered_items() .collect(); // i could make this fancier with iterators and futures::join_all but they would run // concurrently and make a ton of parallel request, we actually want these sequential because // first one may fetch same user as second one // some fancier logic may make a set of all actors and fetch uniques concurrently... let mut out = Vec::new(); for x in activities { if let Some(uid) = x.actor().id() { if let Some(actor) = __users.get(&uid) { out.push(x.set_actor(apb::Node::object(actor.clone()))) } else { let mut req = reqwest::Client::new() .get(format!("https://feditest.alemi.dev/users/+?id={uid}")); if let Some(token) = token.get() { req = req.header("Authorization", format!("Bearer {token}")); } let actor = req.send().await.unwrap().json::().await.unwrap(); __users.insert(uid, actor.clone()); out.push(x.set_actor(apb::Node::object(actor))) } } else { out.push(x) } } out } }); view! { {move || match items.get() { None => view! { loading... }.into_view(), Some(data) => { view! { } } /> }.into_view() }, }} } }
() .await.unwrap(); tx.set(Some(auth)); }); } />
{title}
loading...