presentation/renderers/folder.renderer.ts
presentation/renderers/folder.renderer.ts is a file in Bane's Lab Site. 137 lines of code and 25 definitions.
import type { Block, GlossaryBlock, ListBlock, MetricBlock } from "#types/block.types";
import {
DEFINITIONS_LABEL,
EDGES_LABEL,
FILES_LABEL,
FOLDERS_LABEL,
LINES_LABEL,
} from "#configuration/strings/folder.strings";
import type { FileNode, FolderNode, TreeNode } from "#types/folder.types";
import { ancestorsOf, isFolder, treeLink } from "#presentation/components/folder.component";
import { appendChildren, createElement } from "#core/factories/element.factory";
import { NODE_CLASS } from "#configuration/constants/anatomy.constants";
import { SPACE } from "#configuration/constants/document.constants";
import { fillMarkup } from "#presentation/renderers/text.renderer";
import { renderBlock } from "#presentation/renderers/block.renderer";
import { renderFields } from "#presentation/renderers/ontology.renderer";
import { renderMetricGrid } from "#presentation/renderers/metric.renderer";
const isList = function isList(block: Block): block is ListBlock {
return block.kind === "list";
};
const isGlossary = function isGlossary(block: Block): block is GlossaryBlock {
return block.kind === "glossary";
};
const isMetric = function isMetric(block: Block): block is MetricBlock {
return block.kind === "metric";
};
const renderNodeBlock = function renderNodeBlock(block: Block): Element {
if (isGlossary(block)) {
return renderFields(block);
}
if (isMetric(block)) {
return createElement("div", {
children: [
createElement("h3", { className: "filesystem-listing-title", text: block.caption }),
renderMetricGrid(block),
],
className: "filesystem-metrics",
});
}
return createElement("div", { children: [renderBlock(block)], className: "chapter-panel" });
};
const renderChips = function renderChips(items: readonly string[]): Element {
const list = createElement("ul", { className: "record-chips" });
appendChildren(
list,
items.map((item) => fillMarkup(createElement("li", { className: "record-chip" }), item)),
);
return list;
};
const splitBlocks = function splitBlocks(blocks: readonly Block[]): {
readonly chips: readonly string[];
readonly rest: readonly Block[];
} {
const [first] = blocks;
if (first !== undefined && isList(first)) {
return { chips: first.items, rest: blocks.slice(1) };
}
return { chips: [], rest: blocks };
};
const pathOf = function pathOf(root: FolderNode, node: TreeNode): string {
if (isFolder(node)) {
return node.path;
}
return node.section.title === root.name ? "" : node.section.title;
};
const renderCrumbs = function renderCrumbs(root: FolderNode, node: TreeNode): Element {
const crumbs = ancestorsOf(root, pathOf(root, node)).filter((folder) => folder !== node);
const nav = createElement("nav", { className: "filesystem-crumbs" });
appendChildren(
nav,
crumbs.map((folder) => treeLink(folder, "filesystem-crumb")),
);
return nav;
};
const CARD_METRICS: ReadonlySet<string> = new Set([LINES_LABEL, DEFINITIONS_LABEL, EDGES_LABEL]);
const metricChips = function metricChips(blocks: readonly Block[]): readonly string[] {
const metric = blocks.find(isMetric);
return metric === undefined
? []
: metric.metrics
.filter((entry) => CARD_METRICS.has(entry.label))
.map((entry) => entry.value + SPACE + entry.label.toLowerCase());
};
const renderFileCard = function renderFileCard(file: FileNode): Element {
const { chips, rest } = splitBlocks(file.sub.blocks ?? []);
const all = [...chips, ...metricChips(rest)];
return createElement("article", {
children: [treeLink(file, "filesystem-card-title"), ...(all.length === 0 ? [] : [renderChips(all)])],
className: "filesystem-card",
});
};
const renderFolderCard = function renderFolderCard(folder: FolderNode): Element {
const card = createElement("article", {
children: [treeLink(folder, "filesystem-card-title")],
className: "filesystem-card",
});
if (folder.section.intro !== undefined) {
card.append(fillMarkup(createElement("p", { className: "filesystem-card-text" }), folder.section.intro));
}
return card;
};
const renderListing = function renderListing(label: string, cards: readonly Element[]): readonly Element[] {
if (cards.length === 0) {
return [];
}
return [
createElement("h3", { className: "filesystem-listing-title", text: label }),
createElement("div", { children: cards, className: "filesystem-listing" }),
];
};
const renderFolderView = function renderFolderView(root: FolderNode, folder: FolderNode): Element {
const view = createElement("section", { attributes: { id: folder.id }, className: NODE_CLASS });
view.append(
renderCrumbs(root, folder),
createElement("h2", { className: "filesystem-node-title", text: folder.name }),
);
if (folder.section.intro !== undefined) {
view.append(fillMarkup(createElement("p", { className: "filesystem-intro" }), folder.section.intro));
}
appendChildren(view, (folder.section.blocks ?? []).map(renderNodeBlock));
appendChildren(view, renderListing(FOLDERS_LABEL, folder.folders.map(renderFolderCard)));
appendChildren(view, renderListing(FILES_LABEL, folder.files.map(renderFileCard)));
return view;
};
const renderFileView = function renderFileView(root: FolderNode, file: FileNode): Element {
const { chips, rest } = splitBlocks(file.sub.blocks ?? []);
const view = createElement("article", { attributes: { id: file.id }, className: NODE_CLASS });
view.append(renderCrumbs(root, file), createElement("h2", { className: "filesystem-node-title", text: file.name }));
if (chips.length > 0) {
view.append(renderChips(chips));
}
appendChildren(view, rest.map(renderNodeBlock));
return view;
};
export const renderNode = function renderNode(root: FolderNode, node: TreeNode): Element {
return isFolder(node) ? renderFolderView(root, node) : renderFileView(root, node);
};