Summary: Try to fix eslint issues Reviewers: #reviewers Subscribers: jenkins-user Differential Revision: https://hub.sealcode.org/D1426
212 lines
5.7 KiB
TypeScript
212 lines
5.7 KiB
TypeScript
import { render, renderEarlyAssets } from "@sealcode/jdd";
|
|
import { StatefulPage, to_base64 } from "@sealcode/sealgen";
|
|
import { hasShape, predicates } from "@sealcode/ts-predicates";
|
|
import type { BaseContext } from "koa";
|
|
import type { Templatable } from "tempstream";
|
|
import { tempstream, TempstreamJSX } from "tempstream";
|
|
import html, { defaultHead } from "../html.js";
|
|
import { registry } from "../jdd-components/components.js";
|
|
import { ComponentInput } from "./component-preview/component-input.js";
|
|
import { ComponentPreviewActions } from "./component-preview/component-preview-actions.js";
|
|
import { jdd_context } from "./jdd-context.js";
|
|
|
|
export const actionName = "Components";
|
|
|
|
export type ComponentPreviewState = {
|
|
component: string;
|
|
component_args: Record<string, unknown>;
|
|
current_size?: string;
|
|
};
|
|
|
|
export default new (class ComponentsPage extends StatefulPage<
|
|
ComponentPreviewState,
|
|
typeof ComponentPreviewActions
|
|
> {
|
|
actions = ComponentPreviewActions;
|
|
|
|
async getInitialState() {
|
|
const [component_name, component] = Object.entries(registry.getAll())[0];
|
|
const initial_state = {
|
|
component: component_name,
|
|
component_args: await component.getExampleValues(jdd_context),
|
|
};
|
|
return initial_state;
|
|
}
|
|
|
|
wrapInLayout(
|
|
ctx: BaseContext,
|
|
content: Templatable,
|
|
state: ComponentPreviewState
|
|
): Templatable {
|
|
return html(
|
|
ctx,
|
|
"Components",
|
|
content,
|
|
{
|
|
morphing: true,
|
|
preserveScroll: true,
|
|
autoRefreshCSS: true,
|
|
navbar: () => ``,
|
|
},
|
|
(...args) =>
|
|
tempstream`${defaultHead(...args)}${renderEarlyAssets(
|
|
registry,
|
|
[
|
|
{
|
|
component_name: state.component,
|
|
args: state.component_args,
|
|
},
|
|
],
|
|
jdd_context
|
|
)}`
|
|
);
|
|
}
|
|
|
|
wrapInForm(state: ComponentPreviewState, content: Templatable): Templatable {
|
|
// overwriting this method in order to add enctype to form
|
|
return (
|
|
<form action="./" method="POST" enctype="multipart/form-data">
|
|
<input
|
|
name="state"
|
|
type="hidden"
|
|
value={to_base64(JSON.stringify(state))}
|
|
/>
|
|
{content}
|
|
</form>
|
|
);
|
|
}
|
|
|
|
async preprocessOverrides(
|
|
state: ComponentPreviewState,
|
|
overrides: Record<string, unknown>
|
|
) {
|
|
const component_name = state.component;
|
|
if (!component_name) {
|
|
throw new Error("Unspecified component name");
|
|
}
|
|
const component = registry.get(component_name);
|
|
if (!component) {
|
|
throw new Error(`Unknown component: ${component_name}`);
|
|
}
|
|
if (!hasShape({ component_args: predicates.object }, overrides)) {
|
|
return overrides;
|
|
}
|
|
const promises = Object.entries(component.getArguments()).map(
|
|
async ([arg_name, arg]) => {
|
|
const value = overrides.component_args[arg_name];
|
|
if (value) {
|
|
const new_value = await arg.parseFormInput(
|
|
jdd_context,
|
|
value,
|
|
arg_name
|
|
);
|
|
overrides.component_args[arg_name] = new_value;
|
|
}
|
|
}
|
|
);
|
|
await Promise.all(promises);
|
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
return overrides;
|
|
}
|
|
|
|
containerSizes = ["320", "600", "800", "1024", "1300", "1920"];
|
|
|
|
render(_ctx: BaseContext, state: ComponentPreviewState) {
|
|
const all_components = registry.getAll();
|
|
const component =
|
|
registry.get(state.component) || Object.values(all_components)[0];
|
|
return (
|
|
<div
|
|
class="two-column"
|
|
id="component-debugger"
|
|
style="--resizable-column-width: 50vw"
|
|
data-controller="component-debugger"
|
|
>
|
|
<div class="component-arguments">
|
|
{/*The below button has to be here in order for it to be the default behavior */}
|
|
<input type="submit" value="Preview" />
|
|
<select
|
|
name="component"
|
|
onchange={this.makeActionCallback("change_component")}
|
|
autocomplete="off"
|
|
>
|
|
{Object.entries(all_components).map(([name]) => (
|
|
<option value={name} selected={name == state.component}>
|
|
{name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
{this.makeActionButton(state, "randomize_args")}
|
|
<fieldset class="component-preview-parameters">
|
|
<legend>Parameters</legend>
|
|
{Object.entries(component.getArguments()).map(
|
|
async ([arg_name, arg]) => (
|
|
<ComponentInput
|
|
{...{
|
|
state,
|
|
arg_path: [arg_name],
|
|
arg,
|
|
value:
|
|
state.component_args[arg_name] === undefined
|
|
? await arg.getExampleValue(jdd_context)
|
|
: state.component_args[arg_name],
|
|
onblur: this.rerender(),
|
|
page: this,
|
|
}}
|
|
/>
|
|
)
|
|
)}
|
|
<input type="submit" value="Preview" />
|
|
</fieldset>
|
|
<code>{JSON.stringify(state)}</code>
|
|
</div>
|
|
<div class="resize-gutter" data-component-debugger-target="gutter"></div>
|
|
<div class="component-preview" data-component-debugger-target="preview">
|
|
<fieldset>
|
|
<legend>
|
|
Preview{" "}
|
|
<span data-component-debugger-target="component-width"></span>
|
|
<select
|
|
name="size"
|
|
autocomplete="off"
|
|
class="component-preview-size-select"
|
|
data-component-debugger-target="size-select"
|
|
data-action="change->component-debugger#handleWidthDropdown"
|
|
>
|
|
{this.containerSizes.map((size) => (
|
|
<option
|
|
value={size}
|
|
selected={size === (state.current_size || "800")}
|
|
>
|
|
{`${size} px`}
|
|
</option>
|
|
))}
|
|
</select>
|
|
<noscript>
|
|
{this.makeActionButton(state, "change_size")}
|
|
</noscript>
|
|
</legend>
|
|
{render(
|
|
registry,
|
|
[
|
|
{
|
|
component_name: state.component,
|
|
args: state.component_args,
|
|
},
|
|
],
|
|
jdd_context
|
|
)}
|
|
</fieldset>
|
|
{
|
|
/* HTML */ `<script>
|
|
(function () {
|
|
const gutter = document.querySelector(".resize-gutter");
|
|
})();
|
|
</script>`
|
|
}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
})();
|