feat: add option to sort favorites world by player count (#674)

This commit is contained in:
pa
2026-03-16 13:37:54 +09:00
parent 9bf380f2fc
commit 2a5039b6c9
5 changed files with 50 additions and 17 deletions
+1
View File
@@ -744,6 +744,7 @@
"sort_favorite_by": "Sort Favorites by", "sort_favorite_by": "Sort Favorites by",
"sort_favorite_by_name": "Name", "sort_favorite_by_name": "Name",
"sort_favorite_by_date": "Date", "sort_favorite_by_date": "Date",
"sort_favorite_by_players": "Players",
"sort_instance_users_by": "Sort Instance Users by", "sort_instance_users_by": "Sort Instance Users by",
"sort_instance_users_by_time": "Time", "sort_instance_users_by_time": "Time",
"sort_instance_users_by_alphabet": "Alphabetical", "sort_instance_users_by_alphabet": "Alphabetical",
+3 -3
View File
@@ -2,7 +2,7 @@
<div class="x-container"> <div class="x-container">
<div class="flex flex-col h-full min-h-0 pb-0"> <div class="flex flex-col h-full min-h-0 pb-0">
<FavoritesToolbar <FavoritesToolbar
:sort-favorites="sortFavorites" :sort-value="sortFavorites ? 'date' : 'name'"
v-model:search-query="avatarFavoriteSearch" v-model:search-query="avatarFavoriteSearch"
:search-placeholder="t('view.favorite.avatars.search')" :search-placeholder="t('view.favorite.avatars.search')"
v-model:toolbar-menu-open="avatarToolbarMenuOpen" v-model:toolbar-menu-open="avatarToolbarMenuOpen"
@@ -12,7 +12,7 @@
v-model:card-spacing-value="avatarCardSpacingValue" v-model:card-spacing-value="avatarCardSpacingValue"
:card-spacing-percent="avatarCardSpacingPercent" :card-spacing-percent="avatarCardSpacingPercent"
:card-spacing-slider="avatarCardSpacingSlider" :card-spacing-slider="avatarCardSpacingSlider"
@update:sort-favorites="handleSortFavoritesChange" @update:sort-value="handleSortFavoritesChange"
@search="searchAvatarFavorites" @search="searchAvatarFavorites"
@import="handleAvatarImportClick" @import="handleAvatarImportClick"
@export="handleAvatarExportClick" /> @export="handleAvatarExportClick" />
@@ -606,7 +606,7 @@
* @param value * @param value
*/ */
function handleSortFavoritesChange(value) { function handleSortFavoritesChange(value) {
const next = Boolean(value); const next = value === 'date';
if (next !== sortFavorites.value) { if (next !== sortFavorites.value) {
setSortFavorites(); setSortFavorites();
} }
+3 -3
View File
@@ -2,7 +2,7 @@
<div class="x-container"> <div class="x-container">
<div class="flex flex-col h-full min-h-0 pb-0"> <div class="flex flex-col h-full min-h-0 pb-0">
<FavoritesToolbar <FavoritesToolbar
:sort-favorites="sortFavorites" :sort-value="sortFavorites ? 'date' : 'name'"
v-model:search-query="friendFavoriteSearch" v-model:search-query="friendFavoriteSearch"
:search-placeholder="t('view.favorite.worlds.search')" :search-placeholder="t('view.favorite.worlds.search')"
v-model:toolbar-menu-open="friendToolbarMenuOpen" v-model:toolbar-menu-open="friendToolbarMenuOpen"
@@ -12,7 +12,7 @@
v-model:card-spacing-value="friendCardSpacingValue" v-model:card-spacing-value="friendCardSpacingValue"
:card-spacing-percent="friendCardSpacingPercent" :card-spacing-percent="friendCardSpacingPercent"
:card-spacing-slider="friendCardSpacingSlider" :card-spacing-slider="friendCardSpacingSlider"
@update:sort-favorites="handleSortFavoritesChange" @update:sort-value="handleSortFavoritesChange"
@search="searchFriendFavorites" @search="searchFriendFavorites"
@import="handleFriendImportClick" @import="handleFriendImportClick"
@export="handleFriendExportClick" /> @export="handleFriendExportClick" />
@@ -490,7 +490,7 @@
* @param value * @param value
*/ */
function handleSortFavoritesChange(value) { function handleSortFavoritesChange(value) {
const next = Boolean(value); const next = value === 'date';
if (next !== sortFavorites.value) { if (next !== sortFavorites.value) {
setSortFavorites(); setSortFavorites();
} }
+30 -6
View File
@@ -2,7 +2,8 @@
<div class="x-container"> <div class="x-container">
<div class="flex flex-col h-full min-h-0 pb-0"> <div class="flex flex-col h-full min-h-0 pb-0">
<FavoritesToolbar <FavoritesToolbar
:sort-favorites="sortFavorites" :sort-value="worldSortValue"
:extra-sort-options="worldExtraSortOptions"
v-model:search-query="worldFavoriteSearch" v-model:search-query="worldFavoriteSearch"
:search-placeholder="t('view.favorite.worlds.search')" :search-placeholder="t('view.favorite.worlds.search')"
v-model:toolbar-menu-open="worldToolbarMenuOpen" v-model:toolbar-menu-open="worldToolbarMenuOpen"
@@ -12,7 +13,7 @@
v-model:card-spacing-value="worldCardSpacingValue" v-model:card-spacing-value="worldCardSpacingValue"
:card-spacing-percent="worldCardSpacingPercent" :card-spacing-percent="worldCardSpacingPercent"
:card-spacing-slider="worldCardSpacingSlider" :card-spacing-slider="worldCardSpacingSlider"
@update:sort-favorites="handleSortFavoritesChange" @update:sort-value="handleSortValueChange"
@search="searchWorldFavorites" @search="searchWorldFavorites"
@import="handleWorldImportClick" @import="handleWorldImportClick"
@export="handleWorldExportClick" /> @export="handleWorldExportClick" />
@@ -500,6 +501,16 @@
const refreshCancelToken = ref(null); const refreshCancelToken = ref(null);
const worldEditMode = ref(false); const worldEditMode = ref(false);
const worldToolbarMenuOpen = ref(false); const worldToolbarMenuOpen = ref(false);
const worldSortMode = ref('none');
const worldExtraSortOptions = computed(() => [
{ value: 'players', label: t('view.settings.appearance.appearance.sort_favorite_by_players') }
]);
const worldSortValue = computed(() => {
if (worldSortMode.value === 'players') return 'players';
return sortFavorites.value ? 'date' : 'name';
});
const { const {
activeGroupMenu, activeGroupMenu,
@@ -589,14 +600,22 @@
if (!activeRemoteGroup.value) { if (!activeRemoteGroup.value) {
return []; return [];
} }
return groupedWorldFavorites.value[activeRemoteGroup.value.key] || []; const list = groupedWorldFavorites.value[activeRemoteGroup.value.key] || [];
if (worldSortMode.value === 'players') {
return list.toSorted((a, b) => (b.ref?.occupants ?? 0) - (a.ref?.occupants ?? 0));
}
return list;
}); });
const currentLocalFavorites = computed(() => { const currentLocalFavorites = computed(() => {
if (!activeLocalGroupName.value) { if (!activeLocalGroupName.value) {
return []; return [];
} }
return localWorldFavorites.value[activeLocalGroupName.value] || []; const list = localWorldFavorites.value[activeLocalGroupName.value] || [];
if (worldSortMode.value === 'players') {
return list.toSorted((a, b) => (b.occupants ?? 0) - (a.occupants ?? 0));
}
return list;
}); });
const localFavoritesViewportRef = ref(null); const localFavoritesViewportRef = ref(null);
@@ -683,8 +702,13 @@
* *
* @param value * @param value
*/ */
function handleSortFavoritesChange(value) { function handleSortValueChange(value) {
const next = Boolean(value); if (value === 'players') {
worldSortMode.value = 'players';
return;
}
worldSortMode.value = 'none';
const next = value === 'date';
if (next !== sortFavorites.value) { if (next !== sortFavorites.value) {
setSortFavorites(); setSortFavorites();
} }
@@ -1,7 +1,7 @@
<template> <template>
<div class="flex items-center justify-between gap-3 mb-3 flex-wrap"> <div class="flex items-center justify-between gap-3 mb-3 flex-wrap">
<div> <div>
<Select :model-value="sortFavorites" @update:modelValue="$emit('update:sortFavorites', $event)"> <Select :model-value="sortValue" @update:modelValue="$emit('update:sortValue', $event)">
<SelectTrigger size="sm" class="min-w-[200px]"> <SelectTrigger size="sm" class="min-w-[200px]">
<span class="flex items-center gap-2"> <span class="flex items-center gap-2">
<ArrowUpDown class="h-4 w-4" /> <ArrowUpDown class="h-4 w-4" />
@@ -11,15 +11,22 @@
<SelectContent> <SelectContent>
<SelectGroup> <SelectGroup>
<SelectItem <SelectItem
:value="false" value="name"
:text-value="t('view.settings.appearance.appearance.sort_favorite_by_name')"> :text-value="t('view.settings.appearance.appearance.sort_favorite_by_name')">
{{ t('view.settings.appearance.appearance.sort_favorite_by_name') }} {{ t('view.settings.appearance.appearance.sort_favorite_by_name') }}
</SelectItem> </SelectItem>
<SelectItem <SelectItem
:value="true" value="date"
:text-value="t('view.settings.appearance.appearance.sort_favorite_by_date')"> :text-value="t('view.settings.appearance.appearance.sort_favorite_by_date')">
{{ t('view.settings.appearance.appearance.sort_favorite_by_date') }} {{ t('view.settings.appearance.appearance.sort_favorite_by_date') }}
</SelectItem> </SelectItem>
<SelectItem
v-for="option in extraSortOptions"
:key="option.value"
:value="option.value"
:text-value="option.label">
{{ option.label }}
</SelectItem>
</SelectGroup> </SelectGroup>
</SelectContent> </SelectContent>
</Select> </Select>
@@ -91,7 +98,8 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
defineProps({ defineProps({
sortFavorites: { type: Boolean, default: false }, sortValue: { type: String, default: 'name' },
extraSortOptions: { type: Array, default: () => [] },
searchQuery: { type: String, default: '' }, searchQuery: { type: String, default: '' },
searchPlaceholder: { type: String, default: '' }, searchPlaceholder: { type: String, default: '' },
toolbarMenuOpen: { type: Boolean, default: false }, toolbarMenuOpen: { type: Boolean, default: false },
@@ -104,7 +112,7 @@
}); });
defineEmits([ defineEmits([
'update:sortFavorites', 'update:sortValue',
'update:searchQuery', 'update:searchQuery',
'update:toolbarMenuOpen', 'update:toolbarMenuOpen',
'update:cardScaleValue', 'update:cardScaleValue',