Add Next.js admin panel skeleton
This commit is contained in:
parent
d5bd14f447
commit
6db5d43891
@ -46,3 +46,6 @@ styles/
|
||||
```
|
||||
|
||||
生成的 `out/` 目录即可作为纯静态网站部署。
|
||||
|
||||
## 示例代码结构
|
||||
本仓库 `ui/nextjs` 目录提供了一套最简参考实现,可直接 `npm run build && npx next export` 编译到 `ui/dist` 供 Go 服务嵌入。
|
||||
|
||||
10
ui/nextjs/app/agent/page.tsx
Normal file
10
ui/nextjs/app/agent/page.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
10
ui/nextjs/app/api/page.tsx
Normal file
10
ui/nextjs/app/api/page.tsx
Normal 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
15
ui/nextjs/app/layout.tsx
Normal 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
10
ui/nextjs/app/page.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
10
ui/nextjs/app/subscription/page.tsx
Normal file
10
ui/nextjs/app/subscription/page.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
10
ui/nextjs/app/xray/page.tsx
Normal file
10
ui/nextjs/app/xray/page.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
7
ui/nextjs/components/Card.tsx
Normal file
7
ui/nextjs/components/Card.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
7
ui/nextjs/components/Header.tsx
Normal file
7
ui/nextjs/components/Header.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
21
ui/nextjs/components/Sidebar.tsx
Normal file
21
ui/nextjs/components/Sidebar.tsx
Normal 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
5
ui/nextjs/lib/api.ts
Normal 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
4
ui/nextjs/next-env.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
3
ui/nextjs/next.config.mjs
Normal file
3
ui/nextjs/next.config.mjs
Normal file
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
output: 'export',
|
||||
}
|
||||
6
ui/nextjs/postcss.config.js
Normal file
6
ui/nextjs/postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
7
ui/nextjs/styles/globals.css
Normal file
7
ui/nextjs/styles/globals.css
Normal file
@ -0,0 +1,7 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
@apply text-gray-800;
|
||||
}
|
||||
11
ui/nextjs/tailwind.config.js
Normal file
11
ui/nextjs/tailwind.config.js
Normal 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
24
ui/nextjs/tsconfig.json
Normal 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"]
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user