import React, { ReactNode, useEffect } from 'react'; import { ErrorBoundary } from 'react-error-boundary'; import { Provider as JotaiProvider, useAtomValue } from 'jotai'; import { Box, Button, config, OverlayContainerProvider, PopOutContainerProvider, Text, toRem, TooltipContainerProvider, } from 'folds'; import { RouterProvider } from 'react-router-dom'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { ClientConfigLoader } from '../components/ClientConfigLoader'; import { ClientConfigProvider } from '../hooks/useClientConfig'; import { ConfigConfigError, ConfigConfigLoading } from './ConfigConfig'; import { FeatureCheck } from './FeatureCheck'; import { createRouter } from './Router'; import { ScreenSizeProvider, useScreenSize } from '../hooks/useScreenSize'; import { useCompositionEndTracking } from '../hooks/useComposingCheck'; import { settingsAtom } from '../state/settings'; import { LotusToastContainer } from '../features/toast/LotusToastContainer'; import { useTauriNotificationBadge } from '../hooks/useTauriNotificationBadge'; import { useTauriWindowChrome } from '../hooks/useTauriWindowChrome'; import { isTauri } from '../hooks/useTauri'; import { TitleBar } from '../features/desktop/TitleBar'; import { customWindowChromeAtom } from '../state/customWindowChrome'; import { SeasonalEffect } from '../components/seasonal/SeasonalEffect'; import { applyCustomAccent, removeCustomAccent } from '../utils/accentColor'; import { zIndices } from '../styles/zIndex'; import { OIDC_CALLBACK_PATH } from './paths'; import { OidcCallback } from './auth/oidc/OidcCallback'; const FONT_MAP: Record = { system: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", inter: "'InterVariable', sans-serif", 'jetbrains-mono': "'JetBrains Mono', monospace", 'fira-code': "'Fira Code', monospace", }; function AppearanceEffects() { const settings = useAtomValue(settingsAtom); useEffect(() => { const color = settings.mentionHighlightColor; if (color) { document.body.style.setProperty('--mention-highlight-bg', color); // WCAG 2.1 relative luminance with gamma linearization const toLinear = (c: number) => { const s = c / 255; return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4; }; const r = parseInt(color.slice(1, 3), 16); const g = parseInt(color.slice(3, 5), 16); const b = parseInt(color.slice(5, 7), 16); const lum = 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b); document.body.style.setProperty('--mention-highlight-text', lum > 0.179 ? '#000' : '#fff'); // Derive a visible border: same hue, reduced alpha document.body.style.setProperty('--mention-highlight-border', `rgba(${r},${g},${b},0.5)`); } else { document.body.style.removeProperty('--mention-highlight-bg'); document.body.style.removeProperty('--mention-highlight-text'); document.body.style.removeProperty('--mention-highlight-border'); } }, [settings.mentionHighlightColor]); useEffect(() => { // Custom accent color applies only to non-TDS themes. When Lotus Terminal // (TDS) is active it has its own fixed palette, so we remove any overrides. const accent = settings.customAccentColor; if (accent && !settings.lotusTerminal && applyCustomAccent(accent)) { return () => removeCustomAccent(); } removeCustomAccent(); return undefined; }, [settings.customAccentColor, settings.lotusTerminal]); useEffect(() => { const font = FONT_MAP[settings.fontFamily ?? 'inter'] ?? FONT_MAP.inter; document.body.style.setProperty('--font-secondary', font); }, [settings.fontFamily]); return null; } function TauriEffects() { useTauriNotificationBadge(); return null; } // P5-47 — opt-in TDS window chrome. `useTauriWindowChrome` keeps the native OS // window decorations in sync with the setting; when a desktop user enables // custom chrome we replace the OS titlebar with . When off (the // default, and always in the browser) this returns children unchanged, so there // is zero layout impact for everyone else. function DesktopChrome({ children }: { children: ReactNode }) { const customChrome = useAtomValue(customWindowChromeAtom); useTauriWindowChrome(); const useChrome = isTauri() && customChrome; // Keep the wrapper element structure STABLE across the toggle so flipping the // setting never changes the element type in `children`'s ancestry — otherwise // React would unmount/remount the whole RouterProvider subtree (losing scroll, // menus, unsaved composer state). When off, both wrappers use `display:contents` // so they generate no box → zero layout impact (also the browser default path). return (
{useChrome && }
{children}
); } function NightLightOverlay() { const settings = useAtomValue(settingsAtom); if (!settings.nightLightEnabled) return null; return (