diff options
Diffstat (limited to 'src/components')
20 files changed, 148 insertions, 100 deletions
diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue index 568e9359..8a02174e 100644 --- a/src/components/basic_user_card/basic_user_card.vue +++ b/src/components/basic_user_card/basic_user_card.vue @@ -87,6 +87,7 @@ &-expanded-content { flex: 1; margin-left: 0.7em; + min-width: 0; } } </style> diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js index 2ec72729..2d05ad39 100644 --- a/src/components/extra_buttons/extra_buttons.js +++ b/src/components/extra_buttons/extra_buttons.js @@ -16,6 +16,16 @@ const ExtraButtons = { this.$store.dispatch('unpinStatus', this.status.id) .then(() => this.$emit('onSuccess')) .catch(err => this.$emit('onError', err.error.error)) + }, + muteConversation () { + this.$store.dispatch('muteConversation', this.status.id) + .then(() => this.$emit('onSuccess')) + .catch(err => this.$emit('onError', err.error.error)) + }, + unmuteConversation () { + this.$store.dispatch('unmuteConversation', this.status.id) + .then(() => this.$emit('onSuccess')) + .catch(err => this.$emit('onError', err.error.error)) } }, computed: { @@ -30,9 +40,6 @@ const ExtraButtons = { }, canPin () { return this.ownStatus && (this.status.visibility === 'public' || this.status.visibility === 'unlisted') - }, - enabled () { - return this.canPin || this.canDelete } } } diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index cdad1666..564d34df 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -1,6 +1,5 @@ <template> <v-popover - v-if="enabled" trigger="click" placement="top" class="extra-button-popover" @@ -10,6 +9,20 @@ <div slot="popover"> <div class="dropdown-menu"> <button + v-if="!status.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="status.muted" + class="dropdown-item dropdown-item-icon" + @click.prevent="unmuteConversation" + > + <i class="icon-eye-off" /><span>{{ $t("status.unmute_conversation") }}</span> + </button> + <button v-if="!status.pinned && canPin" v-close-popover class="dropdown-item dropdown-item-icon" diff --git a/src/components/gallery/gallery.vue b/src/components/gallery/gallery.vue index 6adfb76c..6169d294 100644 --- a/src/components/gallery/gallery.vue +++ b/src/components/gallery/gallery.vue @@ -61,13 +61,17 @@ } &.contain-fit { - img, video { + img, + video, + canvas { object-fit: contain; } } &.cover-fit { - img, video { + img, + video, + canvas { object-fit: cover; } } diff --git a/src/components/instance_specific_panel/instance_specific_panel.js b/src/components/instance_specific_panel/instance_specific_panel.js index 9bb5e945..09e3d055 100644 --- a/src/components/instance_specific_panel/instance_specific_panel.js +++ b/src/components/instance_specific_panel/instance_specific_panel.js @@ -2,9 +2,6 @@ const InstanceSpecificPanel = { computed: { instanceSpecificPanelContent () { return this.$store.state.instance.instanceSpecificPanelContent - }, - show () { - return !this.$store.state.config.hideISP } } } diff --git a/src/components/instance_specific_panel/instance_specific_panel.vue b/src/components/instance_specific_panel/instance_specific_panel.vue index a7cf6b48..7448ca06 100644 --- a/src/components/instance_specific_panel/instance_specific_panel.vue +++ b/src/components/instance_specific_panel/instance_specific_panel.vue @@ -1,8 +1,5 @@ <template> - <div - v-if="show" - class="instance-specific-panel" - > + <div class="instance-specific-panel"> <div class="panel panel-default"> <div class="panel-body"> <!-- eslint-disable vue/no-v-html --> @@ -14,6 +11,3 @@ </template> <script src="./instance_specific_panel.js" ></script> - -<style lang="scss"> -</style> diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js index d4e3cc17..1f8a9de9 100644 --- a/src/components/interactions/interactions.js +++ b/src/components/interactions/interactions.js @@ -13,8 +13,8 @@ const Interactions = { } }, methods: { - onModeSwitch (index, dataset) { - this.filterMode = tabModeDict[dataset.filter] + onModeSwitch (key) { + this.filterMode = tabModeDict[key] } }, components: { diff --git a/src/components/interactions/interactions.vue b/src/components/interactions/interactions.vue index d71c99d5..08cee343 100644 --- a/src/components/interactions/interactions.vue +++ b/src/components/interactions/interactions.vue @@ -10,18 +10,15 @@ :on-switch="onModeSwitch" > <span - data-tab-dummy - data-filter="mentions" + key="mentions" :label="$t('nav.mentions')" /> <span - data-tab-dummy - data-filter="likes+repeats" + key="likes+repeats" :label="$t('interactions.favs_repeats')" /> <span - data-tab-dummy - data-filter="follows" + key="follows" :label="$t('interactions.follows')" /> </tab-switcher> diff --git a/src/components/link-preview/link-preview.js b/src/components/link-preview/link-preview.js index 2f6da55e..444aafbe 100644 --- a/src/components/link-preview/link-preview.js +++ b/src/components/link-preview/link-preview.js @@ -5,6 +5,11 @@ const LinkPreview = { 'size', 'nsfw' ], + data () { + return { + imageLoaded: false + } + }, computed: { useImage () { // Currently BE shoudn't give cards if tagged NSFW, this is a bit paranoid @@ -15,6 +20,15 @@ const LinkPreview = { useDescription () { return this.card.description && /\S/.test(this.card.description) } + }, + created () { + if (this.useImage) { + const newImg = new Image() + newImg.onload = () => { + this.imageLoaded = true + } + newImg.src = this.card.image + } } } diff --git a/src/components/link-preview/link-preview.vue b/src/components/link-preview/link-preview.vue index 493774c2..69171977 100644 --- a/src/components/link-preview/link-preview.vue +++ b/src/components/link-preview/link-preview.vue @@ -7,7 +7,7 @@ rel="noopener" > <div - v-if="useImage" + v-if="useImage && imageLoaded" class="card-image" :class="{ 'small-image': size === 'small' }" > diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js index 9b341a3b..c2bb76ee 100644 --- a/src/components/mobile_nav/mobile_nav.js +++ b/src/components/mobile_nav/mobile_nav.js @@ -1,14 +1,12 @@ import SideDrawer from '../side_drawer/side_drawer.vue' import Notifications from '../notifications/notifications.vue' -import MobilePostStatusModal from '../mobile_post_status_modal/mobile_post_status_modal.vue' import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils' import GestureService from '../../services/gesture_service/gesture_service' const MobileNav = { components: { SideDrawer, - Notifications, - MobilePostStatusModal + Notifications }, data: () => ({ notificationsCloseGesture: undefined, diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue index f67b7ff8..d1c24e56 100644 --- a/src/components/mobile_nav/mobile_nav.vue +++ b/src/components/mobile_nav/mobile_nav.vue @@ -70,7 +70,6 @@ ref="sideDrawer" :logout="logout" /> - <MobilePostStatusModal /> </div> </template> diff --git a/src/components/mobile_post_status_modal/mobile_post_status_modal.vue b/src/components/mobile_post_status_modal/mobile_post_status_modal.vue index 5db7584b..b6d7d3ba 100644 --- a/src/components/mobile_post_status_modal/mobile_post_status_modal.vue +++ b/src/components/mobile_post_status_modal/mobile_post_status_modal.vue @@ -34,14 +34,19 @@ @import '../../_variables.scss'; .post-form-modal-view { - max-height: 100%; - display: block; + align-items: flex-start; } .post-form-modal-panel { flex-shrink: 0; - margin: 25% 0 4em 0; + margin-top: 25%; + margin-bottom: 2em; width: 100%; + max-width: 700px; + + @media (orientation: landscape) { + margin-top: 8%; + } } .new-status-button { diff --git a/src/components/search/search.js b/src/components/search/search.js index b434e127..8e903052 100644 --- a/src/components/search/search.js +++ b/src/components/search/search.js @@ -75,8 +75,8 @@ const Search = { const length = this[tabName].length return length === 0 ? '' : ` (${length})` }, - onResultTabSwitch (_index, dataset) { - this.currenResultTab = dataset.filter + onResultTabSwitch (key) { + this.currenResultTab = key }, getActiveTab () { if (this.visibleStatuses.length > 0) { diff --git a/src/components/search/search.vue b/src/components/search/search.vue index 4350e672..746bbaa2 100644 --- a/src/components/search/search.vue +++ b/src/components/search/search.vue @@ -31,21 +31,18 @@ <tab-switcher ref="tabSwitcher" :on-switch="onResultTabSwitch" - :custom-active="currenResultTab" + :active-tab="currenResultTab" > <span - data-tab-dummy - data-filter="statuses" + key="statuses" :label="$t('user_card.statuses') + resultCount('visibleStatuses')" /> <span - data-tab-dummy - data-filter="people" + key="people" :label="$t('search.people') + resultCount('users')" /> <span - data-tab-dummy - data-filter="hashtags" + key="hashtags" :label="$t('search.hashtags') + resultCount('hashtags')" /> </tab-switcher> diff --git a/src/components/status/status.js b/src/components/status/status.js index 3c172e5b..502d9583 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -335,7 +335,7 @@ const Status = { return } } - if (target.className.match(/hashtag/)) { + if (target.rel.match(/(?:^|\s)tag(?:$|\s)/) || target.className.match(/hashtag/)) { // Extract tag name from link url const tag = extractTagFromUrl(target.href) if (tag) { diff --git a/src/components/tab_switcher/tab_switcher.js b/src/components/tab_switcher/tab_switcher.js index a5fe019c..08d5d08f 100644 --- a/src/components/tab_switcher/tab_switcher.js +++ b/src/components/tab_switcher/tab_switcher.js @@ -4,12 +4,22 @@ import './tab_switcher.scss' export default Vue.component('tab-switcher', { name: 'TabSwitcher', - props: ['renderOnlyFocused', 'onSwitch', 'customActive'], + props: ['renderOnlyFocused', 'onSwitch', 'activeTab'], data () { return { active: this.$slots.default.findIndex(_ => _.tag) } }, + computed: { + activeIndex () { + // In case of controlled component + if (this.activeTab) { + return this.$slots.default.findIndex(slot => this.activeTab === slot.key) + } else { + return this.active + } + } + }, beforeUpdate () { const currentSlot = this.$slots.default[this.active] if (!currentSlot.tag) { @@ -17,21 +27,13 @@ export default Vue.component('tab-switcher', { } }, methods: { - activateTab (index, dataset) { + activateTab (index) { return () => { if (typeof this.onSwitch === 'function') { - this.onSwitch.call(null, index, this.$slots.default[index].elm.dataset) + this.onSwitch.call(null, this.$slots.default[index].key) } this.active = index } - }, - isActiveTab (index) { - const customActiveIndex = this.$slots.default.findIndex(slot => { - const dataFilter = slot.data && slot.data.attrs && slot.data.attrs['data-filter'] - return this.customActive && this.customActive === dataFilter - }) - - return customActiveIndex > -1 ? customActiveIndex === index : index === this.active } }, render (h) { @@ -41,13 +43,13 @@ export default Vue.component('tab-switcher', { const classesTab = ['tab'] const classesWrapper = ['tab-wrapper'] - if (this.isActiveTab(index)) { + if (this.activeIndex === index) { classesTab.push('active') classesWrapper.push('active') } if (slot.data.attrs.image) { return ( - <div class={ classesWrapper.join(' ')}> + <div class={classesWrapper.join(' ')}> <button disabled={slot.data.attrs.disabled} onClick={this.activateTab(index)} @@ -59,7 +61,7 @@ export default Vue.component('tab-switcher', { ) } return ( - <div class={ classesWrapper.join(' ')}> + <div class={classesWrapper.join(' ')}> <button disabled={slot.data.attrs.disabled} onClick={this.activateTab(index)} @@ -71,7 +73,7 @@ export default Vue.component('tab-switcher', { const contents = this.$slots.default.map((slot, index) => { if (!slot.tag) return - const active = index === this.active + const active = this.activeIndex === index if (this.renderOnlyFocused) { return active ? <div class="active">{slot}</div> diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js index 39b99dac..00055707 100644 --- a/src/components/user_profile/user_profile.js +++ b/src/components/user_profile/user_profile.js @@ -22,21 +22,23 @@ const FriendList = withLoadMore({ additionalPropNames: ['userId'] })(List) +const defaultTabKey = 'statuses' + const UserProfile = { data () { return { error: false, - userId: null + userId: null, + tab: defaultTabKey } }, created () { - // Make sure that timelines used in this page are empty - this.cleanUp() const routeParams = this.$route.params this.load(routeParams.name || routeParams.id) + this.tab = get(this.$route, 'query.tab', defaultTabKey) }, destroyed () { - this.cleanUp() + this.stopFetching() }, computed: { timeline () { @@ -67,17 +69,36 @@ const UserProfile = { }, methods: { load (userNameOrId) { + const startFetchingTimeline = (timeline, userId) => { + // Clear timeline only if load another user's profile + if (userId !== this.$store.state.statuses.timelines[timeline].userId) { + this.$store.commit('clearTimeline', { timeline }) + } + this.$store.dispatch('startFetchingTimeline', { timeline, userId }) + } + + const loadById = (userId) => { + this.userId = userId + startFetchingTimeline('user', userId) + startFetchingTimeline('media', userId) + if (this.isUs) { + startFetchingTimeline('favorites', userId) + } + // Fetch all pinned statuses immediately + this.$store.dispatch('fetchPinnedStatuses', userId) + } + + // Reset view + this.userId = null + this.error = false + // Check if user data is already loaded in store const user = this.$store.getters.findUser(userNameOrId) if (user) { - this.userId = user.id - this.fetchTimelines() + loadById(user.id) } else { this.$store.dispatch('fetchUser', userNameOrId) - .then(({ id }) => { - this.userId = id - this.fetchTimelines() - }) + .then(({ id }) => loadById(id)) .catch((reason) => { const errorMessage = get(reason, 'error.error') if (errorMessage === 'No user with such user_id') { // Known error @@ -90,40 +111,33 @@ const UserProfile = { }) } }, - fetchTimelines () { - const userId = this.userId - this.$store.dispatch('startFetchingTimeline', { timeline: 'user', userId }) - this.$store.dispatch('startFetchingTimeline', { timeline: 'media', userId }) - if (this.isUs) { - this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId }) - } - // Fetch all pinned statuses immediately - this.$store.dispatch('fetchPinnedStatuses', userId) - }, - cleanUp () { + stopFetching () { this.$store.dispatch('stopFetching', 'user') this.$store.dispatch('stopFetching', 'favorites') this.$store.dispatch('stopFetching', 'media') - this.$store.commit('clearTimeline', { timeline: 'user' }) - this.$store.commit('clearTimeline', { timeline: 'favorites' }) - this.$store.commit('clearTimeline', { timeline: 'media' }) + }, + switchUser (userNameOrId) { + this.stopFetching() + this.load(userNameOrId) + }, + onTabSwitch (tab) { + this.tab = tab + this.$router.replace({ query: { tab } }) } }, watch: { '$route.params.id': function (newVal) { if (newVal) { - this.cleanUp() - this.load(newVal) + this.switchUser(newVal) } }, '$route.params.name': function (newVal) { if (newVal) { - this.cleanUp() - this.load(newVal) + this.switchUser(newVal) } }, - $route () { - this.$refs.tabSwitcher.activateTab(0)() + '$route.query': function (newVal) { + this.tab = newVal.tab || defaultTabKey } }, components: { diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue index cffa28f1..42516916 100644 --- a/src/components/user_profile/user_profile.vue +++ b/src/components/user_profile/user_profile.vue @@ -12,22 +12,24 @@ rounded="top" /> <tab-switcher - ref="tabSwitcher" + :active-tab="tab" :render-only-focused="true" + :on-switch="onTabSwitch" > - <div :label="$t('user_card.statuses')"> - <Timeline - :count="user.statuses_count" - :embedded="true" - :title="$t('user_profile.timeline_title')" - :timeline="timeline" - timeline-name="user" - :user-id="userId" - :pinned-status-ids="user.pinnedStatusIds" - /> - </div> + <Timeline + key="statuses" + :label="$t('user_card.statuses')" + :count="user.statuses_count" + :embedded="true" + :title="$t('user_profile.timeline_title')" + :timeline="timeline" + timeline-name="user" + :user-id="userId" + :pinned-status-ids="user.pinnedStatusIds" + /> <div v-if="followsTabVisible" + key="followees" :label="$t('user_card.followees')" :disabled="!user.friends_count" > @@ -42,6 +44,7 @@ </div> <div v-if="followersTabVisible" + key="followers" :label="$t('user_card.followers')" :disabled="!user.followers_count" > @@ -58,6 +61,7 @@ </FollowerList> </div> <Timeline + key="media" :label="$t('user_card.media')" :disabled="!media.visibleStatuses.length" :embedded="true" @@ -68,6 +72,7 @@ /> <Timeline v-if="isUs" + key="favorites" :label="$t('user_card.favorites')" :disabled="!favorites.visibleStatuses.length" :embedded="true" diff --git a/src/components/who_to_follow/who_to_follow.js b/src/components/who_to_follow/who_to_follow.js index f8100257..8fab6c4d 100644 --- a/src/components/who_to_follow/who_to_follow.js +++ b/src/components/who_to_follow/who_to_follow.js @@ -21,7 +21,8 @@ const WhoToFollow = { name: i.display_name, screen_name: i.acct, profile_image_url: i.avatar || '/images/avi.png', - profile_image_url_original: i.avatar || '/images/avi.png' + profile_image_url_original: i.avatar || '/images/avi.png', + statusnet_profile_url: i.url } this.users.push(user) |
