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;
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;
}
.toc:hover {
background-color: gray;
color: white;
}
/* .cm-string{
z-index: -1;
}
@@ -31,3 +36,16 @@ code {
background-color: rgba(28, 47, 69, 0.6) !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 Markdown from 'react-markdown'
@@ -34,6 +34,8 @@ import {
ExpandMore as ExpandMoreIcon,
FileCopy as FileCopyIcon
} from "@mui/icons-material";
import { fontGrid } from "@mui/material/styles/cssUtils.js";
import { active } from "d3";
const Body = {
//maxWidth: 1000,
@@ -53,6 +55,18 @@ const hrefStyle = {
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 = {
color: "#f86a3e",
textDecoration: "none",
@@ -63,9 +77,42 @@ 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) {
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) => {
const {text, style, onCopy} = props;
const { text, style, onCopy } = props;
const parsedstyle = style !== undefined ? style : {
position: "absolute",
right: 0,
@@ -108,7 +155,7 @@ export const OuterLink = (props) => {
{props.children}
</Link>
);
}
}
export const Img = (props) => {
@@ -140,7 +187,7 @@ export const CodeHandler = (props) => {
if (props.inline === true) {
// Show it inline
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}
</span>
)
@@ -168,7 +215,7 @@ export const CodeHandler = (props) => {
name={""}
/>
:
<div style={{display: "flex", position: "relative", }}>
<div style={{ display: "flex", position: "relative", }}>
<code
style={{
// Wrap if larger than X
@@ -200,21 +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",
@@ -225,36 +269,108 @@ const Docs = (defaultprops) => {
serverside === true ? "" : window.location.href
);
useEffect(() => {
//if (params["key"] === undefined) {
// navigate("/docs/about")
// return
//}
}, [])
useIntersectionObserver(setActiveId);
console.log(activeId)
function handleClick(event) {
setAnchorEl(event.currentTarget);
}
function handleClickToc(event) {
setAnchorElToc(event.currentTarget);
}
function handleCollapse(index) {
setOpen(isopen === index ? -1 : index)
}
function handleMouseOver() {
setHover(!hover);
}
function handleClose() {
setAnchorEl(null);
}
const handleCollapse = (index) => {
setOpen(isopen === index ? -1 : index)
function handleCloseToc() {
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 = {
backgroundColor: theme.palette.surfaceColor,
backgroundColor: "rgb(26,26,26)",
backgroundImage: "none",
overflowX: "hidden",
position: "relative",
paddingLeft: 15,
paddingRight: 15,
paddingTop: 15,
marginTop: 15,
minHeight: "80vh",
//height: "50vh",
};
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(
`h${props.level}`,
{ style: { marginTop: props.level === 1 ? 20 : 50 } },
props.children
{ id: `${id}` },
props.children,
);
const [hover, setHover] = useState(false);
var extraInfo = "";
@@ -270,7 +386,7 @@ const Docs = (defaultprops) => {
}}
>
<div style={{ flex: 3, display: "flex", vAlign: "center", position: "sticky", top: 50, }}>
{isMobile ? null : (
{mobile ? null : (
<Typography style={{ display: "inline", marginTop: 6 }}>
<a
rel="noopener noreferrer"
@@ -284,7 +400,7 @@ const Docs = (defaultprops) => {
</a>
</Typography>
)}
{isMobile ? null : (
{mobile ? null : (
<div
style={{
height: "100%",
@@ -301,7 +417,7 @@ const Docs = (defaultprops) => {
</Typography>
</div>
<div style={{ flex: 2 }}>
{isMobile ||
{mobile ||
selectedMeta.contributors === undefined ||
selectedMeta.contributors === null ? (
""
@@ -314,7 +430,6 @@ const Docs = (defaultprops) => {
rel="noopener noreferrer"
target="_blank"
href={data.url}
target="_blank"
style={{ textDecoration: "none", color: "#f85a3e" }}
>
<Tooltip title={data.url} placement="bottom">
@@ -344,12 +459,12 @@ const Docs = (defaultprops) => {
extraInfo = ""
}
}
return (
<Typography
onMouseOver={() => {
setHover(true);
}}
id={id}
>
{props.level !== 1 ? (
<Divider
@@ -360,26 +475,44 @@ const Docs = (defaultprops) => {
}}
/>
) : null}
<div style={{
display: "flex", marginTop: props.level === 1 ? 20 : 50,
marginBlock: "0.85em", alignItems: "center"
}}>
{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}
</Typography>
)
}
const SideBar = {
minWidth: 300,
width: "20%",
left: 0,
width: "17%",
position: "sticky",
top: 50,
minHeight: "90vh",
maxHeight: "90vh",
minHeight: "93vh",
maxHeight: "93vh",
overflowX: "hidden",
overflowY: "auto",
zIndex: 1000,
//borderRight: "1px solid rgba(255,255,255,0.3)",
};
const IndexBar = {
alignSelf: "flex-start",
position: "sticky",
top: 80,
overflow: "auto",
marginTop: 70,
}
const fetchDocList = () => {
fetch(`${globalUrl}/api/v1/docs`, {
method: "GET",
@@ -418,8 +551,10 @@ const Docs = (defaultprops) => {
if (responseJson.success && responseJson.reason !== undefined) {
// Find <img> tags and translate them into ![]() format
const imgRegex = /<img.*?src="(.*?)"/g;
const newdata = responseJson.reason.replace(imgRegex, '![]($1)');
setData(newdata)
const tocRegex = /^## Table of contents[\s\S]*?(?=^##\s|\Z)|^\* \[[^\]]+\]\([^)]+\)\n?(?![^\n]+\]\([^)]+\))/gm;
const newdata = responseJson.reason.replace(imgRegex, '![]($1)')
.replace(tocRegex, "");
setData(newdata);
if (docId === undefined) {
document.title = "Shuffle documentation introduction";
} else {
@@ -440,50 +575,10 @@ const Docs = (defaultprops) => {
responseJson.reason !== undefined &&
responseJson.reason !== null
) {
const splitkey = responseJson.reason.split("\n");
var innerTocLines = [];
var record = false;
for (var key in splitkey) {
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);
const values = tocvalue(responseJson.reason.match(tocRegex)
.join()
.toString());
setTocLines(values);
}
} else {
setData("# Error\nThis page doesn't exist.");
@@ -530,90 +625,90 @@ const Docs = (defaultprops) => {
fetchDocs(props.match.params.key);
}
const parseElementScroll = () => {
const offset = 45;
var parent = document.getElementById("markdown_wrapper_outer");
if (parent !== null) {
//console.log("IN PARENT")
var elements = parent.getElementsByTagName("h2");
const name = window.location.hash
.slice(1, window.location.hash.lenth)
.toLowerCase()
.split("%20")
.join(" ")
.split("_")
.join(" ")
.split("-")
.join(" ")
.split("?")[0]
//console.log(name)
var found = false;
for (var key in elements) {
const element = elements[key];
if (element.innerHTML === undefined) {
continue;
}
// Fix location..
if (element.innerHTML.toLowerCase() === name) {
//console.log(element.offsetTop)
element.scrollIntoView({ behavior: "smooth" });
//element.scrollTo({
// top: element.offsetTop+offset,
// behavior: "smooth"
//})
found = true;
//element.scrollTo({
// top: element.offsetTop-100,
// behavior: "smooth"
//})
}
}
// H#
if (!found) {
elements = parent.getElementsByTagName("h3");
//console.log("NAMe: ", name)
found = false;
for (key in elements) {
const element = elements[key];
if (element.innerHTML === undefined) {
continue;
}
// Fix location..
if (element.innerHTML.toLowerCase() === name) {
element.scrollIntoView({ behavior: "smooth" });
//element.scrollTo({
// top: element.offsetTop-offset,
// behavior: "smooth"
//})
found = true;
//element.scrollTo({
// top: element.offsetTop-100,
// behavior: "smooth"
//})
}
}
}
}
//console.log(element)
//console.log("NAME: ", name)
//console.log(document.body.innerHTML)
// parent = document.getElementById(parent);
//var descendants = parent.getElementsByTagName(tagname);
// this.scrollDiv.current.scrollIntoView({ behavior: 'smooth' });
//$(".parent").find("h2:contains('Statistics')").parent();
};
// const parseElementScroll = () => {
// const offset = 45;
// var parent = document.getElementById("markdown_wrapper_outer");
// if (parent !== null) {
// //console.log("IN PARENT")
// var elements = parent.getElementsByTagName("h2");
//
// const name = window.location.hash
// .slice(1, window.location.hash.length)
// .toLowerCase()
// .split("%20")
// .join(" ")
// .split("_")
// .join(" ")
// .split("-")
// .join(" ")
// .split("?")[0]
//
// //console.log(name)
// var found = false;
// for (var key in elements) {
// const element = elements[key];
// if (element.innerHTML === undefined) {
// continue;
// }
//
// // Fix location..
// if (element.innerHTML.toLowerCase() === name) {
// //console.log(element.offsetTop)
// element.scrollIntoView({ behavior: "smooth" });
// //element.scrollTo({
// // top: element.offsetTop+offset,
// // behavior: "smooth"
// //})
// found = true;
// //element.scrollTo({
// // top: element.offsetTop-100,
// // behavior: "smooth"
// //})
// }
// }
//
// // H#
// if (!found) {
// elements = parent.getElementsByTagName("h3");
// //console.log("NAMe: ", name)
// found = false;
// for (key in elements) {
// const element = elements[key];
// if (element.innerHTML === undefined) {
// continue;
// }
//
// // Fix location..
// if (element.innerHTML.toLowerCase() === name) {
// element.scrollIntoView({ behavior: "smooth" });
// //element.scrollTo({
// // top: element.offsetTop-offset,
// // behavior: "smooth"
// //})
// found = true;
// //element.scrollTo({
// // top: element.offsetTop-100,
// // behavior: "smooth"
// //})
// }
// }
// }
// }
// //console.log(element)
//
// //console.log("NAME: ", name)
// //console.log(document.body.innerHTML)
// // parent = document.getElementById(parent);
//
// //var descendants = parent.getElementsByTagName(tagname);
//
// // this.scrollDiv.current.scrollIntoView({ behavior: 'smooth' });
//
// //$(".parent").find("h2:contains('Statistics')").parent();
// };
if (serverside !== true && window.location.hash.length > 0) {
parseElementScroll();
scrollToHash()
}
const markdownStyle = {
@@ -627,14 +722,9 @@ const Docs = (defaultprops) => {
fontSize: isMobile ? "1.3rem" : "1.1rem",
};
const CustomButton = (props) => {
const { title, icon, link } = props
const [hover, setHover] = useState(false)
return (
<a
href={link}
@@ -675,7 +765,6 @@ const Docs = (defaultprops) => {
const DocumentationButton = (props) => {
const { item, link } = props
const [hover, setHover] = useState(false);
if (link === undefined || link === null) {
return null
@@ -768,6 +857,7 @@ const Docs = (defaultprops) => {
a: OuterLink,
}
// PostDataBrowser Section
const postDataBrowser =
list === undefined || list === null ? null : (
@@ -780,7 +870,6 @@ const Docs = (defaultprops) => {
if (item === undefined) {
return null;
}
const path = "/docs/" + item;
const newname =
item.charAt(0).toUpperCase() +
@@ -795,11 +884,6 @@ const Docs = (defaultprops) => {
key={index}
style={hrefStyle}
to={path}
onClick={() => {
setTocLines([]);
fetchDocs(item);
handleCollapse(index);
}}
>
<ListItemText
style={{ color: itemMatching ? "#f86a3e" : "inherit" }}
@@ -807,40 +891,14 @@ const Docs = (defaultprops) => {
>
{newname}
</ListItemText>
{isopen === index ? <ExpandMoreIcon /> : <KeyboardArrowRightIcon />}
</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>
);
})}
</List>
</Paper>
</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 ?
mainpageInfo
:
@@ -859,7 +917,65 @@ const Docs = (defaultprops) => {
</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>
)
})}
</nav>
</div >
</div >
);
const mobileStyle = {
@@ -872,7 +988,6 @@ const Docs = (defaultprops) => {
flexDirection: "column",
};
const postDataMobile =
list === undefined || list === null ? null : (
<div style={mobileStyle}>
@@ -918,6 +1033,36 @@ const Docs = (defaultprops) => {
);
})}
</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>
{props.match.params.key === undefined ?
mainpageInfo