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() {
{/* 左侧目录 */}
-
+
+ {/* 侧栏收起时:悬浮展开按钮 */}
+ {siderCollapsed && (
+
+ )}
+
{/* 右侧内容区 */}
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() {
-
+