fix(x): meeting popup window is the card — kills the grey backing slab

macOS NSPanel windows don't honor transparent: true (nor a #00000000
backgroundColor); the transparent margins around the card rendered as an
opaque grey slab. Drop transparency entirely: size the window to the
card (376×48), paint the card color on the window, use native rounded
corners + shadow. The hover × slides in over the card's left edge
instead of overhanging a corner.
This commit is contained in:
Gagan 2026-07-14 13:33:29 +05:30
parent 9ee332e21b
commit 786382c840
2 changed files with 32 additions and 31 deletions

View file

@ -13,9 +13,11 @@ import type { DetectedMeeting } from "@x/core/dist/meetings/detector.js";
* window's existing take-meeting-notes flow.
*/
// Lean bar + margins for the overhanging × and the CSS drop shadow.
const POPUP_WIDTH = 400;
const POPUP_HEIGHT = 76;
// The window IS the card: exact card dimensions, card background, native
// rounded corners + shadow. No transparency — macOS panels don't honor
// `transparent: true` reliably and paint a grey backing slab instead.
const POPUP_WIDTH = 376;
const POPUP_HEIGHT = 48;
const AUTO_DISMISS_MS = 45_000;
// Display names, Granola-style ("Chrome", not "Google Chrome").
@ -109,10 +111,8 @@ export function showMeetingPopup(meeting: DetectedMeeting): void {
alwaysOnTop: true,
skipTaskbar: true,
show: false,
// Transparent window: the rounded card + overhanging × render inside;
// the shadow is CSS (native shadows artifact on transparent windows).
transparent: true,
hasShadow: false,
backgroundColor: "#1d1d1d",
hasShadow: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,

View file

@ -58,43 +58,44 @@ export function MeetingDetectedPopup() {
void window.ipc.invoke('meetingDetect:action', { action }).catch(() => {})
}
// In the browser preview, reproduce the real popup window's exact size
// (448×96) on a desktop-ish backdrop; in Electron the window IS that size.
// The Electron window IS the card (376×48, card background, native macOS
// rounded corners + shadow — no transparency, which panels don't honor).
// The preview emulates that frame with its own rounding/shadow.
// No drag region: draggable areas swallow mouse events, which would keep
// the hover-revealed × from ever showing while over the card body.
const popup = (
<div
className={`group ${isPreview ? 'relative' : 'h-screen w-screen relative bg-transparent'}`}
style={isPreview ? { width: 400, height: 76 } : undefined}
className={`group relative flex items-center gap-3 pl-4 pr-2 bg-[#1d1d1d] overflow-hidden ${
isPreview ? 'rounded-xl shadow-[0_8px_28px_rgba(0,0,0,0.45)]' : 'h-screen w-screen'
}`}
style={isPreview ? { width: 376, height: 48 } : undefined}
>
{/* Close — floats over the card's top-left corner, revealed on hover */}
{/* Close — slides in over the left edge on hover */}
<button
onClick={() => act('dismiss')}
className="absolute left-0.5 top-0.5 z-10 flex size-6 items-center justify-center rounded-full bg-neutral-800 border border-neutral-600 text-neutral-200 shadow-md hover:bg-neutral-700 opacity-0 group-hover:opacity-100 transition-opacity" aria-label="Dismiss"
className="absolute left-1.5 top-1/2 -translate-y-1/2 z-10 flex size-6 items-center justify-center rounded-full bg-neutral-800 border border-neutral-600 text-neutral-200 shadow-md hover:bg-neutral-700 opacity-0 group-hover:opacity-100 transition-opacity"
aria-label="Dismiss"
>
<X className="size-3.5" strokeWidth={2.5} />
</button>
{/* Card */}
<div className="absolute left-3 right-3 top-3 h-12 rounded-2xl bg-[#1d1d1d] shadow-[0_8px_28px_rgba(0,0,0,0.55)] flex items-center gap-3 pl-4 pr-2">
<div className="flex-1 min-w-0">
<div className="text-sm font-semibold text-white leading-tight truncate">
{payload?.title ?? 'Meeting detected'}
</div>
<div className="text-[13px] text-neutral-400 leading-tight truncate mt-0.5">
{payload?.message ?? ''}
</div>
<div className="flex-1 min-w-0 transition-[padding] group-hover:pl-6">
<div className="text-sm font-semibold text-white leading-tight truncate">
{payload?.title ?? 'Meeting detected'}
</div>
<div className="text-[13px] text-neutral-400 leading-tight truncate mt-0.5">
{payload?.message ?? ''}
</div>
<button
onClick={() => act('take-notes')}
className="flex h-8.5 shrink-0 items-center gap-1.5 rounded-lg bg-neutral-800/90 border border-neutral-700 pl-1.5 pr-2.5 hover:bg-neutral-700 transition-colors"
>
<span className="flex size-6 items-center justify-center">
<img src={SAIL_ICON} alt="" className="size-4.5 invert" />
</span>
<span className="text-[13px] font-semibold text-white">Take notes</span>
</button>
</div>
<button
onClick={() => act('take-notes')}
className="flex h-8.5 shrink-0 items-center gap-1.5 rounded-lg bg-neutral-800/90 border border-neutral-700 pl-1.5 pr-2.5 hover:bg-neutral-700 transition-colors"
>
<span className="flex size-6 items-center justify-center">
<img src={SAIL_ICON} alt="" className="size-4.5 invert" />
</span>
<span className="text-[13px] font-semibold text-white">Take notes</span>
</button>
</div>
)