Watch
0
0
Fork
You've already forked hyperhive
0

swarm-ui: an agent's settings and AGENTS.md show placeholders while they load

BadgeSkeleton is the twin of Badge: the real Badge frame, as tall as an
interactive one (the settings values are buttons), with a placeholder for its
value. Permissions, resource caps, internet and allowed domains use it in place of
their "loading…" text, the details popover shows lines of text, and the
AGENTS.md editor a block, in place of theirs. SkeletonLines is a few stacked
lines for such blocks.
This commit is contained in:
iris 2026-11-06 17:27:55 +01:00
commit a9f0d61daa
3 changed files with 106 additions and 27 deletions

View file

@ -0,0 +1,30 @@
// <BadgeSkeleton> — the twin of a <Badge> for a value that is still loading:
// the real Badge frame (so the pill has the height and padding the loaded one
// will have; its settings values are buttons, which keep a 2.75em touch
// target, see Skeleton.css) with a placeholder shape for its value, and the label the badge
// will carry when that is known already. For the settings rows of an agent's
// details, where each value is one badge.
import { Badge } from "@hive/shared/badge.js";
import { Skeleton, SkeletonRegion } from "./Skeleton.js";
export function BadgeSkeleton({
label,
what,
width = "5em",
}: {
/** The badge's dim prefix, e.g. "permissions". */
label?: string;
/** What is loading, as a screen reader says it: "the permissions". */
what: string;
width?: string;
}) {
return (
<SkeletonRegion label={what}>
<Badge
label={label}
value={<Skeleton width={width} />}
class="ui-skeleton-badge"
/>
</SkeletonRegion>
);
}

View file

@ -65,3 +65,24 @@
.ui-skeleton-region {
display: contents;
}
/* Lines of text stacked with a line's own spacing. */
.ui-skeleton-lines {
display: flex;
flex-direction: column;
gap: 0.6em;
}
/* A badge placeholder as tall and wide-set as an interactive Badge
(`.ui-badge-interactive` in @hive/shared's Badge.css: the settings values
are all buttons), so the pill does not change size when its value lands. */
.ui-skeleton-badge {
box-sizing: border-box; /* as the button it stands in for */
min-height: 2.75em;
padding-inline: 0.8em;
border-radius: 999px;
}
.ui-skeleton-badge .ui-skeleton {
display: inline-block;
vertical-align: middle;
}

View file

@ -46,3 +46,25 @@ export function SkeletonRegion({
</div>
);
}
const LINE_WIDTHS = ["90%", "75%", "85%", "60%"];
/** A few lines of text, for a block of prose or a list still loading. */
export function SkeletonLines({
label,
count = 3,
}: {
/** What is loading, as a screen reader says it. */
label: string;
count?: number;
}) {
return (
<SkeletonRegion label={label}>
<div class="ui-skeleton-lines">
{Array.from({ length: count }, (_, i) => (
<Skeleton key={i} width={LINE_WIDTHS[i % LINE_WIDTHS.length]} />
))}
</div>
</SkeletonRegion>
);
}