feat(notifications): auto-dismiss loading OSD on overlay visibility chan

- add dismissOverlayLoadingOsd dep and call it on hide/show paths (macOS only)
- simplify notification card styles: remove accent bar, flatten gradient bg, tweak spacing
- fix test CSS path to use __dirname instead of process.cwd()
This commit is contained in:
2026-06-05 12:58:02 -07:00
parent a3b907adff
commit 0f8370a3a9
7 changed files with 29 additions and 29 deletions
+10
View File
@@ -88,6 +88,7 @@ export function updateVisibleOverlayVisibility(args: {
isMacOSPlatform?: boolean;
isWindowsPlatform?: boolean;
showOverlayLoadingOsd?: (message: string) => void;
dismissOverlayLoadingOsd?: () => void;
shouldShowOverlayLoadingOsd?: () => boolean;
markOverlayLoadingOsdShown?: () => void;
resetOverlayLoadingOsdSuppression?: () => void;
@@ -320,6 +321,12 @@ export function updateVisibleOverlayVisibility(args: {
args.showOverlayLoadingOsd('Overlay loading...');
args.markOverlayLoadingOsdShown?.();
};
const maybeDismissOverlayLoadingOsd = (): void => {
if (!args.isMacOSPlatform) {
return;
}
args.dismissOverlayLoadingOsd?.();
};
const refreshNonNativeOverlayBoundsAfterFirstShow = (geometry: WindowGeometry | null): void => {
if (
@@ -350,6 +357,7 @@ export function updateVisibleOverlayVisibility(args: {
if (!args.visibleOverlayVisible) {
args.setTrackerNotReadyWarningShown(false);
args.resetOverlayLoadingOsdSuppression?.();
maybeDismissOverlayLoadingOsd();
if (args.isWindowsPlatform) {
clearPendingWindowsOverlayReveal(mainWindow);
setOverlayWindowOpacity(mainWindow, 0);
@@ -372,6 +380,7 @@ export function updateVisibleOverlayVisibility(args: {
return;
}
args.setTrackerNotReadyWarningShown(false);
maybeDismissOverlayLoadingOsd();
const geometry = args.windowTracker.getGeometry();
if (geometry) {
args.updateVisibleOverlayBounds(geometry);
@@ -432,6 +441,7 @@ export function updateVisibleOverlayVisibility(args: {
(mainWindow.isVisible() || hasRetainedTrackedGeometry)
) {
args.setTrackerNotReadyWarningShown(false);
maybeDismissOverlayLoadingOsd();
const geometry = args.windowTracker.getGeometry();
if (geometry) {
args.updateVisibleOverlayBounds(geometry);
+3
View File
@@ -2651,6 +2651,9 @@ const overlayVisibilityRuntime = createOverlayVisibilityRuntimeService(
showOverlayLoadingOsd: (message: string) => {
showOverlayLoadingStatusNotification(message);
},
dismissOverlayLoadingOsd: () => {
dismissOverlayNotification('overlay-loading-status');
},
hideNonNativeOverlayWhenTargetUnfocused: () =>
shouldRunLinuxOverlayZOrderKeepAlive() &&
linuxVisibleOverlayWindowMode === 'fullscreen-override',
+2
View File
@@ -30,6 +30,7 @@ export interface OverlayVisibilityRuntimeDeps {
isMacOSPlatform: () => boolean;
isWindowsPlatform: () => boolean;
showOverlayLoadingOsd: (message: string) => void;
dismissOverlayLoadingOsd?: () => void;
resolveFallbackBounds: () => WindowGeometry;
hideNonNativeOverlayWhenTargetUnfocused?: () => boolean;
}
@@ -80,6 +81,7 @@ export function createOverlayVisibilityRuntimeService(
isMacOSPlatform: deps.isMacOSPlatform(),
isWindowsPlatform: deps.isWindowsPlatform(),
showOverlayLoadingOsd: (message: string) => deps.showOverlayLoadingOsd(message),
dismissOverlayLoadingOsd: () => deps.dismissOverlayLoadingOsd?.(),
shouldShowOverlayLoadingOsd: () =>
lastOverlayLoadingOsdAtMs === null ||
Date.now() - lastOverlayLoadingOsdAtMs >= OVERLAY_LOADING_OSD_COOLDOWN_MS,
@@ -36,6 +36,7 @@ test('overlay visibility runtime main deps builder maps state and geometry callb
isMacOSPlatform: () => true,
isWindowsPlatform: () => false,
showOverlayLoadingOsd: () => calls.push('overlay-loading-osd'),
dismissOverlayLoadingOsd: () => calls.push('dismiss-overlay-loading-osd'),
resolveFallbackBounds: () => ({ x: 0, y: 0, width: 20, height: 20 }),
})();
@@ -60,6 +61,7 @@ test('overlay visibility runtime main deps builder maps state and geometry callb
assert.equal(deps.isMacOSPlatform(), true);
assert.equal(deps.isWindowsPlatform(), false);
deps.showOverlayLoadingOsd('Overlay loading...');
deps.dismissOverlayLoadingOsd?.();
assert.deepEqual(deps.resolveFallbackBounds(), { x: 0, y: 0, width: 20, height: 20 });
assert.equal(trackerNotReadyWarningShown, true);
assert.deepEqual(calls, [
@@ -71,5 +73,6 @@ test('overlay visibility runtime main deps builder maps state and geometry callb
'enforce-order',
'sync-shortcuts',
'overlay-loading-osd',
'dismiss-overlay-loading-osd',
]);
});
@@ -32,6 +32,7 @@ export function createBuildOverlayVisibilityRuntimeMainDepsHandler(
isMacOSPlatform: () => deps.isMacOSPlatform(),
isWindowsPlatform: () => deps.isWindowsPlatform(),
showOverlayLoadingOsd: (message: string) => deps.showOverlayLoadingOsd(message),
dismissOverlayLoadingOsd: () => deps.dismissOverlayLoadingOsd?.(),
hideNonNativeOverlayWhenTargetUnfocused: () =>
deps.hideNonNativeOverlayWhenTargetUnfocused?.() ?? false,
resolveFallbackBounds: () => deps.resolveFallbackBounds(),
+2 -2
View File
@@ -85,7 +85,7 @@ function findChildByClass(element: FakeElement, className: string): FakeElement
}
const overlayNotificationCss = readFileSync(
path.join(process.cwd(), 'src/renderer/style.css'),
path.join(__dirname, '..', 'renderer', 'style.css'),
'utf8',
);
@@ -202,7 +202,7 @@ test('overlay notification cards use larger display dimensions', () => {
overlayNotificationCss,
/\.overlay-notification-stack\s*\{[^}]*width:\s*min\(420px,\s*calc\(100vw - 32px\)\);/s,
);
assert.match(overlayNotificationCss, /\.overlay-notification-card\s*\{[^}]*min-height:\s*76px;/s);
assert.match(overlayNotificationCss, /\.overlay-notification-card\s*\{[^}]*min-height:\s*72px;/s);
assert.match(
overlayNotificationCss,
/\.overlay-notification-card\.has-image\s*\{[^}]*min-height:\s*88px;/s,
+8 -27
View File
@@ -176,26 +176,20 @@ body:focus-visible,
}
.overlay-notification-card {
/* Accent color is overridden per variant and drives the bar, icon, and borders. */
/* Accent color is overridden per variant and drives the icon and border tint. */
--overlay-notification-accent: var(--ctp-blue);
position: relative;
display: grid;
grid-template-columns: 22px minmax(0, 1fr) 22px;
gap: 11px;
gap: 12px;
align-items: start;
min-height: 76px;
padding: 16px 16px 16px 20px;
border-radius: 11px;
border: 1px solid color-mix(in srgb, var(--overlay-notification-accent) 24%, var(--ctp-surface1));
background: linear-gradient(
180deg,
color-mix(in srgb, var(--overlay-notification-accent) 9%, var(--ctp-surface0)),
var(--ctp-mantle)
);
box-shadow:
0 14px 32px -10px rgba(24, 25, 38, 0.75),
0 1px 0 rgba(202, 211, 245, 0.05) inset;
min-height: 72px;
padding: 16px;
border-radius: 12px;
border: 1px solid color-mix(in srgb, var(--overlay-notification-accent) 45%, var(--ctp-surface1));
background: var(--ctp-base);
box-shadow: 0 12px 28px -12px rgba(24, 25, 38, 0.7);
color: var(--ctp-text);
overflow: hidden;
}
@@ -226,18 +220,6 @@ body:focus-visible,
animation-name: overlay-notification-leave-top;
}
.overlay-notification-card::before {
content: '';
position: absolute;
left: 0;
top: 11px;
bottom: 11px;
width: 3px;
border-radius: 0 3px 3px 0;
background: var(--overlay-notification-accent);
box-shadow: 0 0 11px -1px var(--overlay-notification-accent);
}
.overlay-notification-card.info {
--overlay-notification-accent: var(--ctp-blue);
}
@@ -264,7 +246,6 @@ body:focus-visible,
instead of letting it spill into the content column. */
grid-template-columns: minmax(0, 100px) minmax(0, 1fr) 22px;
min-height: 88px;
padding-left: 14px;
}
.overlay-notification-image {