文章目录实现页面滚动时对应目录项高亮

This commit is contained in:
lxy 2025-09-22 18:23:17 +08:00
parent fae9655cad
commit 32556a4c4a
38 changed files with 500 additions and 212 deletions

View File

@ -9,5 +9,6 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
tocWidth: number | "auto" | undefined;
tocHeight: number | undefined;
showtitle: boolean;
activeColor: string | undefined;
}>) => React.ReactElement;
export default _default;

View File

@ -29,6 +29,7 @@ export default OakComponent({
tocWidth: undefined,
tocHeight: undefined,
showtitle: false, //大纲顶层显示文章名称
activeColor: undefined,
},
data: {
unsub: undefined,

View File

@ -5,7 +5,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
name?: string;
content?: string;
tocPosition: 'none' | 'left' | 'right';
highlightBgColor: string;
highlightBgColor?: string;
headerTop: number;
className?: string;
tocFixed: boolean;
@ -14,4 +14,5 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
tocWidth?: number;
tocHeight?: number | string;
showtitle: boolean;
activeColor?: string;
}, {}>): React.JSX.Element;

View File

@ -5,7 +5,7 @@ import classNames from 'classnames';
import { TocView } from '../toc/tocView';
import Styles from './web.module.less';
export default function Render(props) {
const { className, name, content, tocPosition = 'none', highlightBgColor = 'none', headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight, showtitle } = props.data;
const { className, name, content, tocPosition = 'none', highlightBgColor = 'none', activeColor, headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight, showtitle } = props.data;
const editorConfig = {
readOnly: true,
autoFocus: true,
@ -40,7 +40,9 @@ export default function Render(props) {
}, [name]);
return (<div className={classNames(Styles.container, className)}>
<div className={Styles.contentContainer}>
{tocPosition === "left" ? (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight ? `calc(${tocHeight} - 32px)` : 'calc(100vh - 32px)'} title={showtitle ? name : undefined}/>) : null}
{tocPosition === "left" ? (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} headerTop={headerTop} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight ? `calc(${tocHeight} - 32px)` : 'calc(100vh - 32px)'} title={showtitle ? name : undefined}/>) : null}
<div className={Styles.content}>
<div className={Styles.editorContainer}>
@ -64,7 +66,9 @@ export default function Render(props) {
</div>
</div>
</div>
{tocPosition === "right" ? (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight ? `calc(${tocHeight} - 32px)` : 'calc(100vh - 32px)'} title={showtitle ? name : undefined}/>) : null}
{tocPosition === "right" ? (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} headerTop={headerTop} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight ? `calc(${tocHeight} - 32px)` : 'calc(100vh - 32px)'} title={showtitle ? name : undefined}/>) : null}
</div>
</div>);
}

View File

@ -8,5 +8,6 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
origin: string;
scrollId: string;
height: number | "auto";
activeColor: string | undefined;
}>) => React.ReactElement;
export default _default;

View File

@ -32,6 +32,7 @@ export default OakComponent({
origin: 'qiniu', // 默认为七牛云
scrollId: '', // 滚动条所在容器id不传默认页面编辑器容器id
height: 600,
activeColor: undefined,
},
listeners: {
'editor,content'(prev, next) {

View File

@ -12,13 +12,14 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
articleMenuId: string;
oakId: string;
tocPosition: 'none' | 'left' | 'right';
highlightBgColor: string;
highlightBgColor?: string;
scrollId?: string;
tocWidth?: number;
tocHeight?: number | string;
height?: number | string;
tocClosed: boolean;
execuable: boolean;
activeColor?: string;
}, {
setHtml: (content: string) => void;
setEditor: (editor: any) => void;

View File

@ -31,7 +31,7 @@ function customCheckImageFn(src, alt, url) {
export default function Render(props) {
const { methods, data } = props;
const { t, setEditor, check, uploadFile, update, setHtml, gotoPreview, clearContentTip, } = methods;
const { oakId, oakFullpath, id, name, content, editor, origin = 'qiniu', tocPosition = 'none', highlightBgColor = 'none', scrollId, tocWidth, tocHeight, height = 600, tocClosed = false, execuable, } = data;
const { oakId, oakFullpath, id, name, content, editor, origin = 'qiniu', tocPosition = 'none', highlightBgColor, scrollId, tocWidth, tocHeight, height = 600, tocClosed = false, execuable, activeColor, } = data;
const [articleId, setArticleId] = useState('');
const [toc, setToc] = useState([]);
const [showToc, setShowToc] = useState(false);
@ -70,7 +70,9 @@ export default function Render(props) {
</div>
</div>
<div className={Style.contentContainer} id='article-upsert-editorContainer'>
{tocPosition === "left" ? (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc} highlightBgColor={highlightBgColor} closed={tocClosed} scrollId={containerId} tocWidth={tocWidth} tocHeight={'calc(100% - 16px)'}/>) : null}
{tocPosition === "left" ? (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} closed={tocClosed} scrollId={containerId} tocWidth={tocWidth} tocHeight={'calc(100% - 16px)'}/>) : null}
<div className={Style.content} style={{ maxWidth: `calc(100% - ${tocWidth || 228}px)` }}>
<div className={classNames(Style.editorContainer, {
@ -178,7 +180,9 @@ export default function Render(props) {
</div>
</div>
</div>
{tocPosition === "right" ? (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc} highlightBgColor={highlightBgColor} scrollId={containerId} tocWidth={tocWidth} tocHeight={tocHeight}/>) : null}
{tocPosition === "right" ? (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} scrollId={containerId} tocWidth={tocWidth} tocHeight={tocHeight}/>) : null}
</div>
</div>);
}

View File

@ -9,5 +9,6 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
tocWidth: number | "auto" | undefined;
tocHeight: number | undefined;
showtitle: boolean;
activeColor: string | undefined;
}>) => React.ReactElement;
export default _default;

View File

@ -34,6 +34,7 @@ export default OakComponent({
tocWidth: undefined,
tocHeight: undefined,
showtitle: false, //大纲顶层显示文章名称
activeColor: undefined,
},
methods: {},
});

View File

@ -5,7 +5,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
title: string;
content?: string;
tocPosition: 'none' | 'left' | 'right';
highlightBgColor: string;
highlightBgColor?: string;
headerTop: number;
className?: string;
tocFixed: boolean;
@ -14,4 +14,5 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
tocWidth?: number;
tocHeight?: number | string;
showtitle: boolean;
activeColor?: string;
}, {}>): React.JSX.Element;

