This commit is contained in:
pa
2026-01-19 11:04:36 +09:00
parent cacbf742d1
commit 7303cd0b33
22 changed files with 107 additions and 178 deletions

90
package-lock.json generated
View File

@@ -8,7 +8,7 @@
"license": "MIT",
"dependencies": {
"hazardous": "^0.3.0",
"node-api-dotnet": "^0.9.18"
"node-api-dotnet": "^0.9.19"
},
"devDependencies": {
"@electron/rebuild": "^4.0.2",
@@ -26,7 +26,7 @@
"@tanstack/vue-table": "^8.21.3",
"@tanstack/vue-virtual": "^3.13.18",
"@types/jest": "^30.0.0",
"@types/node": "^25.0.8",
"@types/node": "^25.0.9",
"@vee-validate/zod": "^4.15.1",
"@vitejs/plugin-vue": "^6.0.3",
"@vitejs/plugin-vue-jsx": "^5.1.3",
@@ -69,7 +69,7 @@
"vue-router": "^4.6.4",
"vue-showdown": "^4.2.0",
"vue-sonner": "^2.0.9",
"worker-timers": "^8.0.28",
"worker-timers": "^8.0.29",
"yargs": "^18.0.0",
"zod": "^3.25.76"
}
@@ -678,9 +678,9 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
"integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
"integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -5262,9 +5262,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "25.0.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.8.tgz",
"integrity": "sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==",
"version": "25.0.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.9.tgz",
"integrity": "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6747,16 +6747,16 @@
}
},
"node_modules/broker-factory": {
"version": "3.1.12",
"resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.12.tgz",
"integrity": "sha512-5Bmeki5j2IVO+lE07dSOUMZp1ZGKkE47b3ILv4ZD0nmTdc0iTKVS1CgYPDCy5m0Qb9jIKHBaF9SUrtqg5oW+1A==",
"version": "3.1.13",
"resolved": "https://registry.npmjs.org/broker-factory/-/broker-factory-3.1.13.tgz",
"integrity": "sha512-H2VALe31mEtO/SRcNp4cUU5BAm1biwhc/JaF77AigUuni/1YT0FLCJfbUxwIEs9y6Kssjk2fmXgf+Y9ALvmKlw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4",
"fast-unique-numbers": "^9.0.25",
"@babel/runtime": "^7.28.6",
"fast-unique-numbers": "^9.0.26",
"tslib": "^2.8.1",
"worker-factory": "^7.0.47"
"worker-factory": "^7.0.48"
}
},
"node_modules/broker-factory/node_modules/tslib": {
@@ -9393,13 +9393,13 @@
"license": "MIT"
},
"node_modules/fast-unique-numbers": {
"version": "9.0.25",
"resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.25.tgz",
"integrity": "sha512-vHLSJfu0jSazb5X1jgYZIbsUd4mztxHxyFxUAPYvaYLkTsvQDn5+NbJRtfp+/tLIsUlMkD/geL2710QBxylH6w==",
"version": "9.0.26",
"resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-9.0.26.tgz",
"integrity": "sha512-3Mtq8p1zQinjGyWfKeuBunbuFoixG72AUkk4VvzbX4ykCW9Q4FzRaNyIlfQhUjnKw2ARVP+/CKnoyr6wfHftig==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4",
"@babel/runtime": "^7.28.6",
"tslib": "^2.8.1"
},
"engines": {
@@ -13844,9 +13844,9 @@
"optional": true
},
"node_modules/node-api-dotnet": {
"version": "0.9.18",
"resolved": "https://registry.npmjs.org/node-api-dotnet/-/node-api-dotnet-0.9.18.tgz",
"integrity": "sha512-cIFp+5YHvCGClJMA6s5JqeCZEWj3gYIN5bQ02p3kRcz1byf53pqRAHxh9eLMyJ90mqktnK50YcuLttV+ftoqyg==",
"version": "0.9.19",
"resolved": "https://registry.npmjs.org/node-api-dotnet/-/node-api-dotnet-0.9.19.tgz",
"integrity": "sha512-7y+mPsIfebm8ftc+ZdQtC/05KT5IRK4N4Kdkb+VPpW7fLJsGupIiTOCCDZ3H4tKNPVvifNzFCbv0lak/JCKh+w==",
"license": "MIT"
},
"node_modules/node-api-version": {
@@ -18148,14 +18148,14 @@
}
},
"node_modules/worker-factory": {
"version": "7.0.47",
"resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.47.tgz",
"integrity": "sha512-Ga5U8n7hJqovn98nlFnbyuJj66s8dCU4QOQd0dU0bje7uvrGGhOFeKtsTdB3b6fO5BD93F88rHpkBCGzgGloKw==",
"version": "7.0.48",
"resolved": "https://registry.npmjs.org/worker-factory/-/worker-factory-7.0.48.tgz",
"integrity": "sha512-CGmBy3tJvpBPjUvb0t4PrpKubUsfkI1Ohg0/GGFU2RvA9j/tiVYwKU8O7yu7gH06YtzbeJLzdUR29lmZKn5pag==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4",
"fast-unique-numbers": "^9.0.25",
"@babel/runtime": "^7.28.6",
"fast-unique-numbers": "^9.0.26",
"tslib": "^2.8.1"
}
},
@@ -18167,30 +18167,30 @@
"license": "0BSD"
},
"node_modules/worker-timers": {
"version": "8.0.28",
"resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.28.tgz",
"integrity": "sha512-+AuNePH2P/PuhQURf5I+SIGBty4dq2CzoQEB+bMXIQiPrYj3WhkUtIW2bSzeETFWyXJFUdQGsyFeZtit15LkOw==",
"version": "8.0.29",
"resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-8.0.29.tgz",
"integrity": "sha512-9jk0MWHhWAZ2xlJPXr45oe5UF/opdpfZrY0HtyPizWuJ+ce1M3IYk/4IIdGct3kn9Ncfs+tkZt3w1tU6KW2Fsg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4",
"@babel/runtime": "^7.28.6",
"tslib": "^2.8.1",
"worker-timers-broker": "^8.0.14",
"worker-timers-worker": "^9.0.12"
"worker-timers-broker": "^8.0.15",
"worker-timers-worker": "^9.0.13"
}
},
"node_modules/worker-timers-broker": {
"version": "8.0.14",
"resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.14.tgz",
"integrity": "sha512-ooCGGWGcAYbWEJY2nkA60K9mZ33atvg/QIOBJ3OzdQJU5Z7/NdPFlEiMLiCYW8dpeP/qLcsaUsZzETrKNgGicg==",
"version": "8.0.15",
"resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-8.0.15.tgz",
"integrity": "sha512-Te+EiVUMzG5TtHdmaBZvBrZSFNauym6ImDaCAnzQUxvjnw+oGjMT2idmAOgDy30vOZMLejd0bcsc90Axu6XPWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4",
"broker-factory": "^3.1.12",
"fast-unique-numbers": "^9.0.25",
"@babel/runtime": "^7.28.6",
"broker-factory": "^3.1.13",
"fast-unique-numbers": "^9.0.26",
"tslib": "^2.8.1",
"worker-timers-worker": "^9.0.12"
"worker-timers-worker": "^9.0.13"
}
},
"node_modules/worker-timers-broker/node_modules/tslib": {
@@ -18201,15 +18201,15 @@
"license": "0BSD"
},
"node_modules/worker-timers-worker": {
"version": "9.0.12",
"resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.12.tgz",
"integrity": "sha512-NBXCnKB/9CkhjWZz2dITgK94QM5GIJx+7LAlCA8mKeO6whdwmfH9S3iPEwakhn3+NOB9nHE3jQqdpKpZZJI23g==",
"version": "9.0.13",
"resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-9.0.13.tgz",
"integrity": "sha512-qjn18szGb1kjcmh2traAdki1eiIS5ikFo+L90nfMOvSRpuDw1hAcR1nzkP2+Hkdqz5thIRnfuWx7QSpsEUsA6Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.28.4",
"@babel/runtime": "^7.28.6",
"tslib": "^2.8.1",
"worker-factory": "^7.0.47"
"worker-factory": "^7.0.48"
}
},
"node_modules/worker-timers-worker/node_modules/tslib": {

View File

@@ -47,7 +47,7 @@
"@tanstack/vue-table": "^8.21.3",
"@tanstack/vue-virtual": "^3.13.18",
"@types/jest": "^30.0.0",
"@types/node": "^25.0.8",
"@types/node": "^25.0.9",
"@vee-validate/zod": "^4.15.1",
"@vitejs/plugin-vue": "^6.0.3",
"@vitejs/plugin-vue-jsx": "^5.1.3",
@@ -90,7 +90,7 @@
"vue-router": "^4.6.4",
"vue-showdown": "^4.2.0",
"vue-sonner": "^2.0.9",
"worker-timers": "^8.0.28",
"worker-timers": "^8.0.29",
"yargs": "^18.0.0",
"zod": "^3.25.76"
},
@@ -179,6 +179,6 @@
},
"dependencies": {
"hazardous": "^0.3.0",
"node-api-dotnet": "^0.9.18"
"node-api-dotnet": "^0.9.19"
}
}

