import type { UIState } from '@presentation/state/UIState'; import type { QueryBus } from '@application/handlers/QueryBus'; import type { DashboardResult } from '@application/queries/GetDashboard'; import { esc } from '@presentation/helpers/format'; export class Sidebar { private el: HTMLElement | null = null; private cachedVersion: string | null = null; constructor( private uiState: UIState, private queryBus: QueryBus, ) {} render(container: HTMLElement): void { this.el = document.createElement('aside'); this.el.className = 'sidebar-new'; container.appendChild(this.el); this.update(); this.fetchAndInjectVersion(); } update(): void { if (!this.el) return; const data = this.queryBus.execute({ type: 'get-dashboard' }); const enclosList = data.enclosSummaries; const activeView = this.uiState.activeView; let html = ''; // ── Header ── html += `
logo
Obsidienne Gestion d'élevage
`; // ── Nav ── html += `
`; // Section Principal html += `
`; html += `
`; html += this.item('dashboard', 'dashboard', 'Tableau de bord', activeView === 'dashboard'); html += this.item('statistiques', 'bar_chart', 'Statistiques', activeView === 'statistiques'); html += `
`; // Section Enclos html += `
`; html += `
`; enclosList.forEach(enc => { const isActive = activeView === enc.id; const dotClass = enc.running ? 'running' : 'idle'; html += ``; }); html += `
`; // Section Outils html += `
`; html += `
`; html += this.item('accouplement', 'favorite', 'Accouplement', activeView === 'accouplement'); html += this.item('appro', 'science', 'R\u00e9appro', activeView === 'appro'); html += this.item('inventaire', 'inventory_2', 'Inventaire', activeView === 'inventaire'); html += this.item('workflows', 'account_tree', 'Workflows', activeView === 'workflows'); html += `
`; html += `
`; // end sb-nav // ── Footer ── html += ` `; this.el.innerHTML = html; this.bindEvents(); this.fetchAndInjectVersion(); } private item(viewId: string, icon: string, label: string, active: boolean): string { return ``; } private bindEvents(): void { if (!this.el) return; this.el.querySelectorAll('.sb-item[data-view]').forEach(btn => { btn.addEventListener('click', () => { const view = btn.dataset['view']!; const viewValue: string | number = /^\d+$/.test(view) ? Number(view) : view; this.uiState.setActiveView(viewValue); }); }); } private fetchAndInjectVersion(): void { if (this.cachedVersion) { const verEl = this.el?.querySelector('#sb-ver'); if (verEl) verEl.textContent = `v${this.cachedVersion}`; return; } const api = (window as any).electronAPI; if (!api?.getVersion) return; api.getVersion().then((v: string) => { this.cachedVersion = v; const verEl = this.el?.querySelector('#sb-ver'); if (verEl) verEl.textContent = `v${v}`; }).catch(() => {}); } destroy(): void { this.el?.remove(); this.el = null; } }