Меню в шапке собрано в группы
Вместо длинного ряда ссылок теперь «Сообщения» (шаблоны, расписания, отправка) и «Пользователи» (список, админы, звания); на десктопе группы раскрываются при наведении и по клику, на телефоне — по нажатию. Служебный текст «админ» и версия из шапки убраны, версия осталась в подвале.
This commit is contained in:
parent
d85bc5b0f4
commit
626ffe2db5
|
|
@ -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`.
|
||||||
|
|
|
||||||
|
|
@ -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>"],
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
__version__ = "0.6.3"
|
__version__ = "0.6.4"
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue