From e7b34ce6ae52f732eb8cb96f58af098cf5f52df2 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Fri, 23 Oct 2026 14:33:21 +0700 Subject: [PATCH] =?UTF-8?q?fix(web):=20=D0=B2=D0=B5=D1=80=D0=BD=D1=83?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BD=D0=B0=D1=82=D0=B8=D0=B2=D0=BD=D1=8B=D0=B5?= =?UTF-8?q?=20=D1=82=D0=BE=D0=BA=D0=B5=D0=BD=D1=8B=20ReUI=20=D0=B8=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D1=88=D0=B0?= =?UTF-8?q?=D0=BF=D0=BA=D1=83=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86?= =?UTF-8?q?=D1=8B=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- apps/web/src/portal-theme.css | 124 +--------------------- apps/web/src/routes/_auth.admin.index.tsx | 17 +++ 2 files changed, 18 insertions(+), 123 deletions(-) diff --git a/apps/web/src/portal-theme.css b/apps/web/src/portal-theme.css index b0b62eb..1b6a106 100644 --- a/apps/web/src/portal-theme.css +++ b/apps/web/src/portal-theme.css @@ -1,7 +1,4 @@ -@import '@fontsource-variable/geist'; -@import '@fontsource-variable/geist-mono'; - -/* Плотность и контраст макета. Атрибуты ставит PreviewProvider и снимает при выходе. */ +/* Плотность портала. Палитра, шрифты и таблицы — нативные токены ReUI из @authportal/ui/globals.css. */ html[data-density='compact'] [data-slot='data-grid-table'] :is(th, td) { padding-block: 0.25rem; } @@ -10,112 +7,6 @@ html[data-density='compact'] [data-slot='sidebar-inset'] > div:last-child { gap: 0.75rem; } -/* Палитра MikrotikManager v2 (доски Auth Portal): только пока смонтирован макет. */ -html:not(.dark) { - --background: oklch(0.973 0.004 247.858); - --foreground: oklch(0.205 0.01 264); - --card: oklch(1 0 0); - --card-foreground: oklch(0.205 0.01 264); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.205 0.01 264); - --secondary: oklch(0.955 0.005 264); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.95 0.006 264); - --muted-foreground: oklch(0.44 0.02 264); - --accent: oklch(0.93 0.01 264); - --accent-foreground: oklch(0.205 0 0); - --border: oklch(0.88 0.008 264); - --input: oklch(0.86 0.008 264); - --ring: oklch(0.488 0.243 264.376); - --sidebar: oklch(0.985 0.003 264); - --sidebar-foreground: oklch(0.205 0.01 264); - --sidebar-accent: oklch(0.93 0.01 264); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.88 0.008 264); - --invert: oklch(0.9 0.01 264); - --sidebar-primary: oklch(0.488 0.243 264.376); - --destructive-foreground: oklch(0.45 0.2 27); - --success: oklch(0.6 0.15 163); - --success-foreground: oklch(0.4 0.1 163); - --warning: oklch(0.75 0.16 80); - --warning-foreground: oklch(0.45 0.1 70); - --info: oklch(0.55 0.23 293); - --info-foreground: oklch(0.42 0.2 293); -} - -html.dark { - --background: oklch(0.133 0.011 264.376); - --foreground: oklch(0.985 0 0); - --card: oklch(0.191 0.011 264.376); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.191 0.011 264.376); - --popover-foreground: oklch(0.985 0 0); - --secondary: oklch(0.252 0.01 264.376); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.252 0.01 264.376); - --muted-foreground: oklch(0.648 0.008 264.376); - --accent: oklch(0.285 0.022 264.376); - --accent-foreground: oklch(0.985 0 0); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.488 0.243 264.376); - --sidebar: oklch(0.191 0.011 264.376); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.262 0.014 264.376); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --invert: oklch(0.37 0.013 285.805); - --destructive: oklch(0.704 0.191 22.216); - --destructive-foreground: oklch(0.577 0.245 27.325); - --success: oklch(0.696 0.17 162.48); - --success-foreground: oklch(0.596 0.145 163.225); - --warning: oklch(0.795 0.184 86.047); - --warning-foreground: oklch(0.681 0.162 75.834); - --info: oklch(0.606 0.25 292.717); - --info-foreground: oklch(0.541 0.281 293.009); -} - -html[data-contrast='high'] { - --border: color-mix(in oklch, var(--foreground) 55%, transparent); - --input: color-mix(in oklch, var(--foreground) 60%, transparent); - --muted-foreground: color-mix(in oklch, var(--foreground) 88%, transparent); - --ring: oklch(0.35 0.2 264); -} - -html.dark[data-contrast='high'] { - --background: oklch(0 0 0); - --primary: oklch(1 0 0); - --primary-foreground: oklch(0 0 0); - --sidebar: oklch(0.1 0 0); - --foreground: oklch(1 0 0); - --success: oklch(0.82 0.19 150); - --success-foreground: oklch(0.9 0.15 150); - --warning: oklch(0.9 0.17 95); - --warning-foreground: oklch(0.95 0.12 95); - --destructive: oklch(0.78 0.2 25); - --destructive-foreground: oklch(0.88 0.12 25); - --info: oklch(0.8 0.15 300); - --info-foreground: oklch(0.9 0.1 300); - --card: oklch(0.12 0 0); - --popover: oklch(0.1 0 0); - --muted: oklch(0.22 0 0); - --muted-foreground: oklch(0.86 0 0); - --border: oklch(1 0 0 / 55%); - --input: oklch(1 0 0 / 60%); - --ring: oklch(0.85 0.17 95); -} - -/* Шрифты дизайн-системы (Geist / Geist Mono) — только пока смонтирован макет. */ -html { - --font-sans: 'Geist Variable', ui-sans-serif, system-ui, sans-serif; - --font-mono: 'Geist Mono Variable', ui-monospace, monospace; -} - -html, -html body { - font-family: var(--font-sans); -} - /* Видимый фокус и reduced motion — как в макете MikrotikManager v2. */ html [data-slot='sidebar-wrapper'] :focus-visible, html #main-content :focus-visible { @@ -130,16 +21,3 @@ html #main-content :focus-visible { transition: none !important; } } - -/* Шапка таблицы как на досках: 12px, лёгкая подложка. */ -html [data-slot='data-grid-table'] thead th, -html [data-slot='data-grid-table'] thead th :is(span, button, div) { - font-size: 0.75rem; - background: color-mix(in oklch, var(--muted) 30%, transparent); -} - -/* Затемнение под панелями без размытия — как на досках. */ -html :is([data-slot='sheet-overlay'], [data-slot='dialog-overlay'], [data-slot='alert-dialog-overlay']) { - background: oklch(0 0 0 / 55%); - backdrop-filter: none; -} diff --git a/apps/web/src/routes/_auth.admin.index.tsx b/apps/web/src/routes/_auth.admin.index.tsx index fa8a02c..ef8f391 100644 --- a/apps/web/src/routes/_auth.admin.index.tsx +++ b/apps/web/src/routes/_auth.admin.index.tsx @@ -6,7 +6,11 @@ import { useCallback, useState } from 'react' import { createFileRoute } from '@tanstack/react-router' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' +import { ShieldCheckIcon, UserCheckIcon, UserXIcon, UsersIcon } from 'lucide-react' import type { AdminUser, CreateUserRequest } from '@authportal/shared' +import { PageHead } from '@/components/portal/bits' +import { kpi } from '@/components/portal/kpi' +import { KpiStrip } from '@/components/portal/kpi-strip' import { AdminUsersGrid } from '@/components/reui-kit/admin-users-grid' import { CreateUserSheet } from '@/components/reui-kit/create-user-sheet' import { UserAccessSheet } from '@/components/reui-kit/user-access-sheet' @@ -173,8 +177,21 @@ function AdminUsersPage() { [invalidateUsers], ) + const admins = users.filter((u) => u.is_admin).length + const disabled = users.filter((u) => u.disabled).length + return ( <> + + {error ? (