Watch
0
0
Fork
You've already forked hyperhive
0

swarm ui: one review page

The two review tabs, runs and try-out, are one: /review. It is a column of
three sections: try a classification and the classifier settings, each a
folded bar (the settings' bar says what they are now), then the recent runs,
always open. The settings had been pinned under the try-out form; they are now
a section of their own. A new Disclosure primitive is the folding bar, a
native details wearing the Panel's classes, so the folded and open sections
read as the same surface.

/review-runs and /review-tryout are gone, with no redirect.
This commit is contained in:
iris 2026-10-14 21:57:23 +02:00 • committed by mara
commit a68d73fa74
19 changed files with 223 additions and 45 deletions

View file

@ -0,0 +1,47 @@
/* A shut disclosure is only its header row, so it has no divider to draw and
no body to space; the divider shows once it is open. */
.ui-disclosure-summary {
cursor: pointer;
list-style: none;
border-bottom-color: transparent;
}
.ui-disclosure-summary::-webkit-details-marker {
display: none;
}
.ui-disclosure[open] > .ui-disclosure-summary {
border-bottom-color: var(--border);
}
.ui-disclosure-summary:hover .ui-panel-title {
text-decoration: underline;
}
.ui-disclosure-summary:focus-visible {
outline: 2px solid var(--blue);
outline-offset: -2px;
border-radius: 0.5em;
}
.ui-disclosure-hint {
min-width: 0;
overflow: hidden;
color: var(--muted);
font-size: 0.9em;
text-overflow: ellipsis;
white-space: nowrap;
}
.ui-disclosure-chevron {
margin-left: auto;
width: 0.55em;
height: 0.55em;
flex: none;
border-right: 2px solid var(--muted);
border-bottom: 2px solid var(--muted);
transform: rotate(-45deg);
transition: transform 0.15s ease;
}
.ui-disclosure[open] > .ui-disclosure-summary .ui-disclosure-chevron {
transform: rotate(45deg);
}
@media (prefers-reduced-motion: reduce) {
.ui-disclosure-chevron {
transition: none;
}
}

View file

@ -0,0 +1,50 @@
// <Disclosure> — a Panel that folds: the header row is the control, and the
// body shows only while it is open. For a section a page keeps within reach
// but that is not the point of the page, such as a form used now and then.
// It is a native `<details>`, so the keyboard and assistive tech get the
// open/closed state for free, and it wears the Panel's own classes, so a
// Disclosure and a Panel on one page read as the same kind of surface.
//
// Controlled: `open` and `onToggle`, so a page can open it for the user (a
// run started, say). The body stays in the DOM while it is shut, so what was
// typed into it survives a fold. `hint` is a short line beside the title that
// says what is in there without opening it.
import type { ComponentChildren } from "preact";
import "../panel/Panel.css";
import "./Disclosure.css";
export function Disclosure({
title,
icon,
hint,
open,
onToggle,
children,
}: {
title: string;
icon?: string;
hint?: ComponentChildren;
open: boolean;
onToggle: (open: boolean) => void;
children: ComponentChildren;
}) {
return (
<details
class="ui-panel ui-disclosure"
open={open}
onToggle={(e) => onToggle((e.currentTarget as HTMLDetailsElement).open)}
>
<summary class="ui-panel-header ui-disclosure-summary">
{icon ? (
<span class="ui-panel-icon" aria-hidden="true">
{icon}
</span>
) : null}
<h2 class="ui-panel-title">{title}</h2>
{hint ? <span class="ui-disclosure-hint">{hint}</span> : null}
<span class="ui-disclosure-chevron" aria-hidden="true" />
</summary>
<div class="ui-panel-body">{children}</div>
</details>
);
}