@design.estate/dees-wcctools 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@design.estate/dees-wcctools",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
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": {
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@design.estate/dees-wcctools',
6
- version: '3.3.0',
6
+ version: '3.4.0',
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
  }
@@ -59,6 +59,9 @@ export class WccDashboard extends DeesElement {
59
59
  @property()
60
60
  accessor selectedTheme: TTheme = 'dark';
61
61
 
62
+ @property()
63
+ accessor searchQuery: string = '';
64
+
62
65
  // Derived from selectedViewport - no need for separate property
63
66
  public get isNative(): boolean {
64
67
  return this.selectedViewport === 'native';
@@ -118,6 +121,7 @@ export class WccDashboard extends DeesElement {
118
121
  <wcc-sidebar
119
122
  .dashboardRef=${this}
120
123
  .selectedItem=${this.selectedItem}
124
+ .searchQuery=${this.searchQuery}
121
125
  .isNative=${this.isNative}
122
126
  @selectedType=${(eventArg) => {
123
127
  this.selectedType = eventArg.detail;
@@ -128,6 +132,10 @@ export class WccDashboard extends DeesElement {
128
132
  @selectedItem=${(eventArg) => {
129
133
  this.selectedItem = eventArg.detail;
130
134
  }}
135
+ @searchChanged=${(eventArg: CustomEvent) => {
136
+ this.searchQuery = eventArg.detail;
137
+ this.updateUrlWithScrollState();
138
+ }}
131
139
  ></wcc-sidebar>
132
140
  <wcc-properties
133
141
  .dashboardRef=${this}
@@ -224,11 +232,17 @@ export class WccDashboard extends DeesElement {
224
232
  }
225
233
  }
226
234
 
227
- // Restore scroll positions from query parameters
235
+ // Restore state from query parameters
228
236
  if (routeInfo.queryParams) {
237
+ const search = routeInfo.queryParams.search;
229
238
  const frameScrollY = routeInfo.queryParams.frameScrollY;
230
239
  const sidebarScrollY = routeInfo.queryParams.sidebarScrollY;
231
240
 
241
+ if (search) {
242
+ this.searchQuery = search;
243
+ } else {
244
+ this.searchQuery = '';
245
+ }
232
246
  if (frameScrollY) {
233
247
  this.frameScrollY = parseInt(frameScrollY);
234
248
  }
@@ -240,6 +254,8 @@ export class WccDashboard extends DeesElement {
240
254
  setTimeout(() => {
241
255
  this.applyScrollPositions();
242
256
  }, 100);
257
+ } else {
258
+ this.searchQuery = '';
243
259
  }
244
260
 
245
261
  const domtoolsInstance = await plugins.deesDomtools.elementBasic.setup();
@@ -280,11 +296,17 @@ export class WccDashboard extends DeesElement {
280
296
  }
281
297
  }
282
298
 
283
- // Restore scroll positions from query parameters
299
+ // Restore state from query parameters
284
300
  if (routeInfo.queryParams) {
301
+ const search = routeInfo.queryParams.search;
285
302
  const frameScrollY = routeInfo.queryParams.frameScrollY;
286
303
  const sidebarScrollY = routeInfo.queryParams.sidebarScrollY;
287
304
 
305
+ if (search) {
306
+ this.searchQuery = search;
307
+ } else {
308
+ this.searchQuery = '';
309
+ }
288
310
  if (frameScrollY) {
289
311
  this.frameScrollY = parseInt(frameScrollY);
290
312
  }
@@ -296,6 +318,8 @@ export class WccDashboard extends DeesElement {
296
318
  setTimeout(() => {
297
319
  this.applyScrollPositions();
298
320
  }, 100);
321
+ } else {
322
+ this.searchQuery = '';
299
323
  }
300
324
 
301
325
  const domtoolsInstance = await plugins.deesDomtools.elementBasic.setup();
@@ -369,6 +393,9 @@ export class WccDashboard extends DeesElement {
369
393
  const baseUrl = `/wcctools-route/${sectionName}/${this.selectedItemName}/${this.selectedDemoIndex}/${this.selectedViewport}/${this.selectedTheme}`;
370
394
  const queryParams = new URLSearchParams();
371
395
 
396
+ if (this.searchQuery) {
397
+ queryParams.set('search', this.searchQuery);
398
+ }
372
399
  if (this.frameScrollY > 0) {
373
400
  queryParams.set('frameScrollY', this.frameScrollY.toString());
374
401
  }
@@ -426,6 +453,9 @@ export class WccDashboard extends DeesElement {
426
453
  const baseUrl = `/wcctools-route/${sectionName}/${this.selectedItemName}/${this.selectedDemoIndex}/${this.selectedViewport}/${this.selectedTheme}`;
427
454
  const queryParams = new URLSearchParams();
428
455
 
456
+ if (this.searchQuery) {
457
+ queryParams.set('search', this.searchQuery);
458
+ }
429
459
  if (this.frameScrollY > 0) {
430
460
  queryParams.set('frameScrollY', this.frameScrollY.toString());
431
461
  }
@@ -27,6 +27,10 @@ export class WccSidebar extends DeesElement {
27
27
  @state()
28
28
  accessor collapsedSections: Set<string> = new Set();
29
29
 
30
+ // Search query for filtering sidebar items
31
+ @property()
32
+ accessor searchQuery: string = '';
33
+
30
34
  private sectionsInitialized = false;
31
35
 
32
36
  public render(): TemplateResult {
@@ -252,7 +256,48 @@ export class WccSidebar extends DeesElement {
252
256
  ::-webkit-scrollbar-thumb:hover {
253
257
  background: rgba(255, 255, 255, 0.2);
254
258
  }
259
+
260
+ .search-container {
261
+ padding: 0.5rem;
262
+ border-bottom: 1px solid var(--border);
263
+ }
264
+
265
+ .search-input {
266
+ width: 100%;
267
+ box-sizing: border-box;
268
+ background: var(--input);
269
+ border: 1px solid var(--border);
270
+ border-radius: var(--radius);
271
+ padding: 0.5rem 0.75rem;
272
+ color: var(--foreground);
273
+ font-size: 0.75rem;
274
+ font-family: inherit;
275
+ outline: none;
276
+ transition: border-color 0.15s ease;
277
+ }
278
+
279
+ .search-input:focus {
280
+ border-color: var(--primary);
281
+ }
282
+
283
+ .search-input::placeholder {
284
+ color: var(--muted-foreground);
285
+ }
286
+
287
+ .highlight {
288
+ background: rgba(59, 130, 246, 0.3);
289
+ border-radius: 2px;
290
+ }
255
291
  </style>
292
+ <div class="search-container">
293
+ <input
294
+ type="text"
295
+ class="search-input"
296
+ placeholder="Search..."
297
+ .value=${this.searchQuery}
298
+ @input=${this.handleSearchInput}
299
+ />
300
+ </div>
256
301
  <div class="menu">
257
302
  ${this.renderSections()}
258
303
  </div>
@@ -282,6 +327,15 @@ export class WccSidebar extends DeesElement {
282
327
  this.initCollapsedSections();
283
328
 
284
329
  return this.dashboardRef.sections.map((section, index) => {
330
+ // Check if section has any matching items
331
+ const entries = getSectionItems(section);
332
+ const filteredEntries = entries.filter(([name]) => this.matchesSearch(name));
333
+
334
+ // Hide section if no items match the search
335
+ if (filteredEntries.length === 0 && this.searchQuery) {
336
+ return null;
337
+ }
338
+
285
339
  const isCollapsed = this.collapsedSections.has(section.name);
286
340
  const sectionIcon = section.icon || (section.type === 'pages' ? 'insert_drive_file' : 'widgets');
287
341
 
@@ -306,9 +360,11 @@ export class WccSidebar extends DeesElement {
306
360
  */
307
361
  private renderSectionItems(section: IWccSection) {
308
362
  const entries = getSectionItems(section);
363
+ // Filter entries by search query
364
+ const filteredEntries = entries.filter(([name]) => this.matchesSearch(name));
309
365
 
310
366
  if (section.type === 'pages') {
311
- return entries.map(([pageName, item]) => {
367
+ return filteredEntries.map(([pageName, item]) => {
312
368
  return html`
313
369
  <div
314
370
  class="selectOption ${this.selectedItem === item ? 'selected' : ''}"
@@ -318,13 +374,13 @@ export class WccSidebar extends DeesElement {
318
374
  }}
319
375
  >
320
376
  <i class="material-symbols-outlined">insert_drive_file</i>
321
- <div class="text">${pageName}</div>
377
+ <div class="text">${this.highlightMatch(pageName)}</div>
322
378
  </div>
323
379
  `;
324
380
  });
325
381
  } else {
326
382
  // type === 'elements'
327
- return entries.map(([elementName, item]) => {
383
+ return filteredEntries.map(([elementName, item]) => {
328
384
  const anonItem = item as any;
329
385
  const demoCount = anonItem.demo ? getDemoCount(anonItem.demo) : 0;
330
386
  const isMultiDemo = anonItem.demo && hasMultipleDemos(anonItem.demo);
@@ -340,7 +396,7 @@ export class WccSidebar extends DeesElement {
340
396
  >
341
397
  <i class="material-symbols-outlined expand-icon">chevron_right</i>
342
398
  <i class="material-symbols-outlined">folder</i>
343
- <div class="text">${elementName}</div>
399
+ <div class="text">${this.highlightMatch(elementName)}</div>
344
400
  </div>
345
401
  ${isExpanded ? html`
346
402
  <div class="demo-children">
@@ -374,7 +430,7 @@ export class WccSidebar extends DeesElement {
374
430
  }}
375
431
  >
376
432
  <i class="material-symbols-outlined">featured_video</i>
377
- <div class="text">${elementName}</div>
433
+ <div class="text">${this.highlightMatch(elementName)}</div>
378
434
  </div>
379
435
  `;
380
436
  }
@@ -402,6 +458,29 @@ export class WccSidebar extends DeesElement {
402
458
  this.expandedElements = newSet;
403
459
  }
404
460
 
461
+ private handleSearchInput(e: Event) {
462
+ const input = e.target as HTMLInputElement;
463
+ this.searchQuery = input.value;
464
+ this.dispatchEvent(new CustomEvent('searchChanged', { detail: this.searchQuery }));
465
+ }
466
+
467
+ private matchesSearch(name: string): boolean {
468
+ if (!this.searchQuery) return true;
469
+ return name.toLowerCase().includes(this.searchQuery.toLowerCase());
470
+ }
471
+
472
+ private highlightMatch(text: string): TemplateResult {
473
+ if (!this.searchQuery) return html`${text}`;
474
+ const lowerText = text.toLowerCase();
475
+ const lowerQuery = this.searchQuery.toLowerCase();
476
+ const index = lowerText.indexOf(lowerQuery);
477
+ if (index === -1) return html`${text}`;
478
+ const before = text.slice(0, index);
479
+ const match = text.slice(index, index + this.searchQuery.length);
480
+ const after = text.slice(index + this.searchQuery.length);
481
+ return html`${before}<span class="highlight">${match}</span>${after}`;
482
+ }
483
+
405
484
  protected updated(changedProperties: Map<string, unknown>) {
406
485
  super.updated(changedProperties);
407
486