Add contextual "?" help icons linking into Docs (ticket 021)

New HelpIcon component + a DocsNavProvider context (webapp/src/lib/docsNav.tsx)
let any component request "open Docs to section X", bumping a nonce each
time so a repeat click re-triggers even if Docs is already open to that
section. NavMenu forwards that request into DocsPanel as a `target` prop,
which expands the right accordion section, scrolls it into view, and
flashes it (a brief accent-tinted background/border, settling back after
1.2s) — verified visually with a live server + Playwright. Opening Docs via
the plain NavMenu button explicitly clears any pending target, so that path
is unchanged: no forced section, no flash.

Added a "?" icon to FilterBar, LogTimeline, LogPreview, Metrics, Dashboards,
and NavMenu's own Settings/Presets panels, plus new Docs sections for
Timeline, Log preview, Settings, and Presets (previously undocumented).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
This commit is contained in:
Hugh Kaznowski
2026-09-05 15:49:49 +01:00
co-authored by Claude Sonnet 5
parent ce711ab70e
commit abc061a7b1
10 changed files with 206 additions and 20 deletions
+28 -3
View File
@@ -2,7 +2,9 @@ import { useEffect, useState } from 'react'
import type { Stats } from '../lib/api'
import type { ColorScheme } from '../lib/api'
import { useSettingsPanel } from '../lib/useSettingsPanel'
import { useDocsNav, type DocsTarget } from '../lib/docsNav'
import { DocsPanel } from './Docs'
import { HelpIcon } from './HelpIcon'
type PanelName = 'settings' | 'presets' | 'docs' | null
@@ -31,11 +33,30 @@ const COLOR_SCHEMES: ColorScheme[] = [
export function NavMenu({ stats }: { stats: Stats | null }) {
const [openPanel, setOpenPanel] = useState<PanelName>(null)
const panel = useSettingsPanel()
const docsNav = useDocsNav()
const [docsPanelTarget, setDocsPanelTarget] = useState<DocsTarget | null>(null)
function togglePanel(name: PanelName) {
setOpenPanel((current) => (current === name ? null : name))
}
// A "?" icon (ticket 021) always opens Docs to that section and flashes it,
// even if Docs is already open to a different section — hence forcing
// `openPanel` here rather than toggling.
useEffect(() => {
if (!docsNav.target) return
setOpenPanel('docs')
setDocsPanelTarget(docsNav.target)
}, [docsNav.target])
// Opening Docs the normal way (this button, not a "?" icon) behaves as
// before: no forced section, no flash — so any pending help-triggered
// target is cleared.
function handleDocsButtonClick() {
togglePanel('docs')
setDocsPanelTarget(null)
}
return (
<div className="flex h-full">
<div className="flex h-full w-48 shrink-0 flex-col justify-between border-r border-border p-3">
@@ -63,7 +84,7 @@ export function NavMenu({ stats }: { stats: Stats | null }) {
</button>
<button
type="button"
onClick={() => togglePanel('docs')}
onClick={handleDocsButtonClick}
className={`rounded px-2 py-1 text-left hover:bg-surface-2 ${
openPanel === 'docs' ? 'bg-surface-2 text-text' : ''
}`}
@@ -93,7 +114,11 @@ export function NavMenu({ stats }: { stats: Stats | null }) {
}`}
>
<div className="mb-3 flex items-center justify-between">
<h2 className="text-sm font-semibold text-text">{PANEL_TITLES[openPanel]}</h2>
<div className="flex items-center gap-1.5">
<h2 className="text-sm font-semibold text-text">{PANEL_TITLES[openPanel]}</h2>
{openPanel === 'settings' && <HelpIcon sectionId="settings" label="Help: Settings" />}
{openPanel === 'presets' && <HelpIcon sectionId="presets" label="Help: Presets" />}
</div>
<button
type="button"
onClick={() => setOpenPanel(null)}
@@ -110,7 +135,7 @@ export function NavMenu({ stats }: { stats: Stats | null }) {
)}
{openPanel === 'settings' && <SettingsPanel panel={panel} />}
{openPanel === 'presets' && <PresetsPanel panel={panel} />}
{openPanel === 'docs' && <DocsPanel />}
{openPanel === 'docs' && <DocsPanel target={docsPanelTarget} />}
</div>
)}
</div>