add loading footer

This commit is contained in:
Nolan Lawson 2018-01-21 16:07:11 -08:00
parent 0d6cf813a8
commit 924e803d16
6 changed files with 88 additions and 12 deletions

View File

@ -0,0 +1,26 @@
<div class="loading-footer">
<LoadingSpinner size={{48}} />
<span class="loading-footer-info">
Loading more...
</span>
</div>
<style>
.loading-footer {
padding: 20px 0 10px;
display: flex;
align-items: center;
justify-content: center;
}
.loading-footer-info {
margin-left: 20px;
font-size: 1.3em;
}
</style>
<script>
import LoadingSpinner from './LoadingSpinner.html'
export default {
components: {
LoadingSpinner
}
}
</script>

View File

@ -1,10 +1,10 @@
<svg class="loading-spinner-icon {{maskStyle ? 'mask-style' : ''}}"> <svg class="loading-spinner-icon {{maskStyle ? 'mask-style' : ''}}"
style="width: {{size || 64}}px; height: {{size || 64}}px;"
>
<use xlink:href="#fa-spinner" /> <use xlink:href="#fa-spinner" />
</svg> </svg>
<style> <style>
.loading-spinner-icon { .loading-spinner-icon {
width: 64px;
height: 64px;
fill: var(--svg-fill); fill: var(--svg-fill);
animation: spin 2s infinite linear; animation: spin 2s infinite linear;
} }

Before

Width:  |  Height:  |  Size: 503 B

After

Width:  |  Height:  |  Size: 533 B

View File

