horizontal expansion
parent
24f3c5df53
commit
63a0fbf857
|
|
@ -463,39 +463,39 @@ function BulkReadBar({ rows, selection, onSetRead, onSetAllRead, busy, canEdit,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="inbox-bulk-bar">
|
||||||
className="flex items-center gap-12"
|
|
||||||
style={{ padding: '10px 16px', borderBottom: '1px solid var(--border)', flexWrap: 'wrap' }}
|
|
||||||
>
|
|
||||||
<RowCheck
|
<RowCheck
|
||||||
checked={allSelected}
|
checked={allSelected}
|
||||||
onToggle={toggleAll}
|
onToggle={toggleAll}
|
||||||
label={allSelected ? 'Clear selection' : 'Select all'}
|
label={allSelected ? 'Clear selection' : 'Select all'}
|
||||||
/>
|
/>
|
||||||
<span className="text-muted text-sm">
|
<span className="inbox-bulk-count" title={n > 0
|
||||||
|
? `${n} selected`
|
||||||
|
: `${total} ${total === 1 ? 'message' : 'messages'}${unreadCount ? ` · ${unreadCount} unread` : ''}`}
|
||||||
|
>
|
||||||
{n > 0
|
{n > 0
|
||||||
? `${n} selected`
|
? `${n} selected`
|
||||||
: `${total} ${total === 1 ? 'message' : 'messages'}${unreadCount ? ` · ${unreadCount} unread` : ''}`}
|
: `${total}${unreadCount ? ` · ${unreadCount}` : ''}`}
|
||||||
</span>
|
</span>
|
||||||
<div className="flex gap-8" style={{ marginLeft: 'auto', flexWrap: 'wrap' }}>
|
<div className="inbox-bulk-actions">
|
||||||
{n > 0 ? (
|
{n > 0 ? (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
className="btn btn-secondary btn-sm"
|
className="btn btn-secondary btn-sm"
|
||||||
disabled={blocked || unreadCount === 0}
|
disabled={blocked || unreadCount === 0}
|
||||||
title={unreadCount === 0 ? nothingTo('read') : tip}
|
title={unreadCount === 0 ? nothingTo('read') : tip || 'Mark selected read'}
|
||||||
onClick={() => flashRead('selected', () => onSetRead(true))}
|
onClick={() => flashRead('selected', () => onSetRead(true))}
|
||||||
>
|
>
|
||||||
{ticked === 'selected' && <Icon name="check" />}
|
{ticked === 'selected' && <Icon name="check" />}
|
||||||
Mark read{unreadCount ? ` (${unreadCount})` : ''}
|
Read
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-secondary btn-sm"
|
className="btn btn-secondary btn-sm"
|
||||||
disabled={blocked || readCount === 0}
|
disabled={blocked || readCount === 0}
|
||||||
title={readCount === 0 ? nothingTo('unread') : tip}
|
title={readCount === 0 ? nothingTo('unread') : tip || 'Mark selected unread'}
|
||||||
onClick={() => onSetRead(false)}
|
onClick={() => onSetRead(false)}
|
||||||
>
|
>
|
||||||
<Icon name="mail" /> Mark unread{readCount ? ` (${readCount})` : ''}
|
Unread
|
||||||
</button>
|
</button>
|
||||||
<button className="btn btn-ghost btn-sm" onClick={clear}>Clear</button>
|
<button className="btn btn-ghost btn-sm" onClick={clear}>Clear</button>
|
||||||
</>
|
</>
|
||||||
|
|
@ -508,7 +508,7 @@ function BulkReadBar({ rows, selection, onSetRead, onSetAllRead, busy, canEdit,
|
||||||
onClick={() => flashRead('all', () => onSetAllRead(true))}
|
onClick={() => flashRead('all', () => onSetAllRead(true))}
|
||||||
>
|
>
|
||||||
{ticked === 'all' && <Icon name="check" />}
|
{ticked === 'all' && <Icon name="check" />}
|
||||||
Mark all read{unreadCount ? ` (${unreadCount})` : ''}
|
Read
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-secondary btn-sm"
|
className="btn btn-secondary btn-sm"
|
||||||
|
|
@ -516,7 +516,7 @@ function BulkReadBar({ rows, selection, onSetRead, onSetAllRead, busy, canEdit,
|
||||||
title={readCount === 0 ? nothingTo('unread') : scopeTip}
|
title={readCount === 0 ? nothingTo('unread') : scopeTip}
|
||||||
onClick={() => onSetAllRead(false)}
|
onClick={() => onSetAllRead(false)}
|
||||||
>
|
>
|
||||||
<Icon name="mail" /> Mark all unread{readCount ? ` (${readCount})` : ''}
|
Unread
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
@ -756,14 +756,8 @@ export default function Inbox() {
|
||||||
{tab === 'Email' ? (
|
{tab === 'Email' ? (
|
||||||
<EmailTab query={emailsQuery} toast={toast} />
|
<EmailTab query={emailsQuery} toast={toast} />
|
||||||
) : (
|
) : (
|
||||||
<div className="split">
|
<div className="split inbox-split">
|
||||||
<div className="split-list">
|
<div className="split-list inbox-queue">
|
||||||
<div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)' }}>
|
|
||||||
<div className="toolbar-search" style={{ maxWidth: 'none' }}>
|
|
||||||
<Icon name="search" />
|
|
||||||
<input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search applications…" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{applicationsQuery.isSuccess && (
|
{applicationsQuery.isSuccess && (
|
||||||
<BulkReadBar
|
<BulkReadBar
|
||||||
rows={list}
|
rows={list}
|
||||||
|
|
@ -775,6 +769,12 @@ export default function Inbox() {
|
||||||
scopeLabel={scopeLabel}
|
scopeLabel={scopeLabel}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<div style={{ padding: '12px 16px', borderBottom: '1px solid var(--border)' }}>
|
||||||
|
<div className="toolbar-search" style={{ maxWidth: 'none' }}>
|
||||||
|
<Icon name="search" />
|
||||||
|
<input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search applications…" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{applicationsQuery.isPending && (
|
{applicationsQuery.isPending && (
|
||||||
<EmptyState icon="inbox" title="Loading…">Fetching applications from the server.</EmptyState>
|
<EmptyState icon="inbox" title="Loading…">Fetching applications from the server.</EmptyState>
|
||||||
|
|
@ -1429,8 +1429,8 @@ function EmailTab({ query, toast }) {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="split">
|
<div className="split inbox-split">
|
||||||
<div className="split-list">
|
<div className="split-list inbox-queue">
|
||||||
{query.isSuccess && emails.length > 0 && (
|
{query.isSuccess && emails.length > 0 && (
|
||||||
<BulkReadBar
|
<BulkReadBar
|
||||||
rows={emails}
|
rows={emails}
|
||||||
|
|
|
||||||
|
|
@ -835,6 +835,46 @@ canvas { width: 100%; max-width: 100%; display: block; }
|
||||||
.ii-pos { font-size: 12.5px; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
.ii-pos { font-size: 12.5px; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||||
.ii-meta { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
|
.ii-meta { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
|
||||||
.ii-time { font-size: 11px; color: var(--text-3); white-space: nowrap; }
|
.ii-time { font-size: 11px; color: var(--text-3); white-space: nowrap; }
|
||||||
|
/* Inbox sidebar only: fit the list instead of scrolling sideways.
|
||||||
|
Username (.ii-name) and subject (.ii-pos) are left alone. */
|
||||||
|
.inbox-split { grid-template-columns: minmax(0, 380px) 1fr; }
|
||||||
|
.inbox-queue { overflow-x: hidden; min-width: 0; }
|
||||||
|
.inbox-queue .inbox-item { min-width: 0; }
|
||||||
|
.inbox-queue .ii-meta { flex-wrap: wrap; min-width: 0; }
|
||||||
|
.inbox-queue .source-chip {
|
||||||
|
min-width: 0; max-width: 100%;
|
||||||
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||||
|
}
|
||||||
|
.inbox-queue .toolbar-search { min-width: 0; }
|
||||||
|
.inbox-bulk-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
.inbox-bulk-count {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--text-3);
|
||||||
|
}
|
||||||
|
.inbox-bulk-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.inbox-bulk-actions .btn-sm {
|
||||||
|
padding: 5px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
/* `--chip` is the source's own brand colour, set inline. It tints the
|
/* `--chip` is the source's own brand colour, set inline. It tints the
|
||||||
background and fills the dot, while the label stays on theme text so
|
background and fills the dot, while the label stays on theme text so
|
||||||
11px copy keeps its contrast in both modes. */
|
11px copy keeps its contrast in both modes. */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue