mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
improve(ui): make chat disclosures compact (#124832)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
This commit is contained in:
@@ -108,9 +108,16 @@ suite.define(() => {
|
||||
});
|
||||
|
||||
it("pairs a canonical parallel batch and renders per-file patch sections", async () => {
|
||||
const artifactDir = process.env.OPENCLAW_CONTROL_UI_E2E_ARTIFACT_DIR?.trim();
|
||||
if (artifactDir) {
|
||||
await fs.mkdir(artifactDir, { recursive: true });
|
||||
}
|
||||
const context = await suite.browser.newContext({
|
||||
locale: "en-US",
|
||||
viewport: { height: 900, width: 1200 },
|
||||
...(artifactDir
|
||||
? { recordVideo: { dir: artifactDir, size: { height: 900, width: 1200 } } }
|
||||
: {}),
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await installMockGateway(page, {
|
||||
@@ -165,12 +172,36 @@ suite.define(() => {
|
||||
const activity = page.locator(".chat-group--activity .chat-activity-group__summary");
|
||||
await activity.waitFor();
|
||||
expect(await activity.textContent()).toContain("Read a file, edited a file, created a file");
|
||||
const activityGeometry = await activity.evaluate((node) => {
|
||||
const container = node.closest<HTMLElement>(".chat-activity-group");
|
||||
const label = node.querySelector<HTMLElement>(".chat-activity-group__label");
|
||||
const chevron = node.querySelector<HTMLElement>(".chat-inline-disclosure__chevron");
|
||||
if (!container || !label || !chevron) {
|
||||
throw new Error("Expected compact activity disclosure parts");
|
||||
}
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const summaryRect = node.getBoundingClientRect();
|
||||
const labelRect = label.getBoundingClientRect();
|
||||
const chevronRect = chevron.getBoundingClientRect();
|
||||
return {
|
||||
containerWidth: containerRect.width,
|
||||
summaryWidth: summaryRect.width,
|
||||
chevronGap: chevronRect.left - labelRect.right,
|
||||
};
|
||||
});
|
||||
expect(activityGeometry.summaryWidth).toBeLessThan(activityGeometry.containerWidth);
|
||||
expect(activityGeometry.chevronGap).toBeLessThanOrEqual(8);
|
||||
await activity.hover();
|
||||
expect(await activity.evaluate((node) => getComputedStyle(node).backgroundColor)).toBe(
|
||||
"rgba(0, 0, 0, 0)",
|
||||
);
|
||||
if ((await activity.getAttribute("aria-expanded")) !== "true") {
|
||||
await activity.click();
|
||||
}
|
||||
|
||||
const rows = page.locator(".chat-activity-group__body .chat-tool-msg-summary");
|
||||
expect(await rows.count()).toBe(2);
|
||||
expect(await rows.locator(".chat-inline-disclosure__chevron").count()).toBe(2);
|
||||
expect(await page.locator(".chat-tool-msg-summary__label", { hasText: "Tool" }).count()).toBe(
|
||||
0,
|
||||
);
|
||||
|
||||
@@ -206,28 +206,31 @@ function activityAlignmentHtml() {
|
||||
<div class="chat-avatar tool">A</div>
|
||||
<div class="chat-group-messages">
|
||||
<div class="chat-activity-group is-open">
|
||||
<button class="chat-activity-group__summary" type="button">
|
||||
<button class="chat-inline-disclosure chat-activity-group__summary" type="button" aria-expanded="true">
|
||||
<span class="chat-activity-group__icon">${iconSvg()}</span>
|
||||
<span class="chat-activity-group__label">Activity: 2 tools</span>
|
||||
<span class="chat-inline-disclosure__chevron">${iconSvg()}</span>
|
||||
</button>
|
||||
<div class="chat-activity-group__body">
|
||||
<div class="chat-bubble chat-bubble--tool-shell" data-activity-call-row>
|
||||
<div class="chat-tools-inline">
|
||||
<div class="chat-tool-msg-collapse">
|
||||
<button class="chat-tool-msg-summary" type="button">
|
||||
<button class="chat-inline-disclosure chat-tool-msg-summary" type="button" aria-expanded="false">
|
||||
<span class="chat-tool-msg-summary__icon">${iconSvg()}</span>
|
||||
<span class="chat-tool-msg-summary__label">Bash</span>
|
||||
<span class="chat-tool-msg-summary__names">search a deliberately long workspace path without extra card chrome</span>
|
||||
<span class="chat-inline-disclosure__chevron">${iconSvg()}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-bubble chat-bubble--tool-shell">
|
||||
<div class="chat-tool-msg-collapse">
|
||||
<button class="chat-tool-msg-summary" data-failed-call-row type="button">
|
||||
<button class="chat-inline-disclosure chat-tool-msg-summary" data-failed-call-row type="button" aria-expanded="false">
|
||||
<span class="chat-tool-msg-summary__icon">${iconSvg()}</span>
|
||||
<span class="chat-tool-msg-summary__label">Bash</span>
|
||||
<span class="chat-tool-msg-summary__names">Bash</span>
|
||||
<span class="chat-inline-disclosure__chevron">${iconSvg()}</span>
|
||||
<span class="chat-tool-row__badge">failed</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1171,7 +1174,7 @@ describeBrowserLayout.concurrent("chat responsive browser layout", () => {
|
||||
it.each([
|
||||
[430, 720],
|
||||
[1366, 900],
|
||||
] as const)("right-aligns activity rows with call bubbles at %sx%s", async (width, height) => {
|
||||
] as const)("keeps activity disclosures compact at %sx%s", async (width, height) => {
|
||||
const page = await openBrowserPage(width, height);
|
||||
try {
|
||||
await page.setContent(
|
||||
@@ -1179,24 +1182,27 @@ describeBrowserLayout.concurrent("chat responsive browser layout", () => {
|
||||
);
|
||||
|
||||
await expectNoHorizontalOverflow(page);
|
||||
const callRow = await getRect(page, "[data-activity-call-row]");
|
||||
const activityGroup = await getRect(page, ".chat-activity-group");
|
||||
const activitySummary = await getRect(page, ".chat-activity-group__summary");
|
||||
const failedSummary = await getRect(page, "[data-failed-call-row]");
|
||||
expect(Math.abs(callRow.right - failedSummary.right)).toBeLessThanOrEqual(1);
|
||||
expect(Math.abs(callRow.height - failedSummary.height)).toBeLessThanOrEqual(1);
|
||||
expect(activitySummary.width).toBeLessThan(activityGroup.width);
|
||||
expect(failedSummary.width).toBeLessThan(activityGroup.width);
|
||||
const styles = await page.evaluate(() => {
|
||||
const call = document.querySelector<HTMLElement>("[data-activity-call-row]")!;
|
||||
const activity = document.querySelector<HTMLElement>(".chat-activity-group__summary")!;
|
||||
const label = activity.querySelector<HTMLElement>(".chat-activity-group__label")!;
|
||||
const chevron = activity.querySelector<HTMLElement>(".chat-inline-disclosure__chevron")!;
|
||||
return {
|
||||
activity: getComputedStyle(
|
||||
document.querySelector<HTMLElement>(".chat-activity-group__summary")!,
|
||||
).userSelect,
|
||||
callBackground: getComputedStyle(call).backgroundColor,
|
||||
activity: getComputedStyle(activity).userSelect,
|
||||
activityBackground: getComputedStyle(activity).backgroundColor,
|
||||
chevronGap: chevron.getBoundingClientRect().left - label.getBoundingClientRect().right,
|
||||
tool: getComputedStyle(document.querySelector<HTMLElement>(".chat-tool-msg-summary")!)
|
||||
.userSelect,
|
||||
};
|
||||
});
|
||||
expect(styles).toEqual({
|
||||
activity: "text",
|
||||
callBackground: "rgba(0, 0, 0, 0)",
|
||||
activityBackground: "rgba(0, 0, 0, 0)",
|
||||
chevronGap: 8,
|
||||
tool: "text",
|
||||
});
|
||||
} finally {
|
||||
|
||||
@@ -463,7 +463,7 @@ export function renderGroupedMessage(
|
||||
: ""}"
|
||||
>
|
||||
<button
|
||||
class="chat-tool-msg-summary"
|
||||
class="chat-inline-disclosure chat-tool-msg-summary"
|
||||
type="button"
|
||||
aria-expanded=${String(toolMessageExpanded)}
|
||||
@click=${(event: MouseEvent) => {
|
||||
@@ -479,6 +479,9 @@ export function renderGroupedMessage(
|
||||
: toolPreview
|
||||
? html`<span class="chat-tool-msg-summary__preview">${toolPreview}</span>`
|
||||
: nothing}
|
||||
<span class="chat-inline-disclosure__chevron" aria-hidden="true"
|
||||
>${icons.chevronDown}</span
|
||||
>
|
||||
${toolMessageHasError
|
||||
? html`<span class="chat-tool-row__badge">${t("chat.toolCards.failed")}</span>`
|
||||
: nothing}
|
||||
|
||||
@@ -280,7 +280,7 @@ export function renderActivityGroup(
|
||||
<div class="chat-group-messages">
|
||||
<div class="chat-activity-group ${activityExpanded ? "is-open" : ""}">
|
||||
<button
|
||||
class="chat-activity-group__summary"
|
||||
class="chat-inline-disclosure chat-activity-group__summary"
|
||||
type="button"
|
||||
aria-expanded=${String(activityExpanded)}
|
||||
aria-controls=${activityBodyId}
|
||||
@@ -294,9 +294,7 @@ export function renderActivityGroup(
|
||||
<span class="chat-activity-group__label" title=${groupSummaryLabel}
|
||||
>${groupSummaryLabel}</span
|
||||
>
|
||||
<span
|
||||
class="collapse-chevron ${activityExpanded ? "" : "collapse-chevron--collapsed"}"
|
||||
aria-hidden="true"
|
||||
<span class="chat-inline-disclosure__chevron" aria-hidden="true"
|
||||
>${icons.chevronDown}</span
|
||||
>
|
||||
</button>
|
||||
|
||||
@@ -169,7 +169,7 @@ export function renderWorkGroupSummary(
|
||||
<div class="chat-group-messages">
|
||||
<div class="chat-activity-group chat-work-group ${opts.expanded ? "is-open" : ""}">
|
||||
<button
|
||||
class="chat-activity-group__summary"
|
||||
class="chat-inline-disclosure chat-activity-group__summary"
|
||||
type="button"
|
||||
aria-expanded=${String(opts.expanded)}
|
||||
@click=${(event: MouseEvent) => {
|
||||
@@ -180,9 +180,7 @@ export function renderWorkGroupSummary(
|
||||
>
|
||||
<span class="chat-activity-group__icon">${icons.check}</span>
|
||||
<span class="chat-activity-group__label" title=${label}>${label}</span>
|
||||
<span
|
||||
class="collapse-chevron ${opts.expanded ? "" : "collapse-chevron--collapsed"}"
|
||||
aria-hidden="true"
|
||||
<span class="chat-inline-disclosure__chevron" aria-hidden="true"
|
||||
>${icons.chevronDown}</span
|
||||
>
|
||||
</button>
|
||||
|
||||
@@ -692,7 +692,8 @@ describe("tool-cards", () => {
|
||||
expect(container.querySelector(".chat-tool-card__preview-frame")).toBeNull();
|
||||
expect(rawToggle).toBeInstanceOf(HTMLButtonElement);
|
||||
expect(rawBody).toBeInstanceOf(HTMLElement);
|
||||
expect([...rawToggle!.classList]).toEqual(["chat-tool-card__raw-toggle"]);
|
||||
expect(rawToggle!.classList).toContain("chat-inline-disclosure");
|
||||
expect(rawToggle!.classList).toContain("chat-tool-card__raw-toggle");
|
||||
expect(rawToggle!.textContent?.trim()).toBe("Raw details");
|
||||
expect(rawToggle!.getAttribute("aria-expanded")).toBe("false");
|
||||
expect(rawBody!.hidden).toBe(true);
|
||||
|
||||
@@ -192,13 +192,13 @@ export function renderRawOutputToggle(text: string) {
|
||||
return html`
|
||||
<div class="chat-tool-card__raw">
|
||||
<button
|
||||
class="chat-tool-card__raw-toggle"
|
||||
class="chat-inline-disclosure chat-tool-card__raw-toggle"
|
||||
type="button"
|
||||
aria-expanded="false"
|
||||
@click=${handleRawDetailsToggle}
|
||||
>
|
||||
<span>${t("chat.toolCards.rawDetails")}</span>
|
||||
<span class="chat-tool-card__raw-toggle-icon">${icons.chevronDown}</span>
|
||||
<span class="chat-inline-disclosure__chevron" aria-hidden="true">${icons.chevronDown}</span>
|
||||
</button>
|
||||
<div class="chat-tool-card__raw-body" hidden>
|
||||
${renderToolDataBlock({ label: t("chat.toolCards.toolOutput"), text })}
|
||||
@@ -630,7 +630,9 @@ export function renderToolCard(
|
||||
: ""}"
|
||||
>
|
||||
<button
|
||||
class="chat-tool-msg-summary chat-tool-row ${isRunning ? "chat-tool-row--running" : ""}"
|
||||
class="chat-inline-disclosure chat-tool-msg-summary chat-tool-row ${isRunning
|
||||
? "chat-tool-row--running"
|
||||
: ""}"
|
||||
type="button"
|
||||
aria-expanded=${String(opts.expanded)}
|
||||
@click=${(event: MouseEvent) => {
|
||||
@@ -641,6 +643,7 @@ export function renderToolCard(
|
||||
>
|
||||
<span class="chat-tool-msg-summary__icon">${renderToolIcon(icon)}</span>
|
||||
${renderToolRowContent(card, view, outcome)}
|
||||
<span class="chat-inline-disclosure__chevron" aria-hidden="true">${icons.chevronDown}</span>
|
||||
${isError
|
||||
? html`<span class="chat-tool-row__badge">${t("chat.toolCards.failed")}</span>`
|
||||
: nothing}
|
||||
|
||||
@@ -2,6 +2,61 @@
|
||||
Tool rows deliberately carry no card chrome (border/background/shadow) so
|
||||
dense agent activity stays scannable; detail surfaces appear only on expand. */
|
||||
|
||||
/* Compact text disclosure shared by activity rollups, tool rows, and raw
|
||||
details. The button hugs its label while the expanded body keeps its own
|
||||
full-width layout. */
|
||||
.chat-inline-disclosure {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 4px 0;
|
||||
border: 0;
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
user-select: text;
|
||||
cursor: var(--cursor-action);
|
||||
transition: color 150ms ease-out;
|
||||
}
|
||||
|
||||
.chat-inline-disclosure:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.chat-inline-disclosure:focus-visible {
|
||||
color: var(--text);
|
||||
outline: 2px solid var(--focus-ring);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.chat-inline-disclosure__chevron {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
transition: transform 150ms ease-out;
|
||||
}
|
||||
|
||||
.chat-inline-disclosure__chevron svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
stroke: currentColor;
|
||||
fill: none;
|
||||
stroke-width: 1.5px;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.chat-inline-disclosure[aria-expanded="false"] .chat-inline-disclosure__chevron {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
/* ── Collapsed tool row ── */
|
||||
.chat-tool-msg-collapse {
|
||||
width: 100%;
|
||||
@@ -15,69 +70,19 @@
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Flat top-level tool rows align their content with the assistant text edge:
|
||||
the row's 8px inline inset bleeds left into the avatar gutter (never right,
|
||||
which could overflow the thread on narrow panes) so the hover pill keeps
|
||||
its inset without indenting the icon/label. Child combinator keeps shells
|
||||
nested in .chat-activity-group__body on the group's indented rail. */
|
||||
.chat-group-messages > .chat-bubble--tool-shell .chat-tool-msg-summary {
|
||||
width: calc(100% + 8px);
|
||||
margin-left: -8px;
|
||||
}
|
||||
|
||||
.chat-tool-msg-summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 4px 8px;
|
||||
font-size: var(--control-ui-text-sm);
|
||||
line-height: 1.5;
|
||||
color: var(--muted);
|
||||
user-select: text;
|
||||
list-style: none;
|
||||
border: 0;
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
text-align: left;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
font-family: inherit;
|
||||
transition:
|
||||
color 150ms ease,
|
||||
background 150ms ease;
|
||||
}
|
||||
|
||||
.chat-tool-msg-summary:hover,
|
||||
.chat-tool-msg-summary:focus-visible {
|
||||
background: color-mix(in srgb, var(--bg-hover) 60%, transparent);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.chat-tool-msg-summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.chat-tool-msg-summary::before {
|
||||
content: "▸";
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 9px;
|
||||
font-size: 12px;
|
||||
line-height: 1;
|
||||
color: var(--muted);
|
||||
opacity: 0.7;
|
||||
flex-shrink: 0;
|
||||
transition: transform 150ms ease;
|
||||
}
|
||||
|
||||
.chat-tool-msg-summary[aria-expanded="true"]::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.chat-tool-msg-summary__icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -111,7 +116,7 @@
|
||||
|
||||
.chat-tool-msg-summary__names,
|
||||
.chat-tool-msg-summary__preview {
|
||||
flex: 1 1 0;
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -152,7 +157,7 @@
|
||||
}
|
||||
|
||||
.chat-tool-row__cmd--secondary {
|
||||
flex: 0 100000 auto;
|
||||
flex: 0 1 auto;
|
||||
color: color-mix(in srgb, var(--muted) 85%, var(--text) 15%);
|
||||
}
|
||||
|
||||
@@ -175,7 +180,7 @@
|
||||
}
|
||||
|
||||
.chat-tool-row__detail {
|
||||
flex: 0 100000 auto;
|
||||
flex: 0 1 auto;
|
||||
min-width: 24px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -239,7 +244,6 @@
|
||||
|
||||
.chat-tool-row__spinner {
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: var(--radius-full, 999px);
|
||||
@@ -269,7 +273,6 @@
|
||||
|
||||
.chat-tool-row__badge {
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
padding: 1px 6px;
|
||||
border-radius: var(--radius-full, 999px);
|
||||
background: color-mix(in srgb, var(--destructive) 14%, transparent);
|
||||
@@ -866,42 +869,7 @@
|
||||
}
|
||||
|
||||
.chat-tool-card__raw-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
font: inherit;
|
||||
font-size: 12px;
|
||||
transition: color 150ms ease-out;
|
||||
}
|
||||
|
||||
.chat-tool-card__raw-toggle:hover,
|
||||
.chat-tool-card__raw-toggle:focus-visible {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.chat-tool-card__raw-toggle[aria-expanded="true"] .chat-tool-card__raw-toggle-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.chat-tool-card__raw-toggle-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: transform 150ms ease-out;
|
||||
}
|
||||
|
||||
.chat-tool-card__raw-toggle-icon svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
stroke: currentColor;
|
||||
fill: none;
|
||||
stroke-width: 1.6px;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.chat-tool-card__raw-body {
|
||||
@@ -1005,26 +973,9 @@
|
||||
}
|
||||
|
||||
.chat-activity-group__summary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 5px 8px;
|
||||
border: 0;
|
||||
border-radius: var(--radius-sm);
|
||||
background: transparent;
|
||||
padding-block: 5px;
|
||||
color: var(--text);
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
user-select: text;
|
||||
transition: background 150ms ease;
|
||||
}
|
||||
|
||||
.chat-activity-group__summary:hover,
|
||||
.chat-activity-group__summary:focus-visible {
|
||||
background: color-mix(in srgb, var(--bg-hover) 60%, transparent);
|
||||
}
|
||||
|
||||
.chat-activity-group__icon {
|
||||
@@ -1046,7 +997,7 @@
|
||||
}
|
||||
|
||||
.chat-activity-group__label {
|
||||
flex: 1 1 auto;
|
||||
flex: 0 1 auto;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
font-size: var(--control-ui-text-sm);
|
||||
@@ -1056,10 +1007,6 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.chat-activity-group__summary .collapse-chevron {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Rows form a flat indented list below the summary. The rail marks the group
|
||||
extent while shared row hover pills remain free of per-row chrome. */
|
||||
.chat-activity-group__body {
|
||||
|
||||
@@ -5144,29 +5144,6 @@ td.data-table-key-col {
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Shared collapse chevron ── */
|
||||
|
||||
.collapse-chevron {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: transform var(--duration-fast) ease;
|
||||
}
|
||||
|
||||
.collapse-chevron svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
stroke: currentColor;
|
||||
fill: none;
|
||||
stroke-width: 1.5px;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.collapse-chevron--collapsed {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
/* Mobile pairing */
|
||||
.device-pair-setup {
|
||||
max-height: calc(100dvh - 48px);
|
||||
|
||||
Reference in New Issue
Block a user