|
@ -2,83 +2,58 @@ |
|
|
<main> |
|
|
<main> |
|
|
<UiBanner /> |
|
|
<UiBanner /> |
|
|
<form |
|
|
<form |
|
|
class="mx-auto mt-10 w-64 overflow-hidden rounded-md bg-white p-5 text-gray-700 shadow dark:bg-neutral-700 dark:text-neutral-200" |
|
|
class="mx-auto mt-10 flex w-64 flex-col gap-5 overflow-hidden rounded-md bg-white p-5 text-gray-700 shadow dark:bg-neutral-700 dark:text-neutral-200" |
|
|
@submit="login" |
|
|
@submit.prevent="login" |
|
|
> |
|
|
> |
|
|
<!-- Avatar --> |
|
|
<!-- Avatar --> |
|
|
<div |
|
|
<div |
|
|
class="relative mx-auto mb-10 mt-5 h-20 w-20 overflow-hidden rounded-full bg-red-800 dark:bg-red-800" |
|
|
class="mx-auto mb-5 mt-5 h-20 w-20 overflow-hidden rounded-full bg-red-800 dark:bg-red-800" |
|
|
> |
|
|
> |
|
|
<IconsAvatar class="m-5 h-10 w-10 text-white dark:text-white" /> |
|
|
<IconsAvatar class="m-5 h-10 w-10 text-white dark:text-white" /> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<input |
|
|
<BaseInput |
|
|
v-model="username" |
|
|
v-model="username" |
|
|
type="text" |
|
|
type="text" |
|
|
name="username" |
|
|
:placeholder="$t('general.username')" |
|
|
:placeholder="$t('username')" |
|
|
|
|
|
autocomplete="username" |
|
|
autocomplete="username" |
|
|
autofocus |
|
|
autofocus |
|
|
class="mb-5 w-full rounded-lg border-2 border-gray-100 px-3 py-2 text-sm text-gray-500 focus:border-red-800 focus:outline-0 focus:ring-0 dark:border-neutral-800 dark:bg-neutral-700 dark:text-gray-500 dark:placeholder:text-neutral-400 dark:focus:border-red-800" |
|
|
name="username" |
|
|
/> |
|
|
/> |
|
|
|
|
|
|
|
|
<input |
|
|
<BaseInput |
|
|
v-model="password" |
|
|
v-model="password" |
|
|
type="password" |
|
|
type="password" |
|
|
name="password" |
|
|
name="password" |
|
|
:placeholder="$t('password')" |
|
|
:placeholder="$t('general.password')" |
|
|
autocomplete="current-password" |
|
|
autocomplete="current-password" |
|
|
class="mb-5 w-full rounded-lg border-2 border-gray-100 px-3 py-2 text-sm text-gray-500 focus:border-red-800 focus:outline-0 focus:ring-0 dark:border-neutral-800 dark:bg-neutral-700 dark:text-gray-500 dark:placeholder:text-neutral-400 dark:focus:border-red-800" |
|
|
|
|
|
/> |
|
|
/> |
|
|
|
|
|
|
|
|
<label |
|
|
<label |
|
|
class="mb-5 inline-block cursor-pointer whitespace-nowrap" |
|
|
class="flex gap-2 whitespace-nowrap" |
|
|
:title="$t('titleRememberMe')" |
|
|
:title="$t('login.rememberMeDesc')" |
|
|
> |
|
|
> |
|
|
<input v-model="remember" type="checkbox" class="sr-only" /> |
|
|
<BaseSwitch v-model="remember" /> |
|
|
|
|
|
<span class="text-sm">{{ $t('login.rememberMe') }}</span> |
|
|
<div |
|
|
|
|
|
v-if="remember" |
|
|
|
|
|
class="mr-1 inline-block h-6 w-10 cursor-pointer rounded-full bg-red-800 align-middle transition-all hover:bg-red-700" |
|
|
|
|
|
> |
|
|
|
|
|
<div class="m-1 ml-5 h-4 w-4 rounded-full bg-white"></div> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div |
|
|
|
|
|
v-if="!remember" |
|
|
|
|
|
class="mr-1 inline-block h-6 w-10 cursor-pointer rounded-full bg-gray-200 align-middle transition-all hover:bg-gray-300 dark:bg-neutral-400 dark:hover:bg-neutral-500" |
|
|
|
|
|
> |
|
|
|
|
|
<div class="m-1 h-4 w-4 rounded-full bg-white"></div> |
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<span class="text-sm">{{ $t('rememberMe') }}</span> |
|
|
|
|
|
</label> |
|
|
</label> |
|
|
|
|
|
|
|
|
<button |
|
|
<button |
|
|
v-if="authenticating" |
|
|
class="rounded py-2 text-sm text-white shadow transition dark:text-white" |
|
|
class="w-full cursor-not-allowed rounded bg-red-800 py-2 text-sm text-white shadow dark:bg-red-800 dark:text-white" |
|
|
:class="{ |
|
|
|
|
|
'cursor-pointer bg-red-800 hover:bg-red-700 dark:bg-red-800 dark:hover:bg-red-700': |
|
|
|
|
|
password && username, |
|
|
|
|
|
'cursor-not-allowed bg-gray-200 dark:bg-neutral-800': |
|
|
|
|
|
!password || !username, |
|
|
|
|
|
}" |
|
|
> |
|
|
> |
|
|
<IconsLoading class="mx-auto w-5 animate-spin" /> |
|
|
<IconsLoading v-if="authenticating" class="mx-auto w-5 animate-spin" /> |
|
|
|
|
|
<span v-else>{{ $t('login.signIn') }}</span> |
|
|
</button> |
|
|
</button> |
|
|
<input |
|
|
|
|
|
v-else |
|
|
|
|
|
type="submit" |
|
|
|
|
|
:class="[ |
|
|
|
|
|
{ |
|
|
|
|
|
'cursor-pointer bg-red-800 transition hover:bg-red-700 dark:bg-red-800 dark:hover:bg-red-700': |
|
|
|
|
|
password, |
|
|
|
|
|
'cursor-not-allowed bg-gray-200 dark:bg-neutral-800': !password, |
|
|
|
|
|
}, |
|
|
|
|
|
'w-full rounded py-2 text-sm text-white shadow dark:text-white', |
|
|
|
|
|
]" |
|
|
|
|
|
:value="$t('signIn')" |
|
|
|
|
|
/> |
|
|
|
|
|
</form> |
|
|
</form> |
|
|
</main> |
|
|
</main> |
|
|
</template> |
|
|
</template> |
|
|
|
|
|
|
|
|
<script setup lang="ts"> |
|
|
<script setup lang="ts"> |
|
|
// TODO: improve |
|
|
|
|
|
import { FetchError } from 'ofetch'; |
|
|
import { FetchError } from 'ofetch'; |
|
|
|
|
|
|
|
|
const { t } = useI18n(); |
|
|
const { t } = useI18n(); |
|
@ -90,9 +65,7 @@ const password = ref<null | string>(null); |
|
|
const authStore = useAuthStore(); |
|
|
const authStore = useAuthStore(); |
|
|
const toast = useToast(); |
|
|
const toast = useToast(); |
|
|
|
|
|
|
|
|
async function login(e: Event) { |
|
|
async function login() { |
|
|
e.preventDefault(); |
|
|
|
|
|
|
|
|
|
|
|
if (!username.value || !password.value || authenticating.value) return; |
|
|
if (!username.value || !password.value || authenticating.value) return; |
|
|
|
|
|
|
|
|
authenticating.value = true; |
|
|
authenticating.value = true; |
|
|