core/evaluators/page.evaluator.ts
core/evaluators/page.evaluator.ts is a file in Bane's Lab Social Share. 59 lines of code and 22 definitions.
import type { ColumnBox, ColumnEntry, ColumnRow, ColumnSpec, FrameContext } from "#types/card.types";
import { HOME_PATH, pagePath } from "@banes-lab/web/core/assets/link.assets.ts";
import { MONO_ADVANCE } from "#configuration/constants/card.constants";
import { SITE_HOST } from "#configuration/data/site.data";
export const pageAddress = function pageAddress(page: string): string {
const path = pagePath(page);
return path === HOME_PATH ? SITE_HOST : SITE_HOST + path;
};
const WORD_SEPARATOR = " ";
const HALF = 2;
export const wrapCount = function wrapCount(text: string, columns: number): number {
const limit = Math.max(1, Math.floor(columns));
let lines = 1;
let used = 0;
for (const word of text.split(WORD_SEPARATOR)) {
const needed = used === 0 ? word.length : used + 1 + word.length;
if (needed <= limit || used === 0) {
used = needed;
} else {
lines += 1;
used = word.length;
}
}
return lines;
};
const rowHeight = function rowHeight(spec: ColumnSpec, entry: ColumnEntry, frame: FrameContext): number {
const row = spec.rows[entry.row];
const size = row.size * frame.profile.width;
if (entry.text.length === 0) {
return size / frame.profile.height;
}
const columns = (spec.width * frame.profile.width) / (MONO_ADVANCE * size);
return (wrapCount(entry.text, columns) * size * row.leading) / frame.profile.height;
};
const rowX = function rowX(spec: ColumnSpec, width: number): number {
if (spec.align === "center") {
return spec.x + (spec.width - width) / HALF;
}
return spec.align === "right" ? spec.x + spec.width - width : spec.x;
};
export const columnOf = function columnOf(
spec: ColumnSpec,
entries: readonly ColumnEntry[],
frame: FrameContext,
): ReadonlyMap<ColumnRow, ColumnBox> {
const heights = entries.map((entry) => rowHeight(spec, entry, frame));
const gaps = entries.map((entry, index) => (index === 0 ? 0 : spec.rows[entry.row].gap));
const total = heights.reduce((sum, height, index) => sum + height + (gaps[index] ?? 0), 0);
let top = spec.y - total / HALF;
const boxes = new Map<ColumnRow, ColumnBox>();
entries.forEach((entry, index) => {
top += gaps[index] ?? 0;
const width = spec.rows[entry.row].width ?? spec.width;
const height = heights[index] ?? 0;
boxes.set(entry.row, { height, width, x: rowX(spec, width), y: top });
top += height;
});
return boxes;
};