Files
ForbiddenStarsApp/frontend/src/pages/admin/AdminLayout.tsx
T
NotBigGhostandClaude Opus 5 ab1fc3f00f Объявления: окно у игрока и редактор в админке
Окно — вариант E из макетов: заголовок в плашке-шапке, текст, точки очереди
и «Понятно», крестика нет. Очередь идёт от старого к новому; закрытое сразу
уходит из кэша, следующее открывается без ожидания сети. У повторно
показанного объявления под заголовком — красная пометка «обновлено».
AppShell показывает окно на любой странице и только когда пароль задан:
обязательное окно пароля всегда первое. Новые и изменённые объявления
приходят SSE-событием announcements, отложенное начало показа — перезапросом
раз в 5 минут.

Админка — вкладка «Объявления» с редактором R1: contenteditable и панель
(жирный, курсив, золотой и красный акцент, эмодзи, снятие оформления),
вставка и перетаскивание только простым текстом, счётчик символов, период
показа по МСК, переключатели «показывать новым игрокам» и «показать заново».
Предпросмотр — тем же окном, что у игрока. Список со статусом, счётчиком
«закрыли N из M» и действиями: изменить, снять с показа, дублировать,
удалить. Выделение текста в форме — полупрозрачный оранжевый вместо синего.

schema.d.ts пересобран из OpenAPI. #84

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 21:26:38 +03:00

51 lines
1.5 KiB
TypeScript

import { NavLink, Outlet, useNavigate } from "react-router-dom";
import { useAdminLogout } from "../../hooks/admin";
export function AdminLayout() {
const logout = useAdminLogout();
const navigate = useNavigate();
const doLogout = async () => {
await logout.mutateAsync().catch(() => {});
navigate("/admin/login", { replace: true });
};
const tab = ({ isActive }: { isActive: boolean }) =>
"btn small" + (isActive ? " btn-primary" : " btn-ghost");
return (
<div className="app-shell">
<header className="top-bar">
<span className="title">Админ-панель</span>
<button className="btn btn-ghost small" onClick={doLogout}>
Выйти
</button>
</header>
<div className="admin-tabs">
<NavLink to="/admin/records" className={tab}>
Записи
</NavLink>
<NavLink to="/admin/accounts" className={tab}>
Аккаунты
</NavLink>
<NavLink to="/admin/factions" className={tab}>
Фракции
</NavLink>
<NavLink to="/admin/achievements" className={tab}>
Ачивки
</NavLink>
<NavLink to="/admin/logs" className={tab}>
Логи
</NavLink>
<NavLink to="/admin/announcements" className={tab}>
Объявления
</NavLink>
</div>
<main className="app-main" style={{ paddingBottom: 24 }}>
<Outlet />
</main>
</div>
);
}