diff --git a/src/components/notification/notification.scss b/src/components/notification/notification.scss index ec291547..14ec6213 100644 --- a/src/components/notification/notification.scss +++ b/src/components/notification/notification.scss @@ -2,7 +2,12 @@ // TODO Copypaste from Status, should unify it somehow .Notification { - --emoji-size: 14px; + border-bottom: 1px solid; + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + word-wrap: break-word; + word-break: break-word; + --emoji-size: 14px; &.-muted { padding: 0.25em 0.6em; diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 634ec8ee..44cd3d8a 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -1,6 +1,7 @@ <template> <Status v-if="notification.type === 'mention'" + class="Notification" :compact="true" :statusoid="notification.status" /> diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 77b3c438..9e5663ed 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -37,11 +37,6 @@ .notification { box-sizing: border-box; - border-bottom: 1px solid; - border-color: $fallback--border; - border-color: var(--border, $fallback--border); - word-wrap: break-word; - word-break: break-word; &:hover .animated.Avatar { canvas { diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue index 6fc9ceaa..5d3c614a 100644 --- a/src/components/settings_modal/tabs/filtering_tab.vue +++ b/src/components/settings_modal/tabs/filtering_tab.vue @@ -1,73 +1,138 @@ <template> <div :label="$t('settings.filtering')"> <div class="setting-item"> - <div class="select-multiple"> - <span class="label">{{ $t('settings.notification_visibility') }}</span> - <ul class="option-list"> - <li> - <BooleanSetting path="notificationVisibility.likes"> - {{ $t('settings.notification_visibility_likes') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="notificationVisibility.repeats"> - {{ $t('settings.notification_visibility_repeats') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="notificationVisibility.follows"> - {{ $t('settings.notification_visibility_follows') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="notificationVisibility.mentions"> - {{ $t('settings.notification_visibility_mentions') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="notificationVisibility.moves"> - {{ $t('settings.notification_visibility_moves') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="notificationVisibility.emojiReactions"> - {{ $t('settings.notification_visibility_emoji_reactions') }} - </BooleanSetting> - </li> - </ul> - </div> - <ChoiceSetting - id="replyVisibility" - path="replyVisibility" - :options="replyVisibilityOptions" - > - {{ $t('settings.replies_in_timeline') }} - </ChoiceSetting> - <div> - <BooleanSetting path="hidePostStats"> - {{ $t('settings.hide_post_stats') }} - </BooleanSetting> - </div> - <div> - <BooleanSetting path="hideUserStats"> - {{ $t('settings.hide_user_stats') }} - </BooleanSetting> - </div> + <h2>{{ $t('settings.posts') }}</h2> + <ul class="setting-list"> + <li> + <BooleanSetting path="hideFilteredStatuses"> + {{ $t('settings.hide_filtered_statuses') }} + </BooleanSetting> + <ul + class="setting-list suboptions" + :class="[{disabled: !streaming}]" + > + <li> + <BooleanSetting + :disabled="hideFilteredStatuses" + path="hideWordFilteredPosts" + > + {{ $t('settings.hide_wordfiltered_statuses') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting + :disabled="hideFilteredStatuses" + path="hideMutedThreads" + > + {{ $t('settings.hide_muted_threads') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting + :disabled="hideFilteredStatuses" + path="hideMutedPosts" + > + {{ $t('settings.hide_muted_posts') }} + </BooleanSetting> + </li> + </ul> + </li> + <li> + <BooleanSetting path="hidePostStats"> + {{ $t('settings.hide_post_stats') }} + </BooleanSetting> + </li> + <ChoiceSetting + id="replyVisibility" + path="replyVisibility" + :options="replyVisibilityOptions" + > + {{ $t('settings.replies_in_timeline') }} + </ChoiceSetting> + <li> + <h3>{{ $t('settings.wordfilter') }}</h3> + <textarea + id="muteWords" + v-model="muteWordsString" + class="resize-height" + /> + <div>{{ $t('settings.filtering_explanation') }}</div> + </li> + <h3>{{ $t('settings.attachments') }}</h3> + <li> + <label for="maxThumbnails"> + {{ $t('settings.max_thumbnails') }} + </label> + <input + id="maxThumbnails" + path.number="maxThumbnails" + class="number-input" + type="number" + min="0" + step="1" + > + </li> + <li> + <BooleanSetting path="hideAttachments"> + {{ $t('settings.hide_attachments_in_tl') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting path="hideAttachmentsInConv"> + {{ $t('settings.hide_attachments_in_convo') }} + </BooleanSetting> + </li> + </ul> </div> <div class="setting-item"> - <div> - <p>{{ $t('settings.filtering_explanation') }}</p> - <textarea - id="muteWords" - v-model="muteWordsString" - class="resize-height" - /> - </div> - <div> - <BooleanSetting path="hideFilteredStatuses"> - {{ $t('settings.hide_filtered_statuses') }} - </BooleanSetting> - </div> + <h2>{{ $t('settings.user_profiles') }}</h2> + <ul class="setting-list"> + <li> + <BooleanSetting path="hideUserStats"> + {{ $t('settings.hide_user_stats') }} + </BooleanSetting> + </li> + </ul> + </div> + <div class="setting-item"> + <h2>{{ $t('settings.notifications') }}</h2> + <ul class="setting-list"> + <li class="select-multiple"> + <span class="label">{{ $t('settings.notification_visibility') }}</span> + <ul class="option-list"> + <li> + <BooleanSetting path="notificationVisibility.likes"> + {{ $t('settings.notification_visibility_likes') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting path="notificationVisibility.repeats"> + {{ $t('settings.notification_visibility_repeats') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting path="notificationVisibility.follows"> + {{ $t('settings.notification_visibility_follows') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting path="notificationVisibility.mentions"> + {{ $t('settings.notification_visibility_mentions') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting path="notificationVisibility.moves"> + {{ $t('settings.notification_visibility_moves') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting path="notificationVisibility.emojiReactions"> + {{ $t('settings.notification_visibility_emoji_reactions') }} + </BooleanSetting> + </li> + </ul> + </li> + </ul> </div> </div> </template> diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index f2ec7d64..bd3ee84e 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -21,24 +21,9 @@ {{ $t('settings.hide_wallpaper') }} </BooleanSetting> </li> - <li v-if="instanceShoutboxPresent"> - <BooleanSetting path="hideShoutbox"> - {{ $t('settings.hide_shoutbox') }} - </BooleanSetting> - </li> - </ul> - </div> - <div class="setting-item"> - <h2>{{ $t('nav.timeline') }}</h2> - <ul class="setting-list"> <li> - <BooleanSetting path="hideMutedPosts"> - {{ $t('settings.hide_muted_posts') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="collapseMessageWithSubject"> - {{ $t('settings.collapse_subject') }} + <BooleanSetting path="stopGifs"> + {{ $t('settings.stop_gifs') }} </BooleanSetting> </li> <li> @@ -68,14 +53,98 @@ </small> </BooleanSetting> </li> + <li> + <BooleanSetting path="virtualScrolling"> + {{ $t('settings.virtual_scrolling') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting path="autohideFloatingPostButton"> + {{ $t('settings.autohide_floating_post_button') }} + </BooleanSetting> + </li> + <li v-if="instanceShoutboxPresent"> + <BooleanSetting path="hideShoutbox"> + {{ $t('settings.hide_shoutbox') }} + </BooleanSetting> + </li> + </ul> + </div> + <div class="setting-item"> + <h2>{{ $t('settings.post_look_feel') }}</h2> + <ul class="setting-list"> + <li> + <BooleanSetting path="collapseMessageWithSubject"> + {{ $t('settings.collapse_subject') }} + </BooleanSetting> + </li> <li> <BooleanSetting path="emojiReactionsOnTimeline"> {{ $t('settings.emoji_reactions_on_timeline') }} </BooleanSetting> </li> + <h3>{{ $t('settings.attachments') }}</h3> <li> - <BooleanSetting path="virtualScrolling"> - {{ $t('settings.virtual_scrolling') }} + <BooleanSetting path="useContainFit"> + {{ $t('settings.use_contain_fit') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting path="hideNsfw"> + {{ $t('settings.nsfw_clickthrough') }} + </BooleanSetting> + </li> + <ul class="setting-list suboptions"> + <li> + <BooleanSetting + path="preloadImage" + :disabled="!hideNsfw" + > + {{ $t('settings.preload_images') }} + </BooleanSetting> + </li> + <li> + <BooleanSetting + path="useOneClickNsfw" + :disabled="!hideNsfw" + > + {{ $t('settings.use_one_click_nsfw') }} + </BooleanSetting> + </li> + </ul> + <li> + <BooleanSetting path="loopVideo"> + {{ $t('settings.loop_video') }} + </BooleanSetting> + <ul + class="setting-list suboptions" + :class="[{disabled: !streaming}]" + > + <li> + <BooleanSetting + path="loopVideoSilentOnly" + :disabled="!loopVideo || !loopSilentAvailable" + > + {{ $t('settings.loop_video_silent_only') }} + </BooleanSetting> + <div + v-if="!loopSilentAvailable" + class="unavailable" + > + <FAIcon icon="globe" />! {{ $t('settings.limited_availability') }} + </div> + </li> + </ul> + </li> + <li> + <BooleanSetting path="playVideosInModal"> + {{ $t('settings.play_videos_in_modal') }} + </BooleanSetting> + </li> + <h3>{{ $t('settings.fun') }}</h3> + <li> + <BooleanSetting path="greentext"> + {{ $t('settings.greentext') }} </BooleanSetting> </li> </ul> @@ -140,97 +209,6 @@ </ul> </div> - <div class="setting-item"> - <h2>{{ $t('settings.attachments') }}</h2> - <ul class="setting-list"> - <li> - <BooleanSetting path="hideAttachments"> - {{ $t('settings.hide_attachments_in_tl') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="hideAttachmentsInConv"> - {{ $t('settings.hide_attachments_in_convo') }} - </BooleanSetting> - </li> - <li> - <label for="maxThumbnails"> - {{ $t('settings.max_thumbnails') }} - </label> - <input - id="maxThumbnails" - path.number="maxThumbnails" - class="number-input" - type="number" - min="0" - step="1" - > - </li> - <li> - <BooleanSetting path="hideNsfw"> - {{ $t('settings.nsfw_clickthrough') }} - </BooleanSetting> - </li> - <ul class="setting-list suboptions"> - <li> - <BooleanSetting - path="preloadImage" - :disabled="!hideNsfw" - > - {{ $t('settings.preload_images') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting - path="useOneClickNsfw" - :disabled="!hideNsfw" - > - {{ $t('settings.use_one_click_nsfw') }} - </BooleanSetting> - </li> - </ul> - <li> - <BooleanSetting path="stopGifs"> - {{ $t('settings.stop_gifs') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="loopVideo"> - {{ $t('settings.loop_video') }} - </BooleanSetting> - <ul - class="setting-list suboptions" - :class="[{disabled: !streaming}]" - > - <li> - <BooleanSetting - path="loopVideoSilentOnly" - :disabled="!loopVideo || !loopSilentAvailable" - > - {{ $t('settings.loop_video_silent_only') }} - </BooleanSetting> - <div - v-if="!loopSilentAvailable" - class="unavailable" - > - <FAIcon icon="globe" />! {{ $t('settings.limited_availability') }} - </div> - </li> - </ul> - </li> - <li> - <BooleanSetting path="playVideosInModal"> - {{ $t('settings.play_videos_in_modal') }} - </BooleanSetting> - </li> - <li> - <BooleanSetting path="useContainFit"> - {{ $t('settings.use_contain_fit') }} - </BooleanSetting> - </li> - </ul> - </div> - <div class="setting-item"> <h2>{{ $t('settings.notifications') }}</h2> <ul class="setting-list"> @@ -241,17 +219,6 @@ </li> </ul> </div> - - <div class="setting-item"> - <h2>{{ $t('settings.fun') }}</h2> - <ul class="setting-list"> - <li> - <BooleanSetting path="greentext"> - {{ $t('settings.greentext') }} - </BooleanSetting> - </li> - </ul> - </div> </div> </template> diff --git a/src/components/status/status.js b/src/components/status/status.js index ac481534..d8f94926 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -186,26 +186,32 @@ const Status = { return this.mentionsLine.length > 0 }, muted () { + if (this.statusoid.user.id === this.currentUser.id) return false + const reasonsToMute = this.userIsMuted || + // Thread is muted + status.thread_muted || + // Wordfiltered + this.muteWordHits.length > 0 + return !this.unmuted && !this.shouldNotMute && reasonsToMute + }, + userIsMuted () { if (this.statusoid.user.id === this.currentUser.id) return false const { status } = this const { reblog } = status const relationship = this.$store.getters.relationship(status.user.id) const relationshipReblog = reblog && this.$store.getters.relationship(reblog.user.id) - const reasonsToMute = ( - // Post is muted according to BE - status.muted || + return status.muted || // Reprööt of a muted post according to BE (reblog && reblog.muted) || // Muted user relationship.muting || // Muted user of a reprööt - (relationshipReblog && relationshipReblog.muting) || - // Thread is muted - status.thread_muted || - // Wordfiltered - this.muteWordHits.length > 0 - ) - const excusesNotToMute = ( + (relationshipReblog && relationshipReblog.muting) + }, + shouldNotMute () { + const { status } = this + const { reblog } = status + return ( ( this.inProfile && ( // Don't mute user's posts on user timeline (except reblogs) @@ -218,14 +224,26 @@ const Status = { (this.inConversation && status.thread_muted) // No excuses if post has muted words ) && !this.muteWordHits.length > 0 - - return !this.unmuted && !excusesNotToMute && reasonsToMute + }, + hideMutedUsers () { + return this.mergedConfig.hideMutedPosts + }, + hideMutedThreads () { + return this.mergedConfig.hideMutedThreads }, hideFilteredStatuses () { return this.mergedConfig.hideFilteredStatuses }, + hideWordFilteredPosts () { + return this.mergedConfig.hideWordFilteredPosts + }, hideStatus () { - return (this.muted && this.hideFilteredStatuses) || this.virtualHidden + return (this.virtualHidden || !this.shouldNotMute) && ( + (this.muted && this.hideFilteredStatuses) || + (this.userIsMuted && this.hideMutedUsers) || + (this.status.thread_muted && this.hideMutedThreads) || + (this.muteWordHits.length > 0 && this.hideWordFilteredPosts) + ) }, isFocused () { // retweet or root of an expanded conversation diff --git a/src/components/timeline/timeline_quick_settings.js b/src/components/timeline/timeline_quick_settings.js index eae65a55..7b4931ce 100644 --- a/src/components/timeline/timeline_quick_settings.js +++ b/src/components/timeline/timeline_quick_settings.js @@ -48,10 +48,9 @@ const TimelineQuickSettings = { } }, hideMutedPosts: { - get () { return this.mergedConfig.hideMutedPosts || this.mergedConfig.hideFilteredStatuses }, + get () { return this.mergedConfig.hideFilteredStatuses }, set () { const value = !this.hideMutedPosts - this.$store.dispatch('setOption', { name: 'hideMutedPosts', value }) this.$store.dispatch('setOption', { name: 'hideFilteredStatuses', value }) } } diff --git a/src/i18n/en.json b/src/i18n/en.json index 8c7e09b2..4be744a3 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -262,8 +262,7 @@ "security": "Security", "setting_changed": "Setting is different from default", "enter_current_password_to_confirm": "Enter your current password to confirm your identity", - "mentions_new_style": "Fancier mention links", - "mentions_new_place": "Put mentions on a separate line", + "post_look_feel": "Posts Look & Feel", "mfa": { "otp": "OTP", "setup_otp": "Setup OTP", @@ -336,6 +335,7 @@ "emoji_reactions_on_timeline": "Show emoji reactions on timeline", "export_theme": "Save preset", "filtering": "Filtering", + "wordfilter": "Wordfilter", "filtering_explanation": "All statuses containing these words will be muted, one per line", "word_filter": "Word filter", "follow_export": "Follow export", @@ -351,7 +351,7 @@ "hide_media_previews": "Hide media previews", "hide_muted_posts": "Hide posts of muted users", "hide_all_muted_posts": "Hide muted posts", - "max_thumbnails": "Maximum amount of thumbnails per post", + "max_thumbnails": "Maximum amount of thumbnails per post (empty = no limit)", "hide_isp": "Hide instance-specific panel", "hide_shoutbox": "Hide instance shoutbox", "right_sidebar": "Show sidebar on the right side", @@ -361,7 +361,9 @@ "use_one_click_nsfw": "Open NSFW attachments with just one click", "hide_post_stats": "Hide post statistics (e.g. the number of favorites)", "hide_user_stats": "Hide user statistics (e.g. the number of followers)", - "hide_filtered_statuses": "Hide filtered statuses", + "hide_filtered_statuses": "Hide all filtered posts", + "hide_wordfiltered_statuses": "Hide word-filtered statuses", + "hide_muted_threads": "Hide muted threads", "import_blocks_from_a_csv_file": "Import blocks from a csv file", "import_followers_from_a_csv_file": "Import follows from a csv file", "import_theme": "Load preset", @@ -402,6 +404,8 @@ "name_bio": "Name & bio", "new_email": "New email", "new_password": "New password", + "posts": "Posts", + "user_profiles": "User Profiles", "notification_visibility": "Types of notifications to show", "notification_visibility_follows": "Follows", "notification_visibility_likes": "Favorites", @@ -418,7 +422,7 @@ "hide_followers_count_description": "Don't show follower count", "show_admin_badge": "Show \"Admin\" badge in my profile", "show_moderator_badge": "Show \"Moderator\" badge in my profile", - "nsfw_clickthrough": "Enable clickthrough attachment and link preview image hiding for NSFW statuses", + "nsfw_clickthrough": "Hide sensitive/NSFW media", "oauth_tokens": "OAuth tokens", "token": "Token", "refresh_token": "Refresh token", @@ -462,7 +466,7 @@ "subject_line_noop": "Do not copy", "post_status_content_type": "Post status content type", "sensitive_by_default": "Mark posts as sensitive by default", - "stop_gifs": "Play-on-hover GIFs", + "stop_gifs": "Pause animated images until you hover on them", "streaming": "Enable automatic streaming of new posts when scrolled to the top", "user_mutes": "Users", "useStreamingApi": "Receive posts and notifications real-time", diff --git a/src/modules/config.js b/src/modules/config.js index bc3db11b..c79302b5 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -24,6 +24,8 @@ export const defaultState = { hideShoutbox: false, // bad name: actually hides posts of muted USERS hideMutedPosts: undefined, // instance default + hideMutedThreads: undefined, // instance default + hideWordFilteredPosts: undefined, // instance default collapseMessageWithSubject: undefined, // instance default padEmoji: true, hideAttachments: false, diff --git a/src/modules/instance.js b/src/modules/instance.js index 539b9c66..60038f08 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -21,7 +21,10 @@ const defaultState = { collapseMessageWithSubject: false, greentext: false, hideFilteredStatuses: false, + // bad name: actually hides posts of muted USERS hideMutedPosts: false, + hideMutedThreads: true, + hideWordFilteredPosts: false, hidePostStats: false, hideSitename: false, hideUserStats: false,