Refine status-bar usage notice styling and test coverage

- Replace hand-tuned light/dark card colors with existing design
  tokens (--popover, --border) and the documented floating elevation,
  so the callout stays in sync with the design system instead of
  duplicating its own palette
- Add tests covering dismiss via X button, "Got it", and Escape
- Scope the foreground-process confirm assertion to the pane's ptyId
  so an unrelated pane's delayed confirm can't cause a false failure
This commit is contained in:
Jinjing
2026-07-11 14:49:03 -07:00
parent 670831f931
commit de4e563732
3 changed files with 62 additions and 51 deletions
+10 -50
View File
@@ -1210,46 +1210,14 @@
}
/* Why: one-shot status-bar callout is portaled fixed above the meters.
Opaque elevated surfaces (not glass) so titlebar/terminal chrome cannot
bleed through; light and dark use separate fills. */
Opaque popover surface (not glass) so titlebar/terminal chrome cannot
bleed through; use design tokens + the documented floating elevation. */
.status-bar-change-notice-card {
border: 1px solid color-mix(in srgb, var(--foreground) 16%, var(--border));
background: var(--card);
color: var(--card-foreground);
box-shadow:
0 0 0 1px color-mix(in srgb, var(--foreground) 6%, transparent),
0 14px 36px color-mix(in srgb, var(--foreground) 14%, transparent),
0 2px 8px color-mix(in srgb, var(--foreground) 8%, transparent);
}
/* Light: pure paper above light chrome — lift with a cool edge, not gray fill. */
:root:not(.dark) .status-bar-change-notice-card {
background: #ffffff;
border-color: #c4c9d2;
color: #0a0a0a;
box-shadow:
0 0 0 1px rgb(15 23 42 / 0.06),
0 16px 40px rgb(15 23 42 / 0.16),
0 3px 10px rgb(15 23 42 / 0.08);
}
:root:not(.dark) .status-bar-change-notice-card .text-muted-foreground {
color: #52525b;
}
/* Dark: lifted charcoal above #0a0a0a / #171717 — not translucent glass. */
.dark .status-bar-change-notice-card {
background: #2a2a2e;
border-color: color-mix(in srgb, #ffffff 26%, transparent);
color: #fafafa;
box-shadow:
0 0 0 1px color-mix(in srgb, #ffffff 12%, transparent),
0 18px 44px rgb(0 0 0 / 0.62),
0 3px 12px rgb(0 0 0 / 0.4);
}
.dark .status-bar-change-notice-card .text-muted-foreground {
color: color-mix(in srgb, #fafafa 68%, transparent);
border: 1px solid var(--border);
background: var(--popover);
color: var(--popover-foreground);
/* STYLEGUIDE: floating elevation for popovers that escape the editor surface. */
box-shadow: 0 10px 24px rgb(0 0 0 / 0.18);
}
/* Why: caret points down at the usage meters this notice explains. */
@@ -1261,17 +1229,9 @@
width: 12px;
height: 12px;
transform: rotate(45deg);
border-right: 1px solid #c4c9d2;
border-bottom: 1px solid #c4c9d2;
background: #ffffff;
box-shadow: 2px 2px 5px rgb(15 23 42 / 0.1);
}
.dark .status-bar-change-notice-card::after {
border-right-color: color-mix(in srgb, #ffffff 26%, transparent);
border-bottom-color: color-mix(in srgb, #ffffff 26%, transparent);
background: #2a2a2e;
box-shadow: 2px 2px 8px rgb(0 0 0 / 0.45);
border-right: 1px solid var(--border);
border-bottom: 1px solid var(--border);
background: var(--popover);
}
/* Why: the first-run Mobile Emulator intro sits directly under that menu row;
@@ -173,4 +173,53 @@ describe('UsagePercentageDisplayChangeNotice', () => {
})
expect(storeState.dismissUsagePercentageDisplayChangeNotice).toHaveBeenCalled()
})
it('dismisses from the X button', () => {
openNotice()
const dismissButton = document.querySelector(
'.status-bar-change-notice-card button[aria-label="Dismiss"]'
)
expect(dismissButton).toBeTruthy()
act(() => {
dismissButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
})
expect(storeState.dismissUsagePercentageDisplayChangeNotice).toHaveBeenCalledTimes(1)
})
it('dismisses from Got it', () => {
openNotice()
const gotItButton = Array.from(
document.querySelectorAll('.status-bar-change-notice-card button')
).find((button) => button.textContent === 'Got it')
expect(gotItButton).toBeTruthy()
act(() => {
gotItButton?.dispatchEvent(new MouseEvent('click', { bubbles: true }))
})
expect(storeState.dismissUsagePercentageDisplayChangeNotice).toHaveBeenCalledTimes(1)
})
it('dismisses on Escape', () => {
openNotice()
act(() => {
window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
})
expect(storeState.dismissUsagePercentageDisplayChangeNotice).toHaveBeenCalledTimes(1)
})
function openNotice(): void {
act(() => {
root.render(
<UsagePercentageDisplayChangeNotice hasVisibleUsageMeters>
<span>usage-meters</span>
</UsagePercentageDisplayChangeNotice>
)
})
act(() => {
vi.advanceTimersByTime(1_800)
})
expect(document.querySelector('.status-bar-change-notice-card')).not.toBeNull()
}
})
@@ -17599,7 +17599,9 @@ describe('connectPanePty', () => {
binding.sampleForegroundAgentOnFocus()
await vi.advanceTimersByTimeAsync(10_000)
expect(window.api.pty.confirmForegroundProcess).not.toHaveBeenCalled()
// Scope to this pane's pty id: a delayed confirm for another test's
// default `tab-pty` pane can fire during this advance and is not our subject.
expect(window.api.pty.confirmForegroundProcess).not.toHaveBeenCalledWith(ptyId)
} finally {
restoreUserAgent()
}