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 ( <> {!collapsed && ( {status?.title} )} {/* 展开时显示收缩按钮 */} {!collapsed && ( } onClick={onToggle} style={{ fontSize: 18 }} /> )} {/* 分组渲染 */} {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 ( restoreWindow(w.id)} icon={} /> ); })} )} {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} ) )} } href="https://github.com/DrizzleTime/Foxel" target="_blank" /> } onClick={() => setIsModalOpen(true)} /> } href="https://t.me/+thDsBfyqJxZkNTU1" target="_blank" /> } href="https://foxel.cc" target="_blank" /> 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('Open Releases')} } /> )} {t('Changelog')} , ul: ({ ...props }) => , li: ({ ...props }) => , p: ({ ...props }) => , a: ({ ...props }) => }} >{latestVersion.body} > ) : ( {t('Fetching latest version...')} )} > ); }); export default SideNav;
{t('Fetching latest version...')}