/** * Shell entry point — loaded on every page. * * Registers the three header web components: * * * */ import { RStackIdentity } from "../shared/components/rstack-identity"; import { RStackNotificationBell } from "../shared/components/rstack-notification-bell"; import { RStackAppSwitcher } from "../shared/components/rstack-app-switcher"; import { RStackSpaceSwitcher } from "../shared/components/rstack-space-switcher"; import { RStackTabBar } from "../shared/components/rstack-tab-bar"; import { RStackMi } from "../shared/components/rstack-mi"; import { RStackModuleSetup } from "../shared/components/rstack-module-setup"; import { RStackOfflineIndicator } from "../shared/components/rstack-offline-indicator"; import { RStackSharePanel } from "../shared/components/rstack-share-panel"; import { RStackCommentBell } from "../shared/components/rstack-comment-bell"; import { RStackCollabOverlay } from "../shared/components/rstack-collab-overlay"; import { RStackUserDashboard } from "../shared/components/rstack-user-dashboard"; import { rspaceNavUrl } from "../shared/url-helpers"; import { TabCache } from "../shared/tab-cache"; // Expose URL helper globally (used by shell inline scripts + components) (window as any).__rspaceNavUrl = rspaceNavUrl; // Expose TabCache for inline shell script to instantiate (window as any).__RSpaceTabCache = TabCache; // Register all header components RStackIdentity.define(); RStackNotificationBell.define(); RStackAppSwitcher.define(); RStackSpaceSwitcher.define(); RStackTabBar.define(); RStackMi.define(); RStackModuleSetup.define(); RStackOfflineIndicator.define(); RStackSharePanel.define(); RStackCommentBell.define(); RStackCollabOverlay.define(); RStackUserDashboard.define(); // ── Offline Runtime (lazy-loaded) ── // Automerge + WASM (~2.5MB) loaded in a separate chunk to avoid blocking first paint. // Components that depend on window.__rspaceOfflineRuntime already handle late init. const spaceSlug = document.body?.getAttribute("data-space-slug"); if (spaceSlug) { import('./shell-offline').then(m => m.initOffline(spaceSlug)).catch(e => { console.warn("[shell] Failed to load offline chunk:", e); }); } // ── Track space visits for dashboard recency sorting ── if (spaceSlug) { try { const RECENT_KEY = "rspace_recent_spaces"; const visits = JSON.parse(localStorage.getItem(RECENT_KEY) || "{}"); visits[spaceSlug] = Date.now(); localStorage.setItem(RECENT_KEY, JSON.stringify(visits)); } catch { /* localStorage unavailable */ } } // Reload space list when user signs in/out (to show/hide private spaces) document.addEventListener("auth-change", (e) => { const reason = (e as CustomEvent).detail?.reason; // Token refreshes are invisible — no UI side-effects needed if (reason === "refresh") return; // Reload space switcher on state-changing events const spaceSwitcher = document.querySelector("rstack-space-switcher") as any; spaceSwitcher?.reload?.(); // Only redirect to homepage on genuine sign-out or server revocation if (reason === "signout" || reason === "revoked") { window.location.href = "/"; } }); // SW update banner is handled by the inline script in server/shell.ts // (single #pwa-update-banner element, no duplicate)