add: better quote post ui

This commit is contained in:
trisua 2025-05-21 00:04:18 -04:00
parent fb2a9285d2
commit 2b91422d18
8 changed files with 138 additions and 102 deletions

View file

@ -95,6 +95,19 @@ macro_rules! get_lang {
}}; }};
} }
#[macro_export]
macro_rules! user_banned {
($user:expr, $other_user:ident, $data:ident, $jar:ident) => {
let lang = get_lang!($jar, $data.0);
let mut context = initial_context(&$data.0.0, lang, &$user).await;
context.insert("profile", &$other_user);
return Ok(Html(
$data.1.render("profile/banned.html", &context).unwrap(),
));
};
}
#[macro_export] #[macro_export]
macro_rules! check_user_blocked_or_private { macro_rules! check_user_blocked_or_private {
($user:expr, $other_user:ident, $data:ident, $jar:ident) => { ($user:expr, $other_user:ident, $data:ident, $jar:ident) => {
@ -115,13 +128,13 @@ macro_rules! check_user_blocked_or_private {
// check if other user is banned // check if other user is banned
if $other_user.permissions.check_banned() { if $other_user.permissions.check_banned() {
let lang = get_lang!($jar, $data.0); if let Some(ref ua) = $user {
let mut context = initial_context(&$data.0.0, lang, &$user).await; if !ua.permissions.check(FinePermission::MANAGE_USERS) {
context.insert("profile", &$other_user); $crate::user_banned!($user, $other_user, $data, $jar);
}
return Ok(Html( } else {
$data.1.render("profile/banned.html", &context).unwrap(), $crate::user_banned!($user, $other_user, $data, $jar);
)); }
} }
// check if we're blocked // check if we're blocked

View file

@ -49,6 +49,13 @@ fn check_staff_badge(value: &Value, _: &HashMap<String, Value>) -> tera::Result<
.into()) .into())
} }
fn check_banned(value: &Value, _: &HashMap<String, Value>) -> tera::Result<Value> {
Ok(FinePermission::from_bits(value.as_u64().unwrap() as u32)
.unwrap()
.check_banned()
.into())
}
#[tokio::main(flavor = "multi_thread")] #[tokio::main(flavor = "multi_thread")]
async fn main() { async fn main() {
tracing_subscriber::fmt() tracing_subscriber::fmt()
@ -78,6 +85,7 @@ async fn main() {
tera.register_filter("color", color_escape); tera.register_filter("color", color_escape);
tera.register_filter("has_supporter", check_supporter); tera.register_filter("has_supporter", check_supporter);
tera.register_filter("has_staff_badge", check_staff_badge); tera.register_filter("has_staff_badge", check_staff_badge);
tera.register_filter("has_banned", check_banned);
let client = Client::new(); let client = Client::new();

View file

@ -54,6 +54,23 @@
</button> </button>
</div> </div>
</div> </div>
{%- endif %} {% if quoting -%}
<div
class="card secondary w-full flex items-center justify-between gap-2 small"
>
<a
class="flex items-center gap-2 flush"
href="/post/{{ quoting[1].id }}"
>
{{ icon "quote" }}
<span>{{ quoting[0].username }}'s post</span>
</a>
<a href="?" class="button quaternary small">
{{ icon "x" }}
<span>{{ text "dialog:action.cancel" }}</span>
</a>
</div>
{%- endif %} {%- endif %}
<div class="card-nest"> <div class="card-nest">
@ -91,7 +108,7 @@
<form <form
class="card flex flex-col gap-2" class="card flex flex-col gap-2"
id="create_form" id="create_form"
onsubmit="create_post_from_form_town_square(event)" onsubmit="create_post_from_form(event)"
> >
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<label for="content" <label for="content"
@ -115,7 +132,7 @@
{{ components::create_post_options() }} {{ components::create_post_options() }}
<div class="flex gap-2"> <div class="flex gap-2">
{% if draft -%} {% if not quoting -%} {% if draft -%}
<button <button
class="secondary small square" class="secondary small square"
title="Save as Draft" title="Save as Draft"
@ -133,7 +150,7 @@
> >
{{ icon "notepad-text-dashed" }} {{ icon "notepad-text-dashed" }}
</button> </button>
{%- endif %} {%- endif %} {%- endif %}
<button class="primary"> <button class="primary">
{{ text "communities:action.create" }} {{ text "communities:action.create" }}
@ -143,8 +160,9 @@
</form> </form>
</div> </div>
{% if not quoting -%}
<script> <script>
async function create_post_from_form_town_square(e) { async function create_post_from_form(e) {
e.preventDefault(); e.preventDefault();
await trigger("atto::debounce", ["posts::create"]); await trigger("atto::debounce", ["posts::create"]);
@ -289,6 +307,27 @@
}); });
} }
</script> </script>
{% else %}
<script>
async function create_post_from_form(e) {
const id = await trigger("me::repost", [
"{{ quoting[1].id }}",
e.target.content.value,
document.getElementById("community_to_post_to")
.selectedOptions[0].value,
false,
]);
// update settings
await update_settings_maybe(id);
// redirect
setTimeout(() => {
window.location.href = `/post/${id}`;
}, 100);
}
</script>
{%- endif %}
</div> </div>
</div> </div>

