@plitzi/cli 0.38.9 → 0.38.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +83 -0
- package/README.md +13 -5
- package/dist/index.js +526 -208
- package/package.json +3 -3
- package/skills/plitzi-cli/reference/projects.md +1 -1
package/dist/index.js
CHANGED
|
@@ -1354,7 +1354,7 @@ var n$3 = [
|
|
|
1354
1354
|
".otf"
|
|
1355
1355
|
];
|
|
1356
1356
|
var r$5 = () => Object.fromEntries(n$3.map((e) => [e, "dataurl"]));
|
|
1357
|
-
var i$
|
|
1357
|
+
var i$4 = /\?(raw|inline)$/;
|
|
1358
1358
|
var a$5 = {
|
|
1359
1359
|
".wasm": "application/wasm",
|
|
1360
1360
|
".js": "text/javascript",
|
|
@@ -1371,8 +1371,8 @@ var a$5 = {
|
|
|
1371
1371
|
var o$4 = () => ({
|
|
1372
1372
|
name: "plitzi-import-queries",
|
|
1373
1373
|
setup: (n) => {
|
|
1374
|
-
n.onResolve({ filter: i$
|
|
1375
|
-
let t = i$
|
|
1374
|
+
n.onResolve({ filter: i$4 }, async (e) => {
|
|
1375
|
+
let t = i$4.exec(e.path)?.[1] ?? "raw", r = await n.resolve(e.path.replace(i$4, ""), {
|
|
1376
1376
|
kind: e.kind,
|
|
1377
1377
|
importer: e.importer,
|
|
1378
1378
|
resolveDir: e.resolveDir
|
|
@@ -2656,7 +2656,7 @@ ${code(".claude/skills/plitzi-cli/SKILL.md")} first: ${code("plitzi plugin add")
|
|
|
2656
2656
|
|
|
2657
2657
|
What you leave behind is the next reader's problem — the user's, or the next agent's. Before calling a change done:
|
|
2658
2658
|
|
|
2659
|
-
- **Nothing unused.** Delete what you made and no longer use — a file, a page, a component, a class, a token, a data file, an import, a plugin folder. No commented-out code, no ${code("console.log")} left from debugging, no copy of a file kept "just in case": git keeps the history.
|
|
2659
|
+
- **Nothing unused.** Delete what you made and no longer use — a file, a page, a component, a class, a token, a data file, an import, a plugin folder. A folder's ${code(".gitkeep")} keeps it in git while it is empty; once the folder holds files it does nothing, and ${code("doctor")} and ${code("upgrade")} ask for it no more. No commented-out code, no ${code("console.log")} left from debugging, no copy of a file kept "just in case": git keeps the history.
|
|
2660
2660
|
- **Scratch goes in ${code(`tmp/`)}, or nowhere.** A one-off script, a dump, a picture to look at — never at the root or beside the source, where it reads as part of the project.
|
|
2661
2661
|
- **One of everything.** A look used twice is a class; a value used twice is a token; a block used twice is a component, and rows of data are one list. Change it where it is defined, and rename everywhere when you rename.
|
|
2662
2662
|
- **Files a reader can find.** One part per file, named after what it is, in the folder of its kind — the shape ${code("src/space/")} already has. Do not start a parallel layout of your own.
|
|
@@ -2908,6 +2908,8 @@ var serverOptionsModule = (local) => `import type { ProjectServerOptions } from
|
|
|
2908
2908
|
*
|
|
2909
2909
|
* - \`images: { domains: ['images.example.com'] }\` — pictures from those hosts resized here, with \`sharp\` installed.
|
|
2910
2910
|
${local ? ACTION_OPTIONS_DOC : ""} * - \`rsc: { elementTimeoutMs }\` — how long a section resolved on the server is waited for: 5 s by default.
|
|
2911
|
+
* - \`devMode\` — the development build, the dev tools, a public action's trace: on unless \`NODE_ENV\` is \`production\`.
|
|
2912
|
+
* \`devMode: false\` keeps them off wherever the server is started, \`NODE_ENV\` or not. \`devReload\` follows it.
|
|
2911
2913
|
*/
|
|
2912
2914
|
export const serverOptions: ProjectServerOptions = {};
|
|
2913
2915
|
`;
|
|
@@ -4425,15 +4427,15 @@ var __exportAll = (all, no_symbols) => {
|
|
|
4425
4427
|
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
4426
4428
|
return target;
|
|
4427
4429
|
};
|
|
4428
|
-
var e$
|
|
4429
|
-
var t$63 = `(?:${e$
|
|
4430
|
-
var n$47 = `\\[\\s*(?:\\d+|'[^']*'|"[^"]*"|${e$
|
|
4431
|
-
var r$36 = `${`${e$
|
|
4432
|
-
var i$
|
|
4433
|
-
var a$24 = `(?:${`\\{\\{\\{\\s*${r$36}\\s*\\}\\}\\}`}|${i$
|
|
4430
|
+
var e$43 = "[a-zA-Z_][a-zA-Z0-9_]*(?:-[a-zA-Z0-9_]+)*";
|
|
4431
|
+
var t$63 = `(?:${e$43}|\\d+)`;
|
|
4432
|
+
var n$47 = `\\[\\s*(?:\\d+|'[^']*'|"[^"]*"|${e$43}(?:\\.${t$63})*)\\s*\\]`;
|
|
4433
|
+
var r$36 = `${`${e$43}(?:${n$47})*(?:\\??\\.${t$63}(?:${n$47})*)*`}(?:\\s*\\?\\?\\s*[^|{}]+?)?(?:\\s*\\|\\s*[a-zA-Z_]+(?:\\([^)]*\\))?)*`;
|
|
4434
|
+
var i$29 = `\\{\\{\\s*${r$36}\\s*\\}\\}`;
|
|
4435
|
+
var a$24 = `(?:${`\\{\\{\\{\\s*${r$36}\\s*\\}\\}\\}`}|${i$29})`;
|
|
4434
4436
|
new RegExp(a$24, "g");
|
|
4435
4437
|
RegExp(`^${a$24}$`);
|
|
4436
|
-
var e$
|
|
4438
|
+
var e$42 = ["smooth", "auto"];
|
|
4437
4439
|
var t$61 = [
|
|
4438
4440
|
"start",
|
|
4439
4441
|
"center",
|
|
@@ -4445,7 +4447,7 @@ var r$34 = {
|
|
|
4445
4447
|
type: "select",
|
|
4446
4448
|
description: "How it moves: \"smooth\" glides there, \"auto\" jumps.",
|
|
4447
4449
|
default: "smooth",
|
|
4448
|
-
options: [...e$
|
|
4450
|
+
options: [...e$42]
|
|
4449
4451
|
};
|
|
4450
4452
|
var a$22 = {
|
|
4451
4453
|
setState: {
|
|
@@ -4561,7 +4563,7 @@ var a$22 = {
|
|
|
4561
4563
|
}
|
|
4562
4564
|
}
|
|
4563
4565
|
};
|
|
4564
|
-
var e$
|
|
4566
|
+
var e$41 = {
|
|
4565
4567
|
onLoad: {
|
|
4566
4568
|
action: "onLoad",
|
|
4567
4569
|
title: "On Load",
|
|
@@ -4731,7 +4733,7 @@ var e$40 = {
|
|
|
4731
4733
|
params: {}
|
|
4732
4734
|
}
|
|
4733
4735
|
};
|
|
4734
|
-
var e$
|
|
4736
|
+
var e$40 = () => (e) => e;
|
|
4735
4737
|
var t$60 = () => (e) => e;
|
|
4736
4738
|
var t$59 = t$60()({
|
|
4737
4739
|
type: "blockHtml",
|
|
@@ -4964,13 +4966,13 @@ var n$44 = {
|
|
|
4964
4966
|
var r$33 = t$60()({
|
|
4965
4967
|
type: "button",
|
|
4966
4968
|
attributeValues: {
|
|
4967
|
-
subType: e$
|
|
4969
|
+
subType: e$40()([
|
|
4968
4970
|
"button",
|
|
4969
4971
|
"submit",
|
|
4970
4972
|
"reset"
|
|
4971
4973
|
]),
|
|
4972
|
-
contentPlacement: e$
|
|
4973
|
-
iconPlacement: e$
|
|
4974
|
+
contentPlacement: e$40()(["before", "after"]),
|
|
4975
|
+
iconPlacement: e$40()(["before", "after"])
|
|
4974
4976
|
},
|
|
4975
4977
|
content: {
|
|
4976
4978
|
attributes: {
|
|
@@ -5038,7 +5040,7 @@ var r$33 = t$60()({
|
|
|
5038
5040
|
});
|
|
5039
5041
|
var n$43 = t$60()({
|
|
5040
5042
|
type: "dropdown",
|
|
5041
|
-
attributeValues: { popupPlacement: e$
|
|
5043
|
+
attributeValues: { popupPlacement: e$40()([
|
|
5042
5044
|
"left",
|
|
5043
5045
|
"right",
|
|
5044
5046
|
"top",
|
|
@@ -5169,7 +5171,7 @@ var t$54 = t$60()({
|
|
|
5169
5171
|
});
|
|
5170
5172
|
var n$42 = t$60()({
|
|
5171
5173
|
type: "heading",
|
|
5172
|
-
attributeValues: { subType: e$
|
|
5174
|
+
attributeValues: { subType: e$40()([
|
|
5173
5175
|
"h1",
|
|
5174
5176
|
"h2",
|
|
5175
5177
|
"h3",
|
|
@@ -5291,20 +5293,20 @@ var n$42 = t$60()({
|
|
|
5291
5293
|
var n$41 = t$60()({
|
|
5292
5294
|
type: "link",
|
|
5293
5295
|
attributeValues: {
|
|
5294
|
-
mode: e$
|
|
5296
|
+
mode: e$40()([
|
|
5295
5297
|
"page",
|
|
5296
5298
|
"internal",
|
|
5297
5299
|
"external"
|
|
5298
5300
|
]),
|
|
5299
|
-
target: e$
|
|
5301
|
+
target: e$40()([
|
|
5300
5302
|
"self",
|
|
5301
5303
|
"blank",
|
|
5302
5304
|
"parent",
|
|
5303
5305
|
"top"
|
|
5304
5306
|
]),
|
|
5305
|
-
contentPlacement: e$
|
|
5306
|
-
iconPlacement: e$
|
|
5307
|
-
current: e$
|
|
5307
|
+
contentPlacement: e$40()(["before", "after"]),
|
|
5308
|
+
iconPlacement: e$40()(["before", "after"]),
|
|
5309
|
+
current: e$40()(["page", "section"])
|
|
5308
5310
|
},
|
|
5309
5311
|
content: {
|
|
5310
5312
|
attributes: {
|
|
@@ -5476,7 +5478,7 @@ var t$52 = t$60()({
|
|
|
5476
5478
|
});
|
|
5477
5479
|
var n$40 = t$60()({
|
|
5478
5480
|
type: "richText",
|
|
5479
|
-
attributeValues: { format: e$
|
|
5481
|
+
attributeValues: { format: e$40()([
|
|
5480
5482
|
"html",
|
|
5481
5483
|
"markdown",
|
|
5482
5484
|
"text"
|
|
@@ -5613,7 +5615,7 @@ var n$39 = {
|
|
|
5613
5615
|
};
|
|
5614
5616
|
var r$32 = t$60()({
|
|
5615
5617
|
type: "themeToggle",
|
|
5616
|
-
attributeValues: { subType: e$
|
|
5618
|
+
attributeValues: { subType: e$40()(["switch", "segmented"]) },
|
|
5617
5619
|
triggers: { onThemeChange: {
|
|
5618
5620
|
action: "onThemeChange",
|
|
5619
5621
|
title: "On Theme Change",
|
|
@@ -5679,7 +5681,7 @@ var r$32 = t$60()({
|
|
|
5679
5681
|
});
|
|
5680
5682
|
var n$38 = t$60()({
|
|
5681
5683
|
type: "form",
|
|
5682
|
-
attributeValues: { method: e$
|
|
5684
|
+
attributeValues: { method: e$40()(["get", "post"]) },
|
|
5683
5685
|
sourceType: "apiContainer",
|
|
5684
5686
|
triggers: { onSubmit: {
|
|
5685
5687
|
action: "onSubmit",
|
|
@@ -5813,7 +5815,7 @@ var r$31 = {
|
|
|
5813
5815
|
...n$37,
|
|
5814
5816
|
"line-height": "20px"
|
|
5815
5817
|
};
|
|
5816
|
-
var i$
|
|
5818
|
+
var i$26 = {
|
|
5817
5819
|
display: "flex",
|
|
5818
5820
|
cursor: "pointer",
|
|
5819
5821
|
"font-weight": "600",
|
|
@@ -5823,7 +5825,7 @@ var i$25 = {
|
|
|
5823
5825
|
"user-select": "none"
|
|
5824
5826
|
};
|
|
5825
5827
|
var a$21 = {
|
|
5826
|
-
...i$
|
|
5828
|
+
...i$26,
|
|
5827
5829
|
"margin-bottom": "4px"
|
|
5828
5830
|
};
|
|
5829
5831
|
var o$23 = {
|
|
@@ -5857,7 +5859,7 @@ var l$13 = {
|
|
|
5857
5859
|
"font-size": "inherit",
|
|
5858
5860
|
"box-shadow": "none"
|
|
5859
5861
|
};
|
|
5860
|
-
var u$
|
|
5862
|
+
var u$14 = {
|
|
5861
5863
|
height: "100%",
|
|
5862
5864
|
width: "100%",
|
|
5863
5865
|
display: "block",
|
|
@@ -5941,7 +5943,7 @@ var m$7 = (e, t, { field: n, icon: r } = {}) => ({
|
|
|
5941
5943
|
var h$4 = { field: l$13 };
|
|
5942
5944
|
var g$4 = t$60()({
|
|
5943
5945
|
type: "formControl",
|
|
5944
|
-
attributeValues: { subType: e$
|
|
5946
|
+
attributeValues: { subType: e$40()([
|
|
5945
5947
|
"text",
|
|
5946
5948
|
"number",
|
|
5947
5949
|
"email",
|
|
@@ -5996,7 +5998,7 @@ var g$4 = t$60()({
|
|
|
5996
5998
|
definition: {
|
|
5997
5999
|
label: "Form Control",
|
|
5998
6000
|
type: "formControl",
|
|
5999
|
-
description: "A single labelled input (text/select/checkbox/… per its subType) inside a form; captures one field of user input. A select offers its `options`: `[{ label, value }, …]` — the text shown, and what the field takes. A `switch` is a checkbox announced and drawn as an on/off switch (`role=\"switch\"`), for a setting that applies at once; both hold `true`/`false`, and a `defaultValue` of `\"true\"` starts them on. Its slots: `label`, `requiredMark` (the `*` that ends the label of a required field), `input` (the box a typed field or a select is drawn in — a textarea, checkbox or switch is its own box), `field` (the `<input>` or `<select>` inside that box), `icon` (the show/hide button of a password) and `error`. The thumb of a switch is no element a class reaches: the class on its `input` slot sets `--plitzi-switch-thumb` (off), `--plitzi-switch-thumb-checked` (on, white by default) and `--plitzi-switch-thumb-shadow`.",
|
|
6001
|
+
description: "A single labelled input (text/select/checkbox/… per its subType) inside a form; captures one field of user input. Optional unless `required: true`, as an HTML field is: a `requiredMessage` alone requires nothing. A select offers its `options`: `[{ label, value }, …]` — the text shown, and what the field takes. A `switch` is a checkbox announced and drawn as an on/off switch (`role=\"switch\"`), for a setting that applies at once; both hold `true`/`false`, and a `defaultValue` of `\"true\"` starts them on. Its slots: `label`, `requiredMark` (the `*` that ends the label of a required field), `input` (the box a typed field or a select is drawn in — a textarea, checkbox or switch is its own box), `field` (the `<input>` or `<select>` inside that box), `icon` (the show/hide button of a password) and `error`. The box is ringed (`2px solid currentColor`) while the field inside has keyboard focus: restyle it with a `focus-within` state on the `input` slot — the box never takes `focus` itself. The thumb of a switch is no element a class reaches: the class on its `input` slot sets `--plitzi-switch-thumb` (off), `--plitzi-switch-thumb-checked` (on, white by default) and `--plitzi-switch-thumb-shadow`.",
|
|
6000
6002
|
bindings: {},
|
|
6001
6003
|
styleSelectors: {
|
|
6002
6004
|
base: "",
|
|
@@ -6051,7 +6053,7 @@ var g$4 = t$60()({
|
|
|
6051
6053
|
color: "inherit",
|
|
6052
6054
|
resize: "vertical"
|
|
6053
6055
|
}),
|
|
6054
|
-
select: m$7("Form Control Select", f$10, { field: u$
|
|
6056
|
+
select: m$7("Form Control Select", f$10, { field: u$14 }),
|
|
6055
6057
|
checkbox: {
|
|
6056
6058
|
name: "Form Control Checkbox",
|
|
6057
6059
|
displayMode: "desktop",
|
|
@@ -6063,7 +6065,7 @@ var g$4 = t$60()({
|
|
|
6063
6065
|
"margin-left": "0px",
|
|
6064
6066
|
"margin-right": "4px"
|
|
6065
6067
|
} },
|
|
6066
|
-
label: { default: i$
|
|
6068
|
+
label: { default: i$26 },
|
|
6067
6069
|
requiredMark: { default: s$20 },
|
|
6068
6070
|
error: { default: o$23 }
|
|
6069
6071
|
}
|
|
@@ -6075,7 +6077,7 @@ var g$4 = t$60()({
|
|
|
6075
6077
|
base: { default: {} },
|
|
6076
6078
|
input: { default: p$11 },
|
|
6077
6079
|
label: { default: {
|
|
6078
|
-
...i$
|
|
6080
|
+
...i$26,
|
|
6079
6081
|
"align-items": "center"
|
|
6080
6082
|
} },
|
|
6081
6083
|
requiredMark: { default: s$20 },
|
|
@@ -6089,7 +6091,7 @@ var g$4 = t$60()({
|
|
|
6089
6091
|
});
|
|
6090
6092
|
var n$36 = t$60()({
|
|
6091
6093
|
type: "layoutContainer",
|
|
6092
|
-
attributeValues: { subType: e$
|
|
6094
|
+
attributeValues: { subType: e$40()([
|
|
6093
6095
|
"div",
|
|
6094
6096
|
"header",
|
|
6095
6097
|
"footer",
|
|
@@ -6221,6 +6223,11 @@ var t$49 = t$60()({
|
|
|
6221
6223
|
});
|
|
6222
6224
|
var t$48 = t$60()({
|
|
6223
6225
|
type: "page",
|
|
6226
|
+
serverTemplates: [
|
|
6227
|
+
"seoPageTitle",
|
|
6228
|
+
"seoPageDescription",
|
|
6229
|
+
"notFound"
|
|
6230
|
+
],
|
|
6224
6231
|
triggers: { onPageLoad: {
|
|
6225
6232
|
action: "onPageLoad",
|
|
6226
6233
|
title: "On Page Load",
|
|
@@ -6388,12 +6395,12 @@ var t$46 = t$60()({
|
|
|
6388
6395
|
var n$35 = t$60()({
|
|
6389
6396
|
type: "image",
|
|
6390
6397
|
attributeValues: {
|
|
6391
|
-
fetchPriority: e$
|
|
6398
|
+
fetchPriority: e$40()([
|
|
6392
6399
|
"high",
|
|
6393
6400
|
"low",
|
|
6394
6401
|
"auto"
|
|
6395
6402
|
]),
|
|
6396
|
-
loadMode: e$
|
|
6403
|
+
loadMode: e$40()([
|
|
6397
6404
|
"auto",
|
|
6398
6405
|
"eager",
|
|
6399
6406
|
"lazy"
|
|
@@ -6542,7 +6549,7 @@ var t$44 = t$60()({
|
|
|
6542
6549
|
var n$34 = t$60()({
|
|
6543
6550
|
type: "apiContainer",
|
|
6544
6551
|
attributeValues: {
|
|
6545
|
-
subType: e$
|
|
6552
|
+
subType: e$40()([
|
|
6546
6553
|
"",
|
|
6547
6554
|
"div",
|
|
6548
6555
|
"header",
|
|
@@ -6555,25 +6562,26 @@ var n$34 = t$60()({
|
|
|
6555
6562
|
"address",
|
|
6556
6563
|
"figure"
|
|
6557
6564
|
]),
|
|
6558
|
-
method: e$
|
|
6565
|
+
method: e$40()([
|
|
6559
6566
|
"get",
|
|
6560
6567
|
"post",
|
|
6561
6568
|
"put",
|
|
6562
6569
|
"delete",
|
|
6563
6570
|
"patch"
|
|
6564
6571
|
]),
|
|
6565
|
-
credentials: e$
|
|
6572
|
+
credentials: e$40()([
|
|
6566
6573
|
"include",
|
|
6567
6574
|
"omit",
|
|
6568
6575
|
"same-origin"
|
|
6569
6576
|
]),
|
|
6570
|
-
pagination: e$
|
|
6577
|
+
pagination: e$40()([
|
|
6571
6578
|
"none",
|
|
6572
6579
|
"url",
|
|
6573
6580
|
"append"
|
|
6574
6581
|
])
|
|
6575
6582
|
},
|
|
6576
6583
|
sourceType: "apiContainer",
|
|
6584
|
+
serverTemplates: ["notFound"],
|
|
6577
6585
|
triggers: {
|
|
6578
6586
|
onApiError: {
|
|
6579
6587
|
action: "onApiError",
|
|
@@ -6715,7 +6723,7 @@ var n$34 = t$60()({
|
|
|
6715
6723
|
});
|
|
6716
6724
|
var n$33 = t$60()({
|
|
6717
6725
|
type: "channel",
|
|
6718
|
-
attributeValues: { subType: e$
|
|
6726
|
+
attributeValues: { subType: e$40()([
|
|
6719
6727
|
"",
|
|
6720
6728
|
"div",
|
|
6721
6729
|
"section",
|
|
@@ -6835,6 +6843,49 @@ var n$33 = t$60()({
|
|
|
6835
6843
|
}
|
|
6836
6844
|
});
|
|
6837
6845
|
var t$43 = t$60()({
|
|
6846
|
+
type: "carouselTrack",
|
|
6847
|
+
ancestorType: "carousel",
|
|
6848
|
+
content: {
|
|
6849
|
+
attributes: {},
|
|
6850
|
+
definition: {
|
|
6851
|
+
label: "Carousel Track",
|
|
6852
|
+
type: "carouselTrack",
|
|
6853
|
+
description: "Where a carousel shows its slides: what is inside is one slide, rendered once per item.",
|
|
6854
|
+
items: [],
|
|
6855
|
+
bindings: {},
|
|
6856
|
+
styleSelectors: { base: "" },
|
|
6857
|
+
initialState: { visibility: !0 }
|
|
6858
|
+
},
|
|
6859
|
+
builder: {
|
|
6860
|
+
canDelete: !0,
|
|
6861
|
+
canSelect: !0,
|
|
6862
|
+
canDragDrop: !0,
|
|
6863
|
+
canMove: !0,
|
|
6864
|
+
canSnippet: !1,
|
|
6865
|
+
itemsAllowed: [],
|
|
6866
|
+
itemsNotAllowed: []
|
|
6867
|
+
},
|
|
6868
|
+
market: {
|
|
6869
|
+
category: "structure",
|
|
6870
|
+
owner: "Plitzi",
|
|
6871
|
+
verified: !0,
|
|
6872
|
+
license: "MIT",
|
|
6873
|
+
website: "https://plitzi.com",
|
|
6874
|
+
backgroundColor: "#4422ee",
|
|
6875
|
+
icon: "fa-solid fa-film"
|
|
6876
|
+
},
|
|
6877
|
+
defaultStyle: {
|
|
6878
|
+
name: "Carousel Track",
|
|
6879
|
+
displayMode: "desktop",
|
|
6880
|
+
style: { base: { default: {
|
|
6881
|
+
position: "relative",
|
|
6882
|
+
overflow: "hidden"
|
|
6883
|
+
} } }
|
|
6884
|
+
},
|
|
6885
|
+
settings: {}
|
|
6886
|
+
}
|
|
6887
|
+
});
|
|
6888
|
+
var t$42 = t$60()({
|
|
6838
6889
|
type: "carousel",
|
|
6839
6890
|
sourceType: "carousel",
|
|
6840
6891
|
triggers: { onChange: {
|
|
@@ -6936,53 +6987,10 @@ var t$43 = t$60()({
|
|
|
6936
6987
|
},
|
|
6937
6988
|
initialItems: ["carouselTrack"]
|
|
6938
6989
|
});
|
|
6939
|
-
var t$42 = t$60()({
|
|
6940
|
-
type: "carouselTrack",
|
|
6941
|
-
ancestorType: "carousel",
|
|
6942
|
-
content: {
|
|
6943
|
-
attributes: {},
|
|
6944
|
-
definition: {
|
|
6945
|
-
label: "Carousel Track",
|
|
6946
|
-
type: "carouselTrack",
|
|
6947
|
-
description: "Where a carousel shows its slides: what is inside is one slide, rendered once per item.",
|
|
6948
|
-
items: [],
|
|
6949
|
-
bindings: {},
|
|
6950
|
-
styleSelectors: { base: "" },
|
|
6951
|
-
initialState: { visibility: !0 }
|
|
6952
|
-
},
|
|
6953
|
-
builder: {
|
|
6954
|
-
canDelete: !0,
|
|
6955
|
-
canSelect: !0,
|
|
6956
|
-
canDragDrop: !0,
|
|
6957
|
-
canMove: !0,
|
|
6958
|
-
canSnippet: !1,
|
|
6959
|
-
itemsAllowed: [],
|
|
6960
|
-
itemsNotAllowed: []
|
|
6961
|
-
},
|
|
6962
|
-
market: {
|
|
6963
|
-
category: "structure",
|
|
6964
|
-
owner: "Plitzi",
|
|
6965
|
-
verified: !0,
|
|
6966
|
-
license: "MIT",
|
|
6967
|
-
website: "https://plitzi.com",
|
|
6968
|
-
backgroundColor: "#4422ee",
|
|
6969
|
-
icon: "fa-solid fa-film"
|
|
6970
|
-
},
|
|
6971
|
-
defaultStyle: {
|
|
6972
|
-
name: "Carousel Track",
|
|
6973
|
-
displayMode: "desktop",
|
|
6974
|
-
style: { base: { default: {
|
|
6975
|
-
position: "relative",
|
|
6976
|
-
overflow: "hidden"
|
|
6977
|
-
} } }
|
|
6978
|
-
},
|
|
6979
|
-
settings: {}
|
|
6980
|
-
}
|
|
6981
|
-
});
|
|
6982
6990
|
var r$30 = t$60()({
|
|
6983
6991
|
type: "container",
|
|
6984
6992
|
attributeValues: {
|
|
6985
|
-
subType: e$
|
|
6993
|
+
subType: e$40()([
|
|
6986
6994
|
"div",
|
|
6987
6995
|
"header",
|
|
6988
6996
|
"footer",
|
|
@@ -7006,7 +7014,7 @@ var r$30 = t$60()({
|
|
|
7006
7014
|
"p",
|
|
7007
7015
|
"span"
|
|
7008
7016
|
]),
|
|
7009
|
-
live: e$
|
|
7017
|
+
live: e$40()([
|
|
7010
7018
|
"",
|
|
7011
7019
|
"polite",
|
|
7012
7020
|
"assertive"
|
|
@@ -7097,8 +7105,8 @@ var B$2 = {
|
|
|
7097
7105
|
BlockHtml: t$59,
|
|
7098
7106
|
BlockJsx: t$58,
|
|
7099
7107
|
Button: r$33,
|
|
7100
|
-
Carousel: t$
|
|
7101
|
-
CarouselTrack: t$
|
|
7108
|
+
Carousel: t$42,
|
|
7109
|
+
CarouselTrack: t$43,
|
|
7102
7110
|
Channel: n$33,
|
|
7103
7111
|
Container: r$30,
|
|
7104
7112
|
Custom: t$57,
|
|
@@ -7231,8 +7239,7 @@ var B$2 = {
|
|
|
7231
7239
|
top: "0",
|
|
7232
7240
|
position: "absolute",
|
|
7233
7241
|
"z-index": "210",
|
|
7234
|
-
"background-color": "
|
|
7235
|
-
opacity: "0.5"
|
|
7242
|
+
"background-color": "rgb(0 0 0 / 50%)"
|
|
7236
7243
|
} },
|
|
7237
7244
|
rootContainer: { default: {
|
|
7238
7245
|
display: "flex",
|
|
@@ -7303,8 +7310,8 @@ var B$2 = {
|
|
|
7303
7310
|
List: t$60()({
|
|
7304
7311
|
type: "list",
|
|
7305
7312
|
attributeValues: {
|
|
7306
|
-
subType: e$
|
|
7307
|
-
source: e$
|
|
7313
|
+
subType: e$40()(["ul", "ol"]),
|
|
7314
|
+
source: e$40()(["none", "controlled"])
|
|
7308
7315
|
},
|
|
7309
7316
|
sourceType: "list",
|
|
7310
7317
|
content: {
|
|
@@ -7467,7 +7474,7 @@ var B$2 = {
|
|
|
7467
7474
|
definition: {
|
|
7468
7475
|
label: "Modal Container",
|
|
7469
7476
|
type: "modalContainer",
|
|
7470
|
-
description: "A modal overlay container opened and closed through interactions; use for dialogs over the page.",
|
|
7477
|
+
description: "A modal overlay container opened and closed through interactions; use for dialogs over the page. The element itself is fixed over the whole viewport, and holds two layers side by side — neither inside the other: `backgroundContainer`, the dim layer, `rgb(0 0 0 / 50%)` (its `background-color` is the whole dim), and `rootContainer`, the dialog, centred by `top: 50%`, `left: 50%` and `transform: translate3d(-50%, -50%, 0)` — to sit it near the top, set `top` and `transform: translateX(-50%)`; flex alignment on the dim layer moves nothing. Inside the dialog, top to bottom: `headerContainer` (with `headerTitle` and `headerCloseButton`) and `bodyContainer`.",
|
|
7471
7478
|
items: [],
|
|
7472
7479
|
bindings: {},
|
|
7473
7480
|
loadStrategy: "lazy",
|
|
@@ -7519,8 +7526,7 @@ var B$2 = {
|
|
|
7519
7526
|
top: "0",
|
|
7520
7527
|
position: "absolute",
|
|
7521
7528
|
"z-index": "210",
|
|
7522
|
-
"background-color": "
|
|
7523
|
-
opacity: "0.5"
|
|
7529
|
+
"background-color": "rgb(0 0 0 / 50%)"
|
|
7524
7530
|
} },
|
|
7525
7531
|
rootContainer: { default: {
|
|
7526
7532
|
display: "flex",
|
|
@@ -7604,8 +7610,8 @@ var B$2 = {
|
|
|
7604
7610
|
Pagination: t$60()({
|
|
7605
7611
|
type: "pagination",
|
|
7606
7612
|
attributeValues: {
|
|
7607
|
-
mode: e$
|
|
7608
|
-
target: e$
|
|
7613
|
+
mode: e$40()(["pages", "loadMore"]),
|
|
7614
|
+
target: e$40()(["url", "interaction"])
|
|
7609
7615
|
},
|
|
7610
7616
|
triggers: { onPageChange: {
|
|
7611
7617
|
action: "onPageChange",
|
|
@@ -7857,6 +7863,7 @@ var B$2 = {
|
|
|
7857
7863
|
ThemeToggle: r$32,
|
|
7858
7864
|
Video: t$44
|
|
7859
7865
|
};
|
|
7866
|
+
Object.fromEntries(Object.values(B$2).flatMap((e) => "serverTemplates" in e ? [[e.type, e.serverTemplates]] : []));
|
|
7860
7867
|
/** Every declaration, read through the part of its shape this catalog uses. */
|
|
7861
7868
|
var declarations$1 = B$2;
|
|
7862
7869
|
/** Keyed by the schema `type`, which is what a document and every catalog address a type by. */
|
|
@@ -7867,7 +7874,7 @@ var elementCatalog = Object.fromEntries(Object.values(declarations$1).map((decla
|
|
|
7867
7874
|
}]));
|
|
7868
7875
|
Object.keys(elementCatalog);
|
|
7869
7876
|
Object.fromEntries(Object.values(declarations$1).filter((declaration) => declaration.sourceType).map((declaration) => [declaration.type, declaration.sourceType]));
|
|
7870
|
-
Object.fromEntries(Object.values(declarations$1).map((declaration) => [declaration.type, [...Object.keys(e$
|
|
7877
|
+
Object.fromEntries(Object.values(declarations$1).map((declaration) => [declaration.type, [...Object.keys(e$41), ...Object.keys(declaration.triggers ?? {})]]));
|
|
7871
7878
|
/** The triggers only some types fire, by action name — for a step builder that wants the title the builder shows. */
|
|
7872
7879
|
var typeTriggerDefinitions = Object.fromEntries(Object.values(declarations$1).flatMap((declaration) => Object.entries(declaration.triggers ?? {})));
|
|
7873
7880
|
Object.fromEntries(Object.values(declarations$1).flatMap((declaration) => Object.entries(declaration.callbacks ?? {})));
|
|
@@ -7968,6 +7975,11 @@ var AUTHORING_CODES = {
|
|
|
7968
7975
|
means: "a page that sends visitors it is not for to a page the space does not have",
|
|
7969
7976
|
fix: "a page's id or slug (`''` is the home page), or a full URL"
|
|
7970
7977
|
},
|
|
7978
|
+
"page-template": {
|
|
7979
|
+
kind: "refused",
|
|
7980
|
+
means: "a template in a page's `seoTitle`, `seoDescription` or `notFound` that reads what is not there when the server answers — anything but the page's `runtime: 'server'` providers and `navigation` — or cannot be read",
|
|
7981
|
+
fix: "read the record from a provider with `runtime: 'server'` on the page or its layout — `'{{ apiContainer_post.title }} — Blog'` — or words of its own"
|
|
7982
|
+
},
|
|
7971
7983
|
"folder-undeclared": {
|
|
7972
7984
|
kind: "refused",
|
|
7973
7985
|
means: "a page, a layout or a folder filed in a folder the space does not declare",
|
|
@@ -8143,6 +8155,11 @@ var AUTHORING_CODES = {
|
|
|
8143
8155
|
means: "an ancestor condition keyed by something that is neither a class name nor `'>'` (the parent)",
|
|
8144
8156
|
fix: "`[card.name]` for a `styles()` declaration, or `'>'` for the parent whatever it wears"
|
|
8145
8157
|
},
|
|
8158
|
+
"focus-on-field-box": {
|
|
8159
|
+
kind: "warned",
|
|
8160
|
+
means: "a `focus` or `focus-visible` state on a text field's or a select's `input` slot — the box the field is drawn in, which never takes focus, so no ring is ever shown",
|
|
8161
|
+
fix: "`'focus-within'` on the same class, or the state on the `field` slot"
|
|
8162
|
+
},
|
|
8146
8163
|
"heading-level-overridden": {
|
|
8147
8164
|
kind: "warned",
|
|
8148
8165
|
means: "a markdown's or richText's `heading` slot and a level's (`heading3`) both setting one property, the general class written later in the stylesheet — the level's value is lost",
|
|
@@ -8380,7 +8397,7 @@ var AUTHORING_CODES = {
|
|
|
8380
8397
|
},
|
|
8381
8398
|
"not-found-not-a-template": {
|
|
8382
8399
|
kind: "refused",
|
|
8383
|
-
means: "`notFound
|
|
8400
|
+
means: "`notFound`, a provider's or a page's, that is not one `{{ expression }}` — never `true`, so never a 404",
|
|
8384
8401
|
fix: "`notFound: '{{ source.found == false }}'`"
|
|
8385
8402
|
},
|
|
8386
8403
|
"server-data-in-browser": {
|
|
@@ -8403,6 +8420,11 @@ var AUTHORING_CODES = {
|
|
|
8403
8420
|
means: "a control in a form with no `name` — its value never reaches `values`",
|
|
8404
8421
|
fix: "`formControl({ name: 'email', … })`"
|
|
8405
8422
|
},
|
|
8423
|
+
"required-message-unused": {
|
|
8424
|
+
kind: "warned",
|
|
8425
|
+
means: "a `requiredMessage` on a field nothing requires — fields are optional unless `required: true`, so it is never shown and an empty answer is sent",
|
|
8426
|
+
fix: "`required: true` on the field, or no message"
|
|
8427
|
+
},
|
|
8406
8428
|
"form-control-name-taken": {
|
|
8407
8429
|
kind: "warned",
|
|
8408
8430
|
means: "two controls in one form with one name — one overwrites the other",
|
|
@@ -8983,7 +9005,7 @@ var sourceRow = (listSource, items) => {
|
|
|
8983
9005
|
index: pathTo(`${listSource}.index`, 0)
|
|
8984
9006
|
};
|
|
8985
9007
|
};
|
|
8986
|
-
var e$
|
|
9008
|
+
var e$39 = [
|
|
8987
9009
|
"variables",
|
|
8988
9010
|
"navigation",
|
|
8989
9011
|
"auth",
|
|
@@ -8993,7 +9015,7 @@ var e$38 = [
|
|
|
8993
9015
|
"flags",
|
|
8994
9016
|
"computed"
|
|
8995
9017
|
];
|
|
8996
|
-
e$
|
|
9018
|
+
e$39.filter((e) => e !== "state" && e !== "computed");
|
|
8997
9019
|
var t$30 = {
|
|
8998
9020
|
DISPLAY: "display",
|
|
8999
9021
|
FLEX_WRAP: "flex-wrap",
|
|
@@ -9199,7 +9221,7 @@ Object.values(t$30).map((e) => ({
|
|
|
9199
9221
|
label: e
|
|
9200
9222
|
}));
|
|
9201
9223
|
t$30.DISPLAY, t$30.FLEX_WRAP, t$30.FLEX_DIRECTION, t$30.ALIGN_ITEMS, t$30.JUSTIFY_ITEMS, t$30.JUSTIFY_CONTENT, t$30.ALIGN_CONTENT, t$30.ROW_GAP, t$30.COLUMN_GAP, t$30.GRID_ROW_GAP, t$30.GRID_COLUMN_GAP, t$30.GRID_TEMPLATE_AREAS, t$30.GRID_TEMPLATE_COLUMNS, t$30.GRID_TEMPLATE_ROWS, t$30.GRID_AUTO_FLOW, t$30.GRID_AUTO_ROWS, t$30.GRID_AUTO_COLUMNS, t$30.GRID_ROW_START, t$30.GRID_COLUMN_START, t$30.GRID_ROW_END, t$30.GRID_COLUMN_END, t$30.ALIGN_SELF, t$30.JUSTIFY_SELF, t$30.ORDER, t$30.FLEX_GROW, t$30.FLEX_SHRINK, t$30.FLEX_BASIS, t$30.LIST_STYLE, t$30.LIST_STYLE_TYPE, t$30.LIST_STYLE_POSITION, t$30.LIST_STYLE_IMAGE, t$30.BACKGROUND_COLOR, t$30.BACKGROUND_IMAGE, t$30.BACKGROUND_POSITION, t$30.BACKGROUND_SIZE, t$30.BACKGROUND_CLIP, t$30.BACKGROUND_ORIGIN, t$30.BACKGROUND_REPEAT, t$30.BACKGROUND_ATTACHMENT, t$30.BACKGROUND_BLEND_MODE, t$30.MASK_IMAGE, t$30.MASK_SIZE, t$30.MASK_POSITION, t$30.MASK_REPEAT, t$30.MASK_COMPOSITE, t$30.WEBKIT_MASK_IMAGE, t$30.BORDER_TOP_STYLE, t$30.BORDER_TOP_WIDTH, t$30.BORDER_TOP_COLOR, t$30.BORDER_BOTTOM_STYLE, t$30.BORDER_BOTTOM_WIDTH, t$30.BORDER_BOTTOM_COLOR, t$30.BORDER_LEFT_STYLE, t$30.BORDER_LEFT_WIDTH, t$30.BORDER_LEFT_COLOR, t$30.BORDER_RIGHT_STYLE, t$30.BORDER_RIGHT_WIDTH, t$30.BORDER_RIGHT_COLOR, t$30.BORDER_TOP_LEFT_RADIUS, t$30.BORDER_TOP_RIGHT_RADIUS, t$30.BORDER_BOTTOM_LEFT_RADIUS, t$30.BORDER_BOTTOM_RIGHT_RADIUS, t$30.BORDER_COLLAPSE, t$30.BORDER_SPACING, t$30.TABLE_LAYOUT, t$30.OPACITY, t$30.VISIBILITY, t$30.CURSOR, t$30.TRANSITION, t$30.TRANSITION_PROPERTY, t$30.TRANSITION_DURATION, t$30.TRANSITION_TIMING_FUNCTION, t$30.TRANSITION_DELAY, t$30.TRANSITION_BEHAVIOR, t$30.ANIMATION, t$30.ANIMATION_NAME, t$30.ANIMATION_DURATION, t$30.ANIMATION_TIMING_FUNCTION, t$30.ANIMATION_DELAY, t$30.ANIMATION_ITERATION_COUNT, t$30.ANIMATION_DIRECTION, t$30.ANIMATION_FILL_MODE, t$30.ANIMATION_PLAY_STATE, t$30.ANIMATION_TIMELINE, t$30.ANIMATION_RANGE, t$30.BOX_SHADOW, t$30.FILTER, t$30.BACKDROP_FILTER, t$30.MIX_BLEND_MODE, t$30.ISOLATION, t$30.CLIP_PATH, t$30.TRANSFORM, t$30.TRANSFORM_ORIGIN, t$30.TRANSLATE, t$30.ROTATE, t$30.SCALE, t$30.TRANSFORM_STYLE, t$30.PERSPECTIVE, t$30.PERSPECTIVE_ORIGIN, t$30.BACKFACE_VISIBILITY, t$30.WILL_CHANGE, t$30.OUTLINE_WIDTH, t$30.OUTLINE_STYLE, t$30.OUTLINE_COLOR, t$30.OUTLINE_OFFSET, t$30.POINTER_EVENTS, t$30.USER_SELECT, t$30.TOUCH_ACTION, t$30.RESIZE, t$30.APPEARANCE, t$30.SCROLL_BEHAVIOR, t$30.OVERSCROLL_BEHAVIOR, t$30.SCROLL_SNAP_TYPE, t$30.SCROLL_SNAP_ALIGN, t$30.SCROLL_SNAP_STOP, t$30.SCROLL_PADDING_TOP, t$30.SCROLL_MARGIN_TOP, t$30.ACCENT_COLOR, t$30.CARET_COLOR, t$30.COLOR_SCHEME, t$30.POSITION, t$30.FLOAT, t$30.CLEAR, t$30.Z_INDEX, t$30.TOP, t$30.BOTTOM, t$30.LEFT, t$30.RIGHT, t$30.BOX_SIZING, t$30.ASPECT_RATIO, t$30.WIDTH, t$30.HEIGHT, t$30.MIN_WIDTH, t$30.MIN_HEIGHT, t$30.MAX_WIDTH, t$30.MAX_HEIGHT, t$30.OVERFLOW, t$30.OVERFLOW_X, t$30.OVERFLOW_Y, t$30.SCROLLBAR_WIDTH, t$30.SCROLLBAR_COLOR, t$30.CONTAINER_TYPE, t$30.CONTENT, t$30.CONTAINER_NAME, t$30.OBJECT_FIT, t$30.OBJECT_POSITION, t$30.COLUMN_WIDTH, t$30.COLUMN_COUNT, t$30.MARGIN_TOP, t$30.MARGIN_BOTTOM, t$30.MARGIN_LEFT, t$30.MARGIN_RIGHT, t$30.PADDING_TOP, t$30.PADDING_BOTTOM, t$30.PADDING_LEFT, t$30.PADDING_RIGHT, t$30.FONT_FAMILY, t$30.FONT_WEIGHT, t$30.FONT_SIZE, t$30.LINE_HEIGHT, t$30.COLOR, t$30.TEXT_ALIGN, t$30.FONT_STYLE, t$30.FONT_VARIANT, t$30.FONT_VARIANT_NUMERIC, t$30.FONT_FEATURE_SETTINGS, t$30.TEXT_DECORATION, t$30.TEXT_DECORATION_LINE, t$30.TEXT_DECORATION_COLOR, t$30.TEXT_DECORATION_STYLE, t$30.TEXT_DECORATION_THICKNESS, t$30.TEXT_UNDERLINE_OFFSET, t$30.LETTER_SPACING, t$30.WORD_SPACING, t$30.TEXT_INDENT, t$30.TEXT_TRANSFORM, t$30.DIRECTION, t$30.WRITING_MODE, t$30.TEXT_ORIENTATION, t$30.WHITE_SPACE, t$30.TEXT_WRAP, t$30.WORD_BREAK, t$30.OVERFLOW_WRAP, t$30.HYPHENS, t$30.VERTICAL_ALIGN, t$30.TEXT_OVERFLOW, t$30.TEXT_SHADOW, t$30.LINE_CLAMP, t$30.WEBKIT_LINE_CLAMP, t$30.WEBKIT_BOX_ORIENT, t$30.WEBKIT_TEXT_FILL_COLOR, t$30.WEBKIT_BACKGROUND_CLIP, t$30.BOX_DECORATION_BREAK, t$30.WEBKIT_BOX_DECORATION_BREAK, t$30.FILL, t$30.STROKE, t$30.STROKE_WIDTH;
|
|
9202
|
-
[...e$
|
|
9224
|
+
[...e$39];
|
|
9203
9225
|
/** Both binding forms as one list. The map form targets attributes, which is what nearly every binding does. */
|
|
9204
9226
|
var toBindingSpecs = (bind) => Array.isArray(bind) ? bind : Object.entries(bind).map(([to, source]) => ({
|
|
9205
9227
|
to,
|
|
@@ -9511,20 +9533,20 @@ var tabContainerItem = defineElement(B$2.TabContainerItem);
|
|
|
9511
9533
|
var text$1 = defineElement(B$2.Text);
|
|
9512
9534
|
var themeToggle = defineElement(B$2.ThemeToggle);
|
|
9513
9535
|
var video = defineElement(B$2.Video);
|
|
9514
|
-
var e$
|
|
9536
|
+
var e$33 = (e) => typeof e == "object" && !!e && !Array.isArray(e);
|
|
9515
9537
|
var STEP_TYPES = [
|
|
9516
9538
|
"trigger",
|
|
9517
9539
|
"globalCallback",
|
|
9518
9540
|
"callback",
|
|
9519
9541
|
"utility"
|
|
9520
9542
|
];
|
|
9521
|
-
var e$
|
|
9543
|
+
var e$31 = {
|
|
9522
9544
|
desktop: 1024,
|
|
9523
9545
|
tablet: 768,
|
|
9524
9546
|
mobile: 0
|
|
9525
9547
|
};
|
|
9526
|
-
var t$26 = (t) => e$
|
|
9527
|
-
var e$
|
|
9548
|
+
var t$26 = (t) => e$31[t] === 0 ? "0" : `${String(e$31[t] / 16)}rem`;
|
|
9549
|
+
var e$30 = [
|
|
9528
9550
|
"desktop",
|
|
9529
9551
|
"tablet",
|
|
9530
9552
|
"mobile"
|
|
@@ -9532,14 +9554,14 @@ var e$29 = [
|
|
|
9532
9554
|
Object.values(/* @__PURE__ */ function(e) {
|
|
9533
9555
|
return e.COLOR = "color", e.SPACING = "spacing", e.SHADOW = "shadow", e.CUSTOM = "custom", e;
|
|
9534
9556
|
}({}));
|
|
9535
|
-
var e$
|
|
9557
|
+
var e$28 = {
|
|
9536
9558
|
"motion-reduce": "@media (prefers-reduced-motion: reduce)",
|
|
9537
9559
|
"motion-safe": "@media (prefers-reduced-motion: no-preference)"
|
|
9538
9560
|
};
|
|
9539
|
-
var t$23 = Object.keys(e$
|
|
9540
|
-
var r$18 = (t) => Object.hasOwn(e$
|
|
9541
|
-
var i$
|
|
9542
|
-
var a$15 = String.raw`\((?:min|max)-width:\s*${i$
|
|
9561
|
+
var t$23 = Object.keys(e$28);
|
|
9562
|
+
var r$18 = (t) => Object.hasOwn(e$28, t);
|
|
9563
|
+
var i$18 = String.raw`\d+(?:\.\d+)?(?:px|rem|em|ch)`;
|
|
9564
|
+
var a$15 = String.raw`\((?:min|max)-width:\s*${i$18}\)`;
|
|
9543
9565
|
var o$17 = new RegExp(String.raw`^container(?:\s+(?<name>-?[_a-zA-Z][\w-]*))?\s+(?<query>${a$15}(?:\s+and\s+${a$15})?)$`);
|
|
9544
9566
|
var s$15 = (e) => {
|
|
9545
9567
|
let t = o$17.exec(e.trim());
|
|
@@ -9553,7 +9575,7 @@ var c$12 = (e) => {
|
|
|
9553
9575
|
let t = s$15(e);
|
|
9554
9576
|
if (t) return t.name ? `container ${t.name} ${t.query}` : `container ${t.query}`;
|
|
9555
9577
|
};
|
|
9556
|
-
var e$
|
|
9578
|
+
var e$27 = [
|
|
9557
9579
|
"before",
|
|
9558
9580
|
"after",
|
|
9559
9581
|
"marker",
|
|
@@ -9572,7 +9594,7 @@ var t$22 = {
|
|
|
9572
9594
|
selection: "::selection"
|
|
9573
9595
|
};
|
|
9574
9596
|
var n$19 = (e) => Object.hasOwn(t$22, e);
|
|
9575
|
-
var i$
|
|
9597
|
+
var i$17 = [
|
|
9576
9598
|
"before",
|
|
9577
9599
|
"after",
|
|
9578
9600
|
"marker"
|
|
@@ -9633,7 +9655,7 @@ var l$8 = {
|
|
|
9633
9655
|
...c$11
|
|
9634
9656
|
]
|
|
9635
9657
|
};
|
|
9636
|
-
var u$
|
|
9658
|
+
var u$8 = (e, t) => {
|
|
9637
9659
|
let n = l$8[e];
|
|
9638
9660
|
return !n || t.startsWith("--") || n.includes(t);
|
|
9639
9661
|
};
|
|
@@ -9672,7 +9694,7 @@ var m$4 = (e) => {
|
|
|
9672
9694
|
let t = p$8(e.trim());
|
|
9673
9695
|
return t?.length ? t.every((e) => /^(["']).*\1$/s.test(e) || d$7.has(e.toLowerCase()) || f$5.test(e) && e.endsWith(")")) : !1;
|
|
9674
9696
|
};
|
|
9675
|
-
var e$
|
|
9697
|
+
var e$26 = [
|
|
9676
9698
|
"hover",
|
|
9677
9699
|
"focus",
|
|
9678
9700
|
"focus-visible",
|
|
@@ -9707,7 +9729,7 @@ var r$16 = {
|
|
|
9707
9729
|
disabled: 13,
|
|
9708
9730
|
hidden: 14
|
|
9709
9731
|
};
|
|
9710
|
-
var i$
|
|
9732
|
+
var i$16 = (e) => Object.hasOwn(r$16, e);
|
|
9711
9733
|
var l$7 = {
|
|
9712
9734
|
current: ":is([aria-current]:not([aria-current=\"false\"]),[aria-pressed=\"true\"],[aria-selected=\"true\"],[role=\"tabpanel\"]:not([hidden]))",
|
|
9713
9735
|
expanded: "[aria-expanded=\"true\"]",
|
|
@@ -9717,7 +9739,7 @@ var l$7 = {
|
|
|
9717
9739
|
odd: ":nth-child(odd)",
|
|
9718
9740
|
even: ":nth-child(even)"
|
|
9719
9741
|
};
|
|
9720
|
-
var u$
|
|
9742
|
+
var u$7 = (e) => (i$16(e) ? l$7[e] : void 0) ?? `:${e}`;
|
|
9721
9743
|
var p$7 = (e) => e === ">";
|
|
9722
9744
|
var n$16 = (e) => {
|
|
9723
9745
|
let t = typeof e == "string" && e.trim() !== "" ? Number(e) : e;
|
|
@@ -9753,7 +9775,7 @@ var r$13 = {
|
|
|
9753
9775
|
del: "delete",
|
|
9754
9776
|
return: "enter"
|
|
9755
9777
|
};
|
|
9756
|
-
var i$
|
|
9778
|
+
var i$13 = /* @__PURE__ */ new Set([
|
|
9757
9779
|
"escape",
|
|
9758
9780
|
"enter",
|
|
9759
9781
|
"tab",
|
|
@@ -9786,7 +9808,7 @@ var o$11 = (e, t) => {
|
|
|
9786
9808
|
}
|
|
9787
9809
|
if (u.length !== 1) return { problem: `"${e.trim()}" names ${u.length ? `${u.length} keys (${u.join(", ")})` : "no key, only modifiers"}: a shortcut is modifiers and ONE key, like "shift+f"` };
|
|
9788
9810
|
let [d] = u;
|
|
9789
|
-
return d.length !== 1 && !i$
|
|
9811
|
+
return d.length !== 1 && !i$13.has(d) ? { problem: `"${d}" in "${e.trim()}" is not a key: use one character ("f", "?", "+") or a key's name (${[...i$13].slice(0, 15).join(", ")}, f1…f12)` } : { combo: a$10(l, d) };
|
|
9790
9812
|
};
|
|
9791
9813
|
var s$9 = (e, t = !1) => {
|
|
9792
9814
|
let n = e.split(",").map((e) => o$11(e, t));
|
|
@@ -9839,7 +9861,7 @@ var steps_exports$1 = /* @__PURE__ */ __exportAll({
|
|
|
9839
9861
|
* the builders useless for exactly the flows that matter most.
|
|
9840
9862
|
*/
|
|
9841
9863
|
var builtinTrigger = (trigger) => {
|
|
9842
|
-
if (Object.hasOwn(e$
|
|
9864
|
+
if (Object.hasOwn(e$41, trigger)) return e$41[trigger];
|
|
9843
9865
|
return Object.hasOwn(typeTriggerDefinitions, trigger) ? typeTriggerDefinitions[trigger] : void 0;
|
|
9844
9866
|
};
|
|
9845
9867
|
var on = (trigger, params = {}) => {
|
|
@@ -10150,7 +10172,7 @@ var carouselGoTo = (target, index) => carouselStep(target, "goTo", "Go To Slide"
|
|
|
10150
10172
|
var carouselPlay = (target) => carouselStep(target, "play", "Play");
|
|
10151
10173
|
/** The carousel `target` stops moving by itself until it is told to play. */
|
|
10152
10174
|
var carouselPause = (target) => carouselStep(target, "pause", "Pause");
|
|
10153
|
-
var e$
|
|
10175
|
+
var e$22 = {
|
|
10154
10176
|
origin: "Requests to the same site",
|
|
10155
10177
|
all: "All cached requests",
|
|
10156
10178
|
elements: "Only these containers",
|
|
@@ -10162,7 +10184,7 @@ var t$16 = (t, n = () => !0) => ({
|
|
|
10162
10184
|
description: "What to refresh once the write succeeded, so the page shows the new data: the requests to the same site, every provider on the page, only the api containers named in `invalidateElements`, or none for a step that only reads. Server-driven containers are refreshed too, asking the server past its cache. Containers on screen ask again at once; the rest when they are shown.",
|
|
10163
10185
|
default: t[0],
|
|
10164
10186
|
options: [...t],
|
|
10165
|
-
optionLabels: Object.fromEntries(t.map((t) => [t, e$
|
|
10187
|
+
optionLabels: Object.fromEntries(t.map((t) => [t, e$22[t]])),
|
|
10166
10188
|
label: "Refresh cached requests",
|
|
10167
10189
|
canBind: !1,
|
|
10168
10190
|
when: n
|
|
@@ -10242,7 +10264,7 @@ var t$15 = {
|
|
|
10242
10264
|
preview: { cancelled: "" }
|
|
10243
10265
|
}
|
|
10244
10266
|
};
|
|
10245
|
-
var e$
|
|
10267
|
+
var e$21 = {
|
|
10246
10268
|
login: {
|
|
10247
10269
|
source: "auth",
|
|
10248
10270
|
title: "Auth Login",
|
|
@@ -10328,7 +10350,7 @@ var e$20 = {
|
|
|
10328
10350
|
params: {}
|
|
10329
10351
|
}
|
|
10330
10352
|
};
|
|
10331
|
-
var e$
|
|
10353
|
+
var e$20 = { hostAction: {
|
|
10332
10354
|
source: "host",
|
|
10333
10355
|
title: "Host Action",
|
|
10334
10356
|
strictParams: !0,
|
|
@@ -10345,7 +10367,7 @@ var e$19 = { hostAction: {
|
|
|
10345
10367
|
}
|
|
10346
10368
|
}
|
|
10347
10369
|
} };
|
|
10348
|
-
var e$
|
|
10370
|
+
var e$19 = { navigate: {
|
|
10349
10371
|
source: "navigation",
|
|
10350
10372
|
title: "Navigate",
|
|
10351
10373
|
strictParams: !0,
|
|
@@ -10372,7 +10394,7 @@ var e$18 = { navigate: {
|
|
|
10372
10394
|
}
|
|
10373
10395
|
}
|
|
10374
10396
|
} };
|
|
10375
|
-
var e$
|
|
10397
|
+
var e$18 = { invalidateQueries: {
|
|
10376
10398
|
source: "queries",
|
|
10377
10399
|
title: "Invalidate Queries",
|
|
10378
10400
|
strictParams: !0,
|
|
@@ -10605,11 +10627,11 @@ var BUILTIN_GLOBAL_CALLBACKS = {
|
|
|
10605
10627
|
default: ""
|
|
10606
10628
|
} }
|
|
10607
10629
|
},
|
|
10608
|
-
...e$19,
|
|
10609
|
-
...e$18,
|
|
10610
10630
|
...e$20,
|
|
10631
|
+
...e$19,
|
|
10632
|
+
...e$21,
|
|
10611
10633
|
...t$15,
|
|
10612
|
-
...e$
|
|
10634
|
+
...e$18
|
|
10613
10635
|
};
|
|
10614
10636
|
var steps_exports = /* @__PURE__ */ __exportAll({
|
|
10615
10637
|
SET_STATE_TYPES: () => SET_STATE_TYPES,
|
|
@@ -10848,10 +10870,11 @@ var t$14 = (e) => {
|
|
|
10848
10870
|
var t$13 = "[A-Za-z_][A-Za-z0-9_]*";
|
|
10849
10871
|
RegExp(`^${t$13}$`);
|
|
10850
10872
|
RegExp(`^!?${t$13}$`);
|
|
10851
|
-
var e$
|
|
10852
|
-
var e$
|
|
10853
|
-
var i$
|
|
10854
|
-
i$
|
|
10873
|
+
var e$9 = "/data/";
|
|
10874
|
+
var e$7 = (e) => typeof e == "string" && /\{\{[\s\S]*?\}\}|\{%[\s\S]*?%\}/.test(e);
|
|
10875
|
+
var i$5 = (e) => `value|round(0, '${e}')`;
|
|
10876
|
+
i$5("floor"), i$5("ceil");
|
|
10877
|
+
new Set(Object.entries(g$4.content.defaultStyle.subTypes).filter(([, variant]) => "field" in variant.style).map(([subType]) => subType));
|
|
10855
10878
|
/** A container with no tag of its own named: the row `list-row-not-li` makes an `<li>` without asking. */
|
|
10856
10879
|
var isPlainContainer = (element) => element.definition.type === "container" && (element.attributes.subType === void 0 || element.attributes.subType === "div");
|
|
10857
10880
|
new Set(STEP_TYPES);
|
|
@@ -11010,7 +11033,7 @@ Array.from({ length: 9 }, (e, t) => ({
|
|
|
11010
11033
|
Object.entries(AUTHORING_CODES).filter(([, entry]) => entry.kind === "suggested").map(([code]) => code);
|
|
11011
11034
|
var URL_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
|
|
11012
11035
|
/** A page target that is really a URL: the one reading of `mailto:`/`https:` a page-mode link can never mean. */
|
|
11013
|
-
var isUrlTarget = (target) => typeof target === "string" && !e$
|
|
11036
|
+
var isUrlTarget = (target) => typeof target === "string" && !e$7(target) && URL_SCHEME.test(target);
|
|
11014
11037
|
var isRoot = (element) => !element.definition.parentId;
|
|
11015
11038
|
var stepsOf$1 = (element) => Object.values(element.definition.interactions ?? {});
|
|
11016
11039
|
/**
|
|
@@ -11021,7 +11044,7 @@ var settleUnknownKeys = (record, known, what, on, report, defaults = {}) => {
|
|
|
11021
11044
|
for (const key of Object.keys(record)) {
|
|
11022
11045
|
if (known.includes(key)) continue;
|
|
11023
11046
|
const wrapped = record[key];
|
|
11024
|
-
if (e$
|
|
11047
|
+
if (e$33(wrapped) && Object.keys(wrapped).length > 0 && Object.keys(wrapped).every((inner) => known.includes(inner))) {
|
|
11025
11048
|
const inners = Object.keys(wrapped);
|
|
11026
11049
|
if (inners.every((inner) => record[inner] === void 0 || record[inner] === defaults[inner])) {
|
|
11027
11050
|
Object.assign(record, wrapped);
|
|
@@ -11302,7 +11325,7 @@ t$4.map((e) => {
|
|
|
11302
11325
|
fieldOf: (e) => t.get(e)
|
|
11303
11326
|
};
|
|
11304
11327
|
});
|
|
11305
|
-
Object.fromEntries(e$
|
|
11328
|
+
Object.fromEntries(e$30.map((e) => [e, t$26(e)]));
|
|
11306
11329
|
/** Every kebab-case CSS property Plitzi's style engine understands. Values written to a definition must use these
|
|
11307
11330
|
* exact keys — camelCase or unknown keys are rejected. */
|
|
11308
11331
|
var cssProperties = Array.from(new Set(Object.values(t$30))).sort();
|
|
@@ -12087,7 +12110,7 @@ var byProperty = (rules) => {
|
|
|
12087
12110
|
return responsive;
|
|
12088
12111
|
};
|
|
12089
12112
|
/** The states a selector can react to — the closed list the style editor offers, read from where it is declared. */
|
|
12090
|
-
var STYLE_STATES = e$
|
|
12113
|
+
var STYLE_STATES = e$26;
|
|
12091
12114
|
var STYLE_STATE_SET = new Set(STYLE_STATES);
|
|
12092
12115
|
var RULE_SET_KEYS = /* @__PURE__ */ new Set([
|
|
12093
12116
|
"css",
|
|
@@ -12151,11 +12174,11 @@ var assertPseudo = (pseudo, part) => {
|
|
|
12151
12174
|
const ruleSets = partRuleSets(part);
|
|
12152
12175
|
for (const rules of ruleSets) for (const [property, value] of Object.entries(rules)) {
|
|
12153
12176
|
if (property === "content") {
|
|
12154
|
-
if (!i$
|
|
12177
|
+
if (!i$17.includes(pseudo)) throw new AuthoringError("style-pseudo-content", `\`content\` on \`::${pseudo}\` draws nothing: only ${i$17.map((name) => `\`::${name}\``).join(", ")} take one.`);
|
|
12155
12178
|
if (!m$4(String(value))) throw new AuthoringError("style-pseudo-content", `\`content: ${String(value)}\` on \`::${pseudo}\` is not text CSS can read, so nothing is drawn. Text goes in quotes inside the string — \`content: '"${String(value).replace(/"/g, "\\\"")}"'\` — and an empty box is \`'""'\`; \`counter()\`, \`attr()\` and \`url()\` are written as they are.`);
|
|
12156
12179
|
continue;
|
|
12157
12180
|
}
|
|
12158
|
-
if (!u$
|
|
12181
|
+
if (!u$8(pseudo, property)) throw new AuthoringError("style-pseudo-property", `\`${property}\` on \`::${pseudo}\` is dropped by every browser — \`::${pseudo}\` honours ${(l$8[pseudo] ?? []).map((name) => `\`${name}\``).join(", ")}. Style the element itself for the rest.`);
|
|
12159
12182
|
}
|
|
12160
12183
|
if (a$14.includes(pseudo) && !ruleSets.some((rules) => Object.hasOwn(rules, "content"))) throw new AuthoringError("style-pseudo-content", `\`::${pseudo}\` has no \`content\`, so the browser draws nothing for it. Give it one — \`content: '""'\` for an empty box — in its rules or in a state's.`);
|
|
12161
12184
|
};
|
|
@@ -12163,7 +12186,7 @@ var toPseudos = (pseudos) => {
|
|
|
12163
12186
|
const parts = /* @__PURE__ */ new Map();
|
|
12164
12187
|
for (const [name, spec] of Object.entries(pseudos ?? {})) {
|
|
12165
12188
|
const bare = name.replace(/^:+/, "");
|
|
12166
|
-
if (!n$19(name)) throw new AuthoringError("style-pseudo-unknown", `Unknown pseudo-element "${name}"${n$19(bare) ? ` — write it without the colons, "${bare}"` : didYouMean(bare, e$
|
|
12189
|
+
if (!n$19(name)) throw new AuthoringError("style-pseudo-unknown", `Unknown pseudo-element "${name}"${n$19(bare) ? ` — write it without the colons, "${bare}"` : didYouMean(bare, e$27)}. A class dresses ${e$27.join(", ")}.`);
|
|
12167
12190
|
const part = partOf(spec);
|
|
12168
12191
|
const rules = {
|
|
12169
12192
|
base: toResponsive(part.css),
|
|
@@ -13789,7 +13812,7 @@ var createTw = ({ colors = {} } = {}) => (classes) => {
|
|
|
13789
13812
|
return rules;
|
|
13790
13813
|
};
|
|
13791
13814
|
createTw();
|
|
13792
|
-
[...new Set(STYLE_STATES.filter((state) => state !== "hidden"))].filter((state) => u$
|
|
13815
|
+
[...new Set(STYLE_STATES.filter((state) => state !== "hidden"))].filter((state) => u$7(state) !== `:${state}`);
|
|
13793
13816
|
new Set("break case catch class const continue debugger default delete do else enum export extends false finally for function if import in instanceof new null return super switch this throw true try typeof var void while with yield let static implements interface package private protected public await element styles".split(" "));
|
|
13794
13817
|
new Set(STYLE_STATES);
|
|
13795
13818
|
new Set([
|
|
@@ -14972,7 +14995,7 @@ var V$1 = (e) => {
|
|
|
14972
14995
|
for (let n of e.filter((e) => x$2.test(e))) t.set(M$1(n), [...t.get(M$1(n)) ?? [], n]);
|
|
14973
14996
|
return [...t].flatMap(([e, t]) => t.slice(1).map((n) => y$1("plugin-type-taken", `${o$1$1}/${n}/`, `${o$1$1}/${t[0]}/ and ${o$1$1}/${n}/ are both the plugin ${e}: the server registers a folder by its name with a small first letter, and keeps one.`, `Put them in one folder, or rename one: git mv ${o$1$1}/${n} ${o$1$1}/<AnotherName>`)));
|
|
14974
14997
|
};
|
|
14975
|
-
var H$1 = (t) => e$
|
|
14998
|
+
var H$1 = (t) => e$33(t.assets) ? Object.values(t.assets).flatMap((t) => e$33(t) && typeof t.src == "string" && typeof t.type == "string" ? [{
|
|
14976
14999
|
src: t.src,
|
|
14977
15000
|
type: t.type,
|
|
14978
15001
|
isMain: t.isMain === !0
|
|
@@ -14986,7 +15009,7 @@ var U$1 = (t, n) => {
|
|
|
14986
15009
|
} catch (e) {
|
|
14987
15010
|
return { problem: y$1("vendor-manifest-invalid", i, `${i} is not JSON (${e instanceof Error ? e.message : String(e)}), so ${n} does not run.`, a) };
|
|
14988
15011
|
}
|
|
14989
|
-
if (!e$
|
|
15012
|
+
if (!e$33(o)) return { problem: y$1("vendor-manifest-invalid", i, `${i} is not a manifest, so ${n} does not run.`, a) };
|
|
14990
15013
|
let s = H$1(o), l = s.find((e) => e.type === "script" && e.isMain) ?? s.find((e) => e.type === "script");
|
|
14991
15014
|
if (!l) return { problem: y$1("vendor-script-missing", i, `${i} names no script to run, so ${n} does not run.`, a) };
|
|
14992
15015
|
if (!C$1(t, path.posix.join(r, l.src), "file")) return { problem: y$1("vendor-script-missing", i, `${i} names ${l.src} as the script to run, and ${r}/${l.src} is not there, so ${n} does not run.`, a) };
|
|
@@ -15110,7 +15133,7 @@ var ce$1 = (e, t) => {
|
|
|
15110
15133
|
var Z$1 = (t) => {
|
|
15111
15134
|
try {
|
|
15112
15135
|
let n = JSON.parse(readFileSync(path.join(t, "package.json"), "utf-8"));
|
|
15113
|
-
return e$
|
|
15136
|
+
return e$33(n) && [n.dependencies, n.devDependencies].some((t) => e$33(t) && "@plitzi/sdk-server" in t);
|
|
15114
15137
|
} catch {
|
|
15115
15138
|
return !1;
|
|
15116
15139
|
}
|
|
@@ -15233,7 +15256,7 @@ var publicData = (folder) => fileReader(folder, "/");
|
|
|
15233
15256
|
* never serves (`dataDir`) — for `authorSpace`'s `serverData`: bindings are held to the file, and a provider reading
|
|
15234
15257
|
* one from the browser is refused.
|
|
15235
15258
|
*/
|
|
15236
|
-
var projectData = (folder) => fileReader(folder, e$
|
|
15259
|
+
var projectData = (folder) => fileReader(folder, e$9);
|
|
15237
15260
|
/**
|
|
15238
15261
|
* The declaration of every plugin under `folder` — `src/plugins/<Name>/declaration.ts`, its default export — for
|
|
15239
15262
|
* `authorSpace`'s `plugins`: what each fires, answers and reads. Found by folder, as the server finds the plugins
|
|
@@ -15255,7 +15278,7 @@ var pluginDeclarations = async (folder) => {
|
|
|
15255
15278
|
var manifestOf$1 = (file) => {
|
|
15256
15279
|
try {
|
|
15257
15280
|
const manifest = JSON.parse(readFileSync(file, "utf-8"));
|
|
15258
|
-
return e$
|
|
15281
|
+
return e$33(manifest) ? manifest : {};
|
|
15259
15282
|
} catch {
|
|
15260
15283
|
return {};
|
|
15261
15284
|
}
|
|
@@ -15266,7 +15289,7 @@ var manifestOf$1 = (file) => {
|
|
|
15266
15289
|
*/
|
|
15267
15290
|
var builtPluginTypes = (folder) => existsSync(folder) ? readdirSync(folder, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((a, b) => a.name.localeCompare(b.name)).flatMap((entry) => {
|
|
15268
15291
|
const { pluginSchema } = manifestOf$1(path.join(folder, entry.name, d$1));
|
|
15269
|
-
return [entry.name, ...e$
|
|
15292
|
+
return [entry.name, ...e$33(pluginSchema) ? Object.keys(pluginSchema) : []];
|
|
15270
15293
|
}) : [];
|
|
15271
15294
|
/**
|
|
15272
15295
|
* The stylesheets of the plugins under `folder` — every `.css` in a plugin's folder, at any depth — as their text, for
|
|
@@ -15335,7 +15358,7 @@ var importProjectModule = async (file, root) => {
|
|
|
15335
15358
|
* What the module exports as `space`, taken as a declaration when it has the shape of one. `authorSpace` checks the
|
|
15336
15359
|
* rest of it, field by field, and says what is wrong — so this only has to tell a space from anything else.
|
|
15337
15360
|
*/
|
|
15338
|
-
var isSpaceSpec = (value) => e$
|
|
15361
|
+
var isSpaceSpec = (value) => e$33(value) && typeof value.name === "string" && typeof value.permanentUrl === "string" && Array.isArray(value.pages);
|
|
15339
15362
|
/**
|
|
15340
15363
|
* `projectSpace` of the project at `root`, held to the same checks: for a tool that works on a project from another
|
|
15341
15364
|
* folder — the CLI, run anywhere inside one. A project's own code calls `projectSpace()` or `authorProjectSpace()`.
|
|
@@ -15343,7 +15366,7 @@ var isSpaceSpec = (value) => e$32(value) && typeof value.name === "string" && ty
|
|
|
15343
15366
|
var projectSpaceAt = async (root) => {
|
|
15344
15367
|
const authoring = await projectAuthoringAt(root);
|
|
15345
15368
|
const module = await importProjectModule(l$2(root, a$1, process.argv[1]), root);
|
|
15346
|
-
const space = e$
|
|
15369
|
+
const space = e$33(module) ? module.space : void 0;
|
|
15347
15370
|
if (!isSpaceSpec(space)) throw new ProjectSpaceError(a$1);
|
|
15348
15371
|
return {
|
|
15349
15372
|
space,
|
|
@@ -16294,7 +16317,8 @@ var unifiedDiff = (file, before, after, context = 2) => {
|
|
|
16294
16317
|
* is left to the author, said with the command that would take the registry's.
|
|
16295
16318
|
* - `skills`: `.claude/skills/plitzi-*` from the packages installed, each replaced whole.
|
|
16296
16319
|
* - `renames`: a name a version renamed, still written in the source (`canTemplate`), at its file and line — and with
|
|
16297
|
-
* `--write`, renamed.
|
|
16320
|
+
* `--write`, renamed. With it, what a version changed that the source may count on — a `formControl` written
|
|
16321
|
+
* before fields became optional — at its file and line, for a project last upgraded before: said, never written.
|
|
16298
16322
|
*
|
|
16299
16323
|
* Shown by default; `--write` makes it. What the space is — its pages, plugins, data — is the project's, never named.
|
|
16300
16324
|
*
|
|
@@ -16355,6 +16379,42 @@ var renamesIn = (file, text) => RENAMES.filter((rename) => !rename.from || impor
|
|
|
16355
16379
|
since: rename.since,
|
|
16356
16380
|
what: rename.what
|
|
16357
16381
|
}] : []));
|
|
16382
|
+
/** Before this version a `formControl` was required unless it said `required: false`; from it, optional unless `true`. */
|
|
16383
|
+
var OPTIONAL_FIELDS_SINCE = "0.38.9";
|
|
16384
|
+
/** The text of the call whose `(` is at `open`, up to its `)` — strings skipped, so a `)` inside one closes nothing. */
|
|
16385
|
+
var callArguments = (text, open) => {
|
|
16386
|
+
let depth = 0;
|
|
16387
|
+
let quote;
|
|
16388
|
+
for (let at = open; at < text.length; at++) {
|
|
16389
|
+
const char = text[at];
|
|
16390
|
+
if (quote && char === "\\") {
|
|
16391
|
+
at++;
|
|
16392
|
+
continue;
|
|
16393
|
+
}
|
|
16394
|
+
if (quote) {
|
|
16395
|
+
quote = char === quote ? void 0 : quote;
|
|
16396
|
+
continue;
|
|
16397
|
+
}
|
|
16398
|
+
if (/['"`]/.test(char)) quote = char;
|
|
16399
|
+
else if (char === "(") depth++;
|
|
16400
|
+
else if (char === ")" && --depth === 0) return text.slice(open + 1, at);
|
|
16401
|
+
}
|
|
16402
|
+
return text.slice(open + 1);
|
|
16403
|
+
};
|
|
16404
|
+
/**
|
|
16405
|
+
* A `formControl(…)` that writes no `required`: one that, written before fields became optional, was required, and now
|
|
16406
|
+
* takes an empty answer. Said, never written — whether a field must be answered is the space's to say. Found as written
|
|
16407
|
+
* in the call: one built by a helper of the project's own is the helper's to look at.
|
|
16408
|
+
*/
|
|
16409
|
+
var optionalFieldsIn = (file, text) => [...text.matchAll(/\bformControl\(/g)].flatMap((match) => {
|
|
16410
|
+
const open = match.index + match[0].length - 1;
|
|
16411
|
+
return /\brequired\s*:/.test(callArguments(text, open)) ? [] : [{
|
|
16412
|
+
file,
|
|
16413
|
+
line: text.slice(0, match.index).split("\n").length,
|
|
16414
|
+
since: OPTIONAL_FIELDS_SINCE,
|
|
16415
|
+
what: "a formControl with no `required` is optional now — write `required: true` if it must be answered"
|
|
16416
|
+
}];
|
|
16417
|
+
});
|
|
16358
16418
|
/** The lowest version a range allows, as numbers: `^0.38.2` → [0, 38, 2]. */
|
|
16359
16419
|
var floorOf$1 = (range) => {
|
|
16360
16420
|
const match = /(\d+)\.(\d+)\.(\d+)/.exec(range);
|
|
@@ -16451,8 +16511,20 @@ var readText$1 = async (file) => {
|
|
|
16451
16511
|
return;
|
|
16452
16512
|
}
|
|
16453
16513
|
};
|
|
16514
|
+
var holdsFiles = async (folder) => {
|
|
16515
|
+
try {
|
|
16516
|
+
return (await fs.readdir(folder)).length > 0;
|
|
16517
|
+
} catch {
|
|
16518
|
+
return false;
|
|
16519
|
+
}
|
|
16520
|
+
};
|
|
16454
16521
|
var planFiles = async (root, files, recorded, take) => Promise.all(Object.entries(files).map(async ([file, ours]) => {
|
|
16455
16522
|
const yours = await readText$1(path.join(root, file));
|
|
16523
|
+
if (yours === void 0 && path.basename(file) === ".gitkeep" && await holdsFiles(path.join(root, file, ".."))) return {
|
|
16524
|
+
file,
|
|
16525
|
+
status: "current",
|
|
16526
|
+
ours
|
|
16527
|
+
};
|
|
16456
16528
|
if (yours === void 0) return {
|
|
16457
16529
|
file,
|
|
16458
16530
|
status: "added",
|
|
@@ -16611,6 +16683,10 @@ var reportText$3 = (report, install) => {
|
|
|
16611
16683
|
lines.push(report.renames.length === 0 ? chalk.green("renames: none written") : "renames:");
|
|
16612
16684
|
lines.push(...report.renames.map((found) => chalk.yellow(` ${report.write ? "~" : "!"} ${found.file}:${String(found.line)} ${found.name} → ${found.to} (${found.since}: ${found.what})`)));
|
|
16613
16685
|
}
|
|
16686
|
+
if (report.changes && report.changes.length > 0) {
|
|
16687
|
+
lines.push("changes the source may count on (look, then decide — never written):");
|
|
16688
|
+
lines.push(...report.changes.map((found) => chalk.yellow(` ! ${found.file}:${String(found.line)} (${found.since}) ${found.what}`)));
|
|
16689
|
+
}
|
|
16614
16690
|
return lines.join("\n");
|
|
16615
16691
|
};
|
|
16616
16692
|
var upgrade = async (parts, options) => {
|
|
@@ -16707,8 +16783,11 @@ var upgrade = async (parts, options) => {
|
|
|
16707
16783
|
}
|
|
16708
16784
|
if (wanted.has("renames")) {
|
|
16709
16785
|
const found = [];
|
|
16786
|
+
const changes = [];
|
|
16787
|
+
const before = record === void 0 || isBelow(record.cli, OPTIONAL_FIELDS_SINCE);
|
|
16710
16788
|
for (const file of await sourceFiles(root)) {
|
|
16711
16789
|
const text = await readText$1(path.join(root, file));
|
|
16790
|
+
if (before && text !== void 0) changes.push(...optionalFieldsIn(file, text));
|
|
16712
16791
|
const inFile = text === void 0 ? [] : renamesIn(file, text);
|
|
16713
16792
|
if (write && text !== void 0 && inFile.length > 0) {
|
|
16714
16793
|
const renamed = [...new Set(inFile.map((entry) => entry.name))].reduce((result, name) => result.replace(wordOf(name), RENAMES.find((rename) => rename.name === name)?.to ?? name), text);
|
|
@@ -16717,6 +16796,7 @@ var upgrade = async (parts, options) => {
|
|
|
16717
16796
|
found.push(...inFile);
|
|
16718
16797
|
}
|
|
16719
16798
|
report.renames = found;
|
|
16799
|
+
report.changes = changes;
|
|
16720
16800
|
}
|
|
16721
16801
|
console.log(options.json ? JSON.stringify(report) : reportText$3(report, installCommand(manager)));
|
|
16722
16802
|
if (report.packages?.install === "failed") {
|
|
@@ -18389,15 +18469,32 @@ var checkAccount = async (root, username) => {
|
|
|
18389
18469
|
password
|
|
18390
18470
|
};
|
|
18391
18471
|
};
|
|
18472
|
+
/** Signs the page's browser in as the account, through the server's `/auth` routes: what went wrong, or nothing. */
|
|
18473
|
+
var signInAs = async (page, origin, account) => {
|
|
18474
|
+
const answer = await page.request.post(`${origin}${SIGN_IN_PATH}`, { data: {
|
|
18475
|
+
username: account.username,
|
|
18476
|
+
password: account.password
|
|
18477
|
+
} });
|
|
18478
|
+
if (answer.ok()) return;
|
|
18479
|
+
return answer.status() === 404 ? `nothing answers at ${SIGN_IN_PATH}: --as signs in through the routes createServer({ auth }) mounts there` : `${account.username} was not signed in (${String(answer.status())}): ${(await answer.text()).slice(0, 200)} — check ${CHECK_PASSWORD_ENV} in .env`;
|
|
18480
|
+
};
|
|
18481
|
+
var withoutTrailingSlash = (path) => path.length > 1 ? path.replace(/\/+$/, "") : path;
|
|
18482
|
+
/** Where the page landed, when that is not the path it was opened at — sent to the sign-in, most often. */
|
|
18483
|
+
var sentElsewhere = (page, pathname) => {
|
|
18484
|
+
const landed = new URL(page.url()).pathname;
|
|
18485
|
+
const asked = new URL(pathname, page.url()).pathname;
|
|
18486
|
+
return withoutTrailingSlash(landed) === withoutTrailingSlash(asked) ? void 0 : landed;
|
|
18487
|
+
};
|
|
18392
18488
|
/** The space the project declares, authored. Only for one written here. */
|
|
18393
18489
|
var projectSpace = async (root) => {
|
|
18394
18490
|
const project = await loadProjectSpace(root);
|
|
18395
18491
|
if ("problem" in project) return { problem: `${project.problem} There is nothing to check the page against.` };
|
|
18396
18492
|
try {
|
|
18397
|
-
const { handles, schema } = authorSpace(project.space, project.authoring);
|
|
18493
|
+
const { handles, schema, style } = authorSpace(project.space, project.authoring);
|
|
18398
18494
|
return {
|
|
18399
18495
|
handles,
|
|
18400
|
-
schema
|
|
18496
|
+
schema,
|
|
18497
|
+
schemes: SCHEMES.filter((scheme) => style.theme.schemes.includes(scheme))
|
|
18401
18498
|
};
|
|
18402
18499
|
} catch (error) {
|
|
18403
18500
|
return { problem: `The space does not author — npm run author says why: ${error instanceof Error ? error.message.split("\n")[0] : String(error)}` };
|
|
@@ -18813,17 +18910,12 @@ var checkAt = async (browser, origin, pathname, width, scheme, authored, asked,
|
|
|
18813
18910
|
devTools: false,
|
|
18814
18911
|
lists: {}
|
|
18815
18912
|
});
|
|
18816
|
-
|
|
18817
|
-
|
|
18818
|
-
|
|
18819
|
-
|
|
18820
|
-
|
|
18821
|
-
|
|
18822
|
-
code: "not-signed-in",
|
|
18823
|
-
message: signedIn.status() === 404 ? `nothing answers at ${SIGN_IN_PATH}: --as signs in through the routes createServer({ auth }) mounts there` : `${account.username} was not signed in (${String(signedIn.status())}): ${(await signedIn.text()).slice(0, 200)} — check ${CHECK_PASSWORD_ENV} in .env`,
|
|
18824
|
-
width
|
|
18825
|
-
});
|
|
18826
|
-
}
|
|
18913
|
+
const notSignedIn = account && await signInAs(page, origin, account);
|
|
18914
|
+
if (notSignedIn) return unchecked({
|
|
18915
|
+
code: "not-signed-in",
|
|
18916
|
+
message: notSignedIn,
|
|
18917
|
+
width
|
|
18918
|
+
});
|
|
18827
18919
|
const consoleErrors = [];
|
|
18828
18920
|
const failedRequests = [];
|
|
18829
18921
|
page.on("pageerror", (error) => consoleErrors.push(error.message));
|
|
@@ -18857,8 +18949,8 @@ var checkAt = async (browser, origin, pathname, width, scheme, authored, asked,
|
|
|
18857
18949
|
consoleErrors,
|
|
18858
18950
|
failedRequests
|
|
18859
18951
|
};
|
|
18860
|
-
const landed =
|
|
18861
|
-
if (
|
|
18952
|
+
const landed = sentElsewhere(page, pathname);
|
|
18953
|
+
if (landed) return {
|
|
18862
18954
|
...unchecked({
|
|
18863
18955
|
code: "redirected",
|
|
18864
18956
|
message: account ? `${pathname} sent the browser to ${landed}, signed in as ${account.username}: that account may not see it` : `${pathname} sent the browser to ${landed} — what a page for signed-in visitors does: \`plitzi page check ${pathname} --as <username>\` signs in first, the password in ${CHECK_PASSWORD_ENV} in .env`,
|
|
@@ -18986,7 +19078,7 @@ var clickedText = (clicked) => {
|
|
|
18986
19078
|
];
|
|
18987
19079
|
};
|
|
18988
19080
|
var reportText$2 = (report, asked) => {
|
|
18989
|
-
const head = `${report.path} at ${String(report.width)} px`;
|
|
19081
|
+
const head = `${report.path} at ${String(report.width)} px${report.scheme ? `, ${report.scheme}` : ""}`;
|
|
18990
19082
|
const held = [
|
|
18991
19083
|
...report.notFound ? [" · sent with status 404: the page for an address that shows nothing"] : [],
|
|
18992
19084
|
...listsText(report.lists),
|
|
@@ -19008,7 +19100,6 @@ var reportText$2 = (report, asked) => {
|
|
|
19008
19100
|
...held
|
|
19009
19101
|
].join("\n");
|
|
19010
19102
|
};
|
|
19011
|
-
var withoutTrailingSlash = (path) => path.length > 1 ? path.replace(/\/+$/, "") : path;
|
|
19012
19103
|
var check = async (routes, options) => {
|
|
19013
19104
|
const project = await projectHere("whose page to check");
|
|
19014
19105
|
if (!project) return;
|
|
@@ -19062,17 +19153,26 @@ var checkRoutes = async (project, routes, options) => {
|
|
|
19062
19153
|
if ("problem" in browser) return browser;
|
|
19063
19154
|
try {
|
|
19064
19155
|
const reports = [];
|
|
19065
|
-
for (const route of routes) for (const width of options.widths)
|
|
19156
|
+
for (const route of routes) for (const width of options.widths) {
|
|
19157
|
+
const report = await checkAt(browser, where.origin, route, width, options.scheme, authored, options.asked, options.ssr, options.account, options.click);
|
|
19158
|
+
reports.push({
|
|
19159
|
+
...report,
|
|
19160
|
+
...options.scheme ? { scheme: options.scheme } : {}
|
|
19161
|
+
});
|
|
19162
|
+
}
|
|
19066
19163
|
return reports;
|
|
19067
19164
|
} finally {
|
|
19068
19165
|
await browser.close();
|
|
19069
19166
|
}
|
|
19070
19167
|
};
|
|
19071
|
-
/**
|
|
19168
|
+
/** What a whole-project check opens: every page with no parameter in its path, in every theme the space can show. */
|
|
19072
19169
|
var staticPaths = async (root) => {
|
|
19073
19170
|
const authored = await projectSpace(root);
|
|
19074
19171
|
if ("problem" in authored) return authored;
|
|
19075
|
-
return
|
|
19172
|
+
return {
|
|
19173
|
+
paths: Object.values(authored.handles.pages).map((page) => isNotFoundPage(page) ? `${page.path.slice(0, -1)}${NOT_FOUND_PROBE}` : page.path).filter((pathname) => pathname.split("/").every((segment) => !segment.startsWith(":") && !/\{\{.*\}\}/.test(segment))),
|
|
19174
|
+
schemes: authored.schemes
|
|
19175
|
+
};
|
|
19076
19176
|
};
|
|
19077
19177
|
//#endregion
|
|
19078
19178
|
//#region src/commands/functions.ts
|
|
@@ -21186,12 +21286,12 @@ var measure = async (browser, url, width, scheme, read = []) => {
|
|
|
21186
21286
|
screen: await page.screenshot({ fullPage: true })
|
|
21187
21287
|
};
|
|
21188
21288
|
};
|
|
21189
|
-
var count$
|
|
21289
|
+
var count$3 = (amount, one, many = `${one}s`) => `${String(amount)} ${amount === 1 ? one : many}`;
|
|
21190
21290
|
var summaryText = (summary, out, stale) => [
|
|
21191
21291
|
chalk.green(`Imported ${summary.url} into ${out}`),
|
|
21192
|
-
` tokens ${count$
|
|
21193
|
-
` outline ${count$
|
|
21194
|
-
...summary.lists.length > 0 ? [` lists ${summary.lists.map((list) => `${list.file} (${count$
|
|
21292
|
+
` tokens ${count$3(summary.colours, "colour")} (${summary.dark ? "light and dark" : "no dark scheme: dark repeats light"}), ${count$3(summary.shadows, "shadow")}, ${count$3(summary.radii, "radius", "radii")}${summary.fonts.length > 0 ? `, fonts ${summary.fonts.join(", ")}` : ""}`,
|
|
21293
|
+
` outline ${count$3(summary.blocks, "block")} at ${summary.widths.join(", ")} px`,
|
|
21294
|
+
...summary.lists.length > 0 ? [` lists ${summary.lists.map((list) => `${list.file} (${count$3(list.rows, "row")})`).join(", ")}`] : [],
|
|
21195
21295
|
` pictures ${String(summary.pictures)} in assets.json`,
|
|
21196
21296
|
...stale.length > 0 ? [chalk.yellow(` earlier ${stale.join(", ")} ${stale.length === 1 ? "was" : "were"} there before and not written this time: delete what is stale`)] : [],
|
|
21197
21297
|
` next ${path.join(out, "IMPORT.md")} says what was not carried over`
|
|
@@ -22409,7 +22509,7 @@ var projectConnectors = async (root) => {
|
|
|
22409
22509
|
manifest: value.manifest
|
|
22410
22510
|
}] : []);
|
|
22411
22511
|
};
|
|
22412
|
-
var count$
|
|
22512
|
+
var count$2 = (entries, noun) => entries ? `${String(entries.length)} ${noun}${entries.length === 1 ? "" : "s"}` : `the space’s ${noun}s as they are`;
|
|
22413
22513
|
/**
|
|
22414
22514
|
* What of the space would not reach Plitzi with it, said before it is sent — never left to be found on a page that
|
|
22415
22515
|
* renders empty there:
|
|
@@ -22494,7 +22594,7 @@ var pushSpaceOf = async (root, connection, space, { base, force, downloads }) =>
|
|
|
22494
22594
|
outcome: "unchanged",
|
|
22495
22595
|
draft: data.draft
|
|
22496
22596
|
};
|
|
22497
|
-
console.log(chalk.green(`The space is ${space.name}’s draft now — its pages and styles, ${count$
|
|
22597
|
+
console.log(chalk.green(`The space is ${space.name}’s draft now — its pages and styles, ${count$2(sent.actions, "action")}, ${count$2(sent.connectors, "connector")}.`) + chalk.dim(" Any builder open on it shows it now."));
|
|
22498
22598
|
return {
|
|
22499
22599
|
outcome: "pushed",
|
|
22500
22600
|
draft: data.draft
|
|
@@ -23522,7 +23622,107 @@ var _ = `[data-motion-enter], [data-motion-stagger] > *, [data-motion-loop] { an
|
|
|
23522
23622
|
"[data-motion-on=\"scroll\"][data-motion-enter], [data-motion-on=\"scroll\"][data-motion-stagger] > * { animation-timeline: auto, auto !important; }"
|
|
23523
23623
|
].join("\n");
|
|
23524
23624
|
//#endregion
|
|
23625
|
+
//#region src/commands/shotSteps.ts
|
|
23626
|
+
var STEP_NAMES = [
|
|
23627
|
+
"click",
|
|
23628
|
+
"type",
|
|
23629
|
+
"press",
|
|
23630
|
+
"wait",
|
|
23631
|
+
"wait-for",
|
|
23632
|
+
"shot",
|
|
23633
|
+
"frames"
|
|
23634
|
+
];
|
|
23635
|
+
/** The longest a script may wait in one step: a page that needs more is waiting for something else. */
|
|
23636
|
+
var MAX_WAIT_MS = 3e4;
|
|
23637
|
+
var unquoted = (text) => text.replace(/^(["'])(.*)\1$/s, "$2");
|
|
23638
|
+
var count$1 = (value, at, max) => {
|
|
23639
|
+
const parsed = Number(value);
|
|
23640
|
+
return Number.isInteger(parsed) && parsed > 0 && parsed <= max ? parsed : { problem: `${at}: "${value ?? ""}" is not a whole number from 1 to ${String(max)}` };
|
|
23641
|
+
};
|
|
23642
|
+
/** A script, read into its steps — or what is wrong with it, said by its step. */
|
|
23643
|
+
var parseSteps = (script, every) => {
|
|
23644
|
+
const lines = script.split(/[;\n]/).map((line) => line.trim()).filter((line) => line !== "" && !line.startsWith("#"));
|
|
23645
|
+
if (lines.length === 0) return { problem: "--steps has no step: click, type, press, wait, wait-for, shot or frames, separated by \";\"" };
|
|
23646
|
+
const steps = [];
|
|
23647
|
+
for (const [index, line] of lines.entries()) {
|
|
23648
|
+
const at = `step ${String(index + 1)} ("${line}")`;
|
|
23649
|
+
const [name, ...rest] = line.split(/\s+/);
|
|
23650
|
+
const argument = unquoted(rest.join(" "));
|
|
23651
|
+
switch (name) {
|
|
23652
|
+
case "click":
|
|
23653
|
+
case "wait-for":
|
|
23654
|
+
if (!argument) return { problem: `${at}: ${name} needs an element — its name or a CSS selector` };
|
|
23655
|
+
steps.push({
|
|
23656
|
+
kind: name,
|
|
23657
|
+
target: argument
|
|
23658
|
+
});
|
|
23659
|
+
break;
|
|
23660
|
+
case "type": {
|
|
23661
|
+
const [target, ...words] = rest;
|
|
23662
|
+
if (!target || words.length === 0) return { problem: `${at}: type needs an element and the text — type <element> <text>` };
|
|
23663
|
+
steps.push({
|
|
23664
|
+
kind: "type",
|
|
23665
|
+
target,
|
|
23666
|
+
text: unquoted(words.join(" "))
|
|
23667
|
+
});
|
|
23668
|
+
break;
|
|
23669
|
+
}
|
|
23670
|
+
case "press":
|
|
23671
|
+
if (!argument) return { problem: `${at}: press needs a key — Enter, Escape, ArrowDown…` };
|
|
23672
|
+
steps.push({
|
|
23673
|
+
kind: "press",
|
|
23674
|
+
key: argument
|
|
23675
|
+
});
|
|
23676
|
+
break;
|
|
23677
|
+
case "wait": {
|
|
23678
|
+
const ms = count$1(rest[0], at, MAX_WAIT_MS);
|
|
23679
|
+
if (typeof ms !== "number") return ms;
|
|
23680
|
+
steps.push({
|
|
23681
|
+
kind: "wait",
|
|
23682
|
+
ms
|
|
23683
|
+
});
|
|
23684
|
+
break;
|
|
23685
|
+
}
|
|
23686
|
+
case "shot":
|
|
23687
|
+
steps.push({
|
|
23688
|
+
kind: "shot",
|
|
23689
|
+
...argument ? { label: argument } : {}
|
|
23690
|
+
});
|
|
23691
|
+
break;
|
|
23692
|
+
case "frames": {
|
|
23693
|
+
const frames = count$1(rest[0], at, 60);
|
|
23694
|
+
if (typeof frames !== "number") return frames;
|
|
23695
|
+
const apart = rest.length < 2 ? every : count$1(rest[1], at, MAX_WAIT_MS);
|
|
23696
|
+
if (typeof apart !== "number") return apart;
|
|
23697
|
+
steps.push({
|
|
23698
|
+
kind: "frames",
|
|
23699
|
+
count: frames,
|
|
23700
|
+
every: apart
|
|
23701
|
+
});
|
|
23702
|
+
break;
|
|
23703
|
+
}
|
|
23704
|
+
default: return { problem: `${at}: "${name}" is not a step — the steps are ${STEP_NAMES.join(", ")}` };
|
|
23705
|
+
}
|
|
23706
|
+
}
|
|
23707
|
+
return steps;
|
|
23708
|
+
};
|
|
23709
|
+
//#endregion
|
|
23525
23710
|
//#region src/commands/shot.ts
|
|
23711
|
+
/**
|
|
23712
|
+
* `plitzi page shot`: a picture of one page of the project — and, asked, the numbers that say what a picture would.
|
|
23713
|
+
*
|
|
23714
|
+
* plitzi page shot /about --width 390 --scheme dark
|
|
23715
|
+
* plitzi page shot / --compare https://example.com --width 1440 # beside another site: what differs, and how
|
|
23716
|
+
* plitzi page shot / --frames 4 --every 500 # what moves: a marquee, an autoplay
|
|
23717
|
+
* plitzi page shot / --clip pricing-table # one element, scrolled to wherever it is
|
|
23718
|
+
* plitzi page shot / --scroll-to faq --viewport --frames 6 # the screen at that section, as it animates
|
|
23719
|
+
*
|
|
23720
|
+
* The project's server has to be running (`npm start`). `--json` answers in one object, for a tool or an agent. The
|
|
23721
|
+
* dev tools' badge is never in the picture; a picture of the whole page has every lazy image loaded and shows every
|
|
23722
|
+
* arrival that waits for the scroll as it ends — taken without scrolling, they would be holes where the sections are.
|
|
23723
|
+
*/
|
|
23724
|
+
/** When a run's first picture is taken: once the page settles, or as soon as its HTML is in. */
|
|
23725
|
+
var SHOT_MOMENTS = ["settled", "load"];
|
|
23526
23726
|
/** A region moves when more than this share of it changed between two frames: below is anti-aliasing and carets. */
|
|
23527
23727
|
var MOVING_PERCENT = .5;
|
|
23528
23728
|
/** How long a whole page waits for its pictures before it is taken anyway. */
|
|
@@ -23533,8 +23733,8 @@ var TEXTS_SHOWN = 12;
|
|
|
23533
23733
|
var DRIFT_PX = 2;
|
|
23534
23734
|
/** An arrival that waits for the scroll and has not had it: one waiting to be seen, or one tied to the scroll. */
|
|
23535
23735
|
var WAITING_FOR_SCROLL = "[data-motion-on=\"view\"]:not([data-motion-seen]), [data-motion-on=\"scroll\"]";
|
|
23536
|
-
/** A selector, or
|
|
23537
|
-
var selectorOf = (target) => /^[#.[]/.test(target) ? target : `[data-plitzi-el="${target}"]`;
|
|
23736
|
+
/** A selector — CSS, or Playwright's own (`text=Saved`, `role=button[name="Publish"]`) — or an element's name. */
|
|
23737
|
+
var selectorOf = (target) => /^([#.[]|(text|role|css|xpath)=)/.test(target) ? target : `[data-plitzi-el="${target}"]`;
|
|
23538
23738
|
var framing = (view) => {
|
|
23539
23739
|
if (view.clip) return {
|
|
23540
23740
|
kind: "element",
|
|
@@ -23559,7 +23759,10 @@ var pictureOf = async (browser, url, view, origin) => {
|
|
|
23559
23759
|
colorScheme: view.scheme ?? "light",
|
|
23560
23760
|
reducedMotion: view.reducedMotion ? "reduce" : "no-preference"
|
|
23561
23761
|
});
|
|
23562
|
-
|
|
23762
|
+
const notSignedIn = origin && view.account && await signInAs(page, origin, view.account);
|
|
23763
|
+
if (notSignedIn) return { problem: `--as ${notSignedIn}.` };
|
|
23764
|
+
if (!(view.fromLoad ? await page.goto(url, { waitUntil: "domcontentloaded" }).catch(() => null) : await openPage(page, url))) return { problem: `Nothing answers at ${url}.${origin ? " Start the project first: npm start" : ""}` };
|
|
23765
|
+
const sentTo = origin ? sentElsewhere(page, new URL(url).pathname) : void 0;
|
|
23563
23766
|
if (view.waitFor) {
|
|
23564
23767
|
if (!await page.waitForSelector(selectorOf(view.waitFor), { timeout: 1e4 }).catch(() => null)) return { problem: `${view.waitFor} did not appear on ${url} within 10 s.` };
|
|
23565
23768
|
}
|
|
@@ -23576,7 +23779,8 @@ var pictureOf = async (browser, url, view, origin) => {
|
|
|
23576
23779
|
png: await capture(page, framing(view)),
|
|
23577
23780
|
scheme: await paintedScheme(page, view.scheme ?? "light"),
|
|
23578
23781
|
settled,
|
|
23579
|
-
unloaded: pictures?.missing ?? 0
|
|
23782
|
+
unloaded: pictures?.missing ?? 0,
|
|
23783
|
+
...sentTo ? { sentTo } : {}
|
|
23580
23784
|
};
|
|
23581
23785
|
};
|
|
23582
23786
|
var shiftText = (shift) => shift !== void 0 && Math.abs(shift) > DRIFT_PX ? ` (${shift > 0 ? "+" : ""}${String(shift)}px there)` : "";
|
|
@@ -23716,6 +23920,65 @@ var clickThrough = async (taken, how, clicks, { frames, every }) => {
|
|
|
23716
23920
|
clicked
|
|
23717
23921
|
};
|
|
23718
23922
|
};
|
|
23923
|
+
/** What a step is, as its label says it. */
|
|
23924
|
+
var stepText = (step) => {
|
|
23925
|
+
switch (step.kind) {
|
|
23926
|
+
case "click":
|
|
23927
|
+
case "wait-for": return `${step.kind} ${step.target}`;
|
|
23928
|
+
case "type": return `type ${step.target}`;
|
|
23929
|
+
case "press": return `press ${step.key}`;
|
|
23930
|
+
case "wait": return `wait ${String(step.ms)} ms`;
|
|
23931
|
+
case "shot": return step.label ?? "shot";
|
|
23932
|
+
case "frames": return `frames ${String(step.count)}`;
|
|
23933
|
+
}
|
|
23934
|
+
};
|
|
23935
|
+
/**
|
|
23936
|
+
* A `--steps` script played on the page: what each step does, and every picture the script asks for — each labelled with
|
|
23937
|
+
* its step and the time since the first, and measured against the one before it, so "nothing changed" is said.
|
|
23938
|
+
*/
|
|
23939
|
+
var playSteps = async (taken, how, steps) => {
|
|
23940
|
+
const { page } = taken;
|
|
23941
|
+
const started = Date.now();
|
|
23942
|
+
const moments = [{
|
|
23943
|
+
label: "before",
|
|
23944
|
+
png: taken.png
|
|
23945
|
+
}];
|
|
23946
|
+
const changes = [];
|
|
23947
|
+
const picture = async (label) => {
|
|
23948
|
+
const before = moments[moments.length - 1].png;
|
|
23949
|
+
const png = await capture(page, how);
|
|
23950
|
+
const at = `${label} · +${String(Date.now() - started)} ms`;
|
|
23951
|
+
moments.push({
|
|
23952
|
+
label: at,
|
|
23953
|
+
png
|
|
23954
|
+
});
|
|
23955
|
+
changes.push({
|
|
23956
|
+
label: at,
|
|
23957
|
+
changed: (await comparePictures(page, dataUrl(before), dataUrl(png))).changed
|
|
23958
|
+
});
|
|
23959
|
+
};
|
|
23960
|
+
for (const [index, step] of steps.entries()) try {
|
|
23961
|
+
if (step.kind === "click" || step.kind === "type") {
|
|
23962
|
+
const element = page.locator(selectorOf(step.target)).first();
|
|
23963
|
+
if (await element.count() === 0) return { problem: `Step ${String(index + 1)}: ${step.target} is not on the page — its name or a CSS selector.` };
|
|
23964
|
+
await element.click({ timeout: 3e3 });
|
|
23965
|
+
if (step.kind === "type") await page.keyboard.type(step.text);
|
|
23966
|
+
} else if (step.kind === "press") await page.keyboard.press(step.key);
|
|
23967
|
+
else if (step.kind === "wait") await page.waitForTimeout(step.ms);
|
|
23968
|
+
else if (step.kind === "wait-for") await page.waitForSelector(selectorOf(step.target), { timeout: 1e4 });
|
|
23969
|
+
else if (step.kind === "shot") await picture(step.label ?? `step ${String(index + 1)}`);
|
|
23970
|
+
else for (let frame = 1; frame <= step.count; frame += 1) {
|
|
23971
|
+
if (frame > 1) await page.waitForTimeout(step.every);
|
|
23972
|
+
await picture(`frame ${String(frame)}/${String(step.count)}`);
|
|
23973
|
+
}
|
|
23974
|
+
} catch (error) {
|
|
23975
|
+
return { problem: `Step ${String(index + 1)} (${stepText(step)}) did not happen: ${error instanceof Error ? error.message.split("\n")[0] : String(error)}` };
|
|
23976
|
+
}
|
|
23977
|
+
return {
|
|
23978
|
+
moments,
|
|
23979
|
+
changes
|
|
23980
|
+
};
|
|
23981
|
+
};
|
|
23719
23982
|
var shot = async (route, options) => {
|
|
23720
23983
|
const project = await projectHere("whose page to picture");
|
|
23721
23984
|
if (!project) return;
|
|
@@ -23724,20 +23987,53 @@ var shot = async (route, options) => {
|
|
|
23724
23987
|
fail(where.problem);
|
|
23725
23988
|
return;
|
|
23726
23989
|
}
|
|
23990
|
+
const account = options.as === void 0 ? void 0 : await checkAccount(project.root, options.as);
|
|
23991
|
+
if (account && "problem" in account) {
|
|
23992
|
+
fail(`--as ${account.problem}.`);
|
|
23993
|
+
return;
|
|
23994
|
+
}
|
|
23727
23995
|
const browser = await launchBrowser(project.root);
|
|
23728
23996
|
if ("problem" in browser) {
|
|
23729
23997
|
fail(browser.problem);
|
|
23730
23998
|
return;
|
|
23731
23999
|
}
|
|
23732
24000
|
const clicks = options.click ?? [];
|
|
24001
|
+
const script = options.steps?.startsWith("@") ? await readFile(path.resolve(options.steps.slice(1)), "utf-8").catch(() => void 0) : options.steps;
|
|
24002
|
+
if (options.steps !== void 0 && script === void 0) {
|
|
24003
|
+
await browser.close();
|
|
24004
|
+
fail(`${options.steps.slice(1)} cannot be read: --steps @<file> names a file of steps.`);
|
|
24005
|
+
return;
|
|
24006
|
+
}
|
|
24007
|
+
const steps = script === void 0 ? void 0 : parseSteps(script, options.every ?? 500);
|
|
24008
|
+
if (steps && "problem" in steps) {
|
|
24009
|
+
await browser.close();
|
|
24010
|
+
fail(`--steps: ${steps.problem}.`);
|
|
24011
|
+
return;
|
|
24012
|
+
}
|
|
24013
|
+
if (steps && (clicks.length > 0 || options.compare || (options.frames ?? 0) > 1)) {
|
|
24014
|
+
await browser.close();
|
|
24015
|
+
fail("`--steps` is the whole interaction — its own clicks and frames: leave out --click, --frames and --compare.");
|
|
24016
|
+
return;
|
|
24017
|
+
}
|
|
23733
24018
|
if (options.compare && clicks.length > 0) {
|
|
23734
24019
|
await browser.close();
|
|
23735
24020
|
fail("`--compare` sets the page beside another site as it loads: leave out --click, or picture the click on its own.");
|
|
23736
24021
|
return;
|
|
23737
24022
|
}
|
|
23738
|
-
if (options.sheet && clicks.length === 0 && (options.frames ?? 0) <= 1) {
|
|
24023
|
+
if (options.sheet && clicks.length === 0 && (options.frames ?? 0) <= 1 && options.steps === void 0) {
|
|
24024
|
+
await browser.close();
|
|
24025
|
+
fail("`--sheet` lays out the pictures a --click, --frames or --steps takes: with none of them, there is one picture and no sheet.");
|
|
24026
|
+
return;
|
|
24027
|
+
}
|
|
24028
|
+
const fromLoad = options.from === "load";
|
|
24029
|
+
if (fromLoad && ((options.frames ?? 0) <= 1 || clicks.length > 0 || options.compare)) {
|
|
24030
|
+
await browser.close();
|
|
24031
|
+
fail("`--from load` starts --frames as the HTML arrives, for what plays while the page loads: give it --frames, and leave out --click and --compare.");
|
|
24032
|
+
return;
|
|
24033
|
+
}
|
|
24034
|
+
if (fromLoad && !options.clip && !options.scrollTo && !options.viewport) {
|
|
23739
24035
|
await browser.close();
|
|
23740
|
-
fail("`--
|
|
24036
|
+
fail("`--from load` pictures the screen as the page arrives, never the whole page — unrolling it waits for it to settle: add --viewport or --clip.");
|
|
23741
24037
|
return;
|
|
23742
24038
|
}
|
|
23743
24039
|
if (options.compare && (options.clip || options.scrollTo || options.viewport)) {
|
|
@@ -23756,12 +24052,14 @@ var shot = async (route, options) => {
|
|
|
23756
24052
|
...options.clip ? { clip: options.clip } : {},
|
|
23757
24053
|
...options.scrollTo ? { scrollTo: options.scrollTo } : {},
|
|
23758
24054
|
...options.viewport ? { viewport: true } : {},
|
|
24055
|
+
...account ? { account } : {},
|
|
24056
|
+
...fromLoad ? { fromLoad } : {},
|
|
23759
24057
|
still: !options.clip && !options.scrollTo && !options.viewport && (options.frames ?? 0) <= 1 && clicks.length === 0
|
|
23760
24058
|
};
|
|
23761
24059
|
const how = framing(view);
|
|
23762
24060
|
const taken = await pictureOf(browser, `${where.origin}${pathname}`, view, where.origin);
|
|
23763
24061
|
if ("problem" in taken) {
|
|
23764
|
-
fail(
|
|
24062
|
+
fail(taken.problem);
|
|
23765
24063
|
return;
|
|
23766
24064
|
}
|
|
23767
24065
|
const name = pathname === "/" ? "home" : pathname.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "");
|
|
@@ -23776,7 +24074,8 @@ var shot = async (route, options) => {
|
|
|
23776
24074
|
scheme: taken.scheme,
|
|
23777
24075
|
out,
|
|
23778
24076
|
...taken.settled > 0 ? { settled: taken.settled } : {},
|
|
23779
|
-
...taken.unloaded > 0 ? { unloaded: taken.unloaded } : {}
|
|
24077
|
+
...taken.unloaded > 0 ? { unloaded: taken.unloaded } : {},
|
|
24078
|
+
...taken.sentTo ? { sentTo: taken.sentTo } : {}
|
|
23780
24079
|
};
|
|
23781
24080
|
if (options.compare) {
|
|
23782
24081
|
const other = new URL(options.compare);
|
|
@@ -23790,7 +24089,15 @@ var shot = async (route, options) => {
|
|
|
23790
24089
|
const frames = options.frames ?? 0;
|
|
23791
24090
|
const every = options.every ?? 500;
|
|
23792
24091
|
let moments = [];
|
|
23793
|
-
if (
|
|
24092
|
+
if (steps) {
|
|
24093
|
+
const played = await playSteps(taken, how, steps);
|
|
24094
|
+
if ("problem" in played) {
|
|
24095
|
+
fail(played.problem);
|
|
24096
|
+
return;
|
|
24097
|
+
}
|
|
24098
|
+
moments = played.moments;
|
|
24099
|
+
report.steps = played.changes;
|
|
24100
|
+
} else if (clicks.length > 0) {
|
|
23794
24101
|
const played = await clickThrough(taken, how, clicks, {
|
|
23795
24102
|
frames,
|
|
23796
24103
|
every
|
|
@@ -23808,7 +24115,7 @@ var shot = async (route, options) => {
|
|
|
23808
24115
|
pictures.push(await capture(taken.page, how));
|
|
23809
24116
|
}
|
|
23810
24117
|
moments = pictures.map((png, frame) => ({
|
|
23811
|
-
label: frame === 0 ? "before" : `+${String(frame * every)} ms`,
|
|
24118
|
+
label: frame === 0 ? fromLoad ? "HTML in" : "before" : `+${String(frame * every)} ms`,
|
|
23812
24119
|
png
|
|
23813
24120
|
}));
|
|
23814
24121
|
const diffs = [];
|
|
@@ -23832,7 +24139,7 @@ var shot = async (route, options) => {
|
|
|
23832
24139
|
})));
|
|
23833
24140
|
report.sheet = `${base}-sheet.png`;
|
|
23834
24141
|
await writeFile(report.sheet, Buffer.from(sheet.replace(/^data:image\/png;base64,/, ""), "base64"));
|
|
23835
|
-
} else if (moments.length > 1 && clicks.length > 0) {
|
|
24142
|
+
} else if (moments.length > 1 && (clicks.length > 0 || steps)) {
|
|
23836
24143
|
report.pictures = [];
|
|
23837
24144
|
for (const [index, moment] of moments.slice(1).entries()) {
|
|
23838
24145
|
const file = `${base}-${String(index + 1)}.png`;
|
|
@@ -23848,9 +24155,11 @@ var shot = async (route, options) => {
|
|
|
23848
24155
|
return;
|
|
23849
24156
|
}
|
|
23850
24157
|
console.log(out);
|
|
24158
|
+
if (report.sentTo) console.log(chalk.yellow(account ? `${pathname} sent the browser to ${report.sentTo}, signed in as ${account.username}: the picture is of ${report.sentTo} — that account may not see ${pathname}` : `${pathname} sent the browser to ${report.sentTo}: the picture is of ${report.sentTo}. A page for signed-in visitors? \`--as <username>\` signs in first, the password in ${CHECK_PASSWORD_ENV} in .env`));
|
|
23851
24159
|
if (report.settled) console.log(chalk.dim(`${String(report.settled)} arrival${report.settled === 1 ? "" : "s"} waiting for the scroll shown as they end — --scroll-to <id> --viewport --frames 4 shows one arriving`));
|
|
23852
24160
|
if (report.unloaded) console.log(chalk.yellow(`${String(report.unloaded)} picture(s) had not loaded when the page was taken`));
|
|
23853
24161
|
if (report.compare) console.log(compareText(report.compare).join("\n"));
|
|
24162
|
+
for (const { label, changed } of report.steps ?? []) console.log(changed > 0 ? `${label}: ${String(changed)}% of the picture changed` : chalk.yellow(`${label}: nothing changed since the picture before`));
|
|
23854
24163
|
for (const { target, changed } of report.clicked ?? []) console.log(changed > 0 ? `clicked ${target}: ${String(changed)}% of the picture changed` : chalk.yellow(`clicked ${target}: nothing changed — the click did nothing to see`));
|
|
23855
24164
|
if (report.sheet) console.log(`sheet: ${report.sheet}`);
|
|
23856
24165
|
for (const picture of report.pictures ?? []) console.log(`${picture.label}: ${picture.out}`);
|
|
@@ -23961,30 +24270,39 @@ var verify = async (options) => {
|
|
|
23961
24270
|
};
|
|
23962
24271
|
var NOT_STARTED = "start it (npm start) and verify again, or --no-pages to leave them";
|
|
23963
24272
|
var pagesChecked = async (project) => {
|
|
23964
|
-
const
|
|
23965
|
-
if ("problem" in
|
|
23966
|
-
const
|
|
23967
|
-
|
|
23968
|
-
|
|
23969
|
-
|
|
24273
|
+
const found = await staticPaths(project.root);
|
|
24274
|
+
if ("problem" in found) return found;
|
|
24275
|
+
const { paths, schemes } = found;
|
|
24276
|
+
const inEveryTheme = async (routes, account) => {
|
|
24277
|
+
const all = [];
|
|
24278
|
+
for (const scheme of schemes) {
|
|
24279
|
+
const reports = await checkRoutes(project, routes, {
|
|
24280
|
+
widths: WIDTHS,
|
|
24281
|
+
asked: { state: false },
|
|
24282
|
+
ssr: false,
|
|
24283
|
+
scheme,
|
|
24284
|
+
...account ? { account } : {}
|
|
24285
|
+
});
|
|
24286
|
+
if ("problem" in reports) return { problem: `${reports.problem} — ${NOT_STARTED}` };
|
|
24287
|
+
all.push(...reports);
|
|
24288
|
+
}
|
|
24289
|
+
return all;
|
|
23970
24290
|
};
|
|
23971
|
-
const reports = await
|
|
23972
|
-
if ("problem" in reports) return
|
|
24291
|
+
const reports = await inEveryTheme(paths);
|
|
24292
|
+
if ("problem" in reports) return reports;
|
|
23973
24293
|
const sentAway = [...new Set(reports.filter(redirected).map((report) => report.path))];
|
|
23974
|
-
if (sentAway.length === 0) return summary(reports);
|
|
24294
|
+
if (sentAway.length === 0) return summary(schemes, reports);
|
|
23975
24295
|
const account = await checkAccount(project.root);
|
|
23976
|
-
if (!account || "problem" in account) return summary(reports, account ?? { none: true });
|
|
23977
|
-
const signedIn = await
|
|
23978
|
-
|
|
23979
|
-
|
|
23980
|
-
});
|
|
23981
|
-
if ("problem" in signedIn) return { problem: `${signedIn.problem} — ${NOT_STARTED}` };
|
|
23982
|
-
return summary([...reports.filter((report) => !sentAway.includes(report.path)), ...signedIn], {
|
|
24296
|
+
if (!account || "problem" in account) return summary(schemes, reports, account ?? { none: true });
|
|
24297
|
+
const signedIn = await inEveryTheme(sentAway, account);
|
|
24298
|
+
if ("problem" in signedIn) return signedIn;
|
|
24299
|
+
return summary(schemes, [...reports.filter((report) => !sentAway.includes(report.path)), ...signedIn], {
|
|
23983
24300
|
as: account.username,
|
|
23984
24301
|
checks: signedIn.filter((report) => !unchecked(report)).length
|
|
23985
24302
|
});
|
|
23986
24303
|
};
|
|
23987
|
-
var summary = (reports, signedIn) => ({
|
|
24304
|
+
var summary = (schemes, reports, signedIn) => ({
|
|
24305
|
+
schemes,
|
|
23988
24306
|
passing: reports.filter((report) => report.ok).length,
|
|
23989
24307
|
failing: reports.filter((report) => !report.ok && !unchecked(report)),
|
|
23990
24308
|
unchecked: [...new Set(reports.filter(unchecked).map((report) => report.path))],
|
|
@@ -24003,7 +24321,7 @@ var verifyText = (results, pages) => [...results.flatMap((result) => result.ok ?
|
|
|
24003
24321
|
...(result.said ?? []).map((line) => ` ${line}`),
|
|
24004
24322
|
...result.fix ? [` → ${result.fix}`] : []
|
|
24005
24323
|
]), ...pages === void 0 ? [chalk.yellow("- pages not checked: --no-pages")] : "waiting" in pages ? [chalk.yellow(`- not run until ${pages.after} passes: ${pages.waiting.join(", ")} (--keep-going runs them anyway)`)] : "problem" in pages ? [chalk.red(`✗ pages — ${pages.problem}`)] : [
|
|
24006
|
-
pages.failing.length === 0 ? chalk.green(`✓ pages — ${String(pages.passing)} checks at ${WIDTHS.join(" and ")} px${pages.signedIn && "as" in pages.signedIn ? `, ${String(pages.signedIn.checks)} of them signed in as ${pages.signedIn.as}` : ""}`) : chalk.red(`✗ pages — ${String(pages.failing.length)} of ${String(pages.passing + pages.failing.length)} checks`),
|
|
24324
|
+
pages.failing.length === 0 ? chalk.green(`✓ pages — ${String(pages.passing)} checks at ${WIDTHS.join(" and ")} px, ${pages.schemes.join(" and ")}${pages.signedIn && "as" in pages.signedIn ? `, ${String(pages.signedIn.checks)} of them signed in as ${pages.signedIn.as}` : ""}`) : chalk.red(`✗ pages — ${String(pages.failing.length)} of ${String(pages.passing + pages.failing.length)} checks`),
|
|
24007
24325
|
...pages.failing.map((report) => reportText$2(report, { state: false })),
|
|
24008
24326
|
...pages.unchecked.length > 0 ? [chalk.yellow(uncheckedText(pages))] : []
|
|
24009
24327
|
]].join("\n");
|
|
@@ -27192,7 +27510,7 @@ pageGroup.command("import").argument("<url>", "The page to start from: https://e
|
|
|
27192
27510
|
768,
|
|
27193
27511
|
390
|
|
27194
27512
|
])).option("-f, --force", "Write over what --out already holds").option("--account", "A site not served from this machine: ask your Plitzi account whether one of your spaces verified its domain (signs in)").option("--json", "One object, for a tool or an agent").option(...API_OPTION).option(...DRY_RUN_OPTION).action((url, options) => importPage(url, options));
|
|
27195
|
-
pageGroup.command("shot").argument("[path]", "The page: /about. The home page when left out").description("A picture of one page of the running project — and, asked, how it differs from another or what moves").addOption(new Option("--width <px>", "The viewport width").argParser(width).default(1280)).addOption(new Option("--height <px>", "The viewport height (the picture is the whole page unless --viewport, --scroll-to or --clip)").argParser(positiveInteger).default(800)).addOption(schemeOption()).option("-o, --out <file>", "Where the picture goes. tmp/shots/<page>-<width>-<scheme>.png by default").option("--compare <url>", "Another site: the same page there, side by side, and how much differs by section").addOption(new Option("--frames <n>", "Pictures taken one after another: which sections move (a marquee, an autoplay)").argParser(positiveInteger)).addOption(new Option("--every <ms>", "How far apart --frames are taken").argParser(positiveInteger).default(500)).option("--wait-for <element>", "An element to wait for first: its name (data-plitzi-el) or a CSS selector").option("--clip <element>", "Only this element — its name or a CSS selector — scrolled to wherever it is").option("--scroll-to <element>", "The page scrolled until this element is in view; the picture is the screen there").option("--viewport", "Only what fits the viewport, not the whole page").option("--click <element...>", "Click these in order once the page settles — each its name or a CSS selector, inside a plugin too — picturing what each changed (--frames pictures --every ms apart after each)").option("--sheet", "Every picture taken — before, after each click, each frame — on one contact sheet").option("--reduced-motion", "As a visitor who asked for less motion").option("--json", "One object, for a tool or an agent").action((path, options) => shot(path, options));
|
|
27513
|
+
pageGroup.command("shot").argument("[path]", "The page: /about. The home page when left out").description("A picture of one page of the running project — and, asked, how it differs from another or what moves").addOption(new Option("--width <px>", "The viewport width").argParser(width).default(1280)).addOption(new Option("--height <px>", "The viewport height (the picture is the whole page unless --viewport, --scroll-to or --clip)").argParser(positiveInteger).default(800)).addOption(schemeOption()).option("-o, --out <file>", "Where the picture goes. tmp/shots/<page>-<width>-<scheme>.png by default").option("--compare <url>", "Another site: the same page there, side by side, and how much differs by section").addOption(new Option("--frames <n>", "Pictures taken one after another: which sections move (a marquee, an autoplay)").argParser(positiveInteger)).addOption(new Option("--every <ms>", "How far apart --frames are taken").argParser(positiveInteger).default(500)).addOption(new Option("--from <moment>", "When --frames start: once the page settles, or as soon as its HTML is in (load) — what plays as it arrives").choices([...SHOT_MOMENTS]).default("settled")).option("--wait-for <element>", "An element to wait for first: its name (data-plitzi-el) or a CSS selector").option("--clip <element>", "Only this element — its name or a CSS selector — scrolled to wherever it is").option("--scroll-to <element>", "The page scrolled until this element is in view; the picture is the screen there").option("--viewport", "Only what fits the viewport, not the whole page").option("--click <element...>", "Click these in order once the page settles — each its name or a CSS selector, inside a plugin too — picturing what each changed (--frames pictures --every ms apart after each)").option("--sheet", "Every picture taken — before, after each click, each frame — on one contact sheet").option("--steps <script>", "An interaction, step by step: \"click <el>; type <el> <text>; press <key>; wait <ms>; wait-for <el>; shot [label]; frames <n> [ms]\" — or @file with one per line").option("--reduced-motion", "As a visitor who asked for less motion").option("--as <username>", "Sign in first as this account, through the server’s /auth routes — the password from PLITZI_CHECK_PASSWORD, in .env").option("--json", "One object, for a tool or an agent").action((path, options) => shot(path, options));
|
|
27196
27514
|
program.command("verify").description("Whether the project is left passing: author, lints, types, format and every page, only the problems said").option("--no-pages", "Leave the pages out — said as such").option("--keep-going", "Run every check even after one fails — by default the first failure ends the run").option("--json", "One object, for a tool or an agent").action((options) => verify(options));
|
|
27197
27515
|
elementGroup.command("where").argument("<query>", "An element’s id, a class it wears, or words it shows: hero-cta, navLink, \"Get started\"").description("Where the project’s code writes an element: the file, the line and the call itself").addOption(new Option("--by <reading>", "Read the query one way only, not the first of id, class and words that matches").choices(WHERE_READINGS)).option("--json", "One object, for a tool or an agent").action((query, options) => where(query, options));
|
|
27198
27516
|
elementGroup.command("edit").argument("<id>", "The element, by its id: hero-cta").description("Change an element’s attributes in the call that writes it, then check the space still authors").option("--set <key=value...>", "An attribute to write: content=\"Start free\", required=true").option("--remove <key...>", "An attribute to take out").option("--every", "The call writes other elements too, and the change is for every one").option("--json", "One object, for a tool or an agent").action((id, options) => edit(id, options));
|