feat(homepage): add responsive multi-level nav (#208)

This commit is contained in:
shenlan 2025-09-13 21:17:42 +08:00 committed by GitHub
parent a4392e0901
commit 76826cb805
3 changed files with 255 additions and 72 deletions

View File

@ -0,0 +1,15 @@
"use client"
import { useLanguage } from '@i18n/LanguageProvider'
import { translations } from '@i18n/translations'
export default function DemoPage() {
const { language } = useLanguage()
const { account } = translations[language].nav
return (
<div className="min-h-screen flex items-center justify-center text-white">
<h1 className="text-2xl font-bold">{account.demo}</h1>
</div>
)
}

View File

@ -6,9 +6,14 @@ import { translations } from '../i18n/translations'
export default function NavBar() {
const [menuOpen, setMenuOpen] = useState(false)
const [openSection, setOpenSection] = useState<string | null>(null)
const { language } = useLanguage()
const nav = translations[language].nav
const toggleSection = (section: string) => {
setOpenSection((prev) => (prev === section ? null : section))
}
return (
<nav className="fixed top-0 w-full z-50 bg-black/30 backdrop-blur border-b border-white/10">
<div className="max-w-7xl mx-auto px-4 py-4 flex justify-between items-center">
@ -17,18 +22,60 @@ export default function NavBar() {
CloudNative Suite
</a>
{/* 桌面导航 */}
{/* Desktop Navigation */}
<div className="hidden md:flex items-center gap-6 text-sm text-white">
<a href="#features" className="hover:text-purple-300">{nav.features}</a>
<a href="#open-sources" className="hover:text-purple-300">{nav.openSource}</a>
<a href="#download" className="hover:text-purple-300">{nav.download}</a>
<a href="#contact" className="hover:text-purple-300">{nav.contact}</a>
<a href="/login" className="hover:text-purple-300">{nav.login}</a>
<a href="/register" className="hover:text-purple-300">{nav.register}</a>
{/* Open Source */}
<div className="relative group">
<button className="hover:text-purple-300">{nav.openSource.title}</button>
<div className="absolute left-0 mt-2 hidden group-hover:block bg-black/80 backdrop-blur rounded-md shadow-lg border border-white/10 py-2">
<a href="#features" className="block px-4 py-2 hover:bg-white/10 whitespace-nowrap">
{nav.openSource.features}
</a>
<a
href="https://github.com/XProxyTeam/XControl"
className="block px-4 py-2 hover:bg-white/10 whitespace-nowrap"
>
{nav.openSource.code}
</a>
<a href="#download" className="block px-4 py-2 hover:bg-white/10 whitespace-nowrap">
{nav.openSource.download}
</a>
</div>
</div>
{/* Services */}
<div className="relative group">
<button className="hover:text-purple-300">{nav.services.title}</button>
<div className="absolute left-0 mt-2 hidden group-hover:block bg-black/80 backdrop-blur rounded-md shadow-lg border border-white/10 py-2">
<a href="#" className="block px-4 py-2 hover:bg-white/10 whitespace-nowrap">
{nav.services.artifact}
</a>
<a href="/docs" className="block px-4 py-2 hover:bg-white/10 whitespace-nowrap">
{nav.services.docs}
</a>
</div>
</div>
{/* Account */}
<div className="relative group">
<button className="hover:text-purple-300">{nav.account.title}</button>
<div className="absolute right-0 mt-2 hidden group-hover:block bg-black/80 backdrop-blur rounded-md shadow-lg border border-white/10 py-2">
<a href="/register" className="block px-4 py-2 hover:bg-white/10 whitespace-nowrap">
{nav.account.register}
</a>
<a href="/login" className="block px-4 py-2 hover:bg-white/10 whitespace-nowrap">
{nav.account.login}
</a>
<a href="/demo" className="block px-4 py-2 hover:bg-white/10 whitespace-nowrap">
{nav.account.demo}
</a>
</div>
</div>
<LanguageToggle />
</div>
{/* 移动端汉堡菜单按钮 */}
{/* Mobile Hamburger Button */}
<button
className="md:hidden flex items-center text-white focus:outline-none"
onClick={() => setMenuOpen(!menuOpen)}
@ -42,61 +89,148 @@ export default function NavBar() {
xmlns="http://www.w3.org/2000/svg"
>
{menuOpen ? (
// 关闭图标 (X)
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
) : (
// 汉堡图标
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
</button>
</div>
{/* 移动端菜单内容,展开时显示 */}
{/* Mobile Menu */}
{menuOpen && (
<div className="md:hidden bg-black/80 backdrop-blur border-t border-white/10 px-4 pb-4">
<a
href="#features"
onClick={() => setMenuOpen(false)}
className="block py-2 text-white hover:text-purple-300"
>
{nav.features}
</a>
<a
href="#open-sources"
onClick={() => setMenuOpen(false)}
className="block py-2 text-white hover:text-purple-300"
>
{nav.openSource}
</a>
<a
href="#download"
onClick={() => setMenuOpen(false)}
className="block py-2 text-white hover:text-purple-300"
>
{nav.download}
</a>
<a
href="#contact"
onClick={() => setMenuOpen(false)}
className="block py-2 text-white hover:text-purple-300"
>
{nav.contact}
</a>
<a
href="/login"
onClick={() => setMenuOpen(false)}
className="block py-2 text-white hover:text-purple-300"
>
{nav.login}
</a>
<a
href="/register"
onClick={() => setMenuOpen(false)}
className="block py-2 text-white hover:text-purple-300"
>
{nav.register}
</a>
{/* Open Source */}
<div>
<button
onClick={() => toggleSection('openSource')}
className="w-full flex justify-between items-center py-2 text-white"
>
<span>{nav.openSource.title}</span>
<svg
className={`w-4 h-4 transform transition-transform ${
openSection === 'openSource' ? 'rotate-180' : ''
}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{openSection === 'openSource' && (
<div className="pl-4">
<a
href="#features"
onClick={() => setMenuOpen(false)}
className="block py-1 text-white hover:text-purple-300"
>
{nav.openSource.features}
</a>
<a
href="https://github.com/XProxyTeam/XControl"
onClick={() => setMenuOpen(false)}
className="block py-1 text-white hover:text-purple-300"
>
{nav.openSource.code}
</a>
<a
href="#download"
onClick={() => setMenuOpen(false)}
className="block py-1 text-white hover:text-purple-300"
>
{nav.openSource.download}
</a>
</div>
)}
</div>
{/* Services */}
<div>
<button
onClick={() => toggleSection('services')}
className="w-full flex justify-between items-center py-2 text-white"
>
<span>{nav.services.title}</span>
<svg
className={`w-4 h-4 transform transition-transform ${
openSection === 'services' ? 'rotate-180' : ''
}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{openSection === 'services' && (
<div className="pl-4">
<a
href="#"
onClick={() => setMenuOpen(false)}
className="block py-1 text-white hover:text-purple-300"
>
{nav.services.artifact}
</a>
<a
href="/docs"
onClick={() => setMenuOpen(false)}
className="block py-1 text-white hover:text-purple-300"
>
{nav.services.docs}
</a>
</div>
)}
</div>
{/* Account */}
<div>
<button
onClick={() => toggleSection('account')}
className="w-full flex justify-between items-center py-2 text-white"
>
<span>{nav.account.title}</span>
<svg
className={`w-4 h-4 transform transition-transform ${
openSection === 'account' ? 'rotate-180' : ''
}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{openSection === 'account' && (
<div className="pl-4">
<a
href="/register"
onClick={() => setMenuOpen(false)}
className="block py-1 text-white hover:text-purple-300"
>
{nav.account.register}
</a>
<a
href="/login"
onClick={() => setMenuOpen(false)}
className="block py-1 text-white hover:text-purple-300"
>
{nav.account.login}
</a>
<a
href="/demo"
onClick={() => setMenuOpen(false)}
className="block py-1 text-white hover:text-purple-300"
>
{nav.account.demo}
</a>
</div>
)}
</div>
<div className="pt-2">
<LanguageToggle />
</div>
@ -104,4 +238,5 @@ export default function NavBar() {
)}
</nav>
)
}
}

View File

@ -12,12 +12,23 @@ export type Translation = {
downloadSubtitle: string
footerLinks: [string, string, string]
nav: {
features: string
openSource: string
download: string
contact: string
login: string
register: string
openSource: {
title: string
features: string
code: string
download: string
}
services: {
title: string
artifact: string
docs: string
}
account: {
title: string
register: string
login: string
demo: string
}
}
termsTitle: string
termsPoints: string[]
@ -39,12 +50,23 @@ export const translations: Record<'en' | 'zh', Translation> = {
downloadSubtitle: 'Select your platform',
footerLinks: ['Privacy Policy', 'Terms of Service', 'Contact Us'],
nav: {
features: 'Features',
openSource: 'Open Source',
download: 'Download',
contact: 'Contact',
login: 'Login',
register: 'Register',
openSource: {
title: 'Open Source',
features: 'Features',
code: 'Code',
download: 'Download',
},
services: {
title: 'Services',
artifact: 'Artifact / Mirror',
docs: 'Docs / Solutions',
},
account: {
title: 'Account',
register: 'Register',
login: 'Login',
demo: 'Demo',
},
},
termsTitle: 'Terms of Service',
termsPoints: [
@ -69,12 +91,23 @@ export const translations: Record<'en' | 'zh', Translation> = {
downloadSubtitle: '选择适合的平台',
footerLinks: ['隐私政策', '服务条款', '联系我们'],
nav: {
features: '功能特性',
openSource: '开源项目',
download: '下载',
contact: '联系我们',
login: '登录',
register: '注册',
openSource: {
title: '开源项目',
features: '功能特性',
code: '代码',
download: '下载',
},
services: {
title: '服务',
artifact: 'Artifact / 镜像',
docs: '文档 / 解决方案',
},
account: {
title: '账户',
register: '注册',
login: '登录',
demo: '演示',
},
},
termsTitle: '服务条款',
termsPoints: [