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:
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')