|
|
|
@ -1,5 +1,8 @@
|
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
|
|
|
|
|
use chrono::DateTime;
|
|
|
|
|
use futures::executor;
|
|
|
|
|
use regex::Regex;
|
|
|
|
|
use yew::{function_component, html, AttrValue, Html, Renderer, ServerRenderer};
|
|
|
|
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
@ -8,7 +11,7 @@ use console_error_panic_hook::set_once as set_panic_hook;
|
|
|
|
|
use yew::prelude::*;
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
data::{Attachment, Outbox, Person},
|
|
|
|
|
data::{Attachment, CommonFields, Item, Outbox, Person, Post as DataPost},
|
|
|
|
|
error::Ærror,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -19,6 +22,13 @@ struct Props {
|
|
|
|
|
pub archive_time: DateTime<chrono::Utc>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(yew::Properties, PartialEq)]
|
|
|
|
|
struct PostProps {
|
|
|
|
|
pub meta: CommonFields,
|
|
|
|
|
pub post: DataPost,
|
|
|
|
|
pub author: Person,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
|
|
|
pub fn render_ssr(
|
|
|
|
|
outbox: Outbox,
|
|
|
|
@ -73,6 +83,7 @@ fn Layout(props: &Props) -> Html {
|
|
|
|
|
html! {
|
|
|
|
|
<>
|
|
|
|
|
<ProfileHeader outbox={props.outbox.clone()} author={props.author.clone()} archive_time={props.archive_time}/>
|
|
|
|
|
<Posts outbox={props.outbox.clone()} author={props.author.clone()} archive_time={props.archive_time}/>
|
|
|
|
|
</>
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -133,7 +144,67 @@ fn ProfileHeader(props: &Props) -> Html {
|
|
|
|
|
|
|
|
|
|
#[function_component]
|
|
|
|
|
fn Posts(props: &Props) -> Html {
|
|
|
|
|
let public = &String::from_str("https://www.w3.org/ns/activitystreams#Public").unwrap();
|
|
|
|
|
let author_str = props.author.clone().id;
|
|
|
|
|
|
|
|
|
|
let mut ordered_items = props.outbox.clone().ordered_items;
|
|
|
|
|
ordered_items.reverse();
|
|
|
|
|
|
|
|
|
|
let posts: Vec<(CommonFields, DataPost)> = ordered_items
|
|
|
|
|
.into_iter()
|
|
|
|
|
.filter_map(|item| match item {
|
|
|
|
|
Item::Post { meta, object } => {
|
|
|
|
|
if meta.to.contains(public)
|
|
|
|
|
&& object.in_reply_to.is_none()
|
|
|
|
|
&& meta.actor == author_str
|
|
|
|
|
{
|
|
|
|
|
Some((meta, object))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => None,
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
html! {
|
|
|
|
|
<p>{"Posts"}</p>
|
|
|
|
|
<>
|
|
|
|
|
<div class="posts-info">
|
|
|
|
|
{posts.len()}
|
|
|
|
|
{" posts"}
|
|
|
|
|
</div>
|
|
|
|
|
<div class="posts">
|
|
|
|
|
{posts.into_iter().map(|(meta, post)| {
|
|
|
|
|
html! {
|
|
|
|
|
<Post post={post} meta={meta} author={props.author.clone()}/>
|
|
|
|
|
}
|
|
|
|
|
}).collect::<Html>()}
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[function_component]
|
|
|
|
|
fn Post(props: &PostProps) -> Html {
|
|
|
|
|
let post = props.post.clone();
|
|
|
|
|
let meta = props.meta.clone();
|
|
|
|
|
|
|
|
|
|
let post_time_utc = DateTime::parse_from_rfc3339(meta.published.as_str()).unwrap();
|
|
|
|
|
let post_time = DateTime::<chrono::offset::Local>::from(post_time_utc);
|
|
|
|
|
|
|
|
|
|
let mut content = String::from_str(&post.content).unwrap();
|
|
|
|
|
|
|
|
|
|
if post.quote_uri.is_some() {
|
|
|
|
|
let regex = Regex::new("<span class=\"quote-inline\">.*</span>").unwrap();
|
|
|
|
|
content = String::from_str(®ex.replace(&content.as_str(), "")).unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
html! {
|
|
|
|
|
<div class="post">
|
|
|
|
|
<div class="post-contents">
|
|
|
|
|
{Html::from_html_unchecked(AttrValue::from(content))}
|
|
|
|
|
</div>
|
|
|
|
|
<span class="post-date">{post_time.format("%b %e, %Y, %H:%M")}</span>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|