Say Remove for displays, and make the default accent purple (#210050)
CI / verify (pull_request) Successful in 1m14s
CI / infrastructure-smoke (pull_request) Successful in 42s
CI / package-release (pull_request) Successful in 49s
CI / migration-smoke (pull_request) Successful in 2m30s
CI / image-build (pull_request) Successful in 1m8s
CI / deploy-smoke (same-origin) (pull_request) Successful in 45s
CI / package-publication (pull_request) Successful in 56s
CI / deploy-smoke (split) (pull_request) Successful in 8m55s

Administrators now remove a display: the card's Remove, "Remove display?",
and "Display removed". The platform still revokes the device's credential;
the endpoint, fields, and security history keep revoke/revoked (ADR 0065).

The default accent is a deep purple anchored on #210050, set in the shared
design tokens only (ADR 0066, superseding ADR 0060's teal in part). The
anchor is the light primary action with white on it; the light accent text,
focus ring, and selection, and the dark theme's lavender accent, are
variants on its hue chosen for contrast. The teal-tinted neutrals move to a
faint violet-grey at the same lightness, so every contrast pairing holds.
The contrast test gains six pairings the accent depends on, and pins the
anchor.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ekklesia
2026-10-16 19:14:46 -05:00
co-authored by Claude Opus 5.5
parent d9dafcb0f7
commit 0009f62fbd
10 changed files with 261 additions and 97 deletions
@@ -419,7 +419,8 @@ function DisplaySetupPanel(props: {
/**
* One active display: its one name, whether it is online (coarsely — see {@link ONLINE_WITHIN_MS}),
* what it shows now, and the two things an administrator does with it — change what it shows, and
* revoke it. Revoked displays are not listed: they are history, not something to manage.
* remove it. Removing a display revokes its credential; revoked displays are not listed: they are
* history, not something to manage. The interface says "remove", the platform's domain "revoke".
*/
function DisplayCard(props: {
readonly device: HostDeviceSummary;
@@ -470,7 +471,7 @@ function DisplayCard(props: {
</Button>
)}
<Button data-testid={`device-revoke-${device.id}`} onClick={props.onRevoke} size="sm">
Revoke
Remove
</Button>
</div>
</li>
@@ -765,9 +766,9 @@ export function DisplaysSettingsPage(props: DisplaysSettingsPageProps): ReactEle
</span>
</InlineNotice>
) : (
<InlineNotice title="Display revoked" tone="info">
<InlineNotice title="Display removed" tone="info">
<span data-testid="device-revoke-success">
{outcome.name} is revoked. Its screen returns to its pairing code.
{outcome.name} was removed. Its screen returns to its pairing code.
</span>
</InlineNotice>
)}
@@ -787,7 +788,7 @@ export function DisplaysSettingsPage(props: DisplaysSettingsPageProps): ReactEle
{list.kind === "loading" ? <LoadingState label="Loading displays…" /> : undefined}
{list.kind === "denied" ? (
<EmptyState
description="If you need to pair or revoke displays, ask an administrator."
description="If you need to add or remove displays, ask an administrator."
title="Displays aren't available to you"
/>
) : undefined}
@@ -871,7 +872,7 @@ export function DisplaysSettingsPage(props: DisplaysSettingsPageProps): ReactEle
/>
)}
{/* Revoking strands the screen until someone re-pairs it in person, so the consequence is
{/* Removing (revoking its credential) strands the screen until someone re-pairs it in person, so the consequence is
spelled out before it happens — never a browser-native confirm. */}
<Dialog
actions={
@@ -889,17 +890,18 @@ export function DisplaysSettingsPage(props: DisplaysSettingsPageProps): ReactEle
onClick={() => (confirming ? void revoke(confirming) : undefined)}
variant="danger"
>
Revoke display
Remove display
</Button>
</>
}
onDismiss={dismissConfirmation}
open={confirming !== undefined}
title={`Revoke ${confirming?.name ?? "this display"}?`}
title="Remove display?"
>
<p style={{ margin: 0 }}>
The screen stops showing content within a few seconds and returns to its pairing code.
This cannot be undone: to use it again, pair it from the screen with a new code.
{confirming?.name ?? "This display"} stops showing content within a few seconds and its
screen returns to its pairing code. This cannot be undone: to use it again, pair it from
the screen with a new code.
</p>
</Dialog>
</div>