kopia lustrzana https://github.com/nolanlawson/pinafore
Merge branch 'master' into refactor-dialogs-2
commit
710b3003be
|
@ -105,17 +105,6 @@
|
|||
import { store } from '../_store/store'
|
||||
|
||||
export default {
|
||||
oncreate () {
|
||||
this.observe('animation', animation => {
|
||||
let { reduceMotion } = this.store.get()
|
||||
if (!animation || reduceMotion) {
|
||||
return
|
||||
}
|
||||
let svg = this.refs.svg
|
||||
let animations = animation.map(({properties, options}) => svg.animate(properties, options))
|
||||
animations.forEach(anim => anim.play())
|
||||
})
|
||||
},
|
||||
store: () => store,
|
||||
computed: {
|
||||
computedClass: (pressable, pressed, big, muted, className) => {
|
||||
|
@ -128,6 +117,17 @@
|
|||
className
|
||||
)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
animate (animation) {
|
||||
let { reduceMotion } = this.store.get()
|
||||
if (!animation || reduceMotion) {
|
||||
return
|
||||
}
|
||||
let svg = this.refs.svg
|
||||
let animations = animation.map(({properties, options}) => svg.animate(properties, options))
|
||||
animations.forEach(anim => anim.play())
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -6,7 +6,7 @@
|
|||
pressed="{{following}}"
|
||||
big="true"
|
||||
on:click="onFollowButtonClick(event)"
|
||||
animation="{{animateFollowButton && followButtonAnimation}}"
|
||||
ref:icon
|
||||
/>
|
||||
</div>
|
||||
<style>
|
||||
|
@ -38,7 +38,6 @@
|
|||
followRequested,
|
||||
blocking
|
||||
} = this.get()
|
||||
this.set({animateFollowButton: true}) // TODO: this should be an event, not toggling a boolean
|
||||
if (blocking) { // unblock
|
||||
await setAccountBlocked(accountId, false)
|
||||
} else { // follow/unfollow
|
||||
|
@ -46,16 +45,14 @@
|
|||
if (!account.locked) { // be optimistic, show the user that it succeeded
|
||||
this.set({overrideFollowing: newFollowingValue})
|
||||
}
|
||||
if (newFollowingValue) {
|
||||
this.refs.icon.animate(FOLLOW_BUTTON_ANIMATION)
|
||||
}
|
||||
await setAccountFollowed(accountId, newFollowingValue)
|
||||
}
|
||||
|
||||
this.set({animateFollowButton: false}) // let animation play next time
|
||||
}
|
||||
},
|
||||
store: () => store,
|
||||
data: () => ({
|
||||
followButtonAnimation: FOLLOW_BUTTON_ANIMATION
|
||||
}),
|
||||
computed: {
|
||||
accountId: (account) => account.id,
|
||||
following: (relationship, overrideFollowing) => {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
disabled="{{reblogDisabled}}"
|
||||
href="{{reblogIcon}}"
|
||||
delegateKey="{{reblogKey}}"
|
||||
animation="{{animateReblog && reblogAnimation}}"
|
||||
ref:reblogIcon
|
||||
/>
|
||||
<IconButton
|
||||
label="Favorite"
|
||||
|
@ -23,7 +23,7 @@
|
|||
pressed="{{favorited}}"
|
||||
href="#fa-star"
|
||||
delegateKey="{{favoriteKey}}"
|
||||
animation="{{animateFavorite && favoriteAnimation}}"
|
||||
ref:favoriteIcon
|
||||
/>
|
||||
<IconButton
|
||||
label="Show more options"
|
||||
|
@ -77,15 +77,21 @@
|
|||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
let { originalStatusId, favorited } = this.get()
|
||||
/* no await */ setFavorited(originalStatusId, !favorited)
|
||||
this.set({animateFavorite: !favorited})
|
||||
let newFavoritedValue = !favorited
|
||||
/* no await */ setFavorited(originalStatusId, newFavoritedValue)
|
||||
if (newFavoritedValue) {
|
||||
this.refs.favoriteIcon.animate(FAVORITE_ANIMATION)
|
||||
}
|
||||
},
|
||||
onReblogClick (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
let { originalStatusId, reblogged } = this.get()
|
||||
/* no await */ setReblogged(originalStatusId, !reblogged)
|
||||
this.set({animateReblog: !reblogged})
|
||||
let newRebloggedValue = !reblogged
|
||||
/* no await */ setReblogged(originalStatusId, newRebloggedValue)
|
||||
if (newRebloggedValue) {
|
||||
this.refs.reblogIcon.animate(REBLOG_ANIMATION)
|
||||
}
|
||||
},
|
||||
onReplyClick (e) {
|
||||
e.preventDefault()
|
||||
|
|
|
@ -4,46 +4,41 @@
|
|||
on:focusWithCapture="saveFocus(event)"
|
||||
on:blurWithCapture="clearFocus(event)"
|
||||
>
|
||||
{{#if virtual}}
|
||||
<VirtualList component="{{VirtualListComponent}}"
|
||||
realm="{{$currentInstance + '/' + timeline}}"
|
||||
containerQuery=".container"
|
||||
:makeProps
|
||||
items="{{$timelineItemIds}}"
|
||||
showFooter="{{$timelineInitialized && $runningUpdate}}"
|
||||
footerComponent="{{LoadingFooter}}"
|
||||
showHeader="{{$showHeader}}"
|
||||
headerComponent="{{MoreHeaderVirtualWrapper}}"
|
||||
:headerProps
|
||||
on:scrollToBottom="onScrollToBottom()"
|
||||
on:scrollToTop="onScrollToTop()"
|
||||
on:scrollTopChanged="onScrollTopChanged(event)"
|
||||
on:initialized="initialize()"
|
||||
on:noNeedToScroll="onNoNeedToScroll()"
|
||||
{{#await componentsPromise}}
|
||||
{{then result}}
|
||||
<:Component {result.listComponent}
|
||||
component="{{result.listItemComponent}}"
|
||||
realm="{{$currentInstance + '/' + timeline}}"
|
||||
containerQuery=".container"
|
||||
:makeProps
|
||||
items="{{$timelineItemIds}}"
|
||||
showFooter="{{$timelineInitialized && $runningUpdate}}"
|
||||
footerComponent="{{LoadingFooter}}"
|
||||
showHeader="{{$showHeader}}"
|
||||
headerComponent="{{MoreHeaderVirtualWrapper}}"
|
||||
:headerProps
|
||||
:scrollToItem
|
||||
on:scrollToBottom="onScrollToBottom()"
|
||||
on:scrollToTop="onScrollToTop()"
|
||||
on:scrollTopChanged="onScrollTopChanged(event)"
|
||||
on:initialized="initialize()"
|
||||
on:noNeedToScroll="onNoNeedToScroll()"
|
||||
/>
|
||||
{{else}}
|
||||
<!-- if this is a status thread, it's easier to just render the
|
||||
whole thing rather than use a virtual list -->
|
||||
<PseudoVirtualList
|
||||
component="{{VirtualListComponent}}"
|
||||
realm="{{$currentInstance + '/' + timeline}}"
|
||||
containerQuery=".container"
|
||||
:makeProps
|
||||
items="{{$timelineItemIds}}"
|
||||
scrollToItem="{{scrollToItem}}"
|
||||
on:initialized="initialize()"
|
||||
/>
|
||||
{{/if}}
|
||||
{{catch error}}
|
||||
<div>Error: component failed to load! Try reloading. {{error}}</div>
|
||||
{{/await}}
|
||||
</div>
|
||||
<script>
|
||||
import { store } from '../../_store/store'
|
||||
import StatusVirtualListItem from './StatusVirtualListItem.html'
|
||||
import NotificationVirtualListItem from './NotificationVirtualListItem.html'
|
||||
import Status from '../status/Status.html'
|
||||
import LoadingFooter from './LoadingFooter.html'
|
||||
import MoreHeaderVirtualWrapper from './MoreHeaderVirtualWrapper.html'
|
||||
import VirtualList from '../virtualList/VirtualList.html'
|
||||
import PseudoVirtualList from '../pseudoVirtualList/PseudoVirtualList.html'
|
||||
import {
|
||||
importVirtualList,
|
||||
importPseudoVirtualList,
|
||||
importStatusVirtualListItem,
|
||||
importNotificationVirtualListItem
|
||||
} from '../../_utils/asyncModules'
|
||||
import { timelines } from '../../_static/timelines'
|
||||
import {
|
||||
getStatus as getStatusFromDatabase,
|
||||
|
@ -81,8 +76,22 @@
|
|||
scrollTop: 0
|
||||
}),
|
||||
computed: {
|
||||
VirtualListComponent: (timelineType) => {
|
||||
return timelineType === 'notifications' ? NotificationVirtualListItem : StatusVirtualListItem
|
||||
// For threads, it's simpler to just render all items as a pseudo-virtual list
|
||||
// due to need to scroll to the right item and thus calculate all item heights up-front.
|
||||
// Here we lazy-load both the virtual list component itself as well as the component
|
||||
// it renders.
|
||||
componentsPromise: (timelineType) => {
|
||||
return Promise.all([
|
||||
timelineType === 'status'
|
||||
? importPseudoVirtualList()
|
||||
: importVirtualList(),
|
||||
timelineType === 'notifications'
|
||||
? importNotificationVirtualListItem()
|
||||
: importStatusVirtualListItem()
|
||||
]).then(results => ({
|
||||
listComponent: results[0],
|
||||
listItemComponent: results[1]
|
||||
}))
|
||||
},
|
||||
makeProps: ($currentInstance, timelineType, timelineValue) => async (itemId) => {
|
||||
let res = {
|
||||
|
@ -120,9 +129,6 @@
|
|||
timelineValue: (timeline) => {
|
||||
return timeline.split('/').slice(-1)[0]
|
||||
},
|
||||
// for threads, it's simpler to just render all items as a pseudo-virtual list
|
||||
// due to need to scroll to the right item and thus calculate all item heights up-front
|
||||
virtual: (timelineType) => timelineType !== 'status',
|
||||
// Scroll to the first item if this is a "status in own thread" timeline.
|
||||
// Don't scroll to the first item because it obscures the "back" button.
|
||||
scrollToItem: (timelineType, timelineValue, $firstTimelineItemId) => (
|
||||
|
@ -138,10 +144,6 @@
|
|||
}
|
||||
},
|
||||
store: () => store,
|
||||
components: {
|
||||
VirtualList,
|
||||
PseudoVirtualList
|
||||
},
|
||||
events: {
|
||||
focusWithCapture,
|
||||
blurWithCapture
|
||||
|
|
|
@ -21,3 +21,19 @@ export const importWebAnimationPolyfill = () => import(
|
|||
export const importWebSocketClient = () => import(
|
||||
/* webpackChunkName: '@gamestdio/websocket' */ '@gamestdio/websocket'
|
||||
).then(mod => mod.default)
|
||||
|
||||
export const importVirtualList = () => import(
|
||||
/* webpackChunkName: 'VirtualList.html' */ '../_components/virtualList/VirtualList.html'
|
||||
).then(mod => mod.default)
|
||||
|
||||
export const importPseudoVirtualList = () => import(
|
||||
/* webpackChunkName: 'PseudoVirtualList.html' */ '../_components/pseudoVirtualList/PseudoVirtualList.html'
|
||||
).then(mod => mod.default)
|
||||
|
||||
export const importStatusVirtualListItem = () => import(
|
||||
/* webpackChunkName: 'StatusVirtualListItem.html' */ '../_components/timeline/StatusVirtualListItem.html'
|
||||
).then(mod => mod.default)
|
||||
|
||||
export const importNotificationVirtualListItem = () => import(
|
||||
/* webpackChunkName: 'NotificationVirtualListItem.html' */ '../_components/timeline/NotificationVirtualListItem.html'
|
||||
).then(mod => mod.default)
|
||||
|
|
Ładowanie…
Reference in New Issue