feat(login): add language switcher and refine page layout
add language switcher with Chinese, English and Thai options at login page bottom integrate i18n locale switching functionality restructure login page container for better content centering adjust van-cell styles to remove side padding and full-width border
This commit is contained in:
@@ -1,41 +1,53 @@
|
||||
<template>
|
||||
<div class="h-[100dvh] flex flex-col items-center justify-center px-4 overflow-hidden bg-white">
|
||||
<div class="px-[12px]">
|
||||
<section>
|
||||
<van-cell :title="t('common.login.fields.country')" :value="selectedCountryDisplay" is-link
|
||||
@click="countryPopupVisible = true" />
|
||||
<div class="h-[100dvh] flex flex-col px-[12px] overflow-hidden bg-white">
|
||||
<div class="flex-1 flex flex-col items-center justify-center">
|
||||
<div>
|
||||
<section>
|
||||
<van-cell :title="t('common.login.fields.country')" :value="selectedCountryDisplay" is-link
|
||||
@click="countryPopupVisible = true" />
|
||||
|
||||
<van-field v-model="phone" type="tel" clearable :label="t('common.login.fields.phone')"
|
||||
:placeholder="t('common.login.placeholders.phone')" autocomplete="tel" />
|
||||
<van-field v-model="phone" type="tel" clearable :label="t('common.login.fields.phone')"
|
||||
:placeholder="t('common.login.placeholders.phone')" autocomplete="tel" />
|
||||
|
||||
<van-field v-model="code" type="digit" clearable maxlength="8" :label="t('common.login.fields.code')"
|
||||
:placeholder="t('common.login.placeholders.code')" autocomplete="one-time-code">
|
||||
<template #button>
|
||||
<van-button class="rounded-full" size="small" @click="handleSendCode">
|
||||
{{ t('common.login.actions.sendCode') }}
|
||||
<van-field v-model="code" type="digit" clearable maxlength="8" :label="t('common.login.fields.code')"
|
||||
:placeholder="t('common.login.placeholders.code')" autocomplete="one-time-code">
|
||||
<template #button>
|
||||
<van-button class="rounded-full" size="small" @click="handleSendCode">
|
||||
{{ t('common.login.actions.sendCode') }}
|
||||
</van-button>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<div class="mt-4">
|
||||
<van-button class="login-main-btn" type="primary" block :loading="phoneSubmitting"
|
||||
:disabled="!canSubmitPhoneLogin" @click="handlePhoneLogin">
|
||||
{{ t('common.login.actions.login') }}
|
||||
</van-button>
|
||||
</template>
|
||||
</van-field>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="mt-4">
|
||||
<van-button class="login-main-btn" type="primary" block :loading="phoneSubmitting"
|
||||
:disabled="!canSubmitPhoneLogin" @click="handlePhoneLogin">
|
||||
{{ t('common.login.actions.login') }}
|
||||
</van-button>
|
||||
<van-divider>{{ t('common.login.dividersText') }}</van-divider>
|
||||
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
<div ref="googleButtonEl" id="buttonDiv" class="google-login-btn"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-divider>{{ t('common.login.dividersText') }}</van-divider>
|
||||
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
<div ref="googleButtonEl" id="buttonDiv" class="google-login-btn"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 语种切换 -->
|
||||
<div class="flex justify-center items-center gap-4 pb-4">
|
||||
<span v-for="lang in languageOptions" :key="lang.locale"
|
||||
class="text-xs transition-colors duration-200 text-[14px]"
|
||||
:class="currentLocale === lang.locale ? 'text-[#00C853] font-medium' : 'text-[#999]'"
|
||||
@click="switchLanguage(lang.locale)">
|
||||
{{ lang.label }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-popup v-model:show="countryPopupVisible" round position="bottom" class="h-[70vh]">
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="p-3">
|
||||
<div class="h-full flex flex-col px-[12px]">
|
||||
<div>
|
||||
<van-search v-model="countrySearch" :placeholder="t('common.login.placeholders.selectCountry')" shape="round" />
|
||||
</div>
|
||||
<div class="flex-1 overflow-y-auto scrollbar-none [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden">
|
||||
@@ -51,7 +63,7 @@ import { computed, nextTick, onMounted, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { oauthToken } from "@/api/login";
|
||||
import { COUNTRY_CALLING_CODES, findCountryCallingCode } from "@/constants/countryCallingCodes";
|
||||
import { getCurrentLocale } from "@/i18n";
|
||||
import { getCurrentLocale, setLocale } from "@/i18n";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
const router = useRouter();
|
||||
@@ -63,6 +75,14 @@ const googleButtonRendered = ref(false);
|
||||
const countryPopupVisible = ref(false);
|
||||
const countrySearch = ref("");
|
||||
|
||||
const languageOptions = [
|
||||
{ locale: "zh-CN", label: "中文" },
|
||||
{ locale: "en-US", label: "English" },
|
||||
{ locale: "th-TH", label: "ภาษาไทย" },
|
||||
];
|
||||
const currentLocale = computed(() => getCurrentLocale());
|
||||
const switchLanguage = (locale: string) => setLocale(locale);
|
||||
|
||||
const selectedCountry = ref(
|
||||
findCountryCallingCode(
|
||||
(() => {
|
||||
@@ -272,6 +292,16 @@ onMounted(() => {
|
||||
border-radius: 50px !important;
|
||||
}
|
||||
|
||||
:deep(.van-cell) {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
|
||||
&::after {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.login-main-btn {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user