diff options
Diffstat (limited to 'src/components')
20 files changed, 277 insertions, 192 deletions
diff --git a/src/components/conversation-page/conversation-page.js b/src/components/conversation-page/conversation-page.js index 1da70ce9..8f996be1 100644 --- a/src/components/conversation-page/conversation-page.js +++ b/src/components/conversation-page/conversation-page.js @@ -5,12 +5,8 @@ const conversationPage = { Conversation }, computed: { - statusoid () { - const id = this.$route.params.id - const statuses = this.$store.state.statuses.allStatusesObject - const status = statuses[id] - - return status + statusId () { + return this.$route.params.id } } } diff --git a/src/components/conversation-page/conversation-page.vue b/src/components/conversation-page/conversation-page.vue index 532f785c..8cc0a55f 100644 --- a/src/components/conversation-page/conversation-page.vue +++ b/src/components/conversation-page/conversation-page.vue @@ -2,7 +2,7 @@ <conversation :collapsable="false" is-page="true" - :statusoid="statusoid" + :status-id="statusId" /> </template> diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 49fa8612..72ee9c39 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -1,4 +1,4 @@ -import { reduce, filter, findIndex, clone } from 'lodash' +import { reduce, filter, findIndex, clone, get } from 'lodash' import Status from '../status/status.vue' const sortById = (a, b) => { @@ -39,10 +39,11 @@ const conversation = { } }, props: [ - 'statusoid', + 'statusId', 'collapsable', 'isPage', - 'pinnedStatusIdsObject' + 'pinnedStatusIdsObject', + 'inProfile' ], created () { if (this.isPage) { @@ -51,21 +52,17 @@ const conversation = { }, computed: { status () { - return this.statusoid + return this.$store.state.statuses.allStatusesObject[this.statusId] }, - statusId () { - if (this.statusoid.retweeted_status) { - return this.statusoid.retweeted_status.id + originalStatusId () { + if (this.status.retweeted_status) { + return this.status.retweeted_status.id } else { - return this.statusoid.id + return this.statusId } }, conversationId () { - if (this.statusoid.retweeted_status) { - return this.statusoid.retweeted_status.statusnet_conversation_id - } else { - return this.statusoid.statusnet_conversation_id - } + return this.getConversationId(this.statusId) }, conversation () { if (!this.status) { @@ -77,7 +74,7 @@ const conversation = { } const conversation = clone(this.$store.state.statuses.conversationsObject[this.conversationId]) - const statusIndex = findIndex(conversation, { id: this.statusId }) + const statusIndex = findIndex(conversation, { id: this.originalStatusId }) if (statusIndex !== -1) { conversation[statusIndex] = this.status } @@ -110,7 +107,15 @@ const conversation = { Status }, watch: { - status: 'fetchConversation', + statusId (newVal, oldVal) { + const newConversationId = this.getConversationId(newVal) + const oldConversationId = this.getConversationId(oldVal) + if (newConversationId && oldConversationId && newConversationId === oldConversationId) { + this.setHighlight(this.originalStatusId) + } else { + this.fetchConversation() + } + }, expanded (value) { if (value) { this.fetchConversation() @@ -120,24 +125,25 @@ const conversation = { methods: { fetchConversation () { if (this.status) { - this.$store.state.api.backendInteractor.fetchConversation({ id: this.status.id }) + this.$store.state.api.backendInteractor.fetchConversation({ id: this.statusId }) .then(({ ancestors, descendants }) => { this.$store.dispatch('addNewStatuses', { statuses: ancestors }) this.$store.dispatch('addNewStatuses', { statuses: descendants }) + this.setHighlight(this.originalStatusId) }) - .then(() => this.setHighlight(this.statusId)) } else { - const id = this.$route.params.id - this.$store.state.api.backendInteractor.fetchStatus({ id }) - .then((status) => this.$store.dispatch('addNewStatuses', { statuses: [status] })) - .then(() => this.fetchConversation()) + this.$store.state.api.backendInteractor.fetchStatus({ id: this.statusId }) + .then((status) => { + this.$store.dispatch('addNewStatuses', { statuses: [status] }) + this.fetchConversation() + }) } }, getReplies (id) { return this.replies[id] || [] }, focused (id) { - return (this.isExpanded) && id === this.status.id + return (this.isExpanded) && id === this.statusId }, setHighlight (id) { if (!id) return @@ -149,6 +155,10 @@ const conversation = { }, toggleExpanded () { this.expanded = !this.expanded + }, + getConversationId (statusId) { + const status = this.$store.state.statuses.allStatusesObject[statusId] + return get(status, 'retweeted_status.statusnet_conversation_id', get(status, 'statusnet_conversation_id')) } } } diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index f184c071..0f1de55f 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -26,6 +26,7 @@ :in-conversation="isExpanded" :highlight="getHighlight()" :replies="getReplies(status.id)" + :in-profile="inProfile" class="status-fadein panel-body" @goto="setHighlight" @toggleExpanded="toggleExpanded" diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index ed0f3aa4..6781a4f8 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -10,14 +10,14 @@ <div slot="popover"> <div class="dropdown-menu"> <button - v-if="canMute && !status.muted" + v-if="canMute && !status.thread_muted" class="dropdown-item dropdown-item-icon" @click.prevent="muteConversation" > <i class="icon-eye-off" /><span>{{ $t("status.mute_conversation") }}</span> </button> <button - v-if="canMute && status.muted" + v-if="canMute && status.thread_muted" class="dropdown-item dropdown-item-icon" @click.prevent="unmuteConversation" > diff --git a/src/components/mobile_post_status_modal/mobile_post_status_modal.js b/src/components/mobile_post_status_button/mobile_post_status_button.js index 3cec23c6..3e77148a 100644 --- a/src/components/mobile_post_status_modal/mobile_post_status_modal.js +++ b/src/components/mobile_post_status_button/mobile_post_status_button.js @@ -1,14 +1,9 @@ -import PostStatusForm from '../post_status_form/post_status_form.vue' import { debounce } from 'lodash' -const MobilePostStatusModal = { - components: { - PostStatusForm - }, +const MobilePostStatusButton = { data () { return { hidden: false, - postFormOpen: false, scrollingDown: false, inputActive: false, oldScrollPos: 0, @@ -28,8 +23,8 @@ const MobilePostStatusModal = { window.removeEventListener('resize', this.handleOSK) }, computed: { - currentUser () { - return this.$store.state.users.currentUser + isLoggedIn () { + return !!this.$store.state.users.currentUser }, isHidden () { return this.autohideFloatingPostButton && (this.hidden || this.inputActive) @@ -57,17 +52,7 @@ const MobilePostStatusModal = { window.removeEventListener('scroll', this.handleScrollEnd) }, openPostForm () { - this.postFormOpen = true - this.hidden = true - - const el = this.$el.querySelector('textarea') - this.$nextTick(function () { - el.focus() - }) - }, - closePostForm () { - this.postFormOpen = false - this.hidden = false + this.$store.dispatch('openPostStatusModal') }, handleOSK () { // This is a big hack: we're guessing from changed window sizes if the @@ -105,4 +90,4 @@ const MobilePostStatusModal = { } } -export default MobilePostStatusModal +export default MobilePostStatusButton diff --git a/src/components/mobile_post_status_modal/mobile_post_status_modal.vue b/src/components/mobile_post_status_button/mobile_post_status_button.vue index b6d7d3ba..9cf45de3 100644 --- a/src/components/mobile_post_status_modal/mobile_post_status_modal.vue +++ b/src/components/mobile_post_status_button/mobile_post_status_button.vue @@ -1,23 +1,5 @@ <template> - <div v-if="currentUser"> - <div - v-show="postFormOpen" - class="post-form-modal-view modal-view" - @click="closePostForm" - > - <div - class="post-form-modal-panel panel" - @click.stop="" - > - <div class="panel-heading"> - {{ $t('post_status.new_status') }} - </div> - <PostStatusForm - class="panel-body" - @posted="closePostForm" - /> - </div> - </div> + <div v-if="isLoggedIn"> <button class="new-status-button" :class="{ 'hidden': isHidden }" @@ -28,27 +10,11 @@ </div> </template> -<script src="./mobile_post_status_modal.js"></script> +<script src="./mobile_post_status_button.js"></script> <style lang="scss"> @import '../../_variables.scss'; -.post-form-modal-view { - align-items: flex-start; -} - -.post-form-modal-panel { - flex-shrink: 0; - margin-top: 25%; - margin-bottom: 2em; - width: 100%; - max-width: 700px; - - @media (orientation: landscape) { - margin-top: 8%; - } -} - .new-status-button { width: 5em; height: 5em; diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 896c6d52..8e817f3b 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -9,7 +9,8 @@ const Notification = { data () { return { userExpanded: false, - betterShadow: this.$store.state.interface.browserSupport.cssFilter + betterShadow: this.$store.state.interface.browserSupport.cssFilter, + unmuted: false } }, props: [ 'notification' ], @@ -23,11 +24,14 @@ const Notification = { toggleUserExpanded () { this.userExpanded = !this.userExpanded }, - userProfileLink (user) { + generateUserProfileLink (user) { return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) }, getUser (notification) { return this.$store.state.users.usersObject[notification.from_profile.id] + }, + toggleMute () { + this.unmuted = !this.unmuted } }, computed: { @@ -47,6 +51,12 @@ const Notification = { return this.userInStore } return this.notification.from_profile + }, + userProfileLink () { + return this.generateUserProfileLink(this.user) + }, + needMute () { + return this.user.muted } } } diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index bafcd026..1f192c77 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -4,104 +4,126 @@ :compact="true" :statusoid="notification.status" /> - <div - v-else - class="non-mention" - :class="[userClass, { highlighted: userStyle }]" - :style="[ userStyle ]" - > - <a - class="avatar-container" - :href="notification.from_profile.statusnet_profile_url" - @click.stop.prevent.capture="toggleUserExpanded" + <div v-else> + <div + v-if="needMute && !unmuted" + class="container muted" > - <UserAvatar - :compact="true" - :better-shadow="betterShadow" - :user="notification.from_profile" - /> - </a> - <div class="notification-right"> - <UserCard - v-if="userExpanded" - :user="getUser(notification)" - :rounded="true" - :bordered="true" - /> - <span class="notification-details"> - <div class="name-and-action"> - <!-- eslint-disable vue/no-v-html --> - <span - v-if="!!notification.from_profile.name_html" - class="username" - :title="'@'+notification.from_profile.screen_name" - v-html="notification.from_profile.name_html" - /> - <!-- eslint-enable vue/no-v-html --> - <span - v-else - class="username" - :title="'@'+notification.from_profile.screen_name" - >{{ notification.from_profile.name }}</span> - <span v-if="notification.type === 'like'"> - <i class="fa icon-star lit" /> - <small>{{ $t('notifications.favorited_you') }}</small> - </span> - <span v-if="notification.type === 'repeat'"> - <i - class="fa icon-retweet lit" - :title="$t('tool_tip.repeat')" + <small> + <router-link :to="userProfileLink"> + {{ notification.from_profile.screen_name }} + </router-link> + </small> + <a + href="#" + class="unmute" + @click.prevent="toggleMute" + ><i class="button-icon icon-eye-off" /></a> + </div> + <div + v-else + class="non-mention" + :class="[userClass, { highlighted: userStyle }]" + :style="[ userStyle ]" + > + <a + class="avatar-container" + :href="notification.from_profile.statusnet_profile_url" + @click.stop.prevent.capture="toggleUserExpanded" + > + <UserAvatar + :compact="true" + :better-shadow="betterShadow" + :user="notification.from_profile" + /> + </a> + <div class="notification-right"> + <UserCard + v-if="userExpanded" + :user="getUser(notification)" + :rounded="true" + :bordered="true" + /> + <span class="notification-details"> + <div class="name-and-action"> + <!-- eslint-disable vue/no-v-html --> + <span + v-if="!!notification.from_profile.name_html" + class="username" + :title="'@'+notification.from_profile.screen_name" + v-html="notification.from_profile.name_html" /> - <small>{{ $t('notifications.repeated_you') }}</small> - </span> - <span v-if="notification.type === 'follow'"> - <i class="fa icon-user-plus lit" /> - <small>{{ $t('notifications.followed_you') }}</small> - </span> - </div> + <!-- eslint-enable vue/no-v-html --> + <span + v-else + class="username" + :title="'@'+notification.from_profile.screen_name" + >{{ notification.from_profile.name }}</span> + <span v-if="notification.type === 'like'"> + <i class="fa icon-star lit" /> + <small>{{ $t('notifications.favorited_you') }}</small> + </span> + <span v-if="notification.type === 'repeat'"> + <i + class="fa icon-retweet lit" + :title="$t('tool_tip.repeat')" + /> + <small>{{ $t('notifications.repeated_you') }}</small> + </span> + <span v-if="notification.type === 'follow'"> + <i class="fa icon-user-plus lit" /> + <small>{{ $t('notifications.followed_you') }}</small> + </span> + </div> + <div + v-if="notification.type === 'follow'" + class="timeago" + > + <span class="faint"> + <Timeago + :time="notification.created_at" + :auto-update="240" + /> + </span> + </div> + <div + v-else + class="timeago" + > + <router-link + v-if="notification.status" + :to="{ name: 'conversation', params: { id: notification.status.id } }" + class="faint-link" + > + <Timeago + :time="notification.created_at" + :auto-update="240" + /> + </router-link> + </div> + <a + v-if="needMute" + href="#" + @click.prevent="toggleMute" + ><i class="button-icon icon-eye-off" /></a> + </span> <div v-if="notification.type === 'follow'" - class="timeago" - > - <span class="faint"> - <Timeago - :time="notification.created_at" - :auto-update="240" - /> - </span> - </div> - <div - v-else - class="timeago" + class="follow-text" > - <router-link - v-if="notification.status" - :to="{ name: 'conversation', params: { id: notification.status.id } }" - class="faint-link" - > - <Timeago - :time="notification.created_at" - :auto-update="240" - /> + <router-link :to="userProfileLink"> + @{{ notification.from_profile.screen_name }} </router-link> </div> - </span> - <div - v-if="notification.type === 'follow'" - class="follow-text" - > - <router-link :to="userProfileLink(notification.from_profile)"> - @{{ notification.from_profile.screen_name }} - </router-link> + <template v-else> + <status + class="faint" + :compact="true" + :statusoid="notification.action" + :no-heading="true" + /> + </template> </div> - <template v-else> - <status - class="faint" - :compact="true" - :statusoid="notification.action" - :no-heading="true" - /> - </template> </div> </div> </template> diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 622d12f4..71876b14 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -33,7 +33,6 @@ .notification { box-sizing: border-box; - display: flex; border-bottom: 1px solid; border-color: $fallback--border; border-color: var(--border, $fallback--border); @@ -47,6 +46,10 @@ } } + .muted { + padding: .25em .6em; + } + .non-mention { display: flex; flex: 1; diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index 40bbf6d4..dc4b419c 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -8,7 +8,7 @@ import fileTypeService from '../../services/file_type/file_type.service.js' import { reject, map, uniqBy } from 'lodash' import suggestor from '../emoji-input/suggestor.js' -const buildMentionsString = ({ user, attentions }, currentUser) => { +const buildMentionsString = ({ user, attentions = [] }, currentUser) => { let allAttentions = [...attentions] allAttentions.unshift(user) diff --git a/src/components/post_status_modal/post_status_modal.js b/src/components/post_status_modal/post_status_modal.js new file mode 100644 index 00000000..1033ba11 --- /dev/null +++ b/src/components/post_status_modal/post_status_modal.js @@ -0,0 +1,32 @@ +import PostStatusForm from '../post_status_form/post_status_form.vue' + +const PostStatusModal = { + components: { + PostStatusForm + }, + computed: { + isLoggedIn () { + return !!this.$store.state.users.currentUser + }, + isOpen () { + return this.isLoggedIn && this.$store.state.postStatus.modalActivated + }, + params () { + return this.$store.state.postStatus.params || {} + } + }, + watch: { + isOpen (val) { + if (val) { + this.$nextTick(() => this.$el.querySelector('textarea').focus()) + } + } + }, + methods: { + closeModal () { + this.$store.dispatch('closePostStatusModal') + } + } +} + +export default PostStatusModal diff --git a/src/components/post_status_modal/post_status_modal.vue b/src/components/post_status_modal/post_status_modal.vue new file mode 100644 index 00000000..3f8eec69 --- /dev/null +++ b/src/components/post_status_modal/post_status_modal.vue @@ -0,0 +1,43 @@ +<template> + <div + v-if="isOpen" + class="post-form-modal-view modal-view" + @click="closeModal" + > + <div + class="post-form-modal-panel panel" + @click.stop="" + > + <div class="panel-heading"> + {{ $t('post_status.new_status') }} + </div> + <PostStatusForm + class="panel-body" + v-bind="params" + @posted="closeModal" + /> + </div> + </div> +</template> + +<script src="./post_status_modal.js"></script> + +<style lang="scss"> +@import '../../_variables.scss'; + +.post-form-modal-view { + align-items: flex-start; +} + +.post-form-modal-panel { + flex-shrink: 0; + margin-top: 25%; + margin-bottom: 2em; + width: 100%; + max-width: 700px; + + @media (orientation: landscape) { + margin-top: 8%; + } +} +</style> diff --git a/src/components/status/status.js b/src/components/status/status.js index 502d9583..d17ba318 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -29,7 +29,8 @@ const Status = { 'isPreview', 'noHeading', 'inlineExpanded', - 'showPinned' + 'showPinned', + 'inProfile' ], data () { return { @@ -117,7 +118,7 @@ const Status = { return hits }, - muted () { return !this.unmuted && (this.status.user.muted || this.muteWordHits.length > 0) }, + muted () { return !this.unmuted && ((!this.inProfile && this.status.user.muted) || (!this.inConversation && this.status.thread_muted) || this.muteWordHits.length > 0) }, hideFilteredStatuses () { return typeof this.$store.state.config.hideFilteredStatuses === 'undefined' ? this.$store.state.instance.hideFilteredStatuses diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js index 8df48f7f..0594576c 100644 --- a/src/components/timeline/timeline.js +++ b/src/components/timeline/timeline.js @@ -25,7 +25,8 @@ const Timeline = { 'tag', 'embedded', 'count', - 'pinnedStatusIds' + 'pinnedStatusIds', + 'inProfile' ], data () { return { diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue index 4ad51714..f1d3903a 100644 --- a/src/components/timeline/timeline.vue +++ b/src/components/timeline/timeline.vue @@ -33,9 +33,10 @@ v-if="timeline.statusesObject[statusId]" :key="statusId + '-pinned'" class="status-fadein" - :statusoid="timeline.statusesObject[statusId]" + :status-id="statusId" :collapsable="true" :pinned-status-ids-object="pinnedStatusIdsObject" + :in-profile="inProfile" /> </template> <template v-for="status in timeline.visibleStatuses"> @@ -43,8 +44,9 @@ v-if="!excludedStatusIdsObject[status.id]" :key="status.id" class="status-fadein" - :statusoid="status" + :status-id="status.id" :collapsable="true" + :in-profile="inProfile" /> </template> </div> diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index 82d3b835..0c200ad1 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -11,7 +11,6 @@ export default { data () { return { followRequestInProgress: false, - followRequestSent: false, hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined' ? this.$store.state.instance.hideUserStats : this.$store.state.config.hideUserStats, @@ -112,9 +111,8 @@ export default { followUser () { const store = this.$store this.followRequestInProgress = true - requestFollow(this.user, store).then(({ sent }) => { + requestFollow(this.user, store).then(() => { this.followRequestInProgress = false - this.followRequestSent = sent }) }, unfollowUser () { @@ -170,6 +168,9 @@ export default { } this.$store.dispatch('setMedia', [attachment]) this.$store.dispatch('setCurrent', attachment) + }, + mentionUser () { + this.$store.dispatch('openPostStatusModal', { replyTo: true, repliedUser: this.user }) } } } diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index fc18e240..f25d16d3 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -135,13 +135,13 @@ <button class="btn btn-default btn-block" :disabled="followRequestInProgress" - :title="followRequestSent ? $t('user_card.follow_again') : ''" + :title="user.requested ? $t('user_card.follow_again') : ''" @click="followUser" > <template v-if="followRequestInProgress"> {{ $t('user_card.follow_progress') }} </template> - <template v-else-if="followRequestSent"> + <template v-else-if="user.requested"> {{ $t('user_card.follow_sent') }} </template> <template v-else> @@ -190,6 +190,15 @@ <div> <button + class="btn btn-default btn-block" + @click="mentionUser" + > + {{ $t('user_card.mention') }} + </button> + </div> + + <div> + <button v-if="user.muted" class="btn btn-default btn-block pressed" @click="unmuteUser" diff --git a/src/components/user_panel/user_panel.vue b/src/components/user_panel/user_panel.vue index c92630e3..e859d612 100644 --- a/src/components/user_panel/user_panel.vue +++ b/src/components/user_panel/user_panel.vue @@ -11,7 +11,7 @@ rounded="top" /> <div class="panel-footer"> - <post-status-form v-if="user" /> + <post-status-form /> </div> </div> <auth-form diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue index 42516916..14082e83 100644 --- a/src/components/user_profile/user_profile.vue +++ b/src/components/user_profile/user_profile.vue @@ -26,6 +26,7 @@ timeline-name="user" :user-id="userId" :pinned-status-ids="user.pinnedStatusIds" + :in-profile="true" /> <div v-if="followsTabVisible" @@ -69,6 +70,7 @@ timeline-name="media" :timeline="media" :user-id="userId" + :in-profile="true" /> <Timeline v-if="isUs" @@ -79,6 +81,7 @@ :title="$t('user_card.favorites')" timeline-name="favorites" :timeline="favorites" + :in-profile="true" /> </tab-switcher> </div> |
