@imagineio/configurator-sdk 0.1.0-beta.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/LICENSE.md +294 -0
- package/README.md +103 -0
- package/dist/00a41227ff.js +1 -0
- package/dist/00ab3dcbb5.js +1 -0
- package/dist/01a664fa9f.css +51 -0
- package/dist/04746bff9a.js +1 -0
- package/dist/04931f795e.js +1 -0
- package/dist/05973a4da2.js +3 -0
- package/dist/061b81ad81.js +1 -0
- package/dist/066fc9aa40.js +1 -0
- package/dist/09c4973968.js +1 -0
- package/dist/0a35b2c5f4.js +1 -0
- package/dist/0af28430ab.js +1 -0
- package/dist/0e2dedae0d.js +1 -0
- package/dist/0f7c8345a8.js +1 -0
- package/dist/12b8165d6d.js +1 -0
- package/dist/1458417bdb.js +1 -0
- package/dist/14c83bc57a.js +1 -0
- package/dist/15d6bec3b5.css +150 -0
- package/dist/16a399703e.js +1 -0
- package/dist/17876f4322.css +114 -0
- package/dist/1870fc037b.js +1 -0
- package/dist/1a2629800a.css +196 -0
- package/dist/1e243363f6.js +1 -0
- package/dist/1fac915f8b.js +1 -0
- package/dist/1fff100656.js +1 -0
- package/dist/205827c5c8.js +1 -0
- package/dist/20b0104576.js +1 -0
- package/dist/2239b22616.js +1 -0
- package/dist/22bd38ddcf.js +1 -0
- package/dist/239b619005.css +1849 -0
- package/dist/23dc0ccf32.js +1 -0
- package/dist/26155bf68c.js +1 -0
- package/dist/2774152dd2.js +1 -0
- package/dist/27fee7007f.js +1 -0
- package/dist/281cf952fa.js +1 -0
- package/dist/28a9d58274.js +1 -0
- package/dist/28d887bf8a.js +1 -0
- package/dist/28df2aa12f.js +1 -0
- package/dist/297e653adf.js +1 -0
- package/dist/2990ba64d6.js +1 -0
- package/dist/2b6aa27f6d.js +1 -0
- package/dist/2c7c1bcef1.js +1 -0
- package/dist/2cab5c5c23.js +1 -0
- package/dist/2cafe3274b.js +1 -0
- package/dist/2e366d7386.js +1 -0
- package/dist/2f8cc8b292.js +1 -0
- package/dist/30be653f00.css +110 -0
- package/dist/31ea036f5c.js +1 -0
- package/dist/32861ea2b0.js +1 -0
- package/dist/33fa2c8ca2.js +1 -0
- package/dist/35d8449ed8.js +1 -0
- package/dist/3656ffa1b8.js +1 -0
- package/dist/367a479d3a.js +1 -0
- package/dist/371ed78aa2.js +1 -0
- package/dist/37596ace72.js +1 -0
- package/dist/37addc7fb3.js +1 -0
- package/dist/388cadacbd.js +1 -0
- package/dist/39a62ef7b8.js +1 -0
- package/dist/3bbcee0334.js +1 -0
- package/dist/3c916f744f.js +1 -0
- package/dist/3f37665dd1.js +1 -0
- package/dist/3fb3ab6757.js +1 -0
- package/dist/40d6aeb28c.js +1 -0
- package/dist/41ed5985ad.js +1 -0
- package/dist/431a2d8618.js +1 -0
- package/dist/44a229099f.js +1 -0
- package/dist/4741e5d07d.css +263 -0
- package/dist/4910c07ca8.css +411 -0
- package/dist/4a99ddb3fd.js +1 -0
- package/dist/4aa671f9f6.js +1 -0
- package/dist/4b8958aa4c.js +1 -0
- package/dist/4ba4f544b9.js +1 -0
- package/dist/4c24338793.js +1 -0
- package/dist/4d7a0d1897.js +1 -0
- package/dist/4e1db1e3b0.js +1 -0
- package/dist/4e7d0a0d4a.js +1 -0
- package/dist/51b23203e5.css +1447 -0
- package/dist/52436e0169.js +1 -0
- package/dist/54413c1eae.js +1 -0
- package/dist/54f0fcf38b.js +1 -0
- package/dist/55ab45ada4.css +370 -0
- package/dist/561dc3f1ab.js +1 -0
- package/dist/58e6419ba8.js +1 -0
- package/dist/5c9fd9201c.js +1 -0
- package/dist/5d05e8982e.js +1 -0
- package/dist/5d5e8a9c58.js +3 -0
- package/dist/5e4f2349ff.js +1 -0
- package/dist/609e5e5d28.js +1 -0
- package/dist/60d697292c.js +1 -0
- package/dist/61e0c0c9b5.js +1 -0
- package/dist/631a9f7fac.js +1 -0
- package/dist/64e9020b49.js +1 -0
- package/dist/66c461dc2c.js +1 -0
- package/dist/672404d987.js +1 -0
- package/dist/67f6338a4a.js +1 -0
- package/dist/6855e6a3b1.js +1 -0
- package/dist/6b0a81e4f8.js +1 -0
- package/dist/6ba86aa3b8.js +1 -0
- package/dist/6bff84d27e.js +1 -0
- package/dist/6c0a2572dd.js +1 -0
- package/dist/6d238282c1.js +1 -0
- package/dist/6e2595aa36.js +1 -0
- package/dist/6f9ae59d6c.js +1 -0
- package/dist/70dd811d74.js +1 -0
- package/dist/710c1ab641.js +1 -0
- package/dist/7206ce49c6.js +1 -0
- package/dist/7281d77ed9.js +1 -0
- package/dist/73f7d65985.js +1 -0
- package/dist/776277593f.js +1 -0
- package/dist/79a397bb92.js +1 -0
- package/dist/7a748aae59.js +1 -0
- package/dist/7bfb0ecfbb.css +572 -0
- package/dist/7bfcd0a517.js +1 -0
- package/dist/7d9ddaeb47.js +1 -0
- package/dist/7f833bc5af.js +1 -0
- package/dist/811b403d43.js +1 -0
- package/dist/817d930a49.js +1 -0
- package/dist/81802759ca.js +1 -0
- package/dist/81eb433604.js +1 -0
- package/dist/82a8a4bc35.js +1 -0
- package/dist/85af90fade.js +1 -0
- package/dist/872c4302e0.js +1 -0
- package/dist/87bb469216.js +1 -0
- package/dist/87dcc12b65.js +1 -0
- package/dist/87f511c4a8.js +1 -0
- package/dist/88251d6671.js +1 -0
- package/dist/882bc739c8.js +1 -0
- package/dist/89ab18ebc5.js +1 -0
- package/dist/8a22e8944f.css +563 -0
- package/dist/8a3a57c008.js +1 -0
- package/dist/8ade32d067.js +1 -0
- package/dist/8bf6d26ad6.css +233 -0
- package/dist/8c27edda0f.js +1 -0
- package/dist/8db8655f21.js +24 -0
- package/dist/8f60e5059a.js +1 -0
- package/dist/91707f5ca0.css +78 -0
- package/dist/921bf270dd.js +20 -0
- package/dist/9326c23506.js +1 -0
- package/dist/94a0a79c65.js +1 -0
- package/dist/9526094bb7.js +1 -0
- package/dist/9544661159.js +1 -0
- package/dist/95a44ebec2.js +1 -0
- package/dist/970313b92b.js +1 -0
- package/dist/9794652102.js +1 -0
- package/dist/983cbed22c.js +1 -0
- package/dist/9840b9ce12.js +1 -0
- package/dist/98f3644031.js +1 -0
- package/dist/992778075d.css +353 -0
- package/dist/9c6c598569.js +1 -0
- package/dist/9f474b5d1a.js +1 -0
- package/dist/a0f71d0bf5.js +1 -0
- package/dist/a3c983d431.js +1 -0
- package/dist/a3f18e76fe.js +1 -0
- package/dist/a493e9aa8f.js +1 -0
- package/dist/a77b15c0d6.js +1 -0
- package/dist/a811c90bd5.js +1 -0
- package/dist/a822c5e4f2.js +1 -0
- package/dist/aaa0e82d7f.css +69 -0
- package/dist/ab6c80484f.js +1 -0
- package/dist/ae96f219e3.js +1 -0
- package/dist/b11b38869d.css +427 -0
- package/dist/b1349d5a21.js +4 -0
- package/dist/b14379d31b.css +151 -0
- package/dist/b3efb26fd7.js +1 -0
- package/dist/b59b0dde17.js +1 -0
- package/dist/b5c372377f.js +1 -0
- package/dist/b976df09ec.js +1 -0
- package/dist/baeaed46c9.js +1 -0
- package/dist/bb719febc6.js +1 -0
- package/dist/bcd44b4040.js +1 -0
- package/dist/bdc4e4c5b9.css +209 -0
- package/dist/bdec200d00.js +1 -0
- package/dist/be0cfe2236.js +1 -0
- package/dist/be337ddda5.js +1 -0
- package/dist/c12c112c6f.js +1 -0
- package/dist/c2a14a77ae.js +1 -0
- package/dist/c3b8f1973b.js +1 -0
- package/dist/c44d37da7a.js +1 -0
- package/dist/c4790179f1.js +1 -0
- package/dist/c5e990946e.js +1 -0
- package/dist/c71892453b.js +1 -0
- package/dist/c9a1656c62.js +1 -0
- package/dist/ca497b066c.js +1 -0
- package/dist/cdb4a0f7b3.js +3 -0
- package/dist/ce663020e4.js +60 -0
- package/dist/cec035efb1.js +1 -0
- package/dist/d0f9681634.js +1 -0
- package/dist/d118c2e7ba.js +1 -0
- package/dist/d20718159b.js +3 -0
- package/dist/d30f1f506e.js +1 -0
- package/dist/d3cd7f1bc1.js +1 -0
- package/dist/d4378d9afa.js +1 -0
- package/dist/d464da28a5.js +1 -0
- package/dist/d566d3874b.js +1 -0
- package/dist/d617bbb9f5.js +26 -0
- package/dist/d65f32e004.js +1 -0
- package/dist/d6851ea979.js +1 -0
- package/dist/d7c9500ba9.js +1 -0
- package/dist/d803155241.js +1 -0
- package/dist/d903df4e0d.js +1 -0
- package/dist/d94df858ea.js +1 -0
- package/dist/da7b5f450d.js +1 -0
- package/dist/daa11edd01.js +1 -0
- package/dist/db4afd43c9.js +1 -0
- package/dist/dbd5ba1d07.js +1 -0
- package/dist/dc2a1a0e13.js +1 -0
- package/dist/dc812f3e14.js +1 -0
- package/dist/dcbf419090.css +122 -0
- package/dist/dcdba78ddf.js +1 -0
- package/dist/de408c4516.js +1 -0
- package/dist/e1cd279733.js +1 -0
- package/dist/e379e0039b.js +1 -0
- package/dist/e4fe0551fd.js +1 -0
- package/dist/e6eed481cc.css +28 -0
- package/dist/e75f1e5992.js +1 -0
- package/dist/ea8577d22b.js +1 -0
- package/dist/ec4a34fc80.css +313 -0
- package/dist/ed6a54cdf6.js +1 -0
- package/dist/ee242c0099.js +1 -0
- package/dist/ee9b9fd7d1.js +1 -0
- package/dist/f0c3d8a28a.js +1 -0
- package/dist/f11a45a150.js +1 -0
- package/dist/f1b3b2622a.js +1 -0
- package/dist/f7b4a178e3.js +1 -0
- package/dist/f89d7cd931.js +1 -0
- package/dist/f8cb80a93c.js +1 -0
- package/dist/f8fec86f10.js +1 -0
- package/dist/fbd844f2d1.js +1 -0
- package/dist/fe235d7160.js +1 -0
- package/dist/fe58a84b85.js +1 -0
- package/dist/fe68b361ba.js +1 -0
- package/dist/ff5b3d17e2.js +1 -0
- package/dist/styles/globals.css +442 -0
- package/dist/styles/themes.css +532 -0
- package/dist/styles/variables.css +299 -0
- package/package.json +68 -0
- package/static/assets/draco/README.md +32 -0
- package/static/assets/draco/draco_decoder.js +34 -0
- package/static/assets/draco/draco_decoder.wasm +0 -0
- package/static/assets/draco/draco_encoder.js +35 -0
- package/static/assets/draco/draco_encoder.wasm +0 -0
- package/static/assets/draco/draco_encoder_wrapper.js +98 -0
- package/static/assets/draco/draco_wasm_wrapper.js +117 -0
- package/static/favicon.svg +28 -0
- package/static/version.txt +1 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
@layer sdk-base, vendor, sdk;
|
|
2
|
+
@layer sdk {
|
|
3
|
+
.notification-container {
|
|
4
|
+
position: fixed;
|
|
5
|
+
top: calc(var(--header-height) + var(--spacing-md));
|
|
6
|
+
right: var(--spacing-md);
|
|
7
|
+
/* Above the evaluate-freeze overlay (.evaluating-overlay = 9999) so a backend
|
|
8
|
+
show_message modal (and toasts) stay on top + clickable during an evaluate.
|
|
9
|
+
This container is a stacking context, so it caps its children's z-index —
|
|
10
|
+
hence the modal's own z:10000 was only "10000 within 1000" and got covered. */
|
|
11
|
+
z-index: 10001;
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
gap: var(--spacing-sm);
|
|
15
|
+
pointer-events: none;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.notification {
|
|
19
|
+
display: flex;
|
|
20
|
+
align-items: center;
|
|
21
|
+
gap: var(--spacing-sm);
|
|
22
|
+
padding: var(--spacing-md);
|
|
23
|
+
background: var(--bg-primary);
|
|
24
|
+
border-radius: var(--border-radius);
|
|
25
|
+
box-shadow: var(--shadow-lg);
|
|
26
|
+
min-width: 280px;
|
|
27
|
+
max-width: 400px;
|
|
28
|
+
pointer-events: auto;
|
|
29
|
+
animation: slideIn 0.3s ease;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@keyframes slideIn {
|
|
33
|
+
from {
|
|
34
|
+
transform: translateX(100%);
|
|
35
|
+
opacity: 0;
|
|
36
|
+
}
|
|
37
|
+
to {
|
|
38
|
+
transform: translateX(0);
|
|
39
|
+
opacity: 1;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Canvas-on-LEFT layouts — the sidebar/options panel is docked RIGHT, so the 3D
|
|
44
|
+
canvas sits on the left (tpl-sidebar-right, ShowroomLayout, WizardLayout). Anchor
|
|
45
|
+
the toasts to the LEFT edge so they float over the canvas instead of over/behind
|
|
46
|
+
the panel, and slide them in from the left. Canvas-on-right layouts (default,
|
|
47
|
+
ShowcaseLayout) keep the default right anchor. Desktop only — on mobile every
|
|
48
|
+
layout reflows to scene-on-top and the mobile block below owns the position.
|
|
49
|
+
Add a layout's root class here whenever its canvas is on the left. */
|
|
50
|
+
@media (min-width: 769px) {
|
|
51
|
+
.main-layout--tpl-sidebar-right .notification-container,
|
|
52
|
+
.showroom-layout .notification-container,
|
|
53
|
+
.wizard-layout .notification-container {
|
|
54
|
+
right: auto;
|
|
55
|
+
left: var(--spacing-md);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.main-layout--tpl-sidebar-right .notification,
|
|
59
|
+
.showroom-layout .notification,
|
|
60
|
+
.wizard-layout .notification {
|
|
61
|
+
animation-name: slideInLeft;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
@keyframes slideInLeft {
|
|
66
|
+
from {
|
|
67
|
+
transform: translateX(-100%);
|
|
68
|
+
opacity: 0;
|
|
69
|
+
}
|
|
70
|
+
to {
|
|
71
|
+
transform: translateX(0);
|
|
72
|
+
opacity: 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.notification--success {
|
|
77
|
+
border-left: 4px solid var(--color-success);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.notification--error {
|
|
81
|
+
border-left: 4px solid var(--color-error);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.notification--warning {
|
|
85
|
+
border-left: 4px solid var(--color-warning);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.notification--info {
|
|
89
|
+
border-left: 4px solid var(--color-primary);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.notification__icon {
|
|
93
|
+
flex-shrink: 0;
|
|
94
|
+
width: 20px;
|
|
95
|
+
height: 20px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.notification--success .notification__icon {
|
|
99
|
+
color: var(--color-success);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.notification--error .notification__icon {
|
|
103
|
+
color: var(--color-error);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.notification--warning .notification__icon {
|
|
107
|
+
color: var(--color-warning);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.notification--info .notification__icon {
|
|
111
|
+
color: var(--color-primary);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.notification__content {
|
|
115
|
+
flex: 1;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.notification__title {
|
|
119
|
+
font-weight: 600;
|
|
120
|
+
font-size: var(--font-size-sm);
|
|
121
|
+
margin-bottom: var(--spacing-xs);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.notification__message {
|
|
125
|
+
font-size: var(--font-size-sm);
|
|
126
|
+
color: var(--text-secondary);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.notification__close {
|
|
130
|
+
flex-shrink: 0;
|
|
131
|
+
padding: var(--spacing-xs);
|
|
132
|
+
background: transparent;
|
|
133
|
+
border: none;
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
color: var(--text-secondary);
|
|
136
|
+
transition: color 0.2s ease;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.notification__close:hover {
|
|
140
|
+
color: var(--text-primary);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.notification__close svg {
|
|
144
|
+
width: 16px;
|
|
145
|
+
height: 16px;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.notification--persistent {
|
|
149
|
+
animation: none;
|
|
150
|
+
border-left-width: 4px;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Responsive — inside the canvas container on mobile */
|
|
154
|
+
@media (max-width: 768px) {
|
|
155
|
+
.notification-container {
|
|
156
|
+
position: absolute;
|
|
157
|
+
top: var(--spacing-sm);
|
|
158
|
+
bottom: auto;
|
|
159
|
+
left: auto;
|
|
160
|
+
right: var(--spacing-sm);
|
|
161
|
+
align-items: flex-end;
|
|
162
|
+
z-index: 10001; /* keep above the evaluate-freeze overlay so the modal stays clickable */
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.notification {
|
|
166
|
+
min-width: auto;
|
|
167
|
+
max-width: none;
|
|
168
|
+
padding: var(--spacing-xs) var(--spacing-sm);
|
|
169
|
+
gap: var(--spacing-xs);
|
|
170
|
+
align-items: center;
|
|
171
|
+
border-left-width: 3px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.notification__icon {
|
|
175
|
+
width: 16px;
|
|
176
|
+
height: 16px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.notification__title {
|
|
180
|
+
font-size: var(--font-size-sm);
|
|
181
|
+
margin-bottom: 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.notification__message {
|
|
185
|
+
font-size: var(--font-size-sm);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.notification__close {
|
|
189
|
+
padding: 2px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.notification__close svg {
|
|
193
|
+
width: 14px;
|
|
194
|
+
height: 14px;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/* Backend show_message display:'modal' — blocking dialog (applyMessages). */
|
|
199
|
+
.message-modal__overlay {
|
|
200
|
+
position: fixed;
|
|
201
|
+
inset: 0;
|
|
202
|
+
background: rgba(0, 0, 0, 0.45);
|
|
203
|
+
/* Every dialog backdrop (ours, host-registered, quote, backend show_message) blurs the page
|
|
204
|
+
behind it by this much. 0 turns it off; the dimming stays. */
|
|
205
|
+
backdrop-filter: blur(var(--modal-backdrop-blur, 4px));
|
|
206
|
+
-webkit-backdrop-filter: blur(var(--modal-backdrop-blur, 4px));
|
|
207
|
+
display: flex;
|
|
208
|
+
align-items: center;
|
|
209
|
+
justify-content: center;
|
|
210
|
+
z-index: 10000;
|
|
211
|
+
/* The parent .notification-container is pointer-events:none (so toasts don't block
|
|
212
|
+
the page). This modal IS interactive — re-enable pointer events here, or every
|
|
213
|
+
click (incl. OK) passes straight through the dialog. */
|
|
214
|
+
pointer-events: auto;
|
|
215
|
+
}
|
|
216
|
+
.message-modal {
|
|
217
|
+
background: var(--bg-primary, #fff);
|
|
218
|
+
color: var(--text-primary, #1a1a1a);
|
|
219
|
+
max-width: 420px;
|
|
220
|
+
width: calc(100% - 48px);
|
|
221
|
+
border-radius: 10px;
|
|
222
|
+
padding: 24px;
|
|
223
|
+
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
|
|
224
|
+
border-top: 4px solid var(--color-info, #2563eb); /* info default */
|
|
225
|
+
}
|
|
226
|
+
.message-modal--warning { border-top-color: #d97706; }
|
|
227
|
+
.message-modal--error { border-top-color: #dc2626; }
|
|
228
|
+
.message-modal--success { border-top-color: #16a34a; }
|
|
229
|
+
.message-modal--info { border-top-color: var(--color-info, #2563eb); }
|
|
230
|
+
.message-modal__body {
|
|
231
|
+
font-size: 15px;
|
|
232
|
+
line-height: 1.5;
|
|
233
|
+
margin-bottom: 20px;
|
|
234
|
+
}
|
|
235
|
+
.message-modal__btn {
|
|
236
|
+
display: inline-block;
|
|
237
|
+
padding: 8px 20px;
|
|
238
|
+
border: none;
|
|
239
|
+
border-radius: 6px;
|
|
240
|
+
background: var(--text-primary, #1a1a1a);
|
|
241
|
+
color: var(--bg-primary, #fff);
|
|
242
|
+
font-size: 14px;
|
|
243
|
+
cursor: pointer;
|
|
244
|
+
}
|
|
245
|
+
.message-modal__btn:hover { background: var(--text-primary, #333); }
|
|
246
|
+
|
|
247
|
+
/* Backend show_message display:'inline' — rendered in the sidebar (applyMessages). */
|
|
248
|
+
.inline-messages { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
|
|
249
|
+
.inline-message {
|
|
250
|
+
font-size: 13px;
|
|
251
|
+
line-height: 1.4;
|
|
252
|
+
padding: 10px 12px;
|
|
253
|
+
border-radius: 6px;
|
|
254
|
+
border-left: 3px solid var(--color-info, #2563eb);
|
|
255
|
+
background: rgba(37, 99, 235, 0.08);
|
|
256
|
+
color: var(--text-primary, #1a1a1a);
|
|
257
|
+
}
|
|
258
|
+
.inline-message--warning { border-left-color: #d97706; background: rgba(217, 119, 6, 0.08); }
|
|
259
|
+
.inline-message--error { border-left-color: #dc2626; background: rgba(220, 38, 38, 0.08); }
|
|
260
|
+
.inline-message--success { border-left-color: #16a34a; background: rgba(22, 163, 74, 0.08); }
|
|
261
|
+
.inline-message--info { border-left-color: var(--color-info, #2563eb); background: rgba(37, 99, 235, 0.08); }
|
|
262
|
+
|
|
263
|
+
}
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
@layer sdk-base, vendor, sdk;
|
|
2
|
+
@layer sdk {
|
|
3
|
+
/* ============================================================================
|
|
4
|
+
ShowcaseLayout (Theme 4) — editorial product page: warm left panel (serif
|
|
5
|
+
heading + intro + summary rows that drill into options) and the scene on the
|
|
6
|
+
right. Calm, premium, neutral. Self-contained (not data-theme dependent).
|
|
7
|
+
============================================================================ */
|
|
8
|
+
|
|
9
|
+
.showcase-layout {
|
|
10
|
+
/* literal = fallback; a theme record's --color-* overrides it (§4). */
|
|
11
|
+
--sc-panel: var(--color-surface, #f4f1ea); /* warm cream panel */
|
|
12
|
+
--sc-scene: var(--color-background, #d9d6cf); /* warm greige scene backdrop */
|
|
13
|
+
/* The literal ends the chain DELIBERATELY. This used to read
|
|
14
|
+
`var(--color-foreground, var(--text-primary, #2b2620))`, while the block below re-exports
|
|
15
|
+
`--text-primary: var(--sc-ink)` — a custom-property CYCLE whenever the theme ships no
|
|
16
|
+
`--color-foreground`. Both sides of a cycle compute to the guaranteed-invalid value, so
|
|
17
|
+
`background: var(--sc-ink)` fell back to transparent and the primary CTA rendered
|
|
18
|
+
pale-on-pale: present, sized, clickable, invisible. applyTheme writes --color-foreground and
|
|
19
|
+
--text-primary from the SAME source, so the hop bought nothing anyway. */
|
|
20
|
+
--sc-ink: var(--color-foreground, #2b2620);
|
|
21
|
+
--sc-ink-soft: var(--color-secondary, #8a8178);
|
|
22
|
+
--sc-line: var(--color-border, #e2dcd0);
|
|
23
|
+
--sc-line-strong: var(--color-border, #d7cfc0);
|
|
24
|
+
--sc-accent: var(--color-accent, #2b2620); /* near-black ink accent */
|
|
25
|
+
--sc-accent-soft: rgba(var(--text-primary-rgb, 43, 38, 32), 0.08);
|
|
26
|
+
|
|
27
|
+
/* Floating AI chat FAB → this theme's accent (matches the CTA colour). */
|
|
28
|
+
--shell-fab-bg: var(--sc-accent);
|
|
29
|
+
--shell-fab-bg-strong: var(--text-primary, #45403a);
|
|
30
|
+
/* NOTE: no --shell-fab-bottom-m here on purpose. The other shells pin their mobile
|
|
31
|
+
footers, so a fixed viewport offset clears them at every scroll position — but THIS
|
|
32
|
+
theme's footer deliberately scrolls with the panel (see the mobile block's comment),
|
|
33
|
+
so no constant works: 16px sat on the Save button at the scroll end, 86px hovered
|
|
34
|
+
mid-air over the option rows everywhere else (both user-reported). The mobile FAB is
|
|
35
|
+
instead re-anchored INSIDE the scene (see the @media block below). */
|
|
36
|
+
|
|
37
|
+
/* embedded-Sidebar token remap (used in the drill-in options view) */
|
|
38
|
+
--color-selection: var(--sc-ink);
|
|
39
|
+
--color-selection-rgb: 43, 38, 32;
|
|
40
|
+
--color-selection-light: var(--sc-accent-soft);
|
|
41
|
+
--color-selection-border: rgba(var(--text-primary-rgb, 43, 38, 32), 0.4);
|
|
42
|
+
--border-selected: var(--sc-ink);
|
|
43
|
+
--thumbnail-border-selected: var(--sc-ink);
|
|
44
|
+
--thumbnail-border-hover: var(--sc-ink);
|
|
45
|
+
--text-link: var(--sc-ink);
|
|
46
|
+
--icon-color-active: var(--sc-ink);
|
|
47
|
+
--color-neutral-900: var(--sc-ink);
|
|
48
|
+
--color-neutral-700: var(--sc-ink-soft);
|
|
49
|
+
--text-primary: var(--sc-ink);
|
|
50
|
+
--text-secondary: var(--sc-ink-soft);
|
|
51
|
+
--bg-scene: var(--sc-scene);
|
|
52
|
+
|
|
53
|
+
position: relative;
|
|
54
|
+
display: flex;
|
|
55
|
+
height: 100%;
|
|
56
|
+
overflow: hidden;
|
|
57
|
+
background: var(--sc-scene);
|
|
58
|
+
color: var(--sc-ink);
|
|
59
|
+
font-family: var(--font-family-base);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* ---------------------------------------------------------------------------------------------
|
|
63
|
+
THE SAME PALETTE ON A DARK PRESET.
|
|
64
|
+
|
|
65
|
+
Every literal above is a LIGHT-mode fallback, reached whenever the theme record ships no
|
|
66
|
+
`--color-*` — which the shared dark skin (styles/themes.css) never does: it remaps the generic
|
|
67
|
+
tokens (--text-primary, --bg-primary, --border-default …), not the --color-* family. So on a
|
|
68
|
+
dark preset this shell kept its near-black ink, and because the block above re-exports
|
|
69
|
+
`--text-primary: var(--<x>-ink)`, it also OVERWROTE the dark skin's light text for every
|
|
70
|
+
descendant. Anything mounted inside the shell that inherits its colour — the live-status
|
|
71
|
+
panel, the chat bar — rendered dark-on-dark: present, sized, unreadable.
|
|
72
|
+
|
|
73
|
+
Same failure mode as the --*-ink cycle documented above, reached by a different route, so the
|
|
74
|
+
repair is the same shape: end the chain in a literal, and let a theme's own --color-* still
|
|
75
|
+
win by keeping the var() in front of it.
|
|
76
|
+
--------------------------------------------------------------------------------------------- */
|
|
77
|
+
:root[data-theme-mode="dark"] .showcase-layout {
|
|
78
|
+
--sc-panel: var(--color-surface, #1e1e22);
|
|
79
|
+
--sc-scene: var(--color-background, #17171a);
|
|
80
|
+
--sc-ink: var(--color-foreground, #f2f2f4);
|
|
81
|
+
--sc-ink-soft: var(--color-secondary, #b8b8be);
|
|
82
|
+
--sc-line: var(--color-border, #34343a);
|
|
83
|
+
--sc-line-strong: var(--color-border, #44444c);
|
|
84
|
+
--sc-accent: var(--color-accent, #f2f2f4);
|
|
85
|
+
--sc-accent-soft: rgba(var(--text-primary-rgb, 242, 242, 244), 0.10);
|
|
86
|
+
--color-selection-rgb: 242, 242, 244;
|
|
87
|
+
--color-selection-border: rgba(var(--text-primary-rgb, 242, 242, 244), 0.4);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* The CTA paints ITS label on an ink ground, so inverting the ink has to invert the label too —
|
|
91
|
+
otherwise the primary action goes white-on-white, which is how this shell's CTA disappeared
|
|
92
|
+
once before. --text-inverse is the existing token for exactly this and the shared dark skin
|
|
93
|
+
already flips it; the light rule above keeps its own warm literal untouched. */
|
|
94
|
+
:root[data-theme-mode="dark"] .showcase-cta { color: var(--text-inverse, #1a1a1a); }
|
|
95
|
+
|
|
96
|
+
/* ---- Left panel ---- */
|
|
97
|
+
.showcase-panel {
|
|
98
|
+
flex: 0 0 clamp(360px, 40vw, 480px);
|
|
99
|
+
display: flex;
|
|
100
|
+
flex-direction: column;
|
|
101
|
+
min-width: 0;
|
|
102
|
+
min-height: 0;
|
|
103
|
+
background: var(--sc-panel);
|
|
104
|
+
/* Bottom is tighter than the top: the foot is pinned now, so its padding-top already
|
|
105
|
+
separates it from the rows and the panel's own bottom padding is all that shows under
|
|
106
|
+
the CTA. 40px there read as a gap (user-reported). */
|
|
107
|
+
padding: 40px 44px 20px;
|
|
108
|
+
/* The panel itself does NOT scroll — `.showcase-rows` does — so the price and CTA stay on
|
|
109
|
+
screen however many option sets a system has. Scrolling the whole panel put "Generate
|
|
110
|
+
Assets" below the fold on a 10-row system: the shopper had to scroll past every option
|
|
111
|
+
to reach the button that finishes the job (user-reported). Showroom and Wizard already
|
|
112
|
+
scroll an inner body and pin their foot; this matches them. */
|
|
113
|
+
overflow: hidden;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Master (summary) view */
|
|
117
|
+
/* `min-height: 0` is what lets the rows scroll instead of stretching the panel — a flex
|
|
118
|
+
item refuses to shrink below its content until told to. */
|
|
119
|
+
.showcase-master { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
|
|
120
|
+
.showcase-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 34px; }
|
|
121
|
+
.showcase-logo { width: 24px; height: 22px; color: var(--sc-ink); }
|
|
122
|
+
.showcase-brand__name { font-size: 13px; font-weight: 600; letter-spacing: 0.4px; color: var(--sc-ink); }
|
|
123
|
+
|
|
124
|
+
.showcase-heading {
|
|
125
|
+
margin: 0 0 16px;
|
|
126
|
+
/* Theme-reachable (beta intake F-16): a record's typography used to apply everywhere
|
|
127
|
+
except the most prominent text on the page. Literal stack stays as the fallback. */
|
|
128
|
+
font-family: var(--font-family-heading, var(--font-family-base, Georgia, 'Times New Roman', 'Playfair Display', serif));
|
|
129
|
+
font-weight: 500;
|
|
130
|
+
font-size: 40px;
|
|
131
|
+
/* Georgia has deep descenders — a 1.1 line-height clipped the tails of "your
|
|
132
|
+
piece". Give the line box room + a hair of descender padding so glyphs never
|
|
133
|
+
touch the box edge. */
|
|
134
|
+
line-height: 1.2;
|
|
135
|
+
padding-bottom: 0.08em;
|
|
136
|
+
letter-spacing: -0.2px;
|
|
137
|
+
color: var(--sc-ink);
|
|
138
|
+
}
|
|
139
|
+
.showcase-sub {
|
|
140
|
+
margin: 0 0 34px;
|
|
141
|
+
font-size: 14px;
|
|
142
|
+
line-height: 1.55;
|
|
143
|
+
color: var(--sc-ink-soft);
|
|
144
|
+
max-width: 34ch;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* Summary rows */
|
|
148
|
+
.showcase-rows {
|
|
149
|
+
display: flex;
|
|
150
|
+
flex-direction: column;
|
|
151
|
+
border-top: 1px solid var(--sc-line);
|
|
152
|
+
/* Takes whatever the header and foot leave, and scrolls inside it. */
|
|
153
|
+
flex: 1 1 auto;
|
|
154
|
+
min-height: 0;
|
|
155
|
+
overflow-y: auto;
|
|
156
|
+
scrollbar-gutter: stable; /* rows do not shift when the scrollbar appears */
|
|
157
|
+
}
|
|
158
|
+
.showcase-row {
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
gap: 16px;
|
|
162
|
+
padding: 18px 4px;
|
|
163
|
+
border: none;
|
|
164
|
+
border-bottom: 1px solid var(--sc-line);
|
|
165
|
+
background: transparent;
|
|
166
|
+
cursor: pointer;
|
|
167
|
+
text-align: left;
|
|
168
|
+
transition: background 0.15s;
|
|
169
|
+
}
|
|
170
|
+
.showcase-row:hover { background: rgba(var(--text-primary-rgb, 43, 38, 32), 0.035); }
|
|
171
|
+
.showcase-row:disabled { cursor: default; opacity: 0.6; }
|
|
172
|
+
.showcase-row__preview {
|
|
173
|
+
position: relative;
|
|
174
|
+
flex: 0 0 auto;
|
|
175
|
+
width: 44px;
|
|
176
|
+
height: 44px;
|
|
177
|
+
border-radius: 6px;
|
|
178
|
+
background: #fff;
|
|
179
|
+
border: 1px solid var(--sc-line-strong);
|
|
180
|
+
overflow: hidden;
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
justify-content: center;
|
|
184
|
+
}
|
|
185
|
+
/* Image overlays the box (and the monogram/plus behind it), so a failed thumbnail
|
|
186
|
+
reveals the fallback instead of a blank square. */
|
|
187
|
+
.showcase-row__preview img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
|
|
188
|
+
/* Monogram fallback: selected option with no thumbnail/colour (or a broken
|
|
189
|
+
thumbnail) → a subtle filled tile with the value's initial. */
|
|
190
|
+
.showcase-row__preview--mono { background: var(--color-surface, #efeae2); }
|
|
191
|
+
.showcase-row__preview-initial {
|
|
192
|
+
font-size: 15px;
|
|
193
|
+
font-weight: 700;
|
|
194
|
+
color: var(--sc-ink-soft, #9a948b);
|
|
195
|
+
line-height: 1;
|
|
196
|
+
text-transform: uppercase;
|
|
197
|
+
}
|
|
198
|
+
/* Unselected / add-piece rows: a dashed, muted "choose" affordance instead of a
|
|
199
|
+
blank white square. */
|
|
200
|
+
.showcase-row__preview--empty {
|
|
201
|
+
background: transparent;
|
|
202
|
+
border-style: dashed;
|
|
203
|
+
border-color: var(--sc-line-strong);
|
|
204
|
+
color: var(--sc-ink-soft, #9a948b);
|
|
205
|
+
}
|
|
206
|
+
.showcase-row__preview-plus { color: inherit; opacity: 0.7; }
|
|
207
|
+
.showcase-row__text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
|
|
208
|
+
.showcase-row__label {
|
|
209
|
+
font-size: 12px;
|
|
210
|
+
font-weight: 700;
|
|
211
|
+
letter-spacing: 0.8px;
|
|
212
|
+
text-transform: uppercase;
|
|
213
|
+
color: var(--sc-ink);
|
|
214
|
+
}
|
|
215
|
+
.showcase-row__value {
|
|
216
|
+
font-size: 14px;
|
|
217
|
+
color: var(--sc-ink-soft);
|
|
218
|
+
overflow: hidden;
|
|
219
|
+
text-overflow: ellipsis;
|
|
220
|
+
white-space: nowrap;
|
|
221
|
+
}
|
|
222
|
+
.showcase-row__chev { width: 18px; height: 18px; color: var(--sc-ink-soft); flex: 0 0 auto; }
|
|
223
|
+
|
|
224
|
+
/* Footer: price + actions, pinned to the bottom of the panel */
|
|
225
|
+
/* Pinned: a sibling after the scrolling rows. `flex: 0 0 auto` rather than the old
|
|
226
|
+
`margin-top: auto` — the rows take the slack now. */
|
|
227
|
+
.showcase-foot { flex: 0 0 auto; padding-top: 26px; }
|
|
228
|
+
.showcase-foot__price { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 14px; }
|
|
229
|
+
.showcase-foot__label { font-size: 11px; font-weight: 700; letter-spacing: 1px; color: var(--sc-ink-soft); }
|
|
230
|
+
.showcase-foot__value { font-size: 22px; font-weight: 700; color: var(--sc-ink); }
|
|
231
|
+
.showcase-foot__actions { display: flex; gap: 10px; }
|
|
232
|
+
.showcase-cta {
|
|
233
|
+
flex: 1;
|
|
234
|
+
display: inline-flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
justify-content: center;
|
|
237
|
+
gap: 8px;
|
|
238
|
+
height: 50px;
|
|
239
|
+
border: none;
|
|
240
|
+
border-radius: 3px;
|
|
241
|
+
background: var(--sc-ink);
|
|
242
|
+
color: #f4f1ea;
|
|
243
|
+
font-size: 13px;
|
|
244
|
+
font-weight: 700;
|
|
245
|
+
letter-spacing: 1px;
|
|
246
|
+
text-transform: uppercase;
|
|
247
|
+
cursor: pointer;
|
|
248
|
+
transition: background 0.15s;
|
|
249
|
+
}
|
|
250
|
+
.showcase-cta:hover { background: var(--text-primary, #45403a); }
|
|
251
|
+
/* Icon-only square (the shared SaveProjectButton also renders a "Save" text node —
|
|
252
|
+
collapse it with font-size:0 so only the sized icon shows; no cramped label). */
|
|
253
|
+
.showcase-save {
|
|
254
|
+
flex: 0 0 auto;
|
|
255
|
+
display: inline-flex;
|
|
256
|
+
align-items: center;
|
|
257
|
+
justify-content: center;
|
|
258
|
+
height: 50px;
|
|
259
|
+
width: 50px;
|
|
260
|
+
padding: 0;
|
|
261
|
+
border: 1px solid var(--sc-line-strong);
|
|
262
|
+
border-radius: 3px;
|
|
263
|
+
background: transparent;
|
|
264
|
+
color: var(--sc-ink-soft);
|
|
265
|
+
font-size: 0;
|
|
266
|
+
cursor: pointer;
|
|
267
|
+
}
|
|
268
|
+
.showcase-save:hover { border-color: var(--sc-ink); color: var(--sc-ink); }
|
|
269
|
+
.showcase-save .save-btn__icon { width: 18px; height: 18px; }
|
|
270
|
+
|
|
271
|
+
/* ---- Detail (drill-in) view ---- */
|
|
272
|
+
.showcase-detail { display: flex; flex-direction: column; min-height: 100%; }
|
|
273
|
+
.showcase-back {
|
|
274
|
+
display: inline-flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
gap: 6px;
|
|
277
|
+
align-self: flex-start;
|
|
278
|
+
padding: 6px 0;
|
|
279
|
+
border: none;
|
|
280
|
+
background: transparent;
|
|
281
|
+
color: var(--sc-ink-soft);
|
|
282
|
+
font-size: 13px;
|
|
283
|
+
font-weight: 600;
|
|
284
|
+
cursor: pointer;
|
|
285
|
+
}
|
|
286
|
+
.showcase-back:hover { color: var(--sc-ink); }
|
|
287
|
+
.showcase-back svg { width: 16px; height: 16px; }
|
|
288
|
+
.showcase-detail__title {
|
|
289
|
+
margin: 10px 0 8px;
|
|
290
|
+
font-family: var(--font-family-heading, var(--font-family-base, Georgia, 'Times New Roman', serif));
|
|
291
|
+
font-weight: 500;
|
|
292
|
+
font-size: 28px;
|
|
293
|
+
color: var(--sc-ink);
|
|
294
|
+
}
|
|
295
|
+
.showcase-detail__body { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; margin: 0 -8px; }
|
|
296
|
+
.showcase-detail__body .sidebar--embedded { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; width: 100%; background: transparent; }
|
|
297
|
+
.showcase-detail__body .sidebar--embedded .sidebar__content { flex: 1 1 auto; overflow-y: auto; padding: 8px; }
|
|
298
|
+
/* ONE HEADING PER SCREEN. The drill-in already announces the set in the shell's own serif
|
|
299
|
+
heading (.showcase-detail__title), and the embedded panel then repeated it as its section
|
|
300
|
+
title — "Width" over "WIDTH". The panel keeps its title everywhere else; here the shell
|
|
301
|
+
owns the naming. A GROUP's children are separate sets with names of their own, so those
|
|
302
|
+
titles stay. */
|
|
303
|
+
.showcase-detail__body .sidebar__section-title { display: none; }
|
|
304
|
+
.showcase-detail__body .sidebar__group-child .sidebar__section-title { display: block; }
|
|
305
|
+
|
|
306
|
+
/* A numbered PALETTE preset is independent of which shell is mounted, and
|
|
307
|
+
`:root[data-theme-preset="theme4"]` paints the panel's section titles (and their rule)
|
|
308
|
+
indigo — a colour from a different design landing inside this shell's warm editorial skin.
|
|
309
|
+
Four classes so this beats that selector's three regardless of stylesheet order. */
|
|
310
|
+
.showcase-layout .showcase-panel .sidebar__content .sidebar__section-title {
|
|
311
|
+
color: var(--sc-ink);
|
|
312
|
+
letter-spacing: 1.2px;
|
|
313
|
+
}
|
|
314
|
+
.showcase-layout .showcase-panel .sidebar__content .sidebar__section-title::after {
|
|
315
|
+
background: var(--sc-line);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* Card labels below (static), inside the drill-in view */
|
|
319
|
+
.showcase-detail__body .finish-thumbnail__name::after,
|
|
320
|
+
.showcase-detail__body .layout-thumbnail__label::after { display: none; }
|
|
321
|
+
.showcase-detail__body .option-thumbnail--has-img {
|
|
322
|
+
aspect-ratio: auto; min-height: 0; padding: 0; display: flex; flex-direction: column; overflow: hidden;
|
|
323
|
+
}
|
|
324
|
+
.showcase-detail__body .option-thumbnail--has-img .option-thumbnail__img {
|
|
325
|
+
width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 0;
|
|
326
|
+
}
|
|
327
|
+
.showcase-detail__body .option-thumbnail__img-label,
|
|
328
|
+
.showcase-detail__body .option-thumbnail__name,
|
|
329
|
+
.showcase-detail__body .color-swatch__name {
|
|
330
|
+
position: static; opacity: 1; background: none; color: var(--sc-ink);
|
|
331
|
+
text-shadow: none; font-size: 11px; font-weight: 600; line-height: 1.25; padding: 6px 4px 7px;
|
|
332
|
+
}
|
|
333
|
+
.showcase-detail__body .finish-thumbnail__name {
|
|
334
|
+
position: static; transform: none; opacity: 1; visibility: visible; pointer-events: auto;
|
|
335
|
+
background: none; color: var(--sc-ink); border-radius: 0; white-space: normal; box-shadow: none;
|
|
336
|
+
margin: 0; padding: 4px 2px 2px; font-size: 10px; font-weight: 600; line-height: 1.2;
|
|
337
|
+
}
|
|
338
|
+
.showcase-detail__body .layout-thumbnail { display: flex; flex-direction: column; }
|
|
339
|
+
.showcase-detail__body .layout-thumbnail__label {
|
|
340
|
+
position: static; transform: none; opacity: 1; visibility: visible; pointer-events: auto;
|
|
341
|
+
background: none; color: var(--sc-ink); border-radius: 0; white-space: normal; box-shadow: none;
|
|
342
|
+
margin: 0; padding: 6px 4px 0; font-size: 11px; font-weight: 600; text-align: center;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* ---- Scene ---- */
|
|
346
|
+
.showcase-scene { flex: 1 1 auto; min-width: 0; position: relative; overflow: hidden; background: var(--sc-scene); }
|
|
347
|
+
.showcase-scene .header__toolbar {
|
|
348
|
+
position: absolute; top: 20px; right: 24px; z-index: 4;
|
|
349
|
+
background: transparent; box-shadow: none; border-radius: 0; padding: 0; gap: 14px;
|
|
350
|
+
}
|
|
351
|
+
.showcase-scene .header__toolbar-btn {
|
|
352
|
+
width: 34px; height: 34px; border: none; border-radius: 0; background: transparent; color: var(--sc-ink);
|
|
353
|
+
}
|
|
354
|
+
.showcase-scene .header__toolbar-btn:hover { color: #000; background: transparent; }
|
|
355
|
+
.showcase-scene .header__toolbar-btn--active { background: transparent; color: #000; box-shadow: none; }
|
|
356
|
+
.showcase-scene .header__toolbar-btn svg { width: 20px; height: 20px; }
|
|
357
|
+
|
|
358
|
+
/* ============================================================================
|
|
359
|
+
MOBILE (≤768px) — reflow the editorial panel-left / scene-right into a single
|
|
360
|
+
column: scene on TOP (order:-1, DOM has the panel first), the editorial panel
|
|
361
|
+
below full-width and scrolling (master rows + drill-in detail both work). No
|
|
362
|
+
MainLayout fallback — the theme keeps its identity on phones.
|
|
363
|
+
============================================================================ */
|
|
364
|
+
@media (max-width: 768px) {
|
|
365
|
+
.showcase-layout { flex-direction: column; }
|
|
366
|
+
.showcase-scene { order: -1; flex: 0 0 42vh; min-height: 0; }
|
|
367
|
+
.showcase-panel {
|
|
368
|
+
flex: 1 1 auto;
|
|
369
|
+
width: auto;
|
|
370
|
+
min-height: 0;
|
|
371
|
+
padding: 18px 20px 24px;
|
|
372
|
+
border-top: 1px solid var(--sc-line);
|
|
373
|
+
/* RESTORE the panel as the scroller. Desktop stops it scrolling so the foot can pin
|
|
374
|
+
beside a scrolling row list; on a phone the scene sits above and the panel IS the
|
|
375
|
+
page, so clipping it here would strand every row with no way to reach them. */
|
|
376
|
+
overflow-y: auto;
|
|
377
|
+
}
|
|
378
|
+
/* ...which means the rows must not be a second, nested scroller here. */
|
|
379
|
+
.showcase-rows { flex: 0 0 auto; min-height: auto; overflow-y: visible; }
|
|
380
|
+
/* Let the panel flow to its CONTENT height (not the panel-viewport height) so the
|
|
381
|
+
footer doesn't pin to the bottom and leave a gap, and the whole thing scrolls
|
|
382
|
+
as one — otherwise the tall editorial hero eats the visible panel and the option
|
|
383
|
+
rows fall below the fold ("customize section trimmed in half"). */
|
|
384
|
+
/* SHORT content (a two-option configurator) must still park the price + CTA on the
|
|
385
|
+
bottom edge: without a grow the master is only as tall as its content, so
|
|
386
|
+
`.showcase-foot`'s `margin-top: auto` has nothing to push against and leaves a band
|
|
387
|
+
of empty panel beneath the button (user-reported). `flex-grow` fills the leftover
|
|
388
|
+
room when there is any and never shrinks the item below its content when there is
|
|
389
|
+
not — so the tall case above is untouched. */
|
|
390
|
+
.showcase-master { min-height: 0; flex: 1 1 auto; }
|
|
391
|
+
/* Compress the hero so the first option rows peek above the fold. */
|
|
392
|
+
.showcase-brand { margin-bottom: 14px; }
|
|
393
|
+
.showcase-heading { font-size: 26px; margin-bottom: 8px; }
|
|
394
|
+
.showcase-sub { margin-bottom: 16px; max-width: none; }
|
|
395
|
+
.showcase-detail__title { font-size: 24px; }
|
|
396
|
+
.showcase-foot { padding-top: 18px; }
|
|
397
|
+
.showcase-cta { height: 46px; }
|
|
398
|
+
/* The chat FAB rides the SCENE (fixed 42vh at the top), not the viewport: the panel
|
|
399
|
+
below scrolls, so a viewport-fixed FAB can't line up with anything in it. Scene
|
|
400
|
+
bottom-right — the watermark owns bottom-left, the toolbar sits top-right. The
|
|
401
|
+
open chat is the global bottom-half sheet (own close button). */
|
|
402
|
+
.showcase-scene .shell-chat-fab {
|
|
403
|
+
position: absolute;
|
|
404
|
+
left: auto;
|
|
405
|
+
right: 14px;
|
|
406
|
+
bottom: 14px;
|
|
407
|
+
}
|
|
408
|
+
.showcase-save { height: 46px; width: 46px; }
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import b from"./872c4302e0.js";import h from"./9c6c598569.js";import _ from"./be337ddda5.js";import{getPlacementBindings as q}from"./817d930a49.js";const S=(e,n)=>e?.[n]??e?.[String(n)]??null;function O({features:e,sceneConfigurations:n,activeSceneConfigId:i}){const s=i!=null?n?.[i]??n?.[String(i)]:null;return(Array.isArray(s?.optionSets)?s.optionSets:[]).map(u=>S(e,u?.id??u)).filter(Boolean)}function x({features:e,bindings:n}){if(!Array.isArray(n))return[];const i=[...n].sort((u,r)=>Number(u?.sequence??0)-Number(r?.sequence??0)),s=new Set,o=[];for(const u of i){const r=u?.optionSetId??u?.option_set_id;if(r==null||s.has(String(r)))continue;s.add(String(r));const f=S(e,r);f&&o.push(f)}return o}function A(e,{features:n,options:i,bindings:s}){const o=e?.feature_id||e?.id;if(!o)return[];const u=Array.isArray(s),r=e?.options?e:n[o]||n[String(o)],f={};r?.options&&r.options.forEach(t=>{typeof t=="object"&&(f[t.id]={sequence:t.sequence||0,disabled:!!t.disabled})});const p=t=>i[t]||i[String(t)]||i[Number(t)];let a=[];r?.options?.length>0&&(a=r.options.map(t=>{const l=typeof t=="object"?t.id:t,c=p(l)||(typeof t=="object"&&t.id!=null?t:null);return c?f[l]?.disabled?{...c,disabled:!0}:c:null}).filter(Boolean)),a.length===0&&(a=Object.values(i).filter(t=>t?.optionSetId==o||t?.option_set_id==o||t?.optionSet==o||t?.feature_id==o));const g=new Set((r?.options||[]).map(t=>String(typeof t=="object"?t?.id:t)));if(a=a.filter(t=>{if(t?.id!=null&&g.has(String(t.id)))return!0;const l=t?.optionSetId??t?.option_set_id??t?.optionSet??t?.feature_id;return l==null||String(l)===String(o)}),a.sort((t,l)=>{const c=f[t.id]?.sequence??t?.sequence??0,d=f[l.id]?.sequence??l?.sequence??0;return c-d}),u){const t=s.find(l=>String(l.optionSetId??l.option_set_id)===String(o));if(t&&Array.isArray(t.available)){const l=new Set(t.available.map(String)),c=a.filter(d=>l.has(String(d.id)));if(c.length)return c;if(t.available.length){const d=t.available.map(m=>p(m)).filter(Boolean);if(d.length)return d}return c}return a}return a}function B(e,n,{features:i,options:s,bindings:o=null}){if(n==null)return null;const u=s?.[n]??s?.[String(n)]??null;if(u)return u;const r=e&&typeof e=="object"?e:S(i,e);return r?A(r,{features:i,options:s,bindings:o}).find(p=>String(p?.id)===String(n))??null:null}function w(e){const n=b.getState(),i=h.getState(),s=_.getState(),o=e===void 0?i.selectedInstanceId??null:e;return{features:n.features||{},options:n.options||{},materials:n.materials||{},sceneConfigurations:s.sceneConfigurations||{},activeSceneConfigId:i.activeSceneConfigId??null,scopeId:o,bindings:o!=null?q(o)||[]:null}}export{B as optionRecordFrom,A as optionsForSetFrom,x as productOptionSetsFrom,w as readOptionSetInputs,O as sceneOptionSetsFrom};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{jsx as l,jsxs as x}from"react/jsx-runtime";import{useMemo as B,useSyncExternalStore as E}from"react";import u from"./be337ddda5.js";import _ from"./d94df858ea.js";import G from"./9c6c598569.js";import $ from"./872c4302e0.js";import{selectOptionForScene as M}from"./a77b15c0d6.js";import{subscribe as V,getVersion as C,isOptionVisible as O,isOptionAvailable as N,getPlacementBindings as W}from"./817d930a49.js";function j(s){const o=s?.textures?.diffuse??s?.diffuseMap??s?.diffuse_map??s?.materialJson?.map,f=r=>typeof r=="string"&&(r.startsWith("http")||r.startsWith("/")||r.startsWith("data:"));if(o)return{backgroundImage:`url("${f(o)?o:`/${o}`}")`,backgroundSize:"cover",backgroundPosition:"center"};let t=s?.color??s?.materialJson?.color;return typeof t=="number"?t=`#${t.toString(16).padStart(6,"0")}`:typeof t=="string"&&/^[0-9a-fA-F]{6}$/.test(t.trim())&&(t=`#${t.trim()}`),{background:t||"#cccccc"}}function w({configId:s}={}){E(V,C,C);const o=_(i=>i.sceneSelections),f=_(i=>i.setSceneSelection),t=u(i=>i.getSceneFeatures),r=u(i=>i.activeSceneConfigId),F=u(i=>i.defaultPresetId),S=u(i=>i.sceneConfigurations),b=$(i=>i.options),m=$(i=>i.materials),p=G(i=>i.selectedInstanceId),g=s||r||F||Object.keys(S||{})[0]||null,y=B(()=>g?t(g)||[]:[],[g,t,S]);if(!y.length)return null;const h=(i,n)=>{if(p==null)return!1;const c=(W(p)||[]).find(e=>String(e.optionSetId??e.option_set_id)===String(i));return!c||!Array.isArray(c.available)?!1:!c.available.some(e=>String(e)===String(n))},k=(i,n)=>{if(!O(i.id,n.id)||!N(i.id,n.id)||h(i.id,n.id))return;f(i.id,n.id);const a=n.optionSetId??n.option_set_id??i.feature_id??i.id;M({optionSetId:a,optionId:n.id}).catch(()=>{})},v=i=>i?.value!=null&&(m?.[i.value]||m?.[String(i.value)])||null,P=i=>typeof i=="object"?i:b?.[i]||b?.[String(i)];return l("div",{className:"sdk-option-sidebar",children:y.map(i=>{const n=(i.options||[]).map(P).filter(Boolean).filter(e=>O(i.id,e.id));if(!n.length)return null;const a=o?.[i.id]??o?.[String(i.id)],c=/finish/i.test(String(i.type||""))||n.every(e=>!!v(e));return x("section",{className:"sdk-option-sidebar__section",children:[l("h4",{className:"sdk-option-sidebar__title",children:i.name||`Option ${i.id}`}),l("div",{className:`sdk-option-sidebar__grid ${c?"is-finish":"is-options"}`,children:n.map(e=>{const A=String(e.id)===String(a),d=!N(i.id,e.id)||h(i.id,e.id),I=`sdk-option-tile${A?" is-selected":""}${d?" is-disabled":""}`;return c?l("button",{type:"button",className:`${I} is-swatch`,title:d?`${e.name||e.value} (Not available)`:e.name||e.value,style:j(v(e)),onClick:()=>k(i,e),"aria-disabled":d||void 0,disabled:d},e.id):l("button",{type:"button",className:I,onClick:()=>k(i,e),"aria-disabled":d||void 0,disabled:d,children:e.name||e.label||e.value||e.id},e.id)})})]},i.id)})})}export{w as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useMemo as l,useCallback as P}from"react";import m from"./9c6c598569.js";import{getPlacementType as f,PLACEMENT_TYPES as E}from"./4d7a0d1897.js";import{computeGaps as I,disarmPlacement as g}from"./ab6c80484f.js";function C({systemId:S,count:r,positionOf:i,insertAt:t,y:s=.6,armed:n=!0}){const p=m(e=>e.pendingPlacementPiece),o=f()===E.INSERT_BETWEEN&&(n?!!p:!0),a=l(()=>o?I(r,i,{y:s}):[],[o,r,s]),u=P(e=>{if(!n){t?.(e,null);return}const c=m.getState().pendingPlacementPiece;c&&(t?.(e,c),g())},[t,n]);return{active:o,gaps:a,onInsert:u}}export{C as usePlacementInteraction};
|