replace el-select

This commit is contained in:
pa
2026-01-13 13:41:11 +09:00
committed by Natsumi
parent 4fbae859f4
commit 9e693e0e97
7 changed files with 290 additions and 151 deletions

View File

@@ -14,19 +14,24 @@
<Switch v-model="feedTable.vip" @update:modelValue="feedTableLookup" />
</TooltipWrapper>
</div>
<el-select
v-model="feedTable.filter"
<Select
multiple
clearable
style="flex: 1"
:placeholder="t('view.feed.filter_placeholder')"
@change="feedTableLookup">
<el-option
v-for="type in ['GPS', 'Online', 'Offline', 'Status', 'Avatar', 'Bio']"
:key="type"
:label="t('view.feed.filters.' + type)"
:value="type"></el-option>
</el-select>
:model-value="Array.isArray(feedTable.filter) ? feedTable.filter : []"
@update:modelValue="handleFeedFilterChange">
<SelectTrigger class="w-full" style="flex: 1">
<SelectValue :placeholder="t('view.feed.filter_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="type in ['GPS', 'Online', 'Offline', 'Status', 'Avatar', 'Bio']"
:key="type"
:value="type">
{{ t('view.feed.filters.' + type) }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField
v-model="feedTable.search"
:placeholder="t('view.feed.search_placeholder')"
@@ -45,9 +50,17 @@
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue
} from '../../components/ui/select';
import { useAppearanceSettingsStore, useFeedStore, useVrcxStore } from '../../stores';
import { InputGroupField } from '../../components/ui/input-group';
import { DataTableLayout } from '../../components/ui/data-table';
import { InputGroupField } from '../../components/ui/input-group';
import { Switch } from '../../components/ui/switch';
import { columns as baseColumns } from './columns.jsx';
import { useDataTableScrollHeight } from '../../composables/useDataTableScrollHeight';
@@ -105,6 +118,11 @@
}
};
function handleFeedFilterChange(value) {
feedTable.value.filter = Array.isArray(value) ? value : [];
feedTableLookup();
}
watch(pageSize, (size) => {
if (pagination.value.pageSize === size) {
return;

View File

@@ -6,20 +6,32 @@
<TooltipWrapper side="bottom" :content="t('view.friend_list.favorites_only_tooltip')">
<Switch v-model="friendsListSearchFilterVIP" @update:modelValue="friendsListSearchChange" />
</TooltipWrapper>
<el-select
v-model="friendsListSearchFilters"
<Select
multiple
clearable
collapse-tags
style="margin: 0 10px; width: 150px"
:placeholder="t('view.friend_list.filter_placeholder')"
@change="friendsListSearchChange">
<el-option
v-for="type in ['Display Name', 'User Name', 'Rank', 'Status', 'Bio', 'Note', 'Memo']"
:key="type"
:label="type"
:value="type"></el-option>
</el-select>
:model-value="Array.isArray(friendsListSearchFilters) ? friendsListSearchFilters : []"
@update:modelValue="handleFriendListFilterChange">
<SelectTrigger style="margin: 0 10px; width: 150px">
<SelectValue :placeholder="t('view.friend_list.filter_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="type in [
'Display Name',
'User Name',
'Rank',
'Status',
'Bio',
'Note',
'Memo'
]"
:key="type"
:value="type">
{{ type }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField
v-model="friendsListSearch"
:placeholder="t('view.friend_list.search_placeholder')"
@@ -259,11 +271,12 @@
</template>
<script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, nextTick, reactive, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { InputGroupField } from '@/components/ui/input-group';
import { Progress } from '@/components/ui/progress';
import { ElMessageBox } from 'element-plus';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
@@ -568,6 +581,11 @@
friendsListTable.data = sortedData;
}
function handleFriendListFilterChange(value) {
friendsListSearchFilters.value = Array.isArray(value) ? value : [];
friendsListSearchChange();
}
</script>
<style scoped>

View File

@@ -8,26 +8,33 @@
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="margin: 0 0 10px; display: flex; align-items: center">
<el-select
v-model="friendLogTable.filters[0].value"
<Select
multiple
clearable
style="flex: 1"
:placeholder="t('view.friend_log.filter_placeholder')"
@change="saveTableFilters">
<el-option
v-for="type in [
'Friend',
'Unfriend',
'FriendRequest',
'CancelFriendRequest',
'DisplayName',
'TrustLevel'
]"
:key="type"
:label="t('view.friend_log.filters.' + type)"
:value="type" />
</el-select>
:model-value="
Array.isArray(friendLogTable.filters?.[0]?.value) ? friendLogTable.filters[0].value : []
"
@update:modelValue="handleFriendLogFilterChange">
<SelectTrigger class="w-full" style="flex: 1">
<SelectValue :placeholder="t('view.friend_log.filter_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="type in [
'Friend',
'Unfriend',
'FriendRequest',
'CancelFriendRequest',
'DisplayName',
'TrustLevel'
]"
:key="type"
:value="type">
{{ t('view.friend_log.filters.' + type) }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField
v-model="friendLogTable.filters[1].value"
:placeholder="t('view.friend_log.search_placeholder')"
@@ -46,6 +53,14 @@
import dayjs from 'dayjs';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue
} from '../../components/ui/select';
import { useAppearanceSettingsStore, useFriendStore, useVrcxStore } from '../../stores';
import { DataTableLayout } from '../../components/ui/data-table';
import { InputGroupField } from '../../components/ui/input-group';
@@ -129,6 +144,10 @@
function saveTableFilters() {
configRepository.setString('VRCX_friendLogTableFilters', JSON.stringify(friendLogTable.value.filters[0].value));
}
function handleFriendLogFilterChange(value) {
friendLogTable.value.filters[0].value = Array.isArray(value) ? value : [];
saveTableFilters();
}
function deleteFriendLogPrompt(row) {
ElMessageBox.confirm('Continue? Delete Log', 'Confirm', {
confirmButtonText: 'Confirm',

View File

@@ -14,28 +14,33 @@
<Switch v-model="gameLogTable.vip" @update:modelValue="gameLogTableLookup" />
</TooltipWrapper>
</div>
<el-select
v-model="gameLogTable.filter"
<Select
multiple
clearable
style="flex: 1"
:placeholder="t('view.game_log.filter_placeholder')"
@change="gameLogTableLookup">
<el-option
v-for="type in [
'Location',
'OnPlayerJoined',
'OnPlayerLeft',
'VideoPlay',
'Event',
'External',
'StringLoad',
'ImageLoad'
]"
:key="type"
:label="t('view.game_log.filters.' + type)"
:value="type"></el-option>
</el-select>
:model-value="Array.isArray(gameLogTable.filter) ? gameLogTable.filter : []"
@update:modelValue="handleGameLogFilterChange">
<SelectTrigger class="w-full" style="flex: 1">
<SelectValue :placeholder="t('view.game_log.filter_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="type in [
'Location',
'OnPlayerJoined',
'OnPlayerLeft',
'VideoPlay',
'Event',
'External',
'StringLoad',
'ImageLoad'
]"
:key="type"
:value="type">
{{ t('view.game_log.filters.' + type) }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField
v-model="gameLogTable.search"
:placeholder="t('view.game_log.search_placeholder')"
@@ -50,6 +55,7 @@
</template>
<script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus';
import { Switch } from '@/components/ui/switch';
@@ -152,6 +158,11 @@
onDeletePrompt: deleteGameLogEntryPrompt
});
function handleGameLogFilterChange(value) {
gameLogTable.value.filter = Array.isArray(value) ? value : [];
gameLogTableLookup();
}
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() =>
gameLogTable.value.pageSizeLinked ? appearanceSettingsStore.tablePageSize : gameLogTable.value.pageSize

View File

@@ -1,19 +1,25 @@
<template>
<div class="x-container" ref="moderationRef">
<div class="tool-slot">
<el-select
v-model="playerModerationTable.filters[0].value"
@change="saveTableFilters()"
<Select
multiple
clearable
style="flex: 1"
:placeholder="t('view.moderation.filter_placeholder')">
<el-option
v-for="item in moderationTypes"
:key="item"
:label="t('view.moderation.filters.' + item)"
:value="item" />
</el-select>
:model-value="
Array.isArray(playerModerationTable.filters?.[0]?.value)
? playerModerationTable.filters[0].value
: []
"
@update:modelValue="handleModerationFilterChange">
<SelectTrigger class="w-full" style="flex: 1">
<SelectValue :placeholder="t('view.moderation.filter_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem v-for="item in moderationTypes" :key="item" :value="item">
{{ t('view.moderation.filters.' + item) }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField
v-model="playerModerationTable.filters[1].value"
:placeholder="t('view.moderation.search_placeholder')"
@@ -42,10 +48,11 @@
</template>
<script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
import { InputGroupField } from '@/components/ui/input-group';
import { ElMessageBox } from 'element-plus';
import { InputGroupField } from '@/components/ui/input-group';
import { Refresh } from '@element-plus/icons-vue';
import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia';
@@ -89,6 +96,11 @@
);
}
function handleModerationFilterChange(value) {
playerModerationTable.value.filters[0].value = Array.isArray(value) ? value : [];
saveTableFilters();
}
async function deletePlayerModeration(row) {
const args = await playerModerationRequest.deletePlayerModeration({
moderated: row.targetUserId,

View File

@@ -9,39 +9,48 @@
:on-page-size-change="handlePageSizeChange">
<template #toolbar>
<div style="margin: 0 0 10px; display: flex; align-items: center">
<el-select
v-model="notificationTable.filters[0].value"
<Select
multiple
clearable
style="flex: 1"
:placeholder="t('view.notification.filter_placeholder')"
@change="saveTableFilters">
<el-option
v-for="type in [
'requestInvite',
'invite',
'requestInviteResponse',
'inviteResponse',
'friendRequest',
'ignoredFriendRequest',
'message',
'boop',
'event.announcement',
'groupChange',
'group.announcement',
'group.informative',
'group.invite',
'group.joinRequest',
'group.transfer',
'group.queueReady',
'moderation.warning.group',
'moderation.report.closed',
'instance.closed'
]"
:key="type"
:label="t('view.notification.filters.' + type)"
:value="type" />
</el-select>
:model-value="
Array.isArray(notificationTable.filters?.[0]?.value)
? notificationTable.filters[0].value
: []
"
@update:modelValue="handleNotificationFilterChange">
<SelectTrigger class="w-full" style="flex: 1">
<SelectValue :placeholder="t('view.notification.filter_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="type in [
'requestInvite',
'invite',
'requestInviteResponse',
'inviteResponse',
'friendRequest',
'ignoredFriendRequest',
'message',
'boop',
'event.announcement',
'groupChange',
'group.announcement',
'group.informative',
'group.invite',
'group.joinRequest',
'group.transfer',
'group.queueReady',
'moderation.warning.group',
'moderation.report.closed',
'instance.closed'
]"
:key="type"
:value="type">
{{ t('view.notification.filters.' + type) }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField
v-model="notificationTable.filters[1].value"
:placeholder="t('view.notification.search_placeholder')"
@@ -73,10 +82,11 @@
</template>
<script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
import { InputGroupField } from '@/components/ui/input-group';
import { ElMessageBox } from 'element-plus';
import { InputGroupField } from '@/components/ui/input-group';
import { Refresh } from '@element-plus/icons-vue';
import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia';
@@ -272,6 +282,11 @@
);
}
function handleNotificationFilterChange(value) {
notificationTable.value.filters[0].value = Array.isArray(value) ? value : [];
saveTableFilters();
}
function openNotificationLink(link) {
if (!link) {
return;

View File

@@ -1,45 +1,63 @@
<template>
<div class="x-aside-container">
<div style="display: flex; align-items: baseline">
<el-select
clearable
:placeholder="t('side_panel.search_placeholder')"
filterable
remote
:remote-method="quickSearchRemoteMethod"
popper-class="x-quick-search"
style="flex: 1; padding: 10px; padding-left: 0"
@change="quickSearchChange">
<el-option v-for="item in quickSearchItems" :key="item.value" :value="item.value" :label="item.label">
<div class="x-friend-item">
<template v-if="item.ref">
<div class="detail">
<span class="name" :style="{ color: item.ref.$userColour }">{{
item.ref.displayName
}}</span>
<span v-if="!item.ref.isFriend" class="extra"></span>
<span v-else-if="item.ref.state === 'offline'" class="extra">{{
t('side_panel.search_result_active')
}}</span>
<span v-else-if="item.ref.state === 'active'" class="extra">{{
t('side_panel.search_result_offline')
}}</span>
<Location
v-else
class="extra"
:location="item.ref.location"
:traveling="item.ref.travelingToLocation"
:link="false" />
<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')"
@focus="handleQuickSearchFocus" />
</PopoverTrigger>
<PopoverContent
side="bottom"
align="start"
class="x-quick-search-popover w-(--reka-popover-trigger-width) p-2"
@open-auto-focus.prevent
@close-auto-focus.prevent>
<div class="max-h-80 overflow-auto">
<button
v-for="item in quickSearchItems"
:key="item.value"
type="button"
class="w-full bg-transparent p-0 text-left"
@mousedown.prevent
@click="handleQuickSearchSelect(item.value)">
<div class="x-friend-item">
<template v-if="item.ref">
<div class="detail">
<span class="name" :style="{ color: item.ref.$userColour }">{{
item.ref.displayName
}}</span>
<span v-if="!item.ref.isFriend" class="extra"></span>
<span v-else-if="item.ref.state === 'offline'" class="extra">{{
t('side_panel.search_result_active')
}}</span>
<span v-else-if="item.ref.state === 'active'" class="extra">{{
t('side_panel.search_result_offline')
}}</span>
<Location
v-else
class="extra"
:location="item.ref.location"
:traveling="item.ref.travelingToLocation"
:link="false" />
</div>
<img :src="userImage(item.ref)" class="avatar" loading="lazy" />
</template>
<span v-else>
{{ t('side_panel.search_result_more') }}
<span style="font-weight: bold">{{ item.label }}</span>
</span>
</div>
</button>
<div v-if="quickSearchItems.length === 0" class="px-2 py-2 text-xs opacity-70">
No results
</div>
<img :src="userImage(item.ref)" class="avatar" loading="lazy" />
</template>
<span v-else>
{{ t('side_panel.search_result_more') }}
<span style="font-weight: bold">{{ item.label }}</span>
</span>
</div>
</el-option>
</el-select>
</div>
</PopoverContent>
</Popover>
</div>
<div>
<TooltipWrapper side="bottom" :content="t('side_panel.refresh_tooltip')">
<Button
@@ -76,7 +94,10 @@
</template>
<script setup>
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Refresh } from '@element-plus/icons-vue';
import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia';
@@ -94,6 +115,31 @@
const { quickSearchItems } = storeToRefs(useSearchStore());
const { inGameGroupOrder, groupInstances } = storeToRefs(useGroupStore());
const { t } = useI18n();
const quickSearchQuery = ref('');
const isQuickSearchOpen = ref(false);
watch(
quickSearchQuery,
(value) => {
quickSearchRemoteMethod(String(value ?? ''));
},
{ immediate: true }
);
function handleQuickSearchFocus() {
isQuickSearchOpen.value = true;
quickSearchRemoteMethod(String(quickSearchQuery.value ?? ''));
}
function handleQuickSearchSelect(value) {
if (!value) {
return;
}
isQuickSearchOpen.value = false;
quickSearchQuery.value = '';
quickSearchChange(String(value));
}
</script>
<style scoped>