View File

@@ -61,14 +61,7 @@
<History class="h-4 w-4" />
</Button>
</TooltipWrapper>
<span v-if="showLastJoinIndicator" class="inline-block ml-2">
<TooltipWrapper side="top" class="ml-5">
<template #content>
<span>{{ t('dialog.user.info.last_join') }} <Timer :epoch="lastJoin" /></span>
</template>
<MapPin class="h-4 w-4 text-muted-foreground" />
</TooltipWrapper>
</span>
<div v-if="showInstanceInfo" class="flex items-center ml-2">
<TooltipWrapper v-if="instanceInfoState.isValidInstance" side="top">
<template #content>
@@ -79,7 +72,8 @@
<template v-if="instanceInfoState.canCloseInstance">
<Button
class="mt-1"
size="sm"
size="xs"
variant="outline"
:disabled="!!instance?.closedAt"
@click="closeInstance(resolvedInstanceLocation)">
{{ t('dialog.user.info.close_instance') }}
@@ -113,17 +107,29 @@
</template>
</div>
</template>
<div class="mr-2 text-muted-foreground">
<div class="mr-1 text-muted-foreground">
<span v-if="resolvedInstanceLocation === locationStore.lastLocation.location">
{{ locationStore.lastLocation.playerList.size }}/{{ instance?.capacity }}
</span>
<span v-else-if="instance?.userCount"> {{ instance.userCount }}/{{ instance?.capacity }} </span>
</div>
</TooltipWrapper>
<span v-if="friendcount" class="ml-1 flex items-center text-muted-foreground"
><UsersRound />{{ friendcount }}</span
>
<TooltipWrapper v-if="friendcount" side="top" :content="t('dialog.user.info.instance_friends_tooltip')">
<span class="ml-1 flex items-center text-muted-foreground"><UsersRound />{{ friendcount }}</span>
</TooltipWrapper>
<span v-if="showLastJoinIndicator" class="inline-block ml-1">
<TooltipWrapper side="top">
<template #content>
<span>{{ t('dialog.user.info.last_join') }} </span>
</template>
<span class="flex items-center ml-1">
<MapPin class="h-4 w-4 text-muted-foreground" />
<Timer class="text-muted-foreground" :epoch="lastJoin" />
</span>
</TooltipWrapper>
</span>
<span v-if="instanceInfoState.isValidInstance && !instance?.hasCapacityForYou" class="ml-1">
{{ t('dialog.user.info.instance_full') }}
</span>