View file

@ -349,14 +349,15 @@ config.town_square or question %}
<span>{{ text "communities:label.repost" }}</span> <span>{{ text "communities:label.repost" }}</span>
</button> </button>
<button <a
onclick="window.REPOST_ID = '{{ post.id }}'; document.getElementById('quote_dialog').showModal()" class="button"
href="/communities/intents/post?quote={{ post.id }}"
> >
{{ icon "quote" }} {{ icon "quote" }}
<span <span
>{{ text "communities:label.quote_post" }}</span >{{ text "communities:label.quote_post" }}</span
> >
</button> </a>
{%- endif %} {% if user.id != post.owner -%} {%- endif %} {% if user.id != post.owner -%}
<b class="title">{{ text "general:label.safety" }}</b> <b class="title">{{ text "general:label.safety" }}</b>
<button <button
@ -640,48 +641,6 @@ user %} {% if user.settings.theme_hue -%}
--{{ css }}: {{ color|color }} !important; --{{ css }}: {{ color|color }} !important;
} }
</style> </style>
{%- endif %} {%- endmacro %} {% macro quote_form() -%} {% if config.town_square
and user %}
<div class="card-nest">
<div class="card small flex flex-col">
<div class="flex items-center gap-2">
{{ icon "quote" }}
<span>{{ text "communities:label.quote_post" }}</span>
</div>
</div>
<form
class="card flex flex-col gap-2"
onsubmit="create_repost_from_form(event)"
>
<div class="flex flex-col gap-1">
<label for="content">{{ text "communities:label.content" }}</label>
<textarea
type="text"
name="content"
id="content"
placeholder="content"
required
minlength="2"
maxlength="4096"
></textarea>
</div>
<button class="primary">{{ text "communities:action.create" }}</button>
</form>
</div>
<script>
async function create_repost_from_form(e) {
e.preventDefault();
await trigger("atto::debounce", ["posts::create"]);
await trigger("me::repost", [
window.REPOST_ID,
e.target.content.value,
"{{ config.town_square }}",
]);
}
</script>
{%- endif %} {%- endmacro %} {% macro question(question, owner, {%- endif %} {%- endmacro %} {% macro question(question, owner,
show_community=true, secondary=false) -%} show_community=true, secondary=false) -%}
<div class="card{% if secondary -%} secondary{%- endif %} flex gap-2"> <div class="card{% if secondary -%} secondary{%- endif %} flex gap-2">
@ -1398,10 +1357,13 @@ is_supporter %}
</div> </div>
</div> </div>
{%- endif %} {%- endmacro %} {% macro create_post_options() -%} {%- endif %} {%- endmacro %} {% macro create_post_options() -%}
<!-- prettier-ignore -->
<div class="flex gap-2"> <div class="flex gap-2">
{{ components::emoji_picker(element_id="content", render_dialog=true) }} {% {{ components::emoji_picker(element_id="content", render_dialog=true) }}
if is_supporter -%} {{ components::file_picker(files_list_id="files_list")
}} {%- endif %} {% if not quoting -%} {% if is_supporter -%}
{{ components::file_picker(files_list_id="files_list") }}
{%- endif %} {%- endif %}
<button <button
class="small square quaternary" class="small square quaternary"

