import { useEffect, useMemo, useState } from 'react' import Markdown from 'markdown-to-jsx' import { Link, useLocation } from 'react-router-dom' import { createMarkdownOptions, preprocessMarkdown } from '../components/MessageContent' import { TopBar } from '../components/TopBar' import './HelpPage.css' // Single source of truth is the repo-root USER_GUIDE.md -- frontend/public/ // symlinks to it, so this fetches the same file a developer sees when // browsing the repo, rather than duplicating its content into the bundle. const GUIDE_URL = '/USER_GUIDE.md' export function HelpPage() { const [content, setContent] = useState(null) const [error, setError] = useState(null) // #21: heading-id/sub/superscript support -- the user guide is exactly // the kind of document that benefits from an explicit anchor override. const markdownPreview = useMemo( () => (content !== null ? preprocessMarkdown(content) : null), [content], ) // #75: the composer's "?" links straight to /help#formatting, but the guide // is fetched after the page loads -- the browser's own scroll-to-hash has // already run (and found nothing) by the time the headings exist. const { hash } = useLocation() useEffect(() => { if (!markdownPreview || !hash) return document.getElementById(hash.slice(1))?.scrollIntoView() }, [markdownPreview, hash]) useEffect(() => { let cancelled = false fetch(GUIDE_URL) .then((res) => { if (!res.ok) throw new Error(`Failed to load guide (${res.status})`) return res.text() }) .then((text) => { if (!cancelled) setContent(text) }) .catch((err) => { if (!cancelled) setError(err instanceof Error ? err.message : 'Failed to load guide') }) return () => { cancelled = true } }, []) return (

Help

Back to chat
{error &&

{error}

} {!error && content === null &&

Loading…

} {!error && markdownPreview && (
{markdownPreview.text}
)}
) }