mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-29 19:53:47 +02:00
replace el-dropdown
This commit is contained in:
@@ -1326,6 +1326,8 @@ i.x-status-icon.red {
|
|||||||
.options-container-item {
|
.options-container-item {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.options-container-item .name {
|
.options-container-item .name {
|
||||||
|
|||||||
@@ -54,64 +54,60 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button
|
<div class="flex justify-end">
|
||||||
|
<Button
|
||||||
|
class="mr-1.5"
|
||||||
|
variant="outline"
|
||||||
:disabled="!checkCanInvite(launchDialog.location)"
|
:disabled="!checkCanInvite(launchDialog.location)"
|
||||||
@click="showInviteDialog(launchDialog.location)">
|
@click="showInviteDialog(launchDialog.location)">
|
||||||
{{ t('dialog.launch.invite') }}
|
{{ t('dialog.launch.invite') }}
|
||||||
</el-button>
|
</Button>
|
||||||
<template v-if="canOpenInstanceInGame">
|
<Button
|
||||||
<el-button
|
v-if="canOpenInstanceInGame"
|
||||||
|
variant="outline"
|
||||||
:disabled="!launchDialog.secureOrShortName"
|
:disabled="!launchDialog.secureOrShortName"
|
||||||
@click="handleAttachGame(launchDialog.location, launchDialog.shortName)">
|
@click="handleAttachGame(launchDialog.location, launchDialog.shortName)">
|
||||||
{{ t('dialog.launch.open_ingame') }}
|
{{ t('dialog.launch.open_ingame') }}
|
||||||
</el-button>
|
</Button>
|
||||||
<el-dropdown
|
<Button
|
||||||
split-button
|
v-else
|
||||||
type="primary"
|
variant="outline"
|
||||||
:disabled="!launchDialog.secureOrShortName"
|
|
||||||
@click="handleLaunchDefault(launchDialog.location, launchDialog.shortName)"
|
|
||||||
@command="(cmd) => handleLaunchCommand(cmd, launchDialog.location, launchDialog.shortName)">
|
|
||||||
{{ launchModeLabel }}
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item :command="launchDialog.desktop ? 'vr' : 'desktop'">
|
|
||||||
{{
|
|
||||||
launchDialog.desktop
|
|
||||||
? t('dialog.launch.launch')
|
|
||||||
: t('dialog.launch.start_as_desktop')
|
|
||||||
}}
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<el-button
|
|
||||||
class="mr-1.25"
|
class="mr-1.25"
|
||||||
:disabled="!launchDialog.secureOrShortName"
|
:disabled="!launchDialog.secureOrShortName"
|
||||||
@click="selfInvite(launchDialog.location, launchDialog.shortName)">
|
@click="selfInvite(launchDialog.location, launchDialog.shortName)">
|
||||||
{{ t('dialog.launch.self_invite') }}
|
{{ t('dialog.launch.self_invite') }}
|
||||||
</el-button>
|
</Button>
|
||||||
<el-dropdown
|
<ButtonGroup>
|
||||||
split-button
|
<Button
|
||||||
type="primary"
|
|
||||||
:disabled="!launchDialog.secureOrShortName"
|
:disabled="!launchDialog.secureOrShortName"
|
||||||
@click="handleLaunchDefault(launchDialog.location, launchDialog.shortName)"
|
@click="handleLaunchDefault(launchDialog.location, launchDialog.shortName)">
|
||||||
@command="(cmd) => handleLaunchCommand(cmd, launchDialog.location, launchDialog.shortName)">
|
|
||||||
{{ launchModeLabel }}
|
{{ launchModeLabel }}
|
||||||
<template #dropdown>
|
</Button>
|
||||||
<el-dropdown-menu>
|
<DropdownMenu>
|
||||||
<el-dropdown-item :command="launchDialog.desktop ? 'vr' : 'desktop'">
|
<DropdownMenuTrigger as-child>
|
||||||
|
<Button size="icon" :disabled="!launchDialog.secureOrShortName" aria-label="More options">
|
||||||
|
<MoreHorizontal class="size-4" />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="end" class="w-52">
|
||||||
|
<DropdownMenuItem
|
||||||
|
@click="
|
||||||
|
handleLaunchCommand(
|
||||||
|
launchDialog.desktop ? 'vr' : 'desktop',
|
||||||
|
launchDialog.location,
|
||||||
|
launchDialog.shortName
|
||||||
|
)
|
||||||
|
">
|
||||||
{{
|
{{
|
||||||
launchDialog.desktop
|
launchDialog.desktop
|
||||||
? t('dialog.launch.launch')
|
? t('dialog.launch.launch')
|
||||||
: t('dialog.launch.start_as_desktop')
|
: t('dialog.launch.start_as_desktop')
|
||||||
}}
|
}}
|
||||||
</el-dropdown-item>
|
</DropdownMenuItem>
|
||||||
</el-dropdown-menu>
|
</DropdownMenuContent>
|
||||||
</template>
|
</DropdownMenu>
|
||||||
</el-dropdown>
|
</ButtonGroup>
|
||||||
</template>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<InviteDialog :invite-dialog="inviteDialog" @closeInviteDialog="closeInviteDialog" />
|
<InviteDialog :invite-dialog="inviteDialog" @closeInviteDialog="closeInviteDialog" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@@ -119,8 +115,17 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue';
|
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue';
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger
|
||||||
|
} from '@/components/ui/dropdown-menu';
|
||||||
import { CopyDocument, Warning } from '@element-plus/icons-vue';
|
import { CopyDocument, Warning } from '@element-plus/icons-vue';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { ButtonGroup } from '@/components/ui/button-group';
|
||||||
import { ElMessageBox } from 'element-plus';
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
import { MoreHorizontal } from 'lucide-vue-next';
|
||||||
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';
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
import { buttonGroupVariants } from '.';
|
import { buttonGroupVariants } from '.';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
class: { type: null, required: false },
|
class: { type: null, required: false },
|
||||||
orientation: { type: null, required: false }
|
orientation: { type: null, required: false }
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { reactiveOmit } from '@vueuse/core';
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
orientation: { type: String, required: false, default: 'vertical' },
|
orientation: { type: String, required: false, default: 'vertical' },
|
||||||
decorative: { type: Boolean, required: false },
|
decorative: { type: Boolean, required: false },
|
||||||
asChild: { type: Boolean, required: false },
|
asChild: { type: Boolean, required: false },
|
||||||
as: { type: null, required: false },
|
as: { type: null, required: false },
|
||||||
class: { type: null, required: false }
|
class: { type: null, required: false }
|
||||||
});
|
});
|
||||||
const delegatedProps = reactiveOmit(props, 'class');
|
const delegatedProps = reactiveOmit(props, 'class');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Primitive } from 'reka-ui';
|
import { Primitive } from 'reka-ui';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
class: { type: null, required: false },
|
class: { type: null, required: false },
|
||||||
orientation: { type: null, required: false },
|
orientation: { type: null, required: false },
|
||||||
asChild: { type: Boolean, required: false },
|
asChild: { type: Boolean, required: false },
|
||||||
as: { type: null, required: false, default: 'div' }
|
as: { type: null, required: false, default: 'div' }
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { SelectRoot, useForwardPropsEmits } from "reka-ui";
|
import { SelectRoot, useForwardPropsEmits } from 'reka-ui';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
open: { type: Boolean, required: false },
|
open: { type: Boolean, required: false },
|
||||||
defaultOpen: { type: Boolean, required: false },
|
defaultOpen: { type: Boolean, required: false },
|
||||||
defaultValue: { type: null, required: false },
|
defaultValue: { type: null, required: false },
|
||||||
@@ -12,11 +12,11 @@ const props = defineProps({
|
|||||||
autocomplete: { type: String, required: false },
|
autocomplete: { type: String, required: false },
|
||||||
disabled: { type: Boolean, required: false },
|
disabled: { type: Boolean, required: false },
|
||||||
name: { type: String, required: false },
|
name: { type: String, required: false },
|
||||||
required: { type: Boolean, required: false },
|
required: { type: Boolean, required: false }
|
||||||
});
|
});
|
||||||
const emits = defineEmits(["update:modelValue", "update:open"]);
|
const emits = defineEmits(['update:modelValue', 'update:open']);
|
||||||
|
|
||||||
const forwarded = useForwardPropsEmits(props, emits);
|
const forwarded = useForwardPropsEmits(props, emits);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,21 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { reactiveOmit } from "@vueuse/core";
|
import { SelectContent, SelectPortal, SelectViewport, useForwardPropsEmits } from 'reka-ui';
|
||||||
import {
|
import { cn } from '@/lib/utils';
|
||||||
SelectContent,
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
SelectPortal,
|
|
||||||
SelectViewport,
|
|
||||||
useForwardPropsEmits,
|
|
||||||
} from "reka-ui";
|
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import { SelectScrollDownButton, SelectScrollUpButton } from ".";
|
|
||||||
|
|
||||||
defineOptions({
|
import { SelectScrollDownButton, SelectScrollUpButton } from '.';
|
||||||
inheritAttrs: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const props = defineProps({
|
defineOptions({
|
||||||
|
inheritAttrs: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
forceMount: { type: Boolean, required: false },
|
forceMount: { type: Boolean, required: false },
|
||||||
position: { type: String, required: false, default: "popper" },
|
position: { type: String, required: false, default: 'popper' },
|
||||||
bodyLock: { type: Boolean, required: false },
|
bodyLock: { type: Boolean, required: false },
|
||||||
side: { type: null, required: false },
|
side: { type: null, required: false },
|
||||||
sideOffset: { type: Number, required: false },
|
sideOffset: { type: Number, required: false },
|
||||||
@@ -37,17 +33,13 @@ const props = defineProps({
|
|||||||
asChild: { type: Boolean, required: false },
|
asChild: { type: Boolean, required: false },
|
||||||
as: { type: null, required: false },
|
as: { type: null, required: false },
|
||||||
disableOutsidePointerEvents: { type: Boolean, required: false },
|
disableOutsidePointerEvents: { type: Boolean, required: false },
|
||||||
class: { type: null, required: false },
|
class: { type: null, required: false }
|
||||||
});
|
});
|
||||||
const emits = defineEmits([
|
const emits = defineEmits(['closeAutoFocus', 'escapeKeyDown', 'pointerDownOutside']);
|
||||||
"closeAutoFocus",
|
|
||||||
"escapeKeyDown",
|
|
||||||
"pointerDownOutside",
|
|
||||||
]);
|
|
||||||
|
|
||||||
const delegatedProps = reactiveOmit(props, "class");
|
const delegatedProps = reactiveOmit(props, 'class');
|
||||||
|
|
||||||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -57,23 +49,21 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|||||||
v-bind="{ ...$attrs, ...forwarded }"
|
v-bind="{ ...$attrs, ...forwarded }"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
|
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-10000 max-h-(--reka-select-content-available-height) min-w-[8rem] overflow-x-hidden overflow-y-auto rounded-md border shadow-md',
|
||||||
position === 'popper' &&
|
position === 'popper' &&
|
||||||
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
|
||||||
props.class,
|
props.class
|
||||||
)
|
)
|
||||||
"
|
">
|
||||||
>
|
|
||||||
<SelectScrollUpButton />
|
<SelectScrollUpButton />
|
||||||
<SelectViewport
|
<SelectViewport
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'p-1',
|
'p-1',
|
||||||
position === 'popper' &&
|
position === 'popper' &&
|
||||||
'h-[var(--reka-select-trigger-height)] w-full min-w-[var(--reka-select-trigger-width)] scroll-my-1',
|
'h-[var(--reka-select-trigger-height)] w-full min-w-[var(--reka-select-trigger-width)] scroll-my-1'
|
||||||
)
|
)
|
||||||
"
|
">
|
||||||
>
|
|
||||||
<slot />
|
<slot />
|
||||||
</SelectViewport>
|
</SelectViewport>
|
||||||
<SelectScrollDownButton />
|
<SelectScrollDownButton />
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { SelectIcon, SelectTrigger, useForwardProps } from 'reka-ui';
|
import { SelectIcon, SelectTrigger, useForwardProps } from 'reka-ui';
|
||||||
import { ChevronDown } from 'lucide-vue-next';
|
import { ChevronDown } from 'lucide-vue-next';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { reactiveOmit } from '@vueuse/core';
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
disabled: { type: Boolean, required: false },
|
disabled: { type: Boolean, required: false },
|
||||||
reference: { type: null, required: false },
|
reference: { type: null, required: false },
|
||||||
asChild: { type: Boolean, required: false },
|
asChild: { type: Boolean, required: false },
|
||||||
as: { type: null, required: false },
|
as: { type: null, required: false },
|
||||||
class: { type: null, required: false },
|
class: { type: null, required: false },
|
||||||
size: { type: String, required: false, default: 'default' }
|
size: { type: String, required: false, default: 'default' }
|
||||||
});
|
});
|
||||||
|
|
||||||
const delegatedProps = reactiveOmit(props, 'class', 'size');
|
const delegatedProps = reactiveOmit(props, 'class', 'size');
|
||||||
const forwardedProps = useForwardProps(delegatedProps);
|
const forwardedProps = useForwardProps(delegatedProps);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { Separator } from 'reka-ui';
|
import { Separator } from 'reka-ui';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { reactiveOmit } from '@vueuse/core';
|
import { reactiveOmit } from '@vueuse/core';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
orientation: { type: String, required: false, default: 'horizontal' },
|
orientation: { type: String, required: false, default: 'horizontal' },
|
||||||
decorative: { type: Boolean, required: false, default: true },
|
decorative: { type: Boolean, required: false, default: true },
|
||||||
asChild: { type: Boolean, required: false },
|
asChild: { type: Boolean, required: false },
|
||||||
as: { type: null, required: false },
|
as: { type: null, required: false },
|
||||||
class: { type: null, required: false }
|
class: { type: null, required: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
const delegatedProps = reactiveOmit(props, 'class');
|
const delegatedProps = reactiveOmit(props, 'class');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -9,65 +9,43 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
|
|
||||||
<el-dropdown trigger="click" size="small">
|
<div class="flex items-center gap-2">
|
||||||
<el-button size="small">
|
<Select
|
||||||
<span v-if="avatarExportFavoriteGroup">
|
:model-value="avatarExportFavoriteGroupSelection"
|
||||||
{{ avatarExportFavoriteGroup.displayName }} ({{ avatarExportFavoriteGroup.count }}/{{
|
@update:modelValue="handleAvatarExportFavoriteGroupSelect">
|
||||||
avatarExportFavoriteGroup.capacity
|
<SelectTrigger size="sm">
|
||||||
}})
|
<SelectValue placeholder="All Favorites" />
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
</SelectTrigger>
|
||||||
</span>
|
<SelectContent>
|
||||||
<span v-else>
|
<SelectGroup>
|
||||||
All Favorites
|
<SelectItem :value="AVATAR_EXPORT_ALL_VALUE">All Favorites</SelectItem>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectItem
|
||||||
</span>
|
v-for="groupAPI in favoriteAvatarGroups"
|
||||||
</el-button>
|
:key="groupAPI.name"
|
||||||
<template #dropdown>
|
:value="groupAPI.name">
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item style="display: block; margin: 10px 0" @click="selectAvatarExportGroup(null)">
|
|
||||||
All Favorites
|
|
||||||
</el-dropdown-item>
|
|
||||||
<template v-for="groupAPI in favoriteAvatarGroups" :key="groupAPI.name">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
@click="selectAvatarExportGroup(groupAPI)">
|
|
||||||
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
|
||||||
|
|
||||||
<el-dropdown trigger="click" size="small" style="margin-left: 10px">
|
<Select
|
||||||
<el-button size="small">
|
:model-value="avatarExportLocalFavoriteGroupSelection"
|
||||||
<span v-if="avatarExportLocalFavoriteGroup">
|
@update:modelValue="handleAvatarExportLocalFavoriteGroupSelect"
|
||||||
{{ avatarExportLocalFavoriteGroup }} ({{
|
style="margin-left: 10px">
|
||||||
localAvatarFavGroupLength(avatarExportLocalFavoriteGroup)
|
<SelectTrigger size="sm">
|
||||||
}})
|
<SelectValue placeholder="Select Group" />
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
</SelectTrigger>
|
||||||
</span>
|
<SelectContent>
|
||||||
<span v-else>
|
<SelectGroup>
|
||||||
Select Group
|
<SelectItem :value="AVATAR_EXPORT_NONE_VALUE">None</SelectItem>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectItem v-for="group in localAvatarFavoriteGroups" :key="group" :value="group">
|
||||||
</span>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
@click="selectAvatarExportLocalGroup(null)">
|
|
||||||
None
|
|
||||||
</el-dropdown-item>
|
|
||||||
<template v-for="group in localAvatarFavoriteGroups" :key="group">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
@click="selectAvatarExportLocalGroup(group)">
|
|
||||||
{{ group }} ({{ localAvatarFavGroupLength(group) }})
|
{{ group }} ({{ localAvatarFavGroupLength(group) }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<el-input
|
<el-input
|
||||||
v-model="avatarExportContent"
|
v-model="avatarExportContent"
|
||||||
@@ -82,8 +60,8 @@
|
|||||||
</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 { ArrowDown } from '@element-plus/icons-vue';
|
|
||||||
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';
|
||||||
@@ -114,6 +92,12 @@
|
|||||||
const avatarExportContent = ref('');
|
const avatarExportContent = ref('');
|
||||||
const avatarExportFavoriteGroup = ref(null);
|
const avatarExportFavoriteGroup = ref(null);
|
||||||
const avatarExportLocalFavoriteGroup = ref(null);
|
const avatarExportLocalFavoriteGroup = ref(null);
|
||||||
|
|
||||||
|
const AVATAR_EXPORT_ALL_VALUE = '__all__';
|
||||||
|
const AVATAR_EXPORT_NONE_VALUE = '__none__';
|
||||||
|
|
||||||
|
const avatarExportFavoriteGroupSelection = ref(AVATAR_EXPORT_ALL_VALUE);
|
||||||
|
const avatarExportLocalFavoriteGroupSelection = ref(AVATAR_EXPORT_NONE_VALUE);
|
||||||
const exportSelectedOptions = ref(['ID', 'Name']);
|
const exportSelectedOptions = ref(['ID', 'Name']);
|
||||||
const exportSelectOptions = ref([
|
const exportSelectOptions = ref([
|
||||||
{ label: 'ID', value: 'id' },
|
{ label: 'ID', value: 'id' },
|
||||||
@@ -144,8 +128,29 @@
|
|||||||
function showAvatarExportDialog() {
|
function showAvatarExportDialog() {
|
||||||
avatarExportFavoriteGroup.value = null;
|
avatarExportFavoriteGroup.value = null;
|
||||||
avatarExportLocalFavoriteGroup.value = null;
|
avatarExportLocalFavoriteGroup.value = null;
|
||||||
|
avatarExportFavoriteGroupSelection.value = AVATAR_EXPORT_ALL_VALUE;
|
||||||
|
avatarExportLocalFavoriteGroupSelection.value = AVATAR_EXPORT_NONE_VALUE;
|
||||||
updateAvatarExportDialog();
|
updateAvatarExportDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleAvatarExportFavoriteGroupSelect(value) {
|
||||||
|
avatarExportFavoriteGroupSelection.value = value;
|
||||||
|
if (value === AVATAR_EXPORT_ALL_VALUE) {
|
||||||
|
selectAvatarExportGroup(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const group = favoriteAvatarGroups.value.find((g) => g.name === value) || null;
|
||||||
|
selectAvatarExportGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAvatarExportLocalFavoriteGroupSelect(value) {
|
||||||
|
avatarExportLocalFavoriteGroupSelection.value = value;
|
||||||
|
if (value === AVATAR_EXPORT_NONE_VALUE) {
|
||||||
|
selectAvatarExportLocalGroup(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectAvatarExportLocalGroup(value);
|
||||||
|
}
|
||||||
function handleCopyAvatarExportData(event) {
|
function handleCopyAvatarExportData(event) {
|
||||||
if (event.target.tagName === 'TEXTAREA') {
|
if (event.target.tagName === 'TEXTAREA') {
|
||||||
event.target.select();
|
event.target.select();
|
||||||
@@ -161,11 +166,24 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function updateAvatarExportDialog() {
|
function updateAvatarExportDialog() {
|
||||||
const formatter = function (str) {
|
const needsCsvQuotes = (text) => {
|
||||||
if (/[\x00-\x1f,"]/.test(str) === true) {
|
for (let i = 0; i < text.length; i++) {
|
||||||
return `"${str.replace(/"/g, '""')}"`;
|
if (text.charCodeAt(i) < 0x20) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return str;
|
}
|
||||||
|
return text.includes(',') || text.includes('"');
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatter = function (value) {
|
||||||
|
if (value === null || typeof value === 'undefined') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const text = String(value);
|
||||||
|
if (needsCsvQuotes(text)) {
|
||||||
|
return `"${text.replace(/"/g, '""')}"`;
|
||||||
|
}
|
||||||
|
return text;
|
||||||
};
|
};
|
||||||
const propsForQuery = exportSelectOptions.value
|
const propsForQuery = exportSelectOptions.value
|
||||||
.filter((option) => exportSelectedOptions.value.includes(option.label))
|
.filter((option) => exportSelectedOptions.value.includes(option.label))
|
||||||
@@ -205,8 +223,8 @@
|
|||||||
favoriteAvatars.value.forEach((ref) => {
|
favoriteAvatars.value.forEach((ref) => {
|
||||||
lines.push(resText(ref.ref));
|
lines.push(resText(ref.ref));
|
||||||
});
|
});
|
||||||
for (let i = 0; i < localAvatarFavoritesList.length; ++i) {
|
for (let i = 0; i < localAvatarFavoritesList.value.length; ++i) {
|
||||||
const avatarId = localAvatarFavoritesList[i];
|
const avatarId = localAvatarFavoritesList.value[i];
|
||||||
const ref = cachedAvatars.get(avatarId);
|
const ref = cachedAvatars.get(avatarId);
|
||||||
if (typeof ref !== 'undefined') {
|
if (typeof ref !== 'undefined') {
|
||||||
lines.push(resText(ref));
|
lines.push(resText(ref));
|
||||||
@@ -218,11 +236,15 @@
|
|||||||
function selectAvatarExportGroup(group) {
|
function selectAvatarExportGroup(group) {
|
||||||
avatarExportFavoriteGroup.value = group;
|
avatarExportFavoriteGroup.value = group;
|
||||||
avatarExportLocalFavoriteGroup.value = null;
|
avatarExportLocalFavoriteGroup.value = null;
|
||||||
|
avatarExportFavoriteGroupSelection.value = group?.name ?? AVATAR_EXPORT_ALL_VALUE;
|
||||||
|
avatarExportLocalFavoriteGroupSelection.value = AVATAR_EXPORT_NONE_VALUE;
|
||||||
updateAvatarExportDialog();
|
updateAvatarExportDialog();
|
||||||
}
|
}
|
||||||
function selectAvatarExportLocalGroup(group) {
|
function selectAvatarExportLocalGroup(group) {
|
||||||
avatarExportLocalFavoriteGroup.value = group;
|
avatarExportLocalFavoriteGroup.value = group;
|
||||||
avatarExportFavoriteGroup.value = null;
|
avatarExportFavoriteGroup.value = null;
|
||||||
|
avatarExportLocalFavoriteGroupSelection.value = group ?? AVATAR_EXPORT_NONE_VALUE;
|
||||||
|
avatarExportFavoriteGroupSelection.value = AVATAR_EXPORT_ALL_VALUE;
|
||||||
updateAvatarExportDialog();
|
updateAvatarExportDialog();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -29,57 +29,43 @@
|
|||||||
style="margin-top: 10px"></el-input>
|
style="margin-top: 10px"></el-input>
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 5px">
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 5px">
|
||||||
<div>
|
<div>
|
||||||
<el-dropdown trigger="click" size="small" style="margin-right: 5px" @click.stop>
|
<div class="flex items-center gap-2">
|
||||||
<el-button size="small">
|
<Select
|
||||||
<span v-if="avatarImportDialog.avatarImportFavoriteGroup">
|
:model-value="avatarImportFavoriteGroupSelection"
|
||||||
{{ avatarImportDialog.avatarImportFavoriteGroup.displayName }} ({{
|
@update:modelValue="handleAvatarImportGroupSelect"
|
||||||
avatarImportDialog.avatarImportFavoriteGroup.count
|
style="margin-right: 5px">
|
||||||
}}/{{ avatarImportDialog.avatarImportFavoriteGroup.capacity }})
|
<SelectTrigger size="sm">
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectValue :placeholder="t('dialog.avatar_import.select_group_placeholder')" />
|
||||||
</span>
|
</SelectTrigger>
|
||||||
<span v-else>
|
<SelectContent>
|
||||||
{{ t('dialog.avatar_import.select_group_placeholder') }}
|
<SelectGroup>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectItem
|
||||||
</span>
|
v-for="groupAPI in favoriteAvatarGroups"
|
||||||
</el-button>
|
:key="groupAPI.name"
|
||||||
<template #dropdown>
|
:value="groupAPI.name"
|
||||||
<el-dropdown-menu>
|
:disabled="groupAPI.count >= groupAPI.capacity">
|
||||||
<template v-for="groupAPI in favoriteAvatarGroups" :key="groupAPI.name">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
:disabled="groupAPI.count >= groupAPI.capacity"
|
|
||||||
@click="selectAvatarImportGroup(groupAPI)">
|
|
||||||
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
|
||||||
<el-dropdown trigger="click" size="small">
|
<Select
|
||||||
<el-button size="small">
|
:model-value="avatarImportLocalFavoriteGroupSelection"
|
||||||
<span v-if="avatarImportDialog.avatarImportLocalFavoriteGroup">
|
@update:modelValue="handleAvatarImportLocalGroupSelect"
|
||||||
{{ avatarImportDialog.avatarImportLocalFavoriteGroup }} ({{
|
style="margin-left: 10px">
|
||||||
localAvatarFavGroupLength(avatarImportDialog.avatarImportLocalFavoriteGroup)
|
<SelectTrigger size="sm">
|
||||||
}})
|
<SelectValue :placeholder="t('dialog.avatar_import.select_group_placeholder')" />
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
</SelectTrigger>
|
||||||
</span>
|
<SelectContent>
|
||||||
<span v-else>
|
<SelectGroup>
|
||||||
{{ t('dialog.avatar_import.select_group_placeholder') }}
|
<SelectItem v-for="group in localAvatarFavoriteGroups" :key="group" :value="group">
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
|
||||||
</span>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<template v-for="group in localAvatarFavoriteGroups" :key="group">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
@click="selectAvatarImportLocalGroup(group)">
|
|
||||||
{{ group }} ({{ localAvatarFavGroupLength(group) }})
|
{{ group }} ({{ localAvatarFavGroupLength(group) }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
</div>
|
||||||
<span v-if="avatarImportDialog.avatarImportFavoriteGroup" style="margin-left: 5px">
|
<span v-if="avatarImportDialog.avatarImportFavoriteGroup" style="margin-left: 5px">
|
||||||
{{ avatarImportTable.data.length }} /
|
{{ avatarImportTable.data.length }} /
|
||||||
{{
|
{{
|
||||||
@@ -176,8 +162,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ArrowDown, Close, Loading } from '@element-plus/icons-vue';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import { Close, Loading } from '@element-plus/icons-vue';
|
||||||
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';
|
||||||
@@ -209,6 +196,9 @@
|
|||||||
importProgressTotal: 0
|
importProgressTotal: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const avatarImportFavoriteGroupSelection = ref('');
|
||||||
|
const avatarImportLocalFavoriteGroupSelection = ref('');
|
||||||
|
|
||||||
const avatarImportTable = ref({
|
const avatarImportTable = ref({
|
||||||
data: [],
|
data: [],
|
||||||
tableProps: {
|
tableProps: {
|
||||||
@@ -305,11 +295,26 @@
|
|||||||
function selectAvatarImportGroup(group) {
|
function selectAvatarImportGroup(group) {
|
||||||
avatarImportDialog.value.avatarImportLocalFavoriteGroup = null;
|
avatarImportDialog.value.avatarImportLocalFavoriteGroup = null;
|
||||||
avatarImportDialog.value.avatarImportFavoriteGroup = group;
|
avatarImportDialog.value.avatarImportFavoriteGroup = group;
|
||||||
|
avatarImportFavoriteGroupSelection.value = group?.name ?? '';
|
||||||
|
avatarImportLocalFavoriteGroupSelection.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectAvatarImportLocalGroup(group) {
|
function selectAvatarImportLocalGroup(group) {
|
||||||
avatarImportDialog.value.avatarImportFavoriteGroup = null;
|
avatarImportDialog.value.avatarImportFavoriteGroup = null;
|
||||||
avatarImportDialog.value.avatarImportLocalFavoriteGroup = group;
|
avatarImportDialog.value.avatarImportLocalFavoriteGroup = group;
|
||||||
|
avatarImportFavoriteGroupSelection.value = '';
|
||||||
|
avatarImportLocalFavoriteGroupSelection.value = group ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAvatarImportGroupSelect(value) {
|
||||||
|
avatarImportFavoriteGroupSelection.value = value;
|
||||||
|
const group = favoriteAvatarGroups.value.find((g) => g.name === value) ?? null;
|
||||||
|
selectAvatarImportGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAvatarImportLocalGroupSelect(value) {
|
||||||
|
avatarImportLocalFavoriteGroupSelection.value = value;
|
||||||
|
selectAvatarImportLocalGroup(value || null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelAvatarImport() {
|
function cancelAvatarImport() {
|
||||||
|
|||||||
@@ -5,34 +5,22 @@
|
|||||||
:title="t('dialog.friend_export.header')"
|
:title="t('dialog.friend_export.header')"
|
||||||
width="650px"
|
width="650px"
|
||||||
destroy-on-close>
|
destroy-on-close>
|
||||||
<el-dropdown trigger="click" size="small">
|
<Select :model-value="friendExportFavoriteGroupSelection" @update:modelValue="handleFriendExportGroupSelect">
|
||||||
<el-button size="small">
|
<SelectTrigger size="sm">
|
||||||
<span v-if="friendExportFavoriteGroup">
|
<SelectValue placeholder="All Favorites" />
|
||||||
{{ friendExportFavoriteGroup.displayName }} ({{ friendExportFavoriteGroup.count }}/{{
|
</SelectTrigger>
|
||||||
friendExportFavoriteGroup.capacity
|
<SelectContent>
|
||||||
}})
|
<SelectGroup>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectItem :value="FRIEND_EXPORT_ALL_VALUE">All Favorites</SelectItem>
|
||||||
</span>
|
<SelectItem v-for="groupAPI in favoriteFriendGroups" :key="groupAPI.name" :value="groupAPI.name">
|
||||||
<span v-else
|
|
||||||
>All Favorites <el-icon class="el-icon--right"><ArrowDown /></el-icon
|
|
||||||
></span>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item style="display: block; margin: 10px 0" @click="selectFriendExportGroup(null)">
|
|
||||||
All Favorites
|
|
||||||
</el-dropdown-item>
|
|
||||||
<template v-for="groupAPI in favoriteFriendGroups" :key="groupAPI.name">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
@click="selectFriendExportGroup(groupAPI)">
|
|
||||||
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<el-input
|
<el-input
|
||||||
v-model="friendExportContent"
|
v-model="friendExportContent"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
@@ -46,8 +34,8 @@
|
|||||||
</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 { ArrowDown } from '@element-plus/icons-vue';
|
|
||||||
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';
|
||||||
@@ -68,6 +56,8 @@
|
|||||||
const { favoriteFriends, favoriteFriendGroups } = storeToRefs(useFavoriteStore());
|
const { favoriteFriends, favoriteFriendGroups } = storeToRefs(useFavoriteStore());
|
||||||
|
|
||||||
const friendExportFavoriteGroup = ref(null);
|
const friendExportFavoriteGroup = ref(null);
|
||||||
|
const FRIEND_EXPORT_ALL_VALUE = '__all__';
|
||||||
|
const friendExportFavoriteGroupSelection = ref(FRIEND_EXPORT_ALL_VALUE);
|
||||||
const friendExportContent = ref('');
|
const friendExportContent = ref('');
|
||||||
|
|
||||||
const isDialogVisible = computed({
|
const isDialogVisible = computed({
|
||||||
@@ -90,9 +80,20 @@
|
|||||||
|
|
||||||
function showFriendExportDialog() {
|
function showFriendExportDialog() {
|
||||||
friendExportFavoriteGroup.value = null;
|
friendExportFavoriteGroup.value = null;
|
||||||
|
friendExportFavoriteGroupSelection.value = FRIEND_EXPORT_ALL_VALUE;
|
||||||
updateFriendExportDialog();
|
updateFriendExportDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleFriendExportGroupSelect(value) {
|
||||||
|
friendExportFavoriteGroupSelection.value = value;
|
||||||
|
if (value === FRIEND_EXPORT_ALL_VALUE) {
|
||||||
|
selectFriendExportGroup(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const group = favoriteFriendGroups.value.find((g) => g.name === value) || null;
|
||||||
|
selectFriendExportGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
function handleCopyFriendExportData(event) {
|
function handleCopyFriendExportData(event) {
|
||||||
if (event.target.tagName === 'TEXTAREA') {
|
if (event.target.tagName === 'TEXTAREA') {
|
||||||
event.target.select();
|
event.target.select();
|
||||||
@@ -109,18 +110,31 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateFriendExportDialog() {
|
function updateFriendExportDialog() {
|
||||||
const _ = function (str) {
|
const needsCsvQuotes = (text) => {
|
||||||
if (/[\x00-\x1f,"]/.test(str) === true) {
|
for (let i = 0; i < text.length; i++) {
|
||||||
return `"${str.replace(/"/g, '""')}"`;
|
if (text.charCodeAt(i) < 0x20) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return str;
|
}
|
||||||
|
return text.includes(',') || text.includes('"');
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatter = function (value) {
|
||||||
|
if (value === null || typeof value === 'undefined') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const text = String(value);
|
||||||
|
if (needsCsvQuotes(text)) {
|
||||||
|
return `"${text.replace(/"/g, '""')}"`;
|
||||||
|
}
|
||||||
|
return text;
|
||||||
};
|
};
|
||||||
const lines = ['UserID,Name'];
|
const lines = ['UserID,Name'];
|
||||||
favoriteFriendGroups.value.forEach((group) => {
|
favoriteFriendGroups.value.forEach((group) => {
|
||||||
if (!friendExportFavoriteGroup.value || friendExportFavoriteGroup.value === group) {
|
if (!friendExportFavoriteGroup.value || friendExportFavoriteGroup.value === group) {
|
||||||
favoriteFriends.value.forEach((ref) => {
|
favoriteFriends.value.forEach((ref) => {
|
||||||
if (group.key === ref.groupKey) {
|
if (group.key === ref.groupKey) {
|
||||||
lines.push(`${_(ref.id)},${_(ref.name)}`);
|
lines.push(`${formatter(ref.id)},${formatter(ref.name)}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -130,6 +144,7 @@
|
|||||||
|
|
||||||
function selectFriendExportGroup(group) {
|
function selectFriendExportGroup(group) {
|
||||||
friendExportFavoriteGroup.value = group;
|
friendExportFavoriteGroup.value = group;
|
||||||
|
friendExportFavoriteGroupSelection.value = group?.name ?? FRIEND_EXPORT_ALL_VALUE;
|
||||||
updateFriendExportDialog();
|
updateFriendExportDialog();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -29,32 +29,24 @@
|
|||||||
style="margin-top: 10px" />
|
style="margin-top: 10px" />
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 5px">
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 5px">
|
||||||
<div>
|
<div>
|
||||||
<el-dropdown trigger="click" size="small">
|
<Select
|
||||||
<el-button size="small">
|
:model-value="friendImportFavoriteGroupSelection"
|
||||||
<span v-if="friendImportDialog.friendImportFavoriteGroup">
|
@update:modelValue="handleFriendImportGroupSelect">
|
||||||
{{ friendImportDialog.friendImportFavoriteGroup.displayName }} ({{
|
<SelectTrigger size="sm">
|
||||||
friendImportDialog.friendImportFavoriteGroup.count
|
<SelectValue :placeholder="t('dialog.friend_import.select_group_placeholder')" />
|
||||||
}}/{{ friendImportDialog.friendImportFavoriteGroup.capacity }})
|
</SelectTrigger>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectContent>
|
||||||
</span>
|
<SelectGroup>
|
||||||
<span v-else
|
<SelectItem
|
||||||
>{{ t('dialog.friend_import.select_group_placeholder') }}
|
v-for="groupAPI in favoriteFriendGroups"
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon
|
:key="groupAPI.name"
|
||||||
></span>
|
:value="groupAPI.name"
|
||||||
</el-button>
|
:disabled="groupAPI.count >= groupAPI.capacity">
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<template v-for="groupAPI in favoriteFriendGroups" :key="groupAPI.name">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
:disabled="groupAPI.count >= groupAPI.capacity"
|
|
||||||
@click="selectFriendImportGroup(groupAPI)">
|
|
||||||
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
|
||||||
<span v-if="friendImportDialog.friendImportFavoriteGroup" style="margin-left: 5px">
|
<span v-if="friendImportDialog.friendImportFavoriteGroup" style="margin-left: 5px">
|
||||||
{{ friendImportTable.data.length }} /
|
{{ friendImportTable.data.length }} /
|
||||||
{{
|
{{
|
||||||
@@ -123,8 +115,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ArrowDown, Close, Loading } from '@element-plus/icons-vue';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import { Close, Loading } from '@element-plus/icons-vue';
|
||||||
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';
|
||||||
@@ -155,6 +148,8 @@
|
|||||||
importProgressTotal: 0
|
importProgressTotal: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const friendImportFavoriteGroupSelection = ref('');
|
||||||
|
|
||||||
const friendImportTable = ref({
|
const friendImportTable = ref({
|
||||||
data: [],
|
data: [],
|
||||||
tableProps: {
|
tableProps: {
|
||||||
@@ -182,6 +177,8 @@
|
|||||||
friendImportDialogIndex.value = getNextDialogIndex();
|
friendImportDialogIndex.value = getNextDialogIndex();
|
||||||
clearFriendImportTable();
|
clearFriendImportTable();
|
||||||
resetFriendImport();
|
resetFriendImport();
|
||||||
|
friendImportFavoriteGroupSelection.value =
|
||||||
|
friendImportDialog.value.friendImportFavoriteGroup?.name ?? '';
|
||||||
if (friendImportDialogInput.value) {
|
if (friendImportDialogInput.value) {
|
||||||
friendImportDialog.value.input = friendImportDialogInput.value;
|
friendImportDialog.value.input = friendImportDialogInput.value;
|
||||||
processFriendImportList();
|
processFriendImportList();
|
||||||
@@ -191,6 +188,14 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function handleFriendImportGroupSelect(value) {
|
||||||
|
friendImportFavoriteGroupSelection.value = value;
|
||||||
|
const group = favoriteFriendGroups.value.find((g) => g.name === value) || null;
|
||||||
|
if (group) {
|
||||||
|
selectFriendImportGroup(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function cancelFriendImport() {
|
function cancelFriendImport() {
|
||||||
friendImportDialog.value.loading = false;
|
friendImportDialog.value.loading = false;
|
||||||
}
|
}
|
||||||
@@ -204,6 +209,7 @@
|
|||||||
}
|
}
|
||||||
function selectFriendImportGroup(group) {
|
function selectFriendImportGroup(group) {
|
||||||
friendImportDialog.value.friendImportFavoriteGroup = group;
|
friendImportDialog.value.friendImportFavoriteGroup = group;
|
||||||
|
friendImportFavoriteGroupSelection.value = group?.name ?? '';
|
||||||
}
|
}
|
||||||
async function importFriendImportTable() {
|
async function importFriendImportTable() {
|
||||||
const D = friendImportDialog.value;
|
const D = friendImportDialog.value;
|
||||||
|
|||||||
@@ -9,61 +9,38 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
|
|
||||||
<el-dropdown trigger="click" size="small">
|
<div class="flex items-center gap-2">
|
||||||
<el-button size="small">
|
<Select :model-value="worldExportFavoriteGroupSelection" @update:modelValue="handleWorldExportGroupSelect">
|
||||||
<span v-if="worldExportFavoriteGroup">
|
<SelectTrigger size="sm">
|
||||||
{{ worldExportFavoriteGroup.displayName }} ({{ worldExportFavoriteGroup.count }}/{{
|
<SelectValue placeholder="All Favorites" />
|
||||||
worldExportFavoriteGroup.capacity
|
</SelectTrigger>
|
||||||
}})
|
<SelectContent>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectGroup>
|
||||||
</span>
|
<SelectItem :value="WORLD_EXPORT_ALL_VALUE">None</SelectItem>
|
||||||
<span v-else>
|
<SelectItem v-for="groupAPI in favoriteWorldGroups" :key="groupAPI.name" :value="groupAPI.name">
|
||||||
All Favorites
|
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
|
||||||
</span>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item style="display: block; margin: 10px 0" @click="selectWorldExportGroup(null)">
|
|
||||||
None
|
|
||||||
</el-dropdown-item>
|
|
||||||
<template v-for="groupAPI in favoriteWorldGroups" :key="groupAPI.name">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
@click="selectWorldExportGroup(groupAPI)">
|
|
||||||
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
|
||||||
|
|
||||||
<el-dropdown trigger="click" size="small" style="margin-left: 10px">
|
<Select
|
||||||
<el-button size="small">
|
:model-value="worldExportLocalFavoriteGroupSelection"
|
||||||
<span v-if="worldExportLocalFavoriteGroup">
|
@update:modelValue="handleWorldExportLocalGroupSelect"
|
||||||
{{ worldExportLocalFavoriteGroup }} ({{ localWorldFavGroupLength(worldExportLocalFavoriteGroup) }})
|
style="margin-left: 10px">
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectTrigger size="sm">
|
||||||
</span>
|
<SelectValue placeholder="Select Group" />
|
||||||
<span v-else>
|
</SelectTrigger>
|
||||||
Select Group
|
<SelectContent>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectGroup>
|
||||||
</span>
|
<SelectItem :value="WORLD_EXPORT_NONE_VALUE">None</SelectItem>
|
||||||
</el-button>
|
<SelectItem v-for="group in localWorldFavoriteGroups" :key="group" :value="group">
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item style="display: block; margin: 10px 0" @click="selectWorldExportLocalGroup(null)">
|
|
||||||
None
|
|
||||||
</el-dropdown-item>
|
|
||||||
<template v-for="group in localWorldFavoriteGroups" :key="group">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
@click="selectWorldExportLocalGroup(group)">
|
|
||||||
{{ group }} ({{ localWorldFavorites[group].length }})
|
{{ group }} ({{ localWorldFavorites[group].length }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
</div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
@@ -80,8 +57,8 @@
|
|||||||
</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 { ArrowDown } from '@element-plus/icons-vue';
|
|
||||||
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';
|
||||||
@@ -112,6 +89,12 @@
|
|||||||
const worldExportContent = ref('');
|
const worldExportContent = ref('');
|
||||||
const worldExportFavoriteGroup = ref(null);
|
const worldExportFavoriteGroup = ref(null);
|
||||||
const worldExportLocalFavoriteGroup = ref(null);
|
const worldExportLocalFavoriteGroup = ref(null);
|
||||||
|
|
||||||
|
const WORLD_EXPORT_ALL_VALUE = '__all__';
|
||||||
|
const WORLD_EXPORT_NONE_VALUE = '__none__';
|
||||||
|
|
||||||
|
const worldExportFavoriteGroupSelection = ref(WORLD_EXPORT_ALL_VALUE);
|
||||||
|
const worldExportLocalFavoriteGroupSelection = ref(WORLD_EXPORT_NONE_VALUE);
|
||||||
// Storage of selected filtering options for model and world export
|
// Storage of selected filtering options for model and world export
|
||||||
const exportSelectedOptions = ref(['ID', 'Name']);
|
const exportSelectedOptions = ref(['ID', 'Name']);
|
||||||
const exportSelectOptions = ref([
|
const exportSelectOptions = ref([
|
||||||
@@ -143,9 +126,30 @@
|
|||||||
function showWorldExportDialog() {
|
function showWorldExportDialog() {
|
||||||
worldExportFavoriteGroup.value = null;
|
worldExportFavoriteGroup.value = null;
|
||||||
worldExportLocalFavoriteGroup.value = null;
|
worldExportLocalFavoriteGroup.value = null;
|
||||||
|
worldExportFavoriteGroupSelection.value = WORLD_EXPORT_ALL_VALUE;
|
||||||
|
worldExportLocalFavoriteGroupSelection.value = WORLD_EXPORT_NONE_VALUE;
|
||||||
updateWorldExportDialog();
|
updateWorldExportDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleWorldExportGroupSelect(value) {
|
||||||
|
worldExportFavoriteGroupSelection.value = value;
|
||||||
|
if (value === WORLD_EXPORT_ALL_VALUE) {
|
||||||
|
selectWorldExportGroup(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const group = favoriteWorldGroups.value.find((g) => g.name === value) || null;
|
||||||
|
selectWorldExportGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWorldExportLocalGroupSelect(value) {
|
||||||
|
worldExportLocalFavoriteGroupSelection.value = value;
|
||||||
|
if (value === WORLD_EXPORT_NONE_VALUE) {
|
||||||
|
selectWorldExportLocalGroup(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectWorldExportLocalGroup(value);
|
||||||
|
}
|
||||||
|
|
||||||
function handleCopyWorldExportData(event) {
|
function handleCopyWorldExportData(event) {
|
||||||
if (event.target.tagName === 'TEXTAREA') {
|
if (event.target.tagName === 'TEXTAREA') {
|
||||||
event.target.select();
|
event.target.select();
|
||||||
@@ -221,12 +225,16 @@
|
|||||||
function selectWorldExportGroup(group) {
|
function selectWorldExportGroup(group) {
|
||||||
worldExportFavoriteGroup.value = group;
|
worldExportFavoriteGroup.value = group;
|
||||||
worldExportLocalFavoriteGroup.value = null;
|
worldExportLocalFavoriteGroup.value = null;
|
||||||
|
worldExportFavoriteGroupSelection.value = group?.name ?? WORLD_EXPORT_ALL_VALUE;
|
||||||
|
worldExportLocalFavoriteGroupSelection.value = WORLD_EXPORT_NONE_VALUE;
|
||||||
updateWorldExportDialog();
|
updateWorldExportDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectWorldExportLocalGroup(group) {
|
function selectWorldExportLocalGroup(group) {
|
||||||
worldExportLocalFavoriteGroup.value = group;
|
worldExportLocalFavoriteGroup.value = group;
|
||||||
worldExportFavoriteGroup.value = null;
|
worldExportFavoriteGroup.value = null;
|
||||||
|
worldExportLocalFavoriteGroupSelection.value = group ?? WORLD_EXPORT_NONE_VALUE;
|
||||||
|
worldExportFavoriteGroupSelection.value = WORLD_EXPORT_ALL_VALUE;
|
||||||
updateWorldExportDialog();
|
updateWorldExportDialog();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -30,57 +30,42 @@
|
|||||||
style="margin-top: 10px"></el-input>
|
style="margin-top: 10px"></el-input>
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 5px">
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 5px">
|
||||||
<div>
|
<div>
|
||||||
<el-dropdown trigger="click" size="small" style="margin-right: 5px" @click.stop>
|
<div class="flex items-center gap-2">
|
||||||
<el-button size="small">
|
<Select
|
||||||
<span v-if="worldImportDialog.worldImportFavoriteGroup">
|
:model-value="worldImportFavoriteGroupSelection"
|
||||||
{{ worldImportDialog.worldImportFavoriteGroup.displayName }}
|
@update:modelValue="handleWorldImportGroupSelect">
|
||||||
({{ worldImportDialog.worldImportFavoriteGroup.count }}/{{
|
<SelectTrigger size="sm">
|
||||||
worldImportDialog.worldImportFavoriteGroup.capacity
|
<SelectValue :placeholder="t('dialog.world_import.select_vrchat_group_placeholder')" />
|
||||||
}})
|
</SelectTrigger>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectContent>
|
||||||
</span>
|
<SelectGroup>
|
||||||
<span v-else>
|
<SelectItem
|
||||||
{{ t('dialog.world_import.select_vrchat_group_placeholder') }}
|
v-for="groupAPI in favoriteWorldGroups"
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
:key="groupAPI.name"
|
||||||
</span>
|
:value="groupAPI.name"
|
||||||
</el-button>
|
:disabled="groupAPI.count >= groupAPI.capacity">
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<template v-for="groupAPI in favoriteWorldGroups" :key="groupAPI.name">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
:disabled="groupAPI.count >= groupAPI.capacity"
|
|
||||||
@click="selectWorldImportGroup(groupAPI)">
|
|
||||||
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
{{ groupAPI.displayName }} ({{ groupAPI.count }}/{{ groupAPI.capacity }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
|
||||||
<el-dropdown trigger="click" size="small" @click.stop>
|
<Select
|
||||||
<el-button size="small">
|
:model-value="worldImportLocalFavoriteGroupSelection"
|
||||||
<span v-if="worldImportDialog.worldImportLocalFavoriteGroup">
|
@update:modelValue="handleWorldImportLocalGroupSelect"
|
||||||
{{ worldImportDialog.worldImportLocalFavoriteGroup }}
|
style="margin-left: 10px">
|
||||||
({{ localWorldFavGroupLength(worldImportDialog.worldImportLocalFavoriteGroup) }})
|
<SelectTrigger size="sm">
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectValue :placeholder="t('dialog.world_import.select_local_group_placeholder')" />
|
||||||
</span>
|
</SelectTrigger>
|
||||||
<span v-else>
|
<SelectContent>
|
||||||
{{ t('dialog.world_import.select_local_group_placeholder') }}
|
<SelectGroup>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectItem v-for="group in localWorldFavoriteGroups" :key="group" :value="group">
|
||||||
</span>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<template v-for="group in localWorldFavoriteGroups" :key="group">
|
|
||||||
<el-dropdown-item
|
|
||||||
style="display: block; margin: 10px 0"
|
|
||||||
@click="selectWorldImportLocalGroup(group)">
|
|
||||||
{{ group }} ({{ localWorldFavGroupLength(group) }})
|
{{ group }} ({{ localWorldFavGroupLength(group) }})
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
</div>
|
||||||
<span v-if="worldImportDialog.worldImportFavoriteGroup" style="margin-left: 5px">
|
<span v-if="worldImportDialog.worldImportFavoriteGroup" style="margin-left: 5px">
|
||||||
{{ worldImportTable.data.length }} /
|
{{ worldImportTable.data.length }} /
|
||||||
{{
|
{{
|
||||||
@@ -172,8 +157,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ArrowDown, Close, Loading } from '@element-plus/icons-vue';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import { Close, Loading } from '@element-plus/icons-vue';
|
||||||
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';
|
||||||
@@ -209,6 +195,9 @@
|
|||||||
importProgressTotal: 0
|
importProgressTotal: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const worldImportFavoriteGroupSelection = ref('');
|
||||||
|
const worldImportLocalFavoriteGroupSelection = ref('');
|
||||||
|
|
||||||
const worldImportTable = ref({
|
const worldImportTable = ref({
|
||||||
data: [],
|
data: [],
|
||||||
tableProps: {
|
tableProps: {
|
||||||
@@ -302,11 +291,26 @@
|
|||||||
function selectWorldImportGroup(group) {
|
function selectWorldImportGroup(group) {
|
||||||
worldImportDialog.value.worldImportLocalFavoriteGroup = null;
|
worldImportDialog.value.worldImportLocalFavoriteGroup = null;
|
||||||
worldImportDialog.value.worldImportFavoriteGroup = group;
|
worldImportDialog.value.worldImportFavoriteGroup = group;
|
||||||
|
worldImportFavoriteGroupSelection.value = group?.name ?? '';
|
||||||
|
worldImportLocalFavoriteGroupSelection.value = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectWorldImportLocalGroup(group) {
|
function selectWorldImportLocalGroup(group) {
|
||||||
worldImportDialog.value.worldImportFavoriteGroup = null;
|
worldImportDialog.value.worldImportFavoriteGroup = null;
|
||||||
worldImportDialog.value.worldImportLocalFavoriteGroup = group;
|
worldImportDialog.value.worldImportLocalFavoriteGroup = group;
|
||||||
|
worldImportFavoriteGroupSelection.value = '';
|
||||||
|
worldImportLocalFavoriteGroupSelection.value = group ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWorldImportGroupSelect(value) {
|
||||||
|
worldImportFavoriteGroupSelection.value = value;
|
||||||
|
const group = favoriteWorldGroups.value.find((g) => g.name === value) ?? null;
|
||||||
|
selectWorldImportGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleWorldImportLocalGroupSelect(value) {
|
||||||
|
worldImportLocalFavoriteGroupSelection.value = value;
|
||||||
|
selectWorldImportLocalGroup(value || null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelWorldImport() {
|
function cancelWorldImport() {
|
||||||
|
|||||||
@@ -71,24 +71,24 @@
|
|||||||
v-loading="isSearchWorldLoading"
|
v-loading="isSearchWorldLoading"
|
||||||
:label="t('view.search.world.header')"
|
:label="t('view.search.world.header')"
|
||||||
style="min-height: 60px">
|
style="min-height: 60px">
|
||||||
<el-dropdown
|
<Select
|
||||||
size="small"
|
:model-value="searchWorldCategoryIndex"
|
||||||
trigger="click"
|
@update:modelValue="handleSearchWorldCategorySelect"
|
||||||
style="margin-bottom: 15px"
|
style="margin-bottom: 15px">
|
||||||
@command="(row) => searchWorld(row)">
|
<SelectTrigger size="sm">
|
||||||
<el-button size="small"
|
<SelectValue :placeholder="t('view.search.world.category')" />
|
||||||
>{{ t('view.search.world.category') }} <el-icon class="el-icon--right"><ArrowDown /></el-icon
|
</SelectTrigger>
|
||||||
></el-button>
|
<SelectContent>
|
||||||
<template #dropdown>
|
<SelectGroup>
|
||||||
<el-dropdown-menu>
|
<SelectItem
|
||||||
<el-dropdown-item
|
|
||||||
v-for="row in cachedConfig.dynamicWorldRows"
|
v-for="row in cachedConfig.dynamicWorldRows"
|
||||||
:key="row.index"
|
:key="row.index"
|
||||||
:command="row"
|
:value="row.index">
|
||||||
v-text="row.name"></el-dropdown-item>
|
{{ row.name }}
|
||||||
</el-dropdown-menu>
|
</SelectItem>
|
||||||
</template>
|
</SelectGroup>
|
||||||
</el-dropdown>
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
<el-checkbox v-model="searchWorldLabs" style="margin-left: 10px">{{
|
<el-checkbox v-model="searchWorldLabs" style="margin-left: 10px">{{
|
||||||
t('view.search.world.community_lab')
|
t('view.search.world.community_lab')
|
||||||
}}</el-checkbox>
|
}}</el-checkbox>
|
||||||
@@ -135,30 +135,25 @@
|
|||||||
style="min-height: 60px">
|
style="min-height: 60px">
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||||
<div style="display: flex; align-items: center">
|
<div style="display: flex; align-items: center">
|
||||||
<el-dropdown
|
<Select
|
||||||
v-if="avatarRemoteDatabaseProviderList.length > 1"
|
v-if="avatarRemoteDatabaseProviderList.length > 1"
|
||||||
trigger="click"
|
:model-value="avatarRemoteDatabaseProvider"
|
||||||
size="small"
|
@update:modelValue="setAvatarProvider"
|
||||||
style="margin-right: 5px"
|
style="margin-right: 5px">
|
||||||
@click.stop>
|
<SelectTrigger size="sm">
|
||||||
<el-button size="small"
|
<SelectValue :placeholder="t('view.search.avatar.search_provider')" />
|
||||||
>{{ t('view.search.avatar.search_provider') }}
|
</SelectTrigger>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon
|
<SelectContent>
|
||||||
></el-button>
|
<SelectGroup>
|
||||||
<template #dropdown>
|
<SelectItem
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-for="provider in avatarRemoteDatabaseProviderList"
|
v-for="provider in avatarRemoteDatabaseProviderList"
|
||||||
:key="provider"
|
:key="provider"
|
||||||
@click="setAvatarProvider(provider)">
|
:value="provider">
|
||||||
<el-icon v-if="provider === avatarRemoteDatabaseProvider" class="el-icon--left"
|
|
||||||
><Check
|
|
||||||
/></el-icon>
|
|
||||||
{{ provider }}
|
{{ provider }}
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</el-dropdown-menu>
|
</SelectGroup>
|
||||||
</template>
|
</SelectContent>
|
||||||
</el-dropdown>
|
</Select>
|
||||||
<TooltipWrapper side="bottom" :content="t('view.search.avatar.refresh_tooltip')">
|
<TooltipWrapper side="bottom" :content="t('view.search.avatar.refresh_tooltip')">
|
||||||
<el-button
|
<el-button
|
||||||
type="default"
|
type="default"
|
||||||
@@ -311,7 +306,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ArrowDown, Back, Check, Delete, Refresh, Right } from '@element-plus/icons-vue';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
|
import { Back, Delete, Refresh, Right } from '@element-plus/icons-vue';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ButtonGroup } from '@/components/ui/button-group';
|
import { ButtonGroup } from '@/components/ui/button-group';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
@@ -368,6 +364,8 @@
|
|||||||
const searchWorldOption = ref('');
|
const searchWorldOption = ref('');
|
||||||
const searchWorldLabs = ref(false);
|
const searchWorldLabs = ref(false);
|
||||||
const searchWorldParams = ref({});
|
const searchWorldParams = ref({});
|
||||||
|
|
||||||
|
const searchWorldCategoryIndex = ref(null);
|
||||||
const searchWorldResults = ref([]);
|
const searchWorldResults = ref([]);
|
||||||
|
|
||||||
const searchAvatarFilter = ref('');
|
const searchAvatarFilter = ref('');
|
||||||
@@ -436,6 +434,7 @@
|
|||||||
|
|
||||||
function searchWorld(ref) {
|
function searchWorld(ref) {
|
||||||
searchWorldOption.value = '';
|
searchWorldOption.value = '';
|
||||||
|
searchWorldCategoryIndex.value = ref?.index ?? null;
|
||||||
const params = {
|
const params = {
|
||||||
n: 10,
|
n: 10,
|
||||||
offset: 0
|
offset: 0
|
||||||
@@ -502,6 +501,12 @@
|
|||||||
moreSearchWorld();
|
moreSearchWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSearchWorldCategorySelect(index) {
|
||||||
|
searchWorldCategoryIndex.value = index;
|
||||||
|
const row = cachedConfig.value?.dynamicWorldRows?.find((r) => r.index === index);
|
||||||
|
searchWorld(row || {});
|
||||||
|
}
|
||||||
|
|
||||||
function moreSearchWorld(go) {
|
function moreSearchWorld(go) {
|
||||||
const params = searchWorldParams.value;
|
const params = searchWorldParams.value;
|
||||||
if (go) {
|
if (go) {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
.simple-switch {
|
.simple-switch {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
.simple-switch > .name {
|
.simple-switch > .name {
|
||||||
width: 225px;
|
width: 225px;
|
||||||
|
|||||||
@@ -4,45 +4,33 @@
|
|||||||
<span class="header">{{ t('view.settings.appearance.appearance.header') }}</span>
|
<span class="header">{{ t('view.settings.appearance.appearance.header') }}</span>
|
||||||
<div class="options-container-item">
|
<div class="options-container-item">
|
||||||
<span class="name">{{ t('view.settings.appearance.appearance.language') }}</span>
|
<span class="name">{{ t('view.settings.appearance.appearance.language') }}</span>
|
||||||
<el-dropdown trigger="click" size="small" @click.stop>
|
<Select :model-value="appLanguage" @update:modelValue="changeAppLanguage">
|
||||||
<el-button size="small">
|
<SelectTrigger size="sm">
|
||||||
<span>
|
<SelectValue :placeholder="getLanguageName(appLanguage)" />
|
||||||
{{ getLanguageName(appLanguage) }} <el-icon class="el-icon--right"> <ArrowDown /></el-icon
|
</SelectTrigger>
|
||||||
></span>
|
<SelectContent>
|
||||||
</el-button>
|
<SelectGroup>
|
||||||
<template #dropdown>
|
<SelectItem v-for="language in languageCodes" :key="language" :value="language">
|
||||||
<el-dropdown-menu>
|
{{ getLanguageName(language) }}
|
||||||
<el-dropdown-item
|
</SelectItem>
|
||||||
v-for="language in languageCodes"
|
</SelectGroup>
|
||||||
:key="language"
|
</SelectContent>
|
||||||
:class="{ 'is-active': appLanguage === language }"
|
</Select>
|
||||||
@click="changeAppLanguage(language)"
|
|
||||||
v-text="getLanguageName(language)" />
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="options-container-item">
|
<div class="options-container-item">
|
||||||
<span class="name">{{ t('view.settings.appearance.appearance.theme_mode') }}</span>
|
<span class="name">{{ t('view.settings.appearance.appearance.theme_mode') }}</span>
|
||||||
<el-dropdown trigger="click" size="small" @click.stop>
|
<Select :model-value="themeMode" @update:modelValue="saveThemeMode">
|
||||||
<el-button size="small">
|
<SelectTrigger size="sm">
|
||||||
<span
|
<SelectValue :placeholder="t(`view.settings.appearance.appearance.theme_mode_${themeMode}`)" />
|
||||||
>{{ t(`view.settings.appearance.appearance.theme_mode_${themeMode}`) }}
|
</SelectTrigger>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon
|
<SelectContent>
|
||||||
></span>
|
<SelectGroup>
|
||||||
</el-button>
|
<SelectItem v-for="(config, themeKey) in THEME_CONFIG" :key="themeKey" :value="themeKey">
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-for="(config, themeKey) in THEME_CONFIG"
|
|
||||||
:key="themeKey"
|
|
||||||
@click="saveThemeMode(themeKey)"
|
|
||||||
:class="{ 'is-active': themeMode === themeKey }">
|
|
||||||
{{ t(`view.settings.appearance.appearance.theme_mode_${themeKey}`) }}
|
{{ t(`view.settings.appearance.appearance.theme_mode_${themeKey}`) }}
|
||||||
</el-dropdown-item>
|
</SelectItem>
|
||||||
</el-dropdown-menu>
|
</SelectGroup>
|
||||||
</template>
|
</SelectContent>
|
||||||
</el-dropdown>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!isLinux" class="options-container-item">
|
<div v-if="!isLinux" class="options-container-item">
|
||||||
<span class="name">{{ t('view.settings.appearance.appearance.zoom') }}</span>
|
<span class="name">{{ t('view.settings.appearance.appearance.zoom') }}</span>
|
||||||
@@ -314,7 +302,7 @@
|
|||||||
:label="t('view.settings.appearance.user_colors.random_colors_from_user_id')"
|
:label="t('view.settings.appearance.user_colors.random_colors_from_user_id')"
|
||||||
:value="randomUserColours"
|
:value="randomUserColours"
|
||||||
@change="updateTrustColor('', '', true)"></simple-switch>
|
@change="updateTrustColor('', '', true)"></simple-switch>
|
||||||
<div class="options-container-item">
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
:model-value="trustColor.untrusted"
|
:model-value="trustColor.untrusted"
|
||||||
@@ -384,8 +372,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ArrowDown, ArrowRight, Notebook } from '@element-plus/icons-vue';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { computed, onBeforeUnmount, ref } from 'vue';
|
import { computed, onBeforeUnmount, ref } from 'vue';
|
||||||
|
import { ArrowRight, Notebook } from '@element-plus/icons-vue';
|
||||||
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';
|
||||||
|
|||||||
@@ -230,22 +230,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="options-container-item">
|
<div class="options-container-item">
|
||||||
<span class="name">{{ t('view.settings.notifications.notifications.text_to_speech.tts_voice') }}</span>
|
<span class="name">{{ t('view.settings.notifications.notifications.text_to_speech.tts_voice') }}</span>
|
||||||
<el-dropdown trigger="click" size="small" @command="(voice) => changeTTSVoice(voice)">
|
<Select
|
||||||
<el-button size="small" :disabled="notificationTTS === 'Never'">
|
:model-value="ttsVoiceIndex"
|
||||||
<span
|
:disabled="notificationTTS === 'Never'"
|
||||||
>{{ getTTSVoiceName() }} <el-icon style="margin-left: 5px"><ArrowDown /></el-icon
|
@update:modelValue="(v) => (ttsVoiceIndex = v)">
|
||||||
></span>
|
<SelectTrigger size="sm">
|
||||||
</el-button>
|
<SelectValue :placeholder="getTTSVoiceName()" />
|
||||||
<template #dropdown>
|
</SelectTrigger>
|
||||||
<el-dropdown-menu>
|
<SelectContent>
|
||||||
<el-dropdown-item
|
<SelectGroup>
|
||||||
v-for="(voice, index) in TTSvoices"
|
<SelectItem v-for="(voice, index) in TTSvoices" :key="index" :value="index">
|
||||||
:key="index"
|
{{ voice.name }}
|
||||||
:command="index"
|
</SelectItem>
|
||||||
v-text="voice.name" />
|
</SelectGroup>
|
||||||
</el-dropdown-menu>
|
</SelectContent>
|
||||||
</template>
|
</Select>
|
||||||
</el-dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
<simple-switch
|
<simple-switch
|
||||||
:label="t('view.settings.notifications.notifications.text_to_speech.use_memo_nicknames')"
|
:label="t('view.settings.notifications.notifications.text_to_speech.use_memo_nicknames')"
|
||||||
@@ -274,14 +273,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ArrowDown, ChatSquare, Rank, Timer, VideoPlay } from '@element-plus/icons-vue';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
|
import { ChatSquare, Rank, Timer, VideoPlay } from '@element-plus/icons-vue';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useAdvancedSettingsStore, useNotificationsSettingsStore, useVrStore } from '../../../../stores';
|
import { useAdvancedSettingsStore, useNotificationsSettingsStore, useVrStore } from '../../../../stores';
|
||||||
import { Slider } from '../../../../components/ui/slider';
|
|
||||||
import { ToggleGroup, ToggleGroupItem } from '../../../../components/ui/toggle-group';
|
import { ToggleGroup, ToggleGroupItem } from '../../../../components/ui/toggle-group';
|
||||||
|
import { Slider } from '../../../../components/ui/slider';
|
||||||
|
|
||||||
import FeedFiltersDialog from '../../dialogs/FeedFiltersDialog.vue';
|
import FeedFiltersDialog from '../../dialogs/FeedFiltersDialog.vue';
|
||||||
import NotificationPositionDialog from '../../dialogs/NotificationPositionDialog.vue';
|
import NotificationPositionDialog from '../../dialogs/NotificationPositionDialog.vue';
|
||||||
@@ -345,6 +345,19 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ttsVoiceIndex = computed({
|
||||||
|
get: () => {
|
||||||
|
const currentName = getTTSVoiceName();
|
||||||
|
const idx = TTSvoices.value.findIndex((v) => v?.name === currentName);
|
||||||
|
return idx >= 0 ? idx : null;
|
||||||
|
},
|
||||||
|
set: (value) => {
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
changeTTSVoice(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function showNotyFeedFiltersDialog() {
|
function showNotyFeedFiltersDialog() {
|
||||||
feedFiltersDialogMode.value = 'noty';
|
feedFiltersDialogMode.value = 'noty';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,23 +7,18 @@
|
|||||||
@close="closeDialog">
|
@close="closeDialog">
|
||||||
<div class="options-container-item">
|
<div class="options-container-item">
|
||||||
<span class="name">{{ t('view.settings.appearance.appearance.bio_language') }}</span>
|
<span class="name">{{ t('view.settings.appearance.appearance.bio_language') }}</span>
|
||||||
<el-dropdown trigger="click" size="small" style="float: right" @click.stop>
|
<Select :model-value="bioLanguage" @update:modelValue="setBioLanguage">
|
||||||
<el-button size="small">
|
<SelectTrigger size="sm" style="float: right">
|
||||||
<span>
|
<SelectValue :placeholder="String(getLanguageName(bioLanguage) || bioLanguage || '')" />
|
||||||
{{ getLanguageName(bioLanguage) || bioLanguage }}
|
</SelectTrigger>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectContent>
|
||||||
</span>
|
<SelectGroup>
|
||||||
</el-button>
|
<SelectItem v-for="language in languageCodes" :key="language" :value="language">
|
||||||
<template #dropdown>
|
{{ getLanguageName(language) }}
|
||||||
<el-dropdown-menu>
|
</SelectItem>
|
||||||
<el-dropdown-item
|
</SelectGroup>
|
||||||
v-for="language in languageCodes"
|
</SelectContent>
|
||||||
:key="language"
|
</Select>
|
||||||
@click="setBioLanguage(language)"
|
|
||||||
v-text="getLanguageName(language)" />
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
<el-form label-position="top" label-width="120px" size="small" style="margin-bottom: 12px">
|
<el-form label-position="top" label-width="120px" size="small" style="margin-bottom: 12px">
|
||||||
@@ -102,8 +97,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { reactive, watch } from 'vue';
|
import { reactive, watch } from 'vue';
|
||||||
import { ArrowDown } from '@element-plus/icons-vue';
|
|
||||||
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';
|
||||||
|
|||||||
@@ -71,81 +71,69 @@
|
|||||||
<div style="display: inline-block; margin-top: 10px">
|
<div style="display: inline-block; margin-top: 10px">
|
||||||
<span>{{ t('dialog.config_json.camera_resolution') }}</span>
|
<span>{{ t('dialog.config_json.camera_resolution') }}</span>
|
||||||
<br />
|
<br />
|
||||||
<el-dropdown
|
<Select
|
||||||
size="small"
|
:model-value="vrchatCameraResolutionKey"
|
||||||
trigger="click"
|
@update:modelValue="(v) => (vrchatCameraResolutionKey = v)">
|
||||||
style="margin-top: 5px"
|
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||||
@command="(command) => setVRChatCameraResolution(command)">
|
<SelectValue :placeholder="getVRChatCameraResolution()" />
|
||||||
<el-button size="small">
|
</SelectTrigger>
|
||||||
<span>
|
<SelectContent>
|
||||||
<span v-text="getVRChatCameraResolution()"></span>
|
<SelectGroup>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectItem
|
||||||
</span>
|
v-for="row in VRChatCameraResolutions"
|
||||||
</el-button>
|
:key="row.name"
|
||||||
<template #dropdown>
|
:value="getVRChatResolutionKey(row)">
|
||||||
<el-dropdown-menu>
|
{{ row.name }}
|
||||||
<el-dropdown-item v-for="row in VRChatCameraResolutions" :key="row.index" :command="row">{{
|
</SelectItem>
|
||||||
row.name
|
</SelectGroup>
|
||||||
}}</el-dropdown-item>
|
</SelectContent>
|
||||||
</el-dropdown-menu>
|
</Select>
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<div style="display: inline-block; margin-top: 10px">
|
<div style="display: inline-block; margin-top: 10px">
|
||||||
<span>{{ t('dialog.config_json.spout_resolution') }}</span>
|
<span>{{ t('dialog.config_json.spout_resolution') }}</span>
|
||||||
<br />
|
<br />
|
||||||
<el-dropdown
|
<Select
|
||||||
size="small"
|
:model-value="vrchatSpoutResolutionKey"
|
||||||
trigger="click"
|
@update:modelValue="(v) => (vrchatSpoutResolutionKey = v)">
|
||||||
style="margin-top: 5px"
|
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||||
@command="(command) => setVRChatSpoutResolution(command)">
|
<SelectValue :placeholder="getVRChatSpoutResolution()" />
|
||||||
<el-button size="small">
|
</SelectTrigger>
|
||||||
<span>
|
<SelectContent>
|
||||||
<span v-text="getVRChatSpoutResolution()"></span>
|
<SelectGroup>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectItem
|
||||||
</span>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-for="row in VRChatScreenshotResolutions"
|
v-for="row in VRChatScreenshotResolutions"
|
||||||
:key="row.index"
|
:key="row.name"
|
||||||
:command="row"
|
:value="getVRChatResolutionKey(row)">
|
||||||
>{{ row.name }}</el-dropdown-item
|
{{ row.name }}
|
||||||
>
|
</SelectItem>
|
||||||
</el-dropdown-menu>
|
</SelectGroup>
|
||||||
</template>
|
</SelectContent>
|
||||||
</el-dropdown>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<div style="display: inline-block; margin-top: 10px">
|
<div style="display: inline-block; margin-top: 10px">
|
||||||
<span>{{ t('dialog.config_json.screenshot_resolution') }}</span>
|
<span>{{ t('dialog.config_json.screenshot_resolution') }}</span>
|
||||||
<br />
|
<br />
|
||||||
<el-dropdown
|
<Select
|
||||||
size="small"
|
:model-value="vrchatScreenshotResolutionKey"
|
||||||
trigger="click"
|
@update:modelValue="(v) => (vrchatScreenshotResolutionKey = v)">
|
||||||
style="margin-top: 5px"
|
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||||
@command="(command) => setVRChatScreenshotResolution(command)">
|
<SelectValue :placeholder="getVRChatScreenshotResolution()" />
|
||||||
<el-button size="small">
|
</SelectTrigger>
|
||||||
<span>
|
<SelectContent>
|
||||||
<span v-text="getVRChatScreenshotResolution()"></span>
|
<SelectGroup>
|
||||||
<el-icon class="el-icon--right"><ArrowDown /></el-icon>
|
<SelectItem
|
||||||
</span>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item
|
|
||||||
v-for="row in VRChatScreenshotResolutions"
|
v-for="row in VRChatScreenshotResolutions"
|
||||||
:key="row.index"
|
:key="row.name"
|
||||||
:command="row"
|
:value="getVRChatResolutionKey(row)">
|
||||||
>{{ row.name }}</el-dropdown-item
|
{{ row.name }}
|
||||||
>
|
</SelectItem>
|
||||||
</el-dropdown-menu>
|
</SelectGroup>
|
||||||
</template>
|
</SelectContent>
|
||||||
</el-dropdown>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
@@ -181,7 +169,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ArrowDown, Delete, FolderDelete, FolderOpened, Refresh } from '@element-plus/icons-vue';
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
|
import { Delete, FolderDelete, FolderOpened, Refresh } from '@element-plus/icons-vue';
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { ElMessageBox } from 'element-plus';
|
import { ElMessageBox } from 'element-plus';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
@@ -199,9 +188,10 @@
|
|||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const VRChatConfigFile = ref({});
|
const VRChatConfigFile = ref(/** @type {Record<string, any>} */ ({}));
|
||||||
// it's a object
|
// it's a object
|
||||||
const VRChatConfigList = ref({
|
const VRChatConfigList = ref(
|
||||||
|
/** @type {Record<string, any>} */ ({
|
||||||
cache_size: {
|
cache_size: {
|
||||||
name: t('dialog.config_json.max_cache_size'),
|
name: t('dialog.config_json.max_cache_size'),
|
||||||
default: '30',
|
default: '30',
|
||||||
@@ -244,7 +234,8 @@
|
|||||||
min: 30,
|
min: 30,
|
||||||
max: 110
|
max: 110
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
@@ -263,6 +254,68 @@
|
|||||||
return VRChatConfigFile.value.cache_size || VRChatTotalCacheSize.value;
|
return VRChatConfigFile.value.cache_size || VRChatTotalCacheSize.value;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const VRCHAT_RESOLUTION_DEFAULT_KEY = '__default__';
|
||||||
|
|
||||||
|
function getVRChatResolutionKey(row) {
|
||||||
|
const width = Number(row?.width);
|
||||||
|
const height = Number(row?.height);
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
|
return `${width}x${height}`;
|
||||||
|
}
|
||||||
|
return VRCHAT_RESOLUTION_DEFAULT_KEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vrchatCameraResolutionKey = computed({
|
||||||
|
get: () => {
|
||||||
|
const width = Number(VRChatConfigFile.value.camera_res_width);
|
||||||
|
const height = Number(VRChatConfigFile.value.camera_res_height);
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
|
return `${width}x${height}`;
|
||||||
|
}
|
||||||
|
return VRCHAT_RESOLUTION_DEFAULT_KEY;
|
||||||
|
},
|
||||||
|
set: (value) => {
|
||||||
|
const row = VRChatCameraResolutions.find((r) => getVRChatResolutionKey(r) === value);
|
||||||
|
if (row) {
|
||||||
|
setVRChatCameraResolution(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const vrchatSpoutResolutionKey = computed({
|
||||||
|
get: () => {
|
||||||
|
const width = Number(VRChatConfigFile.value.camera_spout_res_width);
|
||||||
|
const height = Number(VRChatConfigFile.value.camera_spout_res_height);
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
|
return `${width}x${height}`;
|
||||||
|
}
|
||||||
|
return VRCHAT_RESOLUTION_DEFAULT_KEY;
|
||||||
|
},
|
||||||
|
set: (value) => {
|
||||||
|
const row = VRChatScreenshotResolutions.find((r) => getVRChatResolutionKey(r) === value);
|
||||||
|
if (row) {
|
||||||
|
setVRChatSpoutResolution(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const vrchatScreenshotResolutionKey = computed({
|
||||||
|
get: () => {
|
||||||
|
const width = Number(VRChatConfigFile.value.screenshot_res_width);
|
||||||
|
const height = Number(VRChatConfigFile.value.screenshot_res_height);
|
||||||
|
if (width > 0 && height > 0) {
|
||||||
|
return `${width}x${height}`;
|
||||||
|
}
|
||||||
|
return VRCHAT_RESOLUTION_DEFAULT_KEY;
|
||||||
|
},
|
||||||
|
set: (value) => {
|
||||||
|
const row = VRChatScreenshotResolutions.find((r) => getVRChatResolutionKey(r) === value);
|
||||||
|
if (row) {
|
||||||
|
setVRChatScreenshotResolution(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function showDeleteAllVRChatCacheConfirm() {
|
function showDeleteAllVRChatCacheConfirm() {
|
||||||
ElMessageBox.confirm(`Continue? Delete all VRChat cache`, 'Confirm', {
|
ElMessageBox.confirm(`Continue? Delete all VRChat cache`, 'Confirm', {
|
||||||
confirmButtonText: 'Confirm',
|
confirmButtonText: 'Confirm',
|
||||||
@@ -354,8 +407,11 @@
|
|||||||
delete VRChatConfigFile.value[item];
|
delete VRChatConfigFile.value[item];
|
||||||
} else if (typeof VRChatConfigFile.value[item] === 'boolean' && VRChatConfigFile.value[item] === false) {
|
} else if (typeof VRChatConfigFile.value[item] === 'boolean' && VRChatConfigFile.value[item] === false) {
|
||||||
delete VRChatConfigFile.value[item];
|
delete VRChatConfigFile.value[item];
|
||||||
} else if (typeof VRChatConfigFile.value[item] === 'string' && !isNaN(VRChatConfigFile.value[item])) {
|
} else if (typeof VRChatConfigFile.value[item] === 'string') {
|
||||||
VRChatConfigFile.value[item] = parseInt(VRChatConfigFile.value[item], 10);
|
const parsed = parseInt(VRChatConfigFile.value[item], 10);
|
||||||
|
if (!Number.isNaN(parsed)) {
|
||||||
|
VRChatConfigFile.value[item] = parsed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WriteVRChatConfigFile();
|
WriteVRChatConfigFile();
|
||||||
|
|||||||
Reference in New Issue
Block a user