Adopt shared WebUI layout primitives

This commit is contained in:
2026-08-18 10:42:54 +02:00
parent 21ed6270a3
commit cf4205f780
@@ -10,7 +10,7 @@ import {
X
} from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import {
import { DialogSection, ToolbarGroup, ActionToolbar,
ApiError,
ActionBlockerHint,
Button,
@@ -296,10 +296,10 @@ export default function TemplatesPage({ settings, auth }: Props) {
<main className="templates-page">
<div className="templates-shell">
<aside className="templates-sidebar">
<div className="templates-sidebar-toolbar">
<ActionToolbar className="templates-sidebar-toolbar">
<strong>Template library</strong>
<IconButton label="Add template" icon={<Plus size={17} />} variant="primary" disabled={!canWrite} disabledReason={!canWrite ? TEMPLATES_I18N.writeReason : undefined} onClick={() => requestDiscard(() => setCreateOpen(true))} />
</div>
</ActionToolbar>
<div className="templates-search"><input value={search} onChange={(event) => setSearch(event.target.value)} placeholder="Search templates" /></div>
<div className="templates-list">
{visibleItems.map((item) => (
@@ -324,12 +324,12 @@ export default function TemplatesPage({ settings, auth }: Props) {
</aside>
<section className="templates-workspace">
<header className="templates-workspace-toolbar">
<ActionToolbar className="templates-workspace-toolbar">
<span className="templates-current-title">
<strong>{selected?.name ?? "Select a template"}</strong>
<small>{selected ? `${typeLabel(selected.template_type)} · ${selected.revision.locale}` : ""}</small>
</span>
<div className="templates-toolbar-actions">
<ToolbarGroup align="end" className="templates-toolbar-actions">
<DocumentationHelpLink reference={TEMPLATES_DOCUMENTATION} />
<IconButton label="Discard and reload" icon={<RefreshCw size={17} />} disabled={loading || busy} disabledReason={loading ? TEMPLATES_I18N.loading : busy ? TEMPLATES_I18N.busy : undefined} onClick={() => requestDiscard(() => void reload(selectedId))} />
<Button variant="primary" disabled={!selected || readOnly || !dirty || busy} disabledReason={busy ? TEMPLATES_I18N.busy : !selected ? TEMPLATES_I18N.noSelection : readOnly ? (canWrite ? TEMPLATES_I18N.readOnlyReason : TEMPLATES_I18N.writeReason) : !dirty ? TEMPLATES_I18N.noChanges : undefined} onClick={() => void save()}><Save size={16} /> Save revision</Button>
@@ -341,8 +341,8 @@ export default function TemplatesPage({ settings, auth }: Props) {
options={[{ id: "definition", label: "Definition" }, { id: "preview", label: "Preview" }]}
ariaLabel="Template workspace"
/>
</div>
</header>
</ToolbarGroup>
</ActionToolbar>
<div className="templates-alerts">
{error && <DismissibleAlert tone="danger" resetKey={error}>{error}</DismissibleAlert>}
@@ -392,10 +392,10 @@ export default function TemplatesPage({ settings, auth }: Props) {
</div>
<Dialog open={createOpen} title="Add template" onClose={closeCreate} closeDisabled={busy} footer={<><Button onClick={closeCreate} disabled={busy} disabledReason={busy ? TEMPLATES_I18N.busy : undefined}>Cancel</Button><Button variant="primary" disabled={!createName.trim() || busy} disabledReason={busy ? TEMPLATES_I18N.busy : !createName.trim() ? TEMPLATES_I18N.incomplete : undefined} onClick={() => void create()}>Create</Button></>}>
<div className="templates-dialog-form">
<DialogSection className="templates-dialog-form">
<FormField label="Name" documentation={TEMPLATE_FIELDS_DOCUMENTATION}><input autoFocus value={createName} onChange={(event) => setCreateName(event.target.value)} /></FormField>
<FormField label="Type" documentation={TEMPLATE_FIELDS_DOCUMENTATION}><select value={createType} onChange={(event) => setCreateType(event.target.value as TemplateType)}>{TEMPLATE_TYPES.map((item) => <option key={item.value} value={item.value}>{item.label}</option>)}</select></FormField>
</div>
</DialogSection>
</Dialog>
<ConfirmDialog open={publishOpen} title="i18n:govoplan-templates.publish_title" message="i18n:govoplan-templates.publish_message" confirmLabel="Publish" busy={busy} onCancel={() => setPublishOpen(false)} onConfirm={() => void publish()} />
<ConfirmDialog open={finalRenderOpen} title="i18n:govoplan-templates.render_title" message="i18n:govoplan-templates.render_message" confirmLabel="Render final output" busy={busy} onCancel={() => setFinalRenderOpen(false)} onConfirm={() => void runRender(true)} />