import { useEffect, useState } from 'preact/hooks'; import type { WidgetBootstrap } from './bootstrap'; import type { WidgetApi } from './widget-api'; import { createT, type T } from './i18n'; // Must match the host's capability string (catalog.ts BOT_CAP_ADD_TO_CHAT). const ADD_TO_CHAT_CAP = 'vojo.add_to_chat'; // Lead glyph for the «Добавить в чат» card — a speech bubble with a «+». // Stroke-only so it picks up `currentColor` and matches the bridge widgets' // icon language (viewBox 20×20, stroke-width 1.6). const AddChatIcon = () => ( ); // Shield + check — leads the «Конфиденциальность и данные» card (mirrors the // Telegram widget's info-card-opens-modal pattern). const ShieldIcon = () => ( ); // Full privacy notice, behind a card → modal (Telegram «О боте» pattern). This // is where the Grok / xAI / 30-day / third-party detail lives — NOT on the // surface. Backdrop click + Escape close; no focus-trap (small surface). const AboutModal = ({ t, onClose }: { t: T; onClose: () => void }) => { useEffect(() => { const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [onClose]); return (
); }; type AppProps = { bootstrap: WidgetBootstrap; api: WidgetApi; }; export function App({ bootstrap, api }: AppProps) { const t = createT(bootstrap.clientLanguage); const [aboutOpen, setAboutOpen] = useState(false); // Render the action ONLY when the host advertised the capability. UI hint // only — the host re-checks the capability against the trusted config before // honouring the verb, so a forced render here cannot escalate anything. const canAddToChat = bootstrap.capabilities.includes(ADD_TO_CHAT_CAP); // Follow host theme changes (initial theme applied in main.tsx before paint). useEffect(() => { api.on('themeChange', (name) => { document.documentElement.dataset.theme = name; }); }, [api]); return (