feat(banners-lib): basic title and subtitle manipulation

This commit is contained in:
Guz013
2023-11-30 14:16:20 -03:00
parent 9f71f741e8
commit bd580db9f5
4 changed files with 138 additions and 2 deletions

View File

@@ -12,6 +12,7 @@
</head>
<body>
<a href="packages/banners/test.html">Test</a>
<h1> Hello, world </h1>
</body>

View File

@@ -1,2 +1,97 @@
// eslint-disable-next-line no-console
console.log('Hello world from the package!');
/**
* @typedef {import('./index.js').BannerObject} BannerObject
*/
import getLocalLayout from './layouts.js';
/**
* @param {Readonly<string>} string - The string to be converted.
* @param {Document} document - The document API to be used.
* @returns {HTMLElement} - The DOM of the string.
*/
function stringToHtml(string, document) {
const tmp = document.createElement('template');
tmp.innerHTML = string;
/** @type {HTMLElement} */
const dom = tmp.children[0];
return dom;
}
/**
* @param {HTMLElement} element - The element to be converted to string.
* @param {Document} document - The document API to be used.
* @returns {string} - The resulting string.
*/
function htmlToString(element, document) {
const tmp = document.createElement('template');
tmp.appendChild(element);
return tmp.innerHTML;
}
/**
* @typedef {{
* modify(query: string, callback: (el: Element | null) => T) => T
* }} DOMHelper
* @param {HTMLElement} element - The element to be manipulated.
* @returns {DOMHelper}
*/
function domHelper(element) {
return {
/**
* @template T
* @param {string} query - The query selector to find the element.
* @param {(el: Element | null) => T} callback - Callback to modify the element.
* @returns {T} - The return value of the callback.
* @throws {Error} - Throws if the element is not found.
*/
modify(query, callback) {
const el = element.querySelector(query);
return callback(el);
},
};
}
/**
* @param {BannerObject} object - The Banner Object to be generated from.
* @returns {Promise<string>} - The SVG of the banner.
*/
async function banner(object) {
/** @type {Document} */
// @ts-expect-error because Document is not compatible with Readonly<Document>
const doc = object.lib?.document ?? globalThis.document;
/** @type {Readonly<string>} */
const svg = await getLocalLayout('vertical');
const dom = stringToHtml(svg, doc);
const helper = domHelper(dom);
helper.modify('[data-banner-class="title"] > tspan', (el) => {
if (!el) return;
el.innerHTML = object.title;
});
helper.modify('[data-banner-class="subtitle"] > tspan', (el) => {
if (!el) return;
el.innerHTML = object.subtitle ?? '';
});
return htmlToString(dom, doc);
}
/**
* Test function.
*/
async function test() {
const testBanner = await banner({
lib: {
// @ts-expect-error because Document is not DeepReadonly<Document>
document: new Document(),
fetch,
},
title: 'Hello, world',
});
const body = globalThis.document.getElementsByTagName('body')[0];
body.innerHTML = testBanner;
}
await test();
export default banner;

View File

@@ -0,0 +1,27 @@
/**
* Imports a local layout from the static folder.
*
* @param {import('./types.d.ts').BuiltinLayouts} layout - The banner layout.
* @param {boolean} [rtl] - Is the layout right-to-left?
* @returns {Promise<string>} - The SVG string of the layout file.
*/
async function getLocalLayout(layout, rtl = false) {
let layoutFile;
/* eslint-disable import/no-relative-parent-imports */
switch (layout) {
case 'vertical': {
layoutFile = await import('../static/vertical.svg.js');
break;
}
default: {
if (rtl)
layoutFile = await import('../static/horizontal-rtl.svg.js');
layoutFile = await import('../static/horizontal.svg.js');
}
}
/* eslint-enable */
return layoutFile.default;
}
export default getLocalLayout;

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="module" src="src/index.js"></script>
</head>
<body></body>
</html>