View File

@@ -674,54 +674,29 @@
const groupInvitesModerationTable = reactive({
data: [],
tableProps: { stripe: true, size: 'small' },
pageSize: 15,
paginationProps: {
layout: 'sizes,prev,pager,next,total'
}
pageSize: 15
});
const groupJoinRequestsModerationTable = reactive({
data: [],
tableProps: { stripe: true, size: 'small' },
pageSize: 15,
paginationProps: {
layout: 'sizes,prev,pager,next,total'
}
pageSize: 15
});
const groupBlockedModerationTable = reactive({
data: [],
tableProps: { stripe: true, size: 'small' },
pageSize: 15,
paginationProps: {
small: true,
layout: 'sizes,prev,pager,next,total'
}
pageSize: 15
});
const groupLogsModerationTable = reactive({
data: [],
filters: [{ prop: ['description'], value: '' }],
tableProps: { stripe: true, size: 'small' },
pageSize: 15,
paginationProps: {
layout: 'sizes,prev,pager,next,total'
}
pageSize: 15
});
const groupBansModerationTable = reactive({
data: [],
filters: [{ prop: ['$displayName'], value: '' }],
tableProps: { stripe: true, size: 'small' },
pageSize: 15,
paginationProps: {
layout: 'sizes,prev,pager,next,total'
}
pageSize: 15
});
const groupMemberModerationTable = reactive({
data: [],
tableProps: { stripe: true, size: 'small' },
pageSize: 15,
paginationProps: {
layout: 'sizes,prev,pager,next,total'
}
pageSize: 15
});
const rolesText = (roleIds) => {

View File

@@ -67,8 +67,7 @@
previousInstances: [],
previousInstancesTable: {
data: [],
filters: [{ prop: 'displayName', value: '' }],
tableProps: { stripe: true, size: 'small', height: '400px' }
filters: [{ prop: 'displayName', value: '' }]
}
})
}

