From 29e096862a172acf6493aeebff5477337234c670 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Fri, 17 Jul 2026 23:14:35 +0700 Subject: [PATCH] =?UTF-8?q?feat(web):=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20AppShell=20=D0=B8=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B9?= =?UTF-8?q?=20=D1=8D=D0=BB=D0=B5=D0=BC=D0=B5=D0=BD=D1=82=20EvoBGP=20=D0=B2?= =?UTF-8?q?=20App=20Switcher?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Обновлены стили компонента AppShell для улучшения макета и адаптивности. - Добавлен новый элемент EvoBGP в конфигурацию App Switcher с соответствующими параметрами. - Обновлена документация интерфейса для отражения изменений в AppShell и новых элементах навигации. --- apps/web/src/components/layout/app-shell.tsx | 25 ++++-- apps/web/src/components/layout/apps-menu.tsx | 93 ++++++++++++++++++++ apps/web/src/lib/app-switcher-config.ts | 8 ++ docs/ui-design-contract.md | 25 +++++- packages/db/src/repositories/settings.ts | 8 ++ 5 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 apps/web/src/components/layout/apps-menu.tsx diff --git a/apps/web/src/components/layout/app-shell.tsx b/apps/web/src/components/layout/app-shell.tsx index 37833f3..0f093a1 100644 --- a/apps/web/src/components/layout/app-shell.tsx +++ b/apps/web/src/components/layout/app-shell.tsx @@ -42,15 +42,17 @@ import { Badge } from '@cfdm/ui/components/badge' import { Link, useRouterState } from '@tanstack/react-router' import { useQuery } from '@tanstack/react-query' -import { useState, type ReactNode } from 'react' +import { useState, type CSSProperties, type ReactNode } from 'react' import { ModeToggle } from '@/components/mode-toggle' import { SystemMonitorPopover } from '@/components/layout/system-monitor-popover' +import { AppsMenu } from '@/components/layout/apps-menu' import { AppSwitcher } from '@/components/app-switcher' import { GlobalSearch, GlobalSearchTrigger, useGlobalSearchHotkey } from '@/components/global-search' import { dashboardStatsQueryOptions } from '@/queries/dashboard' import { formatRelativeSyncTime } from '@/lib/sync-format' import { TruncatedText } from '@/components/truncated-text' +import { cn } from '@cfdm/ui/lib/utils' interface NavItem { to: string @@ -146,7 +148,19 @@ export function AppShell({ children }: { children: ReactNode }) { })) return ( - + @@ -206,8 +220,8 @@ export function AppShell({ children }: { children: ReactNode }) { -
- +
+ @@ -231,11 +245,12 @@ export function AppShell({ children }: { children: ReactNode }) { {stats.issuesCount} проблем ) : null} +
-
{children}
+
{children}
diff --git a/apps/web/src/components/layout/apps-menu.tsx b/apps/web/src/components/layout/apps-menu.tsx new file mode 100644 index 0000000..6a09e26 --- /dev/null +++ b/apps/web/src/components/layout/apps-menu.tsx @@ -0,0 +1,93 @@ +import { Link } from '@tanstack/react-router' +import { LayoutGridIcon } from 'lucide-react' +import { Button } from '@cfdm/ui/components/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@cfdm/ui/components/dropdown-menu' +import { + APP_SWITCHER_ICONS, + CURRENT_APP_ID, +} from '@/lib/app-switcher-config' +import { useAppSwitcherConfig } from '@/hooks/use-app-switcher' + +/** Header apps grid — app-shell-12 AppsMenu. @see https://reui.io/preview/base/app-shell-12 */ +export function AppsMenu() { + const { config, isLoading } = useAppSwitcherConfig() + + return ( + + + } + > + + + + + + {isLoading ? 'Загрузка…' : config.menuLabel} + +
+ {config.apps.map((app) => { + const Icon = APP_SWITCHER_ICONS[app.icon] + const isCurrent = app.id === CURRENT_APP_ID + + if (isCurrent) { + return ( + + + + {app.name} + + ) + } + + return ( + } + className="h-auto flex-col gap-1.5 py-3 text-center [&_svg]:size-5" + > + + + {app.name} + + ) + })} +
+ + } + className="justify-center text-sm font-medium" + > + Настроить приложения + +
+
+
+ ) +} diff --git a/apps/web/src/lib/app-switcher-config.ts b/apps/web/src/lib/app-switcher-config.ts index 434910f..c0dd8fc 100644 --- a/apps/web/src/lib/app-switcher-config.ts +++ b/apps/web/src/lib/app-switcher-config.ts @@ -58,6 +58,14 @@ export const DEFAULT_APP_SWITCHER_CONFIG: AppSwitcherConfig = { icon: 'cloud', shortcut: '⌘2', }, + { + id: 'evobgp', + name: 'EvoBGP', + subtitle: 'BGP маршрутизация', + url: 'http://192.168.100.67:3000', + icon: 'globe', + shortcut: '⌘3', + }, ], } diff --git a/docs/ui-design-contract.md b/docs/ui-design-contract.md index d800957..aa35fe0 100644 --- a/docs/ui-design-contract.md +++ b/docs/ui-design-contract.md @@ -17,7 +17,7 @@ Ops / list / dashboard / detail / settings — только **Frame**, не shad | Зона | Block | Preview | |------|-------|---------| -| Shell | `app-shell-12` (+ cmdk/monitor где нужно) | https://reui.io/preview/base/app-shell-12 | +| Shell | `app-shell-12` (+ cmdk/monitor где нужно) | https://reui.io/preview/base/app-shell-12 · https://reui.io/preview/base/app-shell-7 | | KPI | horizontal compact hybrid (icon left + label/Badge + value ± variant; EvoBGP visual) | https://reui.io/preview/base/stats-12 | | Dashboard | `dashboard-1` | https://reui.io/preview/base/dashboard-1 | | Lists | `data-grid-filtering-2` | https://reui.io/preview/base/data-grid-filtering-2 | @@ -47,9 +47,28 @@ Ops / list / dashboard / detail / settings — только **Frame**, не shad Gating: DB preference `showQuickActions` / `show_quick_actions` / `ui_show_quick_actions` (default `true`). +## Shared App Shell chrome + +Эталон: CFDM + ReUI [app-shell-12](https://reui.io/preview/base/app-shell-12) · monitor/switchers [app-shell-7](https://reui.io/preview/base/app-shell-7). + +При переключении между vps-tracker / CFDM / EvoBGP меняются **только** sidebar nav и `main` content. ClassNames chrome идентичны. + +| Токен / зона | Значение | +|--------------|----------| +| `--sidebar-width` | `240px` | +| Sidebar accent | primary **14%** mix + transparent border | +| Header | `h-12`, `sticky`, `border-b`, `px-4 md:px-6` (без blur / без `h-16`) | +| Header right | **AppsMenu** → **SystemMonitorPopover** → **ModeToggle** | +| `main` | `gap-4 md:gap-6`, `px-4 py-4 md:px-6 md:py-5` | +| Sidebar header | `AppSwitcher` (не static brand) | + +App Switcher ids: `vps-tracker` · `cfdm` · `evobgp`. Override: `VITE_APP_SWITCHER` JSON. + +QuickActionGrid icons: только semantic **text** (`text-info` / `text-primary` / …) на kit `bg-muted` — без solid `bg-primary` fills. Preview: [stats-12](https://reui.io/preview/base/stats-12). + ## System monitor -`SystemMonitorPopover` in app header next to `ModeToggle` (EvoBGP pattern: pill «Система» + Норма/Внимание). Preview shell: https://reui.io/preview/base/app-shell-12 +`SystemMonitorPopover` in app header next to `ModeToggle` (после AppsMenu). Preview: https://reui.io/preview/base/app-shell-12 · https://reui.io/preview/base/app-shell-7 ## MCP workflow @@ -63,7 +82,7 @@ Primitives: MCP `plugin-shadcn-shadcn` + `@cfdm/ui` / `@evobgp/ui`. ## Spacing -- Main: `gap-4 md:gap-6`, `px-4 md:px-6` +- AppShell main: `gap-4 md:gap-6`, `px-4 py-4 md:px-6 md:py-5` (shared chrome) - No `space-y-*` / `space-x-*` — use `flex` + `gap-*` - Max 1 primary CTA per screen - Semantic tokens only (`variant="success"|"info"|"warning"`) — no raw `bg-emerald-*` diff --git a/packages/db/src/repositories/settings.ts b/packages/db/src/repositories/settings.ts index a5179cd..2433af1 100644 --- a/packages/db/src/repositories/settings.ts +++ b/packages/db/src/repositories/settings.ts @@ -26,6 +26,14 @@ const DEFAULT_APP_SWITCHER: AppSwitcherConfig = { icon: 'cloud', shortcut: '⌘2', }, + { + id: 'evobgp', + name: 'EvoBGP', + subtitle: 'BGP маршрутизация', + url: 'http://192.168.100.67:3000', + icon: 'globe', + shortcut: '⌘3', + }, ], }