improvment over Docs headings
This commit is contained in:
@@ -24,7 +24,8 @@ function ScrollToTop({ getUserNotifications, curpath, setCurpath, history }) {
|
|||||||
// Custom handler for certain scroll mechanics
|
// Custom handler for certain scroll mechanics
|
||||||
//
|
//
|
||||||
//console.log("OLD: ", curpath, "NeW: ", window.location.pathname)
|
//console.log("OLD: ", curpath, "NeW: ", window.location.pathname)
|
||||||
if (curpath === window.location.pathname && curpath === "/usecases") {
|
if (curpath === window.location.pathname && (curpath === "/usecases" ||
|
||||||
|
(curpath === "/docs" && location.hash.length > 0))) {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
window.scroll({
|
window.scroll({
|
||||||
|
|||||||
+103
-57
@@ -51,7 +51,7 @@ const Body = {
|
|||||||
|
|
||||||
const dividerColor = "rgb(225, 228, 232)";
|
const dividerColor = "rgb(225, 228, 232)";
|
||||||
const hrefStyle = {
|
const hrefStyle = {
|
||||||
color: "rgba(255, 255, 255, 0.40)",
|
color: "rgba(255, 255, 255, 0.8)",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -219,6 +219,7 @@ const Docs = (defaultprops) => {
|
|||||||
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 [lastHeading, setLastHeading] = useState(false);
|
||||||
const [activeId, setActiveId] = useState()
|
const [activeId, setActiveId] = useState()
|
||||||
const [isopen, setOpen] = useState(-1);
|
const [isopen, setOpen] = useState(-1);
|
||||||
const [hover, setHover] = useState(false);
|
const [hover, setHover] = useState(false);
|
||||||
@@ -245,48 +246,40 @@ const Docs = (defaultprops) => {
|
|||||||
//}
|
//}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
function handleClick(event) {
|
const handleClick = (event) => {
|
||||||
setAnchorEl(event.currentTarget);
|
setAnchorEl(event.currentTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClickToc(event) {
|
const handleClickToc = (event) => {
|
||||||
setAnchorElToc(event.currentTarget);
|
setAnchorElToc(event.currentTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCollapse(index) {
|
const handleCollapse = (index) => {
|
||||||
setOpen(isopen === index ? -1 : index)
|
setOpen(isopen === index ? -1 : index)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMouseOver() {
|
const handleMouseOver = () => {
|
||||||
setHover(!hover);
|
setHover(!hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClose() {
|
const handleClose = () => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCloseToc() {
|
const handleCloseToc = () => {
|
||||||
setAnchorElToc(null)
|
setAnchorElToc(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Emma Goto
|
|
||||||
const activeIdsetter = (id) => {
|
|
||||||
setActiveId(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
const intersectionObserver = () => {
|
const intersectionObserver = () => {
|
||||||
const callback = (headings) => {
|
const callback = (headings) => {
|
||||||
console.log("Headings: ", headings)
|
|
||||||
|
|
||||||
headingElementsRef.current = headings.reduce((map, headingElement) => {
|
headingElementsRef.current = headings.reduce((map, headingElement) => {
|
||||||
if (map === undefined) {
|
if (map === undefined) {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headingElement === undefined || headingElement.target === undefined || headingElement.target.id === undefined || headingElement.target.id === null || headingElement.target.id === "") {
|
if (headingElement === undefined || headingElement.target === undefined || headingElement.target.id === undefined || headingElement.target.id === null || headingElement.target.id === "") {
|
||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headingElement.target.id != undefined || headingElement.target.id != "") {
|
if (headingElement.target.id != undefined || headingElement.target.id != "") {
|
||||||
map[headingElement.target.id] = headingElement
|
map[headingElement.target.id] = headingElement
|
||||||
@@ -295,49 +288,92 @@ const Docs = (defaultprops) => {
|
|||||||
}, headingElementsRef.current)
|
}, headingElementsRef.current)
|
||||||
|
|
||||||
const visibleHeadings = []
|
const visibleHeadings = []
|
||||||
Object.keys(headingElementsRef.current).forEach((key) => {
|
const keys = Object.keys(headingElementsRef.current)
|
||||||
const headingElemet = headingElementsRef.current[key]
|
|
||||||
if (headingElemet.isIntersecting) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
visibleHeadings.push(headingElemet)
|
const headingElement = headingElementsRef.current[keys[i]]
|
||||||
}
|
if (headingElement.isIntersecting) {
|
||||||
})
|
visibleHeadings.push(headingElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (visibleHeadings.length > 0) {
|
if (visibleHeadings.length > 0) {
|
||||||
//setActiveId(visibleHeadings[0].target.id)
|
const tocs = document.getElementsByClassName('toc')
|
||||||
activeIdsetter(visibleHeadings[0].target.id)
|
for (const t of tocs) {
|
||||||
|
const currentPoint = t.getElementsByTagName('a')[0]
|
||||||
|
currentPoint.style.color = "white";
|
||||||
|
if (`#${visibleHeadings[0].target.id}`
|
||||||
|
=== currentPoint.hash) {
|
||||||
|
currentPoint.style.color = "#f86a3e";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const observer = new IntersectionObserver(callback, {
|
const observer = new IntersectionObserver(callback, {
|
||||||
|
threshold: [1]
|
||||||
})
|
})
|
||||||
|
|
||||||
const headingElements = Array.from(document.querySelectorAll("h2"))
|
const headingElements = Array.from(document.querySelectorAll("h2"))
|
||||||
if (headingElements.length != 0) {
|
if (headingElements.length != 0) {
|
||||||
headingElements.forEach((element) => observer.observe(element))
|
for (var i = 0; i < headingElements.length; i++) {
|
||||||
|
var element = headingElements[i]
|
||||||
|
observer.observe(element)
|
||||||
|
}
|
||||||
return () => observer.disconnect()
|
return () => observer.disconnect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("ACTIVEID: ", activeId)
|
if (lastHeading) {
|
||||||
|
setTimeout(() => {
|
||||||
|
intersectionObserver()
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
|
||||||
if (hashRendered) {
|
|
||||||
setTimeout(() => {
|
|
||||||
intersectionObserver()
|
|
||||||
}, 2000)
|
|
||||||
}
|
|
||||||
|
|
||||||
const scrollToHash = () => {
|
const scrollToHash = () => {
|
||||||
const hash = window.location.hash.replace("#", "")
|
const hash = window.location.hash.replace("#", "")
|
||||||
if (hash) {
|
if (hash) {
|
||||||
const element = document.getElementById(hash)
|
const element = document.getElementById(hash)
|
||||||
if (element) {
|
if (element) {
|
||||||
element.scrollIntoView({
|
element.scrollIntoView({
|
||||||
behavior: "instant",
|
behavior: "instant",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// extract toc from all headings and subheadings
|
||||||
|
const extractHeadings = (content) => {
|
||||||
|
const headings = [];
|
||||||
|
|
||||||
|
const headingRegex = /^(#{2,3})\s+(.+)$/gm;
|
||||||
|
let match;
|
||||||
|
|
||||||
|
while ((match = headingRegex.exec(content)) !== null) {
|
||||||
|
const level = match[1].length;
|
||||||
|
const title = match[2].trim();
|
||||||
|
|
||||||
|
if (level === 2) {
|
||||||
|
headings.push({
|
||||||
|
id: title.toLowerCase().replace(/\s+/g, '-'),
|
||||||
|
title: title,
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
} else if (level === 3 && headings.length > 0) {
|
||||||
|
const lastHeading = headings[headings.length - 1];
|
||||||
|
lastHeading.items.push({
|
||||||
|
id: title.toLowerCase().replace(/\s+/g, '-'),
|
||||||
|
title: title
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return headings
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// extract TOC from actual markdown
|
||||||
const tocvalue = (markdown) => {
|
const tocvalue = (markdown) => {
|
||||||
const items = [];
|
const items = [];
|
||||||
let currentMainItem = null;
|
let currentMainItem = null;
|
||||||
@@ -346,7 +382,7 @@ const Docs = (defaultprops) => {
|
|||||||
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
const line = lines[i];
|
const line = lines[i];
|
||||||
if (line.startsWith('* [')) {
|
if (line.startsWith('* [') && !line.startsWith(" ", 5)) {
|
||||||
const matches = line.match(/^\* \[([^)]+)\]\(#([^)]+)\)/);
|
const matches = line.match(/^\* \[([^)]+)\]\(#([^)]+)\)/);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
currentMainItem = {
|
currentMainItem = {
|
||||||
@@ -396,12 +432,18 @@ const Docs = (defaultprops) => {
|
|||||||
props.children,
|
props.children,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (serverside !== true && window.location.hash.length > 0 && props.level === 1 && !hashRendered) {
|
if (serverside !== true && window.location.hash.length > 0 && props.level === 1 && !hashRendered) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setHashRendered(true)
|
setHashRendered(true)
|
||||||
scrollToHash()
|
scrollToHash()
|
||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (serverside !== true && !lastHeading) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setLastHeading(true)
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
var extraInfo = "";
|
var extraInfo = "";
|
||||||
if (props.level === 1) {
|
if (props.level === 1) {
|
||||||
@@ -413,7 +455,6 @@ const Docs = (defaultprops) => {
|
|||||||
borderRadius: theme.palette.borderRadius,
|
borderRadius: theme.palette.borderRadius,
|
||||||
marginBottom: 30,
|
marginBottom: 30,
|
||||||
display: "flex",
|
display: "flex",
|
||||||
scrollPaddingTop: 20,
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ flex: 3, display: "flex", vAlign: "center", position: "sticky", top: 50, }}>
|
<div style={{ flex: 3, display: "flex", vAlign: "center", position: "sticky", top: 50, }}>
|
||||||
@@ -496,9 +537,9 @@ const Docs = (defaultprops) => {
|
|||||||
setHover(true);
|
setHover(true);
|
||||||
}}
|
}}
|
||||||
id={id}
|
id={id}
|
||||||
style={{
|
style={{
|
||||||
scrollPaddingTop: 20,
|
scrollPaddingTop: 20,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.level !== 1 ? (
|
{props.level !== 1 ? (
|
||||||
<Divider
|
<Divider
|
||||||
@@ -519,8 +560,8 @@ const Docs = (defaultprops) => {
|
|||||||
paddingLeft: "0.3em", rotate: "-30deg",
|
paddingLeft: "0.3em", rotate: "-30deg",
|
||||||
paddingTop: "0.9em", display: props.level === 1 ? "none" : "block",
|
paddingTop: "0.9em", display: props.level === 1 ? "none" : "block",
|
||||||
}}>
|
}}>
|
||||||
<LinkIcon />
|
<LinkIcon />
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{extraInfo}
|
{extraInfo}
|
||||||
@@ -533,6 +574,7 @@ const Docs = (defaultprops) => {
|
|||||||
width: "17%",
|
width: "17%",
|
||||||
position: "sticky",
|
position: "sticky",
|
||||||
top: 50,
|
top: 50,
|
||||||
|
paddingTop: "0.25em",
|
||||||
minHeight: "93vh",
|
minHeight: "93vh",
|
||||||
maxHeight: "93vh",
|
maxHeight: "93vh",
|
||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
@@ -587,7 +629,7 @@ 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 tocRegex = /^## Table of contents[\s\S]*?(?=^##\s|\Z)|^\* \[[^\]]+\]\([^)]+\)\n?(?![^\n]+\]\([^)]+\))/gm;
|
const tocRegex = /^## Table of contents[\s\S]*?(?=^## )|^## Table of contents[\s\S]*$/gm;
|
||||||
const newdata = responseJson.reason.replace(imgRegex, '')
|
const newdata = responseJson.reason.replace(imgRegex, '')
|
||||||
.replace(tocRegex, "");
|
.replace(tocRegex, "");
|
||||||
setData(newdata);
|
setData(newdata);
|
||||||
@@ -611,10 +653,14 @@ const Docs = (defaultprops) => {
|
|||||||
responseJson.reason !== undefined &&
|
responseJson.reason !== undefined &&
|
||||||
responseJson.reason !== null
|
responseJson.reason !== null
|
||||||
) {
|
) {
|
||||||
|
/*
|
||||||
const values = tocvalue(responseJson.reason.match(tocRegex)
|
const values = tocvalue(responseJson.reason.match(tocRegex)
|
||||||
.join()
|
.join()
|
||||||
.toString());
|
.toString());
|
||||||
setTocLines(values);
|
setTocLines(values);
|
||||||
|
*/
|
||||||
|
const values = extractHeadings(newdata)
|
||||||
|
setTocLines(values)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setData("# Error\nThis page doesn't exist.");
|
setData("# Error\nThis page doesn't exist.");
|
||||||
@@ -1134,7 +1180,7 @@ const Docs = (defaultprops) => {
|
|||||||
|
|
||||||
// Padding and zIndex etc set because of footer in cloud.
|
// Padding and zIndex etc set because of footer in cloud.
|
||||||
const loadedCheck = (
|
const loadedCheck = (
|
||||||
<div style={{ minHeight: 1000, paddingBottom: 100, zIndex: 50000, maxWidth: 1920, minWidth: isMobile ? null : 1366, margin: "auto", }}>
|
<div style={{ minHeight: 1000, paddingTop: "60px", zIndex: 50000, maxWidth: 1920, minWidth: isMobile ? null : 1366, margin: "auto", }}>
|
||||||
<BrowserView>{postDataBrowser}</BrowserView>
|
<BrowserView>{postDataBrowser}</BrowserView>
|
||||||
<MobileView>{postDataMobile}</MobileView>
|
<MobileView>{postDataMobile}</MobileView>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user