Adopt shared WebUI structural primitives

This commit is contained in:
2026-08-18 13:17:32 +02:00
parent 225a3a233b
commit 6b0e3ae37d
3 changed files with 24 additions and 88 deletions
+20 -31
View File
@@ -20,17 +20,21 @@ import {
} from "lucide-react";
import { FormGrid,
ActionBlockerHint,
ActionToolbar,
Button,
ConfirmDialog,
CountBadge,
DataGridPaginationBar,
Dialog,
DismissibleAlert,
DocumentationHelpLink,
FormField,
FilterBar,
IconButton,
SegmentedControl,
SelectionList,
SelectionListItem,
StatePanel,
StatusBadge,
ToggleSwitch,
hasScope,
@@ -585,7 +589,7 @@ export default function PostboxPage({
<main className="workspace-data-page module-entry-page postbox-page">
<div className="postbox-shell">
<aside className="postbox-directory" data-view-surface="postbox.inbox.directory">
<div className="postbox-bar">
<ActionToolbar surface="panel-header" className="postbox-bar">
<div className="postbox-bar-title">
<Inbox size={17} aria-hidden="true" />
<strong>Postbox</strong>
@@ -607,7 +611,7 @@ export default function PostboxPage({
disabledReason={postboxBusyReason(loadingDirectory, busy)}
/>
</div>
</div>
</ActionToolbar>
<div className="postbox-scope-control">
<label htmlFor="postbox-scope">Inbox view</label>
@@ -639,10 +643,7 @@ export default function PostboxPage({
<div className="postbox-directory-list">
{loadingDirectory ? <p className="postbox-note">Loading postboxes</p> : null}
{!loadingDirectory && !postboxes.length ? (
<div className="postbox-empty compact">
<Archive size={20} />
<strong>No assigned postboxes</strong>
<p>Postboxes appear when your account has a current matching function assignment.</p>
<StatePanel size="compact" icon={<Archive size={20} />} title="No assigned postboxes" description="Postboxes appear when your account has a current matching function assignment.">
<ActionBlockerHint
reason={{
summary: POSTBOX_INTERFACE_I18N.noPostbox,
@@ -657,10 +658,10 @@ export default function PostboxPage({
}}
documentation={POSTBOX_DOCUMENTATION}
/>
</div>
</StatePanel>
) : null}
{postboxes.length ? (
<SelectionList label="Assigned postboxes">
<SelectionList variant="navigation" label="Assigned postboxes">
{postboxes.map((postbox) => (
<SelectionListItem
key={postbox.id}
@@ -687,7 +688,7 @@ export default function PostboxPage({
</aside>
<section className="postbox-message-list" data-view-surface="postbox.inbox.messages">
<div className="postbox-bar">
<ActionToolbar surface="panel-header" className="postbox-bar">
<div className="postbox-bar-title">
{selectedPostbox ? (
<>
@@ -705,7 +706,7 @@ export default function PostboxPage({
<strong>All postboxes</strong>
</>
)}
<span className="postbox-total">{total}</span>
<CountBadge tone="neutral">{total}</CountBadge>
</div>
<div className="postbox-icon-actions">
<IconButton
@@ -723,9 +724,9 @@ export default function PostboxPage({
disabledReason={postboxBusyReason(loadingMessages, busy)}
/>
</div>
</div>
</ActionToolbar>
<div className="postbox-message-filters">
<div className="postbox-search-row">
<FilterBar surface="control" wrap="never" className="postbox-search-row">
<input
type="search"
value={searchDraft}
@@ -764,7 +765,7 @@ export default function PostboxPage({
setSelectedMessage(null);
}}
/>
</div>
</FilterBar>
<SegmentedControl<MessageStateFilter>
ariaLabel="Message state"
width="fill"
@@ -791,14 +792,10 @@ export default function PostboxPage({
<div className="postbox-messages">
{loadingMessages ? <p className="postbox-note">Loading messages</p> : null}
{!loadingMessages && !messages.length ? (
<div className="postbox-empty">
<MailOpen size={24} />
<strong>No messages</strong>
<p>This view has no delivered Postbox messages.</p>
</div>
<StatePanel size="fill" icon={<MailOpen size={24} />} title="No messages" description="This view has no delivered Postbox messages." />
) : null}
{messages.length ? (
<SelectionList label="Postbox messages">
<SelectionList variant="navigation" label="Postbox messages">
{messages.map((message) => (
<SelectionListItem
key={message.id}
@@ -855,7 +852,7 @@ export default function PostboxPage({
</section>
<section className="postbox-detail">
<div className="postbox-bar">
<ActionToolbar surface="panel-header" className="postbox-bar">
<div className="postbox-bar-title">
<MailOpen size={17} aria-hidden="true" />
<strong>{selectedMessage?.subject || "Message"}</strong>
@@ -876,7 +873,7 @@ export default function PostboxPage({
<CheckCheck size={16} /> Acknowledge
</Button>
</div>
</div>
</ActionToolbar>
{selectedMessage ? (
<MessageDetail
message={selectedMessage}
@@ -889,17 +886,9 @@ export default function PostboxPage({
}}
/>
) : unavailableSelection ? (
<div className="postbox-empty postbox-unavailable-message">
<Archive size={24} />
<strong>Message unavailable</strong>
<p>{unavailableSelection}</p>
</div>
<StatePanel size="fill" tone="warning" icon={<Archive size={24} />} title="Message unavailable" description={unavailableSelection} className="postbox-unavailable-message" />
) : (
<div className="postbox-empty">
<Inbox size={24} />
<strong>Select a message</strong>
<p>Source, function context, content, and evidence remain attached to the originating postbox.</p>
</div>
<StatePanel size="fill" icon={<Inbox size={24} />} title="Select a message" description="Source, function context, content, and evidence remain attached to the originating postbox." />
)}
</section>
</div>