Enable EarlyAssets and stimulus controllers support. Improve layout in component debugger
This commit is contained in:
parent
c654b092ee
commit
148c533b5b
29
package-lock.json
generated
29
package-lock.json
generated
@ -14,10 +14,11 @@
|
|||||||
"@hotwired/turbo": "^8.0.2",
|
"@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.3.3",
|
"@sealcode/jdd": "^0.3.4",
|
||||||
"@sealcode/sealgen": "^0.14.4",
|
"@sealcode/sealgen": "^0.14.5",
|
||||||
"@sealcode/ts-predicates": "^0.4.3",
|
"@sealcode/ts-predicates": "^0.4.3",
|
||||||
"@types/kill-port": "^2.0.0",
|
"@types/kill-port": "^2.0.0",
|
||||||
|
"@types/leaflet": "^1.9.8",
|
||||||
"get-port": "^7.0.0",
|
"get-port": "^7.0.0",
|
||||||
"js-convert-case": "^4.2.0",
|
"js-convert-case": "^4.2.0",
|
||||||
"koa-responsive-image-router": "^0.2.19",
|
"koa-responsive-image-router": "^0.2.19",
|
||||||
@ -791,9 +792,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sealcode/jdd": {
|
"node_modules/@sealcode/jdd": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@sealcode/jdd/-/jdd-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@sealcode/jdd/-/jdd-0.3.4.tgz",
|
||||||
"integrity": "sha512-mGOBlE/gQSSdXZfg5wP6mq8vw6q/qrxB6HIMGvctSZLAAFjiz/ExnOLN+5lIGmO5XpNRWcCHHlBmFKpBy4Vz3A==",
|
"integrity": "sha512-lwkVoUguOsOxuKYURw/hl3XqFARY85CuqnwzgdHG+gC6x23y/PgljbPREAT5GSKYCIVWkwGdNAfbh0HglV4Z4Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sealcode/ts-predicates": "^0.5.3",
|
"@sealcode/ts-predicates": "^0.5.3",
|
||||||
"koa-responsive-image-router": "^0.2.19",
|
"koa-responsive-image-router": "^0.2.19",
|
||||||
@ -820,8 +821,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sealcode/sealgen": {
|
"node_modules/@sealcode/sealgen": {
|
||||||
"version": "0.14.4",
|
"version": "0.14.5",
|
||||||
"license": "ISC",
|
"resolved": "https://registry.npmjs.org/@sealcode/sealgen/-/sealgen-0.14.5.tgz",
|
||||||
|
"integrity": "sha512-SE3dpS5KAsvpznKJla1VoqlnDNxeHJ2mTN2Kzdwg9Chleht/Mw/ojb7E58ZX/WxJNg+BRuCYy6knJkvkO7SfQg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@koa/router": "^12.0.1",
|
"@koa/router": "^12.0.1",
|
||||||
"@sealcode/ts-predicates": "^0.4.3",
|
"@sealcode/ts-predicates": "^0.4.3",
|
||||||
@ -1031,6 +1033,11 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/geojson": {
|
||||||
|
"version": "7946.0.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz",
|
||||||
|
"integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg=="
|
||||||
|
},
|
||||||
"node_modules/@types/http-assert": {
|
"node_modules/@types/http-assert": {
|
||||||
"version": "1.5.5",
|
"version": "1.5.5",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
@ -1119,6 +1126,14 @@
|
|||||||
"@types/koa-send": "*"
|
"@types/koa-send": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/leaflet": {
|
||||||
|
"version": "1.9.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.8.tgz",
|
||||||
|
"integrity": "sha512-EXdsL4EhoUtGm2GC2ZYtXn+Fzc6pluVgagvo2VC1RHWToLGlTRwVYoDpqS/7QXa01rmDyBjJk3Catpf60VMkwg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/geojson": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/luxon": {
|
"node_modules/@types/luxon": {
|
||||||
"version": "3.3.8",
|
"version": "3.3.8",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "docker-compose up -d db && node .",
|
"start": "docker-compose up -d db && node .",
|
||||||
"typecheck:back": "npx tsc --noEmit --target es6 --lib es2021,dom -p src/back",
|
"typecheck:back": "npx tsc --noEmit --target es6 --lib es2021,dom -p tsconfig-back.json",
|
||||||
"typecheck:front": "npx tsc --noEmit --target es6 --lib es2015,dom -p src/front",
|
"typecheck:front": "npx tsc --noEmit --target es6 --lib es2015,dom -p tsconfig-front.json",
|
||||||
"build": "sealgen build",
|
"build": "sealgen build",
|
||||||
"watch": "multiple-scripts-tmux -p watch",
|
"watch": "multiple-scripts-tmux -p watch",
|
||||||
"reset-db": "docker-compose down && docker-compose up -d",
|
"reset-db": "docker-compose down && docker-compose up -d",
|
||||||
@ -35,10 +35,11 @@
|
|||||||
"@hotwired/turbo": "^8.0.2",
|
"@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.3.3",
|
"@sealcode/jdd": "^0.3.4",
|
||||||
"@sealcode/sealgen": "^0.14.4",
|
"@sealcode/sealgen": "^0.14.5",
|
||||||
"@sealcode/ts-predicates": "^0.4.3",
|
"@sealcode/ts-predicates": "^0.4.3",
|
||||||
"@types/kill-port": "^2.0.0",
|
"@types/kill-port": "^2.0.0",
|
||||||
|
"@types/leaflet": "^1.9.8",
|
||||||
"get-port": "^7.0.0",
|
"get-port": "^7.0.0",
|
||||||
"js-convert-case": "^4.2.0",
|
"js-convert-case": "^4.2.0",
|
||||||
"koa-responsive-image-router": "^0.2.19",
|
"koa-responsive-image-router": "^0.2.19",
|
||||||
|
145
src/back/html.ts
145
src/back/html.ts
@ -46,6 +46,11 @@ export default function html(
|
|||||||
) => Templatable = defaultHead
|
) => Templatable = defaultHead
|
||||||
): Readable {
|
): Readable {
|
||||||
ctx.set("content-type", "text/html;charset=utf-8");
|
ctx.set("content-type", "text/html;charset=utf-8");
|
||||||
|
const controllers: string[] = [];
|
||||||
|
if (htmlOptions.autoRefreshCSS) {
|
||||||
|
controllers.push("refresh-styles");
|
||||||
|
controllers.push("refresh-on-ts-changes");
|
||||||
|
}
|
||||||
return tempstream/* HTML */ ` <!DOCTYPE html>
|
return tempstream/* HTML */ ` <!DOCTYPE html>
|
||||||
<html
|
<html
|
||||||
lang="${htmlOptions.language || DEFAULT_HTML_LANG}"
|
lang="${htmlOptions.language || DEFAULT_HTML_LANG}"
|
||||||
@ -54,146 +59,8 @@ export default function html(
|
|||||||
<head>
|
<head>
|
||||||
${makeHead(ctx, title, htmlOptions)}
|
${makeHead(ctx, title, htmlOptions)}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body data-controller="${controllers.join(" ")}">
|
||||||
${(htmlOptions.navbar || default_navbar)(ctx)} ${body}
|
${(htmlOptions.navbar || default_navbar)(ctx)} ${body}
|
||||||
${htmlOptions.autoRefreshCSS
|
|
||||||
? /* HTML */ `<script>
|
|
||||||
function make_new_link() {
|
|
||||||
const new_link = document.createElement("link");
|
|
||||||
new_link.rel = "stylesheet";
|
|
||||||
new_link.href = \`/dist/main.css?\${Math.random()}+\${Math.random()}\`;
|
|
||||||
new_link.type = "text/css";
|
|
||||||
return new_link;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStyles() {
|
|
||||||
return Array.from(
|
|
||||||
document.querySelectorAll("head link")
|
|
||||||
).filter(
|
|
||||||
(e) => new URL(e.href).pathname == "/dist/main.css"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanup_css() {
|
|
||||||
console.log("clearing styles");
|
|
||||||
getStyles()
|
|
||||||
.slice(0, -1)
|
|
||||||
.forEach((style) => {
|
|
||||||
style.parentElement.removeChild(style);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
document.documentElement.addEventListener(
|
|
||||||
"turbo:morph",
|
|
||||||
cleanup_css
|
|
||||||
);
|
|
||||||
|
|
||||||
const sleep = (time) =>
|
|
||||||
new Promise((resolve) => {
|
|
||||||
setTimeout(resolve, time);
|
|
||||||
});
|
|
||||||
|
|
||||||
const APP_DOWN_ERROR_MESSAGE = "App is currently down";
|
|
||||||
|
|
||||||
function get_status() {
|
|
||||||
return fetch("/status.json").then((r) => r.json());
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wait_for_run_id_to_change() {
|
|
||||||
let first_timestamp;
|
|
||||||
try {
|
|
||||||
const { started_at, status } = await get_status();
|
|
||||||
first_timestamp = started_at;
|
|
||||||
} catch (e) {
|
|
||||||
await wait_for_app_to_be_stable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!first_timestamp) {
|
|
||||||
throw new Error(APP_DOWN_ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
const { started_at, status } =
|
|
||||||
await get_status().catch(() => ({
|
|
||||||
started_at: first_timestamp,
|
|
||||||
}));
|
|
||||||
if (started_at !== first_timestamp) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await sleep(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wait_for_app_to_be_stable(n = 3) {
|
|
||||||
console.log("Waiting for app to be stable....");
|
|
||||||
let counter = 0;
|
|
||||||
while (true) {
|
|
||||||
const { status } = await get_status().catch((e) => ({
|
|
||||||
status: "down",
|
|
||||||
}));
|
|
||||||
if (status == "running") {
|
|
||||||
console.log(counter);
|
|
||||||
counter++;
|
|
||||||
} else {
|
|
||||||
counter = 0;
|
|
||||||
}
|
|
||||||
if (counter == n) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await sleep(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wait_for_app_restart() {
|
|
||||||
try {
|
|
||||||
await wait_for_run_id_to_change();
|
|
||||||
} catch (e) {
|
|
||||||
if (e.message !== APP_DOWN_ERROR_MESSAGE) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await wait_for_app_to_be_stable();
|
|
||||||
}
|
|
||||||
|
|
||||||
(async function () {
|
|
||||||
const { started_at, status } = await fetch(
|
|
||||||
"/status.json"
|
|
||||||
).then((r) => r.json());
|
|
||||||
last_known_start_timestamp = started_at;
|
|
||||||
const { port, watch } = await fetch(
|
|
||||||
"/dist/notifier.json"
|
|
||||||
).then((r) => r.json());
|
|
||||||
if (!watch) {
|
|
||||||
console.warning(
|
|
||||||
"Not running auto refresh on watch because the build process is not running in watch mode"
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const socket = new WebSocket(\`ws://localhost:\${port}\`);
|
|
||||||
socket.onmessage = async (message) => {
|
|
||||||
if (message.data === "css") {
|
|
||||||
const new_link = make_new_link();
|
|
||||||
new_link.onload = cleanup_css;
|
|
||||||
document
|
|
||||||
.querySelector("head")
|
|
||||||
.appendChild(new_link);
|
|
||||||
}
|
|
||||||
if (message.data === "ts") {
|
|
||||||
document.documentElement.classList.add(
|
|
||||||
"restarting"
|
|
||||||
);
|
|
||||||
await wait_for_app_restart();
|
|
||||||
document.documentElement.dispatchEvent(
|
|
||||||
new Event("ts-rebuilt")
|
|
||||||
);
|
|
||||||
document.documentElement.classList.remove(
|
|
||||||
"restarting"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
</script>`
|
|
||||||
: ""}
|
|
||||||
${htmlOptions.disableCopyEvent
|
${htmlOptions.disableCopyEvent
|
||||||
? /* HTML */ "<script>document.addEventListener('copy', (e) => e.preventDefault());</script>"
|
? /* HTML */ "<script>document.addEventListener('copy', (e) => e.preventDefault());</script>"
|
||||||
: ""}
|
: ""}
|
||||||
|
96
src/back/html/refresh-on-ts-changes.stimulus.ts
Normal file
96
src/back/html/refresh-on-ts-changes.stimulus.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
|
const APP_DOWN_ERROR_MESSAGE = "App is currently down";
|
||||||
|
|
||||||
|
const sleep = (time: number) =>
|
||||||
|
new Promise((resolve) => {
|
||||||
|
setTimeout(resolve, time);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function get_status() {
|
||||||
|
const r = await fetch("/status.json");
|
||||||
|
return await r.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function wait_for_run_id_to_change() {
|
||||||
|
let first_timestamp: number;
|
||||||
|
try {
|
||||||
|
const { started_at } = await get_status();
|
||||||
|
first_timestamp = started_at;
|
||||||
|
} catch (e) {
|
||||||
|
await wait_for_app_to_be_stable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!first_timestamp) {
|
||||||
|
throw new Error(APP_DOWN_ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { started_at } = await get_status().catch(() => ({
|
||||||
|
started_at: first_timestamp,
|
||||||
|
}));
|
||||||
|
if (started_at !== first_timestamp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function wait_for_app_to_be_stable(n = 3) {
|
||||||
|
console.log("Waiting for app to be stable....");
|
||||||
|
let counter = 0;
|
||||||
|
while (true) {
|
||||||
|
const { status } = await get_status().catch(() => ({
|
||||||
|
status: "down",
|
||||||
|
}));
|
||||||
|
if (status == "running") {
|
||||||
|
console.log(counter);
|
||||||
|
counter++;
|
||||||
|
} else {
|
||||||
|
counter = 0;
|
||||||
|
}
|
||||||
|
if (counter == n) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function wait_for_app_restart() {
|
||||||
|
try {
|
||||||
|
await wait_for_run_id_to_change();
|
||||||
|
} catch (e) {
|
||||||
|
if (e.message !== APP_DOWN_ERROR_MESSAGE) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await wait_for_app_to_be_stable();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class RefreshOnTSChanges extends Controller {
|
||||||
|
socket: WebSocket;
|
||||||
|
|
||||||
|
async connect() {
|
||||||
|
const { port, watch } = await fetch("/dist/notifier.json").then((r) => r.json());
|
||||||
|
if (!watch) {
|
||||||
|
console.warn(
|
||||||
|
"Not running auto refresh on watch because the build process is not running in watch mode"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const socket = new WebSocket(`ws://localhost:${port}`);
|
||||||
|
socket.onmessage = async (message) => {
|
||||||
|
if (message.data.endsWith("-ts")) {
|
||||||
|
document.documentElement.classList.add("restarting");
|
||||||
|
await wait_for_app_restart();
|
||||||
|
document.documentElement.dispatchEvent(new Event("ts-rebuilt"));
|
||||||
|
document.documentElement.classList.remove("restarting");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect() {
|
||||||
|
this.socket.close();
|
||||||
|
}
|
||||||
|
}
|
46
src/back/html/refresh-styles.stimulus.ts
Normal file
46
src/back/html/refresh-styles.stimulus.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
|
function make_new_link() {
|
||||||
|
const new_link = document.createElement("link");
|
||||||
|
new_link.rel = "stylesheet";
|
||||||
|
new_link.href = `/dist/main.css?${Math.random()}+${Math.random()}`;
|
||||||
|
new_link.type = "text/css";
|
||||||
|
return new_link;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStyles() {
|
||||||
|
return Array.from(document.querySelectorAll("head link")).filter(
|
||||||
|
(e: HTMLLinkElement) => new URL(e.href).pathname == "/dist/main.css"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup_css() {
|
||||||
|
console.log("clearing styles");
|
||||||
|
getStyles()
|
||||||
|
.slice(0, -1)
|
||||||
|
.forEach((style) => {
|
||||||
|
style.parentElement.removeChild(style);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class RefreshStyles extends Controller {
|
||||||
|
socket: WebSocket;
|
||||||
|
|
||||||
|
async connect() {
|
||||||
|
const { port } = await fetch("/dist/notifier.json").then((r) => r.json());
|
||||||
|
this.socket = new WebSocket(`ws://localhost:${port}`);
|
||||||
|
this.socket.onmessage = async (message) => {
|
||||||
|
if (message.data === "css") {
|
||||||
|
const new_link = make_new_link();
|
||||||
|
new_link.onload = cleanup_css;
|
||||||
|
document.querySelector("head").appendChild(new_link);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
document.documentElement.addEventListener("turbo:morph", cleanup_css);
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect() {
|
||||||
|
this.socket.close();
|
||||||
|
document.documentElement.removeEventListener("turbo:morph", cleanup_css);
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
.map-with-pins {
|
.map-with-pins {
|
||||||
#map {
|
height: 534px;
|
||||||
height: 534px;
|
|
||||||
}
|
|
||||||
.popup {
|
.popup {
|
||||||
.leaflet-popup-content-wrapper,
|
.leaflet-popup-content-wrapper,
|
||||||
.leaflet-popup-tip {
|
.leaflet-popup-tip {
|
||||||
@ -32,6 +31,7 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
@ -32,95 +32,36 @@ export class MapWithPins extends Component<typeof component_arguments> {
|
|||||||
return component_arguments;
|
return component_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getEarlyAssets() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: "script" as const,
|
||||||
|
url: "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js",
|
||||||
|
identity: "https://unpkg.com/leaflet@1.9.4/dist/leaflet.js",
|
||||||
|
integrity: "sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "style" as const,
|
||||||
|
url: "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css",
|
||||||
|
integrity: "sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=",
|
||||||
|
identity: "https://unpkg.com/leaflet@1.9.4/dist/leaflet.css",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
toHTML({
|
toHTML({
|
||||||
pins,
|
pins,
|
||||||
}: ExtractStructuredComponentArgumentsValues<
|
}: ExtractStructuredComponentArgumentsValues<
|
||||||
typeof component_arguments
|
typeof component_arguments
|
||||||
>): FlatTemplatable {
|
>): FlatTemplatable {
|
||||||
return (
|
return (
|
||||||
<div class="map-with-pins">
|
<div
|
||||||
<link
|
class="map-with-pins"
|
||||||
rel="stylesheet"
|
data-controller="map-with-pins"
|
||||||
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
|
data-map-with-pins-pins-value={JSON.stringify(pins)
|
||||||
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
|
.replaceAll("\n", "\\n")
|
||||||
crossorigin=""
|
.replaceAll('"', """)}
|
||||||
/>
|
></div>
|
||||||
<script
|
|
||||||
onload="loadMap()"
|
|
||||||
src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
|
|
||||||
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
|
|
||||||
crossorigin=""
|
|
||||||
></script>
|
|
||||||
{
|
|
||||||
/* HTML */ `<script>
|
|
||||||
function loadMap() {
|
|
||||||
const mapDiv = document.getElementById("map");
|
|
||||||
const resizeObserver = new ResizeObserver(() => {
|
|
||||||
map.invalidateSize();
|
|
||||||
});
|
|
||||||
|
|
||||||
resizeObserver.observe(mapDiv);
|
|
||||||
var map = L.map("map");
|
|
||||||
L.tileLayer(
|
|
||||||
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
|
||||||
{
|
|
||||||
maxZoom: 19,
|
|
||||||
attribution:
|
|
||||||
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
|
||||||
}
|
|
||||||
).addTo(map);
|
|
||||||
|
|
||||||
const pins = ${JSON.stringify(pins)};
|
|
||||||
pins.forEach((pin) => addPin(pin, map));
|
|
||||||
}
|
|
||||||
|
|
||||||
function addPin(pin, map) {
|
|
||||||
var pinIcon = L.icon({
|
|
||||||
iconUrl: "/pin-icon.svg",
|
|
||||||
iconSize: [29, 41],
|
|
||||||
iconAnchor: [14, 40],
|
|
||||||
popupAnchor: [-3, 14],
|
|
||||||
});
|
|
||||||
|
|
||||||
var marker = L.marker(
|
|
||||||
pin.coordinates.split(", ").map((x) => parseFloat(x)),
|
|
||||||
{
|
|
||||||
icon: pinIcon,
|
|
||||||
}
|
|
||||||
).addTo(map);
|
|
||||||
|
|
||||||
var popup = L.popup({
|
|
||||||
closeButton: false,
|
|
||||||
autoClose: false,
|
|
||||||
closeOnEscapeKey: false,
|
|
||||||
closeOnClick: false,
|
|
||||||
className: "popup",
|
|
||||||
offset: [0, -32],
|
|
||||||
maxWidth: "auto",
|
|
||||||
})
|
|
||||||
.setLatLng(
|
|
||||||
pin.coordinates.split(", ").map((x) => parseFloat(x))
|
|
||||||
)
|
|
||||||
.setContent(
|
|
||||||
/* HTML */ \`<div class="popup-content">
|
|
||||||
<p class="title">\${pin.title}</p>
|
|
||||||
<p class="address">\${pin.address}</p>
|
|
||||||
<a class="button" href="\${pin.button.link}">
|
|
||||||
\${pin.button.text}
|
|
||||||
</a>
|
|
||||||
</div> \`
|
|
||||||
)
|
|
||||||
.addTo(map);
|
|
||||||
map.setView(
|
|
||||||
pin.coordinates.split(", ").map((x) => parseFloat(x)),
|
|
||||||
13
|
|
||||||
);
|
|
||||||
}
|
|
||||||
</script>`
|
|
||||||
}
|
|
||||||
|
|
||||||
<div id="map"></div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
101
src/back/jdd-components/map-with-pins/map-with-pins.stimulus.ts
Normal file
101
src/back/jdd-components/map-with-pins/map-with-pins.stimulus.ts
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { Controller } from "stimulus";
|
||||||
|
declare const L: any;
|
||||||
|
|
||||||
|
export default class MapWithPins extends Controller {
|
||||||
|
id: string;
|
||||||
|
map: any;
|
||||||
|
initiated: boolean = false;
|
||||||
|
resizeObserver: ResizeObserver;
|
||||||
|
|
||||||
|
static values = {
|
||||||
|
pins: String,
|
||||||
|
};
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
if (this.initiated) {
|
||||||
|
this.map.remove();
|
||||||
|
}
|
||||||
|
if (window.L) {
|
||||||
|
this.initiateMap();
|
||||||
|
} else {
|
||||||
|
document.addEventListener(
|
||||||
|
"loaded-https://unpkg.com/leaflet@1.9.4/dist/leaflet.js",
|
||||||
|
() => {
|
||||||
|
this.initiateMap();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this.map.remove();
|
||||||
|
this.initiated = false;
|
||||||
|
this.resizeObserver.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
initiateMap() {
|
||||||
|
this.map = L.map(this.element);
|
||||||
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
|
this.map.invalidateSize();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resizeObserver.observe(this.element);
|
||||||
|
|
||||||
|
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
|
maxZoom: 19,
|
||||||
|
attribution:
|
||||||
|
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
|
||||||
|
}).addTo(this.map);
|
||||||
|
|
||||||
|
const pins = JSON.parse(
|
||||||
|
this.element.attributes["data-map-with-pins-pins-value"].value
|
||||||
|
);
|
||||||
|
pins.forEach((pin) => this.addPin(pin));
|
||||||
|
this.initiated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pinsValueChanged() {
|
||||||
|
if (this.initiated) {
|
||||||
|
this.connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addPin(pin) {
|
||||||
|
var pinIcon = L.icon({
|
||||||
|
iconUrl: "/pin-icon.svg",
|
||||||
|
iconSize: [29, 41],
|
||||||
|
iconAnchor: [14, 40],
|
||||||
|
popupAnchor: [-3, 14],
|
||||||
|
});
|
||||||
|
|
||||||
|
var marker = L.marker(
|
||||||
|
pin.coordinates.split(", ").map((x) => parseFloat(x)),
|
||||||
|
{
|
||||||
|
icon: pinIcon,
|
||||||
|
}
|
||||||
|
).addTo(this.map);
|
||||||
|
|
||||||
|
var popup = L.popup({
|
||||||
|
closeButton: false,
|
||||||
|
autoClose: false,
|
||||||
|
closeOnEscapeKey: false,
|
||||||
|
closeOnClick: false,
|
||||||
|
className: "popup",
|
||||||
|
offset: [0, -32],
|
||||||
|
maxWidth: "auto",
|
||||||
|
})
|
||||||
|
.setLatLng(pin.coordinates.split(", ").map((x) => parseFloat(x)))
|
||||||
|
.setContent(
|
||||||
|
/* HTML */ `<div class="popup-content">
|
||||||
|
<p class="title">${pin.title}</p>
|
||||||
|
<p class="address">${pin.address}</p>
|
||||||
|
<a class="button" href="${pin.button.link}"> ${pin.button.text} </a>
|
||||||
|
</div> `
|
||||||
|
)
|
||||||
|
.addTo(this.map);
|
||||||
|
this.map.setView(
|
||||||
|
pin.coordinates.split(", ").map((x) => parseFloat(x)),
|
||||||
|
13
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
3
src/back/jdd-components/nice-box/nice-box.css
Normal file
3
src/back/jdd-components/nice-box/nice-box.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.nice-box {
|
||||||
|
background-color: white;
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
|
export default class ComponentDebugger extends Controller {
|
||||||
|
id: string;
|
||||||
|
main_form: HTMLFormElement;
|
||||||
|
is_resizing: boolean = false;
|
||||||
|
origin_x: number;
|
||||||
|
origin_width: number;
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.main_form = document.querySelector("#component-debugger").closest("form");
|
||||||
|
document.documentElement.addEventListener("ts-rebuilt", () => {
|
||||||
|
this.main_form.requestSubmit();
|
||||||
|
});
|
||||||
|
this.main_form.addEventListener("turbo:submit-end", () => {
|
||||||
|
// this clears the values of file inputs, so they don't get unecessarily
|
||||||
|
// re-uploaded on future submissions - the file is alreade there on the server
|
||||||
|
this.main_form
|
||||||
|
.querySelectorAll("input[type=file]")
|
||||||
|
.forEach((input: HTMLInputElement) => (input.value = ""));
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
this.update_width_display();
|
||||||
|
});
|
||||||
|
document.addEventListener("turbo:render", () => this.update_width_display());
|
||||||
|
|
||||||
|
const gutter = this.targets.find("gutter") as HTMLDivElement;
|
||||||
|
gutter.addEventListener("mousedown", (e) => {
|
||||||
|
this.is_resizing = true;
|
||||||
|
this.origin_x = e.clientX;
|
||||||
|
const resizable = this.targets.find("preview") as HTMLSpanElement;
|
||||||
|
this.origin_width = resizable.getBoundingClientRect().width;
|
||||||
|
const handler = this.resizeHandler.bind(this);
|
||||||
|
document.addEventListener("mousemove", handler);
|
||||||
|
document.addEventListener("mouseup", () => {
|
||||||
|
document.removeEventListener("mousemove", handler);
|
||||||
|
});
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update_width_display() {
|
||||||
|
const component_width = (this.targets.find("preview") as HTMLSpanElement)
|
||||||
|
.offsetWidth;
|
||||||
|
(
|
||||||
|
this.targets.find("component-width") as HTMLSpanElement
|
||||||
|
).innerHTML = `(width: ${component_width}px)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeHandler(e: MouseEvent) {
|
||||||
|
const width_offset = this.origin_x - e.clientX;
|
||||||
|
|
||||||
|
const new_width = Math.max(this.origin_width + width_offset, 1);
|
||||||
|
document
|
||||||
|
.getElementById("component-debugger")
|
||||||
|
.style.setProperty("--resizable-column-width", new_width + "px");
|
||||||
|
this.update_width_display();
|
||||||
|
}
|
||||||
|
}
|
@ -40,11 +40,7 @@ export async function ComponentInputTable<
|
|||||||
return (
|
return (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{arg_path.at(-1)}</legend>
|
<legend>{arg_path.at(-1)}</legend>
|
||||||
<div
|
<div>
|
||||||
style={`max-width: calc(var(--resizable-column-width) - ${
|
|
||||||
arg_path.length + 3
|
|
||||||
} * 14px); overflow-x: auto; max-height: 500px; overflow-y: auto;`}
|
|
||||||
>
|
|
||||||
<table style="position: relative; /* necessary for sticky th*/">
|
<table style="position: relative; /* necessary for sticky th*/">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
.two-column {
|
.two-column {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: min-content 15px 1fr;
|
grid-template-columns: 1fr 15px min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.resize-gutter {
|
.resize-gutter {
|
||||||
@ -15,7 +15,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.resizable {
|
.resizable {
|
||||||
width: var(--resizable-column-width);
|
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +23,20 @@
|
|||||||
transform: scale(0.99);
|
transform: scale(0.99);
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.component-preview {
|
||||||
|
width: var(--resizable-column-width);
|
||||||
|
|
||||||
|
& > fieldset {
|
||||||
|
min-width: 0; /* default is min-content and that causes overflow*/
|
||||||
|
max-height: calc(100vh - 75px);
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.component-arguments {
|
||||||
|
max-height: calc(100vh - 80px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.component-preview-parameters {
|
.component-preview-parameters {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { render } from "@sealcode/jdd";
|
import { render, renderEarlyAssets } from "@sealcode/jdd";
|
||||||
import { StateAndMetadata, StatefulPage, to_base64 } from "@sealcode/sealgen";
|
import { StatefulPage, to_base64 } from "@sealcode/sealgen";
|
||||||
import { hasFieldOfType, hasShape, predicates } from "@sealcode/ts-predicates";
|
import { hasShape, predicates } from "@sealcode/ts-predicates";
|
||||||
import { BaseContext } from "koa";
|
import { BaseContext } from "koa";
|
||||||
import { Templatable, TempstreamJSX } from "tempstream";
|
import { Templatable, tempstream, TempstreamJSX } from "tempstream";
|
||||||
import html from "../html.js";
|
import html, { defaultHead } from "../html.js";
|
||||||
import { registry } from "../jdd-components/components.js";
|
import { registry } from "../jdd-components/components.js";
|
||||||
import { ComponentInput } from "./component-preview/component-input.js";
|
import { ComponentInput } from "./component-preview/component-input.js";
|
||||||
import { ComponentPreviewActions } from "./component-preview/component-preview-actions.js";
|
import { ComponentPreviewActions } from "./component-preview/component-preview-actions.js";
|
||||||
@ -31,13 +31,33 @@ export default new (class ComponentsPage extends StatefulPage<
|
|||||||
return initial_state;
|
return initial_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapInLayout(ctx: BaseContext, content: Templatable): Templatable {
|
wrapInLayout(
|
||||||
return html(ctx, "Components", content, {
|
ctx: BaseContext,
|
||||||
morphing: false,
|
content: Templatable,
|
||||||
preserveScroll: true,
|
state: ComponentPreviewState
|
||||||
autoRefreshCSS: true,
|
): Templatable {
|
||||||
navbar: () => ``,
|
return html(
|
||||||
});
|
ctx,
|
||||||
|
"Components",
|
||||||
|
content,
|
||||||
|
{
|
||||||
|
morphing: true,
|
||||||
|
preserveScroll: true,
|
||||||
|
autoRefreshCSS: true,
|
||||||
|
navbar: () => ``,
|
||||||
|
},
|
||||||
|
(...args) =>
|
||||||
|
tempstream`${defaultHead(...args)}${renderEarlyAssets(
|
||||||
|
registry,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
component_name: state.component,
|
||||||
|
args: state.component_args,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
jdd_context
|
||||||
|
)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapInForm(state: ComponentPreviewState, content: Templatable): Templatable {
|
wrapInForm(state: ComponentPreviewState, content: Templatable): Templatable {
|
||||||
@ -96,8 +116,9 @@ export default new (class ComponentsPage extends StatefulPage<
|
|||||||
class="two-column"
|
class="two-column"
|
||||||
id="component-debugger"
|
id="component-debugger"
|
||||||
style="--resizable-column-width: 50vw"
|
style="--resizable-column-width: 50vw"
|
||||||
|
data-controller="component-debugger"
|
||||||
>
|
>
|
||||||
<div class="resizable">
|
<div class="component-arguments">
|
||||||
{/*The below button has to be here in order for it to be the default behavior */}
|
{/*The below button has to be here in order for it to be the default behavior */}
|
||||||
<input type="submit" value="Preview" />
|
<input type="submit" value="Preview" />
|
||||||
<select
|
<select
|
||||||
@ -135,11 +156,12 @@ export default new (class ComponentsPage extends StatefulPage<
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
<code>{JSON.stringify(state)}</code>
|
<code>{JSON.stringify(state)}</code>
|
||||||
</div>
|
</div>
|
||||||
<div class="resize-gutter"></div>
|
<div class="resize-gutter" data-component-debugger-target="gutter"></div>
|
||||||
<div class="component-preview">
|
<div class="component-preview" data-component-debugger-target="preview">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>
|
<legend>
|
||||||
Preview <span id="component_width_span"></span>
|
Preview{" "}
|
||||||
|
<span data-component-debugger-target="component-width"></span>
|
||||||
</legend>
|
</legend>
|
||||||
{render(
|
{render(
|
||||||
registry,
|
registry,
|
||||||
@ -155,75 +177,11 @@ export default new (class ComponentsPage extends StatefulPage<
|
|||||||
{
|
{
|
||||||
/* HTML */ `<script>
|
/* HTML */ `<script>
|
||||||
(function () {
|
(function () {
|
||||||
function update_width_display() {
|
|
||||||
const component_width =
|
|
||||||
document.getElementsByClassName(
|
|
||||||
"component-preview"
|
|
||||||
)[0].offsetWidth;
|
|
||||||
document.getElementById(
|
|
||||||
"component_width_span"
|
|
||||||
).innerHTML = \`(width: \${component_width}px)\`;
|
|
||||||
}
|
|
||||||
window.addEventListener("load", (event) => {
|
|
||||||
update_width_display();
|
|
||||||
});
|
|
||||||
document.addEventListener(
|
|
||||||
"turbo:render",
|
|
||||||
update_width_display
|
|
||||||
);
|
|
||||||
let is_resizing = false;
|
|
||||||
let origin_x;
|
|
||||||
let origin_width;
|
|
||||||
const gutter = document.querySelector(".resize-gutter");
|
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
|
|
||||||
.getElementById("component-debugger")
|
|
||||||
.style.setProperty(
|
|
||||||
"--resizable-column-width",
|
|
||||||
new_width + "px"
|
|
||||||
);
|
|
||||||
update_width_display();
|
|
||||||
};
|
|
||||||
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>`
|
</script>`
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{
|
|
||||||
/* HTML */ `<script>
|
|
||||||
const main_form = document
|
|
||||||
.querySelector("#component-debugger")
|
|
||||||
.closest("form");
|
|
||||||
document.documentElement.addEventListener("ts-rebuilt", () => {
|
|
||||||
main_form.requestSubmit();
|
|
||||||
});
|
|
||||||
main_form.addEventListener("turbo:submit-end", () => {
|
|
||||||
// this clears the values of file inputs, so they don't get unecessarily
|
|
||||||
// re-uploaded on future submissions - the file is alreade there on the server
|
|
||||||
main_form
|
|
||||||
.querySelectorAll("input[type=file]")
|
|
||||||
.forEach((input) => (input.value = ""));
|
|
||||||
});
|
|
||||||
</script>`
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
22
src/front/controllers.ts
Normal file
22
src/front/controllers.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// DO NOT EDIT! This file is generated automaticaly with 'npm run generate-stimulus'
|
||||||
|
|
||||||
|
import * as Turbo from "@hotwired/turbo";
|
||||||
|
import { Application } from "stimulus";
|
||||||
|
const application = Application.start();
|
||||||
|
|
||||||
|
import { default as RefreshOnTsChanges } from "./../back/html/refresh-on-ts-changes.stimulus.js";
|
||||||
|
application.register("refresh-on-ts-changes", RefreshOnTsChanges);
|
||||||
|
|
||||||
|
import { default as RefreshStyles } from "./../back/html/refresh-styles.stimulus.js";
|
||||||
|
application.register("refresh-styles", RefreshStyles);
|
||||||
|
|
||||||
|
import { default as MapWithPins } from "./../back/jdd-components/map-with-pins/map-with-pins.stimulus.js";
|
||||||
|
application.register("map-with-pins", MapWithPins);
|
||||||
|
|
||||||
|
import { default as ComponentDebugger } from "./../back/routes/component-preview/component-debugger.stimulus.js";
|
||||||
|
application.register("component-debugger", ComponentDebugger);
|
||||||
|
|
||||||
|
import { default as InputImagePreview } from "./../back/routes/component-preview/input-image-preview.stimulus.js";
|
||||||
|
application.register("input-image-preview", InputImagePreview);
|
||||||
|
|
||||||
|
export { Turbo };
|
@ -1,10 +1 @@
|
|||||||
import * as Turbo from "@hotwired/turbo";
|
export * from "./controllers.js";
|
||||||
import { Application } from "stimulus";
|
|
||||||
import InputImagePreview from "./controllers/input-image-preview";
|
|
||||||
import TaskController from "./controllers/task-controller";
|
|
||||||
|
|
||||||
export { Turbo };
|
|
||||||
|
|
||||||
const application = Application.start();
|
|
||||||
application.register("task", TaskController);
|
|
||||||
application.register("input-image-preview", InputImagePreview);
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
@import "../node_modules/@sealcode/sealgen/src/forms/forms.css";
|
@import "../node_modules/@sealcode/sealgen/src/forms/forms.css";
|
||||||
@import "back/jdd-components/image-demo/image-demo.css";
|
@import "back/jdd-components/image-demo/image-demo.css";
|
||||||
@import "back/jdd-components/map-with-pins/map-with-pins.css";
|
@import "back/jdd-components/map-with-pins/map-with-pins.css";
|
||||||
|
@import "back/jdd-components/nice-box/nice-box.css";
|
||||||
@import "back/jdd-components/table/table.css";
|
@import "back/jdd-components/table/table.css";
|
||||||
@import "back/routes/common/ui/input.css";
|
@import "back/routes/common/ui/input.css";
|
||||||
@import "back/routes/components.css";
|
@import "back/routes/components.css";
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"target": "ES2019",
|
"target": "ES2019",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"lib": ["es2021"],
|
"lib": ["es2021"],
|
||||||
"outDir": "../../dist/back",
|
"outDir": "./dist/back",
|
||||||
"keyofStringsOnly": true,
|
"keyofStringsOnly": true,
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"reactNamespace": "TempstreamJSX",
|
"reactNamespace": "TempstreamJSX",
|
||||||
@ -19,6 +19,7 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"types": ["vitest/globals"]
|
"types": ["vitest/globals"]
|
||||||
},
|
},
|
||||||
"include": ["./**/*", "./*"],
|
"include": ["./src/back/*", "./src/back/**/*"],
|
||||||
|
"exclude": ["./src/front", "./src/**/*.stimulus.ts"],
|
||||||
"ts-node": { "experimentalResolver": true, "esm": true }
|
"ts-node": { "experimentalResolver": true, "esm": true }
|
||||||
}
|
}
|
@ -5,5 +5,5 @@
|
|||||||
"lib": ["dom"],
|
"lib": ["dom"],
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
"include": ["./**/*", "./index.ts"]
|
"include": ["./src/front", "./src/**/*.stimulus.ts"]
|
||||||
}
|
}
|
6
tsconfig.json
Normal file
6
tsconfig.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig-front.json" },
|
||||||
|
{ "path": "./tsconfig-back.json" }
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user