Skip to content
72 changes: 39 additions & 33 deletions src/components/Config.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import ReactMarkdown from 'react-markdown';
import style from '@site/src/css/markdown-styles.module.css';
import yaml from 'js-yaml';
Expand Down Expand Up @@ -80,8 +80,9 @@ const parseItalics = (key) => {
return key;
}

const YamlNodeWithDescription = ({ name, node, parentKey, root, separator }) => {
const [showDescription, setShowDescription] = useState(false);
const YamlNodeWithDescription = ({ name, node, parentKey, root, separator, showAllDescriptions }) => {
const ignoreInitialRenderRef = useRef(false);
const [showDescription, setShowDescription] = useState(showAllDescriptions);

node.default = node.default || 'N/A';
node.description = node.description || 'N/A';
Expand All @@ -93,9 +94,17 @@ const YamlNodeWithDescription = ({ name, node, parentKey, root, separator }) =>
}
}, [name]);

useEffect(() => {
if (ignoreInitialRenderRef.current) {
setShowDescription(showAllDescriptions);
} else {
ignoreInitialRenderRef.current = true;
}
}, [showAllDescriptions]);

const handleHashLinkClick = (event) => {
event.preventDefault();
history.pushState(null, null, event.currentTarget.hash);
history.pushState(null, "", event.currentTarget.hash);

const fullURL = window.location.href.split('#')[0];
const hash = createUrlHash(parentKey, name);
Expand All @@ -121,30 +130,24 @@ const YamlNodeWithDescription = ({ name, node, parentKey, root, separator }) =>
>
{parseItalics(name)}{parseDefault(node.default.toString(), !showDescription, parentKey, name, handleHashLinkClick, separator)}
</a>
{showDescription ? (
<>
<div className="indent-2" style={{ marginBottom: 10 }}>
<div className="outlined-box description-text color-offset-box">
<ReactMarkdown className={style.reactMarkDown}>{node.description.toString()}</ReactMarkdown>
</div>
</div>
</>
) : (
<></>
)}
<div className="indent-2" style={{ marginBottom: 10, display: !showDescription ? "none" : "" }}>
<div className="outlined-box description-text color-offset-box">
<ReactMarkdown className={style.reactMarkDown}>{node.description.toString()}</ReactMarkdown>
</div>
</div>
</div>
</div>
);
};

const YamlTreeNode = ({ root, key, parentKey, value, separator }) => {
const YamlTreeNode = ({ root, name, parentKey, value, separator, showAllDescriptions }) => {
const handleClick = (event) => {
event.preventDefault();
scrollIntoView(createUrlHash(parentKey, key));
history.pushState(null, null, `#${createUrlHash(parentKey, key)}`);
scrollIntoView(createUrlHash(parentKey, name));
history.pushState(null, "", `#${createUrlHash(parentKey, name)}`);

const fullURL = window.location.href.split('#')[0];
const hash = createUrlHash(parentKey, key);
const hash = createUrlHash(parentKey, name);
navigator.clipboard.writeText(fullURL + '#' + hash);
scrollIntoView(hash);

Expand All @@ -159,45 +162,48 @@ const YamlTreeNode = ({ root, key, parentKey, value, separator }) => {
}

useEffect(() => {
const hash = createUrlHash(parentKey, key);
const hash = createUrlHash(parentKey, name);
if (window.location.hash === `#${hash}`) {
scrollIntoView(hash);
}
}, [key]);
}, [name]);

return (
<div key={key} className={`highlight-config-node`} style={{ paddingLeft: `${root ? 0 : INDENT_SIZE}px` }} id={createUrlHash(parentKey, key)}>
<div key={name} className={`highlight-config-node`} style={{ paddingLeft: `${root ? 0 : INDENT_SIZE}px` }} id={createUrlHash(parentKey, name)}>
<div className={`config-auxiliary-node`} style={{display: "inline-flex"}}>
{parseItalics(key)}{removeTrailingSpaces(separator)}
{parseItalics(name)}{removeTrailingSpaces(separator)}
</div>
<a className={`config-anchor with-value-active-color hash-link`} href={`#${createUrlHash(parentKey, key)}`} onClick={handleClick}></a>
{renderYamlData(value, parentKey ? createUrlHash(parentKey, key) : parseUrlHash(key), false, separator)}
<a className={`config-anchor with-value-active-color hash-link`} href={`#${createUrlHash(parentKey, name)}`} onClick={handleClick}></a>
{renderYamlData(value, parentKey ? createUrlHash(parentKey, name) : parseUrlHash(name), false, separator, showAllDescriptions)}
</div>
);
};

