// DocsUserGuide.jsx — v0.19.0 / roadmap item #30. // // Renders DOCS.md at `/docs/user-guide`. Was `/docs` before v0.19.0 // (the v0.14.0 single-route Docs.jsx surface, now superseded). The // content path is unchanged: backend reads `DOCS.md` from disk and // serves it at `/api/docs`. The body is rendered via the existing // `MarkdownPreview` (the same component the `/philosophy` route uses, // so we don't introduce a second markdown library). // v0.21.0 / roadmap item #31: the loading + error states are brought // onto the same `.docs-empty` / `.docs-error` convention every other // docs surface uses (was a bare `

`), with a retry // button so a transient `/api/docs` failure isn't a dead end. import { useEffect, useState, useCallback } from 'react' import { Link } from 'react-router-dom' import MarkdownPreview from './MarkdownPreview.jsx' import { getDocs } from '../api.js' import { EVENTS, track } from '../lib/analytics' export default function DocsUserGuide() { const [body, setBody] = useState('') const [status, setStatus] = useState('loading') // loading | ok | error const [reloadTick, setReloadTick] = useState(0) useEffect(() => { track(EVENTS.DOC_VIEWED, { section: 'user-guide' }) }, []) useEffect(() => { let active = true setStatus('loading') getDocs() .then(r => { if (!active) return setBody(r.body || '') setStatus('ok') }) .catch(() => { if (!active) return setStatus('error') }) return () => { active = false } }, [reloadTick]) const retry = useCallback(() => setReloadTick(t => t + 1), []) return (

User guide

{status === 'loading' &&

Loading…

} {status === 'error' && (

Couldn't load the user guide.

About sessions

)} {status === 'ok' && (
)}
) }