v0.19.0 frontend: /docs/* route tree + flyout nav + sessions browser
Reorganizes the /docs surface from a single DOCS.md route into a hub with a left-side flyout nav and three new sub-routes for the on-site sessions browser (roadmap item #30): /docs → redirect to /docs/user-guide /docs/user-guide → existing DOCS.md content /docs/sessions → redirect to /docs/sessions/about /docs/sessions/about → README.md of ohm-session-history /docs/sessions/<NNNN> → per-session transcript index /docs/sessions/<NNNN>/<f> → per-transcript view The flyout is a persistent left sidebar on desktop and a slide-out drawer on mobile (toggled by a ☰ button in the docs header). Its session list is driven by the /api/docs/sessions/manifest fetch — loading shows a skeleton; 502 shows an inline retry; empty manifest shows only the "About" row. Each sub-route owns its own empty-state / error handling: - 404 transcripts render "This transcript isn't published yet" with a link back to the parent session index, no JS crash. - 502 (gitea unreachable) renders a retry button. - Manifest 404 is mapped to {} server-side so the flyout renders cleanly with no error banner when no sessions are published yet. Analytics (per SPEC §21): - new EVENTS.DOC_VIEWED ("Doc Viewed") fires on each sub-route mount with `section`: 'user-guide' | 'sessions/about' | 'sessions/<NNNN>' | 'sessions/<NNNN>/<filename>'. - every interactive nav element carries aria-label + data-amp-track-name so autocapture rows are readable. The existing v0.14.0 Docs.jsx component is dropped — its content moved verbatim into DocsUserGuide.jsx; the new layout subsumes the back-button + signed-out home affordances it used to carry. All four new sub-routes reuse the existing MarkdownPreview renderer (marked + mermaid lazy-load) so no second markdown library lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -720,6 +720,60 @@ export async function getDocs() {
|
||||
return jsonOrThrow(await fetch('/api/docs'))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// v0.19.0 / roadmap item #30 — /api/docs/sessions/* surface
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// The framework mediates reads against the public
|
||||
// `wiggleverse/ohm-session-history` gitea repo so the rendered
|
||||
// `/docs/sessions/*` surface inherits the same chrome as
|
||||
// `/docs/user-guide`. Three text-bearing endpoints return markdown
|
||||
// (Content-Type: text/markdown) and the manifest returns JSON. We
|
||||
// wrap each into a small helper.
|
||||
//
|
||||
// 404 from `getSessionAbout` / `getSessionTranscript` / `getSessionIndex`
|
||||
// throws an Error with `.status === 404` so the UI can render its own
|
||||
// empty-state. 502 (gitea unreachable) throws `.status === 502` so
|
||||
// the UI can offer a retry button.
|
||||
|
||||
export async function getSessionsManifest() {
|
||||
// Manifest 404 is mapped server-side to HTTP 200 + `{}` so this
|
||||
// helper never throws on the empty-state path.
|
||||
return jsonOrThrow(await fetch('/api/docs/sessions/manifest'))
|
||||
}
|
||||
|
||||
async function _textOrThrow(res) {
|
||||
if (!res.ok) {
|
||||
let detail = ''
|
||||
try {
|
||||
const body = await res.json()
|
||||
detail = body.detail || JSON.stringify(body)
|
||||
} catch {
|
||||
detail = await res.text()
|
||||
}
|
||||
const error = new Error(detail || `HTTP ${res.status}`)
|
||||
error.status = res.status
|
||||
throw error
|
||||
}
|
||||
return res.text()
|
||||
}
|
||||
|
||||
export async function getSessionsAbout() {
|
||||
return _textOrThrow(await fetch('/api/docs/sessions/about'))
|
||||
}
|
||||
|
||||
export async function getSessionTranscript(nnnn, filename) {
|
||||
return _textOrThrow(await fetch(
|
||||
`/api/docs/sessions/${encodeURIComponent(nnnn)}/${encodeURIComponent(filename)}`
|
||||
))
|
||||
}
|
||||
|
||||
export async function getSessionIndex(nnnn) {
|
||||
return jsonOrThrow(await fetch(
|
||||
`/api/docs/sessions/${encodeURIComponent(nnnn)}/index`
|
||||
))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Slice 7: admin neighborhood (§17 admin/* + user search for the §15.8 mute
|
||||
// typeahead).
|
||||
|
||||
Reference in New Issue
Block a user