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/dees-appui-tabs.js'; import type { DeesAppuiTabs } from '../dees-appui-tabs/dees-appui-tabs.js'; import { demoFunc } from './dees-appui-view.demo.js'; import { themeDefaultStyles } from '../../00theme.js'; export interface IViewTab extends interfaces.IMenuItem { content?: TemplateResult | (() => TemplateResult); useSlotName?: boolean; slotName?: string; paddingPx?: number; } export interface IAppView { id: string; name: string; description?: string; iconName?: string; tabs: IViewTab[]; menuItems?: interfaces.IMenuItem[]; } @customElement('dees-appui-view') export class DeesAppuiView extends DeesElement { public static demo = demoFunc; // INSTANCE @property({ type: Object }) accessor viewConfig: IAppView; @state() accessor selectedTab: IViewTab | null = null; @state() accessor tabs: DeesAppuiTabs; @property({ type: Number }) accessor paddingPx: number = 16; public static styles = [ themeDefaultStyles, cssManager.defaultStyles, css` /* TODO: Migrate hardcoded values to --dees-* CSS variables */ :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`
No view configuration provided
`; } return html`
this.handleTabSelect(e)} >
${this.viewConfig.tabs.map((tab) => { const isActive = tab === this.selectedTab; const content = typeof tab.content === 'function' ? tab.content() : tab.content; const padding = tab.paddingPx ?? this.paddingPx; return html`
${content ? content : tab.useSlotName ? html`` : ''}
`; })}
`; } 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.IMenuItem[] { return this.viewConfig?.menuItems || []; } public getTabs(): IViewTab[] { return this.viewConfig?.tabs || []; } }