@design.estate/dees-wcctools 1.3.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_bundle/bundle.js +197 -34
- package/dist_bundle/bundle.js.map +3 -3
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/wcc-dashboard.d.ts +1 -0
- package/dist_ts_web/elements/wcc-dashboard.js +60 -8
- package/dist_ts_web/elements/wcc-recording-panel.js +6 -2
- package/dist_ts_web/elements/wcc-sidebar.d.ts +3 -1
- package/dist_ts_web/elements/wcc-sidebar.js +133 -18
- package/dist_ts_web/elements/wcctools.helpers.d.ts +13 -0
- package/dist_ts_web/elements/wcctools.helpers.js +26 -1
- package/dist_ts_web/services/ffmpeg.service.d.ts +42 -0
- package/dist_ts_web/services/ffmpeg.service.js +276 -0
- package/dist_ts_web/services/mp4.service.d.ts +32 -0
- package/dist_ts_web/services/mp4.service.js +139 -0
- package/dist_ts_web/services/recorder.service.js +4 -3
- package/dist_watch/bundle.js +202 -35
- package/dist_watch/bundle.js.map +3 -3
- package/package.json +2 -2
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/wcc-dashboard.ts +76 -16
- package/ts_web/elements/wcc-recording-panel.ts +5 -1
- package/ts_web/elements/wcc-sidebar.ts +129 -18
- package/ts_web/elements/wcctools.helpers.ts +31 -0
- package/ts_web/services/recorder.service.ts +4 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@design.estate/dees-wcctools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.",
|
|
6
6
|
"exports": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@git.zone/tsbundle": "^2.6.3",
|
|
23
23
|
"@git.zone/tsrun": "^2.0.0",
|
|
24
24
|
"@git.zone/tstest": "^3.1.3",
|
|
25
|
-
"@git.zone/tswatch": "^2.3.
|
|
25
|
+
"@git.zone/tswatch": "^2.3.12",
|
|
26
26
|
"@push.rocks/projectinfo": "^5.0.2",
|
|
27
27
|
"@types/node": "^25.0.0"
|
|
28
28
|
},
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/dees-wcctools',
|
|
6
|
-
version: '
|
|
6
|
+
version: '2.0.1',
|
|
7
7
|
description: 'A set of web component tools for creating element catalogues, enabling the structured development and documentation of custom elements and pages.'
|
|
8
8
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DeesElement, property, html, customElement, type TemplateResult, queryAsync, render, domtools } from '@design.estate/dees-element';
|
|
2
|
-
import { resolveTemplateFactory } from './wcctools.helpers.js';
|
|
2
|
+
import { resolveTemplateFactory, getDemoAtIndex, getDemoCount, hasMultipleDemos } from './wcctools.helpers.js';
|
|
3
3
|
import type { TTemplateFactory } from './wcctools.helpers.js';
|
|
4
4
|
|
|
5
5
|
import * as plugins from '../wcctools.plugins.js';
|
|
@@ -25,6 +25,9 @@ export class WccDashboard extends DeesElement {
|
|
|
25
25
|
@property()
|
|
26
26
|
accessor selectedItem: TTemplateFactory | DeesElement;
|
|
27
27
|
|
|
28
|
+
@property({ type: Number })
|
|
29
|
+
accessor selectedDemoIndex: number = 0;
|
|
30
|
+
|
|
28
31
|
@property()
|
|
29
32
|
accessor selectedViewport: plugins.deesDomtools.breakpoints.TViewport = 'desktop';
|
|
30
33
|
|
|
@@ -151,11 +154,53 @@ export class WccDashboard extends DeesElement {
|
|
|
151
154
|
this.setupScrollListeners();
|
|
152
155
|
}, 500);
|
|
153
156
|
|
|
157
|
+
// Route with demo index (new format)
|
|
158
|
+
this.domtools.router.on(
|
|
159
|
+
'/wcctools-route/:itemType/:itemName/:demoIndex/:viewport/:theme',
|
|
160
|
+
async (routeInfo) => {
|
|
161
|
+
this.selectedType = routeInfo.params.itemType as TElementType;
|
|
162
|
+
this.selectedItemName = routeInfo.params.itemName;
|
|
163
|
+
this.selectedDemoIndex = parseInt(routeInfo.params.demoIndex) || 0;
|
|
164
|
+
this.selectedViewport = routeInfo.params.viewport as breakpoints.TViewport;
|
|
165
|
+
this.selectedTheme = routeInfo.params.theme as TTheme;
|
|
166
|
+
if (routeInfo.params.itemType === 'element') {
|
|
167
|
+
this.selectedItem = this.elements[routeInfo.params.itemName];
|
|
168
|
+
} else if (routeInfo.params.itemType === 'page') {
|
|
169
|
+
this.selectedItem = this.pages[routeInfo.params.itemName];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Restore scroll positions from query parameters
|
|
173
|
+
if (routeInfo.queryParams) {
|
|
174
|
+
const frameScrollY = routeInfo.queryParams.frameScrollY;
|
|
175
|
+
const sidebarScrollY = routeInfo.queryParams.sidebarScrollY;
|
|
176
|
+
|
|
177
|
+
if (frameScrollY) {
|
|
178
|
+
this.frameScrollY = parseInt(frameScrollY);
|
|
179
|
+
}
|
|
180
|
+
if (sidebarScrollY) {
|
|
181
|
+
this.sidebarScrollY = parseInt(sidebarScrollY);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Apply scroll positions after a short delay to ensure DOM is ready
|
|
185
|
+
setTimeout(() => {
|
|
186
|
+
this.applyScrollPositions();
|
|
187
|
+
}, 100);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const domtoolsInstance = await plugins.deesDomtools.elementBasic.setup();
|
|
191
|
+
this.selectedTheme === 'bright'
|
|
192
|
+
? domtoolsInstance.themeManager.goBright()
|
|
193
|
+
: domtoolsInstance.themeManager.goDark();
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
// Legacy route without demo index (for backwards compatibility)
|
|
154
198
|
this.domtools.router.on(
|
|
155
199
|
'/wcctools-route/:itemType/:itemName/:viewport/:theme',
|
|
156
200
|
async (routeInfo) => {
|
|
157
201
|
this.selectedType = routeInfo.params.itemType as TElementType;
|
|
158
202
|
this.selectedItemName = routeInfo.params.itemName;
|
|
203
|
+
this.selectedDemoIndex = 0; // Default to first demo
|
|
159
204
|
this.selectedViewport = routeInfo.params.viewport as breakpoints.TViewport;
|
|
160
205
|
this.selectedTheme = routeInfo.params.theme as TTheme;
|
|
161
206
|
if (routeInfo.params.itemType === 'element') {
|
|
@@ -163,25 +208,25 @@ export class WccDashboard extends DeesElement {
|
|
|
163
208
|
} else if (routeInfo.params.itemType === 'page') {
|
|
164
209
|
this.selectedItem = this.pages[routeInfo.params.itemName];
|
|
165
210
|
}
|
|
166
|
-
|
|
211
|
+
|
|
167
212
|
// Restore scroll positions from query parameters
|
|
168
213
|
if (routeInfo.queryParams) {
|
|
169
214
|
const frameScrollY = routeInfo.queryParams.frameScrollY;
|
|
170
215
|
const sidebarScrollY = routeInfo.queryParams.sidebarScrollY;
|
|
171
|
-
|
|
216
|
+
|
|
172
217
|
if (frameScrollY) {
|
|
173
218
|
this.frameScrollY = parseInt(frameScrollY);
|
|
174
219
|
}
|
|
175
220
|
if (sidebarScrollY) {
|
|
176
221
|
this.sidebarScrollY = parseInt(sidebarScrollY);
|
|
177
222
|
}
|
|
178
|
-
|
|
223
|
+
|
|
179
224
|
// Apply scroll positions after a short delay to ensure DOM is ready
|
|
180
225
|
setTimeout(() => {
|
|
181
226
|
this.applyScrollPositions();
|
|
182
227
|
}, 100);
|
|
183
228
|
}
|
|
184
|
-
|
|
229
|
+
|
|
185
230
|
const domtoolsInstance = await plugins.deesDomtools.elementBasic.setup();
|
|
186
231
|
this.selectedTheme === 'bright'
|
|
187
232
|
? domtoolsInstance.themeManager.goBright()
|
|
@@ -218,33 +263,48 @@ export class WccDashboard extends DeesElement {
|
|
|
218
263
|
this.setWarning(`component ${anonItem.name} does not expose a demo property.`);
|
|
219
264
|
return;
|
|
220
265
|
}
|
|
221
|
-
|
|
266
|
+
|
|
267
|
+
// Support both single demo (function) and multiple demos (array)
|
|
268
|
+
const isArray = Array.isArray(anonItem.demo);
|
|
269
|
+
const isFunction = typeof anonItem.demo === 'function';
|
|
270
|
+
|
|
271
|
+
if (!isArray && !isFunction) {
|
|
222
272
|
this.setWarning(
|
|
223
|
-
`component ${anonItem.name} has demo property, but it is not of
|
|
273
|
+
`component ${anonItem.name} has demo property, but it is not a function or array of functions`
|
|
224
274
|
);
|
|
225
275
|
return;
|
|
226
276
|
}
|
|
277
|
+
|
|
278
|
+
// Get the specific demo to render
|
|
279
|
+
const demoFactory = getDemoAtIndex(anonItem.demo, this.selectedDemoIndex);
|
|
280
|
+
if (!demoFactory) {
|
|
281
|
+
this.setWarning(
|
|
282
|
+
`component ${anonItem.name} does not have a demo at index ${this.selectedDemoIndex + 1}`
|
|
283
|
+
);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
|
|
227
287
|
this.setWarning(null);
|
|
228
288
|
const viewport = await wccFrame.getViewportElement();
|
|
229
|
-
const demoTemplate = await resolveTemplateFactory(
|
|
289
|
+
const demoTemplate = await resolveTemplateFactory(demoFactory);
|
|
230
290
|
render(demoTemplate, viewport);
|
|
231
291
|
}
|
|
232
292
|
}
|
|
233
293
|
|
|
234
294
|
public buildUrl() {
|
|
235
|
-
const baseUrl = `/wcctools-route/${this.selectedType}/${this.selectedItemName}/${this.selectedViewport}/${this.selectedTheme}`;
|
|
295
|
+
const baseUrl = `/wcctools-route/${this.selectedType}/${this.selectedItemName}/${this.selectedDemoIndex}/${this.selectedViewport}/${this.selectedTheme}`;
|
|
236
296
|
const queryParams = new URLSearchParams();
|
|
237
|
-
|
|
297
|
+
|
|
238
298
|
if (this.frameScrollY > 0) {
|
|
239
299
|
queryParams.set('frameScrollY', this.frameScrollY.toString());
|
|
240
300
|
}
|
|
241
301
|
if (this.sidebarScrollY > 0) {
|
|
242
302
|
queryParams.set('sidebarScrollY', this.sidebarScrollY.toString());
|
|
243
303
|
}
|
|
244
|
-
|
|
304
|
+
|
|
245
305
|
const queryString = queryParams.toString();
|
|
246
306
|
const fullUrl = queryString ? `${baseUrl}?${queryString}` : baseUrl;
|
|
247
|
-
|
|
307
|
+
|
|
248
308
|
this.domtools.router.pushUrl(fullUrl);
|
|
249
309
|
}
|
|
250
310
|
|
|
@@ -286,19 +346,19 @@ export class WccDashboard extends DeesElement {
|
|
|
286
346
|
}
|
|
287
347
|
|
|
288
348
|
private updateUrlWithScrollState() {
|
|
289
|
-
const baseUrl = `/wcctools-route/${this.selectedType}/${this.selectedItemName}/${this.selectedViewport}/${this.selectedTheme}`;
|
|
349
|
+
const baseUrl = `/wcctools-route/${this.selectedType}/${this.selectedItemName}/${this.selectedDemoIndex}/${this.selectedViewport}/${this.selectedTheme}`;
|
|
290
350
|
const queryParams = new URLSearchParams();
|
|
291
|
-
|
|
351
|
+
|
|
292
352
|
if (this.frameScrollY > 0) {
|
|
293
353
|
queryParams.set('frameScrollY', this.frameScrollY.toString());
|
|
294
354
|
}
|
|
295
355
|
if (this.sidebarScrollY > 0) {
|
|
296
356
|
queryParams.set('sidebarScrollY', this.sidebarScrollY.toString());
|
|
297
357
|
}
|
|
298
|
-
|
|
358
|
+
|
|
299
359
|
const queryString = queryParams.toString();
|
|
300
360
|
const fullUrl = queryString ? `${baseUrl}?${queryString}` : baseUrl;
|
|
301
|
-
|
|
361
|
+
|
|
302
362
|
// Use replaceState to update URL without navigation
|
|
303
363
|
window.history.replaceState(null, '', fullUrl);
|
|
304
364
|
}
|
|
@@ -552,6 +552,7 @@ export class WccRecordingPanel extends DeesElement {
|
|
|
552
552
|
@keyframes spin {
|
|
553
553
|
to { transform: rotate(360deg); }
|
|
554
554
|
}
|
|
555
|
+
|
|
555
556
|
`
|
|
556
557
|
];
|
|
557
558
|
|
|
@@ -706,6 +707,7 @@ export class WccRecordingPanel extends DeesElement {
|
|
|
706
707
|
</button>
|
|
707
708
|
</div>
|
|
708
709
|
</div>
|
|
710
|
+
|
|
709
711
|
</div>
|
|
710
712
|
<div class="preview-modal-actions">
|
|
711
713
|
<button class="preview-btn secondary" @click=${() => this.discardRecording()}>Discard</button>
|
|
@@ -714,7 +716,7 @@ export class WccRecordingPanel extends DeesElement {
|
|
|
714
716
|
?disabled=${this.isExporting}
|
|
715
717
|
@click=${() => this.downloadRecording()}
|
|
716
718
|
>
|
|
717
|
-
${this.isExporting ? html`<span class="export-spinner"></span>Exporting...` : 'Download'}
|
|
719
|
+
${this.isExporting ? html`<span class="export-spinner"></span>Exporting...` : 'Download WebM'}
|
|
718
720
|
</button>
|
|
719
721
|
</div>
|
|
720
722
|
</div>
|
|
@@ -815,6 +817,7 @@ export class WccRecordingPanel extends DeesElement {
|
|
|
815
817
|
try {
|
|
816
818
|
let blobToDownload: Blob;
|
|
817
819
|
|
|
820
|
+
// Handle trimming if needed
|
|
818
821
|
const needsTrim = this.trimStart > 0.1 || this.trimEnd < this.videoDuration - 0.1;
|
|
819
822
|
|
|
820
823
|
if (needsTrim) {
|
|
@@ -828,6 +831,7 @@ export class WccRecordingPanel extends DeesElement {
|
|
|
828
831
|
blobToDownload = recordedBlob;
|
|
829
832
|
}
|
|
830
833
|
|
|
834
|
+
// Trigger download
|
|
831
835
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
832
836
|
const filename = `wcctools-recording-${timestamp}.webm`;
|
|
833
837
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as plugins from '../wcctools.plugins.js';
|
|
2
|
-
import { DeesElement, property, html, customElement, type TemplateResult } from '@design.estate/dees-element';
|
|
2
|
+
import { DeesElement, property, html, customElement, type TemplateResult, state } from '@design.estate/dees-element';
|
|
3
3
|
import { WccDashboard } from './wcc-dashboard.js';
|
|
4
4
|
import type { TTemplateFactory } from './wcctools.helpers.js';
|
|
5
|
+
import { getDemoCount, hasMultipleDemos } from './wcctools.helpers.js';
|
|
5
6
|
|
|
6
7
|
export type TElementType = 'element' | 'page';
|
|
7
8
|
|
|
@@ -19,6 +20,10 @@ export class WccSidebar extends DeesElement {
|
|
|
19
20
|
@property()
|
|
20
21
|
accessor isFullscreen: boolean = false;
|
|
21
22
|
|
|
23
|
+
// Track which elements are expanded (for multi-demo elements)
|
|
24
|
+
@state()
|
|
25
|
+
accessor expandedElements: Set<string> = new Set();
|
|
26
|
+
|
|
22
27
|
public render(): TemplateResult {
|
|
23
28
|
return html`
|
|
24
29
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet" />
|
|
@@ -110,7 +115,21 @@ export class WccSidebar extends DeesElement {
|
|
|
110
115
|
color: #999;
|
|
111
116
|
background: transparent;
|
|
112
117
|
}
|
|
113
|
-
|
|
118
|
+
|
|
119
|
+
.selectOption.folder {
|
|
120
|
+
grid-template-columns: 16px 20px 1fr;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.selectOption .expand-icon {
|
|
124
|
+
font-size: 14px;
|
|
125
|
+
opacity: 0.5;
|
|
126
|
+
transition: transform 0.2s ease;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.selectOption.expanded .expand-icon {
|
|
130
|
+
transform: rotate(90deg);
|
|
131
|
+
}
|
|
132
|
+
|
|
114
133
|
.selectOption:hover {
|
|
115
134
|
background: rgba(59, 130, 246, 0.05);
|
|
116
135
|
color: #bbb;
|
|
@@ -143,6 +162,42 @@ export class WccSidebar extends DeesElement {
|
|
|
143
162
|
font-weight: 400;
|
|
144
163
|
}
|
|
145
164
|
|
|
165
|
+
.demo-children {
|
|
166
|
+
margin-left: 1rem;
|
|
167
|
+
overflow: hidden;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.demo-child {
|
|
171
|
+
user-select: none;
|
|
172
|
+
position: relative;
|
|
173
|
+
margin: 0.125rem 0.5rem;
|
|
174
|
+
padding: 0.35rem 0.75rem;
|
|
175
|
+
transition: all 0.15s ease;
|
|
176
|
+
display: grid;
|
|
177
|
+
grid-template-columns: 16px 1fr;
|
|
178
|
+
align-items: center;
|
|
179
|
+
gap: 0.5rem;
|
|
180
|
+
border-radius: var(--radius);
|
|
181
|
+
cursor: pointer;
|
|
182
|
+
font-size: 0.7rem;
|
|
183
|
+
color: #777;
|
|
184
|
+
background: transparent;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.demo-child:hover {
|
|
188
|
+
background: rgba(59, 130, 246, 0.05);
|
|
189
|
+
color: #bbb;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.demo-child.selected {
|
|
193
|
+
background: rgba(59, 130, 246, 0.15);
|
|
194
|
+
color: var(--primary);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.demo-child .material-symbols-outlined {
|
|
198
|
+
font-size: 14px;
|
|
199
|
+
}
|
|
200
|
+
|
|
146
201
|
::-webkit-scrollbar {
|
|
147
202
|
width: 8px;
|
|
148
203
|
}
|
|
@@ -171,7 +226,7 @@ export class WccSidebar extends DeesElement {
|
|
|
171
226
|
class="selectOption ${this.selectedItem === item ? 'selected' : null}"
|
|
172
227
|
@click=${async () => {
|
|
173
228
|
const domtools = await plugins.deesDomtools.DomTools.setupDomTools();
|
|
174
|
-
this.selectItem('page', pageName, item);
|
|
229
|
+
this.selectItem('page', pageName, item, 0);
|
|
175
230
|
}}
|
|
176
231
|
>
|
|
177
232
|
<i class="material-symbols-outlined">insert_drive_file</i>
|
|
@@ -184,31 +239,83 @@ export class WccSidebar extends DeesElement {
|
|
|
184
239
|
${(() => {
|
|
185
240
|
const elements = Object.keys(this.dashboardRef.elements);
|
|
186
241
|
return elements.map(elementName => {
|
|
187
|
-
const item = this.dashboardRef.elements[elementName];
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
242
|
+
const item = this.dashboardRef.elements[elementName] as any;
|
|
243
|
+
const demoCount = item.demo ? getDemoCount(item.demo) : 0;
|
|
244
|
+
const isMultiDemo = item.demo && hasMultipleDemos(item.demo);
|
|
245
|
+
const isExpanded = this.expandedElements.has(elementName);
|
|
246
|
+
const isSelected = this.selectedItem === item;
|
|
247
|
+
|
|
248
|
+
if (isMultiDemo) {
|
|
249
|
+
// Multi-demo element - render as expandable folder
|
|
250
|
+
return html`
|
|
251
|
+
<div
|
|
252
|
+
class="selectOption folder ${isExpanded ? 'expanded' : ''} ${isSelected ? 'selected' : ''}"
|
|
253
|
+
@click=${() => this.toggleExpanded(elementName)}
|
|
254
|
+
>
|
|
255
|
+
<i class="material-symbols-outlined expand-icon">chevron_right</i>
|
|
256
|
+
<i class="material-symbols-outlined">folder</i>
|
|
257
|
+
<div class="text">${elementName}</div>
|
|
258
|
+
</div>
|
|
259
|
+
${isExpanded ? html`
|
|
260
|
+
<div class="demo-children">
|
|
261
|
+
${Array.from({ length: demoCount }, (_, i) => {
|
|
262
|
+
const demoIndex = i;
|
|
263
|
+
const isThisDemoSelected = isSelected && this.dashboardRef.selectedDemoIndex === demoIndex;
|
|
264
|
+
return html`
|
|
265
|
+
<div
|
|
266
|
+
class="demo-child ${isThisDemoSelected ? 'selected' : ''}"
|
|
267
|
+
@click=${async () => {
|
|
268
|
+
await plugins.deesDomtools.DomTools.setupDomTools();
|
|
269
|
+
this.selectItem('element', elementName, item, demoIndex);
|
|
270
|
+
}}
|
|
271
|
+
>
|
|
272
|
+
<i class="material-symbols-outlined">play_circle</i>
|
|
273
|
+
<div class="text">demo${demoIndex + 1}</div>
|
|
274
|
+
</div>
|
|
275
|
+
`;
|
|
276
|
+
})}
|
|
277
|
+
</div>
|
|
278
|
+
` : null}
|
|
279
|
+
`;
|
|
280
|
+
} else {
|
|
281
|
+
// Single demo element - render as normal
|
|
282
|
+
return html`
|
|
283
|
+
<div
|
|
284
|
+
class="selectOption ${isSelected ? 'selected' : null}"
|
|
285
|
+
@click=${async () => {
|
|
286
|
+
await plugins.deesDomtools.DomTools.setupDomTools();
|
|
287
|
+
this.selectItem('element', elementName, item, 0);
|
|
288
|
+
}}
|
|
289
|
+
>
|
|
290
|
+
<i class="material-symbols-outlined">featured_video</i>
|
|
291
|
+
<div class="text">${elementName}</div>
|
|
292
|
+
</div>
|
|
293
|
+
`;
|
|
294
|
+
}
|
|
200
295
|
});
|
|
201
296
|
})()}
|
|
202
297
|
</div>
|
|
203
298
|
`;
|
|
204
299
|
}
|
|
205
300
|
|
|
206
|
-
|
|
301
|
+
private toggleExpanded(elementName: string) {
|
|
302
|
+
const newSet = new Set(this.expandedElements);
|
|
303
|
+
if (newSet.has(elementName)) {
|
|
304
|
+
newSet.delete(elementName);
|
|
305
|
+
} else {
|
|
306
|
+
newSet.add(elementName);
|
|
307
|
+
}
|
|
308
|
+
this.expandedElements = newSet;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
public selectItem(typeArg: TElementType, itemNameArg: string, itemArg: TTemplateFactory | DeesElement, demoIndex: number = 0) {
|
|
207
312
|
console.log('selected item');
|
|
208
313
|
console.log(itemNameArg);
|
|
209
314
|
console.log(itemArg);
|
|
315
|
+
console.log('demo index:', demoIndex);
|
|
210
316
|
this.selectedItem = itemArg;
|
|
211
317
|
this.selectedType = typeArg;
|
|
318
|
+
this.dashboardRef.selectedDemoIndex = demoIndex;
|
|
212
319
|
this.dispatchEvent(
|
|
213
320
|
new CustomEvent('selectedType', {
|
|
214
321
|
detail: typeArg
|
|
@@ -224,7 +331,11 @@ export class WccSidebar extends DeesElement {
|
|
|
224
331
|
detail: itemArg
|
|
225
332
|
})
|
|
226
333
|
);
|
|
227
|
-
|
|
334
|
+
|
|
228
335
|
this.dashboardRef.buildUrl();
|
|
336
|
+
|
|
337
|
+
// Force re-render to update demo child selection indicator
|
|
338
|
+
// (needed when switching between demos of the same element)
|
|
339
|
+
this.requestUpdate();
|
|
229
340
|
}
|
|
230
341
|
}
|
|
@@ -2,8 +2,39 @@ import type { TemplateResult } from 'lit';
|
|
|
2
2
|
|
|
3
3
|
export type TTemplateFactory = () => TemplateResult | Promise<TemplateResult>;
|
|
4
4
|
|
|
5
|
+
// Demo can be a single function or an array of functions
|
|
6
|
+
export type TDemoDefinition = TTemplateFactory | TTemplateFactory[];
|
|
7
|
+
|
|
5
8
|
export const resolveTemplateFactory = async (
|
|
6
9
|
factoryArg: TTemplateFactory
|
|
7
10
|
): Promise<TemplateResult> => {
|
|
8
11
|
return await Promise.resolve(factoryArg());
|
|
9
12
|
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the number of demos for an element
|
|
16
|
+
*/
|
|
17
|
+
export const getDemoCount = (demo: TDemoDefinition): number => {
|
|
18
|
+
if (Array.isArray(demo)) {
|
|
19
|
+
return demo.length;
|
|
20
|
+
}
|
|
21
|
+
return 1;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get a specific demo by index (0-based internally, displayed as 1-based)
|
|
26
|
+
*/
|
|
27
|
+
export const getDemoAtIndex = (demo: TDemoDefinition, index: number): TTemplateFactory | null => {
|
|
28
|
+
if (Array.isArray(demo)) {
|
|
29
|
+
return demo[index] ?? null;
|
|
30
|
+
}
|
|
31
|
+
// Single demo - only index 0 is valid
|
|
32
|
+
return index === 0 ? demo : null;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Check if an element has multiple demos
|
|
37
|
+
*/
|
|
38
|
+
export const hasMultipleDemos = (demo: TDemoDefinition): boolean => {
|
|
39
|
+
return Array.isArray(demo) && demo.length > 1;
|
|
40
|
+
};
|
|
@@ -235,9 +235,11 @@ export class RecorderService {
|
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
private handleRecordingComplete(): void {
|
|
238
|
+
private async handleRecordingComplete(): Promise<void> {
|
|
239
239
|
// Create blob from recorded chunks
|
|
240
|
-
|
|
240
|
+
const blob = new Blob(this.recordedChunks, { type: 'video/webm' });
|
|
241
|
+
|
|
242
|
+
this._recordedBlob = blob;
|
|
241
243
|
|
|
242
244
|
// Stop all tracks
|
|
243
245
|
if (this.currentStream) {
|