split inbox

This commit is contained in:
Arjun 2026-05-13 19:51:00 +05:30
parent 5dd5a338e7
commit 98043ed82b
2 changed files with 69 additions and 35 deletions

View file

@ -215,6 +215,15 @@
letter-spacing: 0.08em;
}
.gmail-section {
display: flex;
flex-direction: column;
}
.gmail-section + .gmail-section {
margin-top: 28px;
}
.gmail-row {
display: grid;
grid-template-columns: 12px minmax(140px, 0.22fr) minmax(0, 1fr) 60px;

View file

@ -558,8 +558,51 @@ export function EmailView() {
})
}, [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 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 (
<div className="gmail-shell">
<div className="gmail-main">
@ -581,42 +624,24 @@ export function EmailView() {
<div className="gmail-empty-state">Could not load mail: {error}</div>
) : hasThreads ? (
<div className="gmail-list" aria-label="Recent emails">
<div className="gmail-list-header">
<span>Last 2 days</span>
<span>{filteredThreads.length} threads</span>
</div>
{filteredThreads.map((thread) => {
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}
/>
)}
{importantThreads.length > 0 && (
<section className="gmail-section">
<div className="gmail-list-header">
<span>Important</span>
<span>{importantThreads.length} thread{importantThreads.length === 1 ? '' : 's'}</span>
</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 className="gmail-empty-state">