feat(web): added reply button

not the best way to do it but it works!
This commit is contained in:
əlemi 2024-05-01 16:46:19 +02:00
parent 102414e1a3
commit f483ea14b4
Signed by: alemi
GPG key ID: A4895B84D311642C
4 changed files with 67 additions and 6 deletions

View file

@ -84,6 +84,12 @@
font-size: .6em;
color: var(--secondary);
}
span.nowrap {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: block;
}
hr.sep {
z-index: 100;
margin-top: 0;

View file

@ -20,6 +20,9 @@ pub fn App() -> impl IntoView {
let user_tl = Timeline::new(format!("{URL_BASE}/users/{}/outbox/page", username.get().unwrap_or_default()));
let context_tl = Timeline::new(format!("{URL_BASE}/outbox/page"));
let reply_controls = ReplyControls::default();
provide_context(reply_controls);
let screen_width = window().screen().map(|x| x.avail_width().unwrap_or_default()).unwrap_or_default();
let (menu, set_menu) = create_signal(screen_width <= 786);

View file

@ -1,5 +1,3 @@
use std::sync::Arc;
use leptos::*;
use crate::{prelude::*, URL_SENSITIVE};
@ -127,7 +125,7 @@ pub fn Object(object: crate::Object) -> impl IntoView {
</Summary>
</blockquote>
<div class="mt-s ml-1 rev">
<ReplyButton n=comments />
<ReplyButton n=comments target=oid.clone() />
<LikeButton n=likes liked=already_liked target=oid.clone() author=author_id private=!public />
<RepostButton n=shares target=oid />
</div>
@ -199,14 +197,23 @@ pub fn LikeButton(
}
#[component]
pub fn ReplyButton(n: u64) -> impl IntoView {
pub fn ReplyButton(n: u64, target: String) -> impl IntoView {
let reply = use_context::<ReplyControls>().expect("missing reply controls context");
let comments = if n > 0 {
Some(view! { <small>{n}</small> })
} else {
None
};
let _target = target.clone(); // TODO ughhhh useless clones
view! {
<span class="emoji ml-2">{comments}" 📨"</span>
<span
class:emoji=move || !reply.reply_to.get().map_or(false, |x| x == _target)
class="emoji-btn cursor ml-2"
on:click=move |_ev| reply.reply(&target)
>
{comments}
" 📨"
</span>
}
}

View file

@ -1,4 +1,4 @@
use apb::{ActivityMut, BaseMut, ObjectMut};
use apb::{ActivityMut, Base, BaseMut, Object, ObjectMut};
use leptos::*;
use crate::prelude::*;
@ -14,9 +14,35 @@ pub fn Navigator() -> impl IntoView {
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ReplyControls {
pub context: RwSignal<Option<String>>,
pub reply_to: RwSignal<Option<String>>,
}
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().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<crate::Object> {
let usr = CACHE.get(post_id)?.attributed_to().id()?;
CACHE.get(&usr)
}
#[component]
pub fn PostBox(username: Signal<Option<String>>, advanced: WriteSignal<bool>) -> impl IntoView {
let auth = use_context::<Auth>().expect("missing auth context");
let reply = use_context::<ReplyControls>().expect("missing reply controls");
let (posting, set_posting) = create_signal(false);
let (error, set_error) = create_signal(None);
let summary_ref: NodeRef<html::Input> = create_node_ref();
@ -26,6 +52,23 @@ pub fn PostBox(username: Signal<Option<String>>, advanced: WriteSignal<bool>) ->
let private_ref: NodeRef<html::Input> = create_node_ref();
view! {
<div class:hidden=move || !auth.present() >
{move ||
reply.reply_to.get().map(|r| {
let actor_strip = post_author(&r).map(|x| view! { <ActorStrip object=x /> });
view! {
<span class="nowrap">
<span
class="cursor emoji emoji-btn mr-s ml-s"
on:click=move|_| reply.clear()
title={format!("> {r} | ctx: {}", reply.context.get().unwrap_or_default())}
>
"📨"
</span>
<small>{actor_strip}</small>
</span>
}
})
}
<table class="align w-100">
<tr>
<td><input type="checkbox" on:input=move |ev| advanced.set(event_target_checked(&ev)) title="advanced" /></td>
@ -58,6 +101,8 @@ pub fn PostBox(username: Signal<Option<String>>, advanced: WriteSignal<bool>) ->
.set_object_type(Some(apb::ObjectType::Note))
.set_summary(summary.as_deref())
.set_content(Some(&content))
.set_context(apb::Node::maybe_link(reply.context.get()))
.set_in_reply_to(apb::Node::maybe_link(reply.reply_to.get()))
.set_to(to)
.set_cc(cc);
let target_url = format!("{URL_BASE}/users/test/outbox");