mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-07 06:56:04 +02:00
replace el-form
This commit is contained in:
@@ -51,65 +51,77 @@
|
||||
<p class="mutual-graph__force-description">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.description') }}
|
||||
</p>
|
||||
<el-form label-position="top" size="small" class="mutual-graph__force-form">
|
||||
<el-form-item :label="t('view.charts.mutual_friend.force_dialog.repulsion')">
|
||||
<NumberField
|
||||
v-model="forceForm.repulsion"
|
||||
:step="1"
|
||||
:format-options="{ maximumFractionDigits: 0 }"
|
||||
class="mutual-graph__number-input">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldInput />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
<div class="mutual-graph__helper">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.repulsion_help') }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('view.charts.mutual_friend.force_dialog.edge_length_min')">
|
||||
<NumberField
|
||||
v-model="forceForm.edgeLengthMin"
|
||||
:step="1"
|
||||
:format-options="{ maximumFractionDigits: 0 }"
|
||||
class="mutual-graph__number-input">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldInput />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
<div class="mutual-graph__helper">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.edge_length_min_help') }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('view.charts.mutual_friend.force_dialog.edge_length_max')">
|
||||
<NumberField
|
||||
v-model="forceForm.edgeLengthMax"
|
||||
:step="1"
|
||||
:format-options="{ maximumFractionDigits: 0 }"
|
||||
class="mutual-graph__number-input">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldInput />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
<div class="mutual-graph__helper">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.edge_length_max_help') }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="t('view.charts.mutual_friend.force_dialog.gravity')">
|
||||
<NumberField
|
||||
v-model="forceForm.gravity"
|
||||
:max="1"
|
||||
:step="0.1"
|
||||
:format-options="{ maximumFractionDigits: 1 }"
|
||||
class="mutual-graph__number-input">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldInput />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
<div class="mutual-graph__helper">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.gravity_help') }}
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<FieldGroup class="mutual-graph__force-form">
|
||||
<Field>
|
||||
<FieldLabel>{{ t('view.charts.mutual_friend.force_dialog.repulsion') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<NumberField
|
||||
v-model="forceForm.repulsion"
|
||||
:step="1"
|
||||
:format-options="{ maximumFractionDigits: 0 }"
|
||||
class="mutual-graph__number-input">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldInput />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
<FieldDescription class="mutual-graph__helper">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.repulsion_help') }}
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>{{ t('view.charts.mutual_friend.force_dialog.edge_length_min') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<NumberField
|
||||
v-model="forceForm.edgeLengthMin"
|
||||
:step="1"
|
||||
:format-options="{ maximumFractionDigits: 0 }"
|
||||
class="mutual-graph__number-input">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldInput />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
<FieldDescription class="mutual-graph__helper">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.edge_length_min_help') }}
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>{{ t('view.charts.mutual_friend.force_dialog.edge_length_max') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<NumberField
|
||||
v-model="forceForm.edgeLengthMax"
|
||||
:step="1"
|
||||
:format-options="{ maximumFractionDigits: 0 }"
|
||||
class="mutual-graph__number-input">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldInput />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
<FieldDescription class="mutual-graph__helper">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.edge_length_max_help') }}
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>{{ t('view.charts.mutual_friend.force_dialog.gravity') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<NumberField
|
||||
v-model="forceForm.gravity"
|
||||
:max="1"
|
||||
:step="0.1"
|
||||
:format-options="{ maximumFractionDigits: 1 }"
|
||||
class="mutual-graph__number-input">
|
||||
<NumberFieldContent>
|
||||
<NumberFieldInput />
|
||||
</NumberFieldContent>
|
||||
</NumberField>
|
||||
<FieldDescription class="mutual-graph__helper">
|
||||
{{ t('view.charts.mutual_friend.force_dialog.gravity_help') }}
|
||||
</FieldDescription>
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</FieldGroup>
|
||||
|
||||
<template #footer>
|
||||
<div class="mutual-graph__dialog-footer">
|
||||
@@ -127,6 +139,7 @@
|
||||
|
||||
<script setup>
|
||||
import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
||||
import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel } from '@/components/ui/field';
|
||||
import { NumberField, NumberFieldContent, NumberFieldInput } from '@/components/ui/number-field';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { ElMessageBox } from 'element-plus';
|
||||
|
||||
+152
-72
@@ -16,71 +16,101 @@
|
||||
<div class="x-login-form-container">
|
||||
<div>
|
||||
<h2 style="font-weight: bold; text-align: center; margin: 0">{{ t('view.login.login') }}</h2>
|
||||
<el-form
|
||||
ref="loginFormRef"
|
||||
:model="loginForm"
|
||||
:rules="loginForm.rules"
|
||||
@submit.prevent="handleLogin()">
|
||||
<el-form-item
|
||||
:label="t('view.login.field.username')"
|
||||
prop="username"
|
||||
required
|
||||
style="display: block">
|
||||
<InputGroupField
|
||||
v-model="loginForm.username"
|
||||
name="username"
|
||||
:placeholder="t('view.login.field.username')"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="t('view.login.field.password')"
|
||||
prop="password"
|
||||
required
|
||||
style="display: block; margin-top: 10px">
|
||||
<InputGroupField
|
||||
v-model="loginForm.password"
|
||||
type="password"
|
||||
name="password"
|
||||
:placeholder="t('view.login.field.password')"
|
||||
clearable
|
||||
show-password />
|
||||
</el-form-item>
|
||||
<form id="login-form" @submit.prevent="onSubmit">
|
||||
<FieldGroup class="gap-3">
|
||||
<VeeField v-slot="{ field, errors }" name="username">
|
||||
<Field :data-invalid="!!errors.length">
|
||||
<FieldLabel for="login-form-username">
|
||||
{{ t('view.login.field.username') }}
|
||||
</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
id="login-form-username"
|
||||
:model-value="field.value"
|
||||
name="username"
|
||||
:placeholder="t('view.login.field.username')"
|
||||
:aria-invalid="!!errors.length"
|
||||
clearable
|
||||
@update:modelValue="field.onChange"
|
||||
@blur="field.onBlur" />
|
||||
<FieldError v-if="errors.length" :errors="errors" />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</VeeField>
|
||||
<VeeField v-slot="{ field, errors }" name="password">
|
||||
<Field :data-invalid="!!errors.length">
|
||||
<FieldLabel for="login-form-password">
|
||||
{{ t('view.login.field.password') }}
|
||||
</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
id="login-form-password"
|
||||
:model-value="field.value"
|
||||
type="password"
|
||||
name="password"
|
||||
:placeholder="t('view.login.field.password')"
|
||||
:aria-invalid="!!errors.length"
|
||||
clearable
|
||||
show-password
|
||||
@update:modelValue="field.onChange"
|
||||
@blur="field.onBlur" />
|
||||
<FieldError v-if="errors.length" :errors="errors" />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</VeeField>
|
||||
</FieldGroup>
|
||||
<label class="inline-flex items-center gap-2 mr-2">
|
||||
<Checkbox v-model="loginForm.saveCredentials" />
|
||||
<span>{{ t('view.login.field.saveCredentials') }}</span>
|
||||
</label>
|
||||
<label class="inline-flex items-center gap-2" style="margin-top: 10px">
|
||||
<Checkbox v-model="enableCustomEndpoint" @update:modelValue="toggleCustomEndpoint" />
|
||||
<Checkbox v-model="enableCustomEndpoint" @update:modelValue="handleCustomEndpointToggle" />
|
||||
<span>{{ t('view.login.field.devEndpoint') }}</span>
|
||||
</label>
|
||||
<el-form-item
|
||||
v-if="enableCustomEndpoint"
|
||||
:label="t('view.login.field.endpoint')"
|
||||
prop="endpoint"
|
||||
style="margin-top: 10px">
|
||||
<InputGroupField
|
||||
v-model="loginForm.endpoint"
|
||||
name="endpoint"
|
||||
:placeholder="AppDebug.endpointDomainVrchat"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="enableCustomEndpoint"
|
||||
:label="t('view.login.field.websocket')"
|
||||
prop="websocket"
|
||||
style="margin-top: 10px">
|
||||
<InputGroupField
|
||||
v-model="loginForm.websocket"
|
||||
name="websocket"
|
||||
:placeholder="AppDebug.websocketDomainVrchat"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<Button class="mt-2" type="submit" size="lg" style="width: 100%">{{
|
||||
t('view.login.login')
|
||||
}}</Button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<FieldGroup v-if="enableCustomEndpoint" class="mt-3 gap-3">
|
||||
<VeeField v-slot="{ field, errors }" name="endpoint">
|
||||
<Field :data-invalid="!!errors.length">
|
||||
<FieldLabel for="login-form-endpoint">
|
||||
{{ t('view.login.field.endpoint') }}
|
||||
</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
id="login-form-endpoint"
|
||||
:model-value="field.value"
|
||||
name="endpoint"
|
||||
:placeholder="AppDebug.endpointDomainVrchat"
|
||||
:aria-invalid="!!errors.length"
|
||||
clearable
|
||||
@update:modelValue="field.onChange"
|
||||
@blur="field.onBlur" />
|
||||
<FieldError v-if="errors.length" :errors="errors" />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</VeeField>
|
||||
<VeeField v-slot="{ field, errors }" name="websocket">
|
||||
<Field :data-invalid="!!errors.length">
|
||||
<FieldLabel for="login-form-websocket">
|
||||
{{ t('view.login.field.websocket') }}
|
||||
</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField
|
||||
id="login-form-websocket"
|
||||
:model-value="field.value"
|
||||
name="websocket"
|
||||
:placeholder="AppDebug.websocketDomainVrchat"
|
||||
:aria-invalid="!!errors.length"
|
||||
clearable
|
||||
@update:modelValue="field.onChange"
|
||||
@blur="field.onBlur" />
|
||||
<FieldError v-if="errors.length" :errors="errors" />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
</VeeField>
|
||||
</FieldGroup>
|
||||
<Field class="mt-2">
|
||||
<Button type="submit" size="lg" style="width: 100%">{{ t('view.login.login') }}</Button>
|
||||
</Field>
|
||||
</form>
|
||||
<Button
|
||||
variant="Secondary"
|
||||
size="lg"
|
||||
@@ -147,14 +177,18 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Field, FieldContent, FieldError, FieldGroup, FieldLabel } from '@/components/ui/field';
|
||||
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue';
|
||||
import { CircleArrowDown, Route } from 'lucide-vue-next';
|
||||
import { Field as VeeField, useForm } from 'vee-validate';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InputGroupField } from '@/components/ui/input-group';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { InputGroupField } from '@/components/ui/input-group';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toTypedSchema } from '@vee-validate/zod';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { useAuthStore, useGeneralSettingsStore, useVRCXUpdaterStore } from '../../stores';
|
||||
import { openExternalLink, userImage } from '../../shared/utils';
|
||||
@@ -171,8 +205,27 @@
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const loginFormRef = ref(null);
|
||||
const savedCredentials = ref({});
|
||||
const requiredMessage = 'Required';
|
||||
|
||||
const formSchema = toTypedSchema(
|
||||
z.object({
|
||||
username: z.string().min(1, requiredMessage),
|
||||
password: z.string().min(1, requiredMessage),
|
||||
endpoint: z.string().optional(),
|
||||
websocket: z.string().optional()
|
||||
})
|
||||
);
|
||||
|
||||
const { handleSubmit, resetForm, setValues, values } = useForm({
|
||||
validationSchema: formSchema,
|
||||
initialValues: {
|
||||
username: loginForm.value.username,
|
||||
password: loginForm.value.password,
|
||||
endpoint: loginForm.value.endpoint,
|
||||
websocket: loginForm.value.websocket
|
||||
}
|
||||
});
|
||||
|
||||
async function clickDeleteSavedLogin(userId) {
|
||||
await deleteSavedLogin(userId);
|
||||
@@ -184,15 +237,22 @@
|
||||
await updateSavedCredentials();
|
||||
}
|
||||
|
||||
function handleLogin() {
|
||||
if (loginFormRef.value) {
|
||||
loginFormRef.value.validate(async (valid) => {
|
||||
if (valid) {
|
||||
await login();
|
||||
await updateSavedCredentials();
|
||||
}
|
||||
});
|
||||
}
|
||||
const onSubmit = handleSubmit(async (formValues) => {
|
||||
loginForm.value.username = formValues.username ?? '';
|
||||
loginForm.value.password = formValues.password ?? '';
|
||||
loginForm.value.endpoint = formValues.endpoint ?? '';
|
||||
loginForm.value.websocket = formValues.websocket ?? '';
|
||||
await login();
|
||||
await updateSavedCredentials();
|
||||
});
|
||||
|
||||
async function handleCustomEndpointToggle() {
|
||||
await toggleCustomEndpoint();
|
||||
setValues({
|
||||
...values,
|
||||
endpoint: loginForm.value.endpoint,
|
||||
websocket: loginForm.value.websocket
|
||||
});
|
||||
}
|
||||
|
||||
async function updateSavedCredentials() {
|
||||
@@ -224,9 +284,29 @@
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (loginFormRef.value) {
|
||||
loginFormRef.value.resetFields();
|
||||
}
|
||||
resetForm({
|
||||
values: {
|
||||
username: '',
|
||||
password: '',
|
||||
endpoint: '',
|
||||
websocket: ''
|
||||
}
|
||||
});
|
||||
loginForm.value.username = '';
|
||||
loginForm.value.password = '';
|
||||
loginForm.value.endpoint = '';
|
||||
loginForm.value.websocket = '';
|
||||
savedCredentials.value = {};
|
||||
});
|
||||
|
||||
watch(
|
||||
values,
|
||||
(formValues) => {
|
||||
loginForm.value.username = formValues.username ?? '';
|
||||
loginForm.value.password = formValues.password ?? '';
|
||||
loginForm.value.endpoint = formValues.endpoint ?? '';
|
||||
loginForm.value.websocket = formValues.websocket ?? '';
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -21,65 +21,83 @@
|
||||
</Select>
|
||||
</div>
|
||||
<br />
|
||||
<el-form label-position="top" label-width="120px" size="small" style="margin-bottom: 12px">
|
||||
<el-form-item :label="t('dialog.translation_api.mode')">
|
||||
<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>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<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'">
|
||||
<el-form label-position="top" label-width="120px" size="small">
|
||||
<el-form-item :label="t('dialog.translation_api.description')">
|
||||
<InputGroupField
|
||||
v-model="form.translationApiKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="AIzaSy..."
|
||||
clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<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'">
|
||||
<el-form label-position="top" label-width="120px" size="small">
|
||||
<el-form-item :label="t('dialog.translation_api.openai.endpoint')">
|
||||
<InputGroupField
|
||||
v-model="form.translationApiEndpoint"
|
||||
placeholder="https://api.openai.com/v1/chat/completions"
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<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>
|
||||
|
||||
<el-form-item :label="t('dialog.translation_api.openai.api_key')">
|
||||
<InputGroupField
|
||||
v-model="form.translationApiKey"
|
||||
type="password"
|
||||
show-password
|
||||
placeholder="sk-..."
|
||||
clearable />
|
||||
</el-form-item>
|
||||
<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>
|
||||
|
||||
<el-form-item :label="t('dialog.translation_api.openai.model')">
|
||||
<InputGroupField v-model="form.translationApiModel" clearable />
|
||||
</el-form-item>
|
||||
<Field>
|
||||
<FieldLabel>{{ t('dialog.translation_api.openai.model') }}</FieldLabel>
|
||||
<FieldContent>
|
||||
<InputGroupField v-model="form.translationApiModel" clearable />
|
||||
</FieldContent>
|
||||
</Field>
|
||||
|
||||
<el-form-item :label="t('dialog.translation_api.openai.prompt_optional')">
|
||||
<InputGroupTextareaField v-model="form.translationApiPrompt" :rows="3" clearable />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<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>
|
||||
@@ -94,14 +112,14 @@
|
||||
">
|
||||
{{ 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
|
||||
variant="secondary"
|
||||
class="mr-2"
|
||||
v-if="form.translationApiType === 'openai'"
|
||||
@click="testOpenAiTranslation">
|
||||
{{ t('dialog.translation_api.test') }}
|
||||
</Button>
|
||||
<Button style="margin-left: auto" @click="saveTranslationApiConfig">
|
||||
{{ t('dialog.translation_api.save') }}
|
||||
</Button>
|
||||
@@ -113,9 +131,10 @@
|
||||
|
||||
<script setup>
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Field, FieldContent, FieldGroup, FieldLabel } from '@/components/ui/field';
|
||||
import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group';
|
||||
import { reactive, watch } from 'vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { InputGroupField, InputGroupTextareaField } from '@/components/ui/input-group';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { toast } from 'vue-sonner';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
@@ -312,9 +312,9 @@
|
||||
.x-link:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.x-link:hover span {
|
||||
/* .x-link:hover span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
} */
|
||||
.is-rotated {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user