mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-21 07:43:50 +02:00
replace el-dialog
This commit is contained in:
@@ -1,33 +1,34 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="isAvatarProviderDialogVisible"
|
||||
:title="t('dialog.avatar_database_provider.header')"
|
||||
width="600px"
|
||||
@close="closeDialog">
|
||||
<div>
|
||||
<InputGroupAction
|
||||
v-for="(provider, index) in avatarRemoteDatabaseProviderList"
|
||||
:key="index"
|
||||
v-model="avatarRemoteDatabaseProviderList[index]"
|
||||
size="sm"
|
||||
style="margin-top: 5px"
|
||||
@change="saveAvatarProviderList">
|
||||
<template #actions>
|
||||
<Button variant="outline" size="icon" @click="removeAvatarProvider(provider)">
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</template>
|
||||
</InputGroupAction>
|
||||
<Dialog :open="isAvatarProviderDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.avatar_database_provider.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div>
|
||||
<InputGroupAction
|
||||
v-for="(provider, index) in avatarRemoteDatabaseProviderList"
|
||||
:key="index"
|
||||
v-model="avatarRemoteDatabaseProviderList[index]"
|
||||
size="sm"
|
||||
style="margin-top: 5px"
|
||||
@change="saveAvatarProviderList">
|
||||
<template #actions>
|
||||
<Button variant="outline" size="icon" @click="removeAvatarProvider(provider)">
|
||||
<Trash2 />
|
||||
</Button>
|
||||
</template>
|
||||
</InputGroupAction>
|
||||
|
||||
<Button size="sm" style="margin-top: 5px" @click="avatarRemoteDatabaseProviderList.push('')">
|
||||
{{ t('dialog.avatar_database_provider.add_provider') }}
|
||||
</Button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<Button size="sm" style="margin-top: 5px" @click="avatarRemoteDatabaseProviderList.push('')">
|
||||
{{ t('dialog.avatar_database_provider.add_provider') }}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InputGroupAction } from '@/components/ui/input-group';
|
||||
import { Trash2 } from 'lucide-vue-next';
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="changeLogDialog.visible"
|
||||
:title="t('dialog.change_log.header')"
|
||||
width="800px"
|
||||
append-to-body
|
||||
@close="closeDialog">
|
||||
<div v-loading="!changeLogDialog.changeLog" class="changelog-dialog">
|
||||
<h2 v-text="changeLogDialog.buildName"></h2>
|
||||
<span v-show="changeLogDialog.buildName">
|
||||
{{ t('dialog.change_log.description') }}
|
||||
<a class="x-link" @click="openExternalLink('https://www.patreon.com/Natsumi_VRCX')">Patreon</a>,
|
||||
<a class="x-link" @click="openExternalLink('https://ko-fi.com/natsumi_sama')">Ko-fi</a>.
|
||||
</span>
|
||||
<VueShowdown
|
||||
:markdown="changeLogDialog.changeLog"
|
||||
flavor="github"
|
||||
:options="showdownOptions"
|
||||
@click="handleLinkClick"
|
||||
style="height: 62vh; overflow-y: auto; margin-top: 10px" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="mr-2"
|
||||
@click="openExternalLink('https://github.com/vrcx-team/VRCX/releases')">
|
||||
{{ t('dialog.change_log.github') }}
|
||||
</Button>
|
||||
<Button variant="outline" class="mr-2" @click="openExternalLink('https://patreon.com/Natsumi_VRCX')">
|
||||
{{ t('dialog.change_log.donate') }}
|
||||
</Button>
|
||||
<Button @click="closeDialog">
|
||||
{{ t('dialog.change_log.close') }}
|
||||
</Button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<Dialog v-model:open="changeLogDialog.visible">
|
||||
<DialogContent class="sm:max-w-4xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.change_log.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div v-loading="!changeLogDialog.changeLog" class="changelog-dialog">
|
||||
<h2 v-text="changeLogDialog.buildName"></h2>
|
||||
<span v-show="changeLogDialog.buildName">
|
||||
{{ t('dialog.change_log.description') }}
|
||||
<a class="x-link" @click="openExternalLink('https://www.patreon.com/Natsumi_VRCX')">Patreon</a>,
|
||||
<a class="x-link" @click="openExternalLink('https://ko-fi.com/natsumi_sama')">Ko-fi</a>.
|
||||
</span>
|
||||
<VueShowdown
|
||||
:markdown="changeLogDialog.changeLog"
|
||||
flavor="github"
|
||||
:options="showdownOptions"
|
||||
@click="handleLinkClick"
|
||||
style="height: 62vh; overflow-y: auto; margin-top: 10px" />
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="mr-2"
|
||||
@click="openExternalLink('https://github.com/vrcx-team/VRCX/releases')">
|
||||
{{ t('dialog.change_log.github') }}
|
||||
</Button>
|
||||
<Button variant="outline" class="mr-2" @click="openExternalLink('https://patreon.com/Natsumi_VRCX')">
|
||||
{{ t('dialog.change_log.donate') }}
|
||||
</Button>
|
||||
<Button @click="closeDialog">
|
||||
{{ t('dialog.change_log.close') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
@@ -1,49 +1,23 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="!!feedFiltersDialogMode"
|
||||
:title="dialogTitle"
|
||||
width="600px"
|
||||
destroy-on-close
|
||||
@close="handleDialogClose">
|
||||
<div class="toggle-list" style="height: 75vh; overflow-y: auto">
|
||||
<div v-for="setting in currentOptions" :key="setting.key" class="toggle-item">
|
||||
<span class="toggle-name"
|
||||
>{{ setting.name
|
||||
}}<TooltipWrapper
|
||||
v-if="setting.tooltip"
|
||||
side="top"
|
||||
style="margin-left: 5px"
|
||||
:content="setting.tooltip">
|
||||
<AlertTriangle v-if="setting.tooltipWarning" />
|
||||
<Info v-else />
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
<Dialog :open="!!feedFiltersDialogMode" @update:open="(open) => !open && handleDialogClose()">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ dialogTitle }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div class="toggle-list" style="height: 75vh; overflow-y: auto">
|
||||
<div v-for="setting in currentOptions" :key="setting.key" class="toggle-item">
|
||||
<span class="toggle-name"
|
||||
>{{ setting.name
|
||||
}}<TooltipWrapper
|
||||
v-if="setting.tooltip"
|
||||
side="top"
|
||||
style="margin-left: 5px"
|
||||
:content="setting.tooltip">
|
||||
<AlertTriangle v-if="setting.tooltipWarning" />
|
||||
<Info v-else />
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
variant="outline"
|
||||
size="sm"
|
||||
:model-value="currentSharedFeedFilters[setting.key]"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
currentSharedFeedFilters[setting.key] = value;
|
||||
saveSharedFeedFilters();
|
||||
}
|
||||
">
|
||||
<ToggleGroupItem v-for="option in setting.options" :key="option.label" :value="option.label">
|
||||
{{ t(option.textKey) }}
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
|
||||
<template v-if="photonLoggingEnabled">
|
||||
<br />
|
||||
<div class="toggle-item">
|
||||
<span class="toggle-name">Photon Event Logging</span>
|
||||
</div>
|
||||
<div v-for="setting in photonFeedFiltersOptions" :key="setting.key" class="toggle-item">
|
||||
<span class="toggle-name">{{ setting.name }}</span>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
@@ -61,22 +35,52 @@
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<Button variant="secondary" @click="currentResetFunction">{{
|
||||
t('dialog.shared_feed_filters.reset')
|
||||
}}</Button>
|
||||
<Button style="margin-left: 10px" @click="handleDialogClose">{{
|
||||
t('dialog.shared_feed_filters.close')
|
||||
}}</Button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<template v-if="photonLoggingEnabled">
|
||||
<br />
|
||||
<div class="toggle-item">
|
||||
<span class="toggle-name">Photon Event Logging</span>
|
||||
</div>
|
||||
<div v-for="setting in photonFeedFiltersOptions" :key="setting.key" class="toggle-item">
|
||||
<span class="toggle-name">{{ setting.name }}</span>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
required
|
||||
variant="outline"
|
||||
size="sm"
|
||||
:model-value="currentSharedFeedFilters[setting.key]"
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
currentSharedFeedFilters[setting.key] = value;
|
||||
saveSharedFeedFilters();
|
||||
}
|
||||
">
|
||||
<ToggleGroupItem
|
||||
v-for="option in setting.options"
|
||||
:key="option.label"
|
||||
:value="option.label">
|
||||
{{ t(option.textKey) }}
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="secondary" @click="currentResetFunction">{{
|
||||
t('dialog.shared_feed_filters.reset')
|
||||
}}</Button>
|
||||
<Button style="margin-left: 10px" @click="handleDialogClose">{{
|
||||
t('dialog.shared_feed_filters.close')
|
||||
}}</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Info, AlertTriangle } from 'lucide-vue-next';
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { AlertTriangle, Info } from 'lucide-vue-next';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { computed } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
@@ -1,63 +1,64 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="isLaunchOptionsDialogVisible"
|
||||
:title="t('dialog.launch_options.header')"
|
||||
width="600px"
|
||||
@close="closeDialog">
|
||||
<div style="font-size: 12px">
|
||||
{{ t('dialog.launch_options.description') }} <br />
|
||||
{{ t('dialog.launch_options.example') }}
|
||||
<Badge variant="outline"
|
||||
>--fps=144 --enable-debug-gui --enable-sdk-log-levels --enable-udon-debug-logging
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<InputGroupTextareaField
|
||||
v-model="launchOptionsDialog.launchArguments"
|
||||
:autosize="{ minRows: 2, maxRows: 5 }"
|
||||
:rows="2"
|
||||
placeholder=""
|
||||
style="margin-top: 10px"
|
||||
input-class="resize-none" />
|
||||
|
||||
<template v-if="!isLinux">
|
||||
<div style="font-size: 12px; margin-top: 10px">
|
||||
{{ t('dialog.launch_options.path_override') }}
|
||||
<Dialog :open="isLaunchOptionsDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.launch_options.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div style="font-size: 12px">
|
||||
{{ t('dialog.launch_options.description') }} <br />
|
||||
{{ t('dialog.launch_options.example') }}
|
||||
<Badge variant="outline"
|
||||
>--fps=144 --enable-debug-gui --enable-sdk-log-levels --enable-udon-debug-logging
|
||||
</Badge>
|
||||
</div>
|
||||
|
||||
<InputGroupTextareaField
|
||||
v-model="launchOptionsDialog.vrcLaunchPathOverride"
|
||||
placeholder="C:\Program Files (x86)\Steam\steamapps\common\VRChat"
|
||||
:rows="1"
|
||||
style="display: block; margin-top: 10px"
|
||||
input-class="resize-none min-h-0" />
|
||||
</template>
|
||||
v-model="launchOptionsDialog.launchArguments"
|
||||
:autosize="{ minRows: 2, maxRows: 5 }"
|
||||
:rows="2"
|
||||
placeholder=""
|
||||
style="margin-top: 10px"
|
||||
input-class="resize-none" />
|
||||
|
||||
<template #footer>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
@click="openExternalLink('https://docs.vrchat.com/docs/launch-options')">
|
||||
{{ t('dialog.launch_options.vrchat_docs') }}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@click="openExternalLink('https://docs.unity3d.com/Manual/CommandLineArguments.html')">
|
||||
{{ t('dialog.launch_options.unity_manual') }}
|
||||
<template v-if="!isLinux">
|
||||
<div style="font-size: 12px; margin-top: 10px">
|
||||
{{ t('dialog.launch_options.path_override') }}
|
||||
</div>
|
||||
|
||||
<InputGroupTextareaField
|
||||
v-model="launchOptionsDialog.vrcLaunchPathOverride"
|
||||
placeholder="C:\Program Files (x86)\Steam\steamapps\common\VRChat"
|
||||
:rows="1"
|
||||
style="display: block; margin-top: 10px"
|
||||
input-class="resize-none min-h-0" />
|
||||
</template>
|
||||
|
||||
<DialogFooter>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
@click="openExternalLink('https://docs.vrchat.com/docs/launch-options')">
|
||||
{{ t('dialog.launch_options.vrchat_docs') }}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
@click="openExternalLink('https://docs.unity3d.com/Manual/CommandLineArguments.html')">
|
||||
{{ t('dialog.launch_options.unity_manual') }}
|
||||
</Button>
|
||||
</div>
|
||||
<Button @click="updateLaunchOptions">
|
||||
{{ t('dialog.launch_options.save') }}
|
||||
</Button>
|
||||
</div>
|
||||
<Button @click="updateLaunchOptions">
|
||||
{{ t('dialog.launch_options.save') }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { computed, ref } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InputGroupTextareaField } from '@/components/ui/input-group';
|
||||
|
||||
@@ -1,92 +1,93 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="isNotificationPositionDialogVisible"
|
||||
:title="t('dialog.notification_position.header')"
|
||||
width="400px"
|
||||
@close="closeDialog">
|
||||
<div style="font-size: 12px">
|
||||
{{ t('dialog.notification_position.description') }}
|
||||
</div>
|
||||
<div class="relative mx-auto mt-4 size-75">
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="80 80 80 100"
|
||||
style="margin-top: 24px"
|
||||
xml:space="preserve"
|
||||
class="absolute inset-0 size-full">
|
||||
<path
|
||||
style="fill: black"
|
||||
d="M291.89,5A3.11,3.11,0,0,1,295,8.11V160.64a3.11,3.11,0,0,1-3.11,3.11H8.11A3.11,3.11,0,0,1,5,160.64V8.11A3.11,3.11,0,0,1,8.11,5H291.89m0-5H8.11A8.11,8.11,0,0,0,0,8.11V160.64a8.11,8.11,0,0,0,8.11,8.11H291.89a8.11,8.11,0,0,0,8.11-8.11V8.11A8.11,8.11,0,0,0,291.89,0Z" />
|
||||
<rect style="fill: #c4c4c4" x="5" y="5" width="290" height="158.75" rx="2.5" />
|
||||
</svg>
|
||||
<RadioGroup
|
||||
:model-value="notificationPosition"
|
||||
class="absolute inset-0"
|
||||
@update:modelValue="changeNotificationPosition">
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-topLeft"
|
||||
aria-label="topLeft"
|
||||
value="topLeft"
|
||||
class="absolute top-[20%] left-[10%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-top"
|
||||
aria-label="top"
|
||||
value="top"
|
||||
class="absolute top-[20%] left-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-topRight"
|
||||
aria-label="topRight"
|
||||
value="topRight"
|
||||
class="absolute top-[20%] left-[90%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-centerLeft"
|
||||
aria-label="centerLeft"
|
||||
value="centerLeft"
|
||||
class="absolute top-1/2 left-[10%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-center"
|
||||
aria-label="center"
|
||||
value="center"
|
||||
class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-centerRight"
|
||||
aria-label="centerRight"
|
||||
value="centerRight"
|
||||
class="absolute top-1/2 left-[90%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-bottomLeft"
|
||||
aria-label="bottomLeft"
|
||||
value="bottomLeft"
|
||||
class="absolute top-[80%] left-[10%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-bottom"
|
||||
aria-label="bottom"
|
||||
value="bottom"
|
||||
class="absolute top-[80%] left-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-bottomRight"
|
||||
aria-label="bottomRight"
|
||||
value="bottomRight"
|
||||
class="absolute top-[80%] left-[90%] -translate-x-1/2 -translate-y-1/2" />
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div style="display: flex">
|
||||
<Button @click="closeDialog">
|
||||
{{ t('dialog.notification_position.ok') }}
|
||||
</Button>
|
||||
<Dialog :open="isNotificationPositionDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.notification_position.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div style="font-size: 12px">
|
||||
{{ t('dialog.notification_position.description') }}
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<div class="relative mx-auto mt-4 size-75">
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="80 80 80 100"
|
||||
style="margin-top: 24px"
|
||||
xml:space="preserve"
|
||||
class="absolute inset-0 size-full">
|
||||
<path
|
||||
style="fill: black"
|
||||
d="M291.89,5A3.11,3.11,0,0,1,295,8.11V160.64a3.11,3.11,0,0,1-3.11,3.11H8.11A3.11,3.11,0,0,1,5,160.64V8.11A3.11,3.11,0,0,1,8.11,5H291.89m0-5H8.11A8.11,8.11,0,0,0,0,8.11V160.64a8.11,8.11,0,0,0,8.11,8.11H291.89a8.11,8.11,0,0,0,8.11-8.11V8.11A8.11,8.11,0,0,0,291.89,0Z" />
|
||||
<rect style="fill: #c4c4c4" x="5" y="5" width="290" height="158.75" rx="2.5" />
|
||||
</svg>
|
||||
<RadioGroup
|
||||
:model-value="notificationPosition"
|
||||
class="absolute inset-0"
|
||||
@update:modelValue="changeNotificationPosition">
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-topLeft"
|
||||
aria-label="topLeft"
|
||||
value="topLeft"
|
||||
class="absolute top-[20%] left-[10%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-top"
|
||||
aria-label="top"
|
||||
value="top"
|
||||
class="absolute top-[20%] left-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-topRight"
|
||||
aria-label="topRight"
|
||||
value="topRight"
|
||||
class="absolute top-[20%] left-[90%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-centerLeft"
|
||||
aria-label="centerLeft"
|
||||
value="centerLeft"
|
||||
class="absolute top-1/2 left-[10%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-center"
|
||||
aria-label="center"
|
||||
value="center"
|
||||
class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-centerRight"
|
||||
aria-label="centerRight"
|
||||
value="centerRight"
|
||||
class="absolute top-1/2 left-[90%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-bottomLeft"
|
||||
aria-label="bottomLeft"
|
||||
value="bottomLeft"
|
||||
class="absolute top-[80%] left-[10%] -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-bottom"
|
||||
aria-label="bottom"
|
||||
value="bottom"
|
||||
class="absolute top-[80%] left-1/2 -translate-x-1/2 -translate-y-1/2" />
|
||||
<RadioGroupItem
|
||||
id="notificationPosition-bottomRight"
|
||||
aria-label="bottomRight"
|
||||
value="bottomRight"
|
||||
class="absolute top-[80%] left-[90%] -translate-x-1/2 -translate-y-1/2" />
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<div style="display: flex">
|
||||
<Button @click="closeDialog">
|
||||
{{ t('dialog.notification_position.ok') }}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="ossDialog"
|
||||
:title="t('dialog.open_source.header')"
|
||||
width="650px"
|
||||
@close="closeDialog"
|
||||
destroy-on-close>
|
||||
<div v-once style="height: 350px; overflow: hidden scroll; word-break: break-all">
|
||||
<div>
|
||||
<span>{{ t('dialog.open_source.description') }}</span>
|
||||
</div>
|
||||
<Dialog :open="ossDialog" @update:open="(open) => !open && closeDialog()">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.open_source.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div v-once style="height: 350px; overflow: hidden scroll; word-break: break-all">
|
||||
<div>
|
||||
<span>{{ t('dialog.open_source.description') }}</span>
|
||||
</div>
|
||||
|
||||
<div v-for="lib in openSourceSoftwareLicenses" :key="lib.name" style="margin-top: 15px">
|
||||
<p style="font-weight: bold">{{ lib.name }}</p>
|
||||
<pre style="font-size: 12px; white-space: pre-line">{{ lib.licenseText }}</pre>
|
||||
<div v-for="lib in openSourceSoftwareLicenses" :key="lib.name" style="margin-top: 15px">
|
||||
<p style="font-weight: bold">{{ lib.name }}</p>
|
||||
<pre style="font-size: 12px; white-space: pre-line">{{ lib.licenseText }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { openSourceSoftwareLicenses } from '../../../shared/constants/ossLicenses';
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
v-model="enablePrimaryPasswordDialog.visible"
|
||||
:before-close="enablePrimaryPasswordDialog.beforeClose"
|
||||
:close-on-click-modal="false"
|
||||
:title="t('dialog.primary_password.header')"
|
||||
width="400px">
|
||||
<InputGroupField
|
||||
v-model="enablePrimaryPasswordDialog.password"
|
||||
:placeholder="t('dialog.primary_password.password_placeholder')"
|
||||
type="password"
|
||||
size="sm"
|
||||
maxlength="32"
|
||||
show-password
|
||||
autofocus />
|
||||
<InputGroupField
|
||||
v-model="enablePrimaryPasswordDialog.rePassword"
|
||||
:placeholder="t('dialog.primary_password.re_input_placeholder')"
|
||||
type="password"
|
||||
style="margin-top: 5px"
|
||||
size="sm"
|
||||
maxlength="32"
|
||||
show-password />
|
||||
<template #footer>
|
||||
<Button
|
||||
:disabled="
|
||||
enablePrimaryPasswordDialog.password.length === 0 ||
|
||||
enablePrimaryPasswordDialog.password !== enablePrimaryPasswordDialog.rePassword
|
||||
"
|
||||
@click="handleSetPrimaryPassword()">
|
||||
{{ t('dialog.primary_password.ok') }}
|
||||
</Button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<Dialog v-model:open="enablePrimaryPasswordDialog.visible">
|
||||
<DialogContent @interact-outside.prevent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.primary_password.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<InputGroupField
|
||||
v-model="enablePrimaryPasswordDialog.password"
|
||||
:placeholder="t('dialog.primary_password.password_placeholder')"
|
||||
type="password"
|
||||
size="sm"
|
||||
maxlength="32"
|
||||
show-password
|
||||
autofocus />
|
||||
<InputGroupField
|
||||
v-model="enablePrimaryPasswordDialog.rePassword"
|
||||
:placeholder="t('dialog.primary_password.re_input_placeholder')"
|
||||
type="password"
|
||||
style="margin-top: 5px"
|
||||
size="sm"
|
||||
maxlength="32"
|
||||
show-password />
|
||||
<DialogFooter>
|
||||
<Button
|
||||
:disabled="
|
||||
enablePrimaryPasswordDialog.password.length === 0 ||
|
||||
enablePrimaryPasswordDialog.password !== enablePrimaryPasswordDialog.rePassword
|
||||
"
|
||||
@click="handleSetPrimaryPassword()">
|
||||
{{ t('dialog.primary_password.ok') }}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InputGroupField } from '@/components/ui/input-group';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
@@ -1,52 +1,54 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="isRegistryBackupDialogVisible"
|
||||
:title="t('dialog.registry_backup.header')"
|
||||
width="600px"
|
||||
@close="closeDialog"
|
||||
@closed="clearVrcRegistryDialog">
|
||||
<div style="margin-top: 10px">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; font-size: 12px">
|
||||
<span class="name" style="margin-right: 24px">{{ t('dialog.registry_backup.auto_backup') }}</span>
|
||||
<Switch :model-value="vrcRegistryAutoBackup" @update:modelValue="setVrcRegistryAutoBackup" />
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
">
|
||||
<span class="name" style="margin-right: 24px">{{ t('dialog.registry_backup.ask_to_restore') }}</span>
|
||||
<Switch :model-value="vrcRegistryAskRestore" @update:modelValue="setVrcRegistryAskRestore" />
|
||||
</div>
|
||||
<DataTableLayout
|
||||
class="min-w-0 w-full"
|
||||
:table="table"
|
||||
:loading="false"
|
||||
:table-style="tableStyle"
|
||||
:show-pagination="false"
|
||||
style="margin-top: 10px" />
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 10px">
|
||||
<Button size="sm" variant="destructive" @click="deleteVrcRegistry">{{
|
||||
t('dialog.registry_backup.reset')
|
||||
}}</Button>
|
||||
<div class="flex gap-2">
|
||||
<Button size="sm" variant="outline" @click="promptVrcRegistryBackupName">{{
|
||||
t('dialog.registry_backup.backup')
|
||||
}}</Button>
|
||||
<Button size="sm" variant="outline" @click="restoreVrcRegistryFromFile">{{
|
||||
t('dialog.registry_backup.restore_from_file')
|
||||
<Dialog :open="isRegistryBackupDialogVisible" @update:open="(open) => !open && closeAndClearDialog()">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.registry_backup.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div style="margin-top: 10px">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; font-size: 12px">
|
||||
<span class="name" style="margin-right: 24px">{{ t('dialog.registry_backup.auto_backup') }}</span>
|
||||
<Switch :model-value="vrcRegistryAutoBackup" @update:modelValue="setVrcRegistryAutoBackup" />
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
">
|
||||
<span class="name" style="margin-right: 24px">{{
|
||||
t('dialog.registry_backup.ask_to_restore')
|
||||
}}</span>
|
||||
<Switch :model-value="vrcRegistryAskRestore" @update:modelValue="setVrcRegistryAskRestore" />
|
||||
</div>
|
||||
<DataTableLayout
|
||||
class="min-w-0 w-full"
|
||||
:table="table"
|
||||
:loading="false"
|
||||
:table-style="tableStyle"
|
||||
:show-pagination="false"
|
||||
style="margin-top: 10px" />
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; margin-top: 10px">
|
||||
<Button size="sm" variant="destructive" @click="deleteVrcRegistry">{{
|
||||
t('dialog.registry_backup.reset')
|
||||
}}</Button>
|
||||
<div class="flex gap-2">
|
||||
<Button size="sm" variant="outline" @click="promptVrcRegistryBackupName">{{
|
||||
t('dialog.registry_backup.backup')
|
||||
}}</Button>
|
||||
<Button size="sm" variant="outline" @click="restoreVrcRegistryFromFile">{{
|
||||
t('dialog.registry_backup.restore_from_file')
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { DataTableLayout } from '@/components/ui/data-table';
|
||||
@@ -201,7 +203,8 @@
|
||||
document.body.appendChild(fileInput);
|
||||
|
||||
fileInput.onchange = function (event) {
|
||||
const file = event.target.files[0];
|
||||
const target = /** @type {HTMLInputElement | null} */ (event.target);
|
||||
const file = target?.files?.[0];
|
||||
if (file) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function () {
|
||||
@@ -263,6 +266,13 @@
|
||||
registryBackupTable.value.data = [];
|
||||
}
|
||||
|
||||
function closeAndClearDialog() {
|
||||
closeDialog();
|
||||
// TODO: Element Plus had a distinct @closed event after animation.
|
||||
// If you ever need exact timing, wrap DialogContent with a Transition and call clear on after-leave.
|
||||
clearVrcRegistryDialog();
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
isRegistryBackupDialogVisible.value = false;
|
||||
}
|
||||
|
||||
@@ -1,136 +1,139 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="isTranslationApiDialogVisible"
|
||||
:title="t('dialog.translation_api.header')"
|
||||
width="450px"
|
||||
@close="closeDialog">
|
||||
<div class="options-container-item">
|
||||
<span class="name">{{ t('view.settings.appearance.appearance.bio_language') }}</span>
|
||||
<Select :model-value="bioLanguage" @update:modelValue="setBioLanguage">
|
||||
<SelectTrigger size="sm" style="float: right">
|
||||
<SelectValue :placeholder="String(getLanguageName(bioLanguage) || bioLanguage || '')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem v-for="language in languageCodes" :key="language" :value="language">
|
||||
{{ getLanguageName(language) }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<br />
|
||||
<FieldGroup class="mb-3">
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.mode') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<Select :model-value="form.translationApiType" @update:modelValue="handleTranslationApiTypeChange">
|
||||
<SelectTrigger size="sm" style="width: 100%">
|
||||
<SelectValue :placeholder="t('dialog.translation_api.mode')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="google" :text-value="t('dialog.translation_api.mode_google')">
|
||||
{{ t('dialog.translation_api.mode_google') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="openai" :text-value="t('dialog.translation_api.mode_openai')">
|
||||
{{ t('dialog.translation_api.mode_openai') }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<template v-if="form.translationApiType === 'google'">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.description') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
v-model="form.translationApiKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="AIzaSy..."
|
||||
clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</template>
|
||||
|
||||
<template v-if="form.translationApiType === 'openai'">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.endpoint') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
v-model="form.translationApiEndpoint"
|
||||
placeholder="https://api.openai.com/v1/chat/completions"
|
||||
clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.api_key') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
v-model="form.translationApiKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="sk-..."
|
||||
clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.model') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField v-model="form.translationApiModel" clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.prompt_optional') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupTextareaField v-model="form.translationApiPrompt" :rows="3" clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex items-center justify-between">
|
||||
<Button
|
||||
variant="outline"
|
||||
v-if="form.translationApiType === 'google'"
|
||||
@click="
|
||||
openExternalLink(
|
||||
'https://translatepress.com/docs/automatic-translation/generate-google-api-key/'
|
||||
)
|
||||
">
|
||||
{{ t('dialog.translation_api.guide') }}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
v-if="form.translationApiType === 'openai'"
|
||||
@click="testOpenAiTranslation">
|
||||
{{ t('dialog.translation_api.test') }}
|
||||
</Button>
|
||||
<div>
|
||||
<Button style="margin-left: auto" @click="saveTranslationApiConfig">
|
||||
{{ t('dialog.translation_api.save') }}
|
||||
</Button>
|
||||
</div>
|
||||
<Dialog :open="isTranslationApiDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.translation_api.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div class="options-container-item">
|
||||
<span class="name">{{ t('view.settings.appearance.appearance.bio_language') }}</span>
|
||||
<Select :model-value="bioLanguage" @update:modelValue="setBioLanguage">
|
||||
<SelectTrigger size="sm" style="float: right">
|
||||
<SelectValue :placeholder="String(getLanguageName(bioLanguage) || bioLanguage || '')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem v-for="language in languageCodes" :key="language" :value="language">
|
||||
{{ getLanguageName(language) }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<br />
|
||||
<FieldGroup class="mb-3">
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.mode') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<Select
|
||||
:model-value="form.translationApiType"
|
||||
@update:modelValue="handleTranslationApiTypeChange">
|
||||
<SelectTrigger size="sm" style="width: 100%">
|
||||
<SelectValue :placeholder="t('dialog.translation_api.mode')" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="google" :text-value="t('dialog.translation_api.mode_google')">
|
||||
{{ t('dialog.translation_api.mode_google') }}
|
||||
</SelectItem>
|
||||
<SelectItem value="openai" :text-value="t('dialog.translation_api.mode_openai')">
|
||||
{{ t('dialog.translation_api.mode_openai') }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<template v-if="form.translationApiType === 'google'">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.description') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
v-model="form.translationApiKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="AIzaSy..."
|
||||
clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</template>
|
||||
|
||||
<template v-if="form.translationApiType === 'openai'">
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.endpoint') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
v-model="form.translationApiEndpoint"
|
||||
placeholder="https://api.openai.com/v1/chat/completions"
|
||||
clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.api_key') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
v-model="form.translationApiKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="sk-..."
|
||||
clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.model') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField v-model="form.translationApiModel" clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.prompt_optional') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupTextareaField v-model="form.translationApiPrompt" :rows="3" clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
</template>
|
||||
|
||||
<DialogFooter>
|
||||
<div class="flex items-center justify-between">
|
||||
<Button
|
||||
variant="outline"
|
||||
v-if="form.translationApiType === 'google'"
|
||||
@click="
|
||||
openExternalLink(
|
||||
'https://translatepress.com/docs/automatic-translation/generate-google-api-key/'
|
||||
)
|
||||
">
|
||||
{{ t('dialog.translation_api.guide') }}
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
class="mr-2"
|
||||
v-if="form.translationApiType === 'openai'"
|
||||
@click="testOpenAiTranslation">
|
||||
{{ t('dialog.translation_api.test') }}
|
||||
</Button>
|
||||
<div>
|
||||
<Button style="margin-left: auto" @click="saveTranslationApiConfig">
|
||||
{{ t('dialog.translation_api.save') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
|
||||
import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group';
|
||||
import { reactive, watch } from 'vue';
|
||||
|
||||
@@ -1,176 +1,181 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="isVRChatConfigDialogVisible"
|
||||
:title="t('dialog.config_json.header')"
|
||||
width="420px"
|
||||
@close="closeDialog">
|
||||
<div v-loading="loading">
|
||||
<div style="font-size: 12px; word-break: keep-all">
|
||||
{{ t('dialog.config_json.description1') }} <br />
|
||||
{{ t('dialog.config_json.description2') }}
|
||||
</div>
|
||||
<br />
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.cache_size') }}</span>
|
||||
<span v-text="VRChatUsedCacheSize"></span>
|
||||
<span>/</span>
|
||||
<span v-text="totalCacheSize"></span>
|
||||
<span>GB</span>
|
||||
<TooltipWrapper side="top" :content="t('dialog.config_json.refresh')">
|
||||
<Button
|
||||
class="rounded-full"
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
:disabled="VRChatCacheSizeLoading"
|
||||
style="margin-left: 5px"
|
||||
@click="getVRChatCacheSize">
|
||||
<Spinner v-if="VRChatCacheSizeLoading" />
|
||||
<RefreshCw v-else />
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_all_cache') }}</span>
|
||||
<Button size="sm" variant="outline" style="margin-left: 5px" @click="showDeleteAllVRChatCacheConfirm">{{
|
||||
t('dialog.config_json.delete_cache')
|
||||
}}</Button>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_old_cache') }}</span>
|
||||
<Button size="sm" variant="outline" style="margin-left: 5px" @click="sweepVRChatCache">{{
|
||||
t('dialog.config_json.sweep_cache')
|
||||
}}</Button>
|
||||
</div>
|
||||
|
||||
<div v-for="(item, value) in VRChatConfigList" :key="value" style="display: block; margin-top: 10px">
|
||||
<span style="word-break: keep-all">{{ item.name }}:</span>
|
||||
<div style="display: flex">
|
||||
<InputGroupAction
|
||||
v-model="VRChatConfigFile[value]"
|
||||
:placeholder="item.default"
|
||||
size="sm"
|
||||
:type="item.type ? item.type : 'text'"
|
||||
:min="item.min"
|
||||
:max="item.max"
|
||||
@input="refreshDialogValues"
|
||||
style="flex: 1; margin-top: 5px">
|
||||
<template #actions>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
v-if="item.folderBrowser"
|
||||
@click="openConfigFolderBrowser(value)">
|
||||
</Button>
|
||||
</template>
|
||||
</InputGroupAction>
|
||||
<Dialog :open="isVRChatConfigDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.config_json.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div v-loading="loading">
|
||||
<div style="font-size: 12px; word-break: keep-all">
|
||||
{{ t('dialog.config_json.description1') }} <br />
|
||||
{{ t('dialog.config_json.description2') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.camera_resolution') }}</span>
|
||||
<br />
|
||||
<Select
|
||||
:model-value="vrchatCameraResolutionKey"
|
||||
@update:modelValue="(v) => (vrchatCameraResolutionKey = v)">
|
||||
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||
<SelectValue :placeholder="getVRChatCameraResolution()" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem
|
||||
v-for="row in VRChatCameraResolutions"
|
||||
:key="row.name"
|
||||
:value="getVRChatResolutionKey(row)">
|
||||
{{ row.name }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.spout_resolution') }}</span>
|
||||
<br />
|
||||
<Select
|
||||
:model-value="vrchatSpoutResolutionKey"
|
||||
@update:modelValue="(v) => (vrchatSpoutResolutionKey = v)">
|
||||
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||
<SelectValue :placeholder="getVRChatSpoutResolution()" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem
|
||||
v-for="row in VRChatScreenshotResolutions"
|
||||
:key="row.name"
|
||||
:value="getVRChatResolutionKey(row)">
|
||||
{{ row.name }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.screenshot_resolution') }}</span>
|
||||
<br />
|
||||
<Select
|
||||
:model-value="vrchatScreenshotResolutionKey"
|
||||
@update:modelValue="(v) => (vrchatScreenshotResolutionKey = v)">
|
||||
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||
<SelectValue :placeholder="getVRChatScreenshotResolution()" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem
|
||||
v-for="row in VRChatScreenshotResolutions"
|
||||
:key="row.name"
|
||||
:value="getVRChatResolutionKey(row)">
|
||||
{{ row.name }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<label class="inline-flex items-center gap-2" style="margin-top: 5px; display: block">
|
||||
<Checkbox
|
||||
v-model="VRChatConfigFile.picture_output_split_by_date"
|
||||
@update:modelValue="refreshDialogValues" />
|
||||
<span>{{ t('dialog.config_json.picture_sort_by_date') }}</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center gap-2" style="margin-top: 5px; display: block">
|
||||
<Checkbox v-model="VRChatConfigFile.disableRichPresence" @update:modelValue="refreshDialogValues" />
|
||||
<span>{{ t('dialog.config_json.disable_discord_presence') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<div>
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.cache_size') }}</span>
|
||||
<span v-text="VRChatUsedCacheSize"></span>
|
||||
<span>/</span>
|
||||
<span v-text="totalCacheSize"></span>
|
||||
<span>GB</span>
|
||||
<TooltipWrapper side="top" :content="t('dialog.config_json.refresh')">
|
||||
<Button
|
||||
variant="ghost"
|
||||
@click="openExternalLink('https://docs.vrchat.com/docs/configuration-file')"
|
||||
>{{ t('dialog.config_json.vrchat_docs') }}</Button
|
||||
class="rounded-full"
|
||||
variant="outline"
|
||||
size="icon-sm"
|
||||
:disabled="VRChatCacheSizeLoading"
|
||||
style="margin-left: 5px"
|
||||
@click="getVRChatCacheSize">
|
||||
<Spinner v-if="VRChatCacheSizeLoading" />
|
||||
<RefreshCw v-else />
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_all_cache') }}</span>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
style="margin-left: 5px"
|
||||
@click="showDeleteAllVRChatCacheConfirm"
|
||||
>{{ t('dialog.config_json.delete_cache') }}</Button
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<Button variant="secondary" class="mr-2" @click="closeDialog">{{
|
||||
t('dialog.config_json.cancel')
|
||||
}}</Button>
|
||||
<Button :disabled="loading" @click="saveVRChatConfigFile">{{
|
||||
t('dialog.config_json.save')
|
||||
|
||||
<div style="margin-top: 10px">
|
||||
<span style="margin-right: 5px">{{ t('dialog.config_json.delete_old_cache') }}</span>
|
||||
<Button size="sm" variant="outline" style="margin-left: 5px" @click="sweepVRChatCache">{{
|
||||
t('dialog.config_json.sweep_cache')
|
||||
}}</Button>
|
||||
</div>
|
||||
|
||||
<div v-for="(item, value) in VRChatConfigList" :key="value" style="display: block; margin-top: 10px">
|
||||
<span style="word-break: keep-all">{{ item.name }}:</span>
|
||||
<div style="display: flex">
|
||||
<InputGroupAction
|
||||
v-model="VRChatConfigFile[value]"
|
||||
:placeholder="item.default"
|
||||
size="sm"
|
||||
:type="item.type ? item.type : 'text'"
|
||||
:min="item.min"
|
||||
:max="item.max"
|
||||
@input="refreshDialogValues"
|
||||
style="flex: 1; margin-top: 5px">
|
||||
<template #actions>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
v-if="item.folderBrowser"
|
||||
@click="openConfigFolderBrowser(value)">
|
||||
</Button>
|
||||
</template>
|
||||
</InputGroupAction>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.camera_resolution') }}</span>
|
||||
<br />
|
||||
<Select
|
||||
:model-value="vrchatCameraResolutionKey"
|
||||
@update:modelValue="(v) => (vrchatCameraResolutionKey = v)">
|
||||
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||
<SelectValue :placeholder="getVRChatCameraResolution()" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem
|
||||
v-for="row in VRChatCameraResolutions"
|
||||
:key="row.name"
|
||||
:value="getVRChatResolutionKey(row)">
|
||||
{{ row.name }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.spout_resolution') }}</span>
|
||||
<br />
|
||||
<Select
|
||||
:model-value="vrchatSpoutResolutionKey"
|
||||
@update:modelValue="(v) => (vrchatSpoutResolutionKey = v)">
|
||||
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||
<SelectValue :placeholder="getVRChatSpoutResolution()" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem
|
||||
v-for="row in VRChatScreenshotResolutions"
|
||||
:key="row.name"
|
||||
:value="getVRChatResolutionKey(row)">
|
||||
{{ row.name }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div style="display: inline-block; margin-top: 10px">
|
||||
<span>{{ t('dialog.config_json.screenshot_resolution') }}</span>
|
||||
<br />
|
||||
<Select
|
||||
:model-value="vrchatScreenshotResolutionKey"
|
||||
@update:modelValue="(v) => (vrchatScreenshotResolutionKey = v)">
|
||||
<SelectTrigger size="sm" style="margin-top: 5px">
|
||||
<SelectValue :placeholder="getVRChatScreenshotResolution()" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem
|
||||
v-for="row in VRChatScreenshotResolutions"
|
||||
:key="row.name"
|
||||
:value="getVRChatResolutionKey(row)">
|
||||
{{ row.name }}
|
||||
</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<label class="inline-flex items-center gap-2" style="margin-top: 5px; display: block">
|
||||
<Checkbox
|
||||
v-model="VRChatConfigFile.picture_output_split_by_date"
|
||||
@update:modelValue="refreshDialogValues" />
|
||||
<span>{{ t('dialog.config_json.picture_sort_by_date') }}</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center gap-2" style="margin-top: 5px; display: block">
|
||||
<Checkbox v-model="VRChatConfigFile.disableRichPresence" @update:modelValue="refreshDialogValues" />
|
||||
<span>{{ t('dialog.config_json.disable_discord_presence') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<DialogFooter>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between">
|
||||
<div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
@click="openExternalLink('https://docs.vrchat.com/docs/configuration-file')"
|
||||
>{{ t('dialog.config_json.vrchat_docs') }}</Button
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<Button variant="secondary" class="mr-2" @click="closeDialog">{{
|
||||
t('dialog.config_json.cancel')
|
||||
}}</Button>
|
||||
<Button :disabled="loading" @click="saveVRChatConfigFile">{{
|
||||
t('dialog.config_json.save')
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
class="x-dialog"
|
||||
:model-value="isYouTubeApiDialogVisible"
|
||||
:title="t('dialog.youtube_api.header')"
|
||||
width="450px"
|
||||
@close="closeDialog">
|
||||
<div style="font-size: 12px">{{ t('dialog.youtube_api.description') }} <br /></div>
|
||||
<Dialog :open="isYouTubeApiDialogVisible" @update:open="(open) => (open ? null : closeDialog())">
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ t('dialog.youtube_api.header') }}</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div style="font-size: 12px">{{ t('dialog.youtube_api.description') }} <br /></div>
|
||||
|
||||
<InputGroupTextareaField
|
||||
v-model="youTubeApiKey"
|
||||
:placeholder="t('dialog.youtube_api.placeholder')"
|
||||
:maxlength="39"
|
||||
:rows="2"
|
||||
class="mt-2.5"
|
||||
show-count />
|
||||
<InputGroupTextareaField
|
||||
v-model="youTubeApiKey"
|
||||
:placeholder="t('dialog.youtube_api.placeholder')"
|
||||
:maxlength="39"
|
||||
:rows="2"
|
||||
class="mt-2.5"
|
||||
show-count />
|
||||
|
||||
<template #footer>
|
||||
<div class="flex items-center justify-between">
|
||||
<Button variant="outline" @click="openExternalLink('https://smashballoon.com/doc/youtube-api-key/')">
|
||||
{{ t('dialog.youtube_api.guide') }}
|
||||
</Button>
|
||||
<Button style="margin-left: auto" @click="testYouTubeApiKey">
|
||||
{{ t('dialog.youtube_api.save') }}
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<DialogFooter>
|
||||
<div class="flex items-center justify-between">
|
||||
<Button
|
||||
variant="outline"
|
||||
@click="openExternalLink('https://smashballoon.com/doc/youtube-api-key/')">
|
||||
{{ t('dialog.youtube_api.guide') }}
|
||||
</Button>
|
||||
<Button style="margin-left: auto" @click="testYouTubeApiKey">
|
||||
{{ t('dialog.youtube_api.save') }}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InputGroupTextareaField } from '@/components/ui/input-group';
|
||||
import { storeToRefs } from 'pinia';
|
||||
|
||||
Reference in New Issue
Block a user