DispelEvilBot/admin/templates/base.html

209 lines
8.8 KiB
HTML

<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{% block title %}Админка{% endblock %} — DispelEvilBot</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/htmx.org@2.0.4" defer></script>
</head>
<body class="min-h-screen bg-slate-100 text-slate-900">
<header class="border-b border-slate-200 bg-white">
<div class="mx-auto max-w-5xl px-4 py-3">
<div class="flex flex-wrap items-center justify-between gap-3">
<a href="/" class="text-lg font-semibold">DispelEvilBot</a>
<button
id="nav-toggle"
type="button"
class="rounded-lg border border-slate-300 px-3 py-1.5 text-sm text-slate-600 sm:hidden"
aria-expanded="false"
>
Меню
</button>
<nav
id="nav-menu"
class="hidden w-full flex-col gap-2 border-t border-slate-100 pt-2 text-sm sm:flex sm:w-auto sm:flex-row sm:items-center sm:gap-1 sm:border-0 sm:pt-0"
>
<a href="/" class="rounded px-2 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Главная</a>
<div class="relative" data-group>
<button
type="button"
class="flex w-full items-center justify-between gap-1 rounded px-2 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900 sm:w-auto"
data-group-toggle
aria-expanded="false"
>
Сообщения <span class="text-xs">▾</span>
</button>
<div
class="hidden flex-col gap-1 rounded-lg border border-slate-200 bg-white p-2 sm:absolute sm:left-0 sm:top-full sm:z-20 sm:min-w-48 sm:shadow-lg"
data-group-dropdown
>
<a href="/sequences" class="rounded px-3 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Шаблоны</a>
<a href="/schedules" class="rounded px-3 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Расписания</a>
<a href="/send" class="rounded px-3 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Отправить</a>
</div>
</div>
<div class="relative" data-group>
<button
type="button"
class="flex w-full items-center justify-between gap-1 rounded px-2 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900 sm:w-auto"
data-group-toggle
aria-expanded="false"
>
Пользователи <span class="text-xs">▾</span>
</button>
<div
class="hidden flex-col gap-1 rounded-lg border border-slate-200 bg-white p-2 sm:absolute sm:left-0 sm:top-full sm:z-20 sm:min-w-48 sm:shadow-lg"
data-group-dropdown
>
<a href="/users" class="rounded px-3 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Список</a>
<a href="/admins" class="rounded px-3 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Админы</a>
<a href="/titles" class="rounded px-3 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Звания</a>
</div>
</div>
<a href="/logs" class="rounded px-2 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Логи</a>
{% if request.session.get('admin_id') %}
<form method="post" action="/logout" class="py-1 sm:ml-1">
<input type="hidden" name="csrf_token" value="{{ request.session.get('csrf', '') }}" />
<button type="submit" class="rounded px-2 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">
Выйти
</button>
</form>
{% endif %}
</nav>
</div>
</div>
</header>
<main class="mx-auto max-w-5xl px-4 py-8">
{% block content %}{% endblock %}
</main>
<footer class="mx-auto max-w-5xl px-4 pb-8 text-xs text-slate-400">DispelEvilBot v{{ version }}</footer>
<script>
document.addEventListener("DOMContentLoaded", function () {
var navToggle = document.getElementById("nav-toggle");
var navMenu = document.getElementById("nav-menu");
if (navToggle && navMenu) {
navToggle.addEventListener("click", function () {
var hidden = navMenu.classList.toggle("hidden");
navMenu.classList.toggle("flex", !hidden);
navToggle.setAttribute("aria-expanded", String(!hidden));
});
}
var groups = document.querySelectorAll("[data-group]");
function hideGroup(group) {
var dropdown = group.querySelector("[data-group-dropdown]");
var toggle = group.querySelector("[data-group-toggle]");
if (dropdown) {
dropdown.classList.add("hidden");
dropdown.classList.remove("flex");
}
if (toggle) toggle.setAttribute("aria-expanded", "false");
}
function hideOthers(current) {
groups.forEach(function (group) {
if (group !== current) hideGroup(group);
});
}
groups.forEach(function (group) {
var toggle = group.querySelector("[data-group-toggle]");
var dropdown = group.querySelector("[data-group-dropdown]");
if (!toggle || !dropdown) return;
var closeTimer = null;
function setOpen(open) {
dropdown.classList.toggle("hidden", !open);
dropdown.classList.toggle("flex", open);
toggle.setAttribute("aria-expanded", String(open));
}
toggle.addEventListener("click", function (event) {
event.stopPropagation();
if (closeTimer) clearTimeout(closeTimer);
var willOpen = dropdown.classList.contains("hidden");
if (willOpen) hideOthers(group);
setOpen(willOpen);
});
if (window.matchMedia("(min-width: 640px)").matches) {
group.addEventListener("mouseenter", function () {
if (closeTimer) clearTimeout(closeTimer);
hideOthers(group);
setOpen(true);
});
group.addEventListener("mouseleave", function () {
if (closeTimer) clearTimeout(closeTimer);
closeTimer = setTimeout(function () { setOpen(false); }, 150);
});
}
});
document.addEventListener("click", function () {
groups.forEach(hideGroup);
});
var tags = {
b: ["<b>", "</b>"],
i: ["<i>", "</i>"],
u: ["<u>", "</u>"],
s: ["<s>", "</s>"],
code: ["<code>", "</code>"],
pre: ["<pre>", "</pre>"],
quote: ["<blockquote>", "</blockquote>"],
spoiler: ["<tg-spoiler>", "</tg-spoiler>"],
a: ['<a href="">', "</a>"],
};
document.querySelectorAll("[data-editor]").forEach(function (root) {
var textarea = root.querySelector("textarea");
var counter = root.querySelector("[data-counter]");
var max = parseInt(root.dataset.max || "0", 10);
function updateCounter() {
if (counter) counter.textContent = textarea.value.length + (max ? " / " + max : "");
}
textarea.addEventListener("input", updateCounter);
updateCounter();
root.querySelectorAll("button[data-tag]").forEach(function (button) {
button.addEventListener("click", function () {
var pair = tags[button.dataset.tag];
if (!pair) return;
var start = textarea.selectionStart;
var end = textarea.selectionEnd;
var selected = textarea.value.slice(start, end);
var inserted = pair[0] + selected + pair[1];
textarea.value = textarea.value.slice(0, start) + inserted + textarea.value.slice(end);
textarea.focus();
textarea.selectionStart = start + pair[0].length;
textarea.selectionEnd = start + pair[0].length + selected.length;
updateCounter();
});
});
textarea.addEventListener("keydown", function (event) {
if (!(event.ctrlKey || event.metaKey)) return;
var key = event.key.toLowerCase();
var tag = key === "b" ? "b" : key === "i" ? "i" : key === "u" ? "u" : null;
if (!tag) return;
event.preventDefault();
var button = root.querySelector('button[data-tag="' + tag + '"]');
if (button) button.click();
});
});
});
</script>
</body>
</html>