More powerful component preview and parameter editor
This commit is contained in:
parent
ef4fa71838
commit
6e634e5d64
41
package-lock.json
generated
41
package-lock.json
generated
@ -11,17 +11,19 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.12.10",
|
"@babel/core": "^7.12.10",
|
||||||
"@hotwired/turbo": "^7.1.0",
|
"@hotwired/turbo": "^8.0.2",
|
||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"@playwright/test": "^1.36.1",
|
"@playwright/test": "^1.36.1",
|
||||||
"@sealcode/jdd": "^0.2.4",
|
"@sealcode/jdd": "^0.2.10",
|
||||||
"@sealcode/sealgen": "^0.11.5",
|
"@sealcode/sealgen": "^0.11.6",
|
||||||
"@sealcode/ts-predicates": "^0.4.3",
|
"@sealcode/ts-predicates": "^0.4.3",
|
||||||
"@types/kill-port": "^2.0.0",
|
"@types/kill-port": "^2.0.0",
|
||||||
"get-port": "^7.0.0",
|
"get-port": "^7.0.0",
|
||||||
|
"js-convert-case": "^4.2.0",
|
||||||
"locreq": "^3.0.0",
|
"locreq": "^3.0.0",
|
||||||
"multiple-scripts-tmux": "^1.0.4",
|
"multiple-scripts-tmux": "^1.0.4",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
|
"object-path": "^0.11.8",
|
||||||
"sealious": "^0.17.48",
|
"sealious": "^0.17.48",
|
||||||
"stimulus": "^2.0.0",
|
"stimulus": "^2.0.0",
|
||||||
"tempstream": "^0.3.2",
|
"tempstream": "^0.3.2",
|
||||||
@ -31,6 +33,7 @@
|
|||||||
"@sealcode/ansi-html-stream": "^1.0.1",
|
"@sealcode/ansi-html-stream": "^1.0.1",
|
||||||
"@types/koa__router": "^12.0.4",
|
"@types/koa__router": "^12.0.4",
|
||||||
"@types/node": "^20.8.4",
|
"@types/node": "^20.8.4",
|
||||||
|
"@types/object-path": "^0.11.4",
|
||||||
"@types/tedious": "^4.0.7",
|
"@types/tedious": "^4.0.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||||
"@typescript-eslint/parser": "^5.10.2",
|
"@typescript-eslint/parser": "^5.10.2",
|
||||||
@ -807,9 +810,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@hotwired/turbo": {
|
"node_modules/@hotwired/turbo": {
|
||||||
"version": "7.3.0",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@hotwired/turbo/-/turbo-7.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@hotwired/turbo/-/turbo-8.0.2.tgz",
|
||||||
"integrity": "sha512-Dcu+NaSvHLT7EjrDrkEmH4qET2ZJZ5IcCWmNXxNQTBwlnE5tBZfN6WxZ842n5cHV52DH/AKNirbPBtcEXDLW4g==",
|
"integrity": "sha512-3K6QZkwWfosAV8zuM5bY+kKF02jp1lMQGsWfSE6wXdZBRBP3ah+Vj26YNqYtkEomBwRWA0QKhZgyJP7xOQkVEg==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
@ -1275,9 +1278,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sealcode/jdd": {
|
"node_modules/@sealcode/jdd": {
|
||||||
"version": "0.2.4",
|
"version": "0.2.10",
|
||||||
"resolved": "https://registry.npmjs.org/@sealcode/jdd/-/jdd-0.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@sealcode/jdd/-/jdd-0.2.10.tgz",
|
||||||
"integrity": "sha512-Lf/UIgY0N8zNHHDonvF4WQufITjWhih9+FAbb+NO21pbygrZyIaXfKPW0Vp+Eh9blTZY6QEG40H7zouuVF55ew==",
|
"integrity": "sha512-8dQfskMUqotrh9Fbnk2sBcXJ12gXNM1ENPvrQOOX6VabXgE7eQc9gAZgmkcgA2prEwn1vbfpo+Lz9wxzpHOLDQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sealcode/ts-predicates": "^0.5.3",
|
"@sealcode/ts-predicates": "^0.5.3",
|
||||||
"marked": "^12.0.0",
|
"marked": "^12.0.0",
|
||||||
@ -1301,9 +1304,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sealcode/sealgen": {
|
"node_modules/@sealcode/sealgen": {
|
||||||
"version": "0.11.5",
|
"version": "0.11.6",
|
||||||
"resolved": "https://registry.npmjs.org/@sealcode/sealgen/-/sealgen-0.11.5.tgz",
|
"resolved": "https://registry.npmjs.org/@sealcode/sealgen/-/sealgen-0.11.6.tgz",
|
||||||
"integrity": "sha512-7mb8zuz2Z3KHVcVeWTRN+f4c9IVPhHKX3OzIhNv1ZY/BfkWifU5lFsBrYJUaT4Zd8EYXQIU0DAsZy4WO1miJFQ==",
|
"integrity": "sha512-6GGZi59aia7ou2bDmejQedDNLyzfoo05bFnGVlsWXuCOMCUhBXuWGlFe3wqkSr+340iyvZiXJvBSfXg3DatX2Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"@sealcode/ts-predicates": "^0.4.3",
|
"@sealcode/ts-predicates": "^0.4.3",
|
||||||
@ -2100,6 +2103,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-1.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-1.3.4.tgz",
|
||||||
"integrity": "sha512-xFdpkAkikBgqBdG9vIlsqffDV8GpvnPEzs0IUtr1v3BEB97ijsFQ4RXVbUZwjFThhB4MDSTUfvmxUD5PGx0wXA=="
|
"integrity": "sha512-xFdpkAkikBgqBdG9vIlsqffDV8GpvnPEzs0IUtr1v3BEB97ijsFQ4RXVbUZwjFThhB4MDSTUfvmxUD5PGx0wXA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/object-path": {
|
||||||
|
"version": "0.11.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/object-path/-/object-path-0.11.4.tgz",
|
||||||
|
"integrity": "sha512-4tgJ1Z3elF/tOMpA8JLVuR9spt9Ynsf7+JjqsQ2IqtiPJtcLoHoXcT6qU4E10cPFqyXX5HDm9QwIzZhBSkLxsw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
"version": "6.9.11",
|
"version": "6.9.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz",
|
||||||
@ -8086,6 +8095,14 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-path": {
|
||||||
|
"version": "0.11.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz",
|
||||||
|
"integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/on-finished": {
|
"node_modules/on-finished": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||||
|
@ -32,17 +32,19 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.12.10",
|
"@babel/core": "^7.12.10",
|
||||||
"@hotwired/turbo": "^7.1.0",
|
"@hotwired/turbo": "^8.0.2",
|
||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"@playwright/test": "^1.36.1",
|
"@playwright/test": "^1.36.1",
|
||||||
"@sealcode/jdd": "^0.2.4",
|
"@sealcode/jdd": "^0.2.10",
|
||||||
"@sealcode/sealgen": "^0.11.5",
|
"@sealcode/sealgen": "^0.11.6",
|
||||||
"@sealcode/ts-predicates": "^0.4.3",
|
"@sealcode/ts-predicates": "^0.4.3",
|
||||||
"@types/kill-port": "^2.0.0",
|
"@types/kill-port": "^2.0.0",
|
||||||
"get-port": "^7.0.0",
|
"get-port": "^7.0.0",
|
||||||
|
"js-convert-case": "^4.2.0",
|
||||||
"locreq": "^3.0.0",
|
"locreq": "^3.0.0",
|
||||||
"multiple-scripts-tmux": "^1.0.4",
|
"multiple-scripts-tmux": "^1.0.4",
|
||||||
"nodemon": "^3.0.1",
|
"nodemon": "^3.0.1",
|
||||||
|
"object-path": "^0.11.8",
|
||||||
"sealious": "^0.17.48",
|
"sealious": "^0.17.48",
|
||||||
"stimulus": "^2.0.0",
|
"stimulus": "^2.0.0",
|
||||||
"tempstream": "^0.3.2",
|
"tempstream": "^0.3.2",
|
||||||
@ -52,6 +54,7 @@
|
|||||||
"@sealcode/ansi-html-stream": "^1.0.1",
|
"@sealcode/ansi-html-stream": "^1.0.1",
|
||||||
"@types/koa__router": "^12.0.4",
|
"@types/koa__router": "^12.0.4",
|
||||||
"@types/node": "^20.8.4",
|
"@types/node": "^20.8.4",
|
||||||
|
"@types/object-path": "^0.11.4",
|
||||||
"@types/tedious": "^4.0.7",
|
"@types/tedious": "^4.0.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||||
"@typescript-eslint/parser": "^5.10.2",
|
"@typescript-eslint/parser": "^5.10.2",
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Templatable, tempstream } from "tempstream";
|
import { FlatTemplatable, Templatable, tempstream } from "tempstream";
|
||||||
import { Readable } from "stream";
|
import { Readable } from "stream";
|
||||||
import { BaseContext } from "koa";
|
import { BaseContext } from "koa";
|
||||||
import navbar from "./routes/common/navbar.js";
|
import { default as default_navbar } from "./routes/common/navbar.js";
|
||||||
|
import { toKebabCase } from "js-convert-case";
|
||||||
|
|
||||||
export const defaultHead = (ctx: BaseContext, title: string) => /* HTML */ `<title>
|
export const defaultHead = (ctx: BaseContext, title: string) => /* HTML */ `<title>
|
||||||
${title} · ${ctx.$app.manifest.name}
|
${title} · ${ctx.$app.manifest.name}
|
||||||
@ -10,20 +11,31 @@ export const defaultHead = (ctx: BaseContext, title: string) => /* HTML */ `<tit
|
|||||||
<script async src="/dist/bundle.js"></script>
|
<script async src="/dist/bundle.js"></script>
|
||||||
<link href="/dist/main.css" rel="stylesheet" type="text/css" />`;
|
<link href="/dist/main.css" rel="stylesheet" type="text/css" />`;
|
||||||
|
|
||||||
|
export type HTMLOptions = {
|
||||||
|
preserveScroll?: boolean;
|
||||||
|
morphing?: boolean;
|
||||||
|
navbar?: (ctx: BaseContext) => FlatTemplatable;
|
||||||
|
};
|
||||||
|
|
||||||
export default function html(
|
export default function html(
|
||||||
ctx: BaseContext,
|
ctx: BaseContext,
|
||||||
title: string,
|
title: string,
|
||||||
body: Templatable,
|
body: Templatable,
|
||||||
|
{ preserveScroll, morphing, navbar }: HTMLOptions = {},
|
||||||
makeHead: (ctx: BaseContext, title: string) => Templatable = defaultHead
|
makeHead: (ctx: BaseContext, title: string) => Templatable = defaultHead
|
||||||
): Readable {
|
): Readable {
|
||||||
ctx.set("content-type", "text/html;charset=utf-8");
|
ctx.set("content-type", "text/html;charset=utf-8");
|
||||||
return tempstream/* HTML */ ` <!DOCTYPE html>
|
return tempstream/* HTML */ ` <!DOCTYPE html>
|
||||||
<html lang="pl">
|
<html lang="pl" class="title--${toKebabCase(title)}">
|
||||||
<head>
|
<head>
|
||||||
${makeHead(ctx, title)}
|
${makeHead(ctx, title)}
|
||||||
|
${morphing ? `<meta name="turbo-refresh-method" content="morph" />` : ""}
|
||||||
|
${preserveScroll
|
||||||
|
? `<meta name="turbo-refresh-scroll" content="preserve">`
|
||||||
|
: ""}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
${navbar(ctx)} ${body}
|
${(navbar || default_navbar)(ctx)} ${body}
|
||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,3 @@ export const registry = new Registry();
|
|||||||
|
|
||||||
import { NiceBox } from "./nice-box/nice-box.jdd.js";
|
import { NiceBox } from "./nice-box/nice-box.jdd.js";
|
||||||
registry.add("nice-box", NiceBox);
|
registry.add("nice-box", NiceBox);
|
||||||
|
|
||||||
import { UsingImages } from "./using-images/using-images.jdd.js";
|
|
||||||
registry.add("using-images", UsingImages);
|
|
||||||
|
27
src/back/routes/components.css
Normal file
27
src/back/routes/components.css
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
.title--components {
|
||||||
|
body {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.two-column {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: min-content 15px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resize-gutter {
|
||||||
|
background-color: gray;
|
||||||
|
cursor: ew-resize;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.resizable {
|
||||||
|
width: var(--resizable-column-width);
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.component-preview-parameters {
|
||||||
|
fieldset {
|
||||||
|
background-color: #80808024;
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,53 @@
|
|||||||
import { TempstreamJSX, Templatable } from "tempstream";
|
import { TempstreamJSX, Templatable, FlatTemplatable, tempstream } from "tempstream";
|
||||||
import { BaseContext } from "koa";
|
import { BaseContext } from "koa";
|
||||||
import { StatefulPage } from "@sealcode/sealgen";
|
import { StatefulPage } from "@sealcode/sealgen";
|
||||||
import html from "../html.js";
|
import html from "../html.js";
|
||||||
import { registry } from "../jdd-components/components.js";
|
import { registry } from "../jdd-components/components.js";
|
||||||
import { render, simpleJDDContext } from "@sealcode/jdd";
|
import {
|
||||||
|
ComponentArgument,
|
||||||
|
Enum,
|
||||||
|
List,
|
||||||
|
render,
|
||||||
|
simpleJDDContext,
|
||||||
|
Structured,
|
||||||
|
} from "@sealcode/jdd";
|
||||||
|
import objectPath from "object-path";
|
||||||
|
|
||||||
export const actionName = "Components";
|
export const actionName = "Components";
|
||||||
|
|
||||||
const actions = {} as const;
|
const actions = {
|
||||||
|
add_array_item: (
|
||||||
|
state: State,
|
||||||
|
_: Record<string, string>,
|
||||||
|
arg_path: string[],
|
||||||
|
empty_value: unknown
|
||||||
|
) => {
|
||||||
|
const args = state.args;
|
||||||
|
objectPath.insert(
|
||||||
|
args,
|
||||||
|
arg_path,
|
||||||
|
empty_value,
|
||||||
|
((objectPath.get(args, arg_path) as unknown[]) || []).length
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
remove_array_item: (
|
||||||
|
state: State,
|
||||||
|
_: Record<string, string>,
|
||||||
|
arg_path: string[],
|
||||||
|
index_to_remove: number
|
||||||
|
) => {
|
||||||
|
const args = state.args;
|
||||||
|
objectPath.del(args, [...arg_path, index_to_remove]);
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
args,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
component: string;
|
component: string;
|
||||||
@ -22,7 +62,150 @@ export default new (class ComponentsPage extends StatefulPage<State, typeof acti
|
|||||||
}
|
}
|
||||||
|
|
||||||
wrapInLayout(ctx: BaseContext, content: Templatable): Templatable {
|
wrapInLayout(ctx: BaseContext, content: Templatable): Templatable {
|
||||||
return html(ctx, "Components", content);
|
return html(ctx, "Components", content, {
|
||||||
|
morphing: true,
|
||||||
|
preserveScroll: true,
|
||||||
|
navbar: () => ``,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderListArgument<T>(
|
||||||
|
state: State,
|
||||||
|
arg_path: string[],
|
||||||
|
arg: List<ComponentArgument<T>>,
|
||||||
|
value: T[] = []
|
||||||
|
): FlatTemplatable {
|
||||||
|
return (
|
||||||
|
<fieldset>
|
||||||
|
<legend>{arg_path.at(-1)}</legend>
|
||||||
|
{value.map((e, i) => (
|
||||||
|
<div style="display: flex">
|
||||||
|
{this.renderArgumentInput(
|
||||||
|
state,
|
||||||
|
[...arg_path, i.toString()],
|
||||||
|
arg.item_type,
|
||||||
|
e
|
||||||
|
)}
|
||||||
|
{this.makeActionButton(
|
||||||
|
state,
|
||||||
|
{ action: "remove_array_item", label: "❌" },
|
||||||
|
arg_path,
|
||||||
|
i
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{this.makeActionButton(
|
||||||
|
state,
|
||||||
|
{
|
||||||
|
action: "add_array_item",
|
||||||
|
label: "➕",
|
||||||
|
},
|
||||||
|
arg_path,
|
||||||
|
arg.item_type.getEmptyValue()
|
||||||
|
)}
|
||||||
|
</fieldset>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderStructuredArgument<
|
||||||
|
T extends Structured<Record<string, ComponentArgument<unknown>>>
|
||||||
|
>(
|
||||||
|
state: State,
|
||||||
|
arg_path: string[],
|
||||||
|
arg: T,
|
||||||
|
value: Record<string, unknown>
|
||||||
|
): FlatTemplatable {
|
||||||
|
return (
|
||||||
|
<fieldset>
|
||||||
|
<legend>{arg_path.at(-1)}</legend>
|
||||||
|
{Object.entries(arg.structure).map(([arg_name, arg]) => (
|
||||||
|
<div>
|
||||||
|
{this.renderArgumentInput(
|
||||||
|
state,
|
||||||
|
[...arg_path, arg_name],
|
||||||
|
arg,
|
||||||
|
(value as Record<string, unknown>)[arg_name]
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</fieldset>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
printArgPath(path: string[]): string {
|
||||||
|
return path.map((e) => `[${e}]`).join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEnumArgument<T extends Enum<any>>(
|
||||||
|
state: State,
|
||||||
|
arg_path: string[],
|
||||||
|
arg: T,
|
||||||
|
value: string
|
||||||
|
): FlatTemplatable {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
{arg_path.at(-1)}
|
||||||
|
<select name={`$.args${this.printArgPath(arg_path)}`}>
|
||||||
|
{arg.values.map((v) => (
|
||||||
|
<option value={v} selected={value == v}>
|
||||||
|
{v}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderArgumentInput<T>(
|
||||||
|
state: State,
|
||||||
|
arg_path: string[],
|
||||||
|
arg: ComponentArgument<T>,
|
||||||
|
value: T
|
||||||
|
): FlatTemplatable {
|
||||||
|
if (value === undefined) {
|
||||||
|
value = arg.getEmptyValue();
|
||||||
|
}
|
||||||
|
if (arg instanceof List) {
|
||||||
|
return this.renderListArgument(state, arg_path, arg, value as T[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg instanceof Structured) {
|
||||||
|
return this.renderStructuredArgument(
|
||||||
|
state,
|
||||||
|
arg_path,
|
||||||
|
arg,
|
||||||
|
value as Record<string, unknown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg instanceof Enum) {
|
||||||
|
return this.renderEnumArgument(state, arg_path, arg, value as string);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
{arg_path.at(-1)}
|
||||||
|
{arg.getTypeName() == "markdown" ? (
|
||||||
|
<textarea
|
||||||
|
name={`$.args${this.printArgPath(arg_path)}`}
|
||||||
|
onblur="this.closest('form').requestSubmit()"
|
||||||
|
cols="70"
|
||||||
|
>
|
||||||
|
{value as string}
|
||||||
|
</textarea>
|
||||||
|
) : (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name={`$.args${this.printArgPath(arg_path)}`}
|
||||||
|
value={value as string}
|
||||||
|
size="70"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render(ctx: BaseContext, state: State, inputs: Record<string, string>) {
|
render(ctx: BaseContext, state: State, inputs: Record<string, string>) {
|
||||||
@ -30,46 +213,87 @@ export default new (class ComponentsPage extends StatefulPage<State, typeof acti
|
|||||||
const component =
|
const component =
|
||||||
registry.get(state.component) || Object.values(all_components)[0];
|
registry.get(state.component) || Object.values(all_components)[0];
|
||||||
return (
|
return (
|
||||||
<div>
|
<div class="two-column">
|
||||||
<div>{JSON.stringify(state)}</div>
|
<div class="resizable">
|
||||||
<select name="$.component" onchange="this.closest('form').submit()">
|
{/*The below button has to be here in order for it to be the default behavior */}
|
||||||
{Object.entries(all_components).map(([name]) => (
|
|
||||||
<option value={name} selected={name == state.component}>
|
|
||||||
{name}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
<fieldset>
|
|
||||||
<legend>Parameters</legend>
|
|
||||||
{Object.entries(component.getArguments()).map(([arg_name, arg]) => (
|
|
||||||
<div>
|
|
||||||
<label>
|
|
||||||
{arg_name}
|
|
||||||
{arg.getTypeName() == "markdown" ? (
|
|
||||||
<textarea name={`$.args[${arg_name}]`}>
|
|
||||||
{state.args[arg_name] as string}
|
|
||||||
</textarea>
|
|
||||||
) : (
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name={`$.args[${arg_name}]`}
|
|
||||||
value={state.args[arg_name] as string}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<input type="submit" value="Preview" />
|
<input type="submit" value="Preview" />
|
||||||
</fieldset>
|
<select
|
||||||
<fieldset>
|
name="$.component"
|
||||||
<legend>Preview</legend>
|
onchange="this.closest('form').requestSubmit()"
|
||||||
{render(
|
>
|
||||||
registry,
|
{Object.entries(all_components).map(([name]) => (
|
||||||
[{ component_name: state.component, args: state.args }],
|
<option value={name} selected={name == state.component}>
|
||||||
simpleJDDContext
|
{name}
|
||||||
)}
|
</option>
|
||||||
</fieldset>
|
))}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<fieldset class="component-preview-parameters">
|
||||||
|
<legend>Parameters</legend>
|
||||||
|
{Object.entries(component.getArguments()).map(([arg_name, arg]) =>
|
||||||
|
this.renderArgumentInput(
|
||||||
|
state,
|
||||||
|
[arg_name],
|
||||||
|
arg,
|
||||||
|
state.args[arg_name]
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<input type="submit" value="Preview" />
|
||||||
|
</fieldset>
|
||||||
|
<div>{JSON.stringify(state)}</div>
|
||||||
|
</div>
|
||||||
|
<div class="resize-gutter"></div>
|
||||||
|
{
|
||||||
|
/* HTML */ `<script>
|
||||||
|
(function () {
|
||||||
|
let is_resizing = false;
|
||||||
|
let origin_x;
|
||||||
|
let origin_width;
|
||||||
|
const gutter = document.querySelector(".resize-gutter");
|
||||||
|
const resizable = document.querySelector(".resizable");
|
||||||
|
const move_listener = (e) => {
|
||||||
|
const new_width = Math.max(
|
||||||
|
origin_width + (e.clientX - origin_x),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--resizable-column-width",
|
||||||
|
new_width + "px"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
gutter.addEventListener("mousedown", (e) => {
|
||||||
|
is_resizing = true;
|
||||||
|
origin_x = e.clientX;
|
||||||
|
origin_width = resizable.getBoundingClientRect().width;
|
||||||
|
document.addEventListener("mousemove", move_listener);
|
||||||
|
document.addEventListener("mouseup", () => {
|
||||||
|
document.removeEventListener(
|
||||||
|
"mousemove",
|
||||||
|
move_listener
|
||||||
|
);
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>`
|
||||||
|
}
|
||||||
|
<div>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Preview</legend>
|
||||||
|
{render(
|
||||||
|
registry,
|
||||||
|
[{ component_name: state.component, args: state.args }],
|
||||||
|
simpleJDDContext
|
||||||
|
)}
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapInForm(state: State, content: Templatable): Templatable {
|
||||||
|
// return tempstream/* HTML */ `<turbo-frame id="components">
|
||||||
|
// ${super.wrapInForm(state, content)}
|
||||||
|
// </turbo-frame> `;
|
||||||
|
// }
|
||||||
})();
|
})();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* DO NOT EDIT! This file is generated automaticaly with npx sealgen generate-scss-includes */
|
/* DO NOT EDIT! This file is generated automaticaly with npx sealgen generate-css-includes */
|
||||||
|
|
||||||
@import "../node_modules/@sealcode/sealgen/src/forms/forms.css";
|
@import "../node_modules/@sealcode/sealgen/src/forms/forms.css";
|
||||||
@import "back/jdd-components/using-images/using-images.css";
|
|
||||||
@import "back/routes/common/ui/input.css";
|
@import "back/routes/common/ui/input.css";
|
||||||
|
@import "back/routes/components.css";
|
||||||
@import "tables.css";
|
@import "tables.css";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user