diff --git a/web/index.html b/web/index.html
index 596e4386..3304329e 100644
--- a/web/index.html
+++ b/web/index.html
@@ -94,6 +94,9 @@
article p {
margin: 0 0 0 .5em;
}
+ article.float-container {
+ overflow-y: hidden;
+ }
b.displayname {
overflow-wrap: break-word;
}
@@ -132,15 +135,16 @@
position: sticky;
background-color: var(--background);
}
- div.border {
- border: 1px dashed var(--accent);
- }
span.border-button {
border: 1px solid var(--background-dim);
}
span.border-button:hover {
background-color: var(--background-dim);
}
+ div.border,
+ span.border {
+ border: 1px dashed var(--accent);
+ }
div.inline {
display: inline;
}
@@ -203,18 +207,25 @@
min-width: 2em;
max-width: 2em;
}
- div.flex-pic-container {
- flex: 1;
- border: solid 3px #bf616a;
- margin-right: .5em;
+ img.flex-pic {
+ float: left;
+ width: 10em;
+ height: 10em;
+ object-fit: cover;
+ margin-right: 1em;
+ margin-top: .5em;
+ margin-bottom: .5em;
+ margin-left: .5em;
}
- div.flex-pic {
- background-size: cover;
- margin: 5px;
- height: calc(100% - 10px); /* TODO can we avoid this calc() without having this overflow??? */
+ img.flex-pic-expand {
+ width: unset;
+ height: unset;
+ max-width: calc(100% - 1.5em);
+ max-height: 55vh;
}
.box {
border: 3px solid var(--accent);
+ box-sizing: border-box;
}
.cursor {
cursor: pointer;
diff --git a/web/src/components/activity.rs b/web/src/activities/item.rs
similarity index 95%
rename from web/src/components/activity.rs
rename to web/src/activities/item.rs
index 09721f80..d2e09e4f 100644
--- a/web/src/components/activity.rs
+++ b/web/src/activities/item.rs
@@ -55,14 +55,14 @@ pub fn Item(
match item.object_type().unwrap_or(apb::ObjectType::Object) {
// special case for placeholder activities
apb::ObjectType::Note | apb::ObjectType::Document(_) =>
- Some(view! { {sep.clone()} }.into_view()),
+ Some(view! { {sep.clone()} }.into_view()),
// everything else
apb::ObjectType::Activity(t) => {
let object_id = item.object().id().str().unwrap_or_default();
let object = match t {
apb::ActivityType::Create | apb::ActivityType::Announce =>
cache::OBJECTS.get(&object_id).map(|obj| {
- view! { }
+ view! { }
}.into_view()),
apb::ActivityType::Follow =>
cache::OBJECTS.get(&object_id).map(|obj| {
diff --git a/web/src/activities/mod.rs b/web/src/activities/mod.rs
new file mode 100644
index 00000000..a35e98d6
--- /dev/null
+++ b/web/src/activities/mod.rs
@@ -0,0 +1 @@
+pub mod item;
diff --git a/web/src/components/mod.rs b/web/src/components/mod.rs
index c4301994..b331057d 100644
--- a/web/src/components/mod.rs
+++ b/web/src/components/mod.rs
@@ -1,15 +1,9 @@
mod login;
pub use login::*;
-mod activity;
-pub use activity::*;
-
mod navigation;
pub use navigation::*;
-mod object;
-pub use object::*;
-
mod user;
pub use user::*;
diff --git a/web/src/lib.rs b/web/src/lib.rs
index af53682c..cb059e0d 100644
--- a/web/src/lib.rs
+++ b/web/src/lib.rs
@@ -3,12 +3,14 @@ mod app;
mod components;
mod page;
mod config;
-mod objects;
mod actors;
-mod getters;
+mod activities;
+mod objects;
mod timeline;
+mod getters;
+
pub use app::App;
pub use config::Config;
pub use auth::Auth;
diff --git a/web/src/objects/attachment.rs b/web/src/objects/attachment.rs
new file mode 100644
index 00000000..d19a6e2a
--- /dev/null
+++ b/web/src/objects/attachment.rs
@@ -0,0 +1,100 @@
+use leptos::*;
+use crate::{prelude::*, URL_SENSITIVE};
+
+use apb::{field::OptionalString, target::Addressed, ActivityMut, Base, Collection, CollectionMut, Document, Object, ObjectMut};
+
+#[component]
+pub fn Attachment(
+ object: serde_json::Value,
+ #[prop(optional)]
+ sensitive: bool
+) -> impl IntoView {
+ let config = use_context::
+
+
+
+
+
+ {Uri::pretty(&href, 50)}
+
+
+ {name.to_string()}
+ {media_type}
+
+ {object.name().map(|name| {
+ view! {
- -
- }.into_view(), - - "video" => { - let _href = href.clone(); - view! { -- -
- }.into_view(), - - "link" | "text" => - view! { -- - - -
- }.into_view(), - - _ => - view! { -
-
- {media_type}
-
- {object.name().map(|name| {
- view! {
{name.to_string()}
} - })} - - }.into_view(), - } +lazy_static::lazy_static! { + static ref REGEX: Regex = regex::Regex::new("@(\\w+)(@\\w+|)").expect("failed compiling @ regex"); } - #[component] -pub fn Object(object: crate::Object) -> impl IntoView { +pub fn Object( + object: crate::Object, + #[prop(optional)] reply: bool, +) -> impl IntoView { let oid = object.id().unwrap_or_default().to_string(); - let content = mdhtml::safe_html(object.content().unwrap_or_default()); let author_id = object.attributed_to().id().str().unwrap_or_default(); let author = cache::OBJECTS.get_or(&author_id, serde_json::Value::String(author_id.clone()).into()); let sensitive = object.sensitive().unwrap_or_default(); @@ -127,6 +40,26 @@ pub fn Object(object: crate::Object) -> impl IntoView { Some(view! { }) }; + let mut content = mdhtml::safe_html(object.content().unwrap_or_default()); + + let mut results = vec![]; + for (matched, [id, username, _domain]) in REGEX.captures_iter(&content).map(|c| c.extract()) { + // TODO what the fuck mastodon........... why are you putting the fancy url in the A HREF???????? + let id = id.replace('@', "users/"); + // TODO ughh ugly on-the-fly html editing, can this be avoided? + let to_replace = format!( + " ", + Uri::web(U::Actor, &id), id, username + ); + results.push((matched.to_string(), to_replace)); + } + + for (from, to) in results { + content = content.replace(&from, &to); + } + + + let audience_badge = object.audience().id().str() .map(|x| view! { @@ -134,7 +67,7 @@ pub fn Object(object: crate::Object) -> impl IntoView { class="border-button" title="this is a group: all interactions will be broadcasted to group members!" > -&
+ &
{Uri::pretty(&x, 30)}
@@ -142,13 +75,11 @@ pub fn Object(object: crate::Object) -> impl IntoView {
});
- let post_image = object.image().get().and_then(|x| x.url().id().str()).map(|x| view! {
-