import { useEffect, useRef } from 'react'; import { createPortal } from 'react-dom'; import { X, Sparkles, Users, Share2, LogIn, MousePointerClick, ListMusic, Inbox, Sliders, LogOut, } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { useHelpModalStore } from '../store/helpModalStore'; import SettingsSubSection from './SettingsSubSection'; /** * Orbit help modal. Rendered once at the app root; triggered from the * launch popover ("How does this work?") and the in-session bar's help * button. 9 accordion sections built on SettingsSubSection; all default * closed so the modal opens compact. Does not touch playback. */ export default function OrbitHelpModal() { const { t } = useTranslation(); const { isOpen, close } = useHelpModalStore(); const bodyRef = useRef(null); useEffect(() => { if (!isOpen) return; // Focus the first accordion summary so arrow keys work immediately. // Uses a short setTimeout because the browser re-focuses the clicked // trigger button after the click handler returns — our focus call has // to happen *after* that, otherwise the browser silently overrides it // and the user only gets keyboard nav after pressing Tab first. const id = window.setTimeout(() => { const first = bodyRef.current?.querySelector('summary'); first?.focus(); }, 60); return () => window.clearTimeout(id); }, [isOpen]); useEffect(() => { if (!isOpen) return; const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') { close(); return; } if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') return; const summaries = Array.from( bodyRef.current?.querySelectorAll('summary') ?? [], ); if (summaries.length === 0) return; const current = document.activeElement as HTMLElement | null; const idx = summaries.indexOf(current as HTMLElement); e.preventDefault(); const next = e.key === 'ArrowDown' ? summaries[(idx + 1 + summaries.length) % summaries.length] : summaries[(idx - 1 + summaries.length) % summaries.length]; next?.focus(); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, [isOpen, close]); if (!isOpen) return null; const hostOnlyLabel = t('orbit.helpHostOnly'); return createPortal(
{ if (e.target === e.currentTarget) close(); }} role="dialog" aria-modal="true" aria-labelledby="orbit-help-title" style={{ alignItems: 'center', paddingTop: 0 }} >

{t('orbit.helpTitle')}

{t('orbit.helpIntro')}

}>

{t('orbit.helpSec1Body')}

}>

{t('orbit.helpSec2Body')}

{t('orbit.helpSec2WarnHead')} {t('orbit.helpSec2WarnBody')}
}>

{t('orbit.helpSec3Body')}

}>

{t('orbit.helpSec4Body')}

}>

{t('orbit.helpSec5Body')}

}>

{t('orbit.helpSec6Body')}

} >

{t('orbit.helpSec7Body')}

} >

{t('orbit.helpSec8Body')}

}>

{t('orbit.helpSec9Body')}

, document.body, ); }