diff options
38 files changed, 221 insertions, 139 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index dd4a2836..9f516b8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Fixed +- Follows/Followers tabs on user profiles now display the content properly. + +## [2.2.2] - 2020-12-22 ### Added - Mouseover titles for emojis in reaction picker - Support to input emoji into the search box in reaction picker - Added some missing unicode emoji +- Added the upload limit to the Features panel in the About page +- Support for solid color wallpaper, instance doesn't have to define a wallpaper anymore ### Fixed - Fixed the occasional bug where screen would scroll 1px when typing into a reply form @@ -17,11 +23,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fixed custom emoji not working in profile field names - Fixed pinned statuses not appearing in user profiles - Fixed some elements not being keyboard navigation friendly +- Fixed error handling when updating various profile images - Fixed your latest chat messages disappearing when closing chat view and opening it again during the same session +- Fixed custom emoji not showing in poll options before voting +- Fixed link color not applied to instance name in topbar ### Changed - Errors when fetching are now shown with popup errors instead of "Error fetching updates" in panel headers - Made reply/fav/repeat etc buttons easier to hit +- Adjusted timeline menu clickable area to match the visible button +- Moved external source link from status heading to the ellipsis menu +- Disabled horizontal textarea resize +- Wallpaper is now top-aligned, horizontally centered. ## [2.2.1] - 2020-11-11 @@ -15,6 +15,7 @@ import UserReportingModal from './components/user_reporting_modal/user_reporting import PostStatusModal from './components/post_status_modal/post_status_modal.vue' import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue' import { windowWidth, windowHeight } from './services/window_utils/window_utils' +import { mapGetters } from 'vuex' export default { name: 'app', @@ -50,17 +51,18 @@ export default { }, computed: { currentUser () { return this.$store.state.users.currentUser }, - background () { - return this.currentUser.background_image || this.$store.state.instance.background + userBackground () { return this.currentUser.background_image }, + instanceBackground () { + return this.mergedConfig.hideInstanceWallpaper + ? null + : this.$store.state.instance.background }, + background () { return this.userBackground || this.instanceBackground }, bgStyle () { - return { - 'background-image': `url(${this.background})` - } - }, - bgAppStyle () { - return { - '--body-background-image': `url(${this.background})` + if (this.background) { + return { + '--body-background-image': `url(${this.background})` + } } }, chat () { return this.$store.state.chat.channel.state === 'joined' }, @@ -77,7 +79,8 @@ export default { return { 'order': this.$store.state.instance.sidebarRight ? 99 : 0 } - } + }, + ...mapGetters(['mergedConfig']) }, methods: { updateMobileState () { diff --git a/src/App.scss b/src/App.scss index cdc3209c..2a1d7b1b 100644 --- a/src/App.scss +++ b/src/App.scss @@ -14,7 +14,9 @@ right: -20px; background-size: cover; background-repeat: no-repeat; - background-position: 0 50%; + background-color: var(--wallpaper); + background-image: var(--body-background-image); + background-position: 50% 50px; } i[class^='icon-'] { @@ -332,6 +334,10 @@ input, textarea, .select, .input { box-sizing: border-box; } } + + &.resize-height { + resize: vertical; + } } option { diff --git a/src/App.vue b/src/App.vue index b4eb0524..1a166778 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,12 +1,11 @@ <template> <div id="app" - :style="bgAppStyle" + :style="bgStyle" > <div id="app_bg_wrapper" class="app-bg-wrapper" - :style="bgStyle" /> <MobileNav v-if="isMobileLayout" /> <DesktopNav v-else /> diff --git a/src/components/desktop_nav/desktop_nav.scss b/src/components/desktop_nav/desktop_nav.scss index 8fd8e620..2d468588 100644 --- a/src/components/desktop_nav/desktop_nav.scss +++ b/src/components/desktop_nav/desktop_nav.scss @@ -5,6 +5,10 @@ width: 100%; position: fixed; + a { + color: var(--topBarLink, $fallback--link); + } + .inner-nav { display: grid; grid-template-rows: 50px; diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js index 1a8eef72..b5b29e8a 100644 --- a/src/components/extra_buttons/extra_buttons.js +++ b/src/components/extra_buttons/extra_buttons.js @@ -5,7 +5,8 @@ import { faBookmark, faEyeSlash, faThumbtack, - faShareAlt + faShareAlt, + faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons' import { faBookmark as faBookmarkReg @@ -17,7 +18,8 @@ library.add( faBookmarkReg, faEyeSlash, faThumbtack, - faShareAlt + faShareAlt, + faExternalLinkAlt ) const ExtraButtons = { diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index e687d487..dc790cad 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -1,5 +1,6 @@ <template> <Popover + class="ExtraButtons" trigger="click" placement="top" :offset="{ y: 5 }" @@ -96,11 +97,23 @@ icon="share-alt" /><span>{{ $t("status.copy_link") }}</span> </button> + <a + v-if="!status.is_local" + class="button-default dropdown-item dropdown-item-icon" + title="Source" + :href="status.external_url" + target="_blank" + > + <FAIcon + fixed-width + icon="external-link-alt" + /><span>{{ $t("status.external_source") }}</span> + </a> </div> </div> <span slot="trigger" - class="ExtraButtons" + class="popover-trigger" > <FAIcon class="fa-scale-110 fa-old-padding" @@ -116,13 +129,15 @@ @import '../../_variables.scss'; .ExtraButtons { - position: static; - padding: 10px; - margin: -10px; + .popover-trigger { + position: static; + padding: 10px; + margin: -10px; - &:hover .svg-inline--fa { - color: $fallback--text; - color: var(--text, $fallback--text); + &:hover .svg-inline--fa { + color: $fallback--text; + color: var(--text, $fallback--text); + } } } </style> diff --git a/src/components/features_panel/features_panel.js b/src/components/features_panel/features_panel.js index 620a85ea..8b142d08 100644 --- a/src/components/features_panel/features_panel.js +++ b/src/components/features_panel/features_panel.js @@ -1,3 +1,5 @@ +import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' + const FeaturesPanel = { computed: { chat: function () { return this.$store.state.instance.chatAvailable }, @@ -6,7 +8,8 @@ const FeaturesPanel = { whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled }, mediaProxy: function () { return this.$store.state.instance.mediaProxyAvailable }, minimalScopesMode: function () { return this.$store.state.instance.minimalScopesMode }, - textlimit: function () { return this.$store.state.instance.textlimit } + textlimit: function () { return this.$store.state.instance.textlimit }, + uploadlimit: function () { return fileSizeFormatService.fileSizeFormat(this.$store.state.instance.uploadlimit) } } } diff --git a/src/components/features_panel/features_panel.vue b/src/components/features_panel/features_panel.vue index 608b11c8..9605d09d 100644 --- a/src/components/features_panel/features_panel.vue +++ b/src/components/features_panel/features_panel.vue @@ -25,6 +25,7 @@ </li> <li>{{ $t('features_panel.scope_options') }}</li> <li>{{ $t('features_panel.text_limit') }} = {{ textlimit }}</li> + <li>{{ $t('features_panel.upload_limit') }} = {{ uploadlimit.num }} {{ $t('upload.file_size_units.' + uploadlimit.unit) }}</li> </ul> </div> </div> diff --git a/src/components/global_notice_list/global_notice_list.vue b/src/components/global_notice_list/global_notice_list.vue index 8a33b9eb..049e23db 100644 --- a/src/components/global_notice_list/global_notice_list.vue +++ b/src/components/global_notice_list/global_notice_list.vue @@ -9,11 +9,15 @@ <div class="notice-message"> {{ $t(notice.messageKey, notice.messageArgs) }} </div> - <FAIcon - class="fa-scale-110 fa-old-padding" - icon="times" + <button + class="button-unstyled close-notice" @click="closeNotice(notice)" - /> + > + <FAIcon + class="fa-scale-110 fa-old-padding" + icon="times" + /> + </button> </div> </div> </template> @@ -54,7 +58,7 @@ .global-error { background-color: var(--alertPopupError, $fallback--cRed); color: var(--alertPopupErrorText, $fallback--text); - i { + .svg-inline--fa { color: var(--alertPopupErrorText, $fallback--text); } } @@ -62,7 +66,7 @@ .global-warning { background-color: var(--alertPopupWarning, $fallback--cOrange); color: var(--alertPopupWarningText, $fallback--text); - i { + .svg-inline--fa { color: var(--alertPopupWarningText, $fallback--text); } } @@ -70,9 +74,16 @@ .global-info { background-color: var(--alertPopupNeutral, $fallback--fg); color: var(--alertPopupNeutralText, $fallback--text); - i { + .svg-inline--fa { color: var(--alertPopupNeutralText, $fallback--text); } } + + .close-notice { + padding-right: 0.2em; + .svg-inline--fa:hover { + opacity: 0.6; + } + } } </style> diff --git a/src/components/image_cropper/image_cropper.js b/src/components/image_cropper/image_cropper.js index 59e4d07e..e8d5ec6d 100644 --- a/src/components/image_cropper/image_cropper.js +++ b/src/components/image_cropper/image_cropper.js @@ -2,12 +2,10 @@ import Cropper from 'cropperjs' import 'cropperjs/dist/cropper.css' import { library } from '@fortawesome/fontawesome-svg-core' import { - faTimes, faCircleNotch } from '@fortawesome/free-solid-svg-icons' library.add( - faTimes, faCircleNotch ) @@ -53,8 +51,7 @@ const ImageCropper = { cropper: undefined, dataUrl: undefined, filename: undefined, - submitting: false, - submitError: null + submitting: false } }, computed: { @@ -66,9 +63,6 @@ const ImageCropper = { }, cancelText () { return this.cancelButtonLabel || this.$t('image_cropper.cancel') - }, - submitErrorMsg () { - return this.submitError && this.submitError instanceof Error ? this.submitError.toString() : this.submitError } }, methods: { @@ -82,12 +76,8 @@ const ImageCropper = { }, submit (cropping = true) { this.submitting = true - this.avatarUploadError = null this.submitHandler(cropping && this.cropper, this.file) .then(() => this.destroy()) - .catch((err) => { - this.submitError = err - }) .finally(() => { this.submitting = false }) @@ -113,9 +103,6 @@ const ImageCropper = { reader.readAsDataURL(this.file) this.$emit('changed', this.file, reader) } - }, - clearError () { - this.submitError = null } }, mounted () { diff --git a/src/components/image_cropper/image_cropper.vue b/src/components/image_cropper/image_cropper.vue index 448461b4..8c48a387 100644 --- a/src/components/image_cropper/image_cropper.vue +++ b/src/components/image_cropper/image_cropper.vue @@ -37,17 +37,6 @@ icon="circle-notch" /> </div> - <div - v-if="submitError" - class="alert error" - > - {{ submitErrorMsg }} - <FAIcon - class="fa-scale-110 fa-old-padding" - icon="times" - @click="clearError" - /> - </div> </div> <input ref="input" diff --git a/src/components/poll/poll.vue b/src/components/poll/poll.vue index 264a5f03..42819c19 100644 --- a/src/components/poll/poll.vue +++ b/src/components/poll/poll.vue @@ -42,7 +42,8 @@ :value="index" > <label class="option-vote"> - <div>{{ option.title }}</div> + <!-- eslint-disable-next-line vue/no-v-html --> + <div v-html="option.title_html" /> </label> </div> </div> diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue index 020eab05..2252c68f 100644 --- a/src/components/popover/popover.vue +++ b/src/components/popover/popover.vue @@ -95,6 +95,7 @@ box-shadow: none; width: 100%; height: 100%; + box-sizing: border-box; --btnText: var(--popoverText, $fallback--text); diff --git a/src/components/remote_follow/remote_follow.vue b/src/components/remote_follow/remote_follow.vue index cb1c2a1b..be827400 100644 --- a/src/components/remote_follow/remote_follow.vue +++ b/src/components/remote_follow/remote_follow.vue @@ -16,7 +16,7 @@ > <button click="submit" - class="remote-button" + class="button-default remote-button" > {{ $t('user_card.remote_follow') }} </button> diff --git a/src/components/settings_modal/tabs/filtering_tab.vue b/src/components/settings_modal/tabs/filtering_tab.vue index 813dc4cd..8f850c8b 100644 --- a/src/components/settings_modal/tabs/filtering_tab.vue +++ b/src/components/settings_modal/tabs/filtering_tab.vue @@ -75,6 +75,7 @@ <p>{{ $t('settings.filtering_explanation') }}</p> <textarea id="muteWords" + class="resize-height" v-model="muteWordsString" /> </div> diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js index df592a10..029ee7a1 100644 --- a/src/components/settings_modal/tabs/general_tab.js +++ b/src/components/settings_modal/tabs/general_tab.js @@ -34,6 +34,10 @@ const GeneralTab = { return this.$store.state.instance.postFormats || [] }, instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel }, + instanceWallpaperUsed () { + return this.$store.state.instance.background && + !this.$store.state.users.currentUser.background_image + }, ...SharedComputedObject() } } diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index c1d0d0ec..a9081793 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -11,6 +11,11 @@ {{ $t('settings.hide_isp') }} </Checkbox> </li> + <li v-if="instanceWallpaperUsed"> + <Checkbox v-model="hideInstanceWallpaper"> + {{ $t('settings.hide_wallpaper') }} + </Checkbox> + </li> </ul> </div> <div class="setting-item"> diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js index a4fed629..9709424c 100644 --- a/src/components/settings_modal/tabs/profile_tab.js +++ b/src/components/settings_modal/tabs/profile_tab.js @@ -45,9 +45,7 @@ const ProfileTab = { banner: null, bannerPreview: null, background: null, - backgroundPreview: null, - bannerUploadError: null, - backgroundUploadError: null + backgroundPreview: null } }, components: { @@ -162,18 +160,18 @@ const ProfileTab = { if (file.size > this.$store.state.instance[slot + 'limit']) { const filesize = fileSizeFormatService.fileSizeFormat(file.size) const allowedsize = fileSizeFormatService.fileSizeFormat(this.$store.state.instance[slot + 'limit']) - this[slot + 'UploadError'] = [ - this.$t('upload.error.base'), - this.$t( - 'upload.error.file_too_big', - { + this.$store.dispatch('pushGlobalNotice', { + messageKey: 'upload.error.message', + messageArgs: [ + this.$t('upload.error.file_too_big', { filesize: filesize.num, filesizeunit: filesize.unit, allowedsize: allowedsize.num, allowedsizeunit: allowedsize.unit - } - ) - ].join(' ') + }) + ], + level: 'error' + }) return } // eslint-disable-next-line no-undef @@ -213,8 +211,9 @@ const ProfileTab = { that.$store.commit('setCurrentUser', user) resolve() }) - .catch((err) => { - reject(new Error(that.$t('upload.error.base') + ' ' + err.message)) + .catch((error) => { + that.displayUploadError(error) + reject(error) }) } @@ -235,24 +234,27 @@ const ProfileTab = { this.$store.commit('setCurrentUser', user) this.bannerPreview = null }) - .catch((err) => { - this.bannerUploadError = this.$t('upload.error.base') + ' ' + err.message - }) - .then(() => { this.bannerUploading = false }) + .catch(this.displayUploadError) + .finally(() => { this.bannerUploading = false }) }, submitBackground (background) { if (!this.backgroundPreview && background !== '') { return } this.backgroundUploading = true - this.$store.state.api.backendInteractor.updateProfileImages({ background }).then((data) => { - if (!data.error) { + this.$store.state.api.backendInteractor.updateProfileImages({ background }) + .then((data) => { this.$store.commit('addNewUsers', [data]) this.$store.commit('setCurrentUser', data) this.backgroundPreview = null - } else { - this.backgroundUploadError = this.$t('upload.error.base') + data.error - } - this.backgroundUploading = false + }) + .catch(this.displayUploadError) + .finally(() => { this.backgroundUploading = false }) + }, + displayUploadError (error) { + this.$store.dispatch('pushGlobalNotice', { + messageKey: 'upload.error.message', + messageArgs: [error.message], + level: 'error' }) } } diff --git a/src/components/settings_modal/tabs/profile_tab.vue b/src/components/settings_modal/tabs/profile_tab.vue index 50d3ee63..b7ef21d7 100644 --- a/src/components/settings_modal/tabs/profile_tab.vue +++ b/src/components/settings_modal/tabs/profile_tab.vue @@ -11,7 +11,7 @@ <input id="username" v-model="newName" - classname="name-changer" + class="name-changer" > </EmojiInput> <p>{{ $t('settings.bio') }}</p> @@ -22,7 +22,7 @@ > <textarea v-model="newBio" - classname="bio" + class="bio resize-height" /> </EmojiInput> <p> @@ -229,17 +229,6 @@ > {{ $t('general.submit') }} </button> - <div - v-if="bannerUploadError" - class="alert error" - > - Error: {{ bannerUploadError }} - <FAIcon - class="fa-scale-110 fa-old-padding" - icon="times" - @click="clearUploadError('banner')" - /> - </div> </div> <div class="setting-item"> <h2>{{ $t('settings.profile_background') }}</h2> @@ -279,18 +268,6 @@ > {{ $t('general.submit') }} </button> - <div - v-if="backgroundUploadError" - class="alert error" - > - Error: {{ backgroundUploadError }} - <FAIcon - size="lg" - class="fa-scale-110 fa-old-padding" - icon="times" - @click="clearUploadError('background')" - /> - </div> </div> </div> </template> diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss index 926eceff..1b7d9f31 100644 --- a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss +++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss @@ -165,7 +165,8 @@ border-color: var(--border, $fallback--border); margin: 1em 0; padding: 1em; - background: var(--body-background-image); + background-color: var(--wallpaper); + background-image: var(--body-background-image); background-size: cover; background-position: 50% 50%; diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.vue b/src/components/settings_modal/tabs/theme_tab/theme_tab.vue index 4ab793d6..b8add42f 100644 --- a/src/components/settings_modal/tabs/theme_tab/theme_tab.vue +++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.vue @@ -617,6 +617,15 @@ /> </div> <div class="color-item"> + <h4>{{ $t('settings.style.advanced_colors.wallpaper') }}</h4> + <ColorInput + v-model="wallpaperColorLocal" + name="wallpaper" + :label="$t('settings.style.advanced_colors.wallpaper')" + :fallback="previewTheme.colors.wallpaper" + /> + </div> + <div class="color-item"> <h4>{{ $t('settings.style.advanced_colors.poll') }}</h4> <ColorInput v-model="pollColorLocal" diff --git a/src/components/status/status.js b/src/components/status/status.js index 142e1fc6..f9c710ab 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -26,7 +26,6 @@ import { faTimes, faRetweet, faReply, - faExternalLinkSquareAlt, faPlusSquare, faSmileBeam, faEllipsisH, @@ -44,7 +43,6 @@ library.add( faTimes, faRetweet, faReply, - faExternalLinkSquareAlt, faPlusSquare, faStar, faSmileBeam, diff --git a/src/components/status/status.scss b/src/components/status/status.scss index 70c6d03d..58b55bc8 100644 --- a/src/components/status/status.scss +++ b/src/components/status/status.scss @@ -139,6 +139,20 @@ $status-margin: 0.75em; .heading-right { display: flex; flex-shrink: 0; + + .button-unstyled { + padding: 5px; + margin: -5px; + + &:hover svg { + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); + } + } + + .svg-inline--fa { + margin-left: 0.25em; + } } .timeago { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 896635ee..6ee8117f 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -184,30 +184,20 @@ :title="status.visibility | capitalize" > <FAIcon - class="fa-scale-110 fa-old-padding" + fixed-width + class="fa-scale-110" :icon="visibilityIcon(status.visibility)" /> </span> - <a - v-if="!status.is_local && !isPreview" - :href="status.external_url" - target="_blank" - class="source_url" - title="Source" - > - <FAIcon - class="fa-scale-110 fa-old-padding" - icon="external-link-square-alt" - /> - </a> <button v-if="expandable && !isPreview" class="button-unstyled" - title="Expand" + :title="$t('status.expand')" @click.prevent="toggleExpanded" > <FAIcon - class="fa-scale-110 fa-old-padding" + fixed-width + class="fa-scale-110" icon="plus-square" /> </button> @@ -217,8 +207,9 @@ @click.prevent="toggleMute" > <FAIcon + fixed-width icon="eye-slash" - class="fa-scale-110 fa-old-padding" + class="fa-scale-110" /> </button> </span> diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue index 0326342b..4c43fe5c 100644 --- a/src/components/timeline/timeline.vue +++ b/src/components/timeline/timeline.vue @@ -102,6 +102,7 @@ .timeline-heading { max-width: 100%; flex-wrap: nowrap; + align-items: center; .loadmore-button { flex-shrink: 0; } diff --git a/src/components/timeline_menu/timeline_menu.js b/src/components/timeline_menu/timeline_menu.js index ef8a5813..8d6a58b1 100644 --- a/src/components/timeline_menu/timeline_menu.js +++ b/src/components/timeline_menu/timeline_menu.js @@ -59,6 +59,14 @@ const TimelineMenu = { this.isOpen = true }, 25) }, + blockOpen (event) { + // For the blank area inside the button element. + // Just setting @click.stop="" makes unintuitive behavior when + // menu is open and clicking on the blank area doesn't close it. + if (!this.isOpen) { + event.stopPropagation() + } + }, timelineName () { const route = this.$route.name if (route === 'tag-timeline') { diff --git a/src/components/timeline_menu/timeline_menu.vue b/src/components/timeline_menu/timeline_menu.vue index c46531be..3c86842b 100644 --- a/src/components/timeline_menu/timeline_menu.vue +++ b/src/components/timeline_menu/timeline_menu.vue @@ -65,10 +65,16 @@ slot="trigger" class="title timeline-menu-title" > - <span>{{ timelineName() }}</span> - <FAIcon - size="sm" - icon="chevron-down" + <span class="timeline-title">{{ timelineName() }}</span> + <span> + <FAIcon + size="sm" + icon="chevron-down" + /> + </span> + <span + class="click-blocker" + @click="blockOpen" /> </div> </Popover> @@ -117,8 +123,9 @@ cursor: pointer; user-select: none; width: 100%; + display: flex; - span { + .timeline-menu-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -128,6 +135,11 @@ margin-left: 0.6em; transition: transform 100ms; } + + .click-blocker { + cursor: default; + flex-grow: 1; + } } &.open .timeline-menu-title svg { diff --git a/src/hocs/with_load_more/with_load_more.js b/src/hocs/with_load_more/with_load_more.js index 7df9dbb2..671b2b6f 100644 --- a/src/hocs/with_load_more/with_load_more.js +++ b/src/hocs/with_load_more/with_load_more.js @@ -29,12 +29,8 @@ const withLoadMore = ({ return { loading: false, bottomedOut: false, - error: false - } - }, - computed: { - entries () { - return select(this.$props, this.$store) || [] + error: false, + entries: [] } }, created () { @@ -48,6 +44,11 @@ const withLoadMore = ({ destroy && destroy(this.$props, this.$store) }, methods: { + // Entries is not a computed because computed can't track the dynamic + // selector for changes and won't trigger after fetch. + updateEntries () { + this.entries = select(this.$props, this.$store) || [] + }, fetchEntries () { if (!this.loading) { this.loading = true @@ -61,6 +62,9 @@ const withLoadMore = ({ this.loading = false this.error = true }) + .finally(() => { + this.updateEntries() + }) } }, scrollLoad (e) { diff --git a/src/i18n/en.json b/src/i18n/en.json index ef23efd6..26dd6144 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -50,7 +50,8 @@ "scope_options": "Scope options", "text_limit": "Text limit", "title": "Features", - "who_to_follow": "Who to follow" + "who_to_follow": "Who to follow", + "upload_limit": "Upload limit" }, "finder": { "error_fetching_user": "Error fetching user", @@ -328,6 +329,7 @@ "hide_muted_posts": "Hide posts of muted users", "max_thumbnails": "Maximum amount of thumbnails per post", "hide_isp": "Hide instance-specific panel", + "hide_wallpaper": "Hide instance wallpaper", "preload_images": "Preload images", "use_one_click_nsfw": "Open NSFW attachments with just one click", "hide_post_stats": "Hide post statistics (e.g. the number of favorites)", @@ -515,6 +517,7 @@ "inputs": "Input fields", "faint_text": "Faded text", "underlay": "Underlay", + "wallpaper": "Wallpaper", "poll": "Poll graph", "icons": "Icons", "highlight": "Highlighted elements", @@ -661,6 +664,7 @@ "unmute_conversation": "Unmute conversation", "status_unavailable": "Status unavailable", "copy_link": "Copy link to status", + "external_source": "External source", "thread_muted": "Thread muted", "thread_muted_and_words": ", has words:", "show_full_subject": "Show full subject", @@ -668,7 +672,8 @@ "show_content": "Show content", "hide_content": "Hide content", "status_deleted": "This post was deleted", - "nsfw": "NSFW" + "nsfw": "NSFW", + "expand": "Expand" }, "user_card": { "approve": "Approve", @@ -758,6 +763,7 @@ "upload": { "error": { "base": "Upload failed.", + "message": "Upload failed: {0}", "file_too_big": "File too big [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]", "default": "Try again later" }, diff --git a/src/i18n/messages.js b/src/i18n/messages.js index c3195f10..2624d1d0 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -33,6 +33,7 @@ const loaders = { ro: () => import('./ro.json'), ru: () => import('./ru.json'), te: () => import('./te.json'), + uk: () => import('./uk.json'), zh: () => import('./zh.json') } diff --git a/src/modules/config.js b/src/modules/config.js index 444b8ec7..cd088737 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -20,6 +20,7 @@ export const defaultState = { customTheme: undefined, customThemeSource: undefined, hideISP: false, + hideInstanceWallpaper: false, // bad name: actually hides posts of muted USERS hideMutedPosts: undefined, // instance default collapseMessageWithSubject: undefined, // instance default diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index 8da933c4..f4483149 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -162,7 +162,12 @@ const updateProfileImages = ({ credentials, avatar = null, banner = null, backgr body: form }) .then((data) => data.json()) - .then((data) => parseUser(data)) + .then((data) => { + if (data.error) { + throw new Error(data.error) + } + return parseUser(data) + }) } const updateProfile = ({ credentials, params }) => { diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index e3a52489..b1e68df5 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -280,7 +280,7 @@ export const parseStatus = (data) => { if (output.poll) { output.poll.options = (output.poll.options || []).map(field => ({ ...field, - title_html: addEmojis(field.title, data.emojis) + title_html: addEmojis(escape(field.title), data.emojis) })) } output.pinned = data.pinned diff --git a/src/services/theme_data/pleromafe.js b/src/services/theme_data/pleromafe.js index 7ed85797..bec1eebd 100644 --- a/src/services/theme_data/pleromafe.js +++ b/src/services/theme_data/pleromafe.js @@ -84,6 +84,10 @@ export const SLOT_INHERITANCE = { opacity: 'bg', priority: 1 }, + wallpaper: { + depends: ['bg'], + color: (mod, bg) => brightness(-2 * mod, bg).rgb + }, fg: { depends: [], priority: 1 diff --git a/static/themes/redmond-xx-se.json b/static/themes/redmond-xx-se.json index 24480d2c..b62769db 100644 --- a/static/themes/redmond-xx-se.json +++ b/static/themes/redmond-xx-se.json @@ -267,6 +267,7 @@ }, "colors": { "bg": "#c0c0c0", + "wallpaper": "#008080", "text": "#000000", "link": "#0000ff", "accent": "#000080", diff --git a/static/themes/redmond-xx.json b/static/themes/redmond-xx.json index cf9010fe..83b59109 100644 --- a/static/themes/redmond-xx.json +++ b/static/themes/redmond-xx.json @@ -258,6 +258,7 @@ }, "colors": { "bg": "#c0c0c0", + "wallpaper": "#008080", "text": "#000000", "link": "#0000ff", "accent": "#000080", diff --git a/static/themes/redmond-xxi.json b/static/themes/redmond-xxi.json index 7fdc4a6d..60ceae7c 100644 --- a/static/themes/redmond-xxi.json +++ b/static/themes/redmond-xxi.json @@ -240,6 +240,7 @@ }, "colors": { "bg": "#d6d6ce", + "wallpaper": "#396ba5", "text": "#000000", "link": "#0000ff", "accent": "#0a246a", |
