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