import { useI18n } from '../i18n' import type { MessageKey } from '../i18n/en' import { isWebAuthnSupported } from '../auth/passkey' import { Callout } from './ui' type T = (key: MessageKey, vars?: Record) => string /** True when the app is rendered inside another frame — passkeys need the top-level origin. */ export function inEmbeddedFrame(): boolean { try { return window.self !== window.top } catch { return true } } export function statusLabel(t: T, status: string): string { const key = `d2.status.${status}` as MessageKey const label = t(key) return label === key ? status : label } export function roleLabel(t: T, role: string): string { const key = `d2.role.${role}` as MessageKey const label = t(key) return label === key ? role : label } /** Shows unsupported-browser and embedded-frame warnings for passkey flows. */ export function PasskeyEnvWarnings() { const { t } = useI18n() return ( <> {!isWebAuthnSupported() && {t('d2.unsupported')}} {inEmbeddedFrame() && {t('d2.iframeWarn')}} ) } /** * When the app is embedded in another site's iframe (e.g. the huggingface.co Spaces page), * browsers may block the session cookie and passkeys. Offer a one-tap break-out to the app's own * first-party tab, where everything works. Renders nothing when not embedded. */ export function OpenInNewTabBanner() { const { t } = useI18n() if (!inEmbeddedFrame()) return null const href = typeof window !== 'undefined' ? window.location.href : '#' return (
{t('d2.openNewTab.title')}

{t('d2.openNewTab.body')}

{t('d2.openNewTab.button')} ↗
) } /** Accessible destructive-action confirmation. Focus lands on Cancel; Esc cancels. */ export function ConfirmDialog({ message, confirmLabel, danger = true, busy = false, onConfirm, onCancel, }: { message: string confirmLabel: string danger?: boolean busy?: boolean onConfirm: () => void onCancel: () => void }) { const { t } = useI18n() return (
e.stopPropagation()} onKeyDown={(e) => { if (e.key === 'Escape') onCancel() }} >

{message}

) }