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
+29 -11
View File
@@ -14,19 +14,24 @@
<Switch v-model="feedTable.vip" @update:modelValue="feedTableLookup" /> <Switch v-model="feedTable.vip" @update:modelValue="feedTableLookup" />
</TooltipWrapper> </TooltipWrapper>
</div> </div>
<el-select <Select
v-model="feedTable.filter"
multiple multiple
clearable :model-value="Array.isArray(feedTable.filter) ? feedTable.filter : []"
style="flex: 1" @update:modelValue="handleFeedFilterChange">
:placeholder="t('view.feed.filter_placeholder')" <SelectTrigger class="w-full" style="flex: 1">
@change="feedTableLookup"> <SelectValue :placeholder="t('view.feed.filter_placeholder')" />
<el-option </SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="type in ['GPS', 'Online', 'Offline', 'Status', 'Avatar', 'Bio']" v-for="type in ['GPS', 'Online', 'Offline', 'Status', 'Avatar', 'Bio']"
:key="type" :key="type"
:label="t('view.feed.filters.' + type)" :value="type">
:value="type"></el-option> {{ t('view.feed.filters.' + type) }}
</el-select> </SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField <InputGroupField
v-model="feedTable.search" v-model="feedTable.search"
:placeholder="t('view.feed.search_placeholder')" :placeholder="t('view.feed.search_placeholder')"
@@ -45,9 +50,17 @@
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue
} from '../../components/ui/select';
import { useAppearanceSettingsStore, useFeedStore, useVrcxStore } from '../../stores'; import { useAppearanceSettingsStore, useFeedStore, useVrcxStore } from '../../stores';
import { InputGroupField } from '../../components/ui/input-group';
import { DataTableLayout } from '../../components/ui/data-table'; import { DataTableLayout } from '../../components/ui/data-table';
import { InputGroupField } from '../../components/ui/input-group';
import { Switch } from '../../components/ui/switch'; import { Switch } from '../../components/ui/switch';
import { columns as baseColumns } from './columns.jsx'; import { columns as baseColumns } from './columns.jsx';
import { useDataTableScrollHeight } from '../../composables/useDataTableScrollHeight'; import { useDataTableScrollHeight } from '../../composables/useDataTableScrollHeight';
@@ -105,6 +118,11 @@
} }
}; };
function handleFeedFilterChange(value) {
feedTable.value.filter = Array.isArray(value) ? value : [];
feedTableLookup();
}
watch(pageSize, (size) => { watch(pageSize, (size) => {
if (pagination.value.pageSize === size) { if (pagination.value.pageSize === size) {
return; return;
+31 -13
View File
@@ -6,20 +6,32 @@
<TooltipWrapper side="bottom" :content="t('view.friend_list.favorites_only_tooltip')"> <TooltipWrapper side="bottom" :content="t('view.friend_list.favorites_only_tooltip')">
<Switch v-model="friendsListSearchFilterVIP" @update:modelValue="friendsListSearchChange" /> <Switch v-model="friendsListSearchFilterVIP" @update:modelValue="friendsListSearchChange" />
</TooltipWrapper> </TooltipWrapper>
<el-select <Select
v-model="friendsListSearchFilters"
multiple multiple
clearable :model-value="Array.isArray(friendsListSearchFilters) ? friendsListSearchFilters : []"
collapse-tags @update:modelValue="handleFriendListFilterChange">
style="margin: 0 10px; width: 150px" <SelectTrigger style="margin: 0 10px; width: 150px">
:placeholder="t('view.friend_list.filter_placeholder')" <SelectValue :placeholder="t('view.friend_list.filter_placeholder')" />
@change="friendsListSearchChange"> </SelectTrigger>
<el-option <SelectContent>
v-for="type in ['Display Name', 'User Name', 'Rank', 'Status', 'Bio', 'Note', 'Memo']" <SelectGroup>
<SelectItem
v-for="type in [
'Display Name',
'User Name',
'Rank',
'Status',
'Bio',
'Note',
'Memo'
]"
:key="type" :key="type"
:label="type" :value="type">
:value="type"></el-option> {{ type }}
</el-select> </SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField <InputGroupField
v-model="friendsListSearch" v-model="friendsListSearch"
:placeholder="t('view.friend_list.search_placeholder')" :placeholder="t('view.friend_list.search_placeholder')"
@@ -259,11 +271,12 @@
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, nextTick, reactive, ref, watch } from 'vue'; import { computed, nextTick, reactive, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { ElMessageBox } from 'element-plus';
import { InputGroupField } from '@/components/ui/input-group'; import { InputGroupField } from '@/components/ui/input-group';
import { Progress } from '@/components/ui/progress'; import { Progress } from '@/components/ui/progress';
import { ElMessageBox } from 'element-plus';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner'; import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@@ -568,6 +581,11 @@
friendsListTable.data = sortedData; friendsListTable.data = sortedData;
} }
function handleFriendListFilterChange(value) {
friendsListSearchFilters.value = Array.isArray(value) ? value : [];
friendsListSearchChange();
}
</script> </script>
<style scoped> <style scoped>
+29 -10
View File
@@ -8,14 +8,18 @@
:on-page-size-change="handlePageSizeChange"> :on-page-size-change="handlePageSizeChange">
<template #toolbar> <template #toolbar>
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div style="margin: 0 0 10px; display: flex; align-items: center">
<el-select <Select
v-model="friendLogTable.filters[0].value"
multiple multiple
clearable :model-value="
style="flex: 1" Array.isArray(friendLogTable.filters?.[0]?.value) ? friendLogTable.filters[0].value : []
:placeholder="t('view.friend_log.filter_placeholder')" "
@change="saveTableFilters"> @update:modelValue="handleFriendLogFilterChange">
<el-option <SelectTrigger class="w-full" style="flex: 1">
<SelectValue :placeholder="t('view.friend_log.filter_placeholder')" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="type in [ v-for="type in [
'Friend', 'Friend',
'Unfriend', 'Unfriend',
@@ -25,9 +29,12 @@
'TrustLevel' 'TrustLevel'
]" ]"
:key="type" :key="type"
:label="t('view.friend_log.filters.' + type)" :value="type">
:value="type" /> {{ t('view.friend_log.filters.' + type) }}
</el-select> </SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField <InputGroupField
v-model="friendLogTable.filters[1].value" v-model="friendLogTable.filters[1].value"
:placeholder="t('view.friend_log.search_placeholder')" :placeholder="t('view.friend_log.search_placeholder')"
@@ -46,6 +53,14 @@
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue
} from '../../components/ui/select';
import { useAppearanceSettingsStore, useFriendStore, useVrcxStore } from '../../stores'; import { useAppearanceSettingsStore, useFriendStore, useVrcxStore } from '../../stores';
import { DataTableLayout } from '../../components/ui/data-table'; import { DataTableLayout } from '../../components/ui/data-table';
import { InputGroupField } from '../../components/ui/input-group'; import { InputGroupField } from '../../components/ui/input-group';
@@ -129,6 +144,10 @@
function saveTableFilters() { function saveTableFilters() {
configRepository.setString('VRCX_friendLogTableFilters', JSON.stringify(friendLogTable.value.filters[0].value)); 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) { function deleteFriendLogPrompt(row) {
ElMessageBox.confirm('Continue? Delete Log', 'Confirm', { ElMessageBox.confirm('Continue? Delete Log', 'Confirm', {
confirmButtonText: 'Confirm', confirmButtonText: 'Confirm',
+21 -10
View File
@@ -14,14 +14,16 @@
<Switch v-model="gameLogTable.vip" @update:modelValue="gameLogTableLookup" /> <Switch v-model="gameLogTable.vip" @update:modelValue="gameLogTableLookup" />
</TooltipWrapper> </TooltipWrapper>
</div> </div>
<el-select <Select
v-model="gameLogTable.filter"
multiple multiple
clearable :model-value="Array.isArray(gameLogTable.filter) ? gameLogTable.filter : []"
style="flex: 1" @update:modelValue="handleGameLogFilterChange">
:placeholder="t('view.game_log.filter_placeholder')" <SelectTrigger class="w-full" style="flex: 1">
@change="gameLogTableLookup"> <SelectValue :placeholder="t('view.game_log.filter_placeholder')" />
<el-option </SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem
v-for="type in [ v-for="type in [
'Location', 'Location',
'OnPlayerJoined', 'OnPlayerJoined',
@@ -33,9 +35,12 @@
'ImageLoad' 'ImageLoad'
]" ]"
:key="type" :key="type"
:label="t('view.game_log.filters.' + type)" :value="type">
:value="type"></el-option> {{ t('view.game_log.filters.' + type) }}
</el-select> </SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField <InputGroupField
v-model="gameLogTable.search" v-model="gameLogTable.search"
:placeholder="t('view.game_log.search_placeholder')" :placeholder="t('view.game_log.search_placeholder')"
@@ -50,6 +55,7 @@
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { Switch } from '@/components/ui/switch'; import { Switch } from '@/components/ui/switch';
@@ -152,6 +158,11 @@
onDeletePrompt: deleteGameLogEntryPrompt onDeletePrompt: deleteGameLogEntryPrompt
}); });
function handleGameLogFilterChange(value) {
gameLogTable.value.filter = Array.isArray(value) ? value : [];
gameLogTableLookup();
}
const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes); const pageSizes = computed(() => appearanceSettingsStore.tablePageSizes);
const pageSize = computed(() => const pageSize = computed(() =>
gameLogTable.value.pageSizeLinked ? appearanceSettingsStore.tablePageSize : gameLogTable.value.pageSize gameLogTable.value.pageSizeLinked ? appearanceSettingsStore.tablePageSize : gameLogTable.value.pageSize
+25 -13
View File
@@ -1,19 +1,25 @@
<template> <template>
<div class="x-container" ref="moderationRef"> <div class="x-container" ref="moderationRef">
<div class="tool-slot"> <div class="tool-slot">
<el-select <Select
v-model="playerModerationTable.filters[0].value"
@change="saveTableFilters()"
multiple multiple
clearable :model-value="
style="flex: 1" Array.isArray(playerModerationTable.filters?.[0]?.value)
:placeholder="t('view.moderation.filter_placeholder')"> ? playerModerationTable.filters[0].value
<el-option : []
v-for="item in moderationTypes" "
:key="item" @update:modelValue="handleModerationFilterChange">
:label="t('view.moderation.filters.' + item)" <SelectTrigger class="w-full" style="flex: 1">
:value="item" /> <SelectValue :placeholder="t('view.moderation.filter_placeholder')" />
</el-select> </SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem v-for="item in moderationTypes" :key="item" :value="item">
{{ t('view.moderation.filters.' + item) }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField <InputGroupField
v-model="playerModerationTable.filters[1].value" v-model="playerModerationTable.filters[1].value"
:placeholder="t('view.moderation.search_placeholder')" :placeholder="t('view.moderation.search_placeholder')"
@@ -42,10 +48,11 @@
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupField } from '@/components/ui/input-group';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { InputGroupField } from '@/components/ui/input-group';
import { Refresh } from '@element-plus/icons-vue'; import { Refresh } from '@element-plus/icons-vue';
import { Spinner } from '@/components/ui/spinner'; import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia'; 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) { async function deletePlayerModeration(row) {
const args = await playerModerationRequest.deletePlayerModeration({ const args = await playerModerationRequest.deletePlayerModeration({
moderated: row.targetUserId, moderated: row.targetUserId,
+26 -11
View File
@@ -9,14 +9,20 @@
:on-page-size-change="handlePageSizeChange"> :on-page-size-change="handlePageSizeChange">
<template #toolbar> <template #toolbar>
<div style="margin: 0 0 10px; display: flex; align-items: center"> <div style="margin: 0 0 10px; display: flex; align-items: center">
<el-select <Select
v-model="notificationTable.filters[0].value"
multiple multiple
clearable :model-value="
style="flex: 1" Array.isArray(notificationTable.filters?.[0]?.value)
:placeholder="t('view.notification.filter_placeholder')" ? notificationTable.filters[0].value
@change="saveTableFilters"> : []
<el-option "
@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 [ v-for="type in [
'requestInvite', 'requestInvite',
'invite', 'invite',
@@ -39,9 +45,12 @@
'instance.closed' 'instance.closed'
]" ]"
:key="type" :key="type"
:label="t('view.notification.filters.' + type)" :value="type">
:value="type" /> {{ t('view.notification.filters.' + type) }}
</el-select> </SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<InputGroupField <InputGroupField
v-model="notificationTable.filters[1].value" v-model="notificationTable.filters[1].value"
:placeholder="t('view.notification.search_placeholder')" :placeholder="t('view.notification.search_placeholder')"
@@ -73,10 +82,11 @@
</template> </template>
<script setup> <script setup>
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { InputGroupField } from '@/components/ui/input-group';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import { InputGroupField } from '@/components/ui/input-group';
import { Refresh } from '@element-plus/icons-vue'; import { Refresh } from '@element-plus/icons-vue';
import { Spinner } from '@/components/ui/spinner'; import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -272,6 +282,11 @@
); );
} }
function handleNotificationFilterChange(value) {
notificationTable.value.filters[0].value = Array.isArray(value) ? value : [];
saveTableFilters();
}
function openNotificationLink(link) { function openNotificationLink(link) {
if (!link) { if (!link) {
return; return;
+57 -11
View File
@@ -1,16 +1,28 @@
<template> <template>
<div class="x-aside-container"> <div class="x-aside-container">
<div style="display: flex; align-items: baseline"> <div style="display: flex; align-items: baseline">
<el-select <div style="flex: 1; padding: 10px; padding-left: 0">
clearable <Popover v-model:open="isQuickSearchOpen">
<PopoverTrigger as-child>
<Input
v-model="quickSearchQuery"
:placeholder="t('side_panel.search_placeholder')" :placeholder="t('side_panel.search_placeholder')"
filterable @focus="handleQuickSearchFocus" />
remote </PopoverTrigger>
:remote-method="quickSearchRemoteMethod" <PopoverContent
popper-class="x-quick-search" side="bottom"
style="flex: 1; padding: 10px; padding-left: 0" align="start"
@change="quickSearchChange"> class="x-quick-search-popover w-(--reka-popover-trigger-width) p-2"
<el-option v-for="item in quickSearchItems" :key="item.value" :value="item.value" :label="item.label"> @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"> <div class="x-friend-item">
<template v-if="item.ref"> <template v-if="item.ref">
<div class="detail"> <div class="detail">
@@ -38,8 +50,14 @@
<span style="font-weight: bold">{{ item.label }}</span> <span style="font-weight: bold">{{ item.label }}</span>
</span> </span>
</div> </div>
</el-option> </button>
</el-select> <div v-if="quickSearchItems.length === 0" class="px-2 py-2 text-xs opacity-70">
No results
</div>
</div>
</PopoverContent>
</Popover>
</div>
<div> <div>
<TooltipWrapper side="bottom" :content="t('side_panel.refresh_tooltip')"> <TooltipWrapper side="bottom" :content="t('side_panel.refresh_tooltip')">
<Button <Button
@@ -76,7 +94,10 @@
</template> </template>
<script setup> <script setup>
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { ref, watch } from 'vue';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Refresh } from '@element-plus/icons-vue'; import { Refresh } from '@element-plus/icons-vue';
import { Spinner } from '@/components/ui/spinner'; import { Spinner } from '@/components/ui/spinner';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
@@ -94,6 +115,31 @@
const { quickSearchItems } = storeToRefs(useSearchStore()); const { quickSearchItems } = storeToRefs(useSearchStore());
const { inGameGroupOrder, groupInstances } = storeToRefs(useGroupStore()); const { inGameGroupOrder, groupInstances } = storeToRefs(useGroupStore());
const { t } = useI18n(); 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> </script>
<style scoped> <style scoped>