@selvajs/ui 6.6.0-beta.13 → 6.6.0-beta.15
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/components/compute/AppLayout.svelte +5 -2
- package/dist/components/preview/inputs/SegmentedInput.svelte +1 -1
- package/dist/components/preview/inputs/TileInput.svelte +2 -1
- package/dist/components/primitives/toggle/toggle.svelte +4 -1
- package/dist/components/primitives/toggle/toggle.svelte.d.ts +3 -0
- package/dist/components/primitives/toggle-group/toggle-group-item.svelte +1 -1
- package/dist/components/viewer/Viewer.svelte +22 -7
- package/dist/components/viewer/Viewer.svelte.d.ts +3 -1
- package/dist/i18n/messages.d.ts +1 -0
- package/dist/i18n/messages.js +2 -0
- package/package.json +9 -9
- package/src/lib/components/compute/AppLayout.svelte +5 -2
- package/src/lib/components/preview/inputs/SegmentedInput.svelte +1 -1
- package/src/lib/components/preview/inputs/TileInput.svelte +2 -1
- package/src/lib/components/primitives/toggle/toggle.svelte +4 -1
- package/src/lib/components/primitives/toggle-group/toggle-group-item.svelte +1 -1
- package/src/lib/components/viewer/Viewer.svelte +22 -7
- package/src/lib/i18n/messages.ts +3 -0
|
@@ -347,7 +347,8 @@
|
|
|
347
347
|
{onViewerReady}
|
|
348
348
|
viewerConfig={{
|
|
349
349
|
...viewerConfig,
|
|
350
|
-
backgroundColor: schema?.viewerOptions?.backgroundColor,
|
|
350
|
+
backgroundColor: schema?.viewerOptions?.backgroundColor ?? viewerConfig.backgroundColor,
|
|
351
|
+
look: schema?.viewerOptions?.look ?? viewerConfig.look,
|
|
351
352
|
showSceneManager: false
|
|
352
353
|
}}
|
|
353
354
|
/>
|
|
@@ -490,7 +491,9 @@
|
|
|
490
491
|
{onViewerReady}
|
|
491
492
|
viewerConfig={{
|
|
492
493
|
...viewerConfig,
|
|
493
|
-
backgroundColor:
|
|
494
|
+
backgroundColor:
|
|
495
|
+
schema?.viewerOptions?.backgroundColor ?? viewerConfig.backgroundColor,
|
|
496
|
+
look: schema?.viewerOptions?.look ?? viewerConfig.look
|
|
494
497
|
}}
|
|
495
498
|
/>
|
|
496
499
|
</Resizable.Pane>
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
bind:this={tiles[index]}
|
|
46
46
|
type="button"
|
|
47
47
|
role="radio"
|
|
48
|
+
title={option.name}
|
|
48
49
|
aria-checked={selected}
|
|
49
50
|
tabindex={index === focusIndex ? 0 : -1}
|
|
50
51
|
{disabled}
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
<span class="text-lg font-medium" aria-hidden="true">{option.name.charAt(0)}</span>
|
|
66
67
|
{/if}
|
|
67
68
|
</span>
|
|
68
|
-
<span class="px-0.5 text-xs leading-tight
|
|
69
|
+
<span class="px-0.5 text-xs leading-tight line-clamp-2" class:font-medium={selected}>
|
|
69
70
|
{option.name}
|
|
70
71
|
</span>
|
|
71
72
|
</button>
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
8
|
default: 'bg-transparent',
|
|
9
|
-
outline: 'border-input hover:bg-muted border bg-transparent'
|
|
9
|
+
outline: 'border-input hover:bg-muted border bg-transparent',
|
|
10
|
+
// Filled accent for the active item; a bare bg-muted is too faint on a form.
|
|
11
|
+
accent:
|
|
12
|
+
'border-input hover:bg-muted border bg-transparent data-[state=on]:bg-primary/15 data-[state=on]:ring-1 data-[state=on]:ring-primary data-[state=on]:ring-inset'
|
|
10
13
|
},
|
|
11
14
|
size: {
|
|
12
15
|
default:
|
|
@@ -3,6 +3,7 @@ export declare const toggleVariants: import("tailwind-variants").TVReturnType<{
|
|
|
3
3
|
variant: {
|
|
4
4
|
default: "bg-transparent";
|
|
5
5
|
outline: "border-input hover:bg-muted border bg-transparent";
|
|
6
|
+
accent: "border-input hover:bg-muted border bg-transparent data-[state=on]:bg-primary/15 data-[state=on]:ring-1 data-[state=on]:ring-primary data-[state=on]:ring-inset";
|
|
6
7
|
};
|
|
7
8
|
size: {
|
|
8
9
|
default: "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2";
|
|
@@ -14,6 +15,7 @@ export declare const toggleVariants: import("tailwind-variants").TVReturnType<{
|
|
|
14
15
|
variant: {
|
|
15
16
|
default: "bg-transparent";
|
|
16
17
|
outline: "border-input hover:bg-muted border bg-transparent";
|
|
18
|
+
accent: "border-input hover:bg-muted border bg-transparent data-[state=on]:bg-primary/15 data-[state=on]:ring-1 data-[state=on]:ring-primary data-[state=on]:ring-inset";
|
|
17
19
|
};
|
|
18
20
|
size: {
|
|
19
21
|
default: "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2";
|
|
@@ -25,6 +27,7 @@ export declare const toggleVariants: import("tailwind-variants").TVReturnType<{
|
|
|
25
27
|
variant: {
|
|
26
28
|
default: "bg-transparent";
|
|
27
29
|
outline: "border-input hover:bg-muted border bg-transparent";
|
|
30
|
+
accent: "border-input hover:bg-muted border bg-transparent data-[state=on]:bg-primary/15 data-[state=on]:ring-1 data-[state=on]:ring-primary data-[state=on]:ring-inset";
|
|
28
31
|
};
|
|
29
32
|
size: {
|
|
30
33
|
default: "h-8 min-w-8 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2";
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
data-size={ctx.size || size}
|
|
24
24
|
data-spacing={ctx.spacing}
|
|
25
25
|
class={cn(
|
|
26
|
-
'group-data-[spacing=0]/toggle-group:px-2 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 shrink-0 group-data-[spacing=0]/toggle-group:rounded-none focus:z-10 focus-visible:z-10 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t',
|
|
26
|
+
'group-data-[spacing=0]/toggle-group:px-2 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 shrink-0 group-data-[spacing=0]/toggle-group:rounded-none focus:z-10 focus-visible:z-10 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=accent]:border-l-0 group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=accent]:border-t-0 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=accent]:first:border-l group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=accent]:first:border-t group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t',
|
|
27
27
|
toggleVariants({
|
|
28
28
|
variant: ctx.variant || variant,
|
|
29
29
|
size: ctx.size || size
|
|
@@ -52,6 +52,8 @@
|
|
|
52
52
|
showDisplayMenu?: boolean;
|
|
53
53
|
enableMeshClick?: boolean;
|
|
54
54
|
backgroundColor?: string;
|
|
55
|
+
/** The look to open in. Default `technical`. */
|
|
56
|
+
look?: Look;
|
|
55
57
|
/** Initial state of the edge overlay and its display-menu checkmark. Default false. */
|
|
56
58
|
showEdges?: boolean;
|
|
57
59
|
}
|
|
@@ -91,6 +93,7 @@
|
|
|
91
93
|
showDisplayMenu: true,
|
|
92
94
|
enableMeshClick: true,
|
|
93
95
|
backgroundColor: '#E6E6E6',
|
|
96
|
+
look: 'technical',
|
|
94
97
|
showEdges: false
|
|
95
98
|
};
|
|
96
99
|
|
|
@@ -124,7 +127,8 @@
|
|
|
124
127
|
let clearEdges: ThreeViewer['clearEdges'] | null = null;
|
|
125
128
|
let invalidate: (() => void) | null = null;
|
|
126
129
|
let captureImage: ThreeViewer['captureImage'] | null = null;
|
|
127
|
-
let setLook:
|
|
130
|
+
let setLook: ThreeViewer['setLook'] | null = null;
|
|
131
|
+
let syncEmissiveLights: (() => void) | null = null;
|
|
128
132
|
let updateGridScale: (() => void) | null = null;
|
|
129
133
|
let updateShadowBounds: (() => void) | null = null;
|
|
130
134
|
let fitToView: (() => void) | null = null;
|
|
@@ -145,9 +149,16 @@
|
|
|
145
149
|
let projection: CameraProjection = $state('perspective');
|
|
146
150
|
let measureActive = $state(false);
|
|
147
151
|
let gridVisible = $state(false);
|
|
148
|
-
|
|
152
|
+
// A saved schema can name a look this build doesn't have, and an unknown look throws on mount.
|
|
153
|
+
const openingLook = untrack(() => {
|
|
154
|
+
const look = viewerConfig.look;
|
|
155
|
+
return look && LOOKS.includes(look) ? look : defaultViewerConfig.look;
|
|
156
|
+
});
|
|
157
|
+
const opensAsLineDrawing = LOOK_PRESETS[openingLook].requiresEdges === true;
|
|
158
|
+
const configuredEdges = untrack(() => viewerConfig.showEdges) ?? defaultViewerConfig.showEdges;
|
|
159
|
+
let renderStyle: Look = $state(openingLook);
|
|
149
160
|
// Seeded once, then owned by the menu toggle.
|
|
150
|
-
let edgesVisible = $state(
|
|
161
|
+
let edgesVisible = $state(opensAsLineDrawing || configuredEdges);
|
|
151
162
|
let selectedMeshMetadata: Record<string, any> | null = $state(null);
|
|
152
163
|
let selectedMeshName: string | null = $state(null);
|
|
153
164
|
|
|
@@ -160,7 +171,8 @@
|
|
|
160
171
|
arctic: t.lookArctic,
|
|
161
172
|
xray: t.lookXray,
|
|
162
173
|
lineart: t.lookLineart,
|
|
163
|
-
wireframe: t.lookWireframe
|
|
174
|
+
wireframe: t.lookWireframe,
|
|
175
|
+
night: t.lookNight
|
|
164
176
|
});
|
|
165
177
|
const styleOptions = $derived<{ look: Look; label: string }[]>(
|
|
166
178
|
LOOKS.map((look) => ({
|
|
@@ -234,6 +246,7 @@
|
|
|
234
246
|
invalidate = init.invalidate;
|
|
235
247
|
captureImage = init.captureImage;
|
|
236
248
|
setLook = init.setLook;
|
|
249
|
+
syncEmissiveLights = init.syncEmissiveLights;
|
|
237
250
|
updateGridScale = init.updateGridScale;
|
|
238
251
|
updateShadowBounds = init.updateShadowBounds;
|
|
239
252
|
fitToView = init.fitToView;
|
|
@@ -279,7 +292,7 @@
|
|
|
279
292
|
|
|
280
293
|
// Edges the lineart look switched on, so leaving it can put the user's own choice back rather
|
|
281
294
|
// than stranding them with overlays they never asked for.
|
|
282
|
-
let edgesBeforeLineDrawing: boolean | null = null;
|
|
295
|
+
let edgesBeforeLineDrawing: boolean | null = opensAsLineDrawing ? configuredEdges : null;
|
|
283
296
|
|
|
284
297
|
function setRenderStyle(look: Look) {
|
|
285
298
|
if (!setLook || look === renderStyle) return;
|
|
@@ -366,7 +379,8 @@
|
|
|
366
379
|
untrack(() => {
|
|
367
380
|
// The new meshes carry the materials the parser built, so a look that overrides them
|
|
368
381
|
// (arctic, x-ray) has to be re-applied or the solve silently reverts to shaded.
|
|
369
|
-
|
|
382
|
+
// Emissive lights wait for `applyTo` below, or a hidden lamp would count as lit.
|
|
383
|
+
setLook?.(renderStyle, { deferEmissiveLights: true });
|
|
370
384
|
// updateScene discarded the previous solve's overlays along with its content.
|
|
371
385
|
if (edgesVisible) applyEdges?.(scene!, edgeOverrides());
|
|
372
386
|
// Rescale the grid so cells and fade match the new content's extent.
|
|
@@ -377,6 +391,7 @@
|
|
|
377
391
|
// The rebuild un-hid everything; the outliner keys hidden state on Grasshopper
|
|
378
392
|
// identity, not on the instances just discarded, so it can re-hide it.
|
|
379
393
|
outliner?.applyTo();
|
|
394
|
+
syncEmissiveLights?.();
|
|
380
395
|
sceneVersion++;
|
|
381
396
|
// Repaint now rather than on the render loop's safety interval.
|
|
382
397
|
invalidate?.();
|
|
@@ -680,7 +695,7 @@
|
|
|
680
695
|
<SceneManager
|
|
681
696
|
{outliner}
|
|
682
697
|
{sceneVersion}
|
|
683
|
-
onVisibilityChange={() =>
|
|
698
|
+
onVisibilityChange={() => syncEmissiveLights?.()}
|
|
684
699
|
onHover={(entry) => setHover?.(entry?.object ?? null, entry?.memberIndex ?? null)}
|
|
685
700
|
/>
|
|
686
701
|
</Resizable.Pane>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ThreeViewer } from '@selvajs/visualization/render';
|
|
1
|
+
import { type Look, type ThreeViewer } from '@selvajs/visualization/render';
|
|
2
2
|
import type { Locale } from '../../i18n/messages';
|
|
3
3
|
export interface ViewerConfig {
|
|
4
4
|
showScreenshotButton?: boolean;
|
|
@@ -9,6 +9,8 @@ export interface ViewerConfig {
|
|
|
9
9
|
showDisplayMenu?: boolean;
|
|
10
10
|
enableMeshClick?: boolean;
|
|
11
11
|
backgroundColor?: string;
|
|
12
|
+
/** The look to open in. Default `technical`. */
|
|
13
|
+
look?: Look;
|
|
12
14
|
/** Initial state of the edge overlay and its display-menu checkmark. Default false. */
|
|
13
15
|
showEdges?: boolean;
|
|
14
16
|
}
|
package/dist/i18n/messages.d.ts
CHANGED
package/dist/i18n/messages.js
CHANGED
|
@@ -32,6 +32,7 @@ const en = {
|
|
|
32
32
|
lookTechnical: 'Technical',
|
|
33
33
|
lookStudio: 'Studio',
|
|
34
34
|
lookShowcase: 'Showcase',
|
|
35
|
+
lookNight: 'Night',
|
|
35
36
|
lookArctic: 'Arctic',
|
|
36
37
|
lookXray: 'X-Ray',
|
|
37
38
|
lookLineart: 'Line Art',
|
|
@@ -206,6 +207,7 @@ const de = {
|
|
|
206
207
|
lookTechnical: 'Technisch',
|
|
207
208
|
lookStudio: 'Studio',
|
|
208
209
|
lookShowcase: 'Präsentation',
|
|
210
|
+
lookNight: 'Nacht',
|
|
209
211
|
lookArctic: 'Arktis',
|
|
210
212
|
lookXray: 'Röntgen',
|
|
211
213
|
lookLineart: 'Strichzeichnung',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@selvajs/ui",
|
|
3
|
-
"version": "6.6.0-beta.
|
|
3
|
+
"version": "6.6.0-beta.15",
|
|
4
4
|
"description": "Shared UI components and utilities for Selva applications",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "VektorNode",
|
|
@@ -63,10 +63,10 @@
|
|
|
63
63
|
"svelte": "^5",
|
|
64
64
|
"tailwind-variants": "^3.3.1",
|
|
65
65
|
"three": "^0.186.1",
|
|
66
|
-
"@selvajs/compute": "^5.0.0-beta.
|
|
67
|
-
"@selvajs/
|
|
68
|
-
"@selvajs/
|
|
69
|
-
"@selvajs/solve": "^2.0.0-beta.
|
|
66
|
+
"@selvajs/compute": "^5.0.0-beta.9",
|
|
67
|
+
"@selvajs/visualization": "^1.6.0-beta.9",
|
|
68
|
+
"@selvajs/schemas": "^5.3.0-beta.2",
|
|
69
|
+
"@selvajs/solve": "^2.0.0-beta.12"
|
|
70
70
|
},
|
|
71
71
|
"peerDependenciesMeta": {
|
|
72
72
|
"three": {
|
|
@@ -94,11 +94,11 @@
|
|
|
94
94
|
"svelte": "5.57.2",
|
|
95
95
|
"tailwind-variants": "^3.3.1",
|
|
96
96
|
"vitest": "^5.0.5",
|
|
97
|
-
"@selvajs/compute": "5.0.0-beta.
|
|
97
|
+
"@selvajs/compute": "5.0.0-beta.9",
|
|
98
|
+
"@selvajs/visualization": "1.6.0-beta.9",
|
|
99
|
+
"@selvajs/solve": "2.0.0-beta.12",
|
|
98
100
|
"@selvajs/config": "0.0.4",
|
|
99
|
-
"@selvajs/schemas": "5.3.0-beta.
|
|
100
|
-
"@selvajs/visualization": "1.6.0-beta.7",
|
|
101
|
-
"@selvajs/solve": "2.0.0-beta.10"
|
|
101
|
+
"@selvajs/schemas": "5.3.0-beta.2"
|
|
102
102
|
},
|
|
103
103
|
"scripts": {
|
|
104
104
|
"predev": "node ../../scripts/sync-shared-assets.js",
|
|
@@ -347,7 +347,8 @@
|
|
|
347
347
|
{onViewerReady}
|
|
348
348
|
viewerConfig={{
|
|
349
349
|
...viewerConfig,
|
|
350
|
-
backgroundColor: schema?.viewerOptions?.backgroundColor,
|
|
350
|
+
backgroundColor: schema?.viewerOptions?.backgroundColor ?? viewerConfig.backgroundColor,
|
|
351
|
+
look: schema?.viewerOptions?.look ?? viewerConfig.look,
|
|
351
352
|
showSceneManager: false
|
|
352
353
|
}}
|
|
353
354
|
/>
|
|
@@ -490,7 +491,9 @@
|
|
|
490
491
|
{onViewerReady}
|
|
491
492
|
viewerConfig={{
|
|
492
493
|
...viewerConfig,
|
|
493
|
-
backgroundColor:
|
|
494
|
+
backgroundColor:
|
|
495
|
+
schema?.viewerOptions?.backgroundColor ?? viewerConfig.backgroundColor,
|
|
496
|
+
look: schema?.viewerOptions?.look ?? viewerConfig.look
|
|
494
497
|
}}
|
|
495
498
|
/>
|
|
496
499
|
</Resizable.Pane>
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
bind:this={tiles[index]}
|
|
46
46
|
type="button"
|
|
47
47
|
role="radio"
|
|
48
|
+
title={option.name}
|
|
48
49
|
aria-checked={selected}
|
|
49
50
|
tabindex={index === focusIndex ? 0 : -1}
|
|
50
51
|
{disabled}
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
<span class="text-lg font-medium" aria-hidden="true">{option.name.charAt(0)}</span>
|
|
66
67
|
{/if}
|
|
67
68
|
</span>
|
|
68
|
-
<span class="px-0.5 text-xs leading-tight
|
|
69
|
+
<span class="px-0.5 text-xs leading-tight line-clamp-2" class:font-medium={selected}>
|
|
69
70
|
{option.name}
|
|
70
71
|
</span>
|
|
71
72
|
</button>
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
variants: {
|
|
7
7
|
variant: {
|
|
8
8
|
default: 'bg-transparent',
|
|
9
|
-
outline: 'border-input hover:bg-muted border bg-transparent'
|
|
9
|
+
outline: 'border-input hover:bg-muted border bg-transparent',
|
|
10
|
+
// Filled accent for the active item; a bare bg-muted is too faint on a form.
|
|
11
|
+
accent:
|
|
12
|
+
'border-input hover:bg-muted border bg-transparent data-[state=on]:bg-primary/15 data-[state=on]:ring-1 data-[state=on]:ring-primary data-[state=on]:ring-inset'
|
|
10
13
|
},
|
|
11
14
|
size: {
|
|
12
15
|
default:
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
data-size={ctx.size || size}
|
|
24
24
|
data-spacing={ctx.spacing}
|
|
25
25
|
class={cn(
|
|
26
|
-
'group-data-[spacing=0]/toggle-group:px-2 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 shrink-0 group-data-[spacing=0]/toggle-group:rounded-none focus:z-10 focus-visible:z-10 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t',
|
|
26
|
+
'group-data-[spacing=0]/toggle-group:px-2 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-end]:pr-1.5 group-data-[spacing=0]/toggle-group:has-data-[icon=inline-start]:pl-1.5 shrink-0 group-data-[spacing=0]/toggle-group:rounded-none focus:z-10 focus-visible:z-10 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:first:rounded-l-lg group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:first:rounded-t-lg group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:last:rounded-r-lg group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:last:rounded-b-lg group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=accent]:border-l-0 group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=accent]:border-t-0 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=accent]:first:border-l group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=accent]:first:border-t group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-l-0 group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:border-t-0 group-data-[orientation=horizontal]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-l group-data-[orientation=vertical]/toggle-group:data-[spacing=0]:data-[variant=outline]:first:border-t',
|
|
27
27
|
toggleVariants({
|
|
28
28
|
variant: ctx.variant || variant,
|
|
29
29
|
size: ctx.size || size
|
|
@@ -52,6 +52,8 @@
|
|
|
52
52
|
showDisplayMenu?: boolean;
|
|
53
53
|
enableMeshClick?: boolean;
|
|
54
54
|
backgroundColor?: string;
|
|
55
|
+
/** The look to open in. Default `technical`. */
|
|
56
|
+
look?: Look;
|
|
55
57
|
/** Initial state of the edge overlay and its display-menu checkmark. Default false. */
|
|
56
58
|
showEdges?: boolean;
|
|
57
59
|
}
|
|
@@ -91,6 +93,7 @@
|
|
|
91
93
|
showDisplayMenu: true,
|
|
92
94
|
enableMeshClick: true,
|
|
93
95
|
backgroundColor: '#E6E6E6',
|
|
96
|
+
look: 'technical',
|
|
94
97
|
showEdges: false
|
|
95
98
|
};
|
|
96
99
|
|
|
@@ -124,7 +127,8 @@
|
|
|
124
127
|
let clearEdges: ThreeViewer['clearEdges'] | null = null;
|
|
125
128
|
let invalidate: (() => void) | null = null;
|
|
126
129
|
let captureImage: ThreeViewer['captureImage'] | null = null;
|
|
127
|
-
let setLook:
|
|
130
|
+
let setLook: ThreeViewer['setLook'] | null = null;
|
|
131
|
+
let syncEmissiveLights: (() => void) | null = null;
|
|
128
132
|
let updateGridScale: (() => void) | null = null;
|
|
129
133
|
let updateShadowBounds: (() => void) | null = null;
|
|
130
134
|
let fitToView: (() => void) | null = null;
|
|
@@ -145,9 +149,16 @@
|
|
|
145
149
|
let projection: CameraProjection = $state('perspective');
|
|
146
150
|
let measureActive = $state(false);
|
|
147
151
|
let gridVisible = $state(false);
|
|
148
|
-
|
|
152
|
+
// A saved schema can name a look this build doesn't have, and an unknown look throws on mount.
|
|
153
|
+
const openingLook = untrack(() => {
|
|
154
|
+
const look = viewerConfig.look;
|
|
155
|
+
return look && LOOKS.includes(look) ? look : defaultViewerConfig.look;
|
|
156
|
+
});
|
|
157
|
+
const opensAsLineDrawing = LOOK_PRESETS[openingLook].requiresEdges === true;
|
|
158
|
+
const configuredEdges = untrack(() => viewerConfig.showEdges) ?? defaultViewerConfig.showEdges;
|
|
159
|
+
let renderStyle: Look = $state(openingLook);
|
|
149
160
|
// Seeded once, then owned by the menu toggle.
|
|
150
|
-
let edgesVisible = $state(
|
|
161
|
+
let edgesVisible = $state(opensAsLineDrawing || configuredEdges);
|
|
151
162
|
let selectedMeshMetadata: Record<string, any> | null = $state(null);
|
|
152
163
|
let selectedMeshName: string | null = $state(null);
|
|
153
164
|
|
|
@@ -160,7 +171,8 @@
|
|
|
160
171
|
arctic: t.lookArctic,
|
|
161
172
|
xray: t.lookXray,
|
|
162
173
|
lineart: t.lookLineart,
|
|
163
|
-
wireframe: t.lookWireframe
|
|
174
|
+
wireframe: t.lookWireframe,
|
|
175
|
+
night: t.lookNight
|
|
164
176
|
});
|
|
165
177
|
const styleOptions = $derived<{ look: Look; label: string }[]>(
|
|
166
178
|
LOOKS.map((look) => ({
|
|
@@ -234,6 +246,7 @@
|
|
|
234
246
|
invalidate = init.invalidate;
|
|
235
247
|
captureImage = init.captureImage;
|
|
236
248
|
setLook = init.setLook;
|
|
249
|
+
syncEmissiveLights = init.syncEmissiveLights;
|
|
237
250
|
updateGridScale = init.updateGridScale;
|
|
238
251
|
updateShadowBounds = init.updateShadowBounds;
|
|
239
252
|
fitToView = init.fitToView;
|
|
@@ -279,7 +292,7 @@
|
|
|
279
292
|
|
|
280
293
|
// Edges the lineart look switched on, so leaving it can put the user's own choice back rather
|
|
281
294
|
// than stranding them with overlays they never asked for.
|
|
282
|
-
let edgesBeforeLineDrawing: boolean | null = null;
|
|
295
|
+
let edgesBeforeLineDrawing: boolean | null = opensAsLineDrawing ? configuredEdges : null;
|
|
283
296
|
|
|
284
297
|
function setRenderStyle(look: Look) {
|
|
285
298
|
if (!setLook || look === renderStyle) return;
|
|
@@ -366,7 +379,8 @@
|
|
|
366
379
|
untrack(() => {
|
|
367
380
|
// The new meshes carry the materials the parser built, so a look that overrides them
|
|
368
381
|
// (arctic, x-ray) has to be re-applied or the solve silently reverts to shaded.
|
|
369
|
-
|
|
382
|
+
// Emissive lights wait for `applyTo` below, or a hidden lamp would count as lit.
|
|
383
|
+
setLook?.(renderStyle, { deferEmissiveLights: true });
|
|
370
384
|
// updateScene discarded the previous solve's overlays along with its content.
|
|
371
385
|
if (edgesVisible) applyEdges?.(scene!, edgeOverrides());
|
|
372
386
|
// Rescale the grid so cells and fade match the new content's extent.
|
|
@@ -377,6 +391,7 @@
|
|
|
377
391
|
// The rebuild un-hid everything; the outliner keys hidden state on Grasshopper
|
|
378
392
|
// identity, not on the instances just discarded, so it can re-hide it.
|
|
379
393
|
outliner?.applyTo();
|
|
394
|
+
syncEmissiveLights?.();
|
|
380
395
|
sceneVersion++;
|
|
381
396
|
// Repaint now rather than on the render loop's safety interval.
|
|
382
397
|
invalidate?.();
|
|
@@ -680,7 +695,7 @@
|
|
|
680
695
|
<SceneManager
|
|
681
696
|
{outliner}
|
|
682
697
|
{sceneVersion}
|
|
683
|
-
onVisibilityChange={() =>
|
|
698
|
+
onVisibilityChange={() => syncEmissiveLights?.()}
|
|
684
699
|
onHover={(entry) => setHover?.(entry?.object ?? null, entry?.memberIndex ?? null)}
|
|
685
700
|
/>
|
|
686
701
|
</Resizable.Pane>
|
package/src/lib/i18n/messages.ts
CHANGED
|
@@ -40,6 +40,7 @@ export interface ViewerMessages {
|
|
|
40
40
|
lookTechnical: string;
|
|
41
41
|
lookStudio: string;
|
|
42
42
|
lookShowcase: string;
|
|
43
|
+
lookNight: string;
|
|
43
44
|
lookArctic: string;
|
|
44
45
|
lookXray: string;
|
|
45
46
|
lookLineart: string;
|
|
@@ -268,6 +269,7 @@ const en: ViewerMessages = {
|
|
|
268
269
|
lookTechnical: 'Technical',
|
|
269
270
|
lookStudio: 'Studio',
|
|
270
271
|
lookShowcase: 'Showcase',
|
|
272
|
+
lookNight: 'Night',
|
|
271
273
|
lookArctic: 'Arctic',
|
|
272
274
|
lookXray: 'X-Ray',
|
|
273
275
|
lookLineart: 'Line Art',
|
|
@@ -461,6 +463,7 @@ const de: ViewerMessages = {
|
|
|
461
463
|
lookTechnical: 'Technisch',
|
|
462
464
|
lookStudio: 'Studio',
|
|
463
465
|
lookShowcase: 'Präsentation',
|
|
466
|
+
lookNight: 'Nacht',
|
|
464
467
|
lookArctic: 'Arktis',
|
|
465
468
|
lookXray: 'Röntgen',
|
|
466
469
|
lookLineart: 'Strichzeichnung',
|