@design.estate/dees-catalog 3.28.1 β†’ 3.29.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.
@@ -1,6 +1,6 @@
1
1
  # DeesAppui
2
2
 
3
- A comprehensive application shell component providing a complete UI framework with navigation, menus, activity logging, and view management.
3
+ A comprehensive application shell component providing a complete UI framework with navigation, menus, activity logging, and view management. πŸš€
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -35,6 +35,34 @@ class MyApp extends DeesElement {
35
35
  }
36
36
  ```
37
37
 
38
+ ## Architecture Overview
39
+
40
+ The DeesAppui shell consists of several interconnected components:
41
+
42
+ ```
43
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
44
+ β”‚ AppBar (dees-appui-appbar) β”‚
45
+ β”‚ β”œβ”€β”€ Menus (File, Edit, View...) β”‚
46
+ β”‚ β”œβ”€β”€ Breadcrumbs β”‚
47
+ β”‚ β”œβ”€β”€ User Profile + Dropdown β”‚
48
+ β”‚ └── Activity Log Toggle β”‚
49
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
50
+ β”‚ Main Menu β”‚ Content Area β”‚ Activity Log β”‚
51
+ β”‚ (collapsed/ β”‚ β”œβ”€β”€ Content Tabs β”‚ (slide panel) β”‚
52
+ β”‚ expanded) β”‚ β”‚ (closable, from tables/lists)β”‚ β”‚
53
+ β”‚ β”‚ └── View Container β”‚ β”‚
54
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ └── Active View β”‚ β”‚
55
+ β”‚ β”‚ 🏠 Home β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚
56
+ β”‚ β”‚ πŸ“ Filesβ”‚ β”‚ Secondary Menu β”‚ β”‚ β”‚
57
+ β”‚ β”‚ βš™ Settings β”œβ”€β”€ Collapsible Groups β”‚ β”‚ β”‚
58
+ β”‚ β”‚ β”‚ β”‚ β”œβ”€β”€ Item 1 β”‚ β”‚ β”‚
59
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”œβ”€β”€ Item 2 (with badge) β”‚ β”‚ β”‚
60
+ β”‚ β”‚ └── Item 3 β”‚ β”‚ β”‚
61
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
62
+ ```
63
+
64
+ ---
65
+
38
66
  ## Configuration API
39
67
 
40
68
  ### `configure(config: IAppConfig)`
@@ -155,74 +183,289 @@ appui.removeMainMenuItem('Main', 'tasks');
155
183
 
156
184
  // Selection
157
185
  appui.setMainMenuSelection('dashboard');
158
- appui.setMainMenuCollapsed(true);
186
+
187
+ // Visibility control
188
+ appui.setMainMenuCollapsed(true); // Collapse to icon-only sidebar
189
+ appui.setMainMenuVisible(false); // Hide completely
159
190
 
160
191
  // Badges
161
192
  appui.setMainMenuBadge('inbox', 12);
162
193
  appui.clearMainMenuBadge('inbox');
163
194
  ```
164
195
 
165
- ### Secondary Menu API
196
+ ---
197
+
198
+ ## Secondary Menu API πŸ“‹
199
+
200
+ The secondary menu is a contextual sidebar that appears next to the main content area. It supports **collapsible groups** with icons and badges, making it perfect for:
166
201
 
167
- Views can control the secondary (contextual) menu.
202
+ - **Settings pages** (grouped settings categories)
203
+ - **File browsers** (folder trees)
204
+ - **Project navigation** (grouped by category)
205
+ - **Documentation** (chapters/sections)
206
+
207
+ ### Collapsible Groups
208
+
209
+ Groups can be collapsed/expanded by clicking the group header. The state is visually indicated with an icon rotation.
168
210
 