View file

@ -67,6 +67,12 @@
{{ icon "shield-user" }} {{ icon "shield-user" }}
</span> </span>
{%- endif %} {%- endif %}
{% if profile.permissions|has_banned -%}
<span title="Banned" style="color: var(--color-primary);" class="flex items-center">
{{ icon "shield-ban" }}
</span>
{%- endif %}
</h3> </h3>
<span class="fade">{{ profile.username }}</span> <span class="fade">{{ profile.username }}</span>

View file

@ -325,26 +325,6 @@ macros -%}
</form> </form>
</div> </div>
</dialog> </dialog>
<dialog id="quote_dialog">
<div class="inner flex flex-col gap-2">
{{ components::quote_form() }}
<div class="flex justify-between">
<div></div>
<div class="flex gap-2">
<button
class="bold red quaternary"
onclick="document.getElementById('quote_dialog').close()"
type="button"
>
{{ icon "x" }} {{ text "dialog:action.close" }}
</button>
</div>
</div>
</div>
</dialog>
{%- endif %} {% if user and use_user_theme -%} {{ {%- endif %} {% if user and use_user_theme -%} {{
components::theme(user=user, components::theme(user=user,
theme_preference=user.settings.theme_preference) }} theme_preference=user.settings.theme_preference) }}

View file

@ -201,31 +201,40 @@
}); });
}); });
self.define("repost", (_, id, content, community) => { self.define(
fetch(`/api/v1/posts/${id}/repost`, { "repost",
method: "POST", (_, id, content, community, do_not_redirect = false) => {
headers: { return new Promise((resolve, _) => {
"Content-Type": "application/json", fetch(`/api/v1/posts/${id}/repost`, {
}, method: "POST",
body: JSON.stringify({ headers: {
content, "Content-Type": "application/json",
community, },
}), body: JSON.stringify({
}) content,
.then((res) => res.json()) community,
.then((res) => { }),
trigger("atto::toast", [ })
res.ok ? "success" : "error", .then((res) => res.json())
res.message, .then((res) => {
]); trigger("atto::toast", [
res.ok ? "success" : "error",
res.message,
]);
if (res.ok) { if (res.ok) {
setTimeout(() => { if (!do_not_redirect) {
window.location.href = `/post/${res.payload}`; setTimeout(() => {
}, 100); window.location.href = `/post/${res.payload}`;
} }, 100);
}
resolve(res.payload);
}
});
}); });
}); },
);
self.define("report", (_, asset, asset_type) => { self.define("report", (_, asset, asset_type) => {
window.open( window.open(

View file

@ -243,6 +243,8 @@ pub struct CreatePostProps {
pub community: usize, pub community: usize,
#[serde(default)] #[serde(default)]
pub from_draft: usize, pub from_draft: usize,
#[serde(default)]
pub quote: usize,
} }
/// `/communities/intents/post` /// `/communities/intents/post`
@ -299,12 +301,29 @@ pub async fn create_post_request(
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)), Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
}; };
// get quoting
let quoting = if props.quote != 0 {
match data.0.get_post_by_id(props.quote).await {
Ok(q) => Some((
match data.0.get_user_by_id(q.owner).await {
Ok(ua) => ua,
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
},
q,
)),
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
}
} else {
None
};
// ... // ...
let lang = get_lang!(jar, data.0); let lang = get_lang!(jar, data.0);
let mut context = initial_context(&data.0.0, lang, &Some(user)).await; let mut context = initial_context(&data.0.0, lang, &Some(user)).await;
context.insert("draft", &draft); context.insert("draft", &draft);
context.insert("drafts", &drafts); context.insert("drafts", &drafts);
context.insert("quoting", &quoting);
context.insert("communities", &communities); context.insert("communities", &communities);
context.insert("selected_community", &props.community); context.insert("selected_community", &props.community);