View File

@@ -65,7 +65,6 @@
<Pencil class="size-4" />
{{ t('dialog.user.actions.edit_pronouns') }}
</DropdownMenuItem>
<DropdownMenuSeparator />
</template>
<template v-else>
<template v-if="userDialog.isFriend">

View File

@@ -47,6 +47,7 @@
:on-refresh="() => refreshInstancePlayerCount(userDialog.$location.tag)" />
</template>
<Location
class="text-sm"
:location="userDialog.ref.location"
:traveling="userDialog.ref.travelingToLocation" />
</div>
@@ -212,7 +213,7 @@
<div class="detail">
<span class="name">{{ t('dialog.user.info.bio') }}</span>
<pre
class="extra"
class="extra truncate"
style="
font-family: inherit;
font-size: 12px;
@@ -1504,10 +1505,7 @@
});
const socialStatusHistoryTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table'
});

View File

@@ -1009,8 +1009,9 @@
"refresh_instance_info": "Refresh Instance Info",
"instance_queue": "Queue:",
"instance_users": "Users:",
"instance_friends_tooltip": "Friends in this instance",
"instance_game_version": "Game Version:",
"last_join": "Last Join:",
"last_join": "Last Join",
"instance_queuing_enabled": "Queuing Enabled",
"instance_disabled_content": "Disabled Content:",
"instance_creator": "Instance Creator",

View File

@@ -977,7 +977,7 @@
"instance_queue": "在排队等待的玩家:",
"instance_users": "房间玩家:",
"instance_game_version": "服务器版本:",
"last_join": "距离上次加入房间",
"last_join": "距离上次加入房间",
"instance_queuing_enabled": "允许排队加入",
"instance_disabled_content": "禁用的内容:",
"instance_creator": "房间建立者",

View File

@@ -18,40 +18,24 @@ export const useInviteStore = defineStore('Invite', () => {
const inviteMessageTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table',
visible: false
});
const inviteResponseMessageTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table',
visible: false
});
const inviteRequestMessageTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table',
visible: false
});
const inviteRequestResponseMessageTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table',
visible: false
});

View File

@@ -66,11 +66,6 @@ export const useNotificationStore = defineStore('Notification', () => {
value: ''
}
],
tableProps: {
stripe: true,
size: 'small',
defaultSort: null
},
pageSize: 20,
pageSizeLinked: true,
paginationProps: {

View File

@@ -103,10 +103,6 @@ export const usePhotonStore = defineStore('Photon', () => {
value: []
}
],
tableProps: {
stripe: true,
size: 'small'
},
pageSize: 10,
paginationProps: {
layout: 'sizes,prev,pager,next,total'
@@ -124,10 +120,6 @@ export const usePhotonStore = defineStore('Photon', () => {
value: []
}
],
tableProps: {
stripe: true,
size: 'small'
},
pageSize: 10,
paginationProps: {
layout: 'sizes,prev,pager,next,total'

View File

@@ -159,10 +159,6 @@
const avatarImportTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table'
});

View File

@@ -139,10 +139,6 @@
const friendImportTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table'
});

View File

@@ -165,10 +165,6 @@
const worldImportTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table'
});

View File

