forked from kofal.net/zmk
docs(codes): Add (key) codes documentation
Create codes documentation for standardized keys. Closes #218. Fixes #308. Ref #21.
This commit is contained in:
17
docs/src/components/codes/Context.jsx
Normal file
17
docs/src/components/codes/Context.jsx
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export default function Context({ children }) {
|
||||
return <p className="context">{children}</p>;
|
||||
}
|
||||
|
||||
Context.propTypes = {
|
||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.string])
|
||||
.isRequired,
|
||||
};
|
||||
51
docs/src/components/codes/Description.jsx
Normal file
51
docs/src/components/codes/Description.jsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const specialCharactersRegex = /(?:^|\s)((?:&(?:(?:\w+)|(?:#\d+));)|[_]|[^\w\s])(?:\s*\[([^[\]]+?)\])/g;
|
||||
|
||||
function renderSpecialCharacters(description) {
|
||||
const matches = Array.from(description.matchAll(specialCharactersRegex));
|
||||
if (matches.length == 0) return description;
|
||||
let lastIndex = 0;
|
||||
const parts = matches.reduce((acc, match, i) => {
|
||||
const { index } = match;
|
||||
const str = match[0];
|
||||
const chars = match[1];
|
||||
const meaning = match[2];
|
||||
if (index != lastIndex) {
|
||||
acc.push(description.substring(lastIndex, index));
|
||||
}
|
||||
const pos = str.indexOf(chars);
|
||||
if (pos > 0) {
|
||||
acc.push(description.substr(index, pos));
|
||||
}
|
||||
acc.push(
|
||||
<span key={i} className="symbol" title={meaning ?? ""}>
|
||||
<code>{description.substr(index + pos, chars.length)}</code>
|
||||
{meaning ? <span className="meaning">{meaning}</span> : undefined}
|
||||
</span>
|
||||
);
|
||||
lastIndex = index + str.length;
|
||||
return acc;
|
||||
}, []);
|
||||
if (lastIndex < description.length) {
|
||||
parts.push(description.substr(lastIndex));
|
||||
}
|
||||
return parts;
|
||||
}
|
||||
|
||||
export default function Description({ description = "" }) {
|
||||
return (
|
||||
<span className="description">{renderSpecialCharacters(description)}</span>
|
||||
);
|
||||
}
|
||||
|
||||
Description.propTypes = {
|
||||
description: PropTypes.string.isRequired,
|
||||
};
|
||||
23
docs/src/components/codes/Footnote.jsx
Normal file
23
docs/src/components/codes/Footnote.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export default function Footnote({ children, symbol, id }) {
|
||||
return (
|
||||
<div className="footnote" id={id}>
|
||||
<div className="symbol">{symbol}</div>
|
||||
<div className="content">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Footnote.propTypes = {
|
||||
children: PropTypes.element.isRequired,
|
||||
symbol: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
};
|
||||
22
docs/src/components/codes/FootnoteRef.jsx
Normal file
22
docs/src/components/codes/FootnoteRef.jsx
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
export default function FootnoteRef({ children, anchor }) {
|
||||
return (
|
||||
<a href={"#" + anchor} className="footnoteRef">
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
FootnoteRef.propTypes = {
|
||||
children: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
|
||||
.isRequired,
|
||||
anchor: PropTypes.string.isRequired,
|
||||
};
|
||||
43
docs/src/components/codes/FootnoteRefs.jsx
Normal file
43
docs/src/components/codes/FootnoteRefs.jsx
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import FootnoteRef from "./FootnoteRef";
|
||||
|
||||
function joinReactElements(arr, delimiter) {
|
||||
return arr.reduce((acc, fragment) => {
|
||||
if (acc === null) {
|
||||
return fragment;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{acc}
|
||||
{delimiter}
|
||||
{fragment}
|
||||
</>
|
||||
);
|
||||
}, null);
|
||||
}
|
||||
|
||||
export default function FootnoteRefs({ footnotes }) {
|
||||
return (
|
||||
<span className="footnoteRefs">
|
||||
{joinReactElements(
|
||||
footnotes.map((footnote) => (
|
||||
<FootnoteRef key={footnote.reference} {...footnote}>
|
||||
{footnote.symbol}
|
||||
</FootnoteRef>
|
||||
)),
|
||||
", "
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
FootnoteRefs.propTypes = {
|
||||
footnotes: PropTypes.array.isRequired,
|
||||
};
|
||||
30
docs/src/components/codes/Footnotes.jsx
Normal file
30
docs/src/components/codes/Footnotes.jsx
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Footnote from "./Footnote";
|
||||
|
||||
export default function Footnotes({ footnotes = [], id }) {
|
||||
return (
|
||||
<div className="footnotes">
|
||||
<a id={id} className="anchor" />
|
||||
<div className="label">Notes</div>
|
||||
<div className="notes">
|
||||
{footnotes.map((footnote) => (
|
||||
<Footnote key={footnote.id} {...footnote}>
|
||||
{footnote.value}
|
||||
</Footnote>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Footnotes.propTypes = {
|
||||
footnotes: PropTypes.array.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
};
|
||||
14
docs/src/components/codes/LinkIcon.jsx
Normal file
14
docs/src/components/codes/LinkIcon.jsx
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
|
||||
export default function LinkIcon() {
|
||||
return <FontAwesomeIcon className="icon" icon={faExternalLinkAlt} />;
|
||||
}
|
||||
|
||||
LinkIcon.propTypes = {};
|
||||
25
docs/src/components/codes/Name.jsx
Normal file
25
docs/src/components/codes/Name.jsx
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import ToastyCopyToClipboard from "./ToastyCopyToClipboard";
|
||||
|
||||
export default function Name({ children, name }) {
|
||||
return (
|
||||
<ToastyCopyToClipboard text={name}>
|
||||
<code className="name" title="Copy 📋">
|
||||
{children}
|
||||
</code>
|
||||
</ToastyCopyToClipboard>
|
||||
);
|
||||
}
|
||||
|
||||
Name.propTypes = {
|
||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.string])
|
||||
.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
};
|
||||
23
docs/src/components/codes/OsLegend.jsx
Normal file
23
docs/src/components/codes/OsLegend.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import operatingSystems from "@site/src/data/operating-systems";
|
||||
|
||||
export default function OsLegend() {
|
||||
return (
|
||||
<div className="codes os legend">
|
||||
{operatingSystems.map(({ key, className, heading, title }) => (
|
||||
<div key={key} className={"os " + className}>
|
||||
<span className="heading">{heading}</span>
|
||||
<span className="title">{title}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
OsLegend.propTypes = {};
|
||||
26
docs/src/components/codes/OsSupport.jsx
Normal file
26
docs/src/components/codes/OsSupport.jsx
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import OsSupportIcon from "./OsSupportIcon";
|
||||
import FootnoteRefs from "./FootnoteRefs";
|
||||
|
||||
export default function OsSupport({ value, footnotes = [] }) {
|
||||
return (
|
||||
<>
|
||||
<OsSupportIcon value={value} />
|
||||
{footnotes.length > 0 ? (
|
||||
<FootnoteRefs footnotes={footnotes} />
|
||||
) : undefined}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
OsSupport.propTypes = {
|
||||
value: PropTypes.oneOf([true, false, null]),
|
||||
footnotes: PropTypes.array.isRequired,
|
||||
};
|
||||
51
docs/src/components/codes/OsSupportIcon.jsx
Normal file
51
docs/src/components/codes/OsSupportIcon.jsx
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
const Icon = ({ children, className, title }) => (
|
||||
<span className={className} title={title}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
||||
Icon.propTypes = {
|
||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.string])
|
||||
.isRequired,
|
||||
className: PropTypes.string.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export const Supported = () => (
|
||||
<Icon className="supported" title="Supported 😄">
|
||||
⭐
|
||||
</Icon>
|
||||
);
|
||||
export const NotSupported = () => (
|
||||
<Icon className="not-supported" title="Not Supported 😢">
|
||||
❌
|
||||
</Icon>
|
||||
);
|
||||
export const NotTested = () => (
|
||||
<Icon className="not-tested" title="Not Tested Yet - PR's welcomed! 🧐">
|
||||
❔
|
||||
</Icon>
|
||||
);
|
||||
|
||||
export default function OsSupportIcon({ value }) {
|
||||
if (value === true) {
|
||||
return <Supported />;
|
||||
}
|
||||
if (value === false) {
|
||||
return <NotSupported />;
|
||||
}
|
||||
return <NotTested />;
|
||||
}
|
||||
|
||||
OsSupportIcon.propTypes = {
|
||||
value: PropTypes.oneOf([true, false, null]),
|
||||
};
|
||||
80
docs/src/components/codes/Table.jsx
Normal file
80
docs/src/components/codes/Table.jsx
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import TableRow from "./TableRow";
|
||||
import Footnotes from "./Footnotes";
|
||||
import LinkIcon from "./LinkIcon";
|
||||
import operatingSystems from "@site/src/data/operating-systems";
|
||||
import { getCodes } from "@site/src/hid";
|
||||
import { getGroup } from "@site/src/groups";
|
||||
import { getFootnote } from "@site/src/footnotes";
|
||||
|
||||
function extractFootnoteIds(codes) {
|
||||
return Array.from(
|
||||
new Set(
|
||||
codes
|
||||
.flatMap(({ footnotes }) => Object.values(footnotes))
|
||||
.map((refs) => (Array.isArray(refs) ? refs.flat() : refs))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default function Table({ group }) {
|
||||
const codes = getCodes(getGroup(group));
|
||||
|
||||
const footnotesAnchor = group + "-" + "footnotes";
|
||||
|
||||
const tableFootnotes = extractFootnoteIds(codes).map((id, i) => {
|
||||
const Component = getFootnote(id);
|
||||
return {
|
||||
id,
|
||||
anchor: footnotesAnchor,
|
||||
symbol: i + 1,
|
||||
value: Component ? <Component /> : undefined,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="codes">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="names">Names</th>
|
||||
<th className="description">Description</th>
|
||||
<th className="documentation" title="Documentation">
|
||||
<LinkIcon />
|
||||
</th>
|
||||
{operatingSystems.map(({ key, className, heading, title }) => (
|
||||
<th key={key} className={`os ${className}`} title={title}>
|
||||
{heading}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Array.isArray(codes)
|
||||
? codes.map((code) => (
|
||||
<TableRow
|
||||
key={code.names[0]}
|
||||
{...code}
|
||||
tableFootnotes={tableFootnotes}
|
||||
/>
|
||||
))
|
||||
: undefined}
|
||||
</tbody>
|
||||
</table>
|
||||
{tableFootnotes.length > 0 ? (
|
||||
<Footnotes id={footnotesAnchor} footnotes={tableFootnotes} />
|
||||
) : undefined}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Table.propTypes = {
|
||||
group: PropTypes.string.isRequired,
|
||||
};
|
||||
70
docs/src/components/codes/TableRow.jsx
Normal file
70
docs/src/components/codes/TableRow.jsx
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Name from "./Name";
|
||||
import Description from "./Description";
|
||||
import Context from "./Context";
|
||||
import LinkIcon from "./LinkIcon";
|
||||
import OsSupport from "./OsSupport";
|
||||
import operatingSystems from "@site/src/data/operating-systems";
|
||||
|
||||
export default function TableRow({
|
||||
names,
|
||||
description,
|
||||
context = "",
|
||||
clarify = false,
|
||||
documentation,
|
||||
os,
|
||||
footnotes,
|
||||
tableFootnotes,
|
||||
}) {
|
||||
return (
|
||||
<tr>
|
||||
<td className="names">
|
||||
{names.map((name) => (
|
||||
<Name key={name} name={name}>
|
||||
{name}
|
||||
</Name>
|
||||
))}
|
||||
</td>
|
||||
<td className="description">
|
||||
<Description description={description} />
|
||||
{clarify && context ? <Context>{context}</Context> : undefined}
|
||||
</td>
|
||||
<td className="documentation" title="Documentation">
|
||||
<a href={documentation} target="_blank" rel="noreferrer">
|
||||
<LinkIcon />
|
||||
</a>
|
||||
</td>
|
||||
{operatingSystems.map(({ key, className, title }) => (
|
||||
<td key={key} className={`os ${className}`} title={title}>
|
||||
<OsSupport
|
||||
value={os[key]}
|
||||
footnotes={tableFootnotes.filter(
|
||||
({ id }) =>
|
||||
(Array.isArray(footnotes[key]) &&
|
||||
footnotes[key].includes(id)) ||
|
||||
footnotes[key] == id
|
||||
)}
|
||||
/>
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
TableRow.propTypes = {
|
||||
names: PropTypes.array.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
context: PropTypes.string.isRequired,
|
||||
clarify: PropTypes.bool,
|
||||
documentation: PropTypes.string.isRequired,
|
||||
os: PropTypes.object.isRequired,
|
||||
footnotes: PropTypes.object.isRequired,
|
||||
tableFootnotes: PropTypes.array.isRequired,
|
||||
};
|
||||
22
docs/src/components/codes/ToastyContainer.jsx
Normal file
22
docs/src/components/codes/ToastyContainer.jsx
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
|
||||
export default function ToastyContainer() {
|
||||
return (
|
||||
<ToastContainer
|
||||
position="bottom-right"
|
||||
autoClose={2000}
|
||||
hideProgressBar={true}
|
||||
newestOnTop={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
ToastyContainer.propTypes = {};
|
||||
30
docs/src/components/codes/ToastyCopyToClipboard.jsx
Normal file
30
docs/src/components/codes/ToastyCopyToClipboard.jsx
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: CC-BY-NC-SA-4.0
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { toast } from "react-toastify";
|
||||
import { CopyToClipboard } from "react-copy-to-clipboard";
|
||||
|
||||
export default function ToastyCopyToClipboard({ children, text }) {
|
||||
const notify = () =>
|
||||
toast(
|
||||
<span>
|
||||
📋 Copied <code>{text}</code>
|
||||
</span>
|
||||
);
|
||||
return (
|
||||
<div onClick={notify}>
|
||||
<CopyToClipboard text={text}>{children}</CopyToClipboard>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ToastyCopyToClipboard.propTypes = {
|
||||
children: PropTypes.oneOfType([PropTypes.element, PropTypes.string])
|
||||
.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
};
|
||||
Reference in New Issue
Block a user