const renderYamlData = (data, parentKey, root = false, separator) => {
const renderedNodes = [];
const renderYamlData = (data, parentKey, root = false, separator, showAllDescriptions) => {
const renderedNodes: JSX.Element[] = [];

for (const [key, value] of Object.entries(data)) {
if (typeof value === 'object') {
if (typeof value === 'object' && value !== null) {
if ('default' in value || 'description' in value) {
renderedNodes.push(<YamlNodeWithDescription key={key} name={key} parentKey={parentKey} node={value} root={root} separator={separator} />);
renderedNodes.push(<YamlNodeWithDescription key={key} name={key} parentKey={parentKey} node={value} root={root} separator={separator} showAllDescriptions={showAllDescriptions} />);
} else {
renderedNodes.push(YamlTreeNode({ root, key, parentKey, value, separator }));
renderedNodes.push(<YamlTreeNode root={root} key={key} name={key} parentKey={parentKey} value={value} separator={separator} showAllDescriptions={showAllDescriptions} />);
}
}
}

return renderedNodes;
};

export default function Config({ data, separator = ': ' }) {
export default function Config({ data, separator = ': ', showDescriptions = false}) {
const [showAllDescriptions, setShowAllExpanded] = useState(showDescriptions);
let ymlData = yaml.load(data);
return (
<div>
<pre>{renderYamlData(ymlData, '', true, separator)}</pre>
<div style={{ display: 'none' }}>{data}</div>
<pre className='config-container'>
<button onClick={() => setShowAllExpanded(!showAllDescriptions)} className={`config-button button button--secondary`}>{showAllDescriptions ? "Collapse All" : "Expand All"}</button>
{renderYamlData(ymlData, '', true, separator, showAllDescriptions)}
</pre>
</div>
);
}
25 changes: 25 additions & 0 deletions src/css/custom.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
:root {
--ifm-color-primary: #0240dc;
--ifm-color-primary-dark: #033ed5;
--ifm-color-secondary: #868686;
--ifm-color-secondary-dark: #5f5f5f;
--ifm-color-warning-contrast-background: #ffe39c;

--ifm-code-font-size: 95%;
Expand All @@ -16,6 +18,8 @@
html[data-theme="dark"] {
--ifm-color-primary: #409efe;
--ifm-color-primary-dark: #0175ec;
--ifm-color-secondary: #ebedf0;
--ifm-color-secondary-dark: #b9b4b4;

--ifm-menu-color: #dadada !important;
--ifm-toc-link-color: #dadada !important;
Expand All @@ -27,6 +31,14 @@ html[data-theme="dark"] {
--config-node-highlight-text-color: white;
}

.button.button--secondary {
color: #f6f7f8;
}

[data-theme="dark"] .button.button--secondary {
color: #1c1e21;
}

.header-icon-link::before {
content: "";
width: 24px;
Expand Down Expand Up @@ -181,6 +193,19 @@ html[data-theme="dark"] {
width: fit-content;
}

.config-container {
font-variant-ligatures: no-contextual;
position: relative;
}

.config-button {
position: absolute;
padding: 0px;
width: 90px;
top: 10px;
right: 10px;
}

.config-anchor {
text-decoration: none;
}
Expand Down