MOBILE-3833 loading: Improve loading spinner styles

main
Pau Ferrer Ocaña 2022-03-24 16:08:17 +01:00
parent aa4f1cdee1
commit cb63541195
3 changed files with 64 additions and 86 deletions

View File

@ -2,8 +2,4 @@
<ion-spinner color="primary" aria-hidden="true"></ion-spinner>
<p class="core-loading-message" *ngIf="message" role="status">{{message}}</p>
</div>
<div #content class="core-loading-content" [id]="uniqueId" [attr.aria-busy]="!hideUntil" @coreShowHideAnimation
[class.opacity-hide]="!hideUntil">
<ng-content *ngIf="loaded">
</ng-content>
</div>
<ng-content *ngIf="loaded" @coreShowHideAnimation></ng-content>

View File

@ -1,5 +1,27 @@
@import "~theme/globals";
@mixin inline() {
min-height: var(--internal-loading-inline-min-height);
max-height: 100vh; // In order show it on the page (content will be cut).
&:not(.core-loading-loaded) {
position: relative;
--contents-display: flex;
flex-direction: column;
}
.core-loading-container {
--loading-background: rgba(var(--loading-background-inline), 0.4);
flex-direction: row;
height: auto;
width: auto;
.core-loading-message {
@include margin(0, 0, 0, 10px);
}
}
}
:host {
--loading-background: var(--ion-background-color);
--loading-background-inline: var(--ion-background-color-rgb);
@ -8,27 +30,28 @@
--loading-inline-margin: 0px;
--loading-inline-min-height: 28px;
--internal-loading-inline-min-height: var(--loading-inline-min-height);
--content-display: contents;
--loading-display: flex;
--loading-display-message: block;
--contents-display: contents;
position: static;
color: var(--loading-text-color);
@include core-transition(all, 200ms);
&.margin {
--loading-inline-margin: 10px;
--internal-loading-inline-min-height: calc(var(--loading-inline-min-height) + var(--loading-inline-margin) + var(--loading-inline-margin));
}
pointer-events: none;
display: var(--contents-display);
&.core-loading-loaded {
position: static;
pointer-events: auto;
--internal-loading-inline-min-height: 0px;
}
ion-spinner {
--color: var(--loading-spinner);
color: var(--color);
&.has-spacer {
--contents-display: flex;
min-height: 100%;
flex-direction: column;
}
}
.core-loading-container {
pointer-events: none;
position: absolute;
@include position(0, 0, 0, 0);
height: 100%;
@ -36,78 +59,38 @@
z-index: 3;
margin: 0;
padding: 0;
color: var(--loading-text-color);
background-color: var(--loading-background);
@include core-transition(all, 200ms);
display: flex;
display: var(--loading-display);
justify-content: center;
align-items: center;
flex-direction: column;
}
.core-loading-content {
@include core-transition(opacity, 200ms);
display: var(--content-display);
}
.core-loading-message {
@include margin(10px, 0, 0, 0);
}
&.core-loading-loaded {
position: unset;
display: contents;
}
&.core-loading-inline {
--loading-background: rgba(var(--loading-background-inline), 0.5);
position: relative;
display: block;
min-height: var(--internal-loading-inline-min-height);
.core-loading-message {
@include margin(0, 0, 0, 10px);
@include margin(10px, 0, 0, 0);
display: var(--loading-display-message);
}
.core-loading-container {
flex-direction: row;
ion-spinner {
--color: var(--loading-spinner);
color: var(--color);
}
}
&.core-loading-full-height .core-loading-content {
height: 100%;
}
&.has-spacer {
--content-display: flex;
.core-loading-content {
min-height: 100%;
flex-direction: column;
}
}
&.list-item-limited-width .core-loading-content {
max-width: var(--list-item-max-width);
margin-left: auto !important;
margin-right: auto !important;
}
&.safe-area-padding:not(.core-loading-inline) .core-loading-content,
&.safe-area-padding-horizontal:not(.core-loading-inline) .core-loading-content {
@include safe-area-padding-horizontal(0px, 0px);
}
&.safe-area-padding:not(.core-loading-inline) .core-loading-content {
padding-bottom: var(--ion-safe-area-bottom);
> * {
--ion-safe-area-bottom: 0px;
}
}
}
:host-context(ion-item) {
&.core-loading-inline {
position: static;
display: block;
@include inline();
}
}
// Force inline on some contexts.
:host-context(ion-item),
:host-context(core-block) {
// Implicit Inline.
@include inline();
}
:host-context(.limited-width > ):not([slot]) {
--contents-display: flex;
flex-direction: column;
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, OnInit, OnChanges, SimpleChange, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { Component, Input, OnInit, OnChanges, SimpleChange, ElementRef, AfterViewInit } from '@angular/core';
import { CoreEventLoadingChangedData, CoreEvents } from '@singletons/events';
import { CoreUtils } from '@services/utils/utils';
@ -50,15 +50,14 @@ import { AsyncComponent } from '@classes/async-component';
})
export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, AsyncComponent {
@Input() hideUntil: unknown; // Determine when should the contents be shown.
@Input() hideUntil = false; // Determine when should the contents be shown.
@Input() message?: string; // Message to show while loading.
@Input() fullscreen = true; // Use the whole screen.
@ViewChild('content') content?: ElementRef;
uniqueId: string;
protected element: HTMLElement; // Current element.
loaded = false; // Only comes true once.
protected element: HTMLElement; // Current element.
protected onReadyPromise = new CorePromisedValue<void>();
constructor(element: ElementRef) {
@ -67,6 +66,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
// Calculate the unique ID.
this.uniqueId = 'core-loading-content-' + CoreUtils.getUniqueId('CoreLoadingComponent');
this.element.setAttribute('id', this.uniqueId);
}
/**
@ -77,7 +77,6 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
// Default loading message.
this.message = Translate.instant('core.loading');
}
this.element.classList.toggle('core-loading-inline', !this.fullscreen);
}
@ -85,7 +84,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
* @inheritdoc
*/
ngAfterViewInit(): void {
this.changeState(!!this.hideUntil);
this.changeState(this.hideUntil);
}
/**
@ -93,7 +92,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
*/
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
if (changes.hideUntil) {
this.changeState(!!this.hideUntil);
this.changeState(this.hideUntil);
}
}
@ -105,7 +104,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
*/
async changeState(loaded: boolean): Promise<void> {
this.element.classList.toggle('core-loading-loaded', loaded);
this.content?.nativeElement.classList.toggle('core-loading-content', loaded);
this.element.setAttribute('aria-busy', loaded ? 'false' : 'true');
if (!this.loaded && loaded) {
this.loaded = true; // Only comes true once.