diff options
author | Peter Johanson <peter@peterjohanson.com> | 2021-03-29 01:20:57 +0000 |
---|---|---|
committer | Pete Johanson <peter@peterjohanson.com> | 2021-09-11 00:50:36 -0400 |
commit | 47abbe7925dece8a50b1001b0b9f32c64268f61b (patch) | |
tree | ade455d82f253244cde1172bfaf0e9124e887530 /docs/src/components | |
parent | 5e6634d2e522289c5169b22a2a0d8b600a0e008d (diff) |
feat(docs): Add dynamic hardware list component.
Diffstat (limited to 'docs/src/components')
-rw-r--r-- | docs/src/components/hardware-list.tsx | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/docs/src/components/hardware-list.tsx b/docs/src/components/hardware-list.tsx new file mode 100644 index 0000000..ec7e8a1 --- /dev/null +++ b/docs/src/components/hardware-list.tsx @@ -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; |