View File

@ -5,7 +5,7 @@ import classNames from 'classnames';
import { TocView } from '../toc/tocView';
import Styles from './web.module.less';
export default function Render(props) {
const { className, title, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight, showtitle } = props.data;
const { className, title, content, tocPosition = 'none', tocFixed, highlightBgColor, activeColor, headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight, showtitle } = props.data;
const editorConfig = {
readOnly: true,
autoFocus: true,
@ -35,7 +35,9 @@ export default function Render(props) {
}, [tocPosition]);
return (<div className={classNames(Styles.container, className)}>
<div className={Styles.contentContainer}>
{tocPosition === "left" && (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight ? `calc(${tocHeight} - 32px)` : 'calc(100vh - 32px)'} title={showtitle ? title : undefined}/>)}
{tocPosition === "left" && (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} headerTop={headerTop} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight ? `calc(${tocHeight} - 32px)` : 'calc(100vh - 32px)'} title={showtitle ? title : undefined}/>)}
<div className={Styles.content}>
<div className={Styles.editorContainer}>
@ -59,7 +61,9 @@ export default function Render(props) {
</div>
</div>
</div>
{tocPosition === "right" && (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc} highlightBgColor={highlightBgColor} headerTop={headerTop} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight} title={showtitle ? title : undefined}/>)}
{tocPosition === "right" && (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} headerTop={headerTop} closed={tocClosed} scrollId={scrollId} tocWidth={tocWidth} tocHeight={tocHeight} title={showtitle ? title : undefined}/>)}
</div>
</div>);
}

View File

