diff options
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/conversation/conversation.js | 3 | ||||
| -rw-r--r-- | src/components/conversation/conversation.vue | 1 | ||||
| -rw-r--r-- | src/components/delete_button/delete_button.js | 21 | ||||
| -rw-r--r-- | src/components/delete_button/delete_button.vue | 21 | ||||
| -rw-r--r-- | src/components/extra_buttons/extra_buttons.js | 61 | ||||
| -rw-r--r-- | src/components/extra_buttons/extra_buttons.vue | 47 | ||||
| -rw-r--r-- | src/components/moderation_tools/moderation_tools.vue | 8 | ||||
| -rw-r--r-- | src/components/status/status.js | 17 | ||||
| -rw-r--r-- | src/components/status/status.vue | 19 | ||||
| -rw-r--r-- | src/components/user_profile/user_profile.js | 6 | ||||
| -rw-r--r-- | src/components/user_profile/user_profile.vue | 32 |
11 files changed, 177 insertions, 59 deletions
diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index ffeb7244..b3074590 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -41,7 +41,8 @@ const conversation = { props: [ 'statusoid', 'collapsable', - 'isPage' + 'isPage', + 'showPinned' ], created () { if (this.isPage) { diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index d04ff722..0b4998c3 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -14,6 +14,7 @@ :inlineExpanded="collapsable && isExpanded" :statusoid="status" :expandable='!isExpanded' + :showPinned="showPinned" :focused="focused(status.id)" :inConversation="isExpanded" :highlight="getHighlight()" diff --git a/src/components/delete_button/delete_button.js b/src/components/delete_button/delete_button.js deleted file mode 100644 index 22f24625..00000000 --- a/src/components/delete_button/delete_button.js +++ /dev/null @@ -1,21 +0,0 @@ -const DeleteButton = { - props: [ 'status' ], - methods: { - deleteStatus () { - const confirmed = window.confirm('Do you really want to delete this status?') - if (confirmed) { - this.$store.dispatch('deleteStatus', { id: this.status.id }) - } - } - }, - computed: { - currentUser () { return this.$store.state.users.currentUser }, - canDelete () { - if (!this.currentUser) { return } - const superuser = this.currentUser.rights.moderator || this.currentUser.rights.admin - return superuser || this.status.user.id === this.currentUser.id - } - } -} - -export default DeleteButton diff --git a/src/components/delete_button/delete_button.vue b/src/components/delete_button/delete_button.vue deleted file mode 100644 index f4c91cfd..00000000 --- a/src/components/delete_button/delete_button.vue +++ /dev/null @@ -1,21 +0,0 @@ -<template> - <div v-if="canDelete"> - <a href="#" v-on:click.prevent="deleteStatus()"> - <i class='button-icon icon-cancel delete-status'></i> - </a> - </div> -</template> - -<script src="./delete_button.js" ></script> - -<style lang="scss"> -@import '../../_variables.scss'; - -.icon-cancel,.delete-status { - cursor: pointer; - &:hover { - color: $fallback--cRed; - color: var(--cRed, $fallback--cRed); - } -} -</style> diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js new file mode 100644 index 00000000..f70ecd1d --- /dev/null +++ b/src/components/extra_buttons/extra_buttons.js @@ -0,0 +1,61 @@ +import Popper from 'vue-popperjs/src/component/popper.js.vue' + +const ExtraButtons = { + props: [ 'status' ], + components: { + Popper + }, + data () { + return { + showDropDown: false, + showPopper: true + } + }, + methods: { + deleteStatus () { + this.refreshPopper() + const confirmed = window.confirm(this.$t('status.delete_confirm')) + if (confirmed) { + this.$store.dispatch('deleteStatus', { id: this.status.id }) + } + }, + toggleMenu () { + this.showDropDown = !this.showDropDown + }, + pinStatus () { + this.refreshPopper() + this.$store.dispatch('pinStatus', this.status.id) + .then(() => this.$emit('onSuccess')) + .catch(err => this.$emit('onError', err.error.error)) + }, + unpinStatus () { + this.refreshPopper() + this.$store.dispatch('unpinStatus', this.status.id) + .then(() => this.$emit('onSuccess')) + .catch(err => this.$emit('onError', err.error.error)) + }, + refreshPopper () { + this.showPopper = false + this.showDropDown = false + setTimeout(() => { + this.showPopper = true + }) + } + }, + computed: { + currentUser () { return this.$store.state.users.currentUser }, + canDelete () { + if (!this.currentUser) { return } + const superuser = this.currentUser.rights.moderator || this.currentUser.rights.admin + return superuser || this.status.user.id === this.currentUser.id + }, + ownStatus () { + return this.status.user.id === this.currentUser.id + }, + canPin () { + return this.ownStatus && (this.status.visibility === 'public' || this.status.visibility === 'unlisted') + } + } +} + +export default ExtraButtons diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue new file mode 100644 index 00000000..38e933bb --- /dev/null +++ b/src/components/extra_buttons/extra_buttons.vue @@ -0,0 +1,47 @@ +<template> + <Popper + trigger="click" + @hide='showDropDown = false' + append-to-body + v-if="showPopper" + :options="{ + placement: 'top', + modifiers: { + arrow: { enabled: true }, + offset: { offset: '0, 5px' }, + } + }" + > + <div class="popper-wrapper"> + <div class="dropdown-menu"> + <button class="dropdown-item dropdown-item-icon" @click.prevent="pinStatus" v-if="!status.pinned && canPin"> + <i class="icon-pin"></i><span>{{$t("status.pin")}}</span> + </button> + <button class="dropdown-item dropdown-item-icon" @click.prevent="unpinStatus" v-if="status.pinned && canPin"> + <i class="icon-pin"></i><span>{{$t("status.unpin")}}</span> + </button> + <button class="dropdown-item dropdown-item-icon" @click.prevent="deleteStatus" v-if="canDelete"> + <i class="icon-cancel"></i><span>{{$t("status.delete")}}</span> + </button> + </div> + </div> + <div class="button-icon" slot="reference" @click="toggleMenu"> + <i class='icon-ellipsis' :class="{'icon-clicked': showDropDown}"></i> + </div> + </Popper> +</template> + +<script src="./extra_buttons.js" ></script> + +<style lang="scss"> +@import '../../_variables.scss'; + +.icon-ellipsis { + cursor: pointer; + + &:hover, &.icon-clicked { + color: $fallback--text; + color: var(--text, $fallback--text); + } +} +</style> diff --git a/src/components/moderation_tools/moderation_tools.vue b/src/components/moderation_tools/moderation_tools.vue index c24a2280..c9e3fc78 100644 --- a/src/components/moderation_tools/moderation_tools.vue +++ b/src/components/moderation_tools/moderation_tools.vue @@ -127,6 +127,14 @@ width: 100%; height: 100%; + &-icon { + padding-left: 0.5rem; + + i { + margin-right: 0.25rem; + } + } + &:hover { // TODO: improve the look on breeze themes background-color: $fallback--fg; diff --git a/src/components/status/status.js b/src/components/status/status.js index c01cfe79..5b3d98c3 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -1,7 +1,7 @@ import Attachment from '../attachment/attachment.vue' import FavoriteButton from '../favorite_button/favorite_button.vue' import RetweetButton from '../retweet_button/retweet_button.vue' -import DeleteButton from '../delete_button/delete_button.vue' +import ExtraButtons from '../extra_buttons/extra_buttons.vue' import PostStatusForm from '../post_status_form/post_status_form.vue' import UserCard from '../user_card/user_card.vue' import UserAvatar from '../user_avatar/user_avatar.vue' @@ -26,7 +26,8 @@ const Status = { 'replies', 'isPreview', 'noHeading', - 'inlineExpanded' + 'inlineExpanded', + 'showPinned' ], data () { return { @@ -37,6 +38,7 @@ const Status = { showPreview: false, showingTall: this.inConversation && this.focused, showingLongSubject: false, + error: null, expandingSubject: typeof this.$store.state.config.collapseMessageWithSubject === 'undefined' ? !this.$store.state.instance.collapseMessageWithSubject : !this.$store.state.config.collapseMessageWithSubject, @@ -269,13 +271,16 @@ const Status = { this.statusFromGlobalRepository.rebloggedBy ) return uniqBy(combinedUsers, 'id') + }, + ownStatus () { + return this.status.user.id === this.$store.state.users.currentUser.id } }, components: { Attachment, FavoriteButton, RetweetButton, - DeleteButton, + ExtraButtons, PostStatusForm, UserCard, UserAvatar, @@ -296,6 +301,12 @@ const Status = { return 'icon-globe' } }, + showError (error) { + this.error = error + }, + clearError () { + this.error = undefined + }, linkClicked (event) { let { target } = event if (target.tagName === 'SPAN') { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 21077972..997c1b31 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -1,5 +1,9 @@ <template> <div class="status-el" v-if="!hideStatus" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"> + <div v-if="error" class="alert error"> + {{error}} + <i class="button-icon icon-cancel" @click="clearError"></i> + </div> <template v-if="muted && !isPreview"> <div class="media status container muted"> <small> @@ -12,6 +16,10 @@ </div> </template> <template v-else> + <div v-if="showPinned && statusoid.pinned" class="status-pin"> + <i class="fa icon-pin faint"></i> + <span class="faint">{{$t('status.pinned')}}</span> + </div> <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" :user="statusoid.user"/> <div class="media-body faint"> @@ -95,7 +103,7 @@ v-if="preview" :isPreview="true" :statusoid="preview" - :compact=true + :compact="true" /> <div v-else class="status-preview status-preview-loading"> <i class="icon-spin4 animate-spin"></i> @@ -164,7 +172,7 @@ </div> <retweet-button :visibility='status.visibility' :loggedIn='loggedIn' :status='status'></retweet-button> <favorite-button :loggedIn='loggedIn' :status='status'></favorite-button> - <delete-button :status='status'></delete-button> + <extra-buttons :status="status" @onError="showError" @onSuccess="clearError"></extra-buttons> </div> </div> </div> @@ -199,6 +207,13 @@ $status-margin: 0.75em; max-width: 100%; } +.status-pin { + padding: $status-margin $status-margin 0; + display: flex; + align-items: center; + justify-content: flex-end; +} + .status-preview { position: absolute; max-width: 95%; diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 4eddb8b1..eab330e7 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -2,6 +2,7 @@ import get from 'lodash/get' import UserCard from '../user_card/user_card.vue' import FollowCard from '../follow_card/follow_card.vue' import Timeline from '../timeline/timeline.vue' +import Conversation from '../conversation/conversation.vue' import ModerationTools from '../moderation_tools/moderation_tools.vue' import List from '../list/list.vue' import withLoadMore from '../../hocs/with_load_more/with_load_more' @@ -95,6 +96,8 @@ const UserProfile = { if (this.isUs) { this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId }) } + // Fetch all pinned statuses immediately + this.$store.dispatch('fetchPinnedStatuses', userId) }, cleanUp () { this.$store.dispatch('stopFetching', 'user') @@ -128,7 +131,8 @@ const UserProfile = { FollowerList, FriendList, ModerationTools, - FollowCard + FollowCard, + Conversation } } diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue index 71c625b7..48b774ea 100644 --- a/src/components/user_profile/user_profile.vue +++ b/src/components/user_profile/user_profile.vue @@ -3,16 +3,28 @@ <div v-if="user" class="user-profile panel panel-default"> <UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/> <tab-switcher :renderOnlyFocused="true" ref="tabSwitcher"> - <Timeline - :label="$t('user_card.statuses')" - :disabled="!user.statuses_count" - :count="user.statuses_count" - :embedded="true" - :title="$t('user_profile.timeline_title')" - :timeline="timeline" - :timeline-name="'user'" - :user-id="userId" - /> + <div :label="$t('user_card.statuses')" :disabled="!user.statuses_count"> + <div class="timeline"> + <template v-for="statusId in user.pinnedStatuseIds"> + <Conversation + v-if="timeline.statusesObject[statusId]" + class="status-fadein" + :key="statusId" + :statusoid="timeline.statusesObject[statusId]" + :collapsable="true" + :showPinned="true" + /> + </template> + </div> + <Timeline + :count="user.statuses_count" + :embedded="true" + :title="$t('user_profile.timeline_title')" + :timeline="timeline" + :timeline-name="'user'" + :user-id="userId" + /> + </div> <div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count"> <FriendList :userId="userId"> <template slot="item" slot-scope="{item}"> |
