优化web服务页面样式

This commit is contained in:
xintaofei
2026-03-25 23:52:01 +08:00
parent 20c5bb4944
commit 2d3d8d791f

View File

@@ -1,23 +1,49 @@
"use client" "use client"
import { useCallback, useEffect, useState } from "react" import { useCallback, useEffect, useState } from "react"
import { Check, Copy, Eye, EyeOff } from "lucide-react" import { Check, Copy, ExternalLink, Eye, EyeOff } from "lucide-react"
import { import {
startWebServer, startWebServer,
stopWebServer, stopWebServer,
getWebServerStatus, getWebServerStatus,
type WebServerInfo, type WebServerInfo,
} from "@/lib/api" } from "@/lib/api"
import { openUrl } from "@/lib/platform"
function CopyableCard({ function AddressCard({ label, value }: { label: string; value: string }) {
label, const [hovered, setHovered] = useState(false)
value,
masked, return (
}: { <div className="space-y-1.5">
label: string <div className="text-xs font-medium text-muted-foreground">{label}</div>
value: string <div
masked?: boolean className="group relative flex items-center rounded-md border bg-muted/40 px-3 py-2"
}) { onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
<code className="min-w-0 flex-1 truncate text-sm select-all">
{value}
</code>
<div
className={`ml-2 flex shrink-0 items-center gap-1 transition-opacity ${
hovered ? "opacity-100" : "opacity-0"
}`}
>
<button
type="button"
onClick={() => openUrl(value)}
className="inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground"
title="打开"
>
<ExternalLink className="h-3.5 w-3.5" />
</button>
</div>
</div>
</div>
)
}
function TokenCard({ label, value }: { label: string; value: string }) {
const [hovered, setHovered] = useState(false) const [hovered, setHovered] = useState(false)
const [copied, setCopied] = useState(false) const [copied, setCopied] = useState(false)
const [revealed, setRevealed] = useState(false) const [revealed, setRevealed] = useState(false)
@@ -28,10 +54,9 @@ function CopyableCard({
setTimeout(() => setCopied(false), 1500) setTimeout(() => setCopied(false), 1500)
} }
const displayValue = const displayValue = revealed
masked && !revealed ? value
? value.slice(0, 4) + "\u2022".repeat(Math.max(value.length - 4, 8)) : "\u2022".repeat(Math.max(value.length, 12))
: value
return ( return (
<div className="space-y-1.5"> <div className="space-y-1.5">
@@ -49,20 +74,18 @@ function CopyableCard({
hovered ? "opacity-100" : "opacity-0" hovered ? "opacity-100" : "opacity-0"
}`} }`}
> >
{masked && ( <button
<button type="button"
type="button" onClick={() => setRevealed((v) => !v)}
onClick={() => setRevealed((v) => !v)} className="inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground"
className="inline-flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground" title={revealed ? "隐藏" : "显示"}
title={revealed ? "隐藏" : "显示"} >
> {revealed ? (
{revealed ? ( <EyeOff className="h-3.5 w-3.5" />
<EyeOff className="h-3.5 w-3.5" /> ) : (
) : ( <Eye className="h-3.5 w-3.5" />
<Eye className="h-3.5 w-3.5" /> )}
)} </button>
</button>
)}
<button <button
type="button" type="button"
onClick={handleCopy} onClick={handleCopy}
@@ -194,13 +217,9 @@ export function WebServiceSettings() {
{isRunning && ( {isRunning && (
<div className="space-y-3"> <div className="space-y-3">
{status.addresses.map((addr) => ( {status.addresses.map((addr) => (
<CopyableCard key={addr} label="访问地址" value={addr} /> <AddressCard key={addr} label="访问地址" value={addr} />
))} ))}
<CopyableCard <TokenCard label="访问 Token" value={status.token} />
label="访问 Token"
value={status.token}
masked
/>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
Web 访 Token Web 访 Token
</p> </p>