courrier clean 2

This commit is contained in:
alma 2025-04-26 12:12:43 +02:00
parent c325d3cdf7
commit 4db3140ece
2 changed files with 118 additions and 25 deletions

View File

@ -88,3 +88,23 @@
.email-content .header { margin-bottom: 1em; }
.email-content .footer { font-size: 0.875rem; color: #6b7280; margin-top: 1em; }
/* Force email content direction */
.email-content-wrapper {
direction: ltr !important;
unicode-bidi: isolate !important;
text-align: left !important;
}
.email-content-wrapper * {
direction: ltr !important;
unicode-bidi: isolate !important;
text-align: left !important;
}
/* Email editor styles */
.email-editor {
direction: ltr !important;
unicode-bidi: isolate !important;
text-align: left !important;
}

View File

@ -88,6 +88,8 @@ export default function ComposeEmail({
const fileInputRef = useRef<HTMLInputElement>(null);
const contentEditableRef = useRef<HTMLDivElement>(null);
const [useRichEditor, setUseRichEditor] = useState(false);
const [userMessage, setUserMessage] = useState('');
const [quotedContent, setQuotedContent] = useState('');
useEffect(() => {
// When forwarding or replying, use rich editor
@ -102,17 +104,16 @@ export default function ComposeEmail({
setComposeTo(formattedEmail.to);
setComposeSubject(formattedEmail.subject);
// Use the body but preserve the original UI styling
// Extract just the content portion from the client formatter output
// and apply the original styling
let bodyContent = formattedEmail.body;
// Apply DOMPurify to the content for safety
bodyContent = DOMPurify.sanitize(bodyContent, {
// Store the quoted content separately
const bodyContent = DOMPurify.sanitize(formattedEmail.body, {
ADD_TAGS: ['style'],
FORBID_TAGS: ['script', 'iframe']
});
setQuotedContent(bodyContent);
setUserMessage(''); // Clear user input
// Keep composeBody for backwards compatibility
setComposeBody(bodyContent);
}
}, [replyTo, setComposeTo, setComposeSubject, setComposeBody]);
@ -162,13 +163,23 @@ export default function ComposeEmail({
});
}
// Set body with header and content, preserving the original UI layout
setComposeBody(`
${headerHtml}
<div style="margin-top: 10px;">
${contentHtml}
// Store the quoted content
const formattedQuote = `
<div dir="ltr" style="unicode-bidi: isolate; direction: ltr;">
${headerHtml}
<div style="margin-top: 10px; unicode-bidi: isolate; direction: ltr; text-align: left;">
<div style="isolation: isolate; contain: content; overflow: auto; unicode-bidi: isolate; direction: ltr; text-align: left;">
${contentHtml}
</div>
</div>
</div>
`);
`;
setQuotedContent(formattedQuote);
setUserMessage(''); // Clear user input
// Keep composeBody for backwards compatibility
setComposeBody(formattedQuote);
};
// Handle file attachment selection
@ -180,9 +191,44 @@ export default function ComposeEmail({
};
// Handle contentEditable input changes
const handleContentEditableChange = () => {
const handleUserMessageChange = () => {
if (contentEditableRef.current) {
setComposeBody(contentEditableRef.current.innerHTML);
setUserMessage(contentEditableRef.current.innerHTML);
// Combine user message with quoted content for the full email body
const combined = `
<div dir="ltr" style="direction: ltr; unicode-bidi: isolate; text-align: left;">
${contentEditableRef.current.innerHTML}
</div>
${quotedContent}
`;
setComposeBody(combined);
}
};
// Handle sending with combined content
const handleSendWithCombinedContent = async () => {
// For rich editor mode, ensure we combine user message with quoted content
if (useRichEditor) {
// Create the final combined email body
const finalBody = `
<div dir="ltr" style="direction: ltr; unicode-bidi: isolate; text-align: left;">
${userMessage}
</div>
${quotedContent}
`;
// Set the complete body and send after a brief delay to ensure state is updated
setComposeBody(finalBody);
// Small delay to ensure state update completes
setTimeout(() => {
handleSend();
}, 50);
} else {
// For normal textarea mode, just use the existing handler
handleSend();
}
};
@ -295,21 +341,48 @@ export default function ComposeEmail({
<Label htmlFor="message" className="block text-sm font-medium text-gray-700">Message</Label>
{useRichEditor ? (
<div
ref={contentEditableRef}
contentEditable
className="w-full mt-1 min-h-[200px] p-3 bg-white border border-gray-300 rounded-md overflow-auto text-gray-900"
style={{ direction: 'ltr' }}
dangerouslySetInnerHTML={{ __html: composeBody }}
onInput={handleContentEditableChange}
/>
<div className="mt-1 border border-gray-300 rounded-md overflow-hidden">
{/* User input area - completely separate from quoted content */}
<div
ref={contentEditableRef}
contentEditable
className="w-full p-3 bg-white min-h-[100px] text-gray-900 email-editor"
style={{
direction: 'ltr',
unicodeBidi: 'isolate',
textAlign: 'left'
}}
onInput={handleUserMessageChange}
dir="ltr"
>
{!userMessage && <p style={{ color: '#718096' }}>Write your message here...</p>}
</div>
{/* Original email content - completely isolated */}
{quotedContent && (
<div
className="w-full bg-gray-50 border-t border-gray-300 email-content-wrapper"
style={{
direction: 'ltr',
unicodeBidi: 'isolate'
}}
>
<div
className="p-3 opacity-75 text-sm email-content"
dangerouslySetInnerHTML={{ __html: quotedContent }}
/>
</div>
)}
</div>
) : (
<Textarea
id="message"
value={composeBody}
onChange={(e) => setComposeBody(e.target.value)}
placeholder="Write your message..."
className="w-full mt-1 min-h-[200px] bg-white border-gray-300 text-gray-900 resize-none"
className="w-full mt-1 min-h-[200px] bg-white border-gray-300 text-gray-900 resize-none email-editor"
dir="ltr"
style={{ direction: 'ltr', unicodeBidi: 'isolate', textAlign: 'left' }}
/>
)}
</div>
@ -351,7 +424,7 @@ export default function ComposeEmail({
</Button>
<Button
className="bg-blue-600 text-white hover:bg-blue-700"
onClick={handleSend}
onClick={handleSendWithCombinedContent}
disabled={isSending}
>
{isSending ? 'Sending...' : 'Send'}