@ -4,6 +4,8 @@
items="{{keyedStatuses}}" items="{{keyedStatuses}}"
on:scrollToBottom="onScrollToBottom()" on:scrollToBottom="onScrollToBottom()"
shown="{{initialized}}" shown="{{initialized}}"
footerComponent="{{LoadingFooter}}"
showFooter="{{initialized && runningUpdate}}"
/> />
</div> </div>
<style> <style>
@ -15,6 +17,7 @@
import { store } from '../_utils/store' import { store } from '../_utils/store'
import { getTimeline } from '../_utils/mastodon/timelines' import { getTimeline } from '../_utils/mastodon/timelines'
import StatusListItem from './StatusListItem.html' import StatusListItem from './StatusListItem.html'
import LoadingFooter from './LoadingFooter.html'
import VirtualList from './VirtualList.html' import VirtualList from './VirtualList.html'
import { splice, push } from 'svelte-extras' import { splice, push } from 'svelte-extras'
import worker from 'workerize-loader!../_utils/database/database' import worker from 'workerize-loader!../_utils/database/database'
@ -40,6 +43,7 @@
}, },
data: () => ({ data: () => ({
StatusListItem: StatusListItem, StatusListItem: StatusListItem,
LoadingFooter: LoadingFooter,
statuses: [], statuses: [],
runningUpdate: false, runningUpdate: false,
initialized: false initialized: false
@ -69,8 +73,8 @@
mark('onScrollToBottom') mark('onScrollToBottom')
this.set({ runningUpdate: true }) this.set({ runningUpdate: true })
let newStatuses = await this.fetchStatusesAndPossiblyFallBack() let newStatuses = await this.fetchStatusesAndPossiblyFallBack()
this.addStatuses(newStatuses)
this.set({ runningUpdate: false }) this.set({ runningUpdate: false })
this.addStatuses(newStatuses)
stop('onScrollToBottom') stop('onScrollToBottom')
}, },
addStatuses(newStatuses) { addStatuses(newStatuses) {

View File

@ -1,13 +1,16 @@
<!-- TODO: setting height is hacky, just make this element the scroller --> <!-- TODO: setting height is hacky, just make this element the scroller -->
<div class="virtual-list {{shown ? '' : 'hidden'}}" style="height: {{$height}}px;"> <div class="virtual-list {{shown ? '' : 'hidden'}}" style="height: {{$height}}px;">
{{#each $visibleItems as item @key}} {{#each $visibleItems as item @key}}
<VirtualListItem :component <VirtualListItem :component
offset="{{item.offset}}" offset="{{item.offset}}"
props="{{item.props}}" props="{{item.props}}"
key="{{item.key}}" key="{{item.key}}"
index="{{item.index}}" index="{{item.index}}"
/> />
{{/each}} {{/each}}
{{#if $showFooter}}
<VirtualListFooter component="{{footerComponent}}"/>
{{/if}}
</div> </div>
<style> <style>
.virtual-list { .virtual-list {
@ -17,6 +20,7 @@
</style> </style>
<script> <script>
import VirtualListItem from './VirtualListItem' import VirtualListItem from './VirtualListItem'
import VirtualListFooter from './VirtualListFooter.html'
import { virtualListStore } from '../_utils/virtualListStore' import { virtualListStore } from '../_utils/virtualListStore'
import throttle from 'lodash/throttle' import throttle from 'lodash/throttle'
import { mark, stop } from '../_utils/marks' import { mark, stop } from '../_utils/marks'
@ -26,6 +30,9 @@
export default { export default {
oncreate () { oncreate () {
this.observe('showFooter', showFooter => {
this.store.set({showFooter: showFooter})
})
this.observe('items', (items) => { this.observe('items', (items) => {
mark('set items') mark('set items')
this.store.set({ this.store.set({
@ -55,7 +62,8 @@
}), }),
store: () => virtualListStore, store: () => virtualListStore,
components: { components: {
VirtualListItem VirtualListItem,
VirtualListFooter
}, },
computed: { computed: {
distanceFromBottom: ($scrollHeight, $scrollTop, $offsetHeight) => { distanceFromBottom: ($scrollHeight, $scrollTop, $offsetHeight) => {

View File

@ -0,0 +1,27 @@
<div class="virtual-list-footer"
ref:node
style="transform: translateY({{$heightWithoutFooter}}px);" >
<:Component {component} />
</div>
<style>
.virtual-list-footer {
position: absolute;
top: 0;
width: 100%;
}
</style>
<script>
import { virtualListStore } from '../_utils/virtualListStore'
import { AsyncLayout } from '../_utils/AsyncLayout'
export default {
oncreate() {
const asyncLayout = new AsyncLayout(() => '__footer__')
asyncLayout.observe('__footer__', this.refs.node, (rect) => {
asyncLayout.disconnect()
this.store.set({footerHeight: rect.height})
})
},
store: () => virtualListStore,
}
</script>

View File

@ -42,6 +42,8 @@ class VirtualListStore extends Store {
const virtualListStore = new VirtualListStore({ const virtualListStore = new VirtualListStore({
items: [], items: [],
itemHeights: {}, itemHeights: {},
showFooter: false,
footerHeight: 0
}) })
virtualListStore.compute('visibleItems', virtualListStore.compute('visibleItems',
@ -79,7 +81,9 @@ virtualListStore.compute('visibleItems',
return visibleItems return visibleItems
}) })
virtualListStore.compute('height', ['items', 'itemHeights'], (items, itemHeights) => { virtualListStore.compute('heightWithoutFooter',
['items', 'itemHeights'],
(items, itemHeights) => {
let sum = 0 let sum = 0
let i = -1 let i = -1
let len = items.length let len = items.length
@ -89,6 +93,13 @@ virtualListStore.compute('height', ['items', 'itemHeights'], (items, itemHeights
return sum return sum
}) })
virtualListStore.compute('height',
['heightWithoutFooter', 'showFooter', 'footerHeight'],
(heightWithoutFooter, showFooter, footerHeight) => {
return showFooter ? (heightWithoutFooter + footerHeight) : heightWithoutFooter
})
virtualListStore.compute('numItems', ['items'], (items) => items.length) virtualListStore.compute('numItems', ['items'], (items) => items.length)
if (process.browser && process.env.NODE_ENV !== 'production') { if (process.browser && process.env.NODE_ENV !== 'production') {