mirror of
https://codeberg.org/catask-org/catask.git
synced 2025-04-19 21:33:41 -05:00
new admin templates
This commit is contained in:
parent
1e9973cfa8
commit
c2dd774e60
7 changed files with 467 additions and 1 deletions
87
templates/admin/base.html
Normal file
87
templates/admin/base.html
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
{% block title %}{% block _title %}{% endblock %} - Admin{% endblock %}
|
||||||
|
{% set adminLink = 'active' %}
|
||||||
|
{% block additionalHeadItems %}
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/toastify.css') }}">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/coloris.min.css') }}">
|
||||||
|
<style>
|
||||||
|
@media screen and (max-width: 800px) {
|
||||||
|
#sidebar-col {
|
||||||
|
border-right: 0 !important;
|
||||||
|
padding-right: calc(var(--bs-gutter-x) * .5) !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
#sidebar {
|
||||||
|
padding-top: 0 !important;
|
||||||
|
}
|
||||||
|
#content {
|
||||||
|
padding-left: calc(var(--bs-gutter-x) * .5) !important;
|
||||||
|
margin-top: 1rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<!-- <h1 class="mb-2"><i class="bi bi-sliders me-1"></i> Admin panel</h1> -->
|
||||||
|
<!-- this is actually not used anymore, but htmx requires a valid target so we have to use it -->
|
||||||
|
<div id="response-container"></div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3 border-end pe-4" id="sidebar-col">
|
||||||
|
<div id="sidebar" class="sticky-lg-top pt-2">
|
||||||
|
<a class="ps-3 btn btn-outline-secondary my-1 fs-6 scale-parent {{ info_link }} d-flex align-items-center" href="{{ url_for('admin.information') }}">
|
||||||
|
<i class="bi bi-card-text fs-5 scale-child"></i>
|
||||||
|
<span class="sidebar-btn-text ms-2 ps-1">Information</span>
|
||||||
|
</a>
|
||||||
|
<a class="ps-3 btn btn-outline-secondary my-1 fs-6 scale-parent {{ custom_link }} d-flex align-items-center" href="{{ url_for('admin.customize') }}">
|
||||||
|
<i class="bi bi-columns-gap fs-5 scale-child"></i>
|
||||||
|
<span class="sidebar-btn-text ms-2 ps-1">Customize</span>
|
||||||
|
</a>
|
||||||
|
<a class="ps-3 btn btn-outline-secondary my-1 fs-6 scale-parent {{ general_link }} d-flex align-items-center" href="{{ url_for('admin.general') }}">
|
||||||
|
<i class="bi bi-gear fs-5 scale-child"></i>
|
||||||
|
<span class="sidebar-btn-text ms-2 ps-1">General</span>
|
||||||
|
</a>
|
||||||
|
<a class="ps-3 btn btn-outline-secondary my-1 fs-6 scale-parent {{ emojis_link }} d-flex align-items-center" href="{{ url_for('admin.emojis') }}">
|
||||||
|
<i class="bi bi-emoji-smile fs-5 scale-child"></i>
|
||||||
|
<span class="sidebar-btn-text ms-2 ps-1">Emojis</span>
|
||||||
|
</a>
|
||||||
|
<a class="ps-3 btn btn-outline-secondary my-1 fs-6 scale-parent {{ blacklist_link }} d-flex align-items-center" href="{{ url_for('admin.blacklist') }}">
|
||||||
|
<i class="bi bi-ban fs-5 scale-child"></i>
|
||||||
|
<span class="sidebar-btn-text ms-2 ps-1">Word blacklist</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-9 ps-4" id="content">
|
||||||
|
{% block _content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block scripts %}
|
||||||
|
<script src="{{ url_for('static', filename='js/toastify.min.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener('htmx:afterRequest', function(event) {
|
||||||
|
const jsonResponse = event.detail.xhr.response;
|
||||||
|
if (jsonResponse) {
|
||||||
|
const parsed = JSON.parse(jsonResponse);
|
||||||
|
const alertType = event.detail.successful ? 'success' : 'danger';
|
||||||
|
message = event.detail.successful ? parsed.message : parsed.error;
|
||||||
|
if (event.detail.target.id != "question-count") {
|
||||||
|
console.log(event.detail.target);
|
||||||
|
if (event.detail.target.className.includes("emoji-")) {
|
||||||
|
event.detail.target.remove();
|
||||||
|
}
|
||||||
|
Toastify({
|
||||||
|
text: message,
|
||||||
|
duration: 3000,
|
||||||
|
gravity: "top",
|
||||||
|
position: "right",
|
||||||
|
stopOnFocus: true,
|
||||||
|
className: `alert alert-${alertType} shadow alert-dismissible`,
|
||||||
|
close: true
|
||||||
|
}).showToast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% block _scripts %}
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
18
templates/admin/categories/blacklist.html
Normal file
18
templates/admin/categories/blacklist.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{% extends 'admin/base.html' %}
|
||||||
|
{% block _title %}Blacklist{% endblock %}
|
||||||
|
{% set blacklist_link = 'active' %}
|
||||||
|
{% block _content %}
|
||||||
|
<form hx-post="{{ url_for('admin.blacklist') }}" hx-target="#response-container" hx-swap="none">
|
||||||
|
<input type="hidden" name="action" value="update_word_blacklist">
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label class="form-label" for="blacklist_cat"><h2 id="blacklist" class="fw-normal">Word blacklist</h2></label>
|
||||||
|
<p class="text-body-secondary">Blacklisted words for questions; one word per line</p>
|
||||||
|
<textarea id="blacklist_cat" name="blacklist" style="height: 300px; resize: vertical;" class="form-control">{{ blacklist }}</textarea>
|
||||||
|
<button type="submit" class="btn btn-primary mt-3" id="save-blacklist">
|
||||||
|
<span class="me-1 spinner-border spinner-border-sm htmx-indicator" aria-hidden="true"></span>
|
||||||
|
<span class="visually-hidden" role="status">Loading...</span>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
149
templates/admin/categories/customize.html
Normal file
149
templates/admin/categories/customize.html
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
{% extends 'admin/base.html' %}
|
||||||
|
{% block _title %}Customize{% endblock %}
|
||||||
|
{% set custom_link = 'active' %}
|
||||||
|
{% block _content %}
|
||||||
|
<h2 id="customize" class="mb-3 fw-normal">Customize</h2>
|
||||||
|
<h3 class="fw-light">Favicon</h3>
|
||||||
|
<form hx-post="{{ url_for('api.uploadFavicon') }}" hx-target="#response-container" hx-swap="none" hx-encoding="multipart/form-data">
|
||||||
|
<p class="m-0">Current favicon: <img src="{{ url_for('static', filename='icons/favicon/apple-touch-icon.png') }}" width="32" height="32" alt="{{ cfg.instance.title }}'s icon" class="rounded"></p>
|
||||||
|
<div>
|
||||||
|
<label for="favicon" class="form-label">Upload favicon</label>
|
||||||
|
<input class="form-control" type="file" id="favicon" name="favicon">
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<button type="submit" class="btn btn-primary mt-3" id="saveFavicon">
|
||||||
|
<span class="spinner-border spinner-border-sm htmx-indicator" aria-hidden="true"></span>
|
||||||
|
<span class="visually-hidden" role="status">Loading...</span>
|
||||||
|
Upload
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form hx-post="{{ url_for('api.updateConfig') }}" hx-target="#response-container" hx-swap="none">
|
||||||
|
<h3 class="fw-light">Accent color</h3>
|
||||||
|
{# <h4 class="fw-light">Color</h4> #}
|
||||||
|
<div class="form-group d-flex flex-column">
|
||||||
|
<label class="form-label" for="style.accentLight">Light theme</label>
|
||||||
|
<input type="text" name="style.accentLight" id="style.accentLight" value="{{ cfg.style.accentLight }}" class="form-control" data-coloris>
|
||||||
|
<p class="form-text">Default: <b>#6345d9</b></p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group d-flex flex-column">
|
||||||
|
<label class="form-label" for="style.accentDark">Dark theme</label>
|
||||||
|
<input type="text" name="style.accentDark" id="style.accentDark" value="{{ cfg.style.accentDark }}" class="form-control" data-coloris>
|
||||||
|
<p class="form-text">Default: <b>#7a63e3</b></p>
|
||||||
|
</div>
|
||||||
|
{# brain doesn't feel like implementing this rn (9/27/24)
|
||||||
|
<h4 class="fw-light mt-2">Background</h4>
|
||||||
|
<div class="form-group d-flex flex-column">
|
||||||
|
<label class="form-label" for="style.bgLight">Light theme</label>
|
||||||
|
<input type="text" name="style.bgLight" id="style.bgLight" value="{{ cfg.style.bgLight }}" class="form-control" data-coloris>
|
||||||
|
<p class="form-text">Default: <b>#ffffff</b></p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group d-flex flex-column">
|
||||||
|
<label class="form-label" for="style.bgDark">Dark theme</label>
|
||||||
|
<input type="text" name="style.bgDark" id="style.bgDark" value="{{ cfg.style.bgDark }}" class="form-control" data-coloris>
|
||||||
|
<p class="form-text">Default: <b>#202020</b></p>
|
||||||
|
</div>
|
||||||
|
#}
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="_style.tintColors"
|
||||||
|
id="_style.tintColors"
|
||||||
|
value="{{ cfg.style.tintColors }}"
|
||||||
|
{% if cfg.style.tintColors == true %}checked{% endif %}>
|
||||||
|
<input type="hidden" id="style.tintColors" name="style.tintColors" value="{{ cfg.style.tintColors }}">
|
||||||
|
<label for="_style.tintColors" class="form-check-label">Tint all colors with accent color</label>
|
||||||
|
</div>
|
||||||
|
{#
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="_style.tintBackground"
|
||||||
|
id="_style.tintBackground"
|
||||||
|
value="{{ cfg.style.tintBackground }}"
|
||||||
|
{% if cfg.style.tintBackground == true %}checked{% endif %}>
|
||||||
|
<input type="hidden" id="style.tintBackground" name="style.tintBackground" value="{{ cfg.style.tintBackground }}">
|
||||||
|
<label for="_style.tintBackground" class="form-check-label">Tint background with accent color</label>
|
||||||
|
</div>
|
||||||
|
#}
|
||||||
|
<h3 class="fw-light">Navbar link style</h3>
|
||||||
|
<div class="btn-group mb-4 w-100" role="group" aria-label="Navbar link style group">
|
||||||
|
<input class="btn-check" type="radio" name="style.navStyle" id="style.navStyle.underline" value="underline" {% if cfg.style.navStyle == 'underline' %}checked{% endif %}>
|
||||||
|
<label class="btn btn-outline-secondary w-50" for="style.navStyle.underline">
|
||||||
|
Underline
|
||||||
|
</label>
|
||||||
|
<input class="btn-check" type="radio" name="style.navStyle" id="style.navStyle.pills" value="pills" {% if cfg.style.navStyle == 'pills' %}checked{% endif %}>
|
||||||
|
<label class="btn btn-outline-secondary w-50" for="style.navStyle.pills">
|
||||||
|
Pills
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<h3 class="fw-light">Homepage layout</h3>
|
||||||
|
<div class="btn-group mb-4 w-100" role="group" aria-label="General layout group">
|
||||||
|
<input class="btn-check" type="radio" name="style.homepageLayout" id="style.homepageLayout.catask" value="catask" {% if cfg.style.homepageLayout == 'catask' %}checked{% endif %}>
|
||||||
|
<label class="btn btn-outline-secondary w-50" for="style.homepageLayout.catask">
|
||||||
|
CatAsk
|
||||||
|
</label>
|
||||||
|
<input class="btn-check" type="radio" name="style.homepageLayout" id="style.homepageLayout.retrospring" value="retrospring" {% if cfg.style.homepageLayout == 'retrospring' %}checked{% endif %}>
|
||||||
|
<label class="btn btn-outline-secondary w-50" for="style.homepageLayout.retrospring">
|
||||||
|
Retrospring
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<h3 class="fw-light">Info box layout</h3>
|
||||||
|
<div class="btn-group mb-4 w-100" role="group" aria-label="Info box layout group">
|
||||||
|
<input class="btn-check" type="radio" name="style.infoBoxLayout" id="style.infoBoxLayout.column" value="column" {% if cfg.style.infoBoxLayout == 'column' %}checked{% endif %}>
|
||||||
|
<label class="btn btn-outline-secondary w-50" for="style.infoBoxLayout.column">
|
||||||
|
Column
|
||||||
|
</label>
|
||||||
|
<input class="btn-check" type="radio" name="style.infoBoxLayout" id="style.infoBoxLayout.row" value="row" {% if cfg.style.infoBoxLayout == 'row' %}checked{% endif %}>
|
||||||
|
<label class="btn btn-outline-secondary w-50" for="style.infoBoxLayout.row">
|
||||||
|
Row
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<h3 class="fw-light">Trimmed content</h3>
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label class="form-label" for="trimContentAfter">Trim content after (characters)</label>
|
||||||
|
<input type="number" id="trimContentAfter" name="trimContentAfter" value="{{ cfg.trimContentAfter }}" class="form-control">
|
||||||
|
<p class="form-text">Maximum length of content before it gets trimmed (used in sharing options); set to 0 to disable</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" class="btn btn-primary mt-3" id="saveConfig">
|
||||||
|
<span class="spinner-border spinner-border-sm htmx-indicator" aria-hidden="true"></span>
|
||||||
|
<span class="visually-hidden" role="status">Loading...</span>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
{% block _scripts %}
|
||||||
|
<script src="{{ url_for('static', filename='js/coloris.min.js') }}"></script>
|
||||||
|
<script>
|
||||||
|
Coloris({
|
||||||
|
theme: 'square',
|
||||||
|
themeMode: 'auto',
|
||||||
|
formatToggle: true,
|
||||||
|
alpha: false,
|
||||||
|
swatches: [
|
||||||
|
'#c70f0f', // Red
|
||||||
|
'#db5d0e', // Orange
|
||||||
|
'#968829', // Yellow
|
||||||
|
'#217d1a', // Green
|
||||||
|
'#28b59b', // Turquoise
|
||||||
|
'#338FFF', // Blue
|
||||||
|
'#3358ff',
|
||||||
|
'#7a63e3', // Indigo
|
||||||
|
'#A833FF', // Purple
|
||||||
|
'#d1298b' // Pink
|
||||||
|
],
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
// fix handling checkboxes
|
||||||
|
document.querySelectorAll('.form-check-input[type=checkbox]').forEach(function(checkbox) {
|
||||||
|
checkbox.addEventListener('change', function() {
|
||||||
|
checkbox.nextElementSibling.value = this.checked ? 'True' : 'False';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
83
templates/admin/categories/emojis.html
Normal file
83
templates/admin/categories/emojis.html
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
{% extends 'admin/base.html' %}
|
||||||
|
{% block _title %}Emojis{% endblock %}
|
||||||
|
{% set emojis_link = 'active' %}
|
||||||
|
{% block _content %}
|
||||||
|
<h2 id="customEmojis" class="mb-3 fw-normal">Custom emojis</h2>
|
||||||
|
<h3 class="fw-light">Upload</h3>
|
||||||
|
<form hx-post="{{ url_for('api.uploadEmoji') }}" hx-target="#response-container" hx-swap="none" hx-encoding="multipart/form-data">
|
||||||
|
<div>
|
||||||
|
<label for="emoji" class="form-label">Upload an emoji</label>
|
||||||
|
<input class="form-control" type="file" id="emoji" name="emoji">
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<button type="submit" class="btn btn-primary mt-3" id="uploadEmoji">
|
||||||
|
<span class="spinner-border spinner-border-sm htmx-indicator" aria-hidden="true"></span>
|
||||||
|
<span class="visually-hidden" role="status">Loading...</span>
|
||||||
|
<i class="bi bi-file-earmark-plus me-1"></i> Upload emoji
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<hr>
|
||||||
|
<form hx-post="{{ url_for('api.uploadEmojiPack') }}" hx-target="#response-container" hx-swap="none" hx-encoding="multipart/form-data">
|
||||||
|
<div>
|
||||||
|
<label for="emoji_archive" class="form-label">Upload emoji pack</label>
|
||||||
|
<input class="form-control" type="file" id="emoji_archive" name="emoji_archive">
|
||||||
|
<p class="form-text mb-0">Supported archive formats: <strong>.zip, .tar, .tar.gz, .tar.bz2, .tar.xz</strong></p>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<button type="submit" class="btn btn-primary mt-3" id="uploadEmojiPack">
|
||||||
|
<span class="spinner-border spinner-border-sm htmx-indicator" aria-hidden="true"></span>
|
||||||
|
<span class="visually-hidden" role="status">Loading...</span>
|
||||||
|
<i class="bi bi-file-earmark-zip me-1"></i> Upload pack
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<h3 class="fw-light">Manage</h3>
|
||||||
|
<h4 class="fw-light">Emojis</h4>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="emojiTable" class="table align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Image</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Filename</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="emojis">
|
||||||
|
{% for emoji in emojis %}
|
||||||
|
{% include 'snippets/admin/emojiRow.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<h4 class="fw-light mt-3">Emoji packs</h4>
|
||||||
|
<p class="text-body-secondary small">Please note that if meta.json is not found in the archive, preview images are selected by first emoji name to appear alphabetically, so they may not be accurate sometimes</p>
|
||||||
|
{% if packs %}
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="emojiPackTable" class="table align-middle">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Image</th>
|
||||||
|
<th>Name</th>
|
||||||
|
{% if json_pack %}
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Released</th>
|
||||||
|
{% endif %}
|
||||||
|
<th>Folder</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="packs">
|
||||||
|
{% for pack in packs %}
|
||||||
|
{% with json_pack = json_pack %}
|
||||||
|
{% include 'snippets/admin/packRow.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p class="text-center">No emoji packs uploaded</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
79
templates/admin/categories/general.html
Normal file
79
templates/admin/categories/general.html
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
{% extends 'admin/base.html' %}
|
||||||
|
{% block _title %}General{% endblock %}
|
||||||
|
{% set general_link = 'active' %}
|
||||||
|
{% block _content %}
|
||||||
|
<form hx-post="{{ url_for('api.updateConfig') }}" hx-target="#response-container" hx-swap="none">
|
||||||
|
<h2 id="general" class="mb-3 fw-normal">General</h2>
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label class="form-label" for="charLimit">Question character limit</label>
|
||||||
|
<input type="number" id="charLimit" name="charLimit" value="{{ cfg.charLimit }}" class="form-control">
|
||||||
|
<p class="form-text">Max length of a question in characters; questions extending this character limit will not be added to the database</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-4">
|
||||||
|
<label class="form-label" for="anonName">Name for anonymous users</label>
|
||||||
|
<input type="text" id="anonName" name="anonName" value="{{ cfg.anonName }}" class="form-control">
|
||||||
|
<p class="form-text">This name will be used for questions asked to you by anonymous users</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-check mb-2">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="_lockInbox"
|
||||||
|
id="_lockInbox"
|
||||||
|
value="{{ cfg.lockInbox }}"
|
||||||
|
{% if cfg.lockInbox == true %}checked{% endif %}>
|
||||||
|
<input type="hidden" id="lockInbox" name="lockInbox" value="{{ cfg.lockInbox }}">
|
||||||
|
<label for="_lockInbox" class="form-check-label">Lock inbox and don't allow new questions</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check mb-2">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="_allowAnonQuestions"
|
||||||
|
id="_allowAnonQuestions"
|
||||||
|
value="{{ cfg.allowAnonQuestions }}"
|
||||||
|
{% if cfg.allowAnonQuestions == true %}checked{% endif %}>
|
||||||
|
<input type="hidden" id="allowAnonQuestions" name="allowAnonQuestions" value="{{ cfg.allowAnonQuestions }}">
|
||||||
|
<label for="_allowAnonQuestions" class="form-check-label">Allow anonymous questions</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check mb-2">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="_noDeleteConfirm"
|
||||||
|
id="_noDeleteConfirm"
|
||||||
|
value="{{ cfg.noDeleteConfirm }}"
|
||||||
|
{% if cfg.noDeleteConfirm == true %}checked{% endif %}>
|
||||||
|
<input type="hidden" id="noDeleteConfirm" name="noDeleteConfirm" value="{{ cfg.noDeleteConfirm }}">
|
||||||
|
<label for="_noDeleteConfirm" class="form-check-label">Disable confirmation when deleting questions</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input
|
||||||
|
class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
name="_showQuestionCount"
|
||||||
|
id="_showQuestionCount"
|
||||||
|
value="{{ cfg.showQuestionCount }}"
|
||||||
|
{% if cfg.showQuestionCount == true %}checked{% endif %}>
|
||||||
|
<input type="hidden" id="showQuestionCount" name="showQuestionCount" value="{{ cfg.showQuestionCount }}">
|
||||||
|
<label for="_showQuestionCount" class="form-check-label">Show question count in homepage</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" class="btn btn-primary mt-3" id="saveConfig">
|
||||||
|
<span class="spinner-border spinner-border-sm htmx-indicator" aria-hidden="true"></span>
|
||||||
|
<span class="visually-hidden" role="status">Loading...</span>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
||||||
|
{% block _scripts %}
|
||||||
|
<script>
|
||||||
|
// fix handling checkboxes
|
||||||
|
document.querySelectorAll('.form-check-input[type=checkbox]').forEach(function(checkbox) {
|
||||||
|
checkbox.addEventListener('change', function() {
|
||||||
|
checkbox.nextElementSibling.value = this.checked ? 'True' : 'False';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
46
templates/admin/categories/instance.html
Normal file
46
templates/admin/categories/instance.html
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
{% extends 'admin/base.html' %}
|
||||||
|
{% block _title %}Information{% endblock %}
|
||||||
|
{% set info_link = 'active' %}
|
||||||
|
{% block _content %}
|
||||||
|
<form hx-post="{{ url_for('api.updateConfig') }}" hx-target="#response-container" hx-swap="none">
|
||||||
|
<h2 id="instance" class="mb-3 fw-normal">Information</h2>
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label class="form-label" for="instance.title">Title <small class="text-body-secondary">(e.g. My question box)</small></label>
|
||||||
|
<input type="text" id="instance.title" name="instance.title" value="{{ cfg.instance.title }}" class="form-control">
|
||||||
|
<p class="form-text">Title of this CatAsk instance</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label class="form-label d-flex flex-column flex-lg-row align-items-lg-center justify-content-between" for="instance.description">
|
||||||
|
<span>Description <small class="text-body-secondary">(e.g. Ask me a question!)</small></span>
|
||||||
|
<small class="text-body-secondary"><i class="bi bi-markdown me-1"></i> Markdown supported</small>
|
||||||
|
</label>
|
||||||
|
<textarea spellcheck="false" id="instance.description" name="instance.description" class="form-control" style="height: 200px; resize: vertical;">{{ cfg.instance.description }}</textarea>
|
||||||
|
<p class="form-text">Description of this CatAsk instance</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label class="form-label d-flex flex-column flex-lg-row align-items-lg-center justify-content-between" for="instance.rules">
|
||||||
|
<span>Rules</span>
|
||||||
|
<small class="text-body-secondary"><i class="bi bi-markdown me-1"></i> Markdown supported</small>
|
||||||
|
</label>
|
||||||
|
<textarea spellcheck="false" id="instance.rules" name="instance.rules" class="form-control" style="height: 200px; resize: vertical;">{{ cfg.instance.rules }}</textarea>
|
||||||
|
<p class="form-text">Rules of this CatAsk instance</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-3">
|
||||||
|
<label class="form-label" for="instance.image">Relative image path <small class="text-body-secondary">(default: /static/icons/favicon/android-chrome-512x512.png)</small></label>
|
||||||
|
<input type="text" id="instance.image" name="instance.image" value="{{ cfg.instance.image }}" class="form-control">
|
||||||
|
<p class="form-text">Image that's going to be used in a link preview</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group mb-2">
|
||||||
|
<label class="form-label" for="instance.fullBaseUrl">Base URL <small class="text-body-secondary">(e.g. https://ask.example.com)</small></label>
|
||||||
|
<input type="text" id="instance.fullBaseUrl" name="instance.fullBaseUrl" value="{{ cfg.instance.fullBaseUrl }}" class="form-control">
|
||||||
|
<p class="form-text">Full URL to homepage of this CatAsk instance without a trailing slash</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" class="btn btn-primary" id="saveConfig">
|
||||||
|
<span class="spinner-border spinner-border-sm htmx-indicator" aria-hidden="true"></span>
|
||||||
|
<span class="visually-hidden" role="status">Loading...</span>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
|
@ -7,10 +7,14 @@
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="text-center mb-4 mt-2">Login to {{ cfg.instance.title }}</h2>
|
<h2 class="text-center mb-4 mt-2">Login to {{ cfg.instance.title }}</h2>
|
||||||
<form action="{{ url_for('admin.login') }}" method="POST">
|
<form action="{{ url_for('admin.login') }}" method="POST">
|
||||||
<div class="form-floating mb-3">
|
<div class="form-floating mb-2">
|
||||||
<input type="password" required class="form-control" id="admin_password" name="admin_password" placeholder="Password">
|
<input type="password" required class="form-control" id="admin_password" name="admin_password" placeholder="Password">
|
||||||
<label for="admin_password">Password</label>
|
<label for="admin_password">Password</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check mb-3">
|
||||||
|
<input type="checkbox" class="form-check-input" id="remember_me" name="remember_me" checked>
|
||||||
|
<label class="form-check-label" for="remember_me">Stay logged in</label>
|
||||||
|
</div>
|
||||||
<button type="submit" class="btn btn-primary w-100">Login</button>
|
<button type="submit" class="btn btn-primary w-100">Login</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue