diff --git a/apps/x/apps/renderer/src/components/markdown-editor.tsx b/apps/x/apps/renderer/src/components/markdown-editor.tsx index e97f7c6e..10e429d8 100644 --- a/apps/x/apps/renderer/src/components/markdown-editor.tsx +++ b/apps/x/apps/renderer/src/components/markdown-editor.tsx @@ -20,7 +20,7 @@ import { IframeBlockExtension } from '@/extensions/iframe-block' import { ChartBlockExtension } from '@/extensions/chart-block' import { TableBlockExtension } from '@/extensions/table-block' import { CalendarBlockExtension } from '@/extensions/calendar-block' -import { EmailBlockExtension } from '@/extensions/email-block' +import { EmailBlockExtension, EmailsBlockExtension } from '@/extensions/email-block' import { TranscriptBlockExtension } from '@/extensions/transcript-block' import { MermaidBlockExtension } from '@/extensions/mermaid-block' import { Markdown } from 'tiptap-markdown' @@ -707,6 +707,7 @@ export const MarkdownEditor = forwardRef" or plain email */ function extractName(from: string): string { const match = from.match(/^([^<]+) void +}) { + const [draftBody, setDraftBody] = useState(config.draft_response || '') + const [copied, setCopied] = useState(false) + const bodyRef = useRef(null) + + useEffect(() => { + setDraftBody(config.draft_response || '') + }, [config.draft_response]) + + useEffect(() => { + if (bodyRef.current) { + bodyRef.current.style.height = 'auto' + bodyRef.current.style.height = bodyRef.current.scrollHeight + 'px' + } + }, [draftBody]) + + const draftWithAssistant = useCallback(() => { + let prompt = draftBody + ? `Help me refine this draft response to an email` + : `Help me draft a response to this email` + if (config.threadId) { + prompt += `. Read the full thread at gmail_sync/${config.threadId}.md for context` + } + prompt += `.\n\n**From:** ${config.from || 'Unknown'}\n**Subject:** ${config.subject || 'No subject'}\n` + if (draftBody) prompt += `\n**Current draft:**\n${draftBody}\n` + window.__pendingEmailDraft = { prompt } + window.dispatchEvent(new Event('email-block:draft-with-assistant')) + }, [config, draftBody]) + + const copyDraft = useCallback(() => { + navigator.clipboard.writeText(draftBody).then(() => { + setCopied(true) + setTimeout(() => setCopied(false), 2000) + }).catch(() => { + const el = document.createElement('textarea') + el.value = draftBody + document.body.appendChild(el) + el.select() + document.execCommand('copy') + document.body.removeChild(el) + setCopied(true) + setTimeout(() => setCopied(false), 2000) + }) + }, [draftBody]) + + const gmailUrl = config.threadId + ? `https://mail.google.com/mail/u/0/#all/${config.threadId}` + : null + + const senderName = config.from ? extractName(config.from) : 'Unknown' + const initial = config.from ? getInitial(config.from) : '?' + const color = config.from ? avatarColor(config.from) : '#5f6368' + const hasDraft = !!config.draft_response + + return ( +
+ {config.subject && ( +
{config.subject}
+ )} + +
+
{initial}
+
+
{senderName}
+
+ {config.to && to {config.to}} + {config.date && {formatFullDate(config.date)}} +
+
+
+ {gmailUrl && ( + + )} + {onDelete && ( + + )} +
+
+ +
{config.latest_email}
+ + {config.past_summary && ( +
+
Earlier conversation
+
{config.past_summary}
+
+ )} + + {/* Reply / Forward / Draft with Rowboat row */} +
+ + {gmailUrl && ( + + )} + +
+ + {hasDraft && ( +
+
+ Reply + {config.from && {config.from}} +
+