@thatopen/services 0.3.15 → 0.4.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 +62 -62
- package/dist/built-in/index.d.ts +165 -2
- package/dist/cli.js +27 -13
- package/dist/core/client.d.ts +1 -0
- package/dist/core/platform-client.d.ts +7 -0
- package/dist/index.cjs.js +2 -2
- package/dist/index.es.js +396 -374
- package/dist/vite-env.d.ts +1 -1
- package/docs/builtin/paths.json +94 -86
- package/docs/cli/create.md +29 -29
- 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 +4 -4
- 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/ClashesManager/example.ts +283 -283
- package/src/built-in/UIManager/src/app/example.ts +97 -97
- package/src/built-in/UIManager/src/app/examples/AppState/example.ts +140 -140
- package/src/built-in/UIManager/src/app/examples/Banner/example.ts +159 -159
- package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +123 -123
- package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +124 -124
- package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +90 -90
- package/src/built-in/UIManager/src/app/examples/Modal/example.ts +163 -163
- package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +133 -133
- package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -0
- package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +102 -102
- package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -160
- package/src/built-in/UIManager/src/models-list/example.ts +122 -122
- package/src/built-in/UIManager/src/topics-panel/example.ts +170 -0
- package/src/built-in/index.ts +1048 -881
- package/src/cli/templates/app/index.html +35 -35
- package/src/cli/templates/app/package.json +32 -32
- package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -95
- 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 -1
- package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -26
- package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -1
- package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -15
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -37
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -1
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -14
- package/src/cli/templates/app/src/ui-components/index.ts +2 -2
- package/src/cli/templates/app/tsconfig.json +16 -16
- package/src/cli/templates/app/vite.config.js +57 -57
- 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 -5
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
/* MD
|
|
2
|
-
## File drag-and-drop with top:files-dropped
|
|
3
|
-
---
|
|
4
|
-
Desktop BIM workflows often rely on dragging files straight from the OS file
|
|
5
|
-
manager onto the browser window — but wiring a document-level dragenter,
|
|
6
|
-
dragover, dragleave, and drop handler that correctly tracks nested enter/leave
|
|
7
|
-
counts, shows a visual overlay, and forwards the files to the right component
|
|
8
|
-
is tedious boilerplate to repeat for every app.
|
|
9
|
-
|
|
10
|
-
top-app handles all of that automatically. It listens for file drag events on
|
|
11
|
-
the document, shows a configurable overlay while files are in flight, and fires
|
|
12
|
-
a single top:files-dropped event when the user releases the files. The drop
|
|
13
|
-
message can be a static string or a function evaluated at render time, so it
|
|
14
|
-
can reflect live application state.
|
|
15
|
-
|
|
16
|
-
This tutorial covers receiving dropped files via top:files-dropped; filtering
|
|
17
|
-
them by extension and surfacing a warning when none are supported; setting
|
|
18
|
-
dropMessage as a function that reads a live model counter so the hint text
|
|
19
|
-
updates as models are loaded; and showing a toast on success using the
|
|
20
|
-
top:notification event from the same handler.
|
|
21
|
-
|
|
22
|
-
By the end, you'll have an app with a drag-and-drop zone whose overlay message
|
|
23
|
-
adapts to how many models are already loaded, and that reports unsupported
|
|
24
|
-
files with a warning toast.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
import { html } from "lit";
|
|
28
|
-
import * as THREE from "three";
|
|
29
|
-
import * as OBC from "@thatopen/components";
|
|
30
|
-
import * as OBF from "@thatopen/components-front";
|
|
31
|
-
import * as FRAGS from "@thatopen/fragments";
|
|
32
|
-
import * as BUI from "@thatopen/ui";
|
|
33
|
-
import { PlatformClient, UIManager } from "@thatopen/services";
|
|
34
|
-
import type { App, AppReadyEvent } from "../../index";
|
|
35
|
-
|
|
36
|
-
const client = PlatformClient.fromPlatformContext();
|
|
37
|
-
const { components } = (await client.setup(
|
|
38
|
-
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
39
|
-
{ uuid: UIManager.uuid },
|
|
40
|
-
)) as { components: OBC.Components };
|
|
41
|
-
components.get(UIManager).init();
|
|
42
|
-
|
|
43
|
-
const app = document.createElement("top-app") as unknown as App;
|
|
44
|
-
|
|
45
|
-
app.setup = (waitUntil) => {
|
|
46
|
-
waitUntil(
|
|
47
|
-
(async () => {
|
|
48
|
-
const fragments = components.get(OBC.FragmentsManager);
|
|
49
|
-
const workerUrl = await FRAGS.FragmentsModels.getWorker();
|
|
50
|
-
fragments.init(await FRAGS.toClassicWorker(workerUrl), {
|
|
51
|
-
classicWorker: true,
|
|
52
|
-
});
|
|
53
|
-
})(),
|
|
54
|
-
"Fragments Core",
|
|
55
|
-
);
|
|
56
|
-
return { components, client };
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
app.elements = {
|
|
60
|
-
viewer: () =>
|
|
61
|
-
html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
app.base = "viewer";
|
|
65
|
-
app.layouts = {
|
|
66
|
-
main: {
|
|
67
|
-
label: "Main",
|
|
68
|
-
icon: "solar:home-bold",
|
|
69
|
-
template: `"_" 1fr / 1fr`,
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
app.layout = "main";
|
|
73
|
-
|
|
74
|
-
// dropMessage as a function is evaluated at render time so it can read live state.
|
|
75
|
-
// Here it reads how many models are already loaded and adjusts the hint text.
|
|
76
|
-
let loadedCount = 0;
|
|
77
|
-
app.dropMessage = () =>
|
|
78
|
-
loadedCount === 0
|
|
79
|
-
? "Drop an IFC or FRAG file to load your first model"
|
|
80
|
-
: `Drop a file to add to the ${loadedCount} loaded model${loadedCount === 1 ? "" : "s"}`;
|
|
81
|
-
|
|
82
|
-
// top:files-dropped fires when the user drops files onto the window.
|
|
83
|
-
// e.detail.files is a File[]. Handle upload, load, or validation here.
|
|
84
|
-
app.addEventListener("top:files-dropped", (e) => {
|
|
85
|
-
const { files } = (e as CustomEvent<{ files: File[] }>).detail;
|
|
86
|
-
|
|
87
|
-
const supported = files.filter(
|
|
88
|
-
(f) => f.name.endsWith(".ifc") || f.name.endsWith(".frag"),
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
// Dispatch top:notification to surface feedback without a reference to top-app.
|
|
92
|
-
if (!supported.length) {
|
|
93
|
-
app.dispatchEvent(
|
|
94
|
-
new CustomEvent("top:notification", {
|
|
95
|
-
bubbles: true,
|
|
96
|
-
composed: true,
|
|
97
|
-
detail: { message: "No supported files dropped", type: "warning" },
|
|
98
|
-
}),
|
|
99
|
-
);
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
loadedCount += supported.length;
|
|
104
|
-
app.dispatchEvent(
|
|
105
|
-
new CustomEvent("top:notification", {
|
|
106
|
-
bubbles: true,
|
|
107
|
-
composed: true,
|
|
108
|
-
detail: {
|
|
109
|
-
message: `${supported.length} file${supported.length === 1 ? "" : "s"} received`,
|
|
110
|
-
type: "success",
|
|
111
|
-
description: supported.map((f) => f.name).join(", "),
|
|
112
|
-
},
|
|
113
|
-
}),
|
|
114
|
-
);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
app.addEventListener("top:app-ready", (e) => {
|
|
118
|
-
const { app: readyApp } = (e as AppReadyEvent).detail;
|
|
119
|
-
readyApp.showToast("App ready — try dropping an IFC or FRAG file", "info");
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const container = document.getElementById("that-open-app") ?? document.body;
|
|
123
|
-
container.appendChild(app);
|
|
124
|
-
document.body.style.margin = "0";
|
|
1
|
+
/* MD
|
|
2
|
+
## File drag-and-drop with top:files-dropped
|
|
3
|
+
---
|
|
4
|
+
Desktop BIM workflows often rely on dragging files straight from the OS file
|
|
5
|
+
manager onto the browser window — but wiring a document-level dragenter,
|
|
6
|
+
dragover, dragleave, and drop handler that correctly tracks nested enter/leave
|
|
7
|
+
counts, shows a visual overlay, and forwards the files to the right component
|
|
8
|
+
is tedious boilerplate to repeat for every app.
|
|
9
|
+
|
|
10
|
+
top-app handles all of that automatically. It listens for file drag events on
|
|
11
|
+
the document, shows a configurable overlay while files are in flight, and fires
|
|
12
|
+
a single top:files-dropped event when the user releases the files. The drop
|
|
13
|
+
message can be a static string or a function evaluated at render time, so it
|
|
14
|
+
can reflect live application state.
|
|
15
|
+
|
|
16
|
+
This tutorial covers receiving dropped files via top:files-dropped; filtering
|
|
17
|
+
them by extension and surfacing a warning when none are supported; setting
|
|
18
|
+
dropMessage as a function that reads a live model counter so the hint text
|
|
19
|
+
updates as models are loaded; and showing a toast on success using the
|
|
20
|
+
top:notification event from the same handler.
|
|
21
|
+
|
|
22
|
+
By the end, you'll have an app with a drag-and-drop zone whose overlay message
|
|
23
|
+
adapts to how many models are already loaded, and that reports unsupported
|
|
24
|
+
files with a warning toast.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { html } from "lit";
|
|
28
|
+
import * as THREE from "three";
|
|
29
|
+
import * as OBC from "@thatopen/components";
|
|
30
|
+
import * as OBF from "@thatopen/components-front";
|
|
31
|
+
import * as FRAGS from "@thatopen/fragments";
|
|
32
|
+
import * as BUI from "@thatopen/ui";
|
|
33
|
+
import { PlatformClient, UIManager } from "@thatopen/services";
|
|
34
|
+
import type { App, AppReadyEvent } from "../../index";
|
|
35
|
+
|
|
36
|
+
const client = PlatformClient.fromPlatformContext();
|
|
37
|
+
const { components } = (await client.setup(
|
|
38
|
+
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
39
|
+
{ uuid: UIManager.uuid },
|
|
40
|
+
)) as { components: OBC.Components };
|
|
41
|
+
components.get(UIManager).init();
|
|
42
|
+
|
|
43
|
+
const app = document.createElement("top-app") as unknown as App;
|
|
44
|
+
|
|
45
|
+
app.setup = (waitUntil) => {
|
|
46
|
+
waitUntil(
|
|
47
|
+
(async () => {
|
|
48
|
+
const fragments = components.get(OBC.FragmentsManager);
|
|
49
|
+
const workerUrl = await FRAGS.FragmentsModels.getWorker();
|
|
50
|
+
fragments.init(await FRAGS.toClassicWorker(workerUrl), {
|
|
51
|
+
classicWorker: true,
|
|
52
|
+
});
|
|
53
|
+
})(),
|
|
54
|
+
"Fragments Core",
|
|
55
|
+
);
|
|
56
|
+
return { components, client };
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
app.elements = {
|
|
60
|
+
viewer: () =>
|
|
61
|
+
html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
app.base = "viewer";
|
|
65
|
+
app.layouts = {
|
|
66
|
+
main: {
|
|
67
|
+
label: "Main",
|
|
68
|
+
icon: "solar:home-bold",
|
|
69
|
+
template: `"_" 1fr / 1fr`,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
app.layout = "main";
|
|
73
|
+
|
|
74
|
+
// dropMessage as a function is evaluated at render time so it can read live state.
|
|
75
|
+
// Here it reads how many models are already loaded and adjusts the hint text.
|
|
76
|
+
let loadedCount = 0;
|
|
77
|
+
app.dropMessage = () =>
|
|
78
|
+
loadedCount === 0
|
|
79
|
+
? "Drop an IFC or FRAG file to load your first model"
|
|
80
|
+
: `Drop a file to add to the ${loadedCount} loaded model${loadedCount === 1 ? "" : "s"}`;
|
|
81
|
+
|
|
82
|
+
// top:files-dropped fires when the user drops files onto the window.
|
|
83
|
+
// e.detail.files is a File[]. Handle upload, load, or validation here.
|
|
84
|
+
app.addEventListener("top:files-dropped", (e) => {
|
|
85
|
+
const { files } = (e as CustomEvent<{ files: File[] }>).detail;
|
|
86
|
+
|
|
87
|
+
const supported = files.filter(
|
|
88
|
+
(f) => f.name.endsWith(".ifc") || f.name.endsWith(".frag"),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Dispatch top:notification to surface feedback without a reference to top-app.
|
|
92
|
+
if (!supported.length) {
|
|
93
|
+
app.dispatchEvent(
|
|
94
|
+
new CustomEvent("top:notification", {
|
|
95
|
+
bubbles: true,
|
|
96
|
+
composed: true,
|
|
97
|
+
detail: { message: "No supported files dropped", type: "warning" },
|
|
98
|
+
}),
|
|
99
|
+
);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
loadedCount += supported.length;
|
|
104
|
+
app.dispatchEvent(
|
|
105
|
+
new CustomEvent("top:notification", {
|
|
106
|
+
bubbles: true,
|
|
107
|
+
composed: true,
|
|
108
|
+
detail: {
|
|
109
|
+
message: `${supported.length} file${supported.length === 1 ? "" : "s"} received`,
|
|
110
|
+
type: "success",
|
|
111
|
+
description: supported.map((f) => f.name).join(", "),
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
app.addEventListener("top:app-ready", (e) => {
|
|
118
|
+
const { app: readyApp } = (e as AppReadyEvent).detail;
|
|
119
|
+
readyApp.showToast("App ready — try dropping an IFC or FRAG file", "info");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const container = document.getElementById("that-open-app") ?? document.body;
|
|
123
|
+
container.appendChild(app);
|
|
124
|
+
document.body.style.margin = "0";
|
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
/* MD
|
|
2
|
-
## Floating layout
|
|
3
|
-
---
|
|
4
|
-
Developers building BIM coordination tools often want the 3D model to fill the
|
|
5
|
-
entire window while control panels float above it — but standard grid layouts
|
|
6
|
-
give every area equal standing, shrinking the viewer into one cell and leaving
|
|
7
|
-
visible seams between it and the panels.
|
|
8
|
-
|
|
9
|
-
top-app supports a floating mode where one element is mounted as an absolute
|
|
10
|
-
background that fills the container edge-to-edge, and all other layout areas
|
|
11
|
-
render as a transparent overlay on top of it with independent pointer events.
|
|
12
|
-
|
|
13
|
-
This tutorial covers assigning the viewer as the absolute background of the app;
|
|
14
|
-
defining an overlay layout where a side panel floats above the viewer without
|
|
15
|
-
sharing grid space; and annotating why the base element is excluded from the
|
|
16
|
-
layout template.
|
|
17
|
-
|
|
18
|
-
By the end, you'll have a full-screen 3D viewer with a floating side panel
|
|
19
|
-
hovering above it, with the model filling the entire window and the panel
|
|
20
|
-
receiving its own pointer events.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import { html } from "lit";
|
|
24
|
-
import * as THREE from "three";
|
|
25
|
-
import * as OBC from "@thatopen/components";
|
|
26
|
-
import * as OBF from "@thatopen/components-front";
|
|
27
|
-
import * as FRAGS from "@thatopen/fragments";
|
|
28
|
-
import * as BUI from "@thatopen/ui";
|
|
29
|
-
import { PlatformClient, UIManager } from "@thatopen/services";
|
|
30
|
-
import type { App } from "../../index";
|
|
31
|
-
|
|
32
|
-
const client = PlatformClient.fromPlatformContext();
|
|
33
|
-
const { components } = (await client.setup(
|
|
34
|
-
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
35
|
-
{ uuid: UIManager.uuid },
|
|
36
|
-
)) as { components: OBC.Components };
|
|
37
|
-
components.get(UIManager).init();
|
|
38
|
-
|
|
39
|
-
const app = document.createElement("top-app") as unknown as App;
|
|
40
|
-
|
|
41
|
-
app.setup = (waitUntil) => {
|
|
42
|
-
waitUntil(
|
|
43
|
-
(async () => {
|
|
44
|
-
const fragments = components.get(OBC.FragmentsManager);
|
|
45
|
-
const workerUrl = await FRAGS.FragmentsModels.getWorker();
|
|
46
|
-
fragments.init(await FRAGS.toClassicWorker(workerUrl), {
|
|
47
|
-
classicWorker: true,
|
|
48
|
-
});
|
|
49
|
-
})(),
|
|
50
|
-
"Fragments Core",
|
|
51
|
-
);
|
|
52
|
-
return { components, client };
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
app.elements = {
|
|
56
|
-
// "viewer" is referenced by app.base — rendered as a position:absolute layer
|
|
57
|
-
// behind all layout content so it fills the container edge-to-edge.
|
|
58
|
-
viewer: () =>
|
|
59
|
-
html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
|
|
60
|
-
|
|
61
|
-
// Panels declared here appear in the floating content grid on top of the viewer.
|
|
62
|
-
// Their container has pointer-events: none; each child re-enables them individually.
|
|
63
|
-
panel: () => html`
|
|
64
|
-
<bim-panel>
|
|
65
|
-
<bim-panel-section label="Models" icon="solar:layers-bold">
|
|
66
|
-
<bim-label>Load models here</bim-label>
|
|
67
|
-
</bim-panel-section>
|
|
68
|
-
</bim-panel>
|
|
69
|
-
`,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// Setting app.base to an element key mounts that element as the absolute background.
|
|
73
|
-
// Layout templates then only list the floating overlay areas — not the base element.
|
|
74
|
-
// Without app.base, every area in the template is a peer grid cell (inline mode).
|
|
75
|
-
app.base = "viewer";
|
|
76
|
-
|
|
77
|
-
app.layouts = {
|
|
78
|
-
main: {
|
|
79
|
-
label: "Main",
|
|
80
|
-
icon: "solar:home-bold",
|
|
81
|
-
// Only overlay areas appear here. "viewer" is not listed because it is the base.
|
|
82
|
-
template: `"panel" 1fr / 22rem`,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
app.layout = "main";
|
|
87
|
-
|
|
88
|
-
const container = document.getElementById("that-open-app") ?? document.body;
|
|
89
|
-
container.appendChild(app);
|
|
90
|
-
document.body.style.margin = "0";
|
|
1
|
+
/* MD
|
|
2
|
+
## Floating layout
|
|
3
|
+
---
|
|
4
|
+
Developers building BIM coordination tools often want the 3D model to fill the
|
|
5
|
+
entire window while control panels float above it — but standard grid layouts
|
|
6
|
+
give every area equal standing, shrinking the viewer into one cell and leaving
|
|
7
|
+
visible seams between it and the panels.
|
|
8
|
+
|
|
9
|
+
top-app supports a floating mode where one element is mounted as an absolute
|
|
10
|
+
background that fills the container edge-to-edge, and all other layout areas
|
|
11
|
+
render as a transparent overlay on top of it with independent pointer events.
|
|
12
|
+
|
|
13
|
+
This tutorial covers assigning the viewer as the absolute background of the app;
|
|
14
|
+
defining an overlay layout where a side panel floats above the viewer without
|
|
15
|
+
sharing grid space; and annotating why the base element is excluded from the
|
|
16
|
+
layout template.
|
|
17
|
+
|
|
18
|
+
By the end, you'll have a full-screen 3D viewer with a floating side panel
|
|
19
|
+
hovering above it, with the model filling the entire window and the panel
|
|
20
|
+
receiving its own pointer events.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { html } from "lit";
|
|
24
|
+
import * as THREE from "three";
|
|
25
|
+
import * as OBC from "@thatopen/components";
|
|
26
|
+
import * as OBF from "@thatopen/components-front";
|
|
27
|
+
import * as FRAGS from "@thatopen/fragments";
|
|
28
|
+
import * as BUI from "@thatopen/ui";
|
|
29
|
+
import { PlatformClient, UIManager } from "@thatopen/services";
|
|
30
|
+
import type { App } from "../../index";
|
|
31
|
+
|
|
32
|
+
const client = PlatformClient.fromPlatformContext();
|
|
33
|
+
const { components } = (await client.setup(
|
|
34
|
+
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
35
|
+
{ uuid: UIManager.uuid },
|
|
36
|
+
)) as { components: OBC.Components };
|
|
37
|
+
components.get(UIManager).init();
|
|
38
|
+
|
|
39
|
+
const app = document.createElement("top-app") as unknown as App;
|
|
40
|
+
|
|
41
|
+
app.setup = (waitUntil) => {
|
|
42
|
+
waitUntil(
|
|
43
|
+
(async () => {
|
|
44
|
+
const fragments = components.get(OBC.FragmentsManager);
|
|
45
|
+
const workerUrl = await FRAGS.FragmentsModels.getWorker();
|
|
46
|
+
fragments.init(await FRAGS.toClassicWorker(workerUrl), {
|
|
47
|
+
classicWorker: true,
|
|
48
|
+
});
|
|
49
|
+
})(),
|
|
50
|
+
"Fragments Core",
|
|
51
|
+
);
|
|
52
|
+
return { components, client };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
app.elements = {
|
|
56
|
+
// "viewer" is referenced by app.base — rendered as a position:absolute layer
|
|
57
|
+
// behind all layout content so it fills the container edge-to-edge.
|
|
58
|
+
viewer: () =>
|
|
59
|
+
html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
|
|
60
|
+
|
|
61
|
+
// Panels declared here appear in the floating content grid on top of the viewer.
|
|
62
|
+
// Their container has pointer-events: none; each child re-enables them individually.
|
|
63
|
+
panel: () => html`
|
|
64
|
+
<bim-panel>
|
|
65
|
+
<bim-panel-section label="Models" icon="solar:layers-bold">
|
|
66
|
+
<bim-label>Load models here</bim-label>
|
|
67
|
+
</bim-panel-section>
|
|
68
|
+
</bim-panel>
|
|
69
|
+
`,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Setting app.base to an element key mounts that element as the absolute background.
|
|
73
|
+
// Layout templates then only list the floating overlay areas — not the base element.
|
|
74
|
+
// Without app.base, every area in the template is a peer grid cell (inline mode).
|
|
75
|
+
app.base = "viewer";
|
|
76
|
+
|
|
77
|
+
app.layouts = {
|
|
78
|
+
main: {
|
|
79
|
+
label: "Main",
|
|
80
|
+
icon: "solar:home-bold",
|
|
81
|
+
// Only overlay areas appear here. "viewer" is not listed because it is the base.
|
|
82
|
+
template: `"panel" 1fr / 22rem`,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
app.layout = "main";
|
|
87
|
+
|
|
88
|
+
const container = document.getElementById("that-open-app") ?? document.body;
|
|
89
|
+
container.appendChild(app);
|
|
90
|
+
document.body.style.margin = "0";
|