169
211
  ```typescript
170
- // Set menu
212
+ // Set secondary menu with collapsible groups
171
213
  appui.setSecondaryMenu({
172
214
  heading: 'Settings',
173
215
  groups: [
174
216
  {
175
217
  name: 'Account',
218
+ iconName: 'lucide:user', // Group icon
219
+ collapsed: false, // Initial state (default: false)
176
220
  items: [
177
- { key: 'profile', iconName: 'lucide:user', action: () => {} },
178
- { key: 'security', iconName: 'lucide:shield', action: () => {} },
221
+ { key: 'profile', iconName: 'lucide:user', action: () => showProfile() },
222
+ { key: 'security', iconName: 'lucide:shield', badge: '!', badgeVariant: 'warning', action: () => showSecurity() },
223
+ { key: 'billing', iconName: 'lucide:credit-card', action: () => showBilling() }
224
+ ]
225
+ },
226
+ {
227
+ name: 'Preferences',
228
+ iconName: 'lucide:settings',
229
+ collapsed: true, // Start collapsed
230
+ items: [
231
+ { key: 'notifications', iconName: 'lucide:bell', action: () => {} },
232
+ { key: 'appearance', iconName: 'lucide:palette', action: () => {} },
233
+ { key: 'language', iconName: 'lucide:globe', action: () => {} }
179
234
  ]
180
235
  }
181
236
  ]
182
237
  });
238
+ ```
239
+
240
+ ### Secondary Menu Item Properties
241
+
242
+ ```typescript
243
+ interface ISecondaryMenuItem {
244
+ key: string; // Unique identifier
245
+ iconName?: string; // Icon (e.g., 'lucide:user')
246
+ action: () => void; // Click handler
247
+ badge?: string | number; // Badge text/count
248
+ badgeVariant?: 'default' | 'success' | 'warning' | 'error';
249
+ }
183
250
 
184
- // Update group
185
- appui.updateSecondaryMenuGroup('Account', { items: newItems });
251
+ interface ISecondaryMenuGroup {
252
+ name: string; // Group name (shown in header)
253
+ iconName?: string; // Group icon
254
+ collapsed?: boolean; // Initial collapsed state
255
+ items: ISecondaryMenuItem[]; // Items in this group
256
+ }
257
+ ```
258
+
259
+ ### Updating Secondary Menu
260
+
261
+ ```typescript
262
+ // Update a specific group
263
+ appui.updateSecondaryMenuGroup('Account', {
264
+ items: [...newItems]
265
+ });
186
266
 
187
- // Add item
267
+ // Add item to a group
188
268
  appui.addSecondaryMenuItem('Account', {
189
- key: 'notifications',
190
- iconName: 'lucide:bell',
191
- action: () => {}
269
+ key: 'api-keys',
270
+ iconName: 'lucide:key',
271
+ action: () => showApiKeys()
192
272
  });
193
273
 
194
- // Selection
274
+ // Selection (highlights the item)
195
275
  appui.setSecondaryMenuSelection('profile');
196
276
 
277
+ // Visibility control
278
+ appui.setSecondaryMenuCollapsed(true); // Collapse panel
279
+ appui.setSecondaryMenuVisible(false); // Hide completely
280
+
197
281
  // Clear
198
282
  appui.clearSecondaryMenu();
199
283
  ```
200
284
 
201
- ### Content Tabs API
285
+ ### View-Specific Secondary Menus
286
+
287
+ Each view can define its own secondary menu that appears when the view is activated:
288
+
289
+ ```typescript
290
+ // In view definition
291
+ {
292
+ id: 'settings',
293
+ name: 'Settings',
294
+ content: 'my-settings-view',
295
+ secondaryMenu: [
296
+ {
297
+ name: 'General',
298
+ items: [
299
+ { key: 'account', iconName: 'lucide:user', action: () => {} },
300
+ { key: 'security', iconName: 'lucide:shield', action: () => {} }
301
+ ]
302
+ }
303
+ ]
304
+ }
305
+
306
+ // Or set dynamically in view's onActivate hook
307
+ onActivate(context: IViewActivationContext) {
308
+ context.appui.setSecondaryMenu({
309
+ heading: 'Project Files',
310
+ groups: [...]
311
+ });
312
+ }
313
+ ```
314
+
315
+ ---
316
+
317
+ ## Content Tabs API πŸ“‘
318
+
319
+ Content tabs appear above the main view content. They're designed for **opening multiple items** from tables, lists, or other data sourcesβ€”similar to browser tabs or IDE editor tabs.
202
320
 
