Merge pull request #1382 from yashsinghcodes/1.4.0

fresh look for docs
This commit is contained in:
Frikky
2024-05-10 14:44:08 +02:00
committed by GitHub
3 changed files with 1044 additions and 867 deletions
+14
View File
@@ -90,3 +90,17 @@ code {
color: #fff; color: #fff;
font-size: 14px; font-size: 14px;
} }
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-thumb {
background-color: #494949;
border-radius: 5px;
}
::-webkit-scrollbar-track {
background-color: rgb(26,26,26);
}
+18
View File
@@ -18,6 +18,11 @@ code {
margin-right: -13px; margin-right: -13px;
} }
.toc:hover {
background-color: gray;
color: white;
}
/* .cm-string{ /* .cm-string{
z-index: -1; z-index: -1;
} }
@@ -31,3 +36,16 @@ code {
background-color: rgba(28, 47, 69, 0.6) !important; background-color: rgba(28, 47, 69, 0.6) !important;
color: rgb(255, 255, 255) !important; color: rgb(255, 255, 255) !important;
} }
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-thumb {
background-color: #494949;
border-radius: 5px;
}
::-webkit-scrollbar-track {
background-color: rgb(26,26,26);
}
+342 -197
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useLayoutEffect, useRef, useState } from "react";
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import Markdown from 'react-markdown' import Markdown from 'react-markdown'
@@ -34,6 +34,8 @@ import {
ExpandMore as ExpandMoreIcon, ExpandMore as ExpandMoreIcon,
FileCopy as FileCopyIcon FileCopy as FileCopyIcon
} from "@mui/icons-material"; } from "@mui/icons-material";
import { fontGrid } from "@mui/material/styles/cssUtils.js";
import { active } from "d3";
const Body = { const Body = {
//maxWidth: 1000, //maxWidth: 1000,
@@ -53,6 +55,18 @@ const hrefStyle = {
textDecoration: "none", textDecoration: "none",
}; };
const hrefStyleToc2 = {
color: "rgba(255, 255, 255, 0.6)",
textDecoration: "none",
fontSize: "14px",
fontWeight: 400,
padding: "4px 0",
paddingLeft: "12px",
paddingRight: "12px",
lineHeight: "20px",
};
const hrefStyle2 = { const hrefStyle2 = {
color: "#f86a3e", color: "#f86a3e",
textDecoration: "none", textDecoration: "none",
@@ -63,9 +77,42 @@ const innerHrefStyle = {
textDecoration: "none", 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) {
console.log(visibleHeadings)
setActiveId(visibleHeadings[0].target.id)
}
}
const observer = new IntersectionObserver(callback, {
});
const headingElements = Array.from(document.querySelectorAll("h2"))
if (headingElements.length != 0) {
headingElements.forEach((element) => observer.observe(element));
return () => observer.disconnect()
}
}
export const CopyToClipboard = (props) => { export const CopyToClipboard = (props) => {
const {text, style, onCopy} = props; const { text, style, onCopy } = props;
const parsedstyle = style !== undefined ? style : { const parsedstyle = style !== undefined ? style : {
position: "absolute", position: "absolute",
right: 0, right: 0,
@@ -108,7 +155,7 @@ export const OuterLink = (props) => {
{props.children} {props.children}
</Link> </Link>
); );
} }
export const Img = (props) => { export const Img = (props) => {
@@ -140,7 +187,7 @@ export const CodeHandler = (props) => {
if (props.inline === true) { if (props.inline === true) {
// Show it inline // Show it inline
return ( return (
<span style={{backgroundColor: theme.palette.inputColor, display: "inline", whiteSpace: "pre-wrap", padding: "6px 3px 6px 3px", }}> <span style={{ backgroundColor: theme.palette.inputColor, display: "inline", whiteSpace: "pre-wrap", padding: "6px 3px 6px 3px", }}>
{newprop} {newprop}
</span> </span>
) )
@@ -168,7 +215,7 @@ export const CodeHandler = (props) => {
name={""} name={""}
/> />
: :
<div style={{display: "flex", position: "relative", }}> <div style={{ display: "flex", position: "relative", }}>
<code <code
style={{ style={{
// Wrap if larger than X // Wrap if larger than X
@@ -200,21 +247,18 @@ const Docs = (defaultprops) => {
props.match = {} props.match = {}
props.match.params = params props.match.params = params
useEffect(() => {
//if (params["key"] === undefined) {
// navigate("/docs/about")
// return
//}
}, [])
//console.log("PARAMS: ", params) //console.log("PARAMS: ", params)
const [mobile, setMobile] = useState(serverMobile === true || isMobile === true ? true : false); const [mobile, setMobile] = useState(serverMobile === true || isMobile === true ? true : false);
const [data, setData] = useState(""); const [data, setData] = useState("");
const [firstrequest, setFirstrequest] = useState(true); const [firstrequest, setFirstrequest] = useState(true);
const [list, setList] = useState([]); const [list, setList] = useState([]);
const [activeId, setActiveId] = useState();
const [isopen, setOpen] = useState(-1); const [isopen, setOpen] = useState(-1);
const [hover, setHover] = useState(false);
const [, setListLoaded] = useState(false); const [, setListLoaded] = useState(false);
const [anchorEl, setAnchorEl] = React.useState(null); const [anchorEl, setAnchorEl] = React.useState(null);
const [anchorElToc, setAnchorElToc] = React.useState(null);
const [headingSet, setHeadingSet] = React.useState(false); const [headingSet, setHeadingSet] = React.useState(false);
const [selectedMeta, setSelectedMeta] = React.useState({ const [selectedMeta, setSelectedMeta] = React.useState({
link: "hello", link: "hello",
@@ -225,36 +269,108 @@ const Docs = (defaultprops) => {
serverside === true ? "" : window.location.href serverside === true ? "" : window.location.href
); );
useEffect(() => {
//if (params["key"] === undefined) {
// navigate("/docs/about")
// return
//}
}, [])
useIntersectionObserver(setActiveId);
console.log(activeId)
function handleClick(event) { function handleClick(event) {
setAnchorEl(event.currentTarget); setAnchorEl(event.currentTarget);
} }
function handleClickToc(event) {
setAnchorElToc(event.currentTarget);
}
function handleCollapse(index) {
setOpen(isopen === index ? -1 : index)
}
function handleMouseOver() {
setHover(!hover);
}
function handleClose() { function handleClose() {
setAnchorEl(null); setAnchorEl(null);
} }
const handleCollapse = (index) => { function handleCloseToc() {
setOpen(isopen === index ? -1 : index) setAnchorElToc(null);
}
function scrollToHash() {
const hash = window.location.hash.replace("#", "")
if (hash) {
const element = document.getElementById(hash)
if (element) {
element.scrollIntoView({ behavior: "instant" })
}
}
}
function tocvalue(markdown) {
const items = [];
let currentMainItem = null;
const lines = markdown.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith('* [')) {
const matches = line.match(/^\* \[([^)]+)\]\(#([^)]+)\)/);
if (matches) {
currentMainItem = {
id: matches[2],
title: matches[1],
items: [],
}; };
items.push(currentMainItem);
}
} else if (line.startsWith(' * [')) {
if (currentMainItem) {
const matches = line.match(/^ \* \[([^)]+)\]\(#([^)]+)\)/);
if (matches) {
currentMainItem.items.push({
id: matches[2],
title: matches[1],
});
}
}
} else if (line.startsWith('##')) {
continue
}
}
return items
}
const SidebarPaperStyle = { const SidebarPaperStyle = {
backgroundColor: theme.palette.surfaceColor, backgroundColor: "rgb(26,26,26)",
backgroundImage: "none",
overflowX: "hidden", overflowX: "hidden",
position: "relative", position: "relative",
paddingLeft: 15, paddingLeft: 15,
paddingRight: 15, paddingRight: 15,
paddingTop: 15,
marginTop: 15,
minHeight: "80vh", minHeight: "80vh",
//height: "50vh",
}; };
const Heading = (props) => { const Heading = (props) => {
var id = props.children[0].toLowerCase().toString()
if (props.level <= 3) {
id = props.children[0].toLowerCase().toString().replaceAll(" ", "-");
}
const element = React.createElement( const element = React.createElement(
`h${props.level}`, `h${props.level}`,
{ style: { marginTop: props.level === 1 ? 20 : 50 } }, { id: `${id}` },
props.children props.children,
); );
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
var extraInfo = ""; var extraInfo = "";
@@ -270,7 +386,7 @@ const Docs = (defaultprops) => {
}} }}
> >
<div style={{ flex: 3, display: "flex", vAlign: "center", position: "sticky", top: 50, }}> <div style={{ flex: 3, display: "flex", vAlign: "center", position: "sticky", top: 50, }}>
{isMobile ? null : ( {mobile ? null : (
<Typography style={{ display: "inline", marginTop: 6 }}> <Typography style={{ display: "inline", marginTop: 6 }}>
<a <a
rel="noopener noreferrer" rel="noopener noreferrer"
@@ -284,7 +400,7 @@ const Docs = (defaultprops) => {
</a> </a>
</Typography> </Typography>
)} )}
{isMobile ? null : ( {mobile ? null : (
<div <div
style={{ style={{
height: "100%", height: "100%",
@@ -301,7 +417,7 @@ const Docs = (defaultprops) => {
</Typography> </Typography>
</div> </div>
<div style={{ flex: 2 }}> <div style={{ flex: 2 }}>
{isMobile || {mobile ||
selectedMeta.contributors === undefined || selectedMeta.contributors === undefined ||
selectedMeta.contributors === null ? ( selectedMeta.contributors === null ? (
"" ""
@@ -314,7 +430,6 @@ const Docs = (defaultprops) => {
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
href={data.url} href={data.url}
target="_blank"
style={{ textDecoration: "none", color: "#f85a3e" }} style={{ textDecoration: "none", color: "#f85a3e" }}
> >
<Tooltip title={data.url} placement="bottom"> <Tooltip title={data.url} placement="bottom">
@@ -344,12 +459,12 @@ const Docs = (defaultprops) => {
extraInfo = "" extraInfo = ""
} }
} }
return ( return (
<Typography <Typography
onMouseOver={() => { onMouseOver={() => {
setHover(true); setHover(true);
}} }}
id={id}
> >
{props.level !== 1 ? ( {props.level !== 1 ? (
<Divider <Divider
@@ -360,26 +475,44 @@ const Docs = (defaultprops) => {
}} }}
/> />
) : null} ) : null}
<div style={{
display: "flex", marginTop: props.level === 1 ? 20 : 50,
marginBlock: "0.85em", alignItems: "center"
}}>
{element} {element}
<a href={`#${id}`} style={{
textDecoration: "none", color: "white",
paddingLeft: "0.3em", rotate: "-30deg",
paddingTop: "0.9em", display: props.level === 1 ? "none" : "block",
}}><LinkIcon></LinkIcon></a>
</div>
{extraInfo} {extraInfo}
</Typography> </Typography>
) )
} }
const SideBar = { const SideBar = {
minWidth: 300, width: "17%",
width: "20%",
left: 0,
position: "sticky", position: "sticky",
top: 50, top: 50,
minHeight: "90vh", minHeight: "93vh",
maxHeight: "90vh", maxHeight: "93vh",
overflowX: "hidden", overflowX: "hidden",
overflowY: "auto", overflowY: "auto",
zIndex: 1000, zIndex: 1000,
//borderRight: "1px solid rgba(255,255,255,0.3)", //borderRight: "1px solid rgba(255,255,255,0.3)",
}; };
const IndexBar = {
alignSelf: "flex-start",
position: "sticky",
top: 80,
overflow: "auto",
marginTop: 70,
}
const fetchDocList = () => { const fetchDocList = () => {
fetch(`${globalUrl}/api/v1/docs`, { fetch(`${globalUrl}/api/v1/docs`, {
method: "GET", method: "GET",
@@ -418,8 +551,10 @@ const Docs = (defaultprops) => {
if (responseJson.success && responseJson.reason !== undefined) { if (responseJson.success && responseJson.reason !== undefined) {
// Find <img> tags and translate them into ![]() format // Find <img> tags and translate them into ![]() format
const imgRegex = /<img.*?src="(.*?)"/g; const imgRegex = /<img.*?src="(.*?)"/g;
const newdata = responseJson.reason.replace(imgRegex, '![]($1)'); const tocRegex = /^## Table of contents[\s\S]*?(?=^##\s|\Z)|^\* \[[^\]]+\]\([^)]+\)\n?(?![^\n]+\]\([^)]+\))/gm;
setData(newdata) const newdata = responseJson.reason.replace(imgRegex, '![]($1)')
.replace(tocRegex, "");
setData(newdata);
if (docId === undefined) { if (docId === undefined) {
document.title = "Shuffle documentation introduction"; document.title = "Shuffle documentation introduction";
} else { } else {
@@ -440,50 +575,10 @@ const Docs = (defaultprops) => {
responseJson.reason !== undefined && responseJson.reason !== undefined &&
responseJson.reason !== null responseJson.reason !== null
) { ) {
const splitkey = responseJson.reason.split("\n"); const values = tocvalue(responseJson.reason.match(tocRegex)
var innerTocLines = []; .join()
var record = false; .toString());
for (var key in splitkey) { setTocLines(values);
const line = splitkey[key];
//console.log("Line: ", line)
if (line.toLowerCase().includes("table of contents")) {
record = true;
continue;
}
if (record && line.length < 3) {
record = false;
}
if (record) {
const parsedline = line.split("](");
if (parsedline.length > 1) {
parsedline[0] = parsedline[0].replaceAll("*", "");
parsedline[0] = parsedline[0].replaceAll("[", "");
parsedline[0] = parsedline[0].replaceAll("]", "");
parsedline[0] = parsedline[0].replaceAll("(", "");
parsedline[0] = parsedline[0].replaceAll(")", "");
parsedline[0] = parsedline[0].trim();
parsedline[1] = parsedline[1].replaceAll("*", "");
parsedline[1] = parsedline[1].replaceAll("[", "");
parsedline[1] = parsedline[1].replaceAll("]", "");
parsedline[1] = parsedline[1].replaceAll(")", "");
parsedline[1] = parsedline[1].replaceAll("(", "");
parsedline[1] = parsedline[1].trim();
//console.log(parsedline[0], parsedline[1])
innerTocLines.push({
text: parsedline[0],
link: parsedline[1],
});
} else {
console.log("Bad line for parsing: ", line);
}
}
}
setTocLines(innerTocLines);
} }
} else { } else {
setData("# Error\nThis page doesn't exist."); setData("# Error\nThis page doesn't exist.");
@@ -530,90 +625,90 @@ const Docs = (defaultprops) => {
fetchDocs(props.match.params.key); fetchDocs(props.match.params.key);
} }
const parseElementScroll = () => { // const parseElementScroll = () => {
const offset = 45; // const offset = 45;
var parent = document.getElementById("markdown_wrapper_outer"); // var parent = document.getElementById("markdown_wrapper_outer");
if (parent !== null) { // if (parent !== null) {
//console.log("IN PARENT") // //console.log("IN PARENT")
var elements = parent.getElementsByTagName("h2"); // var elements = parent.getElementsByTagName("h2");
//
const name = window.location.hash // const name = window.location.hash
.slice(1, window.location.hash.lenth) // .slice(1, window.location.hash.length)
.toLowerCase() // .toLowerCase()
.split("%20") // .split("%20")
.join(" ") // .join(" ")
.split("_") // .split("_")
.join(" ") // .join(" ")
.split("-") // .split("-")
.join(" ") // .join(" ")
.split("?")[0] // .split("?")[0]
//
//console.log(name) // //console.log(name)
var found = false; // var found = false;
for (var key in elements) { // for (var key in elements) {
const element = elements[key]; // const element = elements[key];
if (element.innerHTML === undefined) { // if (element.innerHTML === undefined) {
continue; // continue;
} // }
//
// Fix location.. // // Fix location..
if (element.innerHTML.toLowerCase() === name) { // if (element.innerHTML.toLowerCase() === name) {
//console.log(element.offsetTop) // //console.log(element.offsetTop)
element.scrollIntoView({ behavior: "smooth" }); // element.scrollIntoView({ behavior: "smooth" });
//element.scrollTo({ // //element.scrollTo({
// top: element.offsetTop+offset, // // top: element.offsetTop+offset,
// behavior: "smooth" // // behavior: "smooth"
//}) // //})
found = true; // found = true;
//element.scrollTo({ // //element.scrollTo({
// top: element.offsetTop-100, // // top: element.offsetTop-100,
// behavior: "smooth" // // behavior: "smooth"
//}) // //})
} // }
} // }
//
// H# // // H#
if (!found) { // if (!found) {
elements = parent.getElementsByTagName("h3"); // elements = parent.getElementsByTagName("h3");
//console.log("NAMe: ", name) // //console.log("NAMe: ", name)
found = false; // found = false;
for (key in elements) { // for (key in elements) {
const element = elements[key]; // const element = elements[key];
if (element.innerHTML === undefined) { // if (element.innerHTML === undefined) {
continue; // continue;
} // }
//
// Fix location.. // // Fix location..
if (element.innerHTML.toLowerCase() === name) { // if (element.innerHTML.toLowerCase() === name) {
element.scrollIntoView({ behavior: "smooth" }); // element.scrollIntoView({ behavior: "smooth" });
//element.scrollTo({ // //element.scrollTo({
// top: element.offsetTop-offset, // // top: element.offsetTop-offset,
// behavior: "smooth" // // behavior: "smooth"
//}) // //})
found = true; // found = true;
//element.scrollTo({ // //element.scrollTo({
// top: element.offsetTop-100, // // top: element.offsetTop-100,
// behavior: "smooth" // // behavior: "smooth"
//}) // //})
} // }
} // }
} // }
} // }
//console.log(element) // //console.log(element)
//
//console.log("NAME: ", name) // //console.log("NAME: ", name)
//console.log(document.body.innerHTML) // //console.log(document.body.innerHTML)
// parent = document.getElementById(parent); // // parent = document.getElementById(parent);
//
//var descendants = parent.getElementsByTagName(tagname); // //var descendants = parent.getElementsByTagName(tagname);
//
// this.scrollDiv.current.scrollIntoView({ behavior: 'smooth' }); // // this.scrollDiv.current.scrollIntoView({ behavior: 'smooth' });
//
//$(".parent").find("h2:contains('Statistics')").parent(); // //$(".parent").find("h2:contains('Statistics')").parent();
}; // };
if (serverside !== true && window.location.hash.length > 0) { if (serverside !== true && window.location.hash.length > 0) {
parseElementScroll(); scrollToHash()
} }
const markdownStyle = { const markdownStyle = {
@@ -627,14 +722,9 @@ const Docs = (defaultprops) => {
fontSize: isMobile ? "1.3rem" : "1.1rem", fontSize: isMobile ? "1.3rem" : "1.1rem",
}; };
const CustomButton = (props) => { const CustomButton = (props) => {
const { title, icon, link } = props const { title, icon, link } = props
const [hover, setHover] = useState(false)
return ( return (
<a <a
href={link} href={link}
@@ -675,7 +765,6 @@ const Docs = (defaultprops) => {
const DocumentationButton = (props) => { const DocumentationButton = (props) => {
const { item, link } = props const { item, link } = props
const [hover, setHover] = useState(false);
if (link === undefined || link === null) { if (link === undefined || link === null) {
return null return null
@@ -768,6 +857,7 @@ const Docs = (defaultprops) => {
a: OuterLink, a: OuterLink,
} }
// PostDataBrowser Section // PostDataBrowser Section
const postDataBrowser = const postDataBrowser =
list === undefined || list === null ? null : ( list === undefined || list === null ? null : (
@@ -780,7 +870,6 @@ const Docs = (defaultprops) => {
if (item === undefined) { if (item === undefined) {
return null; return null;
} }
const path = "/docs/" + item; const path = "/docs/" + item;
const newname = const newname =
item.charAt(0).toUpperCase() + item.charAt(0).toUpperCase() +
@@ -795,11 +884,6 @@ const Docs = (defaultprops) => {
key={index} key={index}
style={hrefStyle} style={hrefStyle}
to={path} to={path}
onClick={() => {
setTocLines([]);
fetchDocs(item);
handleCollapse(index);
}}
> >
<ListItemText <ListItemText
style={{ color: itemMatching ? "#f86a3e" : "inherit" }} style={{ color: itemMatching ? "#f86a3e" : "inherit" }}
@@ -807,40 +891,14 @@ const Docs = (defaultprops) => {
> >
{newname} {newname}
</ListItemText> </ListItemText>
{isopen === index ? <ExpandMoreIcon /> : <KeyboardArrowRightIcon />}
</ListItemButton> </ListItemButton>
{itemMatching &&
tocLines !== null &&
tocLines !== undefined &&
tocLines.length > 0 ? (
<Collapse in={isopen === index} timeout="auto" unmountOnExit>
{tocLines.map((data, index) => {
return (
<ListItemButton
component={Link}
key={index}
style={innerHrefStyle}
to={data.link}
>
<ListItemText
variant="body2"
style={{ cursor: "pointer" }}
>
{data.text}
</ListItemText>
</ListItemButton>
);
})}
</Collapse>
) : null}
</li> </li>
); );
})} })}
</List> </List>
</Paper> </Paper>
</div> </div>
<div style={{ width: "70%", margin: "auto", overflow: "hidden", marginTop: 50, paddingRight: 50 }}> <div style={{ width: "60%", margin: "30px 0px 30px 30px", overflow: "hidden", paddingRight: 50, paddingLeft: 40 }}>
{props.match.params.key === undefined ? {props.match.params.key === undefined ?
mainpageInfo mainpageInfo
: :
@@ -859,7 +917,65 @@ const Docs = (defaultprops) => {
</div> </div>
} }
</div> </div>
<div style={IndexBar}>
{tocLines.length > 0 ?
(
<h4 style={{ fontWeight: 600, margin: 0, fontSize: "16px", marginBottom: "8px" }}>Table Of Content</h4>
) : null}
<nav>
{tocLines.map((data, index) => {
return (
<div className="toc">
<ListItemButton
key={data.text}
href={`#${data.id}`}
style={{
color: activeId === data.id ? "#f86a3e" : "inherit",
textDecoration: "none",
fontSize: "14px",
fontWeight: 400,
padding: "4px 0",
paddingLeft: "8px",
paddingRight: "8px",
lineHeight: "20px",
}}
onClick={(e) => {
handleCollapse(index)
}}
>
{data.title}
{data.items.length > 0 ? (
<>{isopen == index ? <ExpandMoreIcon /> : <KeyboardArrowRightIcon />}</>
) : null}
</ListItemButton>
{
data.items.length > 0 &&
data.items !== null &&
data.items !== undefined ? (
<Collapse in={isopen === index} timeout="auto" unmountOnExit>
{data.items.map((d, i) => {
return (
<ListItemButton
key={i}
style={hrefStyleToc2}
href={`#${d.id}`}
>
{d.title}
</ListItemButton>
)
})}
</Collapse>
) : null
}
</div> </div>
)
})}
</nav>
</div >
</div >
); );
const mobileStyle = { const mobileStyle = {
@@ -872,7 +988,6 @@ const Docs = (defaultprops) => {
flexDirection: "column", flexDirection: "column",
}; };
const postDataMobile = const postDataMobile =
list === undefined || list === null ? null : ( list === undefined || list === null ? null : (
<div style={mobileStyle}> <div style={mobileStyle}>
@@ -918,6 +1033,36 @@ const Docs = (defaultprops) => {
); );
})} })}
</Menu> </Menu>
<Button
fullWidth
style={{ marginTop: "2px" }}
aria-controls="simple-menu"
aria-haspopup="ture"
variant="outlined"
color="primary"
onClick={handleClickToc}
>
<div style={{ color: "white" }}>Table Of Contents</div>
</Button>
<Menu
id="simple-menu"
anchorEl={anchorElToc}
style={{}}
keepMounted
open={Boolean(anchorElToc)}
onClose={handleCloseToc}
>
{tocLines.map((data, index) => {
return (
<MenuItem
key={index}
style={{ color: "white" }}
>
<a href={`#${data.id}`} style={hrefStyle}>{data.title}</a>
</MenuItem>
)
})}
</Menu>
</div> </div>
{props.match.params.key === undefined ? {props.match.params.key === undefined ?
mainpageInfo mainpageInfo