add loading footer
This commit is contained in:
		
							parent
							
								
									0d6cf813a8
								
							
						
					
					
						commit
						924e803d16
					
				
					 6 changed files with 88 additions and 12 deletions
				
			
		
							
								
								
									
										26
									
								
								routes/_components/LoadingFooter.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								routes/_components/LoadingFooter.html
									
										
									
									
									
										Normal 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>
 | 
			
		||||
| 
						 | 
				
			
			@ -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" />
 | 
			
		||||
</svg>
 | 
			
		||||
<style>
 | 
			
		||||
  .loading-spinner-icon {
 | 
			
		||||
    width: 64px;
 | 
			
		||||
    height: 64px;
 | 
			
		||||
    fill: var(--svg-fill);
 | 
			
		||||
    animation: spin 2s infinite linear;
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
		 Before Width: | Height: | Size: 503 B After Width: | Height: | Size: 533 B  | 
| 
						 | 
				
			
			@ -4,6 +4,8 @@
 | 
			
		|||
               items="{{keyedStatuses}}"
 | 
			
		||||
               on:scrollToBottom="onScrollToBottom()"
 | 
			
		||||
               shown="{{initialized}}"
 | 
			
		||||
               footerComponent="{{LoadingFooter}}"
 | 
			
		||||
               showFooter="{{initialized && runningUpdate}}"
 | 
			
		||||
  />
 | 
			
		||||
</div>
 | 
			
		||||
<style>
 | 
			
		||||
| 
						 | 
				
			
			@ -15,6 +17,7 @@
 | 
			
		|||
  import { store } from '../_utils/store'
 | 
			
		||||
  import { getTimeline } from '../_utils/mastodon/timelines'
 | 
			
		||||
  import StatusListItem from './StatusListItem.html'
 | 
			
		||||
  import LoadingFooter from './LoadingFooter.html'
 | 
			
		||||
  import VirtualList from './VirtualList.html'
 | 
			
		||||
  import { splice, push } from 'svelte-extras'
 | 
			
		||||
  import worker from 'workerize-loader!../_utils/database/database'
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +43,7 @@
 | 
			
		|||
    },
 | 
			
		||||
    data: () => ({
 | 
			
		||||
      StatusListItem: StatusListItem,
 | 
			
		||||
      LoadingFooter: LoadingFooter,
 | 
			
		||||
      statuses: [],
 | 
			
		||||
      runningUpdate: false,
 | 
			
		||||
      initialized: false
 | 
			
		||||
| 
						 | 
				
			
			@ -69,8 +73,8 @@
 | 
			
		|||
        mark('onScrollToBottom')
 | 
			
		||||
        this.set({ runningUpdate: true })
 | 
			
		||||
        let newStatuses = await this.fetchStatusesAndPossiblyFallBack()
 | 
			
		||||
        this.addStatuses(newStatuses)
 | 
			
		||||
        this.set({ runningUpdate: false })
 | 
			
		||||
        this.addStatuses(newStatuses)
 | 
			
		||||
        stop('onScrollToBottom')
 | 
			
		||||
      },
 | 
			
		||||
      addStatuses(newStatuses) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,16 @@
 | 
			
		|||
<!-- TODO: setting height is hacky, just make this element the scroller -->
 | 
			
		||||
<div class="virtual-list {{shown ? '' : 'hidden'}}" style="height: {{$height}}px;">
 | 
			
		||||
  {{#each $visibleItems as item @key}}
 | 
			
		||||
  <VirtualListItem :component
 | 
			
		||||
                   offset="{{item.offset}}"
 | 
			
		||||
                   props="{{item.props}}"
 | 
			
		||||
                   key="{{item.key}}"
 | 
			
		||||
                   index="{{item.index}}"
 | 
			
		||||
  />
 | 
			
		||||
    <VirtualListItem :component
 | 
			
		||||
                     offset="{{item.offset}}"
 | 
			
		||||
                     props="{{item.props}}"
 | 
			
		||||
                     key="{{item.key}}"
 | 
			
		||||
                     index="{{item.index}}"
 | 
			
		||||
    />
 | 
			
		||||
  {{/each}}
 | 
			
		||||
  {{#if $showFooter}}
 | 
			
		||||
    <VirtualListFooter component="{{footerComponent}}"/>
 | 
			
		||||
  {{/if}}
 | 
			
		||||
</div>
 | 
			
		||||
<style>
 | 
			
		||||
  .virtual-list {
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +20,7 @@
 | 
			
		|||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
  import VirtualListItem from './VirtualListItem'
 | 
			
		||||
  import VirtualListFooter from './VirtualListFooter.html'
 | 
			
		||||
  import { virtualListStore } from '../_utils/virtualListStore'
 | 
			
		||||
  import throttle from 'lodash/throttle'
 | 
			
		||||
  import { mark, stop } from '../_utils/marks'
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +30,9 @@
 | 
			
		|||
 | 
			
		||||
  export default {
 | 
			
		||||
    oncreate () {
 | 
			
		||||
      this.observe('showFooter', showFooter => {
 | 
			
		||||
        this.store.set({showFooter: showFooter})
 | 
			
		||||
      })
 | 
			
		||||
      this.observe('items', (items) => {
 | 
			
		||||
        mark('set items')
 | 
			
		||||
        this.store.set({
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +62,8 @@
 | 
			
		|||
    }),
 | 
			
		||||
    store: () => virtualListStore,
 | 
			
		||||
    components: {
 | 
			
		||||
      VirtualListItem
 | 
			
		||||
      VirtualListItem,
 | 
			
		||||
      VirtualListFooter
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      distanceFromBottom: ($scrollHeight, $scrollTop, $offsetHeight) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								routes/_components/VirtualListFooter.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								routes/_components/VirtualListFooter.html
									
										
									
									
									
										Normal 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>
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +42,8 @@ class VirtualListStore extends Store {
 | 
			
		|||
const virtualListStore = new VirtualListStore({
 | 
			
		||||
  items: [],
 | 
			
		||||
  itemHeights: {},
 | 
			
		||||
  showFooter: false,
 | 
			
		||||
  footerHeight: 0
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
virtualListStore.compute('visibleItems',
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +81,9 @@ virtualListStore.compute('visibleItems',
 | 
			
		|||
  return visibleItems
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
virtualListStore.compute('height', ['items', 'itemHeights'], (items, itemHeights) => {
 | 
			
		||||
virtualListStore.compute('heightWithoutFooter',
 | 
			
		||||
    ['items', 'itemHeights'],
 | 
			
		||||
    (items, itemHeights) => {
 | 
			
		||||
  let sum = 0
 | 
			
		||||
  let i = -1
 | 
			
		||||
  let len = items.length
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +93,13 @@ virtualListStore.compute('height', ['items', 'itemHeights'], (items, itemHeights
 | 
			
		|||
  return sum
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
virtualListStore.compute('height',
 | 
			
		||||
    ['heightWithoutFooter', 'showFooter', 'footerHeight'],
 | 
			
		||||
    (heightWithoutFooter, showFooter, footerHeight) => {
 | 
			
		||||
  return showFooter ? (heightWithoutFooter + footerHeight) : heightWithoutFooter
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
virtualListStore.compute('numItems', ['items'], (items) => items.length)
 | 
			
		||||
 | 
			
		||||
if (process.browser && process.env.NODE_ENV !== 'production') {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue