adb5d25715
Roadmap item #32 (session/transcript page polish) plus the /docs surfaces' share of #31, for rfc-app v0.21.0. - DocsSessionIndex: the session root (/docs/sessions/:nnnn) no longer renders a dead-end "N transcript(s) — select from the nav" placeholder. It now renders a transcript INLINE: the lone transcript for single-transcript sessions, or the `.0` driver transcript (falling back to first-by-sort) for multi-transcript sessions, with the remaining siblings listed/linked above the body. URL stays stable to the session number — inline render, no 301. - DocsSessionTranscript: adds a compact metadata header above the body (title; started/ended parsed from the filename's ISO segments, human-readable; derived duration; optional TL;DR from the manifest's `tldr` string field, graceful-degrade when absent; external "View source on git.wiggleverse.org" link). The parse/header helpers are exported so the inline-collapse view reuses identical rendering. - Docs.css (new): token-based styling for the new metadata-header + sibling-list elements only; existing docs classes stay owned by App.css to avoid racing the #31 sweep. - DocsUserGuide: loading/error states brought onto the shared .docs-empty/.docs-error convention with a retry button. No backend change: /api/docs/sessions/manifest already passes the full sessions.json entry through, so a `tldr` field on an entry reaches the frontend with no docs_sessions.py change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82 lines
2.6 KiB
React
82 lines
2.6 KiB
React
// 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 `<p className="error">`), 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 (
|
|
<article className="docs-article">
|
|
<h1 className="docs-article-title">User guide</h1>
|
|
{status === 'loading' && <p className="muted">Loading…</p>}
|
|
{status === 'error' && (
|
|
<div className="docs-error" role="alert">
|
|
<p>Couldn't load the user guide.</p>
|
|
<button
|
|
type="button"
|
|
onClick={retry}
|
|
aria-label="Retry"
|
|
data-amp-track-name="Docs User Guide Retry"
|
|
>
|
|
Try again
|
|
</button>
|
|
<p>
|
|
<Link
|
|
to="/docs/sessions/about"
|
|
aria-label="About sessions"
|
|
data-amp-track-name="Docs User Guide Error About Link"
|
|
>
|
|
About sessions
|
|
</Link>
|
|
</p>
|
|
</div>
|
|
)}
|
|
{status === 'ok' && (
|
|
<div className="philosophy-body">
|
|
<MarkdownPreview content={body} />
|
|
</div>
|
|
)}
|
|
</article>
|
|
)
|
|
}
|