diff --git a/changelog.md b/changelog.md
index 6d919a2..2eb220b 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,15 @@
# Changelog
+## 2025-12-08 - 3.0.0 - BREAKING CHANGE(dees-appui-secondarymenu)
+Add SecondaryMenu component and replace Mainselector with new SecondaryMenu in AppUI
+
+- Add dees-appui-secondarymenu component: collapsible groups, badges, dynamic heading, context menu and legacy flat-options support
+- Introduce interfaces ISecondaryMenuItem and ISecondaryMenuGroup under elements/interfaces
+- Replace dees-appui-mainselector usage with dees-appui-secondarymenu in DeesAppuiBase (props/events updated: secondarymenuGroups, secondarymenuHeading, secondarymenuOptions, item-select / secondarymenu-item-select)
+- Remove dees-appui-mainselector implementation and its index export; update group exports and imports to expose secondarymenu
+- Update demos and pages to showcase the new SecondaryMenu and adjust import paths for grouped components
+- Bump devDependency @git.zone/tswatch to ^2.3.1
+
## 2025-12-08 - 2.0.7 - fix(structure)
Add many new UI components, input controls, charts, editors, and demos
diff --git a/package.json b/package.json
index a79c34f..b661ac4 100644
--- a/package.json
+++ b/package.json
@@ -48,7 +48,7 @@
"@git.zone/tsbuild": "^3.1.2",
"@git.zone/tsbundle": "^2.6.3",
"@git.zone/tstest": "^3.1.3",
- "@git.zone/tswatch": "^2.2.3",
+ "@git.zone/tswatch": "^2.3.1",
"@push.rocks/projectinfo": "^5.0.2",
"@push.rocks/tapbundle": "^6.0.3",
"@types/node": "^24.10.1"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 668416e..bdcd461 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -98,10 +98,10 @@ importers:
version: 2.6.3
'@git.zone/tstest':
specifier: ^3.1.3
- version: 3.1.3(socks@2.8.7)(typescript@5.9.3)
+ version: 3.1.3(@push.rocks/smartserve@1.3.0)(socks@2.8.7)(typescript@5.9.3)
'@git.zone/tswatch':
- specifier: ^2.2.3
- version: 2.2.3
+ specifier: ^2.3.1
+ version: 2.3.1(@tiptap/pm@2.27.1)
'@push.rocks/projectinfo':
specifier: ^5.0.2
version: 5.0.2
@@ -126,6 +126,9 @@ packages:
'@api.global/typedserver@3.0.80':
resolution: {integrity: sha512-dcp0oXsjBL+XdFg1wUUP08uJQid5bQ0Yv3V3Y3lnI2QCbat0FU+Tsb0TZRnZ4+P150Vj/ITBqJUgDzFsF34grA==}
+ '@api.global/typedserver@7.11.0':
+ resolution: {integrity: sha512-DHB3oGRgiLbAeRRFAlXIbjvNACw9YqsfOtLVCPq0nUcGMGSsUQ4SNrJ5OGk9GhVF8bl/jn8SF8w08rnApmZ0uw==}
+
'@api.global/typedsocket@3.1.1':
resolution: {integrity: sha512-Wkz3NlhmfdZMKqXXI2c2dMtGGmSmhdOegZiziL+9b2mqPYdc7Gd8AZRdEOKvbSoIvc9G22/5BEadIWHrfq66TA==}
peerDependencies:
@@ -134,6 +137,11 @@ packages:
'@push.rocks/smartserve':
optional: true
+ '@api.global/typedsocket@4.1.0':
+ resolution: {integrity: sha512-ttmoU5BNHmLAkAF/o+Ta8F5O4F7CUmkFo6LK7NKHQvuYJvodPMYWdhJ6yCINTF4pfCgljkMDUqoVKobm6ea4mQ==}
+ peerDependencies:
+ '@push.rocks/smartserve': '>=1.1.0'
+
'@aws-crypto/crc32@5.2.0':
resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==}
engines: {node: '>=16.0.0'}
@@ -321,6 +329,9 @@ packages:
'@dabh/diagnostics@2.0.8':
resolution: {integrity: sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==}
+ '@design.estate/dees-catalog@2.0.7':
+ resolution: {integrity: sha512-rshv71LqA2PXaEEf6C1/hv6Yu2ovRuWaZhdnUznCDpjdYgxBq7PHkiHCNvg/m6wJ9Ue/03HcuuPqtj2bksgAag==}
+
'@design.estate/dees-comms@1.0.30':
resolution: {integrity: sha512-KchMlklJfKAjQiJiR0xmofXtQ27VgZtBIxcMwPE9d+h3jJRv+lPZxzBQVOM0eyM0uS44S5vJMZ11IeV4uDXSHg==}
@@ -541,8 +552,8 @@ packages:
resolution: {integrity: sha512-t+/cKV21JHK8X7NGAmihs5M/eMm+V+jn4R5rzfwGG97WJFAcP5qE1Os9VYtyZw3tx/NZXA2yA4abo/ELluTuRA==}
hasBin: true
- '@git.zone/tswatch@2.2.3':
- resolution: {integrity: sha512-BKyVYXWOjVL+eUcnwjfTKFhUsEBHpgpSv5rbuZYOhmVp9BcglWaEswuAstGEISkCioizUcHiZkpJVPXO99sLHQ==}
+ '@git.zone/tswatch@2.3.1':
+ resolution: {integrity: sha512-KjJRXs+XkXXXDUqmEb1tZuDM1IEVI/RzAo3wS2bFv/UhOY7iYAxPL+eKl55FxBFftB4ecAfxeBhbhijTbklAMA==}
hasBin: true
'@hapi/bourne@3.0.0':
@@ -970,6 +981,9 @@ packages:
'@push.rocks/smarts3@3.0.3':
resolution: {integrity: sha512-Y9nXMwurthJ9Z7yi0RwjhPFUC58aY8Mhia8kFo6Xj1tBM4LE8Oxg/ydejF7otHqQGr3QyqV5C4YrDEG17rUuzg==}
+ '@push.rocks/smartserve@1.3.0':
+ resolution: {integrity: sha512-4ZR9uKVWXVAPzU5wtCQ1mA9jNmOlUl3oGr50EceLT6803UwbNcst7Ek/BhzSaZ0qb2pz0jO5T/V+icgvZ1/5ww==}
+
'@push.rocks/smartshell@3.3.0':
resolution: {integrity: sha512-m0w618H6YBs+vXGz1CgS4nPi5CUAnqRtckcS9/koGwfcIx1IpjqmiP47BoCTbdgcv0IPUxQVBG1IXTHPuZ8Z5g==}
@@ -4642,11 +4656,11 @@ snapshots:
'@push.rocks/webrequest': 3.0.37
'@push.rocks/webstream': 1.0.10
- '@api.global/typedserver@3.0.80':
+ '@api.global/typedserver@3.0.80(@push.rocks/smartserve@1.3.0)':
dependencies:
'@api.global/typedrequest': 3.2.5
'@api.global/typedrequest-interfaces': 3.0.19
- '@api.global/typedsocket': 3.1.1
+ '@api.global/typedsocket': 3.1.1(@push.rocks/smartserve@1.3.0)
'@cloudflare/workers-types': 4.20251205.0
'@design.estate/dees-comms': 1.0.30
'@push.rocks/lik': 6.2.2
@@ -4690,7 +4704,53 @@ snapshots:
- utf-8-validate
- vue
- '@api.global/typedsocket@3.1.1':
+ '@api.global/typedserver@7.11.0(@tiptap/pm@2.27.1)':
+ dependencies:
+ '@api.global/typedrequest': 3.2.5
+ '@api.global/typedrequest-interfaces': 3.0.19
+ '@api.global/typedsocket': 4.1.0(@push.rocks/smartserve@1.3.0)
+ '@cloudflare/workers-types': 4.20251205.0
+ '@design.estate/dees-catalog': 2.0.7(@tiptap/pm@2.27.1)
+ '@design.estate/dees-comms': 1.0.30
+ '@push.rocks/lik': 6.2.2
+ '@push.rocks/smartdelay': 3.0.5
+ '@push.rocks/smartenv': 6.0.0
+ '@push.rocks/smartfeed': 1.4.0
+ '@push.rocks/smartfile': 13.1.0
+ '@push.rocks/smartfs': 1.2.0
+ '@push.rocks/smartjson': 5.2.0
+ '@push.rocks/smartlog': 3.1.10
+ '@push.rocks/smartlog-destination-devtools': 1.0.12
+ '@push.rocks/smartlog-interfaces': 3.0.2
+ '@push.rocks/smartmanifest': 2.0.2
+ '@push.rocks/smartmatch': 2.0.0
+ '@push.rocks/smartmime': 2.0.4
+ '@push.rocks/smartntml': 2.0.8
+ '@push.rocks/smartopen': 2.0.0
+ '@push.rocks/smartpath': 6.0.0
+ '@push.rocks/smartpromise': 4.2.3
+ '@push.rocks/smartrequest': 5.0.1
+ '@push.rocks/smartrx': 3.0.10
+ '@push.rocks/smartserve': 1.3.0
+ '@push.rocks/smartsitemap': 2.0.4
+ '@push.rocks/smartstream': 3.2.5
+ '@push.rocks/smarttime': 4.1.1
+ '@push.rocks/smartwatch': 5.0.0
+ '@push.rocks/taskbuffer': 3.5.0
+ '@push.rocks/webrequest': 4.0.1
+ '@push.rocks/webstore': 2.0.20
+ '@tsclass/tsclass': 9.3.0
+ lit: 3.3.1
+ transitivePeerDependencies:
+ - '@nuxt/kit'
+ - '@tiptap/pm'
+ - bufferutil
+ - react
+ - supports-color
+ - utf-8-validate
+ - vue
+
+ '@api.global/typedsocket@3.1.1(@push.rocks/smartserve@1.3.0)':
dependencies:
'@api.global/typedrequest': 3.2.5
'@api.global/typedrequest-interfaces': 3.0.19
@@ -4700,6 +4760,8 @@ snapshots:
'@push.rocks/smartsocket': 2.1.0
'@push.rocks/smartstring': 4.1.0
'@push.rocks/smarturl': 3.1.0
+ optionalDependencies:
+ '@push.rocks/smartserve': 1.3.0
transitivePeerDependencies:
- '@nuxt/kit'
- bufferutil
@@ -4708,6 +4770,19 @@ snapshots:
- utf-8-validate
- vue
+ '@api.global/typedsocket@4.1.0(@push.rocks/smartserve@1.3.0)':
+ dependencies:
+ '@api.global/typedrequest': 3.2.5
+ '@api.global/typedrequest-interfaces': 3.0.19
+ '@push.rocks/isohash': 2.0.1
+ '@push.rocks/smartdelay': 3.0.5
+ '@push.rocks/smartjson': 5.2.0
+ '@push.rocks/smartpromise': 4.2.3
+ '@push.rocks/smartrx': 3.0.10
+ '@push.rocks/smartserve': 1.3.0
+ '@push.rocks/smartstring': 4.1.0
+ '@push.rocks/smarturl': 3.1.0
+
'@aws-crypto/crc32@5.2.0':
dependencies:
'@aws-crypto/util': 5.2.0
@@ -5213,6 +5288,42 @@ snapshots:
enabled: 2.0.0
kuler: 2.0.0
+ '@design.estate/dees-catalog@2.0.7(@tiptap/pm@2.27.1)':
+ dependencies:
+ '@design.estate/dees-domtools': 2.3.6
+ '@design.estate/dees-element': 2.1.3
+ '@design.estate/dees-wcctools': 1.2.1
+ '@fortawesome/fontawesome-svg-core': 7.1.0
+ '@fortawesome/free-brands-svg-icons': 7.1.0
+ '@fortawesome/free-regular-svg-icons': 7.1.0
+ '@fortawesome/free-solid-svg-icons': 7.1.0
+ '@push.rocks/smarti18n': 1.0.4
+ '@push.rocks/smartpromise': 4.2.3
+ '@push.rocks/smartstring': 4.1.0
+ '@tiptap/core': 2.27.1(@tiptap/pm@2.27.1)
+ '@tiptap/extension-link': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))(@tiptap/pm@2.27.1)
+ '@tiptap/extension-text-align': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
+ '@tiptap/extension-typography': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
+ '@tiptap/extension-underline': 2.27.1(@tiptap/core@2.27.1(@tiptap/pm@2.27.1))
+ '@tiptap/starter-kit': 2.27.1
+ '@tsclass/tsclass': 9.3.0
+ '@webcontainer/api': 1.2.0
+ apexcharts: 5.3.6
+ highlight.js: 11.11.1
+ ibantools: 4.5.1
+ lit: 3.3.1
+ lucide: 0.555.0
+ monaco-editor: 0.52.2
+ pdfjs-dist: 4.10.38
+ xterm: 5.3.0
+ xterm-addon-fit: 0.8.0(xterm@5.3.0)
+ transitivePeerDependencies:
+ - '@nuxt/kit'
+ - '@tiptap/pm'
+ - react
+ - supports-color
+ - vue
+
'@design.estate/dees-comms@1.0.30':
dependencies:
'@api.global/typedrequest': 3.2.5
@@ -5453,9 +5564,9 @@ snapshots:
'@push.rocks/smartshell': 3.3.0
tsx: 4.21.0
- '@git.zone/tstest@3.1.3(socks@2.8.7)(typescript@5.9.3)':
+ '@git.zone/tstest@3.1.3(@push.rocks/smartserve@1.3.0)(socks@2.8.7)(typescript@5.9.3)':
dependencies:
- '@api.global/typedserver': 3.0.80
+ '@api.global/typedserver': 3.0.80(@push.rocks/smartserve@1.3.0)
'@git.zone/tsbundle': 2.6.3
'@git.zone/tsrun': 2.0.0
'@push.rocks/consolecolor': 2.0.3
@@ -5502,9 +5613,9 @@ snapshots:
- utf-8-validate
- vue
- '@git.zone/tswatch@2.2.3':
+ '@git.zone/tswatch@2.3.1(@tiptap/pm@2.27.1)':
dependencies:
- '@api.global/typedserver': 3.0.80
+ '@api.global/typedserver': 7.11.0(@tiptap/pm@2.27.1)
'@git.zone/tsbundle': 2.6.3
'@git.zone/tsrun': 2.0.0
'@push.rocks/early': 4.0.4
@@ -5520,8 +5631,11 @@ snapshots:
transitivePeerDependencies:
- '@nuxt/kit'
- '@swc/helpers'
+ - '@tiptap/pm'
+ - bufferutil
- react
- supports-color
+ - utf-8-validate
- vue
'@hapi/bourne@3.0.0': {}
@@ -6441,6 +6555,18 @@ snapshots:
transitivePeerDependencies:
- aws-crt
+ '@push.rocks/smartserve@1.3.0':
+ dependencies:
+ '@api.global/typedrequest': 3.2.5
+ '@push.rocks/lik': 6.2.2
+ '@push.rocks/smartenv': 6.0.0
+ '@push.rocks/smartlog': 3.1.10
+ '@push.rocks/smartpath': 6.0.0
+ ws: 8.18.3
+ transitivePeerDependencies:
+ - bufferutil
+ - utf-8-validate
+
'@push.rocks/smartshell@3.3.0':
dependencies:
'@push.rocks/smartdelay': 3.0.5
@@ -6462,7 +6588,7 @@ snapshots:
'@push.rocks/smartsocket@2.1.0':
dependencies:
'@api.global/typedrequest-interfaces': 3.0.19
- '@api.global/typedserver': 3.0.80
+ '@api.global/typedserver': 3.0.80(@push.rocks/smartserve@1.3.0)
'@push.rocks/isohash': 2.0.1
'@push.rocks/isounique': 1.0.5
'@push.rocks/lik': 6.2.2
@@ -6589,17 +6715,20 @@ snapshots:
transitivePeerDependencies:
- '@aws-sdk/credential-providers'
- '@mongodb-js/zstd'
+ - '@nuxt/kit'
- aws-crt
- bare-abort-controller
- bufferutil
- gcp-metadata
- kerberos
- mongodb-client-encryption
+ - react
- react-native-b4a
- snappy
- socks
- supports-color
- utf-8-validate
+ - vue
'@push.rocks/taskbuffer@3.5.0':
dependencies:
diff --git a/ts_web/00_commitinfo_data.ts b/ts_web/00_commitinfo_data.ts
index ac060f5..38adb38 100644
--- a/ts_web/00_commitinfo_data.ts
+++ b/ts_web/00_commitinfo_data.ts
@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@design.estate/dees-catalog',
- version: '2.0.7',
+ version: '3.0.0',
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
}
diff --git a/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.demo.ts b/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.demo.ts
index 52ee680..d25ee60 100644
--- a/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.demo.ts
+++ b/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.demo.ts
@@ -4,6 +4,7 @@ import type { IAppBarMenuItem } from '../../interfaces/appbarmenuitem.js';
import type { ITab } from '../../interfaces/tab.js';
import type { ISelectionOption } from '../../interfaces/selectionoption.js';
import type { IMenuGroup } from '../../interfaces/menugroup.js';
+import type { ISecondaryMenuGroup } from '../../interfaces/secondarymenu.js';
import * as plugins from '../../00plugins.js';
import '@design.estate/dees-wcctools/demotools';
@@ -95,14 +96,48 @@ export const demoFunc = () => {
{ key: 'Help', iconName: 'lucide:helpCircle', action: () => console.log('Help selected') },
];
- // Selector options (second sidebar)
- const selectorOptions: (ISelectionOption | { divider: true })[] = [
- { key: 'Overview', iconName: 'home', action: () => console.log('Overview selected') },
- { key: 'Components', iconName: 'package', action: () => console.log('Components selected') },
- { key: 'Services', iconName: 'server', action: () => console.log('Services selected') },
- { divider: true },
- { key: 'Database', iconName: 'database', action: () => console.log('Database selected') },
- { key: 'Settings', iconName: 'settings', action: () => console.log('Settings selected') },
+ // Secondary menu groups (second sidebar with collapsible groups)
+ // These showcase the new shadcn-style design with badges and collapsible sections
+ const secondaryMenuGroups: ISecondaryMenuGroup[] = [
+ {
+ name: 'Quick Access',
+ iconName: 'lucide:zap',
+ items: [
+ { key: 'Overview', iconName: 'layoutDashboard', action: () => console.log('Overview selected') },
+ { key: 'Recent Activity', iconName: 'clock', action: () => console.log('Recent Activity selected'), badge: 5 },
+ { key: 'Favorites', iconName: 'star', action: () => console.log('Favorites selected') },
+ ]
+ },
+ {
+ name: 'Resources',
+ iconName: 'lucide:layers',
+ items: [
+ { key: 'Components', iconName: 'package', action: () => console.log('Components selected'), badge: 24 },
+ { key: 'Services', iconName: 'server', action: () => console.log('Services selected'), badge: 'new', badgeVariant: 'success' },
+ { key: 'APIs', iconName: 'globe', action: () => console.log('APIs selected'), badge: 3, badgeVariant: 'warning' },
+ { key: 'Webhooks', iconName: 'webhook', action: () => console.log('Webhooks selected') },
+ ]
+ },
+ {
+ name: 'Data Management',
+ iconName: 'lucide:database',
+ items: [
+ { key: 'Database', iconName: 'database', action: () => console.log('Database selected') },
+ { key: 'Storage', iconName: 'hardDrive', action: () => console.log('Storage selected'), badge: '85%', badgeVariant: 'warning' },
+ { key: 'Backups', iconName: 'archive', action: () => console.log('Backups selected'), badge: 'OK', badgeVariant: 'success' },
+ ]
+ },
+ {
+ name: 'System',
+ iconName: 'lucide:settings',
+ collapsed: true,
+ items: [
+ { key: 'Configuration', iconName: 'sliders', action: () => console.log('Configuration selected') },
+ { key: 'Integrations', iconName: 'plug', action: () => console.log('Integrations selected'), badge: 2, badgeVariant: 'error' },
+ { key: 'Permissions', iconName: 'shield', action: () => console.log('Permissions selected') },
+ { key: 'Logs', iconName: 'fileText', action: () => console.log('Logs selected') },
+ ]
+ }
];
// Main content tabs
@@ -155,7 +190,8 @@ export const demoFunc = () => {
.mainmenuLogoText=${'Acme App'}
.mainmenuGroups=${mainMenuGroups}
.mainmenuBottomTabs=${mainMenuBottomTabs}
- .mainselectorOptions=${selectorOptions}
+ .secondarymenuHeading=${'Dashboard'}
+ .secondarymenuGroups=${secondaryMenuGroups}
.maincontentTabs=${mainContentTabs}
@appbar-menu-select=${(e: CustomEvent) => console.log('Menu selected:', e.detail)}
@appbar-breadcrumb-navigate=${(e: CustomEvent) => console.log('Breadcrumb:', e.detail)}
@@ -163,19 +199,37 @@ export const demoFunc = () => {
@appbar-user-menu-open=${() => console.log('User menu opened')}
@appbar-profile-menu-select=${(e: CustomEvent) => console.log('Profile menu selected:', e.detail)}
@mainmenu-tab-select=${(e: CustomEvent) => console.log('Tab selected:', e.detail)}
- @mainselector-option-select=${(e: CustomEvent) => console.log('Option selected:', e.detail)}
+ @secondarymenu-item-select=${(e: CustomEvent) => console.log('Item selected:', e.detail)}
>
-
-
Application Content
-
This is the main content area where your application's primary interface would be displayed.
-
The layout includes:
-
- - App bar with menus, breadcrumbs, and user account
- - Main menu (left sidebar) for primary navigation
- - Selector menu (second sidebar) for sub-navigation
- - Main content area (this section)
- - Activity log (right sidebar)
-
+
+
Welcome to Acme App
+
This demo showcases the AppUI component system with the new SecondaryMenu.
+
+
+
+
SecondaryMenu Features
+
+ - Collapsible groups with smooth animations
+ - Badge support (counts, status, variants)
+ - Dynamic heading from MainMenu selection
+ - shadcn-inspired modern design
+
+
+
+
Badge Variants
+
+ default
+ success
+ warning
+ error
+
+
+
+
+
+ Try clicking items in the MainMenu (left) - the SecondaryMenu heading updates automatically.
+ Click group headers in the SecondaryMenu to collapse/expand sections.
+
diff --git a/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.ts b/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.ts
index 675d398..ccd0f6e 100644
--- a/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.ts
+++ b/ts_web/elements/00group-appui/dees-appui-base/dees-appui-base.ts
@@ -12,7 +12,7 @@ import * as interfaces from '../../interfaces/index.js';
import * as plugins from '../../00plugins.js';
import type { DeesAppuiBar } from '../dees-appui-appbar/index.js';
import type { DeesAppuiMainmenu } from '../dees-appui-mainmenu/dees-appui-mainmenu.js';
-import type { DeesAppuiMainselector } from '../dees-appui-mainselector/dees-appui-mainselector.js';
+import type { DeesAppuiSecondarymenu } from '../dees-appui-secondarymenu/dees-appui-secondarymenu.js';
import type { DeesAppuiMaincontent } from '../dees-appui-maincontent/dees-appui-maincontent.js';
import type { DeesAppuiActivitylog } from '../dees-appui-activitylog/dees-appui-activitylog.js';
import { demoFunc } from './dees-appui-base.demo.js';
@@ -20,7 +20,7 @@ import { demoFunc } from './dees-appui-base.demo.js';
// Import child components
import '../dees-appui-appbar/index.js';
import '../dees-appui-mainmenu/dees-appui-mainmenu.js';
-import '../dees-appui-mainselector/dees-appui-mainselector.js';
+import '../dees-appui-secondarymenu/dees-appui-secondarymenu.js';
import '../dees-appui-maincontent/dees-appui-maincontent.js';
import '../dees-appui-activitylog/dees-appui-activitylog.js';
@@ -75,12 +75,19 @@ export class DeesAppuiBase extends DeesElement {
@property({ type: Object })
accessor mainmenuSelectedTab: interfaces.ITab | undefined = undefined;
- // Properties for mainselector
+ // Properties for secondarymenu
+ @property({ type: String })
+ accessor secondarymenuHeading: string = 'Menu';
+
@property({ type: Array })
- accessor mainselectorOptions: (interfaces.ISelectionOption | { divider: true })[] = [];
+ accessor secondarymenuGroups: interfaces.ISecondaryMenuGroup[] = [];
@property({ type: Object })
- accessor mainselectorSelectedOption: interfaces.ISelectionOption | undefined = undefined;
+ accessor secondarymenuSelectedItem: interfaces.ISecondaryMenuItem | undefined = undefined;
+
+ /** Legacy support for flat options (backward compatibility) */
+ @property({ type: Array })
+ accessor secondarymenuOptions: (interfaces.ISelectionOption | { divider: true })[] = [];
// Properties for maincontent
@property({ type: Array })
@@ -94,7 +101,7 @@ export class DeesAppuiBase extends DeesElement {
accessor mainmenu: DeesAppuiMainmenu | undefined = undefined;
@state()
- accessor mainselector: DeesAppuiMainselector | undefined = undefined;
+ accessor secondarymenu: DeesAppuiSecondarymenu | undefined = undefined;
@state()
accessor maincontent: DeesAppuiMaincontent | undefined = undefined;
@@ -151,11 +158,13 @@ export class DeesAppuiBase extends DeesElement {
.selectedTab=${this.mainmenuSelectedTab}
@tab-select=${(e: CustomEvent) => this.handleMainmenuTabSelect(e)}
>
- this.handleMainselectorOptionSelect(e)}
- >
+ this.handleSecondarymenuItemSelect(e)}
+ >
@@ -170,7 +179,7 @@ export class DeesAppuiBase extends DeesElement {
// Get references to child components
this.appbar = this.shadowRoot.querySelector('dees-appui-appbar');
this.mainmenu = this.shadowRoot.querySelector('dees-appui-mainmenu');
- this.mainselector = this.shadowRoot.querySelector('dees-appui-mainselector');
+ this.secondarymenu = this.shadowRoot.querySelector('dees-appui-secondarymenu');
this.maincontent = this.shadowRoot.querySelector('dees-appui-maincontent');
this.activitylog = this.shadowRoot.querySelector('dees-appui-activitylog');
}
@@ -217,6 +226,8 @@ export class DeesAppuiBase extends DeesElement {
// Event handlers for mainmenu
private handleMainmenuTabSelect(e: CustomEvent) {
this.mainmenuSelectedTab = e.detail.tab;
+ // Update secondary menu heading based on main menu selection
+ this.secondarymenuHeading = e.detail.tab.key;
this.dispatchEvent(new CustomEvent('mainmenu-tab-select', {
detail: e.detail,
bubbles: true,
@@ -224,10 +235,10 @@ export class DeesAppuiBase extends DeesElement {
}));
}
- // Event handlers for mainselector
- private handleMainselectorOptionSelect(e: CustomEvent) {
- this.mainselectorSelectedOption = e.detail.option;
- this.dispatchEvent(new CustomEvent('mainselector-option-select', {
+ // Event handlers for secondarymenu
+ private handleSecondarymenuItemSelect(e: CustomEvent) {
+ this.secondarymenuSelectedItem = e.detail.item;
+ this.dispatchEvent(new CustomEvent('secondarymenu-item-select', {
detail: e.detail,
bubbles: true,
composed: true
diff --git a/ts_web/elements/00group-appui/dees-appui-mainselector/dees-appui-mainselector.ts b/ts_web/elements/00group-appui/dees-appui-mainselector/dees-appui-mainselector.ts
deleted file mode 100644
index dfe385d..0000000
--- a/ts_web/elements/00group-appui/dees-appui-mainselector/dees-appui-mainselector.ts
+++ /dev/null
@@ -1,211 +0,0 @@
-import * as plugins from '../../00plugins.js';
-import * as interfaces from '../../interfaces/index.js';
-
-import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js';
-import '../../dees-icon/dees-icon.js';
-
-import {
- DeesElement,
- type TemplateResult,
- property,
- customElement,
- html,
- css,
- cssManager,
-} from '@design.estate/dees-element';
-
-/**
- * the property selector menu
- * mainly used to select assets within in an organization
- */
-@customElement('dees-appui-mainselector')
-export class DeesAppuiMainselector extends DeesElement {
- public static demo = () => html`
- console.log('Overview') },
- { key: 'Components', iconName: 'package', action: () => console.log('Components') },
- { key: 'Services', iconName: 'server', action: () => console.log('Services') },
- { key: 'Database', iconName: 'database', action: () => console.log('Database') },
- { key: 'Settings', iconName: 'settings', action: () => console.log('Settings') },
- ]}
- >
- `;
-
- // INSTANCE
- @property({ type: Array })
- accessor selectionOptions: (interfaces.ISelectionOption | { divider: true })[] = [
- { key: '⚠️ Please set selection options', action: () => console.warn('No selection options configured for mainselector') },
- ];
-
- @property()
- accessor selectedOption: interfaces.ISelectionOption = null;
-
- public static styles = [
- cssManager.defaultStyles,
- css`
- :host {
- color: ${cssManager.bdTheme('#333', '#fff')};
- position: relative;
- display: block;
- width: 100%;
- max-width: 300px;
- height: 100%;
- background: ${cssManager.bdTheme('#fafafa', '#000000')};
- border-right: 1px solid ${cssManager.bdTheme('#e0e0e0', '#202020')};
- }
- .maincontainer {
- position: absolute;
- top: 0px;
- left: 0px;
- height: 100%;
- width: 100%;
- }
-
- .topbar {
- position: absolute;
- height: 40px;
- width: 100%;
- display: flex;
- align-items: center;
- border-bottom: 1px solid ${cssManager.bdTheme('#e0e0e0', '#202020')};
- }
-
- .topbar .heading {
- padding-left: 12px;
- font-family: 'Geist Sans', sans-serif;
- font-weight: 600;
- font-size: 12px;
- color: ${cssManager.bdTheme('#666', '#999')};
- text-transform: uppercase;
- letter-spacing: 0.5px;
- }
-
- .selectionOptions {
- position: absolute;
- top: 40px;
- left: 0px;
- right: 0px;
- bottom: 0px;
- overflow-y: auto;
- font-family: 'Geist Sans', sans-serif;
- font-size: 12px;
- padding: 4px 0;
- }
-
- .selectionOptions .selectionOption {
- cursor: default;
- padding: 8px 12px;
- margin: 0;
- transition: background 0.1s;
- display: flex;
- align-items: center;
- gap: 8px;
- color: ${cssManager.bdTheme('#333', '#ccc')};
- user-select: none;
- }
-
- .selectionOptions .selectionOption:hover {
- background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.04)', 'rgba(255, 255, 255, 0.08)')};
- }
-
- .selectionOptions .selectionOption:active {
- background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.12)')};
- }
-
- .selectionOptions .selectionOption.selectedOption {
- background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.08)', 'rgba(255, 255, 255, 0.12)')};
- color: ${cssManager.bdTheme('#000', '#fff')};
- font-weight: 500;
- }
-
- .selectionOptions .selectionOption.selectedOption::before {
- content: '';
- position: absolute;
- left: 0;
- top: 0;
- bottom: 0;
- width: 3px;
- background: ${cssManager.bdTheme('#26a69a', '#26a69a')};
- }
-
- .selectionOption {
- position: relative;
- }
-
- .selection-divider {
- height: 1px;
- background: ${cssManager.bdTheme('#e0e0e0', '#202020')};
- margin: 4px 0;
- }
- `,
- ];
-
- public render(): TemplateResult {
- return html`
-
-
-
-
- ${this.selectionOptions.map((selectionOptionArg) => {
- if ('divider' in selectionOptionArg && selectionOptionArg.divider) {
- return html`
`;
- }
-
- const option = selectionOptionArg as interfaces.ISelectionOption;
- return html`
-
{
- this.selectOption(option);
- }}"
- @contextmenu="${(eventArg: MouseEvent) => {
- DeesContextmenu.openContextMenuWithOptions(eventArg, [
- {
- name: 'property settings',
- action: async () => {},
- iconName: 'gear',
- },
- ]);
- }}"
- >
- ${option.iconName ? html`
-
- ` : ''}
- ${option.key}
-
- `;
- })}
-
-
- `;
- }
-
- private selectOption(optionArg: interfaces.ISelectionOption) {
- this.selectedOption = optionArg;
- this.selectedOption.action();
-
- // Emit option-select event
- this.dispatchEvent(new CustomEvent('option-select', {
- detail: { option: optionArg },
- bubbles: true,
- composed: true
- }));
- }
-
- async firstUpdated(_changedProperties: Map) {
- await super.firstUpdated(_changedProperties);
- if (this.selectionOptions && this.selectionOptions.length > 0) {
- await this.updateComplete;
- // Find first non-divider option
- const firstOption = this.selectionOptions.find(option => !('divider' in option)) as interfaces.ISelectionOption;
- if (firstOption) {
- this.selectOption(firstOption);
- }
- }
- }
-}
diff --git a/ts_web/elements/00group-appui/dees-appui-mainselector/index.ts b/ts_web/elements/00group-appui/dees-appui-mainselector/index.ts
deleted file mode 100644
index 85bf178..0000000
--- a/ts_web/elements/00group-appui/dees-appui-mainselector/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './dees-appui-mainselector.js';
diff --git a/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts b/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts
new file mode 100644
index 0000000..7ead8c3
--- /dev/null
+++ b/ts_web/elements/00group-appui/dees-appui-secondarymenu/dees-appui-secondarymenu.ts
@@ -0,0 +1,486 @@
+import * as plugins from '../../00plugins.js';
+import * as interfaces from '../../interfaces/index.js';
+
+import { DeesContextmenu } from '../../dees-contextmenu/dees-contextmenu.js';
+import '../../dees-icon/dees-icon.js';
+
+import {
+ DeesElement,
+ type TemplateResult,
+ property,
+ state,
+ customElement,
+ html,
+ css,
+ cssManager,
+} from '@design.estate/dees-element';
+
+/**
+ * Secondary navigation menu for sub-navigation within MainMenu views
+ * Supports collapsible groups, badges, and dynamic headings
+ */
+@customElement('dees-appui-secondarymenu')
+export class DeesAppuiSecondarymenu extends DeesElement {
+ public static demo = () => html`
+
+
+ console.log('Frontend'), badge: 3, badgeVariant: 'warning' },
+ { key: 'API Server', iconName: 'server', action: () => console.log('API'), badge: 'new', badgeVariant: 'success' },
+ { key: 'Database', iconName: 'database', action: () => console.log('Database') },
+ ]
+ },
+ {
+ name: 'Archived',
+ iconName: 'lucide:archive',
+ collapsed: true,
+ items: [
+ { key: 'Legacy System', iconName: 'box', action: () => console.log('Legacy') },
+ { key: 'Old API', iconName: 'server', action: () => console.log('Old API') },
+ ]
+ },
+ {
+ name: 'Settings',
+ iconName: 'lucide:settings',
+ items: [
+ { key: 'Configuration', iconName: 'sliders', action: () => console.log('Config') },
+ { key: 'Integrations', iconName: 'plug', action: () => console.log('Integrations'), badge: 5, badgeVariant: 'error' },
+ ]
+ }
+ ] as interfaces.ISecondaryMenuGroup[]}
+ @item-select=${(e: CustomEvent) => console.log('Selected:', e.detail)}
+ >
+
+ `;
+
+ // INSTANCE
+
+ /** Dynamic heading - typically shows the selected MainMenu item */
+ @property({ type: String })
+ accessor heading: string = 'Menu';
+
+ /** Grouped items with collapse support */
+ @property({ type: Array })
+ accessor groups: interfaces.ISecondaryMenuGroup[] = [];
+
+ /** Legacy flat list support for backward compatibility */
+ @property({ type: Array })
+ accessor selectionOptions: (interfaces.ISelectionOption | { divider: true })[] = [];
+
+ /** Currently selected item */
+ @property({ type: Object })
+ accessor selectedItem: interfaces.ISecondaryMenuItem | null = null;
+
+ /** Internal state for collapsed groups */
+ @state()
+ accessor collapsedGroups: Set = new Set();
+
+ public static styles = [
+ cssManager.defaultStyles,
+ css`
+ :host {
+ --sidebar-width: 240px;
+ --sidebar-bg: ${cssManager.bdTheme('#fafafa', '#0a0a0a')};
+ --sidebar-fg: ${cssManager.bdTheme('#525252', '#a3a3a3')};
+ --sidebar-fg-muted: ${cssManager.bdTheme('#737373', '#737373')};
+ --sidebar-fg-active: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
+ --sidebar-border: ${cssManager.bdTheme('#e5e5e5', '#1a1a1a')};
+ --sidebar-hover: ${cssManager.bdTheme('rgba(0, 0, 0, 0.04)', 'rgba(255, 255, 255, 0.06)')};
+ --sidebar-active: ${cssManager.bdTheme('rgba(0, 0, 0, 0.06)', 'rgba(255, 255, 255, 0.08)')};
+ --sidebar-accent: ${cssManager.bdTheme('#0a0a0a', '#fafafa')};
+
+ /* Badge colors */
+ --badge-default-bg: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
+ --badge-default-fg: ${cssManager.bdTheme('#3f3f46', '#a1a1aa')};
+ --badge-success-bg: ${cssManager.bdTheme('#dcfce7', '#14532d')};
+ --badge-success-fg: ${cssManager.bdTheme('#166534', '#4ade80')};
+ --badge-warning-bg: ${cssManager.bdTheme('#fef3c7', '#451a03')};
+ --badge-warning-fg: ${cssManager.bdTheme('#92400e', '#fbbf24')};
+ --badge-error-bg: ${cssManager.bdTheme('#fee2e2', '#450a0a')};
+ --badge-error-fg: ${cssManager.bdTheme('#991b1b', '#f87171')};
+
+ display: block;
+ height: 100%;
+ width: var(--sidebar-width);
+ background: var(--sidebar-bg);
+ border-right: 1px solid var(--sidebar-border);
+ font-family: 'Geist Sans', 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
+ user-select: none;
+ }
+
+ .maincontainer {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: hidden;
+ }
+
+ /* Header Section */
+ .header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px 16px;
+ border-bottom: 1px solid var(--sidebar-border);
+ flex-shrink: 0;
+ }
+
+ .header .heading {
+ font-size: 14px;
+ font-weight: 600;
+ color: var(--sidebar-fg-active);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ /* Scrollable Menu Section */
+ .menuSection {
+ flex: 1;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 8px 0;
+ }
+
+ .menuSection::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ .menuSection::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ .menuSection::-webkit-scrollbar-thumb {
+ background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.15)', 'rgba(255, 255, 255, 0.15)')};
+ border-radius: 3px;
+ }
+
+ .menuSection::-webkit-scrollbar-thumb:hover {
+ background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.25)', 'rgba(255, 255, 255, 0.25)')};
+ }
+
+ /* Menu Group */
+ .menuGroup {
+ padding: 0 8px;
+ margin-bottom: 4px;
+ }
+
+ .groupHeader {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 8px;
+ cursor: pointer;
+ border-radius: 6px;
+ transition: background 0.15s ease;
+ }
+
+ .groupHeader:hover {
+ background: var(--sidebar-hover);
+ }
+
+ .groupHeader .groupTitle {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 11px;
+ font-weight: 600;
+ color: var(--sidebar-fg-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ }
+
+ .groupHeader .groupTitle dees-icon {
+ font-size: 14px;
+ opacity: 0.7;
+ }
+
+ .groupHeader .chevron {
+ font-size: 12px;
+ transition: transform 0.2s ease;
+ color: var(--sidebar-fg-muted);
+ }
+
+ .groupHeader.collapsed .chevron {
+ transform: rotate(-90deg);
+ }
+
+ /* Group Items Container */
+ .groupItems {
+ overflow: hidden;
+ transition: max-height 0.25s ease, opacity 0.2s ease;
+ max-height: 500px;
+ opacity: 1;
+ }
+
+ .groupItems.collapsed {
+ max-height: 0;
+ opacity: 0;
+ }
+
+ /* Menu Item */
+ .menuItem {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 12px;
+ margin: 2px 0;
+ font-size: 13px;
+ font-weight: 450;
+ border-radius: 6px;
+ cursor: pointer;
+ transition: all 0.15s ease;
+ color: var(--sidebar-fg);
+ }
+
+ .menuItem:hover {
+ background: var(--sidebar-hover);
+ color: var(--sidebar-fg-active);
+ }
+
+ .menuItem:active {
+ background: var(--sidebar-active);
+ }
+
+ .menuItem.selected {
+ background: var(--sidebar-active);
+ color: var(--sidebar-fg-active);
+ font-weight: 500;
+ }
+
+ .menuItem.selected::before {
+ content: '';
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 3px;
+ height: 16px;
+ background: var(--sidebar-accent);
+ border-radius: 0 2px 2px 0;
+ }
+
+ .menuItem dees-icon {
+ font-size: 16px;
+ opacity: 0.7;
+ flex-shrink: 0;
+ }
+
+ .menuItem.selected dees-icon {
+ opacity: 1;
+ }
+
+ .menuItem .itemLabel {
+ flex: 1;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ /* Badge Styles */
+ .badge {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 18px;
+ height: 18px;
+ padding: 0 6px;
+ font-size: 10px;
+ font-weight: 600;
+ border-radius: 9px;
+ flex-shrink: 0;
+ }
+
+ .badge.default {
+ background: var(--badge-default-bg);
+ color: var(--badge-default-fg);
+ }
+
+ .badge.success {
+ background: var(--badge-success-bg);
+ color: var(--badge-success-fg);
+ }
+
+ .badge.warning {
+ background: var(--badge-warning-bg);
+ color: var(--badge-warning-fg);
+ }
+
+ .badge.error {
+ background: var(--badge-error-bg);
+ color: var(--badge-error-fg);
+ }
+
+ /* Divider */
+ .divider {
+ height: 1px;
+ background: var(--sidebar-border);
+ margin: 8px 12px;
+ }
+
+ /* Legacy options container */
+ .legacyOptions {
+ padding: 0 8px;
+ }
+ `,
+ ];
+
+ public render(): TemplateResult {
+ return html`
+
+
+
+
+ `;
+ }
+
+ private renderGroups(): TemplateResult {
+ return html`
+ ${this.groups.map((group) => html`
+
+ `)}
+ `;
+ }
+
+ private renderMenuItem(item: interfaces.ISecondaryMenuItem, group?: interfaces.ISecondaryMenuGroup): TemplateResult {
+ const isSelected = this.selectedItem?.key === item.key;
+ return html`
+
+ `;
+ }
+
+ private renderLegacyOptions(): TemplateResult {
+ return html`
+
+ ${this.selectionOptions.map((option) => {
+ if ('divider' in option && option.divider) {
+ return html`
`;
+ }
+ const item = option as interfaces.ISelectionOption;
+ return this.renderMenuItem({
+ key: item.key,
+ iconName: item.iconName,
+ action: item.action,
+ });
+ })}
+
+ `;
+ }
+
+ private toggleGroup(groupName: string): void {
+ const newCollapsed = new Set(this.collapsedGroups);
+ if (newCollapsed.has(groupName)) {
+ newCollapsed.delete(groupName);
+ } else {
+ newCollapsed.add(groupName);
+ }
+ this.collapsedGroups = newCollapsed;
+ }
+
+ private selectItem(item: interfaces.ISecondaryMenuItem, group?: interfaces.ISecondaryMenuGroup): void {
+ this.selectedItem = item;
+ item.action();
+
+ this.dispatchEvent(new CustomEvent('item-select', {
+ detail: { item, group },
+ bubbles: true,
+ composed: true
+ }));
+ }
+
+ private handleContextMenu(event: MouseEvent, item: interfaces.ISecondaryMenuItem): void {
+ DeesContextmenu.openContextMenuWithOptions(event, [
+ {
+ name: 'View details',
+ action: async () => {},
+ iconName: 'lucide:eye',
+ },
+ {
+ name: 'Edit',
+ action: async () => {},
+ iconName: 'lucide:pencil',
+ },
+ ]);
+ }
+
+ async firstUpdated(_changedProperties: Map) {
+ await super.firstUpdated(_changedProperties);
+
+ // Initialize collapsed state from group defaults
+ if (this.groups.length > 0) {
+ const initialCollapsed = new Set();
+ this.groups.forEach(group => {
+ if (group.collapsed) {
+ initialCollapsed.add(group.name);
+ }
+ });
+ this.collapsedGroups = initialCollapsed;
+
+ // Auto-select first item if none selected
+ if (!this.selectedItem && this.groups[0]?.items.length > 0) {
+ this.selectItem(this.groups[0].items[0], this.groups[0]);
+ }
+ } else if (this.selectionOptions.length > 0) {
+ // Legacy mode: select first non-divider option
+ const firstOption = this.selectionOptions.find(opt => !('divider' in opt)) as interfaces.ISelectionOption;
+ if (firstOption && !this.selectedItem) {
+ this.selectItem({
+ key: firstOption.key,
+ iconName: firstOption.iconName,
+ action: firstOption.action,
+ });
+ }
+ }
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'dees-appui-secondarymenu': DeesAppuiSecondarymenu;
+ }
+}
diff --git a/ts_web/elements/00group-appui/dees-appui-secondarymenu/index.ts b/ts_web/elements/00group-appui/dees-appui-secondarymenu/index.ts
new file mode 100644
index 0000000..07111c2
--- /dev/null
+++ b/ts_web/elements/00group-appui/dees-appui-secondarymenu/index.ts
@@ -0,0 +1 @@
+export * from './dees-appui-secondarymenu.js';
diff --git a/ts_web/elements/00group-appui/index.ts b/ts_web/elements/00group-appui/index.ts
index cdc0e19..150a331 100644
--- a/ts_web/elements/00group-appui/index.ts
+++ b/ts_web/elements/00group-appui/index.ts
@@ -4,7 +4,7 @@ export * from './dees-appui-appbar/index.js';
export * from './dees-appui-base/index.js';
export * from './dees-appui-maincontent/index.js';
export * from './dees-appui-mainmenu/index.js';
-export * from './dees-appui-mainselector/index.js';
+export * from './dees-appui-secondarymenu/index.js';
export * from './dees-appui-profiledropdown/index.js';
export * from './dees-appui-tabs/index.js';
export * from './dees-appui-view/index.js';
diff --git a/ts_web/elements/interfaces/index.ts b/ts_web/elements/interfaces/index.ts
index 665e9f6..009fd4c 100644
--- a/ts_web/elements/interfaces/index.ts
+++ b/ts_web/elements/interfaces/index.ts
@@ -2,3 +2,4 @@ export * from './tab.js';
export * from './selectionoption.js';
export * from './appbarmenuitem.js';
export * from './menugroup.js';
+export * from './secondarymenu.js';
diff --git a/ts_web/elements/interfaces/secondarymenu.ts b/ts_web/elements/interfaces/secondarymenu.ts
new file mode 100644
index 0000000..898879f
--- /dev/null
+++ b/ts_web/elements/interfaces/secondarymenu.ts
@@ -0,0 +1,20 @@
+/**
+ * Interface for individual menu items in the secondary menu
+ */
+export interface ISecondaryMenuItem {
+ key: string;
+ iconName?: string;
+ action: () => void;
+ badge?: string | number;
+ badgeVariant?: 'default' | 'success' | 'warning' | 'error';
+}
+
+/**
+ * Interface for collapsible groups in the secondary menu
+ */
+export interface ISecondaryMenuGroup {
+ name: string;
+ items: ISecondaryMenuItem[];
+ collapsed?: boolean;
+ iconName?: string;
+}
diff --git a/ts_web/pages/zindex-showcase.ts b/ts_web/pages/zindex-showcase.ts
index 3aaa28d..f8cc23b 100644
--- a/ts_web/pages/zindex-showcase.ts
+++ b/ts_web/pages/zindex-showcase.ts
@@ -2,15 +2,15 @@ import { html, css, cssManager } from '@design.estate/dees-element';
import { DeesModal } from '../elements/dees-modal/dees-modal.js';
import { DeesToast } from '../elements/dees-toast/dees-toast.js';
import { DeesContextmenu } from '../elements/dees-contextmenu/dees-contextmenu.js';
-import '../elements/dees-button/dees-button.js';
-import '../elements/dees-input-dropdown/dees-input-dropdown.js';
-import '../elements/dees-form/dees-form.js';
+import '../elements/00group-button/dees-button/dees-button.js';
+import '../elements/00group-input/dees-input-dropdown/dees-input-dropdown.js';
+import '../elements/00group-form/dees-form/dees-form.js';
import '../elements/dees-panel/dees-panel.js';
-import '../elements/dees-input-text/dees-input-text.js';
-import '../elements/dees-input-radiogroup/dees-input-radiogroup.js';
-import '../elements/dees-input-tags/dees-input-tags.js';
-import '../elements/dees-input-wysiwyg.js';
-import '../elements/dees-appui-profiledropdown/dees-appui-profiledropdown.js';
+import '../elements/00group-input/dees-input-text/dees-input-text.js';
+import '../elements/00group-input/dees-input-radiogroup/dees-input-radiogroup.js';
+import '../elements/00group-input/dees-input-tags/dees-input-tags.js';
+import '../elements/00group-input/dees-input-wysiwyg/dees-input-wysiwyg.js';
+import '../elements/00group-appui/dees-appui-profiledropdown/dees-appui-profiledropdown.js';
export const zIndexShowcase = () => html`