add: "town square" community option

with a town square community, users can post directly from their profiles!
This commit is contained in:
trisua 2025-04-03 20:25:00 -04:00
parent ca0c4b9e0b
commit 48e0b02198
7 changed files with 90 additions and 9 deletions

View file

@ -3,8 +3,9 @@
<div class="flex flex-col gap-4 w-full"> <div class="flex flex-col gap-4 w-full">
{% if user and can_post %} {% if user and can_post %}
<div class="card-nest"> <div class="card-nest">
<div class="card small"> <div class="card small flex items-center gap-2">
<b>{{ text "communities:label.create_post" }}</b> {{ icon "pencil" }}
<span>{{ text "communities:label.create_post" }}</span>
</div> </div>
<form <form

View file

@ -106,7 +106,7 @@ community %}
</div> </div>
{%- endmacro %} {% macro post(post, owner, secondary=false, community=false, {%- endmacro %} {% macro post(post, owner, secondary=false, community=false,
show_community=true, can_manage_post=false) -%} {% if community and show_community=true, can_manage_post=false) -%} {% if community and
show_community %} show_community and post.community != config.town_square %}
<div class="card-nest"> <div class="card-nest">
<div class="card small"> <div class="card small">
<a <a
@ -225,7 +225,8 @@ show_community %}
</div> </div>
</div> </div>
</div> </div>
{% if community and show_community %} {% if community and show_community and post.community != config.town_square
%}
</div> </div>
{% endif %} {%- endmacro %} {% macro notification(notification) -%} {% endif %} {%- endmacro %} {% macro notification(notification) -%}
<div class="w-full card-nest"> <div class="w-full card-nest">

View file

@ -1,5 +1,73 @@
{% import "macros.html" as macros %} {% extends "profile/base.html" %} {% block {% import "macros.html" as macros %} {% extends "profile/base.html" %} {% block
content %} content %} {% if config.town_square %}
<div class="card-nest">
<div class="card small flex flex-col">
<div class="flex items-center gap-2">
{{ icon "pencil" }}
<span>{{ text "communities:label.create_post" }}</span>
</div>
<span class="fade"
>Posts created here go to the
<a href="/api/v1/communities/find/{{ config.town_square }}"
>town square</a
>
community!</span
>
</div>
<form
class="card flex flex-col gap-2"
onsubmit="create_post_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_post_from_form(e) {
e.preventDefault();
await trigger("atto::debounce", ["posts::create"]);
fetch("/api/v1/posts", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
content: e.target.content.value,
community: "{{ config.town_square }}",
}),
})
.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>
{% endif %}
<div class="card-nest"> <div class="card-nest">
<div class="card small flex gap-2 items-center"> <div class="card small flex gap-2 items-center">
{{ icon "clock" }} {{ icon "clock" }}

View file

@ -95,6 +95,7 @@
const atto = ns("atto"); const atto = ns("atto");
atto.disconnect_observers(); atto.disconnect_observers();
atto.remove_false_options();
atto.clean_date_codes(); atto.clean_date_codes();
atto.link_filter(); atto.link_filter();

View file

@ -36,10 +36,6 @@ media_theme_pref();
(() => { (() => {
const self = reg_ns("atto"); const self = reg_ns("atto");
for (const element of document.querySelectorAll('[selected="false"]')) {
element.removeAttribute("selected");
}
// init // init
use("me", () => {}); use("me", () => {});
@ -74,6 +70,12 @@ media_theme_pref();
}); });
}); });
self.define("remove_false_options", () => {
for (const element of document.querySelectorAll('[selected="false"]')) {
element.removeAttribute("selected");
}
});
self.define("rel_date", (_, date) => { self.define("rel_date", (_, date) => {
// stolen and slightly modified because js dates suck // stolen and slightly modified because js dates suck
const diff = (new Date().getTime() - date.getTime()) / 1000; const diff = (new Date().getTime() - date.getTime()) / 1000;

View file

@ -187,6 +187,12 @@ pub struct Config {
/// Configuration for Cloudflare Turnstile. /// Configuration for Cloudflare Turnstile.
#[serde(default = "default_turnstile")] #[serde(default = "default_turnstile")]
pub turnstile: TurnstileConfig, pub turnstile: TurnstileConfig,
/// The ID of the "town square" community. This community is required to allow
/// people to post from their profiles.
///
/// This community **must** have open write access.
#[serde(default)]
pub town_square: String,
} }
fn default_name() -> String { fn default_name() -> String {
@ -261,6 +267,7 @@ impl Default for Config {
banned_usernames: default_banned_usernames(), banned_usernames: default_banned_usernames(),
policies: default_policies(), policies: default_policies(),
turnstile: default_turnstile(), turnstile: default_turnstile(),
town_square: String::new(),
} }
} }
} }

View file

@ -15,6 +15,7 @@ banned_usernames = [
"post", "post",
"void", "void",
] ]
town_square = "166340372315581657"
[security] [security]
registration_enabled = true registration_enabled = true