# Building Applications with dees-appui Architecture ## Overview The dees-appui system provides a comprehensive framework for building desktop-style web applications with a consistent layout, navigation, and view management system. This document outlines the architecture and best practices for building applications using these components. ## Core Architecture ### Component Hierarchy ``` dees-appui-base ├── dees-appui-appbar (top menu bar) ├── dees-appui-mainmenu (left sidebar - primary navigation) ├── dees-appui-mainselector (second sidebar - contextual navigation) ├── dees-appui-maincontent (main content area) │ └── dees-appui-view (view container) │ └── dees-appui-tabs (tab navigation within views) └── dees-appui-activitylog (right sidebar - optional) ``` ### View-Based Architecture The system is built around the concept of **Views** - self-contained modules that represent different sections of your application. Each view can have: - Its own tabs for sub-navigation - Menu items for the selector (contextual navigation) - Content areas with dynamic loading - State management - Event handling ## Implementation Plan ### Phase 1: Application Shell Setup ```typescript // app-shell.ts import { LitElement, html, css } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import type { IAppView } from '@design.estate/dees-catalog'; @customElement('my-app-shell') export class MyAppShell extends LitElement { @property({ type: Array }) views: IAppView[] = []; @property({ type: String }) activeViewId: string = ''; render() { const activeView = this.views.find(v => v.id === this.activeViewId); return html` `; } } ``` ### Phase 2: View Definition ```typescript // views/dashboard-view.ts export const dashboardView: IAppView = { id: 'dashboard', name: 'Dashboard', description: 'System overview and metrics', iconName: 'home', tabs: [ { key: 'overview', iconName: 'chart-line', action: () => console.log('Overview selected'), content: () => html` ` }, { key: 'metrics', iconName: 'tachometer-alt', action: () => console.log('Metrics selected'), content: () => html` ` }, { key: 'alerts', iconName: 'bell', action: () => console.log('Alerts selected'), content: () => html` ` } ], menuItems: [ { key: 'Time Range', action: () => showTimeRangeSelector() }, { key: 'Refresh Rate', action: () => showRefreshSettings() }, { key: 'Export Data', action: () => exportDashboardData() } ] }; ``` ### Phase 3: View Management System ```typescript // services/view-manager.ts export class ViewManager { private views: Map = new Map(); private activeView: IAppView | null = null; private viewCache: Map = new Map(); registerView(view: IAppView) { this.views.set(view.id, view); } async activateView(viewId: string) { const view = this.views.get(viewId); if (!view) throw new Error(`View ${viewId} not found`); // Deactivate current view if (this.activeView) { await this.deactivateView(this.activeView.id); } // Activate new view this.activeView = view; // Update navigation this.updateMainSelector(view.menuItems); this.updateBreadcrumbs(view); // Load view data if needed if (!this.viewCache.has(viewId)) { await this.loadViewData(view); } return view; } private async loadViewData(view: IAppView) { // Implement lazy loading of view data const viewData = await import(`./views/${view.id}/data.js`); this.viewCache.set(view.id, viewData); } } ``` ### Phase 4: Navigation Integration ```typescript // navigation/app-navigation.ts export class AppNavigation { constructor( private viewManager: ViewManager, private appShell: MyAppShell ) {} setupMainMenu(): ITab[] { return [ { key: 'dashboard', iconName: 'home', action: () => this.navigateToView('dashboard') }, { key: 'projects', iconName: 'folder', action: () => this.navigateToView('projects') }, { key: 'analytics', iconName: 'chart-bar', action: () => this.navigateToView('analytics') }, { key: 'settings', iconName: 'cog', action: () => this.navigateToView('settings') } ]; } async navigateToView(viewId: string) { const view = await this.viewManager.activateView(viewId); this.appShell.activeViewId = viewId; // Update URL window.history.pushState( { viewId }, view.name, `/${viewId}` ); } handleBrowserNavigation() { window.addEventListener('popstate', (event) => { if (event.state?.viewId) { this.navigateToView(event.state.viewId); } }); } } ``` ### Phase 5: Dynamic View Loading ```typescript // views/view-loader.ts export class ViewLoader { private loadedViews: Set = new Set(); async loadView(viewId: string): Promise { if (this.loadedViews.has(viewId)) { return this.getViewConfig(viewId); } // Dynamic import const viewModule = await import(`./views/${viewId}/index.js`); const viewConfig = viewModule.default as IAppView; // Register custom elements if needed if (viewModule.registerElements) { await viewModule.registerElements(); } this.loadedViews.add(viewId); return viewConfig; } async preloadViews(viewIds: string[]) { const promises = viewIds.map(id => this.loadView(id)); await Promise.all(promises); } } ``` ## Best Practices ### 1. View Organization ``` src/ ├── views/ │ ├── dashboard/ │ │ ├── index.ts # View configuration │ │ ├── data.ts # Data fetching/management │ │ ├── components/ # View-specific components │ │ │ ├── dashboard-overview.ts │ │ │ ├── dashboard-metrics.ts │ │ │ └── dashboard-alerts.ts │ │ └── styles.ts # View-specific styles │ ├── projects/ │ │ └── ... │ └── settings/ │ └── ... ├── services/ │ ├── view-manager.ts │ ├── navigation.ts │ └── state-manager.ts └── app-shell.ts ``` ### 2. State Management ```typescript // services/state-manager.ts export class StateManager { private viewStates: Map = new Map(); saveViewState(viewId: string, state: any) { this.viewStates.set(viewId, { ...this.getViewState(viewId), ...state, lastUpdated: Date.now() }); } getViewState(viewId: string): any { return this.viewStates.get(viewId) || {}; } // Persist to localStorage persistState() { const serialized = JSON.stringify( Array.from(this.viewStates.entries()) ); localStorage.setItem('app-state', serialized); } restoreState() { const saved = localStorage.getItem('app-state'); if (saved) { const entries = JSON.parse(saved); this.viewStates = new Map(entries); } } } ``` ### 3. View Communication ```typescript // events/view-events.ts export class ViewEventBus { private eventTarget = new EventTarget(); emit(eventName: string, detail: any) { this.eventTarget.dispatchEvent( new CustomEvent(eventName, { detail }) ); } on(eventName: string, handler: (detail: any) => void) { this.eventTarget.addEventListener(eventName, (e: CustomEvent) => { handler(e.detail); }); } // Cross-view communication sendMessage(fromView: string, toView: string, message: any) { this.emit('view-message', { from: fromView, to: toView, message }); } } ``` ### 4. Responsive Design ```typescript // views/responsive-view.ts export const createResponsiveView = (config: IAppView): IAppView => { return { ...config, tabs: config.tabs.map(tab => ({ ...tab, content: () => html`
${tab.content()}
` })) }; }; function getDeviceClass(): string { const width = window.innerWidth; if (width < 768) return 'mobile'; if (width < 1024) return 'tablet'; return 'desktop'; } ``` ### 5. Performance Optimization ```typescript // optimization/lazy-components.ts export const lazyComponent = ( importFn: () => Promise, componentName: string ) => { let loaded = false; return () => { if (!loaded) { importFn().then(() => { loaded = true; }); return html``; } return html`<${componentName}>`; }; }; // Usage in view tabs: [ { key: 'heavy-component', content: lazyComponent( () => import('./components/heavy-component.js'), 'heavy-component' ) } ] ``` ## Advanced Features ### 1. View Permissions ```typescript interface IAppViewWithPermissions extends IAppView { requiredPermissions?: string[]; visibleTo?: (user: User) => boolean; } class PermissionManager { canAccessView(view: IAppViewWithPermissions, user: User): boolean { if (view.visibleTo) { return view.visibleTo(user); } if (view.requiredPermissions) { return view.requiredPermissions.every( perm => user.permissions.includes(perm) ); } return true; } } ``` ### 2. View Lifecycle Hooks ```typescript interface IAppViewLifecycle extends IAppView { onActivate?: () => Promise; onDeactivate?: () => Promise; onTabChange?: (oldTab: string, newTab: string) => void; onDestroy?: () => void; } ``` ### 3. Dynamic Menu Generation ```typescript class DynamicMenuBuilder { buildMainMenu(views: IAppView[], user: User): ITab[] { return views .filter(view => this.canShowInMenu(view, user)) .map(view => ({ key: view.id, iconName: view.iconName || 'file', action: () => this.navigation.navigateToView(view.id) })); } buildSelectorMenu(view: IAppView, context: any): ISelectionOption[] { const baseItems = view.menuItems || []; const contextItems = this.getContextualItems(view, context); return [...baseItems, ...contextItems]; } } ``` ## Migration Strategy For existing applications: 1. **Identify Views**: Map existing routes/pages to views 2. **Extract Components**: Move page-specific components into view folders 3. **Define View Configs**: Create IAppView configurations 4. **Update Navigation**: Replace existing routing with view navigation 5. **Migrate State**: Move page state to ViewManager 6. **Test & Optimize**: Ensure smooth transitions and performance ## Example Application Structure ```typescript // main.ts import { ViewManager } from './services/view-manager.js'; import { AppNavigation } from './services/navigation.js'; import { dashboardView } from './views/dashboard/index.js'; import { projectsView } from './views/projects/index.js'; import { settingsView } from './views/settings/index.js'; const app = new MyAppShell(); const viewManager = new ViewManager(); const navigation = new AppNavigation(viewManager, app); // Register views viewManager.registerView(dashboardView); viewManager.registerView(projectsView); viewManager.registerView(settingsView); // Setup navigation app.views = [dashboardView, projectsView, settingsView]; navigation.setupMainMenu(); navigation.handleBrowserNavigation(); // Initial navigation navigation.navigateToView('dashboard'); document.body.appendChild(app); ``` This architecture provides: - **Modularity**: Each view is self-contained - **Scalability**: Easy to add new views - **Performance**: Lazy loading and caching - **Consistency**: Unified navigation and layout - **Flexibility**: Customizable per view - **Maintainability**: Clear separation of concerns