Skip to content
Snippets Groups Projects
Commit 1e5fcce1 authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

Proper errors, loading indicators and more animations

parent a5472401
No related branches found
No related tags found
No related merge requests found
...@@ -24,3 +24,25 @@ ...@@ -24,3 +24,25 @@
to to
margin-top: 0 margin-top: 0
opacity: 1 opacity: 1
@keyframes indeterminate
0%
left: -35%
right: 100%
60%
left: 100%
right: -90%
100%
left: 100%
right: -90%
@keyframes indeterminate-short
0%
left: -200%
right: 100%
60%
left: 107%
right: -8%
100%
left: 107%
right: -8%
\ No newline at end of file
...@@ -14,6 +14,21 @@ ...@@ -14,6 +14,21 @@
padding-right: 0 padding-right: 0
padding-bottom: 0 padding-bottom: 0
.error
text-align: center
height: 100%
margin: 4rem
animation-duration: 0.6s
animation-name: slidein
img
max-width: 100%
h1
margin-top: 2rem
color: #777
font-weight: normal
.buffer .buffer
display: block display: block
margin-top: 0 margin-top: 0
......
.progress
position: absolute
height: 4px
display: block
background-color: rgba(255,255,255,0.2)
overflow: hidden
transition: opacity 400ms
bottom: 0
left: 0
right: 0
&:not(.visible)
opacity: 0
.indeterminate
background-color: rgba(255,255,255,0.8)
&:before
content: ''
position: absolute
background-color: inherit
top: 0
left: 0
bottom: 0
will-change: left, right
animation: indeterminate 4.2s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite
&:after
content: ''
position: absolute
background-color: inherit
top: 0
left: 0
bottom: 0
will-change: left, right
animation: indeterminate-short 4.2s cubic-bezier(0.165, 0.84, 0.44, 1) infinite
animation-delay: 2.25s
...@@ -189,6 +189,12 @@ ...@@ -189,6 +189,12 @@
.icon .icon
color: #757575 color: #757575
.progress
background-color: rgba(117, 117, 117, 0.2)
.indeterminate
background-color: rgba(117, 117, 117, 0.8)
.history .history
transform: translateY(0) transform: translateY(0)
......
...@@ -61,6 +61,40 @@ body { ...@@ -61,6 +61,40 @@ body {
visibility: hidden !important; visibility: hidden !important;
display: none !important; } display: none !important; }
.progress {
position: absolute;
height: 4px;
display: block;
background-color: rgba(255, 255, 255, 0.2);
overflow: hidden;
transition: opacity 400ms;
bottom: 0;
left: 0;
right: 0; }
.progress:not(.visible) {
opacity: 0; }
.progress .indeterminate {
background-color: rgba(255, 255, 255, 0.8); }
.progress .indeterminate:before {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
animation: indeterminate 4.2s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite; }
.progress .indeterminate:after {
content: '';
position: absolute;
background-color: inherit;
top: 0;
left: 0;
bottom: 0;
will-change: left, right;
animation: indeterminate-short 4.2s cubic-bezier(0.165, 0.84, 0.44, 1) infinite;
animation-delay: 2.25s; }
.nav { .nav {
position: fixed; position: fixed;
left: 0; left: 0;
...@@ -225,6 +259,10 @@ body { ...@@ -225,6 +259,10 @@ body {
color: #757575; } color: #757575; }
.nav.focus .bar .container .icon { .nav.focus .bar .container .icon {
color: #757575; } color: #757575; }
.nav.focus .bar .progress {
background-color: rgba(117, 117, 117, 0.2); }
.nav.focus .bar .progress .indeterminate {
background-color: rgba(117, 117, 117, 0.8); }
.nav.focus .history { .nav.focus .history {
transform: translateY(0); } transform: translateY(0); }
.nav.focus + .results { .nav.focus + .results {
...@@ -909,6 +947,18 @@ body { ...@@ -909,6 +947,18 @@ body {
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
padding-bottom: 0; } } padding-bottom: 0; } }
.results .error {
text-align: center;
height: 100%;
margin: 4rem;
animation-duration: 0.6s;
animation-name: slidein; }
.results .error img {
max-width: 100%; }
.results .error h1 {
margin-top: 2rem;
color: #777;
font-weight: normal; }
.results .buffer { .results .buffer {
display: block; display: block;
margin-top: 0; margin-top: 0;
...@@ -1239,3 +1289,25 @@ body { ...@@ -1239,3 +1289,25 @@ body {
to { to {
margin-top: 0; margin-top: 0;
opacity: 1; } } opacity: 1; } }
@keyframes indeterminate {
0% {
left: -35%;
right: 100%; }
60% {
left: 100%;
right: -90%; }
100% {
left: 100%;
right: -90%; } }
@keyframes indeterminate-short {
0% {
left: -200%;
right: 100%; }
60% {
left: 107%;
right: -8%; }
100% {
left: 107%;
right: -8%; } }
...@@ -24,6 +24,7 @@ body ...@@ -24,6 +24,7 @@ body
visibility: hidden !important visibility: hidden !important
display: none !important display: none !important
@import "loading"
@import "nav" @import "nav"
@import "searchoptions" @import "searchoptions"
@import "content" @import "content"
......
...@@ -4,6 +4,7 @@ class App { ...@@ -4,6 +4,7 @@ class App {
this.navigation = new Navigation(); this.navigation = new Navigation();
this.buffers = []; this.buffers = [];
this.loadingQuery = 0; this.loadingQuery = 0;
this.error = null;
if (Storage.exists('language')) { if (Storage.exists('language')) {
moment.locale(Storage.get('language')); moment.locale(Storage.get('language'));
} }
...@@ -31,6 +32,7 @@ class App { ...@@ -31,6 +32,7 @@ class App {
} }
search(query, sender, buffer, network, before, since) { search(query, sender, buffer, network, before, since) {
this.clear(); this.clear();
this.navigation.loading.show();
this.navigation.input.blur(); this.navigation.input.blur();
this.navigation.historyView.resetNavigation(); this.navigation.historyView.resetNavigation();
this.navigation.historyView.add(new HistoryElement(query)); this.navigation.historyView.add(new HistoryElement(query));
...@@ -43,12 +45,16 @@ class App { ...@@ -43,12 +45,16 @@ class App {
load('web/search/', statehandler.parse()).then(result => { load('web/search/', statehandler.parse()).then(result => {
if (this.loadingQuery !== queryId) if (this.loadingQuery !== queryId)
return; return;
this.navigation.loading.hide();
this.buffers = result.map(buffer => { this.buffers = result.map(buffer => {
return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map(msg => { return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map(msg => {
return new Context(new Message(msg.messageid, msg.type, msg.time, msg.sender, msg.message, true)); return new Context(new Message(msg.messageid, msg.type, msg.time, msg.sender, msg.message, true));
})); }));
}); });
this.buffers.forEach(buffer => this.insert(buffer)); this.buffers.forEach(buffer => this.insert(buffer));
if (this.buffers.length === 0) {
this.showError(translation.error.none_found);
}
}); });
} }
clear() { clear() {
...@@ -56,12 +62,19 @@ class App { ...@@ -56,12 +62,19 @@ class App {
const buffer = this.buffers.pop(); const buffer = this.buffers.pop();
this.resultContainer.removeChild(buffer.elem); this.resultContainer.removeChild(buffer.elem);
} }
if (this.error) {
this.resultContainer.removeChild(this.error.elem);
}
} }
clearAll() { clearAll() {
this.clear(); this.clear();
this.navigation.historyView.clear(); this.navigation.historyView.clear();
statehandler.clear(); statehandler.clear();
} }
showError(text) {
this.error = new Error(text);
this.resultContainer.appendChild(this.error.elem);
}
insert(buffer) { insert(buffer) {
this.resultContainer.appendChild(buffer.elem); this.resultContainer.appendChild(buffer.elem);
buffer.addEventListener('loadMore', () => this.bufferLoadMore(buffer)); buffer.addEventListener('loadMore', () => this.bufferLoadMore(buffer));
......
...@@ -6,6 +6,7 @@ class App { ...@@ -6,6 +6,7 @@ class App {
this.buffers = []; this.buffers = [];
this.loadingQuery = 0; this.loadingQuery = 0;
this.error = null;
if (Storage.exists('language')) { if (Storage.exists('language')) {
moment.locale(Storage.get('language')); moment.locale(Storage.get('language'));
...@@ -32,6 +33,8 @@ class App { ...@@ -32,6 +33,8 @@ class App {
search(query, sender, buffer, network, before, since) { search(query, sender, buffer, network, before, since) {
this.clear(); this.clear();
this.navigation.loading.show();
this.navigation.input.blur(); this.navigation.input.blur();
this.navigation.historyView.resetNavigation(); this.navigation.historyView.resetNavigation();
this.navigation.historyView.add(new HistoryElement(query)); this.navigation.historyView.add(new HistoryElement(query));
...@@ -47,12 +50,16 @@ class App { ...@@ -47,12 +50,16 @@ class App {
if (this.loadingQuery !== queryId) if (this.loadingQuery !== queryId)
return; return;
this.navigation.loading.hide();
this.buffers = result.map((buffer) => { this.buffers = result.map((buffer) => {
return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map((msg) => { return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map((msg) => {
return new Context(new Message(msg.messageid, msg.type, msg.time, msg.sender, msg.message, true)); return new Context(new Message(msg.messageid, msg.type, msg.time, msg.sender, msg.message, true));
})); }));
}); });
this.buffers.forEach((buffer) => this.insert(buffer)); this.buffers.forEach((buffer) => this.insert(buffer));
if (this.buffers.length === 0) {
this.showError(translation.error.none_found);
}
}); });
} }
...@@ -61,6 +68,10 @@ class App { ...@@ -61,6 +68,10 @@ class App {
const buffer = this.buffers.pop(); const buffer = this.buffers.pop();
this.resultContainer.removeChild(buffer.elem); this.resultContainer.removeChild(buffer.elem);
} }
if (this.error) {
this.resultContainer.removeChild(this.error.elem);
}
} }
clearAll() { clearAll() {
...@@ -69,6 +80,11 @@ class App { ...@@ -69,6 +80,11 @@ class App {
statehandler.clear(); statehandler.clear();
} }
showError(text) {
this.error = new Error(text);
this.resultContainer.appendChild(this.error.elem);
}
insert(buffer) { insert(buffer) {
this.resultContainer.appendChild(buffer.elem); this.resultContainer.appendChild(buffer.elem);
buffer.addEventListener("loadMore", () => this.bufferLoadMore(buffer)); buffer.addEventListener("loadMore", () => this.bufferLoadMore(buffer));
......
class Error {
constructor(text) {
this.render(text);
}
render(text) {
return this.elem = function () {
var $$a = document.createElement('div');
$$a.setAttribute('class', 'error');
var $$b = document.createElement('img');
$$b.setAttribute('src', 'res/icons/error.png');
$$a.appendChild($$b);
var $$c = document.createElement('h1');
$$a.appendChild($$c);
$$c.appendChildren(text);
return $$a;
}.call(this);
}
}
\ No newline at end of file
class Error {
constructor(text) {
this.render(text);
}
render(text) {
return this.elem = (
<div className="error">
<img src="res/icons/error.png"/>
<h1>{text}</h1>
</div>
);
}
}
\ No newline at end of file
class Loading {
constructor() {
this.render();
}
render() {
return this.elem = function () {
var $$a = document.createElement('div');
$$a.setAttribute('class', 'progress');
var $$b = document.createElement('div');
$$b.setAttribute('class', 'indeterminate');
$$a.appendChild($$b);
return $$a;
}.call(this);
}
show() {
this.elem.classList.add('visible');
}
hide() {
this.elem.classList.remove('visible');
}
}
\ No newline at end of file
class Loading {
constructor() {
this.render();
}
render() {
return this.elem = (
<div className="progress">
<div className="indeterminate">
</div>
</div>
);
}
show() {
this.elem.classList.add("visible");
}
hide() {
this.elem.classList.remove("visible");
}
}
\ No newline at end of file
...@@ -52,6 +52,7 @@ class Navigation extends Component { ...@@ -52,6 +52,7 @@ class Navigation extends Component {
$$i.appendChild($$j); $$i.appendChild($$j);
var $$k = document.createTextNode('exit_to_app'); var $$k = document.createTextNode('exit_to_app');
$$j.appendChild($$k); $$j.appendChild($$k);
$$b.appendChildren((this.loading = new Loading()).elem);
$$a.appendChildren((this.historyView = new HistoryView()).elem); $$a.appendChildren((this.historyView = new HistoryView()).elem);
return $$a; return $$a;
}.call(this); }.call(this);
......
...@@ -36,6 +36,7 @@ class Navigation extends Component { ...@@ -36,6 +36,7 @@ class Navigation extends Component {
className="icon">exit_to_app</a> className="icon">exit_to_app</a>
</div> </div>
</div> </div>
{(this.loading = new Loading()).elem}
</div> </div>
{(this.historyView = new HistoryView()).elem} {(this.historyView = new HistoryView()).elem}
</div> </div>
......
...@@ -42,6 +42,8 @@ ...@@ -42,6 +42,8 @@
<script src="res/js/component/nav.js"></script> <script src="res/js/component/nav.js"></script>
<script src="res/js/component/message.js"></script> <script src="res/js/component/message.js"></script>
<script src="res/js/component/loadmore.js"></script> <script src="res/js/component/loadmore.js"></script>
<script src="res/js/component/error.js"></script>
<script src="res/js/component/loading.js"></script>
<script src="res/js/component/context.js"></script> <script src="res/js/component/context.js"></script>
<script src="res/js/component/buffer.js"></script> <script src="res/js/component/buffer.js"></script>
<script src="res/js/component/app.js"></script> <script src="res/js/component/app.js"></script>
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
"error_unauthed": "Sie müssen angemeldet sein, um diese Seite zu nutzen." "error_unauthed": "Sie müssen angemeldet sein, um diese Seite zu nutzen."
} }
}, },
"error": {
"none_found": "Keine Ergebnisse gefunden"
},
"search": "Suchen", "search": "Suchen",
"logout": "Abmelden", "logout": "Abmelden",
"title": "QuasselSearch" "title": "QuasselSearch"
......
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
"error_unauthed": "You need to be logged in to access this page." "error_unauthed": "You need to be logged in to access this page."
} }
}, },
"error": {
"none_found": "No results found"
},
"search": "Search", "search": "Search",
"logout": "Logout", "logout": "Logout",
"title": "QuasselSearch" "title": "QuasselSearch"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment