From d2fe8b29f49fc07b5fdf319c7ee68392c530073c Mon Sep 17 00:00:00 2001 From: Nolan Lawson Date: Tue, 30 Jan 2018 18:26:13 -0800 Subject: [PATCH] more work on pseudo-virtual list --- .../pseudoVirtualList/PseudoVirtualList.html | 52 +++++++++++-------- .../pseudoVirtualListStore.js | 24 +++++++++ routes/_components/status/Status.html | 12 ++++- routes/_components/timeline/LazyTimeline.html | 6 +-- .../timeline/StatusVirtualListItem.html | 1 + routes/_components/timeline/Timeline.html | 4 +- 6 files changed, 71 insertions(+), 28 deletions(-) create mode 100644 routes/_components/pseudoVirtualList/pseudoVirtualListStore.js diff --git a/routes/_components/pseudoVirtualList/PseudoVirtualList.html b/routes/_components/pseudoVirtualList/PseudoVirtualList.html index 0da90ba4..c179ab73 100644 --- a/routes/_components/pseudoVirtualList/PseudoVirtualList.html +++ b/routes/_components/pseudoVirtualList/PseudoVirtualList.html @@ -7,9 +7,8 @@ makeProps="{{makeProps}}" key="{{wrappedItem.item}}" intersectionObserver="{{intersectionObserver}}" - hide="{{shouldHide(wrappedItem.item, intersectionStates)}}" - height="{{getHeight(wrappedItem.item, intersectionStates)}}" - on:renderedListItem="onRenderedListItem()" + hide="{{shouldHide(wrappedItem.item, $intersectionStates)}}" + height="{{getHeight(wrappedItem.item, $intersectionStates)}}" /> {{/each}} @@ -24,16 +23,26 @@ import PseudoVirtualListLazyItem from './PseudoVirtualListLazyItem.html' import { getRectFromEntry } from '../../_utils/getRectFromEntry' import { mark, stop } from '../../_utils/marks' + import { pseudoVirtualListStore } from './pseudoVirtualListStore' export default { oncreate() { - this.set({ - intersectionObserver: new IntersectionObserver(this.onIntersection.bind(this), { - root: document.getElementsByClassName('container')[0], // TODO: fix this - rootMargin: '300% 0px' - }), - intersectionStates: {} - }) + mark('PseudoVirtualList oncreate()') + this.store.set({currentRealm: this.get('realm')}) + + // When re-rendering, assume all items are non-intersecting until told otherwise. + // We already have the heights cached. + let intersectionStates = this.store.get('intersectionStates') + let keys = Object.keys(intersectionStates) + for (let key of keys) { + intersectionStates[key].isIntersecting = false + } + this.store.setForRealm({intersectionStates: intersectionStates}) + + this.set({intersectionObserver: new IntersectionObserver(this.onIntersection.bind(this), { + root: document.getElementsByClassName('container')[0], // TODO: fix this + rootMargin: '300% 0px' + })}) this.observe('allItemsHaveHeight', allItemsHaveHeight => { console.log('allItemsHaveHeight', allItemsHaveHeight) if (allItemsHaveHeight && !this.get('initialized')) { @@ -42,6 +51,7 @@ this.fire('initializedVisibleItems') } }) + stop('PseudoVirtualList oncreate()') }, ondestroy() { let intersectionObserver = this.get('intersectionObserver') @@ -49,15 +59,12 @@ intersectionObserver.disconnect() } }, - data: () => ({ - intersectionStates: {} - }), helpers: { - shouldHide(key, intersectionStates) { - return !!(intersectionStates[key] && !intersectionStates[key].isIntersecting) + shouldHide(key, $intersectionStates) { + return !!($intersectionStates[key] && !$intersectionStates[key].isIntersecting) }, - getHeight(key, intersectionStates) { - return intersectionStates[key] && intersectionStates[key].rect.height + getHeight(key, $intersectionStates) { + return $intersectionStates[key] && $intersectionStates[key].rect.height } }, methods: { @@ -85,7 +92,7 @@ mark('onIntersection') let newIntersectionStates = {} let scrollToItem = this.get('scrollToItem') - let intersectionStates = this.get('intersectionStates') + let intersectionStates = this.store.get('intersectionStates') for (let entry of entries) { let key = entry.target.getAttribute('pseudo-virtual-list-key') let rect = getRectFromEntry(entry) @@ -98,18 +105,18 @@ } } intersectionStates = Object.assign(intersectionStates, newIntersectionStates) - this.set({intersectionStates: intersectionStates}) + this.store.setForRealm({intersectionStates: intersectionStates}) stop('onIntersection') } }, computed: { wrappedItems: (items) => items.map(item => ({item: item})), - allItemsHaveHeight: (items, intersectionStates) => { + allItemsHaveHeight: (items, $intersectionStates) => { if (!items.length) { return false } for (let item of items) { - if (!intersectionStates[item]) { + if (!$intersectionStates[item]) { return false } } @@ -118,6 +125,7 @@ }, components: { PseudoVirtualListLazyItem - } + }, + store: () => pseudoVirtualListStore } \ No newline at end of file diff --git a/routes/_components/pseudoVirtualList/pseudoVirtualListStore.js b/routes/_components/pseudoVirtualList/pseudoVirtualListStore.js new file mode 100644 index 00000000..f0faada6 --- /dev/null +++ b/routes/_components/pseudoVirtualList/pseudoVirtualListStore.js @@ -0,0 +1,24 @@ +import { Store } from 'svelte/store.js' + +class PseudoVirtualListStore extends Store { + setForRealm(obj) { + let realmName = this.get('currentRealm') + let realms = this.get('realms') || {} + realms[realmName] = Object.assign(realms[realmName] || {}, obj) + this.set({realms: realms}) + } +} + +const pseudoVirtualListStore = new PseudoVirtualListStore() + +pseudoVirtualListStore.compute('intersectionStates', + ['realms', 'currentRealm'], + (realms, currentRealm) => { + return (realms && realms[currentRealm] && realms[currentRealm].intersectionStates) || {} +}) + +if (process.browser && process.env.NODE_NODE !== 'production') { + window.pseudoVirtualListStore = pseudoVirtualListStore +} + +export { pseudoVirtualListStore } \ No newline at end of file diff --git a/routes/_components/status/Status.html b/routes/_components/status/Status.html index e8336bf5..50ea7312 100644 --- a/routes/_components/status/Status.html +++ b/routes/_components/status/Status.html @@ -19,7 +19,7 @@ {{'@' + originalAccount.acct}} - {{#if timelineType === 'status'}} + {{#if isStatusInContext}} @@ -39,7 +39,7 @@ {{/if}} {{#if !originalStatus.spoiler_text || spoilerShown}} -
+
{{{emojifiedContent}}}
{{/if}} @@ -176,6 +176,11 @@ font-size: 0.9em; } + .status-content.status-in-context { + font-size: 1.1em; + margin: 20px 10px 20px 5px; + } + :global(.status-content .status-emoji) { width: 20px; height: 20px; @@ -323,6 +328,9 @@ }, store: () => store, computed: { + isStatusInContext: (timelineType, timelineValue, statusId) => { + return timelineType === 'status' && timelineValue === statusId + }, createdAtDate: (status) => status.created_at, relativeDate: (createdAtDate) => { mark('compute relativeDate') diff --git a/routes/_components/timeline/LazyTimeline.html b/routes/_components/timeline/LazyTimeline.html index 3ccbc12a..e24420f6 100644 --- a/routes/_components/timeline/LazyTimeline.html +++ b/routes/_components/timeline/LazyTimeline.html @@ -19,15 +19,15 @@ min-height: 60vh; } .loading-page { - position: absolute; - top: 0; + position: fixed; + top: 72px; left: 0; bottom: 0; right: 0; display: flex; align-items: center; justify-content: center; - z-index: 50 + z-index: 50; }