import { render } from 'preact'; import { readBootstrap } from './bootstrap'; import { App } from './App'; import { createT } from './i18n'; import { WidgetApi, buildCapabilities } from './widget-api'; import './styles.css'; // Input-mode detector — see apps/widget-telegram/src/main.tsx for the // full rationale. Capacitor Android WebView mis-reports `hover: hover` // on touch devices, so we drive `:hover` styling off the actual // `pointerdown.pointerType` instead of media queries. The initial guess // based on `(any-pointer: coarse)` covers the pre-first-pointerdown // frame so a touch device doesn't briefly show mouse-mode hover // affordances if the user immediately taps a card. const setInputMode = (mode: 'touch' | 'mouse'): void => { document.documentElement.dataset.input = mode; }; setInputMode(window.matchMedia('(any-pointer: coarse)').matches ? 'touch' : 'mouse'); window.addEventListener( 'pointerdown', (event) => { setInputMode(event.pointerType === 'mouse' ? 'mouse' : 'touch'); }, { passive: true, capture: true } ); const root = document.getElementById('app'); if (!root) { throw new Error('#app root element missing — index.html out of sync'); } const result = readBootstrap(window.location.search); if (!result.ok) { // Either someone opened the widget URL directly (no host params), or a // host bug failed to provide them. Render a self-contained diagnostic // instead of going silent. Bootstrap failed before we could read // clientLanguage, so let createT fall back to navigator.language. const t = createT(); render(
{t('bootstrap.failed')} {t('bootstrap.missing-params', { names: result.missing.join(', ') })}{' '} {t('bootstrap.embedded-only', { route: '/bots/discord' })}
, root ); } else { // Apply initial theme synchronously so the first paint isn't flashed // through the wrong palette. document.documentElement.dataset.theme = result.bootstrap.theme; // Instantiate WidgetApi BEFORE React render. The constructor attaches // the message listener synchronously, so by the time the host's // ClientWidgetApi fires its capabilities request on iframe `load`, // we're already listening. Constructing inside a useEffect would race // with the cached-bundle remount path. See widget-telegram for full // rationale. const api = new WidgetApi(result.bootstrap, buildCapabilities(result.bootstrap.roomId)); render(, root); }