Adopt shared WebUI structural primitives

This commit is contained in:
2026-08-18 13:17:31 +02:00
parent 0b4e7b6391
commit e05d5b4a54
3 changed files with 119 additions and 86 deletions
+89 -86
View File
@@ -8,10 +8,10 @@ import {
Dialog,
DismissibleAlert,
ExplorerTree,
LoadingFrame,
PageTitle,
PageLayout,
SegmentedControl,
StatusBadge,
WorkspaceLayout,
adminErrorMessage,
useGuardedNavigate,
usePlatformLanguage,
@@ -133,92 +133,95 @@ export default function DocsPage({ settings }: { settings: ApiSettings }) {
}, [treeNodes, selectedPage?.id]);
return (
<div className="workspace module-workspace docs-workspace">
<aside className="section-sidebar docs-outline" aria-label="i18n:govoplan-docs.documentation_outline.6f836b99">
<div className="docs-sidebar-header">
<div className="section-title">i18n:govoplan-docs.help_center.f3f3a34b</div>
<AudienceToggle
selected={documentationType}
onSelect={selectDocumentationType}
canViewAdmin={context?.actor.available_documentation_types.includes("admin") ?? documentationType === "admin"}
/>
<label className="docs-version-selector" title={context?.versions.fallback_policy}>
<span>Version</span>
<select
value={selectedVersion ?? ""}
onChange={(event) => selectVersion(event.target.value || null)}
>
<option value="">Installed versions</option>
{selectedVersion && !context?.versions.supported_versions.includes(selectedVersion) &&
<option value={selectedVersion}>{selectedVersion} (unsupported)</option>
}
{(context?.versions.supported_versions ?? []).map((version) => (
<option key={version} value={version}>{version}</option>
))}
</select>
</label>
</div>
<nav className="docs-tree" aria-label="i18n:govoplan-docs.documentation_outline.6f836b99">
<ExplorerTree
nodes={treeNodes}
getNodeId={(node) => node.id}
getNodeLabel={(node) => node.title}
getNodeChildren={(node) => node.children}
activeId={activeNodeIdForPage(treeNodes, selectedPage?.id ?? "")}
expandedIds={expandedNodes}
depth={0}
childrenBaseClassName="docs-tree-children"
nodeContainerClassName="docs-tree-node"
nodeWrapBaseClassName="docs-tree-row"
toggleBaseClassName="docs-tree-toggle"
nodeButtonBaseClassName="docs-tree-page"
getNodeWrapStyle={(_node, context) => ({ paddingLeft: `${context.depth * 14}px` })}
getNodeButtonClassName={(node) => selectedPage?.id === node.page.id ? "is-active" : ""}
renderToggleIcon={(_node, context) => context.hasChildren ? context.expanded ? <ChevronDown size={15} /> : <ChevronRight size={15} /> : <span className="docs-tree-toggle-placeholder" />}
renderNodeContent={(node) => node.title}
onToggle={(node) => toggleNode(node.id)}
onOpen={(node) => selectPage(node.page)}
/>
</nav>
</aside>
<section className="workspace-content docs-workspace-content">
<div className="content-pad workspace-data-page docs-page">
<div className="page-heading split workspace-heading">
<div>
<PageTitle loading={loading}>i18n:govoplan-docs.help_center.f3f3a34b</PageTitle>
<p>{adminDocs ? "i18n:govoplan-docs.technical_documentation_for_the_modules_and_conf.267e739e" : "i18n:govoplan-docs.guidance_for_the_functions_available_in_this_ins.723b7cad"}</p>
</div>
<div className="button-row compact-actions">
<Button onClick={() => void load()} disabled={loading}><RefreshCw size={16} /> i18n:govoplan-docs.reload.cce71553</Button>
</div>
<WorkspaceLayout
className="module-workspace docs-workspace"
primarySize="wide"
primaryLabel="i18n:govoplan-docs.documentation_outline.6f836b99"
contentLabel="i18n:govoplan-docs.help_center.f3f3a34b"
documentationType={documentationType}
contentClassName="docs-workspace-content"
primary={(
<aside className="section-sidebar docs-outline" aria-label="i18n:govoplan-docs.documentation_outline.6f836b99">
<div className="docs-sidebar-header">
<div className="section-title">i18n:govoplan-docs.help_center.f3f3a34b</div>
<AudienceToggle
selected={documentationType}
onSelect={selectDocumentationType}
canViewAdmin={context?.actor.available_documentation_types.includes("admin") ?? documentationType === "admin"}
/>
<label className="docs-version-selector" title={context?.versions.fallback_policy}>
<span>Version</span>
<select
value={selectedVersion ?? ""}
onChange={(event) => selectVersion(event.target.value || null)}
>
<option value="">Installed versions</option>
{selectedVersion && !context?.versions.supported_versions.includes(selectedVersion) &&
<option value={selectedVersion}>{selectedVersion} (unsupported)</option>
}
{(context?.versions.supported_versions ?? []).map((version) => (
<option key={version} value={version}>{version}</option>
))}
</select>
</label>
</div>
{error && <DismissibleAlert tone="danger" resetKey={error} floating>{error}</DismissibleAlert>}
<LoadingFrame loading={loading} label="i18n:govoplan-docs.loading_documentation_context.1c091645">
<div className="docs-content">
<main className="docs-page-main">
<SelectedPageContent
page={selectedPage}
adminDocs={adminDocs}
documentationType={documentationType}
topicById={topicById}
moduleRows={moduleRows}
visibleRoutes={visibleRoutes}
availableRoutes={availableRoutes}
grantedPermissions={grantedPermissions}
evidenceModules={context?.layers.evidence.optional_modules ?? []}
evidenceSources={context?.layers.evidence.sources ?? []}
settings={settings}
locale={locale}
/>
</main>
<PageOutline items={outlineItems} />
</div>
</LoadingFrame>
<nav className="docs-tree" aria-label="i18n:govoplan-docs.documentation_outline.6f836b99">
<ExplorerTree
nodes={treeNodes}
getNodeId={(node) => node.id}
getNodeLabel={(node) => node.title}
getNodeChildren={(node) => node.children}
activeId={activeNodeIdForPage(treeNodes, selectedPage?.id ?? "")}
expandedIds={expandedNodes}
depth={0}
childrenBaseClassName="docs-tree-children"
nodeContainerClassName="docs-tree-node"
nodeWrapBaseClassName="docs-tree-row"
toggleBaseClassName="docs-tree-toggle"
nodeButtonBaseClassName="docs-tree-page"
getNodeWrapStyle={(_node, context) => ({ paddingLeft: `${context.depth * 14}px` })}
getNodeButtonClassName={(node) => selectedPage?.id === node.page.id ? "is-active" : ""}
renderToggleIcon={(_node, context) => context.hasChildren ? context.expanded ? <ChevronDown size={15} /> : <ChevronRight size={15} /> : <span className="docs-tree-toggle-placeholder" />}
renderNodeContent={(node) => node.title}
onToggle={(node) => toggleNode(node.id)}
onOpen={(node) => selectPage(node.page)}
/>
</nav>
</aside>
)}
>
<PageLayout
title="i18n:govoplan-docs.help_center.f3f3a34b"
description={adminDocs ? "i18n:govoplan-docs.technical_documentation_for_the_modules_and_conf.267e739e" : "i18n:govoplan-docs.guidance_for_the_functions_available_in_this_ins.723b7cad"}
actions={<Button onClick={() => void load()} disabled={loading}><RefreshCw size={16} /> i18n:govoplan-docs.reload.cce71553</Button>}
loading={loading}
loadingLabel="i18n:govoplan-docs.loading_documentation_context.1c091645"
error={error}
mode="workspace"
documentationType={documentationType}
className="docs-page"
>
<div className="docs-content">
<main className="docs-page-main">
<SelectedPageContent
page={selectedPage}
adminDocs={adminDocs}
documentationType={documentationType}
topicById={topicById}
moduleRows={moduleRows}
visibleRoutes={visibleRoutes}
availableRoutes={availableRoutes}
grantedPermissions={grantedPermissions}
evidenceModules={context?.layers.evidence.optional_modules ?? []}
evidenceSources={context?.layers.evidence.sources ?? []}
settings={settings}
locale={locale}
/>
</main>
<PageOutline items={outlineItems} />
</div>
</section>
</div>
</PageLayout>
</WorkspaceLayout>
);
function selectDocumentationType(type: DocumentationType) {