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

@ -32,6 +32,16 @@
.ui-dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
}
/* `plain` (see Dialog.tsx's file-top comment): drop this dialog's own
card look entirely — sizing/backdrop/scroll behavior above are the
only things left that are actually this component's job once the
content supplies its own bordered card (a `Panel`). */
.ui-dialog-plain {
border: none;
border-radius: 0;
background: none;
padding: 0;
}
.ui-dialog-close {
position: absolute;
top: 0.75em;
@ -60,3 +70,9 @@
render directly under the button instead of beside it. */
padding-right: 3.25em;
}
/* `plain` has no floating close button of its own to clear — the
content's own `Panel` header carries one instead (see `.ui-panel-close`
in Panel.css). */
.ui-dialog-body-plain {
padding-right: 0;
}

View file

@ -10,6 +10,18 @@
// from its former life as a standalone route — reusing that unchanged
// is simpler and lower-risk than re-deriving a modal-specific layout
// for content mara has already reviewed).
//
// `plain` (mara, screenshot of the matrix-account dialog: "the outer
// card does not serve a purpose. move the close btn into the bar and
// drop one layer"): content that's already a `Panel` — a bordered
// card with its own header bar — nested inside this dialog's own
// bordered card produced two concentric boxes in the same `--bg-elev`,
// one serving no purpose. `plain` drops this dialog's own card chrome
// (border/background/padding) and its floating close button, so a
// `Panel` (with its own `onClose` wired into its header) becomes the
// dialog's sole visible card instead of a second one nested inside it.
// Escape and backdrop-click still close it either way — those are the
// native `<dialog>`'s own behavior, not this button's.
import { useEffect, useRef } from "preact/hooks";
import type { ComponentChildren } from "preact";
import "./Dialog.css";
@ -19,6 +31,7 @@ export function Dialog({
onClose,
label,
children,
plain = false,
}: {
open: boolean;
onClose: () => void;
@ -26,6 +39,10 @@ export function Dialog({
// why content owns its own heading.
label: string;
children: ComponentChildren;
/** Drop this dialog's own card chrome + floating close button — see
* file-top comment. Pair with a `Panel` (or similar) that renders its
* own header + `onClose` button as the dialog's content. */
plain?: boolean;
}) {
const ref = useRef<HTMLDialogElement>(null);
@ -57,7 +74,7 @@ export function Dialog({
return (
<dialog
ref={ref}
class="ui-dialog"
class={plain ? "ui-dialog ui-dialog-plain" : "ui-dialog"}
aria-label={label}
// A click lands on the `<dialog>` element itself (not any child)
// exactly when it's outside the rendered content box — inside
@ -67,15 +84,21 @@ export function Dialog({
if (e.target === ref.current) onClose();
}}
>
<button
type="button"
class="ui-dialog-close"
aria-label="close"
onClick={onClose}
{plain ? null : (
<button
type="button"
class="ui-dialog-close"
aria-label="close"
onClick={onClose}
>
✕
</button>
)}
<div
class={plain ? "ui-dialog-body ui-dialog-body-plain" : "ui-dialog-body"}
>
✕
</button>
<div class="ui-dialog-body">{children}</div>
{children}
</div>
</dialog>
);
}