Concept jsx usage
This commit is contained in:
parent
bf444ccb1a
commit
d769e298b1
7 changed files with 92 additions and 20 deletions
170
src/render/html/index.tsx
Normal file
170
src/render/html/index.tsx
Normal file
|
@ -0,0 +1,170 @@
|
|||
import { Playbill } from "@proscenium/playbill";
|
||||
import sortBy from "lodash-es/sortBy";
|
||||
import { html, renderMarkdown } 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";
|
||||
import { renderToString } from "react-dom/server";
|
||||
|
||||
interface HTMLRenderOptions {
|
||||
styles?: string;
|
||||
}
|
||||
|
||||
export async function renderPlaybillToHTML(
|
||||
playbillToRender: Playbill,
|
||||
opts: HTMLRenderOptions = {},
|
||||
): Promise<string> {
|
||||
// Make a copy of the playbill to avoid modifying the original
|
||||
// and compile all description markdown
|
||||
const playbill = Playbill.fromSerialized(playbillToRender.serialize());
|
||||
await playbill.processComponents(renderMarkdown);
|
||||
|
||||
// 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 = rulesByOrder.map(RuleSection);
|
||||
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">
|
||||
${renderToString(rules)}
|
||||
</article>
|
||||
|
||||
<article id="glossary" class="view">
|
||||
${glossaryHTML}
|
||||
</article>
|
||||
|
||||
<article id="resources" class="view">
|
||||
${resources}
|
||||
</article>
|
||||
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
return doc;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue