feat(ui): refresh panel landing with user center summary (#352)

This commit is contained in:
shenlan 2025-10-01 17:05:55 +08:00 committed by GitHub
parent f414e96508
commit af124368f0
4 changed files with 131 additions and 43 deletions

View File

@ -44,8 +44,8 @@ export default function Header({ onMenu }: HeaderProps) {
<div className="flex flex-1 items-center justify-end gap-4 md:justify-between">
<div className="hidden flex-col text-sm text-gray-500 md:flex">
<span className="font-semibold text-gray-900">XControl Control Center</span>
<span>Unified governance for admins and end users</span>
<span className="font-semibold text-gray-900">XControl User Center</span>
<span>Personalized access across every service touchpoint</span>
</div>
<div className="flex items-center gap-3">
<span className={`rounded-full px-3 py-1 text-xs font-semibold ${badgeClasses}`}>{statusBadge}</span>

View File

@ -32,58 +32,58 @@ interface NavSection {
const navSections: NavSection[] = [
{
title: 'Overview',
title: '用户中心',
items: [
{
href: '/panel',
label: 'Dashboard',
description: 'Control center snapshot',
description: '专属于你的信息总览',
icon: Home,
},
],
},
{
title: 'Admin Toolkit',
title: '功能特性',
items: [
{
href: '/panel/agent',
label: 'Agents',
description: 'Manage runtime nodes',
description: '管理运行时节点',
icon: Server,
},
{
href: '/panel/api',
label: 'APIs',
description: 'Observe backend services',
description: '洞察后端服务',
icon: Code,
},
{
href: '/panel/subscription',
label: 'Subscription',
description: 'Billing & plan controls',
description: '套餐与计费控制',
icon: CreditCard,
},
{
href: '/panel/xray',
label: 'XRay',
description: 'Inspect network policies',
description: '审视网络策略',
icon: Search,
},
],
},
{
title: 'Identity & Access',
title: '权限设置',
items: [
{
href: '/panel/account',
label: 'Accounts',
description: 'Directory & MFA settings',
description: '目录与多因素设置',
icon: User,
},
{
href: '/panel/ldp',
label: 'LDP',
description: 'Low-latency identity plane',
description: '低时延身份平面',
icon: Shield,
},
],
@ -104,8 +104,8 @@ export default function Sidebar({ className = '', onNavigate }: SidebarProps) {
<aside className={`flex h-full w-72 flex-col gap-6 border-r border-gray-200 bg-white/90 p-6 shadow-lg backdrop-blur ${className}`}>
<div className="space-y-1">
<p className="text-xs font-semibold uppercase tracking-wide text-purple-600">XControl</p>
<h2 className="text-lg font-bold text-gray-900">Control Center</h2>
<p className="text-sm text-gray-500">Switch between admin and self-service spaces.</p>
<h2 className="text-lg font-bold text-gray-900">User Center</h2>
<p className="text-sm text-gray-500">在同一处掌控权限与功能特性。</p>
</div>
<nav className="flex flex-1 flex-col gap-6 overflow-y-auto">

View File

@ -0,0 +1,115 @@
'use client'
import { useCallback, useMemo, useState } from 'react'
import { Copy } from 'lucide-react'
import Card from './Card'
import { useUser } from '@lib/userStore'
function resolveDisplayName(
user: {
name?: string
username: string
email: string
} | null,
) {
if (!user) {
return '访客'
}
if (user.name && user.name.trim().length > 0) {
return user.name.trim()
}
if (user.username && user.username.trim().length > 0) {
return user.username.trim()
}
return user.email
}
export default function UserOverview() {
const { user, isLoading } = useUser()
const [copied, setCopied] = useState(false)
const displayName = useMemo(() => resolveDisplayName(user), [user])
const uuid = user?.id ?? '—'
const username = user?.username ?? '—'
const email = user?.email ?? '—'
const handleCopy = useCallback(async () => {
if (!user?.id) {
return
}
try {
if (typeof navigator !== 'undefined' && navigator.clipboard && 'writeText' in navigator.clipboard) {
await navigator.clipboard.writeText(user.id)
} else {
const textarea = document.createElement('textarea')
textarea.value = user.id
textarea.style.position = 'fixed'
textarea.style.opacity = '0'
document.body.appendChild(textarea)
textarea.focus()
textarea.select()
document.execCommand('copy')
document.body.removeChild(textarea)
}
setCopied(true)
setTimeout(() => setCopied(false), 2000)
} catch (error) {
console.warn('Failed to copy UUID', error)
}
}, [user?.id])
return (
<div className="space-y-6">
<div>
<h1 className="text-3xl font-bold text-gray-900">用户中心</h1>
<p className="mt-2 text-sm text-gray-600">
{isLoading ? '正在加载你的专属空间…' : user ? `欢迎回来,${displayName}。` : '请登录后解锁属于你的用户中心。'}
</p>
<p className="mt-1 text-xs text-gray-500">
UUID 是你在 XControl 中的唯一身份凭证,后续的所有服务都与它神秘地关联在一起。
</p>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
<Card>
<div className="flex items-start justify-between gap-4">
<div>
<p className="text-xs font-semibold uppercase tracking-wide text-purple-600">UUID</p>
<p className="mt-1 break-all text-base font-medium text-gray-900">{uuid}</p>
</div>
<button
type="button"
onClick={handleCopy}
disabled={!user?.id}
className="inline-flex items-center gap-2 rounded-full border border-gray-300 px-3 py-1 text-xs font-medium text-gray-700 transition hover:border-purple-400 hover:text-purple-600 disabled:cursor-not-allowed disabled:border-gray-200 disabled:text-gray-400"
aria-label="复制 UUID"
>
<Copy className="h-3.5 w-3.5" />
{copied ? '已复制' : '复制'}
</button>
</div>
<p className="mt-3 text-xs text-gray-500">
这是一串只属于你的身份指纹,让平台中的每项服务都能准确识别你。
</p>
</Card>
<Card>
<p className="text-xs font-semibold uppercase tracking-wide text-purple-600">UserName</p>
<p className="mt-1 text-base font-medium text-gray-900">{username}</p>
<p className="mt-3 text-xs text-gray-500">面向系统的登录凭据,展示给自动化流程与团队成员。</p>
</Card>
<Card>
<p className="text-xs font-semibold uppercase tracking-wide text-purple-600">UserEmail</p>
<p className="mt-1 break-all text-base font-medium text-gray-900">{email}</p>
<p className="mt-3 text-xs text-gray-500">用来接收通知、验证操作,并保持与你的 UUID 一致的信任链路。</p>
</Card>
</div>
</div>
)
}

View File

@ -1,34 +1,7 @@
export const dynamic = 'error'
import Card from './components/Card'
import UserOverview from './components/UserOverview'
export default function PanelHome() {
return (
<>
<div>
<h1 className="text-3xl font-bold text-gray-900">Dashboard</h1>
<p className="mt-2 text-sm text-gray-600">
Welcome to the XControl control center. Switch between administrator modules and self-service experiences to manage
your platform with confidence.
</p>
</div>
<div className="grid gap-6 md:grid-cols-2">
<Card>
<h2 className="text-lg font-semibold text-gray-900">Administrator modules</h2>
<p className="mt-2 text-sm text-gray-600">
Toggle core services, observe infrastructure health, and govern network gateways. Each module mirrors the original
admin panel layout so existing workflows continue to work.
</p>
</Card>
<Card>
<h2 className="text-lg font-semibold text-gray-900">Self-service experiences</h2>
<p className="mt-2 text-sm text-gray-600">
Empower end users with password resets, MFA configuration, and delegated group management without leaving the
homepage theme.
</p>
</Card>
</div>
</>
)
return <UserOverview />
}