Меню в шапке собрано в группы
CI / lint-test (push) Successful in 18s Details
CI / build-push (push) Successful in 18s Details

Вместо длинного ряда ссылок теперь «Сообщения» (шаблоны, расписания, отправка) и «Пользователи» (список, админы, звания); на десктопе группы раскрываются при наведении и по клику, на телефоне — по нажатию. Служебный текст «админ» и версия из шапки убраны, версия осталась в подвале.
This commit is contained in:
MpakobecEx 2026-10-26 01:54:34 +05:00
parent d85bc5b0f4
commit 73e83e2413
4 changed files with 79 additions and 16 deletions

View File

@ -171,7 +171,7 @@ make backup E=test # на домашнем сервере: ./scripts/clickho
## Версионирование ## Версионирование
- Единый источник версии — `common/version.py` (`__version__`), текущая — `0.6.3`. - Единый источник версии — `common/version.py` (`__version__`), текущая — `0.6.4`.
- Схема — SemVer-подобная (`MAJOR.MINOR.PATCH`); git-тег = `v` + версия (`v0.1`). - Схема — SemVer-подобная (`MAJOR.MINOR.PATCH`); git-тег = `v` + версия (`v0.1`).
- Docker-образы тегируются версией (Блок 2), события ClickHouse получают `bot_version` (Блок 3). - Docker-образы тегируются версией (Блок 2), события ClickHouse получают `bot_version` (Блок 3).
- Выпуск: изменить `common/version.py` → коммит → аннотированный тег `vX.Y` → `git push --tags`. - Выпуск: изменить `common/version.py` → коммит → аннотированный тег `vX.Y` → `git push --tags`.

View File

@ -22,24 +22,58 @@
</button> </button>
<nav <nav
id="nav-menu" 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-4 sm:border-0 sm:pt-0" 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="py-1 text-slate-600 hover:text-slate-900">Главная</a> <a href="/" class="rounded px-2 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">Главная</a>
<a href="/sequences" class="py-1 text-slate-600 hover:text-slate-900">Шаблоны</a>
<a href="/schedules" class="py-1 text-slate-600 hover:text-slate-900">Расписания</a> <div class="relative" data-group>
<a href="/users" class="py-1 text-slate-600 hover:text-slate-900">Пользователи</a> <button
<a href="/titles" class="py-1 text-slate-600 hover:text-slate-900">Звания</a> type="button"
<a href="/admins" class="py-1 text-slate-600 hover:text-slate-900">Админы</a> 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"
<a href="/logs" class="py-1 text-slate-600 hover:text-slate-900">Логи</a> data-group-toggle
<a href="/send" class="py-1 text-slate-600 hover:text-slate-900">Отправить</a> aria-expanded="false"
>
Сообщения <span class="text-xs">▾</span>
</button>
<div
class="mt-1 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:mt-1 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="mt-1 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:mt-1 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') %} {% if request.session.get('admin_id') %}
<span class="py-1 text-slate-500">{{ request.session.get('admin_username') or 'админ' }}</span> <form method="post" action="/logout" class="py-1 sm:ml-1">
<form method="post" action="/logout" class="py-1">
<input type="hidden" name="csrf_token" value="{{ request.session.get('csrf', '') }}" /> <input type="hidden" name="csrf_token" value="{{ request.session.get('csrf', '') }}" />
<button type="submit" class="text-slate-600 hover:text-slate-900">Выйти</button> <button type="submit" class="rounded px-2 py-1.5 text-slate-600 hover:bg-slate-100 hover:text-slate-900">
Выйти
</button>
</form> </form>
{% endif %} {% endif %}
<span class="py-1 text-slate-500">админка · v{{ version }}</span>
</nav> </nav>
</div> </div>
</div> </div>
@ -63,6 +97,35 @@
}); });
} }
var groups = document.querySelectorAll("[data-group]");
groups.forEach(function (group) {
var toggle = group.querySelector("[data-group-toggle]");
var dropdown = group.querySelector("[data-group-dropdown]");
if (!toggle || !dropdown) return;
function setOpen(open) {
dropdown.classList.toggle("hidden", !open);
toggle.setAttribute("aria-expanded", String(open));
}
toggle.addEventListener("click", function (event) {
event.stopPropagation();
setOpen(dropdown.classList.contains("hidden"));
});
if (window.matchMedia("(min-width: 640px)").matches) {
group.addEventListener("mouseenter", function () { setOpen(true); });
group.addEventListener("mouseleave", function () { setOpen(false); });
}
});
document.addEventListener("click", function () {
groups.forEach(function (group) {
var dropdown = group.querySelector("[data-group-dropdown]");
if (dropdown) dropdown.classList.add("hidden");
});
});
var tags = { var tags = {
b: ["<b>", "</b>"], b: ["<b>", "</b>"],
i: ["<i>", "</i>"], i: ["<i>", "</i>"],

View File

@ -7,4 +7,4 @@
from __future__ import annotations from __future__ import annotations
__version__ = "0.6.3" __version__ = "0.6.4"

View File

@ -7,4 +7,4 @@ from common import __version__
def test_version_is_set(): def test_version_is_set():
assert __version__ assert __version__
assert __version__ == "0.6.3" assert __version__ == "0.6.4"