logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git
commit: 4d23d31fecf480abfccc4db3ac79c6640078dc3b
parent 9632b77786a9d3735f04ecf4a814311fad926ad0
Author: Henry Jameson <me@hjkos.com>
Date:   Tue, 14 Mar 2023 21:50:43 +0200

initial admin settings prototype (WIP)

Diffstat:

Asrc/components/admin_modal/admin_modal.js68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/admin_modal/admin_modal.scss80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/admin_modal/admin_modal.vue121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/admin_modal/admin_modal_content.js88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/admin_modal/admin_modal_content.scss56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/admin_modal/tabs/general_tab.js33+++++++++++++++++++++++++++++++++
Msrc/components/desktop_nav/desktop_nav.js5++++-
Msrc/components/desktop_nav/desktop_nav.vue9++++-----
Msrc/components/notification/notification.vue2+-
Asrc/components/settings_modal/admin_tabs/instance_tab.js29+++++++++++++++++++++++++++++
Asrc/components/settings_modal/admin_tabs/instance_tab.vue35+++++++++++++++++++++++++++++++++++
Msrc/components/settings_modal/helpers/setting.js14+++++++++++++-
Asrc/components/settings_modal/helpers/string_setting.js9+++++++++
Asrc/components/settings_modal/helpers/string_setting.vue25+++++++++++++++++++++++++
Msrc/components/settings_modal/settings_modal.js23++++++++++++++++++-----
Msrc/components/settings_modal/settings_modal.vue3++-
Asrc/components/settings_modal/settings_modal_admin_content.js76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Rsrc/components/settings_modal/settings_modal_content.scss -> src/components/settings_modal/settings_modal_admin_content.scss0
Asrc/components/settings_modal/settings_modal_admin_content.vue21+++++++++++++++++++++
Dsrc/components/settings_modal/settings_modal_content.vue83-------------------------------------------------------------------------------
Rsrc/components/settings_modal/settings_modal_content.js -> src/components/settings_modal/settings_modal_user_content.js0
Rsrc/components/settings_modal/settings_modal_content.scss -> src/components/settings_modal/settings_modal_user_content.scss0
Asrc/components/settings_modal/settings_modal_user_content.vue83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/components/tab_switcher/tab_switcher.jsx8+-------
Msrc/modules/adminSettings.js5+++--
Msrc/modules/interface.js21+++++++++++++++------
26 files changed, 785 insertions(+), 112 deletions(-)

