Watch
0
0
Fork
You've already forked hyperhive
0

swarm-ui: drop the redundant outer dialog card, move close into the panel header

Dialog and Panel both drew their own bordered/backgrounded card in the
same --bg-elev, so a Panel-based dialog (create-agent, link-matrix-account)
rendered as two concentric cards with a floating close button on the
outer one and no purpose to it.

Give Dialog a "plain" mode that drops its own card chrome (border,
background, padding) and floating close button, and give Panel an
optional onClose that renders a close button at the end of its own
header row instead. AgentsPage's two Panel-backed dialogs now use
plain + Panel's onClose, so the Panel is the dialog's only visible
card. ConfirmDialog (no Panel of its own) is unaffected — plain
defaults to false, unchanged card + floating close button.

Added a ComponentsPage sample demonstrating the plain + onClose
pairing. Verified both dialog modes via a real headless-chromium
screenshot (plain dialog: single card, close button in the header
bar; default dialog: unchanged floating close button).
This commit is contained in:
iris 2026-09-13 00:58:53 +02:00
commit 8a4c613e4e
8 changed files with 158 additions and 18 deletions

View file

@ -219,6 +219,36 @@ function DialogSample() {
);
}
// `plain`: a `Panel`'s own header bar/border is the dialog's
// only card, not a second one nested inside `Dialog`'s own — pair
// `plain` with `Panel`'s `onClose` so the close button still exists,
// just moved into that header instead of floating over the whole thing.
function PlainDialogSample() {
const [open, setOpen] = useState(false);
return (
<>
<Button onClick={() => setOpen(true)}>open plain dialog</Button>
<Dialog
open={open}
onClose={() => setOpen(false)}
label="sample plain dialog"
plain
>
<Panel
title="a form-shaped dialog"
icon="🔗"
onClose={() => setOpen(false)}
>
<p>
One card, one header bar — the close button lives here instead of
floating over a second, purposeless outer one.
</p>
</Panel>
</Dialog>
</>
);
}
// Own state for the same reason `TextFieldSample` needs it — a
// controlled sample has to actually respond to interaction.
function MultiselectFilterSample() {
@ -458,6 +488,9 @@ export function ComponentsPage() {
<Sample label="modal, caller-owned content">
<DialogSample />
</Sample>
<Sample label="plain — content supplies its own card + close">
<PlainDialogSample />
</Sample>
</Section>
<Section title="ConfirmDialog">