Add Next.js admin panel skeleton

This commit is contained in:
shenlan 2025-06-18 10:51:38 +08:00
parent d5bd14f447
commit 6db5d43891
17 changed files with 163 additions and 0 deletions

View File

@ -46,3 +46,6 @@ styles/
```
生成的 `out/` 目录即可作为纯静态网站部署。
## 示例代码结构
本仓库 `ui/nextjs` 目录提供了一套最简参考实现,可直接 `npm run build && npx next export` 编译到 `ui/dist` 供 Go 服务嵌入。

View File

@ -0,0 +1,10 @@
export const dynamic = 'force-static'
export default function AgentPage() {
return (
<div>
<h1 className="text-xl font-semibold mb-2">Agent Management</h1>
<p>Manage node agents here.</p>
</div>
)
}

View File

@ -0,0 +1,10 @@
export const dynamic = 'force-static'
export default function APIPage() {
return (
<div>
<h1 className="text-xl font-semibold mb-2">API Status</h1>
<p>View backend API health here.</p>
</div>
)
}

15
ui/nextjs/app/layout.tsx Normal file
View File

@ -0,0 +1,15 @@
import '../styles/globals.css'
import Sidebar from '../components/Sidebar'
export const dynamic = 'force-static'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className="flex min-h-screen">
<Sidebar />
<main className="flex-1 p-4">{children}</main>
</body>
</html>
)
}

10
ui/nextjs/app/page.tsx Normal file
View File

@ -0,0 +1,10 @@
export const dynamic = 'force-static'
export default function Home() {
return (
<div className="space-y-4">
<h1 className="text-2xl font-semibold">Dashboard</h1>
<p>Welcome to XControl admin panel.</p>
</div>
)
}

View File

@ -0,0 +1,10 @@
export const dynamic = 'force-static'
export default function SubscriptionPage() {
return (
<div>
<h1 className="text-xl font-semibold mb-2">Subscription</h1>
<p>Manage vless subscriptions.</p>
</div>
)
}

View File

@ -0,0 +1,10 @@
export const dynamic = 'force-static'
export default function XRayPage() {
return (
<div>
<h1 className="text-xl font-semibold mb-2">XRay</h1>
<p>Control XRay configuration.</p>
</div>
)
}

View File

@ -0,0 +1,7 @@
export default function Card({ children }: { children: React.ReactNode }) {
return (
<div className="p-4 border rounded shadow-sm bg-white">
{children}
</div>
)
}

View File

@ -0,0 +1,7 @@
export default function Header() {
return (
<header className="p-4 border-b">
<h1 className="text-lg font-bold">XControl Admin</h1>
</header>
)
}

View File

@ -0,0 +1,21 @@
import Link from 'next/link'
const menu = [
{ href: '/', label: 'Home' },
{ href: '/agent', label: 'Agent' },
{ href: '/api', label: 'API' },
{ href: '/subscription', label: 'Subscription' },
{ href: '/xray', label: 'XRay' },
]
export default function Sidebar() {
return (
<nav className="w-48 bg-gray-100 p-4 space-y-2">
{menu.map(m => (
<Link key={m.href} href={m.href} className="block p-2 rounded hover:bg-gray-200">
{m.label}
</Link>
))}
</nav>
)
}

5
ui/nextjs/lib/api.ts Normal file
View File

@ -0,0 +1,5 @@
export async function fetchJSON<T>(url: string): Promise<T> {
const res = await fetch(url)
if (!res.ok) throw new Error(`API error: ${res.status}`)
return res.json() as Promise<T>
}

4
ui/nextjs/next-env.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited

View File

@ -0,0 +1,3 @@
export default {
output: 'export',
}

View File

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -0,0 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
@apply text-gray-800;
}

View File

@ -0,0 +1,11 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./app/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}

24
ui/nextjs/tsconfig.json Normal file
View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": false,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": ["./*"]
},
"types": ["node"]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}