mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-07 14:56:06 +02:00
Remove the ScrollArea from the sidebar
This commit is contained in:
@@ -95,16 +95,12 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #friends>
|
<template #friends>
|
||||||
<div class="h-full overflow-hidden">
|
<div class="h-full overflow-hidden">
|
||||||
<ScrollArea class="h-full">
|
<FriendsSidebar />
|
||||||
<FriendsSidebar />
|
|
||||||
</ScrollArea>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #groups>
|
<template #groups>
|
||||||
<div class="h-full overflow-hidden">
|
<div class="h-full overflow-hidden">
|
||||||
<ScrollArea class="h-full">
|
<GroupsSidebar />
|
||||||
<GroupsSidebar />
|
|
||||||
</ScrollArea>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</TabsUnderline>
|
</TabsUnderline>
|
||||||
@@ -118,7 +114,6 @@
|
|||||||
import { DataTableEmpty } from '@/components/ui/data-table';
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { RefreshCw } from 'lucide-vue-next';
|
import { RefreshCw } from 'lucide-vue-next';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { TabsUnderline } from '@/components/ui/tabs';
|
import { TabsUnderline } from '@/components/ui/tabs';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|||||||
@@ -1,83 +1,88 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="listRootRef" class="x-friend-list" style="padding: 10px 5px">
|
<div ref="scrollRootRef" class="relative h-full">
|
||||||
<div v-if="virtualRows.length" class="friend-sidebar__virtual" :style="virtualContainerStyle">
|
<div ref="scrollViewportRef" class="h-full w-full overflow-auto">
|
||||||
<template v-for="item in virtualItems" :key="String(item.virtualItem.key)">
|
<div class="x-friend-list px-1.5 py-2.5">
|
||||||
<div
|
<div v-if="virtualRows.length" class="relative w-full box-border" :style="virtualContainerStyle">
|
||||||
v-if="item.row"
|
<template v-for="item in virtualItems" :key="String(item.virtualItem.key)">
|
||||||
class="friend-sidebar__virtual-row"
|
|
||||||
:class="`friend-sidebar__virtual-row--${item.row.type}`"
|
|
||||||
:data-index="item.virtualItem.index"
|
|
||||||
:ref="virtualizer.measureElement"
|
|
||||||
:style="rowStyle(item)">
|
|
||||||
<template v-if="item.row.type === 'toggle-header'">
|
|
||||||
<div
|
<div
|
||||||
class="x-friend-group cursor-pointer flex items-center"
|
v-if="item.row"
|
||||||
:style="item.row.headerPadding ? { padding: item.row.headerPadding } : undefined"
|
class="absolute left-0 top-0 w-full box-border"
|
||||||
@click="item.row.onClick && item.row.onClick()">
|
:data-index="item.virtualItem.index"
|
||||||
<ChevronDown class="rotation-transition" :class="{ 'is-rotated': !item.row.expanded }" />
|
:ref="virtualizer.measureElement"
|
||||||
<span style="margin-left: 5px">
|
:style="rowStyle(item)">
|
||||||
{{ item.row.label }}
|
<template v-if="item.row.type === 'toggle-header'">
|
||||||
<template v-if="item.row.count !== null && item.row.count !== undefined">
|
<div
|
||||||
― {{ item.row.count }}
|
class="x-friend-group flex cursor-pointer items-center pt-4 pb-1.5 text-xs"
|
||||||
</template>
|
:style="item.row.headerPadding ? { padding: item.row.headerPadding } : undefined"
|
||||||
</span>
|
@click="item.row.onClick && item.row.onClick()">
|
||||||
|
<ChevronDown
|
||||||
|
class="transition-transform duration-200 ease-in-out"
|
||||||
|
:class="{ '-rotate-90': !item.row.expanded }" />
|
||||||
|
<span class="ml-1.5">
|
||||||
|
{{ item.row.label }}
|
||||||
|
<template v-if="item.row.count !== null && item.row.count !== undefined">
|
||||||
|
― {{ item.row.count }}
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="item.row.type === 'me-item'">
|
||||||
|
<div class="x-friend-item" @click="showUserDialog(currentUser.id)">
|
||||||
|
<div class="avatar" :class="userStatusClass(currentUser)">
|
||||||
|
<img :src="userImage(currentUser)" loading="lazy" />
|
||||||
|
</div>
|
||||||
|
<div class="detail h-9 flex flex-col justify-between">
|
||||||
|
<span class="name" :style="{ color: currentUser.$userColour }">{{
|
||||||
|
currentUser.displayName
|
||||||
|
}}</span>
|
||||||
|
<Location
|
||||||
|
v-if="isGameRunning && !gameLogDisabled"
|
||||||
|
class="extra block truncate text-xs"
|
||||||
|
:location="lastLocation.location"
|
||||||
|
:traveling="lastLocationDestination"
|
||||||
|
:link="false" />
|
||||||
|
<Location
|
||||||
|
v-else-if="
|
||||||
|
isRealInstance(currentUser.$locationTag) ||
|
||||||
|
isRealInstance(currentUser.$travelingToLocation)
|
||||||
|
"
|
||||||
|
class="extra block truncate text-xs"
|
||||||
|
:location="currentUser.$locationTag"
|
||||||
|
:traveling="currentUser.$travelingToLocation"
|
||||||
|
:link="false" />
|
||||||
|
|
||||||
|
<span v-else class="extra block truncate text-xs">{{
|
||||||
|
currentUser.statusDescription
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="item.row.type === 'vip-subheader'">
|
||||||
|
<div>
|
||||||
|
<span class="text-xs">{{ item.row.label }}</span>
|
||||||
|
<span class="text-xs ml-1.5">{{ `(${item.row.count})` }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="item.row.type === 'instance-header'">
|
||||||
|
<div class="mb-1 flex items-center">
|
||||||
|
<Location class="inline text-xs" :location="item.row.location" />
|
||||||
|
<span class="text-xs ml-1.5">{{ `(${item.row.count})` }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="item.row.type === 'friend-item'">
|
||||||
|
<friend-item
|
||||||
|
:friend="item.row.friend"
|
||||||
|
:style="item.row.itemStyle"
|
||||||
|
:is-group-by-instance="item.row.isGroupByInstance" />
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="item.row.type === 'me-item'">
|
|
||||||
<div class="x-friend-item" @click="showUserDialog(currentUser.id)">
|
|
||||||
<div class="avatar" :class="userStatusClass(currentUser)">
|
|
||||||
<img :src="userImage(currentUser)" loading="lazy" />
|
|
||||||
</div>
|
|
||||||
<div class="detail h-9 flex flex-col justify-between">
|
|
||||||
<span class="name" :style="{ color: currentUser.$userColour }">{{
|
|
||||||
currentUser.displayName
|
|
||||||
}}</span>
|
|
||||||
<Location
|
|
||||||
v-if="isGameRunning && !gameLogDisabled"
|
|
||||||
class="extra block truncate text-xs"
|
|
||||||
:location="lastLocation.location"
|
|
||||||
:traveling="lastLocationDestination"
|
|
||||||
:link="false" />
|
|
||||||
<Location
|
|
||||||
v-else-if="
|
|
||||||
isRealInstance(currentUser.$locationTag) ||
|
|
||||||
isRealInstance(currentUser.$travelingToLocation)
|
|
||||||
"
|
|
||||||
class="extra block truncate text-xs"
|
|
||||||
:location="currentUser.$locationTag"
|
|
||||||
:traveling="currentUser.$travelingToLocation"
|
|
||||||
:link="false" />
|
|
||||||
|
|
||||||
<span v-else class="extra block truncate text-xs">{{
|
|
||||||
currentUser.statusDescription
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-else-if="item.row.type === 'vip-subheader'">
|
|
||||||
<div>
|
|
||||||
<span class="text-xs">{{ item.row.label }}</span>
|
|
||||||
<span class="text-xs" style="margin-left: 5px">{{ `(${item.row.count})` }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-else-if="item.row.type === 'instance-header'">
|
|
||||||
<div class="mb-1 flex items-center">
|
|
||||||
<Location class="text-xs" :location="item.row.location" style="display: inline" />
|
|
||||||
<span class="text-xs" style="margin-left: 5px">{{ `(${item.row.count})` }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-else-if="item.row.type === 'friend-item'">
|
|
||||||
<friend-item
|
|
||||||
:friend="item.row.friend"
|
|
||||||
:style="item.row.itemStyle"
|
|
||||||
:is-group-by-instance="item.row.isGroupByInstance" />
|
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<BackToTopVirtual :virtualizer="virtualizer" :target="scrollViewportRef" :teleport-to="scrollRootRef" />
|
<BackToTopVirtual :virtualizer="virtualizer" :target="scrollViewportRef" :teleport-to="scrollRootRef" />
|
||||||
</div>
|
</div>
|
||||||
@@ -127,7 +132,6 @@
|
|||||||
const isActiveFriends = ref(true);
|
const isActiveFriends = ref(true);
|
||||||
const isOfflineFriends = ref(true);
|
const isOfflineFriends = ref(true);
|
||||||
const isSidebarGroupByInstanceCollapsed = ref(false);
|
const isSidebarGroupByInstanceCollapsed = ref(false);
|
||||||
const listRootRef = ref(null);
|
|
||||||
const scrollViewportRef = ref(null);
|
const scrollViewportRef = ref(null);
|
||||||
const scrollRootRef = ref(null);
|
const scrollRootRef = ref(null);
|
||||||
|
|
||||||
@@ -476,8 +480,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
scrollViewportRef.value = listRootRef.value?.closest('[data-slot="scroll-area-viewport"]') ?? null;
|
|
||||||
scrollRootRef.value = listRootRef.value?.closest('[data-slot="scroll-area"]') ?? null;
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
virtualizer.value?.measure?.();
|
virtualizer.value?.measure?.();
|
||||||
});
|
});
|
||||||
@@ -490,31 +492,3 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.is-rotated {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
}
|
|
||||||
.rotation-transition {
|
|
||||||
transition: transform 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.friend-sidebar__virtual {
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.friend-sidebar__virtual-row {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.friend-sidebar__virtual-row--toggle-header .x-friend-group {
|
|
||||||
padding: 16px 0 6px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -1,49 +1,56 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="listRootRef" class="x-friend-list" style="padding: 10px 5px">
|
<div ref="scrollRootRef" class="relative h-full">
|
||||||
<div v-if="virtualRows.length" class="group-sidebar__virtual" :style="virtualContainerStyle">
|
<div ref="scrollViewportRef" class="h-full w-full overflow-auto">
|
||||||
<template v-for="item in virtualItems" :key="String(item.virtualItem.key)">
|
<div class="x-friend-list px-1.5 py-2.5">
|
||||||
<div
|
<div v-if="virtualRows.length" class="relative w-full box-border" :style="virtualContainerStyle">
|
||||||
v-if="item.row"
|
<template v-for="item in virtualItems" :key="String(item.virtualItem.key)">
|
||||||
class="group-sidebar__virtual-row"
|
|
||||||
:class="`group-sidebar__virtual-row--${item.row.type}`"
|
|
||||||
:data-index="item.virtualItem.index"
|
|
||||||
:ref="virtualizer.measureElement"
|
|
||||||
:style="rowStyle(item)">
|
|
||||||
<template v-if="item.row.type === 'group-header'">
|
|
||||||
<div
|
<div
|
||||||
class="x-friend-group cursor-pointer"
|
v-if="item.row"
|
||||||
:style="item.row.headerPaddingTop ? { paddingTop: item.row.headerPaddingTop } : undefined">
|
class="absolute left-0 top-0 w-full box-border"
|
||||||
<div
|
:data-index="item.virtualItem.index"
|
||||||
@click="toggleGroupSidebarCollapse(item.row.groupId)"
|
:ref="virtualizer.measureElement"
|
||||||
style="display: flex; align-items: center">
|
:style="rowStyle(item)">
|
||||||
<ChevronDown
|
<template v-if="item.row.type === 'group-header'">
|
||||||
class="rotation-transition"
|
<div
|
||||||
:class="{ 'is-rotated': item.row.isCollapsed }" />
|
class="x-friend-group cursor-pointer pt-4 pb-1.5 text-xs"
|
||||||
<span style="margin-left: 5px"> {{ item.row.label }} – {{ item.row.count }} </span>
|
:style="
|
||||||
</div>
|
item.row.headerPaddingTop
|
||||||
</div>
|
? { paddingTop: item.row.headerPaddingTop }
|
||||||
</template>
|
: undefined
|
||||||
|
">
|
||||||
<template v-else-if="item.row.type === 'group-item'">
|
<div
|
||||||
<div class="x-friend-item" @click="showGroupDialog(item.row.ownerId)">
|
@click="toggleGroupSidebarCollapse(item.row.groupId)"
|
||||||
<template v-if="item.row.isVisible">
|
class="flex items-center">
|
||||||
<div class="avatar">
|
<ChevronDown
|
||||||
<img :src="getSmallGroupIconUrl(item.row.iconUrl)" loading="lazy" />
|
class="transition-transform duration-200 ease-in-out"
|
||||||
|
:class="{ '-rotate-90': item.row.isCollapsed }" />
|
||||||
|
<span class="ml-1.5"> {{ item.row.label }} – {{ item.row.count }} </span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="detail">
|
</template>
|
||||||
<span class="name">
|
|
||||||
<span v-text="item.row.name"></span>
|
<template v-else-if="item.row.type === 'group-item'">
|
||||||
<span style="font-weight: normal; margin-left: 5px"
|
<div class="x-friend-item" @click="showGroupDialog(item.row.ownerId)">
|
||||||
>({{ item.row.userCount }}/{{ item.row.capacity }})</span
|
<template v-if="item.row.isVisible">
|
||||||
>
|
<div class="avatar">
|
||||||
</span>
|
<img :src="getSmallGroupIconUrl(item.row.iconUrl)" loading="lazy" />
|
||||||
<Location class="text-xs" :location="item.row.location" :link="false" />
|
</div>
|
||||||
|
<div class="detail">
|
||||||
|
<span class="name">
|
||||||
|
<span v-text="item.row.name"></span>
|
||||||
|
<span class="ml-1.5 font-normal">
|
||||||
|
({{ item.row.userCount }}/{{ item.row.capacity }})
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<Location class="text-xs" :location="item.row.location" :link="false" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<BackToTopVirtual :virtualizer="virtualizer" :target="scrollViewportRef" :teleport-to="scrollRootRef" />
|
<BackToTopVirtual :virtualizer="virtualizer" :target="scrollViewportRef" :teleport-to="scrollRootRef" />
|
||||||
</div>
|
</div>
|
||||||
@@ -66,7 +73,6 @@
|
|||||||
const { groupInstances } = storeToRefs(useGroupStore());
|
const { groupInstances } = storeToRefs(useGroupStore());
|
||||||
|
|
||||||
const groupInstancesCfg = ref({});
|
const groupInstancesCfg = ref({});
|
||||||
const listRootRef = ref(null);
|
|
||||||
const scrollViewportRef = ref(null);
|
const scrollViewportRef = ref(null);
|
||||||
const scrollRootRef = ref(null);
|
const scrollRootRef = ref(null);
|
||||||
|
|
||||||
@@ -177,8 +183,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
scrollViewportRef.value = listRootRef.value?.closest('[data-slot="scroll-area-viewport"]') ?? null;
|
|
||||||
scrollRootRef.value = listRootRef.value?.closest('[data-slot="scroll-area"]') ?? null;
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
virtualizer.value?.measure?.();
|
virtualizer.value?.measure?.();
|
||||||
});
|
});
|
||||||
@@ -190,31 +194,3 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.is-rotated {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
}
|
|
||||||
.rotation-transition {
|
|
||||||
transition: transform 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-sidebar__virtual {
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-sidebar__virtual-row {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-sidebar__virtual-row--group-header .x-friend-group {
|
|
||||||
padding: 16px 0 5px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user