// Help Content View // Purpose: Defines the Help Content View module and the local helpers/components used in this file. // Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit. import { useMemo } from 'react'; import { formatKeyLabel } from '../../controls/keymapUtils.js'; import { getHelpContent } from '../../help/content.js'; function KeyPill({ actionId, keymap }) { const value = keymap?.[actionId]?.[0] ?? ''; return ( {formatKeyLabel(value)} ); } function renderSegments(segments, keymap) { return segments.map((segment, idx) => { if (typeof segment === 'string') { return {segment}; } if (segment?.action) { return ; } if (segment?.text) { return {segment.text}; } return null; }); } function renderLine(line, keymap) { if (typeof line === 'string') return line; if (Array.isArray(line?.segments)) return renderSegments(line.segments, keymap); if (line && typeof line === 'object') { // Fallback: render any stray object as text if possible if (typeof line.text === 'string') return line.text; if (Array.isArray(line)) return renderSegments(line, keymap); } return String(line ?? ''); } function Hero({ hero, keymap }) { if (!hero) return null; return (

{hero.title}

{hero.subtitle &&

{hero.subtitle}

}
{hero.chips && (
{hero.chips.map((chip) => ( {chip} ))}
)}
{hero.bullets && ( )}
); } function ListBlock({ block, keymap }) { return (

{block.title}

); } function CalloutBlock({ block }) { const toneClass = block.tone === 'info' ? 'border-cyan-500/40' : 'border-slate-700'; return (

{block.title}

{block.body && ( )}
); } function KeyboardGroup({ group, keymap }) { return (

{group.title}

{group.items.map((item) => (
{/* A binding label may wrap in a slim sidebar, while the key remains a compact complete token instead of forcing horizontal overflow. */} {item.label}
))}
); } function KeyboardBlock({ block, keymap }) { if (!block) return null; return (
{/* Heading and footnote share a row when possible and wrap independently when the Help card is mounted in a narrow desktop column. */}
{block.title} {block.footnote && {block.footnote}}
{/* Two keyboard groups fit comfortably once the Help surface reaches 32rem. Using the real content threshold restores the established old-page layout without forcing two crushed columns inside the narrow new-drive sidebar. */}
{block.groups?.map((group) => ( ))}
); } function GamepadBlock({ block }) { if (!block) return null; return (

{block.title}

); } function BlockRenderer({ block, keymap }) { if (!block) return null; switch (block.type) { case 'list': return ; case 'callout': return ; case 'keyboard': return ; case 'gamepad': return ; default: return null; } } export function HelpContentView({ layout, keymap }) { const content = useMemo(() => getHelpContent(layout), [layout]); const bindings = keymap || {}; const mainBlocks = content.main || []; const asideBlocks = content.aside || []; return (
{/* The previous fixed 360px minimum was wider than the new-drive sidebar and forced the entire Help card to overflow. This intrinsic minimum uses one full-width column when 22.5rem cannot physically fit, while preserving the multi-column presentation in genuinely wide panels. */}
{mainBlocks.map((block, idx) => ( ))}
{asideBlocks.map((block, idx) => ( ))}
); } export default HelpContentView;