mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-03-15 17:53:44 +08:00
239 lines
7 KiB
JavaScript
239 lines
7 KiB
JavaScript
const React = require('react');
|
|
const {
|
|
ListTabular,
|
|
RetinaImg,
|
|
MailLabelSet,
|
|
MailImportantIcon,
|
|
InjectedComponent,
|
|
InjectedComponentSet,
|
|
} = require('mailspring-component-kit');
|
|
|
|
const { FocusedPerspectiveStore, Utils, DateUtils } = require('mailspring-exports');
|
|
|
|
const { ThreadArchiveQuickAction, ThreadTrashQuickAction } = require('./thread-list-quick-actions');
|
|
const ThreadListParticipants = require('./thread-list-participants');
|
|
const ThreadListIcon = require('./thread-list-icon');
|
|
|
|
// Get and format either last sent or last received timestamp depending on thread-list being viewed
|
|
const ThreadListTimestamp = function({ thread }) {
|
|
let rawTimestamp = FocusedPerspectiveStore.current().isSent()
|
|
? thread.lastMessageSentTimestamp
|
|
: thread.lastMessageReceivedTimestamp;
|
|
const timestamp = DateUtils.shortTimeString(rawTimestamp);
|
|
return <span className="timestamp">{timestamp}</span>;
|
|
};
|
|
|
|
ThreadListTimestamp.containerRequired = false;
|
|
|
|
const subject = function(subj) {
|
|
if ((subj || '').trim().length === 0) {
|
|
return <span className="no-subject">(No Subject)</span>;
|
|
} else if (subj.split(/([\uD800-\uDBFF][\uDC00-\uDFFF])/g).length > 1) {
|
|
const subjComponents = [];
|
|
const subjParts = subj.split(/([\uD800-\uDBFF][\uDC00-\uDFFF])/g);
|
|
for (let idx = 0; idx < subjParts.length; idx++) {
|
|
const part = subjParts[idx];
|
|
if (part.match(/([\uD800-\uDBFF][\uDC00-\uDFFF])/g)) {
|
|
subjComponents.push(
|
|
<span className="emoji" key={idx}>
|
|
{part}
|
|
</span>
|
|
);
|
|
} else {
|
|
subjComponents.push(<span key={idx}>{part}</span>);
|
|
}
|
|
}
|
|
return subjComponents;
|
|
} else {
|
|
return subj;
|
|
}
|
|
};
|
|
|
|
const getSnippet = function(thread) {
|
|
const messages = thread.__messages || [];
|
|
if (messages.length === 0) {
|
|
return thread.snippet;
|
|
}
|
|
for (let ii = messages.length - 1; ii >= 0; ii--) {
|
|
if (messages[ii].snippet) return messages[ii].snippet;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
const c1 = new ListTabular.Column({
|
|
name: '★',
|
|
resolver: thread => {
|
|
return [
|
|
<ThreadListIcon key="thread-list-icon" thread={thread} />,
|
|
<MailImportantIcon
|
|
key="mail-important-icon"
|
|
thread={thread}
|
|
showIfAvailableForAnyAccount={true}
|
|
/>,
|
|
<InjectedComponentSet
|
|
key="injected-component-set"
|
|
inline={true}
|
|
containersRequired={false}
|
|
matching={{ role: 'ThreadListIcon' }}
|
|
className="thread-injected-icons"
|
|
exposedProps={{ thread: thread }}
|
|
/>,
|
|
];
|
|
},
|
|
});
|
|
|
|
const c2 = new ListTabular.Column({
|
|
name: 'Participants',
|
|
width: 200,
|
|
resolver: thread => {
|
|
const hasDraft = (thread.__messages || []).find(m => m.draft);
|
|
if (hasDraft) {
|
|
return (
|
|
<div style={{ display: 'flex' }}>
|
|
<ThreadListParticipants thread={thread} />
|
|
<RetinaImg
|
|
name="icon-draft-pencil.png"
|
|
className="draft-icon"
|
|
mode={RetinaImg.Mode.ContentPreserve}
|
|
/>
|
|
</div>
|
|
);
|
|
} else {
|
|
return <ThreadListParticipants thread={thread} />;
|
|
}
|
|
},
|
|
});
|
|
|
|
const c3 = new ListTabular.Column({
|
|
name: 'Message',
|
|
flex: 4,
|
|
resolver: thread => {
|
|
let attachment = false;
|
|
const messages = thread.__messages || [];
|
|
|
|
const hasAttachments =
|
|
thread.attachmentCount > 0 && messages.find(m => Utils.showIconForAttachments(m.files));
|
|
if (hasAttachments) {
|
|
attachment = <div className="thread-icon thread-icon-attachment" />;
|
|
}
|
|
|
|
return (
|
|
<span className="details">
|
|
<MailLabelSet thread={thread} />
|
|
<span className="subject">{subject(thread.subject)}</span>
|
|
<span className="snippet">{getSnippet(thread)}</span>
|
|
{attachment}
|
|
</span>
|
|
);
|
|
},
|
|
});
|
|
|
|
const c4 = new ListTabular.Column({
|
|
name: 'Date',
|
|
resolver: thread => {
|
|
return (
|
|
<InjectedComponent
|
|
className="thread-injected-timestamp"
|
|
fallback={ThreadListTimestamp}
|
|
exposedProps={{ thread: thread }}
|
|
matching={{ role: 'ThreadListTimestamp' }}
|
|
/>
|
|
);
|
|
},
|
|
});
|
|
|
|
const c5 = new ListTabular.Column({
|
|
name: 'HoverActions',
|
|
resolver: thread => {
|
|
return (
|
|
<div className="inner">
|
|
<InjectedComponentSet
|
|
key="injected-component-set"
|
|
inline={true}
|
|
containersRequired={false}
|
|
children={[
|
|
<ThreadTrashQuickAction key="thread-trash-quick-action" thread={thread} />,
|
|
<ThreadArchiveQuickAction key="thread-archive-quick-action" thread={thread} />,
|
|
]}
|
|
matching={{ role: 'ThreadListQuickAction' }}
|
|
className="thread-injected-quick-actions"
|
|
exposedProps={{ thread: thread }}
|
|
/>
|
|
</div>
|
|
);
|
|
},
|
|
});
|
|
|
|
const cNarrow = new ListTabular.Column({
|
|
name: 'Item',
|
|
flex: 1,
|
|
resolver: thread => {
|
|
let pencil = false;
|
|
let attachment = false;
|
|
const messages = thread.__messages || [];
|
|
|
|
const hasAttachments =
|
|
thread.attachmentCount > 0 && messages.find(m => Utils.showIconForAttachments(m.files));
|
|
if (hasAttachments) {
|
|
attachment = <div className="thread-icon thread-icon-attachment" />;
|
|
}
|
|
|
|
const hasDraft = messages.find(m => m.draft);
|
|
if (hasDraft) {
|
|
pencil = (
|
|
<RetinaImg
|
|
name="icon-draft-pencil.png"
|
|
className="draft-icon"
|
|
mode={RetinaImg.Mode.ContentPreserve}
|
|
/>
|
|
);
|
|
}
|
|
|
|
// TODO We are limiting the amount on injected icons in narrow mode to 1
|
|
// until we revisit the UI to accommodate more icons
|
|
return (
|
|
<div style={{ display: 'flex', alignItems: 'flex-start' }}>
|
|
<div className="icons-column">
|
|
<ThreadListIcon thread={thread} />
|
|
<InjectedComponentSet
|
|
inline={true}
|
|
matchLimit={1}
|
|
direction="column"
|
|
containersRequired={false}
|
|
key="injected-component-set"
|
|
exposedProps={{ thread: thread }}
|
|
matching={{ role: 'ThreadListIcon' }}
|
|
className="thread-injected-icons"
|
|
/>
|
|
<MailImportantIcon thread={thread} showIfAvailableForAnyAccount={true} />
|
|
</div>
|
|
<div className="thread-info-column">
|
|
<div className="participants-wrapper">
|
|
<ThreadListParticipants thread={thread} />
|
|
{pencil}
|
|
<span style={{ flex: 1 }} />
|
|
{attachment}
|
|
<InjectedComponent
|
|
key="thread-injected-timestamp"
|
|
className="thread-injected-timestamp"
|
|
fallback={ThreadListTimestamp}
|
|
exposedProps={{ thread: thread }}
|
|
matching={{ role: 'ThreadListTimestamp' }}
|
|
/>
|
|
</div>
|
|
<div className="subject">{subject(thread.subject)}</div>
|
|
<div className="snippet-and-labels">
|
|
<div className="snippet">{getSnippet(thread)} </div>
|
|
<div style={{ flex: 1, flexShrink: 1 }} />
|
|
<MailLabelSet thread={thread} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
},
|
|
});
|
|
|
|
module.exports = {
|
|
Narrow: [cNarrow],
|
|
Wide: [c1, c2, c3, c4, c5],
|
|
};
|