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:
@@ -2193,3 +2193,199 @@
|
||||
font-size: 11px; text-transform: uppercase;
|
||||
color: #6b7280; letter-spacing: 0.05em; font-weight: 600;
|
||||
}
|
||||
|
||||
/* ──────────────────────────────────────────────────────────────────
|
||||
v0.19.0 / roadmap item #30 — /docs/* flyout + sessions browser.
|
||||
|
||||
The shell is `.docs-layout` (header + body). The body is a flex
|
||||
row: `.docs-nav` is the persistent left sidebar on desktop and a
|
||||
slide-out drawer on mobile (toggled by the `.docs-drawer-toggle`
|
||||
icon in `.docs-header`). The content area `.docs-content` mounts
|
||||
the sub-route via React Router's <Outlet/>.
|
||||
|
||||
The article body inside each sub-route reuses `.philosophy-body`
|
||||
(defined above) for the markdown rendering — same `marked` lib,
|
||||
same typography. The new classes here just handle the chrome
|
||||
(sidebar + drawer + header).
|
||||
────────────────────────────────────────────────────────────────── */
|
||||
|
||||
.docs-layout {
|
||||
height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
|
||||
.docs-header {
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
padding: 12px 24px 12px 16px;
|
||||
border-bottom: 1px solid #f0f0ee;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.docs-back, .docs-drawer-toggle {
|
||||
border: none; background: none; cursor: pointer;
|
||||
color: #4b5563; font-size: 13px;
|
||||
padding: 4px 8px; border-radius: 4px;
|
||||
}
|
||||
.docs-back:hover, .docs-drawer-toggle:hover {
|
||||
background: #f3f4f6; color: #111;
|
||||
}
|
||||
.docs-drawer-toggle {
|
||||
display: none;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
.docs-title {
|
||||
font-size: 13px; color: #6b7280;
|
||||
text-transform: uppercase; letter-spacing: 0.08em;
|
||||
}
|
||||
.docs-signin {
|
||||
margin-left: auto;
|
||||
font-size: 13px; color: #4b5563; text-decoration: none;
|
||||
}
|
||||
.docs-signin:hover { color: #111; text-decoration: underline; }
|
||||
|
||||
.docs-body {
|
||||
flex: 1; min-height: 0;
|
||||
display: flex; flex-direction: row;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.docs-nav {
|
||||
flex-shrink: 0;
|
||||
width: 260px;
|
||||
border-right: 1px solid #f0f0ee;
|
||||
padding: 24px 20px;
|
||||
overflow-y: auto;
|
||||
background: #fafaf9;
|
||||
}
|
||||
|
||||
.docs-nav-inner { display: flex; flex-direction: column; gap: 24px; }
|
||||
.docs-nav-section { display: flex; flex-direction: column; gap: 8px; }
|
||||
.docs-nav-section-label {
|
||||
font-size: 11px; font-weight: 600;
|
||||
text-transform: uppercase; letter-spacing: 0.08em;
|
||||
color: #6b7280;
|
||||
}
|
||||
.docs-nav-list {
|
||||
list-style: none; padding: 0; margin: 0;
|
||||
display: flex; flex-direction: column; gap: 2px;
|
||||
}
|
||||
.docs-nav-list a {
|
||||
display: block;
|
||||
padding: 6px 10px; border-radius: 4px;
|
||||
color: #1f2937; text-decoration: none;
|
||||
font-size: 14px; line-height: 1.4;
|
||||
word-break: break-word;
|
||||
}
|
||||
.docs-nav-list a:hover { background: #f0f0ee; }
|
||||
.docs-nav-list a.active {
|
||||
background: #e7e5e4; color: #111; font-weight: 600;
|
||||
}
|
||||
|
||||
.docs-nav-skeleton .skeleton-row {
|
||||
display: block;
|
||||
height: 14px; margin: 8px 10px;
|
||||
background: linear-gradient(90deg, #f0f0ee 25%, #e7e5e4 50%, #f0f0ee 75%);
|
||||
background-size: 200% 100%;
|
||||
border-radius: 4px;
|
||||
animation: docs-skeleton-shimmer 1.2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes docs-skeleton-shimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
.docs-nav-error {
|
||||
padding: 8px 10px;
|
||||
font-size: 13px; color: #9a3412;
|
||||
background: #fff7ed; border: 1px solid #fed7aa; border-radius: 4px;
|
||||
display: flex; flex-direction: column; gap: 6px;
|
||||
}
|
||||
.docs-nav-error button {
|
||||
align-self: flex-start;
|
||||
background: #fff; border: 1px solid #fed7aa;
|
||||
color: #9a3412; font-size: 12px;
|
||||
padding: 4px 8px; border-radius: 4px; cursor: pointer;
|
||||
}
|
||||
.docs-nav-error button:hover { background: #fff7ed; }
|
||||
|
||||
.docs-content {
|
||||
flex: 1; min-width: 0;
|
||||
overflow-y: auto;
|
||||
padding: 24px 32px 64px;
|
||||
}
|
||||
|
||||
.docs-article {
|
||||
max-width: 760px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.docs-article-title {
|
||||
font-size: 28px; font-weight: 700; margin: 0 0 24px;
|
||||
letter-spacing: -0.01em;
|
||||
color: #111;
|
||||
}
|
||||
.docs-breadcrumbs { margin: 0 0 16px; font-size: 13px; }
|
||||
.docs-breadcrumbs a {
|
||||
color: #4b5563; text-decoration: none;
|
||||
}
|
||||
.docs-breadcrumbs a:hover { color: #111; text-decoration: underline; }
|
||||
|
||||
.docs-session-files {
|
||||
list-style: none; padding: 0; margin: 0;
|
||||
display: flex; flex-direction: column; gap: 6px;
|
||||
}
|
||||
.docs-session-files a {
|
||||
display: block;
|
||||
padding: 10px 14px; border-radius: 6px;
|
||||
background: #fafaf9; border: 1px solid #f0f0ee;
|
||||
color: #1f2937; text-decoration: none;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
font-size: 13px; word-break: break-all;
|
||||
}
|
||||
.docs-session-files a:hover {
|
||||
background: #f3f4f6; border-color: #e5e7eb;
|
||||
}
|
||||
|
||||
.docs-empty, .docs-error {
|
||||
padding: 16px; border-radius: 6px;
|
||||
background: #fafaf9; border: 1px solid #f0f0ee;
|
||||
font-size: 14px; line-height: 1.6; color: #4b5563;
|
||||
}
|
||||
.docs-error { background: #fef2f2; border-color: #fecaca; color: #991b1b; }
|
||||
.docs-error button {
|
||||
margin-top: 10px;
|
||||
background: #fff; border: 1px solid #fecaca;
|
||||
color: #991b1b; font-size: 13px;
|
||||
padding: 6px 12px; border-radius: 4px; cursor: pointer;
|
||||
}
|
||||
.docs-error button:hover { background: #fef2f2; }
|
||||
|
||||
.docs-drawer-scrim {
|
||||
display: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.3);
|
||||
border: none; padding: 0;
|
||||
cursor: pointer;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
/* Mobile: the sidebar becomes a slide-out drawer. */
|
||||
@media (max-width: 720px) {
|
||||
.docs-drawer-toggle { display: inline-block; }
|
||||
.docs-nav {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0; left: 0;
|
||||
width: 80%; max-width: 320px;
|
||||
z-index: 10;
|
||||
transform: translateX(-100%);
|
||||
transition: transform 200ms ease-out;
|
||||
box-shadow: 2px 0 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
.docs-body--drawer-open .docs-nav {
|
||||
transform: translateX(0);
|
||||
}
|
||||
.docs-body--drawer-open .docs-drawer-scrim {
|
||||
display: block;
|
||||
}
|
||||
.docs-content { padding: 16px 18px 64px; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user