feat(appui): add dees-appui-bottombar component with config, programmatic API, demo and docs

This commit is contained in:
2026-01-03 12:40:11 +00:00
parent ba4aa912af
commit 9b0b448cb1
10 changed files with 899 additions and 4 deletions

View File

@@ -663,6 +663,44 @@ export const demoFunc = () => {
defaultView: 'dashboard',
bottomBar: {
visible: true,
widgets: [
{
id: 'status',
iconName: 'lucide:activity',
label: 'System Online',
status: 'success',
tooltip: 'All systems operational',
onClick: () => console.log('Status clicked'),
},
{
id: 'notifications',
iconName: 'lucide:bell',
label: '3 notifications',
status: 'warning',
tooltip: 'You have unread notifications',
onClick: () => console.log('Notifications clicked'),
},
{
id: 'version',
iconName: 'lucide:gitBranch',
label: 'v1.2.3',
position: 'right',
tooltip: 'Current version',
},
],
actions: [
{
id: 'terminal',
iconName: 'lucide:terminal',
tooltip: 'Open Terminal',
position: 'right',
onClick: () => console.log('Terminal clicked'),
},
],
},
onViewChange: (viewId, view) => {
console.log(`View changed to: ${viewId} (${view.name})`);
},

View File

@@ -15,6 +15,7 @@ import type { DeesAppuiMainmenu } from '../dees-appui-mainmenu/dees-appui-mainme
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 type { DeesAppuiBottombar } from '../dees-appui-bottombar/dees-appui-bottombar.js';
import { demoFunc } from './dees-appui.demo.js';
import { themeDefaultStyles } from '../../00theme.js';
@@ -23,6 +24,7 @@ import { ViewRegistry } from './view.registry.js';
// Import child components
import '../dees-appui-appbar/index.js';
import '../dees-appui-bottombar/dees-appui-bottombar.js';
import '../dees-appui-mainmenu/dees-appui-mainmenu.js';
import '../dees-appui-secondarymenu/dees-appui-secondarymenu.js';
import '../dees-appui-maincontent/dees-appui-maincontent.js';
@@ -156,6 +158,12 @@ export class DeesAppui extends DeesElement {
@state()
accessor activitylogElement: DeesAppuiActivitylog | undefined = undefined;
@state()
accessor bottombarElement: DeesAppuiBottombar | undefined = undefined;
@state()
accessor bottombarVisible: boolean = true;
// Current view state
@state()
accessor currentView: interfaces.IViewDefinition | undefined = undefined;
@@ -179,15 +187,27 @@ export class DeesAppui extends DeesElement {
.maingrid {
position: absolute;
top: 40px;
height: calc(100% - 40px);
height: calc(100% - 40px - 24px);
width: 100%;
display: grid;
/* grid-template-columns set dynamically in template */
grid-template-rows: 1fr;
transition: grid-template-columns 0.3s ease;
transition: grid-template-columns 0.3s ease, height 0.3s ease;
overflow: hidden;
}
:host([bottombar-hidden]) .maingrid {
height: calc(100% - 40px);
}
dees-appui-bottombar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 4;
}
/* Z-index layering for proper stacking */
.maingrid > dees-appui-mainmenu {
position: relative;
@@ -295,6 +315,9 @@ export class DeesAppui extends DeesElement {
class="${this.activityLogVisible ? 'visible' : 'hidden'}"
></dees-appui-activitylog>
</div>
${this.bottombarVisible ? html`
<dees-appui-bottombar></dees-appui-bottombar>
` : ''}
`;
}
@@ -305,6 +328,7 @@ export class DeesAppui extends DeesElement {
this.secondarymenu = this.shadowRoot!.querySelector('dees-appui-secondarymenu') as DeesAppuiSecondarymenu;
this.maincontent = this.shadowRoot!.querySelector('dees-appui-maincontent') as DeesAppuiMaincontent;
this.activitylogElement = this.shadowRoot!.querySelector('dees-appui-activitylog') as DeesAppuiActivitylog;
this.bottombarElement = this.shadowRoot!.querySelector('dees-appui-bottombar') as DeesAppuiBottombar;
// Subscribe to activity log entry changes for badge count
if (this.activitylogElement) {
@@ -730,6 +754,72 @@ export class DeesAppui extends DeesElement {
return this.activityLogVisible;
}
// ==========================================
// PROGRAMMATIC API: BOTTOM BAR
// ==========================================
/**
* Get the bottom bar API for widget/action management
*/
public get bottomBar(): interfaces.IBottomBarAPI {
if (!this.bottombarElement) {
// Return a deferred API that will work after firstUpdated
return {
addWidget: (widget) => {
this.updateComplete.then(() => this.bottombarElement?.addWidget(widget));
},
updateWidget: (id, update) => {
this.updateComplete.then(() => this.bottombarElement?.updateWidget(id, update));
},
removeWidget: (id) => {
this.updateComplete.then(() => this.bottombarElement?.removeWidget(id));
},
getWidget: (id) => this.bottombarElement?.getWidget(id),
clearWidgets: () => {
this.updateComplete.then(() => this.bottombarElement?.clearWidgets());
},
addAction: (action) => {
this.updateComplete.then(() => this.bottombarElement?.addAction(action));
},
removeAction: (id) => {
this.updateComplete.then(() => this.bottombarElement?.removeAction(id));
},
clearActions: () => {
this.updateComplete.then(() => this.bottombarElement?.clearActions());
},
};
}
return {
addWidget: (widget) => this.bottombarElement!.addWidget(widget),
updateWidget: (id, update) => this.bottombarElement!.updateWidget(id, update),
removeWidget: (id) => this.bottombarElement!.removeWidget(id),
getWidget: (id) => this.bottombarElement!.getWidget(id),
clearWidgets: () => this.bottombarElement!.clearWidgets(),
addAction: (action) => this.bottombarElement!.addAction(action),
removeAction: (id) => this.bottombarElement!.removeAction(id),
clearActions: () => this.bottombarElement!.clearActions(),
};
}
/**
* Set bottom bar visibility
*/
public setBottomBarVisible(visible: boolean): void {
this.bottombarVisible = visible;
if (!visible) {
this.setAttribute('bottombar-hidden', '');
} else {
this.removeAttribute('bottombar-hidden');
}
}
/**
* Get bottom bar visibility state
*/
public getBottomBarVisible(): boolean {
return this.bottombarVisible;
}
// ==========================================
// PROGRAMMATIC API: NAVIGATION
// ==========================================
@@ -842,6 +932,23 @@ export class DeesAppui extends DeesElement {
}
}
// Apply bottom bar config
if (config.bottomBar) {
this.setBottomBarVisible(config.bottomBar.visible ?? true);
if (config.bottomBar.widgets) {
config.bottomBar.widgets.forEach(widget => {
this.bottomBar.addWidget(widget);
});
}
if (config.bottomBar.actions) {
config.bottomBar.actions.forEach(action => {
this.bottomBar.addAction(action);
});
}
}
// Setup domtools.router integration
this.setupRouterIntegration(config);