settings: rework settings frontend

master
justcool393 2022-11-06 01:35:49 -05:00
parent 68bd20a1f9
commit 6e0fd23ba3
12 changed files with 759 additions and 909 deletions

View File

@ -1086,6 +1086,7 @@ input[type=submit].btn-follow, input[type=reset].btn-follow, input[type=button].
margin-bottom: 0;
list-style: none;
}
nav
{

View File

@ -365,7 +365,8 @@ def serviceworker():
def settings_security(v):
return render_template("settings_security.html",
v=v,
mfa_secret=pyotp.random_base32() if not v.mfa_secret else None
mfa_secret=pyotp.random_base32() if not v.mfa_secret else None,
now=int(time.time())
)

View File

@ -8,12 +8,9 @@
{{html_head.html_head(true, false, true, none, "Settings", "", "", false)}}
<body id="settings" {% if SITE_NAME == 'rDrama' and v and (v.is_banned or v.agendaposter) %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/anime/1.webp?v=3) center center fixed; background-color: var(--background)"{% elif v and v.background %}style="overflow-x: hidden;background:url(/assets/images/backgrounds/{{v.background}}?v=3) center center fixed; background-color: var(--background){% if 'anime' not in v.background %};background-size: cover{% endif %}"{% endif %}>
{% include "header.html" %}
<div class="container">
<div class="row justify-content-around">
<div class="col h-100">
{% if error %}
@ -40,72 +37,31 @@
{% endif %}
<div class="mt-3">
<h1 class="d-mob-none">Settings</h1>
<h3 class="mt-5 d-md-none">Settings</h3>
</div>
<div class="flex-row bg-white box-shadow-bottom sticky d-none d-sm-flex mt-3 mb-3 mb-sm-5">
<nav>
<ul class="nav settings-nav">
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/profile' %} active{% endif %}" href="/settings/profile">Profile</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/content' %} active{% endif %}" href="/settings/content">Content</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/css' %} active{% endif %}" href="/settings/css">Custom CSS</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/profilecss' %} active{% endif %}" href="/settings/profilecss">Profile CSS</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/security' %} active{% endif %}" href="/settings/security">Security</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/blocks' %} active{% endif %}" href="/settings/blocks">Block users</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/apps' %} active{% endif %}" href="/settings/apps">Apps</a>
</li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/personal' %} active{% endif %}" href="/settings/personal">Personal</a></li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/advanced' %} active{% endif %}" href="/settings/advanced">Advanced Settings</a></li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/css' %} active{% endif %}" href="/settings/css">CSS</a></li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/security' %} active{% endif %}" href="/settings/security">Security</a></li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/apps' %} active{% endif %}" href="/settings/apps">Apps/Bots</a></li>
</ul>
</nav>
</div>
<div class="flex-row bg-white box-shadow-bottom sticky justify-content-center d-flex d-sm-none mt-3 mb-3 mb-sm-5">
<nav>
<ul class="nav settings-nav">
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/profile' %} active{% endif %} navsettings" href="/settings/profile"><i class="fas fa-cog text-base mr-0"></i></a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/content' %} active{% endif %} navsettings" href="/settings/content"><i class="fas fa-filter text-base mr-0"></i></a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/css' %} active{% endif %} navsettings" href="/settings/css"><i class="fas fa-palette text-base mr-0"></i></a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/profilecss' %} active{% endif %} navsettings" href="/settings/profilecss"><i class="fas fa-palette text-base mr-0"></i></a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/security' %} active{% endif %} navsettings" href="/settings/security"><i class="fas fa-lock-alt text-base mr-0"></i></a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/blocks' %} active{% endif %} navsettings" href="/settings/blocks"><i class="fas fa-user-minus text-base mr-0"></i></a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path=='/settings/apps' %} active{% endif %} navsettings" href="/settings/apps"><i class="fas fa-code text-base mr-0"></i></a>
</li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/personal' %} active{% endif %} navsettings" href="/settings/personal"><i class="fas fa-cog text-base mr-0"></i></a></li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/advanced' %} active{% endif %} navsettings" href="/settings/advanced"><i class="fas fa-filter text-base mr-0"></i></a></li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/css' %} active{% endif %} navsettings" href="/settings/css"><i class="fas fa-palette text-base mr-0"></i></a></li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/security' %} active{% endif %} navsettings" href="/settings/security"><i class="fas fa-lock-alt text-base mr-0"></i></a></li>
<li class="nav-item"><a class="nav-link{% if request.path=='/settings/apps' %} active{% endif %} navsettings" href="/settings/apps"><i class="fas fa-code text-base mr-0"></i></a></li>
</ul>
</nav>
</div>
{% block content %}
{% endblock %}
</div>
@ -180,8 +136,6 @@
</div>
</div>
{% endif %}
{% block clipboard %}
<div class="toast clipboard" id="toast-success" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body text-center">
@ -189,8 +143,6 @@
</div>
</div>
{% endblock %}
<div class="toast" id="toast-post-success" style="position: fixed; bottom: 1.5rem; margin: 0 auto; left: 0; right: 0; width: 275px; z-index: 1000" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body bg-success text-center text-white">
<i class="fas fa-comment-alt-smile mr-2"></i><span id="toast-post-success-text">Action successful!</span>
@ -201,13 +153,7 @@
<i class="fas fa-exclamation-circle mr-2"></i><span id="toast-post-error-text">Error, please try again later.</span>
</div>
</div>
{% block onload %}{% endblock %}
<script defer src="{{'js/clipboard.js' | asset}}"></script>
</body>
</html>

View File

