- Updated dees-appui-mainmenu to accept dynamic tabs with actions and icons. - Modified dees-appui-mainselector to support dynamic selection options. - Introduced dees-appui-tabs for improved tab navigation with customizable styles. - Added dees-appui-view to manage views with tabs and content dynamically. - Implemented event dispatching for tab and option selections. - Created a comprehensive architecture documentation for dees-appui system. - Added demo implementations for dees-appui-base and other components. - Improved responsiveness and user interaction feedback across components.
192 lines
4.5 KiB
TypeScript
192 lines
4.5 KiB
TypeScript
import * as interfaces from './interfaces/index.js';
|
|
|
|
import {
|
|
DeesElement,
|
|
type TemplateResult,
|
|
property,
|
|
customElement,
|
|
html,
|
|
css,
|
|
cssManager,
|
|
state,
|
|
} from '@design.estate/dees-element';
|
|
|
|
import './dees-appui-tabs.js';
|
|
import type { DeesAppuiTabs } from './dees-appui-tabs.js';
|
|
|
|
export interface IAppViewTab extends interfaces.ITab {
|
|
content?: TemplateResult | (() => TemplateResult);
|
|
}
|
|
|
|
export interface IAppView {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
iconName?: string;
|
|
tabs: IAppViewTab[];
|
|
menuItems?: interfaces.ISelectionOption[];
|
|
}
|
|
|
|
@customElement('dees-appui-view')
|
|
export class DeesAppuiView extends DeesElement {
|
|
public static demo = () => html`
|
|
<dees-appui-view
|
|
.viewConfig=${{
|
|
id: 'demo-view',
|
|
name: 'Demo View',
|
|
description: 'A demonstration view',
|
|
iconName: 'home',
|
|
tabs: [
|
|
{
|
|
key: 'overview',
|
|
iconName: 'chart-line',
|
|
action: () => console.log('Overview tab'),
|
|
content: html`<div style="padding: 20px;">Overview Content</div>`
|
|
},
|
|
{
|
|
key: 'details',
|
|
iconName: 'file-alt',
|
|
action: () => console.log('Details tab'),
|
|
content: html`<div style="padding: 20px;">Details Content</div>`
|
|
}
|
|
],
|
|
menuItems: [
|
|
{ key: 'General', action: () => console.log('General') },
|
|
{ key: 'Advanced', action: () => console.log('Advanced') },
|
|
]
|
|
}}
|
|
></dees-appui-view>
|
|
`;
|
|
|
|
// INSTANCE
|
|
@property({ type: Object })
|
|
public viewConfig: IAppView;
|
|
|
|
@state()
|
|
private selectedTab: IAppViewTab | null = null;
|
|
|
|
@state()
|
|
private tabs: DeesAppuiTabs;
|
|
|
|
public static styles = [
|
|
cssManager.defaultStyles,
|
|
css`
|
|
:host {
|
|
display: block;
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #161616;
|
|
}
|
|
|
|
.view-container {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.view-header {
|
|
background: #000000;
|
|
border-bottom: 1px solid #333;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.view-content {
|
|
flex: 1;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.tab-content {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
overflow: auto;
|
|
opacity: 0;
|
|
transition: opacity 0.2s;
|
|
}
|
|
|
|
.tab-content.active {
|
|
opacity: 1;
|
|
}
|
|
|
|
dees-appui-tabs {
|
|
height: 60px;
|
|
}
|
|
`,
|
|
];
|
|
|
|
public render(): TemplateResult {
|
|
if (!this.viewConfig) {
|
|
return html`<div>No view configuration provided</div>`;
|
|
}
|
|
|
|
return html`
|
|
<div class="view-container">
|
|
<div class="view-header">
|
|
<dees-appui-tabs
|
|
.tabs=${this.viewConfig.tabs}
|
|
.selectedTab=${this.selectedTab}
|
|
@tab-select=${(e: CustomEvent) => this.handleTabSelect(e)}
|
|
></dees-appui-tabs>
|
|
</div>
|
|
<div class="view-content">
|
|
${this.viewConfig.tabs.map((tab) => {
|
|
const isActive = tab === this.selectedTab;
|
|
const content = typeof tab.content === 'function' ? tab.content() : tab.content;
|
|
return html`
|
|
<div class="tab-content ${isActive ? 'active' : ''}">
|
|
${content || html`<slot name="${tab.key}"></slot>`}
|
|
</div>
|
|
`;
|
|
})}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
async firstUpdated() {
|
|
this.tabs = this.shadowRoot.querySelector('dees-appui-tabs');
|
|
|
|
if (this.viewConfig?.tabs?.length > 0) {
|
|
this.selectedTab = this.viewConfig.tabs[0];
|
|
}
|
|
}
|
|
|
|
private handleTabSelect(e: CustomEvent) {
|
|
this.selectedTab = e.detail.tab;
|
|
|
|
// Re-emit the event with view context
|
|
this.dispatchEvent(new CustomEvent('view-tab-select', {
|
|
detail: {
|
|
view: this.viewConfig,
|
|
tab: e.detail.tab
|
|
},
|
|
bubbles: true,
|
|
composed: true
|
|
}));
|
|
}
|
|
|
|
// Public methods for external control
|
|
public selectTab(tabKey: string) {
|
|
const tab = this.viewConfig.tabs.find(t => t.key === tabKey);
|
|
if (tab) {
|
|
this.selectedTab = tab;
|
|
if (this.tabs) {
|
|
this.tabs.selectedTab = tab;
|
|
}
|
|
}
|
|
}
|
|
|
|
public getMenuItems(): interfaces.ISelectionOption[] {
|
|
return this.viewConfig?.menuItems || [];
|
|
}
|
|
|
|
public getTabs(): IAppViewTab[] {
|
|
return this.viewConfig?.tabs || [];
|
|
}
|
|
} |