mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-09-05 15:47:00 +08:00
feat: update sidebar navigation to add social buttons
This commit is contained in:
+130
-73
@@ -1,9 +1,9 @@
|
|||||||
import { Layout, Menu, theme, Button } from 'antd';
|
import { Layout, Menu, theme, Button, Modal } from 'antd';
|
||||||
import { navGroups } from './nav.ts';
|
import { navGroups } from './nav.ts';
|
||||||
import type { NavItem, NavGroup } from './nav.ts';
|
import type { NavItem, NavGroup } from './nav.ts';
|
||||||
import { memo } from 'react';
|
import { memo, useState } from 'react';
|
||||||
import { useSystemStatus } from '../contexts/SystemContext.tsx';
|
import { useSystemStatus } from '../contexts/SystemContext.tsx';
|
||||||
import { MenuFoldOutlined } from '@ant-design/icons';
|
import { GithubOutlined, MenuFoldOutlined, SendOutlined, WechatOutlined } from '@ant-design/icons';
|
||||||
import '../styles/sider-menu.css';
|
import '../styles/sider-menu.css';
|
||||||
|
|
||||||
const { Sider } = Layout;
|
const { Sider } = Layout;
|
||||||
@@ -18,79 +18,136 @@ export interface SideNavProps {
|
|||||||
const SideNav = memo(function SideNav({ collapsed, activeKey, onChange, onToggle }: SideNavProps) {
|
const SideNav = memo(function SideNav({ collapsed, activeKey, onChange, onToggle }: SideNavProps) {
|
||||||
const status = useSystemStatus();
|
const status = useSystemStatus();
|
||||||
const { token } = theme.useToken();
|
const { token } = theme.useToken();
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<Sider
|
<>
|
||||||
collapsedWidth={60}
|
<Sider
|
||||||
collapsible
|
collapsedWidth={60}
|
||||||
trigger={null}
|
collapsible
|
||||||
collapsed={collapsed}
|
trigger={null}
|
||||||
width={208}
|
collapsed={collapsed}
|
||||||
style={{ background: token.colorBgContainer, borderRight: `1px solid ${token.colorBorderSecondary}` }}
|
width={208}
|
||||||
>
|
style={{
|
||||||
<div style={{
|
background: token.colorBgContainer,
|
||||||
height: 56,
|
borderRight: `1px solid ${token.colorBorderSecondary}`,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
flexDirection: 'column'
|
||||||
justifyContent: collapsed ? 'center' : 'space-between',
|
}}
|
||||||
padding: '0 14px',
|
>
|
||||||
fontWeight: 600,
|
<div style={{
|
||||||
fontSize: 18,
|
height: 56,
|
||||||
letterSpacing: .5
|
display: 'flex',
|
||||||
}}>
|
alignItems: 'center',
|
||||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
justifyContent: collapsed ? 'center' : 'space-between',
|
||||||
<img
|
padding: '0 14px',
|
||||||
src={status?.logo}
|
fontWeight: 600,
|
||||||
alt="Foxel"
|
fontSize: 18,
|
||||||
style={{
|
letterSpacing: .5,
|
||||||
width: 24,
|
flexShrink: 0
|
||||||
height: 24,
|
}}>
|
||||||
objectFit: 'contain',
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
marginRight: collapsed ? 0 : 8,
|
<img
|
||||||
...(status?.logo?.endsWith('.svg') && { filter: 'brightness(0) saturate(100%)' })
|
src={status?.logo}
|
||||||
}}
|
alt="Foxel"
|
||||||
/>
|
style={{
|
||||||
{!collapsed && <span style={{ fontWeight: 700 }}>{status?.title}</span>}
|
width: 24,
|
||||||
</div>
|
height: 24,
|
||||||
{/* 展开时显示收缩按钮 */}
|
objectFit: 'contain',
|
||||||
{!collapsed && (
|
marginRight: collapsed ? 0 : 8,
|
||||||
<Button
|
...(status?.logo?.endsWith('.svg') && { filter: 'brightness(0) saturate(100%)' })
|
||||||
type="text"
|
}}
|
||||||
icon={<MenuFoldOutlined />}
|
|
||||||
onClick={onToggle}
|
|
||||||
style={{ fontSize: 18 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{/* 分组渲染 */}
|
|
||||||
<div style={{ overflowY: 'auto', height: 'calc(100% - 56px)', padding: '4px 4px 8px' }}>
|
|
||||||
{navGroups.map((group: NavGroup) => (
|
|
||||||
<div key={group.key} style={{ marginBottom: 12 }}>
|
|
||||||
{group.title && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: 11,
|
|
||||||
fontWeight: 600,
|
|
||||||
letterSpacing: .5,
|
|
||||||
padding: '6px 10px 4px',
|
|
||||||
color: token.colorTextTertiary,
|
|
||||||
textTransform: 'uppercase'
|
|
||||||
}}
|
|
||||||
>{group.title}</div>
|
|
||||||
)}
|
|
||||||
<Menu
|
|
||||||
mode="inline"
|
|
||||||
selectable
|
|
||||||
inlineIndent={12}
|
|
||||||
selectedKeys={[activeKey]}
|
|
||||||
onClick={(e) => onChange(e.key)}
|
|
||||||
items={group.children.map((i: NavItem) => ({ key: i.key, icon: i.icon, label: i.label }))}
|
|
||||||
style={{ borderInline: 'none', background: 'transparent' }}
|
|
||||||
className="sider-menu-group foxel-sider-menu"
|
|
||||||
/>
|
/>
|
||||||
|
{!collapsed && <span style={{ fontWeight: 700 }}>{status?.title}</span>}
|
||||||
</div>
|
</div>
|
||||||
))}
|
{/* 展开时显示收缩按钮 */}
|
||||||
</div>
|
{!collapsed && (
|
||||||
</Sider>
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<MenuFoldOutlined />}
|
||||||
|
onClick={onToggle}
|
||||||
|
style={{ fontSize: 18 }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{/* 分组渲染 */}
|
||||||
|
<div style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: '4px 4px 8px' }}>
|
||||||
|
{navGroups.map((group: NavGroup) => (
|
||||||
|
<div key={group.key} style={{ marginBottom: 12 }}>
|
||||||
|
{group.title && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: 11,
|
||||||
|
fontWeight: 600,
|
||||||
|
letterSpacing: .5,
|
||||||
|
padding: '6px 10px 4px',
|
||||||
|
color: token.colorTextTertiary,
|
||||||
|
textTransform: 'uppercase'
|
||||||
|
}}
|
||||||
|
>{group.title}</div>
|
||||||
|
)}
|
||||||
|
<Menu
|
||||||
|
mode="inline"
|
||||||
|
selectable
|
||||||
|
inlineIndent={12}
|
||||||
|
selectedKeys={[activeKey]}
|
||||||
|
onClick={(e) => onChange(e.key)}
|
||||||
|
items={group.children.map((i: NavItem) => ({ key: i.key, icon: i.icon, label: i.label }))}
|
||||||
|
style={{ borderInline: 'none', background: 'transparent' }}
|
||||||
|
className="sider-menu-group foxel-sider-menu"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
bottom: '10px',
|
||||||
|
position: 'absolute',
|
||||||
|
width: '100%',
|
||||||
|
padding: '12px 8px',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: 8,
|
||||||
|
flexShrink: 0,
|
||||||
|
borderTop: `1px solid ${token.colorBorderSecondary}`
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
icon={<GithubOutlined />}
|
||||||
|
href="https://github.com/DrizzleTime/Foxel"
|
||||||
|
target="_blank"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
icon={<WechatOutlined />}
|
||||||
|
onClick={() => setIsModalOpen(true)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
shape="circle"
|
||||||
|
icon={<SendOutlined />}
|
||||||
|
href="https://t.me/+thDsBfyqJxZkNTU1"
|
||||||
|
target="_blank"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Sider>
|
||||||
|
<Modal
|
||||||
|
open={isModalOpen}
|
||||||
|
onCancel={() => setIsModalOpen(false)}
|
||||||
|
title="加入社区"
|
||||||
|
footer={null}
|
||||||
|
width={320}
|
||||||
|
>
|
||||||
|
<div style={{ textAlign: 'center', padding: '12px 0' }}>
|
||||||
|
<img src="https://foxel.cc/image/wechat.png" width={200} alt="wechat" />
|
||||||
|
<div style={{ marginTop: 12, color: token.colorTextSecondary }}>
|
||||||
|
微信扫码加入交流群
|
||||||
|
</div>
|
||||||
|
<div style={{ marginTop: 8, fontSize: 12, color: token.colorTextTertiary }}>
|
||||||
|
如二维码失效,请添加 drizzle2001 拉群
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ interface HeaderProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Header: React.FC<HeaderProps> = ({
|
export const Header: React.FC<HeaderProps> = ({
|
||||||
navKey,
|
|
||||||
path,
|
path,
|
||||||
loading,
|
loading,
|
||||||
uploading,
|
uploading,
|
||||||
@@ -95,7 +94,7 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
<Flex align="center" justify="space-between" style={{ padding: '10px 16px', borderBottom: `1px solid ${token.colorBorderSecondary}`, gap: 12 }}>
|
<Flex align="center" justify="space-between" style={{ padding: '10px 16px', borderBottom: `1px solid ${token.colorBorderSecondary}`, gap: 12 }}>
|
||||||
<Flex align="center" gap={8} style={{ flexWrap: 'wrap', flex: 1, overflow: 'hidden' }}>
|
<Flex align="center" gap={8} style={{ flexWrap: 'wrap', flex: 1, overflow: 'hidden' }}>
|
||||||
<Button size="small" icon={<ArrowUpOutlined />} onClick={onGoUp} disabled={path === '/'} />
|
<Button size="small" icon={<ArrowUpOutlined />} onClick={onGoUp} disabled={path === '/'} />
|
||||||
<Typography.Text strong>{navKey}</Typography.Text>
|
<Typography.Text strong>文件管理</Typography.Text>
|
||||||
<Divider type="vertical" />
|
<Divider type="vertical" />
|
||||||
{renderBreadcrumb()}
|
{renderBreadcrumb()}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export const ShareModal = memo(function ShareModal({ entries, path, open, onOk,
|
|||||||
message.success('已复制到剪贴板');
|
message.success('已复制到剪贴板');
|
||||||
};
|
};
|
||||||
|
|
||||||
const shareUrl = createdShare ? `${window.location.origin}/s/${createdShare.token}` : '';
|
const shareUrl = createdShare ? `${window.location.origin}/share/${createdShare.token}` : '';
|
||||||
|
|
||||||
const renderForm = () => (
|
const renderForm = () => (
|
||||||
<Form form={form} layout="vertical" initialValues={{ name: defaultName, accessType: 'public', expiresInDays: 7 }}>
|
<Form form={form} layout="vertical" initialValues={{ name: defaultName, accessType: 'public', expiresInDays: 7 }}>
|
||||||
|
|||||||
Reference in New Issue
Block a user