feat(export): pin session table edge columns

This commit is contained in:
aits2026
2026-03-10 14:55:34 +08:00
parent 092450e4f8
commit fe1c8862e6
2 changed files with 118 additions and 44 deletions

View File

@@ -1722,9 +1722,12 @@
--contacts-default-visible-rows: 10;
--contacts-default-list-height: calc(var(--contacts-row-height) * var(--contacts-default-visible-rows));
--contacts-select-col-width: 34px;
--contacts-avatar-col-width: 44px;
--contacts-inline-padding: 12px;
--contacts-column-gap: 12px;
--contacts-name-text-width: 10em;
--contacts-main-col-width: calc(44px + 12px + var(--contacts-name-text-width));
--contacts-main-col-width: calc(var(--contacts-avatar-col-width) + var(--contacts-column-gap) + var(--contacts-name-text-width));
--contacts-left-sticky-width: calc(var(--contacts-select-col-width) + var(--contacts-main-col-width) + var(--contacts-column-gap));
--contacts-message-col-width: 120px;
--contacts-media-col-width: 72px;
--contacts-action-col-width: 140px;
@@ -1886,13 +1889,14 @@
}
.contacts-list-header {
--contacts-header-bg: color-mix(in srgb, var(--bg-secondary) 90%, var(--bg-primary));
display: flex;
align-items: center;
gap: 12px;
gap: var(--contacts-column-gap);
padding: 10px var(--contacts-inline-padding) 8px;
min-width: max(100%, var(--contacts-table-min-width));
border-bottom: 1px solid color-mix(in srgb, var(--border-color) 85%, transparent);
background: color-mix(in srgb, var(--bg-secondary) 90%, var(--bg-primary));
background: var(--contacts-header-bg);
font-size: 12px;
color: var(--text-tertiary);
font-weight: 600;
@@ -1909,6 +1913,30 @@
}
}
.contacts-list-header-left {
position: sticky;
left: 0;
z-index: 12;
display: flex;
align-items: center;
gap: var(--contacts-column-gap);
width: var(--contacts-left-sticky-width);
min-width: var(--contacts-left-sticky-width);
max-width: var(--contacts-left-sticky-width);
background: var(--contacts-header-bg);
&::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
right: calc(-1 * var(--contacts-column-gap));
width: var(--contacts-column-gap);
background: var(--contacts-header-bg);
pointer-events: none;
}
}
.contacts-list-header-select {
width: var(--contacts-select-col-width);
min-width: var(--contacts-select-col-width);
@@ -1974,8 +2002,8 @@
flex-shrink: 0;
position: sticky;
right: 0;
z-index: 8;
background: var(--bg-secondary);
z-index: 13;
background: var(--contacts-header-bg);
white-space: nowrap;
&::before {
@@ -1986,7 +2014,7 @@
left: -8px;
width: 8px;
pointer-events: none;
background: linear-gradient(to right, transparent, var(--bg-secondary));
background: linear-gradient(to right, transparent, var(--contacts-header-bg));
}
}
@@ -2110,14 +2138,16 @@
padding-bottom: 4px;
&.selected .contact-item {
background: rgba(var(--primary-rgb), 0.08);
--contacts-row-bg: rgba(var(--primary-rgb), 0.08);
background: var(--contacts-row-bg);
}
}
.contact-item {
--contacts-row-bg: var(--bg-secondary);
display: flex;
align-items: center;
gap: 12px;
gap: var(--contacts-column-gap);
padding: 12px 6px 12px var(--contacts-inline-padding);
min-width: max(100%, var(--contacts-table-min-width));
height: 72px;
@@ -2125,9 +2155,36 @@
border-radius: 10px;
transition: all 0.2s;
cursor: default;
background: var(--contacts-row-bg);
&:hover {
background: var(--bg-hover);
--contacts-row-bg: var(--bg-hover);
background: var(--contacts-row-bg);
}
}
.row-left-sticky {
position: sticky;
left: 0;
z-index: 11;
display: flex;
align-items: center;
align-self: stretch;
gap: var(--contacts-column-gap);
width: var(--contacts-left-sticky-width);
min-width: var(--contacts-left-sticky-width);
max-width: var(--contacts-left-sticky-width);
background: var(--contacts-row-bg);
&::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
right: calc(-1 * var(--contacts-column-gap));
width: var(--contacts-column-gap);
background: var(--contacts-row-bg);
pointer-events: none;
}
}
@@ -2496,6 +2553,8 @@
display: flex;
flex-direction: column;
align-items: flex-end;
justify-content: center;
align-self: stretch;
gap: 4px;
width: var(--contacts-action-col-width);
min-width: var(--contacts-action-col-width);
@@ -2503,7 +2562,18 @@
position: sticky;
right: 0;
z-index: 10;
background: transparent;
background: var(--contacts-row-bg);
&::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: -8px;
width: 8px;
pointer-events: none;
background: linear-gradient(to right, transparent, var(--contacts-row-bg));
}
.row-action-main {
display: inline-flex;

View File

@@ -5876,27 +5876,29 @@ function ExportPage() {
return (
<div className={`contact-row ${checked ? 'selected' : ''}`}>
<div className="contact-item">
<div className="row-select-cell">
<button
className={`select-icon-btn ${checked ? 'checked' : ''}`}
type="button"
disabled={!canExport}
onClick={() => toggleSelectSession(contact.username)}
title={canExport ? (checked ? '取消选择' : '选择会话') : '该联系人暂无会话记录'}
>
{checked ? <CheckSquare size={16} /> : <Square size={16} />}
</button>
</div>
<div className="contact-avatar">
{contact.avatarUrl ? (
<img src={contact.avatarUrl} alt="" loading="lazy" />
) : (
<span>{getAvatarLetter(contact.displayName)}</span>
)}
</div>
<div className="contact-info">
<div className="contact-name">{contact.displayName}</div>
<div className="contact-remark">{contact.alias || contact.username}</div>
<div className="row-left-sticky">
<div className="row-select-cell">
<button
className={`select-icon-btn ${checked ? 'checked' : ''}`}
type="button"
disabled={!canExport}
onClick={() => toggleSelectSession(contact.username)}
title={canExport ? (checked ? '取消选择' : '选择会话') : '该联系人暂无会话记录'}
>
{checked ? <CheckSquare size={16} /> : <Square size={16} />}
</button>
</div>
<div className="contact-avatar">
{contact.avatarUrl ? (
<img src={contact.avatarUrl} alt="" loading="lazy" />
) : (
<span>{getAvatarLetter(contact.displayName)}</span>
)}
</div>
<div className="contact-info">
<div className="contact-name">{contact.displayName}</div>
<div className="contact-remark">{contact.alias || contact.username}</div>
</div>
</div>
<div className="row-message-count">
<div className="row-message-stats">
@@ -6394,19 +6396,21 @@ function ExportPage() {
onPointerUp={handleContactsHeaderPointerUp}
onPointerCancel={handleContactsHeaderPointerCancel}
>
<span className="contacts-list-header-select">
<button
className={`select-icon-btn ${isAllVisibleSelected ? 'checked' : ''}`}
type="button"
onClick={toggleSelectAllVisible}
disabled={visibleSelectableCount === 0}
title={isAllVisibleSelected ? '取消全选当前筛选联系人' : '全选当前筛选联系人'}
>
{isAllVisibleSelected ? <CheckSquare size={16} /> : <Square size={16} />}
</button>
</span>
<span className="contacts-list-header-main">
<span className="contacts-list-header-main-label">{contactsHeaderMainLabel}</span>
<span className="contacts-list-header-left">
<span className="contacts-list-header-select">
<button
className={`select-icon-btn ${isAllVisibleSelected ? 'checked' : ''}`}
type="button"
onClick={toggleSelectAllVisible}
disabled={visibleSelectableCount === 0}
title={isAllVisibleSelected ? '取消全选当前筛选联系人' : '全选当前筛选联系人'}
>
{isAllVisibleSelected ? <CheckSquare size={16} /> : <Square size={16} />}
</button>
</span>
<span className="contacts-list-header-main">
<span className="contacts-list-header-main-label">{contactsHeaderMainLabel}</span>
</span>
</span>
<span className="contacts-list-header-count"></span>
<span className="contacts-list-header-media"></span>