Update JDD and adjust the components API
This commit is contained in:
parent
19d04ff48b
commit
106fcc86c8
74
package-lock.json
generated
74
package-lock.json
generated
@ -13,11 +13,12 @@
|
|||||||
"@hotwired/turbo": "^8.0.2",
|
"@hotwired/turbo": "^8.0.2",
|
||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"@sealcode/file-manager": "^1.0.2",
|
"@sealcode/file-manager": "^1.0.2",
|
||||||
"@sealcode/jdd": "^0.4.10",
|
"@sealcode/jdd": "^0.5.0",
|
||||||
"@sealcode/sealgen": "^0.15.45",
|
"@sealcode/sealgen": "^0.15.45",
|
||||||
"@sealcode/ts-predicates": "^0.6.2",
|
"@sealcode/ts-predicates": "^0.6.2",
|
||||||
"@types/kill-port": "^2.0.0",
|
"@types/kill-port": "^2.0.0",
|
||||||
"@types/leaflet": "^1.9.8",
|
"@types/leaflet": "^1.9.8",
|
||||||
|
"@types/turndown": "^5.0.4",
|
||||||
"escape-goat": "^4.0.0",
|
"escape-goat": "^4.0.0",
|
||||||
"get-port": "^7.0.0",
|
"get-port": "^7.0.0",
|
||||||
"js-convert-case": "^4.2.0",
|
"js-convert-case": "^4.2.0",
|
||||||
@ -29,7 +30,9 @@
|
|||||||
"qs": "^6.12.0",
|
"qs": "^6.12.0",
|
||||||
"sealious": "^0.19.9",
|
"sealious": "^0.19.9",
|
||||||
"stimulus": "^3.2.2",
|
"stimulus": "^3.2.2",
|
||||||
"tempstream": "^0.3.16"
|
"tempstream": "^0.3.16",
|
||||||
|
"throttle-debounce": "^5.0.2",
|
||||||
|
"turndown": "^7.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
@ -38,6 +41,7 @@
|
|||||||
"@types/node": "^20.8.4",
|
"@types/node": "^20.8.4",
|
||||||
"@types/object-path": "^0.11.4",
|
"@types/object-path": "^0.11.4",
|
||||||
"@types/tedious": "^4.0.7",
|
"@types/tedious": "^4.0.7",
|
||||||
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "7.4",
|
"@typescript-eslint/eslint-plugin": "7.4",
|
||||||
"@typescript-eslint/parser": "7.4",
|
"@typescript-eslint/parser": "7.4",
|
||||||
@ -731,6 +735,11 @@
|
|||||||
"node": ">= 12"
|
"node": ">= 12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mixmark-io/domino": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="
|
||||||
|
},
|
||||||
"node_modules/@mongodb-js/saslprep": {
|
"node_modules/@mongodb-js/saslprep": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.5.tgz",
|
||||||
@ -824,19 +833,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sealcode/jdd": {
|
"node_modules/@sealcode/jdd": {
|
||||||
"version": "0.4.10",
|
"version": "0.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sealcode/jdd/-/jdd-0.4.10.tgz",
|
"resolved": "https://registry.npmjs.org/@sealcode/jdd/-/jdd-0.5.0.tgz",
|
||||||
"integrity": "sha512-WAZcE0hMDzs29nhrlhH5k5OQrIPV8zSg44pA5FA1uONpBjg4JSb8Y04gzadP5rTQflV68kOAEjmqJs4MFT4JvA==",
|
"integrity": "sha512-5HkFzV7pHfmLg2Ta9+TocueLJUpQrodJ+n1ymY2RkiAzEuVSCnZr5ZAXpreDVbcz2PxDUq94ygVpOPMtS7pkGQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sealcode/file-manager": "^1.0.2",
|
"@sealcode/file-manager": "^1.0.2",
|
||||||
"@sealcode/ts-predicates": "^0.5.3",
|
"@sealcode/ts-predicates": "^0.5.3",
|
||||||
"escape-goat": "^4.0.0",
|
"escape-goat": "^4.0.0",
|
||||||
"koa-responsive-image-router": "^0.2.19",
|
"hyphenopoly": "^5.3.0",
|
||||||
|
"koa-responsive-image-router": "^0.2.29",
|
||||||
"locreq": "^3.0.0",
|
"locreq": "^3.0.0",
|
||||||
"marked": "^12.0.0",
|
"marked": "^12.0.0",
|
||||||
"mri": "^1.2.0",
|
"mri": "^1.2.0",
|
||||||
"tempstream": "^0.3.4",
|
"prettier": "^2.7.1",
|
||||||
|
"tempstream": "^0.3.18",
|
||||||
"uuid": "^9.0.1"
|
"uuid": "^9.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"sealious": "^0.19.18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sealcode/jdd/node_modules/@sealcode/ts-predicates": {
|
"node_modules/@sealcode/jdd/node_modules/@sealcode/ts-predicates": {
|
||||||
@ -1347,6 +1361,18 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/throttle-debounce": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/turndown": {
|
||||||
|
"version": "5.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.4.tgz",
|
||||||
|
"integrity": "sha512-28GI33lCCkU4SGH1GvjDhFgOVr+Tym4PXGBIU1buJUa6xQolniPArtUT+kv42RR2N9MsMLInkr904Aq+ESHBJg=="
|
||||||
|
},
|
||||||
"node_modules/@types/uuid": {
|
"node_modules/@types/uuid": {
|
||||||
"version": "9.0.8",
|
"version": "9.0.8",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
@ -4742,6 +4768,14 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hyphenopoly": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hyphenopoly/-/hyphenopoly-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-9GajH50TuO+c25VzYUq2luYpyOybpVcDQ4B7fNWy+n3yQ3dSLRFcEC9oJqG96C/rE5Z3zVP8L/K/3ilzBa49PA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
@ -8736,8 +8770,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sealious": {
|
"node_modules/sealious": {
|
||||||
"version": "0.19.9",
|
"version": "0.19.21",
|
||||||
"license": "BSD-2-Clause",
|
"resolved": "https://registry.npmjs.org/sealious/-/sealious-0.19.21.tgz",
|
||||||
|
"integrity": "sha512-2LVVD30q9X5MhgmpKnGMQ4351I0awr243DzSFy6sk3ZCsfPo63TZ/5vZbBwhK84Lf+BPRbP9pCkz+m2BdG8AHQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"@sealcode/file-manager": "^1.0.1",
|
"@sealcode/file-manager": "^1.0.1",
|
||||||
@ -9504,8 +9539,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tempstream": {
|
"node_modules/tempstream": {
|
||||||
"version": "0.3.16",
|
"version": "0.3.18",
|
||||||
"license": "ISC",
|
"resolved": "https://registry.npmjs.org/tempstream/-/tempstream-0.3.18.tgz",
|
||||||
|
"integrity": "sha512-0V/efjocOnjQtBFC6tR8twlI+ygRNgpisOLneVd+Uma9Oic6fo67OqCwEdrIN2DHs3H72St4ACPqHmnlI1YRag==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"classnames": "^2.5.1"
|
"classnames": "^2.5.1"
|
||||||
}
|
}
|
||||||
@ -9583,6 +9619,14 @@
|
|||||||
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/throttle-debounce": {
|
||||||
|
"version": "5.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz",
|
||||||
|
"integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tiny-glob": {
|
"node_modules/tiny-glob": {
|
||||||
"version": "0.2.9",
|
"version": "0.2.9",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||||
@ -9864,6 +9908,14 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/turndown": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@mixmark-io/domino": "^2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
|
@ -44,11 +44,12 @@
|
|||||||
"@hotwired/turbo": "^8.0.2",
|
"@hotwired/turbo": "^8.0.2",
|
||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"@sealcode/file-manager": "^1.0.2",
|
"@sealcode/file-manager": "^1.0.2",
|
||||||
"@sealcode/jdd": "^0.4.10",
|
"@sealcode/jdd": "^0.5.0",
|
||||||
"@sealcode/sealgen": "^0.15.45",
|
"@sealcode/sealgen": "^0.15.45",
|
||||||
"@sealcode/ts-predicates": "^0.6.2",
|
"@sealcode/ts-predicates": "^0.6.2",
|
||||||
"@types/kill-port": "^2.0.0",
|
"@types/kill-port": "^2.0.0",
|
||||||
"@types/leaflet": "^1.9.8",
|
"@types/leaflet": "^1.9.8",
|
||||||
|
"@types/turndown": "^5.0.4",
|
||||||
"escape-goat": "^4.0.0",
|
"escape-goat": "^4.0.0",
|
||||||
"get-port": "^7.0.0",
|
"get-port": "^7.0.0",
|
||||||
"js-convert-case": "^4.2.0",
|
"js-convert-case": "^4.2.0",
|
||||||
@ -60,7 +61,9 @@
|
|||||||
"qs": "^6.12.0",
|
"qs": "^6.12.0",
|
||||||
"sealious": "^0.19.9",
|
"sealious": "^0.19.9",
|
||||||
"stimulus": "^3.2.2",
|
"stimulus": "^3.2.2",
|
||||||
"tempstream": "^0.3.16"
|
"tempstream": "^0.3.16",
|
||||||
|
"throttle-debounce": "^5.0.2",
|
||||||
|
"turndown": "^7.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.44.1",
|
||||||
@ -69,6 +72,7 @@
|
|||||||
"@types/node": "^20.8.4",
|
"@types/node": "^20.8.4",
|
||||||
"@types/object-path": "^0.11.4",
|
"@types/object-path": "^0.11.4",
|
||||||
"@types/tedious": "^4.0.7",
|
"@types/tedious": "^4.0.7",
|
||||||
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@types/uuid": "^9.0.8",
|
"@types/uuid": "^9.0.8",
|
||||||
"@typescript-eslint/eslint-plugin": "7.4",
|
"@typescript-eslint/eslint-plugin": "7.4",
|
||||||
"@typescript-eslint/parser": "7.4",
|
"@typescript-eslint/parser": "7.4",
|
||||||
|
1
secrets.json
Normal file
1
secrets.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
@ -33,6 +33,7 @@ export type HTMLOptions = {
|
|||||||
autoRefreshCSS?: boolean;
|
autoRefreshCSS?: boolean;
|
||||||
disableCopyEvent?: boolean;
|
disableCopyEvent?: boolean;
|
||||||
language?: string;
|
language?: string;
|
||||||
|
bodyClasses?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function html(
|
export default function html(
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
import type { FlatTemplatable } from "tempstream";
|
|
||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type {
|
import type { ComponentToHTMLArgs } from "@sealcode/jdd";
|
||||||
ExtractStructuredComponentArgumentsParsed,
|
|
||||||
JDDContext,
|
|
||||||
} from "@sealcode/jdd";
|
|
||||||
import { Component, ComponentArguments } from "@sealcode/jdd";
|
import { Component, ComponentArguments } from "@sealcode/jdd";
|
||||||
|
|
||||||
import arrow from "./autoscrolling-images-arrow.svg";
|
import arrow from "./autoscrolling-images-arrow.svg";
|
||||||
@ -25,15 +21,10 @@ export class AutoscrollingImages extends Component<typeof component_arguments> {
|
|||||||
return component_arguments;
|
return component_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
toHTML(
|
toHTML({
|
||||||
{
|
args: { title, interval, imagesPerPage, images },
|
||||||
title,
|
jdd_context: { render_image },
|
||||||
interval,
|
}: ComponentToHTMLArgs<typeof component_arguments>) {
|
||||||
imagesPerPage,
|
|
||||||
images,
|
|
||||||
}: ExtractStructuredComponentArgumentsParsed<typeof component_arguments>,
|
|
||||||
{ render_image }: JDDContext
|
|
||||||
): FlatTemplatable {
|
|
||||||
const imageNumberPerPage = parseInt(imagesPerPage);
|
const imageNumberPerPage = parseInt(imagesPerPage);
|
||||||
const parsedImagesArray = [];
|
const parsedImagesArray = [];
|
||||||
|
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
import type { FlatTemplatable } from "tempstream";
|
import type { FlatTemplatable } from "tempstream";
|
||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type {
|
import type { ComponentToHTMLArgs, ExtractParsed, JDDContext } from "@sealcode/jdd";
|
||||||
ExtractParsed,
|
|
||||||
ExtractStructuredComponentArgumentsParsed,
|
|
||||||
JDDContext,
|
|
||||||
} from "@sealcode/jdd";
|
|
||||||
import { Component, ComponentArguments } from "@sealcode/jdd";
|
import { Component, ComponentArguments } from "@sealcode/jdd";
|
||||||
|
|
||||||
type ExtractArray<T> = T extends Array<infer X> ? X : never;
|
type ExtractArray<T> = T extends Array<infer X> ? X : never;
|
||||||
@ -123,13 +119,10 @@ export class DynamicGrid extends Component<typeof component_arguments> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toHTML(
|
toHTML({
|
||||||
{
|
args: { heading, tabs },
|
||||||
heading,
|
jdd_context,
|
||||||
tabs,
|
}: ComponentToHTMLArgs<typeof component_arguments>): FlatTemplatable {
|
||||||
}: ExtractStructuredComponentArgumentsParsed<typeof component_arguments>,
|
|
||||||
jdd_context: JDDContext
|
|
||||||
): FlatTemplatable {
|
|
||||||
const { value: id } = generate_id.next();
|
const { value: id } = generate_id.next();
|
||||||
return (
|
return (
|
||||||
<div class="dynamic-grid-component">
|
<div class="dynamic-grid-component">
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import type { FlatTemplatable } from "tempstream";
|
import type { FlatTemplatable } from "tempstream";
|
||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type {
|
import type { ComponentToHTMLArgs } from "@sealcode/jdd";
|
||||||
ExtractStructuredComponentArgumentsParsed,
|
|
||||||
JDDContext,
|
|
||||||
} from "@sealcode/jdd";
|
|
||||||
import { Component, ComponentArguments } from "@sealcode/jdd";
|
import { Component, ComponentArguments } from "@sealcode/jdd";
|
||||||
|
|
||||||
const component_arguments = {
|
const component_arguments = {
|
||||||
@ -29,15 +26,10 @@ export class FaqComponent extends Component<typeof component_arguments> {
|
|||||||
return component_arguments;
|
return component_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
toHTML(
|
toHTML({
|
||||||
{
|
args: { title, content, faq, button },
|
||||||
title,
|
jdd_context: { render_markdown, language },
|
||||||
content,
|
}: ComponentToHTMLArgs<typeof component_arguments>): FlatTemplatable {
|
||||||
faq,
|
|
||||||
button,
|
|
||||||
}: ExtractStructuredComponentArgumentsParsed<typeof component_arguments>,
|
|
||||||
{ render_markdown }: JDDContext
|
|
||||||
): FlatTemplatable {
|
|
||||||
const buttonText = button.buttonText.toUpperCase();
|
const buttonText = button.buttonText.toUpperCase();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -46,7 +38,7 @@ export class FaqComponent extends Component<typeof component_arguments> {
|
|||||||
<div class="title-container">
|
<div class="title-container">
|
||||||
<div class="title">{title} </div>
|
<div class="title">{title} </div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{render_markdown(content.text)}{" "}
|
{render_markdown(language, content.text)}{" "}
|
||||||
<strong>{content.number}</strong>
|
<strong>{content.number}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -56,7 +48,7 @@ export class FaqComponent extends Component<typeof component_arguments> {
|
|||||||
<details class="question-container" open={index == 0}>
|
<details class="question-container" open={index == 0}>
|
||||||
<summary class="question">{element.question}</summary>
|
<summary class="question">{element.question}</summary>
|
||||||
<div class="answer">
|
<div class="answer">
|
||||||
<p>{render_markdown(element.answer)}</p>
|
<p>{render_markdown(language, element.answer)}</p>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
))}
|
))}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import type { FlatTemplatable } from "tempstream";
|
import type { FlatTemplatable } from "tempstream";
|
||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type {
|
import type { ComponentToHTMLArgs } from "@sealcode/jdd";
|
||||||
ExtractStructuredComponentArgumentsParsed,
|
|
||||||
JDDContext,
|
|
||||||
} from "@sealcode/jdd";
|
|
||||||
import { Component, ComponentArguments } from "@sealcode/jdd";
|
import { Component, ComponentArguments } from "@sealcode/jdd";
|
||||||
|
|
||||||
const component_arguments = {
|
const component_arguments = {
|
||||||
@ -24,15 +21,10 @@ export class HeaderWithImage extends Component<typeof component_arguments> {
|
|||||||
return component_arguments;
|
return component_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
toHTML(
|
toHTML({
|
||||||
{
|
args: { title, content, image_with_alt, button },
|
||||||
title,
|
jdd_context: { render_markdown, render_image, language },
|
||||||
content,
|
}: ComponentToHTMLArgs<typeof component_arguments>): FlatTemplatable {
|
||||||
image_with_alt,
|
|
||||||
button,
|
|
||||||
}: ExtractStructuredComponentArgumentsParsed<typeof component_arguments>,
|
|
||||||
{ render_markdown, render_image }: JDDContext
|
|
||||||
): FlatTemplatable {
|
|
||||||
const buttonText = button.text.toUpperCase();
|
const buttonText = button.text.toUpperCase();
|
||||||
const titleUpperCase = title.toUpperCase();
|
const titleUpperCase = title.toUpperCase();
|
||||||
|
|
||||||
@ -49,7 +41,7 @@ export class HeaderWithImage extends Component<typeof component_arguments> {
|
|||||||
<div class="title-wrapper">
|
<div class="title-wrapper">
|
||||||
<h2 class="title">{titleUpperCase}</h2>
|
<h2 class="title">{titleUpperCase}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">{render_markdown(content)}</div>
|
<div class="content">{render_markdown(language, content)}</div>
|
||||||
{button.text === "" ? null : (
|
{button.text === "" ? null : (
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<a class="button" href={button.link}>
|
<a class="button" href={button.link}>
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
import type { FlatTemplatable } from "tempstream";
|
import type { FlatTemplatable } from "tempstream";
|
||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type {
|
import type { ComponentToHTMLArgs } from "@sealcode/jdd";
|
||||||
ExtractStructuredComponentArgumentsParsed,
|
|
||||||
JDDContext,
|
|
||||||
} from "@sealcode/jdd";
|
|
||||||
import { Component, ComponentArguments } from "@sealcode/jdd";
|
import { Component, ComponentArguments } from "@sealcode/jdd";
|
||||||
|
|
||||||
const component_arguments = {
|
const component_arguments = {
|
||||||
@ -19,13 +16,10 @@ export class ImageDemo extends Component<typeof component_arguments> {
|
|||||||
return component_arguments;
|
return component_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
toHTML(
|
toHTML({
|
||||||
{
|
args: { image_with_alt, multiple_images },
|
||||||
image_with_alt,
|
jdd_context: { render_image },
|
||||||
multiple_images,
|
}: ComponentToHTMLArgs<typeof component_arguments>): FlatTemplatable {
|
||||||
}: ExtractStructuredComponentArgumentsParsed<typeof component_arguments>,
|
|
||||||
{ render_image }: JDDContext
|
|
||||||
): FlatTemplatable {
|
|
||||||
return (
|
return (
|
||||||
<div class="image-demo">
|
<div class="image-demo">
|
||||||
<h2>Image with alt text</h2>
|
<h2>Image with alt text</h2>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { FlatTemplatable } from "tempstream";
|
|
||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type { ExtractStructuredComponentArgumentsParsed } from "@sealcode/jdd";
|
import type { ComponentToHTMLArgs } from "@sealcode/jdd";
|
||||||
import { Component, ComponentArguments } from "@sealcode/jdd";
|
import { Component, ComponentArguments } from "@sealcode/jdd";
|
||||||
|
|
||||||
const coordinates = new ComponentArguments.ShortText();
|
const coordinates = new ComponentArguments.ShortText();
|
||||||
@ -49,11 +48,7 @@ export class MapWithPins extends Component<typeof component_arguments> {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
toHTML({
|
toHTML({ args: { pins } }: ComponentToHTMLArgs<typeof component_arguments>) {
|
||||||
pins,
|
|
||||||
}: ExtractStructuredComponentArgumentsParsed<
|
|
||||||
typeof component_arguments
|
|
||||||
>): FlatTemplatable {
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class="map-with-pins"
|
class="map-with-pins"
|
||||||
|
0
src/back/jdd-components/map-with-pins/newFile.tsx
Normal file
0
src/back/jdd-components/map-with-pins/newFile.tsx
Normal file
@ -1,8 +1,5 @@
|
|||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type {
|
import type { ComponentToHTMLArgs } from "@sealcode/jdd";
|
||||||
ExtractStructuredComponentArgumentsParsed,
|
|
||||||
JDDContext,
|
|
||||||
} from "@sealcode/jdd";
|
|
||||||
import { Component, ComponentArguments } from "@sealcode/jdd";
|
import { Component, ComponentArguments } from "@sealcode/jdd";
|
||||||
import type { Readable } from "stream";
|
import type { Readable } from "stream";
|
||||||
|
|
||||||
@ -22,18 +19,15 @@ export class NiceBox extends Component<typeof component_arguments> {
|
|||||||
return component_arguments;
|
return component_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
async toHTML(
|
async toHTML({
|
||||||
{
|
args: { title, content, images },
|
||||||
title,
|
classes,
|
||||||
content,
|
jdd_context: { render_markdown, render_image, language },
|
||||||
images,
|
}: ComponentToHTMLArgs<typeof component_arguments>): Promise<Readable> {
|
||||||
}: ExtractStructuredComponentArgumentsParsed<typeof component_arguments>,
|
|
||||||
{ render_markdown, render_image }: JDDContext
|
|
||||||
): Promise<Readable> {
|
|
||||||
return (
|
return (
|
||||||
<div class="nice-box">
|
<div class={["nice-box", ...classes]}>
|
||||||
<h2>{title}</h2>
|
<h2>{title}</h2>
|
||||||
<div>{render_markdown(content)}</div>
|
<div>{render_markdown(language, content)}</div>
|
||||||
{images.map((image) =>
|
{images.map((image) =>
|
||||||
render_image(image.image, {
|
render_image(image.image, {
|
||||||
container: {
|
container: {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import type { FlatTemplatable } from "tempstream";
|
|
||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type { ExtractStructuredComponentArgumentsParsed } from "@sealcode/jdd";
|
import type { ComponentToHTMLArgs } from "@sealcode/jdd";
|
||||||
import { Component, ComponentArguments, isTableHeader } from "@sealcode/jdd";
|
import { Component, ComponentArguments, isTableHeader } from "@sealcode/jdd";
|
||||||
|
|
||||||
const component_arguments = {
|
const component_arguments = {
|
||||||
@ -23,11 +22,7 @@ export class Table extends Component<typeof component_arguments> {
|
|||||||
return component_arguments;
|
return component_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
toHTML({
|
toHTML({ args: { table } }: ComponentToHTMLArgs<typeof component_arguments>) {
|
||||||
table,
|
|
||||||
}: ExtractStructuredComponentArgumentsParsed<
|
|
||||||
typeof component_arguments
|
|
||||||
>): FlatTemplatable {
|
|
||||||
return (
|
return (
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<table>
|
<table>
|
||||||
|
@ -7,6 +7,7 @@ import { imageRouter } from "./image-router.js";
|
|||||||
|
|
||||||
export function makeJDDContext(ctx: BaseContext): JDDContext {
|
export function makeJDDContext(ctx: BaseContext): JDDContext {
|
||||||
return {
|
return {
|
||||||
|
language: "pl",
|
||||||
...makeSimpleJDDContext(TheFileManager),
|
...makeSimpleJDDContext(TheFileManager),
|
||||||
render_image: async (image: string | FilePointer | null, args) => {
|
render_image: async (image: string | FilePointer | null, args) => {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-unsafe-assignment */
|
||||||
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
|
export default class AutogrowTextarea extends Controller<HTMLTextAreaElement> {
|
||||||
|
connect() {
|
||||||
|
this.autogrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
autogrow() {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
|
||||||
|
(this.element.parentNode as any).dataset.replicatedValue = this.element.value;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,16 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
|
||||||
import { Controller } from "stimulus";
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
export default class ComponentDebugger extends Controller {
|
export default class ComponentDebugger extends Controller {
|
||||||
|
declare gutterTarget: HTMLDivElement;
|
||||||
|
declare checkboxTarget: HTMLInputElement;
|
||||||
|
declare checkboxTargets: HTMLInputElement[];
|
||||||
|
declare previewTarget: HTMLDivElement;
|
||||||
|
declare componentBlockTargets: HTMLDivElement[];
|
||||||
|
declare componentBlockTargetDisconnected: (e: HTMLDivElement) => void;
|
||||||
|
static targets = ["gutter", "componentBlock", "checkbox", "preview"];
|
||||||
|
|
||||||
id: string;
|
id: string;
|
||||||
main_form: HTMLFormElement;
|
main_form: HTMLFormElement;
|
||||||
is_resizing = false;
|
is_resizing = false;
|
||||||
@ -26,7 +36,7 @@ export default class ComponentDebugger extends Controller {
|
|||||||
document.addEventListener("turbo:render", () => this.update_width_display());
|
document.addEventListener("turbo:render", () => this.update_width_display());
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
const gutter = this.targets.find("gutter") as HTMLDivElement;
|
const gutter = this.gutterTarget;
|
||||||
gutter.addEventListener("mousedown", (e) => {
|
gutter.addEventListener("mousedown", (e) => {
|
||||||
this.is_resizing = true;
|
this.is_resizing = true;
|
||||||
this.origin_x = e.clientX;
|
this.origin_x = e.clientX;
|
||||||
@ -74,4 +84,82 @@ export default class ComponentDebugger extends Controller {
|
|||||||
const value = dropdown.value;
|
const value = dropdown.value;
|
||||||
this.setPreviewWidth(parseInt(value));
|
this.setPreviewWidth(parseInt(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentBlockTargetConnected(block_element: HTMLDivElement) {
|
||||||
|
const index = parseInt(block_element.getAttribute("data-component-index"));
|
||||||
|
block_element.addEventListener("focusin", () => {
|
||||||
|
this.scrollToComponentPreview(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
previewTargetConnected(preview_element: HTMLDivElement) {
|
||||||
|
preview_element.addEventListener("click", ({ target }) => {
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const closest = target.closest(".jdd-component");
|
||||||
|
if (!closest) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const index = parseInt(
|
||||||
|
Array.from(closest.classList)
|
||||||
|
.find((c) => c.startsWith("component-number-"))
|
||||||
|
?.replace("component-number-", "")
|
||||||
|
);
|
||||||
|
if (isNaN(index)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.focusComponentBlock(index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
focusComponentBlock(index: number) {
|
||||||
|
const block = this.componentBlockTargets[index];
|
||||||
|
if (!block) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.checkboxTargets[index].checked = true;
|
||||||
|
block.scrollIntoView({ behavior: "smooth" });
|
||||||
|
(
|
||||||
|
block.querySelector(".component-preview-parameters input") as HTMLInputElement
|
||||||
|
)?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
getIndex(block_element: HTMLDivElement) {
|
||||||
|
const index = parseInt(block_element.getAttribute("data-component-index"));
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
labelClicked(element: MouseEvent) {
|
||||||
|
const block_element = (element.target as HTMLDivElement).closest(
|
||||||
|
`[data-component-debugger-target="componentBlock"]`
|
||||||
|
) as HTMLDivElement;
|
||||||
|
const index = this.getIndex(block_element);
|
||||||
|
if (!this.checkboxTargets?.[index].checked) {
|
||||||
|
this.scrollToComponentPreview(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreviewElementForComponentIndex(index: number) {
|
||||||
|
const element = this.element.querySelector(
|
||||||
|
`.component-number-${index}`
|
||||||
|
) as HTMLDialogElement;
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollToComponentPreview(index: number) {
|
||||||
|
const element = this.getPreviewElementForComponentIndex(index);
|
||||||
|
if (!element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const preview_element = this.element.querySelector(".component-preview");
|
||||||
|
if (element.clientHeight > preview_element.clientHeight) {
|
||||||
|
preview_element.scrollTop = element.offsetTop - 44;
|
||||||
|
} else {
|
||||||
|
preview_element.scrollTop =
|
||||||
|
element.offsetTop -
|
||||||
|
(preview_element.clientHeight - element.clientHeight) / 2 -
|
||||||
|
44;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ export function ComponentInputImage<State extends JDDPageState>({
|
|||||||
arg,
|
arg,
|
||||||
value,
|
value,
|
||||||
ctx,
|
ctx,
|
||||||
|
page,
|
||||||
|
state,
|
||||||
}: {
|
}: {
|
||||||
state: State;
|
state: State;
|
||||||
arg_path: string[];
|
arg_path: string[];
|
||||||
@ -30,13 +32,16 @@ export function ComponentInputImage<State extends JDDPageState>({
|
|||||||
data-controller="input-image-preview"
|
data-controller="input-image-preview"
|
||||||
>
|
>
|
||||||
{arg_path.at(-1) || ""}
|
{arg_path.at(-1) || ""}
|
||||||
{value &&
|
<div class="image-preview-container">
|
||||||
jdd_context.render_image(value, {
|
{value &&
|
||||||
container: { width: 40, height: 40, objectFit: "cover" },
|
jdd_context.render_image(value, {
|
||||||
crop: { width: 40, height: 40 },
|
container: { width: 40, height: 40, objectFit: "cover" },
|
||||||
style: "height: 40px; width: 40px;",
|
crop: { width: 40, height: 40 },
|
||||||
alt: "",
|
style: "height: 40px; width: 40px;",
|
||||||
})}
|
alt: "",
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
name={`$${printArgPath(arg_path)}.new`}
|
name={`$${printArgPath(arg_path)}.new`}
|
||||||
@ -54,6 +59,14 @@ export function ComponentInputImage<State extends JDDPageState>({
|
|||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{page.makeActionButton(
|
||||||
|
state,
|
||||||
|
{
|
||||||
|
action: "remove_file",
|
||||||
|
label: "❌",
|
||||||
|
},
|
||||||
|
arg_path
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
import type { BaseContext } from "koa";
|
||||||
|
import type { SingleReference } from "@sealcode/jdd";
|
||||||
|
import { TempstreamJSX } from "tempstream";
|
||||||
|
import { makeJDDContext } from "../../jdd-context.js";
|
||||||
|
import { printArgPath } from "./print-arg-path.js";
|
||||||
|
|
||||||
|
export async function ComponentInputSingleReference<
|
||||||
|
State,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
T extends SingleReference<any>
|
||||||
|
>({
|
||||||
|
ctx,
|
||||||
|
arg_path,
|
||||||
|
arg,
|
||||||
|
value,
|
||||||
|
onchange,
|
||||||
|
}: {
|
||||||
|
ctx: BaseContext;
|
||||||
|
state: State;
|
||||||
|
arg_path: string[];
|
||||||
|
arg: T;
|
||||||
|
value: string;
|
||||||
|
onchange?: string;
|
||||||
|
}): Promise<import("stream").Readable> {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
{arg_path.at(-1) || ""}
|
||||||
|
<select name={`$${printArgPath(arg_path)}`} onchange={onchange}>
|
||||||
|
{(await arg.getValues(makeJDDContext(ctx))).map((v) => (
|
||||||
|
<option value={v.value} selected={value == v.value}>
|
||||||
|
{v.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -3,6 +3,7 @@ import { isTableHeader } from "@sealcode/jdd";
|
|||||||
import type { StatefulPage } from "@sealcode/sealgen";
|
import type { StatefulPage } from "@sealcode/sealgen";
|
||||||
import type { BaseContext } from "koa";
|
import type { BaseContext } from "koa";
|
||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
|
import { makeJDDContext } from "../../jdd-context.js";
|
||||||
import { ComponentInput } from "./component-input.js";
|
import { ComponentInput } from "./component-input.js";
|
||||||
import type { ComponentPreviewActions } from "./component-preview-actions.js";
|
import type { ComponentPreviewActions } from "./component-preview-actions.js";
|
||||||
import type { JDDPageState } from "./jdd-page.js";
|
import type { JDDPageState } from "./jdd-page.js";
|
||||||
@ -34,7 +35,7 @@ export async function ComponentInputTable<
|
|||||||
page: StatefulPage<JDDPageState, typeof ComponentPreviewActions>;
|
page: StatefulPage<JDDPageState, typeof ComponentPreviewActions>;
|
||||||
}): Promise<import("stream").Readable> {
|
}): Promise<import("stream").Readable> {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
value = arg.getEmptyValue();
|
value = await arg.getEmptyValue(makeJDDContext(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { printArgPath } from "./print-arg-path.js";
|
import { printArgPath } from "./print-arg-path.js";
|
||||||
import type { BaseContext } from "koa";
|
import type { BaseContext } from "koa";
|
||||||
import type { ComponentArgument, TableData } from "@sealcode/jdd";
|
import type { ComponentArgument, TableData } from "@sealcode/jdd";
|
||||||
|
import { SingleReference } from "@sealcode/jdd";
|
||||||
import { ComponentArguments, Enum, Image, List, Structured, Table } from "@sealcode/jdd";
|
import { ComponentArguments, Enum, Image, List, Structured, Table } from "@sealcode/jdd";
|
||||||
import { ComponentInputStructured } from "./component-input-structured.js";
|
import { ComponentInputStructured } from "./component-input-structured.js";
|
||||||
import type { StatefulPage } from "@sealcode/sealgen";
|
import type { StatefulPage } from "@sealcode/sealgen";
|
||||||
@ -14,11 +15,13 @@ import { ComponentInputTable } from "./component-input-table.js";
|
|||||||
import { TempstreamJSX } from "tempstream";
|
import { TempstreamJSX } from "tempstream";
|
||||||
import type { FilePointer } from "@sealcode/file-manager";
|
import type { FilePointer } from "@sealcode/file-manager";
|
||||||
import { is, predicates } from "@sealcode/ts-predicates";
|
import { is, predicates } from "@sealcode/ts-predicates";
|
||||||
|
import { makeJDDContext } from "../../jdd-context.js";
|
||||||
|
import { ComponentInputSingleReference } from "./component-input-single-reference.js";
|
||||||
|
|
||||||
export const actionName = "Components";
|
export const actionName = "Components";
|
||||||
const absoluteUrlPattern = "http(s?)(://)((www.)?)(([^.]+).)?([a-zA-z0-9-_]+)";
|
const absoluteUrlPattern = "http(s?)(://)((www.)?)(([^.]+).)?([a-zA-z0-9-_]+)";
|
||||||
|
|
||||||
export function ComponentInput<State extends JDDPageState, T>({
|
export async function ComponentInput<State extends JDDPageState, T>({
|
||||||
ctx,
|
ctx,
|
||||||
state,
|
state,
|
||||||
arg_path,
|
arg_path,
|
||||||
@ -32,9 +35,9 @@ export function ComponentInput<State extends JDDPageState, T>({
|
|||||||
arg: ComponentArgument<T>;
|
arg: ComponentArgument<T>;
|
||||||
value: T;
|
value: T;
|
||||||
page: StatefulPage<JDDPageState, typeof ComponentPreviewActions>;
|
page: StatefulPage<JDDPageState, typeof ComponentPreviewActions>;
|
||||||
}): Readable | Promise<Readable> {
|
}): Promise<Readable> {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
value = arg.getEmptyValue();
|
value = await arg.getEmptyValue(makeJDDContext(ctx));
|
||||||
}
|
}
|
||||||
if (arg instanceof List) {
|
if (arg instanceof List) {
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
@ -66,6 +69,18 @@ export function ComponentInput<State extends JDDPageState, T>({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg instanceof SingleReference) {
|
||||||
|
return ComponentInputSingleReference({
|
||||||
|
ctx,
|
||||||
|
state,
|
||||||
|
arg_path,
|
||||||
|
arg,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
value: value as string,
|
||||||
|
onchange: page.rerender(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (arg instanceof Enum) {
|
if (arg instanceof Enum) {
|
||||||
return ComponentInputEnum({
|
return ComponentInputEnum({
|
||||||
state,
|
state,
|
||||||
@ -106,13 +121,21 @@ export function ComponentInput<State extends JDDPageState, T>({
|
|||||||
<label>
|
<label>
|
||||||
{arg_path.at(-1) || ""}
|
{arg_path.at(-1) || ""}
|
||||||
{argType == "markdown" ? (
|
{argType == "markdown" ? (
|
||||||
<textarea
|
<div
|
||||||
name={`$${printArgPath(arg_path)}`}
|
class="grow-wrap"
|
||||||
onblur={page.rerender()}
|
data-replicated-value={is(value, predicates.string) ? value : ""}
|
||||||
cols="40"
|
|
||||||
>
|
>
|
||||||
{is(value, predicates.string) ? value : ""}
|
{/* putting the content in the attribute to enable autogrow */}
|
||||||
</textarea>
|
<textarea
|
||||||
|
name={`$${printArgPath(arg_path)}`}
|
||||||
|
onblur={page.rerender()}
|
||||||
|
cols="40"
|
||||||
|
data-controller="autogrow-textarea submit-on-input paste-to-markdown"
|
||||||
|
data-action="autogrow-textarea#autogrow blur->autogrow-textarea#autogrow resize->autogrow-textarea#autogrow submit-on-input#sendValues focus->submit-on-input#makePermanent blur->submit-on-input#makeNotPermanent"
|
||||||
|
>
|
||||||
|
{is(value, predicates.string) ? value : ""}
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<input
|
<input
|
||||||
type={inputType}
|
type={inputType}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||||
import type { Registry, TableData } from "@sealcode/jdd";
|
import type { Registry, TableData } from "@sealcode/jdd";
|
||||||
import { List, Table } from "@sealcode/jdd";
|
import { List, Table } from "@sealcode/jdd";
|
||||||
import type { BaseContext } from "koa";
|
import type { BaseContext } from "koa";
|
||||||
@ -18,9 +19,13 @@ export function getComponentData(
|
|||||||
arg_path: string[],
|
arg_path: string[],
|
||||||
registry: Registry
|
registry: Registry
|
||||||
) {
|
) {
|
||||||
const component_index = parseInt(arg_path[1]);
|
const index_arg = arg_path[1];
|
||||||
const component_args = state.components[component_index].args;
|
if (!index_arg) {
|
||||||
const component_name = state.components[component_index].component_name;
|
throw new Error("Missing component index in arg path");
|
||||||
|
}
|
||||||
|
const component_index = parseInt(index_arg);
|
||||||
|
const component_args = state.components[component_index]?.args || {};
|
||||||
|
const component_name = state.components[component_index]?.component_name || "";
|
||||||
const component = registry.get(component_name);
|
const component = registry.get(component_name);
|
||||||
const arg_path_within_component = arg_path.slice(3); // remove "components" and the index of the component and "args"
|
const arg_path_within_component = arg_path.slice(3); // remove "components" and the index of the component and "args"
|
||||||
|
|
||||||
@ -94,7 +99,7 @@ export const ComponentPreviewActions = <const>{
|
|||||||
|
|
||||||
change_component: async (
|
change_component: async (
|
||||||
ctx: BaseContext,
|
ctx: BaseContext,
|
||||||
state: JDDPageState,
|
_state: JDDPageState,
|
||||||
inputs: Record<string, unknown>
|
inputs: Record<string, unknown>
|
||||||
): Promise<JDDPageState> => {
|
): Promise<JDDPageState> => {
|
||||||
const component_name = inputs.component;
|
const component_name = inputs.component;
|
||||||
@ -128,7 +133,11 @@ export const ComponentPreviewActions = <const>{
|
|||||||
registry
|
registry
|
||||||
);
|
);
|
||||||
|
|
||||||
state.components[component_index].args =
|
const component_data = state.components[component_index];
|
||||||
|
if (!component_data) {
|
||||||
|
throw new Error("Missing component data");
|
||||||
|
}
|
||||||
|
component_data.args =
|
||||||
(await component?.getExampleValues(makeJDDContext(ctx))) || {};
|
(await component?.getExampleValues(makeJDDContext(ctx))) || {};
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
@ -304,6 +313,9 @@ export const ComponentPreviewActions = <const>{
|
|||||||
inputs: Record<string, string>
|
inputs: Record<string, string>
|
||||||
): Promise<JDDPageState> => {
|
): Promise<JDDPageState> => {
|
||||||
const component_name = inputs.component;
|
const component_name = inputs.component;
|
||||||
|
if (!component_name) {
|
||||||
|
throw new Error("Missing component name");
|
||||||
|
}
|
||||||
const component = registry.get(component_name);
|
const component = registry.get(component_name);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -339,9 +351,12 @@ export const ComponentPreviewActions = <const>{
|
|||||||
component_index: number
|
component_index: number
|
||||||
): Promise<JDDPageState> => {
|
): Promise<JDDPageState> => {
|
||||||
const newComps = [...state.components];
|
const newComps = [...state.components];
|
||||||
// prettier-ignore
|
const prev = newComps[component_index - 1];
|
||||||
[newComps[component_index], newComps[component_index - 1]] =
|
const curr = newComps[component_index];
|
||||||
[newComps[component_index - 1], newComps[component_index]];
|
if (!prev || !curr) {
|
||||||
|
throw new Error("No component at such index or cannot move it up");
|
||||||
|
}
|
||||||
|
[newComps[component_index], newComps[component_index - 1]] = [prev, curr];
|
||||||
return { ...state, components: newComps };
|
return { ...state, components: newComps };
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -352,9 +367,21 @@ export const ComponentPreviewActions = <const>{
|
|||||||
component_index: number
|
component_index: number
|
||||||
): Promise<JDDPageState> => {
|
): Promise<JDDPageState> => {
|
||||||
const newComps = [...state.components];
|
const newComps = [...state.components];
|
||||||
// prettier-ignore
|
const next = newComps[component_index + 1];
|
||||||
[newComps[component_index], newComps[component_index + 1]] =
|
const curr = newComps[component_index];
|
||||||
[newComps[component_index + 1], newComps[component_index]];
|
if (!next || !curr) {
|
||||||
|
throw new Error("No component at such index or cannot move it up");
|
||||||
|
}
|
||||||
|
[newComps[component_index], newComps[component_index + 1]] = [next, curr];
|
||||||
return { ...state, components: newComps };
|
return { ...state, components: newComps };
|
||||||
},
|
},
|
||||||
|
remove_file: async (
|
||||||
|
_ctx: BaseContext,
|
||||||
|
state: JDDPageState,
|
||||||
|
_: Record<string, string>,
|
||||||
|
arg_path: string[]
|
||||||
|
): Promise<JDDPageState> => {
|
||||||
|
objectPath.set(state, arg_path, null);
|
||||||
|
return state;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
124
src/back/routes/component-preview/edit-jdd-field.tsx
Normal file
124
src/back/routes/component-preview/edit-jdd-field.tsx
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||||
|
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
import type Router from "@koa/router";
|
||||||
|
import type { JDDocumentContainer, RawJDDocument } from "@sealcode/jdd";
|
||||||
|
import {
|
||||||
|
documentContainerFromStorage,
|
||||||
|
documentToParsed,
|
||||||
|
documentToStorage,
|
||||||
|
} from "@sealcode/jdd";
|
||||||
|
import type { BaseContext } from "koa";
|
||||||
|
import type { Collection, CollectionItem, FieldNames } from "sealious";
|
||||||
|
import { TempstreamJSX } from "tempstream";
|
||||||
|
import { registry } from "../../jdd-components/registry.js";
|
||||||
|
import { makeJDDContext } from "../../jdd-context.js";
|
||||||
|
import JDDCreator from "./jdd-creator.js";
|
||||||
|
import type { JDDPageState } from "./jdd-page.js";
|
||||||
|
|
||||||
|
export const actionName = "ArticleContentEdit";
|
||||||
|
|
||||||
|
export abstract class EditJDDField<C extends Collection> extends JDDCreator {
|
||||||
|
async getID(ctx: BaseContext): Promise<string> {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
const id = ctx.params["id"] as string;
|
||||||
|
if (!id) {
|
||||||
|
throw new Error("Missing URL parameter: " + "id");
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract getCollection(ctx: BaseContext): C;
|
||||||
|
|
||||||
|
async getItem(ctx: BaseContext): Promise<CollectionItem<C>> {
|
||||||
|
const {
|
||||||
|
items: [item],
|
||||||
|
} = await this.getCollection(ctx)
|
||||||
|
.list(ctx.$context)
|
||||||
|
.ids([await this.getID(ctx)])
|
||||||
|
.fetch();
|
||||||
|
if (!item) {
|
||||||
|
throw new Error("Couldn't get item of id " + (await this.getID(ctx)));
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract getJDDFieldName(): FieldNames<C["fields"]>;
|
||||||
|
|
||||||
|
mount(router: Router, path: string) {
|
||||||
|
super.mount(router, path);
|
||||||
|
|
||||||
|
router.post(path + "save/", async (ctx) => {
|
||||||
|
const { state } = await this.extractState(ctx);
|
||||||
|
const item = await this.getItem(ctx);
|
||||||
|
|
||||||
|
item.set(
|
||||||
|
this.getJDDFieldName(),
|
||||||
|
(
|
||||||
|
await documentToStorage(registry, makeJDDContext(ctx), {
|
||||||
|
value: state.components,
|
||||||
|
} as unknown as JDDocumentContainer<"parsed">)
|
||||||
|
).value as any
|
||||||
|
);
|
||||||
|
await item.save(ctx.$context);
|
||||||
|
ctx.type = "html";
|
||||||
|
ctx.status = 422;
|
||||||
|
if (!state.messages) {
|
||||||
|
state.messages = [];
|
||||||
|
}
|
||||||
|
state.messages.push("Saved!");
|
||||||
|
ctx.body = this.render(ctx, state);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async renderHeader(_ctx: BaseContext, _item: CollectionItem<C>) {
|
||||||
|
return <h1>Edit JDD</h1>;
|
||||||
|
}
|
||||||
|
|
||||||
|
async renderPreParameterButtons(ctx: BaseContext) {
|
||||||
|
const item = await this.getItem(ctx);
|
||||||
|
return <div>{this.renderHeader(ctx, item)}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderParameterButtons(state: JDDPageState) {
|
||||||
|
{
|
||||||
|
/*The below button has to be here in order for it to be the default behavior */
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<input type="submit" value="Preview" />
|
||||||
|
<select name="component">
|
||||||
|
{Object.keys(this.getRegistryComponents()).map((cmp) => (
|
||||||
|
<option value={cmp}>{cmp}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
{this.makeActionButton(state, {
|
||||||
|
action: "add_component",
|
||||||
|
label: "Add component",
|
||||||
|
})}
|
||||||
|
<input type="submit" formaction="./save/" value="zapisz" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getInitialState(ctx: BaseContext) {
|
||||||
|
const article = await this.getItem(ctx);
|
||||||
|
const parsed_document = await documentToParsed(
|
||||||
|
registry,
|
||||||
|
makeJDDContext(ctx),
|
||||||
|
documentContainerFromStorage(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||||
|
(article.get(this.getJDDFieldName()) as RawJDDocument) || []
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
components: parsed_document.value.map((e) => ({ ...e, open: true })),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// uncomment to create whitelist of allowed components
|
||||||
|
// getAllowedComponents() {
|
||||||
|
// return ["nice-box"];
|
||||||
|
// }
|
||||||
|
}
|
33
src/back/routes/component-preview/grow-wrap.css
Normal file
33
src/back/routes/component-preview/grow-wrap.css
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/* https://chriscoyier.net/2023/09/29/css-solves-auto-expanding-textareas-probably-eventually/ */
|
||||||
|
|
||||||
|
.grow-wrap {
|
||||||
|
/* easy way to plop the elements on top of each other and have them both sized based on the tallest one's height */
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
.grow-wrap::after {
|
||||||
|
/* Note the weird space! Needed to preventy jumpy behavior */
|
||||||
|
content: attr(data-replicated-value) " ";
|
||||||
|
|
||||||
|
/* This is how textarea text behaves */
|
||||||
|
white-space: pre-wrap;
|
||||||
|
|
||||||
|
/* Hidden from view, clicks, and screen readers */
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.grow-wrap > textarea {
|
||||||
|
/* You could leave this, but after a user resizes, then it ruins the auto sizing */
|
||||||
|
resize: none;
|
||||||
|
|
||||||
|
/* Firefox shows scrollbar on growth, you can hide like this. */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.grow-wrap > textarea,
|
||||||
|
.grow-wrap::after {
|
||||||
|
/* Identical styling required!! */
|
||||||
|
border: 1px solid black;
|
||||||
|
padding: 0.5rem;
|
||||||
|
font: inherit;
|
||||||
|
|
||||||
|
/* Place on top of each other */
|
||||||
|
grid-area: 1 / 1 / 2 / 2;
|
||||||
|
}
|
@ -4,7 +4,12 @@ export default class InputImagePreview extends Controller {
|
|||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
handleChange() {
|
handleChange() {
|
||||||
const img = this.element.querySelector("img");
|
let img = this.element.querySelector("img");
|
||||||
|
if (!img) {
|
||||||
|
img = document.createElement("img");
|
||||||
|
img.setAttribute("style", "height: 40px; width: 40px");
|
||||||
|
this.element.querySelector(".image-preview-container").appendChild(img);
|
||||||
|
}
|
||||||
window.URL.revokeObjectURL(img.src);
|
window.URL.revokeObjectURL(img.src);
|
||||||
const new_url = window.URL.createObjectURL(
|
const new_url = window.URL.createObjectURL(
|
||||||
this.element.querySelector("input").files[0]
|
this.element.querySelector("input").files[0]
|
||||||
|
@ -20,8 +20,8 @@ export default abstract class JDDCreator extends JDDPage {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getRegistryCompoments() {
|
getRegistryComponents() {
|
||||||
const all_components = super.getRegistryCompoments();
|
const all_components = super.getRegistryComponents();
|
||||||
const allowed_components = this.getAllowedComponents();
|
const allowed_components = this.getAllowedComponents();
|
||||||
|
|
||||||
if (allowed_components.length > 0) {
|
if (allowed_components.length > 0) {
|
||||||
@ -43,7 +43,7 @@ export default abstract class JDDCreator extends JDDPage {
|
|||||||
<div>
|
<div>
|
||||||
<input type="submit" value="Preview" />
|
<input type="submit" value="Preview" />
|
||||||
<select name="component">
|
<select name="component">
|
||||||
{Object.keys(this.getRegistryCompoments()).map((cmp) => (
|
{Object.keys(this.getRegistryComponents()).map((cmp) => (
|
||||||
<option value={cmp}>{cmp}</option>
|
<option value={cmp}>{cmp}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
@ -64,42 +64,71 @@ export default abstract class JDDCreator extends JDDPage {
|
|||||||
},
|
},
|
||||||
component_index: number
|
component_index: number
|
||||||
) {
|
) {
|
||||||
|
const checkbox_id = `component_${component_index}_open`;
|
||||||
return (
|
return (
|
||||||
<fieldset>
|
<div
|
||||||
<legend>Component - {component.component_name}</legend>
|
class={[
|
||||||
{this.makeActionButton(
|
"jdd-editor__component-block",
|
||||||
state,
|
"jdd-editor__component-block--number-" + component_index,
|
||||||
{ action: "remove_component", label: "❌" },
|
]}
|
||||||
component_index
|
data-component-debugger-target="componentBlock"
|
||||||
)}
|
data-component-index={component_index.toString()}
|
||||||
{this.makeActionButton(
|
>
|
||||||
state,
|
<summary class="jdd-editor__component-block__top_bar">
|
||||||
{
|
{this.makeActionButton(
|
||||||
action: "move_component_up",
|
state,
|
||||||
label: "Move this row up",
|
{ action: "remove_component", label: "❌" },
|
||||||
content: /* HTML */ `<img
|
component_index
|
||||||
width="20"
|
)}
|
||||||
height="20"
|
{this.makeActionButton(
|
||||||
src="${move_row_up_icon.url}"
|
state,
|
||||||
/>`,
|
{
|
||||||
},
|
action: "move_component_up",
|
||||||
component_index
|
label: "Move this row up",
|
||||||
)}
|
content: /* HTML */ `<img
|
||||||
{this.makeActionButton(
|
width="20"
|
||||||
state,
|
height="20"
|
||||||
{
|
src="${move_row_up_icon.url}"
|
||||||
action: "move_component_down",
|
/>`,
|
||||||
label: "Move this row down",
|
},
|
||||||
content: /* HTML */ `<img
|
component_index
|
||||||
width="20"
|
)}
|
||||||
height="20"
|
{this.makeActionButton(
|
||||||
src="${move_row_down_icon.url}"
|
state,
|
||||||
/>`,
|
{
|
||||||
},
|
action: "move_component_down",
|
||||||
component_index
|
label: "Move this row down",
|
||||||
)}
|
content: /* HTML */ `<img
|
||||||
{super.renderComponentBlock(ctx, state, component, component_index)}
|
width="20"
|
||||||
</fieldset>
|
height="20"
|
||||||
|
src="${move_row_down_icon.url}"
|
||||||
|
/>`,
|
||||||
|
},
|
||||||
|
component_index
|
||||||
|
)}
|
||||||
|
<span>{component.component_name}</span>
|
||||||
|
<label
|
||||||
|
class="component-block__handle"
|
||||||
|
for={checkbox_id}
|
||||||
|
style="flex-grow: 1"
|
||||||
|
data-action="click->component-debugger#labelClicked"
|
||||||
|
>
|
||||||
|
<span class="jdd-editor__component-block__chevron"> > </span>
|
||||||
|
</label>
|
||||||
|
</summary>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="component-collapse-toggle"
|
||||||
|
name={`$[components][${component_index}][open]`}
|
||||||
|
data-turbo-permanent
|
||||||
|
id={checkbox_id}
|
||||||
|
style="display:none"
|
||||||
|
data-component-debugger-target="checkbox"
|
||||||
|
/>
|
||||||
|
<div class="jdd-editor__component-block__inner">
|
||||||
|
{super.renderComponentBlock(ctx, state, component, component_index)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ export const actionName = "Components";
|
|||||||
export type JDDPageState = {
|
export type JDDPageState = {
|
||||||
components: RawJDDocument;
|
components: RawJDDocument;
|
||||||
preview_size?: string;
|
preview_size?: string;
|
||||||
|
messages?: string[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export default abstract class JDDPage extends StatefulPage<
|
export default abstract class JDDPage extends StatefulPage<
|
||||||
@ -27,14 +28,17 @@ export default abstract class JDDPage extends StatefulPage<
|
|||||||
|
|
||||||
previewSizes = ["320", "600", "800", "1024", "1300", "1920"];
|
previewSizes = ["320", "600", "800", "1024", "1300", "1920"];
|
||||||
|
|
||||||
getRegistryCompoments() {
|
getRegistryComponents() {
|
||||||
return registry.getAll();
|
return registry.getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
async getInitialState(ctx: BaseContext) {
|
async getInitialState(ctx: BaseContext) {
|
||||||
const [component_name, component] = Object.entries(
|
const all_components = Object.entries(this.getRegistryComponents());
|
||||||
this.getRegistryCompoments()
|
const first_component = all_components[0];
|
||||||
)[0];
|
if (!first_component) {
|
||||||
|
throw new Error("No defined components!");
|
||||||
|
}
|
||||||
|
const [component_name, component] = first_component;
|
||||||
const initial_state = {
|
const initial_state = {
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@ -60,6 +64,7 @@ export default abstract class JDDPage extends StatefulPage<
|
|||||||
preserveScroll: true,
|
preserveScroll: true,
|
||||||
autoRefreshCSS: true,
|
autoRefreshCSS: true,
|
||||||
navbar: () => ``,
|
navbar: () => ``,
|
||||||
|
bodyClasses: ["jdd-editor"],
|
||||||
},
|
},
|
||||||
(...args) =>
|
(...args) =>
|
||||||
tempstream`${defaultHead(...args)}${renderEarlyAssets(
|
tempstream`${defaultHead(...args)}${renderEarlyAssets(
|
||||||
@ -96,8 +101,9 @@ export default abstract class JDDPage extends StatefulPage<
|
|||||||
if (!component) {
|
if (!component) {
|
||||||
throw new Error(`Unknown component: ${component_name}`);
|
throw new Error(`Unknown component: ${component_name}`);
|
||||||
}
|
}
|
||||||
const overrides_for_component =
|
const overrides_for_component = overrides.components[
|
||||||
overrides.components[parseInt(component_index)];
|
parseInt(component_index)
|
||||||
|
] || { args: {} };
|
||||||
const promises = Object.entries(component.getArguments()).map(
|
const promises = Object.entries(component.getArguments()).map(
|
||||||
async ([arg_name, arg]) => {
|
async ([arg_name, arg]) => {
|
||||||
const value = overrides_for_component.args[arg_name];
|
const value = overrides_for_component.args[arg_name];
|
||||||
@ -126,8 +132,7 @@ export default abstract class JDDPage extends StatefulPage<
|
|||||||
) {
|
) {
|
||||||
const jdd_context = makeJDDContext(ctx);
|
const jdd_context = makeJDDContext(ctx);
|
||||||
return (
|
return (
|
||||||
<fieldset class="component-preview-parameters">
|
<div class="component-preview-parameters">
|
||||||
<legend>Parameters</legend>
|
|
||||||
{Object.entries(component.getArguments()).map(async ([arg_name, arg]) => (
|
{Object.entries(component.getArguments()).map(async ([arg_name, arg]) => (
|
||||||
<ComponentInput
|
<ComponentInput
|
||||||
{...{
|
{...{
|
||||||
@ -144,8 +149,7 @@ export default abstract class JDDPage extends StatefulPage<
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<input type="submit" value="Preview" />
|
</div>
|
||||||
</fieldset>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +241,25 @@ export default abstract class JDDPage extends StatefulPage<
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderPreParameterButtons(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
_ctx: BaseContext,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
_state: JDDPageState
|
||||||
|
): FlatTemplatable | Promise<FlatTemplatable> {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
renderMessages(_ctx: BaseContext, state: JDDPageState) {
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{(state.messages || []).map((e) => (
|
||||||
|
<li>{e}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
render(ctx: BaseContext, state: JDDPageState) {
|
render(ctx: BaseContext, state: JDDPageState) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -246,51 +269,46 @@ export default abstract class JDDPage extends StatefulPage<
|
|||||||
data-controller="component-debugger"
|
data-controller="component-debugger"
|
||||||
>
|
>
|
||||||
<div class="component-arguments">
|
<div class="component-arguments">
|
||||||
|
{this.renderPreParameterButtons(ctx, state)}
|
||||||
{this.renderParameterButtons(state)}
|
{this.renderParameterButtons(state)}
|
||||||
|
{this.renderMessages(ctx, state)}
|
||||||
{state.components.map((component, component_index) =>
|
{state.components.map((component, component_index) =>
|
||||||
this.renderComponentBlock(ctx, state, component, component_index)
|
this.renderComponentBlock(ctx, state, component, component_index)
|
||||||
)}
|
)}
|
||||||
<code>{this.serializeState(ctx, state)}</code>
|
<code style="max-height: 100px; display: block; overflow: hidden; font-size: 9px; color: #a8a8a8; padding: 1rem;">
|
||||||
|
{this.serializeState(ctx, state)}
|
||||||
|
</code>
|
||||||
</div>
|
</div>
|
||||||
<div class="resize-gutter" data-component-debugger-target="gutter"></div>
|
<div class="resize-gutter" data-component-debugger-target="gutter"></div>
|
||||||
<div class="component-preview" data-component-debugger-target="preview">
|
<div class="component-preview" data-component-debugger-target="preview">
|
||||||
<fieldset>
|
<div class="component-preview__header">
|
||||||
<legend>
|
<span>Preview</span>
|
||||||
Preview{" "}
|
<span data-component-debugger-target="component-width"></span>
|
||||||
<span data-component-debugger-target="component-width"></span>
|
<select
|
||||||
<select
|
name="size"
|
||||||
name="size"
|
autocomplete="off"
|
||||||
autocomplete="off"
|
class="component-preview-size-select"
|
||||||
class="component-preview-size-select"
|
data-component-debugger-target="size-select"
|
||||||
data-component-debugger-target="size-select"
|
data-action="change->component-debugger#handleWidthDropdown"
|
||||||
data-action="change->component-debugger#handleWidthDropdown"
|
>
|
||||||
>
|
{this.previewSizes.map((size) => (
|
||||||
{this.previewSizes.map((size) => (
|
<option
|
||||||
<option
|
value={size}
|
||||||
value={size}
|
selected={size === (state.preview_size || "800")}
|
||||||
selected={size === (state.preview_size || "800")}
|
>
|
||||||
>
|
{`${size} px`}
|
||||||
{`${size} px`}
|
</option>
|
||||||
</option>
|
))}
|
||||||
))}
|
</select>
|
||||||
</select>
|
<noscript>{this.makeActionButton(state, "change_size")}</noscript>
|
||||||
<noscript>
|
</div>
|
||||||
{this.makeActionButton(state, "change_size")}
|
<div class="jdd-container">
|
||||||
</noscript>
|
|
||||||
</legend>
|
|
||||||
{render(
|
{render(
|
||||||
registry,
|
registry,
|
||||||
documentContainerFromParsed(state.components),
|
documentContainerFromParsed(state.components),
|
||||||
makeJDDContext(ctx)
|
makeJDDContext(ctx)
|
||||||
)}
|
)}
|
||||||
</fieldset>
|
</div>
|
||||||
{
|
|
||||||
/* HTML */ `<script>
|
|
||||||
(function () {
|
|
||||||
const gutter = document.querySelector(".resize-gutter");
|
|
||||||
})();
|
|
||||||
</script>`
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-unsafe-assignment */
|
||||||
|
import { Controller } from "stimulus";
|
||||||
|
import TurndownService from "turndown";
|
||||||
|
|
||||||
|
export default class PasteToMarkdown extends Controller<HTMLTextAreaElement> {
|
||||||
|
connect() {
|
||||||
|
this.element.addEventListener("paste", (event) => {
|
||||||
|
if (event.clipboardData.types.includes("text/html")) {
|
||||||
|
const turndownService = new TurndownService({
|
||||||
|
headingStyle: "atx",
|
||||||
|
preformattedCode: true,
|
||||||
|
} as any);
|
||||||
|
event.preventDefault();
|
||||||
|
const html = (event.clipboardData.getData("text/html") as string)
|
||||||
|
.replaceAll("\n", " ")
|
||||||
|
// to get rid of some of the style metadata from libreoffice
|
||||||
|
.replace(/^<!doctype.*<body[^>]*>/i, "");
|
||||||
|
document.execCommand("insertText", false, turndownService.turndown(html));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-unsafe-assignment */
|
||||||
|
import { Controller } from "stimulus";
|
||||||
|
import { throttle } from "throttle-debounce";
|
||||||
|
|
||||||
|
export default class SubmitOnInput extends Controller<HTMLTextAreaElement> {
|
||||||
|
sendValues: () => void;
|
||||||
|
connect() {
|
||||||
|
this.sendValues = throttle(
|
||||||
|
500,
|
||||||
|
() => {
|
||||||
|
this.element.closest("form").requestSubmit();
|
||||||
|
},
|
||||||
|
{ noTrailing: false }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
makePermanent() {
|
||||||
|
// this prevents morphing from overwriting the input value with previous half-dane values - https://github.com/hotwired/turbo/issues/1199
|
||||||
|
this.element.setAttribute("data-turbo-permanent", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
makeNotPermanent() {
|
||||||
|
this.element.removeAttribute("data-turbo-permanent");
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,7 @@ export const actionName = "Components";
|
|||||||
|
|
||||||
export default new (class JddcomponentDebuggerPage extends JDDPage {
|
export default new (class JddcomponentDebuggerPage extends JDDPage {
|
||||||
renderParameterButtons(state: JDDPageState): Stringifiable {
|
renderParameterButtons(state: JDDPageState): Stringifiable {
|
||||||
const all_components = super.getRegistryCompoments();
|
const all_components = super.getRegistryComponents();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<input type="submit" value="Preview" />
|
<input type="submit" value="Preview" />
|
||||||
|
@ -19,10 +19,19 @@ application.register("map-with-pins", MapWithPins);
|
|||||||
import { default as HorizontalScroller } from "./../back/routes/common/horizontal-scroller/horizontal-scroller.stimulus.js";
|
import { default as HorizontalScroller } from "./../back/routes/common/horizontal-scroller/horizontal-scroller.stimulus.js";
|
||||||
application.register("horizontal-scroller", HorizontalScroller);
|
application.register("horizontal-scroller", HorizontalScroller);
|
||||||
|
|
||||||
|
import { default as AutogrowTextarea } from "./../back/routes/component-preview/autogrow-textarea.stimulus.js";
|
||||||
|
application.register("autogrow-textarea", AutogrowTextarea);
|
||||||
|
|
||||||
import { default as ComponentDebugger } from "./../back/routes/component-preview/component-debugger.stimulus.js";
|
import { default as ComponentDebugger } from "./../back/routes/component-preview/component-debugger.stimulus.js";
|
||||||
application.register("component-debugger", ComponentDebugger);
|
application.register("component-debugger", ComponentDebugger);
|
||||||
|
|
||||||
import { default as InputImagePreview } from "./../back/routes/component-preview/input-image-preview.stimulus.js";
|
import { default as InputImagePreview } from "./../back/routes/component-preview/input-image-preview.stimulus.js";
|
||||||
application.register("input-image-preview", InputImagePreview);
|
application.register("input-image-preview", InputImagePreview);
|
||||||
|
|
||||||
|
import { default as PasteToMarkdown } from "./../back/routes/component-preview/paste-to-markdown.stimulus.js";
|
||||||
|
application.register("paste-to-markdown", PasteToMarkdown);
|
||||||
|
|
||||||
|
import { default as SubmitOnInput } from "./../back/routes/component-preview/submit-on-input.stimulus.js";
|
||||||
|
application.register("submit-on-input", SubmitOnInput);
|
||||||
|
|
||||||
export { Turbo };
|
export { Turbo };
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true
|
||||||
},
|
},
|
||||||
"include": ["./src/back/*", "./src/back/**/*", "./src/back/routes/common/navbar.ts"],
|
"include": ["./src/back/*", "./src/back/**/*", "./src/back/routes/common/navbar.ts"],
|
||||||
"exclude": ["./src/front", "./src/**/*.stimulus.ts"],
|
"exclude": ["./src/front", "./src/**/*.stimulus.ts"],
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "CommonJS",
|
"module": "CommonJS",
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"lib": ["dom"],
|
"lib": ["dom", "es2021"],
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true
|
||||||
},
|
},
|
||||||
"include": ["./src/front", "./src/**/*.stimulus.ts"]
|
"include": ["./src/front", "./src/**/*.stimulus.ts"]
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user