diff --git a/frontend/app/element/markdown.less b/frontend/app/element/markdown.less index 6e4cbcc05..e98cb2395 100644 --- a/frontend/app/element/markdown.less +++ b/frontend/app/element/markdown.less @@ -17,7 +17,6 @@ font-size: 14px; overflow-wrap: break-word; margin-bottom: 10px; - --half-contents-height: 10em; .heading { &:first-of-type { @@ -26,7 +25,6 @@ color: var(--app-text-color); margin-top: 16px; margin-bottom: 8px; - scroll-margin-block-end: var(--half-contents-height); } strong { diff --git a/frontend/app/element/markdown.tsx b/frontend/app/element/markdown.tsx index 8caaf0974..bb33e5ac5 100644 --- a/frontend/app/element/markdown.tsx +++ b/frontend/app/element/markdown.tsx @@ -8,13 +8,12 @@ import * as util from "@/util/util"; import { useAtomValueSafe } from "@/util/util"; import { clsx } from "clsx"; import { Atom } from "jotai"; -import { OverlayScrollbarsComponent } from "overlayscrollbars-react"; -import React, { CSSProperties, useCallback, useMemo, useRef } from "react"; +import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react"; +import React, { CSSProperties, useRef } from "react"; import ReactMarkdown from "react-markdown"; import rehypeRaw from "rehype-raw"; import RemarkFlexibleToc, { TocItem } from "remark-flexible-toc"; import remarkGfm from "remark-gfm"; -import { useHeight } from "../hook/useHeight"; import "./markdown.less"; const Link = ({ href, children }: { href: string; children: React.ReactNode }) => { @@ -148,23 +147,23 @@ const Markdown = ({ text, textAtom, showTocAtom, style, className, resolveOpts, const textAtomValue = useAtomValueSafe(textAtom); const tocRef = useRef([]); const showToc = useAtomValueSafe(showTocAtom) ?? false; - const contentsRef = useRef(null); - const contentsHeight = useHeight(contentsRef, 200); + const contentsOsRef = useRef(null); - const halfContentsHeight = useMemo(() => { - return `${contentsHeight / 2}px`; - }, [contentsHeight]); - - const onTocClick = useCallback((data: string) => { - if (contentsRef.current) { - const headings = contentsRef.current.getElementsByClassName("heading"); + const onTocClick = (data: string) => { + if (contentsOsRef.current && contentsOsRef.current.osInstance()) { + const { viewport } = contentsOsRef.current.osInstance().elements(); + const headings = viewport.getElementsByClassName("heading"); for (const heading of headings) { if (heading.textContent === data) { - heading.scrollIntoView({ inline: "nearest", block: "end" }); + const headingBoundingRect = heading.getBoundingClientRect(); + const viewportBoundingRect = viewport.getBoundingClientRect(); + const headingTop = headingBoundingRect.top - viewportBoundingRect.top; + viewport.scrollBy({ top: headingTop }); + break; } } } - }, []); + }; const markdownComponents = { a: Link, @@ -180,30 +179,19 @@ const Markdown = ({ text, textAtom, showTocAtom, style, className, resolveOpts, pre: (props: any) => , }; - const toc = useMemo(() => { - if (showToc && tocRef.current.length > 0) { - return tocRef.current.map((item) => { - return ( - onTocClick(item.value)} - > - {item.value} - - ); - }); - } - }, [showToc, tocRef]); + // const toc = useMemo(() => { + // if (showToc && tocRef.current.length > 0) { + // return + // } + // }, [showToc, tocRef]); text = textAtomValue ?? text; return ( -
+

Table of Contents

- {toc} + {tocRef.current.map((item) => { + return ( + onTocClick(item.value)} + > + {item.value} + + ); + })}
)}