# presentation/renderers/card.renderer.ts

> 87 lines of code and 13 definitions.

Tree: Site tree
Language: typescript
Layer: product
Canonical: https://banes-lab.com/anatomy/tree#file-presentation-renderers-card-renderer-ts
Source text: https://banes-lab.com/assets/sources/source.dc67313af8270f1dc7c0bfa3b82e1ae7f3257db6ab67caf26a9012b3c71f9ddc.generated.txt

## Definitions

- `renderRules` (lexical_declaration, line 46)
- `renderItem` (lexical_declaration, line 37)
- `renderCardHeader` (lexical_declaration, line 21)
- `renderCards` (lexical_declaration, line 90, exported)
- `renderCard` (lexical_declaration, line 58)
- `renderFile` (lexical_declaration, line 13)
- `PERMITTED_CLASS` (lexical_declaration, line 10)
- `RESTRICTED_CLASS` (lexical_declaration, line 11)
- `badges` (lexical_declaration, line 22)
- `titles` (lexical_declaration, line 27)
- `list` (lexical_declaration, line 47)
- `body` (lexical_declaration, line 59)
- `grid` (lexical_declaration, line 91, exported)

## Uses

- [core/factories/element.factory.ts](https://banes-lab.com/source/tree/core/factories/element.factory.ts.md)
- [presentation/renderers/element.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/element.renderer.ts.md)
- [presentation/renderers/text.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/text.renderer.ts.md)

## Used by

- [presentation/renderers/block.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/block.renderer.ts.md)

## Source

```typescript
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;
};
```