@ -9,7 +9,8 @@ export declare function TocView(props: {
showToc: boolean;
tocPosition: 'left' | 'right';
setShowToc: (showToc: boolean) => void;
highlightBgColor: string;
highlightBgColor?: string;
activeColor?: string;
headerTop?: number;
scrollId?: string;
closed?: boolean;

View File

@ -1,19 +1,16 @@
import React, { useEffect, useState } from "react";
import React, { useEffect } from "react";
import { Button, Tooltip } from "antd";
import { CaretDownOutlined, CloseOutlined, MenuOutlined } from "@ant-design/icons";
import classNames from "classnames";
import Style from './tocView.module.less';
export function TocView(props) {
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, headerTop = 0, scrollId, closed = false, tocWidth, tocHeight = '100vh', title } = props;
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, activeColor = 'var(--oak-color-primary)', headerTop = 0, scrollId, closed = false, tocWidth, tocHeight = '100vh', title } = props;
// useEffect(() => {
// document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
// }, [highlightBgColor]);
useEffect(() => {
document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
}, [highlightBgColor]);
const [selectedId, setSelectedId] = useState('');
useEffect(() => {
if (selectedId && selectedId !== '') {
const e = document.getElementById(`li-${selectedId}`);
}
}, [selectedId]);
document.documentElement.style.setProperty('--active-color', activeColor);
}, [activeColor]);
const generateTocList = (items, currentLevel = 1, parentId = null) => {
//递归生成嵌套列表
const result = [];
@ -51,35 +48,7 @@ export function TocView(props) {
ulElem?.classList.add(Style.fold);
}
}}/>
<div style={{ fontSize: '1em', fontWeight: item.level === 1 ? 'bold' : 'normal' }} className={Style.tocItem} onClick={(event) => {
setSelectedId(item.id);
//页面滚动到对应元素
const elem = document.getElementById(item.id);
const elemTop = elem?.getBoundingClientRect().top;
if (scrollId) {
const scrollContainer = document.getElementById(scrollId);
const containerTop = scrollContainer?.getBoundingClientRect().top;
scrollContainer?.scrollBy({
top: elemTop - containerTop,
behavior: 'smooth',
});
}
else {
// const containerTop = document.body.getBoundingClientRect().top;
window.scrollBy({
top: elemTop - headerTop,
behavior: 'smooth',
});
}
//添加背景色
elem?.classList.add(Style.highlight);
//移除背景色类名
setTimeout(function () {
elem?.classList.remove(Style.highlight);
}, 1000);
event.preventDefault();
event.stopPropagation();
}}>
<div style={{ fontSize: '1em', fontWeight: item.level === 1 ? 'bold' : 'normal' }} className={Style.tocItem}>
{item.text}
</div>
</li>);
@ -89,6 +58,129 @@ export function TocView(props) {
}
return result;
};
useEffect(() => {
const tocContainer = document.getElementById('tocContainer');
const tocItems = tocContainer?.querySelectorAll('li');
let sections = [];
for (const t of toc) {
const item = document.getElementById(t.id);
sections.push(item);
}
let currentHighlighted = '';
let isClick = false;
let clickTimeout = undefined;
// 滚动目录以确保指定目录项可见
function scrollToTocItem(item) {
if (tocContainer) {
const tocRect = tocContainer.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
// 检查目录项是否在可视区域内
if (itemRect.top < tocRect.top || itemRect.bottom > tocRect.bottom) {
const itemOffsetTop = item.offsetTop;
const containerHeight = tocContainer.clientHeight;
const itemHeight = item.offsetHeight;
let targetScrollTop;
if (itemRect.top < tocRect.top) {
// 目录项在可视区域上方
targetScrollTop = itemOffsetTop - 80;
}
else {
// 目录项在可视区域下方
targetScrollTop = itemOffsetTop - containerHeight + itemHeight + 10;
}
tocContainer.scrollTo({
top: targetScrollTop,
behavior: 'smooth'
});
}
}
}
// 高亮指定的目录项
function highlightTocItem(targetId, source) {
// 移除所有目录项的active样式
tocItems?.forEach(item => {
item.classList.remove(Style.active);
});
// 找到对应的目录项并添加active样式
const correspondingTocItem = document.querySelector(`#${targetId}`);
if (correspondingTocItem) {
correspondingTocItem.classList.add(Style.active);
// 滚动目录
scrollToTocItem(correspondingTocItem);
// 如果是点击触发的,设置超时
if (source === 'click') {
isClick = true;
// 设置超时1秒后恢复滚动的高亮功能
clearTimeout(clickTimeout);
clickTimeout = setTimeout(() => {
isClick = false;
}, 1000);
}
currentHighlighted = targetId;
}
}
// 点击目录项平滑滚动到对应区块并高亮
const handleClick = function (event) {
const targetSection = event.target.closest('li');
const targetId = targetSection.getAttribute('id');
if (targetSection) {
// 高亮点击的目录项
highlightTocItem(targetId, 'click');
// 平滑滚动到目标位置
const itemId = targetId.substring(3);
const elem = document.getElementById(itemId);
const elemTop = elem?.getBoundingClientRect().top;
if (scrollId) {
const scrollContainer = document.getElementById(scrollId);
const containerTop = scrollContainer?.getBoundingClientRect().top;
scrollContainer?.scrollBy({
top: elemTop - containerTop,
behavior: 'smooth',
});
}
else {
window.scrollBy({
top: elemTop - headerTop,
behavior: 'smooth',
});
}
}
};
tocItems?.forEach(item => {
item.addEventListener('click', handleClick);
});
// 创建Intersection Observer实例
const observer = new IntersectionObserver(entries => {
// 如果处于点击状态,跳过滚动检测
if (isClick)
return;
entries.forEach(entry => {
if (entry.isIntersecting) {
// 获取当前可见区块的ID
const id = `li-${entry.target.getAttribute('id')}`;
if (id && id !== currentHighlighted) {
highlightTocItem(id, 'scroll');
}
}
});
}, {
threshold: 0.5,
rootMargin: '0px 0px -75% 0px',
});
// 开始观察所有内容区块
sections.forEach(section => {
observer.observe(section);
});
return () => {
if (tocContainer) {
tocContainer.removeEventListener('click', handleClick);
observer.disconnect();
if (clickTimeout) {
clearTimeout(clickTimeout);
}
}
};
}, [toc, showToc]);
return (<div className={Style.tocContainer} style={Object.assign({}, tocWidth ? { width: tocWidth } : {}, tocHeight ? { height: tocHeight } : {})}>
{showToc ? (<>
<div className={Style.catalogTitle}>
@ -96,7 +188,7 @@ export function TocView(props) {
{closed ? (<CloseOutlined style={{ color: '#A5A5A5' }} onClick={() => setShowToc(false)}/>) : null}
</div>
{(toc && toc.length > 0) ? (<ul style={{ listStyleType: 'none', paddingInlineStart: '0px', overflowX: 'hidden', overflowY: 'auto', height: '100%', borderLeft: tocPosition === 'right' ? '1px solid var(--oak-border-color)' : '' }}>{generateTocList([...toc])}</ul>) : (<div style={{ display: 'flex', alignItems: 'center', color: '#B1B1B1', height: '200px' }}>
{(toc && toc.length > 0) ? (<ul id="tocContainer" style={{ listStyleType: 'none', paddingInlineStart: '0px', overflowX: 'hidden', overflowY: 'auto', height: '100%', borderLeft: tocPosition === 'right' ? '1px solid var(--oak-border-color)' : '' }}>{generateTocList([...toc])}</ul>) : (<div style={{ display: 'flex', alignItems: 'center', color: '#B1B1B1', height: '200px' }}>
<div>
<div>
对文档内容应用标题样式

View File

@ -38,8 +38,8 @@
transition: all 1s ease;
}
.highlightBorder {
border-left: 1px solid var(--oak-color-primary);
.active {
color: var(--active-color);
}
.catalogTitle {

View File

@ -8,5 +8,6 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
origin: string;
scrollId: string;
height: number | "auto";
activeColor: string | undefined;
}>) => React.ReactElement;
export default _default;

View File

@ -31,6 +31,7 @@ export default OakComponent({
origin: 'qiniu', // 默认为七牛云
scrollId: '', // 滚动条所在容器id不传默认页面编辑器容器id
height: 600,
activeColor: undefined,
},
listeners: {
'editor,content'(prev, next) {

View File

@ -12,11 +12,12 @@ export default function Render(props: WebComponentProps<EntityDict, 'article', f
articleMenuId: string;
oakId: string;
tocPosition: 'none' | 'left' | 'right';
highlightBgColor: string;
highlightBgColor?: string;
scrollId?: string;
tocWidth?: number;
tocHeight?: number | string;
height?: number | string;
activeColor?: string;
}, {
setHtml: (content: string) => void;
setEditor: (editor: any) => void;

View File

@ -31,7 +31,7 @@ function customCheckImageFn(src, alt, url) {
export default function Render(props) {
const { methods, data } = props;
const { t, setEditor, check, uploadFile, update, setHtml, gotoPreview, clearContentTip, } = methods;
const { oakId, oakFullpath, id, content, editor, origin = 'qiniu', tocPosition = 'none', highlightBgColor = 'none', scrollId, tocWidth, tocHeight, height = 600 } = data;
const { oakId, oakFullpath, id, content, editor, origin = 'qiniu', tocPosition = 'none', highlightBgColor, activeColor, scrollId, tocWidth, tocHeight, height = 600 } = data;
const [articleId, setArticleId] = useState('');
const [toc, setToc] = useState([]);
const [showToc, setShowToc] = useState(false);
@ -52,7 +52,9 @@ export default function Render(props) {
<Toolbar editor={editor} defaultConfig={toolbarConfig} mode="default"/>
</div>
<div className={Style.contentContainer}>
{tocPosition === "left" ? (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc} highlightBgColor={highlightBgColor} scrollId={containerId} tocWidth={tocWidth} tocHeight={tocHeight || (height === 'auto' ? '100vh' : height)}/>) : null}
{tocPosition === "left" ? (<TocView toc={toc} showToc={showToc} tocPosition="left" setShowToc={setShowToc}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} scrollId={containerId} tocWidth={tocWidth} tocHeight={tocHeight || (height === 'auto' ? '100vh' : height)}/>) : null}
<div className={Style.content} style={{ maxWidth: `calc(100% - ${tocWidth || 228}px)` }}>
<div id={containerId} className={classNames(Style.editorContainer, {
@ -166,7 +168,9 @@ export default function Render(props) {
</Space>
</div>
</div>
{tocPosition === "right" ? (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc} highlightBgColor={highlightBgColor} scrollId={containerId} tocWidth={tocWidth} tocHeight={tocHeight}/>) : null}
{tocPosition === "right" ? (<TocView toc={toc} showToc={showToc} tocPosition="right" setShowToc={setShowToc}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} scrollId={containerId} tocWidth={tocWidth} tocHeight={tocHeight}/>) : null}
</div>
</div>);
}

View File

@ -10,4 +10,5 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
}[];
highlightBgColor: string;
allowHiddenMenu: boolean;
activeColor?: string;
}, {}>): React.JSX.Element;

View File

@ -6,7 +6,7 @@ import ArticleDetail from '../../article/detail';
import classNames from 'classnames';
export default function Render(props) {
const { data, methods } = props;
const { oakFullpath, menu, menuName, articles, highlightBgColor, allowHiddenMenu } = data;
const { oakFullpath, menu, menuName, articles, highlightBgColor, activeColor, allowHiddenMenu } = data;
const { t } = methods;
const [selectedId, setSelectedId] = useState('');
const [menuHidden, setMenuHidden] = useState(false);
@ -43,7 +43,9 @@ export default function Render(props) {
</div>))}
</div>)}
<div className={Styles.docContainer} id="articleBox">
{selectedId && (<ArticleDetail oakPath={`$articleMenu/detail-articleDetail-${selectedId}`} oakId={selectedId} tocPosition='right' tocFixed={true} highlightBgColor={highlightBgColor} style={{ width: '100%' }} scrollId={"articleBox"}/>)}
{selectedId && (<ArticleDetail oakPath={`$articleMenu/detail-articleDetail-${selectedId}`} oakId={selectedId} tocPosition='right' tocFixed={true}
// highlightBgColor={highlightBgColor}
activeColor={activeColor} style={{ width: '100%' }} scrollId={"articleBox"}/>)}
</div>
</div>);

View File

@ -14,5 +14,6 @@ declare const _default: (props: import("oak-frontend-base").ReactComponentProps<
setCopyArticleUrl: (articleId: string) => string;
origin: string;
scrollId: string;
activeColor: string | undefined;
}>) => React.ReactElement;
export default _default;

View File

@ -27,5 +27,6 @@ export default OakComponent({
setCopyArticleUrl: (articleId) => '',
origin: 'qiniu', // cos origin默认七牛云
scrollId: '', // 滚动条所在容器id不传默认页面编辑器容器id
activeColor: undefined, //目录高亮颜色
},
});

View File

@ -15,6 +15,7 @@ export default function Render(props: WebComponentProps<EntityDict, 'articleMenu
onArticleEdit: (oakId: string) => void;
setCopyArticleUrl: (id: string) => string;
scrollId?: string;
activeColor?: string;
}, {
gotoDoc: () => void;
gotoArticleDetail: (oakId: string) => void;

View File

@ -9,18 +9,18 @@ import Styles from './web.pc.module.less';
function BreadcrumbView(props) {
const { breadcrumbItems } = props;
return (<div style={{ fontSize: 14, display: 'flex', flexDirection: 'row', margin: 10 }}>
{breadcrumbItems?.map((breadcrumbItem, index) => {
{breadcrumbItems?.map((breadcrumbItem, index) => {
return index !== breadcrumbItems.length - 1 ? (<div style={{ color: '#B2B2B2' }} key={index}>
{breadcrumbItem}
<span style={{ margin: '0 6px' }}>/</span>
</div>) : (<div className={Styles.breadcrumbItem} key={index}>
{breadcrumbItem}
</div>);
{breadcrumbItem}
<span style={{ margin: '0 6px' }}>/</span>
</div>) : (<div className={Styles.breadcrumbItem} key={index}>
{breadcrumbItem}
</div>);
})}
</div>);
</div>);
}
export default function Render(props) {
const { entity, entityId, oakFullpath, show, articleMenuId, articleId, tocPosition, highlightBgColor, onMenuViewById, onArticlePreview, onArticleEdit, origin, setCopyArticleUrl, scrollId } = props.data;
const { entity, entityId, oakFullpath, show, articleMenuId, articleId, tocPosition, highlightBgColor, activeColor, onMenuViewById, onArticlePreview, onArticleEdit, origin, setCopyArticleUrl, scrollId } = props.data;
const { gotoDoc, setMessage, gotoArticleDetail } = props.methods;
const [editArticleId, setEditArticleId] = useState('');
const [breadcrumbItems, setBreadcrumbItems] = useState([]);
@ -117,7 +117,7 @@ export default function Render(props) {
</Space>
</div>
<BreadcrumbView breadcrumbItems={breadcrumbItems}/>
{isEdit ? (<ArticleUpsert key={editArticleId} oakId={editArticleId} oakAutoUnmount={true} oakPath={`$articleMenu/treeManager-ArticleUpsert-${editArticleId}`} changeIsEdit={changeIsEdit} tocPosition={tocPosition} highlightBgColor={highlightBgColor} origin={origin} scrollId={scrollId}/>) : (<ArticleCell key={editArticleId} oakId={editArticleId} oakAutoUnmount={true} oakPath={`$articleMenu/treeManager-ArticleCell-${editArticleId}`}/>)}
{isEdit ? (<ArticleUpsert key={editArticleId} oakId={editArticleId} oakAutoUnmount={true} oakPath={`$articleMenu/treeManager-ArticleUpsert-${editArticleId}`} changeIsEdit={changeIsEdit} tocPosition={tocPosition} highlightBgColor={highlightBgColor} activeColor={activeColor} origin={origin} scrollId={scrollId}/>) : (<ArticleCell key={editArticleId} oakId={editArticleId} oakAutoUnmount={true} oakPath={`$articleMenu/treeManager-ArticleCell-${editArticleId}`}/>)}
</div>) : null}
</div>
</div>);
@ -125,33 +125,35 @@ export default function Render(props) {
return (<div className={Styles.container}>
{menuHidden ? (<div className={Styles.menu_hidden}>
<div className={Styles.menuHeader}>
<Tooltip title={'显示菜单'}>
<Button type="text" icon={<MenuUnfoldOutlined />} size="small" onClick={() => setMenuHidden(false)}/>
</Tooltip>
<Tooltip title={'显示菜单'}>
<Button type="text" icon={<MenuUnfoldOutlined />} size="small" onClick={() => setMenuHidden(false)}/>
</Tooltip>
</div>
</div>) : (<div className={Styles.menu}>
<div className={Styles.menuHeader}>
<div className={Styles.menuTitle}>菜单</div>
<div className={Styles.menuActions}>
<Space size={4}>
<Tooltip title={'查看文档'}>
<Button type="text" icon={<EyeOutlined />} size="small" onClick={() => gotoDoc()}/>
</Tooltip>
<Tooltip title={'添加分类'}>
<Button type="text" icon={<PlusOutlined />} size="small" onClick={() => setAddOpen(true)}/>
</Tooltip>
<Tooltip title={'隐藏菜单'}>
<Button type="text" icon={<MenuFoldOutlined />} size="small" onClick={() => setMenuHidden(true)}/>
</Tooltip>
</Space>
</div>
<div className={Styles.menuTitle}>菜单</div>
<div className={Styles.menuActions}>
<Space size={4}>
<Tooltip title={'查看文档'}>
<Button type="text" icon={<EyeOutlined />} size="small" onClick={() => gotoDoc()}/>
</Tooltip>
<Tooltip title={'添加分类'}>
<Button type="text" icon={<PlusOutlined />} size="small" onClick={() => setAddOpen(true)}/>
</Tooltip>
<Tooltip title={'隐藏菜单'}>
<Button type="text" icon={<MenuFoldOutlined />} size="small" onClick={() => setMenuHidden(true)}/>
</Tooltip>
</Space>
</div>
</div>
<TreeList oakPath={`$articleMenu/treeManager-TreeList`} entity={entity} entityId={entityId} onGrandChildEditArticleChange={checkEditArticle} show={show} changeAddOpen={changeAddOpen} addOpen={addOpen} onMenuViewById={onMenuViewById} setCopyArticleUrl={setCopyArticleUrl}/>
</div>)}
<div className={Styles.editor}>
{editArticleId ? (<ArticleUpsert key={editArticleId} oakId={editArticleId} oakAutoUnmount={true} oakPath={`$articleMenu/treeManager-ArticleUpsert-${editArticleId}`} tocPosition={tocPosition} highlightBgColor={highlightBgColor} onArticlePreview={onArticlePreview} origin={origin} scrollId={scrollId}/>) : null}
{editArticleId ? (<ArticleUpsert key={editArticleId} oakId={editArticleId} oakAutoUnmount={true} oakPath={`$articleMenu/treeManager-ArticleUpsert-${editArticleId}`} tocPosition={tocPosition}
// highlightBgColor={highlightBgColor}
onArticlePreview={onArticlePreview} origin={origin} scrollId={scrollId}/>) : null}
</div>
</div>);
}

View File

@ -30,6 +30,7 @@ export default OakComponent({
tocWidth: undefined as number | 'auto' | undefined,
tocHeight: undefined as number | undefined,
showtitle: false, //大纲顶层显示文章名称
activeColor: undefined as string | undefined,
},
data: {
unsub: undefined as undefined | (() => void),

View File

@ -19,7 +19,7 @@ export default function Render(
name?: string;
content?: string;
tocPosition: 'none' | 'left' | 'right';
highlightBgColor: string;
highlightBgColor?: string;
headerTop: number;
className?: string;
tocFixed: boolean;
@ -28,11 +28,12 @@ export default function Render(
tocWidth?: number;
tocHeight?: number | string;
showtitle: boolean;
activeColor?: string;
},
{}
>
) {
const { className, name, content, tocPosition = 'none', highlightBgColor = 'none', headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight, showtitle } = props.data;
const { className, name, content, tocPosition = 'none', highlightBgColor = 'none', activeColor, headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight, showtitle } = props.data;
const editorConfig: Partial<IEditorConfig> = {
readOnly: true,
autoFocus: true,
@ -80,7 +81,8 @@ export default function Render(
showToc={showToc}
tocPosition="left"
setShowToc={setShowToc}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
headerTop={headerTop}
closed={tocClosed}
scrollId={scrollId}
@ -131,7 +133,8 @@ export default function Render(
showToc={showToc}
tocPosition="right"
setShowToc={setShowToc}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
headerTop={headerTop}
closed={tocClosed}
scrollId={scrollId}

View File

@ -36,6 +36,7 @@ export default OakComponent({
origin: 'qiniu', // 默认为七牛云
scrollId: '', // 滚动条所在容器id不传默认页面编辑器容器id
height: 600 as number | 'auto',
activeColor: undefined as string | undefined,
},
listeners: {
'editor,content'(prev, next) {

View File

@ -60,13 +60,14 @@ export default function Render(
articleMenuId: string;
oakId: string;
tocPosition: 'none' | 'left' | 'right';
highlightBgColor: string;
highlightBgColor?: string;
scrollId?: string;
tocWidth?: number;
tocHeight?: number | string;
height?: number | string;
tocClosed: boolean;
execuable: boolean;
activeColor?: string;
},
{
setHtml: (content: string) => void;
@ -101,13 +102,14 @@ export default function Render(
editor,
origin = 'qiniu',
tocPosition = 'none',
highlightBgColor = 'none',
highlightBgColor,
scrollId,
tocWidth,
tocHeight,
height = 600,
tocClosed = false,
execuable,
activeColor,
} = data;
const [articleId, setArticleId] = useState('');
const [toc, setToc] = useState<TocItem[]>([]);
@ -173,7 +175,8 @@ export default function Render(
showToc={showToc}
tocPosition="left"
setShowToc={setShowToc}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
closed={tocClosed}
scrollId={containerId}
tocWidth={tocWidth}
@ -364,7 +367,8 @@ export default function Render(
showToc={showToc}
tocPosition="right"
setShowToc={setShowToc}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
scrollId={containerId}
tocWidth={tocWidth}
tocHeight={tocHeight}

View File

@ -36,6 +36,7 @@ export default OakComponent({
tocWidth: undefined as number | 'auto' | undefined,
tocHeight: undefined as number | undefined,
showtitle: false, //大纲顶层显示文章名称
activeColor: undefined as string | undefined,
},
methods: {},
});

View File

@ -17,7 +17,7 @@ export default function Render(
title: string;
content?: string;
tocPosition: 'none' | 'left' | 'right';
highlightBgColor: string;
highlightBgColor?: string;
headerTop: number;
className?: string;
tocFixed: boolean;
@ -26,11 +26,12 @@ export default function Render(
tocWidth?: number;
tocHeight?: number | string;
showtitle: boolean;
activeColor?: string;
},
{}
>
) {
const { className, title, content, tocPosition = 'none', tocFixed, highlightBgColor = 'none', headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight, showtitle } = props.data;
const { className, title, content, tocPosition = 'none', tocFixed, highlightBgColor, activeColor, headerTop = 0, tocClosed = false, scrollId, tocWidth, tocHeight, showtitle } = props.data;
const editorConfig: Partial<IEditorConfig> = {
readOnly: true,
autoFocus: true,
@ -71,7 +72,8 @@ export default function Render(
showToc={showToc}
tocPosition="left"
setShowToc={setShowToc}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
headerTop={headerTop}
closed={tocClosed}
scrollId={scrollId}
@ -122,7 +124,8 @@ export default function Render(
showToc={showToc}
tocPosition="right"
setShowToc={setShowToc}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
headerTop={headerTop}
closed={tocClosed}
scrollId={scrollId}

View File

@ -38,8 +38,8 @@
transition: all 1s ease;
}
.highlightBorder {
border-left: 1px solid var(--oak-color-primary);
.active {
color: var(--active-color);
}
.catalogTitle {

View File

@ -16,7 +16,8 @@ export function TocView(
showToc: boolean;
tocPosition: 'left' | 'right';
setShowToc: (showToc: boolean) => void;
highlightBgColor: string;
highlightBgColor?: string; //暂时废弃背景色改为高亮文字
activeColor?: string;
headerTop?: number;
scrollId?: string;
closed?: boolean,
@ -25,19 +26,14 @@ export function TocView(
title?: string,
}
) {
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, headerTop = 0, scrollId, closed = false, tocWidth, tocHeight = '100vh', title } = props;
const { toc, showToc, tocPosition, setShowToc, highlightBgColor, activeColor = 'var(--oak-color-primary)', headerTop = 0, scrollId, closed = false, tocWidth, tocHeight = '100vh', title } = props;
// useEffect(() => {
// document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
// }, [highlightBgColor]);
useEffect(() => {
document.documentElement.style.setProperty('--highlight-bg-color', highlightBgColor);
}, [highlightBgColor]);
const [selectedId, setSelectedId] = useState('');
useEffect(() => {
if (selectedId && selectedId !== '') {
const e = document.getElementById(`li-${selectedId}`);
}
}, [selectedId]);
document.documentElement.style.setProperty('--active-color', activeColor);
}, [activeColor]);
const generateTocList = (items: TocItem[], currentLevel: number = 1, parentId: string | null = null): React.ReactNode => {
//递归生成嵌套列表
@ -82,39 +78,38 @@ export function TocView(
<div
style={{ fontSize: '1em', fontWeight: item.level === 1 ? 'bold' : 'normal' }}
className={Style.tocItem}
onClick={(event: any) => {
setSelectedId(item.id);
//页面滚动到对应元素
const elem = document.getElementById(item.id);
const elemTop = elem?.getBoundingClientRect().top;
// onClick={(event: any) => {
// //页面滚动到对应元素
// const elem = document.getElementById(item.id);
// const elemTop = elem?.getBoundingClientRect().top;
if (scrollId) {
const scrollContainer = document.getElementById(scrollId);
const containerTop = scrollContainer?.getBoundingClientRect().top;
// if (scrollId) {
// const scrollContainer = document.getElementById(scrollId);
// const containerTop = scrollContainer?.getBoundingClientRect().top;
scrollContainer?.scrollBy({
top: elemTop! - containerTop!,
behavior: 'smooth',
});
}
else {
// const containerTop = document.body.getBoundingClientRect().top;
window.scrollBy({
top: elemTop! - headerTop,
behavior: 'smooth',
});
}
// scrollContainer?.scrollBy({
// top: elemTop! - containerTop!,
// behavior: 'smooth',
// });
// }
// else {
// // const containerTop = document.body.getBoundingClientRect().top;
// window.scrollBy({
// top: elemTop! - headerTop,
// behavior: 'smooth',
// });
// }
//添加背景色
elem?.classList.add(Style.highlight);
//移除背景色类名
setTimeout(function () {
elem?.classList.remove(Style.highlight);
}, 1000);
// //添加背景色
// elem?.classList.add(Style.highlight);
// //移除背景色类名
// setTimeout(function () {
// elem?.classList.remove(Style.highlight);
// }, 1000);
event.preventDefault();
event.stopPropagation();
}}
// event.preventDefault();
// event.stopPropagation();
// }}
>
{item.text}
</div>
@ -127,6 +122,147 @@ export function TocView(
return result;
};
useEffect(() => {
const tocContainer = document.getElementById('tocContainer');
const tocItems = tocContainer?.querySelectorAll('li');
let sections = [];
for (const t of toc) {
const item = document.getElementById(t.id);
sections.push(item!);
}
let currentHighlighted = '';
let isClick = false;
let clickTimeout: NodeJS.Timeout | undefined = undefined;
// 滚动目录以确保指定目录项可见
function scrollToTocItem(item: any) {
if (tocContainer) {
const tocRect = tocContainer.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
// 检查目录项是否在可视区域内
if (itemRect.top < tocRect.top || itemRect.bottom > tocRect.bottom) {
const itemOffsetTop = item.offsetTop;
const containerHeight = tocContainer.clientHeight;
const itemHeight = item.offsetHeight;
let targetScrollTop;
if (itemRect.top < tocRect.top) {
// 目录项在可视区域上方
targetScrollTop = itemOffsetTop - 80;
} else {
// 目录项在可视区域下方
targetScrollTop = itemOffsetTop - containerHeight + itemHeight + 10;
}
tocContainer.scrollTo({
top: targetScrollTop,
behavior: 'smooth'
});
}
}
}
// 高亮指定的目录项
function highlightTocItem(targetId: string, source: 'click' | 'scroll') {
// 移除所有目录项的active样式
tocItems?.forEach(item => {
item.classList.remove(Style.active);
});
// 找到对应的目录项并添加active样式
const correspondingTocItem = document.querySelector(`#${targetId}`);
if (correspondingTocItem) {
correspondingTocItem.classList.add(Style.active);
// 滚动目录
scrollToTocItem(correspondingTocItem);
// 如果是点击触发的,设置超时
if (source === 'click') {
isClick = true;
// 设置超时1秒后恢复滚动的高亮功能
clearTimeout(clickTimeout);
clickTimeout = setTimeout(() => {
isClick = false;
}, 1000);
}
currentHighlighted = targetId;
}
}
// 点击目录项平滑滚动到对应区块并高亮
const handleClick = function (event: any) {
const targetSection = event.target.closest('li');
const targetId = targetSection.getAttribute('id');
if (targetSection) {
// 高亮点击的目录项
highlightTocItem(targetId, 'click');
// 平滑滚动到目标位置
const itemId = targetId.substring(3);
const elem = document.getElementById(itemId);
const elemTop = elem?.getBoundingClientRect().top;
if (scrollId) {
const scrollContainer = document.getElementById(scrollId);
const containerTop = scrollContainer?.getBoundingClientRect().top;
scrollContainer?.scrollBy({
top: elemTop! - containerTop!,
behavior: 'smooth',
});
}
else {
window.scrollBy({
top: elemTop! - headerTop,
behavior: 'smooth',
});
}
}
}
tocItems?.forEach(item => {
item.addEventListener('click', handleClick);
});
// 创建Intersection Observer实例
const observer = new IntersectionObserver(entries => {
// 如果处于点击状态,跳过滚动检测
if (isClick) return;
entries.forEach(entry => {
if (entry.isIntersecting) {
// 获取当前可见区块的ID
const id = `li-${entry.target.getAttribute('id')}`;
if (id && id !== currentHighlighted) {
highlightTocItem(id, 'scroll');
}
}
});
}, {
threshold: 0.5,
rootMargin: '0px 0px -75% 0px',
});
// 开始观察所有内容区块
sections.forEach(section => {
observer.observe(section);
});
return () => {
if (tocContainer) {
tocContainer.removeEventListener('click', handleClick);
observer.disconnect();
if (clickTimeout) {
clearTimeout(clickTimeout);
}
}
};
}, [toc, showToc]);
return (
<div
className={Style.tocContainer}
@ -140,7 +276,7 @@ export function TocView(
</div>
{(toc && toc.length > 0) ? (
<ul style={{ listStyleType: 'none', paddingInlineStart: '0px', overflowX: 'hidden', overflowY: 'auto', height: '100%', borderLeft: tocPosition === 'right' ? '1px solid var(--oak-border-color)' : '' }}>{generateTocList([...toc])}</ul>
<ul id="tocContainer" style={{ listStyleType: 'none', paddingInlineStart: '0px', overflowX: 'hidden', overflowY: 'auto', height: '100%', borderLeft: tocPosition === 'right' ? '1px solid var(--oak-border-color)' : '' }}>{generateTocList([...toc])}</ul>
) : (
<div style={{ display: 'flex', alignItems: 'center', color: '#B1B1B1', height: '200px' }}>
<div>

View File

@ -34,6 +34,7 @@ export default OakComponent({
origin: 'qiniu', // 默认为七牛云
scrollId: '', // 滚动条所在容器id不传默认页面编辑器容器id
height: 600 as number | 'auto',
activeColor: undefined as string | undefined,
},
listeners: {
'editor,content'(prev, next) {

View File

@ -60,11 +60,12 @@ export default function Render(
articleMenuId: string;
oakId: string;
tocPosition: 'none' | 'left' | 'right';
highlightBgColor: string;
highlightBgColor?: string;
scrollId?: string;
tocWidth?: number;
tocHeight?: number | string;
height?: number | string;
activeColor?: string;
},
{
setHtml: (content: string) => void;
@ -98,7 +99,8 @@ export default function Render(
editor,
origin = 'qiniu',
tocPosition = 'none',
highlightBgColor = 'none',
highlightBgColor,
activeColor,
scrollId,
tocWidth,
tocHeight,
@ -141,7 +143,8 @@ export default function Render(
showToc={showToc}
tocPosition="left"
setShowToc={setShowToc}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
scrollId={containerId}
tocWidth={tocWidth}
tocHeight={tocHeight || (height === 'auto' ? '100vh' : height)}
@ -351,7 +354,8 @@ export default function Render(
showToc={showToc}
tocPosition="right"
setShowToc={setShowToc}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
scrollId={containerId}
tocWidth={tocWidth}
tocHeight={tocHeight}

View File

@ -22,13 +22,14 @@ export default function Render(
}[]
highlightBgColor: string;
allowHiddenMenu: boolean;
activeColor?: string;
},
{
}
>
) {
const { data, methods } = props;
const { oakFullpath, menu, menuName, articles, highlightBgColor, allowHiddenMenu } = data;
const { oakFullpath, menu, menuName, articles, highlightBgColor, activeColor, allowHiddenMenu } = data;
const { t } = methods;
const [selectedId, setSelectedId] = useState('');
const [menuHidden, setMenuHidden] = useState(false);
@ -78,7 +79,7 @@ export default function Render(
behavior: 'instant',
});
}, 100);
}
}}
className={ele.id === selectedId ? classNames(Styles.article, Styles['article-selected']) : Styles.article}
@ -96,7 +97,8 @@ export default function Render(
oakId={selectedId}
tocPosition='right'
tocFixed={true}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
activeColor={activeColor}
style={{ width: '100%' }}
scrollId={"articleBox"}
/>

View File

@ -28,5 +28,6 @@ export default OakComponent({
setCopyArticleUrl: (articleId: string) => '' as string,
origin: 'qiniu', // cos origin默认七牛云
scrollId: '', // 滚动条所在容器id不传默认页面编辑器容器id
activeColor: undefined as string | undefined, //目录高亮颜色
},
});

View File

@ -13,21 +13,21 @@ function BreadcrumbView(props: { breadcrumbItems: string[] }) {
const { breadcrumbItems } = props;
return (
<div style={{ fontSize: 14, display: 'flex', flexDirection: 'row', margin: 10 }}>
{
breadcrumbItems?.map((breadcrumbItem: string, index: number) => {
return index !== breadcrumbItems.length - 1 ? (
<div style={{ color: '#B2B2B2' }} key={index}>
{breadcrumbItem}
<span style={{ margin: '0 6px' }}>/</span>
</div>
) : (
<div className={Styles.breadcrumbItem} key={index}>
{breadcrumbItem}
</div>
)
})
}
</div>
{
breadcrumbItems?.map((breadcrumbItem: string, index: number) => {
return index !== breadcrumbItems.length - 1 ? (
<div style={{ color: '#B2B2B2' }} key={index}>
{breadcrumbItem}
<span style={{ margin: '0 6px' }}>/</span>
</div>
) : (
<div className={Styles.breadcrumbItem} key={index}>
{breadcrumbItem}
</div>
)
})
}
</div>
)
}
@ -49,7 +49,8 @@ export default function Render(
onArticlePreview: (content?: string, title?: string) => void;
onArticleEdit: (oakId: string) => void;
setCopyArticleUrl: (id: string) => string;
scrollId?: string
scrollId?: string;
activeColor?: string;
},
{
gotoDoc: () => void;
@ -57,7 +58,7 @@ export default function Render(
}
>
) {
const { entity, entityId, oakFullpath, show, articleMenuId, articleId, tocPosition, highlightBgColor, onMenuViewById, onArticlePreview, onArticleEdit, origin, setCopyArticleUrl, scrollId } = props.data;
const { entity, entityId, oakFullpath, show, articleMenuId, articleId, tocPosition, highlightBgColor, activeColor, onMenuViewById, onArticlePreview, onArticleEdit, origin, setCopyArticleUrl, scrollId } = props.data;
const { gotoDoc, setMessage, gotoArticleDetail } = props.methods;
const [editArticleId, setEditArticleId] = useState('');
const [breadcrumbItems, setBreadcrumbItems] = useState([] as string[]);
@ -201,13 +202,13 @@ export default function Render(
{isEdit ? (
<Button
onClick={() => setIsEdit(false)}
>
>
<FileOutlined />
</Button>
) : (
<Button
onClick={() => setIsEdit(true)}
>
>
<EditOutlined />
</Button>
)}
@ -224,6 +225,7 @@ export default function Render(
changeIsEdit={changeIsEdit}
tocPosition={tocPosition}
highlightBgColor={highlightBgColor}
activeColor={activeColor}
origin={origin}
scrollId={scrollId}
/>
@ -250,49 +252,49 @@ export default function Render(
menuHidden ? (
<div className={Styles.menu_hidden}>
<div className={Styles.menuHeader}>
<Tooltip title={'显示菜单'}>
<Button
type="text"
icon={<MenuUnfoldOutlined />}
size="small"
onClick={() => setMenuHidden(false)}
/>
</Tooltip>
<Tooltip title={'显示菜单'}>
<Button
type="text"
icon={<MenuUnfoldOutlined />}
size="small"
onClick={() => setMenuHidden(false)}
/>
</Tooltip>
</div>
</div>
) : (
<div className={Styles.menu}>
<div className={Styles.menuHeader}>
<div className={Styles.menuTitle}></div>
<div className={Styles.menuActions}>
<Space size={4}>
<Tooltip title={'查看文档'}>
<Button
type="text"
icon={<EyeOutlined />}
size="small"
onClick={() => gotoDoc()}
/>
</Tooltip>
<Tooltip title={'添加分类'}>
<Button
type="text"
icon={<PlusOutlined />}
size="small"
onClick={() => setAddOpen(true)}
/>
</Tooltip>
<Tooltip title={'隐藏菜单'}>
<Button
type="text"
icon={<MenuFoldOutlined />}
size="small"
onClick={() => setMenuHidden(true)}
/>
</Tooltip>
</Space>
</div>
<div className={Styles.menuTitle}></div>
<div className={Styles.menuActions}>
<Space size={4}>
<Tooltip title={'查看文档'}>
<Button
type="text"
icon={<EyeOutlined />}
size="small"
onClick={() => gotoDoc()}
/>
</Tooltip>
<Tooltip title={'添加分类'}>
<Button
type="text"
icon={<PlusOutlined />}
size="small"
onClick={() => setAddOpen(true)}
/>
</Tooltip>
<Tooltip title={'隐藏菜单'}>
<Button
type="text"
icon={<MenuFoldOutlined />}
size="small"
onClick={() => setMenuHidden(true)}
/>
</Tooltip>
</Space>
</div>
</div>
<TreeList
oakPath={`$articleMenu/treeManager-TreeList`}
@ -308,7 +310,7 @@ export default function Render(
</div>
)
}
<div className={Styles.editor}>
{
editArticleId ? (
@ -318,7 +320,7 @@ export default function Render(
oakAutoUnmount={true}
oakPath={`$articleMenu/treeManager-ArticleUpsert-${editArticleId}`}
tocPosition={tocPosition}
highlightBgColor={highlightBgColor}
// highlightBgColor={highlightBgColor}
onArticlePreview={onArticlePreview}
origin={origin}
scrollId={scrollId}