UX Overhaul Part 1 (#3047)

Co-authored-by: Joseph Milazzo <joseph.v.milazzo@gmail.com>
This commit is contained in:
Robbie Davis 2024-08-09 13:55:31 -04:00 committed by GitHub
parent 5934d516f3
commit ff79710ac6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
324 changed files with 11589 additions and 4598 deletions

View file

@ -3,5 +3,9 @@
}
.card {
background-color: var(--primary-color);
background-color: var(--login-card-bg-color);
}
p {
font-family: var(--login-input-font-family);
}

View file

@ -42,7 +42,7 @@
{{t('password-validation')}}
</ng-template>
<span class="visually-hidden" id="password-help"><ng-container [ngTemplateOutlet]="passwordTooltip"></ng-container></span>
<input id="password" class="form-control" maxlength="32" minlength="6" pattern="^.{6,32}$" formControlName="password" type="password" aria-describedby="password-help">
<input id="password" class="form-control" maxlength="256" minlength="6" pattern="^.{6,256}$" formControlName="password" type="password" aria-describedby="password-help">
<div id="inviteForm-password-validations" class="invalid-feedback" *ngIf="registerForm.dirty || registerForm.touched">
<div *ngIf="registerForm.get('password')?.errors?.required">
{{t('required-field')}}

View file

@ -1,4 +1,5 @@
input {
background-color: #fff !important;
color: black !important;
font-family: var(--login-input-font-family);
}

View file

