diff --git a/src/app/globals.css b/src/app/globals.css index 20ed68e..36a2507 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,38 +1,53 @@ @import "tailwindcss"; -/* Tailwind v4: class-based dark mode (set by next-themes on ) */ @custom-variant dark (&:where(.dark, .dark *)); -/* Design tokens */ :root { --bg: #ffffff; --bg-subtle: #f8fafc; - --bg-card: #f1f5f9; + --bg-card: #fdfdfd; --border: #e2e8f0; --border-subtle: #f1f5f9; --text: #0f172a; --text-muted: #64748b; --text-faint: #94a3b8; --accent: #10b981; - --accent-dim: rgba(16,185,129,0.12); + --accent-dim: rgba(16,185,129,0.08); --accent-border: rgba(16,185,129,0.3); + --accent-glow: rgba(16,185,129,0.2); } .dark { --bg: #09090b; --bg-subtle: #111113; - --bg-card: #18181b; + --bg-card: #121214; --border: #27272a; --border-subtle: #1f1f22; --text: #f4f4f5; - --text-muted: #71717a; - --text-faint: #3f3f46; + --text-muted: #a1a1aa; + --text-faint: #52525b; --accent: #10b981; --accent-dim: rgba(16,185,129,0.1); --accent-border: rgba(16,185,129,0.25); + --accent-glow: rgba(16,185,129,0.15); } body { background: var(--bg); color: var(--text); } + +@utility bg-grid { + background-size: 32px 32px; + background-image: + linear-gradient(to right, var(--border) 1px, transparent 1px), + linear-gradient(to bottom, var(--border) 1px, transparent 1px); + mask-image: radial-gradient(circle at top center, black, transparent 80%); + -webkit-mask-image: radial-gradient(circle at top center, black, transparent 80%); +} + +@utility glass { + background-color: var(--bg-card); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); +} diff --git a/src/components/Dashboard.tsx b/src/components/Dashboard.tsx index 3f676fa..90d84b2 100644 --- a/src/components/Dashboard.tsx +++ b/src/components/Dashboard.tsx @@ -68,24 +68,25 @@ export default function Dashboard({ apps }: { apps: SshAppData[] }) { }, [apps, search, selectedTag]); return ( -
+
{/* Background accent */}
-
+
+
-
+
{/* Header */}
-
-
- +
+
+
-

+

SSH 管理台

-

+

Cloudflare Zero Trust · 浏览器终端

@@ -93,7 +94,7 @@ export default function Dashboard({ apps }: { apps: SshAppData[] }) {
{/* Stats row */} -
+
} label="主机总数" @@ -217,17 +218,22 @@ function StatCard({ accent?: boolean; }) { return ( -
+
+ {accent && ( +
+ )}
- {icon} +
+ {icon} +
{label}
@@ -239,45 +245,49 @@ function StatCard({ function HostCard({ app }: { app: SshAppData }) { return ( -
- +
+
+ {/* Top row */} -
-
-
- +
+
+
+
- {app.name} + {app.name} +
+
+
-
{/* Domain */} -
- - {app.domain} +
+ + {app.domain}
{/* Extra domains */} {app.domains.length > 1 && ( -
+
+ 另有 {app.domains.length - 1} 个域名
)} {/* Tags */} {app.tags.length > 0 && ( -
+
{app.tags.slice(0, 3).map((tag) => ( {tag} ))} {app.tags.length > 3 && ( - + +{app.tags.length - 3} )} @@ -285,20 +295,20 @@ function HostCard({ app }: { app: SshAppData }) { )} {/* Bottom info */} -
-
- +
+
+ {timeAgo(app.updatedAt)}
{app.sessionDuration && ( - TTL {app.sessionDuration} + TTL {app.sessionDuration} )}
{/* Metrics widget (outside the connect link) */} {app.metricsUrl && ( -
+
)} diff --git a/src/components/TunnelList.tsx b/src/components/TunnelList.tsx index 9131843..3d7627d 100644 --- a/src/components/TunnelList.tsx +++ b/src/components/TunnelList.tsx @@ -56,41 +56,45 @@ export default function TunnelList({ tunnels }: { tunnels: Tunnel[] }) { ).length; return ( -
+
+ {/* Dynamic Backgrounds */}
-
+
+
-
+
{/* Header */} -
-
- +
+
+
-

隧道列表

-

- 共 {tunnels.length} 条 · {activeCount} 条在线 +

隧道列表

+

+ 共 {tunnels.length} 条 · {activeCount} 条在线

{/* Search */} -
- +
+ setSearch(e.target.value)} - className="w-full rounded-xl border border-[var(--border)] bg-[var(--bg-subtle)] pl-10 pr-4 py-2.5 text-sm text-[var(--text)] placeholder:text-[var(--text-faint)] outline-none transition focus:border-[var(--accent-border)] focus:ring-1 focus:ring-[var(--accent-dim)]" + className="w-full rounded-2xl border border-[var(--border)] bg-white/60 dark:bg-zinc-900/60 backdrop-blur-xl pl-11 pr-4 py-3.5 text-[var(--text)] placeholder:text-[var(--text-faint)] outline-none transition-all focus:border-[var(--accent-border)] focus:ring-2 focus:ring-[var(--accent-glow)] shadow-sm" />
{/* Empty */} {filtered.length === 0 && (
- +
+ +

未找到隧道

@@ -98,29 +102,36 @@ export default function TunnelList({ tunnels }: { tunnels: Tunnel[] }) { )} {/* Tunnel cards */} -
+
{filtered.map((tunnel) => { const isActive = tunnel.connections && tunnel.connections.length > 0; return (
-
+ {isActive && ( +
+ )} + +
{/* Left */}
-
+
{isActive ? ( - +
+ + +
) : ( - + )} - + {tunnel.name}
-

+

{tunnel.id}

{/* Right meta */} -
-
- +
+
+ 创建于 {timeAgo(tunnel.created_at)}
@@ -145,14 +156,14 @@ export default function TunnelList({ tunnels }: { tunnels: Tunnel[] }) { {/* Connections */} {isActive && tunnel.connections.length > 0 && ( -
+
{tunnel.connections.map((conn) => (
- - {conn.origin_ip} + + {conn.origin_ip} · {timeAgo(conn.opened_at)}