@intentius/behold 0.29.7 → 0.29.8
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/README.md +7 -0
- package/dist/cli.js +1221 -765
- package/package.json +1 -1
- package/web/app.js +60 -4
- package/web/index.html +2 -0
- package/web/kiosk-annotations.js +528 -0
- package/web/kiosk-annotations.test.js +83 -0
- package/web/kiosk-approval.js +241 -0
- package/web/kiosk-approval.test.js +122 -0
- package/web/kiosk-popover.js +1 -0
- package/web/kiosk-repo.js +25 -0
- package/web/kiosk-repo.test.js +43 -0
- package/web/kiosk-roots.js +15 -7
- package/web/kiosk-runs.js +341 -25
- package/web/kiosk-runs.test.js +77 -1
- package/web/kiosk-vendor.js +380 -0
- package/web/kiosk-vendor.test.js +265 -0
- package/web/kiosk.html +157 -17
- package/web/kiosk.js +449 -47
- package/web/kiosk.test.js +73 -8
- package/web/theme.js +112 -0
- package/web/theme.test.js +51 -1
- package/web/vendors/choudoufu-128.png +0 -0
- package/web/vendors/choudoufu-64.png +0 -0
- package/web/view-repo.js +44 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/behold",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.8",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "behold — a live control plane on chant. See your whole estate (every substrate in one graph), coloured by drift; act through delegated, gated Ops.",
|
package/web/app.js
CHANGED
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
// floating control panel's chrome (panel.js — drag/snap/collapse/tabs, persisted
|
|
9
9
|
// position), and the theme picker into the panel's View-tab slot (a stable element
|
|
10
10
|
// renderPanelView never rewrites, so the select mounts once and survives re-renders).
|
|
11
|
+
import "./view-repo.js"; // behold#571: first, so every read carries the page's ?repo=
|
|
11
12
|
import { createRefreshQueue } from "./refresh-queue.js";
|
|
12
13
|
import { readViewQuery, writeViewQuery, settleView, settlePlace, refusalLine } from "./view-url.js";
|
|
13
14
|
import { quietCardLines, readEmbed, selectMessage, viewFromMessage } from "./embed.js";
|
|
14
15
|
import { WORDS as POP_WORDS, cardRoot as popCardRoot, placePopover, popReduce, popState, resourcePopover, rootPopover } from "./kiosk-popover.js";
|
|
15
|
-
import { cssString, hoverCss, hoverFromMessage, hoverLinks, hoverMessage, isLightBg,
|
|
16
|
+
import { cssString, hoverCss, hoverFromMessage, hoverLinks, hoverMessage, isLightBg, rootPaint, rootText } from "./kiosk-roots.js";
|
|
16
17
|
import { gateCards } from "./workspace-gates.js";
|
|
17
18
|
import { cornerOf, estateLine, hrefOf as tgHref, legend as tgLegend, markLine, rootRows as tgRootRows, waveCards } from "./terragucci.js";
|
|
18
19
|
import { laneElement as tgLane, rootOfCard as tgRootOfCard, historyElement as tgHistoryLane } from "./terragucci-timeline.js";
|
|
@@ -4179,7 +4180,7 @@ function kioskDots(svg) {
|
|
|
4179
4180
|
if (!roots.length) return;
|
|
4180
4181
|
const light = kioskLight();
|
|
4181
4182
|
const dotBy = (text, root) => {
|
|
4182
|
-
const colour =
|
|
4183
|
+
const colour = rootPaint(root, roots, { light });
|
|
4183
4184
|
if (!colour) return;
|
|
4184
4185
|
let bb;
|
|
4185
4186
|
try {
|
|
@@ -4194,7 +4195,8 @@ function kioskDots(svg) {
|
|
|
4194
4195
|
c.setAttribute("cx", String(bb.x + bb.width + 9));
|
|
4195
4196
|
c.setAttribute("cy", String(bb.y + bb.height / 2));
|
|
4196
4197
|
c.setAttribute("r", "5.5");
|
|
4197
|
-
|
|
4198
|
+
// The theme's own root colour (--root-<i>): a style, since a fill attribute takes no var().
|
|
4199
|
+
c.style.fill = colour;
|
|
4198
4200
|
c.setAttribute("pointer-events", "none");
|
|
4199
4201
|
text.parentNode.insertBefore(c, text.nextSibling);
|
|
4200
4202
|
};
|
|
@@ -4292,7 +4294,9 @@ function kioskPopRender() {
|
|
|
4292
4294
|
}
|
|
4293
4295
|
if (content.more > 0) ul.appendChild(Object.assign(document.createElement("li"), { className: "k-pop-more", textContent: `and ${content.more} more` }));
|
|
4294
4296
|
}
|
|
4295
|
-
|
|
4297
|
+
// behold#571: a finger opens the popover with a tap, so a touch screen reads the tap's words.
|
|
4298
|
+
const touchOnly = typeof matchMedia === "function" && matchMedia("(hover: none)").matches;
|
|
4299
|
+
add("p", "k-pop-hint", kioskPop.pinned ? (touchOnly ? POP_WORDS.tapPinnedHint : POP_WORDS.pinnedHint) : POP_WORDS.pinHint);
|
|
4296
4300
|
pop.hidden = false;
|
|
4297
4301
|
const cb = card.getBoundingClientRect();
|
|
4298
4302
|
const pb = pop.getBoundingClientRect();
|
|
@@ -4339,6 +4343,8 @@ function wireKioskFrame() {
|
|
|
4339
4343
|
window.addEventListener("message", (e) => {
|
|
4340
4344
|
if (!embedOpts.host || e.origin !== embedOpts.host) return;
|
|
4341
4345
|
if (e.data && e.data.type === "behold:unpin") return kioskPopEvent({ type: "outside" });
|
|
4346
|
+
// behold#571: the kiosk's theme picker moved; follow it here without a reload.
|
|
4347
|
+
if (e.data && e.data.type === "behold:theme" && typeof e.data.name === "string") return void setTheme(e.data.name, { persist: false });
|
|
4342
4348
|
const h = hoverFromMessage(e.data);
|
|
4343
4349
|
if (h === undefined) return;
|
|
4344
4350
|
kioskHostHover = h;
|
|
@@ -5982,6 +5988,54 @@ function ensureZoomControls(host) {
|
|
|
5982
5988
|
},
|
|
5983
5989
|
{ passive: false },
|
|
5984
5990
|
);
|
|
5991
|
+
// behold#571: on a touch screen (the kiosk on a phone), one finger pans and two pinch to zoom.
|
|
5992
|
+
let touch = null;
|
|
5993
|
+
const touchPoints = (e) => [...e.touches].map((t) => ({ x: t.clientX, y: t.clientY }));
|
|
5994
|
+
host.addEventListener(
|
|
5995
|
+
"touchstart",
|
|
5996
|
+
(e) => {
|
|
5997
|
+
if (!vb) return;
|
|
5998
|
+
touch = { pts: touchPoints(e), moved: false };
|
|
5999
|
+
},
|
|
6000
|
+
{ passive: true },
|
|
6001
|
+
);
|
|
6002
|
+
host.addEventListener(
|
|
6003
|
+
"touchmove",
|
|
6004
|
+
(e) => {
|
|
6005
|
+
const s = currentSvg();
|
|
6006
|
+
if (!touch || !vb || !s) return;
|
|
6007
|
+
const pts = touchPoints(e);
|
|
6008
|
+
const r = s.getBoundingClientRect();
|
|
6009
|
+
e.preventDefault();
|
|
6010
|
+
if (pts.length >= 2 && touch.pts.length >= 2) {
|
|
6011
|
+
const dist = (p) => Math.hypot(p[0].x - p[1].x, p[0].y - p[1].y) || 1;
|
|
6012
|
+
const mid = (p) => ({ x: (p[0].x + p[1].x) / 2, y: (p[0].y + p[1].y) / 2 });
|
|
6013
|
+
const f = dist(touch.pts) / dist(pts);
|
|
6014
|
+
const m = mid(pts);
|
|
6015
|
+
const m0 = mid(touch.pts);
|
|
6016
|
+
const cx = vb[0] + ((m.x - r.left) / r.width) * vb[2];
|
|
6017
|
+
const cy = vb[1] + ((m.y - r.top) / r.height) * vb[3];
|
|
6018
|
+
const nw = Math.min(vbInit[2] * 3, Math.max(vbInit[2] / 60, vb[2] * f));
|
|
6019
|
+
const nh = nw * (vb[3] / vb[2]);
|
|
6020
|
+
vb[0] = cx - ((cx - vb[0]) * nw) / vb[2] - ((m.x - m0.x) / r.width) * nw;
|
|
6021
|
+
vb[1] = cy - ((cy - vb[1]) * nh) / vb[3] - ((m.y - m0.y) / r.height) * nh;
|
|
6022
|
+
vb[2] = nw;
|
|
6023
|
+
vb[3] = nh;
|
|
6024
|
+
} else if (pts.length === 1 && touch.pts.length === 1) {
|
|
6025
|
+
vb[0] -= ((pts[0].x - touch.pts[0].x) / r.width) * vb[2];
|
|
6026
|
+
vb[1] -= ((pts[0].y - touch.pts[0].y) / r.height) * vb[3];
|
|
6027
|
+
}
|
|
6028
|
+
if (!touch.moved && touch.pts.length && Math.abs(pts[0].x - touch.pts[0].x) + Math.abs(pts[0].y - touch.pts[0].y) > 3) touch.moved = true;
|
|
6029
|
+
if (touch.moved) panMoved = true;
|
|
6030
|
+
touch.pts = pts;
|
|
6031
|
+
vbAtFit = false;
|
|
6032
|
+
applyVB();
|
|
6033
|
+
},
|
|
6034
|
+
{ passive: false },
|
|
6035
|
+
);
|
|
6036
|
+
host.addEventListener("touchend", (e) => {
|
|
6037
|
+
touch = e.touches.length ? { pts: touchPoints(e), moved: !!(touch && touch.moved) } : null;
|
|
6038
|
+
});
|
|
5985
6039
|
let drag = false;
|
|
5986
6040
|
let px = 0;
|
|
5987
6041
|
let py = 0;
|
|
@@ -6478,6 +6532,8 @@ function ensureLayoutDrag(host) {
|
|
|
6478
6532
|
layoutWired = true;
|
|
6479
6533
|
host.addEventListener("pointerdown", (e) => {
|
|
6480
6534
|
if (e.button !== 0 || !layoutIndex) return;
|
|
6535
|
+
// behold#571: in the kiosk's bare frame a finger pans the graph; it never moves a card.
|
|
6536
|
+
if (e.pointerType === "touch" && embedOpts.bare) return;
|
|
6481
6537
|
const t = layoutTargetOf(e);
|
|
6482
6538
|
if (!t || !currentSvg()) return;
|
|
6483
6539
|
layoutDrag = { ...t, x0: e.clientX, y0: e.clientY, base: layoutDeltas[t.id] || {}, moved: false };
|
package/web/index.html
CHANGED
|
@@ -426,6 +426,8 @@
|
|
|
426
426
|
border: 1px solid var(--rule); border-radius: 8px; box-shadow: 0 6px 22px color-mix(in srgb, var(--shadow) 70%, transparent);
|
|
427
427
|
font: 14px/1.4 var(--font-ui); pointer-events: auto; }
|
|
428
428
|
#k-pop[hidden] { display: none; }
|
|
429
|
+
/* behold#571: on a phone the popover takes the frame's width, less a margin. */
|
|
430
|
+
@media (max-width: 600px) { #k-pop { max-width: calc(100vw - 16px); } }
|
|
429
431
|
#k-pop.k-pinned { border-color: var(--focus); }
|
|
430
432
|
#k-pop p { margin: 0.25em 0; }
|
|
431
433
|
.k-pop-addr { font: 700 1.05em var(--font-mono); overflow-wrap: anywhere; }
|