164 lines
4.4 KiB
TypeScript
164 lines
4.4 KiB
TypeScript
import type { Playbill } from "@proscenium/playbill";
|
|
import sortBy from "lodash-es/sortBy";
|
|
import { html } from "#lib";
|
|
import { GlossaryTable } from "./component/glossary";
|
|
import { PageHeader } from "./component/header";
|
|
import { ItemCard } from "./component/item";
|
|
import { MethodSection } from "./component/method";
|
|
import { ResourceSection } from "./component/resource";
|
|
import { RuleSection } from "./component/rule";
|
|
import { SpeciesSection } from "./component/species";
|
|
|
|
interface HTMLRenderOptions {
|
|
styles?: string;
|
|
}
|
|
|
|
export async function renderPlaybillToHTML(
|
|
playbill: Playbill,
|
|
opts: HTMLRenderOptions = {},
|
|
): Promise<string> {
|
|
// Render various resources
|
|
const resources = (
|
|
await Promise.all(Object.values(playbill.resources).map(ResourceSection))
|
|
).join("\n");
|
|
|
|
const methods = (
|
|
await Promise.all(
|
|
Object.values(playbill.methods).map((method) => {
|
|
return MethodSection(method, playbill);
|
|
}),
|
|
)
|
|
).join("\n");
|
|
|
|
const species = (
|
|
await Promise.all(
|
|
Object.values(playbill.species).map((species) => {
|
|
return SpeciesSection(species, playbill);
|
|
}),
|
|
)
|
|
).join("\n");
|
|
|
|
const items = (
|
|
await Promise.all(
|
|
Object.values(playbill.items).map((item) => {
|
|
return ItemCard(item);
|
|
}),
|
|
)
|
|
).join("\n");
|
|
|
|
const rulesByOrder = sortBy(Object.values(playbill.rules), "order");
|
|
const rules = (await Promise.all(rulesByOrder.map(RuleSection))).join("\n");
|
|
const glossaryHTML = await GlossaryTable(playbill.glossary);
|
|
|
|
// Prepare stylesheet
|
|
const css = opts.styles ? html`<style>${opts.styles}</style>` : "";
|
|
|
|
// Main document
|
|
const doc = html`
|
|
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Playbill: ${playbill.name}</title>
|
|
${css}
|
|
|
|
<script>
|
|
function removeHash() {
|
|
history.pushState("", document.title, window.location.pathname);
|
|
}
|
|
|
|
function setHash(hash) {
|
|
if (hash.length > 0) {
|
|
history.pushState(null, null, "#" + hash);
|
|
} else {
|
|
removeHash();
|
|
}
|
|
}
|
|
|
|
function hideAllViews() {
|
|
document.querySelectorAll(".view").forEach((view) => {
|
|
view.style.display = "none";
|
|
});
|
|
}
|
|
|
|
function showAllViews() {
|
|
document.querySelectorAll(".view").forEach((view) => {
|
|
view.style.display = "block";
|
|
});
|
|
setHash("");
|
|
}
|
|
|
|
function showView(viewId) {
|
|
document.getElementById(viewId).style.display = "block";
|
|
setHash(viewId);
|
|
}
|
|
|
|
|
|
function hideAllAndShow(viewId) {
|
|
hideAllViews();
|
|
showView(viewId);
|
|
}
|
|
|
|
function navigateFromHash() {
|
|
const hash = window.location.hash.slice(1);
|
|
if (hash.length > 0) {
|
|
const view = document.getElementById(hash);
|
|
|
|
if (view !== null) {
|
|
hideAllAndShow(hash);
|
|
} else {
|
|
showAllViews();
|
|
}
|
|
} else {
|
|
showAllViews();
|
|
}
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", navigateFromHash());
|
|
window.addEventListener("hashchange", navigateFromHash())
|
|
</script>
|
|
</head>
|
|
<body>
|
|
${await PageHeader(playbill)}
|
|
<blockquote class="overview"><p>${playbill.description}</p></blockquote>
|
|
<nav>
|
|
<button onclick="hideAllAndShow('species')" id="species-nav">Species</button>
|
|
<button onclick="hideAllAndShow('methods')" id="methods-nav">Methods</button>
|
|
<button onclick="hideAllAndShow('items')" id="items-nav">Items</button>
|
|
<button onclick="hideAllAndShow('rules')" id="rules-nav">Rulebook</button>
|
|
<button onclick="hideAllAndShow('glossary')" id="glossary-nav">Glossary</button>
|
|
<button onclick="hideAllAndShow('resources')" id="resources-nav">Resources</button>
|
|
<button onclick="showAllViews()" id="all-nav">Show All</button>
|
|
</nav>
|
|
<article id="species" class="view">
|
|
${species}
|
|
</article>
|
|
|
|
<article id="methods" class="view">
|
|
${methods}
|
|
</article>
|
|
|
|
<article id="items" class="view">
|
|
${items}
|
|
</article>
|
|
|
|
<article id="rules" class="view">
|
|
${rules}
|
|
</article>
|
|
|
|
<article id="glossary" class="view">
|
|
${glossaryHTML}
|
|
</article>
|
|
|
|
<article id="resources" class="view">
|
|
${resources}
|
|
</article>
|
|
|
|
</article>
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
return doc;
|
|
}
|