Commit c032b3a3 authored by Sandro Lutz's avatar Sandro Lutz Committed by Sandro Lutz
Browse files

Improve user experience with FilteredListPage

* Adds a time delay until the loading animation is shown
* Adds the option to always show some lists regardless of the state of
the page
parent 08548286
......@@ -96,20 +96,32 @@
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
position: relative;
width: 100%;
height: 50vh;
> * {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}
}
.empty-list {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
font-size: 1.2em;
text-align: center;
width: calc(100% - 2em);
position: relative;
width: 100%;
height: 50vh;
> * {
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
font-size: 1.2em;
text-align: center;
width: calc(100% - 2em);
}
}
.list_header {
......
......@@ -11,6 +11,7 @@ import { i18n, currentLanguage } from '../models/language';
import FilterView from '../components/FilterView';
import icons from '../images/icons';
const LIST_LOADING_DELAY = 150;
const LIST_LOADING = 'loading';
const LIST_LOADED = 'loaded';
const LIST_ERROR = 'error';
......@@ -310,12 +311,17 @@ export class FilteredListPage {
}
reload() {
this.dataStore.listState = LIST_LOADING;
const timeout = setTimeout(() => {
this.dataStore.listState = LIST_LOADING;
m.redraw();
}, LIST_LOADING_DELAY);
return this._reloadData()
.then(() => {
clearTimeout(timeout);
this.dataStore.listState = LIST_LOADED;
})
.catch(err => {
clearTimeout(timeout);
error(err);
this.dataStore.listState = LIST_ERROR;
})
......@@ -434,8 +440,10 @@ export class FilteredListPage {
values: this.dataStore.filterValues,
...this._filterViewAttributes,
onchange: async values => {
this.dataStore.listState = LIST_LOADING;
m.redraw();
const timeout = setTimeout(() => {
this.dataStore.listState = LIST_LOADING;
m.redraw();
}, LIST_LOADING_DELAY);
try {
await this._filterViewAttributes.onchange(values);
......@@ -445,8 +453,10 @@ export class FilteredListPage {
this._handleItemDirectLink(this.itemId);
}
}
clearTimeout(timeout);
this.dataStore.listState = LIST_LOADED;
} catch (_error) {
clearTimeout(timeout);
this.dataStore.listState = LIST_ERROR;
if (_error) error(_error);
}
......@@ -458,42 +468,53 @@ export class FilteredListPage {
}
get _listContainerView() {
if (this.dataStore.listState === LIST_LOADING) {
return m('div.loading', m(Spinner, { show: true, size: '96px' }));
const lists = this._lists;
const listLoaded = this.dataStore.listState === LIST_LOADED;
const containsPinnedList = lists.some(
list => list.name === this.constructor.pinnedListIdentifier
);
let pinnedList;
if (this.dataStore.pinnedItem && !this.dataStore.pinnedItem.loading) {
pinnedList = this._renderList({
name: this.constructor.pinnedListIdentifier,
items: [this.dataStore.pinnedItem.item],
});
}
if (this.dataStore.listState === LIST_LOADED) {
if (this._hasItems()) {
let pinnedList;
if (this.dataStore.pinnedItem && !this.dataStore.pinnedItem.loading) {
pinnedList = this._renderList({
name: this.constructor.pinnedListIdentifier,
items: [this.dataStore.pinnedItem.item],
});
}
const lists = this._lists;
const containsPinnedList = lists.some(
list => list.name === this.constructor.pinnedListIdentifier
);
let fullPageMessage;
return [
!containsPinnedList ? pinnedList : null,
...lists.map(list => {
if (list.name === this.constructor.pinnedListIdentifier) {
return pinnedList;
}
return this._renderList(list);
}),
];
}
return this.constructor._renderFullPageMessage(i18n('emptyList'));
if (this.dataStore.listState === LIST_LOADING) {
fullPageMessage = m('div.loading', m(Spinner, { show: true, size: '96px' }));
} else if (this.dataStore.listState === LIST_ERROR) {
fullPageMessage = this.constructor._renderFullPageMessage(i18n('loadingError'));
} else if (!this._hasItems()) {
fullPageMessage = this.constructor._renderFullPageMessage(i18n('emptyList'));
}
return this.constructor._renderFullPageMessage(i18n('loadingError'));
return [
listLoaded && !containsPinnedList ? pinnedList : null,
...lists.map(list => {
if (list.permanent === true) {
return this._renderList(list);
}
if (listLoaded) {
if (list.name === this.constructor.pinnedListIdentifier) {
return pinnedList;
}
if (this._hasItems()) {
return this._renderList(list);
}
}
return null;
}),
fullPageMessage,
];
}
static _renderFullPageMessage(message) {
return m('span.empty-list', message);
return m('div.empty-list', m('span', message));
}
_renderList(list) {
......
......@@ -228,10 +228,12 @@ export default class StudydocList extends FilteredListPage {
return [
{
name: 'quickfilter',
permanent: true,
items: [m(StudydocQuickFilter, { controller, dataStore })],
},
{
name: 'notice',
permanent: true,
items: [
m(Infobox, {
icon: m(Icon, { svg: { content: m.trust(icons.info) } }),
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment