mirror of
https://github.com/nextcloud/server.git
synced 2026-02-19 02:38:40 -05:00
Use new vue components in login form
- Improve accessibility - Simply code Signed-off-by: Carl Schwan <carl@carlschwan.eu>
This commit is contained in:
parent
f496e471e0
commit
df40fc9172
4 changed files with 101 additions and 148 deletions
|
|
@ -108,14 +108,6 @@ form {
|
|||
margin: auto;
|
||||
padding: 0;
|
||||
}
|
||||
form fieldset {
|
||||
width: 260px;
|
||||
margin-top: 8px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
form #sqliteInformation {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 20px;
|
||||
|
|
@ -160,9 +152,6 @@ form #datadirField legend {
|
|||
.wrapper {
|
||||
margin-top: 0;
|
||||
}
|
||||
.alternative-logins {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -262,9 +251,6 @@ input[type='email'] {
|
|||
color: var(--color-text-lighter);
|
||||
cursor: text;
|
||||
font-family: inherit;
|
||||
-webkit-appearance: textfield;
|
||||
-moz-appearance: textfield;
|
||||
box-sizing: content-box;
|
||||
font-weight: normal;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
|
|
@ -491,34 +477,6 @@ form .warning input[type='checkbox']+label {
|
|||
color: var(--color-primary-text);
|
||||
}
|
||||
|
||||
/* Alternative Logins */
|
||||
.alternative-logins legend {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.alternative-logins li {
|
||||
height: 40px;
|
||||
white-space: nowrap;
|
||||
padding: 05px;
|
||||
}
|
||||
.alternative-logins a.button,
|
||||
.alternative-logins li a {
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
border: 2px solid var(--color-primary-text);
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-primary-text);
|
||||
border-radius: 100px; /* --border-radius-pill */
|
||||
}
|
||||
|
||||
.alternative-logins a.button:focus,
|
||||
.alternative-logins li a:focus {
|
||||
border: 2px solid var(--color-primary-hover);
|
||||
background-image: linear-gradient(40deg, var(--color-primary) 0%, var(--color-primary-light) 100%);
|
||||
background-position: initial;
|
||||
}
|
||||
|
||||
/* fixes for update page TODO should be fixed some time in a proper way */
|
||||
/* this is just for an error while updating the ownCloud instance */
|
||||
.updateProgress .error {
|
||||
|
|
|
|||
|
|
@ -21,11 +21,12 @@
|
|||
|
||||
<template>
|
||||
<form ref="loginForm"
|
||||
class="login-form"
|
||||
method="post"
|
||||
name="login"
|
||||
:action="loginActionUrl"
|
||||
@submit="submit">
|
||||
<fieldset>
|
||||
<fieldset class="login-form__fieldset">
|
||||
<div v-if="apacheAuthFailed"
|
||||
class="warning">
|
||||
{{ t('core', 'Server side authentication failed!') }}<br>
|
||||
|
|
@ -52,65 +53,36 @@
|
|||
<!-- the following div ensures that the spinner is always inside the #message div -->
|
||||
<div style="clear: both;" />
|
||||
</div>
|
||||
<p class="grouptop"
|
||||
:class="{shake: invalidPassword}">
|
||||
<input id="user"
|
||||
ref="user"
|
||||
v-model="user"
|
||||
type="text"
|
||||
name="user"
|
||||
autocapitalize="none"
|
||||
autocorrect="off"
|
||||
:autocomplete="autoCompleteAllowed ? 'on' : 'off'"
|
||||
:placeholder="t('core', 'Username or email')"
|
||||
:aria-label="t('core', 'Username or email')"
|
||||
required
|
||||
@change="updateUsername">
|
||||
<label for="user" class="infield">{{ t('core', 'Username or email') }}</label>
|
||||
</p>
|
||||
<NcTextField id="user"
|
||||
:label="t('core', 'Username or email')"
|
||||
:labelVisible="true"
|
||||
ref="user"
|
||||
name="user"
|
||||
:class="{shake: invalidPassword}"
|
||||
:value.sync="user"
|
||||
autocapitalize="none"
|
||||
:spellchecking="false"
|
||||
:autocomplete="autoCompleteAllowed ? 'username' : 'off'"
|
||||
:aria-label="t('core', 'Username or email')"
|
||||
required
|
||||
@change="updateUsername" />
|
||||
|
||||
<p class="groupbottom"
|
||||
:class="{shake: invalidPassword}">
|
||||
<input id="password"
|
||||
ref="password"
|
||||
:type="passwordInputType"
|
||||
class="password-with-toggle"
|
||||
name="password"
|
||||
autocorrect="off"
|
||||
autocapitalize="none"
|
||||
:autocomplete="autoCompleteAllowed ? 'current-password' : 'off'"
|
||||
:placeholder="t('core', 'Password')"
|
||||
:aria-label="t('core', 'Password')"
|
||||
required>
|
||||
<label for="password"
|
||||
class="infield">{{ t('core', 'Password') }}</label>
|
||||
<NcButton class="toggle-password"
|
||||
type="tertiary-no-background"
|
||||
:aria-label="isPasswordHidden ? t('core', 'Show password') : t('core', 'Hide password')"
|
||||
@click.stop.prevent="togglePassword">
|
||||
<template #icon>
|
||||
<Eye v-if="isPasswordHidden" :size="20" />
|
||||
<EyeOff v-else :size="20" />
|
||||
</template>
|
||||
</NcButton>
|
||||
</p>
|
||||
<NcPasswordField id="password"
|
||||
ref="password"
|
||||
name="password"
|
||||
:labelVisible="true"
|
||||
:class="{shake: invalidPassword}"
|
||||
:value.sync="password"
|
||||
:spellchecking="false"
|
||||
autocapitalize="none"
|
||||
:autocomplete="autoCompleteAllowed ? 'current-password' : 'off'"
|
||||
:label="t('core', 'Password')"
|
||||
:helperText="errorLabel"
|
||||
:error="isError"
|
||||
required />
|
||||
|
||||
<LoginButton :loading="loading" />
|
||||
|
||||
<p v-if="invalidPassword"
|
||||
class="warning wrongPasswordMsg">
|
||||
{{ t('core', 'Wrong username or password.') }}
|
||||
</p>
|
||||
<p v-else-if="userDisabled"
|
||||
class="warning userDisabledMsg">
|
||||
{{ t('core', 'User disabled') }}
|
||||
</p>
|
||||
|
||||
<p v-if="throttleDelay && throttleDelay > 5000"
|
||||
class="warning throttledMsg">
|
||||
{{ t('core', 'We have detected multiple invalid login attempts from your IP. Therefore your next login is throttled up to 30 seconds.') }}
|
||||
</p>
|
||||
|
||||
<input v-if="redirectUrl"
|
||||
type="hidden"
|
||||
name="redirect_url"
|
||||
|
|
@ -136,7 +108,9 @@
|
|||
import jstz from 'jstimezonedetect'
|
||||
import { generateUrl, imagePath } from '@nextcloud/router'
|
||||
|
||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton'
|
||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
|
||||
import NcPasswordField from '@nextcloud/vue/dist/Components/NcPasswordField.js'
|
||||
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
|
||||
import Eye from 'vue-material-design-icons/Eye'
|
||||
import EyeOff from 'vue-material-design-icons/EyeOff'
|
||||
|
||||
|
|
@ -150,6 +124,8 @@ export default {
|
|||
Eye,
|
||||
EyeOff,
|
||||
LoginButton,
|
||||
NcPasswordField,
|
||||
NcTextField,
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
@ -190,11 +166,26 @@ export default {
|
|||
timezoneOffset: (-new Date().getTimezoneOffset() / 60),
|
||||
user: this.username,
|
||||
password: '',
|
||||
passwordInputType: 'password',
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
isError() {
|
||||
return this.invalidPassword || this.userDisabled
|
||||
|| (this.throttleDelay && this.throttleDelay > 5000)
|
||||
},
|
||||
errorLabel() {
|
||||
if (this.invalidPassword) {
|
||||
return t('core', 'Wrong username or password.')
|
||||
}
|
||||
if (this.userDisabled) {
|
||||
return t('core', 'User disabled')
|
||||
}
|
||||
if (this.throttleDelay && this.throttleDelay > 5000) {
|
||||
return t('core', 'We have detected multiple invalid login attempts from your IP. Therefore your next login is throttled up to 30 seconds.')
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
apacheAuthFailed() {
|
||||
return this.errors.indexOf('apacheAuthFailed') !== -1
|
||||
},
|
||||
|
|
@ -213,9 +204,6 @@ export default {
|
|||
loginActionUrl() {
|
||||
return generateUrl('login')
|
||||
},
|
||||
isPasswordHidden() {
|
||||
return this.passwordInputType === 'password'
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
|
|
@ -227,13 +215,6 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
togglePassword() {
|
||||
if (this.passwordInputType === 'password') {
|
||||
this.passwordInputType = 'text'
|
||||
} else {
|
||||
this.passwordInputType = 'password'
|
||||
}
|
||||
},
|
||||
updateUsername() {
|
||||
this.$emit('update:username', this.user)
|
||||
},
|
||||
|
|
@ -246,10 +227,15 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.toggle-password {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 10px;
|
||||
color: var(--color-text-lighter);
|
||||
.login-form {
|
||||
text-align: left;
|
||||
font-size: 1rem;
|
||||
|
||||
&__fieldset {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -20,39 +20,35 @@
|
|||
-->
|
||||
|
||||
<template>
|
||||
<form @submit.prevent="submit">
|
||||
<fieldset>
|
||||
<p>
|
||||
<input id="user"
|
||||
v-model="user"
|
||||
type="text"
|
||||
name="user"
|
||||
autocapitalize="off"
|
||||
:placeholder="t('core', 'Username or email')"
|
||||
:aria-label="t('core', 'Username or email')"
|
||||
required
|
||||
@change="updateUsername">
|
||||
<form @submit.prevent="submit" class="login-form">
|
||||
<fieldset class="login-form__fieldset">
|
||||
<NcTextField id="user"
|
||||
:value.sync="user"
|
||||
name="user"
|
||||
autocapitalize="off"
|
||||
:label="t('core', 'Username or email')"
|
||||
:labelVisible="true"
|
||||
required
|
||||
@change="updateUsername" />
|
||||
<!--<?php p($_['user_autofocus'] ? 'autofocus' : ''); ?>
|
||||
autocomplete="<?php p($_['login_form_autocomplete']); ?>" autocapitalize="none" autocorrect="off"-->
|
||||
<label for="user" class="infield">{{ t('core', 'Username or email') }}</label>
|
||||
</p>
|
||||
<div id="reset-password-wrapper">
|
||||
<LoginButton :value="t('core', 'Reset password')" />
|
||||
</div>
|
||||
<p v-if="message === 'send-success'"
|
||||
class="notecard success">
|
||||
<NcNoteCard v-if="message === 'send-success'"
|
||||
type="success">
|
||||
{{ t('core', 'A password reset message has been sent to the email address of this account. If you do not receive it, check your spam/junk folders or ask your local administrator for help.') }}
|
||||
<br>
|
||||
{{ t('core', 'If it is not there ask your local administrator.') }}
|
||||
</p>
|
||||
<p v-else-if="message === 'send-error'"
|
||||
class="notecard error">
|
||||
</NcNoteCard>
|
||||
<NcNoteCard v-else-if="message === 'send-error'"
|
||||
type="error">
|
||||
{{ t('core', 'Couldn\'t send reset email. Please contact your administrator.') }}
|
||||
</p>
|
||||
<p v-else-if="message === 'reset-error'"
|
||||
class="notecard error">
|
||||
</NcNoteCard>
|
||||
<NcNoteCard v-else-if="message === 'reset-error'"
|
||||
type="error">
|
||||
{{ t('core', 'Password cannot be changed. Please contact your administrator.') }}
|
||||
</p>
|
||||
</NcNoteCard>
|
||||
|
||||
<a href="#"
|
||||
@click.prevent="$emit('abort')">
|
||||
|
|
@ -66,11 +62,15 @@
|
|||
import axios from '@nextcloud/axios'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import LoginButton from './LoginButton.vue'
|
||||
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
|
||||
import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
|
||||
|
||||
export default {
|
||||
name: 'ResetPassword',
|
||||
components: {
|
||||
LoginButton,
|
||||
NcNoteCard,
|
||||
NcTextField,
|
||||
},
|
||||
props: {
|
||||
username: {
|
||||
|
|
@ -131,7 +131,15 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.update {
|
||||
width: auto;
|
||||
.login-form {
|
||||
text-align: left;
|
||||
font-size: 1rem;
|
||||
|
||||
&__fieldset {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -192,6 +192,9 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#login {
|
||||
width: 300px;
|
||||
}
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity .3s;
|
||||
}
|
||||
|
|
@ -205,15 +208,13 @@ export default {
|
|||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.alternative-logins button {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
.alternative-logins {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
.button-vue {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in a new issue