mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-06-15 20:05:16 +02:00
split inbox
This commit is contained in:
parent
83b54feb0c
commit
375d8bf2e0
2 changed files with 69 additions and 35 deletions
|
|
@ -215,6 +215,15 @@
|
||||||
letter-spacing: 0.08em;
|
letter-spacing: 0.08em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gmail-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gmail-section + .gmail-section {
|
||||||
|
margin-top: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
.gmail-row {
|
.gmail-row {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 12px minmax(140px, 0.22fr) minmax(0, 1fr) 60px;
|
grid-template-columns: 12px minmax(140px, 0.22fr) minmax(0, 1fr) 60px;
|
||||||
|
|
|
||||||
|
|
@ -558,8 +558,51 @@ export function EmailView() {
|
||||||
})
|
})
|
||||||
}, [query, threads])
|
}, [query, threads])
|
||||||
|
|
||||||
|
const { importantThreads, otherThreads } = useMemo(() => {
|
||||||
|
const important: GmailThread[] = []
|
||||||
|
const other: GmailThread[] = []
|
||||||
|
for (const thread of filteredThreads) {
|
||||||
|
if (thread.messages.length > 1) important.push(thread)
|
||||||
|
else other.push(thread)
|
||||||
|
}
|
||||||
|
return { importantThreads: important, otherThreads: other }
|
||||||
|
}, [filteredThreads])
|
||||||
|
|
||||||
const hasThreads = filteredThreads.length > 0
|
const hasThreads = filteredThreads.length > 0
|
||||||
|
|
||||||
|
const renderRow = (thread: GmailThread) => {
|
||||||
|
const latest = latestMessage(thread)
|
||||||
|
const isSelected = thread.threadId === selectedThreadId
|
||||||
|
const isUnread = thread.unread === true
|
||||||
|
const isMounted = openedThreadIds.includes(thread.threadId)
|
||||||
|
return (
|
||||||
|
<div key={thread.threadId} className="gmail-row-group">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={cn('gmail-row', isSelected && 'gmail-row-selected', isUnread && 'gmail-row-unread')}
|
||||||
|
onClick={() => toggleThread(thread.threadId)}
|
||||||
|
onMouseEnter={() => scheduleHoverPrefetch(thread)}
|
||||||
|
onMouseLeave={cancelHoverPrefetch}
|
||||||
|
>
|
||||||
|
<span className="gmail-row-dot" aria-hidden />
|
||||||
|
<span className="gmail-row-sender">{extractName(latest?.from || thread.from)}</span>
|
||||||
|
<span className="gmail-row-content">
|
||||||
|
<strong>{thread.subject || '(No subject)'}</strong>
|
||||||
|
<span>{snippet(latest?.body || thread.latest_email)}</span>
|
||||||
|
</span>
|
||||||
|
<span className="gmail-row-date">{formatInboxTime(latest?.date || thread.date)}</span>
|
||||||
|
</button>
|
||||||
|
{isMounted && (
|
||||||
|
<ThreadDetail
|
||||||
|
thread={thread}
|
||||||
|
onClose={() => setSelectedThreadId(null)}
|
||||||
|
hidden={!isSelected}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="gmail-shell">
|
<div className="gmail-shell">
|
||||||
<div className="gmail-main">
|
<div className="gmail-main">
|
||||||
|
|
@ -581,42 +624,24 @@ export function EmailView() {
|
||||||
<div className="gmail-empty-state">Could not load mail: {error}</div>
|
<div className="gmail-empty-state">Could not load mail: {error}</div>
|
||||||
) : hasThreads ? (
|
) : hasThreads ? (
|
||||||
<div className="gmail-list" aria-label="Recent emails">
|
<div className="gmail-list" aria-label="Recent emails">
|
||||||
<div className="gmail-list-header">
|
{importantThreads.length > 0 && (
|
||||||
<span>Last 2 days</span>
|
<section className="gmail-section">
|
||||||
<span>{filteredThreads.length} threads</span>
|
<div className="gmail-list-header">
|
||||||
</div>
|
<span>Important</span>
|
||||||
{filteredThreads.map((thread) => {
|
<span>{importantThreads.length} thread{importantThreads.length === 1 ? '' : 's'}</span>
|
||||||
const latest = latestMessage(thread)
|
|
||||||
const isSelected = thread.threadId === selectedThreadId
|
|
||||||
const isUnread = thread.unread === true
|
|
||||||
const isMounted = openedThreadIds.includes(thread.threadId)
|
|
||||||
return (
|
|
||||||
<div key={thread.threadId} className="gmail-row-group">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={cn('gmail-row', isSelected && 'gmail-row-selected', isUnread && 'gmail-row-unread')}
|
|
||||||
onClick={() => toggleThread(thread.threadId)}
|
|
||||||
onMouseEnter={() => scheduleHoverPrefetch(thread)}
|
|
||||||
onMouseLeave={cancelHoverPrefetch}
|
|
||||||
>
|
|
||||||
<span className="gmail-row-dot" aria-hidden />
|
|
||||||
<span className="gmail-row-sender">{extractName(latest?.from || thread.from)}</span>
|
|
||||||
<span className="gmail-row-content">
|
|
||||||
<strong>{thread.subject || '(No subject)'}</strong>
|
|
||||||
<span>{snippet(latest?.body || thread.latest_email)}</span>
|
|
||||||
</span>
|
|
||||||
<span className="gmail-row-date">{formatInboxTime(latest?.date || thread.date)}</span>
|
|
||||||
</button>
|
|
||||||
{isMounted && (
|
|
||||||
<ThreadDetail
|
|
||||||
thread={thread}
|
|
||||||
onClose={() => setSelectedThreadId(null)}
|
|
||||||
hidden={!isSelected}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
{importantThreads.map(renderRow)}
|
||||||
})}
|
</section>
|
||||||
|
)}
|
||||||
|
{otherThreads.length > 0 && (
|
||||||
|
<section className="gmail-section">
|
||||||
|
<div className="gmail-list-header">
|
||||||
|
<span>Everything else</span>
|
||||||
|
<span>{otherThreads.length} thread{otherThreads.length === 1 ? '' : 's'}</span>
|
||||||
|
</div>
|
||||||
|
{otherThreads.map(renderRow)}
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="gmail-empty-state">
|
<div className="gmail-empty-state">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue