This commit is contained in:
pa
2026-01-17 23:14:31 +09:00
committed by Natsumi
parent 5e5abc1141
commit 2d812d7c05
18 changed files with 211 additions and 97 deletions
+8 -2
View File
@@ -16,12 +16,18 @@ html {
.x-container { .x-container {
position: relative; position: relative;
flex: 1;
padding: 10px; padding: 10px;
overflow: hidden auto; overflow: hidden auto;
box-sizing: border-box; box-sizing: border-box;
background: var(--background);
height: calc(100vh - 20px);
margin: 10px 10px 10px 0;
border-radius: var(--radius);
border: 1px solid var(--border);
}
html.dark .x-container {
background: var(--sidebar); background: var(--sidebar);
height: 100%;
} }
+4 -3
View File
@@ -8,7 +8,7 @@
:class="['x-location', { 'x-link': link && location !== 'private' && location !== 'offline' }]" :class="['x-location', { 'x-link': link && location !== 'private' && location !== 'offline' }]"
class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden" class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden"
@click="handleShowWorldDialog"> @click="handleShowWorldDialog">
<Loader2 :class="['is-loading']" class="mr-1" v-if="isTraveling" /> <Spinner v-if="isTraveling" class="mr-1" />
<span class="min-w-0 truncate">{{ text }}</span> <span class="min-w-0 truncate">{{ text }}</span>
<span v-if="showInstanceIdInLocation && instanceName" class="ml-1 whitespace-nowrap">{{ <span v-if="showInstanceIdInLocation && instanceName" class="ml-1 whitespace-nowrap">{{
` · #${instanceName}` ` · #${instanceName}`
@@ -31,7 +31,7 @@
:class="['x-location', { 'x-link': link && location !== 'private' && location !== 'offline' }]" :class="['x-location', { 'x-link': link && location !== 'private' && location !== 'offline' }]"
class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden" class="inline-flex min-w-0 flex-nowrap items-center overflow-hidden"
@click="handleShowWorldDialog"> @click="handleShowWorldDialog">
<Loader2 :class="['is-loading']" class="mr-1" v-if="isTraveling" /> <Spinner v-if="isTraveling" class="mr-1" />
<span class="min-w-0 truncate">{{ text }}</span> <span class="min-w-0 truncate">{{ text }}</span>
<span v-if="showInstanceIdInLocation && instanceName" class="ml-1 whitespace-nowrap">{{ <span v-if="showInstanceIdInLocation && instanceName" class="ml-1 whitespace-nowrap">{{
` · #${instanceName}` ` · #${instanceName}`
@@ -54,8 +54,8 @@
</template> </template>
<script setup> <script setup>
import { AlertTriangle, Loader2, Lock } from 'lucide-vue-next';
import { onBeforeUnmount, ref, watch } from 'vue'; import { onBeforeUnmount, ref, watch } from 'vue';
import { AlertTriangle, Lock } from 'lucide-vue-next';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -67,6 +67,7 @@
useWorldStore useWorldStore
} from '../stores'; } from '../stores';
import { getGroupName, getWorldName, parseLocation } from '../shared/utils'; import { getGroupName, getWorldName, parseLocation } from '../shared/utils';
import { Spinner } from './ui/spinner';
import { accessTypeLocaleKeyMap } from '../shared/constants'; import { accessTypeLocaleKeyMap } from '../shared/constants';
const { t } = useI18n(); const { t } = useI18n();
+56 -6
View File
@@ -1,6 +1,6 @@
<template> <template>
<Sidebar side="left" variant="sidebar" collapsible="icon"> <Sidebar side="left" variant="sidebar" collapsible="icon">
<SidebarContent class="pt-4"> <SidebarContent class="pt-2">
<div v-if="navLayoutReady" class="px-2"> <div v-if="navLayoutReady" class="px-2">
<SidebarMenu> <SidebarMenu>
<SidebarMenuItem v-if="pendingVRCXUpdate || pendingVRCXInstall"> <SidebarMenuItem v-if="pendingVRCXUpdate || pendingVRCXInstall">
@@ -40,7 +40,39 @@
</SidebarMenuItem> </SidebarMenuItem>
<SidebarMenuItem v-else> <SidebarMenuItem v-else>
<DropdownMenu
v-if="isCollapsed"
:open="collapsedDropdownOpenId === item.index"
@update:open="(value) => handleCollapsedDropdownOpenChange(item.index, value)">
<DropdownMenuTrigger as-child>
<SidebarMenuButton
:is-active="item.children?.some((e) => e.index === activeMenuIndex)"
:tooltip="item.titleIsCustom ? item.title : t(item.title || '')"
:class="isNavItemNotified(item) ? 'notify' : undefined">
<i
:class="item.icon"
class="inline-flex size-6 items-center justify-center text-lg" />
<span v-show="!isCollapsed">{{
item.titleIsCustom ? item.title : t(item.title || '')
}}</span>
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent side="right" align="start" class="w-56">
<DropdownMenuItem
v-for="entry in item.children"
:key="entry.index"
@select="(event) => handleCollapsedSubmenuSelect(event, entry, item.index)">
<i
v-if="entry.icon"
:class="entry.icon"
class="inline-flex size-4 items-center justify-center text-base" />
<span>{{ t(entry.label) }}</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Collapsible <Collapsible
v-else
class="group/collapsible" class="group/collapsible"
:default-open=" :default-open="
activeMenuIndex && item.children?.some((e) => e.index === activeMenuIndex) activeMenuIndex && item.children?.some((e) => e.index === activeMenuIndex)
@@ -87,7 +119,7 @@
</SidebarGroup> </SidebarGroup>
</SidebarContent> </SidebarContent>
<SidebarFooter class="p-2"> <SidebarFooter class="px-2 py-3">
<SidebarMenu> <SidebarMenu>
<SidebarMenuItem> <SidebarMenuItem>
<DropdownMenu> <DropdownMenu>
@@ -249,8 +281,6 @@
</SidebarMenuItem> </SidebarMenuItem>
</SidebarMenu> </SidebarMenu>
</SidebarFooter> </SidebarFooter>
<SidebarRail />
</Sidebar> </Sidebar>
<CustomNavDialog <CustomNavDialog
@@ -272,8 +302,7 @@
SidebarMenuItem, SidebarMenuItem,
SidebarMenuSub, SidebarMenuSub,
SidebarMenuSubButton, SidebarMenuSubButton,
SidebarMenuSubItem, SidebarMenuSubItem
SidebarRail
} from '@/components/ui/sidebar'; } from '@/components/ui/sidebar';
import { import {
DropdownMenu, DropdownMenu,
@@ -358,6 +387,7 @@
const { themeMode, tableDensity, isDarkMode, isNavCollapsed: isCollapsed } = storeToRefs(appearanceSettingsStore); const { themeMode, tableDensity, isDarkMode, isNavCollapsed: isCollapsed } = storeToRefs(appearanceSettingsStore);
const navLayout = ref([]); const navLayout = ref([]);
const navLayoutReady = ref(false); const navLayoutReady = ref(false);
const collapsedDropdownOpenId = ref(null);
const menuItems = computed(() => { const menuItems = computed(() => {
const items = []; const items = [];
@@ -454,6 +484,15 @@
} }
); );
watch(
() => isCollapsed.value,
(value) => {
if (!value) {
collapsedDropdownOpenId.value = null;
}
}
);
const generateFolderId = () => `nav-folder-${dayjs().toISOString()}-${Math.random().toString().slice(2, 4)}`; const generateFolderId = () => `nav-folder-${dayjs().toISOString()}-${Math.random().toString().slice(2, 4)}`;
const sanitizeLayout = (layout) => { const sanitizeLayout = (layout) => {
@@ -721,6 +760,17 @@
triggerNavAction(entry, navIndex); triggerNavAction(entry, navIndex);
}; };
const handleCollapsedDropdownOpenChange = (index, value) => {
collapsedDropdownOpenId.value = value ? index : null;
};
const handleCollapsedSubmenuSelect = (event, entry, index) => {
if (event?.preventDefault) {
event.preventDefault();
}
handleSubmenuClick(entry, index);
};
const handleMenuItemClick = (item) => { const handleMenuItemClick = (item) => {
triggerNavAction(item, item?.index); triggerNavAction(item, item?.index);
}; };
@@ -124,8 +124,8 @@
PaginationPrevious PaginationPrevious
} from '../pagination'; } from '../pagination';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../table'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../table';
import { ScrollArea } from '../scroll-area';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select';
import { ScrollArea } from '../scroll-area';
const props = defineProps({ const props = defineProps({
table: { table: {
+3 -3
View File
@@ -75,7 +75,7 @@
<div <div
:class=" :class="
cn( cn(
'relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear', 'relative w-(--sidebar-width) bg-transparent',
'group-data-[collapsible=offcanvas]:w-0', 'group-data-[collapsible=offcanvas]:w-0',
'group-data-[side=right]:rotate-180', 'group-data-[side=right]:rotate-180',
variant === 'floating' || variant === 'inset' variant === 'floating' || variant === 'inset'
@@ -86,14 +86,14 @@
<div <div
:class=" :class="
cn( cn(
'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex', 'fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) md:flex',
side === 'left' side === 'left'
? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]' ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
: 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]', : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
// Adjust the padding for floating and inset variants. // Adjust the padding for floating and inset variants.
variant === 'floating' || variant === 'inset' variant === 'floating' || variant === 'inset'
? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]' ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4))+2px)]'
: 'group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[side=left]:border-r group-data-[side=right]:border-l', : 'group-data-[collapsible=icon]:w-(--sidebar-width-icon)',
props.class props.class
) )
" "
+3
View File
@@ -553,8 +553,11 @@
"bio_language": "Target Language", "bio_language": "Target Language",
"theme_mode": "Theme", "theme_mode": "Theme",
"font_family": "Font", "font_family": "Font",
"font_family_tooltip": "Does not change CJK fonts",
"font_family_inter": "Inter", "font_family_inter": "Inter",
"font_family_noto_sans": "Noto Sans", "font_family_noto_sans": "Noto Sans",
"font_family_source_sans_3": "Source Sans 3",
"font_family_ibm_plex_sans": "IBM Plex Sans",
"font_family_harmonyos_sans": "HarmonyOS Sans", "font_family_harmonyos_sans": "HarmonyOS Sans",
"theme_mode_system": "System", "theme_mode_system": "System",
"theme_mode_light": "Light", "theme_mode_light": "Light",
+11 -1
View File
@@ -1,4 +1,4 @@
const APP_FONT_DEFAULT_KEY = 'noto_sans'; const APP_FONT_DEFAULT_KEY = 'inter';
const APP_FONT_CONFIG = Object.freeze({ const APP_FONT_CONFIG = Object.freeze({
inter: { inter: {
@@ -9,6 +9,16 @@ const APP_FONT_CONFIG = Object.freeze({
cssName: "'Noto Sans Variable'", cssName: "'Noto Sans Variable'",
link: null link: null
}, },
source_sans_3: {
cssName: "'Source Sans 3'",
cssImport:
"@import url('https://fonts.googleapis.com/css2?family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap');"
},
ibm_plex_sans: {
cssName: "'IBM Plex Sans'",
cssImport:
"@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&family=Source+Sans+3:ital,wght@0,200..900;1,200..900&display=swap');"
},
harmonyos_sans: { harmonyos_sans: {
cssName: "'HarmonyOS Sans'", cssName: "'HarmonyOS Sans'",
cssImport: cssImport:
+27 -17
View File
@@ -152,26 +152,36 @@ function resolveAppFontFamily(fontKey) {
}; };
} }
function ensureAppFontLinks() { function ensureAppFontLinks(fontKey) {
const head = document.head; const head = document.head;
if (!head) { if (!head) {
return; return;
} }
Object.entries(APP_FONT_CONFIG).forEach(([key, config]) => {
if (!config?.cssImport) { document
return; .querySelectorAll(`style[${APP_FONT_LINK_ATTR}]`)
} .forEach((styleEl) => {
const existing = document.querySelector( if (styleEl.getAttribute(APP_FONT_LINK_ATTR) !== fontKey) {
`style[${APP_FONT_LINK_ATTR}="${key}"]` styleEl.remove();
); }
if (existing) { });
return;
} const config = APP_FONT_CONFIG[fontKey];
const styleEl = document.createElement('style'); if (!config?.cssImport) {
styleEl.setAttribute(APP_FONT_LINK_ATTR, key); return;
styleEl.textContent = config.cssImport; }
head.appendChild(styleEl);
}); const existing = document.querySelector(
`style[${APP_FONT_LINK_ATTR}="${fontKey}"]`
);
if (existing) {
return;
}
const styleEl = document.createElement('style');
styleEl.setAttribute(APP_FONT_LINK_ATTR, fontKey);
styleEl.textContent = config.cssImport;
head.appendChild(styleEl);
} }
function applyAppFontFamily(fontKey) { function applyAppFontFamily(fontKey) {
@@ -179,7 +189,7 @@ function applyAppFontFamily(fontKey) {
const root = document.documentElement; const root = document.documentElement;
root.style.setProperty('--font-western-primary', resolved.cssName); root.style.setProperty('--font-western-primary', resolved.cssName);
ensureAppFontLinks(); ensureAppFontLinks(resolved.key);
return resolved; return resolved;
} }
+9 -7
View File
@@ -533,13 +533,15 @@ export const useVrcxStore = defineStore('Vrcx', () => {
if (advancedSettingsStore.sentryErrorReporting) { if (advancedSettingsStore.sentryErrorReporting) {
try { try {
import('@sentry/vue').then((Sentry) => { import('@sentry/vue').then((Sentry) => {
const trail = getPiniaActionTrail().filter((entry) => { const trail = getPiniaActionTrail()
if (!entry) return false; .filter((entry) => {
return ( if (!entry) return false;
typeof entry.t === 'string' && return (
typeof entry.a === 'string' typeof entry.t === 'string' &&
); typeof entry.a === 'string'
}); );
})
.reverse();
const trailText = JSON.stringify(trail); const trailText = JSON.stringify(trail);
Sentry.withScope((scope) => { Sentry.withScope((scope) => {
scope.setLevel('fatal'); scope.setLevel('fatal');
+18
View File
@@ -162,6 +162,8 @@
@layer base { @layer base {
* { * {
@apply border-border outline-ring/50; @apply border-border outline-ring/50;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
} }
body { body {
@apply bg-background text-foreground; @apply bg-background text-foreground;
@@ -172,6 +174,22 @@
} }
} }
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: var(--border);
border-radius: 9999px;
border: 2px solid transparent;
background-clip: content-box;
}
@layer utilities { @layer utilities {
.scrollbar-hidden { .scrollbar-hidden {
scrollbar-width: none; scrollbar-width: none;
+4 -2
View File
@@ -1892,12 +1892,14 @@
display: flex; display: flex;
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid var(--border);
border-radius: calc(8px * var(--favorites-card-scale, 1)); border-radius: calc(8px * var(--favorites-card-scale, 1));
padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px); padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px);
cursor: pointer; cursor: pointer;
transition: transition:
border-color 0.2s ease, border-color 0.2s ease,
box-shadow 0.2s ease; box-shadow 0.2s ease,
transform 0.2s ease;
box-shadow: 0 0 6px rgba(15, 23, 42, 0.04); box-shadow: 0 0 6px rgba(15, 23, 42, 0.04);
width: 100%; width: 100%;
min-width: var(--favorites-card-min-width, 240px); min-width: var(--favorites-card-min-width, 240px);
@@ -1906,7 +1908,7 @@
:deep(.favorites-search-card:hover) { :deep(.favorites-search-card:hover) {
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.07); box-shadow: 0 4px 14px rgba(15, 23, 42, 0.07);
transform: translateY(-2px); transform: translateY(calc(-2px * var(--favorites-card-scale, 1)));
} }
:deep(.favorites-search-card__content) { :deep(.favorites-search-card__content) {
+4 -2
View File
@@ -1159,12 +1159,14 @@
display: flex; display: flex;
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid var(--border);
border-radius: calc(8px * var(--favorites-card-scale, 1)); border-radius: calc(8px * var(--favorites-card-scale, 1));
padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px); padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px);
cursor: pointer; cursor: pointer;
transition: transition:
border-color 0.2s ease, border-color 0.2s ease,
box-shadow 0.2s ease; box-shadow 0.2s ease,
transform 0.2s ease;
box-shadow: 0 0 6px rgba(15, 23, 42, 0.04); box-shadow: 0 0 6px rgba(15, 23, 42, 0.04);
width: 100%; width: 100%;
min-width: var(--favorites-card-min-width, 240px); min-width: var(--favorites-card-min-width, 240px);
@@ -1173,7 +1175,7 @@
:deep(.favorites-search-card:hover) { :deep(.favorites-search-card:hover) {
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.07); box-shadow: 0 4px 14px rgba(15, 23, 42, 0.07);
transform: translateY(-2px); transform: translateY(calc(-2px * var(--favorites-card-scale, 1)));
} }
:deep(.favorites-search-card.is-selected) { :deep(.favorites-search-card.is-selected) {
+4 -2
View File
@@ -1661,12 +1661,14 @@
display: flex; display: flex;
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid var(--border);
border-radius: calc(8px * var(--favorites-card-scale, 1)); border-radius: calc(8px * var(--favorites-card-scale, 1));
padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px); padding: var(--favorites-card-padding-y, 8px) var(--favorites-card-padding-x, 10px);
cursor: pointer; cursor: pointer;
transition: transition:
border-color 0.2s ease, border-color 0.2s ease,
box-shadow 0.2s ease; box-shadow 0.2s ease,
transform 0.2s ease;
box-shadow: 0 0 6px rgba(15, 23, 42, 0.04); box-shadow: 0 0 6px rgba(15, 23, 42, 0.04);
width: 100%; width: 100%;
min-width: var(--favorites-card-min-width, 240px); min-width: var(--favorites-card-min-width, 240px);
@@ -1675,7 +1677,7 @@
:deep(.favorites-search-card:hover) { :deep(.favorites-search-card:hover) {
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.07); box-shadow: 0 4px 14px rgba(15, 23, 42, 0.07);
transform: translateY(-2px); transform: translateY(calc(-2px * var(--favorites-card-scale, 1)));
} }
:deep(.favorites-search-card.is-selected) { :deep(.favorites-search-card.is-selected) {
+2 -2
View File
@@ -3,7 +3,7 @@
<SidebarProvider <SidebarProvider
:open="sidebarOpen" :open="sidebarOpen"
:width="navWidth" :width="navWidth"
:width-icon="64" :width-icon="48"
class="relative flex-1 h-full min-w-0" class="relative flex-1 h-full min-w-0"
@update:open="handleSidebarOpenChange"> @update:open="handleSidebarOpenChange">
<NavMenu /> <NavMenu />
@@ -14,7 +14,7 @@
:style="{ left: 'var(--sidebar-width)' }" :style="{ left: 'var(--sidebar-width)' }"
@pointerdown.prevent="startNavResize" /> @pointerdown.prevent="startNavResize" />
<SidebarInset class="min-w-0"> <SidebarInset class="min-w-0 bg-sidebar">
<ResizablePanelGroup <ResizablePanelGroup
ref="panelGroupRef" ref="panelGroupRef"
direction="horizontal" direction="horizontal"
+18 -19
View File
@@ -128,7 +128,9 @@
<div class="x-friend-item" style="cursor: default"> <div class="x-friend-item" style="cursor: default">
<div class="detail"> <div class="detail">
<span class="name">{{ t('dialog.world.info.last_updated') }}</span> <span class="name">{{ t('dialog.world.info.last_updated') }}</span>
<span class="block truncate text-xs">{{ formatDateFilter(currentInstanceWorld.lastUpdated, 'long') }}</span> <span class="block truncate text-xs">{{
formatDateFilter(currentInstanceWorld.lastUpdated, 'long')
}}</span>
</div> </div>
</div> </div>
<div class="x-friend-item" style="cursor: default"> <div class="x-friend-item" style="cursor: default">
@@ -148,13 +150,10 @@
<div class="current-instance-table flex min-h-0 min-w-0 flex-1"> <div class="current-instance-table flex min-h-0 min-w-0 flex-1">
<DataTableLayout <DataTableLayout
class="min-w-0 w-full [&_th]:px-2.5! [&_th]:py-0.75! [&_td]:px-2.5! [&_td]:py-0.75! [&_tr]:h-7!" class="[&_th]:px-2.5! [&_th]:py-0.75! [&_td]:px-2.5! [&_td]:py-0.75! [&_tr]:h-7!"
:table="playerListTable" :table="playerListTable"
table-class="min-w-max w-max"
:use-table-min-width="true"
:table-style="playerListTableStyle" :table-style="playerListTableStyle"
:loading="false" :loading="false"
:total-items="playerListTotalItems"
:show-pagination="false" :show-pagination="false"
:on-row-click="handlePlayerListRowClick" /> :on-row-click="handlePlayerListRowClick" />
</div> </div>
@@ -255,15 +254,9 @@
return a[field].toLowerCase().localeCompare(b[field].toLowerCase()); return a[field].toLowerCase().localeCompare(b[field].toLowerCase());
} }
const initialColumnPinning = {
left: ['avatar', 'timer', 'displayName'],
right: []
};
const playerListColumns = computed(() => const playerListColumns = computed(() =>
createColumns({ createColumns({
randomUserColours, randomUserColours,
photonLoggingEnabled,
chatboxUserBlacklist, chatboxUserBlacklist,
onBlockChatbox: addChatboxUserBlacklist, onBlockChatbox: addChatboxUserBlacklist,
onUnblockChatbox: deleteChatboxUserBlacklist, onUnblockChatbox: deleteChatboxUserBlacklist,
@@ -274,14 +267,8 @@
const { table: playerListTable } = useVrcxVueTable({ const { table: playerListTable } = useVrcxVueTable({
persistKey: 'playerList', persistKey: 'playerList',
data: currentInstanceUsersData, data: currentInstanceUsersData,
columns: playerListColumns.value, columns: playerListColumns,
getRowId: (row) => `${row?.ref?.id ?? ''}:${row?.displayName ?? ''}`, getRowId: (row) => `${row?.ref?.id ?? ''}:${row?.displayName ?? ''}`
enablePinning: true,
initialColumnPinning,
initialPagination: {
pageIndex: 0,
pageSize: 500
}
}); });
watch( watch(
@@ -295,6 +282,18 @@
{ immediate: true } { immediate: true }
); );
watch(
photonLoggingEnabled,
(enabled) => {
const column = playerListTable?.getColumn?.('photonId');
if (!column) {
return;
}
column.toggleVisibility(Boolean(enabled));
},
{ immediate: true }
);
const playerListTotalItems = computed(() => playerListTable.getRowModel().rows.length); const playerListTotalItems = computed(() => playerListTable.getRowModel().rows.length);
const handlePlayerListRowClick = (row) => { const handlePlayerListRowClick = (row) => {
+15 -16
View File
@@ -58,13 +58,11 @@ const sortInstanceIcon = (a, b) =>
export const createColumns = ({ export const createColumns = ({
randomUserColours, randomUserColours,
photonLoggingEnabled,
chatboxUserBlacklist, chatboxUserBlacklist,
onBlockChatbox, onBlockChatbox,
onUnblockChatbox, onUnblockChatbox,
sortAlphabetically sortAlphabetically
}) => { }) => {
/** @type {import('@tanstack/vue-table').ColumnDef<any, any>[]} */
const cols = [ const cols = [
{ {
id: 'avatar', id: 'avatar',
@@ -72,7 +70,6 @@ export const createColumns = ({
header: () => t('table.playerList.avatar'), header: () => t('table.playerList.avatar'),
size: 70, size: 70,
enableSorting: false, enableSorting: false,
enableResizing: false,
cell: ({ row }) => { cell: ({ row }) => {
const userRef = row.original?.ref; const userRef = row.original?.ref;
const src = userImage(userRef); const src = userImage(userRef);
@@ -94,7 +91,6 @@ export const createColumns = ({
header: ({ column }) => header: ({ column }) =>
sortButton({ column, label: t('table.playerList.timer') }), sortButton({ column, label: t('table.playerList.timer') }),
size: 90, size: 90,
enableResizing: false,
sortingFn: (rowA, rowB) => sortingFn: (rowA, rowB) =>
(rowA.original?.timer ?? 0) - (rowB.original?.timer ?? 0), (rowA.original?.timer ?? 0) - (rowB.original?.timer ?? 0),
cell: ({ row }) => <Timer epoch={row.original?.timer} /> cell: ({ row }) => <Timer epoch={row.original?.timer} />
@@ -144,7 +140,11 @@ export const createColumns = ({
id: 'status', id: 'status',
accessorFn: (row) => row?.ref?.statusDescription, accessorFn: (row) => row?.ref?.statusDescription,
header: () => t('table.playerList.status'), header: () => t('table.playerList.status'),
minSize: 200, size:200,
minSize: 100,
meta: {
stretch: true
},
enableSorting: false, enableSorting: false,
cell: ({ row }) => { cell: ({ row }) => {
const userRef = row.original?.ref; const userRef = row.original?.ref;
@@ -165,16 +165,14 @@ export const createColumns = ({
</span> </span>
); );
} }
} },
]; {
if (photonLoggingEnabled?.value) {
cols.push({
id: 'photonId', id: 'photonId',
accessorFn: (row) => row?.photonId, accessorFn: (row) => row?.photonId,
header: ({ column }) => header: ({ column }) =>
sortButton({ column, label: t('table.playerList.photonId') }), sortButton({ column, label: t('table.playerList.photonId') }),
size: 110, size: 110,
enableHiding: true,
sortingFn: (rowA, rowB) => sortingFn: (rowA, rowB) =>
(rowA.original?.photonId ?? 0) - (rowB.original?.photonId ?? 0), (rowA.original?.photonId ?? 0) - (rowB.original?.photonId ?? 0),
cell: ({ row }) => { cell: ({ row }) => {
@@ -208,10 +206,7 @@ export const createColumns = ({
</div> </div>
); );
} }
}); },
}
cols.push(
{ {
id: 'icon', id: 'icon',
header: ({ column }) => header: ({ column }) =>
@@ -295,6 +290,10 @@ export const createColumns = ({
id: 'platform', id: 'platform',
header: () => t('table.playerList.platform'), header: () => t('table.playerList.platform'),
size: 90, size: 90,
meta: {
stretch: true
},
minSize: 20,
enableSorting: false, enableSorting: false,
cell: ({ row }) => { cell: ({ row }) => {
const userRef = row.original?.ref; const userRef = row.original?.ref;
@@ -405,7 +404,7 @@ export const createColumns = ({
accessorFn: (row) => row?.ref?.note, accessorFn: (row) => row?.ref?.note,
header: () => t('table.playerList.note'), header: () => t('table.playerList.note'),
size: 150, size: 150,
minSize: 40, minSize: 20,
meta: { meta: {
stretch: true stretch: true
}, },
@@ -419,7 +418,7 @@ export const createColumns = ({
return <span>{text}</span>; return <span>{text}</span>;
} }
} }
); ];
return cols; return cols;
}; };
@@ -33,7 +33,16 @@
</Select> </Select>
</div> </div>
<div class="options-container-item"> <div class="options-container-item">
<span class="name">{{ t('view.settings.appearance.appearance.font_family') }}</span> <span class="name flex! items-center!">
{{ t('view.settings.appearance.appearance.font_family') }}
<TooltipWrapper
side="top"
style="margin-left: 5px"
:content="t('view.settings.appearance.appearance.font_family_tooltip')">
<Info />
</TooltipWrapper>
</span>
<Select :model-value="appFontFamily" @update:modelValue="setAppFontFamily"> <Select :model-value="appFontFamily" @update:modelValue="setAppFontFamily">
<SelectTrigger size="sm"> <SelectTrigger size="sm">
<SelectValue <SelectValue
@@ -41,10 +50,7 @@
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
<SelectItem <SelectItem v-for="fontKey in appFontFamilyOptions" :key="fontKey" :value="fontKey">
v-for="fontKey in appFontFamilyOptions"
:key="fontKey"
:value="fontKey">
{{ t(`view.settings.appearance.appearance.font_family_${fontKey}`) }} {{ t(`view.settings.appearance.appearance.font_family_${fontKey}`) }}
</SelectItem> </SelectItem>
</SelectGroup> </SelectGroup>
@@ -437,9 +443,9 @@
TagsInputItemDelete, TagsInputItemDelete,
TagsInputItemText TagsInputItemText
} from '@/components/ui/tags-input'; } from '@/components/ui/tags-input';
import { ArrowRight, CheckIcon, ChevronDown, Info } from 'lucide-vue-next';
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { computed, onBeforeUnmount, ref, watch } from 'vue'; import { computed, onBeforeUnmount, ref, watch } from 'vue';
import { ArrowRight, CheckIcon, ChevronDown } from 'lucide-vue-next';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -449,8 +455,8 @@
import PresetColorPicker from '@/components/PresetColorPicker.vue'; import PresetColorPicker from '@/components/PresetColorPicker.vue';
import { useAppearanceSettingsStore, useFavoriteStore, useVrStore } from '../../../../stores'; import { useAppearanceSettingsStore, useFavoriteStore, useVrStore } from '../../../../stores';
import { getLanguageName, languageCodes } from '../../../../localization';
import { APP_FONT_FAMILIES, THEME_CONFIG } from '../../../../shared/constants'; import { APP_FONT_FAMILIES, THEME_CONFIG } from '../../../../shared/constants';
import { getLanguageName, languageCodes } from '../../../../localization';
import SimpleSwitch from '../SimpleSwitch.vue'; import SimpleSwitch from '../SimpleSwitch.vue';
+11 -7
View File
@@ -27,12 +27,16 @@
item.ref.displayName item.ref.displayName
}}</span> }}</span>
<span v-if="!item.ref.isFriend" class="block truncate text-xs"></span> <span v-if="!item.ref.isFriend" class="block truncate text-xs"></span>
<span v-else-if="item.ref.state === 'offline'" class="block truncate text-xs">{{ <span
t('side_panel.search_result_active') v-else-if="item.ref.state === 'offline'"
}}</span> class="block truncate text-xs"
<span v-else-if="item.ref.state === 'active'" class="block truncate text-xs">{{ >{{ t('side_panel.search_result_active') }}</span
t('side_panel.search_result_offline') >
}}</span> <span
v-else-if="item.ref.state === 'active'"
class="block truncate text-xs"
>{{ t('side_panel.search_result_offline') }}</span
>
<Location <Location
v-else v-else
class="text-xs" class="text-xs"
@@ -182,7 +186,7 @@
display: flex; display: flex;
flex: none; flex: none;
flex-direction: column; flex-direction: column;
padding: 13px 5px 5px 5px; padding: 10px 5px 5px 5px;
order: 99; order: 99;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;