fix sidebar auto scroll on list update

This commit is contained in:
pa
2026-01-21 00:06:11 +09:00
committed by Natsumi
parent f8daa6ff4c
commit 81acfa8734
4 changed files with 82 additions and 5 deletions

View File

@@ -150,7 +150,7 @@
size="icon-lg"
style="margin-left: 5px"
@click="clearGroupRepresentation(groupDialog.id)">
<Star />
<BookmarkCheck />
</Button>
</TooltipWrapper>
<TooltipWrapper v-else side="top" :content="t('dialog.group.actions.represent_tooltip')">
@@ -161,7 +161,7 @@
size="icon-lg"
:disabled="groupDialog.ref.privacy === 'private'"
@click="setGroupRepresentation(groupDialog.id)">
<Star />
<Bookmark />
</Button>
</span>
</TooltipWrapper>
@@ -1117,6 +1117,8 @@
import {
Bell,
BellOff,
Bookmark,
BookmarkCheck,
Check,
CheckCircle,
Copy,
@@ -1128,7 +1130,6 @@
RefreshCw,
Settings,
Share2,
Star,
Tag,
Ticket,
Trash2,

View File

@@ -0,0 +1,62 @@
import { nextTick } from 'vue';
export function useVirtualizerAnchor({
virtualizer,
virtualRows,
scrollViewportRef
}) {
const captureScrollAnchor = () => {
const viewport = scrollViewportRef.value;
const items = virtualizer.value?.getVirtualItems?.() ?? [];
if (!viewport || !items.length) {
return null;
}
const firstItem = items[0];
const row = virtualRows.value[firstItem.index];
const key = row?.key ?? firstItem.key;
if (typeof key === 'undefined') {
return null;
}
return {
key,
offset: viewport.scrollTop - firstItem.start
};
};
const restoreScrollAnchor = (anchor) => {
if (!anchor) {
return;
}
const index = virtualRows.value.findIndex(
(row) => row?.key === anchor.key
);
if (index === -1) {
return;
}
const offsetInfo = virtualizer.value?.getOffsetForIndex?.(
index,
'start'
);
const targetStart = Array.isArray(offsetInfo) ? offsetInfo[0] : null;
if (typeof targetStart !== 'number') {
return;
}
virtualizer.value?.scrollToOffset?.(targetStart + anchor.offset);
};
const measureWithAnchor = (measureFn) => {
const anchor = captureScrollAnchor();
nextTick(() => {
if (measureFn) {
measureFn();
}
restoreScrollAnchor(anchor);
});
};
return {
captureScrollAnchor,
restoreScrollAnchor,
measureWithAnchor
};
}

View File

@@ -99,6 +99,7 @@
} from '../../../stores';
import { isRealInstance, userImage, userStatusClass } from '../../../shared/utils';
import { getFriendsLocations } from '../../../shared/utils/location.js';
import { useVirtualizerAnchor } from '../../../composables/useVirtualizerAnchor';
import FriendItem from './FriendItem.vue';
import Location from '../../../components/Location.vue';
@@ -422,6 +423,12 @@
};
};
const { measureWithAnchor } = useVirtualizerAnchor({
virtualizer,
virtualRows,
scrollViewportRef
});
function saveFriendsGroupStates() {
configRepository.setBool('VRCX_isFriendsGroupMe', isFriendsGroupMe.value);
configRepository.setBool('VRCX_isFriendsGroupFavorites', isVIPFriends.value);
@@ -482,7 +489,7 @@
});
watch(virtualRows, () => {
nextTick(() => {
measureWithAnchor(() => {
virtualizer.value?.measure?.();
});
});

View File

@@ -56,6 +56,7 @@
import { useAppearanceSettingsStore, useGroupStore } from '../../../stores';
import { convertFileUrlToImageUrl } from '../../../shared/utils';
import { useVirtualizerAnchor } from '../../../composables/useVirtualizerAnchor';
import Location from '../../../components/Location.vue';
@@ -168,6 +169,12 @@
transform: `translateY(${item.virtualItem.start}px)`
});
const { measureWithAnchor } = useVirtualizerAnchor({
virtualizer,
virtualRows,
scrollViewportRef
});
function getSmallGroupIconUrl(url) {
return convertFileUrlToImageUrl(url);
}
@@ -188,7 +195,7 @@
});
watch(virtualRows, () => {
nextTick(() => {
measureWithAnchor(() => {
virtualizer.value?.measure?.();
});
});