From 3e57728ddcddb1335365e16541692f6957eaa3f1 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Fri, 26 Jun 2026 15:50:30 +0700 Subject: [PATCH] =?UTF-8?q?feat(web):=20=D1=82=D1=91=D0=BC=D0=BD=D0=B0?= =?UTF-8?q?=D1=8F=20=D1=82=D0=B5=D0=BC=D0=B0=20(system/manual)=20=D0=B8=20?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D1=81=20=D0=BB=D0=BE=D0=B3=D0=BE=D1=82=D0=B8?= =?UTF-8?q?=D0=BF=D0=B0=20=D0=B2=20icon-=D1=80=D0=B5=D0=B6=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=20=D1=81=D0=B0=D0=B9=D0=B4=D0=B1=D0=B0=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ThemeProvider (next-themes, attribute=class, defaultTheme=system) - ModeToggle в header: светлая / тёмная / системная - suppressHydrationWarning на против FOUC - логотип в SidebarHeader через SidebarMenuButton size="lg" (корректное схлопывание в icon-режиме, aspect-square для иконки) Co-authored-by: Cursor --- apps/web/index.html | 2 +- apps/web/src/components/layout/app-shell.tsx | 30 ++++++++++++++------ apps/web/src/components/mode-toggle.tsx | 29 +++++++++++++++++++ apps/web/src/components/theme-provider.tsx | 15 ++++++++++ apps/web/src/main.tsx | 11 ++++--- 5 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 apps/web/src/components/mode-toggle.tsx create mode 100644 apps/web/src/components/theme-provider.tsx diff --git a/apps/web/index.html b/apps/web/index.html index 47cefdc..4a1e835 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -1,5 +1,5 @@ - + diff --git a/apps/web/src/components/layout/app-shell.tsx b/apps/web/src/components/layout/app-shell.tsx index 2544454..430d540 100644 --- a/apps/web/src/components/layout/app-shell.tsx +++ b/apps/web/src/components/layout/app-shell.tsx @@ -37,6 +37,8 @@ import { Separator } from '@cfdm/ui/components/separator' import { Link, useRouterState } from '@tanstack/react-router' import type { ReactNode } from 'react' +import { ModeToggle } from '@/components/mode-toggle' + interface NavItem { to: string label: string @@ -68,15 +70,22 @@ export function AppShell({ children }: { children: ReactNode }) { -
-
- -
-
- VPS Tracker - Учёт виртуальных серверов -
-
+ + + }> +
+ +
+
+ VPS Tracker + Учёт виртуальных серверов +
+
+
+
@@ -116,6 +125,9 @@ export function AppShell({ children }: { children: ReactNode }) { +
+ +
{children}
diff --git a/apps/web/src/components/mode-toggle.tsx b/apps/web/src/components/mode-toggle.tsx new file mode 100644 index 0000000..b7059fc --- /dev/null +++ b/apps/web/src/components/mode-toggle.tsx @@ -0,0 +1,29 @@ +import { Moon, Sun } from 'lucide-react' +import { useTheme } from 'next-themes' + +import { Button } from '@cfdm/ui/components/button' +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@cfdm/ui/components/dropdown-menu' + +export function ModeToggle() { + const { setTheme } = useTheme() + + return ( + + }> + + + Сменить тему + + + setTheme('light')}>Светлая + setTheme('dark')}>Тёмная + setTheme('system')}>Системная + + + ) +} diff --git a/apps/web/src/components/theme-provider.tsx b/apps/web/src/components/theme-provider.tsx new file mode 100644 index 0000000..702c7e0 --- /dev/null +++ b/apps/web/src/components/theme-provider.tsx @@ -0,0 +1,15 @@ +import { ThemeProvider as NextThemesProvider } from 'next-themes' +import type { ReactNode } from 'react' + +export function ThemeProvider({ children }: { children: ReactNode }) { + return ( + + {children} + + ) +} diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx index c38d918..1f93d91 100644 --- a/apps/web/src/main.tsx +++ b/apps/web/src/main.tsx @@ -8,6 +8,7 @@ import '@cfdm/ui/globals.css' import { queryClient } from '@/lib/queryClient' import { createRouter } from '@/lib/router' +import { ThemeProvider } from '@/components/theme-provider' const router = createRouter({ context: { queryClient } }) @@ -16,9 +17,11 @@ if (!rootEl) throw new Error('Root element #root not found') createRoot(rootEl).render( - - - - + + + + + + , )