tetratto/crates/app/src/public/html/post/post.lisp
2025-08-11 20:21:05 -04:00

400 lines
15 KiB
Common Lisp

(text "{% extends \"root.html\" %} {% block head %}")
(title
(text "Post - {{ config.name }}"))
(meta
("name" "og:title")
("content" "{% if owner.settings.display_name -%} {{ owner.settings.display_name }} {%- else -%} {{ owner.username }} {%- endif %}'s post"))
(meta
("name" "description")
("content" "View this post from @{{ owner.username }} on {{ config.name }}!"))
(meta
("name" "og:description")
("content" "View this post from @{{ owner.username }} on {{ config.name }}!"))
(meta
("property" "og:type")
("content" "website"))
(meta
("name" "og:image")
("content" "{{ config.host|safe }}/api/v1/auth/user/{{ owner.username }}/avatar?selector_type=username"))
(meta
("name" "twitter:image")
("content" "{{ config.host|safe }}/api/v1/auth/user/{{ owner.username }}/avatar?selector_type=usernamev"))
(meta
("name" "twitter:card")
("content" "summary"))
(meta
("name" "twitter:title")
("content" "{% if owner.settings.display_name -%} {{ owner.settings.display_name }} {%- else -%} {{ owner.username }} {%- endif %}'s post"))
(meta
("name" "twitter:description")
("content" "View this post from @{{ owner.username }} on {{ config.name }}!"))
(text "{% endblock %} {% block body %} {{ macros::nav() }}")
(main
("class" "flex flex_col gap_2 {% if community.is_forum -%}content_container{%- endif %}")
(text "{% if post.replying_to -%}")
(a
("href" "/post/{{ post.replying_to }}")
("class" "button")
(text "{{ icon \"arrow-up\" }}")
(span
(text "{{ text \"communities:action.continue_thread\" }}")))
(text "{%- endif %}")
; post
(text "{% if not community.is_forum -%}")
(div
("style" "display: contents")
(text "{% if post.context.repost and post.context.repost.reposting -%} {{ components::repost(repost=reposting, post=post, owner=owner, community=community, show_community=true, can_manage_post=can_manage_posts) }} {% else %} {{ components::post(post=post, owner=owner, question=question, community=community, show_community=true, can_manage_post=can_manage_posts, poll=poll, dont_show_title=true) }} {%- endif %}"))
(text "{% else %}")
(div
("style" "display: contents")
(text "{{ components::forum_post(post=post, owner=owner, community=community, can_manage_post=can_manage_posts, poll=poll, show_show_thread=false) }}"))
(text "{%- endif %}")
; ...
(text "{% if user and post.context.comments_enabled -%}")
(div
("class" "card_nest")
(div
("class" "card small")
(b
(text "{{ text \"communities:label.create_reply\" }}")))
(form
("class" "card flex flex_col gap_2")
("onsubmit" "create_reply_from_form(event)")
(div
("class" "flex flex_col gap_1")
(label
("for" "content")
(text "{{ text \"communities:label.content\" }}"))
(textarea
("type" "text")
("name" "content")
("id" "content")
("placeholder" "content")
("minlength" "2")
("maxlength" "4096")))
(div
("id" "files_list")
("class" "flex gap_2 flex_wrap"))
(div
("class" "flex gap_2")
(text "{{ components::emoji_picker(element_id=\"content\", render_dialog=true) }} {% if is_supporter -%} {{ components::file_picker(files_list_id=\"files_list\") }} {% endif %}")
(button
(str (text "communities:action.create"))))))
(text "{%- endif %}")
(div
("class" "pillmenu")
(a
("href" "#/replies")
("data-tab-button" "replies")
("class" "active")
(text "{{ icon \"newspaper\" }}")
(span
(text "{{ text \"communities:label.replies\" }}")))
(a
("href" "/post/{{ post.id }}/reposts")
(text "{{ icon \"repeat-2\" }}")
(span
(text "{{ text \"communities:label.reposts\" }}")))
(a
("href" "/post/{{ post.id }}/reposts?quotes=true")
(text "{{ icon \"quote\" }}")
(span
(text "{{ text \"communities:label.quotes\" }}"))))
(text "{% if (user and user.id == post.owner) or can_manage_posts -%}")
(div
("class" "pillmenu")
(text "{% if user and user.id == post.owner -%}")
(a
("href" "/post/{{ post.id }}#/edit")
("data-tab-button" "edit")
(text "{{ icon \"pen\" }}")
(span
(text "{{ text \"communities:label.edit_content\" }}")))
(text "{%- endif %}")
(a
("href" "/post/{{ post.id }}/likes")
(text "{{ icon \"heart\" }}")
(span
(text "{{ text \"communities:label.likes\" }}")))
(a
("href" "#/configure")
("data-tab-button" "configure")
(text "{{ icon \"settings\" }}")
(span
(text "{{ text \"communities:action.configure\" }}"))))
(div
("class" "flex flex_col gap_2 hidden")
("data-tab" "configure")
(div
("class" "card_nest w_full")
(div
("class" "card small flex items_center gap_2")
(text "{{ icon \"settings\" }}")
(span
(text "{{ text \"communities:action.configure\" }}")))
(div
("class" "card lowered flex flex_col gap_4")
("id" "post_context")))
(button
("onclick" "save_context()")
(text "{{ icon \"check\" }}")
(span
(text "{{ text \"general:action.save\" }}")))
(script
(text "setTimeout(async () => {
const ui = await ns(\"ui\");
const element = document.getElementById(\"post_context\");
const settings = JSON.parse(\"{{ post_context_serde|safe }}\");
globalThis.save_context = () => {
fetch(\"/api/v1/posts/{{ post.id }}/context\", {
method: \"POST\",
headers: {
\"Content-Type\": \"application/json\",
},
body: JSON.stringify({
context: settings,
}),
})
.then((res) => res.json())
.then((res) => {
trigger(\"atto::toast\", [
res.ok ? \"success\" : \"error\",
res.message,
]);
});
};
ui.refresh_container(element, []);
const can_manage_pins = \"{{ can_manage_pins }}\" === \"true\";
const is_owner =
\"{{ user and user.id == post.owner }}\" === \"true\";
const settings_fields = [
[
[
\"comments_enabled\",
\"Allow people to comment on your post\",
],
\"{{ post.context.comments_enabled }}\",
\"checkbox\",
],
[
[
\"reposts_enabled\",
\"Allow people to repost/quote your post\",
],
\"{{ post.context.reposts_enabled }}\",
\"checkbox\",
],
[
[
\"reactions_enabled\",
\"Allow people to like/dislike your post\",
],
\"{{ post.context.reactions_enabled }}\",
\"checkbox\",
],
[
[\"is_nsfw\", \"Mark as NSFW\"],
\"{{ community.context.is_nsfw }}\",
\"checkbox\",
],
[
[\"content_warning\", \"Content warning\"],
settings.content_warning,
\"textarea\",
],
[
[\"full_unlist\", \"Unlist from timelines\"],
\"{{ user.settings.auto_full_unlist }}\",
\"checkbox\",
],
[
[\"tags\", \"Tags\"],
settings.tags.join(\", \"),
\"input\",
{
embed_html:
'<span class=\"fade\">Tags should be separated by a comma.</span>',
},
],
];
if (can_manage_pins) {
settings_fields.push([
[\"is_pinned\", \"Pinned to community wall\"],
\"{{ post.context.is_pinned }}\",
\"checkbox\",
]);
}
if (is_owner) {
settings_fields.push([
[\"is_profile_pinned\", \"Pinned to your profile\"],
\"{{ post.context.is_profile_pinned }}\",
\"checkbox\",
]);
}
ui.generate_settings_ui(element, settings_fields, settings, {
tags: (new_tags) => {
settings.tags = new_tags
.split(\",\")
.map((t) => t.trim());
},
});
}, 250);")))
(text "{%- endif %}")
(text "{% if user and user.id == post.owner -%}")
(div
("class" "card_nest w_full hidden")
("data-tab" "edit")
(div
("class" "card small flex items_center gap_2")
(text "{{ icon \"pen\" }}")
(span
(text "{{ text \"communities:label.edit_content\" }}")))
(form
("class" "card flex flex_col gap_2")
("onsubmit" "edit_post_from_form(event)")
(div
("class" "flex flex_col gap_1")
(label
("for" "content")
(text "{{ text \"communities:label.content\" }}"))
(textarea
("type" "text")
("name" "new_content")
("id" "new_content")
("placeholder" "content")
("required" "")
("minlength" "2")
("maxlength" "4096")
(text "{{ post.content }}")))
(div
("class" "flex gap_2")
(text "{{ components::emoji_picker(element_id=\"new_content\", render_dialog=false) }}")
(button
(text "{{ text \"general:action.save\" }}")))))
(script
(text "async function edit_post_from_form(e) {
e.preventDefault();
await trigger(\"atto::debounce\", [\"posts::edit\"]);
fetch(\"/api/v1/posts/{{ post.id }}/content\", {
method: \"POST\",
headers: {
\"Content-Type\": \"application/json\",
},
body: JSON.stringify({
content: e.target.new_content.value,
}),
})
.then((res) => res.json())
.then((res) => {
trigger(\"atto::toast\", [
res.ok ? \"success\" : \"error\",
res.message,
]);
});
}"))
(text "{%- endif %}")
(div
("class" "card_nest w_full")
("data-tab" "replies")
(div
("class" "card small flex items_center gap_2")
(text "{{ icon \"newspaper\" }}")
(span
(text "{{ text \"communities:label.replies\" }}")))
(div
("class" "card flex flex_col gap_4")
(text "{% for post in replies %}")
; reply
(text "{% if not community.is_forum -%}")
(div
("style" "display: contents")
(text "{{ components::post(post=post[0], owner=post[1], question=post[3], secondary=true, show_community=false, poll=post[4]) }}"))
(text "{% else %}")
(div
("style" "display: contents")
(text "{{ components::forum_post(post=post[0], owner=post[1], community=community, can_manage_post=can_manage_posts, poll=post[4]) }}"))
(text "{%- endif %} {% endfor %} {{ components::pagination(page=page, items=replies|length) }}"))))
(script
(text "globalThis.continue_thread = async (target, post_id, id, page = 0) => {
const btn_id = `tmp_${window.crypto.randomUUID()}`;
target.setAttribute(\"disabled\", \"true\");
target.id = btn_id;
document.getElementById(id).innerHTML +=
await (await fetch(`/post/${post_id}/_quick_replies?page=${page}`)).text();
document.getElementById(id).classList.remove(\"hidden\");
await trigger(\"atto::clean_date_codes\");
await trigger(\"atto::link_filter\");
await trigger(\"atto::hooks::check_reactions\");
await trigger(\"atto::hooks::online_indicator\");
document.getElementById(btn_id).parentElement.remove();
}
async function create_reply_from_form(e) {
e.preventDefault();
await trigger(\"atto::debounce\", [\"posts::create\"]);
// poll
const poll_data = [true, null];
// create body
const body = new FormData();
if (e.target.file_picker) {
for (const file of e.target.file_picker.files) {
body.append(file.name, file);
}
}
body.append(
\"body\",
JSON.stringify({
content: e.target.content.value,
community: \"{{ community.id }}\",
stack: \"{{ post.stack }}\",
topic: \"{{ post.topic }}\",
replying_to: \"{{ post.id }}\",
poll: poll_data[1],
}),
);
// ...
fetch(\"/api/v1/posts\", {
method: \"POST\",
body,
})
.then((res) => res.json())
.then((res) => {
trigger(\"atto::toast\", [
res.ok ? \"success\" : \"error\",
res.message,
]);
if (res.ok) {
setTimeout(() => {
window.location.href = `/post/${res.payload}`;
}, 100);
}
});
}"))
(text "{% endblock %}")