From 42f472996934543426f76e09c44475efc4719187 Mon Sep 17 00:00:00 2001 From: yashsinghcodes Date: Fri, 10 May 2024 09:37:40 +0000 Subject: [PATCH] scoll view for toc --- frontend/src/views/Docs.jsx | 233 +++++++++++++++++++++++++----------- 1 file changed, 166 insertions(+), 67 deletions(-) diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx index a79e26c4..9ad90b28 100755 --- a/frontend/src/views/Docs.jsx +++ b/frontend/src/views/Docs.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useLayoutEffect, useRef, useState } from "react"; import { toast } from 'react-toastify'; import Markdown from 'react-markdown' @@ -35,6 +35,7 @@ import { FileCopy as FileCopyIcon } from "@mui/icons-material"; import { fontGrid } from "@mui/material/styles/cssUtils.js"; +import { active } from "d3"; const Body = { //maxWidth: 1000, @@ -54,17 +55,6 @@ const hrefStyle = { textDecoration: "none", }; -const hrefStyleToc = { - color: "rgba(255, 255, 255, 0.6)", - textDecoration: "none", - fontSize: "14px", - fontWeight: 400, - padding: "4px 0", - paddingLeft: "8px", - paddingRight: "8px", - lineHeight: "20px", -}; - const hrefStyleToc2 = { color: "rgba(255, 255, 255, 0.6)", @@ -87,8 +77,38 @@ const innerHrefStyle = { textDecoration: "none", }; +// Emma Goto +const useIntersectionObserver = (setActiveId) => { + const headingElementsRef = useRef({}) + const callback = (headings) => { + headingElementsRef.current = headings.reduce((map, headingElemet) => { + if (headingElemet.target.id != undefined || headingElemet.target.id != "") { + map[headingElemet.target.id] = headingElemet + return map + } + }, headingElementsRef.current) + const visibleHeadings = []; + Object.keys(headingElementsRef.current).forEach((key) => { + const headingElemet = headingElementsRef.current[key]; + if (headingElemet.isIntersecting) visibleHeadings.push(headingElemet) + }) + if (visibleHeadings.length > 0) { + setActiveId(visibleHeadings[0].target.id) + } + } + + const observer = new IntersectionObserver(callback, { + rootMargin: "10%", + }); + + const headingElements = Array.from(document.querySelectorAll("h2")) + if (headingElements.length != 0) { + headingElements.forEach((element) => observer.observe(element)); + return () => observer.disconnect() + } +} export const CopyToClipboard = (props) => { @@ -227,22 +247,18 @@ const Docs = (defaultprops) => { props.match = {} props.match.params = params - useEffect(() => { - //if (params["key"] === undefined) { - // navigate("/docs/about") - // return - //} - }, []) //console.log("PARAMS: ", params) const [mobile, setMobile] = useState(serverMobile === true || isMobile === true ? true : false); const [data, setData] = useState(""); const [firstrequest, setFirstrequest] = useState(true); const [list, setList] = useState([]); + const [activeId, setActiveId] = useState(); const [isopen, setOpen] = useState(-1); const [hover, setHover] = useState(false); const [, setListLoaded] = useState(false); const [anchorEl, setAnchorEl] = React.useState(null); + const [anchorElToc, setAnchorElToc] = React.useState(null); const [headingSet, setHeadingSet] = React.useState(false); const [selectedMeta, setSelectedMeta] = React.useState({ link: "hello", @@ -253,10 +269,23 @@ const Docs = (defaultprops) => { serverside === true ? "" : window.location.href ); + useEffect(() => { + //if (params["key"] === undefined) { + // navigate("/docs/about") + // return + //} + }, []) + + useIntersectionObserver(setActiveId); + function handleClick(event) { setAnchorEl(event.currentTarget); } + function handleClickToc(event) { + setAnchorElToc(event.currentTarget); + } + function handleCollapse(index) { setOpen(isopen === index ? -1 : index) } @@ -269,6 +298,21 @@ const Docs = (defaultprops) => { setAnchorEl(null); } + function handleCloseToc() { + setAnchorElToc(null); + } + + function scrollToHash() { + const hash = window.location.hash.replace("#", "") + if (hash) { + const element = document.getElementById(hash) + if (element) { + element.scrollIntoView({ behavior: 'smooth' }) + } + } + + } + function tocvalue(markdown) { const items = []; let currentMainItem = null; @@ -322,7 +366,7 @@ const Docs = (defaultprops) => { const element = React.createElement( `h${props.level}`, - { style: { marginTop: props.level === 1 ? 20 : 50 } }, + { style: { marginTop: props.level === 1 ? 20 : 50, scrollPaddingTop: "50px" }, id: `${id}` }, props.children ); @@ -361,8 +405,8 @@ const Docs = (defaultprops) => { width: "17%", position: "sticky", top: 50, - minHeight: "100vh", - maxHeight: "100vh", + minHeight: "93vh", + maxHeight: "93vh", overflowX: "hidden", overflowY: "auto", zIndex: 1000, @@ -399,6 +443,8 @@ const Docs = (defaultprops) => { }; const fetchDocs = (docId) => { + setActiveId("") + setTocLines([]) fetch(`${globalUrl}/api/v1/docs/${docId}`, { method: "GET", headers: { @@ -571,9 +617,9 @@ const Docs = (defaultprops) => { // //$(".parent").find("h2:contains('Statistics')").parent(); // }; - // if (serverside !== true && window.location.hash.length > 0) { - // parseElementScroll(); - // } + if (serverside !== true && window.location.hash.length > 0) { + scrollToHash() + } const markdownStyle = { color: "rgba(255, 255, 255, 0.90)", @@ -786,14 +832,27 @@ const Docs = (defaultprops) => { }
-

Table Of Content

+ {tocLines.length > 0 ? + ( +

Table Of Content

+ + ) : null} -
+ ); @@ -841,7 +902,6 @@ const Docs = (defaultprops) => { flexDirection: "column", }; - const postDataMobile = list === undefined || list === null ? null : (
@@ -856,28 +916,67 @@ const Docs = (defaultprops) => { >
More docs
- {list.map((data, index) => { - const item = data.name; - if (item === undefined) { - return null; - } + + {list.map((data, index) => { + const item = data.name; + if (item === undefined) { + return null; + } - const path = "/docs/" + item; - const newname = - item.charAt(0).toUpperCase() + - item.substring(1).split("_").join(" ").split("-").join(" "); - return ( - { - window.location.pathname = path; - }} - > - {newname} - - ); - })} + const path = "/docs/" + item; + const newname = + item.charAt(0).toUpperCase() + + item.substring(1).split("_").join(" ").split("-").join(" "); + return ( + { + window.location.pathname = path; + }} + > + {newname} + + ); + })} + + + + {tocLines.map((data, index) => { + return ( + + {data.title} + + ) + })} +
{props.match.params.key === undefined ? mainpageInfo