Edit login and registration details

This commit is contained in:
2026-09-19 13:57:15 +03:30
parent a428c6f135
commit 9c7dad3677
8 changed files with 319 additions and 272 deletions
+96 -45
View File
@@ -9,6 +9,7 @@ import type { LoginChallengeResponse, LoginOrganizationChoiceResponse } from '@m
import { USER_ROLE_LABELS } from '@/lib/roles';
import { brand } from '@mento/shared';
import BrandName from '@/components/brand/BrandName.vue';
import UiIcon from '@/components/UiIcon.vue';
const auth = useAuthStore();
const router = useRouter();
@@ -18,8 +19,8 @@ const route = useRoute();
const mode = ref<'password' | 'otp'>('password');
const otpStep = ref<'mobile' | 'code'>('mobile');
const identifier = ref('owner@demo.local');
const password = ref('demo1234');
const identifier = ref('');
const password = ref('');
const mobile = ref('');
const showPassword = ref(false);
const remember = ref(true);
@@ -209,15 +210,17 @@ function cancelOrgChoice() {
required
autocomplete="username"
placeholder="ایمیل یا شماره موبایل خود را وارد کنید"
dir="ltr"
class="ltr-value"
/>
<span class="ico user" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="user" :size="18" />
</span>
</div>
</div>
<div class="field">
<label for="password">رمز عبور</label>
<div class="input-wrap">
<div class="input-wrap has-eye">
<input
id="password"
v-model="password"
@@ -225,16 +228,18 @@ function cancelOrgChoice() {
required
autocomplete="current-password"
placeholder="رمز عبور خود را وارد کنید"
dir="ltr"
class="ltr-value"
/>
<span class="ico lock" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="lock" :size="18" />
</span>
<button
type="button"
class="eye"
:aria-label="showPassword ? 'مخفی کردن رمز' : 'نمایش رمز'"
@click="showPassword = !showPassword"
>
{{ showPassword ? 'مخفی' : 'نمایش' }}
<UiIcon :name="showPassword ? 'eye-off' : 'eye'" :size="18" />
</button>
</div>
</div>
@@ -266,9 +271,11 @@ function cancelOrgChoice() {
required
autocomplete="tel"
placeholder="۰۹۱۲۱۲۳۴۵۶۷"
dir="ltr"
class="ltr-value"
/>
<span class="ico user" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="phone" :size="18" />
</span>
</div>
</div>
<p v-if="error" class="error">{{ error }}</p>
@@ -297,7 +304,7 @@ function cancelOrgChoice() {
required
autocomplete="one-time-code"
placeholder="کد را وارد کنید"
dir="ltr"
class="ltr-value"
/>
</div>
</div>
@@ -339,21 +346,22 @@ function cancelOrgChoice() {
padding: 1rem;
padding-bottom: max(1rem, env(safe-area-inset-bottom));
background:
radial-gradient(circle at 90% 0%, rgba(13, 148, 136, 0.08), transparent 36%),
var(--bg);
radial-gradient(ellipse 70% 45% at 50% 0%, rgba(45, 212, 191, 0.12), transparent 55%),
radial-gradient(rgba(13, 148, 136, 0.12) 1px, transparent 1.2px),
#f5fbfb;
background-size: auto, 20px 20px, auto;
}
.auth-shell {
flex: 1;
width: min(1040px, 100%);
width: min(1100px, 100%);
margin: 0 auto;
display: grid;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
background: transparent;
border: 0;
box-shadow: none;
overflow: hidden;
min-height: min(640px, calc(100dvh - 5.5rem));
min-height: min(680px, calc(100dvh - 5.5rem));
}
.form-panel {
@@ -361,6 +369,9 @@ function cancelOrgChoice() {
flex-direction: column;
padding: clamp(1.2rem, 3vw, 2.4rem);
min-width: 0;
background: #fff;
border-radius: 28px;
box-shadow: 0 18px 48px rgba(15, 23, 42, 0.06);
}
.mobile-brand {
@@ -434,6 +445,22 @@ h1 {
gap: 0.95rem;
}
.form input {
direction: rtl;
text-align: right;
}
.form input::placeholder {
direction: rtl;
text-align: right;
color: #cdd4de;
}
.form input.ltr-value:not(:placeholder-shown) {
direction: ltr;
text-align: left;
}
.input-wrap {
position: relative;
}
@@ -446,48 +473,42 @@ h1 {
background: #fff;
}
.input-wrap.has-eye input {
padding-left: 2.7rem;
}
.input-wrap input:focus {
outline: 2px solid var(--accent-soft);
border-color: var(--accent);
}
.ico {
.field-ico {
position: absolute;
top: 50%;
inset-inline-end: 0.85rem;
right: 0.75rem;
left: auto;
transform: translateY(-50%);
width: 18px;
height: 18px;
opacity: 0.45;
color: #94a3b8;
display: grid;
place-items: center;
pointer-events: none;
}
.ico.user {
background:
radial-gradient(circle at 50% 35%, currentColor 0 28%, transparent 29%),
radial-gradient(circle at 50% 85%, currentColor 0 38%, transparent 39%);
color: #64748b;
border-radius: 999px;
}
.ico.lock {
background:
linear-gradient(currentColor, currentColor) center 62%/10px 8px no-repeat,
radial-gradient(circle at 50% 38%, transparent 34%, currentColor 35% 55%, transparent 56%);
color: #64748b;
}
.eye {
position: absolute;
top: 50%;
inset-inline-start: 0.55rem;
left: 0.45rem;
right: auto;
transform: translateY(-50%);
border: 0;
background: transparent;
color: var(--muted);
font-size: 0.75rem;
color: #64748b;
cursor: pointer;
padding: 0.25rem 0.4rem;
padding: 0;
width: 36px;
height: 36px;
display: grid;
place-items: center;
}
.row-actions {
@@ -612,8 +633,34 @@ h1 {
}
@media (min-width: 900px) {
.auth-page {
padding: 0;
background: #fff;
}
.auth-shell {
grid-template-columns: minmax(280px, 0.9fr) minmax(340px, 1.1fr);
width: 100%;
min-height: 100dvh;
grid-template-columns: minmax(420px, 1fr) minmax(440px, 1.05fr);
grid-template-areas: "form brand";
background: #fff;
border-radius: 0;
box-shadow: none;
}
.form-panel {
grid-area: form;
border-radius: 0;
box-shadow: none;
background: #fff;
justify-content: center;
}
.auth-shell :deep(.brand-panel) {
grid-area: brand;
height: 100dvh;
position: sticky;
top: 0;
}
.mobile-brand {
@@ -621,8 +668,12 @@ h1 {
}
.form-inner {
margin: 0;
margin: 0 auto;
width: min(440px, 100%);
}
.auth-footer {
display: none;
}
}
</style>
+121 -60
View File
@@ -8,6 +8,7 @@ import MentoLogo from '@/components/brand/MentoLogo.vue';
import axios from 'axios';
import { brand, type RegisterChallengeResponse } from '@mento/shared';
import BrandName from '@/components/brand/BrandName.vue';
import UiIcon from '@/components/UiIcon.vue';
const auth = useAuthStore();
const router = useRouter();
@@ -105,10 +106,7 @@ function backToForm() {
<template>
<div class="auth-page">
<div class="auth-shell">
<AuthBrandPanel
headline="همه ارتباطات، یکجا مدیریت می‌شوند"
:description="`با ساخت حساب ${brand.nameFa}، سازمان خود را راه‌اندازی کنید و فروش و پشتیبانی را از یکجا پیش ببرید.`"
/>
<AuthBrandPanel />
<section class="form-panel">
<header class="mobile-brand">
@@ -134,6 +132,9 @@ function backToForm() {
<label for="org">نام سازمان <em>*</em></label>
<div class="input-wrap">
<input id="org" v-model="organizationName" required placeholder="نام سازمان" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="building" :size="18" />
</span>
</div>
</div>
<div class="field">
@@ -157,7 +158,9 @@ function backToForm() {
required
placeholder="نام و نام خانوادگی خود را وارد کنید"
/>
<span class="ico user" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="user" :size="18" />
</span>
</div>
</div>
<div class="field">
@@ -169,9 +172,11 @@ function backToForm() {
type="email"
required
placeholder="ایمیل خود را وارد کنید"
dir="ltr"
class="ltr-value"
/>
<span class="ico mail" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="mail" :size="18" />
</span>
</div>
</div>
</div>
@@ -187,14 +192,16 @@ function backToForm() {
type="tel"
required
placeholder="۹۱۲۱۲۳۴۵۶۷"
dir="ltr"
class="ltr-value"
/>
<span class="ico phone" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="phone" :size="18" />
</span>
</div>
</div>
<div class="field">
<label for="password">رمز عبور <em>*</em></label>
<div class="input-wrap">
<div class="input-wrap has-eye">
<input
id="password"
v-model="password"
@@ -202,15 +209,18 @@ function backToForm() {
minlength="6"
required
placeholder="رمز عبور خود را وارد کنید"
dir="ltr"
class="ltr-value"
/>
<span class="ico lock" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="lock" :size="18" />
</span>
<button
type="button"
class="eye"
:aria-label="showPassword ? 'مخفی کردن رمز' : 'نمایش رمز'"
@click="showPassword = !showPassword"
>
{{ showPassword ? 'مخفی' : 'نمایش' }}
<UiIcon :name="showPassword ? 'eye-off' : 'eye'" :size="18" />
</button>
</div>
</div>
@@ -219,7 +229,7 @@ function backToForm() {
<div class="grid-2">
<div class="field">
<label for="passwordConfirm">تکرار رمز عبور <em>*</em></label>
<div class="input-wrap">
<div class="input-wrap has-eye">
<input
id="passwordConfirm"
v-model="passwordConfirm"
@@ -227,15 +237,18 @@ function backToForm() {
minlength="6"
required
placeholder="رمز عبور خود را تکرار کنید"
dir="ltr"
class="ltr-value"
/>
<span class="ico lock" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="lock" :size="18" />
</span>
<button
type="button"
class="eye"
:aria-label="showPasswordConfirm ? 'مخفی کردن رمز' : 'نمایش رمز'"
@click="showPasswordConfirm = !showPasswordConfirm"
>
{{ showPasswordConfirm ? 'مخفی' : 'نمایش' }}
<UiIcon :name="showPasswordConfirm ? 'eye-off' : 'eye'" :size="18" />
</button>
</div>
</div>
@@ -247,7 +260,9 @@ function backToForm() {
v-model="referralCode"
placeholder="اگر کد معرف دارید وارد کنید"
/>
<span class="ico gift" aria-hidden="true" />
<span class="field-ico" aria-hidden="true">
<UiIcon name="gift" :size="18" />
</span>
</div>
</div>
</div>
@@ -297,7 +312,7 @@ function backToForm() {
type="text"
inputmode="numeric"
required
dir="ltr"
class="ltr-value"
placeholder="کد ایمیل"
/>
</div>
@@ -309,7 +324,7 @@ function backToForm() {
type="text"
inputmode="numeric"
required
dir="ltr"
class="ltr-value"
placeholder="کد موبایل"
/>
</div>
@@ -349,8 +364,10 @@ function backToForm() {
padding: 1rem;
padding-bottom: max(1rem, env(safe-area-inset-bottom));
background:
radial-gradient(circle at 8% 0%, rgba(13, 148, 136, 0.07), transparent 34%),
var(--bg);
radial-gradient(ellipse 70% 45% at 50% 0%, rgba(45, 212, 191, 0.12), transparent 55%),
radial-gradient(rgba(13, 148, 136, 0.12) 1px, transparent 1.2px),
#f5fbfb;
background-size: auto, 20px 20px, auto;
}
.auth-shell {
@@ -358,16 +375,18 @@ function backToForm() {
width: min(1100px, 100%);
margin: 0 auto;
display: grid;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
background: transparent;
border: 0;
box-shadow: none;
overflow: hidden;
}
.form-panel {
padding: clamp(1rem, 2.5vw, 2rem);
min-width: 0;
background: #fff;
border-radius: 28px;
box-shadow: 0 18px 48px rgba(15, 23, 42, 0.06);
}
.mobile-brand {
@@ -466,6 +485,23 @@ h1 {
padding: 0.8rem 0.95rem;
width: 100%;
background: #fff;
direction: rtl;
text-align: right;
}
.field select {
color: var(--ink);
}
.form input::placeholder {
direction: rtl;
text-align: right;
color: #cdd4de;
}
.form input.ltr-value:not(:placeholder-shown) {
direction: ltr;
text-align: left;
}
.input-wrap {
@@ -473,16 +509,21 @@ h1 {
}
.input-wrap input {
padding-inline-end: 2.5rem;
padding-right: 2.6rem;
}
.input-wrap.has-eye input {
padding-left: 2.7rem;
}
.mobile-wrap input {
padding-inline-start: 3.4rem;
padding-left: 3.4rem;
}
.cc {
position: absolute;
inset-inline-start: 0.7rem;
left: 0.7rem;
right: auto;
top: 50%;
transform: translateY(-50%);
color: var(--muted);
@@ -490,49 +531,33 @@ h1 {
pointer-events: none;
}
.ico {
.field-ico {
position: absolute;
top: 50%;
inset-inline-end: 0.8rem;
right: 0.7rem;
left: auto;
transform: translateY(-50%);
width: 16px;
height: 16px;
opacity: 0.45;
color: #94a3b8;
display: grid;
place-items: center;
pointer-events: none;
background: #64748b;
border-radius: var(--radius);
}
.ico.user {
border-radius: 999px;
background:
radial-gradient(circle at 50% 35%, #64748b 0 28%, transparent 29%),
radial-gradient(circle at 50% 85%, #64748b 0 38%, transparent 39%);
}
.ico.mail {
background: linear-gradient(#64748b, #64748b);
mask: linear-gradient(#000 0 0);
opacity: 0.4;
border-radius: var(--radius);
}
.ico.lock,
.ico.phone,
.ico.gift {
opacity: 0.35;
}
.eye {
position: absolute;
top: 50%;
inset-inline-start: 0.45rem;
left: 0.35rem;
right: auto;
transform: translateY(-50%);
border: 0;
background: transparent;
color: var(--muted);
font-size: 0.72rem;
color: #64748b;
cursor: pointer;
padding: 0;
width: 36px;
height: 36px;
display: grid;
place-items: center;
}
.terms {
@@ -618,12 +643,48 @@ h1 {
}
@media (min-width: 900px) {
.auth-page {
padding: 0;
background: #fff;
}
.auth-shell {
grid-template-columns: minmax(260px, 0.85fr) minmax(380px, 1.15fr);
width: 100%;
min-height: 100dvh;
grid-template-columns: minmax(420px, 1fr) minmax(440px, 1.05fr);
grid-template-areas: "form brand";
background: #fff;
border-radius: 0;
box-shadow: none;
}
.form-panel {
grid-area: form;
border-radius: 0;
box-shadow: none;
background: #fff;
display: flex;
flex-direction: column;
justify-content: center;
}
.auth-shell :deep(.brand-panel) {
grid-area: brand;
height: 100dvh;
position: sticky;
top: 0;
}
.mobile-brand {
display: none;
}
.form-inner {
margin: 0 auto;
}
.auth-footer {
display: none;
}
}
</style>