add: blocked users page

This commit is contained in:
trisua 2025-05-09 22:36:16 -04:00
parent 6893aeedb5
commit 3706764437
18 changed files with 427 additions and 178 deletions

View file

@ -30,7 +30,9 @@
</button>
</form>
</div>
{% endif %}
{% if list|length >= 4 %} {{ components::supporter_ad(body="Become a
supporter to create up to 10 communities!") }} {% endif %} {% endif %}
<div class="card-nest w-full">
<div class="card small flex items-center justify-between gap-2">

View file

@ -1242,4 +1242,24 @@ show_kick=false, secondary=false) -%}
</div>
</div>
</dialog>
{% endif %} {%- endmacro %} {% macro supporter_ad(body="") -%} {% if
config.stripe and not is_supporter %}
<div
class="card w-full supporter_ad"
ui_ident="supporter_ad"
onclick="window.location.href = '/settings#/account/billing'"
>
<div class="card w-full flex flex-wrap items-center gap-2 justify-between">
{% if body %}
<b>{{ body }}</b>
{% else %}
<b>{{ text "general:label.supporter_motivation" }}</b>
{% endif %}
<a href="/settings#/account/billing" class="button small">
{{ icon "heart" }}
<span>{{ text "general:action.become_supporter" }}</span>
</a>
</div>
</div>
{% endif %} {%- endmacro %}

View file

@ -38,36 +38,24 @@
<div class="w-full flex flex-col gap-2" data-tab="account">
<div class="card tertiary flex flex-col gap-2" id="account_settings">
{% if config.stripe %}
<div class="card-nest" ui_ident="supporter_card">
<div class="card small flex items-center gap-2">
{{ icon "star" }}
<b>Supporter status</b>
</div>
<div class="pillmenu" ui_ident="account_settings_tabs">
<a data-tab-button="account/security" href="#/account/security">
{{ icon "user-lock" }}
<span>{{ text "settings:tab.security" }}</span>
</a>
<div class="card">
{% if is_supporter %}
<p>You <b>are</b> a supporter! Thank you for all that you do. You can manage your billing information below. <b>Please use your email address you supplied when paying to login to the billing portal.</b></p>
<a href="{{ config.stripe.billing_portal_url }}" class="button quaternary" target="_blank">Manage billing</a>
{% else %}
<p>You're <b>not</b> currently a supporter! No pressure, but it helps us do some pretty cool things! As a supporter, you'll get:</p>
<a data-tab-button="account/blocks" href="#/account/blocks">
{{ icon "shield" }}
<span>{{ text "settings:tab.blocks" }}</span>
</a>
<ul style="margin-bottom: 1rem">
<li>Vanity badge on profile</li>
<li>Ability to upload gif avatars/banners</li>
<li>Be an admin/owner of up to 10 communities</li>
<li>Use custom CSS on your profile</li>
<li>Ability to use community emojis outside of their community <b>(soon)</b></li>
<li>Ability to upload and use gif emojis <b>(soon)</b></li>
<li><b>Create infinite stack timelines</b></li>
</ul>
<a href="{{ config.stripe.payment_link }}?client_reference_id={{ user.id }}" class="button" target="_blank">Become a supporter</a>
<span class="fade">Please use your <b>real email</b> when completing payment. It is required to manage your billing settings.</span>
{% endif %}
</div>
{% if config.stripe %}
<a data-tab-button="account/billing" href="#/account/billing">
{{ icon "credit-card" }}
<span>{{ text "settings:tab.billing" }}</span>
</a>
{% endif %}
</div>
{% endif %}
<div class="card-nest" ui_ident="home_timeline">
<div class="card small">
@ -153,62 +141,22 @@
<div class="card flex flex-col gap-2">
<button id="notifications_button"></button>
<span class="fade">Notifications require you to keep {{ config.name }} open in your browser for real-time updates. This setting does not sync across browsers.</span>
<span class="fade"
>Notifications require you to keep {{ config.name }}
open in your browser for real-time updates. This setting
does not sync across browsers.</span
>
</div>
</div>
<script>
setTimeout(() => {
trigger("me::notifications_button", [document.getElementById("notifications_button")]);
}, 150)
trigger("me::notifications_button", [
document.getElementById("notifications_button"),
]);
}, 150);
</script>
<div class="card-nest" ui_ident="change_password">
<div class="card small">
<b>{{ text "settings:label.change_password" }}</b>
</div>
<form
class="card flex flex-col gap-2"
onsubmit="change_password(event)"
>
<div class="flex flex-col gap-1">
<label for="current_password"
>{{ text "settings:label.current_password" }}</label
>
<input
type="password"
name="current_password"
id="current_password"
placeholder="current_password"
required
minlength="6"
autocomplete="off"
/>
</div>
<div class="flex flex-col gap-1">
<label for="new_password"
>{{ text "settings:label.new_password" }}</label
>
<input
type="password"
name="new_password"
id="new_password"
placeholder="new_password"
required
minlength="6"
autocomplete="off"
/>
</div>
<button class="primary">
{{ icon "check" }}
<span>{{ text "general:action.save" }}</span>
</button>
</form>
</div>
<div class="card-nest" ui_ident="change_username">
<div class="card small">
<b>{{ text "settings:label.change_username" }}</b>
@ -238,63 +186,9 @@
</button>
</form>
</div>
<div class="card-nest" ui_ident="two_factor_authentication">
<div class="card small">
<b>{{ text "settings:label.two_factor_authentication" }}</b>
</div>
<div class="card flex flex-col gap-2">
{% if profile.totp|length == 0 %}
<div id="totp_stuff" style="display: none">
<span
>Scan this QR code in a TOTP authenticator app (like
Google Authenticator):
</span>
<img id="totp_qr" style="max-width: 250px" />
<span>TOTP secret (do NOT share):</span>
<pre id="totp_secret"></pre>
<span
>Recovery codes (STORE SAFELY, these can only be
viewed once):</span
>
<pre id="totp_recovery_codes"></pre>
</div>
<button
class="quaternary green"
onclick="enable_totp(event)"
>
Enable TOTP 2FA
</button>
{% else %}
<pre id="totp_recovery_codes" style="display: none"></pre>
<div class="flex gap-2 flex-wrap">
<button
class="quaternary red"
onclick="refresh_totp_codes(event)"
>
Refresh recovery codes
</button>
<button
class="quaternary red"
onclick="disable_totp(event)"
>
Disable TOTP 2FA
</button>
</div>
{% endif %}
</div>
</div>
</div>
<div class="card-nest" ui_ident="change_password">
<div class="card-nest" ui_ident="delete_account">
<div class="card small flex items-center gap-2 red">
{{ icon "skull" }}
<b>{{ text "settings:label.delete_account" }}</b>
@ -332,8 +226,262 @@
</button>
</div>
<div class="w-full flex flex-col gap-2" data-tab="account/security">
<div class="card tertiary flex flex-col gap-2">
<a href="#/account" class="button secondary">
{{ icon "arrow-left" }}
<span>{{ text "general:action.back" }}</span>
</a>
<div class="card-nest">
<div class="card flex items-center gap-2 small">
{{ icon "user-lock" }}
<span>{{ text "settings:tab.security" }}</span>
</div>
<div class="card flex flex-col gap-2 secondary">
<div class="card-nest" ui_ident="two_factor_authentication">
<div class="card small">
<b
>{{ text
"settings:label.two_factor_authentication" }}</b
>
</div>
<div class="card flex flex-col gap-2">
{% if profile.totp|length == 0 %}
<div id="totp_stuff" style="display: none">
<span
>Scan this QR code in a TOTP authenticator
app (like Google Authenticator):
</span>
<img id="totp_qr" style="max-width: 250px" />
<span>TOTP secret (do NOT share):</span>
<pre id="totp_secret"></pre>
<span
>Recovery codes (STORE SAFELY, these can
only be viewed once):</span
>
<pre id="totp_recovery_codes"></pre>
</div>
<button
class="quaternary green"
onclick="enable_totp(event)"
>
Enable TOTP 2FA
</button>
{% else %}
<pre
id="totp_recovery_codes"
style="display: none"
></pre>
<div class="flex gap-2 flex-wrap">
<button
class="quaternary red"
onclick="refresh_totp_codes(event)"
>
Refresh recovery codes
</button>
<button
class="quaternary red"
onclick="disable_totp(event)"
>
Disable TOTP 2FA
</button>
</div>
{% endif %}
</div>
</div>
<div class="card-nest" ui_ident="change_password">
<div class="card small">
<b>{{ text "settings:label.change_password" }}</b>
</div>
<form
class="card flex flex-col gap-2"
onsubmit="change_password(event)"
>
<div class="flex flex-col gap-1">
<label for="current_password"
>{{ text "settings:label.current_password"
}}</label
>
<input
type="password"
name="current_password"
id="current_password"
placeholder="current_password"
required
minlength="6"
autocomplete="off"
/>
</div>
<div class="flex flex-col gap-1">
<label for="new_password"
>{{ text "settings:label.new_password"
}}</label
>
<input
type="password"
name="new_password"
id="new_password"
placeholder="new_password"
required
minlength="6"
autocomplete="off"
/>
</div>
<button class="primary">
{{ icon "check" }}
<span>{{ text "general:action.save" }}</span>
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="w-full flex flex-col gap-2" data-tab="account/blocks">
<div class="card tertiary flex flex-col gap-2">
<a href="#/account" class="button secondary">
{{ icon "arrow-left" }}
<span>{{ text "general:action.back" }}</span>
</a>
<div class="card-nest">
<div class="card flex items-center gap-2 small">
{{ icon "users-round" }}
<span>{{ text "settings:label.users" }}</span>
</div>
<div class="card flex flex-col gap-2">
{% for user in blocks %}
<div
class="card secondary flex flex-wrap gap-2 items-center justify-between"
>
<div class="flex gap-2">
{{ components::avatar(username=user.username) }} {{
components::full_username(user=user) }}
</div>
<a
href="/@{{ user.username }}"
class="button quaternary small"
>
{{ icon "external-link" }}
<span
>{{ text "requests:action.view_profile" }}</span
>
</a>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="w-full flex flex-col gap-2" data-tab="account/billing">
<div class="card tertiary flex flex-col gap-2">
<a href="#/account" class="button secondary">
{{ icon "arrow-left" }}
<span>{{ text "general:action.back" }}</span>
</a>
<div class="card-nest">
<div class="card flex items-center gap-2 small">
{{ icon "credit-card" }}
<span>{{ text "settings:tab.billing" }}</span>
</div>
<div class="card flex flex-col gap-2 secondary">
{% if config.stripe %}
<div class="card-nest" ui_ident="supporter_card">
<div class="card small flex items-center gap-2">
{{ icon "star" }}
<b>Supporter status</b>
</div>
<div class="card flex flex-col gap-2">
{% if is_supporter %}
<p>
You <b>are</b> a supporter! Thank you for all
that you do. You can manage your billing
information below.
<b
>Please use your email address you supplied
when paying to login to the billing
portal.</b
>
</p>
<a
href="{{ config.stripe.billing_portal_url }}"
class="button quaternary"
target="_blank"
>Manage billing</a
>
{% else %}
<p>
You're <b>not</b> currently a supporter! No
pressure, but it helps us do some pretty cool
things! As a supporter, you'll get:
</p>
<ul style="margin-bottom: 1rem">
<li>Vanity badge on profile</li>
<li>No more supporter ads (duh)</li>
<li>Ability to upload gif avatars/banners</li>
<li>
Be an admin/owner of up to 10 communities
</li>
<li>Use custom CSS on your profile</li>
<li>
Ability to use community emojis outside of
their community <b>(soon)</b>
</li>
<li>
Ability to upload and use gif emojis
<b>(soon)</b>
</li>
<li>Create infinite stack timelines</li>
</ul>
<a
href="{{ config.stripe.payment_link }}?client_reference_id={{ user.id }}"
class="button"
target="_blank"
>Become a supporter</a
>
<span class="fade"
>Please use your <b>real email</b> when
completing payment. It is required to manage
your billing settings.</span
>
{% endif %}
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<div class="w-full hidden flex flex-col gap-2" data-tab="profile">
<div class="card tertiary flex flex-col gap-2" id="profile_settings">
{{ components::supporter_ad(body="Become a supporter to upload GIF
images!") }}
<div class="card-nest" ui_ident="change_avatar">
<div class="card small">
<b>{{ text "settings:label.change_avatar" }}</b>
@ -358,7 +506,9 @@
</div>
<span class="fade"
>Images must be less than 8 MB large. Animated GIFs are only supported for supporter users. GIFs can be at most 2 MB large.</span
>Images must be less than 8 MB large. Animated GIFs are
only supported for supporter users. GIFs can be at most
2 MB large.</span
>
</form>
</div>
@ -477,6 +627,9 @@
</button>
</div>
{{ components::supporter_ad(body="Become a supporter to add custom
CSS!") }}
<div class="card-nest" ui_ident="theme_preference">
<div class="card small">
<b>Theme preference</b>
@ -607,9 +760,9 @@
</button>
<label for="{{ key }}-shown" class="flex items-center gap-2">
<!-- prettier-ignore -->
<input
type="checkbox"
<!-- prettier-ignore -->
{% if value[0].show_on_profile %}checked{% endif %}
id="{{ key }}-shown"
onchange="trigger('connections::push_con_shown', ['{{ key }}', event.target.checked])"
@ -933,18 +1086,20 @@
const theme_settings = document.getElementById("theme_settings");
ui.refresh_container(account_settings, [
"supporter_card",
"supporter_ad",
"account_settings_tabs",
"home_timeline",
"notifications",
"change_password",
"change_username",
"two_factor_authentication",
"delete_account",
]);
ui.refresh_container(profile_settings, [
"supporter_ad",
"change_avatar",
"change_banner",
]);
ui.refresh_container(theme_settings, [
"supporter_ad",
"awful_contrast",
"import_export",
"theme_preference",
@ -964,11 +1119,7 @@
settings.biography,
"textarea",
],
[
["status", "Status"],
settings.status,
"textarea",
],
[["status", "Status"], settings.status, "textarea"],
[
["warning", "Profile warning"],
settings.warning,