inbox streamlining
This commit is contained in:
parent
f969cfed44
commit
220168abd0
4 changed files with 279 additions and 245 deletions
|
|
@ -77,18 +77,37 @@ function metricTotal(stats) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function emailContextSummary(email) {
|
function emailContextSummary(email) {
|
||||||
const text = (email?.body_text || email?.snippet || "").trim();
|
const text = (email?.body_text || email?.snippet || "").trim().toLowerCase();
|
||||||
if (!text) return "Open message loaded — summary will appear here.";
|
const sender = email?.sender?.name || email?.sender_display_name || "The sender";
|
||||||
return text.length > 160 ? `${text.slice(0, 157)}…` : text;
|
if (!text) return "This message is open — a summary will appear here.";
|
||||||
|
if (text.includes("check") && text.includes("inbox") && text.includes("repl")) {
|
||||||
|
return `${sender} asks you to check the inbox and review messages and replies.`;
|
||||||
|
}
|
||||||
|
if (text.includes("check") && text.includes("inbox")) {
|
||||||
|
return `${sender} asks you to check the inbox.`;
|
||||||
|
}
|
||||||
|
if (text.includes("repl")) {
|
||||||
|
return `${sender} is following up about replies or responses.`;
|
||||||
|
}
|
||||||
|
if (text.includes("attach")) {
|
||||||
|
return `${sender} references an attachment that may need review.`;
|
||||||
|
}
|
||||||
|
const snippet = (email?.body_text || email?.snippet || "").trim();
|
||||||
|
const firstSentence = snippet.split(/[.!?\n]/).find((part) => part.trim().length > 8)?.trim();
|
||||||
|
if (firstSentence) {
|
||||||
|
return `${sender} wrote: “${firstSentence.length > 120 ? `${firstSentence.slice(0, 117)}…` : firstSentence}.”`;
|
||||||
|
}
|
||||||
|
return `${sender} sent a short message that may need a response.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function emailContextActions(email) {
|
function emailContextActions(email) {
|
||||||
const text = (email?.body_text || email?.snippet || "").toLowerCase();
|
const text = (email?.body_text || email?.snippet || "").toLowerCase();
|
||||||
const actions = [];
|
const actions = [];
|
||||||
if (text.includes("check") && text.includes("inbox")) actions.push("Check inbox");
|
if (text.includes("check") && text.includes("inbox")) actions.push("Check inbox");
|
||||||
|
if (text.includes("message")) actions.push("Review messages");
|
||||||
if (text.includes("repl")) actions.push("Review replies");
|
if (text.includes("repl")) actions.push("Review replies");
|
||||||
if (text.includes("attach")) actions.push("Review attachments");
|
if (text.includes("attach")) actions.push("Review attachments");
|
||||||
if (!actions.length) actions.push("Review message", "Draft a reply");
|
if (!actions.length) actions.push("Review message");
|
||||||
return actions.slice(0, 3);
|
return actions.slice(0, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,9 +189,12 @@ export default function AgAgentPanel({
|
||||||
<h3>Summary</h3>
|
<h3>Summary</h3>
|
||||||
<p>{emailContextSummary(contextEmail)}</p>
|
<p>{emailContextSummary(contextEmail)}</p>
|
||||||
<h3>Action items</h3>
|
<h3>Action items</h3>
|
||||||
<ul>
|
<ul className="agent-email-action-list">
|
||||||
{emailContextActions(contextEmail).map((item) => (
|
{emailContextActions(contextEmail).map((item) => (
|
||||||
<li key={item}>{item}</li>
|
<li key={item}>
|
||||||
|
<span className="agent-email-action-check" aria-hidden="true" />
|
||||||
|
{item}
|
||||||
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<button type="button" className="agent-email-context-reply" onClick={() => onCompose?.()}>
|
<button type="button" className="agent-email-context-reply" onClick={() => onCompose?.()}>
|
||||||
|
|
@ -209,7 +231,7 @@ export default function AgAgentPanel({
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{showFullPanel && !allMetricsZero && (
|
{showFullPanel && !emailContextMode && !allMetricsZero && (
|
||||||
<div className="agent-stat-grid">
|
<div className="agent-stat-grid">
|
||||||
{cards.map((card) => {
|
{cards.map((card) => {
|
||||||
const Icon = card.icon;
|
const Icon = card.icon;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
Archive,
|
Archive,
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
|
|
@ -20,7 +21,7 @@ import SenderAvatar from "./SenderAvatar";
|
||||||
import { addressText, senderDisplayName } from "../utils/senderAvatar";
|
import { addressText, senderDisplayName } from "../utils/senderAvatar";
|
||||||
import { attachmentCount } from "../utils/inboxSignals";
|
import { attachmentCount } from "../utils/inboxSignals";
|
||||||
|
|
||||||
const ICON = { size: 17, strokeWidth: 1.7 };
|
const ICON = { size: 16, strokeWidth: 1.7 };
|
||||||
|
|
||||||
function joinAddresses(value) {
|
function joinAddresses(value) {
|
||||||
if (!value) return "";
|
if (!value) return "";
|
||||||
|
|
@ -45,13 +46,6 @@ function messageBody(email) {
|
||||||
return { mode: "text", value: "This message has no readable content." };
|
return { mode: "text", value: "This message has no readable content." };
|
||||||
}
|
}
|
||||||
|
|
||||||
function plainTextParagraphs(text) {
|
|
||||||
return text
|
|
||||||
.split(/\n{2,}/)
|
|
||||||
.map((block) => block.trim())
|
|
||||||
.filter(Boolean);
|
|
||||||
}
|
|
||||||
|
|
||||||
function detailTime(email) {
|
function detailTime(email) {
|
||||||
const value = email?.received_at || email?.sent_at || email?.created_at || email?.updated_at;
|
const value = email?.received_at || email?.sent_at || email?.created_at || email?.updated_at;
|
||||||
if (!value) return { absolute: "", relative: "" };
|
if (!value) return { absolute: "", relative: "" };
|
||||||
|
|
@ -73,9 +67,9 @@ function senderIdentity(email) {
|
||||||
const name = senderDisplayName(email);
|
const name = senderDisplayName(email);
|
||||||
const address = addressText(email.sender || email.from);
|
const address = addressText(email.sender || email.from);
|
||||||
if (name && address && !name.includes("@")) {
|
if (name && address && !name.includes("@")) {
|
||||||
return `${name} <${address}>`;
|
return { name, address, display: `${name} <${address}>` };
|
||||||
}
|
}
|
||||||
return address || name || "Unknown sender";
|
return { name: name || address, address, display: address || name || "Unknown sender" };
|
||||||
}
|
}
|
||||||
|
|
||||||
function recipientLabel(email, viewerEmail) {
|
function recipientLabel(email, viewerEmail) {
|
||||||
|
|
@ -106,11 +100,17 @@ function mailboxLabel(mailbox) {
|
||||||
return mailbox;
|
return mailbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ToolbarButton({ title, label, onClick, disabled, danger, children }) {
|
function hasMultipleRecipients(email) {
|
||||||
|
const toCount = Array.isArray(email.recipients || email.to) ? (email.recipients || email.to).length : 0;
|
||||||
|
const ccCount = Array.isArray(email.cc) ? email.cc.length : 0;
|
||||||
|
return toCount > 1 || ccCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ToolbarButton({ title, label, onClick, disabled, destructive, children }) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={danger ? "danger" : ""}
|
className={destructive ? "destructive" : ""}
|
||||||
title={title}
|
title={title}
|
||||||
aria-label={label || title}
|
aria-label={label || title}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
|
@ -144,20 +144,23 @@ export default function MailDetail({
|
||||||
onExtractActions,
|
onExtractActions,
|
||||||
onSummarizeThread,
|
onSummarizeThread,
|
||||||
onAnalyzeAttachment,
|
onAnalyzeAttachment,
|
||||||
onDraftReply,
|
|
||||||
}) {
|
}) {
|
||||||
|
const [headersOpen, setHeadersOpen] = useState(false);
|
||||||
const files = email ? attachmentCount(email) : 0;
|
const files = email ? attachmentCount(email) : 0;
|
||||||
const body = email ? messageBody(email) : null;
|
const body = email ? messageBody(email) : null;
|
||||||
const time = email ? detailTime(email) : { absolute: "", relative: "" };
|
const time = email ? detailTime(email) : { absolute: "", relative: "" };
|
||||||
const attachments = email?.attachments || [];
|
const attachments = email?.attachments || [];
|
||||||
const summarizeLabel = threadSize > 1 ? "Summarize thread" : "Summarize email";
|
const sender = email ? senderIdentity(email) : null;
|
||||||
|
const summarizeLabel = threadSize > 1 ? "Summarize thread" : "Summarize";
|
||||||
|
const showReplyAll = email ? hasMultipleRecipients(email) : false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article className={`mail-detail${email || loading ? " open" : ""}`} aria-live="polite">
|
<article className={`mail-detail${email || loading ? " open" : ""}`} aria-live="polite">
|
||||||
|
<div className="mail-detail-reader">
|
||||||
<header className="mail-detail-toolbar">
|
<header className="mail-detail-toolbar">
|
||||||
<div className="mail-detail-toolbar-group">
|
<div className="mail-detail-toolbar-group">
|
||||||
<ToolbarButton title="Back to inbox" label="Back" onClick={onClose}>
|
<ToolbarButton title="Back to inbox" label="Back" onClick={onClose}>
|
||||||
<ArrowLeft {...ICON} />
|
<ArrowLeft size={16} strokeWidth={1.7} />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</div>
|
</div>
|
||||||
{email && (
|
{email && (
|
||||||
|
|
@ -173,7 +176,7 @@ export default function MailDetail({
|
||||||
title={mailbox === "trash" ? "Delete permanently" : "Delete"}
|
title={mailbox === "trash" ? "Delete permanently" : "Delete"}
|
||||||
onClick={mailbox === "trash" ? onDelete : onTrash}
|
onClick={mailbox === "trash" ? onDelete : onTrash}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
danger
|
destructive
|
||||||
>
|
>
|
||||||
<Trash2 {...ICON} />
|
<Trash2 {...ICON} />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
|
|
@ -193,10 +196,10 @@ export default function MailDetail({
|
||||||
</div>
|
</div>
|
||||||
<span className="mail-detail-toolbar-sep" aria-hidden="true" />
|
<span className="mail-detail-toolbar-sep" aria-hidden="true" />
|
||||||
<div className="mail-detail-toolbar-group">
|
<div className="mail-detail-toolbar-group">
|
||||||
<ToolbarButton title="Move to" onClick={onMove} disabled={busy}>
|
<ToolbarButton title="Move to folder" onClick={onMove} disabled={busy}>
|
||||||
<FolderInput {...ICON} />
|
<FolderInput {...ICON} />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
<ToolbarButton title="Labels" onClick={onMove} disabled={busy}>
|
<ToolbarButton title="Apply labels" onClick={onMove} disabled={busy}>
|
||||||
<Tag {...ICON} />
|
<Tag {...ICON} />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
<ToolbarButton title="More actions" onClick={onMove} disabled={busy}>
|
<ToolbarButton title="More actions" onClick={onMove} disabled={busy}>
|
||||||
|
|
@ -207,7 +210,7 @@ export default function MailDetail({
|
||||||
<>
|
<>
|
||||||
<span className="mail-detail-toolbar-sep" aria-hidden="true" />
|
<span className="mail-detail-toolbar-sep" aria-hidden="true" />
|
||||||
<div className="mail-detail-toolbar-group">
|
<div className="mail-detail-toolbar-group">
|
||||||
<ToolbarButton title="Restore" onClick={onRestore} disabled={busy}>
|
<ToolbarButton title="Restore from trash" onClick={onRestore} disabled={busy}>
|
||||||
<RotateCcw {...ICON} />
|
<RotateCcw {...ICON} />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -221,15 +224,17 @@ export default function MailDetail({
|
||||||
{error && <div className="mail-detail-state error" role="alert">{error}</div>}
|
{error && <div className="mail-detail-state error" role="alert">{error}</div>}
|
||||||
|
|
||||||
{email && !loading && (
|
{email && !loading && (
|
||||||
|
<div className="mail-detail-sheet">
|
||||||
<div className="mail-detail-content">
|
<div className="mail-detail-content">
|
||||||
|
<div className="mail-detail-reading-column">
|
||||||
<div className="mail-detail-subject-row">
|
<div className="mail-detail-subject-row">
|
||||||
<div className="mail-detail-subject-main">
|
|
||||||
<h1>{email.subject?.trim() || "(No subject)"}</h1>
|
<h1>{email.subject?.trim() || "(No subject)"}</h1>
|
||||||
<div className="mail-detail-labels">
|
<div className="mail-detail-labels">
|
||||||
<span className="mail-detail-label-pill">{mailboxLabel(mailbox)}</span>
|
<span className="mail-detail-label-pill">{mailboxLabel(mailbox)}</span>
|
||||||
{email.is_starred && <span className="mail-detail-label-pill starred">Starred</span>}
|
{email.is_starred && <span className="mail-detail-label-pill starred">Starred</span>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mail-detail-ai-chips">
|
<div className="mail-detail-ai-chips">
|
||||||
<button type="button" className="mail-detail-ai-chip" onClick={onSummarizeThread}>
|
<button type="button" className="mail-detail-ai-chip" onClick={onSummarizeThread}>
|
||||||
<AgentSpark /> {summarizeLabel}
|
<AgentSpark /> {summarizeLabel}
|
||||||
|
|
@ -237,32 +242,39 @@ export default function MailDetail({
|
||||||
<button type="button" className="mail-detail-ai-chip" onClick={onExtractActions}>
|
<button type="button" className="mail-detail-ai-chip" onClick={onExtractActions}>
|
||||||
<AgentSpark /> Extract actions
|
<AgentSpark /> Extract actions
|
||||||
</button>
|
</button>
|
||||||
<button type="button" className="mail-detail-ai-chip" onClick={onDraftReply}>
|
|
||||||
<AgentSpark /> Draft reply
|
|
||||||
</button>
|
|
||||||
{files > 0 && (
|
{files > 0 && (
|
||||||
<button type="button" className="mail-detail-ai-chip" onClick={onAnalyzeAttachment}>
|
<button type="button" className="mail-detail-ai-chip" onClick={onAnalyzeAttachment}>
|
||||||
<AgentSpark /> Analyze attachment
|
<AgentSpark /> Analyze attachment
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mail-detail-sender-row">
|
<div className="mail-detail-sender-row">
|
||||||
<div className="mail-detail-sender-left">
|
|
||||||
<SenderAvatar email={email} />
|
<SenderAvatar email={email} />
|
||||||
<div className="mail-detail-sender-meta">
|
<div className="mail-detail-sender-meta">
|
||||||
<div className="mail-detail-sender-line">
|
<div className="mail-detail-sender-line">
|
||||||
<strong>{senderIdentity(email)}</strong>
|
<strong>{sender?.name}</strong>
|
||||||
|
{sender?.address && <span className="mail-detail-sender-email"><{sender.address}></span>}
|
||||||
</div>
|
</div>
|
||||||
<button type="button" className="mail-detail-recipient-toggle">
|
<button
|
||||||
{recipientLabel(email, viewerEmail)} <ChevronDown size={12} strokeWidth={1.75} />
|
type="button"
|
||||||
|
className={`mail-detail-recipient-toggle${headersOpen ? " open" : ""}`}
|
||||||
|
onClick={() => setHeadersOpen((open) => !open)}
|
||||||
|
aria-expanded={headersOpen}
|
||||||
|
>
|
||||||
|
{recipientLabel(email, viewerEmail)}
|
||||||
|
<ChevronDown size={12} strokeWidth={1.75} />
|
||||||
</button>
|
</button>
|
||||||
|
{headersOpen && (
|
||||||
<div className="mail-detail-recipient-details">
|
<div className="mail-detail-recipient-details">
|
||||||
|
<small>From: {joinAddresses(email.sender) || sender?.display}</small>
|
||||||
<small>To: {joinAddresses(email.recipients || email.to) || "Undisclosed"}</small>
|
<small>To: {joinAddresses(email.recipients || email.to) || "Undisclosed"}</small>
|
||||||
{joinAddresses(email.cc) && <small>Cc: {joinAddresses(email.cc)}</small>}
|
{joinAddresses(email.cc) && <small>Cc: {joinAddresses(email.cc)}</small>}
|
||||||
|
{joinAddresses(email.bcc) && <small>Bcc: {joinAddresses(email.bcc)}</small>}
|
||||||
|
<small>Date: {time.absolute}{time.relative ? ` (${time.relative})` : ""}</small>
|
||||||
|
<small>Subject: {email.subject?.trim() || "(No subject)"}</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="mail-detail-sender-actions">
|
<div className="mail-detail-sender-actions">
|
||||||
<time dateTime={email.created_at}>
|
<time dateTime={email.created_at}>
|
||||||
|
|
@ -281,7 +293,7 @@ export default function MailDetail({
|
||||||
<button type="button" className="mail-detail-icon-btn" title="Reply" onClick={onReply}>
|
<button type="button" className="mail-detail-icon-btn" title="Reply" onClick={onReply}>
|
||||||
<Reply size={16} strokeWidth={1.75} />
|
<Reply size={16} strokeWidth={1.75} />
|
||||||
</button>
|
</button>
|
||||||
<button type="button" className="mail-detail-icon-btn" title="More" onClick={onMove}>
|
<button type="button" className="mail-detail-icon-btn" title="More actions" onClick={onMove}>
|
||||||
<MoreHorizontal size={16} strokeWidth={1.75} />
|
<MoreHorizontal size={16} strokeWidth={1.75} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -291,18 +303,7 @@ export default function MailDetail({
|
||||||
{body?.mode === "html" ? (
|
{body?.mode === "html" ? (
|
||||||
<div className="mail-detail-body-html" dangerouslySetInnerHTML={{ __html: body.value }} />
|
<div className="mail-detail-body-html" dangerouslySetInnerHTML={{ __html: body.value }} />
|
||||||
) : (
|
) : (
|
||||||
<div className="mail-detail-body-text">
|
<div className="mail-detail-body-text">{body?.value}</div>
|
||||||
{plainTextParagraphs(body?.value || "").map((paragraph) => (
|
|
||||||
<p key={paragraph.slice(0, 24)}>
|
|
||||||
{paragraph.split("\n").map((line, index, lines) => (
|
|
||||||
<span key={`${line}-${index}`}>
|
|
||||||
{line}
|
|
||||||
{index < lines.length - 1 && <br />}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</p>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -323,22 +324,25 @@ export default function MailDetail({
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<footer className="mail-detail-reply-bar">
|
<footer className="mail-detail-reply-bar">
|
||||||
<button type="button" className="mail-detail-reply-btn" onClick={onReply}>
|
<button type="button" className="mail-detail-reply-btn" onClick={onReply}>
|
||||||
<Reply size={15} strokeWidth={1.75} /> Reply
|
<Reply size={15} strokeWidth={1.75} /> Reply
|
||||||
</button>
|
</button>
|
||||||
{(email.recipients?.length > 1 || email.cc?.length) && (
|
{showReplyAll ? (
|
||||||
<button type="button" className="mail-detail-reply-btn subtle" onClick={onReply}>
|
<button type="button" className="mail-detail-reply-btn subtle" onClick={onReply}>
|
||||||
Reply all
|
Reply all
|
||||||
</button>
|
</button>
|
||||||
)}
|
) : null}
|
||||||
<button type="button" className="mail-detail-reply-btn subtle" onClick={onForward}>
|
<button type="button" className="mail-detail-reply-btn subtle" onClick={onForward}>
|
||||||
<Forward size={15} strokeWidth={1.75} /> Forward
|
<Forward size={15} strokeWidth={1.75} /> Forward
|
||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -715,7 +715,6 @@ export default function MailboxView({
|
||||||
onExtractActions={() => detail && extractActions(detail)}
|
onExtractActions={() => detail && extractActions(detail)}
|
||||||
onSummarizeThread={() => detail && summarizeThread(detail)}
|
onSummarizeThread={() => detail && summarizeThread(detail)}
|
||||||
onAnalyzeAttachment={() => detail && analyzeAttachment(detail)}
|
onAnalyzeAttachment={() => detail && analyzeAttachment(detail)}
|
||||||
onDraftReply={() => detail && extractActions(detail)}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -546,8 +546,8 @@ h1 em { color:var(--coral); font-style:normal; font-weight:500; }
|
||||||
.mailbox-toolbar { min-height:62px; padding:11px 15px; display:flex; align-items:center; gap:8px; border-bottom:1px solid #ebe7e3; background:#fffefd; }
|
.mailbox-toolbar { min-height:62px; padding:11px 15px; display:flex; align-items:center; gap:8px; border-bottom:1px solid #ebe7e3; background:#fffefd; }
|
||||||
.mailbox-toolbar>label { height:38px; min-width:160px; flex:1; padding:0 12px; display:flex; align-items:center; gap:8px; border:1px solid #e8e3df; border-radius:10px; color:#aaa4ac; background:#fcfbfa; }
|
.mailbox-toolbar>label { height:38px; min-width:160px; flex:1; padding:0 12px; display:flex; align-items:center; gap:8px; border:1px solid #e8e3df; border-radius:10px; color:#aaa4ac; background:#fcfbfa; }
|
||||||
.mailbox-toolbar input { min-width:0; width:100%; border:0; outline:0; background:transparent; color:var(--ink); font-size:12px; }
|
.mailbox-toolbar input { min-width:0; width:100%; border:0; outline:0; background:transparent; color:var(--ink); font-size:12px; }
|
||||||
.mailbox-toolbar>button,.mail-detail-toolbar button { height:36px; padding:0 10px; display:flex; align-items:center; justify-content:center; gap:6px; border:0; border-radius:9px; background:transparent; color:#77717a; font-size:10px; font-weight:700; }
|
.mailbox-toolbar>button { height:36px; padding:0 10px; display:flex; align-items:center; justify-content:center; gap:6px; border:0; border-radius:9px; background:transparent; color:#77717a; font-size:10px; font-weight:700; }
|
||||||
.mailbox-toolbar>button:hover,.mailbox-toolbar>button.active,.mail-detail-toolbar button:hover { background:#fff0eb; color:#bd5947; }
|
.mailbox-toolbar>button:hover,.mailbox-toolbar>button.active { background:#fff0eb; color:#bd5947; }
|
||||||
.mailbox-filters { padding:var(--space-3); display:grid; grid-template-columns:1fr 1.5fr 1fr 1fr; gap:var(--space-3); border-bottom:1px solid var(--border-subtle); background:#fafafa; }
|
.mailbox-filters { padding:var(--space-3); display:grid; grid-template-columns:1fr 1.5fr 1fr 1fr; gap:var(--space-3); border-bottom:1px solid var(--border-subtle); background:#fafafa; }
|
||||||
.mailbox-filters label { display:grid; gap:5px; color:#76717a; font-size:9px; font-weight:700; text-transform:uppercase; letter-spacing:.5px; }
|
.mailbox-filters label { display:grid; gap:5px; color:#76717a; font-size:9px; font-weight:700; text-transform:uppercase; letter-spacing:.5px; }
|
||||||
.mailbox-filters input,.mailbox-filters select { min-width:0; height:34px; padding:0 9px; border:1px solid #e4dfdc; border-radius:8px; outline:0; background:white; color:#393745; font-size:10px; text-transform:none; }
|
.mailbox-filters input,.mailbox-filters select { min-width:0; height:34px; padding:0 9px; border:1px solid #e4dfdc; border-radius:8px; outline:0; background:white; color:#393745; font-size:10px; text-transform:none; }
|
||||||
|
|
@ -649,71 +649,78 @@ h1 em { color:var(--coral); font-style:normal; font-weight:500; }
|
||||||
.sticky-note-form-actions button[type="submit"] { background:var(--ink); color:white; }
|
.sticky-note-form-actions button[type="submit"] { background:var(--ink); color:white; }
|
||||||
.sticky-note-form-actions button:disabled { opacity:.5; cursor:not-allowed; }
|
.sticky-note-form-actions button:disabled { opacity:.5; cursor:not-allowed; }
|
||||||
|
|
||||||
.mailbox-shell.detail-visible { border:1px solid rgba(24,20,35,.06); border-radius:10px; box-shadow:none; background:#fff; }
|
.mailbox-shell.detail-visible { align-self:start; overflow:visible; border:0; border-radius:0; box-shadow:none; background:transparent; }
|
||||||
.mailbox-shell.detail-visible .mailbox-categories,
|
.mailbox-shell.detail-visible .mailbox-categories,
|
||||||
.mailbox-shell.detail-visible .mailbox-rows,
|
.mailbox-shell.detail-visible .mailbox-rows,
|
||||||
.mailbox-shell.detail-visible .mailbox-pagination { display:none; }
|
.mailbox-shell.detail-visible .mailbox-pagination { display:none; }
|
||||||
.mailbox-shell.detail-visible .mailbox-list-pane { display:block; min-height:0; height:auto; }
|
.mailbox-shell.detail-visible .mailbox-list-pane { display:block; min-height:0; height:auto; background:var(--canvas); border-radius:0; padding:0 0 24px; }
|
||||||
.mail-detail { min-width:0; display:none; position:relative; z-index:1; background:#fff; }
|
.mail-detail { min-width:0; display:none; position:relative; z-index:1; }
|
||||||
.mail-detail.open { display:block; }
|
.mail-detail.open { display:block; }
|
||||||
.mail-detail-toolbar { height:50px; padding:0 24px; display:flex; align-items:center; gap:6px; border-bottom:1px solid #EEECEF; background:#fff; }
|
.mail-detail-reader { width:100%; background:#fff; border:1px solid rgba(25,22,40,.055); border-radius:12px; box-shadow:0 1px 2px rgba(20,18,30,.025),0 8px 24px rgba(20,18,30,.035); overflow:hidden; }
|
||||||
|
.mail-detail-toolbar { height:48px; padding:0 28px; display:flex; align-items:center; gap:6px; border-bottom:1px solid #ECE9EE; background:#fff; }
|
||||||
.mail-detail-toolbar-group { display:flex; align-items:center; gap:4px; }
|
.mail-detail-toolbar-group { display:flex; align-items:center; gap:4px; }
|
||||||
.mail-detail-toolbar-sep { width:1px; height:18px; margin:0 4px; background:#ECE9EE; flex-shrink:0; }
|
.mail-detail-toolbar-sep { width:1px; height:18px; margin:0 8px; background:#ECE9EE; flex-shrink:0; }
|
||||||
.mail-detail-toolbar button { width:32px; height:32px; padding:0; display:grid; place-items:center; border:0; border-radius:7px; background:transparent; color:#5a5562; }
|
.mail-detail-toolbar button { width:32px; height:32px; padding:0; display:grid; place-items:center; border:0; border-radius:7px; background:transparent; color:#5a5562; }
|
||||||
.mail-detail-toolbar button:hover { background:#f5f4f2; color:#241f2b; }
|
.mail-detail-toolbar button:hover { background:#f5f4f2; color:#241f2b; }
|
||||||
.mail-detail-toolbar button.danger { color:#bb4e43; }
|
.mail-detail-toolbar button.destructive { color:#5a5562; }
|
||||||
.mail-detail-toolbar button.danger:hover { background:#fdeeed; }
|
.mail-detail-toolbar button.destructive:hover { background:#fdeeed; color:#bb4e43; }
|
||||||
.mail-detail-state { min-height:200px; padding:32px; display:grid; place-items:center; color:#8d8891; font-size:12px; text-align:center; }
|
.mail-detail-sheet { height:auto; min-height:0; margin:0; background:#fff; }
|
||||||
|
.mail-detail-state { min-height:160px; padding:32px; display:grid; place-items:center; color:#8d8891; font-size:12px; text-align:center; background:#fff; border:1px solid rgba(25,22,40,.055); border-radius:12px; }
|
||||||
.mail-detail-state.error { color:#a94f40; }
|
.mail-detail-state.error { color:#a94f40; }
|
||||||
.mail-detail-content { padding:24px 32px 32px; }
|
.mail-detail-content { padding:0 0 28px; }
|
||||||
.mail-detail-subject-row { margin-bottom:22px; display:flex; align-items:flex-start; justify-content:space-between; gap:20px; }
|
.mail-detail-reading-column { max-width:820px; padding:24px 32px 0; }
|
||||||
.mail-detail-subject-main { min-width:0; display:flex; flex-wrap:wrap; align-items:center; gap:10px; }
|
.mail-detail-subject-row { margin:0 0 11px; display:flex; flex-wrap:wrap; align-items:center; gap:8px; }
|
||||||
.mail-detail-subject-main h1 { margin:0; overflow-wrap:anywhere; font:600 23px/30px "Manrope"; letter-spacing:-.5px; color:#171424; }
|
.mail-detail-subject-row h1 { margin:0; overflow-wrap:anywhere; font:650 22px/30px "Manrope"; letter-spacing:-.4px; color:#171424; }
|
||||||
.mail-detail-labels { display:flex; flex-wrap:wrap; gap:6px; }
|
.mail-detail-labels { display:flex; flex-wrap:wrap; gap:6px; }
|
||||||
.mail-detail-label-pill { height:21px; padding:0 8px; display:inline-flex; align-items:center; border-radius:6px; background:#f5f4f2; color:#77758a; font-size:10px; font-weight:600; }
|
.mail-detail-label-pill { height:21px; padding:0 8px; display:inline-flex; align-items:center; border-radius:6px; background:#f5f4f2; color:#77758a; font-size:10px; font-weight:600; }
|
||||||
.mail-detail-label-pill.starred { background:#fff8e8; color:#9a7228; }
|
.mail-detail-label-pill.starred { background:#fff8e8; color:#9a7228; }
|
||||||
.mail-detail-ai-chips { display:flex; flex-wrap:wrap; justify-content:flex-end; gap:6px; flex-shrink:0; }
|
.mail-detail-ai-chips { margin-bottom:20px; display:flex; flex-wrap:wrap; gap:8px; }
|
||||||
.mail-detail-ai-chip { height:28px; padding:0 10px; display:inline-flex; align-items:center; gap:5px; border:1px solid #ece7ff; border-radius:7px; background:#fbf9ff; color:#6d5bd0; font-size:10px; font-weight:600; white-space:nowrap; }
|
.mail-detail-ai-chip { height:28px; padding:0 10px; display:inline-flex; align-items:center; gap:5px; border:1px solid #ece7ff; border-radius:7px; background:#fbf9ff; color:#6d5bd0; font-size:10px; font-weight:600; white-space:nowrap; }
|
||||||
.mail-detail-ai-chip:hover { background:#f3efff; border-color:#ddd4ff; }
|
.mail-detail-ai-chip:hover { background:#f3efff; border-color:#ddd4ff; }
|
||||||
.mail-detail-sender-row { margin-bottom:24px; display:flex; align-items:flex-start; justify-content:space-between; gap:16px; }
|
.mail-detail-sender-row { margin-bottom:24px; display:grid; grid-template-columns:38px minmax(0,1fr) auto; gap:12px; align-items:start; }
|
||||||
.mail-detail-sender-left { min-width:0; display:flex; align-items:flex-start; gap:12px; }
|
.mail-detail-sender-row .sender-avatar { width:38px; height:38px; font-size:12px; }
|
||||||
.mail-detail-sender-left .sender-avatar { width:38px; height:38px; font-size:12px; flex-shrink:0; }
|
.mail-detail-sender-meta { min-width:0; display:grid; gap:4px; }
|
||||||
.mail-detail-sender-meta { min-width:0; display:grid; gap:3px; }
|
.mail-detail-sender-line { display:flex; flex-wrap:wrap; align-items:baseline; gap:6px; }
|
||||||
.mail-detail-sender-line strong { font:600 14px/1.35 "DM Sans"; color:#171424; overflow-wrap:anywhere; }
|
.mail-detail-sender-line strong { font:650 13px/1.35 "DM Sans"; color:#171424; }
|
||||||
.mail-detail-recipient-toggle { padding:0; display:inline-flex; align-items:center; gap:3px; border:0; background:transparent; color:#77758a; font-size:11px; font-weight:500; }
|
.mail-detail-sender-email { font:400 11px/1.35 "DM Sans"; color:#6f6b7c; overflow-wrap:anywhere; }
|
||||||
|
.mail-detail-recipient-toggle { padding:0; display:inline-flex; align-items:center; gap:3px; border:0; background:transparent; color:#77758a; font-size:11px; font-weight:500; text-align:left; }
|
||||||
|
.mail-detail-recipient-toggle svg { transition:transform var(--motion-fast) var(--ease-standard); }
|
||||||
|
.mail-detail-recipient-toggle.open svg { transform:rotate(180deg); }
|
||||||
.mail-detail-recipient-toggle:hover { color:#4a4652; }
|
.mail-detail-recipient-toggle:hover { color:#4a4652; }
|
||||||
.mail-detail-recipient-details { display:grid; gap:2px; }
|
.mail-detail-recipient-details { margin-top:4px; padding:8px 10px; display:grid; gap:4px; border-radius:8px; background:#faf9fc; border:1px solid #f0eef5; }
|
||||||
.mail-detail-recipient-details small { color:#77758a; font-size:11px; line-height:1.4; }
|
.mail-detail-recipient-details small { color:#77758a; font-size:11px; line-height:1.4; }
|
||||||
.mail-detail-sender-actions { display:flex; align-items:center; gap:4px; flex-shrink:0; }
|
.mail-detail-sender-actions { display:flex; align-items:center; gap:2px; flex-shrink:0; }
|
||||||
.mail-detail-sender-actions time { margin-right:6px; color:#77758a; font-size:11px; white-space:nowrap; }
|
.mail-detail-sender-actions time { margin-right:4px; color:#77758a; font-size:11px; white-space:nowrap; }
|
||||||
.mail-detail-icon-btn { width:32px; height:32px; display:grid; place-items:center; border:0; border-radius:7px; background:transparent; color:#6f6a73; }
|
.mail-detail-icon-btn { width:32px; height:32px; display:grid; place-items:center; border:0; border-radius:7px; background:transparent; color:#6f6a73; }
|
||||||
.mail-detail-icon-btn:hover { background:#f5f4f2; color:#241f2b; }
|
.mail-detail-icon-btn:hover { background:#f5f4f2; color:#241f2b; }
|
||||||
.mail-detail-icon-btn.active { color:#d4a017; }
|
.mail-detail-icon-btn.active { color:#d4a017; }
|
||||||
.mail-detail-body { color:#292536; }
|
.mail-detail-body { margin:0 0 24px 50px; color:#292536; }
|
||||||
.mail-detail-body.is-text { max-width:800px; font-size:14px; line-height:1.62; }
|
.mail-detail-body.is-text { max-width:760px; font-size:13px; line-height:1.58; }
|
||||||
.mail-detail-body-text p { margin:0 0 10px; }
|
.mail-detail-body-text { white-space:pre-line; overflow-wrap:anywhere; }
|
||||||
.mail-detail-body-text p:last-child { margin-bottom:0; }
|
.mail-detail-body.is-html { max-width:none; margin-left:0; font-size:14px; line-height:1.55; }
|
||||||
.mail-detail-body.is-html { max-width:none; font-size:14px; line-height:1.55; }
|
|
||||||
.mail-detail-body-html { white-space:normal; }
|
.mail-detail-body-html { white-space:normal; }
|
||||||
.mail-detail-body-html p { margin:0 0 12px; }
|
.mail-detail-body-html p { margin:0 0 12px; }
|
||||||
.mail-detail-body-html a { color:#4d74c4; text-decoration:underline; }
|
.mail-detail-body-html a { color:#4d74c4; text-decoration:underline; }
|
||||||
.mail-detail-attachments { margin-top:24px; display:flex; flex-wrap:wrap; gap:10px; }
|
.mail-detail-attachments { margin:20px 0 0 50px; max-width:760px; display:flex; flex-wrap:wrap; gap:10px; }
|
||||||
.mail-detail-attachment { min-width:220px; max-width:320px; padding:10px 12px; display:grid; grid-template-columns:auto 1fr auto; gap:10px; align-items:center; border:1px solid #ECE9EE; border-radius:8px; background:#fcfbfa; }
|
.mail-detail-attachment { min-width:220px; max-width:320px; padding:10px 12px; display:grid; grid-template-columns:auto 1fr auto; gap:10px; align-items:center; border:1px solid #ECE9EE; border-radius:8px; background:#fcfbfa; }
|
||||||
.mail-detail-attachment-icon { font-size:18px; }
|
.mail-detail-attachment-icon { font-size:18px; }
|
||||||
.mail-detail-attachment strong { display:block; font-size:12px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
.mail-detail-attachment strong { display:block; font-size:12px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
||||||
.mail-detail-attachment small { display:block; margin-top:2px; color:#77758a; font-size:10px; }
|
.mail-detail-attachment small { display:block; margin-top:2px; color:#77758a; font-size:10px; }
|
||||||
.mail-detail-attachment-actions { display:flex; flex-direction:column; gap:2px; }
|
.mail-detail-attachment-actions { display:flex; flex-direction:column; gap:2px; }
|
||||||
.mail-detail-attachment-actions button { padding:2px 4px; border:0; background:transparent; color:#6d5bd0; font-size:9px; font-weight:700; }
|
.mail-detail-attachment-actions button { padding:2px 4px; border:0; background:transparent; color:#6d5bd0; font-size:9px; font-weight:700; }
|
||||||
.mail-detail-reply-bar { margin-top:30px; display:flex; flex-wrap:wrap; gap:8px; }
|
.mail-detail-reply-bar { margin:20px 32px 0; padding:16px 0 0 50px; max-width:820px; display:flex; flex-wrap:wrap; gap:8px; border-top:1px solid #F0EEF2; }
|
||||||
.mail-detail-reply-btn { height:38px; padding:0 16px; display:inline-flex; align-items:center; gap:7px; border:1px solid #ECE9EE; border-radius:8px; background:#fff; color:#241f2b; font-size:12px; font-weight:600; }
|
.mail-detail-reply-btn { height:36px; padding:0 14px; display:inline-flex; align-items:center; gap:7px; border:1px solid #ECE9EE; border-radius:8px; background:#fff; color:#241f2b; font-size:12px; font-weight:600; }
|
||||||
.mail-detail-reply-btn:hover { background:#f8f7f5; border-color:#ddd8d3; }
|
.mail-detail-reply-btn:hover { background:#f8f7f5; border-color:#ddd8d3; }
|
||||||
.mail-detail-reply-btn.subtle { color:#5a5562; background:#fafafa; }
|
.mail-detail-reply-btn.subtle { color:#5a5562; background:#fafafa; }
|
||||||
.agent-panel.email-context .agent-stat-grid { display:none; }
|
.agent-panel.email-context .agent-stat-grid,
|
||||||
.agent-panel.email-context .agent-context-block { display:none; }
|
.agent-panel.email-context .agent-context-block,
|
||||||
.agent-email-context { margin:10px 0 14px; padding:12px; border:1px solid #ece9f2; border-radius:10px; background:#faf9fc; }
|
.agent-panel.email-context .agent-quick { display:none; }
|
||||||
|
.agent-email-context { margin:10px 0 14px; padding:0; }
|
||||||
.agent-email-context h3 { margin:0 0 6px; font-size:10px; font-weight:700; letter-spacing:.4px; text-transform:uppercase; color:#8a8496; }
|
.agent-email-context h3 { margin:0 0 6px; font-size:10px; font-weight:700; letter-spacing:.4px; text-transform:uppercase; color:#8a8496; }
|
||||||
.agent-email-context p { margin:0 0 12px; font-size:12px; line-height:1.5; color:#4a4652; }
|
.agent-email-context p { margin:0 0 14px; font-size:12px; line-height:1.55; color:#4a4652; }
|
||||||
.agent-email-context ul { margin:0 0 12px; padding-left:16px; color:#4a4652; font-size:12px; line-height:1.5; }
|
.agent-email-action-list { margin:0 0 14px; padding:0; list-style:none; display:grid; gap:8px; }
|
||||||
|
.agent-email-action-list li { display:flex; align-items:center; gap:8px; color:#4a4652; font-size:12px; line-height:1.4; }
|
||||||
|
.agent-email-action-check { width:14px; height:14px; flex-shrink:0; border:1.5px solid #c8c3d0; border-radius:4px; background:#fff; }
|
||||||
.agent-email-context-reply { height:34px; padding:0 12px; display:inline-flex; align-items:center; gap:6px; border:1px solid #ddd4ff; border-radius:8px; background:#f6f2ff; color:#6d4aff; font-size:11px; font-weight:700; }
|
.agent-email-context-reply { height:34px; padding:0 12px; display:inline-flex; align-items:center; gap:6px; border:1px solid #ddd4ff; border-radius:8px; background:#f6f2ff; color:#6d4aff; font-size:11px; font-weight:700; }
|
||||||
.agent-email-context-reply:hover { background:#ebe4ff; }
|
.agent-email-context-reply:hover { background:#ebe4ff; }
|
||||||
|
|
||||||
|
|
@ -886,11 +893,13 @@ body.compose-blank-open .mailbox-empty-cta { opacity:.42; filter:saturate(.55);
|
||||||
.mailbox-shell.detail-visible .mailbox-toolbar,
|
.mailbox-shell.detail-visible .mailbox-toolbar,
|
||||||
.mailbox-shell.detail-visible .mailbox-filters,
|
.mailbox-shell.detail-visible .mailbox-filters,
|
||||||
.mailbox-shell.detail-visible .mailbox-list-footer { display:none; }
|
.mailbox-shell.detail-visible .mailbox-list-footer { display:none; }
|
||||||
.mail-detail-content { padding:20px 18px 28px; }
|
.mail-detail-reader { border-radius:10px; }
|
||||||
.mail-detail-subject-row { flex-direction:column; }
|
.mail-detail-toolbar { padding:0 16px; }
|
||||||
.mail-detail-ai-chips { justify-content:flex-start; }
|
.mail-detail-reading-column { padding:20px 18px 0; }
|
||||||
.mail-detail-sender-row { flex-direction:column; }
|
.mail-detail-body,.mail-detail-attachments,.mail-detail-reply-bar { margin-left:0; padding-left:0; }
|
||||||
.mail-detail-sender-actions { width:100%; justify-content:flex-start; }
|
.mail-detail-reply-bar { margin:16px 18px 0; }
|
||||||
|
.mail-detail-sender-row { grid-template-columns:34px minmax(0,1fr); }
|
||||||
|
.mail-detail-sender-actions { grid-column:1/-1; justify-content:flex-start; }
|
||||||
.compose-dock { right:12px !important; bottom:12px; }
|
.compose-dock { right:12px !important; bottom:12px; }
|
||||||
.compose-window { width:min(calc(100vw - 24px),560px); min-width:0; max-width:none; height:min(560px,calc(100vh - 24px)); }
|
.compose-window { width:min(calc(100vw - 24px),560px); min-width:0; max-width:none; height:min(560px,calc(100vh - 24px)); }
|
||||||
.compose-window.expanded { width:calc(100vw - 24px); min-width:0; height:min(78vh,calc(100vh - 24px)); }
|
.compose-window.expanded { width:calc(100vw - 24px); min-width:0; height:min(78vh,calc(100vh - 24px)); }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue