Files
web/src/app/admin/layout.tsx
2025-04-09 17:17:39 +08:00

101 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {ReactNode} from 'react'
import Image from 'next/image'
import logo from '@/assets/logo.webp'
import Profile from '@/app/admin/_server/profile'
import {merge} from '@/lib/utils'
import Link from 'next/link'
import {getProfile} from '@/actions/auth/auth'
import {redirect} from 'next/navigation'
export type DashboardLayoutProps = {
children: ReactNode
}
export default async function DashboardLayout(props: DashboardLayoutProps) {
const profile = await getProfile()
if (!profile) {
return redirect('/login')
}
return (
<div className={`h-screen flex flex-col overflow-hidden min-w-7xl overflow-y-hidden relative`}>
{/* background */}
<div className={`-z-10 absolute inset-0 overflow-hidden`}>
<div className={`absolute w-screen h-screen bg-gray-50`}></div>
<div className={`absolute w-[2000px] h-[2000px] -left-[1000px] -top-[1000px] bg-radial from-blue-50 from-10% to-transparent to-50%`}></div>
<div className={`absolute w-[2000px] h-[2000px] -right-[1000px] -top-[1000px] bg-radial from-blue-50 from-10% to-transparent to-50%`}></div>
<div className={`absolute w-[2000px] h-[2000px] left-[calc(50%-1000px)] -bottom-[1000px] bg-radial from-blue-50 from-10% to-transparent to-50%`}></div>
</div>
{/* content */}
<header className={`flex-none basis-20 flex items-stretch`}>
{/* logo */}
<div className={`flex-none basis-60 flex items-center justify-center`}>
<Image src={logo} alt={`logo`} height={40}/>
</div>
{/* title */}
<div className={`flex-auto overflow-hidden flex items-center`}>
</div>
{/* profile */}
<div className={`flex-none basis-80 flex items-center justify-end`}>
<Profile/>
</div>
</header>
<div className={`flex-auto overflow-hidden flex items-stretch gap-4`}>
<nav className={merge(
`flex-none basis-60 rounded-tr-xl bg-white p-4`,
`flex flex-col overflow-auto`,
)}>
<NavItem href={'/admin'} icon={`🏠`} label={`账户总览`}/>
<NavTitle label={`个人信息`}/>
<NavItem href={`/admin`} icon={`📝`} label={`修改信息`}/>
<NavItem href={`/admin/identify`} icon={`🆔`} label={`实名认证`}/>
<NavItem href={`/admin/whitelist`} icon={`🔒`} label={`白名单`}/>
<NavItem href={`/admin`} icon={`💰`} label={`我的账单`}/>
<NavTitle label={`套餐管理`}/>
<NavItem href={`/admin/purchase`} icon={`🛒`} label={`购买套餐`}/>
<NavItem href={`/admin/resources`} icon={`📦`} label={`我的套餐`}/>
<NavTitle label={`IP 管理`}/>
<NavItem href={`/admin/extract`} icon={`📤`} label={`IP提取`}/>
<NavItem href={`/admin`} icon={`📜`} label={`IP提取记录`}/>
<NavItem href={`/admin`} icon={`👁️`} label={`查看提取IP`}/>
<NavItem href={`/admin`} icon={`🗂️`} label={`查看使用IP`}/>
</nav>
{props.children}
</div>
</div>
)
}
function NavTitle(props: {
label: string
}) {
return (
<p className={`px-4 py-2 text-sm text-gray-500`}>
{props.label}
</p>
)
}
function NavItem(props: {
href: string
icon?: ReactNode
label: string
}) {
return (
<Link className={merge(
`px-4 py-2 flex items-center rounded-md`,
`hover:bg-gray-100`,
)} href={props.href}>
<span className={`w-6 h-6 flex items-center justify-center`}>{props.icon}</span>
<span className={`ml-2`}>{props.label}</span>
</Link>
)
}