import { Layout, Menu, theme, Button, Modal, Tag, Tooltip, Descriptions, Alert, Divider, Spin } from 'antd'; import { navGroups } from './nav.ts'; import type { NavItem, NavGroup } from './nav.ts'; import { memo, useEffect, useState } from 'react'; import { useSystemStatus } from '../contexts/SystemContext.tsx'; import { CheckCircleOutlined, FileTextOutlined, GithubOutlined, MenuFoldOutlined, SendOutlined, WechatOutlined, WarningOutlined } from '@ant-design/icons'; import '../styles/sider-menu.css'; import { getLatestVersion } from '../api/config.ts'; import ReactMarkdown from 'react-markdown'; import { useTheme } from '../contexts/ThemeContext'; import { useI18n } from '../i18n'; import { useAppWindows } from '../contexts/AppWindowsContext'; import WeChatModal from '../components/WeChatModal'; const { Sider } = Layout; export interface SideNavProps { collapsed: boolean; onToggle(): void; activeKey: string; onChange(key: string): void; } const SideNav = memo(function SideNav({ collapsed, activeKey, onChange, onToggle }: SideNavProps) { const status = useSystemStatus(); const { token } = theme.useToken(); const { resolvedMode } = useTheme(); const { t } = useI18n(); const [isModalOpen, setIsModalOpen] = useState(false); const [isVersionModalOpen, setIsVersionModalOpen] = useState(false); const [latestVersion, setLatestVersion] = useState<{ version: string; body: string; } | null>(null); useEffect(() => { getLatestVersion().then(resp => { if (resp.latest_version && resp.body) { setLatestVersion({ version: resp.latest_version, body: resp.body }); } }); }, []); const showVersionModal = () => { setIsVersionModalOpen(true); }; const hasUpdate = latestVersion && latestVersion.version !== status?.version; const { windows, restoreWindow } = useAppWindows(); const minimized = windows.filter(w => w.minimized); const DEFAULT_APP_ICON = 'data:image/svg+xml;utf8,' + encodeURIComponent( ` ` ); return ( <>
Foxel {!collapsed && ( {status?.title} )}
{/* 展开时显示收缩按钮 */} {!collapsed && (
{/* 分组渲染 */}
{navGroups.map((group: NavGroup) => (
{group.title && (
{t(group.title)}
)} onChange(e.key)} items={group.children.map((i: NavItem) => ({ key: i.key, icon: i.icon, label: t(i.label) }))} style={{ borderInline: 'none', background: 'transparent' }} className="sider-menu-group foxel-sider-menu" />
))}
{/* 最小化应用 Dock */} {minimized.length > 0 && (
{minimized.map(w => { const src = w.app.iconUrl || DEFAULT_APP_ICON; return (
)}
{hasUpdate ? ( {collapsed ? ( } color="warning" style={{ marginInlineEnd: 0 }} /> ) : ( } color="warning"> {status?.version} - {t('Update available')} [{latestVersion?.version}] )} ) : ( latestVersion ? ( {collapsed ? ( } color="success" style={{ marginInlineEnd: 0 }} /> ) : ( } color="success"> {t('Up to date')} )} ) : ( collapsed ? null : {status?.version} ) )}
setIsModalOpen(false)} /> setIsVersionModalOpen(false)} title={t('Version Info')} footer={null} width={600} >
{latestVersion ? ( <> {status?.version} {latestVersion.version} {hasUpdate && ( {t('New version found: {version}', { version: latestVersion.version })}} description={{t('Please update to the latest for features and fixes')}} type="info" showIcon style={{ marginTop: 24, marginBottom: 24, background: token.colorInfoBg, borderColor: token.colorInfoBorder }} action={ } /> )} {t('Changelog')}

, ul: ({ ...props }) =>

) : (

{t('Fetching latest version...')}

)}
); }); export default SideNav;