presentation/components/code.component.ts
presentation/components/code.component.ts is a file in Bane's Lab Site. 89 lines of code and 12 definitions.
import {
CODE_LINE_ATTRIBUTE,
CODE_LINE_CLASS,
CODE_LINE_MARKED_CLASS,
} from "#configuration/constants/syntax.constants";
import {
COLLAPSED_LINE_LIMIT,
EXPANDABLE_CLASS,
LANGUAGE_ATTRIBUTE,
LINE_BREAK,
} from "#configuration/constants/code.constants";
import { LINES_SUFFIX, VIEW_FULL_CODE_TITLE } from "#configuration/strings/code.strings";
import { PANEL_CLASS, PANEL_REVEAL_EVENT } from "#configuration/constants/panel.constants";
import { SCROLL_BEHAVIOR, SCROLL_BLOCK } from "#configuration/constants/tab.constants";
import { appendChildren, createElement } from "#core/factories/element.factory";
import { createCopyButton } from "#presentation/components/clipboard.component";
import { createExpandButton } from "#presentation/components/overlay.component";
import { createPanel } from "#presentation/components/panel.component";
import { renderSyntax } from "#presentation/renderers/syntax.renderer";
const createCodeBody = function createCodeBody(code: string, language: string, className: string): HTMLElement {
return createPanel(renderSyntax(code, language), className, "origin").element;
};
export const revealLine = function revealLine(scope: Element, line: number): boolean {
for (const marked of scope.querySelectorAll(`.${CODE_LINE_CLASS}.${CODE_LINE_MARKED_CLASS}`)) {
marked.classList.remove(CODE_LINE_MARKED_CLASS);
}
const span = scope.querySelector<HTMLElement>(`.${CODE_LINE_CLASS}[${CODE_LINE_ATTRIBUTE}="${String(line)}"]`);
if (span === null) {
return false;
}
span.classList.add(CODE_LINE_MARKED_CLASS);
const panel = span.closest(`.${PANEL_CLASS}`);
if (panel === null) {
span.scrollIntoView({ behavior: SCROLL_BEHAVIOR, block: SCROLL_BLOCK });
} else {
panel.dispatchEvent(new CustomEvent(PANEL_REVEAL_EVENT, { detail: span.offsetTop }));
}
return true;
};
export const createPlainCodeBlock = function createPlainCodeBlock(
code: string,
title: string,
language: string,
): HTMLElement {
const header = createElement("div", {
children: [
createElement("span", { className: "code-title", text: title }),
createElement("div", { children: [createCopyButton(() => code, "code-copy")], className: "code-actions" }),
],
className: "code-header",
});
const block = createElement("pre", {
attributes: { [LANGUAGE_ATTRIBUTE]: language },
className: "code-block code-plain",
});
appendChildren(block, [
header,
createElement("div", { children: [renderSyntax(code, language)], className: "code-whole" }),
]);
return block;
};
export const createCodeBlock = function createCodeBlock(code: string, title: string, language: string): HTMLElement {
const lines = code.split(LINE_BREAK).length;
const expandable = lines > COLLAPSED_LINE_LIMIT;
const actions = createElement("div", { className: "code-actions" });
if (expandable) {
const count = createElement("span", { text: String(lines) + LINES_SUFFIX });
actions.append(
createExpandButton(
"code-expand",
VIEW_FULL_CODE_TITLE,
title,
() => createCodeBody(code, language, "code-full"),
[count],
),
);
}
actions.append(createCopyButton(() => code, "code-copy"));
const header = createElement("div", {
children: [createElement("span", { className: "code-title", text: title }), actions],
className: "code-header",
});
const block = createElement("pre", {
attributes: { [LANGUAGE_ATTRIBUTE]: language },
className: expandable ? `code-block ${EXPANDABLE_CLASS}` : "code-block",
});
appendChildren(block, [header, createCodeBody(code, language, "code-content")]);
return block;
};