diff options
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/conversation-page/conversation-page.vue | 6 | ||||
| -rw-r--r-- | src/components/conversation/conversation.js | 70 | ||||
| -rw-r--r-- | src/components/conversation/conversation.vue | 50 | ||||
| -rw-r--r-- | src/components/side_drawer/side_drawer.js | 18 | ||||
| -rw-r--r-- | src/components/side_drawer/side_drawer.vue | 24 | ||||
| -rw-r--r-- | src/components/status/status.js | 1 | ||||
| -rw-r--r-- | src/components/status/status.vue | 10 | ||||
| -rw-r--r-- | src/components/status_or_conversation/status_or_conversation.js | 22 | ||||
| -rw-r--r-- | src/components/status_or_conversation/status_or_conversation.vue | 14 | ||||
| -rw-r--r-- | src/components/timeline/timeline.js | 4 | ||||
| -rw-r--r-- | src/components/timeline/timeline.vue | 8 |
11 files changed, 135 insertions, 92 deletions
diff --git a/src/components/conversation-page/conversation-page.vue b/src/components/conversation-page/conversation-page.vue index b03eea28..9e322cf5 100644 --- a/src/components/conversation-page/conversation-page.vue +++ b/src/components/conversation-page/conversation-page.vue @@ -1,5 +1,9 @@ <template> - <conversation :collapsable="false" :statusoid="statusoid"></conversation> + <conversation + :collapsable="false" + isPage="true" + :statusoid="statusoid" + ></conversation> </template> <script src="./conversation-page.js"></script> diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index e806be8e..69058bf6 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -1,10 +1,12 @@ -import { reduce, filter } from 'lodash' +import { reduce, filter, findIndex } from 'lodash' import { set } from 'vue' import Status from '../status/status.vue' const sortById = (a, b) => { - const seqA = Number(a.id) - const seqB = Number(b.id) + const idA = a.type === 'retweet' ? a.retweeted_status.id : a.id + const idB = b.type === 'retweet' ? b.retweeted_status.id : b.id + const seqA = Number(idA) + const seqB = Number(idB) const isSeqA = !Number.isNaN(seqA) const isSeqB = !Number.isNaN(seqB) if (isSeqA && isSeqB) { @@ -14,12 +16,19 @@ const sortById = (a, b) => { } else if (!isSeqA && isSeqB) { return 1 } else { - return a.id < b.id ? -1 : 1 + return idA < idB ? -1 : 1 } } -const sortAndFilterConversation = (conversation) => { - conversation = filter(conversation, (status) => status.type !== 'retweet') +const sortAndFilterConversation = (conversation, statusoid) => { + if (statusoid.type === 'retweet') { + conversation = filter( + conversation, + (status) => (status.type === 'retweet' || status.id !== statusoid.retweeted_status.id) + ) + } else { + conversation = filter(conversation, (status) => status.type !== 'retweet') + } return conversation.filter(_ => _).sort(sortById) } @@ -27,13 +36,20 @@ const conversation = { data () { return { highlight: null, + expanded: false, converationStatusIds: [] } }, props: [ 'statusoid', - 'collapsable' + 'collapsable', + 'isPage' ], + created () { + if (this.isPage) { + this.fetchConversation() + } + }, computed: { status () { return this.statusoid @@ -59,12 +75,22 @@ const conversation = { return [] } + if (!this.isExpanded) { + return [this.status] + } + const statusesObject = this.$store.state.statuses.allStatusesObject const conversation = this.idsToShow.reduce((acc, id) => { acc.push(statusesObject[id]) return acc }, []) - return sortAndFilterConversation(conversation) + + const statusIndex = findIndex(conversation, { id: this.statusId }) + if (statusIndex !== -1) { + conversation[statusIndex] = this.status + } + + return sortAndFilterConversation(conversation, this.status) }, replies () { let i = 1 @@ -82,16 +108,21 @@ const conversation = { i++ return result }, {}) + }, + isExpanded () { + return this.expanded || this.isPage } }, components: { Status }, - created () { - this.fetchConversation() - }, watch: { - '$route': 'fetchConversation' + '$route': 'fetchConversation', + expanded (value) { + if (value) { + this.fetchConversation() + } + } }, methods: { fetchConversation () { @@ -101,9 +132,9 @@ const conversation = { this.$store.dispatch('addNewStatuses', { statuses: ancestors }) this.$store.dispatch('addNewStatuses', { statuses: descendants }) set(this, 'converationStatusIds', [].concat( - ancestors.map(_ => _.id), + ancestors.map(_ => _.id).filter(_ => _ !== this.statusId), this.statusId, - descendants.map(_ => _.id))) + descendants.map(_ => _.id).filter(_ => _ !== this.statusId))) }) .then(() => this.setHighlight(this.statusId)) } else { @@ -117,10 +148,19 @@ const conversation = { return this.replies[id] || [] }, focused (id) { - return id === this.statusId + return (this.isExpanded) && id === this.status.id }, setHighlight (id) { this.highlight = id + }, + getHighlight () { + return this.isExpanded ? this.highlight : null + }, + toggleExpanded () { + this.expanded = !this.expanded + if (!this.expanded) { + this.setHighlight(null) + } } } } diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 5528fef6..c39a3ed9 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -1,26 +1,42 @@ <template> - <div class="timeline panel panel-default"> - <div class="panel-heading conversation-heading"> + <div class="timeline panel-default" :class="[isExpanded ? 'panel' : 'panel-disabled']"> + <div v-if="isExpanded" class="panel-heading conversation-heading"> <span class="title"> {{ $t('timeline.conversation') }} </span> <span v-if="collapsable"> - <a href="#" @click.prevent="$emit('toggleExpanded')">{{ $t('timeline.collapse') }}</a> + <a href="#" @click.prevent="toggleExpanded">{{ $t('timeline.collapse') }}</a> </span> </div> - <div class="panel-body"> - <div class="timeline"> - <status - v-for="status in conversation" - @goto="setHighlight" :key="status.id" - :inlineExpanded="collapsable" :statusoid="status" - :expandable='false' :focused="focused(status.id)" - :inConversation='true' - :highlight="highlight" - :replies="getReplies(status.id)" - class="status-fadein"> - </status> - </div> - </div> + <status + v-for="status in conversation" + @goto="setHighlight" + @toggleExpanded="toggleExpanded" + :key="status.id" + :inlineExpanded="collapsable" + :statusoid="status" + :expandable='!expanded' + :focused="focused(status.id)" + :inConversation="isExpanded" + :highlight="getHighlight()" + :replies="getReplies(status.id)" + class="status-fadein panel-body" + /> </div> </template> <script src="./conversation.js"></script> + +<style lang="scss"> +@import '../../_variables.scss'; + +.timeline { + .panel-disabled { + .status-el { + border-left: none; + border-bottom-width: 1px; + border-bottom-style: solid; + border-color: var(--border, $fallback--border); + border-radius: 0; + } + } +} +</style> diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js index ad3738d1..567d2e5e 100644 --- a/src/components/side_drawer/side_drawer.js +++ b/src/components/side_drawer/side_drawer.js @@ -1,17 +1,16 @@ import UserCard from '../user_card/user_card.vue' import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils' - -// TODO: separate touch gesture stuff into their own utils if more components want them -const deltaCoord = (oldCoord, newCoord) => [newCoord[0] - oldCoord[0], newCoord[1] - oldCoord[1]] - -const touchEventCoord = e => ([e.touches[0].screenX, e.touches[0].screenY]) +import GestureService from '../../services/gesture_service/gesture_service' const SideDrawer = { props: [ 'logout' ], data: () => ({ closed: true, - touchCoord: [0, 0] + closeGesture: undefined }), + created () { + this.closeGesture = GestureService.swipeGesture(GestureService.DIRECTION_LEFT, this.toggleDrawer) + }, components: { UserCard }, computed: { currentUser () { @@ -46,13 +45,10 @@ const SideDrawer = { this.toggleDrawer() }, touchStart (e) { - this.touchCoord = touchEventCoord(e) + GestureService.beginSwipe(e, this.closeGesture) }, touchMove (e) { - const delta = deltaCoord(this.touchCoord, touchEventCoord(e)) - if (delta[0] < -30 && Math.abs(delta[1]) < Math.abs(delta[0]) && !this.closed) { - this.toggleDrawer() - } + GestureService.updateSwipe(e, this.closeGesture) } } } diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue index 95ee21b4..e5046496 100644 --- a/src/components/side_drawer/side_drawer.vue +++ b/src/components/side_drawer/side_drawer.vue @@ -2,6 +2,7 @@ <div class="side-drawer-container" :class="{ 'side-drawer-container-closed': closed, 'side-drawer-container-open': !closed }" > + <div class="side-drawer-darken" :class="{ 'side-drawer-darken-closed': closed}" /> <div class="side-drawer" :class="{'side-drawer-closed': closed}" @touchstart="touchStart" @@ -111,16 +112,32 @@ height: 100%; display: flex; align-items: stretch; + transition-duration: 0s; + transition-property: transform; } .side-drawer-container-open { + transform: translate(0%); +} + +.side-drawer-container-closed { + transition-delay: 0.35s; + transform: translate(-100%); +} + +.side-drawer-darken { + top: 0; + left: 0; + width: 100vw; + height: 100vh; + position: fixed; + z-index: -1; transition: 0.35s; transition-property: background-color; background-color: rgba(0, 0, 0, 0.5); } -.side-drawer-container-closed { - left: -100%; +.side-drawer-darken-closed { background-color: rgba(0, 0, 0, 0); } @@ -130,8 +147,9 @@ .side-drawer { overflow-x: hidden; - transition: 0.35s; transition-timing-function: cubic-bezier(0, 1, 0.5, 1); + transition: 0.35s; + transition-property: transform; margin: 0 0 0 -100px; padding: 0 0 1em 100px; width: 80%; diff --git a/src/components/status/status.js b/src/components/status/status.js index c90da6d4..550fe76f 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -310,7 +310,6 @@ const Status = { this.replying = !this.replying }, gotoOriginal (id) { - // only handled by conversation, not status_or_conversation if (this.inConversation) { this.$emit('goto', id) } diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 1f6d0325..1f415534 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -12,7 +12,7 @@ </div> </template> <template v-else> - <div v-if="retweet && !noHeading" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info"> + <div v-if="retweet && !noHeading && !inConversation" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info"> <UserAvatar class="media-left" v-if="retweet" :betterShadow="betterShadow" :src="statusoid.user.profile_image_url_original"/> <div class="media-body faint"> <span class="user-name"> @@ -24,7 +24,7 @@ </div> </div> - <div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet }]" :style="[ userStyle ]" class="media status"> + <div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet && !inConversation }]" :style="[ userStyle ]" class="media status"> <div v-if="!noHeading" class="media-left"> <router-link :to="userProfileLink" @click.stop.prevent.capture.native="toggleUserExpanded"> <UserAvatar :compact="compact" :betterShadow="betterShadow" :src="status.user.profile_image_url_original"/> @@ -135,9 +135,8 @@ <div v-if="!noHeading && !isPreview" class='status-actions media-body'> <div v-if="loggedIn"> - <a href="#" v-on:click.prevent="toggleReplying" :title="$t('tool_tip.reply')"> - <i class="button-icon icon-reply" :class="{'icon-reply-active': replying}"></i> - </a> + <i class="button-icon icon-reply" v-on:click.prevent="toggleReplying" :title="$t('tool_tip.reply')" :class="{'icon-reply-active': replying}"></i> + <span v-if="status.replies_count > 0">{{status.replies_count}}</span> </div> <retweet-button :visibility='status.visibility' :loggedIn='loggedIn' :status='status'></retweet-button> <favorite-button :loggedIn='loggedIn' :status='status'></favorite-button> @@ -551,6 +550,7 @@ $status-margin: 0.75em; .icon-reply:hover { color: $fallback--cBlue; color: var(--cBlue, $fallback--cBlue); + cursor: pointer; } .icon-reply.icon-reply-active { diff --git a/src/components/status_or_conversation/status_or_conversation.js b/src/components/status_or_conversation/status_or_conversation.js deleted file mode 100644 index 441552ca..00000000 --- a/src/components/status_or_conversation/status_or_conversation.js +++ /dev/null @@ -1,22 +0,0 @@ -import Status from '../status/status.vue' -import Conversation from '../conversation/conversation.vue' - -const statusOrConversation = { - props: ['statusoid'], - data () { - return { - expanded: false - } - }, - components: { - Status, - Conversation - }, - methods: { - toggleExpanded () { - this.expanded = !this.expanded - } - } -} - -export default statusOrConversation diff --git a/src/components/status_or_conversation/status_or_conversation.vue b/src/components/status_or_conversation/status_or_conversation.vue deleted file mode 100644 index 9647d5eb..00000000 --- a/src/components/status_or_conversation/status_or_conversation.vue +++ /dev/null @@ -1,14 +0,0 @@ -<template> - <div> - <conversation v-if="expanded" @toggleExpanded="toggleExpanded" :collapsable="true" :statusoid="statusoid"></conversation> - <status v-if="!expanded" @toggleExpanded="toggleExpanded" :expandable="true" :inConversation="false" :focused="false" :statusoid="statusoid"></status> - </div> -</template> - -<script src="./status_or_conversation.js"></script> - -<style lang="scss"> - .spacer { - height: 1em - } -</style> diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js index c45f8947..1da7d5cc 100644 --- a/src/components/timeline/timeline.js +++ b/src/components/timeline/timeline.js @@ -1,6 +1,6 @@ import Status from '../status/status.vue' import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js' -import StatusOrConversation from '../status_or_conversation/status_or_conversation.vue' +import Conversation from '../conversation/conversation.vue' import { throttle } from 'lodash' const Timeline = { @@ -43,7 +43,7 @@ const Timeline = { }, components: { Status, - StatusOrConversation + Conversation }, created () { const store = this.$store diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue index 8f28d65c..e0a34bd1 100644 --- a/src/components/timeline/timeline.vue +++ b/src/components/timeline/timeline.vue @@ -16,7 +16,13 @@ </div> <div :class="classes.body"> <div class="timeline"> - <status-or-conversation v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status" class="status-fadein"></status-or-conversation> + <conversation + v-for="status in timeline.visibleStatuses" + class="status-fadein" + :key="status.id" + :statusoid="status" + :collapsable="true" + /> </div> </div> <div :class="classes.footer"> |