diff --git a/src/components/admin_modal/admin_modal.js b/src/components/admin_modal/admin_modal.js @@ -0,0 +1,68 @@ +import Modal from 'src/components/modal/modal.vue' +import PanelLoading from 'src/components/panel_loading/panel_loading.vue' +import AsyncComponentError from 'src/components/async_component_error/async_component_error.vue' +import getResettableAsyncComponent from 'src/services/resettable_async_component.js' +import Popover from '../popover/popover.vue' +import Checkbox from 'src/components/checkbox/checkbox.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + newImporter, + newExporter +} from 'src/services/export_import/export_import.js' +import { + faTimes, + faFileUpload, + faFileDownload, + faChevronDown +} from '@fortawesome/free-solid-svg-icons' +import { + faWindowMinimize +} from '@fortawesome/free-regular-svg-icons' + +library.add( + faTimes, + faWindowMinimize, + faFileUpload, + faFileDownload, + faChevronDown +) + +const AdminModal = { + data () { + return {} + }, + components: { + Modal, + Popover, + Checkbox, + AdminModalContent: getResettableAsyncComponent( + () => import('./admin_modal_content.vue'), + { + loadingComponent: PanelLoading, + errorComponent: AsyncComponentError, + delay: 0 + } + ) + }, + methods: { + closeModal () { + this.$store.dispatch('closeAdminModal') + }, + peekModal () { + this.$store.dispatch('togglePeekAdminModal') + } + }, + computed: { + modalActivated () { + return this.$store.state.interface.adminModalState !== 'hidden' + }, + modalOpenedOnce () { + return this.$store.state.interface.adminModalLoaded + }, + modalPeeked () { + return this.$store.state.interface.adminModalState === 'minimized' + } + } +} + +export default AdminModal diff --git a/src/components/admin_modal/admin_modal.scss b/src/components/admin_modal/admin_modal.scss @@ -0,0 +1,80 @@ +@import "src/variables"; + +.admin-modal { + overflow: hidden; + + .setting-list, + .option-list { + list-style-type: none; + padding-left: 2em; + + li { + margin-bottom: 0.5em; + } + + .suboptions { + margin-top: 0.3em; + } + } + + .admin-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: 100%; + } + + >.panel-body { + height: 100%; + overflow-y: hidden; + + .btn { + min-height: 2em; + min-width: 10em; + padding: 0 2em; + } + } + } + + .admin-footer { + display: flex; + + >* { + margin-right: 0.5em; + } + + .extra-content { + display: flex; + flex-grow: 1; + } + } + + &.peek { + .admin-modal-panel { + /* Explanation: + * Modal is positioned vertically centered. + * 100vh - 100% = Distance between modal's top+bottom boundaries and screen + * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen + * + 100% - we move modal completely off-screen, it's top boundary touches + * bottom of the screen + * - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible + */ + transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px)); + + @media all and (max-width: 800px) { + /* For mobile, the modal takes 100% of the available screen. + This ensures the minimized modal is always 50px above the browser bottom + bar regardless of whether or not it is visible. + */ + transform: translateY(calc(100% - 50px)); + } + } + } +} diff --git a/src/components/admin_modal/admin_modal.vue b/src/components/admin_modal/admin_modal.vue @@ -0,0 +1,121 @@ +<template> + <Modal + :is-open="modalActivated" + class="admin-modal" + :class="{ peek: modalPeeked }" + :no-background="modalPeeked" + > + <div class="admin-modal-panel panel"> + <div class="panel-heading"> + <span class="title"> + {{ $t('admin.settings') }} + </span> + <transition name="fade"> + <div + v-if="currentSaveStateNotice" + class="alert" + :class="{ transparent: !currentSaveStateNotice.error, error: currentSaveStateNotice.error}" + @click.prevent + > + {{ currentSaveStateNotice.error ? $t('admin.saving_err') : $t('settings.saving_ok') }} + </div> + </transition> + <button + class="btn button-default" + :title="$t('general.peek')" + @click="peekModal" + > + <FAIcon + :icon="['far', 'window-minimize']" + fixed-width + /> + </button> + <button + class="btn button-default" + :title="$t('general.close')" + @click="closeModal" + > + <FAIcon + icon="times" + fixed-width + /> + </button> + </div> + <div class="panel-body"> + <AdminModalContent v-if="modalOpenedOnce" /> + </div> + <div class="panel-footer admin-footer"> + <Popover + class="export" + trigger="click" + placement="top" + :offset="{ y: 5, x: 5 }" + :bound-to="{ x: 'container' }" + remove-padding + > + <template #trigger> + <button + class="btn button-default" + :title="$t('general.close')" + > + <span>{{ $t("admin.file_export_import.backup_restore") }}</span> + {{ ' ' }} + <FAIcon + icon="chevron-down" + /> + </button> + </template> + <template #content="{close}"> + <div class="dropdown-menu"> + <button + class="button-default dropdown-item dropdown-item-icon" + @click.prevent="backup" + @click="close" + > + <FAIcon + icon="file-download" + fixed-width + /><span>{{ $t("admin.file_export_import.backup_settings") }}</span> + </button> + <button + class="button-default dropdown-item dropdown-item-icon" + @click.prevent="backupWithTheme" + @click="close" + > + <FAIcon + icon="file-download" + fixed-width + /><span>{{ $t("admin.file_export_import.backup_settings_theme") }}</span> + </button> + <button + class="button-default dropdown-item dropdown-item-icon" + @click.prevent="restore" + @click="close" + > + <FAIcon + icon="file-upload" + fixed-width + /><span>{{ $t("admin.file_export_import.restore_settings") }}</span> + </button> + </div> + </template> + </Popover> + + <Checkbox + :model-value="!!expertLevel" + @update:modelValue="expertLevel = Number($event)" + > + {{ $t("admin.expert_mode") }} + </Checkbox> + <span + id="unscrolled-content" + class="extra-content" + /> + </div> + </div> + </Modal> +</template> + +<script src="./admin_modal.js"></script> + +<style src="./admin_modal.scss" lang="scss"></style> diff --git a/src/components/admin_modal/admin_modal_content.js b/src/components/admin_modal/admin_modal_content.js @@ -0,0 +1,88 @@ +import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' + +import DataImportExportTab from './tabs/data_import_export_tab.vue' +import MutesAndBlocksTab from './tabs/mutes_and_blocks_tab.vue' +import NotificationsTab from './tabs/notifications_tab.vue' +import FilteringTab from './tabs/filtering_tab.vue' +import SecurityTab from './tabs/security_tab/security_tab.vue' +import ProfileTab from './tabs/profile_tab.vue' +import GeneralTab from './tabs/general_tab.vue' +import VersionTab from './tabs/version_tab.vue' +import ThemeTab from './tabs/theme_tab/theme_tab.vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faWrench, + faUser, + faFilter, + faPaintBrush, + faBell, + faDownload, + faEyeSlash, + faInfo +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faWrench, + faUser, + faFilter, + faPaintBrush, + faBell, + faDownload, + faEyeSlash, + faInfo +) + +const AdminModalContent = { + components: { + TabSwitcher, + + DataImportExportTab, + MutesAndBlocksTab, + NotificationsTab, + FilteringTab, + SecurityTab, + ProfileTab, + GeneralTab, + VersionTab, + ThemeTab + }, + computed: { + isLoggedIn () { + return !!this.$store.state.users.currentUser + }, + open () { + return this.$store.state.interface.AdminModalState !== 'hidden' + }, + bodyLock () { + return this.$store.state.interface.AdminModalState === 'visible' + } + }, + methods: { + onOpen () { + const targetTab = this.$store.state.interface.AdminModalTargetTab + // We're being told to open in specific tab + if (targetTab) { + const tabIndex = this.$refs.tabSwitcher.$slots.default().findIndex(elm => { + return elm.props && elm.props['data-tab-name'] === targetTab + }) + if (tabIndex >= 0) { + this.$refs.tabSwitcher.setTab(tabIndex) + } + } + // Clear the state of target tab, so that next time Admin is opened + // it doesn't force it. + this.$store.dispatch('clearAdminModalTargetTab') + } + }, + mounted () { + this.onOpen() + }, + watch: { + open: function (value) { + if (value) this.onOpen() + } + } +} + +export default AdminModalContent diff --git a/src/components/admin_modal/admin_modal_content.scss b/src/components/admin_modal/admin_modal_content.scss @@ -0,0 +1,56 @@ +@import "src/variables"; + +.admin_tab-switcher { + height: 100%; + + .setting-item { + border-bottom: 2px solid var(--fg, $fallback--fg); + margin: 1em 1em 1.4em; + padding-bottom: 1.4em; + + > div, + > label { + display: block; + margin-bottom: 0.5em; + + &:last-child { + margin-bottom: 0; + } + } + + .select-multiple { + display: flex; + + .option-list { + margin: 0; + padding-left: 0.5em; + } + } + + &:last-child { + border-bottom: none; + padding-bottom: 0; + margin-bottom: 1em; + } + + select { + min-width: 10em; + } + + textarea { + width: 100%; + max-width: 100%; + height: 100px; + } + + .unavailable, + .unavailable svg { + color: var(--cRed, $fallback--cRed); + color: $fallback--cRed; + } + + .number-input { + max-width: 6em; + } + } +} diff --git a/src/components/admin_modal/tabs/general_tab.js b/src/components/admin_modal/tabs/general_tab.js @@ -0,0 +1,33 @@ +import BooleanSetting from '../settings_modal/helpers/boolean_setting.vue' +import ChoiceSetting from '../settings_modal/helpers/choice_setting.vue' +import IntegerSetting from '../settings_modal/helpers/integer_setting.vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faGlobe +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faGlobe +) + +const GeneralTab = { + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + }, + computed: { + mergedConfig () { + console.log(this.$store.state) + return this.$store.state + } + }, + methods: { + changeDefaultScope (value) { + this.$store.dispatch('setProfileOption', { name: 'defaultScope', value }) + } + } +} + +export default GeneralTab diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js @@ -107,7 +107,10 @@ export default { this.searchBarHidden = hidden }, openSettingsModal () { - this.$store.dispatch('openSettingsModal') + this.$store.dispatch('openSettingsModal', 'user') + }, + openAdminModal () { + this.$store.dispatch('openSettingsModal', 'admin') } } } diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue @@ -48,20 +48,19 @@ icon="cog" /> </button> - <a + <button v-if="currentUser && currentUser.role === 'admin'" - href="/pleroma/admin/#/login-pleroma" - class="nav-icon" + class="button-unstyled nav-icon" target="_blank" :title="$t('nav.administration')" - @click.stop + @click.stop="openAdminModal" > <FAIcon fixed-width class="fa-scale-110 fa-old-padding" icon="tachometer-alt" /> - </a> + </button> <span class="spacer" /> <button v-if="currentUser" diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue @@ -153,9 +153,9 @@ </router-link> <button class="button-unstyled expand-icon" - @click.prevent="toggleStatusExpanded" :title="$t('tool_tip.toggle_expand')" :aria-expanded="statusExpanded" + @click.prevent="toggleStatusExpanded" > <FAIcon class="fa-scale-110" diff --git a/src/components/settings_modal/admin_tabs/instance_tab.js b/src/components/settings_modal/admin_tabs/instance_tab.js @@ -0,0 +1,29 @@ +import BooleanSetting from '../helpers/boolean_setting.vue' +import ChoiceSetting from '../helpers/choice_setting.vue' +import IntegerSetting from '../helpers/integer_setting.vue' +import StringSetting from '../helpers/string_setting.vue' + +import SharedComputedObject from '../helpers/shared_computed_object.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faGlobe +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faGlobe +) + +const InstanceTab = { + data () {}, + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + StringSetting + }, + computed: { + ...SharedComputedObject() + } +} + +export default InstanceTab diff --git a/src/components/settings_modal/admin_tabs/instance_tab.vue b/src/components/settings_modal/admin_tabs/instance_tab.vue @@ -0,0 +1,35 @@ +<template> + <div :label="$t('settings.general')"> + <div class="setting-item"> + <h2>{{ $t('admin_dash.instance') }}</h2> + <ul class="setting-list"> + <li> + <StringSetting source="admin" path=":pleroma.:instance.:name"> + NAME + </StringSetting> + </li> + <li> + <StringSetting source="admin" path=":pleroma.:instance.:description"> + DESCRIPTION + </StringSetting> + </li> + </ul> + </div> + </div> +</template> + +<script src="./instance_tab.js"></script> + +<style lang="scss"> +.column-settings { + display: flex; + justify-content: space-evenly; + flex-wrap: wrap; +} + +.column-settings .size-label { + display: block; + margin-bottom: 0.5em; + margin-top: 0.5em; +} +</style> diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js @@ -42,6 +42,8 @@ export default { switch (this.source) { case 'profile': return this.$store.state.profileConfig + case 'admin': + return this.$store.state.adminSettings.config default: return this.$store.getters.mergedConfig } @@ -50,6 +52,8 @@ export default { switch (this.source) { case 'profile': return (k, v) => this.$store.dispatch('setProfileOption', { name: k, value: v }) + case 'admin': + return (k, v) => console.log(this.path, k, v) default: return (k, v) => this.$store.dispatch('setOption', { name: k, value: v }) } @@ -66,7 +70,15 @@ export default { return this.source === 'profile' }, isChanged () { - return !this.source === 'default' && this.state !== this.defaultState + switch (this.source) { + case 'profile': + return false + case 'admin': + console.log(this.$store.state.adminSettings.modifiedPaths) + return this.$store.state.adminSettings.modifiedPaths.has(this.path) + default: + return this.state !== this.defaultState + } }, matchesExpertLevel () { return (this.expert || 0) <= this.$store.state.config.expertLevel > 0 diff --git a/src/components/settings_modal/helpers/string_setting.js b/src/components/settings_modal/helpers/string_setting.js @@ -0,0 +1,9 @@ +import ModifiedIndicator from './modified_indicator.vue' +import Setting from './setting.js' + +export default { + components: { + ModifiedIndicator + }, + ...Setting +} diff --git a/src/components/settings_modal/helpers/string_setting.vue b/src/components/settings_modal/helpers/string_setting.vue @@ -0,0 +1,25 @@ +<template> + <label + v-if="matchesExpertLevel" + class="StringSetting" + > + <label :for="path"> + <slot /> + </label> + <input + :id="path" + class="string-input" + step="1" + :disabled="disabled" + :value="state" + @change="update" + > + {{ ' ' }} + <ModifiedIndicator + :changed="isChanged" + :onclick="reset" + /> + </label> +</template> + +<script src="./boolean_setting.js"></script> diff --git a/src/components/settings_modal/settings_modal.js b/src/components/settings_modal/settings_modal.js @@ -53,8 +53,16 @@ const SettingsModal = { Modal, Popover, Checkbox, - SettingsModalContent: getResettableAsyncComponent( - () => import('./settings_modal_content.vue'), + SettingsModalUserContent: getResettableAsyncComponent( + () => import('./settings_modal_user_content.vue'), + { + loadingComponent: PanelLoading, + errorComponent: AsyncComponentError, + delay: 0 + } + ), + SettingsModalAdminContent: getResettableAsyncComponent( + () => import('./settings_modal_admin_content.vue'), { loadingComponent: PanelLoading, errorComponent: AsyncComponentError, @@ -156,8 +164,14 @@ const SettingsModal = { modalActivated () { return this.$store.state.interface.settingsModalState !== 'hidden' }, - modalOpenedOnce () { - return this.$store.state.interface.settingsModalLoaded + modalMode () { + return this.$store.state.interface.settingsModalMode + }, + modalOpenedOnceUser () { + return this.$store.state.interface.settingsModalLoadedUser + }, + modalOpenedOnceAdmin () { + return this.$store.state.interface.settingsModalLoadedAdmin }, modalPeeked () { return this.$store.state.interface.settingsModalState === 'minimized' @@ -167,7 +181,6 @@ const SettingsModal = { return this.$store.state.config.expertLevel > 0 }, set (value) { - console.log(value) this.$store.dispatch('setOption', { name: 'expertLevel', value: value ? 1 : 0 }) } } diff --git a/src/components/settings_modal/settings_modal.vue b/src/components/settings_modal/settings_modal.vue @@ -42,7 +42,8 @@ </button> </div> <div class="panel-body"> - <SettingsModalContent v-if="modalOpenedOnce" /> + <SettingsModalUserContent v-if="modalMode === 'user' && modalOpenedOnceUser" /> + <SettingsModalAdminContent v-if="modalMode === 'admin' && modalOpenedOnceAdmin" /> </div> <div class="panel-footer settings-footer"> <Popover diff --git a/src/components/settings_modal/settings_modal_admin_content.js b/src/components/settings_modal/settings_modal_admin_content.js @@ -0,0 +1,76 @@ +import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' + +import DataImportExportTab from './tabs/data_import_export_tab.vue' +import MutesAndBlocksTab from './tabs/mutes_and_blocks_tab.vue' +import InstanceTab from './admin_tabs/instance_tab.vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faWrench, + faUser, + faFilter, + faPaintBrush, + faBell, + faDownload, + faEyeSlash, + faInfo +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faWrench, + faUser, + faFilter, + faPaintBrush, + faBell, + faDownload, + faEyeSlash, + faInfo +) + +const SettingsModalAdminContent = { + components: { + TabSwitcher, + + DataImportExportTab, + MutesAndBlocksTab, + InstanceTab + }, + computed: { + isLoggedIn () { + return !!this.$store.state.users.currentUser + }, + open () { + return this.$store.state.interface.settingsModalState !== 'hidden' + }, + bodyLock () { + return this.$store.state.interface.settingsModalState === 'visible' + } + }, + methods: { + onOpen () { + const targetTab = this.$store.state.interface.settingsModalTargetTab + // We're being told to open in specific tab + if (targetTab) { + const tabIndex = this.$refs.tabSwitcher.$slots.default().findIndex(elm => { + return elm.props && elm.props['data-tab-name'] === targetTab + }) + if (tabIndex >= 0) { + this.$refs.tabSwitcher.setTab(tabIndex) + } + } + // Clear the state of target tab, so that next time settings is opened + // it doesn't force it. + this.$store.dispatch('clearSettingsModalTargetTab') + } + }, + mounted () { + this.onOpen() + }, + watch: { + open: function (value) { + if (value) this.onOpen() + } + } +} + +export default SettingsModalAdminContent diff --git a/src/components/settings_modal/settings_modal_content.scss b/src/components/settings_modal/settings_modal_admin_content.scss diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue @@ -0,0 +1,21 @@ +<template> + <tab-switcher + ref="tabSwitcher" + class="settings_tab-switcher" + :side-tab-bar="true" + :scrollable-tabs="true" + :body-scroll-lock="bodyLock" + > + <div + :label="$t('settings.general')" + icon="wrench" + data-tab-name="general" + > + <InstanceTab /> + </div> + </tab-switcher> +</template> + +<script src="./settings_modal_admin_content.js"></script> + +<style src="./settings_modal_admin_content.scss" lang="scss"></style> diff --git a/src/components/settings_modal/settings_modal_content.vue b/src/components/settings_modal/settings_modal_content.vue @@ -1,83 +0,0 @@ -<template> - <tab-switcher - ref="tabSwitcher" - class="settings_tab-switcher" - :side-tab-bar="true" - :scrollable-tabs="true" - :body-scroll-lock="bodyLock" - > - <div - :label="$t('settings.general')" - icon="wrench" - data-tab-name="general" - > - <GeneralTab /> - </div> - <div - v-if="isLoggedIn" - :label="$t('settings.profile_tab')" - icon="user" - data-tab-name="profile" - > - <ProfileTab /> - </div> - <div - v-if="isLoggedIn" - :label="$t('settings.security_tab')" - icon="lock" - data-tab-name="security" - > - <SecurityTab /> - </div> - <div - :label="$t('settings.filtering')" - icon="filter" - data-tab-name="filtering" - > - <FilteringTab /> - </div> - <div - :label="$t('settings.theme')" - icon="paint-brush" - data-tab-name="theme" - > - <ThemeTab /> - </div> - <div - v-if="isLoggedIn" - :label="$t('settings.notifications')" - icon="bell" - data-tab-name="notifications" - > - <NotificationsTab /> - </div> - <div - v-if="isLoggedIn" - :label="$t('settings.data_import_export_tab')" - icon="download" - data-tab-name="dataImportExport" - > - <DataImportExportTab /> - </div> - <div - v-if="isLoggedIn" - :label="$t('settings.mutes_and_blocks')" - :fullHeight="true" - icon="eye-slash" - data-tab-name="mutesAndBlocks" - > - <MutesAndBlocksTab /> - </div> - <div - :label="$t('settings.version.title')" - icon="info" - data-tab-name="version" - > - <VersionTab /> - </div> - </tab-switcher> -</template> - -<script src="./settings_modal_content.js"></script> - -<style src="./settings_modal_content.scss" lang="scss"></style> diff --git a/src/components/settings_modal/settings_modal_content.js b/src/components/settings_modal/settings_modal_user_content.js diff --git a/src/components/settings_modal/settings_modal_content.scss b/src/components/settings_modal/settings_modal_user_content.scss diff --git a/src/components/settings_modal/settings_modal_user_content.vue b/src/components/settings_modal/settings_modal_user_content.vue @@ -0,0 +1,83 @@ +<template> + <tab-switcher + ref="tabSwitcher" + class="settings_tab-switcher" + :side-tab-bar="true" + :scrollable-tabs="true" + :body-scroll-lock="bodyLock" + > + <div + :label="$t('settings.general')" + icon="wrench" + data-tab-name="general" + > + <GeneralTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.profile_tab')" + icon="user" + data-tab-name="profile" + > + <ProfileTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.security_tab')" + icon="lock" + data-tab-name="security" + > + <SecurityTab /> + </div> + <div + :label="$t('settings.filtering')" + icon="filter" + data-tab-name="filtering" + > + <FilteringTab /> + </div> + <div + :label="$t('settings.theme')" + icon="paint-brush" + data-tab-name="theme" + > + <ThemeTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.notifications')" + icon="bell" + data-tab-name="notifications" + > + <NotificationsTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.data_import_export_tab')" + icon="download" + data-tab-name="dataImportExport" + > + <DataImportExportTab /> + </div> + <div + v-if="isLoggedIn" + :label="$t('settings.mutes_and_blocks')" + :fullHeight="true" + icon="eye-slash" + data-tab-name="mutesAndBlocks" + > + <MutesAndBlocksTab /> + </div> + <div + :label="$t('settings.version.title')" + icon="info" + data-tab-name="version" + > + <VersionTab /> + </div> + </tab-switcher> +</template> + +<script src="./settings_modal_user_content.js"></script> + +<style src="./settings_modal_user_content.scss" lang="scss"></style> diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx @@ -60,13 +60,7 @@ export default { const isWanted = slot => slot.props && slot.props['data-tab-name'] === tabName return this.$slots.default().findIndex(isWanted) === this.activeIndex } - }, - settingsModalVisible () { - return this.settingsModalState === 'visible' - }, - ...mapState({ - settingsModalState: state => state.interface.settingsModalState - }) + } }, beforeUpdate () { const currentSlot = this.slots()[this.active] diff --git a/src/modules/adminSettings.js b/src/modules/adminSettings.js @@ -10,7 +10,7 @@ export const newUserFlags = { ...defaultState.flagStorage } -const serverSideStorage = { +const adminSettingsStorage = { state: { ...cloneDeep(defaultState) }, @@ -40,9 +40,10 @@ const serverSideStorage = { } set(config, path, convert(c.value)) }) + console.log(config) commit('updateAdminSettings', { config, modifiedPaths }) } } } -export default serverSideStorage +export default adminSettingsStorage diff --git a/src/modules/interface.js b/src/modules/interface.js @@ -1,7 +1,9 @@ const defaultState = { settingsModalState: 'hidden', - settingsModalLoaded: false, + settingsModalLoadedUser: false, + settingsModalLoadedAdmin: false, settingsModalTargetTab: null, + settingsModalMode: 'user', settings: { currentSaveStateNotice: null, noticeClearTimeout: null, @@ -54,10 +56,17 @@ const interfaceMod = { throw new Error('Illegal minimization state of settings modal') } }, - openSettingsModal (state) { + openSettingsModal (state, value) { + state.settingsModalMode = value state.settingsModalState = 'visible' - if (!state.settingsModalLoaded) { - state.settingsModalLoaded = true + if (value === 'user') { + if (!state.settingsModalLoadedUser) { + state.settingsModalLoadedUser = true + } + } else if (value === 'admin') { + if (!state.settingsModalLoadedAdmin) { + state.settingsModalLoadedAdmin = true + } } }, setSettingsModalTargetTab (state, value) { @@ -92,8 +101,8 @@ const interfaceMod = { closeSettingsModal ({ commit }) { commit('closeSettingsModal') }, - openSettingsModal ({ commit }) { - commit('openSettingsModal') + openSettingsModal ({ commit }, value = 'user') { + commit('openSettingsModal', value) }, togglePeekSettingsModal ({ commit }) { commit('togglePeekSettingsModal')