@@ -170,7 +170,7 @@
persistKey: 'gameLog',
data: gameLogDisplayData,
columns,
getRowId: (row) => `${row.type}:${row.rowId ?? row.displayName + row.location + row.time}`,
getRowId: (row, index) => `${row.type}:${row.rowId ?? index}`,
initialSorting: [],
initialPagination: {
pageIndex: 0,

View File

@@ -13,7 +13,7 @@
@click="showFullscreenImageDialog(currentInstanceWorld.ref.imageUrl)"
loading="lazy" />
<div style="margin-left: 10px; display: flex; flex-direction: column; min-width: 320px; width: 100%">
<div>
<div class="flex items-center">
<span
class="cursor-pointer"
style="
@@ -25,14 +25,15 @@
line-clamp: 1;
"
@click="showWorldDialog(currentInstanceWorld.ref.id)">
<Home
v-if="
currentUser.$homeLocation &&
currentUser.$homeLocation.worldId === currentInstanceWorld.ref.id
"
style="margin-right: 5px" />
{{ currentInstanceWorld.ref.name }}
</span>
{{ currentInstanceWorld.ref.name }}
<Home
v-if="
currentUser.$homeLocation &&
currentUser.$homeLocation.worldId === currentInstanceWorld.ref.id
"
class="ml-1" />
</div>
<div>
<span

View File

@@ -86,6 +86,14 @@
setHideNicknames();
saveOpenVROption();
" />
<simple-switch
:label="t('view.settings.appearance.appearance.striped_data_table_mode')"
:value="isDataTableStriped"
@change="toggleStripedDataTable" />
<simple-switch
:label="t('view.settings.appearance.appearance.toggle_pointer_on_hover')"
:value="showPointerOnHover"
@change="togglePointerOnHover" />
<simple-switch
:label="t('view.settings.appearance.appearance.age_gated_instances')"
:value="isAgeGatedInstancesVisible"
@@ -180,19 +188,12 @@
</ListboxRoot>
</Popover>
</div>
<simple-switch
:label="t('view.settings.appearance.appearance.striped_data_table_mode')"
:value="isDataTableStriped"
@change="toggleStripedDataTable" />
<div class="options-container-item">
<Button size="sm" variant="outline" @click="promptMaxTableSizeDialog">{{
t('view.settings.appearance.appearance.table_max_size')
}}</Button>
</div>
<simple-switch
:label="t('view.settings.appearance.appearance.toggle_pointer_on_hover')"
:value="showPointerOnHover"
@change="togglePointerOnHover" />
</div>
<div class="options-container">
<span class="header">{{ t('view.settings.appearance.timedate.header') }}</span>
@@ -451,15 +452,15 @@
import { ArrowRight, CheckIcon, ChevronDown, Info } from 'lucide-vue-next';
import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { computed, onBeforeUnmount, ref, watch } from 'vue';
import { useAppearanceSettingsStore, useFavoriteStore, useVrStore } from '@/stores';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { getLanguageName, languageCodes } from '@/localization';
import { APP_FONT_FAMILIES } from '@/shared/constants';
import { Button } from '@/components/ui/button';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
import { useAppearanceSettingsStore, useFavoriteStore, useVrStore } from '@/stores';
import { getLanguageName, languageCodes } from '@/localization';
import { APP_FONT_FAMILIES } from '@/shared/constants';
import PresetColorPicker from '@/components/PresetColorPicker.vue';
import SimpleSwitch from '../SimpleSwitch.vue';

View File

@@ -42,9 +42,8 @@
t('view.settings.general.vrcx_updater.change_build')
}}</Button>
</div>
<div v-if="!noUpdater" class="options-container-item">
<div v-if="!noUpdater" class="text-sm mt-2 flex flex-col align-baseline">
<span class="name">{{ t('view.settings.general.vrcx_updater.update_action') }}</span>
<br />
<ToggleGroup
type="single"
required

View File

@@ -74,14 +74,6 @@
const registryBackupTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small',
defaultSort: {
prop: 'date',
order: 'descending'
}
},
layout: 'table'
});

View File

@@ -4,7 +4,10 @@
<div style="flex: 1; padding: 10px; padding-left: 0">
<Popover v-model:open="isQuickSearchOpen">
<PopoverTrigger as-child>
<Input v-model="quickSearchQuery" :placeholder="t('side_panel.search_placeholder')" />
<Input
v-model="quickSearchQuery"
:placeholder="t('side_panel.search_placeholder')"
autocomplete="off" />
</PopoverTrigger>
<PopoverContent
side="bottom"

View File

@@ -93,10 +93,6 @@
const noteExportTable = ref({
data: [],
tableProps: {
stripe: true,
size: 'small'
},
layout: 'table'
});