Split desktop and mobile layouts with shared page data so APIs fetch once per context.
Add layout shells, desktop views, module-level page caches, and UI fixes for auth, home, wallet, transactions, address, and related pages. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import DesktopAuthShell from './components/DesktopAuthShell.vue'
|
||||
import Login from '../components/Login.vue'
|
||||
import Register from '../components/Register.vue'
|
||||
import { useLoginPageContext } from '../composables/useLoginPage'
|
||||
|
||||
const page = useLoginPageContext()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DesktopAuthShell>
|
||||
<div class="dauth-card">
|
||||
<header v-if="!page.enterType" class="dauth-card__header">
|
||||
<p class="dauth-card__eyebrow">حساب کاربری</p>
|
||||
<h2 class="dauth-card__title">ورود</h2>
|
||||
<p class="dauth-card__subtitle">برای ادامه، روش ورود خود را انتخاب کنید</p>
|
||||
</header>
|
||||
<header v-else class="dauth-card__header">
|
||||
<p class="dauth-card__eyebrow">حساب جدید</p>
|
||||
<h2 class="dauth-card__title">ثبت نام</h2>
|
||||
<p class="dauth-card__subtitle">اطلاعات خود را برای ایجاد حساب وارد کنید</p>
|
||||
</header>
|
||||
|
||||
<Login
|
||||
v-if="!page.enterType"
|
||||
variant="desktop"
|
||||
@register="page.setEnterType"
|
||||
/>
|
||||
<Register
|
||||
v-else
|
||||
variant="desktop"
|
||||
@register="page.setEnterType"
|
||||
/>
|
||||
</div>
|
||||
</DesktopAuthShell>
|
||||
</template>
|
||||
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div class="dauth" :class="{ 'dauth--boursecu': isBoursecu }">
|
||||
<div class="dauth__layout">
|
||||
<aside class="dauth-brand" :class="{ 'dauth-brand--boursecu': isBoursecu }">
|
||||
<div class="dauth-brand__pattern" />
|
||||
<div class="dauth-brand__content">
|
||||
<img
|
||||
:src="logo"
|
||||
alt=""
|
||||
class="dauth-brand__logo"
|
||||
:class="{ 'dauth-brand__logo--round': !hasCustomLayout }"
|
||||
>
|
||||
<h1 class="dauth-brand__title">{{ brandTitle }}</h1>
|
||||
<p v-if="tagline" class="dauth-brand__tagline">{{ tagline }}</p>
|
||||
<ul class="dauth-brand__features">
|
||||
<li v-for="feature in features" :key="feature" class="dauth-brand__feature">
|
||||
<span class="dauth-brand__feature-icon">
|
||||
<BasicIcon icon="vuesax-linear:tick-circle" size="16" />
|
||||
</span>
|
||||
{{ feature }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="dauth-brand__footer">نسخه {{ version }}</div>
|
||||
</aside>
|
||||
|
||||
<main class="dauth-form-panel">
|
||||
<slot />
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue'
|
||||
import pkg from '../../../../../package.json'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import {
|
||||
getProjectLoginLogo,
|
||||
getProjectLoginTaglineLines,
|
||||
hasCustomLoginLogoLayout,
|
||||
isBoursecuProject,
|
||||
} from '@/utils/config'
|
||||
|
||||
const config = useConfigStore()
|
||||
const isBoursecu = isBoursecuProject()
|
||||
const hasCustomLayout = hasCustomLoginLogoLayout()
|
||||
const version = pkg.version
|
||||
|
||||
const logo = computed(() => getProjectLoginLogo(config.config?.avatar))
|
||||
|
||||
const taglineLines = computed(() => getProjectLoginTaglineLines())
|
||||
const tagline = computed(() => {
|
||||
if (taglineLines.value?.length) {
|
||||
return taglineLines.value.join(' ')
|
||||
}
|
||||
return 'پلتفرم امن و سریع برای مدیریت دارایی و معاملات شما'
|
||||
})
|
||||
|
||||
const brandTitle = computed(() => config.config?.name_fa ?? 'خوش آمدید')
|
||||
|
||||
const features = computed(() => {
|
||||
if (isBoursecu) {
|
||||
return [
|
||||
'قیمت لحظهای و نمودار بازار',
|
||||
'مدیریت دارایی و کیف پول',
|
||||
'معاملات سریع و امن',
|
||||
]
|
||||
}
|
||||
return [
|
||||
'ورود امن با پیامک یا رمز عبور',
|
||||
'مدیریت یکپارچه داراییها',
|
||||
'دسترسی سریع به خدمات',
|
||||
]
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" src="../styles/desktop-auth.less"></style>
|
||||
@@ -0,0 +1,204 @@
|
||||
<script setup lang="ts">
|
||||
import { mobileValidation, required } from '@/utils/inputRules'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import BasicIcon from '@/components/BasicPacks/BasicIcon.vue'
|
||||
import OtpInput from 'vue3-otp-input'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { useLoginPageContext } from '../../composables/useLoginPage'
|
||||
import DesktopPwaGuideModal from './DesktopPwaGuideModal.vue'
|
||||
import router from '@/router'
|
||||
|
||||
const emit = defineEmits<{
|
||||
register: [val: boolean]
|
||||
}>()
|
||||
|
||||
const config = useConfigStore()
|
||||
const {
|
||||
time,
|
||||
enableSendAgainCode,
|
||||
stepTwoVerify,
|
||||
formRef,
|
||||
refOtpInput,
|
||||
isSMS,
|
||||
isRegister,
|
||||
showPWAInstallGuide,
|
||||
userFormState,
|
||||
loading,
|
||||
submitLabel,
|
||||
showFingerprint,
|
||||
setIsSMS,
|
||||
reSendCode,
|
||||
enterFingerPrint,
|
||||
handleOnChange,
|
||||
handleOnComplete,
|
||||
phoneVerification,
|
||||
editPhoneNumber,
|
||||
installWebApp,
|
||||
proceedWithInstall,
|
||||
} = useLoginPageContext().loginForm
|
||||
|
||||
function goToEducate() {
|
||||
router.push({ name: 'educate' })
|
||||
}
|
||||
|
||||
function goToAboutUs() {
|
||||
router.push('/aboutUs')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dauth-card">
|
||||
<header class="dauth-card__header">
|
||||
<p class="dauth-card__eyebrow">حساب کاربری</p>
|
||||
<h2 class="dauth-card__title">ورود</h2>
|
||||
<p class="dauth-card__subtitle">برای ادامه، روش ورود خود را انتخاب کنید</p>
|
||||
</header>
|
||||
|
||||
<div class="dauth-toggle">
|
||||
<button
|
||||
type="button"
|
||||
class="dauth-toggle__btn"
|
||||
:class="{ 'dauth-toggle__btn--active': isSMS }"
|
||||
@click="setIsSMS(true)"
|
||||
>
|
||||
ورود با پیامک
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="dauth-toggle__btn"
|
||||
:class="{ 'dauth-toggle__btn--active': !isSMS }"
|
||||
@click="setIsSMS(false)"
|
||||
>
|
||||
ورود با کلمه عبور
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="userFormState"
|
||||
layout="vertical"
|
||||
class="dauth-form"
|
||||
name="desktop-login"
|
||||
@finish="phoneVerification"
|
||||
>
|
||||
<a-form-item
|
||||
v-if="!stepTwoVerify"
|
||||
:rules="[required('شماره تلفن'), mobileValidation('شماره تلفن')]"
|
||||
:validate-trigger="['change', 'blur']"
|
||||
label="شماره تلفن"
|
||||
name="mobile"
|
||||
>
|
||||
<BasicInput
|
||||
v-model:value="userFormState.mobile"
|
||||
place-holder="۰۹۱۲۳۴۵۶۷۸۹"
|
||||
size="large"
|
||||
inputmode="numeric"
|
||||
type="tel"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
v-if="!isSMS"
|
||||
:rules="[required('کلمه عبور')]"
|
||||
label="کلمه عبور"
|
||||
name="password"
|
||||
>
|
||||
<AInputPassword
|
||||
v-model:value="userFormState.password"
|
||||
place-holder="کلمه عبور"
|
||||
size="large"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<template v-if="isSMS && stepTwoVerify">
|
||||
<AFormItem
|
||||
:rules="[
|
||||
{ required: true, message: 'کد ارسال شده را وارد نمایید' },
|
||||
{ min: 4, max: 4, message: 'کد ارسال شده را وارد نمایید' },
|
||||
]"
|
||||
class="error-token"
|
||||
name="token"
|
||||
>
|
||||
<OtpInput
|
||||
ref="refOtpInput"
|
||||
:is-input-num="true"
|
||||
:num-inputs="4"
|
||||
:should-auto-focus="true"
|
||||
autocomplete="one-time-code"
|
||||
class="dauth-otp justify-center"
|
||||
input-classes="otp-input"
|
||||
separator=""
|
||||
style="direction: ltr"
|
||||
value=""
|
||||
@on-change="handleOnChange"
|
||||
@on-complete="handleOnComplete"
|
||||
/>
|
||||
</AFormItem>
|
||||
|
||||
<div class="dauth-phone-edit">
|
||||
<span class="dauth-phone-edit__number">{{ userFormState.mobile }}</span>
|
||||
<button type="button" class="dauth-phone-edit__btn" @click="editPhoneNumber">
|
||||
<span>ویرایش شماره</span>
|
||||
<BasicIcon icon="vuesax-linear:edit" size="16" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dauth-resend">
|
||||
<AButton :disabled="!enableSendAgainCode" class="w-full" type="dashed" @click="reSendCode">
|
||||
<span v-if="!enableSendAgainCode">
|
||||
ارسال مجدد کد در <span class="text-primary mx-1">{{ time }}</span> دیگر
|
||||
</span>
|
||||
<span v-else>ارسال مجدد کد تایید</span>
|
||||
</AButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="dauth-actions">
|
||||
<BasicButton :disabled="loading" class="w-full" html-type="submit" type="primary">
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<span v-else>{{ submitLabel }}</span>
|
||||
</BasicButton>
|
||||
|
||||
<BasicButton
|
||||
v-if="showFingerprint"
|
||||
:disabled="loading"
|
||||
class="w-full"
|
||||
@click="enterFingerPrint"
|
||||
>
|
||||
ورود با اثر انگشت
|
||||
</BasicButton>
|
||||
|
||||
<template v-if="config.config?.name === 'garoosi'">
|
||||
<div class="dauth-actions-row">
|
||||
<a
|
||||
class="dauth-link-btn dauth-link-btn--primary"
|
||||
download="Garoosi.apk"
|
||||
href="https://garoosigholaktala.ir/apk/Garoosi.apk"
|
||||
>
|
||||
دانلود اپ اندروید
|
||||
</a>
|
||||
<button type="button" class="dauth-link-btn" @click="installWebApp">
|
||||
نصب نسخه وب اپ
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="dauth-link-btn" @click="goToEducate">
|
||||
آموزش کار با نرم افزار
|
||||
</button>
|
||||
<button type="button" class="dauth-link-btn" @click="goToAboutUs">
|
||||
درباره ما
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="isRegister" class="dauth-switch">
|
||||
<span>حساب کاربری ندارید؟</span>
|
||||
<button type="button" class="dauth-switch__link" @click="emit('register', true)">
|
||||
ثبت نام کنید
|
||||
</button>
|
||||
</div>
|
||||
</a-form>
|
||||
|
||||
<DesktopPwaGuideModal v-model:show="showPWAInstallGuide" @confirm="proceedWithInstall" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import BasicModal from '@/components/BasicPacks/BasicModal.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import shareAppleIcon from '@/assets/img/share-apple.png'
|
||||
import addToHomeScreenIcon from '@/assets/img/Add-to-homeScreen.png'
|
||||
|
||||
defineProps<{
|
||||
show: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:show': [value: boolean]
|
||||
confirm: []
|
||||
}>()
|
||||
|
||||
function close() {
|
||||
emit('update:show', false)
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
emit('confirm')
|
||||
close()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasicModal
|
||||
:visible="show"
|
||||
:custom-footer="true"
|
||||
destroy-on-close
|
||||
@update:visible="emit('update:show', $event)"
|
||||
>
|
||||
<h2 class="text-base font-semibold text-center mb-2 text-gray-800">
|
||||
وب اپلیکیشن گروسی را به صفحه اصلی خود اضافه کنید
|
||||
</h2>
|
||||
|
||||
<div class="dauth-pwa-steps">
|
||||
<div class="dauth-pwa-step">
|
||||
<div class="dauth-pwa-step__icon">
|
||||
<img :src="shareAppleIcon" alt="Share" />
|
||||
</div>
|
||||
<p class="dauth-pwa-step__text">روی دکمه Share در نوار پایین کلیک کنید.</p>
|
||||
</div>
|
||||
|
||||
<div class="dauth-pwa-step">
|
||||
<div class="dauth-pwa-step__icon">
|
||||
<img :src="addToHomeScreenIcon" alt="Add to Home Screen" />
|
||||
</div>
|
||||
<p class="dauth-pwa-step__text">
|
||||
در منوی باز شده در قسمت پایین گزینه Add to Home Screen را انتخاب کنید.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="dauth-pwa-step">
|
||||
<div class="dauth-pwa-step__icon">
|
||||
<span class="text-blue-600 font-bold text-lg">Add</span>
|
||||
</div>
|
||||
<p class="dauth-pwa-step__text">در مرحله آخر در قسمت بالا روی Add کلیک کنید.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BasicButton class="w-full mt-4" type="primary" @click="confirm">
|
||||
متوجه شدم
|
||||
</BasicButton>
|
||||
</BasicModal>
|
||||
</template>
|
||||
@@ -0,0 +1,144 @@
|
||||
<script setup lang="ts">
|
||||
import { mobileValidation, required } from '@/utils/inputRules'
|
||||
import BasicInput from '@/components/BasicPacks/BasicInput.vue'
|
||||
import BasicButton from '@/components/BasicPacks/BasicButton.vue'
|
||||
import DialogVantOneButton from '@/components/DialogVantOneButton.vue'
|
||||
import registerDelayImage from '@/assets/img/registerDelay.svg'
|
||||
import { useConfigStore } from '@/store/configStore'
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
import { useLoginPageContext } from '../../composables/useLoginPage'
|
||||
import router from '@/router'
|
||||
|
||||
const emit = defineEmits<{
|
||||
register: [val: boolean]
|
||||
}>()
|
||||
|
||||
const config = useConfigStore()
|
||||
const {
|
||||
registeredInfo,
|
||||
disableForm,
|
||||
userFormState,
|
||||
formRef,
|
||||
loading,
|
||||
registerAccount,
|
||||
dismissSuccess,
|
||||
} = useLoginPageContext().registerForm
|
||||
|
||||
function goToEducate() {
|
||||
router.push({ name: 'educate' })
|
||||
}
|
||||
|
||||
function goToAboutUs() {
|
||||
router.push('/aboutUs')
|
||||
}
|
||||
|
||||
function handleSuccessDismiss() {
|
||||
dismissSuccess()
|
||||
emit('register', false)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="dauth-card">
|
||||
<header class="dauth-card__header">
|
||||
<p class="dauth-card__eyebrow">حساب جدید</p>
|
||||
<h2 class="dauth-card__title">ثبت نام</h2>
|
||||
<p class="dauth-card__subtitle">اطلاعات خود را برای ایجاد حساب وارد کنید</p>
|
||||
</header>
|
||||
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="userFormState"
|
||||
layout="vertical"
|
||||
class="dauth-form"
|
||||
name="desktop-register"
|
||||
@finish="registerAccount"
|
||||
>
|
||||
<a-form-item :rules="[required()]" label="نام" name="fname">
|
||||
<BasicInput v-model:value="userFormState.fname" place-holder="نام" size="large" />
|
||||
</a-form-item>
|
||||
<a-form-item :rules="[required()]" label="نام خانوادگی" name="lname">
|
||||
<BasicInput
|
||||
v-model:value="userFormState.lname"
|
||||
place-holder="نام خانوادگی"
|
||||
size="large"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
:rules="[required(), mobileValidation('شماره تلفن')]"
|
||||
label="شماره تلفن"
|
||||
name="mobile"
|
||||
>
|
||||
<BasicInput
|
||||
v-model:value="userFormState.mobile"
|
||||
place-holder="۰۹۱۲۳۴۵۶۷۸۹"
|
||||
size="large"
|
||||
inputmode="numeric"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item :rules="[required()]" label="کلمه عبور" name="password">
|
||||
<AInputPassword
|
||||
v-model:value="userFormState.password"
|
||||
place-holder="کلمه عبور"
|
||||
size="large"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
:rules="isBoursecuProject() ? [] : [required()]"
|
||||
label="کد معرف"
|
||||
name="referral_id"
|
||||
>
|
||||
<BasicInput
|
||||
v-model:value="userFormState.referral_id"
|
||||
:disabled="disableForm"
|
||||
place-holder="کد معرف (اختیاری)"
|
||||
size="large"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<div class="dauth-actions">
|
||||
<BasicButton :disabled="loading" class="w-full" html-type="submit" type="primary">
|
||||
<a-spin v-if="loading" size="small" />
|
||||
<span v-else>ثبت نام</span>
|
||||
</BasicButton>
|
||||
|
||||
<template v-if="config.config?.name === 'garoosi'">
|
||||
<button type="button" class="dauth-link-btn" @click="goToEducate">
|
||||
آموزش کار با نرم افزار
|
||||
</button>
|
||||
<button type="button" class="dauth-link-btn" @click="goToAboutUs">
|
||||
درباره ما
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="dauth-switch">
|
||||
<span>حساب کاربری دارید؟</span>
|
||||
<button type="button" class="dauth-switch__link" @click="emit('register', false)">
|
||||
وارد شوید
|
||||
</button>
|
||||
</div>
|
||||
</a-form>
|
||||
|
||||
<DialogVantOneButton
|
||||
v-model:show="registeredInfo"
|
||||
:closeOnClickOverlay="false"
|
||||
:timeOut="-1"
|
||||
>
|
||||
<template #img>
|
||||
<img :src="registerDelayImage" alt="" class="opacity-80" />
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="p-5 text-center text-sm">
|
||||
ثبت نام شما با موفقیت انجام شد. شما میتوانید با اطلاعات خود، وارد اپلیکیشن شوید.
|
||||
</div>
|
||||
</template>
|
||||
<template #button>
|
||||
<div class="text-center" @click="handleSuccessDismiss">متوجه شدم</div>
|
||||
</template>
|
||||
</DialogVantOneButton>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,490 @@
|
||||
/* Premium desktop auth — split-panel SaaS login */
|
||||
|
||||
.dauth {
|
||||
min-height: 100vh;
|
||||
background: #f6f7f9;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
.dauth__layout {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(380px, 1fr) minmax(420px, 520px);
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Brand panel — uses config primary color (same as buttons) */
|
||||
.dauth-brand {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 56px 64px;
|
||||
background: @App-primary-color;
|
||||
overflow: hidden;
|
||||
|
||||
&--boursecu {
|
||||
.dauth-brand__logo {
|
||||
max-width: 300px;
|
||||
max-height: 110px;
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
&__pattern {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
opacity: 0.04;
|
||||
background-image: radial-gradient(circle at 1px 1px, #fff 1px, transparent 0);
|
||||
background-size: 28px 28px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&__content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
width: auto;
|
||||
max-width: 220px;
|
||||
height: auto;
|
||||
max-height: 72px;
|
||||
object-fit: contain;
|
||||
margin-bottom: 32px;
|
||||
|
||||
&--round {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
border-radius: 16px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.03em;
|
||||
color: #ffffff;
|
||||
line-height: 1.25;
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
|
||||
&__tagline {
|
||||
font-size: 15px;
|
||||
font-weight: 400;
|
||||
color: rgba(255, 255, 255, 0.72);
|
||||
line-height: 1.7;
|
||||
margin: 0 0 40px;
|
||||
}
|
||||
|
||||
&__features {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__feature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
&__feature-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: #ffffff;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
position: absolute;
|
||||
bottom: 32px;
|
||||
right: 64px;
|
||||
left: 64px;
|
||||
font-size: 11px;
|
||||
color: rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
/* Form panel */
|
||||
.dauth-form-panel {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 48px 56px;
|
||||
}
|
||||
|
||||
.dauth-card {
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
padding: 36px 40px;
|
||||
box-shadow:
|
||||
0 1px 2px rgba(15, 23, 42, 0.04),
|
||||
0 8px 24px rgba(15, 23, 42, 0.06);
|
||||
|
||||
&__header {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
&__eyebrow {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #9ca3af;
|
||||
margin: 0 0 6px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.02em;
|
||||
color: #111827;
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
margin: 8px 0 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* Method toggle */
|
||||
.dauth-toggle {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4px;
|
||||
padding: 4px;
|
||||
background: #f3f4f6;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
&__btn {
|
||||
padding: 9px 12px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
color: #6b7280;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
|
||||
|
||||
&--active {
|
||||
background: #ffffff;
|
||||
color: #111827;
|
||||
box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
|
||||
}
|
||||
|
||||
&:hover:not(&--active) {
|
||||
color: #374151;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Form fields */
|
||||
.dauth-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
&.ant-form-vertical :deep(.ant-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
&.ant-form-vertical :deep(.ant-form-item-label) {
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
&.ant-form-vertical :deep(.ant-form-item-label > label) {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label > label) {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
}
|
||||
|
||||
:deep(.ant-input),
|
||||
:deep(.ant-input-affix-wrapper) {
|
||||
border-radius: 10px;
|
||||
border-color: #e5e7eb;
|
||||
padding: 10px 14px;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&-focused {
|
||||
border-color: @App-primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-input-lg) {
|
||||
padding: 11px 14px;
|
||||
}
|
||||
|
||||
.dauth-toggle {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.dauth-actions,
|
||||
.dauth-switch {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* OTP */
|
||||
.dauth-otp {
|
||||
margin-top: 8px;
|
||||
|
||||
:deep(.otp-input) {
|
||||
width: 52px !important;
|
||||
height: 52px !important;
|
||||
border-radius: 10px !important;
|
||||
border: 1px solid #e5e7eb !important;
|
||||
font-size: 20px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.dauth-phone-edit {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin: 16px 0 20px;
|
||||
font-size: 13px;
|
||||
|
||||
&__number {
|
||||
color: #9ca3af;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
&__btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #374151;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
transition: background 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: #f3f4f6;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dauth-resend {
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.ant-btn) {
|
||||
border-radius: 10px;
|
||||
height: 42px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
.dauth-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
margin-top: 8px;
|
||||
width: 100%;
|
||||
|
||||
&__submit {
|
||||
min-height: 44px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:deep(.ant-btn),
|
||||
:deep(button),
|
||||
:deep(.noname-base-button) {
|
||||
border-radius: 10px;
|
||||
min-height: 44px;
|
||||
height: auto;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.dauth-actions-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.dauth-switch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4px;
|
||||
margin-top: 20px;
|
||||
padding-top: 4px;
|
||||
font-size: 13px;
|
||||
color: #6b7280;
|
||||
flex-shrink: 0;
|
||||
|
||||
&__link {
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: @App-primary-color;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Garoosi extras */
|
||||
.dauth-garoosi-links {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.dauth-link-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
padding: 10px 16px;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
background: #ffffff;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: background 0.15s ease, border-color 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background: #f9fafb;
|
||||
border-color: #d1d5db;
|
||||
color: #111827;
|
||||
}
|
||||
|
||||
&--primary {
|
||||
background: @App-primary-color;
|
||||
border-color: @App-primary-color;
|
||||
color: #ffffff;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.92;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* PWA guide modal */
|
||||
.dauth-pwa-steps {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
margin: 20px 0 8px;
|
||||
}
|
||||
|
||||
.dauth-pwa-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
|
||||
&__icon {
|
||||
flex-shrink: 0;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 10px;
|
||||
background: #f0f4ff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
font-size: 13px;
|
||||
color: #374151;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.dauth__layout {
|
||||
grid-template-columns: minmax(300px, 1fr) minmax(340px, 1fr);
|
||||
}
|
||||
|
||||
.dauth-brand {
|
||||
padding: 40px 36px;
|
||||
|
||||
&__footer {
|
||||
right: 36px;
|
||||
left: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.dauth-form-panel {
|
||||
padding: 32px 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.login-form--desktop {
|
||||
:deep(.ant-form-item) {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
:deep(.ant-form-item-label > label) {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user