返回 AiToEarn
index.tsx
1 /**
2 * MobileNav - 移动端顶部栏 + 底部导航 + 抽屉式侧边栏
3 * 布局:顶部 Logo/头像常驻,底部 BottomBar 导航,抽屉承载完整导航和常用功能
4 */
5 'use client'
6
7 import { Settings } from 'lucide-react'
8 import { useState } from 'react'
9 import { useShallow } from 'zustand/react/shallow'
10 import { useTransClient } from '@/app/i18n/client'
11 import { useNavigationLogic } from '@/app/layout/shared'
12 import { useChannelManagerStore } from '@/components/ChannelManager'
13 import { useSettingsModalStore } from '@/store/settingsModal'
14 import { cn } from '@/utils/className'
15 import { MobileBottomBar, MobileNavList, MobileTopBar } from './components'
16 import { MobileUserSection } from './components/MobileUserSection'
17
18 function MobileNav() {
19 const [isOpen, setIsOpen] = useState(false)
20 const { currRouter, isAuthPage, isBottomNavHidden } = useNavigationLogic()
21 const { openSettings } = useSettingsModalStore()
22 const { t } = useTransClient('common')
23
24 // 频道管理器
25 const { openModal } = useChannelManagerStore(
26 useShallow(state => ({
27 openModal: state.openModal,
28 })),
29 )
30
31 // auth 页面不显示
32 if (isAuthPage) {
33 return null
34 }
35
36 const handleClose = () => setIsOpen(false)
37
38 const actionItemClassName
39 = 'flex w-full items-center gap-3 px-4 py-3 rounded-lg text-base font-medium text-muted-foreground transition-all hover:bg-brand-cyan/10 hover:text-brand-cyan cursor-pointer'
40
41 return (
42 <>
43 {/* 移动端顶部栏 */}
44 <MobileTopBar onOpen={() => setIsOpen(true)} />
45
46 {/* 移动端底部导航 */}
47 <MobileBottomBar currentRoute={currRouter} hidden={isBottomNavHidden} />
48
49 {/* 抽屉遮罩 */}
50 {isOpen && (
51 <div
52 className="md:hidden fixed inset-0 z-50 bg-muted-foreground/45 transition-opacity"
53 data-testid="mobile-drawer-overlay"
54 onClick={handleClose}
55 />
56 )}
57
58 {/* 抽屉导航 */}
59 <div
60 data-testid="mobile-drawer"
61 className={cn(
62 'md:hidden fixed top-0 right-0 z-500 w-75 h-full bg-background shadow-xl transition-transform duration-300 ease-in-out flex flex-col',
63 isOpen ? 'translate-x-0' : 'translate-x-full',
64 )}
65 >
66 {/* 用户信息区域 */}
67 <div className="shrink-0 border-b border-border">
68 <MobileUserSection onClose={handleClose} onOpenSettings={openSettings} />
69 </div>
70
71 {/* 可滚动导航区域 */}
72 <div className="flex-1 overflow-y-auto">
73 <MobileNavList
74 currentRoute={currRouter}
75 onClose={handleClose}
76 onOpenMyChannels={openModal}
77 />
78
79 {/* 常用功能区域 */}
80 <div className="border-t border-border px-4 pb-4 pt-3 flex flex-col gap-1">
81 {/* 设置 */}
82 <button
83 onClick={() => {
84 handleClose()
85 openSettings()
86 }}
87 className={actionItemClassName}
88 data-testid="mobile-settings-btn"
89 >
90 <span className="relative flex items-center justify-center">
91 <Settings size={20} />
92 </span>
93 <span>{t('settings')}</span>
94 </button>
95 </div>
96 </div>
97 </div>
98 </>
99 )
100 }
101
102 export default MobileNav
103
103 lines Plain Text