presentation/renderers/grammar.renderer.ts
presentation/renderers/grammar.renderer.ts is a file in Bane's Lab Site. 127 lines of code and 20 definitions.
import { CHECKED_ICON, CORRECT_ICON, WRONG_ICON } from "#configuration/icons/grammar.icons";
import { CORRECT_LABEL, WRONG_LABEL } from "#configuration/strings/tab.strings";
import type {
CheckBlock,
CompareBlock,
Comparison,
DiagramBlock,
GrammarBlock,
Keyword,
KeywordBlock,
Signature,
TypeBlock,
} from "#types/grammar.types";
import { appendChildren, createElement } from "#core/factories/element.factory";
import { ICON_BASE_CLASS } from "#configuration/icons/element.icons";
import { SPACE } from "#configuration/constants/document.constants";
import { fillMarkup } from "#presentation/renderers/text.renderer";
const CHECKED_CLASS = "checked";
const WRONG_CLASS = "compare-wrong";
const CORRECT_CLASS = "compare-correct";
const renderKeyword = function renderKeyword(keyword: Keyword | string): Element {
if (typeof keyword === "string") {
return createElement("code", { className: "keyword", text: keyword });
}
const tooltip = createElement("div", {
children: [createElement("span", { className: "keyword-tooltip-text", text: keyword.description })],
className: "keyword-tooltip",
});
if (keyword.example !== undefined) {
tooltip.append(createElement("code", { className: "keyword-tooltip-example", text: keyword.example }));
}
return createElement("div", {
children: [createElement("code", { className: "keyword interactive", text: keyword.name }), tooltip],
className: "keyword-wrapper",
});
};
const renderKeywords = function renderKeywords(block: KeywordBlock): Element {
const grid = createElement("div", { className: "keyword-grid" });
appendChildren(grid, block.keywords.map(renderKeyword));
return grid;
};
const renderVerdict = function renderVerdict(className: string, icon: string, label: string, code: string): Element {
const caption = createElement("span", { className: "compare-label" });
caption.append(createElement("i", { className: `${ICON_BASE_CLASS} ${icon}` }), SPACE + label);
return createElement("div", {
children: [caption, createElement("code", { className: "compare-code", text: code })],
className,
});
};
const renderComparison = function renderComparison(entry: Comparison): Element {
return createElement("div", {
children: [
createElement("span", { className: "compare-issue", text: entry.issue }),
renderVerdict(WRONG_CLASS, WRONG_ICON, WRONG_LABEL, entry.wrong),
renderVerdict(CORRECT_CLASS, CORRECT_ICON, CORRECT_LABEL, entry.correct),
],
className: "compare-card",
});
};
const renderCompare = function renderCompare(block: CompareBlock): Element {
const grid = createElement("div", { className: "compare-grid" });
appendChildren(grid, block.entries.map(renderComparison));
return grid;
};
const renderCheckItem = function renderCheckItem(item: string): Element {
const box = createElement("span", {
children: [createElement("i", { className: `${ICON_BASE_CLASS} ${CHECKED_ICON}` })],
className: "check-box",
});
const element = createElement("div", {
children: [box, fillMarkup(createElement("span", { className: "check-label" }), item)],
className: "check-item",
});
element.addEventListener("click", () => {
element.classList.toggle(CHECKED_CLASS);
});
return element;
};
const renderChecks = function renderChecks(block: CheckBlock): Element {
const grid = createElement("div", { className: "check-grid" });
appendChildren(grid, block.items.map(renderCheckItem));
return grid;
};
const renderSignature = function renderSignature(signature: Signature): Element {
return createElement("div", {
children: [
createElement("code", { className: "type-name", text: signature.name }),
createElement("span", { className: "type-verb", text: signature.verb }),
createElement("span", { className: "type-purpose", text: signature.purpose }),
],
className: "type-card",
});
};
const renderTypes = function renderTypes(block: TypeBlock): Element {
const grid = createElement("div", { className: "type-grid" });
appendChildren(grid, block.types.map(renderSignature));
return grid;
};
const renderDiagram = function renderDiagram(block: DiagramBlock): Element {
const className = block.grammar === true ? "diagram grammar" : "diagram";
return createElement("div", {
children: [createElement("pre", { children: [createElement("code", { text: block.text })], className })],
className: "diagram-block",
});
};
export const renderGrammarBlock = function renderGrammarBlock(block: GrammarBlock): Element {
switch (block.kind) {
case "keyword": {
return renderKeywords(block);
}
case "compare": {
return renderCompare(block);
}
case "check": {
return renderChecks(block);
}
case "type": {
return renderTypes(block);
}
case "diagram": {
return renderDiagram(block);
}
default: {
return renderDiagram(block);
}
}
};