More convert to jsx

This commit is contained in:
Endeavorance 2025-03-18 10:02:58 -04:00
parent d769e298b1
commit 0f72d048ee
8 changed files with 79 additions and 114 deletions

View file

@ -18,12 +18,10 @@ Usage:
Options: Options:
--check Only load and check the current binding and resources, but do not compile --check Only load and check the current binding and resources, but do not compile
--write Write the output to a file. If not specified, outputs to stdout --outfile, -o Specify the output file path. If not specified, output to stdout
--outfile Specify the output file path [default: playbill.json] --watch, -w Watch the directory for changes and recompile
--verbose, -v Verbose output --renderer, -r Specify the output renderer. Options: json, html
--minify, -m Minify the output JSON --help, -h Show this help message
--watch Watch the directory for changes and recompile
--help, -h Show this help message
`.trim(); `.trim();
enum ExitCode { enum ExitCode {
@ -58,10 +56,9 @@ async function processBinding({ inputFilePath, options }: CLIArguments) {
throw new CLIError(`Unknown renderer: ${options.renderer}`); throw new CLIError(`Unknown renderer: ${options.renderer}`);
} }
// -- WRITE TO DISK OR STDOUT --// // Write to disk if an outfile is specified
if (options.write) { if (options.outfile !== "") {
await Bun.write(options.outfile, serializedPlaybill); await Bun.write(options.outfile, serializedPlaybill);
return ExitCode.Success; return ExitCode.Success;
} }

View file

@ -1,41 +0,0 @@
import type { Ability } from "@proscenium/playbill";
import { html, renderMarkdown } from "#lib";
export async function AbilityCard(ability: Ability): Promise<string> {
const renderedMarkdown = await renderMarkdown(ability.description);
const costs: string[] = [];
if (ability.ap > 0) {
costs.push(`<li class="ability-cost-ap">${ability.ap} AP</li>`);
}
if (ability.hp > 0) {
costs.push(`<li class="ability-cost-hp">${ability.hp} HP</li>`);
}
if (ability.ep > 0) {
costs.push(`<li class="ability-cost-ep">${ability.ep} EP</li>`);
}
const costList =
costs.length > 0
? `<ul class="ability-costs">${costs.join("\n")}</ul>`
: "";
const classList = `ability ability-${ability.type}`;
return html`
<div class="${classList}" data-component-id="${ability.id}">
<div class="ability-header">
<h4>${ability.name}</h4>
<span class="ability-type">${ability.type}</span>
<span class="ability-cost-xp">${ability.xp} XP</span>
${costList}
</div>
<div class="ability-content">
${renderedMarkdown}
</div>
</div>
`;
}

View file

@ -0,0 +1,38 @@
import type { Ability } from "@proscenium/playbill";
interface AbilityCardProps {
ability: Ability;
}
export function AbilityCard({ ability }: AbilityCardProps) {
const costs: React.ReactNode[] = [];
if (ability.ap > 0) {
costs.push(<li key="ap" className="ability-cost-ap">{ability.ap} AP</li>);
}
if (ability.hp > 0) {
costs.push(<li key="hp" className="ability-cost-hp">{ability.hp} HP</li>);
}
if (ability.ep > 0) {
costs.push(<li key="ep" className="ability-cost-ep">{ability.ep} EP</li>);
}
const costList =
costs.length > 0
? `<ul class="ability-costs">${costs.join("\n")}</ul>`
: "";
const classList = `ability ability-${ability.type}`;
return <div className={classList} data-component-id={ability.id}>
<div className="ability-header">
<h4>${ability.name}</h4>
<span className="ability-type">${ability.type}</span>
<span className="ability-cost-xp">${ability.xp} XP</span>
${costList}
</div>
<div className="ability-content" dangerouslySetInnerHTML={{ __html: ability.description }} />
</div>
}

View file

@ -4,7 +4,7 @@ import React from "react";
interface SectionProps { interface SectionProps {
type: string; type: string;
title: string; title: string;
content: string; content: React.ReactNode;
preInfo?: React.ReactNode; preInfo?: React.ReactNode;
info?: React.ReactNode; info?: React.ReactNode;
componentId?: string; componentId?: string;
@ -26,6 +26,8 @@ export function Section({
const headerClasses = classNames("section-header", `${type}-header`); const headerClasses = classNames("section-header", `${type}-header`);
const contentClasses = classNames("section-content", `${type}-content`); const contentClasses = classNames("section-content", `${type}-content`);
const contentDiv = typeof content === "string" ? <div className={contentClasses} dangerouslySetInnerHTML={{ __html: content }} /> : <div className={contentClasses}>{content}</div>;
return <section className={sectionClasses} data-component-id={componentId}> return <section className={sectionClasses} data-component-id={componentId}>
<div className={headerClasses}> <div className={headerClasses}>
{preInfo} {preInfo}
@ -34,7 +36,7 @@ export function Section({
</div> </div>
<div className="section-tag section-tag--left">{leftCornerTag}</div> <div className="section-tag section-tag--left">{leftCornerTag}</div>
<div className="section-tag section-tag--right">{rightCornerTag}</div> <div className="section-tag section-tag--right">{rightCornerTag}</div>
<div className={contentClasses} dangerouslySetInnerHTML={{ __html: content }} /> {contentDiv}
</section> </section>
} }

View file

@ -1,38 +0,0 @@
import type { Method, Playbill } from "@proscenium/playbill";
import { html, renderMarkdown } from "#lib";
import { AbilityCard } from "./ability";
import { Section } from "./base/section";
export async function MethodSection(method: Method, playbill: Playbill) {
const descriptionHTML = await renderMarkdown(method.description);
let ranksHTML = "";
let rankNumber = 1;
for (const rank of method.abilities) {
ranksHTML += `<div class="method-rank"><h3>Rank ${rankNumber}</h3><div class="method-rank-content">`;
for (const ability of rank) {
const html = await AbilityCard(playbill.abilities[ability]);
ranksHTML += html;
}
ranksHTML += "</div></div>";
rankNumber++;
}
const methodContent = html`
<div class="method-ranks">
${ranksHTML}
</div>
`;
return Section({
type: "method",
componentId: method.id,
title: method.name,
preInfo: html`<p class="method-curator">${method.curator}'s Method of</p>`,
info: html`<p class="method-description">${descriptionHTML}</p>`,
content: methodContent,
});
}

View file

@ -0,0 +1,28 @@
import type { Method, Playbill } from "@proscenium/playbill";
import { AbilityCard } from "./ability";
import { Section } from "./base/react-section";
export function MethodSection(method: Method, playbill: Playbill) {
const ranks = method.abilities.map((rank, i) => {
return <div className="method-rank" key={i}>
<h3>Rank {i + 1}</h3>
<div className="method-rank-content">
{rank.map((abilityId) => {
const ability = playbill.abilities[abilityId];
return <AbilityCard ability={ability} key={abilityId} />;
})
}
</div>
</div>
});
return <Section
type="method"
componentId={method.id}
title={method.name}
preInfo={<p className="method-curator">{method.curator}</p>}
info={<p className="method-description">{method.description}</p>}
content={<div className="method-ranks">{ranks}</div>}
/>
}

View file

@ -5,12 +5,6 @@ import { Section } from "./base/section";
export async function SpeciesSection(species: Species, playbill: Playbill) { export async function SpeciesSection(species: Species, playbill: Playbill) {
const descriptionHTML = await renderMarkdown(species.description); const descriptionHTML = await renderMarkdown(species.description);
let abilitiesHTML = "";
for (const ability of species.abilities) {
abilitiesHTML += await AbilityCard(playbill.abilities[ability]);
}
const hpString = species.hp >= 0 ? `+${species.hp}` : `-${species.hp}`; const hpString = species.hp >= 0 ? `+${species.hp}` : `-${species.hp}`;
const apString = species.ap >= 0 ? `+${species.ap}` : `-${species.ap}`; const apString = species.ap >= 0 ? `+${species.ap}` : `-${species.ap}`;
const epString = species.ep >= 0 ? `+${species.ep}` : `-${species.ep}`; const epString = species.ep >= 0 ? `+${species.ep}` : `-${species.ep}`;
@ -21,7 +15,6 @@ export async function SpeciesSection(species: Species, playbill: Playbill) {
? html` ? html`
<div class="species-abilities"> <div class="species-abilities">
<h3>Innate Abilities</h3> <h3>Innate Abilities</h3>
${abilitiesHTML}
</div> </div>
` `
: ""; : "";

View file

@ -13,11 +13,9 @@ export interface CLIArguments {
inputFilePath: string; inputFilePath: string;
options: { options: {
write: boolean;
check: boolean; check: boolean;
outfile: string; outfile: string;
help: boolean; help: boolean;
minify: boolean;
renderer: Renderer; renderer: Renderer;
watch: boolean; watch: boolean;
}; };
@ -35,11 +33,6 @@ export function parseCLIArguments(argv: string[]): CLIArguments {
const { values: options, positionals: args } = parseArgs({ const { values: options, positionals: args } = parseArgs({
args: argv, args: argv,
options: { options: {
write: {
short: "w",
type: "boolean",
default: false,
},
check: { check: {
short: "c", short: "c",
type: "boolean", type: "boolean",
@ -48,18 +41,13 @@ export function parseCLIArguments(argv: string[]): CLIArguments {
outfile: { outfile: {
short: "o", short: "o",
type: "string", type: "string",
default: "playbill.json", default: "",
}, },
help: { help: {
short: "h", short: "h",
default: false, default: false,
type: "boolean", type: "boolean",
}, },
minify: {
short: "m",
default: false,
type: "boolean",
},
renderer: { renderer: {
short: "r", short: "r",
default: "json", default: "json",
@ -75,8 +63,8 @@ export function parseCLIArguments(argv: string[]): CLIArguments {
}); });
// -- ARG VALIDATION -- // // -- ARG VALIDATION -- //
if (options.check && options.write) { if (options.check && options.outfile !== "") {
throw new CLIError("Cannot use --check and --write together"); throw new CLIError("Cannot use --check and --outfile together");
} }
const parsedRenderer = RendererSchema.safeParse(options.renderer); const parsedRenderer = RendererSchema.safeParse(options.renderer);
@ -89,11 +77,9 @@ export function parseCLIArguments(argv: string[]): CLIArguments {
inputFilePath: args[0] ?? "./binding.yaml", inputFilePath: args[0] ?? "./binding.yaml",
options: { options: {
write: options.write,
check: options.check, check: options.check,
outfile: options.outfile, outfile: options.outfile,
help: options.help, help: options.help,
minify: options.minify,
renderer: parsedRenderer.data, renderer: parsedRenderer.data,
watch: options.watch, watch: options.watch,
}, },