From 4531e5366bb652e6db116a3848b1d25da1c796e4 Mon Sep 17 00:00:00 2001 From: SerinaNya <34389622+SerinaNya@users.noreply.github.com> Date: Sun, 23 Aug 2026 23:57:41 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20implement=20web=20overview,?= =?UTF-8?q?=20connections,=20and=20settings=20pages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Overview page with realtime metrics, SRv6 SID display, and TUN alert - Add Connections page with card/table views and action menus - Add Settings page with 4 tabs, dynamic item lists, and auto-connect toggle - Implement HashRouter navigation and SSE live event stream integration - Integrate Base UI-based shadcn components and Toaster notifications - Support enableTUN flag and refactor connection table naming conventions --- src/App.tsx | 35 +- src/components/ui/field.tsx | 238 ++++++ src/components/ui/label.tsx | 20 + src/components/ui/select.tsx | 199 +++++ src/components/ui/separator.tsx | 2 - src/components/ui/slider.tsx | 52 ++ src/components/ui/switch.tsx | 32 + src/components/ui/tabs.tsx | 80 ++ src/components/ui/textarea.tsx | 18 + src/components/ui/toast.tsx | 232 ++++++ src/hooks/use-klalb-config.ts | 85 ++ src/pages/overview.tsx | 5 +- src/pages/settings.tsx | 1288 +++++++++++++++++++++++++++++++ src/types/api.ts | 39 + 14 files changed, 2305 insertions(+), 20 deletions(-) create mode 100644 src/components/ui/field.tsx create mode 100644 src/components/ui/label.tsx create mode 100644 src/components/ui/select.tsx create mode 100644 src/components/ui/slider.tsx create mode 100644 src/components/ui/switch.tsx create mode 100644 src/components/ui/tabs.tsx create mode 100644 src/components/ui/textarea.tsx create mode 100644 src/components/ui/toast.tsx create mode 100644 src/hooks/use-klalb-config.ts create mode 100644 src/pages/settings.tsx diff --git a/src/App.tsx b/src/App.tsx index 06d6606..87ba06b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,10 +1,12 @@ import { useMemo } from 'react' import { SidebarProvider, SidebarInset } from '@/components/ui/sidebar' import { TooltipProvider } from '@/components/ui/tooltip' +import { Toaster } from '@/components/ui/toast' import { AppSidebar } from '@/components/layout/app-sidebar' import { AppHeader } from '@/components/layout/app-header' import { OverviewPage } from '@/pages/overview' import { ConnectionsPage } from '@/pages/connections' +import { SettingsPage } from '@/pages/settings' import { useKlalbSSE } from '@/hooks/use-klalb-sse' import { useHashRoute } from '@/hooks/use-hash-route' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' @@ -68,22 +70,27 @@ export function App() { /> )} - {currentTab !== 'overview' && currentTab !== 'connections' && ( -
- - - {currentTab} 模块 - - -

- 该模块即将实现。当前可查看「总览」与「连接」进行实时监控与管理。 -

-
-
-
- )} + {currentTab === 'settings' && } + + {currentTab !== 'overview' && + currentTab !== 'connections' && + currentTab !== 'settings' && ( +
+ + + {currentTab} 模块 + + +

+ 该模块即将实现。当前可查看「总览」、「连接」与「系统配置」进行实时监控与管理。 +

+
+
+
+ )} + ) diff --git a/src/components/ui/field.tsx b/src/components/ui/field.tsx new file mode 100644 index 0000000..887fa2f --- /dev/null +++ b/src/components/ui/field.tsx @@ -0,0 +1,238 @@ +"use client" + +import { useMemo } from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" +import { Label } from "@/components/ui/label" +import { Separator } from "@/components/ui/separator" + +function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) { + return ( +
[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3", + className + )} + {...props} + /> + ) +} + +function FieldLegend({ + className, + variant = "legend", + ...props +}: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) { + return ( + + ) +} + +function FieldGroup({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +const fieldVariants = cva( + "group/field flex w-full gap-2 data-[invalid=true]:text-destructive", + { + variants: { + orientation: { + vertical: "flex-col *:w-full [&>.sr-only]:w-auto", + horizontal: + "flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + responsive: + "flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px", + }, + }, + defaultVariants: { + orientation: "vertical", + }, + } +) + +function Field({ + className, + orientation = "vertical", + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function FieldContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function FieldLabel({ + className, + ...props +}: React.ComponentProps) { + return ( +