From 55c16af04c220d881ea7835a2ad59bbaac99958a Mon Sep 17 00:00:00 2001 From: Arjun <6592213+arkml@users.noreply.github.com> Date: Wed, 13 May 2026 18:06:33 +0530 Subject: [PATCH] iframe mounted across toggle and cached height --- apps/x/apps/main/src/ipc.ts | 6 +- apps/x/apps/renderer/src/App.css | 4 ++ .../renderer/src/components/email-view.tsx | 56 ++++++++++++++++--- .../packages/core/src/knowledge/sync_gmail.ts | 28 ++++++++-- apps/x/packages/shared/src/blocks.ts | 1 + apps/x/packages/shared/src/ipc.ts | 8 +++ 6 files changed, 89 insertions(+), 14 deletions(-) diff --git a/apps/x/apps/main/src/ipc.ts b/apps/x/apps/main/src/ipc.ts index 618d7f62..04821874 100644 --- a/apps/x/apps/main/src/ipc.ts +++ b/apps/x/apps/main/src/ipc.ts @@ -47,7 +47,7 @@ import { summarizeMeeting } from '@x/core/dist/knowledge/summarize_meeting.js'; import { getAccessToken } from '@x/core/dist/auth/tokens.js'; import { getRowboatConfig } from '@x/core/dist/config/rowboat.js'; import { runLiveNoteAgent } from '@x/core/dist/knowledge/live-note/runner.js'; -import { fetchThreadSnapshot, listRecentThreadIds, listCachedThreads } from '@x/core/dist/knowledge/sync_gmail.js'; +import { fetchThreadSnapshot, listRecentThreadIds, listCachedThreads, saveMessageBodyHeight } from '@x/core/dist/knowledge/sync_gmail.js'; import { liveNoteBus } from '@x/core/dist/knowledge/live-note/bus.js'; import { getInstallationId } from '@x/core/dist/analytics/installation.js'; import { API_URL } from '@x/core/dist/config/env.js'; @@ -506,6 +506,10 @@ export function setupIpcHandlers() { 'gmail:listCachedThreads': async (_event, args) => { return { threads: listCachedThreads(args.daysAgo ?? 2) }; }, + 'gmail:saveMessageHeight': async (_event, args) => { + saveMessageBodyHeight(args.threadId, args.messageId, args.height); + return {}; + }, 'mcp:listTools': async (_event, args) => { return mcpCore.listTools(args.serverName, args.cursor); }, diff --git a/apps/x/apps/renderer/src/App.css b/apps/x/apps/renderer/src/App.css index 9d054aa0..0d30d94a 100644 --- a/apps/x/apps/renderer/src/App.css +++ b/apps/x/apps/renderer/src/App.css @@ -323,6 +323,10 @@ box-shadow: inset 2px 0 0 var(--gm-accent); } +.gmail-detail-hidden { + display: none; +} + .gmail-detail-toolbar { display: flex; align-items: center; diff --git a/apps/x/apps/renderer/src/components/email-view.tsx b/apps/x/apps/renderer/src/components/email-view.tsx index d2695158..2a9be83f 100644 --- a/apps/x/apps/renderer/src/components/email-view.tsx +++ b/apps/x/apps/renderer/src/components/email-view.tsx @@ -110,10 +110,12 @@ function buildEmailDocument(html: string): string { ${html}` } -function MessageBody({ message }: { message: GmailThreadMessage }) { +function MessageBody({ message, threadId }: { message: GmailThreadMessage; threadId: string }) { const iframeRef = useRef(null) const observerRef = useRef(null) - const [height, setHeight] = useState(80) + const saveTimerRef = useRef | null>(null) + const lastSavedHeightRef = useRef(message.bodyHeight ?? 0) + const [height, setHeight] = useState(message.bodyHeight ?? 80) const srcDoc = useMemo(() => { if (message.bodyHtml && message.bodyHtml.trim()) { @@ -130,6 +132,17 @@ function MessageBody({ message }: { message: GmailThreadMessage }) { const measure = () => { const next = Math.max(40, doc.documentElement.scrollHeight) setHeight((current) => (current === next ? current : next)) + if (!message.id) return + if (Math.abs(next - lastSavedHeightRef.current) < 4) return + if (saveTimerRef.current) clearTimeout(saveTimerRef.current) + saveTimerRef.current = setTimeout(() => { + lastSavedHeightRef.current = next + void window.ipc.invoke('gmail:saveMessageHeight', { + threadId, + messageId: message.id!, + height: next, + }).catch(() => {}) + }, 500) } measure() observerRef.current?.disconnect() @@ -137,9 +150,12 @@ function MessageBody({ message }: { message: GmailThreadMessage }) { observerRef.current = new ResizeObserver(measure) observerRef.current.observe(doc.body) } - }, []) + }, [message.id, threadId]) - useEffect(() => () => observerRef.current?.disconnect(), []) + useEffect(() => () => { + observerRef.current?.disconnect() + if (saveTimerRef.current) clearTimeout(saveTimerRef.current) + }, []) return (