203
- Control tabs in the main content area.
321
+ ### Common Use Cases
322
+
323
+ - **Table row details** - Click a row to open it as a tab
324
+ - **Document editing** - Open multiple documents
325
+ - **Entity inspection** - View customer, order, product details
326
+ - **Multi-file editing** - Edit multiple configuration files
327
+
328
+ ### Closable Tabs
329
+
330
+ Tabs can be closable, allowing users to open items, work with them, and close when done:
204
331
 
205
332
  ```typescript
206
- // Set tabs
333
+ // Set initial tabs
207
334
  appui.setContentTabs([
208
- { key: 'code', iconName: 'lucide:code', action: () => {} },
209
- { key: 'preview', iconName: 'lucide:eye', action: () => {} }
335
+ { key: 'overview', iconName: 'lucide:home', action: () => showOverview() },
336
+ { key: 'activity', iconName: 'lucide:activity', action: () => showActivity() }
210
337
  ]);
211
338
 
212
- // Add/remove
213
- appui.addContentTab({ key: 'debug', iconName: 'lucide:bug', action: () => {} });
339
+ // Add a closable tab when user clicks a table row
340
+ table.addEventListener('row-click', (e) => {
341
+ const item = e.detail.item;
342
+
343
+ appui.addContentTab({
344
+ key: `item-${item.id}`,
345
+ label: item.name, // Display label
346
+ iconName: 'lucide:file',
347
+ closable: true, // Allow closing
348
+ action: () => showItemDetails(item)
349
+ });
350
+
351
+ // Select the new tab
352
+ appui.selectContentTab(`item-${item.id}`);
353
+ });
354
+
355
+ // Handle tab close
356
+ appui.addEventListener('tab-close', (e) => {
357
+ const tabKey = e.detail.key;
358
+ // Cleanup resources if needed
359
+ console.log(`Tab ${tabKey} closed`);
360
+ });
361
+ ```
362
+
363
+ ### Tab Management
364
+
365
+ ```typescript
366
+ // Add/remove tabs
367
+ appui.addContentTab({
368
+ key: 'debug',
369
+ iconName: 'lucide:bug',
370
+ closable: true,
371
+ action: () => {}
372
+ });
214
373
  appui.removeContentTab('debug');
215
374
 
216
- // Select
375
+ // Select tab
217
376
  appui.selectContentTab('preview');
218
377
 
219
- // Get current
378
+ // Get current tab
220
379
  const current = appui.getSelectedContentTab();
380
+
381
+ // Visibility control
382
+ appui.setContentTabsVisible(false); // Hide tab bar
383
+
384
+ // Auto-hide when only one tab
385
+ appui.setContentTabsAutoHide(true, 1); // Hide when ≀ 1 tab
386
+ ```
387
+
388
+ ### Opening Items from Tables/Lists
389
+
390
+ A common pattern is opening table rows as closable tabs:
391
+
392
+ ```typescript
393
+ @customElement('my-customers-view')
394
+ class MyCustomersView extends DeesElement {
395
+ private appui: DeesAppui;
396
+
397
+ onActivate(context: IViewActivationContext) {
398
+ this.appui = context.appui;
399
+
400
+ // Set base tabs
401
+ this.appui.setContentTabs([
402
+ { key: 'list', label: 'All Customers', iconName: 'lucide:users', action: () => this.showList() }
403
+ ]);
404
+ }
405
+
406
+ render() {
407
+ return html`
408
+ <dees-table
409
+ .data=${this.customers}
410
+ @row-dblclick=${this.openCustomerTab}
411
+ ></dees-table>
412
+ `;
413
+ }
414
+
415
+ openCustomerTab(e: CustomEvent) {
416
+ const customer = e.detail.item;
417
+ const tabKey = `customer-${customer.id}`;
418
+
419
+ // Check if tab already exists
420
+ const existingTab = this.appui.getSelectedContentTab();
421
+ if (existingTab?.key === tabKey) {
422
+ return; // Already viewing this customer
423
+ }
424
+
425
+ // Add new closable tab
426
+ this.appui.addContentTab({
427
+ key: tabKey,
428
+ label: customer.name,
429
+ iconName: 'lucide:user',
430
+ closable: true,
431
+ action: () => this.showCustomerDetails(customer)
432
+ });
433
+
434
+ this.appui.selectContentTab(tabKey);
435
+ }
436
+
437
+ showCustomerDetails(customer: Customer) {
438
+ // Render customer details
439
+ this.currentView = html`<customer-details .customer=${customer}></customer-details>`;
440
+ }
441
+
442
+ showList() {
443
+ this.currentView = html`<dees-table ...></dees-table>`;
444
+ }
445
+ }
221
446
  ```
