/* ObsiGate — Module orchestrator (ES modules). Replaces the monolithic frontend/app.js IIFE. All code lives in frontend/js/*.js modules. */ import * as UI from './ui.js'; import * as Utils from './utils.js'; import { initI18n, t } from './i18n.js'; import { initAIFab } from './ai-fab.js'; import { initNowPlaying } from './now-playing.js'; // Wire up AI toolbar toast (avoids circular import in utils.js) window._obsigateShowToast = UI.showToast; import * as Sidebar from './sidebar.js'; import * as Auth from './auth.js'; import * as Viewer from './viewer.js'; import * as Sync from './sync.js'; import { initGraphView } from './graph.js'; import * as Legacy from './legacy.js'; import { initCommandPalette } from './palette.js'; import { initMobileToolbar } from './mobile-toolbar.js'; import { initMobileEditor } from './mobile-editor.js'; import { initDragDrop } from './dragdrop.js'; import { initMermaid, setupFocusMode } from './mermaid-viewer.js'; import PaneManager from './pane-manager.js'; import { initDesktopIntegration, isTauriEnv } from './desktop.js'; import { initPush } from './push.js'; import { initPlugins } from './plugins.js'; import { populateVersions } from './config.js'; import { initSidebarChat } from './filechat.js'; // ========================================================================= // Initialization — mirrors the original app.js init() ordering // ========================================================================= async function init() { // 1. Init i18n FIRST — loads fallback (FR) + selected locale // Server language check may fail (no auth yet), falls to localStorage // LocalStorage has correct language if user set it previously await initI18n(); // 1b. Desktop bridge — crash banner + OS theme sync (before theme engine). // No-op on web (Docker); on desktop it also readies the vault picker. await initDesktopIntegration(); // 2. Init auth — now t() works inside showApp()/renderUserMenu() const authOk = await Auth.AuthManager.initAuth(); UI.initTheme(); UI.initHeaderMenu(); UI.initCustomDropdowns(); document.getElementById("theme-toggle").addEventListener("click", UI.toggleTheme); document.getElementById("header-logo").addEventListener("click", Legacy.goHome); const refreshBtn = document.getElementById("header-refresh-btn"); if (refreshBtn) refreshBtn.addEventListener("click", Legacy.goHome); Legacy.initSearch(); UI.initSidebarToggle(); UI.initMobile(); Sidebar.initVaultContext(); Legacy.initSidebarTabs(); Legacy.initHelpModal(); Legacy.initConfigModal(); Legacy.initAboutModal(); Sidebar.initSidebarFilter(); initSidebarChat(); // #190 B — formulaire du chat général (sidebar) UI.initSidebarResize(); Utils.initEditor(); Auth.initLoginForm(); Legacy.initRecentTab(); UI.RightSidebarManager.init(); UI.FindInPageManager.init(); UI.ContextMenuManager.init(); UI.TabManager.init(); PaneManager.init(); initCommandPalette(); initMobileToolbar(); initMobileEditor(); initPush(); initPlugins(); if (authOk) { Legacy.initSyncStatus(); try { await Promise.all([Legacy.loadVaultSettings(), Sidebar.loadVaults(), Sidebar.loadTags()]); initDragDrop(); Legacy.DashboardRecentWidget.init(); const urlParams = new URLSearchParams(window.location.search); if (urlParams.get("popup") === "true") { document.body.classList.add("popup-mode"); } if (window.location.hash && window.location.hash.startsWith("#file=")) { const hashVal = window.location.hash.substring(6); const sepIndex = hashVal.indexOf(":"); if (sepIndex > -1) { const vault = decodeURIComponent(hashVal.substring(0, sepIndex)); const path = decodeURIComponent(hashVal.substring(sepIndex + 1)); Viewer.openFile(vault, path); } } else if (urlParams.get("popup") !== "true") { Legacy.showWelcome(); } } catch (err) { console.error("Failed to initialize ObsiGate:", err); UI.showToast(t("error.initialization"), "error"); } } initGraphView(); initMermaid(); setupFocusMode(); Utils.safeCreateIcons(); initAIFab(); initNowPlaying(); } document.addEventListener("DOMContentLoaded", async () => { try { await init(); Sync.init(); } finally { // Signale au splash de démarrage (index.html #boot-splash) que l'app est // initialisée : le splash est retiré et le squelette stylé révélé. // Set AFTER init() resolves so every handler (search, tabs, …) is bound. window.__OBSIGATE_BOOTED = true; if (typeof window.__obsigateBootReady === "function") window.__obsigateBootReady(); } // Show version in header — always visible, fallback before the async fetch populateVersions(); fetch('/api/health') .then(r => r.json()) .then(d => { if (d && d.version) populateVersions(d.version); }) .catch(() => {}); });