feat(docs): Add dynamic hardware list component.
This commit is contained in:
parent
5e6634d2e5
commit
47abbe7925
7 changed files with 214 additions and 64 deletions
|
@ -1,56 +0,0 @@
|
||||||
---
|
|
||||||
title: Supported Hardware
|
|
||||||
sidebar_label: Supported Hardware
|
|
||||||
---
|
|
||||||
|
|
||||||
:::warning
|
|
||||||
|
|
||||||
ZMK Firmware is still an early stage project. Many features are still waiting to be implemented, and only a select few keyboards
|
|
||||||
have had their hardware details codified in boards/shields for ZMK.
|
|
||||||
|
|
||||||
:::
|
|
||||||
|
|
||||||
With the solid technical foundation of Zephyr™ RTOS, ZMK can support a wide diversity of hardware targets.
|
|
||||||
That being said, there are currently only a few specific [boards](faq.md#what-is-a-board)/[shields](faq.md#what-is-a-shield) that have been written and tested by the ZMK contributors.
|
|
||||||
|
|
||||||
## Boards
|
|
||||||
|
|
||||||
- [nice!nano](https://nicekeyboards.com/nice-nano) (`nice_nano`, `nice_nano_v2`)
|
|
||||||
- [nrfMicro](https://github.com/joric/nrfmicro) (`nrfmicro_13`, `nrfmicro_11`, `nrfmicro_11_flipped`)
|
|
||||||
- [BlueMicro840](https://store.jpconstantineau.com/#/group/bluemicro) (`bluemicro840_v1`)
|
|
||||||
- [QMK Proton-C](https://qmk.fm/proton-c/) (`proton_c`)
|
|
||||||
- [BDN9 Rev2](https://keeb.io/products/bdn9-rev-2-3x3-9-key-macropad-rotary-encoder-and-rgb) (`bdn9_rev2`)
|
|
||||||
|
|
||||||
## Keyboard Shields
|
|
||||||
|
|
||||||
- [Kyria](https://splitkb.com/products/kyria-pcb-kit) (`kyria_left` and `kyria_right`)
|
|
||||||
- [Corne](https://github.com/foostan/crkbd) (`corne_left` and `corne_right`)
|
|
||||||
- [Helix](https://github.com/mcmadhatter/helix) (`helix_left` and `helix_right`)
|
|
||||||
- [Lily58](https://github.com/kata0510/Lily58) (`lily58_left` and `lily58_right`)
|
|
||||||
- [Sofle](https://github.com/josefadamcik/SofleKeyboard) (`sofle_left` and `sofle_right`)
|
|
||||||
- [Splitreus62](https://github.com/Na-Cly/splitreus62) (`splitreus62_left` and `splitreus62_right`)
|
|
||||||
- [Jorne](https://github.com/joric/jorne) (`jorne_left` and `jorne_right`)
|
|
||||||
- [Jian](https://github.com/KGOH/Jian-Info) (`jian_left` and `jian_right`)
|
|
||||||
- [Reviung41](https://github.com/gtips/reviung/tree/master/reviung41) (`reviung41`)
|
|
||||||
- [RoMac+ v4](https://www.littlekeyboards.com/products/romac) (`romac_plus`)
|
|
||||||
- [RoMac v2](https://mechboards.co.uk/shop/kits/romac-macro-pad/) (`romac`)
|
|
||||||
- [Boardsource 3x4 Macro](https://boardsource.xyz/store/5ecc2008eee64242946c98c1) (`boardsource3x4`)
|
|
||||||
- [QAZ](https://www.cbkbd.com/product/qaz-keyboard-kit) (`qaz`)
|
|
||||||
- [CRBN](https://keygem.store/collections/group-buys/products/group-buy-featherlight-40-kit) (`crbn`)
|
|
||||||
- [tidbit](https://nullbits.co/tidbit/) (`tidbit`)
|
|
||||||
- [Eek!](https://www.cbkbd.com/product/eek-keyboard) (`eek`)
|
|
||||||
- [BFO-9000](https://keeb.io/products/bfo-9000-keyboard-customizable-full-size-split-ortholinear) (`bfo9000_left` and `bfo9000_right`)
|
|
||||||
|
|
||||||
## Other Hardware
|
|
||||||
|
|
||||||
In addition to the basic keyboard functionality, there is some initial support for additional keyboard hardware:
|
|
||||||
|
|
||||||
- Encoders
|
|
||||||
- OLEDs
|
|
||||||
- RGB Underglow
|
|
||||||
|
|
||||||
Until detailed documentation is available, feel free to ask questions about how these are supported in the [Discord server](https://zmk.dev/community/discord/invite).
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
If you'd like to add support for a new keyboard shield, head over to the [New Keyboard Shield](development/new-shield.md) documentation.
|
|
26
docs/docs/hardware.mdx
Normal file
26
docs/docs/hardware.mdx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
title: Supported Hardware
|
||||||
|
sidebar_label: Supported Hardware
|
||||||
|
---
|
||||||
|
|
||||||
|
import HardwareList from "@site/src/components/hardware-list";
|
||||||
|
import Metadata from "@site/src/data/hardware-metadata.json";
|
||||||
|
|
||||||
|
With the solid technical foundation of Zephyr™ RTOS, ZMK can support a wide diversity of hardware targets.
|
||||||
|
That being said, there are currently only a few specific [boards](/docs/faq#what-is-a-board)/[shields](faq.md#what-is-a-shield) that have been implemented and tested by the ZMK contributors.
|
||||||
|
|
||||||
|
<HardwareList items={Metadata} />
|
||||||
|
|
||||||
|
## Other Hardware
|
||||||
|
|
||||||
|
In addition to the basic keyboard functionality, there is some initial support for additional keyboard hardware:
|
||||||
|
|
||||||
|
- Encoders
|
||||||
|
- Displays
|
||||||
|
- RGB Underglow
|
||||||
|
|
||||||
|
Until detailed documentation is available, feel free to ask questions about how these are supported in the [Discord server](https://zmk.dev/community/discord/invite).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
If you'd like to add support for a new keyboard shield, head over to the [New Keyboard Shield](development/new-shield.md) documentation.
|
|
@ -11,7 +11,7 @@ module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
path.resolve(__dirname, "src/docusaurus-tree-sitter-plugin"),
|
path.resolve(__dirname, "src/docusaurus-tree-sitter-plugin"),
|
||||||
path.resolve(__dirname, "src/hardware-metadata-collection-plugin"),
|
path.resolve(__dirname, "src/hardware-metadata-collection-plugin"),
|
||||||
path.resolve(__dirname, "src/hardware-schema-typescript-plugin")
|
path.resolve(__dirname, "src/hardware-schema-typescript-plugin"),
|
||||||
],
|
],
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
colorMode: {
|
colorMode: {
|
||||||
|
|
176
docs/src/components/hardware-list.tsx
Normal file
176
docs/src/components/hardware-list.tsx
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Board,
|
||||||
|
HardwareMetadata,
|
||||||
|
Interconnect,
|
||||||
|
Shield,
|
||||||
|
} from "../hardware-metadata";
|
||||||
|
|
||||||
|
interface HardwareListProps {
|
||||||
|
items: HardwareMetadata[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type ElementOrString = JSX.Element | string;
|
||||||
|
|
||||||
|
function itemHasMultiple(item: HardwareMetadata) {
|
||||||
|
return (
|
||||||
|
(item.type == "board" || item.type == "shield") &&
|
||||||
|
(item.siblings?.length ?? 1) > 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function itemIds(item: HardwareMetadata) {
|
||||||
|
if (item.type == "board" || item.type == "shield") {
|
||||||
|
let nodes = (item.siblings ?? [item.id])
|
||||||
|
.map<ElementOrString>((id) => <code key={id}>{id}</code>)
|
||||||
|
.reduce(
|
||||||
|
(prev, curr, index) => [...prev, index > 0 ? ", " : "", curr],
|
||||||
|
[] as ElementOrString[]
|
||||||
|
);
|
||||||
|
return <span key={item.id}>{nodes}</span>;
|
||||||
|
} else {
|
||||||
|
return <code key={item.id}>{item.id}</code>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const TYPE_LABELS: Record<
|
||||||
|
HardwareMetadata["type"],
|
||||||
|
Record<"singular" | "plural", string>
|
||||||
|
> = {
|
||||||
|
board: { plural: "Boards: ", singular: "Board: " },
|
||||||
|
shield: { singular: "Shield: ", plural: "Shields: " },
|
||||||
|
interconnect: { singular: "Interconnect: ", plural: "Interconnects: " },
|
||||||
|
};
|
||||||
|
|
||||||
|
function HardwareLineItem({ item }: { item: HardwareMetadata }) {
|
||||||
|
return (
|
||||||
|
<li>
|
||||||
|
<a href={item.url}>{item.name}</a> (
|
||||||
|
{TYPE_LABELS[item.type][itemHasMultiple(item) ? "plural" : "singular"]}{" "}
|
||||||
|
{itemIds(item)})
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InterconnectDetails {
|
||||||
|
interconnect?: Interconnect;
|
||||||
|
boards: Board[];
|
||||||
|
shields: Shield[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapInterconnect({
|
||||||
|
interconnect,
|
||||||
|
boards,
|
||||||
|
shields,
|
||||||
|
}: InterconnectDetails) {
|
||||||
|
if (!interconnect) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={interconnect.id}>
|
||||||
|
<h4>{interconnect.name} Keyboards</h4>
|
||||||
|
{interconnect.description && <p>{interconnect.description}</p>}
|
||||||
|
<h5>Boards</h5>
|
||||||
|
<ul>
|
||||||
|
{boards.map((s) => (
|
||||||
|
<HardwareLineItem key={s.id} item={s} />
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<h5>Shields</h5>
|
||||||
|
<ul>
|
||||||
|
{shields.map((s) => (
|
||||||
|
<HardwareLineItem key={s.id} item={s} />
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GroupedMetadata {
|
||||||
|
onboard: Board[];
|
||||||
|
interconnects: Record<string, InterconnectDetails>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupedBoard(agg: GroupedMetadata, board: Board) {
|
||||||
|
if (board.features?.includes("keys")) {
|
||||||
|
agg.onboard.push(board);
|
||||||
|
} else if (board.exposes) {
|
||||||
|
board.exposes.forEach((element) => {
|
||||||
|
let ic = agg.interconnects[element] ?? {
|
||||||
|
boards: [],
|
||||||
|
shields: [],
|
||||||
|
};
|
||||||
|
ic.boards.push(board);
|
||||||
|
agg.interconnects[element] = ic;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error("Board without keys or interconnect");
|
||||||
|
}
|
||||||
|
|
||||||
|
return agg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupedShield(agg: GroupedMetadata, shield: Shield) {
|
||||||
|
shield.requires.forEach((id) => {
|
||||||
|
let ic = agg.interconnects[id] ?? { boards: [], shields: [] };
|
||||||
|
ic.shields.push(shield);
|
||||||
|
agg.interconnects[id] = ic;
|
||||||
|
});
|
||||||
|
|
||||||
|
return agg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function groupedInterconnect(agg: GroupedMetadata, item: Interconnect) {
|
||||||
|
let ic = agg.interconnects[item.id] ?? { boards: [], shields: [] };
|
||||||
|
ic.interconnect = item;
|
||||||
|
agg.interconnects[item.id] = ic;
|
||||||
|
|
||||||
|
return agg;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HardwareList({ items }: HardwareListProps) {
|
||||||
|
let grouped = items.reduce<GroupedMetadata>(
|
||||||
|
(agg, hm) => {
|
||||||
|
switch (hm.type) {
|
||||||
|
case "board":
|
||||||
|
return groupedBoard(agg, hm);
|
||||||
|
case "shield":
|
||||||
|
return groupedShield(agg, hm);
|
||||||
|
case "interconnect":
|
||||||
|
return groupedInterconnect(agg, hm);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ onboard: [] as Board[], interconnects: {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h2>Keyboards</h2>
|
||||||
|
<h3>Onboard Controller Boards</h3>
|
||||||
|
<p>
|
||||||
|
Keyboards with onboard controllers are single PCBs that contain all the
|
||||||
|
components of a keyboard, including the controller chip, switch
|
||||||
|
footprints, etc.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
{grouped["onboard"]
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
.map((s) => (
|
||||||
|
<HardwareLineItem key={s.id} item={s} />
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<h3>Composite Boards</h3>
|
||||||
|
<p>
|
||||||
|
Composite keyboards are composed of two main PCBs: a small controller
|
||||||
|
board with exposed pads, and a larger keyboard PCB (a shield, in ZMK
|
||||||
|
lingo) with switch footprints and location a where the controller is
|
||||||
|
added.
|
||||||
|
</p>
|
||||||
|
{Object.values(grouped.interconnects).map(mapInterconnect)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HardwareList;
|
|
@ -8,12 +8,16 @@ var PrebuildPlugin = require("prebuild-webpack-plugin");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const yaml = require("js-yaml");
|
const yaml = require("js-yaml");
|
||||||
const glob = require("glob");
|
const glob = require("glob");
|
||||||
const { compile, compileFromFile } = require('json-schema-to-typescript');
|
|
||||||
|
|
||||||
function generateHardwareMetadataAggregate() {
|
function generateHardwareMetadataAggregate() {
|
||||||
glob("../app/boards/**/*.zmk.yml", (error, files) => {
|
glob("../app/boards/**/*.zmk.yml", (error, files) => {
|
||||||
const aggregated = files.flatMap(f => yaml.safeLoadAll(fs.readFileSync(f, "utf8")));
|
const aggregated = files.flatMap((f) =>
|
||||||
fs.writeFileSync("src/data/hardware-metadata.json", JSON.stringify(aggregated));
|
yaml.safeLoadAll(fs.readFileSync(f, "utf8"))
|
||||||
|
);
|
||||||
|
fs.writeFileSync(
|
||||||
|
"src/data/hardware-metadata.json",
|
||||||
|
JSON.stringify(aggregated)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
var PrebuildPlugin = require("prebuild-webpack-plugin");
|
var PrebuildPlugin = require("prebuild-webpack-plugin");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const { compileFromFile } = require('json-schema-to-typescript');
|
const { compileFromFile } = require("json-schema-to-typescript");
|
||||||
|
|
||||||
async function generateHardwareMetadataTypescript() {
|
async function generateHardwareMetadataTypescript() {
|
||||||
const ts = await compileFromFile("../schema/hardware-metadata.schema.json");
|
const ts = await compileFromFile("../schema/hardware-metadata.schema.json");
|
||||||
|
|
Loading…
Add table
Reference in a new issue