@thatopen/services 0.1.3 → 0.3.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/README.md +59 -46
- package/dist/built-in/index.d.ts +486 -563
- package/dist/cli/lib/npmrc.d.ts +28 -0
- package/dist/cli/lib/npmrc.test.d.ts +1 -0
- package/dist/cli.js +91 -7
- package/dist/core/client.d.ts +10 -0
- package/dist/index.cjs.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +42 -32
- package/dist/types/npm.d.ts +14 -0
- package/dist/vite-env.d.ts +1 -1
- package/docs/builtin/paths.json +74 -70
- package/docs/cli/create.md +28 -28
- package/docs/cli/local-server.md +38 -38
- package/docs/cli/login.md +32 -32
- package/docs/cli/publish.md +31 -31
- package/docs/cli/run.md +26 -26
- package/docs/cli/serve.md +43 -43
- package/docs/cli/swap.md +30 -30
- package/package.json +100 -100
- package/resources/AGENTS.md +40 -40
- package/src/built-in/CDEManager/example.ts +214 -214
- package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
- package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
- package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
- package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
- package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
- package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
- package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
- package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
- package/src/built-in/UIManager/src/app/example.ts +99 -99
- package/src/built-in/UIManager/src/app/examples/AppState/example.ts +142 -142
- package/src/built-in/UIManager/src/app/examples/Banner/example.ts +161 -0
- package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +125 -125
- package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +126 -0
- package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +92 -92
- package/src/built-in/UIManager/src/app/examples/Modal/example.ts +165 -0
- package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +135 -161
- package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +104 -104
- package/src/built-in/index.ts +649 -755
- package/src/cli/templates/app/README.md +241 -241
- package/src/cli/templates/app/index.html +35 -27
- package/src/cli/templates/app/package.json +31 -27
- package/src/cli/templates/app/src/app.ts +37 -0
- package/src/cli/templates/app/src/assets/tool-placeholder.ts +50 -0
- package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -87
- package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
- package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
- package/src/cli/templates/app/src/bim-components/index.ts +1 -1
- package/src/cli/templates/app/src/globals.ts +1 -0
- package/src/cli/templates/app/src/main.ts +340 -56
- package/src/cli/templates/app/src/setups/active-tool-hud.ts +69 -0
- package/src/cli/templates/app/src/setups/camera-tools.ts +63 -0
- package/src/cli/templates/app/src/setups/camera-views.ts +201 -0
- package/src/cli/templates/app/src/setups/card-header.ts +35 -0
- package/src/cli/templates/app/src/setups/clipper-panel.ts +167 -0
- package/src/cli/templates/app/src/setups/clipper-tool.ts +754 -0
- package/src/cli/templates/app/src/setups/clipper.ts +75 -0
- package/src/cli/templates/app/src/setups/cloud-runner.ts +13 -9
- package/src/cli/templates/app/src/setups/commands-panel.ts +239 -0
- package/src/cli/templates/app/src/setups/data-table-panel.ts +2224 -0
- package/src/cli/templates/app/src/setups/exploded-view.ts +246 -0
- package/src/cli/templates/app/src/setups/file-format-icons.ts +95 -0
- package/src/cli/templates/app/src/setups/files-panel.ts +1503 -0
- package/src/cli/templates/app/src/setups/fps-indicator.ts +63 -0
- package/src/cli/templates/app/src/setups/graphics-panel.ts +490 -0
- package/src/cli/templates/app/src/setups/helper-panel.ts +88 -0
- package/src/cli/templates/app/src/setups/hider.ts +98 -0
- package/src/cli/templates/app/src/setups/index.ts +33 -3
- package/src/cli/templates/app/src/setups/inspection.ts +136 -0
- package/src/cli/templates/app/src/setups/measurement-panel.ts +188 -0
- package/src/cli/templates/app/src/setups/measurement-settings-panel.ts +161 -0
- package/src/cli/templates/app/src/setups/measurement-tool.ts +570 -0
- package/src/cli/templates/app/src/setups/measurements.ts +133 -0
- package/src/cli/templates/app/src/setups/model-tree.ts +797 -0
- package/src/cli/templates/app/src/setups/navigation-gizmo.ts +316 -0
- package/src/cli/templates/app/src/setups/objects-panel.ts +127 -0
- package/src/cli/templates/app/src/setups/plans-panel.ts +619 -0
- package/src/cli/templates/app/src/setups/properties-panel.ts +1048 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/hidden-tiles-plugin.ts +88 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/point-tile-plugin.ts +166 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/render-frame.ts +31 -0
- package/src/cli/templates/app/src/setups/reality-capture/lib/splat-tile-plugin.ts +51 -0
- package/src/cli/templates/app/src/setups/reality-capture-viewer.ts +1383 -0
- package/src/cli/templates/app/src/setups/right-sidebar.ts +178 -0
- package/src/cli/templates/app/src/setups/settings-panel.ts +94 -0
- package/src/cli/templates/app/src/setups/styles-panel.ts +110 -0
- package/src/cli/templates/app/src/setups/styles.ts +375 -0
- package/src/cli/templates/app/src/setups/tool-mode-manager.ts +150 -0
- package/src/cli/templates/app/src/setups/tool-mode.ts +23 -0
- package/src/cli/templates/app/src/setups/toolbar.ts +229 -0
- package/src/cli/templates/app/src/setups/ui-manager.ts +27 -0
- package/src/cli/templates/app/src/setups/visibility-toolbar.ts +498 -0
- package/src/cli/templates/app/src/setups/walkthrough.ts +528 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -0
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -0
- package/src/cli/templates/app/src/ui-components/index.ts +2 -1
- package/src/cli/templates/app/tsconfig.json +16 -17
- package/src/cli/templates/app/vite.config.js +45 -42
- package/src/cli/templates/cloud-component/README.md +205 -205
- package/src/cli/templates/cloud-component/_thatopen +5 -5
- package/src/cli/templates/cloud-component/declarations.json +4 -4
- package/src/cli/templates/cloud-component/package.json +21 -21
- package/src/cli/templates/cloud-component/src/main.ts +70 -70
- package/src/cli/templates/cloud-component/tsconfig.json +16 -16
- package/src/cli/templates/cloud-component/vite.config.js +46 -46
- package/src/cli/templates/shared/AGENTS.md +8 -8
- package/src/cli/templates/shared/CLAUDE.md +1 -1
- package/src/cli/templates/shared/_gitignore +5 -4
- package/src/built-in/AppManager/example.ts +0 -86
- package/src/built-in/FileList/example.ts +0 -107
- package/src/built-in/TabbedNavigation/example.ts +0 -115
- package/src/built-in/ViewportsManager/example.ts +0 -106
- package/src/cli/templates/app/src/setups/fragments.ts +0 -18
- package/src/cli/templates/app/src/setups/ifc-loader.ts +0 -12
- package/src/cli/templates/app/src/ui-components/AppPanel/index.ts +0 -160
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as OBC from "@thatopen/components";
|
|
2
|
+
import * as OBF from "@thatopen/components-front";
|
|
3
|
+
import type { ModeTool } from "./tool-mode";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Section / clipping-planes tool. Wraps `OBC.Clipper` as a toolbar mode tool:
|
|
7
|
+
*
|
|
8
|
+
* - double-click on the model → create a clip plane on the surface under the
|
|
9
|
+
* pointer (raycast; the plane's normal is the hit face normal),
|
|
10
|
+
* - drag the plane's arrow gizmo to move it along its normal (handled by the
|
|
11
|
+
* Clipper's built-in TransformControls while the mode is active),
|
|
12
|
+
* - Delete / Backspace → delete the plane under the cursor,
|
|
13
|
+
* - Shift + Delete / Shift + Backspace → clear ALL section planes.
|
|
14
|
+
*
|
|
15
|
+
* Clipping is applied through `renderer.three.clippingPlanes` with
|
|
16
|
+
* `localClippingEnabled = true` (set by the SimpleRenderer), so the cut is
|
|
17
|
+
* honored during the deferred pipeline's single capture render — no
|
|
18
|
+
* deferred-lib change is needed. (Worth an explicit live check that the section
|
|
19
|
+
* actually cuts geometry in deferred mode.)
|
|
20
|
+
*
|
|
21
|
+
* Leaving the mode keeps the existing section planes cutting the model (so a
|
|
22
|
+
* section persists while navigating); it only stops creating/dragging new ones.
|
|
23
|
+
*/
|
|
24
|
+
export const clipper = (
|
|
25
|
+
components: OBC.Components,
|
|
26
|
+
world: OBC.World,
|
|
27
|
+
): ModeTool => {
|
|
28
|
+
const clipperComp = components.get(OBC.Clipper);
|
|
29
|
+
|
|
30
|
+
const canvas = (world.renderer as OBF.PostproductionRenderer | null)?.three
|
|
31
|
+
.domElement;
|
|
32
|
+
if (!canvas) {
|
|
33
|
+
throw new Error("clipper setup: world has no renderer with a canvas");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const onDblClick = () => {
|
|
37
|
+
void clipperComp.create(world);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
41
|
+
if (event.code !== "Delete" && event.code !== "Backspace") return;
|
|
42
|
+
if (event.shiftKey) {
|
|
43
|
+
clipperComp.deleteAll();
|
|
44
|
+
} else {
|
|
45
|
+
// No-op when nothing is hovered (the Clipper raycasts for a plane).
|
|
46
|
+
void clipperComp.delete(world);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
let active = false;
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
label: "Section",
|
|
54
|
+
icon: "mdi:scissors-cutting",
|
|
55
|
+
activate() {
|
|
56
|
+
if (active) return;
|
|
57
|
+
active = true;
|
|
58
|
+
clipperComp.enabled = true; // allow create + drag-to-move
|
|
59
|
+
clipperComp.visible = true;
|
|
60
|
+
canvas.addEventListener("dblclick", onDblClick);
|
|
61
|
+
window.addEventListener("keydown", onKeyDown);
|
|
62
|
+
canvas.style.cursor = "crosshair";
|
|
63
|
+
},
|
|
64
|
+
deactivate() {
|
|
65
|
+
if (!active) return;
|
|
66
|
+
active = false;
|
|
67
|
+
// Stop creating / dragging, but keep the planes in the renderer's
|
|
68
|
+
// clippingPlanes so the section stays cut while navigating.
|
|
69
|
+
clipperComp.enabled = false;
|
|
70
|
+
canvas.removeEventListener("dblclick", onDblClick);
|
|
71
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
72
|
+
canvas.style.cursor = "";
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
};
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import * as OBC from "@thatopen/components";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export const
|
|
6
|
-
const runner = components.get(CloudRunner);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import * as OBC from "@thatopen/components";
|
|
2
|
+
import { CloudRunner } from "../bim-components";
|
|
3
|
+
import { getUIManager } from "./ui-manager";
|
|
4
|
+
|
|
5
|
+
export const cloudRunner = (components: OBC.Components) => {
|
|
6
|
+
const runner = components.get(CloudRunner);
|
|
7
|
+
const uis = getUIManager(components);
|
|
8
|
+
|
|
9
|
+
// Re-render all appInfoSection instances whenever execution state changes.
|
|
10
|
+
runner.onExecutionUpdated.add(() => {
|
|
11
|
+
uis.custom.get("cloudRunnerSection").updateInstances();
|
|
12
|
+
});
|
|
13
|
+
};
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import * as OBC from "@thatopen/components";
|
|
3
|
+
import * as OBF from "@thatopen/components-front";
|
|
4
|
+
import * as BUI from "@thatopen/ui";
|
|
5
|
+
import { hider } from "./hider";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* COMMANDS — a docked side-panel (alongside Explorer / Files / Graphics) that is
|
|
9
|
+
* both the keyboard-shortcut registry and its palette UI.
|
|
10
|
+
*
|
|
11
|
+
* A single `COMMANDS` table maps each viewer action to a shortcut + an mdi icon
|
|
12
|
+
* and a `run()` wired to the EXISTING components (the `hider` controller for
|
|
13
|
+
* visibility, the Highlighter for the current selection + clear, camera-controls
|
|
14
|
+
* for focus). The panel lists every command with its shortcut (command-palette
|
|
15
|
+
* style, click-to-run), and a global `keydown` handler dispatches the shortcuts —
|
|
16
|
+
* ignored while typing in an input so search fields aren't hijacked.
|
|
17
|
+
*
|
|
18
|
+
* Self-contained: returns the panel element WITHOUT self-mounting (like
|
|
19
|
+
* modelTree / graphicsPanel) and installs its own window keydown listener.
|
|
20
|
+
*
|
|
21
|
+
* @param components engine components
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
interface ViewerCommand {
|
|
25
|
+
id: string;
|
|
26
|
+
label: string;
|
|
27
|
+
icon: string;
|
|
28
|
+
/** Display chips, e.g. ["Shift", "H"]. */
|
|
29
|
+
keys: string[];
|
|
30
|
+
/** Does this keydown event trigger the command? */
|
|
31
|
+
match: (e: KeyboardEvent) => boolean;
|
|
32
|
+
run: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const noMods = (e: KeyboardEvent) =>
|
|
36
|
+
!e.shiftKey && !e.ctrlKey && !e.metaKey && !e.altKey;
|
|
37
|
+
|
|
38
|
+
// Don't hijack shortcuts while the user is typing in a field.
|
|
39
|
+
const typingInField = (e: KeyboardEvent) => {
|
|
40
|
+
const path = (e.composedPath?.() ?? []) as HTMLElement[];
|
|
41
|
+
const el = (path[0] ?? (e.target as HTMLElement)) || null;
|
|
42
|
+
const active = (document.activeElement as HTMLElement) || null;
|
|
43
|
+
const isField = (n: HTMLElement | null) =>
|
|
44
|
+
!!n &&
|
|
45
|
+
(n.isContentEditable ||
|
|
46
|
+
/^(input|textarea|select)$/i.test(n.tagName) ||
|
|
47
|
+
/^bim-(text|number)-input$/i.test(n.tagName));
|
|
48
|
+
return path.some(isField) || isField(el) || isField(active);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const commandsPanel = (components: OBC.Components) => {
|
|
52
|
+
const fragments = components.get(OBC.FragmentsManager);
|
|
53
|
+
const highlighter = components.get(OBF.Highlighter);
|
|
54
|
+
const selectName = highlighter.config.selectName;
|
|
55
|
+
const h = hider(components);
|
|
56
|
+
|
|
57
|
+
const hasSelection = () => {
|
|
58
|
+
const map = highlighter.selection[selectName];
|
|
59
|
+
return !!map && Object.values(map).some((s) => s.size > 0);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const focusSelection = async () => {
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
const world = [...components.get(OBC.Worlds).list.values()][0] as any;
|
|
65
|
+
const controls = world?.camera?.controls;
|
|
66
|
+
if (!controls) return;
|
|
67
|
+
const map = highlighter.selection[selectName];
|
|
68
|
+
const hasSel = !!map && Object.values(map).some((s) => s.size > 0);
|
|
69
|
+
try {
|
|
70
|
+
const box = new THREE.Box3();
|
|
71
|
+
if (hasSel) {
|
|
72
|
+
const boxes = (await fragments.getBBoxes(map)) as THREE.Box3[];
|
|
73
|
+
for (const b of boxes) box.union(b);
|
|
74
|
+
} else {
|
|
75
|
+
// Nothing selected → focus = zoom to fit the WHOLE model (union of all
|
|
76
|
+
// loaded models' bounds). This makes a dedicated fit/home button unnecessary.
|
|
77
|
+
for (const model of fragments.list.values()) {
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
|
+
const b = (model as any).box as THREE.Box3 | undefined;
|
|
80
|
+
if (b && !b.isEmpty()) box.union(b);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (box.isEmpty()) return;
|
|
84
|
+
const sphere = box.getBoundingSphere(new THREE.Sphere());
|
|
85
|
+
await controls.fitToSphere(sphere, true);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.warn("[commands] focus failed", error);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const clearSelection = () => void highlighter.clear(selectName);
|
|
92
|
+
|
|
93
|
+
const COMMANDS: ViewerCommand[] = [
|
|
94
|
+
{
|
|
95
|
+
id: "focus",
|
|
96
|
+
label: "Focus selection",
|
|
97
|
+
icon: "mdi:image-filter-center-focus",
|
|
98
|
+
keys: ["F"],
|
|
99
|
+
match: (e) => e.key.toLowerCase() === "f" && noMods(e),
|
|
100
|
+
run: () => void focusSelection(),
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: "hide",
|
|
104
|
+
label: "Hide selected",
|
|
105
|
+
icon: "mdi:eye-off-outline",
|
|
106
|
+
keys: ["H"],
|
|
107
|
+
match: (e) => e.key.toLowerCase() === "h" && noMods(e),
|
|
108
|
+
run: () => h.hideSelected(),
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: "isolate",
|
|
112
|
+
label: "Isolate selected",
|
|
113
|
+
icon: "mdi:select-search",
|
|
114
|
+
keys: ["Shift", "H"],
|
|
115
|
+
match: (e) =>
|
|
116
|
+
e.key.toLowerCase() === "h" &&
|
|
117
|
+
e.shiftKey &&
|
|
118
|
+
!e.ctrlKey &&
|
|
119
|
+
!e.metaKey &&
|
|
120
|
+
!e.altKey,
|
|
121
|
+
run: () => h.isolateSelected(),
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "ghost",
|
|
125
|
+
label: "Ghost selected",
|
|
126
|
+
icon: "mdi:ghost-outline",
|
|
127
|
+
keys: ["G"],
|
|
128
|
+
match: (e) => e.key.toLowerCase() === "g" && noMods(e),
|
|
129
|
+
run: () => h.ghostSelected(),
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: "showAll",
|
|
133
|
+
label: "Show all",
|
|
134
|
+
icon: "mdi:eye-outline",
|
|
135
|
+
keys: ["Shift", "A"],
|
|
136
|
+
match: (e) =>
|
|
137
|
+
e.key.toLowerCase() === "a" &&
|
|
138
|
+
e.shiftKey &&
|
|
139
|
+
!e.ctrlKey &&
|
|
140
|
+
!e.metaKey &&
|
|
141
|
+
!e.altKey,
|
|
142
|
+
run: () => h.showAll(),
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: "clear",
|
|
146
|
+
label: "Clear selection",
|
|
147
|
+
icon: "mdi:close",
|
|
148
|
+
keys: ["Esc"],
|
|
149
|
+
match: (e) => e.key === "Escape" && noMods(e),
|
|
150
|
+
run: () => clearSelection(),
|
|
151
|
+
},
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
// ── Global shortcut dispatch ───────────────────────────────────
|
|
155
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
156
|
+
if (typingInField(e)) return;
|
|
157
|
+
for (const cmd of COMMANDS) {
|
|
158
|
+
if (cmd.match(e)) {
|
|
159
|
+
e.preventDefault();
|
|
160
|
+
cmd.run();
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
window.addEventListener("keydown", onKeyDown);
|
|
166
|
+
|
|
167
|
+
// ── Panel UI (command-palette list; mirrors graphics-panel chrome) ──
|
|
168
|
+
const [panel, update] = BUI.Component.create<BUI.Panel, { query: string }>(
|
|
169
|
+
(state) => {
|
|
170
|
+
const q = state.query.trim().toLowerCase();
|
|
171
|
+
const rows = COMMANDS.filter((c) => !q || c.label.toLowerCase().includes(q));
|
|
172
|
+
return BUI.html`
|
|
173
|
+
<bim-panel
|
|
174
|
+
label="Commands"
|
|
175
|
+
icon="mdi:keyboard"
|
|
176
|
+
style="width: 100%; height: 100%; pointer-events: auto;"
|
|
177
|
+
>
|
|
178
|
+
<style>
|
|
179
|
+
.cmd-vp::-webkit-scrollbar { width: 0.4rem; height: 0.4rem; }
|
|
180
|
+
.cmd-vp::-webkit-scrollbar-thumb { border-radius: 0.25rem; background-color: var(--bim-scrollbar--c, #3C3C41); }
|
|
181
|
+
.cmd-vp::-webkit-scrollbar-track { background-color: var(--bim-scrollbar--bgc, var(--bim-ui_bg-contrast-10)); }
|
|
182
|
+
.cmd-row { box-sizing: border-box; min-height: 32px; display: flex;
|
|
183
|
+
align-items: center; gap: 0.55rem; padding: 0.35rem 0.4rem 0.35rem 1.1rem;
|
|
184
|
+
font-size: 0.78rem; line-height: 1.3; cursor: pointer;
|
|
185
|
+
color: var(--bim-ui_bg-contrast-100, #e3e3e3);
|
|
186
|
+
border-bottom: 1px solid var(--bim-ui_bg-contrast-20, rgba(255,255,255,0.1)); }
|
|
187
|
+
.cmd-row:hover { background: var(--bim-ui_bg-contrast-20, rgba(255,255,255,0.08)); }
|
|
188
|
+
.cmd-ico { flex: 0 0 auto; color: #99a0ae; font-size: 0.95rem; }
|
|
189
|
+
.cmd-label { flex: 1 1 auto; min-width: 0; overflow: hidden;
|
|
190
|
+
text-overflow: ellipsis; white-space: nowrap; }
|
|
191
|
+
.cmd-keys { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 0.2rem; }
|
|
192
|
+
.cmd-kbd { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
193
|
+
font-size: 0.66rem; line-height: 1; padding: 0.12rem 0.35rem;
|
|
194
|
+
border-radius: 0.25rem; color: var(--bim-ui_bg-contrast-80, #c9c9c9);
|
|
195
|
+
background: var(--bim-ui_bg-contrast-20, rgba(255,255,255,0.08));
|
|
196
|
+
border: 1px solid var(--bim-ui_bg-contrast-40, rgba(255,255,255,0.18)); }
|
|
197
|
+
.cmd-plus { opacity: 0.4; font-size: 0.66rem; }
|
|
198
|
+
</style>
|
|
199
|
+
<div style="display: flex; flex-direction: column; height: 100%; width: 100%;">
|
|
200
|
+
<div style="flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 0.4rem 0.4rem 0.4rem 1.1rem; gap: 0.25rem;">
|
|
201
|
+
<bim-text-input
|
|
202
|
+
icon="mdi:magnify"
|
|
203
|
+
icon-inside
|
|
204
|
+
placeholder="Search commands…"
|
|
205
|
+
style="flex: 0 0 auto; width: 100%; margin: 0 0 0.25rem -0.35rem;"
|
|
206
|
+
@input=${(e: Event) => {
|
|
207
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
208
|
+
update({ query: String((e.target as any).value ?? "") });
|
|
209
|
+
}}
|
|
210
|
+
></bim-text-input>
|
|
211
|
+
<div style="flex: 0 0 auto; border-bottom: 1px solid var(--bim-ui_bg-contrast-20, rgba(255,255,255,0.1)); margin: 0 -0.4rem 0.1rem -1.1rem;"></div>
|
|
212
|
+
<div class="cmd-vp" style="flex: 1 1 auto; min-height: 0; overflow-y: auto; margin-left: -1.1rem; margin-right: -0.4rem;">
|
|
213
|
+
${rows.length === 0
|
|
214
|
+
? BUI.html`<div style="padding: 0.75rem 1.1rem;"><bim-label style="opacity: 0.6;">No commands.</bim-label></div>`
|
|
215
|
+
: rows.map(
|
|
216
|
+
(c) => BUI.html`
|
|
217
|
+
<div class="cmd-row" title=${c.label} @click=${() => c.run()}>
|
|
218
|
+
<bim-icon class="cmd-ico" icon=${c.icon}></bim-icon>
|
|
219
|
+
<span class="cmd-label">${c.label}</span>
|
|
220
|
+
<span class="cmd-keys">
|
|
221
|
+
${c.keys.map(
|
|
222
|
+
(k, i) => BUI.html`${i > 0
|
|
223
|
+
? BUI.html`<span class="cmd-plus">+</span>`
|
|
224
|
+
: null}<span class="cmd-kbd">${k}</span>`,
|
|
225
|
+
)}
|
|
226
|
+
</span>
|
|
227
|
+
</div>`,
|
|
228
|
+
)}
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</bim-panel>
|
|
233
|
+
`;
|
|
234
|
+
},
|
|
235
|
+
{ query: "" },
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
return panel;
|
|
239
|
+
};
|