Make admin panel responsive

This commit is contained in:
shenlan 2025-06-18 11:09:16 +08:00
parent 6db5d43891
commit 07a68ca204
5 changed files with 56 additions and 11 deletions

View File

@ -42,10 +42,18 @@ styles/
```
- 使用 `next export` 生成静态 HTML
```bash
npm run build && npx next export
npm run build && npx next export
```
生成的 `out/` 目录即可作为纯静态网站部署。
## 响应式设计
示例实现利用 Tailwind 的 `md:` 等断点完成移动端适配:
- 小屏幕默认隐藏侧边栏,在 Header 内提供菜单按钮控制显示。
- 大屏幕侧边栏常驻,内容区域使用 `md:ml-64` 留出宽度。
布局组件 `layout.tsx` 中使用 React 状态切换侧边栏,可满足主流移动端浏览体验。
## 示例代码结构
本仓库 `ui/nextjs` 目录提供了一套最简参考实现,可直接 `npm run build && npx next export` 编译到 `ui/dist` 供 Go 服务嵌入。

View File

@ -1,14 +1,26 @@
'use client'
import '../styles/globals.css'
import { useState } from 'react'
import Sidebar from '../components/Sidebar'
import Header from '../components/Header'
export const dynamic = 'force-static'
export default function RootLayout({ children }: { children: React.ReactNode }) {
const [open, setOpen] = useState(false)
return (
<html lang="en">
<body className="flex min-h-screen">
<Sidebar />
<main className="flex-1 p-4">{children}</main>
<body className="flex min-h-screen overflow-x-hidden">
<Sidebar
className={`fixed inset-y-0 left-0 z-20 transform transition-transform bg-gray-100 md:static md:translate-x-0 ${open ? 'translate-x-0' : '-translate-x-full md:translate-x-0'}`}
onNavigate={() => setOpen(false)}
/>
<div className="flex flex-col flex-1">
<Header onMenu={() => setOpen(!open)} />
<main className="flex-1 p-4 md:ml-64">{children}</main>
</div>
</body>
</html>
)

View File

@ -1,7 +1,21 @@
export default function Header() {
export interface HeaderProps {
onMenu?: () => void
}
export default function Header({ onMenu }: HeaderProps) {
return (
<header className="p-4 border-b">
<h1 className="text-lg font-bold">XControl Admin</h1>
<header className="flex items-center justify-between p-4 border-b bg-white shadow md:ml-64">
<button
className="md:hidden p-2 text-gray-600"
onClick={onMenu}
aria-label="Toggle navigation"
>
{/* simple hamburger icon */}
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
<h1 className="text-lg font-bold flex-1 text-center md:text-left">XControl Admin</h1>
</header>
)
}

View File

@ -1,5 +1,10 @@
import Link from 'next/link'
export interface SidebarProps {
className?: string
onNavigate?: () => void
}
const menu = [
{ href: '/', label: 'Home' },
{ href: '/agent', label: 'Agent' },
@ -8,11 +13,16 @@ const menu = [
{ href: '/xray', label: 'XRay' },
]
export default function Sidebar() {
export default function Sidebar({ className = '', onNavigate }: SidebarProps) {
return (
<nav className="w-48 bg-gray-100 p-4 space-y-2">
<nav className={`w-64 bg-gray-100 p-4 space-y-2 ${className}`}>
{menu.map(m => (
<Link key={m.href} href={m.href} className="block p-2 rounded hover:bg-gray-200">
<Link
key={m.href}
href={m.href}
className="block p-2 rounded hover:bg-gray-200"
onClick={onNavigate}
>
{m.label}
</Link>
))}

View File

@ -2,6 +2,7 @@
@tailwind components;
@tailwind utilities;
html,
body {
@apply text-gray-800;
@apply h-full text-gray-800;
}