diff --git a/CHANGELOG.md b/CHANGELOG.md index f1e0dec201c602a44824c3b3fb2ea7d9c3ba5422..5d1bd11880eefbff835cded14d453b9a9f4946d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix status ellipsis menu being cut off in notifications column - Fixed autocomplete sometimes not returning the right user when there's already some results - Reply filtering options in Settings -> Filtering now work again using filtering on server +- Don't show just blank-screen when cookies are disabled ## [2.0.3] - 2020-05-02 ### Fixed diff --git a/src/App.js b/src/App.js index 040138c978bd98dfe3e0eea0f417aba57e73be9b..92c4e2f58266b22c0b5b3e9cffa20af4e3c51f23 100644 --- a/src/App.js +++ b/src/App.js @@ -13,6 +13,7 @@ import MobilePostStatusButton from './components/mobile_post_status_button/mobil import MobileNav from './components/mobile_nav/mobile_nav.vue' import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue' import PostStatusModal from './components/post_status_modal/post_status_modal.vue' +import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue' import { windowWidth } from './services/window_utils/window_utils' export default { @@ -32,7 +33,8 @@ export default { MobileNav, SettingsModal, UserReportingModal, - PostStatusModal + PostStatusModal, + GlobalNoticeList }, data: () => ({ mobileActivePanel: 'timeline', diff --git a/src/App.vue b/src/App.vue index 7b9ad3dc1233f33d2311215454ec39c2d3c8c440..03b632eccb5a3be0667944789fbd0c4b8f6e1dae 100644 --- a/src/App.vue +++ b/src/App.vue @@ -128,6 +128,7 @@ <PostStatusModal /> <SettingsModal /> <portal-target name="modal" /> + <GlobalNoticeList /> </div> </template> diff --git a/src/components/global_notice_list/global_notice_list.js b/src/components/global_notice_list/global_notice_list.js new file mode 100644 index 0000000000000000000000000000000000000000..3af29c23421eff018fb9f60320ca54e124827796 --- /dev/null +++ b/src/components/global_notice_list/global_notice_list.js @@ -0,0 +1,15 @@ + +const GlobalNoticeList = { + computed: { + notices () { + return this.$store.state.interface.globalNotices + } + }, + methods: { + closeNotice (notice) { + this.$store.dispatch('removeGlobalNotice', notice) + } + } +} + +export default GlobalNoticeList diff --git a/src/components/global_notice_list/global_notice_list.vue b/src/components/global_notice_list/global_notice_list.vue new file mode 100644 index 0000000000000000000000000000000000000000..0e4285ccff8ad1bb5b48512ad26f13c2d326a397 --- /dev/null +++ b/src/components/global_notice_list/global_notice_list.vue @@ -0,0 +1,77 @@ +<template> + <div class="global-notice-list"> + <div + v-for="(notice, index) in notices" + :key="index" + class="alert global-notice" + :class="{ ['global-' + notice.level]: true }" + > + <div class="notice-message"> + {{ $t(notice.messageKey, notice.messageArgs) }} + </div> + <i + class="button-icon icon-cancel" + @click="closeNotice(notice)" + /> + </div> + </div> +</template> + +<script src="./global_notice_list.js"></script> + +<style lang="scss"> +@import '../../_variables.scss'; + +.global-notice-list { + position: fixed; + top: 50px; + width: 100%; + pointer-events: none; + z-index: 1001; + display: flex; + flex-direction: column; + align-items: center; + + .global-notice { + pointer-events: auto; + text-align: center; + width: 40em; + max-width: calc(100% - 3em); + display: flex; + padding-left: 1.5em; + line-height: 2em; + .notice-message { + flex: 1 1 100%; + } + i { + flex: 0 0; + width: 1.5em; + cursor: pointer; + } + } + + .global-error { + background-color: var(--alertPopupError, $fallback--cRed); + color: var(--alertPopupErrorText, $fallback--text); + i { + color: var(--alertPopupErrorText, $fallback--text); + } + } + + .global-warning { + background-color: var(--alertPopupWarning, $fallback--cOrange); + color: var(--alertPopupWarningText, $fallback--text); + i { + color: var(--alertPopupWarningText, $fallback--text); + } + } + + .global-info { + background-color: var(--alertPopupNeutral, $fallback--fg); + color: var(--alertPopupNeutralText, $fallback--text); + i { + color: var(--alertPopupNeutralText, $fallback--text); + } + } +} +</style> diff --git a/src/i18n/en.json b/src/i18n/en.json index 2e48c4738c02885302a8c050170b4e92fbc6c66b..8f13dfe9e1ca901f6bea86327fa120ab25a97565 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -164,6 +164,9 @@ "load_all_hint": "Loaded first {saneAmount} emoji, loading all emoji may cause performance issues.", "load_all": "Loading all {emojiAmount} emoji" }, + "errors": { + "storage_unavailable": "Pleroma could not access browser storage. Your login or your local settings won't be saved and you might encounter unexpected issues. Try enabling cookies." + }, "interactions": { "favs_repeats": "Repeats and Favorites", "follows": "New follows", diff --git a/src/main.js b/src/main.js index 9a201e4fac76b041a7931c2b7e764750f7f33252..5bddc76e4a4428e23cf04b70418654c86d8c0478 100644 --- a/src/main.js +++ b/src/main.js @@ -62,7 +62,15 @@ const persistedStateOptions = { }; (async () => { - const persistedState = await createPersistedState(persistedStateOptions) + let storageError = false + const plugins = [pushNotifications] + try { + const persistedState = await createPersistedState(persistedStateOptions) + plugins.push(persistedState) + } catch (e) { + console.error(e) + storageError = true + } const store = new Vuex.Store({ modules: { i18n: { @@ -85,11 +93,13 @@ const persistedStateOptions = { polls: pollsModule, postStatus: postStatusModule }, - plugins: [persistedState, pushNotifications], + plugins, strict: false // Socket modifies itself, let's ignore this for now. // strict: process.env.NODE_ENV !== 'production' }) - + if (storageError) { + store.dispatch('pushGlobalNotice', { messageKey: 'errors.storage_unavailable', level: 'error' }) + } afterStoreSetup({ store, i18n }) })() diff --git a/src/modules/interface.js b/src/modules/interface.js index eeebd65ebf5047b0083e0ac5849684ac0bc7f82b..e31630fcb2d05856bb32c6ab58094afcd79d6139 100644 --- a/src/modules/interface.js +++ b/src/modules/interface.js @@ -14,7 +14,8 @@ const defaultState = { window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)') ) }, - mobileLayout: false + mobileLayout: false, + globalNotices: [] } const interfaceMod = { @@ -58,6 +59,12 @@ const interfaceMod = { if (!state.settingsModalLoaded) { state.settingsModalLoaded = true } + }, + pushGlobalNotice (state, notice) { + state.globalNotices.push(notice) + }, + removeGlobalNotice (state, notice) { + state.globalNotices = state.globalNotices.filter(n => n !== notice) } }, actions: { @@ -81,6 +88,28 @@ const interfaceMod = { }, togglePeekSettingsModal ({ commit }) { commit('togglePeekSettingsModal') + }, + pushGlobalNotice ( + { commit, dispatch }, + { + messageKey, + messageArgs = {}, + level = 'error', + timeout = 0 + }) { + const notice = { + messageKey, + messageArgs, + level + } + if (timeout) { + setTimeout(() => dispatch('removeGlobalNotice', notice), timeout) + } + commit('pushGlobalNotice', notice) + return notice + }, + removeGlobalNotice ({ commit }, notice) { + commit('removeGlobalNotice', notice) } } } diff --git a/src/services/theme_data/pleromafe.js b/src/services/theme_data/pleromafe.js index b577cfab85b4055c5abeeaa7f13f1f839224be67..6b25cd6f65f37b3631269a576b527be243c6ad76 100644 --- a/src/services/theme_data/pleromafe.js +++ b/src/services/theme_data/pleromafe.js @@ -34,7 +34,8 @@ export const DEFAULT_OPACITY = { alert: 0.5, input: 0.5, faint: 0.5, - underlay: 0.15 + underlay: 0.15, + alertPopup: 0.95 } /** SUBJECT TO CHANGE IN THE FUTURE, this is all beta @@ -627,6 +628,39 @@ export const SLOT_INHERITANCE = { textColor: true }, + alertPopupError: { + depends: ['alertError'], + opacity: 'alertPopup' + }, + alertPopupErrorText: { + depends: ['alertErrorText'], + layer: 'popover', + variant: 'alertPopupError', + textColor: true + }, + + alertPopupWarning: { + depends: ['alertWarning'], + opacity: 'alertPopup' + }, + alertPopupWarningText: { + depends: ['alertWarningText'], + layer: 'popover', + variant: 'alertPopupWarning', + textColor: true + }, + + alertPopupNeutral: { + depends: ['alertNeutral'], + opacity: 'alertPopup' + }, + alertPopupNeutralText: { + depends: ['alertNeutralText'], + layer: 'popover', + variant: 'alertPopupNeutral', + textColor: true + }, + badgeNotification: '--cRed', badgeNotificationText: { depends: ['text', 'badgeNotification'],