@booboo-brain/panel 0.4.0 → 0.5.0
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/dist/index.js
CHANGED
|
@@ -290,10 +290,11 @@ body { font-family: var(--font); color: var(--ink); background: var(--bg); overf
|
|
|
290
290
|
.pending-item { font-size: 11.5px; color: var(--warn); font-family: var(--mono); }
|
|
291
291
|
.pnl-err { position: relative; z-index: 2; padding: 10px 26px; color: #e07b6a; font-size: 12.5px; }
|
|
292
292
|
|
|
293
|
-
/* layout
|
|
294
|
-
|
|
293
|
+
/* layout — 100% so a HOST container decides the height (embedded panel);
|
|
294
|
+
the standalone app gives html/body/#root 100%, so served behaviour is unchanged. */
|
|
295
|
+
.pnl { height: 100%; min-height: 480px; }
|
|
295
296
|
.body { position: relative; z-index: 1; flex: 1; display: flex; min-height: 0; }
|
|
296
|
-
.tree { flex: 1; min-width: 0; padding: 24px 26px 24px; overflow: hidden;
|
|
297
|
+
.tree { position: relative; flex: 1; min-width: 0; padding: 24px 26px 24px; overflow: hidden;
|
|
297
298
|
display: flex; flex-direction: column;
|
|
298
299
|
/* the ground plane: a faint dot grid (engineered surface, drag affordance)
|
|
299
300
|
+ a verdigris pool anchoring the eye at the root. Static — capture-safe. */
|
|
@@ -310,11 +311,23 @@ body { font-family: var(--font); color: var(--ink); background: var(--bg); overf
|
|
|
310
311
|
/* the measuring viewport — flex:1 + min-height:0 lets it consume the height
|
|
311
312
|
.tree gives it; align/justify center the scaled block for narrow orgs. */
|
|
312
313
|
.chart-fit { position: relative; flex: 1; min-height: 0; display: flex; align-items: flex-start; justify-content: center; overflow: hidden; }
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
314
|
+
/* user-zoomed: native scroll is the pan; top-left origin keeps the scaled
|
|
315
|
+
overflow fully reachable (top/center origin would clip the left half). */
|
|
316
|
+
.chart-fit.zoomed { overflow: auto; justify-content: flex-start; }
|
|
317
|
+
.chart-fit.zoomed .chart { transform-origin: top left; }
|
|
318
|
+
.zoomer {
|
|
319
|
+
position: absolute; right: 34px; bottom: 32px; z-index: 3; display: flex; align-items: center; gap: 2px;
|
|
320
|
+
font-family: var(--mono); font-size: 11px; color: var(--ink-2);
|
|
321
|
+
background: var(--bg-2); border: 1px solid var(--line); border-radius: 8px; padding: 3px 6px;
|
|
322
|
+
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
|
|
317
323
|
}
|
|
324
|
+
.zoomer button {
|
|
325
|
+
all: unset; cursor: pointer; padding: 2px 8px; border-radius: 5px; color: var(--ink-2);
|
|
326
|
+
font-family: var(--mono); font-size: 12px; line-height: 1.4;
|
|
327
|
+
}
|
|
328
|
+
.zoomer button:hover { background: var(--accent-dim); color: var(--ink); }
|
|
329
|
+
.zoomer button.on { color: var(--accent); }
|
|
330
|
+
.zoomer-pct { min-width: 40px; text-align: center; color: var(--ink-3); }
|
|
318
331
|
/* min-width:max-content keeps connectors geometrically correct at natural size
|
|
319
332
|
BEFORE scaling; the measured --fit shrinks the whole block toward its head. */
|
|
320
333
|
.chart {
|
|
@@ -1184,6 +1197,8 @@ function OrgScreen({
|
|
|
1184
1197
|
const fitRef = useRef(null);
|
|
1185
1198
|
const chartRef = useRef(null);
|
|
1186
1199
|
const [fit, setFit] = useState(1);
|
|
1200
|
+
const [zoom, setZoom] = useState(null);
|
|
1201
|
+
const eff = zoom ?? fit;
|
|
1187
1202
|
useLayoutEffect(() => {
|
|
1188
1203
|
const vp = fitRef.current, chart = chartRef.current;
|
|
1189
1204
|
if (!vp || !chart) return;
|
|
@@ -1201,31 +1216,47 @@ function OrgScreen({
|
|
|
1201
1216
|
ro.observe(chart);
|
|
1202
1217
|
return () => ro.disconnect();
|
|
1203
1218
|
}, [draft, health, selected]);
|
|
1219
|
+
const effRef = useRef(eff);
|
|
1220
|
+
effRef.current = eff;
|
|
1221
|
+
useEffect(() => {
|
|
1222
|
+
const vp = fitRef.current;
|
|
1223
|
+
if (!vp) return;
|
|
1224
|
+
const onWheel = (e) => {
|
|
1225
|
+
if (!e.ctrlKey && !e.metaKey) return;
|
|
1226
|
+
e.preventDefault();
|
|
1227
|
+
const k = e.deltaY < 0 ? 1.12 : 1 / 1.12;
|
|
1228
|
+
setZoom(Math.min(2.5, Math.max(0.2, effRef.current * k)));
|
|
1229
|
+
};
|
|
1230
|
+
vp.addEventListener("wheel", onWheel, { passive: false });
|
|
1231
|
+
return () => vp.removeEventListener("wheel", onWheel);
|
|
1232
|
+
}, []);
|
|
1204
1233
|
const root = draft.agents.find((a) => a.id === draft.root);
|
|
1205
1234
|
return /* @__PURE__ */ jsxs("div", { className: "body", onClick: () => setSelected(null), children: [
|
|
1206
1235
|
/* @__PURE__ */ jsxs("main", { className: "tree", onClick: (e) => e.stopPropagation(), children: [
|
|
1207
1236
|
/* @__PURE__ */ jsx("p", { className: "tree-hint", children: "drag an agent onto its new parent \xB7 click for its dossier \xB7 machine trays show live health" }),
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
Math.round(
|
|
1237
|
+
/* @__PURE__ */ jsx("div", { className: `chart-fit${zoom !== null ? " zoomed" : ""}`, ref: fitRef, children: /* @__PURE__ */ jsx("div", { className: "chart", ref: chartRef, style: { ["--fit"]: eff }, children: root && /* @__PURE__ */ jsx(
|
|
1238
|
+
ChartNode,
|
|
1239
|
+
{
|
|
1240
|
+
org: draft,
|
|
1241
|
+
a: root,
|
|
1242
|
+
depth: 0,
|
|
1243
|
+
order: 0,
|
|
1244
|
+
selected,
|
|
1245
|
+
dragId,
|
|
1246
|
+
health,
|
|
1247
|
+
onSelect: setSelected,
|
|
1248
|
+
onDragStart: setDragId,
|
|
1249
|
+
onDropOn: dropOn
|
|
1250
|
+
}
|
|
1251
|
+
) }) }),
|
|
1252
|
+
/* @__PURE__ */ jsxs("div", { className: "zoomer", children: [
|
|
1253
|
+
/* @__PURE__ */ jsx("button", { type: "button", title: "zoom out (ctrl+wheel)", onClick: () => setZoom(Math.max(0.2, eff / 1.25)), children: "\u2212" }),
|
|
1254
|
+
/* @__PURE__ */ jsxs("span", { className: "zoomer-pct", children: [
|
|
1255
|
+
Math.round(eff * 100),
|
|
1227
1256
|
"%"
|
|
1228
|
-
] })
|
|
1257
|
+
] }),
|
|
1258
|
+
/* @__PURE__ */ jsx("button", { type: "button", title: "zoom in (ctrl+wheel)", onClick: () => setZoom(Math.min(2.5, eff * 1.25)), children: "\uFF0B" }),
|
|
1259
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: zoom === null ? "on" : "", title: "fit the whole org in view", onClick: () => setZoom(null), children: "fit" })
|
|
1229
1260
|
] })
|
|
1230
1261
|
] }),
|
|
1231
1262
|
selected && /* @__PURE__ */ jsx(
|