# presentation/renderers/document.renderer.ts

> 92 lines of code and 17 definitions.

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

## Definitions

- `renderHeader` (lexical_declaration, line 17)
- `renderFooter` (lexical_declaration, line 66)
- `renderDocumentSections` (lexical_declaration, line 76, exported)
- `renderBody` (lexical_declaration, line 72)
- `renderContentsLink` (lexical_declaration, line 38)
- `renderDocument` (lexical_declaration, line 83, exported)
- `renderContents` (lexical_declaration, line 55)
- `header` (lexical_declaration, line 18)
- `dates` (lexical_declaration, line 28)
- `link` (lexical_declaration, line 43)
- `list` (lexical_declaration, line 56)
- `footer` (lexical_declaration, line 67)
- `pairs` (lexical_declaration, line 84, exported)
- `target` (lexical_declaration, line 85, exported)
- `rendered` (lexical_declaration, line 88, exported)
- `links` (lexical_declaration, line 89, exported)
- `layout` (lexical_declaration, line 90, exported)

## Uses

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

## Used by

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

## Source

```typescript
import {
    CONTENTS_TITLE,
    EFFECTIVE_LABEL,
    UPDATED_LABEL,
    VERSION_PREFIX,
} from "#configuration/strings/document.strings";
import type { DocumentMeta, Section } from "#types/document.types";
import { FADE_IN, FADE_IN_UP } from "#configuration/constants/element.constants";
import { appendChildren, createElement } from "#core/factories/element.factory";
import { ANCHOR_PREFIX } from "#configuration/constants/document.constants";
import { animated } from "#presentation/renderers/element.renderer";
import { fillMarkup } from "#presentation/renderers/text.renderer";
import { observeSections } from "#core/observers/document.observer";
import { renderChapterSection } from "#presentation/renderers/chapter.renderer";
import { sectionLabel } from "#presentation/renderers/section.renderer";

const renderHeader = function renderHeader(meta: DocumentMeta): Element {
    const header = animated("header", { className: "tab-page-header" }, FADE_IN_UP);
    if (meta.emblem !== undefined) {
        header.append(
            createElement("img", { attributes: { alt: meta.title, src: meta.emblem }, className: "tab-page-emblem" }),
        );
    }
    header.append(createElement("h1", { className: "tab-page-title", text: meta.title }));
    if (meta.intro !== undefined) {
        header.append(createElement("p", { className: "tab-page-subtitle", text: meta.intro }));
    }
    const dates = createElement("p", { className: "document-dates" });
    appendChildren(dates, [
        createElement("span", { text: EFFECTIVE_LABEL + meta.effectiveDate }),
        createElement("span", { text: UPDATED_LABEL + meta.lastUpdated }),
        createElement("span", { text: VERSION_PREFIX + meta.version }),
    ]);
    header.append(dates);
    return header;
};

const renderContentsLink = function renderContentsLink(
    section: Section,
    index: number,
    target: Element,
): HTMLAnchorElement {
    const link = createElement("a", { attributes: { href: ANCHOR_PREFIX + section.id }, className: "contents-link" });
    appendChildren(link, [
        createElement("span", { className: "contents-mark", text: sectionLabel(index) }),
        createElement("span", { text: section.title }),
    ]);
    link.addEventListener("click", (click) => {
        click.preventDefault();
        target.scrollIntoView({ behavior: "smooth", block: "start" });
    });
    return link;
};

const renderContents = function renderContents(links: readonly Element[]): Element {
    const list = createElement("ul", {
        children: links.map((link) => createElement("li", { children: [link], className: "contents-item" })),
        className: "contents-list",
    });
    return createElement("nav", {
        children: [createElement("p", { className: "contents-title", text: CONTENTS_TITLE }), list],
        className: "document-contents",
    });
};

const renderFooter = function renderFooter(meta: DocumentMeta): Element {
    const footer = animated("footer", { className: "document-footer" }, FADE_IN);
    footer.append(fillMarkup(createElement("p", { className: "document-closing" }), meta.closing));
    return footer;
};

const renderBody = function renderBody(sections: readonly Element[]): Element {
    return createElement("div", { children: sections, className: "chapter document-body" });
};

export const renderDocumentSections = function renderDocumentSections(sections: readonly Section[]): Element {
    return createElement("article", {
        children: [renderBody(sections.map(renderChapterSection))],
        className: "document",
    });
};

export const renderDocument = function renderDocument(meta: DocumentMeta, sections: readonly Section[]): Element {
    const pairs = sections.map((section, index) => {
        const target = renderChapterSection(section, index);
        return { link: renderContentsLink(section, index, target), target };
    });
    const rendered = pairs.map((pair) => pair.target);
    const links = pairs.map((pair) => pair.link);
    const layout = createElement("div", {
        children: [renderContents(links), renderBody(rendered)],
        className: "document-layout",
    });
    void observeSections(rendered, links);
    return createElement("article", {
        children: [renderHeader(meta), layout, renderFooter(meta)],
        className: "document",
    });
};
```
