diff options
| author | Henry Jameson <me@hjkos.com> | 2020-01-28 20:44:13 +0200 |
|---|---|---|
| committer | Henry Jameson <me@hjkos.com> | 2020-01-28 20:44:13 +0200 |
| commit | f0c4bb1193f71cb93546be7e8f41236c4c192f85 (patch) | |
| tree | 26c35a98a8aa80279a1d8d938e41629a774fda37 /src/components | |
| parent | b63e679a31a573c30868477f17322d6ed040af58 (diff) | |
| parent | c54111797ae1058e59931b2d1f12e6ab6a6f96a9 (diff) | |
Merge remote-tracking branch 'upstream/develop' into themes-accent
* upstream/develop: (33 commits)
add emoji reactions to changelog
fix emoji reaction classes broken in develop
review changes
Fix password and email update
remove unnecessary anonymous function
Apply suggestion to src/services/api/api.service.js
remove logs/commented code
remove favs count from react button
remove mock data
change emoji reactions to use new format
Added polyfills for EventTarget (needed for Safari) and CustomEvent (needed for IE)
Fix missing TWKN when logged in, but server is set to private mode.
Fix follower request fetching
Add domain mutes to changelog
Implement domain mutes v2
change changelog to reflect actual release history of frontend
Fix #750 , fix error messages and captcha resetting
Optimize Notifications Rendering
update CHANGELOG
Use last seen notif instead of first unseen notif for sinceId
...
Diffstat (limited to 'src/components')
27 files changed, 503 insertions, 72 deletions
diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 08283fff..45fb2bf6 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -150,6 +150,7 @@ const conversation = { if (!id) return this.highlight = id this.$store.dispatch('fetchFavsAndRepeats', id) + this.$store.dispatch('fetchEmojiReactionsBy', id) }, getHighlight () { return this.isExpanded ? this.highlight : null diff --git a/src/components/domain_mute_card/domain_mute_card.js b/src/components/domain_mute_card/domain_mute_card.js new file mode 100644 index 00000000..c8e838ba --- /dev/null +++ b/src/components/domain_mute_card/domain_mute_card.js @@ -0,0 +1,15 @@ +import ProgressButton from '../progress_button/progress_button.vue' + +const DomainMuteCard = { + props: ['domain'], + components: { + ProgressButton + }, + methods: { + unmuteDomain () { + return this.$store.dispatch('unmuteDomain', this.domain) + } + } +} + +export default DomainMuteCard diff --git a/src/components/domain_mute_card/domain_mute_card.vue b/src/components/domain_mute_card/domain_mute_card.vue new file mode 100644 index 00000000..567d81c5 --- /dev/null +++ b/src/components/domain_mute_card/domain_mute_card.vue @@ -0,0 +1,38 @@ +<template> + <div class="domain-mute-card"> + <div class="domain-mute-card-domain"> + {{ domain }} + </div> + <ProgressButton + :click="unmuteDomain" + class="btn btn-default" + > + {{ $t('domain_mute_card.unmute') }} + <template slot="progress"> + {{ $t('domain_mute_card.unmute_progress') }} + </template> + </ProgressButton> + </div> +</template> + +<script src="./domain_mute_card.js"></script> + +<style lang="scss"> +.domain-mute-card { + flex: 1 0; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.6em 1em 0.6em 0; + + &-domain { + margin-right: 1em; + overflow: hidden; + text-overflow: ellipsis; + } + + button { + width: 10em; + } +} +</style> diff --git a/src/components/emoji_reactions/emoji_reactions.js b/src/components/emoji_reactions/emoji_reactions.js new file mode 100644 index 00000000..95d52cb6 --- /dev/null +++ b/src/components/emoji_reactions/emoji_reactions.js @@ -0,0 +1,32 @@ + +const EmojiReactions = { + name: 'EmojiReactions', + props: ['status'], + computed: { + emojiReactions () { + return this.status.emoji_reactions + } + }, + methods: { + reactedWith (emoji) { + const user = this.$store.state.users.currentUser + const reaction = this.status.emoji_reactions.find(r => r.emoji === emoji) + return reaction.accounts && reaction.accounts.find(u => u.id === user.id) + }, + reactWith (emoji) { + this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji }) + }, + unreact (emoji) { + this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji }) + }, + emojiOnClick (emoji, event) { + if (this.reactedWith(emoji)) { + this.unreact(emoji) + } else { + this.reactWith(emoji) + } + } + } +} + +export default EmojiReactions diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue new file mode 100644 index 00000000..00d6d2b7 --- /dev/null +++ b/src/components/emoji_reactions/emoji_reactions.vue @@ -0,0 +1,49 @@ +<template> + <div class="emoji-reactions"> + <button + v-for="(reaction) in emojiReactions" + :key="reaction.emoji" + class="emoji-reaction btn btn-default" + :class="{ 'picked-reaction': reactedWith(reaction.emoji) }" + @click="emojiOnClick(reaction.emoji, $event)" + > + <span class="reaction-emoji">{{ reaction.emoji }}</span> + <span>{{ reaction.count }}</span> + </button> + </div> +</template> + +<script src="./emoji_reactions.js" ></script> +<style lang="scss"> +@import '../../_variables.scss'; + +.emoji-reactions { + display: flex; + margin-top: 0.25em; + flex-wrap: wrap; +} + +.emoji-reaction { + padding: 0 0.5em; + margin-right: 0.5em; + margin-top: 0.5em; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + .reaction-emoji { + width: 1.25em; + margin-right: 0.25em; + } + &:focus { + outline: none; + } +} + +.picked-reaction { + border: 1px solid var(--link, $fallback--link); + margin-left: -1px; // offset the border, can't use inset shadows either + margin-right: calc(0.5em - 1px); +} + +</style> diff --git a/src/components/interactions/interactions.js b/src/components/interactions/interactions.js index 1f8a9de9..cc31ff20 100644 --- a/src/components/interactions/interactions.js +++ b/src/components/interactions/interactions.js @@ -3,7 +3,8 @@ import Notifications from '../notifications/notifications.vue' const tabModeDict = { mentions: ['mention'], 'likes+repeats': ['repeat', 'like'], - follows: ['follow'] + follows: ['follow'], + moves: ['move'] } const Interactions = { diff --git a/src/components/interactions/interactions.vue b/src/components/interactions/interactions.vue index 08cee343..a2e252ab 100644 --- a/src/components/interactions/interactions.vue +++ b/src/components/interactions/interactions.vue @@ -21,6 +21,10 @@ key="follows" :label="$t('interactions.follows')" /> + <span + key="moves" + :label="$t('interactions.moves')" + /> </tab-switcher> <Notifications ref="notifications" diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js index d9268585..8f7edb7f 100644 --- a/src/components/nav_panel/nav_panel.js +++ b/src/components/nav_panel/nav_panel.js @@ -3,7 +3,7 @@ import { mapState } from 'vuex' const NavPanel = { created () { if (this.currentUser && this.currentUser.locked) { - this.$store.dispatch('startFetchingFollowRequest') + this.$store.dispatch('startFetchingFollowRequests') } }, computed: mapState({ diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue index a934a411..8cd04dc7 100644 --- a/src/components/nav_panel/nav_panel.vue +++ b/src/components/nav_panel/nav_panel.vue @@ -33,7 +33,7 @@ <i class="button-icon icon-users" /> {{ $t("nav.public_tl") }} </router-link> </li> - <li v-if="federating && !privateMode"> + <li v-if="federating && (currentUser || !privateMode)"> <router-link :to="{ name: 'public-external-timeline' }"> <i class="button-icon icon-globe" /> {{ $t("nav.twkn") }} </router-link> diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 7d46eb5a..e7bd769e 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -43,18 +43,18 @@ const Notification = { const user = this.notification.from_profile return highlightStyle(highlight[user.screen_name]) }, - userInStore () { - return this.$store.getters.findUser(this.notification.from_profile.id) - }, user () { - if (this.userInStore) { - return this.userInStore - } - return this.notification.from_profile + return this.$store.getters.findUser(this.notification.from_profile.id) }, userProfileLink () { return this.generateUserProfileLink(this.user) }, + targetUser () { + return this.$store.getters.findUser(this.notification.target.id) + }, + targetUserProfileLink () { + return this.generateUserProfileLink(this.targetUser) + }, needMute () { return this.user.muted } diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 1f192c77..16124e50 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -74,9 +74,13 @@ <i class="fa icon-user-plus lit" /> <small>{{ $t('notifications.followed_you') }}</small> </span> + <span v-if="notification.type === 'move'"> + <i class="fa icon-arrow-curved lit" /> + <small>{{ $t('notifications.migrated_to') }}</small> + </span> </div> <div - v-if="notification.type === 'follow'" + v-if="notification.type === 'follow' || notification.type === 'move'" class="timeago" > <span class="faint"> @@ -115,6 +119,14 @@ @{{ notification.from_profile.screen_name }} </router-link> </div> + <div + v-else-if="notification.type === 'move'" + class="move-text" + > + <router-link :to="targetUserProfileLink"> + @{{ notification.target.screen_name }} + </router-link> + </div> <template v-else> <status class="faint" diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index a89c0cdc..26ffbab6 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -2,10 +2,12 @@ import Notification from '../notification/notification.vue' import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js' import { notificationsFromStore, - visibleNotificationsFromStore, + filteredNotificationsFromStore, unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils.js' +const DEFAULT_SEEN_TO_DISPLAY_COUNT = 30 + const Notifications = { props: { // Disables display of panel header @@ -18,7 +20,11 @@ const Notifications = { }, data () { return { - bottomedOut: false + bottomedOut: false, + // How many seen notifications to display in the list. The more there are, + // the heavier the page becomes. This count is increased when loading + // older notifications, and cut back to default whenever hitting "Read!". + seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT } }, computed: { @@ -34,14 +40,17 @@ const Notifications = { unseenNotifications () { return unseenNotificationsFromStore(this.$store) }, - visibleNotifications () { - return visibleNotificationsFromStore(this.$store, this.filterMode) + filteredNotifications () { + return filteredNotificationsFromStore(this.$store, this.filterMode) }, unseenCount () { return this.unseenNotifications.length }, loading () { return this.$store.state.statuses.notifications.loading + }, + notificationsToDisplay () { + return this.filteredNotifications.slice(0, this.unseenCount + this.seenToDisplayCount) } }, components: { @@ -64,12 +73,21 @@ const Notifications = { methods: { markAsSeen () { this.$store.dispatch('markNotificationsAsSeen') + this.seenToDisplayCount = DEFAULT_SEEN_TO_DISPLAY_COUNT }, fetchOlderNotifications () { if (this.loading) { return } + const seenCount = this.filteredNotifications.length - this.unseenCount + if (this.seenToDisplayCount < seenCount) { + this.seenToDisplayCount = Math.min(this.seenToDisplayCount + 20, seenCount) + return + } else if (this.seenToDisplayCount > seenCount) { + this.seenToDisplayCount = seenCount + } + const store = this.$store const credentials = store.state.users.currentUser.credentials store.commit('setNotificationsLoading', { value: true }) @@ -82,6 +100,7 @@ const Notifications = { if (notifs.length === 0) { this.bottomedOut = true } + this.seenToDisplayCount += notifs.length }) } } diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index ca762432..64ded936 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -79,7 +79,7 @@ } } - .follow-text { + .follow-text, .move-text { padding: 0.5em 0; } @@ -154,6 +154,11 @@ color: var(--cOrange, $fallback--cOrange); } + .icon-arrow-curved.lit { + color: $fallback--cBlue; + color: var(--cBlue, $fallback--cBlue); + } + .status-content { margin: 0; max-height: 300px; diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index c42c35e6..d477a41b 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -32,7 +32,7 @@ </div> <div class="panel-body"> <div - v-for="notification in visibleNotifications" + v-for="notification in notificationsToDisplay" :key="notification.id" class="notification" :class="{"unseen": !minimalMode && !notification.seen}" diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js new file mode 100644 index 00000000..6fb2a780 --- /dev/null +++ b/src/components/react_button/react_button.js @@ -0,0 +1,43 @@ +import { mapGetters } from 'vuex' + +const ReactButton = { + props: ['status', 'loggedIn'], + data () { + return { + showTooltip: false, + filterWord: '', + popperOptions: { + modifiers: { + preventOverflow: { padding: { top: 50 }, boundariesElement: 'viewport' } + } + } + } + }, + methods: { + openReactionSelect () { + this.showTooltip = true + this.filterWord = '' + }, + closeReactionSelect () { + this.showTooltip = false + }, + addReaction (event, emoji) { + this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji }) + this.closeReactionSelect() + } + }, + computed: { + commonEmojis () { + return ['❤️', '😠', '👀', '😂', '🔥'] + }, + emojis () { + if (this.filterWord !== '') { + return this.$store.state.instance.emoji.filter(emoji => emoji.displayText.includes(this.filterWord)) + } + return this.$store.state.instance.emoji || [] + }, + ...mapGetters(['mergedConfig']) + } +} + +export default ReactButton diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue new file mode 100644 index 00000000..c925dd71 --- /dev/null +++ b/src/components/react_button/react_button.vue @@ -0,0 +1,109 @@ +<template> + <v-popover + :popper-options="popperOptions" + :open="showTooltip" + trigger="manual" + placement="top" + class="react-button-popover" + @hide="closeReactionSelect" + > + <div slot="popover"> + <div class="reaction-picker-filter"> + <input + v-model="filterWord" + :placeholder="$t('emoji.search_emoji')" + > + </div> + <div class="reaction-picker"> + <span + v-for="emoji in commonEmojis" + :key="emoji" + class="emoji-button" + @click="addReaction($event, emoji)" + > + {{ emoji }} + </span> + <div class="reaction-picker-divider" /> + <span + v-for="(emoji, key) in emojis" + :key="key" + class="emoji-button" + @click="addReaction($event, emoji.replacement)" + > + {{ emoji.replacement }} + </span> + <div class="reaction-bottom-fader" /> + </div> + </div> + <div + v-if="loggedIn" + @click.prevent="openReactionSelect" + > + <i + class="icon-smile button-icon add-reaction-button" + :title="$t('tool_tip.add_reaction')" + /> + </div> + </v-popover> +</template> + +<script src="./react_button.js" ></script> + +<style lang="scss"> +@import '../../_variables.scss'; + +.reaction-picker-filter { + padding: 0.5em; +} + +.reaction-picker-divider { + height: 1px; + width: 100%; + margin: 0.5em; + background-color: var(--border, $fallback--border); +} + +.reaction-picker { + width: 10em; + height: 9em; + font-size: 1.5em; + overflow-y: scroll; + display: flex; + flex-wrap: wrap; + padding: 0.5em; + text-align: center; + align-content: flex-start; + user-select: none; + + mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat, + linear-gradient(to bottom, white 0, transparent 100%) top no-repeat, + linear-gradient(to top, white, white); + transition: mask-size 150ms; + mask-size: 100% 20px, 100% 20px, auto; + // Autoprefixed seem to ignore this one, and also syntax is different + -webkit-mask-composite: xor; + mask-composite: exclude; + + .emoji-button { + cursor: pointer; + + flex-basis: 20%; + line-height: 1.5em; + align-content: center; + + &:hover { + transform: scale(1.25); + } + } +} + +.add-reaction-button { + cursor: pointer; + + &:hover { + color: $fallback--text; + color: var(--text, $fallback--text); + } +} + +</style> diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js index 57f3caf0..ace8cc7c 100644 --- a/src/components/registration/registration.js +++ b/src/components/registration/registration.js @@ -63,7 +63,8 @@ const registration = { await this.signUp(this.user) this.$router.push({ name: 'friends' }) } catch (error) { - console.warn('Registration failed: ' + error) + console.warn('Registration failed: ', error) + this.setCaptcha() } } }, diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue index 222b67a8..fdbda007 100644 --- a/src/components/registration/registration.vue +++ b/src/components/registration/registration.vue @@ -170,7 +170,7 @@ <label class="form--label" for="captcha-label" - >{{ $t('captcha') }}</label> + >{{ $t('registration.captcha') }}</label> <template v-if="['kocaptcha', 'native'].includes(captcha.type)"> <img diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index e118dbcc..22e14a89 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -323,6 +323,11 @@ {{ $t('settings.notification_visibility_mentions') }} </Checkbox> </li> + <li> + <Checkbox v-model="notificationVisibility.moves"> + {{ $t('settings.notification_visibility_moves') }} + </Checkbox> + </li> </ul> </div> <div> diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js index 2534eb8f..2181ecc7 100644 --- a/src/components/side_drawer/side_drawer.js +++ b/src/components/side_drawer/side_drawer.js @@ -12,7 +12,7 @@ const SideDrawer = { this.closeGesture = GestureService.swipeGesture(GestureService.DIRECTION_LEFT, this.toggleDrawer) if (this.currentUser && this.currentUser.locked) { - this.$store.dispatch('startFetchingFollowRequest') + this.$store.dispatch('startFetchingFollowRequests') } }, components: { UserCard }, diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue index 25e4de01..df1d22a4 100644 --- a/src/components/side_drawer/side_drawer.vue +++ b/src/components/side_drawer/side_drawer.vue @@ -88,7 +88,7 @@ </router-link> </li> <li - v-if="federating && !privateMode" + v-if="federating && (currentUser || !privateMode)" @click="toggleDrawer" > <router-link to="/main/all"> diff --git a/src/components/staff_panel/staff_panel.js b/src/components/staff_panel/staff_panel.js index 93e950ad..4f98fff6 100644 --- a/src/components/staff_panel/staff_panel.js +++ b/src/components/staff_panel/staff_panel.js @@ -1,3 +1,4 @@ +import map from 'lodash/map' import BasicUserCard from '../basic_user_card/basic_user_card.vue' const StaffPanel = { @@ -6,7 +7,7 @@ const StaffPanel = { }, computed: { staffAccounts () { - return this.$store.state.instance.staffAccounts + return map(this.$store.state.instance.staffAccounts, nickname => this.$store.getters.findUser(nickname)).filter(_ => _) } } } diff --git a/src/components/status/status.js b/src/components/status/status.js index c49e729c..81b57667 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -1,5 +1,6 @@ import Attachment from '../attachment/attachment.vue' import FavoriteButton from '../favorite_button/favorite_button.vue' +import ReactButton from '../react_button/react_button.vue' import RetweetButton from '../retweet_button/retweet_button.vue' import Poll from '../poll/poll.vue' import ExtraButtons from '../extra_buttons/extra_buttons.vue' @@ -11,6 +12,7 @@ import LinkPreview from '../link-preview/link-preview.vue' import AvatarList from '../avatar_list/avatar_list.vue' import Timeago from '../timeago/timeago.vue' import StatusPopover from '../status_popover/status_popover.vue' +import EmojiReactions from '../emoji_reactions/emoji_reactions.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import fileType from 'src/services/file_type/file_type.service' import { processHtml } from 'src/services/tiny_post_html_processor/tiny_post_html_processor.service.js' @@ -319,6 +321,7 @@ const Status = { components: { Attachment, FavoriteButton, + ReactButton, RetweetButton, ExtraButtons, PostStatusForm, @@ -329,7 +332,8 @@ const Status = { LinkPreview, AvatarList, Timeago, - StatusPopover + StatusPopover, + EmojiReactions }, methods: { visibilityIcon (visibility) { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index b1048832..a326874e 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -354,6 +354,10 @@ </div> </transition> + <EmojiReactions + :status="status" + /> + <div v-if="!noHeading && !isPreview" class="status-actions media-body" @@ -382,6 +386,10 @@ :logged-in="loggedIn" :status="status" /> + <ReactButton + :logged-in="loggedIn" + :status="status" + /> <extra-buttons :status="status" @onError="showError" diff --git a/src/components/user_settings/mfa.js b/src/components/user_settings/mfa.js index 3090138a..abf37062 100644 --- a/src/components/user_settings/mfa.js +++ b/src/components/user_settings/mfa.js @@ -139,7 +139,7 @@ const Mfa = { // fetch settings from server async fetchSettings () { - let result = await this.backendInteractor.fetchSettingsMFA() + let result = await this.backendInteractor.settingsMFA() if (result.error) return this.settings = result.settings this.settings.available = true diff --git a/src/components/user_settings/user_settings.js b/src/components/user_settings/user_settings.js index d5d671e4..38373056 100644 --- a/src/components/user_settings/user_settings.js +++ b/src/components/user_settings/user_settings.js @@ -9,6 +9,7 @@ import ScopeSelector from '../scope_selector/scope_selector.vue' import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' import BlockCard from '../block_card/block_card.vue' import MuteCard from '../mute_card/mute_card.vue' +import DomainMuteCard from '../domain_mute_card/domain_mute_card.vue' import SelectableList from '../selectable_list/selectable_list.vue' import ProgressButton from '../progress_button/progress_button.vue' import EmojiInput from '../emoji_input/emoji_input.vue' @@ -32,6 +33,12 @@ const MuteList = withSubscription({ childPropName: 'items' })(SelectableList) +const DomainMuteList = withSubscription({ + fetch: (props, $store) => $store.dispatch('fetchDomainMutes'), + select: (props, $store) => get($store.state.users.currentUser, 'domainMutes', []), + childPropName: 'items' +})(SelectableList) + const UserSettings = { data () { return { @@ -67,7 +74,8 @@ const UserSettings = { changedPassword: false, changePasswordError: false, activeTab: 'profile', - notificationSettings: this.$store.state.users.currentUser.notification_settings + notificationSettings: this.$store.state.users.currentUser.notification_settings, + newDomainToMute: '' } }, created () { @@ -80,10 +88,12 @@ const UserSettings = { ImageCropper, BlockList, MuteList, + DomainMuteList, EmojiInput, Autosuggest, BlockCard, MuteCard, + DomainMuteCard, ProgressButton, Importer, Exporter, @@ -297,7 +307,7 @@ const UserSettings = { newPassword: this.changePasswordInputs[1], newPasswordConfirmation: this.changePasswordInputs[2] } - this.$store.state.api.backendInteractor.changePassword({ params }) + this.$store.state.api.backendInteractor.changePassword(params) .then((res) => { if (res.status === 'success') { this.changedPassword = true @@ -314,7 +324,7 @@ const UserSettings = { email: this.newEmail, password: this.changeEmailPassword } - this.$store.state.api.backendInteractor.changeEmail({ params }) + this.$store.state.api.backendInteractor.changeEmail(params) .then((res) => { if (res.status === 'success') { this.changedEmail = true @@ -365,6 +375,13 @@ const UserSettings = { unmuteUsers (ids) { return this.$store.dispatch('unmuteUsers', ids) }, + unmuteDomains (domains) { + return this.$store.dispatch('unmuteDomains', domains) + }, + muteDomain () { + return this.$store.dispatch('muteDomain', this.newDomainToMute) + .then(() => { this.newDomainToMute = '' }) + }, identity (value) { return value } diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue index 3f1982a6..2222c293 100644 --- a/src/components/user_settings/user_settings.vue +++ b/src/components/user_settings/user_settings.vue @@ -509,59 +509,114 @@ </div> <div :label="$t('settings.mutes_tab')"> - <div class="profile-edit-usersearch-wrapper"> - <Autosuggest - :filter="filterUnMutedUsers" - :query="queryUserIds" - :placeholder="$t('settings.search_user_to_mute')" - > - <MuteCard - slot-scope="row" - :user-id="row.item" - /> - </Autosuggest> - </div> - <MuteList - :refresh="true" - :get-key="identity" - > - <template - slot="header" - slot-scope="{selected}" - > - <div class="profile-edit-bulk-actions"> - <ProgressButton - v-if="selected.length > 0" - class="btn btn-default" - :click="() => muteUsers(selected)" + <tab-switcher> + <div label="Users"> + <div class="profile-edit-usersearch-wrapper"> + <Autosuggest + :filter="filterUnMutedUsers" + :query="queryUserIds" + :placeholder="$t('settings.search_user_to_mute')" + > + <MuteCard + slot-scope="row" + :user-id="row.item" + /> + </Autosuggest> + </div> + <MuteList + :refresh="true" + :get-key="identity" + > + <template + slot="header" + slot-scope="{selected}" + > + <div class="profile-edit-bulk-actions"> + <ProgressButton + v-if="selected.length > 0" + class="btn btn-default" + :click="() => muteUsers(selected)" + > + {{ $t('user_card.mute') }} + <template slot="progress"> + {{ $t('user_card.mute_progress') }} + </template> + </ProgressButton> + <ProgressButton + v-if="selected.length > 0" + class="btn btn-default" + :click="() => unmuteUsers(selected)" + > + {{ $t('user_card.unmute') }} + <template slot="progress"> + {{ $t('user_card.unmute_progress') }} + </template> + </ProgressButton> + </div> + </template> + <template + slot="item" + slot-scope="{item}" + > + <MuteCard :user-id="item" /> + </template> + <template slot="empty"> + {{ $t('settings.no_mutes') }} + </template> + </MuteList> + </div> + + <div :label="$t('settings.domain_mutes')"> + <div class="profile-edit-domain-mute-form"> + <input + v-model="newDomainToMute" + :placeholder="$t('settings.type_domains_to_mute')" + type="text" + @keyup.enter="muteDomain" > - {{ $t('user_card.mute') }} - <template slot="progress"> - {{ $t('user_card.mute_progress') }} - </template> - </ProgressButton> <ProgressButton - v-if="selected.length > 0" class="btn btn-default" - :click="() => unmuteUsers(selected)" + :click="muteDomain" > - {{ $t('user_card.unmute') }} + {{ $t('domain_mute_card.mute') }} <template slot="progress"> - {{ $t('user_card.unmute_progress') }} + {{ $t('domain_mute_card.mute_progress') }} </template> </ProgressButton> </div> - </template> - <template - slot="item" - slot-scope="{item}" - > - <MuteCard :user-id="item" /> - </template> - <template slot="empty"> - {{ $t('settings.no_mutes') }} - </template> - </MuteList> + <DomainMuteList + :refresh="true" + :get-key="identity" + > + <template + slot="header" + slot-scope="{selected}" + > + <div class="profile-edit-bulk-actions"> + <ProgressButton + v-if="selected.length > 0" + class="btn btn-default" + :click="() => unmuteDomains(selected)" + > + {{ $t('domain_mute_card.unmute') }} + <template slot="progress"> + {{ $t('domain_mute_card.unmute_progress') }} + </template> + </ProgressButton> + </div> + </template> + <template + slot="item" + slot-scope="{item}" + > + <DomainMuteCard :domain="item" /> + </template> + <template slot="empty"> + {{ $t('settings.no_mutes') }} + </template> + </DomainMuteList> + </div> + </tab-switcher> </div> </tab-switcher> </div> @@ -639,6 +694,18 @@ } } + &-domain-mute-form { + padding: 1em; + display: flex; + flex-direction: column; + + button { + align-self: flex-end; + margin-top: 1em; + width: 10em; + } + } + .setting-subitem { margin-left: 1.75em; } |
