presentation/renderers/site.renderer.ts
presentation/renderers/site.renderer.ts is a file in Bane's Lab Site. 112 lines of code and 26 definitions.
import {
CLOSING_SEPARATOR,
CONTACT_CLOSING,
INFORMATION_TITLE,
LINK_SEPARATOR,
MODEL_CLOSING,
PRIVACY_TITLE,
TERMS_TITLE,
USE_CLOSING,
} from "#configuration/strings/page.strings";
import { COPYRIGHT_PREFIX, COPYRIGHT_SUFFIX } from "#configuration/strings/company.strings";
import type { Closing, License } from "#types/site.types";
import { INFORMATION_PAGE, PRIVACY_PAGE, TERMS_PAGE } from "#core/ids/page.ids";
import { createExternalLink, createLink, createPageLink } from "#presentation/components/link.component";
import type { ClosingCell } from "#types/page.types";
import { FADE_IN } from "#configuration/constants/element.constants";
import { ICON_BASE_CLASS } from "#configuration/icons/element.icons";
import type { IconLink } from "#types/link.types";
import { PROFILE_LINKS } from "#configuration/icons/company.icons";
import { SPACE } from "#configuration/constants/document.constants";
import { animated } from "#presentation/renderers/element.renderer";
import { createElement } from "#core/factories/element.factory";
const CLOSING_STEP = 60;
const FOOTER_LINK_CLASS = "footer-link";
const closingTerm = function closingTerm(term: string, linked: boolean): HTMLElement {
const code = createElement("code", { text: term });
return linked ? createExternalLink(term, "closing-route", [code]) : code;
};
const stackedBody = function stackedBody(closing: Closing): HTMLElement {
return createElement("div", {
children: closing.terms.map((term) => createElement("span", { className: "closing-line", text: term })),
className: "closing-stack",
});
};
const routeBody = function routeBody(closing: Closing): HTMLElement {
const linked = closing.linked === true;
const body = createElement("p");
for (const [index, term] of closing.terms.entries()) {
if (index > 0) {
body.append(CLOSING_SEPARATOR);
}
body.append(term.includes(SPACE) ? term : closingTerm(term, linked));
}
return body;
};
const closingBody = function closingBody(closing: Closing): readonly HTMLElement[] {
const body = closing.stacked === true ? stackedBody(closing) : routeBody(closing);
if (closing.note === undefined) {
return [body];
}
return [createElement("p", { className: "closing-note", text: closing.note }), body];
};
const renderClosing = function renderClosing(cell: ClosingCell, delay: number): HTMLElement {
const { closing, tail } = cell;
const heading = createElement("h3", { children: [createElement("i", { className: closing.icon }), closing.title] });
return animated("div", { children: [heading, ...closingBody(closing), ...tail] }, FADE_IN, delay);
};
const renderClosings = function renderClosings(cells: readonly ClosingCell[]): HTMLElement {
return createElement("section", {
children: cells.map((cell, index) => renderClosing(cell, index * CLOSING_STEP)),
className: "site-closing",
});
};
const profileLink = function profileLink(link: IconLink): HTMLElement {
return createExternalLink(link.href, `${FOOTER_LINK_CLASS} profile-link`, [
createElement("i", { className: `${ICON_BASE_CLASS} ${link.icon}` }),
link.title,
]);
};
const linkRow = function linkRow(links: readonly HTMLElement[]): HTMLElement {
const joined = links.flatMap((link, index) => (index === 0 ? [link] : [LINK_SEPARATOR, link]));
return createElement("p", { children: joined, className: "link-row" });
};
const PLATFORM_PAGES: readonly (readonly [string, string])[] = [
[TERMS_PAGE, TERMS_TITLE],
[PRIVACY_PAGE, PRIVACY_TITLE],
[INFORMATION_PAGE, INFORMATION_TITLE],
];
const platformLinks = function platformLinks(): HTMLElement {
return linkRow(PLATFORM_PAGES.map(([page, title]) => createPageLink(page, FOOTER_LINK_CLASS, [title])));
};
const renderBadges = function renderBadges(license: License): readonly HTMLElement[] {
if (license.badges.length === 0) {
return [];
}
const images = license.badges.map((badge) =>
createElement("img", { attributes: { alt: badge.alt, src: badge.source }, className: "license-badge" }),
);
return [createExternalLink(license.href, "license-badges", images)];
};
const renderLicense = function renderLicense(license: License): HTMLElement {
const terms = createElement("p", { className: "site-license" });
terms.append(
license.lead,
createLink(license.href, FOOTER_LINK_CLASS, [license.name]),
SPACE,
...renderBadges(license),
);
return terms;
};
export const copyrightText = function copyrightText(): string {
return COPYRIGHT_PREFIX + String(new Date().getFullYear()) + COPYRIGHT_SUFFIX;
};
export const renderSiteFooter = function renderSiteFooter(license?: License): Element {
const notice = license === undefined ? [] : [renderLicense(license)];
const closings = renderClosings([
{ closing: MODEL_CLOSING, tail: [] },
{ closing: USE_CLOSING, tail: [platformLinks(), ...notice] },
{ closing: CONTACT_CLOSING, tail: [linkRow(PROFILE_LINKS.map(profileLink))] },
]);
return createElement("footer", { children: [closings], className: "site-footer" });
};