@ -0,0 +1,159 @@
{% extends "settings.html" %}
{% block pagetitle %}Advanced Settings - {{SITE_NAME}}{% endblock %}
{% block content %}
{% import 'settings_common.html' as common with context %}
<div class="row settings-page" id="settings-page-advanced">
<div class="col col-lg-8">
<div class="settings">
{# toggle_section(title, id, name, flag, below_text) #}
<section id="site-settings-poorcel-mode-section" class="settings-section-section"> {# note: not using the thing from common just because of how much stuff there is in here #}
<h5>Poor Mode</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="poor">Poor Mode</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="poor" name="poor"{% if v.poor %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?poor='+document.getElementById('poor').checked);">
<label class="custom-control-label" for="poor"></label>
</div>
<span class="text-small text-muted">Makes the site faster for low-end devices:</span>
<ul>
<li><small>Disables the effects of cosmetic awards.</small></li>
<li><small>Hides signatures.</small></li>
<li><small>Makes emoji search only start when you press Enter.</small></li>
<li><small>Disables UI animations.</small></li>
</ul>
</div>
</div>
</div>
</section>
<section id="site-settings-frontpage-size-section" class="settings-section-section">
<h5>Frontpage Size</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="frontsize">Frontpage Size</label>
</div>
<div class="body w-lg-100">
<p>Change how many posts appear on every page.</p>
<div class="input-group mb2">
<select autocomplete="off" id='frontsize' class="form-control" form="profile-settings" name="frontsize" onchange="postToastSwitch(this,'/settings/profile?frontsize='+document.getElementById('frontsize').value)">
{% for entry in [15, 25, 50, 100] %}
<option value="{{entry}}"{{' selected' if v.frontsize==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
</section>
<section id="site-settings-sort-time-filter-section" class="settings-section-section">
<h5>Default Sorting and Time Filter</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="defaultsortingcomments">Default Sorting for Comments</label>
</div>
<div class="body w-lg-100">
<p>Change the default sorting for comments.</p>
<div class="input-group mb2">
<select autocomplete="off" id='defaultsortingcomments' class="form-control" form="profile-settings" name="defaultsortingcomments" onchange="postToastSwitch(this,'/settings/profile?defaultsortingcomments='+document.getElementById('defaultsortingcomments').value)">
{% for entry in ["new", "old", "top", "hot", "bottom", "controversial"] %}
<option value="{{entry}}"{{' selected' if v.defaultsortingcomments==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="defaultsorting">Default Sorting for Posts</label>
</div>
<div class="body w-lg-100">
<p>Change the default sorting for posts.</p>
<div class="input-group mb2">
<select autocomplete="off" id='defaultsorting' class="form-control" form="profile-settings" name="defaultsorting" onchange="postToastSwitch(this,'/settings/profile?defaultsorting='+document.getElementById('defaultsorting').value)">
{% for entry in ["hot", "bump", "new", "old", "top", "bottom", "controversial", "comments"] %}
<option value="{{entry}}"{{' selected' if v.defaultsorting==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="defaulttime">Default Time Filter for Posts</label>
</div>
<div class="body w-lg-100">
<p>Change the default time filter for posts.</p>
<div class="input-group mb2">
<select autocomplete="off" id='defaulttime' class="form-control" form="profile-settings" name="defaulttime" onchange="postToastSwitch(this,'/settings/profile?defaulttime='+document.getElementById('defaulttime').value)">
{% for entry in ["hour", "day", "week", "month", "year", "all"] %}
<option value="{{entry}}"{{' selected' if v.defaulttime==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
</section>
<section id="site-settings-tab-behavior-section" class="settings-section-section">
<h5>Tab Behavior</h5>
<div class="settings-section rounded">
{{common.toggle_section("Open Internal Links In New Tabs", "newtab", "newtab", v.newtab, "Enable if you would like to automatically open links to other pages on the site in new tabs.")}}
{{common.toggle_section("Open External Links In New Tabs", "newtabexternal", "newtabexternal", v.newtabexternal, "Enable if you would like to automatically open links to other sites in new tabs.")}}
</div>
</section>
<section id="site-settings-external-services-section" class="settings-section-section">
<h5>External Services</h5>
<div class="settings-section rounded">
{{common.toggle_section("Use Nitter for Twitter Links", "nitter", "nitter", v.nitter, "Enable if you would like to automatically convert twitter.com links to nitter.lacontrevoie.fr links.")}}
{{common.toggle_section("Use Imginn for Instagram Links", "imginn", "imginn", v.imginn, "Enable if you would like to automatically convert instagram.com links to imginn.com links.")}}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="reddit">Reddit Domain</label>
</div>
<div class="body w-lg-100">
<p>Change the domain you would like to view reddit posts in.</p>
<div class="input-group mb2">
<select autocomplete="off" id='reddit' class="form-control" form="profile-settings" name="reddit" onchange="postToastSwitch(this,'/settings/profile?reddit='+document.getElementById('reddit').value)">
{% for entry in ['old.reddit.com', 'reddit.com', 'i.reddit.com', 'unddit.com', 'teddit.net', 'libredd.it'] %}
<option value="{{entry}}"{{' selected' if v.reddit==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
{{common.toggle_section("Sort Redit Links by Controversial", "controversial", "controversial", v.controversial, "Enable if you would like to automatically sort reddit.com links by controversial.")}}
</div>
</section>
<section id="site-settings-content-filters" class="settings-section-section">
<h5>Content Filters</h5>
<div class="settings-section rounded">
{{common.toggle_section('Disable Signatures', 'sigs_disabled', 'sigs_disabled', v.sigs_disabled, 'Hide user signatures.')}}
{{common.toggle_section('Disable +18 Warnings', 'over18', 'over18', v.over18, "Enable if you would like to not get a warning before viewing +18 content.")}}
{{common.toggle_section('Hide Posts Voted On', 'hidevotedon', 'hidevotedon', v.hidevotedon), 'Enable if you would like to automatically hide posts you have voted on from your frontpage.'}}
<div class="body w-lg-100">
<form id="custom-filter" action="/settings/filters" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<small>Hides matching posts from the frontpage and collapses matching comments.</small>
<textarea autocomplete="off" class="form-control rounded" id="filters-text" aria-label="With textarea"
placeholder="Add your own custom content filters."
rows="3" name="filters" form="custom-filter" maxlength="1000">{% if v.custom_filter_list %}{{v.custom_filter_list}}{% endif %}</textarea>
<div class="d-flex">
<small>Use a new line for each filter entry. Limit of 1000 characters.</small>
<input autocomplete="off" class="btn btn-primary ml-auto" id="bioSave" type="submit" onclick="disable(this)" value="Save Changes">
</div>
</form>
</div>
</div>
</section>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,10 +1,5 @@
{% extends "settings.html" %}
{% block title %}
<title>{{SITE_NAME}} - FAQ</title>
{% endblock %}
{% block pagetitle %}<title>Apps/Bots - {{SITE_NAME}}</title>{% endblock %}
{% block content %}
<div class="row">
<div class="col col-lg-8">
@ -12,16 +7,13 @@
<h5><a href="/api">API Guide</a></h5>
<h5 class="mt-1">Your API Applications</h5>
{% for app in v.applications if app.client_id %}
<form id="edit-app-{{app.id}}" action="/edit_app/{{app.id}}" method="post">
<div class="settings-section rounded">
<div class="d-lg-flex">
<div class="title w-lg-25">
<label for="over18">{{app.app_name}}</label>
<label for="name-{{app.id}}">{{app.app_name}}</label>
</div>
<div class="body w-lg-100">
<input type="hidden" name="formkey" value="{{v.formkey}}">
@ -46,21 +38,18 @@
</div>
</div>
</div>
</form>
{% else %}
<p>None</p>
{% endfor %}
<h5>API Applications Awaiting Approval</h5>
{% for app in v.applications if not app.client_id %}
<form id="edit-app-{{app.id}}" action="/edit_app/{{app.id}}" method="post">
<div class="settings-section rounded">
<div class="d-lg-flex">
<div class="title w-lg-25">
<label for="over18">{{app.app_name}}</label>
<label for="name-{{app.id}}">{{app.app_name}}</label>
</div>
<div class="body w-lg-100">
<input type="hidden" name="formkey" value="{{v.formkey}}">
@ -84,20 +73,17 @@
</div>
</div>
</div>
</form>
{% else %}
<p>None</p>
{% endfor %}
<h5>Your Authorized Applications</h5>
{% for auth in v.authorizations %}
<div id="auth-{{auth.id}}" class="settings-section rounded">
<div class="d-lg-flex">
<div class="title w-lg-25">
<label for="over18">{{auth.application.app_name}}</label>
<label for="name-{{app.id}}">{{auth.application.app_name}}</label>
</div>
<div class="body w-lg-100">
<input type="hidden" name="formkey" value="{{v.formkey}}">
@ -143,8 +129,6 @@
</div>
</div>
{% endblock %}
{% block clipboard %}
<div class="toast clipboard" id="toast-success" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body text-center">

View File

@ -1,116 +0,0 @@
{% extends "settings.html" %}
{% block pagetitle %}Block Settings - {{SITE_NAME}}{% endblock %}
{% block content %}
<div class="row">
<div class="col">
{% if error %}
<div class="alert alert-danger alert-dismissible fade show my-3" role="alert">
<i class="fas fa-exclamation-circle my-auto"></i>
<span>
{{error}}
</span>
<button type="button" class="close" data-bs-dismiss="alert" aria-label="Close">
<span aria-hidden="true"><i class="far fa-times"></i></span>
</button>
</div>
{% endif %}
</div>
</div>
<div class="row">
<div class="col">
<div class="d-md-flex justify-content-between mb-3">
<div>
<h5>Users you block</h5>
<p class="text-small text-muted mb-md-0">You have blocked the following users. They cannot reply to your content or notify you with a username mention.</p>
</div>
<div class="mt-auto">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#blockmodal">Block user</button>
</div>
</div>
{% if v.blocking.first() %}
<div class="card mb-5">
<div class="overflow-x-auto"><table class="table table-hover rounded mb-0">
<thead class="thead-dark">
<tr>
<th scope="col">User</th>
<th scope="col">Unblock</th>
</tr>
</thead>
<tbody class="text-muted">
{% for block in v.blocking %}
{% set user=block.target %}
<tr>
<td>
{% include "user_in_table.html" %}
</td>
<td>
<button type="button" class="btn btn-primary" onclick="postToastSwitch(this,'/settings/unblock?username={{user.username}}&formkey={{v.formkey}}')">
Unblock
</button>
</td>
</tr>
{% else %}
<td>There are no blocked users</td>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center border-md rounded py-7">
<i class="fas fa-ghost text-gray-500 mb-3" style="font-size: 3.5rem;"></i>
<p class="font-weight-bold text-gray-500 mb-0">No blocked users</p>
</div>
{% endif %}
</div>
</div>
<div class="modal fade" id="blockmodal" tabindex="-1" role="dialog" aria-labelledby="blockmodal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<form class="m-auto" action="/settings/block" id="exile-form" method="post" onsubmit="return false;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Block users</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true"><i class="far fa-times"></i></span>
</button>
</div>
<div class="modal-body">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input autocomplete="off" type="text" name="username" placeholder="Enter username..." id="exile-username" class="form-control" maxlength=25 required>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-link text-muted" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="exileUserButton" onclick="block_user()">Block user</button>
</div>
</div>
</form>
</div>
</div>
<div class="toast error" id="toast-exile-error" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body text-center">
<i class="fas fa-exclamation-circle text-danger mr-2"></i><span id="toast-error-message">Error. Please try again.</span>
</div>
</div>
<script defer src="{{'js/settings_blocks.js' | asset}}"></script>
{% endblock %}

View File

@ -0,0 +1,16 @@
{% macro toggle_section(title, id, name, flag, below_text) %}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="{{id}}">{{title}}</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="{{id}}" name="{{name}}"{% if flag %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?{{name}}='+document.getElementById('{{id}}').checked)">
<label class="custom-control-label" for="{{id}}"></label>
</div>
{% if below_text %}
<span class="text-small text-muted">{{below_text}}</span>
{% endif %}
</div>
</div>
{% endmacro %}

View File

@ -1,21 +1,12 @@
{% extends "settings.html" %}
{% block pagetitle %}Custom CSS - {{SITE_NAME}}{% endblock %}
{% block content %}
<div class="row">
<div class="col col-md-8">
<div class="settings">
<div id="description">
<p class="text-small text-muted">Edit your custom CSS for the site.</p>
<div class="settings-section rounded mb-0">
<div class="settings col col-md-8">
<section>
<h5>Custom CSS</h5>
<div id="settings-custom-css" class="settings-section rounded mb-0">
<p class="text-small text-muted">Edit your custom CSS for the site</p>
<div class="body d-lg-flex border-bottom">
<div class="w-lg-100">
<form id="profile-settings" action="/settings/css" method="post">
@ -27,15 +18,27 @@
</div>
</form>
</div>
</div>
</div>
</section>
<section>
<h5>Profile CSS</h5>
<div id="settings-profile-css" class="settings-section rounded mb-0">
<p class="text-small text-muted">Edit your profile CSS</p>
<div class="body d-lg-flex border-bottom">
<div class="w-lg-100">
<form id="profile-settings" action="/settings/profilecss" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<textarea autocomplete="off" class="form-control rounded" id="bio-text" aria-label="With textarea" placeholder="Custom profile css" rows="50" name="profilecss" form="profile-settings" maxlength="4000">{% if v.profilecss %}{{v.profilecss}}{% endif %}</textarea>
<small>Limit of 4000 characters</small>
<div class="d-flex mt-2">
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" onclick="disable(this)" value="Save">
</div>
</form>
</div>
</div>
</div>
</section>
</div>
</div>
{% endblock %}

View File

@ -1,366 +0,0 @@
{% extends "settings.html" %}
{% block pagetitle %}Content Settings - {{SITE_NAME}}{% endblock %}
{% block content %}
<div class="row">
<div class="col col-lg-8">
<div class="settings">
<h5 name="referral">Poor Mode</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="poor">Poor Mode</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="poor" name="poor"{% if v.poor %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?poor='+document.getElementById('poor').checked);">
<label class="custom-control-label" for="poor"></label>
</div>
<span class="text-small text-muted">Makes the site faster for low-end devices:</span>
<ul>
<li><small>Disables the effects of cosmetic awards.</small></li>
<li><small>Hides signatures.</small></li>
<li><small>Makes emoji search only start when you press Enter.</small></li>
<li><small>Disables UI animations.</small></li>
</ul>
</div>
</div>
</div>
<h5 name="referral">Frontpage Size</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="frontsize">Frontpage Size</label>
</div>
<div class="body w-lg-100">
<p>Change how many posts appear on every page.</p>
<div class="input-group mb2">
<select autocomplete="off" id='frontsize' class="form-control" form="profile-settings" name="frontsize" onchange="postToastSwitch(this,'/settings/profile?frontsize='+document.getElementById('frontsize').value)">
{% for entry in [15, 25, 50, 100] %}
<option value="{{entry}}"{{' selected' if v.frontsize==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
<h5 name="referral">Default Sorting and Time Filter</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="defaultsortingcomments">Default Sorting for Comments</label>
</div>
<div class="body w-lg-100">
<p>Change the default sorting for comments.</p>
<div class="input-group mb2">
<select autocomplete="off" id='defaultsortingcomments' class="form-control" form="profile-settings" name="defaultsortingcomments" onchange="postToastSwitch(this,'/settings/profile?defaultsortingcomments='+document.getElementById('defaultsortingcomments').value)">
{% for entry in ["new", "old", "top", "hot", "bottom", "controversial"] %}
<option value="{{entry}}"{{' selected' if v.defaultsortingcomments==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="defaultsorting">Default Sorting for Posts</label>
</div>
<div class="body w-lg-100">
<p>Change the default sorting for posts.</p>
<div class="input-group mb2">
<select autocomplete="off" id='defaultsorting' class="form-control" form="profile-settings" name="defaultsorting" onchange="postToastSwitch(this,'/settings/profile?defaultsorting='+document.getElementById('defaultsorting').value)">
{% for entry in ["hot", "bump", "new", "old", "top", "bottom", "controversial", "comments"] %}
<option value="{{entry}}"{{' selected' if v.defaultsorting==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="defaulttime">Default Time Filter for Posts</label>
</div>
<div class="body w-lg-100">
<p>Change the default time filter for posts.</p>
<div class="input-group mb2">
<select autocomplete="off" id='defaulttime' class="form-control" form="profile-settings" name="defaulttime" onchange="postToastSwitch(this,'/settings/profile?defaulttime='+document.getElementById('defaulttime').value)">
{% for entry in ["hour", "day", "week", "month", "year", "all"] %}
<option value="{{entry}}"{{' selected' if v.defaulttime==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
</div>
<h5>Tab Behaviour</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="newtab">Open Internal Links In New Tabs</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="newtab" name="newtab"{% if v.newtab %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?newtab='+document.getElementById('newtab').checked);">
<label class="custom-control-label" for="newtab"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically open links to other pages on the site in new tabs.</span>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="newtabexternal">Open External Links In New Tabs</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="newtabexternal" name="newtabexternal"{% if v.newtabexternal %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?newtabexternal='+document.getElementById('newtabexternal').checked);">
<label class="custom-control-label" for="newtabexternal"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically open links to other sites in new tabs.</span>
</div>
</div>
</div>
<h5>Twitter Links</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="nitter">Use Nitter</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="nitter" name="nitter"{% if v.nitter %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?nitter='+document.getElementById('nitter').checked);">
<label class="custom-control-label" for="nitter"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically convert twitter.com links to nitter.lacontrevoie.fr links.</span>
</div>
</div>
</div>
<h5>Instagram Links</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="imginn">Use Imginn</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="imginn" name="imginn"{% if v.imginn %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?imginn='+document.getElementById('imginn').checked);">
<label class="custom-control-label" for="imginn"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically convert instagram.com links to imginn.com links.</span>
</div>
</div>
</div>
<h5>Reddit Links</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="reddit">Reddit Domain</label>
</div>
<div class="body w-lg-100">
<p>Change the domain you would like to view reddit posts in.</p>
<div class="input-group mb2">
<select autocomplete="off" id='reddit' class="form-control" form="profile-settings" name="reddit" onchange="postToastSwitch(this,'/settings/profile?reddit='+document.getElementById('reddit').value)">
{% for entry in ['old.reddit.com', 'reddit.com', 'i.reddit.com', 'unddit.com', 'teddit.net', 'libredd.it'] %}
<option value="{{entry}}"{{' selected' if v.reddit==entry}}>{{entry}}</option>
{% endfor %}
</select>
</div>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="controversial">Sort by Controversial</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="controversial" name="controversial"{% if v.controversial %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?controversial='+document.getElementById('controversial').checked);">
<label class="custom-control-label" for="controversial"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically sort reddit.com links by controversial.</span>
</div>
</div>
</div>
<h5>Content Filters</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="sigs_disabled">Disable signatures</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="sigs_disabled" name="sigs_disabled"{% if v.sigs_disabled %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?sigs_disabled='+document.getElementById('sigs_disabled').checked);">
<label class="custom-control-label" for="sigs_disabled"></label>
</div>
<span class="text-small text-muted">Hide user signatures.</span>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="over18">Disable +18 Warnings</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="over18" name="over18"{% if v.over_18 %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?over18='+document.getElementById('over18').checked);">
<label class="custom-control-label" for="over18"></label>
</div>
<span class="text-small text-muted">Enable if you would like to not get a warning before viewing +18 content.</span>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="slurreplacer">Slur Replacer</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="slurreplacer" name="slurreplacer"{% if v.slurreplacer %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?slurreplacer='+document.getElementById('slurreplacer').checked);">
<label class="custom-control-label" for="slurreplacer"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically replace slurs.</span>
</div>
</div>
{% if SITE_NAME == 'rDrama' %}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="profanityreplacer">Profanity Replacer</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="profanityreplacer" name="profanityreplacer"{% if v.profanityreplacer %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?profanityreplacer='+document.getElementById('profanityreplacer').checked);">
<label class="custom-control-label" for="profanityreplacer"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically replace profanities.</span>
</div>
</div>
{% endif %}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="hidevotedon">Hide Posts Voted On</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="hidevotedon" name="hidevotedon"{% if v.hidevotedon %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?hidevotedon='+document.getElementById('hidevotedon').checked);">
<label class="custom-control-label" for="hidevotedon"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically hide posts you have voted on from your frontpage.</span>
</div>
</div>
<div class="d-lg-flex">
<div class="title w-lg-25">
<label for="filters-text">Custom Filters</label>
</div>
<div class="body w-lg-100">
<form id="custom-filter" action="/settings/filters" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<small>Hides matching posts from the frontpage and collapses matching comments.</small>
<textarea autocomplete="off" class="form-control rounded" id="filters-text" aria-label="With textarea"
placeholder="Add your own custom content filters."
rows="3" name="filters" form="custom-filter" maxlength="1000">{% if v.custom_filter_list %}{{v.custom_filter_list}}{% endif %}</textarea>
<div class="d-flex">
<small>Use a new line for each filter entry. Limit of 1000 characters.</small>
<input autocomplete="off" class="btn btn-primary ml-auto" id="bioSave" type="submit" onclick="disable(this)" value="Save Changes">
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,304 @@
{% extends "settings.html" %}
{% block pagetitle %}Content Settings - {{SITE_NAME}}{% endblock %}
{% import 'settings_common.html' as common with context %}
{# common sections start #}
{% macro color_section(id, form_action, form_name, section_title, current_color) %}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="{{id}}">{{section_title}}</label>
</div>
<div class="d-flex">
<form action="{{form_action}}" id="{{id}}-form" method="post" class="color-picker" style="line-height: 0">
<input type="hidden" name="formkey" value="{{v.formkey}}">
{% for themecolor in COLORS %}
<input autocomplete="off" type="radio" name="themecolor" id="{{id}}-{{themecolor}}" value="{{themecolor}}" {% if current_color == themecolor %}checked{% endif %} onclick="document.getElementById('{{id}}-form').submit()">
<label class="color-radio" for="{{id}}-{{themecolor}}">
<span style="background-color: #{{themecolor}}">
{% if current_color.lower() == themecolor %}
<i class="fas fa-check text-white"></i>
{% else %}
&nbsp;
{% endif %}
</span>
</label>
{% endfor %}
</form>
</div>
<p class="text-small mb-2">Or type a color hex code:</p>
<div class="d-flex">
<form action="{{form_action}}" id="{{id}}-color-code-form" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input class="form-control" type="text" name="{{form_name}}" id="{{id}}-color-code" minlength="6" maxlength="6" value="{% if current_color %}{{current_color}}{% endif %}">
<label class="btn btn-secondary text-capitalize mr-2 mt-2 mb-0">Update<input type="text" for="{{id}}-color-code" onclick="form.submit()" hidden=""></label>
</form>
</div>
</div>
{% endmacro %}
{% macro line_text_section(id, form_action, form_name, section_title, contents, below_text, placeholder_text, button_text, show_marseys, minlength, maxlength, pattern, show_if) %}
{% if show_if -%}
<div class="body d-lg-flex border-bottom">
<label class="text-black w-lg-25">{{section_title}}</label>
<div class="w-lg-100">
<form id="{{id}}-form" action="/settings/pronouns_change" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input minlength=3 maxlength=11 pattern="{{pattern}}" autocomplete="off" id="{{id}}-body" type="text" name="{{form_name}}" class="form-control" placeholder='{{placeholder_text}}' value="{% if contents %}{{contents}}{% endif %}">
<div class="d-flex mt-2">
<small>{{below_text}}</small>
{% if show_marseys %}
<div role="button"><i class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('{{id}}-body')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></i></div>
{% endif %}
<input autocomplete="off" class="btn btn-primary ml-auto" id="{{id}}-save" type="submit" onclick="disable(this)" value="{{button_text}}">
</div>
</form>
</div>
</div>
{%- endif %}
{% endmacro %}
{% macro text_area_section(id, form_action, form_name, section_title, contents, below_text, placeholder_text, show_extras, show_file_upload, maxlength, show_if) %}
{% if show_if -%}
<div class="body d-lg-flex border-bottom">
<label class="text-black w-lg-25">{{section_title}}</label>
<div class="w-lg-100">
<form id="{{id}}-form" action="{{form_action}}" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<textarea autocomplete="off" id="{{id}}-text" class="form-control rounded" aria-label="With textarea" placeholder="{{placeholder_text}}" rows="3" name="bio" form="{{id}}-form" maxlength="{{maxlength}}">{% if contents %}{{contents}}{% endif %}</textarea>
{% if show_extras %}
<div class="d-flex">
<pre style="padding-top:0.7rem;line-height:1" class="btn btn-secondary format d-inline-block m-0 font-weight-bolder text-uppercase" onclick="commentForm('bio-text');getGif()" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#gifModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add GIF">GIF</pre>
&nbsp;
<pre style="padding-top:0.7rem" class="btn btn-secondary format d-inline-block m-0 fas fa-smile-beam" onclick="loadEmojis('bio-text')" aria-hidden="true" data-bs-toggle="modal" data-bs-target="#emojiModal" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Add Emoji"></pre>
&nbsp;
{% if show_file_upload and request.headers.get('cf-ipcountry') != "T1" %}
<label class="btn btn-secondary format d-inline-block m-0">
<div id="filename-show"><i class="fas fa-file"></i></div>
<input autocomplete="off" id="file-upload" accept="image/*, video/*, audio/*" type="file" name="file" multiple="multiple" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} onchange="changename('filename-show','file-upload')" hidden>
</label>
{% endif %}
</div>
{% endif %}
<div class="d-flex mt-1">
<small>{{below_text}}</small>
<input autocomplete="off" class="btn btn-primary ml-auto" id="bioSave" type="submit" onclick="disable(this)" value="Save Changes">
</div>
</form>
</div>
</div>
{%- endif %}
{% endmacro %}
{# common sections end #}
{% block content %}
<div class="row settings-page" id="settings-page-personal">
<div class="col col-lg-8">
<div class="settings">
<section id="site-settings-experience-section" class="settings-section-section">
<h5>Site Experience</h5>
<div class="settings-section rounded" id="site-settings-experience">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="paypig-status">Paypig Status</label>
</div>
<div class="body w-lg-100">
You are a {{v.patron}}. Example text until me carp and sneks figure out what to put here. Dude bussy lmao
</div>
</div>
{# theme #}
color_section(id, form_action, form_name, section_title, current_color)
{{color_section('theme-color', '/settings/themecolor', 'Theme Color', v.themecolor)}}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="background">Website Backgrounds</label>
</div>
<div class="body w-lg-100">
<p>Change the background for the website.</p>
<div class="input-group mb2">
<select autocomplete="off" id='backgroundSelector' class="form-control" form="profile-settings" name="background" onchange="updatebgselection();">
{% for entry in ["anime", "fantasy", "solarpunk", "pixelart"] %}
<option value="{{entry}}" {% if v.background and v.background.startswith(entry) %}selected{% endif %}>
{{entry}}
</option>
{% endfor %}
</select>
</div>
{% if v.background %}
<div class="d-flex mt-2">
<button type="button" class="btn btn-primary ml-auto mb-1" onclick="postToastReload(this,'/settings/removebackground')">Remove Background</button>
</div>
{% endif %}
<div id="bgcontainer"></div>
</div>
</div>
</div>
</section>
<section id="site-settings-aesthetic-section" class="settings-section-section">
<h5>Your Aesthetic</h5>
<div class="settings-section-rounded" id="site-settings-aesthetic">
{% if FEATURES['HOUSES'] %}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="theme">House</label>
</div>
<div class="body w-lg-100">
{% if v.house %}
{% set cost = HOUSE_SWITCH_COST %}
<p>Change your house (cost: {{cost}} coins or marseybux).</p>
{% if ' Founder' in v.house %}
<p>Warning: you'll lose your founder status if you join a different house</p>
{% endif %}
{% else %}
{% set cost = HOUSE_JOIN_COST %}
<p>Join a house (cost: {{cost}} coins or marseybux).</p>
{% endif %}
<div class="input-group mb2">
<select {% if v.coins < cost and v.procoins < cost or v.bite %}disabled{% endif %} autocomplete="off" id='house' class="form-control" form="profile-settings" name="house" onchange="postToastReload(this,'/settings/profile?house='+document.getElementById('house').value)">
{% for entry in ("None","Furry","Femboy","Vampire","Racist") %}
<option value="{{entry}}" {% if v.house == entry %} selected {% endif %}>
{{entry}}
</option>
{% endfor %}
</select>
</div>
</div>
</div>
{%- endif %}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25 text-md-center">
<img loading="lazy" alt="your profile picture" src="{{v.profile_url}}" class="profile-pic-75">
</div>
<div class="body w-lg-100 my-auto">
<div class="d-flex">
<div>
<form action="/settings/images/profile" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<label class="btn btn-secondary text-capitalize mr-2 mb-0">
Update<input autocomplete="off" type="file" accept="image/*" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} hidden name="profile" onchange="form.submit()">
</label>
</form>
</div>
</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.</div>
</div>
</div>
{% if FEATURES['USERS_PROFILE_BANNER'] -%}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-75 text-md-center">
<img loading="lazy" alt="your banner" src="{{v.banner_url}}" class="banner-pic-135">
</div>
<div class="body w-lg-100 my-auto">
<div class="d-flex">
<div>
<form action="/settings/images/banner" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<label class="btn btn-secondary text-capitalize mr-2 mb-0">
Update<input autocomplete="off" type="file" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} accept="image/*" hidden name="banner" onchange="form.submit()">
</label>
</form>
</div>
</div>
<div class="text-small text-muted mt-3">All image files are supported. Max file size is {% if v and v.patron %}16{% else %}8{% endif %} MB.</div>
</div>
</div>
{%- endif %}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="name">Username</label>
</div>
<div class="body w-lg-100">
<p>Your original username will always stay reserved for you: <code>{{v.original_username}}</code></p>
<form action="/settings/name_change" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input autocomplete="off" type="text" name="name" class="form-control" value="{{v.username}}">
<small>3-25 characters, including letters, numbers, _ , and -</small>
<div class="d-flex mt-2">
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" onclick="disable(this)" value="Change Display Name">
</div>
</form>
</div>
</div>
{{color_section('namecolor', '/settings/namecolor', 'Name Color', v.name_color)}}
{{line_text_section('pronouns', '/settings/pronouns_change', 'pronouns', 'Pronouns', v.pronouns, '{2-5 characters} / {2-5 characters}', 'Enter pronouns here', 'Change Pronouns', false, 3, 11, '([a-zA-Z]{1,5})/[a-zA-Z]{1,5}(/[a-zA-Z]{1,5})?', FEATURES['PRONOUNS'])}}
{# line_text_section(id, form_action, form_name, section_title, contents, below_text, placeholder_text, button_text, show_marseys, minlength, maxlength, pattern, show_if) #}
{{line_text_section('flair', '/settings/title_change', 'custom-flair', 'Flair', v.customtitleplain, 'Limit of 100 characters', 'Enter a flair here', 'Change Flair', true, 0, 100, '', true)}}
{{color_section('flaircolor', '/settings/titlecolor', 'Flair Color', v.titlecolor)}}
{% if v.verified %}
{{color_section('verifiedcolor', '/settings/verifiedcolor', 'Checkmark Color', v.verifiedcolor)}}
{{line_text_section('checkmark_text', '/settings/checkmark_text', 'checkmark-text', 'Checkmark Text', v.verified, 'Limit of 100 characters', 'Enter checkmark hover text here', 'Change Text', false, 0, 100, '', v.verified)}}
{% endif %}
{% if FEATURES['USERS_PROFILE_SONG'] -%}
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="anthem">Profile Anthem</label>
</div>
<div class="w-lg-100">
<p>You can use an MP3 file or a YouTube video.</p>
<form action="/settings/song_change_mp3" method="post" enctype="multipart/form-data">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<label class="btn btn-secondary format d-inline-block m-0 mb-3">
<div id="filename-show2"><i class="fas fa-file"></i>
{% if v.song and v.song|length in (1,2,3,4,5,17) %}
{{v.song}}.mp3
{% else %}
Use an MP3 file (Max size is 8MB)
{% endif %}
</div>
<input autocomplete="off" id="file-upload2" type="file" name="file" {% if request.headers.get('cf-ipcountry')=="T1" %}disabled{% endif %} accept="audio/mp3" onchange="this.form.submit()" hidden>
</label>
</form>
<form action="/settings/song_change" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input class="form-control" style="display:inline;max-width:75%;font-size: min(3.5vw,16px)!important" autocomplete="off" type="text" name="song" class="form-control" value="{% if v.song and v.song|length not in (1,2,3,4,5,17) %}https://youtu.be/{{v.song}}{% endif %}" placeholder='Enter a YouTube video link here'>
<input class="btn btn-primary" style="font-size: min(3.5vw,16px)!important" autocomplete="off" class="btn btn-primary ml-auto" type="submit" onclick="disable(this)" value="Submit">
</form>
<br><small>In some browsers, users have to click at least once anywhere in the profile page for the anthem to play.</small>
</div>
</div>
{%- endif %}
{{text_area_section('profile-bio', '/settings/profile', 'bio', 'Limit of 1500 characters', 'Tell the community a bit about yourself.', true, true, 1500, FEATURES['USERS_PROFILE_BODYTEXT'])}}
{{text_area_section('profile-friends', '/settings/profile', 'friends', 'Limit of 500 characters', 'Enter your friends on the site...', false, false, 500, true)}}
{{text_area_section('profile-enemies', '/settings/profile', 'enemies', 'Limit of 500 characters', 'Enter your enemies on the site...', false, false, 500, true)}}
{{text_area_section('profile-signature', '/settings/profile', 'sig', 'Limit of 200 characters', 'Enter a signature...', true, false, 200, v.patron or v.sig)}}
{# toggle_section(title, id, name, flag, below_text) #}
{{common.toggle_section('Private Mode', 'privateswitch', 'private', v.is_private, 'This will hide your post and comment history from others. We will also ask search engines to not index your profile page. (Your content will still be accessible via direct link.)')}}
{{common.toggle_section('Spider', 'spiderswitch', 'spider', v.spider, 'Have a spider friend accompany you during your journey on the site.')}}
</div>
</section>
<section id="site-settings-filters-section" class="settings-section-section">
<h5>Filters</h5>
<div class="settings-section rounded" id="site-settings-filters">
{# profanity filter toggle (and lock?) #}
{# slur filter toggle (and lock?) #}
</div>
</section>
<section id="site-settings-referral-section" class="settings-section-section">
<h5>Refer a Friend!</h5>
<div class="settings-section-rounded" id="site-settings-referral">
<div class="title w-lg-25">
<label for="referral_code">Referral code</label>
</div>
<div class="body w-lg-100">
<div class="input-group">
<input autocomplete="off" type="text" readonly="" class="form-control copy-link" id="referral_code" value="{{SITE_FULL}}/signup?ref={{v.username}}" data-clipboard-text="{{SITE_FULL}}/signup?ref={{v.username}}">
<span class="input-group-append" data-bs-toggle="tooltip" data-bs-placement="top" title="You have referred {{v.referral_count}} user{{'s' if v.referral_count != 1 else ''}} so far. {% if v.referral_count==0 %}¯\_(ツ)_/¯{% elif v.referral_count>10%}Wow!{% endif %}">
<span class="input-group-text text-primary border-0"><i class="far fa-user mr-1" aria-hidden="true"></i>{{v.referral_count}}</span>
</span>
</div>
<div class="text-small text-muted mt-3">Share this link with a friend. {% if v.referral_count==0 %} When they sign up, you'll get the bronze recruitment badge. <a href="/badges">Learn more.</a>{% elif v.referral_count<10 %} When you refer 10 friends, you'll receive the silver recruitment badge. <a href="/badges">Learn more.</a>{% elif v.referral_count<100 %} When you refer 100 friends, you'll receive the gold recruitment badge. <a href="/badges">Learn more</a>.{% endif %}</div>
</div>
</div>
</section>
</div>
</div>
</div>
{% include "emoji_modal.html" %}
{% include "gif_modal.html" %}
{% if v.flairchanged %}
<script>
const date = new Date({{v.flairchanged}}*1000).toString();
const text = ` - Your flair has been locked until ${date}`
document.getElementById('customtitlebody').value += text;
</script>
{% endif %}
<script defer src="{{'js/settings_profile.js' | asset}}"></script>
{% endblock %}

View File

@ -1,31 +0,0 @@
{% extends "settings.html" %}
{% block pagetitle %}Custom Profile CSS - {{SITE_NAME}}{% endblock %}
{% block content %}
<div class="row">
<div class="col col-md-8">
<div class="settings">
<div id="description">
<p class="text-small text-muted">Edit your profile CSS</p>
<div class="settings-section rounded mb-0">
<div class="body d-lg-flex border-bottom">
<div class="w-lg-100">
<form id="profile-settings" action="/settings/profilecss" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<textarea autocomplete="off" class="form-control rounded" id="bio-text" aria-label="With textarea" placeholder="Custom profile css" rows="50" name="profilecss" form="profile-settings" maxlength="4000">{% if v.profilecss %}{{v.profilecss}}{% endif %}</textarea>
<small>Limit of 4000 characters</small>
<div class="d-flex mt-2">
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" onclick="disable(this)" value="Save">
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -1,25 +1,16 @@
{% extends "settings.html" %}
{% block pagetitle %}Security Settings - {{SITE_NAME}}{% endblock %}
{% block content %}
<script defer src="{{'js/settings_security.js' | asset}}"></script>
<div class="row">
<div class="row settings-page" id="settings-page-security">
<div class="col col-lg-8">
<div class="settings">
<section id="site-settings-email-section" class="settings-section-section">
<h5>Email</h5>
<p class="text-small text-muted">Change the email address used to sign in to your account.</p>
<div class="settings-section rounded">
<form action="/settings/security" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="now" value="{{now}}">
<div class="body">
<div class="d-lg-flex">
<label for="new-email" class="w-lg-25">Email</label>
@ -72,210 +63,168 @@
</div>
</form>
</div>
</section>
<section id="site-settings-password-section" class="settings-section-section">
<h5>Password</h5>
<p class="text-small text-muted">Change your account password.</p>
<div class="settings-section rounded">
<form action="/settings/security" method="post">
<div class="body">
<div class="d-lg-flex">
<label for="old_password" class="mb-0 w-lg-25">Old Password</label>
<input autocomplete="off" class="form-control mb-2 w-lg-100" id="old_password"
aria-describedby="old_password" type="password" name="old_password"
required>
<input autocomplete="off" class="form-control mb-2 w-lg-100" id="old_password" aria-describedby="old_password" type="password" name="old_password" required>
</div>
<div class="d-lg-flex mt-5">
<label for="new_password" class="mb-0 w-lg-25">New Password</label>
<input autocomplete="off" class="form-control w-lg-100" id="new_password"
aria-describedby="new_password" type="password" name="new_password"
required>
<small id="passwordHelpChange"
class="form-text font-weight-bold text-muted d-none mt-1 w-lg-100">Minimum of 8
characters
required.</small>
<small id="passwordHelpChangeSuccess"
class="form-text font-weight-bold text-success d-none mt-1 w-lg-100">Your password
meets the
requirements.
</small>
<input autocomplete="off" class="form-control w-lg-100" id="new_password" aria-describedby="new_password" type="password" name="new_password" required>
<small id="passwordHelpChange" class="form-text font-weight-bold text-muted d-none mt-1 w-lg-100">Minimum of 8 characters required.</small>
<small id="passwordHelpChangeSuccess" class="form-text font-weight-bold text-success d-none mt-1 w-lg-100">Your password meets the requirements.</small>
</div>
<div class="d-lg-flex mt-4">
<label for="cnf_password" class="mb-0 w-lg-25">Confirm New Password</label>
<input autocomplete="off" class="form-control w-lg-100" id="cnf_password"
aria-describedby="cnf_password" type="password" name="cnf_password"
required>
<small id="passwordHelpCnf"
class="form-text font-weight-bold text-muted d-none mt-1 w-lg-100">Passwords do not
match.</small>
<small id="passwordHelpCnfSuccess"
class="form-text font-weight-bold text-success d-none mt-1 w-lg-100">Passwords match.
</small>
<input autocomplete="off" class="form-control w-lg-100" id="cnf_password" aria-describedby="cnf_password" type="password" name="cnf_password" required>
<small id="passwordHelpCnf" class="form-text font-weight-bold text-muted d-none mt-1 w-lg-100">Passwords do not match.</small>
<small id="passwordHelpCnfSuccess" class="form-text font-weight-bold text-success d-none mt-1 w-lg-100">Passwords match.</small>
</div>
</div>
<div class="footer">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<input type="hidden" name="now" value="1563891643">
<input type="hidden" name="now" value="{{now}}">
<div class="d-flex">
<input autocomplete="off" class="btn btn-primary ml-auto"
type="submit" onclick="disable(this)" value="Change Password">
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" onclick="disable(this)" value="Change Password">
</div>
</div>
</form>
</div>
</section>
<section id="site-settings-2fa-section" class="settings-section-section">
<h5>Two-Factor Authentication</h5>
<p class="text-small text-muted">Change the two-factor settings for your account.</p>
<div class="settings-section rounded">
<div class="d-lg-flex">
<div class="title w-lg-25">
<label for="2faToggle">Use 2-step login</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="2faToggle" name="2faToggle" onchange="twoStepModal.show()" {% if v.mfa_secret %}checked{% endif %}>
<label class="custom-control-label" for="2faToggle"></label>
</div>
<span class="text-small text-muted">This requires entering a randomly-generated, 6-digit code and your password to login.</span>
</div>
</div>
</div>
</section>
<section id="site-settings-logout-everywhere-section" class="settings-section-section">
<h5>Log Out Everywhere</h5>
<p class="text-small text-muted">Log all other devices out of your {{SITE_NAME}} account.</p>
<div class="settings-section rounded">
<form action="/settings/log_out_all_others" method="post">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<div class="body">
<div class="d-lg-flex">
<label for="forcelog-password" class="w-lg-25" id="email-password-label">Password</label>
<div class="w-lg-100">
<input autocomplete="off" type="password" class="form-control mb-2" id="forcelog-password" name="password" required>
</div>
</div>
<small id="emailpasswordRequired" class="form-text mt-1">This will also invalidate any existing recovery links associated with this account.</small>
</div>
<div class="footer">
<div class="d-flex">
<input autocomplete="off" class="btn btn-primary ml-auto"
type="submit" onclick="disable(this)" value="Log out everywhere">
<input autocomplete="off" class="btn btn-primary ml-auto" type="submit" onclick="disable(this)" value="Log out everywhere">
</div>
</div>
</form>
</section>
<section id="site-settings-blocks-section" class="settings-section-section">
<div class="row">
<div class="col">
{% if error %}
<div class="alert alert-danger alert-dismissible fade show my-3" role="alert">
<i class="fas fa-exclamation-circle my-auto"></i>
<span>
{{error}}
</span>
<button type="button" class="close" data-bs-dismiss="alert" aria-label="Close">
<span aria-hidden="true"><i class="far fa-times"></i></span>
</button>
</div>
{% endif %}
</div>
</div>
<div class="row">
<div class="col">
<div class="d-md-flex justify-content-between mb-3">
<div>
<h5>Users you block</h5>
<p class="text-small text-muted mb-md-0">You have blocked the following users. They cannot reply to your content or notify you with a username mention.</p>
</div>
<div class="mt-auto">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#blockmodal">Block user</button>
</div>
</div>
<div class="modal fade" id="deleteAccountModal" tabindex="-1" role="dialog" aria-labelledby="deleteAccountModal" aria-hidden="true">
{% if v.blocking.first() %}
<div class="card mb-5">
<div class="overflow-x-auto"><table class="table table-hover rounded mb-0">
<thead class="thead-dark">
<tr>
<th scope="col">User</th>
<th scope="col">Unblock</th>
</tr>
</thead>
<tbody class="text-muted">
{% for block in v.blocking %}
{% set user=block.target %}
<tr>
<td>
{% include "user_in_table.html" %}
</td>
<td>
<button type="button" class="btn btn-primary" onclick="postToastSwitch(this,'/settings/unblock?username={{user.username}}&formkey={{v.formkey}}')">Unblock</button>
</td>
</tr>
{% else %}
<td>There are no blocked users</td>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center border-md rounded py-7">
<i class="fas fa-ghost text-gray-500 mb-3" style="font-size: 3.5rem;"></i>
<p class="font-weight-bold text-gray-500 mb-0">No blocked users</p>
</div>
{% endif %}
</div>
</div>
</section>
</div>
</div>
</div>
<div class="modal fade" id="blockmodal" tabindex="-1" role="dialog" aria-labelledby="blockmodal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<form class="m-auto" action="/settings/block" id="exile-form" method="post" onsubmit="return false;">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Delete your {{SITE_NAME}} account</h5>
<h5 class="modal-title">Block users</h5>
<button type="button" class="close" data-bs-dismiss="modal" aria-label="Close">
<span aria-hidden="true"><i class="far fa-times"></i></span>
</button>
</div>
<div id="deleteFormContainer">
<form id="deleteAccountForm" method="post" action="/settings/delete_account">
<div class="modal-body">
<input type="hidden" name="formkey" value="{{v.formkey}}">
<div class="modal-body body">
<div class="d-lg-flex">
<label for="delete-password" class="w-lg-25" id="email-password-label">Password</label>
<div class="w-lg-100">
<input autocomplete="off" type="password" class="form-control mb-2" id="delete-password" name="password" required>
<input autocomplete="off" type="text" name="username" placeholder="Enter username..." id="exile-username" class="form-control" maxlength=25 required>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-link text-muted" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="exileUserButton" onclick="block_user()">Block user</button>
</div>
{% if v.mfa_secret %}
<div class="d-lg-flex mt-3">
<label for="delete-mfa" class="w-lg-25" id="email-password-label">Two-Factor Code</label>
<div class="w-lg-100">
<input autocomplete="off" type="text" class="form-control mb-2" id="delete-mfa" name="twofactor" required>
</div>
</div>
{% endif %}
</div>
</form>
</div>
</div>
<div class="toast error" id="toast-exile-error" role="alert" aria-live="assertive" aria-atomic="true" data-bs-animation="true" data-bs-autohide="true" data-bs-delay="5000">
<div class="toast-body text-center">
<i class="fas fa-exclamation-circle text-danger mr-2"></i><span id="toast-error-message">Error. Please try again.</span>
</div>
</div>
<script defer src="{{'js/settings_blocks.js' | asset}}"></script>
{% endblock %}