diff --git a/frontend/src/pages/Document/DocumentPage.css b/frontend/src/pages/Document/DocumentPage.css index f39f45c..67098af 100644 --- a/frontend/src/pages/Document/DocumentPage.css +++ b/frontend/src/pages/Document/DocumentPage.css @@ -28,6 +28,33 @@ height: 100%; } +/* 侧栏收起时:左侧悬浮展开按钮 */ +.docs-sider-expand-btn { + position: fixed; + left: 12px; + top: 50%; + transform: translateY(-50%); + z-index: 30; + width: 32px; + height: 48px; + border-radius: 8px; + border: 1px solid var(--border-color); + background: var(--header-bg); + color: var(--text-color-secondary); + font-size: 16px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12); + transition: color 0.2s ease, border-color 0.2s ease; +} + +.docs-sider-expand-btn:hover { + color: var(--link-color); + border-color: var(--link-color); +} + .docs-sider-header { padding: 12px 10px 12px; border-bottom: 1px solid var(--border-color); diff --git a/frontend/src/pages/Document/DocumentPage.jsx b/frontend/src/pages/Document/DocumentPage.jsx index 7202e08..4e2bf77 100644 --- a/frontend/src/pages/Document/DocumentPage.jsx +++ b/frontend/src/pages/Document/DocumentPage.jsx @@ -1,7 +1,7 @@ import { useState, useEffect, useRef, useMemo } from 'react' import { useParams, useNavigate, useSearchParams } from 'react-router-dom' import { Layout, Spin, Button, Tooltip, Modal, Input, Space, Dropdown, Empty, Switch, Select, TreeSelect, Radio, Alert } from 'antd' -import { ShareAltOutlined, FileTextOutlined, FolderOutlined, FolderOpenOutlined, FilePdfOutlined, CopyOutlined, CloudDownloadOutlined, CloudUploadOutlined, ArrowLeftOutlined, ReloadOutlined, VerticalAlignTopOutlined } from '@ant-design/icons' +import { ShareAltOutlined, FileTextOutlined, FolderOutlined, FolderOpenOutlined, FilePdfOutlined, CopyOutlined, CloudDownloadOutlined, CloudUploadOutlined, ArrowLeftOutlined, ReloadOutlined, VerticalAlignTopOutlined, MenuUnfoldOutlined } from '@ant-design/icons' import ReactMarkdown from 'react-markdown' import remarkGfm from 'remark-gfm' import rehypeRaw from 'rehype-raw' @@ -61,6 +61,7 @@ function DocumentPage() { const [pdfUrl, setPdfUrl] = useState('') const [pdfFilename, setPdfFilename] = useState('') const [viewMode, setViewMode] = useState('markdown') + const [siderCollapsed, setSiderCollapsed] = useState(false) const [gitRepos, setGitRepos] = useState([]) // Git 同步范围弹窗状态 const [gitSyncModalVisible, setGitSyncModalVisible] = useState(false) @@ -131,6 +132,7 @@ function DocumentPage() { setMarkdownContent('') setTocItems([]) setViewMode('folder') + setSiderCollapsed(true) expandParentFolders(`${folderPath}/placeholder`) // 从内容区点击进入子文件夹时,同时展开自身,保证与左侧文件树同步 @@ -149,6 +151,7 @@ function DocumentPage() { setMarkdownContent('') setTocItems([]) setViewMode('folder') + setSiderCollapsed(true) setOpenKeys([]) if (syncUrl) { @@ -1259,7 +1262,7 @@ function DocumentPage() {
{/* 左侧目录 */} - +
+ )} + {/* 右侧内容区 */} diff --git a/frontend/src/pages/Preview/FileSharePage.jsx b/frontend/src/pages/Preview/FileSharePage.jsx index 42f6071..6b57ad0 100644 --- a/frontend/src/pages/Preview/FileSharePage.jsx +++ b/frontend/src/pages/Preview/FileSharePage.jsx @@ -37,6 +37,32 @@ function FileSharePage() { const contentRef = useRef(null) const largeMarkdownRef = useRef(null) const [headerVisible, setHeaderVisible] = useState(false) + const headerHoveringRef = useRef(false) + const headerHideTimerRef = useRef(null) + const clearHeaderHideTimer = () => { + if (headerHideTimerRef.current) { + clearTimeout(headerHideTimerRef.current) + headerHideTimerRef.current = null + } + } + // 延迟隐藏 Header(鼠标悬停时保持显示) + const scheduleHeaderHide = () => { + clearHeaderHideTimer() + if (headerHoveringRef.current) return + headerHideTimerRef.current = setTimeout(() => setHeaderVisible(false), 1200) + } + // 鼠标进入 Header:取消隐藏计时,保持显示 + const handleHeaderMouseEnter = () => { + headerHoveringRef.current = true + clearHeaderHideTimer() + } + // 鼠标离开 Header:若已滚动则重新计时隐藏 + const handleHeaderMouseLeave = () => { + headerHoveringRef.current = false + const root = contentRef.current + const target = root ? findScrollableEl(root) : null + if (target && target.scrollTop > 8) scheduleHeaderHide() + } const [pdfToolbarTarget, setPdfToolbarTarget] = useState(null) const [shareInfo, setShareInfo] = useState(null) const [contentInfo, setContentInfo] = useState(null) @@ -60,30 +86,22 @@ function FileSharePage() { return () => window.removeEventListener('resize', checkMobile) }, []) - // 内容区 Header:仅在滚动时显示,滚动停止后延迟隐藏(含 PDF/大文档内部滚动) + // 内容区 Header:仅在滚动时显示,滚动停止后延迟隐藏;鼠标悬停时保持显示 useEffect(() => { const root = contentRef.current if (!root) return - const hideTimer = { current: null } - const clearHideTimer = () => { - if (hideTimer.current) { - clearTimeout(hideTimer.current) - hideTimer.current = null - } - } const sync = (scrollEl = null) => { const target = scrollEl || findScrollableEl(root) if (!target) { - clearHideTimer() + clearHeaderHideTimer() setHeaderVisible(true) return } if (target.scrollTop > 8) { setHeaderVisible(true) - clearHideTimer() - hideTimer.current = setTimeout(() => setHeaderVisible(false), 1200) + scheduleHeaderHide() } else { - clearHideTimer() + clearHeaderHideTimer() setHeaderVisible(false) } } @@ -92,7 +110,7 @@ function FileSharePage() { sync() return () => { root.removeEventListener('scroll', onScroll, true) - clearHideTimer() + clearHeaderHideTimer() } }, [contentInfo?.type, isLargeMarkdown, loading]) @@ -222,7 +240,10 @@ function FileSharePage() {
-
+