Concept jsx usage
This commit is contained in:
parent
bf444ccb1a
commit
d769e298b1
7 changed files with 92 additions and 20 deletions
19
bun.lock
19
bun.lock
|
@ -6,8 +6,11 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@proscenium/playbill": "link:@proscenium/playbill",
|
"@proscenium/playbill": "link:@proscenium/playbill",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
|
"classnames": "^2.5.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"marked": "^15.0.7",
|
"marked": "^15.0.7",
|
||||||
|
"react": "^19.0.0",
|
||||||
|
"react-dom": "^19.0.0",
|
||||||
"slugify": "^1.6.6",
|
"slugify": "^1.6.6",
|
||||||
"yaml": "^2.7.0",
|
"yaml": "^2.7.0",
|
||||||
"zod": "^3.24.1",
|
"zod": "^3.24.1",
|
||||||
|
@ -16,6 +19,8 @@
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/react": "^19.0.11",
|
||||||
|
"@types/react-dom": "^19.0.4",
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
|
@ -51,16 +56,30 @@
|
||||||
|
|
||||||
"@types/node": ["@types/node@22.13.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw=="],
|
"@types/node": ["@types/node@22.13.10", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw=="],
|
||||||
|
|
||||||
|
"@types/react": ["@types/react@19.0.11", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-vrdxRZfo9ALXth6yPfV16PYTLZwsUWhVjjC+DkfE5t1suNSbBrWC9YqSuuxJZ8Ps6z1o2ycRpIqzZJIgklq4Tw=="],
|
||||||
|
|
||||||
|
"@types/react-dom": ["@types/react-dom@19.0.4", "", { "peerDependencies": { "@types/react": "^19.0.0" } }, "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg=="],
|
||||||
|
|
||||||
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
|
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
|
||||||
|
|
||||||
"bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="],
|
"bun-types": ["bun-types@1.2.5", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-3oO6LVGGRRKI4kHINx5PIdIgnLRb7l/SprhzqXapmoYkFl5m4j6EvALvbDVuuBFaamB46Ap6HCUxIXNLCGy+tg=="],
|
||||||
|
|
||||||
"chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
"chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
||||||
|
|
||||||
|
"classnames": ["classnames@2.5.1", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="],
|
||||||
|
|
||||||
|
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||||
|
|
||||||
"lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="],
|
"lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="],
|
||||||
|
|
||||||
"marked": ["marked@15.0.7", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-dgLIeKGLx5FwziAnsk4ONoGwHwGPJzselimvlVskE9XLN4Orv9u2VA3GWw/lYUqjfA0rUT/6fqKwfZJapP9BEg=="],
|
"marked": ["marked@15.0.7", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-dgLIeKGLx5FwziAnsk4ONoGwHwGPJzselimvlVskE9XLN4Orv9u2VA3GWw/lYUqjfA0rUT/6fqKwfZJapP9BEg=="],
|
||||||
|
|
||||||
|
"react": ["react@19.0.0", "", {}, "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ=="],
|
||||||
|
|
||||||
|
"react-dom": ["react-dom@19.0.0", "", { "dependencies": { "scheduler": "^0.25.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ=="],
|
||||||
|
|
||||||
|
"scheduler": ["scheduler@0.25.0", "", {}, "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA=="],
|
||||||
|
|
||||||
"slugify": ["slugify@1.6.6", "", {}, "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw=="],
|
"slugify": ["slugify@1.6.6", "", {}, "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw=="],
|
||||||
|
|
||||||
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
|
"typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
"@types/lodash-es": "^4.17.12"
|
"@types/lodash-es": "^4.17.12",
|
||||||
|
"@types/react": "^19.0.11",
|
||||||
|
"@types/react-dom": "^19.0.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5.0.0"
|
"typescript": "^5.0.0"
|
||||||
|
@ -14,8 +16,11 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@proscenium/playbill": "link:@proscenium/playbill",
|
"@proscenium/playbill": "link:@proscenium/playbill",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.4.1",
|
||||||
|
"classnames": "^2.5.1",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"marked": "^15.0.7",
|
"marked": "^15.0.7",
|
||||||
|
"react": "^19.0.0",
|
||||||
|
"react-dom": "^19.0.0",
|
||||||
"slugify": "^1.6.6",
|
"slugify": "^1.6.6",
|
||||||
"yaml": "^2.7.0",
|
"yaml": "^2.7.0",
|
||||||
"zod": "^3.24.1"
|
"zod": "^3.24.1"
|
||||||
|
|
|
@ -226,6 +226,11 @@ export async function loadFromBinding(
|
||||||
playbill.addBlueprint(blueprint);
|
playbill.addBlueprint(blueprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add rules
|
||||||
|
for (const rule of rules) {
|
||||||
|
playbill.addRule(rule);
|
||||||
|
}
|
||||||
|
|
||||||
// Add all definitions
|
// Add all definitions
|
||||||
for (const glossary of glossaries) {
|
for (const glossary of glossaries) {
|
||||||
for (const [term, definitions] of Object.entries(glossary)) {
|
for (const [term, definitions] of Object.entries(glossary)) {
|
||||||
|
|
40
src/render/html/component/base/react-section.tsx
Normal file
40
src/render/html/component/base/react-section.tsx
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import classNames from "classnames";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface SectionProps {
|
||||||
|
type: string;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
preInfo?: React.ReactNode;
|
||||||
|
info?: React.ReactNode;
|
||||||
|
componentId?: string;
|
||||||
|
leftCornerTag?: React.ReactNode;
|
||||||
|
rightCornerTag?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Section({
|
||||||
|
type,
|
||||||
|
title,
|
||||||
|
content,
|
||||||
|
preInfo,
|
||||||
|
info,
|
||||||
|
componentId,
|
||||||
|
leftCornerTag,
|
||||||
|
rightCornerTag,
|
||||||
|
}: SectionProps) {
|
||||||
|
const sectionClasses = classNames("section", type);
|
||||||
|
const headerClasses = classNames("section-header", `${type}-header`);
|
||||||
|
const contentClasses = classNames("section-content", `${type}-content`);
|
||||||
|
|
||||||
|
return <section className={sectionClasses} data-component-id={componentId}>
|
||||||
|
<div className={headerClasses}>
|
||||||
|
{preInfo}
|
||||||
|
<h2>{title}</h2>
|
||||||
|
{info}
|
||||||
|
</div>
|
||||||
|
<div className="section-tag section-tag--left">{leftCornerTag}</div>
|
||||||
|
<div className="section-tag section-tag--right">{rightCornerTag}</div>
|
||||||
|
<div className={contentClasses} dangerouslySetInnerHTML={{ __html: content }} />
|
||||||
|
</section>
|
||||||
|
|
||||||
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
import type { Rule } from "@proscenium/playbill";
|
|
||||||
import { renderMarkdown } from "#lib";
|
|
||||||
import { Section } from "./base/section";
|
|
||||||
|
|
||||||
export async function RuleSection(rule: Rule): Promise<string> {
|
|
||||||
const renderedMarkdown = await renderMarkdown(rule.description);
|
|
||||||
|
|
||||||
return Section({
|
|
||||||
title: rule.name,
|
|
||||||
componentId: rule.id,
|
|
||||||
content: renderedMarkdown,
|
|
||||||
type: "rule",
|
|
||||||
});
|
|
||||||
}
|
|
11
src/render/html/component/rule.tsx
Normal file
11
src/render/html/component/rule.tsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import type { Rule } from "@proscenium/playbill";
|
||||||
|
import { Section } from "./base/react-section";
|
||||||
|
|
||||||
|
export function RuleSection(rule: Rule) {
|
||||||
|
return <Section
|
||||||
|
title={rule.name}
|
||||||
|
componentId={rule.id}
|
||||||
|
content={rule.description}
|
||||||
|
type="rule"
|
||||||
|
/>;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import type { Playbill } from "@proscenium/playbill";
|
import { Playbill } from "@proscenium/playbill";
|
||||||
import sortBy from "lodash-es/sortBy";
|
import sortBy from "lodash-es/sortBy";
|
||||||
import { html } from "#lib";
|
import { html, renderMarkdown } from "#lib";
|
||||||
import { GlossaryTable } from "./component/glossary";
|
import { GlossaryTable } from "./component/glossary";
|
||||||
import { PageHeader } from "./component/header";
|
import { PageHeader } from "./component/header";
|
||||||
import { ItemCard } from "./component/item";
|
import { ItemCard } from "./component/item";
|
||||||
|
@ -8,15 +8,21 @@ import { MethodSection } from "./component/method";
|
||||||
import { ResourceSection } from "./component/resource";
|
import { ResourceSection } from "./component/resource";
|
||||||
import { RuleSection } from "./component/rule";
|
import { RuleSection } from "./component/rule";
|
||||||
import { SpeciesSection } from "./component/species";
|
import { SpeciesSection } from "./component/species";
|
||||||
|
import { renderToString } from "react-dom/server";
|
||||||
|
|
||||||
interface HTMLRenderOptions {
|
interface HTMLRenderOptions {
|
||||||
styles?: string;
|
styles?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function renderPlaybillToHTML(
|
export async function renderPlaybillToHTML(
|
||||||
playbill: Playbill,
|
playbillToRender: Playbill,
|
||||||
opts: HTMLRenderOptions = {},
|
opts: HTMLRenderOptions = {},
|
||||||
): Promise<string> {
|
): 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
|
// Render various resources
|
||||||
const resources = (
|
const resources = (
|
||||||
await Promise.all(Object.values(playbill.resources).map(ResourceSection))
|
await Promise.all(Object.values(playbill.resources).map(ResourceSection))
|
||||||
|
@ -47,7 +53,7 @@ export async function renderPlaybillToHTML(
|
||||||
).join("\n");
|
).join("\n");
|
||||||
|
|
||||||
const rulesByOrder = sortBy(Object.values(playbill.rules), "order");
|
const rulesByOrder = sortBy(Object.values(playbill.rules), "order");
|
||||||
const rules = (await Promise.all(rulesByOrder.map(RuleSection))).join("\n");
|
const rules = rulesByOrder.map(RuleSection);
|
||||||
const glossaryHTML = await GlossaryTable(playbill.glossary);
|
const glossaryHTML = await GlossaryTable(playbill.glossary);
|
||||||
|
|
||||||
// Prepare stylesheet
|
// Prepare stylesheet
|
||||||
|
@ -144,7 +150,7 @@ export async function renderPlaybillToHTML(
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article id="rules" class="view">
|
<article id="rules" class="view">
|
||||||
${rules}
|
${renderToString(rules)}
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article id="glossary" class="view">
|
<article id="glossary" class="view">
|
Loading…
Add table
Add a link
Reference in a new issue