@ -28,7 +28,7 @@ export class ConfirmEmailComponent implements OnDestroy {
registerForm: FormGroup = new FormGroup({
email: new FormControl('', [Validators.required]),
username: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6), Validators.pattern("^.{6,32}$")]),
password: new FormControl('', [Validators.required, Validators.maxLength(256), Validators.minLength(6), Validators.pattern("^.{6,256}$")]),
});
/**

View file

@ -10,7 +10,7 @@
{{t('password-validation')}}
</ng-template>
<span class="visually-hidden" id="password-help"><ng-container [ngTemplateOutlet]="passwordTooltip"></ng-container></span>
<input id="password" class="form-control" maxlength="32" minlength="6" formControlName="password" type="password" aria-describedby="password-help">
<input id="password" class="form-control" maxlength="256" minlength="6" formControlName="password" type="password" aria-describedby="password-help">
<div id="inviteForm-validations" class="invalid-feedback" *ngIf="registerForm.dirty || registerForm.touched">
<div *ngIf="registerForm.get('password')?.errors?.required">
{{t('required-field')}}

View file

@ -22,7 +22,7 @@ export class ConfirmResetPasswordComponent {
token: string = '';
registerForm: FormGroup = new FormGroup({
email: new FormControl('', [Validators.required, Validators.email]),
password: new FormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]),
password: new FormControl('', [Validators.required, Validators.maxLength(256), Validators.minLength(6)]),
});
constructor(private route: ActivatedRoute, private router: Router,

View file

@ -4,9 +4,9 @@
<ng-container body>
<p>{{t('description')}}</p>
<form [formGroup]="registerForm" (ngSubmit)="submit()">
<div class="mb-3">
<div class="mb-3 text-start">
<label for="username" class="form-label">{{t('username-label')}}</label>
<input id="username" class="form-control" formControlName="username" type="text" autocomplete="username"
<input id="username" class="form-control custom-input" formControlName="username" type="text" autocomplete="username"
[class.is-invalid]="registerForm.get('username')?.invalid && registerForm.get('username')?.touched" aria-describedby="username-validations">
<div id="username-validations" class="invalid-feedback" *ngIf="registerForm.dirty || registerForm.touched">
<div *ngIf="registerForm.get('username')?.errors?.required">
@ -15,14 +15,14 @@
</div>
</div>
<div class="mb-3" style="width:100%">
<label for="email" class="form-label">{{t('email-label')}}</label>
<div class="mb-3 text-start">
<label for="email" class="form-label float-start">{{t('email-label')}}</label>
<i class="fa fa-info-circle ms-1" placement="right" [ngbTooltip]="emailTooltip" role="button" tabindex="0"></i>
<ng-template #emailTooltip>{{t('email-tooltip')}}</ng-template>
<span class="visually-hidden" id="email-help">
<ng-container [ngTemplateOutlet]="emailTooltip"></ng-container>
</span>
<input class="form-control" type="email" inputmode="email" id="email" autocomplete="email" formControlName="email" required aria-describedby="email-help"
<input class="form-control custom-input" type="email" inputmode="email" id="email" autocomplete="email" formControlName="email" required aria-describedby="email-help"
[class.is-invalid]="registerForm.get('email')?.invalid && registerForm.get('email')?.touched">
<div id="email-validations" class="invalid-feedback" *ngIf="registerForm.dirty || registerForm.touched">
<div *ngIf="registerForm.get('email')?.errors?.required">
@ -34,14 +34,14 @@
</div>
</div>
<div class="mb-3">
<div class="mb-3 text-start">
<label for="password" class="form-label">Password</label>
<i class="fa fa-info-circle ms-1" placement="right" [ngbTooltip]="passwordTooltip" role="button" tabindex="0"></i>
<ng-template #passwordTooltip>
{{t('password-validation')}}
</ng-template>
<span class="visually-hidden" id="password-help"><ng-container [ngTemplateOutlet]="passwordTooltip"></ng-container></span>
<input id="password" class="form-control" maxlength="32" minlength="6" pattern="^.{6,32}$" formControlName="password" autocomplete="new-password"
<input id="password" class="form-control custom-input" maxlength="256" minlength="6" pattern="^.{6,256}$" formControlName="password" autocomplete="new-password"
type="password" aria-describedby="password-help" [class.is-invalid]="registerForm.get('password')?.invalid && registerForm.get('password')?.touched">
@if (registerForm.dirty || registerForm.touched) {
<div id="password-validations" class="invalid-feedback">
@ -55,8 +55,8 @@
}
</div>
<div class="float-end">
<button class="btn btn-secondary alt" type="submit" [disabled]="!registerForm.valid">{{t('register')}}</button>
<div>
<button class="btn btn-primary" type="submit" [disabled]="!registerForm.valid">{{t('register')}}</button>
</div>
</form>
</ng-container>

View file

@ -1,4 +1,35 @@
input {
background-color: #fff !important;
color: black !important;
.custom-input {
background-color: var(--login-input-background-color);
color: var(--login-input-color);
border-color: var(--login-input-border-color);
font-family: var(--login-input-font-family);
&.is-invalid {
border-color: var(--bs-form-invalid-border-color);
}
&:focus {
border-color: var(--login-input-border-color-focus);
box-shadow: var(--login-input-box-shadow-focus);
}
&::placeholder {
opacity: var(--login-input-placeholder-opacity);
color: var(--login-input-placeholder-color);
font-family: var(--login-input-font-family);
}
}
label {
font-family: var(--login-input-font-family);
margin-bottom: 0;
}
p {
font-family: var(--login-input-font-family);
}
.btn {
width: 100%;
font-family: var(--login-input-font-family);
}

View file

@ -27,8 +27,8 @@ export class RegisterComponent {
registerForm: FormGroup = new FormGroup({
email: new FormControl('', [Validators.required]),
username: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required, Validators.maxLength(32),
Validators.minLength(6), Validators.pattern("^.{6,32}$")]),
password: new FormControl('', [Validators.required, Validators.maxLength(256),
Validators.minLength(6), Validators.pattern("^.{6,256}$")]),
});
private readonly navService = inject(NavService);

View file

@ -5,8 +5,8 @@
<p>{{t('description')}}</p>
<form [formGroup]="registerForm" (ngSubmit)="submit()">
<div class="mb-3" style="width:100%">
<label for="email" class="form-label">Email</label>
<input class="form-control custom-input" type="email" inputmode="email" id="email" formControlName="email" [class.is-invalid]="registerForm.get('email')?.invalid && registerForm.get('email')?.touched">
<label for="email" class="form-label visually-hidden">{{t('email-label')}}</label>
<input class="form-control custom-input" type="email" inputmode="email" id="email" formControlName="email" [class.is-invalid]="registerForm.get('email')?.invalid && registerForm.get('email')?.touched" [placeholder]="t('email-label')">
<div id="inviteForm-validations" class="invalid-feedback" *ngIf="registerForm.dirty || registerForm.touched">
<div *ngIf="registerForm.get('email')?.errors?.required">
{{t('required-field')}}
@ -18,7 +18,7 @@
</div>
<div>
<button class="btn btn-secondary alt" type="submit">{{t('submit')}}</button>
<button class="btn btn-primary" type="submit">{{t('submit')}}</button>
</div>
</form>
</ng-container>

View file

@ -1,8 +1,26 @@
.btn {
width: 100%
width: 100%;
font-family: var(--login-input-font-family);
}
.custom-input {
background-color: #fff !important;
color: black !important;
background-color: var(--login-input-background-color);
color: var(--login-input-color);
border-color: var(--login-input-border-color);
font-family: var(--login-input-font-family);
&:focus {
border-color: var(--login-input-border-color-focus);
box-shadow: var(--login-input-box-shadow-focus);
}
&::placeholder {
opacity: 0.5;
color: var(--login-input-placeholder-color);
font-family: var(--login-input-font-family);
}
}
p {
font-family: var(--login-input-font-family);
}

View file

@ -1,12 +1,26 @@
<div class="mx-auto login" [ngStyle]="{'height': (navService.navbarVisible$ | async) ? 'calc(var(--vh, 1vh) * 100 - 57px)' : 'calc(var(--vh, 1vh) * 100)'}">
<div class="mx-auto container login text-center"
[ngStyle]="{'height': (navService.navbarVisible$ | async) ? 'calc(var(--vh, 1vh) * 100 - var(--nav-offset))' : 'calc(var(--vh, 1vh) * 100)'}">
<div class="row row-cols-4 row-cols-md-4 row-cols-sm-2 row-cols-xs-2">
<div class="col align-self-center card p-3">
<div class="row align-items-center row-cols-1 logo-container mb-3 justify-content-center">
<div class="col col-md-4 col-sm-12 col-xs-12 align-self-center p-0">
<div class="row align-items-center row-cols-1 justify-content-center">
<div class="col col-lg-8 col-md-10 col-sm-10 col-xs-10 p-0 position-relative">
<div class="justify-content-center">
<div class="logo" aria-hidden="true"></div>
<h2>Kavita</h2>
</div>
</div>
</div>
</div>
</div>
<div class="row align-items-center row-cols-1 login-container justify-content-center">
<div class="col col-xl-2 col-lg-3 col-md-3 col-sm-10 col-xs-10 align-self-center card p-3">
<span>
<div class="logo-container">
<h3 class="card-title text-center">
<div class="card-title text-center">
<ng-content select="[title]"></ng-content>
</h3>
</div>
</div>
</span>
@ -17,4 +31,4 @@
</div>
</div>
</div>

View file

@ -1,38 +1,65 @@
::ng-deep body {
scrollbar-gutter: stable;
}
.login {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: calc(var(--vh, 1vh) * 100 - 57px);
min-height: 289px;
position: relative;
width: 100vw;
max-width: 100vw;
background: var(--login-background-color);
&::before {
content: "";
background-image: url('../../../../assets/images/login-bg.jpg');
background-size: cover;
background-image: var(--login-background-url);
background-size: var(--login-background-size);
position: absolute;
top: 0;
right: 0;
bottom: 0;
opacity: 0.1;
opacity: var(--login-background-opacity);
width: 100%;
}
h2 {
font-family: "Spartan", sans-serif;
font-size: 1.5rem;
margin-bottom: 0;
font-weight: bold;
display: inline-block;
margin-left: 5px;
vertical-align: middle;
}
.logo-container {
width: 100%;
.logo {
display:inline-block;
height: 50px;
width: var(--login-logo-width);
height: var(--login-logo-height);
background-image: var(--login-logo-image);
background-size: var(--login-logo-bg-size);
background-repeat: var(--login-logo-bg-repeat);
display: inline-block;
vertical-align: middle;
}
}
.login-container {
width: 100%;
}
.card {
background-color: var(--primary-color);
background-color: var(--login-card-bg-color);
color: #fff;
min-width: 300px;
max-width: 12rem;
max-width: 300px;
border-width: var(--login-card-border-width);
border-style: var(--login-card-border-style);
border-color: var(--login-card-border-color);
&:focus {
border: 2px solid white;
@ -40,12 +67,14 @@
}
.card-title {
font-family: 'Spartan', sans-serif;
font-weight: bold;
display: inline-block;
vertical-align: middle;
width: 100%;
::ng-deep.card-title {
h2 {
font-family: 'Poppins', sans-serif;
display: inline-block;
vertical-align: middle;
width: 100%;
font-size: 1rem;
}
}
.card-text {

View file

@ -17,12 +17,12 @@
id="password" type="password" [placeholder]="t('password')">
</div>
<div class="mb-3">
<a routerLink="/registration/reset-password" style="color: white">{{t('forgot-password')}}</a>
<div class="mb-3 forgot-password">
<a routerLink="/registration/reset-password">{{t('forgot-password')}}</a>
</div>
<div>
<button class="btn btn-secondary alt" type="submit" [disabled]="isSubmitting">{{t('submit')}}</button>
<div class="sign-in">
<button class="btn btn-outline-primary" type="submit" [disabled]="isSubmitting">{{t('submit')}}</button>
</div>
</div>
</form>

View file

@ -11,11 +11,38 @@ a {
}
.custom-input {
background-color: #fff !important;
color: black !important;
background-color: #343A40 !important;
color: #fff !important;
border-color: var(--login-input-border-color);
font-family: var(--login-input-font-family);
&:focus {
border-color: var(--login-input-border-color-focus);
box-shadow: var(--login-input-box-shadow-focus);
}
&::placeholder {
opacity: var(--login-input-placeholder-opacity);
color: var(--login-input-placeholder-color);
font-family: var(--login-input-font-family);
}
}
.invalid-feedback {
display: inline-block;
color: #343c59;
color: var(--bs-form-invalid-color);
font-family: var(--login-input-font-family);
}
.forgot-password {
a {
color: var(--login-forgot-password-color);
font-family: var(--login-input-font-family);
}
}
.sign-in {
.btn {
font-family: var(--login-input-font-family);
}
}

View file

@ -24,7 +24,7 @@ export class UserLoginComponent implements OnInit {
loginForm: FormGroup = new FormGroup({
username: new FormControl('', [Validators.required]),
password: new FormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6), Validators.pattern("^.{6,32}$")])
password: new FormControl('', [Validators.required, Validators.maxLength(256), Validators.minLength(6), Validators.pattern("^.{6,256}$")])
});
/**