{% extends "root.html" %} {% block head %} <title>Post - {{ config.name }}</title> {% endblock %} {% block body %} {{ macros::nav() }} <main class="flex flex-col gap-2"> {% if post.replying_to %} <a href="/post/{{ post.replying_to }}" class="button"> {{ icon "arrow-up" }} <span>{{ text "communities:action.continue_thread" }}</span> </a> {% endif %} <!-- prettier-ignore --> <div style="display: contents;"> {% 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) }} {% endif %} </div> {% if user and post.context.comments_enabled %} <div class="card-nest"> <div class="card small"> <b>{{ text "communities:label.create_reply" }}</b> </div> <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 "communities:label.content" }}</label > <textarea type="text" name="content" id="content" placeholder="content" required minlength="2" maxlength="4096" ></textarea> </div> <div id="files_list" class="flex gap-2 flex-wrap"></div> <div class="flex gap-2"> {{ components::emoji_picker(element_id="content", render_dialog=true) }} {% if is_supporter %} {{ components::file_picker(files_list_id="files_list") }} {% endif %} <button class="primary"> {{ text "communities:action.create" }} </button> </div> </form> </div> {% endif %} <div class="pillmenu"> <a href="#/replies" data-tab-button="replies" class="active"> {{ icon "newspaper" }} <span>{{ text "communities:label.replies" }}</span> </a> <a href="/post/{{ post.id }}/reposts"> {{ icon "repeat-2" }} <span>{{ text "communities:label.reposts" }}</span> </a> <a href="/post/{{ post.id }}/reposts?quotes=true"> {{ icon "quote" }} <span>{{ text "communities:label.quotes" }}</span> </a> <a href="/post/{{ post.id }}/likes"> {{ icon "heart" }} <span>{{ text "communities:label.likes" }}</span> </a> </div> {% if (user and user.id == post.owner) or can_manage_posts %} <div class="pillmenu"> {% if user and user.id == post.owner %} <a href="/post/{{ post.id }}#/edit"> {{ icon "pen" }} <span>{{ text "communities:label.edit_content" }}</span> </a> {% endif %} <a href="#/configure" data-tab-button="configure"> {{ icon "settings" }} <span>{{ text "communities:action.configure" }}</span> </a> </div> {% endif %} <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"> {{ icon "settings" }} <span>{{ text "communities:action.configure" }}</span> </div> <div class="card tertiary flex flex-col gap-4" id="post_context" ></div> </div> <button onclick="save_context()"> {{ icon "check" }} <span>{{ text "general:action.save" }}</span> </button> <script> setTimeout(() => { const ui = 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", "Hide from public timelines"], "{{ community.context.is_nsfw }}", "checkbox", ], [ ["content_warning", "Content warning"], settings.content_warning, "textarea", ], [ ["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); </script> </div> {% 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"> {{ icon "pen" }} <span>{{ text "communities:label.edit_content" }}</span> </div> <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 "communities:label.content" }}</label > <textarea type="text" name="new_content" id="new_content" placeholder="content" required minlength="2" maxlength="4096" > {{ post.content }}</textarea > </div> <div class="flex gap-2"> {{ components::emoji_picker(element_id="new_content", render_dialog=false) }} <button class="primary"> {{ text "general:action.save" }} </button> </div> </form> </div> <script> 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, ]); }); } </script> {% endif %} <div class="card-nest w-full" data-tab="replies"> <div class="card small flex items-center gap-2"> {{ icon "newspaper" }} <span>{{ text "communities:label.replies" }}</span> </div> <div class="card flex flex-col gap-4"> <!-- prettier-ignore --> {% for post in replies %} {{ components::post(post=post[0], owner=post[1], question=post[3], secondary=true, show_community=false) }} {% endfor %} {{ components::pagination(page=page, items=replies|length) }} </div> </div> </main> <script> async function create_reply_from_form(e) { e.preventDefault(); await trigger("atto::debounce", ["posts::create"]); // 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 }}", replying_to: "{{ post.id }}", }), ); // ... 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); } }); } </script> {% endblock %}