fix(export): keep session row actions sticky in viewport

This commit is contained in:
aits2026
2026-03-06 19:47:49 +08:00
parent 95d0937015
commit 3b3fd8b35c
2 changed files with 26 additions and 2 deletions

View File

@@ -2480,11 +2480,13 @@
align-items: flex-end; align-items: flex-end;
gap: 4px; gap: 4px;
width: var(--contacts-action-col-width); width: var(--contacts-action-col-width);
min-width: var(--contacts-action-col-width);
flex-shrink: 0; flex-shrink: 0;
position: sticky; position: sticky;
right: 0; right: 0;
z-index: 6; z-index: 10;
background: var(--bg-primary); background: var(--bg-primary);
will-change: transform;
&::before { &::before {
content: ''; content: '';

View File

@@ -1513,6 +1513,7 @@ function ExportPage() {
const [nowTick, setNowTick] = useState(Date.now()) const [nowTick, setNowTick] = useState(Date.now())
const [isContactsListAtTop, setIsContactsListAtTop] = useState(true) const [isContactsListAtTop, setIsContactsListAtTop] = useState(true)
const [isContactsHeaderDragging, setIsContactsHeaderDragging] = useState(false) const [isContactsHeaderDragging, setIsContactsHeaderDragging] = useState(false)
const [contactsHorizontalScrollLeft, setContactsHorizontalScrollLeft] = useState(0)
const [contactsHorizontalScrollMetrics, setContactsHorizontalScrollMetrics] = useState({ const [contactsHorizontalScrollMetrics, setContactsHorizontalScrollMetrics] = useState({
viewportWidth: 0, viewportWidth: 0,
contentWidth: 0 contentWidth: 0
@@ -5632,6 +5633,19 @@ function ExportPage() {
const contactsBottomScrollbarInnerStyle = useMemo<CSSProperties>(() => ({ const contactsBottomScrollbarInnerStyle = useMemo<CSSProperties>(() => ({
width: `${Math.max(contactsHorizontalScrollMetrics.contentWidth, contactsHorizontalScrollMetrics.viewportWidth)}px` width: `${Math.max(contactsHorizontalScrollMetrics.contentWidth, contactsHorizontalScrollMetrics.viewportWidth)}px`
}), [contactsHorizontalScrollMetrics.contentWidth, contactsHorizontalScrollMetrics.viewportWidth]) }), [contactsHorizontalScrollMetrics.contentWidth, contactsHorizontalScrollMetrics.viewportWidth])
const contactsActionStickyStyle = useMemo<CSSProperties>(() => {
const maxScrollLeft = Math.max(0, contactsHorizontalScrollMetrics.contentWidth - contactsHorizontalScrollMetrics.viewportWidth)
if (maxScrollLeft <= 0) return {}
const compensatedTranslateX = Math.min(0, contactsHorizontalScrollLeft - maxScrollLeft)
return Math.abs(compensatedTranslateX) > 0.5
? { transform: `translateX(${compensatedTranslateX}px)` }
: {}
}, [
contactsHorizontalScrollLeft,
contactsHorizontalScrollMetrics.contentWidth,
contactsHorizontalScrollMetrics.viewportWidth
])
const nonExportBackgroundTasks = useMemo(() => ( const nonExportBackgroundTasks = useMemo(() => (
backgroundTasks.filter(task => task.sourcePage !== 'export') backgroundTasks.filter(task => task.sourcePage !== 'export')
), [backgroundTasks]) ), [backgroundTasks])
@@ -5687,6 +5701,10 @@ function ExportPage() {
bottomScrollbar.scrollLeft = scrollLeft bottomScrollbar.scrollLeft = scrollLeft
} }
setContactsHorizontalScrollLeft(prev => (
Math.abs(prev - scrollLeft) > 1 ? scrollLeft : prev
))
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
if (contactsScrollSyncSourceRef.current === source) { if (contactsScrollSyncSourceRef.current === source) {
contactsScrollSyncSourceRef.current = null contactsScrollSyncSourceRef.current = null
@@ -5774,6 +5792,9 @@ function ExportPage() {
if (Math.abs(viewport.scrollLeft - clampedScrollLeft) > 1) { if (Math.abs(viewport.scrollLeft - clampedScrollLeft) > 1) {
viewport.scrollLeft = clampedScrollLeft viewport.scrollLeft = clampedScrollLeft
} }
setContactsHorizontalScrollLeft(prev => (
Math.abs(prev - clampedScrollLeft) > 1 ? clampedScrollLeft : prev
))
const bottomScrollbar = contactsBottomScrollbarRef.current const bottomScrollbar = contactsBottomScrollbarRef.current
if (bottomScrollbar) { if (bottomScrollbar) {
@@ -5995,7 +6016,7 @@ function ExportPage() {
)} )}
</div> </div>
)} )}
<div className="row-action-cell"> <div className="row-action-cell" style={contactsActionStickyStyle}>
<div className={`row-action-main ${hasRecentExport ? '' : 'single-line'}`.trim()}> <div className={`row-action-main ${hasRecentExport ? '' : 'single-line'}`.trim()}>
<div className={`row-export-action-stack ${hasRecentExport ? '' : 'single-line'}`.trim()}> <div className={`row-export-action-stack ${hasRecentExport ? '' : 'single-line'}`.trim()}>
<button <button
@@ -6044,6 +6065,7 @@ function ExportPage() {
isLoading, isLoading,
isSessionEnriching, isSessionEnriching,
showSessionDetailPanel, showSessionDetailPanel,
contactsActionStickyStyle,
shouldShowMutualFriendsColumn, shouldShowMutualFriendsColumn,
shouldShowSnsColumn, shouldShowSnsColumn,
snsUserPostCounts, snsUserPostCounts,