presentation/renderers/card.renderer.ts

presentation/renderers/card.renderer.ts is a file in Bane's Lab Site. 87 lines of code and 13 definitions.

import type { Card, CardBlock, CardFile } from "#types/block.types";
import { PERMITTED_ICON, RESTRICTED_ICON } from "#configuration/icons/card.icons";
import { PERMITTED_TITLE, RESTRICTED_TITLE } from "#configuration/strings/card.strings";
import { appendChildren, createElement } from "#core/factories/element.factory";
import { FADE_IN_UP } from "#configuration/constants/element.constants";
import { ICON_BASE_CLASS } from "#configuration/icons/element.icons";
import { animated } from "#presentation/renderers/element.renderer";
import { fillMarkup } from "#presentation/renderers/text.renderer";

const PERMITTED_CLASS = "permitted";
const RESTRICTED_CLASS = "restricted";

const renderFile = function renderFile(file: CardFile): Element {
    return createElement("a", {
        attributes: { download: file.name, href: file.href, title: file.title },
        children: [createElement("i", { className: `${ICON_BASE_CLASS} ${file.icon}` })],
        className: "block-card-file",
    });
};

const renderCardHeader = function renderCardHeader(card: Card): Element {
    const badges = createElement("div", {
        children: [createElement("span", { className: "block-card-badge", text: card.status })],
        className: "block-card-badges",
    });
    appendChildren(badges, (card.files ?? []).map(renderFile));
    const titles = createElement("div", {
        children: [createElement("h3", { className: "block-card-title", text: card.title }), badges],
        className: "block-card-titles",
    });
    return createElement("div", {
        children: [createElement("i", { className: `${card.icon} block-card-icon` }), titles],
        className: "block-card-header",
    });
};

const renderItem = function renderItem(item: string, icon: string): Element {
    return createElement("li", {
        children: [
            createElement("i", { className: `${ICON_BASE_CLASS} ${icon}` }),
            fillMarkup(createElement("span", {}), item),
        ],
    });
};

const renderRules = function renderRules(items: readonly string[], title: string, tone: string, icon: string): Element {
    const list = createElement("ul", { className: `block-card-rules ${tone}` });
    appendChildren(
        list,
        items.map((item) => renderItem(item, icon)),
    );
    return createElement("div", {
        children: [createElement("h4", { className: "block-card-rules-title", text: title }), list],
        className: "block-card-group",
    });
};

const renderCard = function renderCard(card: Card): Element {
    const body = createElement("div", { className: "block-card-body" });
    appendChildren(body, [
        createElement("code", { className: "block-card-spdx", text: card.spdx }),
        fillMarkup(createElement("p", { className: "block-card-description" }), card.description),
    ]);
    if (card.permitted.length > 0) {
        body.append(renderRules(card.permitted, PERMITTED_TITLE, PERMITTED_CLASS, PERMITTED_ICON));
    }
    if (card.restricted.length > 0) {
        body.append(renderRules(card.restricted, RESTRICTED_TITLE, RESTRICTED_CLASS, RESTRICTED_ICON));
    }
    if (card.action !== undefined) {
        body.append(
            createElement("a", {
                attributes: { href: card.action.href },
                className: "block-card-action",
                text: card.action.text,
            }),
        );
    }
    return animated(
        "div",
        {
            attributes: { id: card.id },
            children: [renderCardHeader(card), body],
            className: `block-card ${card.accent}`,
        },
        FADE_IN_UP,
    );
};

export const renderCards = function renderCards(block: CardBlock): Element {
    const grid = createElement("div", { className: "block-cards" });
    appendChildren(grid, block.cards.map(renderCard));
    return grid;
};