change storage error one-off into a global notice system
This commit is contained in:
parent
0997e5ff66
commit
1293bec77e
8 changed files with 167 additions and 40 deletions
10
src/App.js
10
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 MobileNav from './components/mobile_nav/mobile_nav.vue'
|
||||||
import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue'
|
import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue'
|
||||||
import PostStatusModal from './components/post_status_modal/post_status_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'
|
import { windowWidth } from './services/window_utils/window_utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -32,7 +33,8 @@ export default {
|
||||||
MobileNav,
|
MobileNav,
|
||||||
SettingsModal,
|
SettingsModal,
|
||||||
UserReportingModal,
|
UserReportingModal,
|
||||||
PostStatusModal
|
PostStatusModal,
|
||||||
|
GlobalNoticeList
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
mobileActivePanel: 'timeline',
|
mobileActivePanel: 'timeline',
|
||||||
|
@ -107,9 +109,6 @@ export default {
|
||||||
return {
|
return {
|
||||||
'order': this.$store.state.instance.sidebarRight ? 99 : 0
|
'order': this.$store.state.instance.sidebarRight ? 99 : 0
|
||||||
}
|
}
|
||||||
},
|
|
||||||
showStorageError () {
|
|
||||||
return this.$store.state.interface.storageError === 'show'
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -132,9 +131,6 @@ export default {
|
||||||
if (changed) {
|
if (changed) {
|
||||||
this.$store.dispatch('setMobileLayout', mobileLayout)
|
this.$store.dispatch('setMobileLayout', mobileLayout)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
hideStorageError () {
|
|
||||||
this.$store.dispatch('setStorageError', 'hide')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -806,15 +806,6 @@ nav {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.storage-error-notice {
|
|
||||||
text-align: center;
|
|
||||||
i {
|
|
||||||
cursor: pointer;
|
|
||||||
color: $fallback--text;
|
|
||||||
color: var(--alertErrorText, $fallback--text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-icon {
|
.button-icon {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
11
src/App.vue
11
src/App.vue
|
@ -101,16 +101,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div
|
|
||||||
v-if="showStorageError"
|
|
||||||
class="alert error storage-error-notice"
|
|
||||||
>
|
|
||||||
{{ $t("errors.storage_unavailable") }}
|
|
||||||
<i
|
|
||||||
class="icon-cancel"
|
|
||||||
@click="hideStorageError"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
v-if="!currentUser"
|
v-if="!currentUser"
|
||||||
class="login-hint panel panel-default"
|
class="login-hint panel panel-default"
|
||||||
|
@ -138,6 +128,7 @@
|
||||||
<PostStatusModal />
|
<PostStatusModal />
|
||||||
<SettingsModal />
|
<SettingsModal />
|
||||||
<portal-target name="modal" />
|
<portal-target name="modal" />
|
||||||
|
<GlobalNoticeList />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
15
src/components/global_notice_list/global_notice_list.js
Normal file
15
src/components/global_notice_list/global_notice_list.js
Normal file
|
@ -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
|
77
src/components/global_notice_list/global_notice_list.vue
Normal file
77
src/components/global_notice_list/global_notice_list.vue
Normal file
|
@ -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>
|
16
src/main.js
16
src/main.js
|
@ -62,14 +62,14 @@ const persistedStateOptions = {
|
||||||
};
|
};
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
let persistedState
|
let storageError = false
|
||||||
let storageError = 'none'
|
const plugins = [pushNotifications]
|
||||||
try {
|
try {
|
||||||
persistedState = await createPersistedState(persistedStateOptions)
|
const persistedState = await createPersistedState(persistedStateOptions)
|
||||||
|
plugins.push(persistedState)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
storageError = 'show'
|
storageError = true
|
||||||
persistedState = _ => _
|
|
||||||
}
|
}
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
modules: {
|
modules: {
|
||||||
|
@ -93,11 +93,13 @@ const persistedStateOptions = {
|
||||||
polls: pollsModule,
|
polls: pollsModule,
|
||||||
postStatus: postStatusModule
|
postStatus: postStatusModule
|
||||||
},
|
},
|
||||||
plugins: [persistedState, pushNotifications],
|
plugins,
|
||||||
strict: false // Socket modifies itself, let's ignore this for now.
|
strict: false // Socket modifies itself, let's ignore this for now.
|
||||||
// strict: process.env.NODE_ENV !== 'production'
|
// strict: process.env.NODE_ENV !== 'production'
|
||||||
})
|
})
|
||||||
store.dispatch('setStorageError', storageError)
|
if (storageError) {
|
||||||
|
store.dispatch('pushGlobalNotice', { messageKey: 'errors.storage_unavailable', level: 'error' })
|
||||||
|
}
|
||||||
afterStoreSetup({ store, i18n })
|
afterStoreSetup({ store, i18n })
|
||||||
})()
|
})()
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,14 @@ const defaultState = {
|
||||||
noticeClearTimeout: null,
|
noticeClearTimeout: null,
|
||||||
notificationPermission: null
|
notificationPermission: null
|
||||||
},
|
},
|
||||||
storageError: 'none',
|
|
||||||
browserSupport: {
|
browserSupport: {
|
||||||
cssFilter: window.CSS && window.CSS.supports && (
|
cssFilter: window.CSS && window.CSS.supports && (
|
||||||
window.CSS.supports('filter', 'drop-shadow(0 0)') ||
|
window.CSS.supports('filter', 'drop-shadow(0 0)') ||
|
||||||
window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)')
|
window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)')
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
mobileLayout: false
|
mobileLayout: false,
|
||||||
|
globalNotices: []
|
||||||
}
|
}
|
||||||
|
|
||||||
const interfaceMod = {
|
const interfaceMod = {
|
||||||
|
@ -60,8 +60,11 @@ const interfaceMod = {
|
||||||
state.settingsModalLoaded = true
|
state.settingsModalLoaded = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setStorageError (state, value) {
|
pushGlobalNotice (state, notice) {
|
||||||
state.storageError = value
|
state.globalNotices.push(notice)
|
||||||
|
},
|
||||||
|
removeGlobalNotice (state, notice) {
|
||||||
|
state.globalNotices = state.globalNotices.filter(n => n !== notice)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
@ -86,8 +89,26 @@ const interfaceMod = {
|
||||||
togglePeekSettingsModal ({ commit }) {
|
togglePeekSettingsModal ({ commit }) {
|
||||||
commit('togglePeekSettingsModal')
|
commit('togglePeekSettingsModal')
|
||||||
},
|
},
|
||||||
setStorageError ({ commit }, value) {
|
pushGlobalNotice (
|
||||||
commit('setStorageError', value)
|
{ commit, dispatch },
|
||||||
|
{
|
||||||
|
messageKey,
|
||||||
|
messageArgs = {},
|
||||||
|
level = 'error',
|
||||||
|
timeout = 0
|
||||||
|
}) {
|
||||||
|
const notice = {
|
||||||
|
messageKey,
|
||||||
|
messageArgs,
|
||||||
|
level
|
||||||
|
}
|
||||||
|
if (timeout) {
|
||||||
|
setTimeout(() => dispatch('removeGlobalNotice', notice), timeout)
|
||||||
|
}
|
||||||
|
commit('pushGlobalNotice', notice)
|
||||||
|
},
|
||||||
|
removeGlobalNotice ({ commit }, notice) {
|
||||||
|
commit('removeGlobalNotice', notice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,8 @@ export const DEFAULT_OPACITY = {
|
||||||
alert: 0.5,
|
alert: 0.5,
|
||||||
input: 0.5,
|
input: 0.5,
|
||||||
faint: 0.5,
|
faint: 0.5,
|
||||||
underlay: 0.15
|
underlay: 0.15,
|
||||||
|
alertPopup: 0.85
|
||||||
}
|
}
|
||||||
|
|
||||||
/** SUBJECT TO CHANGE IN THE FUTURE, this is all beta
|
/** SUBJECT TO CHANGE IN THE FUTURE, this is all beta
|
||||||
|
@ -627,6 +628,39 @@ export const SLOT_INHERITANCE = {
|
||||||
textColor: true
|
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',
|
badgeNotification: '--cRed',
|
||||||
badgeNotificationText: {
|
badgeNotificationText: {
|
||||||
depends: ['text', 'badgeNotification'],
|
depends: ['text', 'badgeNotification'],
|
||||||
|
|
Loading…
Reference in a new issue