diff --git a/apps/web/src/components/AdminNav.astro b/apps/web/src/components/AdminNav.astro new file mode 100644 index 0000000..fd89993 --- /dev/null +++ b/apps/web/src/components/AdminNav.astro @@ -0,0 +1,12 @@ +--- +const path = Astro.url.pathname; +const links = [ + ["/admin", "Обзор"], + ["/admin/moderation", "Уловы"], + ["/admin/external-sources", "Источники"], + ["/admin/media", "Медиа"], +] as const; +--- + diff --git a/apps/web/src/pages/admin/external-sources.astro b/apps/web/src/pages/admin/external-sources.astro index 1b5e98b..41cc9a4 100644 --- a/apps/web/src/pages/admin/external-sources.astro +++ b/apps/web/src/pages/admin/external-sources.astro @@ -1,10 +1,12 @@ --- import Layout from "../../layouts/Layout.astro"; +import AdminNav from "../../components/AdminNav.astro"; const apiUrl = import.meta.env.PUBLIC_API_URL || "http://localhost:8000"; ---
ADMIN Staging

Внешние
наблюдения

Сопоставьте названия с каноническим каталогом. Опубликовать можно только запись с координатами и весом.

+

Токен остаётся только в памяти страницы. Исходная ссылка и происхождение сохраняются при публикации.

diff --git a/apps/web/src/pages/admin/index.astro b/apps/web/src/pages/admin/index.astro index 0c83e7c..c49757e 100644 --- a/apps/web/src/pages/admin/index.astro +++ b/apps/web/src/pages/admin/index.astro @@ -1,10 +1,12 @@ --- import Layout from "../../layouts/Layout.astro"; +import AdminNav from "../../components/AdminNav.astro"; const apiUrl = import.meta.env.PUBLIC_API_URL || "http://localhost:8000"; ---
ADMIN Центр управления

Панель
модератора

Очереди, состояние источников и последние импорты в одном безопасном обзоре.

+

Токен существует только в памяти вкладки. Сессия завершится после 15 минут бездействия.

diff --git a/apps/web/src/pages/admin/media.astro b/apps/web/src/pages/admin/media.astro index 4aa9120..d4dae72 100644 --- a/apps/web/src/pages/admin/media.astro +++ b/apps/web/src/pages/admin/media.astro @@ -1,10 +1,12 @@ --- import Layout from "../../layouts/Layout.astro"; +import AdminNav from "../../components/AdminNav.astro"; const apiUrl = import.meta.env.PUBLIC_API_URL || "http://localhost:8000"; ---
ADMIN Media review

Проверка
медиа

Сравнение approved и upgrade_queued файлов перед отдельным редакционным решением.

+

Публичные файлы не переключаются из этого экрана. Токен хранится только в памяти страницы.

diff --git a/apps/web/src/pages/admin/moderation.astro b/apps/web/src/pages/admin/moderation.astro index f09987d..94a47a2 100644 --- a/apps/web/src/pages/admin/moderation.astro +++ b/apps/web/src/pages/admin/moderation.astro @@ -1,10 +1,12 @@ --- import Layout from "../../layouts/Layout.astro"; +import AdminNav from "../../components/AdminNav.astro"; const apiUrl = import.meta.env.PUBLIC_API_URL || "http://localhost:8000"; ---
ADMIN Очередь проверки

Модерация
уловов

Проверьте данные и скриншот до того, как запись повлияет на публичную статистику.

+

Токен хранится только в памяти страницы и не записывается в URL или localStorage.

diff --git a/apps/web/src/styles/global.css b/apps/web/src/styles/global.css index 35e4f61..4969245 100644 --- a/apps/web/src/styles/global.css +++ b/apps/web/src/styles/global.css @@ -59,6 +59,9 @@ footer{min-height:118px;background:var(--deep);color:#dbe4df;padding:28px max(32 /* One semantic treatment for empty, unavailable and invalid public states. */ .state.unavailable-state{border-style:solid;border-color:color-mix(in srgb,var(--warning) 35%,var(--border));background:color-mix(in srgb,var(--warning-soft) 35%,var(--surface))}.state.error-state{background:color-mix(in srgb,var(--danger-soft) 28%,var(--surface))}.state>a{margin-top:8px;font-weight:750;text-underline-offset:4px} +/* Admin navigation keeps all operational surfaces reachable by keyboard. */ +.admin-nav{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 18px}.admin-nav a{padding:9px 13px;border:1px solid var(--line);border-radius:999px;color:var(--text-muted);font-size:12px;text-decoration:none}.admin-nav a:hover,.admin-nav a.active{border-color:var(--focus);color:var(--deep);background:var(--lime)} + /* Action hierarchy stays semantic across public and admin surfaces. */ [data-action]{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:42px;padding:0 18px;border:1px solid transparent;border-radius:10px;font-weight:750;text-decoration:none;transition:background-color var(--motion-fast) var(--ease-out),border-color var(--motion-fast) var(--ease-out),color var(--motion-fast) var(--ease-out),transform var(--motion-fast) var(--ease-out)}[data-action]:hover:not(:disabled){transform:translateY(-1px)}[data-action]:active:not(:disabled){transform:translateY(0)}[data-action="primary"]{background:var(--lime);color:var(--deep)}[data-action="secondary"]{border-color:var(--border);background:var(--surface-soft);color:var(--text-muted)}[data-action="inverse"]{border-color:#ffffff38;background:var(--deep);color:var(--white)}[data-action="danger"]{background:var(--danger-soft);color:var(--danger)}[data-action="quiet-danger"]{border-color:color-mix(in srgb,var(--danger) 35%,transparent);background:transparent;color:var(--danger)}[data-action="quiet"]{background:transparent;color:#d5dfdc;text-decoration:underline;text-underline-offset:4px}[data-action]:disabled{opacity:.55;cursor:not-allowed}