Move modal frame parts away from modal-content into modal, improve error handling

This commit is contained in:
Henry Jameson 2020-05-26 23:58:55 +03:00
parent 5187b37aca
commit a8e013bd65
10 changed files with 190 additions and 178 deletions

View file

@ -1,19 +1,17 @@
<template> <template>
<div class="error-window panel"> <div class="async-component-error">
<div class="panel-heading"> <div>
<span class="title"> <h4>
{{ $t('general.generic_error') }} {{ $t('general.generic_error') }}
</span> </h4>
</div>
<div class="panel-body">
<p> <p>
{{ $t('general.error_retry') }} {{ $t('general.error_retry') }}
</p> </p>
<button <button
class="btn" class="btn"
@click="closeAllModals" @click="retry"
> >
{{ $t('general.close') }} {{ $t('general.retry') }}
</button> </button>
</div> </div>
</div> </div>
@ -22,9 +20,7 @@
<script> <script>
export default { export default {
methods: { methods: {
closeAllModals () { retry () {
// TODO make a global hook to close all modals?
this.$store.dispatch('closeSettingsModal')
this.$emit('resetAsyncComponent') this.$emit('resetAsyncComponent')
} }
} }
@ -32,7 +28,11 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.error-window { .async-component-error {
display: flex;
height: 100%;
align-items: center;
justify-content: center;
.btn { .btn {
margin: .5em; margin: .5em;
padding: .5em 2em; padding: .5em 2em;

View file

@ -1,16 +0,0 @@
<template>
<div class="big-spinner">
<i class="icon-spin4 animate-spin" />
</div>
</template>
<style lang="scss">
.big-spinner {
font-size: 15em;
line-height: 0;
opacity: .6;
> i {
color: white;
}
}
</style>

View file

@ -0,0 +1,29 @@
<template>
<div class="panel-loading">
<span class="loading-text">
<i class="icon-spin4 animate-spin" />
{{ $t('general.loading') }}
</span>
</div>
</template>
<style lang="scss">
@import 'src/_variables.scss';
.panel-loading {
display: flex;
height: 100%;
align-items: center;
justify-content: center;
font-size: 2em;
color: $fallback--text;
color: var(--text, $fallback--text);
.loading-text i {
font-size: 3em;
line-height: 0;
vertical-align: middle;
color: $fallback--text;
color: var(--text, $fallback--text);
}
}
</style>

View file

@ -1,6 +1,6 @@
import Modal from 'src/components/modal/modal.vue' import Modal from 'src/components/modal/modal.vue'
import BigSpinner from 'src/components/big_spinner/big_spinner.vue' import PanelLoading from 'src/components/panel_loading/panel_loading.vue'
import ErrorWindow from 'src/components/error_window/error_window.vue' import AsyncComponentError from 'src/components/async_component_error/async_component_error.vue'
import getResettableAsyncComponent from 'src/services/resettable_async_component.js' import getResettableAsyncComponent from 'src/services/resettable_async_component.js'
const SettingsModal = { const SettingsModal = {
@ -9,12 +9,20 @@ const SettingsModal = {
SettingsModalContent: getResettableAsyncComponent( SettingsModalContent: getResettableAsyncComponent(
() => import('./settings_modal_content.vue'), () => import('./settings_modal_content.vue'),
{ {
loading: BigSpinner, loading: PanelLoading,
error: ErrorWindow, error: AsyncComponentError,
delay: 0 delay: 0
} }
) )
}, },
methods: {
closeModal () {
this.$store.dispatch('closeSettingsModal')
},
peekModal () {
this.$store.dispatch('togglePeekSettingsModal')
}
},
computed: { computed: {
modalActivated () { modalActivated () {
return this.$store.state.interface.settingsModalState !== 'hidden' return this.$store.state.interface.settingsModalState !== 'hidden'

View file

@ -3,7 +3,7 @@
overflow: hidden; overflow: hidden;
&.peek { &.peek {
.modal-panel { .settings-modal-panel {
/* Explanation: /* Explanation:
* Modal is positioned vertically centered. * Modal is positioned vertically centered.
* 100vh - 100% = Distance between modal's top+bottom boundaries and screen * 100vh - 100% = Distance between modal's top+bottom boundaries and screen
@ -15,4 +15,30 @@
transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px)); transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px));
} }
} }
.settings-modal-panel {
overflow: hidden;
transition: transform;
transition-timing-function: ease-in-out;
transition-duration: 300ms;
width: 1000px;
max-width: 90vw;
height: 90vh;
@media all and (max-width: 800px) {
max-width: 100vw;
height: 100vh;
}
.panel-body {
height: 100%;
overflow-y: hidden;
.btn {
min-height: 28px;
min-width: 10em;
padding: 0 2em;
}
}
}
} }

View file

@ -5,10 +5,47 @@
:class="{ peek: modalPeeked }" :class="{ peek: modalPeeked }"
:no-background="modalPeeked" :no-background="modalPeeked"
> >
<SettingsModalContent <div class="settings-modal-panel panel">
v-if="modalActivated" <div class="panel-heading">
class="modal-panel" <span class="title">
/> {{ $t('settings.settings') }}
</span>
<transition name="fade">
<template v-if="currentSaveStateNotice">
<div
v-if="currentSaveStateNotice.error"
class="alert error"
@click.prevent
>
{{ $t('settings.saving_err') }}
</div>
<div
v-if="!currentSaveStateNotice.error"
class="alert transparent"
@click.prevent
>
{{ $t('settings.saving_ok') }}
</div>
</template>
</transition>
<button
class="btn"
@click="peekModal"
>
{{ $t('general.peek') }}
</button>
<button
class="btn"
@click="closeModal"
>
{{ $t('general.close') }}
</button>
</div>
<div class="panel-body">
<SettingsModalContent v-if="modalActivated" />
</div>
</div>
</Modal> </Modal>
</template> </template>

View file

@ -31,14 +31,6 @@ const SettingsModalContent = {
isLoggedIn () { isLoggedIn () {
return !!this.$store.state.users.currentUser return !!this.$store.state.users.currentUser
} }
},
methods: {
closeModal () {
this.$store.dispatch('closeSettingsModal')
},
peekModal () {
this.$store.dispatch('togglePeekSettingsModal')
}
} }
} }

View file

@ -1,32 +1,6 @@
@import 'src/_variables.scss'; @import 'src/_variables.scss';
.settings_tab-switcher {
.settings-modal-panel { height: 100%;
overflow: hidden;
transition: transform;
transition-timing-function: ease-in-out;
transition-duration: 300ms;
width: 1000px;
max-width: 90vw;
height: 90vh;
@media all and (max-width: 800px) {
max-width: 100vw;
height: 100vh;
}
.settings_tab-switcher {
height: 100%;
}
.panel-body {
height: 100%;
overflow-y: hidden;
.btn {
min-height: 28px;
min-width: 10em;
padding: 0 2em;
}
}
.full-height { .full-height {
height: 100%; height: 100%;

View file

@ -1,112 +1,72 @@
<template> <template>
<div class="settings-modal-panel panel"> <tab-switcher
<div class="panel-heading"> ref="tabSwitcher"
<span class="title"> class="settings_tab-switcher"
{{ $t('settings.settings') }} :side-tab-bar="true"
</span> :scrollable-tabs="true"
<transition name="fade"> >
<template v-if="currentSaveStateNotice"> <div
<div :label="$t('settings.general')"
v-if="currentSaveStateNotice.error" icon="wrench"
class="alert error"
@click.prevent
>
{{ $t('settings.saving_err') }}
</div>
<div
v-if="!currentSaveStateNotice.error"
class="alert transparent"
@click.prevent
>
{{ $t('settings.saving_ok') }}
</div>
</template>
</transition>
<button
class="btn"
@click="peekModal"
> >
{{ $t('general.peek') }} <GeneralTab />
</button>
<button
class="btn"
@click="closeModal"
>
{{ $t('general.close') }}
</button>
</div> </div>
<div class="panel-body"> <div
<tab-switcher v-if="isLoggedIn"
ref="tabSwitcher" :label="$t('settings.profile_tab')"
class="settings_tab-switcher" icon="user"
:side-tab-bar="true"
:scrollable-tabs="true"
> >
<div <ProfileTab />
:label="$t('settings.general')"
icon="wrench"
>
<GeneralTab />
</div>
<div
v-if="isLoggedIn"
:label="$t('settings.profile_tab')"
icon="user"
>
<ProfileTab />
</div>
<div
v-if="isLoggedIn"
:label="$t('settings.security_tab')"
icon="lock"
>
<SecurityTab />
</div>
<div
:label="$t('settings.filtering')"
icon="filter"
>
<FilteringTab />
</div>
<div
:label="$t('settings.theme')"
icon="brush"
>
<ThemeTab />
</div>
<div
v-if="isLoggedIn"
:label="$t('settings.notifications')"
icon="chat"
>
<NotificationsTab />
</div>
<div
v-if="isLoggedIn"
:label="$t('settings.data_import_export_tab')"
icon="download"
>
<DataImportExportTab />
</div>
<div
v-if="isLoggedIn"
:label="$t('settings.mutes_and_blocks')"
:fullHeight="true"
class="full-height"
icon="eye-off"
>
<MutesAndBlocksTab />
</div>
<div
:label="$t('settings.version.title')"
icon="info-circled"
>
<VersionTab />
</div>
</tab-switcher>
</div> </div>
</div> <div
v-if="isLoggedIn"
:label="$t('settings.security_tab')"
icon="lock"
>
<SecurityTab />
</div>
<div
:label="$t('settings.filtering')"
icon="filter"
>
<FilteringTab />
</div>
<div
:label="$t('settings.theme')"
icon="brush"
>
<ThemeTab />
</div>
<div
v-if="isLoggedIn"
:label="$t('settings.notifications')"
icon="chat"
>
<NotificationsTab />
</div>
<div
v-if="isLoggedIn"
:label="$t('settings.data_import_export_tab')"
icon="download"
>
<DataImportExportTab />
</div>
<div
v-if="isLoggedIn"
:label="$t('settings.mutes_and_blocks')"
:fullHeight="true"
class="full-height"
icon="eye-off"
>
<MutesAndBlocksTab />
</div>
<div
:label="$t('settings.version.title')"
icon="info-circled"
>
<VersionTab />
</div>
</tab-switcher>
</template> </template>
<script src="./settings_modal_content.js"></script> <script src="./settings_modal_content.js"></script>

View file

@ -59,8 +59,10 @@
"apply": "Apply", "apply": "Apply",
"submit": "Submit", "submit": "Submit",
"more": "More", "more": "More",
"loading": "Loading…",
"generic_error": "An error occured", "generic_error": "An error occured",
"error_retry": "Please try again", "error_retry": "Please try again",
"retry": "Try again",
"optional": "optional", "optional": "optional",
"show_more": "Show more", "show_more": "Show more",
"show_less": "Show less", "show_less": "Show less",