diff --git a/src/components/settings/settings-shell.tsx b/src/components/settings/settings-shell.tsx index 947d954..2e499c3 100644 --- a/src/components/settings/settings-shell.tsx +++ b/src/components/settings/settings-shell.tsx @@ -64,16 +64,16 @@ const SETTINGS_NAV_ITEMS: SettingsNavItem[] = [ labelKey: "version_control", icon: GitBranch, }, - { - href: "/settings/system", - labelKey: "system", - icon: Settings, - }, { href: "/settings/web-service", labelKey: "web_service", icon: Globe, }, + { + href: "/settings/system", + labelKey: "system", + icon: Settings, + }, ] interface SettingsShellProps { diff --git a/src/components/settings/web-service-settings.tsx b/src/components/settings/web-service-settings.tsx index f010a9f..e50da91 100644 --- a/src/components/settings/web-service-settings.tsx +++ b/src/components/settings/web-service-settings.tsx @@ -1,6 +1,7 @@ "use client" import { useCallback, useEffect, useState } from "react" +import { Check, Copy, Eye, EyeOff } from "lucide-react" import { startWebServer, stopWebServer, @@ -8,6 +9,78 @@ import { type WebServerInfo, } from "@/lib/api" +function CopyableCard({ + label, + value, + masked, +}: { + label: string + value: string + masked?: boolean +}) { + const [hovered, setHovered] = useState(false) + const [copied, setCopied] = useState(false) + const [revealed, setRevealed] = useState(false) + + function handleCopy() { + navigator.clipboard.writeText(value) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } + + const displayValue = + masked && !revealed + ? value.slice(0, 4) + "\u2022".repeat(Math.max(value.length - 4, 8)) + : value + + return ( +
+
{label}
+
setHovered(true)} + onMouseLeave={() => setHovered(false)} + > + + {displayValue} + +
+ {masked && ( + + )} + +
+
+
+ ) +} + export function WebServiceSettings() { const [status, setStatus] = useState(null) const [port, setPort] = useState("3080") @@ -61,20 +134,6 @@ export function WebServiceSettings() { } } - function copyToken() { - if (status?.token) { - navigator.clipboard.writeText(status.token) - } - } - - function copyUrl() { - if (status?.addresses?.[1]) { - navigator.clipboard.writeText(status.addresses[1]) - } else if (status?.addresses?.[0]) { - navigator.clipboard.writeText(status.addresses[0]) - } - } - const isRunning = status !== null return ( @@ -133,41 +192,15 @@ export function WebServiceSettings() { {/* Connection info */} {isRunning && ( -
-
-
- 访问地址 -
- {status.addresses.map((addr) => ( -
- {addr} -
- ))} - -
- -
-
- 访问 Token -
-
- - {status.token} - - -
-
- +
+ {status.addresses.map((addr) => ( + + ))} +

Web 客户端首次访问时需输入此 Token