222
447
 
223
- ### Activity Log API
448
+ ---
449
+
450
+ ## Activity Log API πŸ“Š
451
+
452
+ The activity log is a slide-out panel on the right side showing user actions and system events.
224
453
 
225
- Add activity entries to the right-side activity log.
454
+ ### Activity Log Toggle
455
+
456
+ The appbar includes a toggle button with a badge showing the entry count:
457
+
458
+ ```typescript
459
+ // Control visibility
460
+ appui.setActivityLogVisible(true); // Show panel
461
+ appui.toggleActivityLog(); // Toggle state
462
+ const isVisible = appui.getActivityLogVisible();
463
+
464
+ // The toggle button automatically shows entry count
465
+ // Add entries and the badge updates automatically
466
+ ```
467
+
468
+ ### Adding Entries
226
469
 
227
470
  ```typescript
228
471
  // Add single entry
@@ -234,19 +477,35 @@ appui.activityLog.add({
234
477
  data: { invoiceId: '123' } // Optional metadata
235
478
  });
236
479
 
237
- // Add multiple
480
+ // Add multiple entries (e.g., from backend)
238
481
  appui.activityLog.addMany([...entries]);
239
482
 
240
- // Clear
483
+ // Clear all entries
241
484
  appui.activityLog.clear();
242
485
 
243
- // Query
486
+ // Query entries
244
487
  const entries = appui.activityLog.getEntries();
245
488
  const filtered = appui.activityLog.filter({ user: 'John', type: 'create' });
246
489
  const searched = appui.activityLog.search('invoice');
247
490
  ```
248
491
 
249
- ### Navigation API
492
+ ### Activity Entry Types
493
+
494
+ Each type has a default icon that can be overridden:
495
+
496
+ | Type | Default Icon | Use Case |
497
+ |------|--------------|----------|
498
+ | `login` | `lucide:log-in` | User sign-in |
499
+ | `logout` | `lucide:log-out` | User sign-out |
500
+ | `view` | `lucide:eye` | Page/item viewed |
501
+ | `create` | `lucide:plus` | New item created |
502
+ | `update` | `lucide:pencil` | Item modified |
503
+ | `delete` | `lucide:trash` | Item deleted |
504
+ | `custom` | `lucide:activity` | Custom events |
505
+
506
+ ---
507
+
508
+ ## Navigation API
250
509
 
251
510
  Navigate between views programmatically.
252
511
 
@@ -512,6 +771,7 @@ class CrmSettings extends DeesElement {
512
771
  groups: [
513
772
  {
514
773
  name: 'Account',
774
+ iconName: 'lucide:user',
515
775
  items: [
516
776
  { key: 'profile', iconName: 'lucide:user', action: () => this.showSection('profile') },
517
777
  { key: 'security', iconName: 'lucide:shield', action: () => this.showSection('security') }
@@ -519,6 +779,8 @@ class CrmSettings extends DeesElement {
519
779
  },
520
780
  {
521
781
  name: 'Preferences',
782
+ iconName: 'lucide:settings',
783
+ collapsed: true,
522
784
  items: [
523
785
  { key: 'notifications', iconName: 'lucide:bell', action: () => this.showSection('notifications') }
524
786
  ]
@@ -557,4 +819,5 @@ All interfaces are exported from `@design.estate/dees-catalog`:
557
819
  - `IAppBarMenuItem` - App bar menu item
558
820
  - `IMainMenuConfig` - Main menu configuration
559
821
  - `ISecondaryMenuGroup` - Secondary menu group
560
- - `ITab` - Tab definition
822
+ - `ISecondaryMenuItem` - Secondary menu item
823
+ - `IMenuItem` - Tab/menu item definition