presentation/renderers/section.renderer.ts
presentation/renderers/section.renderer.ts is a file in Bane's Lab Site. 92 lines of code and 23 definitions.
import { FADE_IN, FADE_IN_UP } from "#configuration/constants/element.constants";
import {
LABEL_GROUP_SIZE,
LABEL_SEPARATOR,
SECTION_LETTERS,
SUBSECTION_INFIX,
} from "#configuration/constants/tab.constants";
import type { Section, Subsection } from "#types/document.types";
import { appendChildren, createElement } from "#core/factories/element.factory";
import { COPY_SECTION_TITLE } from "#configuration/strings/tab.strings";
import { ICON_BASE_CLASS } from "#configuration/icons/element.icons";
import { IGNORED_SELECTORS } from "#configuration/constants/document.constants";
import { animated } from "#presentation/renderers/element.renderer";
import { convertText } from "#core/converters/text.converter";
import { createCopyButton } from "#presentation/components/clipboard.component";
import { fillMarkup } from "#presentation/renderers/text.renderer";
import { renderBlock } from "#presentation/renderers/block.renderer";
const CALLOUT = "callout";
const GRID = "grid";
const DELAY_INTRO = 50;
export const subsectionId = function subsectionId(section: string, index: number, own?: string): string {
return own ?? section + SUBSECTION_INFIX + String(index);
};
const sectionLetter = function sectionLetter(sectionIndex: number): string {
const base = SECTION_LETTERS.length;
const last = SECTION_LETTERS.charAt(sectionIndex % base);
const rest = Math.floor(sectionIndex / base);
return rest === 0 ? last : sectionLetter(rest - 1) + last;
};
export const sectionLabel = function sectionLabel(sectionIndex: number): string {
return sectionLetter(sectionIndex) + String(1);
};
export const subsectionLabel = function subsectionLabel(sectionIndex: number, subIndex: number): string {
const group = Math.floor(subIndex / LABEL_GROUP_SIZE) + 1;
const position = (subIndex % LABEL_GROUP_SIZE) + 1;
return sectionLetter(sectionIndex) + String(group) + LABEL_SEPARATOR + String(position);
};
const renderSubsectionTitle = function renderSubsectionTitle(sub: Subsection, label: string | undefined): Element {
const title = createElement("h3", { className: "subsection-title", text: sub.title });
if (label !== undefined) {
title.append(createElement("span", { className: "subsection-symbol", text: label }));
}
return title;
};
const renderSubsection = function renderSubsection(sub: Subsection, id: string, label: string | undefined): Element {
const wrapper = animated("div", { attributes: { id }, className: "tab-subsection" }, FADE_IN_UP);
wrapper.append(renderSubsectionTitle(sub, label));
if (sub.content !== undefined) {
wrapper.append(fillMarkup(createElement("p", { className: "section-text" }), sub.content));
}
const blocks = (sub.blocks ?? []).map(renderBlock);
if (sub.layout === GRID) {
wrapper.append(createElement("div", { children: blocks, className: "tab-subsection-grid" }));
return wrapper;
}
appendChildren(wrapper, blocks);
return wrapper;
};
const renderTitle = function renderTitle(section: Section, target: Element, label: string | undefined): Element {
const wrapper = createElement("div", { className: "section-title-wrapper" });
if (section.layout === CALLOUT) {
wrapper.append(createElement("i", { className: `${ICON_BASE_CLASS} ${section.icon} callout-icon` }));
}
const title = animated("h2", { className: "section-title", text: section.title }, FADE_IN_UP);
if (label !== undefined) {
title.append(createElement("span", { className: "subsection-symbol", text: label }));
}
appendChildren(wrapper, [
title,
createCopyButton(() => convertText(target, IGNORED_SELECTORS), "copy-button medium", COPY_SECTION_TITLE),
]);
return wrapper;
};
export const renderTabSection = function renderTabSection(section: Section, sectionIndex: number): Element {
const callout = section.layout === CALLOUT;
const className = callout ? "tab-section callout" : "tab-section";
const element = createElement("section", { attributes: { id: section.id }, className });
element.append(renderTitle(section, element, callout ? undefined : sectionLabel(sectionIndex)));
if (section.intro !== undefined) {
element.append(fillMarkup(animated("p", { className: "section-text" }, FADE_IN, DELAY_INTRO), section.intro));
}
appendChildren(element, (section.blocks ?? []).map(renderBlock));
const subsections = section.subsections.map((sub, index) =>
renderSubsection(
sub,
subsectionId(section.id, index, sub.id),
callout ? undefined : subsectionLabel(sectionIndex, index),
),
);
element.append(createElement("div", { children: subsections, className: "tab-section-grid" }));
return element;
};