import React, { useCallback, useEffect, useState } from 'react'; import { View, StyleSheet, ScrollView, TouchableOpacity, Text, Platform, } from 'react-native'; import { useSafeAreaInsets, SafeAreaView } from 'react-native-safe-area-context'; import { MaterialCommunityIcons } from '@expo/vector-icons'; import { usePathname, useRouter } from 'expo-router'; import { colors, shadows } from '../theme'; import { useTotalUnreadCount } from '../stores'; import { AppRouteStack } from './AppRouteStack'; type TabName = 'HomeTab' | 'MessageTab' | 'AppsTab' | 'ProfileTab'; const SIDEBAR_WIDTH_DESKTOP = 240; const SIDEBAR_WIDTH_TABLET = 200; const SIDEBAR_COLLAPSED_WIDTH = 72; const NAV_ITEMS: { name: TabName; label: string; href: string; icon: string; iconOutline: string }[] = [ { name: 'HomeTab', label: '首页', href: '/home', icon: 'home', iconOutline: 'home-outline' }, { name: 'MessageTab', label: '消息', href: '/messages', icon: 'message-text', iconOutline: 'message-text-outline' }, { name: 'AppsTab', label: '应用', href: '/apps', icon: 'view-grid', iconOutline: 'view-grid-outline' }, { name: 'ProfileTab', label: '我的', href: '/profile', icon: 'account', iconOutline: 'account-outline' }, ]; function pathToTab(pathname: string): TabName { if (pathname.startsWith('/messages')) return 'MessageTab'; if (pathname.startsWith('/apps')) return 'AppsTab'; if (pathname.startsWith('/profile')) return 'ProfileTab'; if (pathname.startsWith('/home')) return 'HomeTab'; return 'HomeTab'; } export function AppDesktopShell() { const insets = useSafeAreaInsets(); const router = useRouter(); const pathname = usePathname(); const unreadCount = useTotalUnreadCount(); const [isCollapsed, setIsCollapsed] = useState(false); const [isDesktop, setIsDesktop] = useState(false); useEffect(() => { if (Platform.OS !== 'web') return; const check = () => { const w = window.innerWidth || document.documentElement.clientWidth; setIsDesktop(w >= SIDEBAR_WIDTH_DESKTOP); }; check(); window.addEventListener('resize', check); return () => window.removeEventListener('resize', check); }, []); const sidebarWidth = isCollapsed ? SIDEBAR_COLLAPSED_WIDTH : isDesktop ? SIDEBAR_WIDTH_DESKTOP : SIDEBAR_WIDTH_TABLET; const currentTab = pathToTab(pathname || '/home'); const handleTabChange = useCallback( (href: string) => { router.replace(href); }, [router] ); return ( {!isCollapsed && 胡萝卜BBS} {NAV_ITEMS.map((item) => { const isActive = currentTab === item.name; const showBadge = item.name === 'MessageTab' && unreadCount > 0; return ( handleTabChange(item.href)} activeOpacity={0.7} > {showBadge ? ( {unreadCount > 99 ? '99+' : unreadCount} ) : null} {!isCollapsed ? ( {item.label} ) : null} ); })} setIsCollapsed((c) => !c)} activeOpacity={0.7} > ); } const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'row', backgroundColor: colors.background.default, }, sidebar: { backgroundColor: colors.background.paper, borderRightWidth: 1, borderRightColor: colors.divider, flexDirection: 'column', ...shadows.md, }, sidebarHeader: { paddingHorizontal: 16, paddingVertical: 20, borderBottomWidth: 1, borderBottomColor: colors.divider, alignItems: 'center', justifyContent: 'center', flexDirection: 'row', }, logoText: { fontSize: 18, fontWeight: '700', color: colors.primary.main, marginLeft: 8, }, sidebarContent: { flex: 1, paddingTop: 8, }, sidebarItem: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 16, paddingVertical: 12, marginHorizontal: 8, marginVertical: 4, borderRadius: 12, }, sidebarItemActive: { backgroundColor: `${colors.primary.main}15`, }, sidebarItemCollapsed: { justifyContent: 'center', paddingHorizontal: 0, }, sidebarIconContainer: { position: 'relative', width: 40, height: 40, alignItems: 'center', justifyContent: 'center', borderRadius: 12, }, sidebarLabel: { fontSize: 15, fontWeight: '500', color: colors.text.secondary, marginLeft: 12, flex: 1, }, sidebarLabelActive: { color: colors.primary.main, fontWeight: '600', }, collapseButton: { flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end', paddingHorizontal: 16, paddingVertical: 12, borderTopWidth: 1, borderTopColor: colors.divider, }, collapseButtonCollapsed: { justifyContent: 'center', paddingHorizontal: 0, }, badge: { position: 'absolute', top: 2, right: 2, backgroundColor: colors.error.main, borderRadius: 10, minWidth: 18, height: 18, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 4, }, badgeText: { color: colors.primary.contrast, fontSize: 10, fontWeight: '600', }, mainContent: { flex: 1, backgroundColor: colors.background.default, }, });