mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 19:14:16 +00:00
improve settings initialization
This commit is contained in:
parent
739c110b4a
commit
f2f3988da6
@ -2,162 +2,166 @@ import React from "react"
|
|||||||
import config from "config"
|
import config from "config"
|
||||||
import { Select } from "antd"
|
import { Select } from "antd"
|
||||||
|
|
||||||
export default [
|
export default {
|
||||||
{
|
icon: "Command",
|
||||||
"id": "language",
|
label: "App",
|
||||||
"storaged": true,
|
settings: [
|
||||||
"group": "general",
|
{
|
||||||
"component": "Select",
|
"id": "language",
|
||||||
"icon": "MdTranslate",
|
"storaged": true,
|
||||||
"title": "Language",
|
"group": "general",
|
||||||
"description": "Choose a language for the application",
|
"component": "Select",
|
||||||
"props": {
|
"icon": "MdTranslate",
|
||||||
children: config.i18n.languages.map((language) => {
|
"title": "Language",
|
||||||
return <Select.Option value={language.locale}>{language.name}</Select.Option>
|
"description": "Choose a language for the application",
|
||||||
})
|
"props": {
|
||||||
|
children: config.i18n.languages.map((language) => {
|
||||||
|
return <Select.Option value={language.locale}>{language.name}</Select.Option>
|
||||||
|
})
|
||||||
|
},
|
||||||
|
"emitEvent": "changeLanguage"
|
||||||
},
|
},
|
||||||
"emitEvent": "changeLanguage"
|
{
|
||||||
},
|
"id": "haptic_feedback",
|
||||||
{
|
"storaged": true,
|
||||||
"id": "haptic_feedback",
|
"group": "general",
|
||||||
"storaged": true,
|
"component": "Switch",
|
||||||
"group": "general",
|
"icon": "MdVibration",
|
||||||
"component": "Switch",
|
"title": "Haptic Feedback",
|
||||||
"icon": "MdVibration",
|
"description": "Enable haptic feedback on touch events.",
|
||||||
"title": "Haptic Feedback",
|
},
|
||||||
"description": "Enable haptic feedback on touch events.",
|
{
|
||||||
},
|
"id": "selection_longPress_timeout",
|
||||||
{
|
"storaged": true,
|
||||||
"id": "selection_longPress_timeout",
|
"group": "general",
|
||||||
"storaged": true,
|
"component": "Slider",
|
||||||
"group": "general",
|
"icon": "MdTimer",
|
||||||
"component": "Slider",
|
"title": "Selection press delay",
|
||||||
"icon": "MdTimer",
|
"description": "Set the delay before the selection trigger is activated.",
|
||||||
"title": "Selection press delay",
|
"props": {
|
||||||
"description": "Set the delay before the selection trigger is activated.",
|
min: 300,
|
||||||
"props": {
|
max: 2000,
|
||||||
min: 300,
|
step: 100,
|
||||||
max: 2000,
|
marks: {
|
||||||
step: 100,
|
300: "0.3s",
|
||||||
marks: {
|
600: "0.6s",
|
||||||
300: "0.3s",
|
1000: "1s",
|
||||||
600: "0.6s",
|
1500: "1.5s",
|
||||||
1000: "1s",
|
2000: "2s",
|
||||||
1500: "1.5s",
|
}
|
||||||
2000: "2s",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "clear_internal_storage",
|
|
||||||
"storaged": false,
|
|
||||||
"group": "general",
|
|
||||||
"component": "Button",
|
|
||||||
"icon": "MdDelete",
|
|
||||||
"title": "Clear internal storage",
|
|
||||||
"description": "Clear all the data stored in the internal storage, including your current session. It will not affect the data stored in the cloud.",
|
|
||||||
"emitEvent": "app.clearInternalStorage"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "notifications_sound",
|
|
||||||
"storaged": true,
|
|
||||||
"group": "notifications",
|
|
||||||
"component": "Switch",
|
|
||||||
"icon": "MdVolumeUp",
|
|
||||||
"title": "Notifications Sound",
|
|
||||||
"description": "Play a sound when a notification is received.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "notifications_vibrate",
|
|
||||||
"storaged": true,
|
|
||||||
"group": "notifications",
|
|
||||||
"component": "Switch",
|
|
||||||
"icon": "MdVibration",
|
|
||||||
"title": "Vibration",
|
|
||||||
"description": "Vibrate the device when a notification is received.",
|
|
||||||
"emitEvent": "changeNotificationsVibrate"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "notifications_sound_volume",
|
|
||||||
"storaged": true,
|
|
||||||
"group": "notifications",
|
|
||||||
"component": "Slider",
|
|
||||||
"icon": "MdVolumeUp",
|
|
||||||
"title": "Sound Volume",
|
|
||||||
"description": "Set the volume of the sound when a notification is received.",
|
|
||||||
"props": {
|
|
||||||
tipFormatter: (value) => {
|
|
||||||
return `${value}%`
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"emitEvent": "changeNotificationsSoundVolume"
|
{
|
||||||
},
|
"id": "clear_internal_storage",
|
||||||
{
|
"storaged": false,
|
||||||
"id": "collapseOnLooseFocus",
|
"group": "general",
|
||||||
"storaged": true,
|
"component": "Button",
|
||||||
"group": "sidebar",
|
"icon": "MdDelete",
|
||||||
"component": "Switch",
|
"title": "Clear internal storage",
|
||||||
"icon": "Columns",
|
"description": "Clear all the data stored in the internal storage, including your current session. It will not affect the data stored in the cloud.",
|
||||||
"title": "Auto Collapse",
|
"emitEvent": "app.clearInternalStorage"
|
||||||
"description": "Collapse the sidebar when loose focus",
|
|
||||||
"emitEvent": "settingChanged.sidebar_collapse",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "autoCollapseDelay",
|
|
||||||
"storaged": true,
|
|
||||||
"group": "sidebar",
|
|
||||||
"component": "Slider",
|
|
||||||
"icon": "MdTimer",
|
|
||||||
"dependsOn": {
|
|
||||||
"collapseOnLooseFocus": true
|
|
||||||
},
|
},
|
||||||
"title": "Auto Collapse timeout",
|
{
|
||||||
"description": "Set the delay before the sidebar is collapsed",
|
"id": "notifications_sound",
|
||||||
"props": {
|
"storaged": true,
|
||||||
min: 0,
|
"group": "notifications",
|
||||||
max: 2000,
|
"component": "Switch",
|
||||||
step: 100,
|
"icon": "MdVolumeUp",
|
||||||
marks: {
|
"title": "Notifications Sound",
|
||||||
0: "No delay",
|
"description": "Play a sound when a notification is received.",
|
||||||
600: "0.6s",
|
},
|
||||||
1000: "1s",
|
{
|
||||||
1500: "1.5s",
|
"id": "notifications_vibrate",
|
||||||
2000: "2s",
|
"storaged": true,
|
||||||
|
"group": "notifications",
|
||||||
|
"component": "Switch",
|
||||||
|
"icon": "MdVibration",
|
||||||
|
"title": "Vibration",
|
||||||
|
"description": "Vibrate the device when a notification is received.",
|
||||||
|
"emitEvent": "changeNotificationsVibrate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "notifications_sound_volume",
|
||||||
|
"storaged": true,
|
||||||
|
"group": "notifications",
|
||||||
|
"component": "Slider",
|
||||||
|
"icon": "MdVolumeUp",
|
||||||
|
"title": "Sound Volume",
|
||||||
|
"description": "Set the volume of the sound when a notification is received.",
|
||||||
|
"props": {
|
||||||
|
tipFormatter: (value) => {
|
||||||
|
return `${value}%`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"emitEvent": "changeNotificationsSoundVolume"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "collapseOnLooseFocus",
|
||||||
|
"storaged": true,
|
||||||
|
"group": "sidebar",
|
||||||
|
"component": "Switch",
|
||||||
|
"icon": "Columns",
|
||||||
|
"title": "Auto Collapse",
|
||||||
|
"description": "Collapse the sidebar when loose focus",
|
||||||
|
"emitEvent": "settingChanged.sidebar_collapse",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "autoCollapseDelay",
|
||||||
|
"storaged": true,
|
||||||
|
"group": "sidebar",
|
||||||
|
"component": "Slider",
|
||||||
|
"icon": "MdTimer",
|
||||||
|
"dependsOn": {
|
||||||
|
"collapseOnLooseFocus": true
|
||||||
|
},
|
||||||
|
"title": "Auto Collapse timeout",
|
||||||
|
"description": "Set the delay before the sidebar is collapsed",
|
||||||
|
"props": {
|
||||||
|
min: 0,
|
||||||
|
max: 2000,
|
||||||
|
step: 100,
|
||||||
|
marks: {
|
||||||
|
0: "No delay",
|
||||||
|
600: "0.6s",
|
||||||
|
1000: "1s",
|
||||||
|
1500: "1.5s",
|
||||||
|
2000: "2s",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "feed_max_fetch",
|
|
||||||
"title": "Fetch max items",
|
|
||||||
"description": "Set the maximum number of items to load per fetch in the feed list",
|
|
||||||
"component": "Slider",
|
|
||||||
"icon": "MdFormatListNumbered",
|
|
||||||
"group": "posts",
|
|
||||||
"props": {
|
|
||||||
min: 5,
|
|
||||||
max: 50,
|
|
||||||
},
|
},
|
||||||
"storaged": true,
|
{
|
||||||
},
|
"id": "feed_max_fetch",
|
||||||
{
|
"title": "Fetch max items",
|
||||||
"id": "postCard_carrusel_auto",
|
"description": "Set the maximum number of items to load per fetch in the feed list",
|
||||||
"title": "Post autoplay",
|
"component": "Slider",
|
||||||
"description": "Automatically play the post medias when the post has multiple medias",
|
"icon": "MdFormatListNumbered",
|
||||||
"component": "Switch",
|
"group": "posts",
|
||||||
"icon": "MdPhotoCameraBack",
|
"props": {
|
||||||
"group": "posts",
|
min: 5,
|
||||||
"storaged": true,
|
max: 50,
|
||||||
"emitEvent": "router.forceUpdate",
|
},
|
||||||
"disabled": true
|
"storaged": true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "postCard_expansible_actions",
|
"id": "postCard_carrusel_auto",
|
||||||
"title": "Expansible actions",
|
"title": "Post autoplay",
|
||||||
"description": "Automatically show or hide the actions bar",
|
"description": "Automatically play the post medias when the post has multiple medias",
|
||||||
"component": "Switch",
|
"component": "Switch",
|
||||||
"icon": "MdCallToAction",
|
"icon": "MdPhotoCameraBack",
|
||||||
"group": "posts",
|
"group": "posts",
|
||||||
"storaged": true,
|
"storaged": true,
|
||||||
"emitEvent": "router.forceUpdate"
|
"emitEvent": "router.forceUpdate",
|
||||||
},
|
"disabled": true
|
||||||
]
|
},
|
||||||
|
{
|
||||||
|
"id": "postCard_expansible_actions",
|
||||||
|
"title": "Expansible actions",
|
||||||
|
"description": "Automatically show or hide the actions bar",
|
||||||
|
"component": "Switch",
|
||||||
|
"icon": "MdCallToAction",
|
||||||
|
"group": "posts",
|
||||||
|
"storaged": true,
|
||||||
|
"emitEvent": "router.forceUpdate"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
@ -3,167 +3,171 @@ import loadable from "@loadable/component"
|
|||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
export default [
|
export default {
|
||||||
{
|
icon: "Eye",
|
||||||
"id": "compactWidth",
|
label: "Apparence",
|
||||||
"title": "Compact Width",
|
settings: [
|
||||||
"description": "Sets the width of the app to a compact width to facilitate the vision of components.",
|
{
|
||||||
"component": "Switch",
|
"id": "compactWidth",
|
||||||
"icon": "MdCompress",
|
"title": "Compact Width",
|
||||||
"group": "layout",
|
"description": "Sets the width of the app to a compact width to facilitate the vision of components.",
|
||||||
"experimental": true,
|
"component": "Switch",
|
||||||
"storaged": true
|
"icon": "MdCompress",
|
||||||
},
|
"group": "layout",
|
||||||
{
|
"experimental": true,
|
||||||
"id": "sidebar.floating",
|
"storaged": true
|
||||||
"title": "Floating Sidebar",
|
},
|
||||||
"description": "Make the sidebar float over layout content.",
|
{
|
||||||
"component": "Switch",
|
"id": "sidebar.floating",
|
||||||
"icon": "MdOutlineLastPage",
|
"title": "Floating Sidebar",
|
||||||
"group": "layout",
|
"description": "Make the sidebar float over layout content.",
|
||||||
"emitEvent": "app.softReload",
|
"component": "Switch",
|
||||||
"storaged": true
|
"icon": "MdOutlineLastPage",
|
||||||
},
|
"group": "layout",
|
||||||
{
|
"emitEvent": "app.softReload",
|
||||||
"id": "reduceAnimations",
|
"storaged": true
|
||||||
"storaged": true,
|
},
|
||||||
"group": "animations",
|
{
|
||||||
"component": "Switch",
|
"id": "reduceAnimations",
|
||||||
"icon": "MdOutlineSlowMotionVideo",
|
"storaged": true,
|
||||||
"title": "Reduce animation",
|
"group": "animations",
|
||||||
"experimental": true
|
"component": "Switch",
|
||||||
},
|
"icon": "MdOutlineSlowMotionVideo",
|
||||||
{
|
"title": "Reduce animation",
|
||||||
"id": "pageTransitionDuration",
|
"experimental": true
|
||||||
"storaged": true,
|
},
|
||||||
"group": "animations",
|
{
|
||||||
"component": "Slider",
|
"id": "pageTransitionDuration",
|
||||||
"icon": "MdOutlineSpeed",
|
"storaged": true,
|
||||||
"title": "Page transition duration",
|
"group": "animations",
|
||||||
"description": "Change the duration of the page transition animation.",
|
"component": "Slider",
|
||||||
"props": {
|
"icon": "MdOutlineSpeed",
|
||||||
min: 0,
|
"title": "Page transition duration",
|
||||||
max: 1000,
|
"description": "Change the duration of the page transition animation.",
|
||||||
step: 50,
|
"props": {
|
||||||
tooltip: {
|
min: 0,
|
||||||
formatter: (value) => `${value / 1000}s`
|
max: 1000,
|
||||||
|
step: 50,
|
||||||
|
tooltip: {
|
||||||
|
formatter: (value) => `${value / 1000}s`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"emitEvent": "modifyTheme",
|
||||||
|
"emissionValueUpdate": (value) => {
|
||||||
|
return {
|
||||||
|
"page-transition-duration": `${value}ms`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "auto_darkMode",
|
||||||
|
"experimental": true,
|
||||||
|
"storaged": true,
|
||||||
|
"group": "aspect",
|
||||||
|
"component": "Switch",
|
||||||
|
"icon": "Moon",
|
||||||
|
"title": "Auto dark mode",
|
||||||
|
"emitEvent": "style.autoDarkModeToogle",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"experimental": true,
|
||||||
|
"dependsOn": {
|
||||||
|
"auto_darkMode": false
|
||||||
|
},
|
||||||
|
"id": "darkMode",
|
||||||
|
"storaged": true,
|
||||||
|
"group": "aspect",
|
||||||
|
"component": "Switch",
|
||||||
|
"icon": "Moon",
|
||||||
|
"title": "Dark mode",
|
||||||
|
"emitEvent": "theme.applyVariant",
|
||||||
|
"emissionValueUpdate": (value) => {
|
||||||
|
return value ? "dark" : "light"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "primaryColor",
|
||||||
|
"storaged": true,
|
||||||
|
"group": "aspect",
|
||||||
|
"component": "SliderColorPicker",
|
||||||
|
"title": "Primary color",
|
||||||
|
"description": "Change primary color of the application.",
|
||||||
|
"emitEvent": "modifyTheme",
|
||||||
|
"reloadValueOnUpdateEvent": "resetTheme",
|
||||||
|
"emissionValueUpdate": (value) => {
|
||||||
|
return {
|
||||||
|
primaryColor: value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"emitEvent": "modifyTheme",
|
{
|
||||||
"emissionValueUpdate": (value) => {
|
"id": "backgroundImage",
|
||||||
return {
|
"storaged": true,
|
||||||
"page-transition-duration": `${value}ms`
|
"group": "aspect",
|
||||||
}
|
"title": "Background image",
|
||||||
|
"description": "Change background image of the application. You can use a local image or a remote image (URL).",
|
||||||
|
"component": loadable(() => import("../components/ImageUploader")),
|
||||||
|
"props": {
|
||||||
|
"noPreview": true,
|
||||||
|
},
|
||||||
|
"emitEvent": "modifyTheme",
|
||||||
|
"emissionValueUpdate": (value) => {
|
||||||
|
return {
|
||||||
|
backgroundImage: `url(${value})`
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
"id": "backgroundBlur",
|
||||||
"id": "auto_darkMode",
|
"storaged": true,
|
||||||
"experimental": true,
|
"group": "aspect",
|
||||||
"storaged": true,
|
"component": "Slider",
|
||||||
"group": "aspect",
|
"icon": "Eye",
|
||||||
"component": "Switch",
|
"title": "Background blur",
|
||||||
"icon": "Moon",
|
"description": "Create a blur effect on the background.",
|
||||||
"title": "Auto dark mode",
|
"props": {
|
||||||
"emitEvent": "style.autoDarkModeToogle",
|
min: 0,
|
||||||
},
|
max: 50,
|
||||||
{
|
step: 5
|
||||||
"experimental": true,
|
},
|
||||||
"dependsOn": {
|
"emitEvent": "modifyTheme",
|
||||||
"auto_darkMode": false
|
"emissionValueUpdate": (value) => {
|
||||||
|
return {
|
||||||
|
backgroundBlur: `${value}px`,
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"id": "darkMode",
|
{
|
||||||
"storaged": true,
|
"id": "backgroundColorTransparency",
|
||||||
"group": "aspect",
|
"storaged": true,
|
||||||
"component": "Switch",
|
"group": "aspect",
|
||||||
"icon": "Moon",
|
"component": "Slider",
|
||||||
"title": "Dark mode",
|
"icon": "Eye",
|
||||||
"emitEvent": "theme.applyVariant",
|
"title": "Background color transparency",
|
||||||
"emissionValueUpdate": (value) => {
|
"description": "Adjust the transparency of the background color.",
|
||||||
return value ? "dark" : "light"
|
"props": {
|
||||||
|
min: 0,
|
||||||
|
max: 1,
|
||||||
|
step: 0.1
|
||||||
|
},
|
||||||
|
"emitEvent": "modifyTheme",
|
||||||
|
"emissionValueUpdate": (value) => {
|
||||||
|
return {
|
||||||
|
backgroundColorTransparency: value,
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
"id": "resetTheme",
|
||||||
"id": "primaryColor",
|
"storaged": true,
|
||||||
"storaged": true,
|
"group": "aspect",
|
||||||
"group": "aspect",
|
"component": "Button",
|
||||||
"component": "SliderColorPicker",
|
"title": "Reset theme",
|
||||||
"title": "Primary color",
|
"props": {
|
||||||
"description": "Change primary color of the application.",
|
"children": "Default Theme"
|
||||||
"emitEvent": "modifyTheme",
|
},
|
||||||
"reloadValueOnUpdateEvent": "resetTheme",
|
"emitEvent": "resetTheme",
|
||||||
"emissionValueUpdate": (value) => {
|
"noUpdate": true,
|
||||||
return {
|
|
||||||
primaryColor: value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
]
|
||||||
{
|
}
|
||||||
"id": "backgroundImage",
|
|
||||||
"storaged": true,
|
|
||||||
"group": "aspect",
|
|
||||||
"title": "Background image",
|
|
||||||
"description": "Change background image of the application. You can use a local image or a remote image (URL).",
|
|
||||||
"component": loadable(() => import("../components/ImageUploader")),
|
|
||||||
"props": {
|
|
||||||
"noPreview": true,
|
|
||||||
},
|
|
||||||
"emitEvent": "modifyTheme",
|
|
||||||
"emissionValueUpdate": (value) => {
|
|
||||||
return {
|
|
||||||
backgroundImage: `url(${value})`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "backgroundBlur",
|
|
||||||
"storaged": true,
|
|
||||||
"group": "aspect",
|
|
||||||
"component": "Slider",
|
|
||||||
"icon": "Eye",
|
|
||||||
"title": "Background blur",
|
|
||||||
"description": "Create a blur effect on the background.",
|
|
||||||
"props": {
|
|
||||||
min: 0,
|
|
||||||
max: 50,
|
|
||||||
step: 5
|
|
||||||
},
|
|
||||||
"emitEvent": "modifyTheme",
|
|
||||||
"emissionValueUpdate": (value) => {
|
|
||||||
return {
|
|
||||||
backgroundBlur: `${value}px`,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "backgroundColorTransparency",
|
|
||||||
"storaged": true,
|
|
||||||
"group": "aspect",
|
|
||||||
"component": "Slider",
|
|
||||||
"icon": "Eye",
|
|
||||||
"title": "Background color transparency",
|
|
||||||
"description": "Adjust the transparency of the background color.",
|
|
||||||
"props": {
|
|
||||||
min: 0,
|
|
||||||
max: 1,
|
|
||||||
step: 0.1
|
|
||||||
},
|
|
||||||
"emitEvent": "modifyTheme",
|
|
||||||
"emissionValueUpdate": (value) => {
|
|
||||||
return {
|
|
||||||
backgroundColorTransparency: value,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "resetTheme",
|
|
||||||
"storaged": true,
|
|
||||||
"group": "aspect",
|
|
||||||
"component": "Button",
|
|
||||||
"title": "Reset theme",
|
|
||||||
"props": {
|
|
||||||
"children": "Default Theme"
|
|
||||||
},
|
|
||||||
"emitEvent": "resetTheme",
|
|
||||||
"noUpdate": true,
|
|
||||||
}
|
|
||||||
]
|
|
@ -6,29 +6,9 @@ import ApparenceSettings from "./apparence"
|
|||||||
//import ExtensionsSettings from "./extensions"
|
//import ExtensionsSettings from "./extensions"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
app: {
|
app: AppSettings,
|
||||||
icon: "Command",
|
profile: ProfileSettings,
|
||||||
label: "App",
|
apparence: ApparenceSettings,
|
||||||
settings: AppSettings
|
security: SecuritySettings,
|
||||||
},
|
notifications: NotificationsSettings,
|
||||||
profile: {
|
|
||||||
icon: "User",
|
|
||||||
label: "Profile",
|
|
||||||
settings: ProfileSettings
|
|
||||||
},
|
|
||||||
apparence: {
|
|
||||||
icon: "Eye",
|
|
||||||
label: "Apparence",
|
|
||||||
settings: ApparenceSettings
|
|
||||||
},
|
|
||||||
security: {
|
|
||||||
icon: "Shield",
|
|
||||||
label: "Security",
|
|
||||||
settings: SecuritySettings
|
|
||||||
},
|
|
||||||
notifications: {
|
|
||||||
icon: "Bell",
|
|
||||||
label: "Notifications",
|
|
||||||
settings: NotificationsSettings
|
|
||||||
},
|
|
||||||
}
|
}
|
@ -1,5 +1,9 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
|
|
||||||
export default [
|
export default {
|
||||||
|
icon: "Bell",
|
||||||
|
label: "Notifications",
|
||||||
|
settings: [
|
||||||
|
|
||||||
]
|
]
|
||||||
|
}
|
@ -2,183 +2,191 @@ import React from "react"
|
|||||||
import { User } from "models"
|
import { User } from "models"
|
||||||
import loadable from "@loadable/component"
|
import loadable from "@loadable/component"
|
||||||
|
|
||||||
export default [
|
export default {
|
||||||
{
|
icon: "User",
|
||||||
"id": "username",
|
label: "Profile",
|
||||||
"group": "account.basicInfo",
|
ctxData: async () => {
|
||||||
"component": "Button",
|
const userData = await User.data()
|
||||||
"icon": "AtSign",
|
|
||||||
"title": "Username",
|
return {
|
||||||
"description": "Your username is the name you use to log in to your account.",
|
userData
|
||||||
"props": {
|
}
|
||||||
"disabled": true,
|
|
||||||
"children": "Change username",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
settings: [
|
||||||
"id": "fullName",
|
{
|
||||||
"group": "account.basicInfo",
|
"id": "username",
|
||||||
"component": "Input",
|
"group": "account.basicInfo",
|
||||||
"icon": "Edit3",
|
"component": "Button",
|
||||||
"title": "Name",
|
"icon": "AtSign",
|
||||||
"description": "Change your public name",
|
"title": "Username",
|
||||||
"props": {
|
"description": "Your username is the name you use to log in to your account.",
|
||||||
// set max length
|
"props": {
|
||||||
"maxLength": 120,
|
"disabled": true,
|
||||||
"showCount": true,
|
"children": "Change username",
|
||||||
"allowClear": true,
|
},
|
||||||
"placeholder": "Enter your name. e.g. John Doe",
|
|
||||||
},
|
},
|
||||||
"defaultValue": async () => {
|
{
|
||||||
const userData = await User.data()
|
"id": "fullName",
|
||||||
return userData.fullName
|
"group": "account.basicInfo",
|
||||||
},
|
"component": "Input",
|
||||||
"onUpdate": async (value) => {
|
"icon": "Edit3",
|
||||||
const selfId = await User.selfUserId()
|
"title": "Name",
|
||||||
|
"description": "Change your public name",
|
||||||
|
"props": {
|
||||||
|
// set max length
|
||||||
|
"maxLength": 120,
|
||||||
|
"showCount": true,
|
||||||
|
"allowClear": true,
|
||||||
|
"placeholder": "Enter your name. e.g. John Doe",
|
||||||
|
},
|
||||||
|
"defaultValue": (ctx) => {
|
||||||
|
console.log(ctx)
|
||||||
|
|
||||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
return ctx.userData.fullName
|
||||||
_id: selfId,
|
},
|
||||||
update: {
|
"onUpdate": async (value) => {
|
||||||
fullName: value
|
const selfId = await User.selfUserId()
|
||||||
|
|
||||||
|
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||||
|
_id: selfId,
|
||||||
|
update: {
|
||||||
|
fullName: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
"extraActions": [
|
||||||
if (result) {
|
{
|
||||||
return result
|
"id": "unset",
|
||||||
}
|
"icon": "Delete",
|
||||||
},
|
"title": "Unset",
|
||||||
"extraActions": [
|
"onClick": async () => {
|
||||||
{
|
window.app.api.withEndpoints("main").post.unsetPublicName()
|
||||||
"id": "unset",
|
}
|
||||||
"icon": "Delete",
|
|
||||||
"title": "Unset",
|
|
||||||
"onClick": async () => {
|
|
||||||
window.app.api.withEndpoints("main").post.unsetPublicName()
|
|
||||||
}
|
}
|
||||||
}
|
],
|
||||||
],
|
"debounced": true,
|
||||||
"debounced": true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "email",
|
|
||||||
"group": "account.basicInfo",
|
|
||||||
"component": "Input",
|
|
||||||
"icon": "Mail",
|
|
||||||
"title": "Email",
|
|
||||||
"description": "Change your email address",
|
|
||||||
"props": {
|
|
||||||
"placeholder": "Enter your email address",
|
|
||||||
"allowClear": true,
|
|
||||||
"showCount": true,
|
|
||||||
"maxLength": 320,
|
|
||||||
},
|
},
|
||||||
"defaultValue": async () => {
|
{
|
||||||
const userData = await User.data()
|
"id": "email",
|
||||||
return userData.email
|
"group": "account.basicInfo",
|
||||||
},
|
"component": "Input",
|
||||||
"onUpdate": async (value) => {
|
"icon": "Mail",
|
||||||
const selfId = await User.selfUserId()
|
"title": "Email",
|
||||||
|
"description": "Change your email address",
|
||||||
|
"props": {
|
||||||
|
"placeholder": "Enter your email address",
|
||||||
|
"allowClear": true,
|
||||||
|
"showCount": true,
|
||||||
|
"maxLength": 320,
|
||||||
|
},
|
||||||
|
"defaultValue": (ctx) => {
|
||||||
|
return ctx.userData.email
|
||||||
|
},
|
||||||
|
"onUpdate": async (value) => {
|
||||||
|
const selfId = await User.selfUserId()
|
||||||
|
|
||||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||||
_id: selfId,
|
_id: selfId,
|
||||||
update: {
|
update: {
|
||||||
email: value
|
email: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
"debounced": true,
|
||||||
if (result) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"debounced": true,
|
{
|
||||||
},
|
"id": "avatar",
|
||||||
{
|
"group": "account.profile",
|
||||||
"id": "avatar",
|
"icon": "Image",
|
||||||
"group": "account.profile",
|
"title": "Avatar",
|
||||||
"icon": "Image",
|
"description": "Change your avatar (Upload an image or use an URL)",
|
||||||
"title": "Avatar",
|
"component": loadable(() => import("../components/ImageUploader")),
|
||||||
"description": "Change your avatar (Upload an image or use an URL)",
|
"defaultValue": (ctx) => {
|
||||||
"component": loadable(() => import("../components/ImageUploader")),
|
return ctx.userData.avatar
|
||||||
"defaultValue": async () => {
|
},
|
||||||
const userData = await User.data()
|
"onUpdate": async (value) => {
|
||||||
return userData.avatar
|
const selfId = await User.selfUserId()
|
||||||
},
|
|
||||||
"onUpdate": async (value) => {
|
|
||||||
const selfId = await User.selfUserId()
|
|
||||||
|
|
||||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||||
_id: selfId,
|
_id: selfId,
|
||||||
update: {
|
update: {
|
||||||
avatar: value
|
avatar: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
app.message.success("Avatar updated")
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
"debounced": true,
|
||||||
if (result) {
|
|
||||||
app.message.success("Avatar updated")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"debounced": true,
|
{
|
||||||
},
|
"id": "cover",
|
||||||
{
|
"group": "account.profile",
|
||||||
"id": "cover",
|
"icon": "Image",
|
||||||
"group": "account.profile",
|
"title": "Cover",
|
||||||
"icon": "Image",
|
"description": "Change your profile cover (Upload an image or use an URL)",
|
||||||
"title": "Cover",
|
"component": loadable(() => import("../components/ImageUploader")),
|
||||||
"description": "Change your profile cover (Upload an image or use an URL)",
|
"defaultValue": (ctx) => {
|
||||||
"component": loadable(() => import("../components/ImageUploader")),
|
return ctx.userData.cover
|
||||||
"defaultValue": async () => {
|
},
|
||||||
const userData = await User.data()
|
"onUpdate": async (value) => {
|
||||||
return userData.cover
|
const selfId = await User.selfUserId()
|
||||||
},
|
|
||||||
"onUpdate": async (value) => {
|
|
||||||
const selfId = await User.selfUserId()
|
|
||||||
|
|
||||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||||
_id: selfId,
|
_id: selfId,
|
||||||
update: {
|
update: {
|
||||||
cover: value
|
cover: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
app.message.success("Cover updated")
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
"debounced": true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "description",
|
||||||
|
"group": "account.profile",
|
||||||
|
"component": "TextArea",
|
||||||
|
"icon": "Edit3",
|
||||||
|
"title": "Description",
|
||||||
|
"description": "Change your description for your profile",
|
||||||
|
"props": {
|
||||||
|
"placeholder": "Enter here a description for your profile",
|
||||||
|
"maxLength": 1000,
|
||||||
|
"showCount": true,
|
||||||
|
"allowClear": true
|
||||||
|
},
|
||||||
|
"defaultValue": (ctx) => {
|
||||||
|
return ctx.userData.description
|
||||||
|
},
|
||||||
|
"onUpdate": async (value) => {
|
||||||
|
const selfId = await User.selfUserId()
|
||||||
|
|
||||||
if (result) {
|
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||||
app.message.success("Cover updated")
|
_id: selfId,
|
||||||
return result
|
update: {
|
||||||
}
|
description: value
|
||||||
},
|
}
|
||||||
"debounced": true,
|
})
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "description",
|
|
||||||
"group": "account.profile",
|
|
||||||
"component": "TextArea",
|
|
||||||
"icon": "Edit3",
|
|
||||||
"title": "Description",
|
|
||||||
"description": "Change your description for your profile",
|
|
||||||
"props": {
|
|
||||||
"placeholder": "Enter here a description for your profile",
|
|
||||||
"maxLength": 1000,
|
|
||||||
"showCount": true,
|
|
||||||
"allowClear": true
|
|
||||||
},
|
|
||||||
"defaultValue": async () => {
|
|
||||||
const userData = await User.data()
|
|
||||||
return userData.description
|
|
||||||
},
|
|
||||||
"onUpdate": async (value) => {
|
|
||||||
const selfId = await User.selfUserId()
|
|
||||||
|
|
||||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
if (result) {
|
||||||
_id: selfId,
|
return result
|
||||||
update: {
|
|
||||||
description: value
|
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
|
"debounced": true,
|
||||||
if (result) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"debounced": true,
|
]
|
||||||
},
|
}
|
||||||
]
|
|
@ -3,39 +3,43 @@ import loadable from "@loadable/component"
|
|||||||
|
|
||||||
// TODO: Make logout button require a valid session to be not disabled
|
// TODO: Make logout button require a valid session to be not disabled
|
||||||
|
|
||||||
export default [
|
export default {
|
||||||
{
|
icon: "Shield",
|
||||||
"id": "change-password",
|
label: "Security",
|
||||||
"group": "security.account",
|
settings: [
|
||||||
"title": "Change Password",
|
{
|
||||||
"description": "Change your password",
|
"id": "change-password",
|
||||||
"icon": "Lock",
|
"group": "security.account",
|
||||||
"component": loadable(() => import("../components/changePassword")),
|
"title": "Change Password",
|
||||||
},
|
"description": "Change your password",
|
||||||
{
|
"icon": "Lock",
|
||||||
"id": "two-factor-authentication",
|
"component": loadable(() => import("../components/changePassword")),
|
||||||
"group": "security.account",
|
},
|
||||||
"title": "Two-Factor Authentication",
|
{
|
||||||
"description": "Add an extra layer of security to your account",
|
"id": "two-factor-authentication",
|
||||||
"icon": "MdOutlineSecurity",
|
"group": "security.account",
|
||||||
"component": "Switch",
|
"title": "Two-Factor Authentication",
|
||||||
},
|
"description": "Add an extra layer of security to your account",
|
||||||
{
|
"icon": "MdOutlineSecurity",
|
||||||
"id": "sessions",
|
"component": "Switch",
|
||||||
"group": "security.account",
|
},
|
||||||
"title": "Sessions",
|
{
|
||||||
"description": "Manage your active sessions",
|
"id": "sessions",
|
||||||
"icon": "Monitor",
|
"group": "security.account",
|
||||||
"component": loadable(() => import("../components/sessions")),
|
"title": "Sessions",
|
||||||
"storaged": false
|
"description": "Manage your active sessions",
|
||||||
},
|
"icon": "Monitor",
|
||||||
{
|
"component": loadable(() => import("../components/sessions")),
|
||||||
"id": "logout",
|
"storaged": false
|
||||||
"group": "security.other",
|
},
|
||||||
"component": "Button",
|
{
|
||||||
"icon": "LogOut",
|
"id": "logout",
|
||||||
"title": "Logout",
|
"group": "security.other",
|
||||||
"description": "Logout from your account",
|
"component": "Button",
|
||||||
"emitEvent": "session.logout",
|
"icon": "LogOut",
|
||||||
}
|
"title": "Logout",
|
||||||
]
|
"description": "Logout from your account",
|
||||||
|
"emitEvent": "session.logout",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -56,7 +56,7 @@ const SettingItem = (props) => {
|
|||||||
let { item } = props
|
let { item } = props
|
||||||
|
|
||||||
const [loading, setLoading] = React.useState(true)
|
const [loading, setLoading] = React.useState(true)
|
||||||
const [value, setValue] = React.useState(item.defaultValue ?? false)
|
const [value, setValue] = React.useState(null)
|
||||||
const [delayedValue, setDelayedValue] = React.useState(null)
|
const [delayedValue, setDelayedValue] = React.useState(null)
|
||||||
const [disabled, setDisabled] = React.useState(false)
|
const [disabled, setDisabled] = React.useState(false)
|
||||||
|
|
||||||
@ -130,15 +130,6 @@ const SettingItem = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onUnmount = () => {
|
|
||||||
// unsubscribe eventBus events
|
|
||||||
if (typeof item.dependsOn === "object") {
|
|
||||||
for (let key in item.dependsOn) {
|
|
||||||
window.app.eventBus.off(`setting.update.${key}`, onUpdateItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const checkDependsValidation = () => {
|
const checkDependsValidation = () => {
|
||||||
return !Boolean(Object.keys(item.dependsOn).every((key) => {
|
return !Boolean(Object.keys(item.dependsOn).every((key) => {
|
||||||
const storagedValue = window.app.settings.get(key)
|
const storagedValue = window.app.settings.get(key)
|
||||||
@ -160,7 +151,11 @@ const SettingItem = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof item.defaultValue === "function") {
|
if (typeof item.defaultValue === "function") {
|
||||||
setValue(await item.defaultValue())
|
setLoading(true)
|
||||||
|
|
||||||
|
setValue(await item.defaultValue(props.ctx))
|
||||||
|
|
||||||
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.disabled === true) {
|
if (item.disabled === true) {
|
||||||
@ -196,7 +191,13 @@ const SettingItem = (props) => {
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
settingInitialization()
|
settingInitialization()
|
||||||
|
|
||||||
return onUnmount
|
return () => {
|
||||||
|
if (typeof item.dependsOn === "object") {
|
||||||
|
for (let key in item.dependsOn) {
|
||||||
|
window.app.eventBus.off(`setting.update.${key}`, onUpdateItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
if (typeof SettingComponent === "string") {
|
if (typeof SettingComponent === "string") {
|
||||||
@ -301,37 +302,140 @@ const SettingItem = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="component">
|
<div className="component">
|
||||||
<div>
|
<div>
|
||||||
{loading ? <div> Loading... </div> : React.createElement(SettingComponent, {
|
{
|
||||||
...item.props,
|
loading
|
||||||
ctx: {
|
? <div> Loading... </div>
|
||||||
currentValue: value,
|
: React.createElement(SettingComponent, {
|
||||||
dispatchUpdate,
|
...item.props,
|
||||||
onUpdateItem,
|
ctx: {
|
||||||
...props.ctx,
|
currentValue: value,
|
||||||
}
|
dispatchUpdate,
|
||||||
})}
|
onUpdateItem,
|
||||||
|
...props.ctx,
|
||||||
|
}
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{delayedValue && <div>
|
{
|
||||||
<antd.Button
|
delayedValue && <div>
|
||||||
type="round"
|
<antd.Button
|
||||||
icon={<Icons.Save />}
|
type="round"
|
||||||
onClick={async () => await dispatchUpdate(value)}
|
icon={<Icons.Save />}
|
||||||
>
|
onClick={async () => await dispatchUpdate(value)}
|
||||||
Save
|
>
|
||||||
</antd.Button>
|
Save
|
||||||
</div>}
|
</antd.Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SettingGroup = React.memo((props) => {
|
||||||
|
const {
|
||||||
|
ctx,
|
||||||
|
groupKey,
|
||||||
|
settings,
|
||||||
|
loading,
|
||||||
|
} = props
|
||||||
|
|
||||||
|
const fromDecoratorIcon = groupsDecorator[groupKey]?.icon
|
||||||
|
const fromDecoratorTitle = groupsDecorator[groupKey]?.title
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <antd.Skeleton active />
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div index={groupKey} key={groupKey} className="group">
|
||||||
|
<h1>
|
||||||
|
{
|
||||||
|
fromDecoratorIcon ? React.createElement(Icons[fromDecoratorIcon]) : null
|
||||||
|
}
|
||||||
|
<Translation>
|
||||||
|
{
|
||||||
|
t => t(fromDecoratorTitle ?? groupKey)
|
||||||
|
}
|
||||||
|
</Translation>
|
||||||
|
</h1>
|
||||||
|
<div className="content">
|
||||||
|
{
|
||||||
|
settings.map((item) => <SettingItem
|
||||||
|
item={item}
|
||||||
|
ctx={ctx}
|
||||||
|
/>)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
})
|
||||||
|
|
||||||
|
const SettingTab = React.memo((props) => {
|
||||||
|
const { tab } = props
|
||||||
|
|
||||||
|
const [loading, setLoading] = React.useState(true)
|
||||||
|
const [ctxData, setCtxData] = React.useState(null)
|
||||||
|
|
||||||
|
let groupsSettings = {}
|
||||||
|
|
||||||
|
if (!Array.isArray(tab.settings)) {
|
||||||
|
console.error("Cannot generate settings from non-array")
|
||||||
|
return groupsSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
tab.settings.forEach((item) => {
|
||||||
|
if (!groupsSettings[item.group]) {
|
||||||
|
groupsSettings[item.group] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
groupsSettings[item.group].push(item)
|
||||||
|
})
|
||||||
|
|
||||||
|
const processCtx = async () => {
|
||||||
|
setLoading(true)
|
||||||
|
|
||||||
|
if (typeof tab.ctxData === "function") {
|
||||||
|
const resultCtx = await tab.ctxData()
|
||||||
|
|
||||||
|
setCtxData(resultCtx)
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
processCtx()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return Object.keys(groupsSettings).map((groupKey) => {
|
||||||
|
return <SettingGroup
|
||||||
|
groupKey={groupKey}
|
||||||
|
settings={groupsSettings[groupKey]}
|
||||||
|
loading={loading}
|
||||||
|
ctx={ctxData}
|
||||||
|
/>
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const SettingsTabs = Object.keys(SettingsList).map((settingsKey) => {
|
||||||
|
const tab = SettingsList[settingsKey]
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: settingsKey,
|
||||||
|
label: <>
|
||||||
|
{createIconRender(tab.icon ?? "Settings")}
|
||||||
|
{tab.label}
|
||||||
|
</>,
|
||||||
|
children: <SettingTab
|
||||||
|
tab={tab}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export default class SettingsMenu extends React.PureComponent {
|
export default class SettingsMenu extends React.PureComponent {
|
||||||
state = {
|
state = {
|
||||||
transitionActive: false,
|
|
||||||
activeKey: "app"
|
activeKey: "app"
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount = async () => {
|
||||||
if (typeof this.props.close === "function") {
|
if (typeof this.props.close === "function") {
|
||||||
// register escape key to close settings menu
|
// register escape key to close settings menu
|
||||||
window.addEventListener("keydown", this.handleKeyDown)
|
window.addEventListener("keydown", this.handleKeyDown)
|
||||||
@ -350,85 +454,6 @@ export default class SettingsMenu extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePageTransition = (key) => {
|
|
||||||
this.setState({
|
|
||||||
transitionActive: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.setState({
|
|
||||||
activeKey: key
|
|
||||||
})
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.setState({
|
|
||||||
transitionActive: false,
|
|
||||||
})
|
|
||||||
}, 100)
|
|
||||||
}, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
renderSettings = (key, group) => {
|
|
||||||
const fromDecoratorIcon = groupsDecorator[key]?.icon
|
|
||||||
const fromDecoratorTitle = groupsDecorator[key]?.title
|
|
||||||
|
|
||||||
return <div className={classnames("fade-opacity-active", { "fade-opacity-leave": this.state.transitionActive })}>
|
|
||||||
<div key={key} className="group">
|
|
||||||
<h1>
|
|
||||||
{fromDecoratorIcon ? React.createElement(Icons[fromDecoratorIcon]) : null}
|
|
||||||
<Translation>{
|
|
||||||
t => t(fromDecoratorTitle ?? key)
|
|
||||||
}</Translation>
|
|
||||||
</h1>
|
|
||||||
<div className="content">
|
|
||||||
{group.map((item) => <SettingItem
|
|
||||||
item={item}
|
|
||||||
ctx={{
|
|
||||||
close: this.props.close
|
|
||||||
}}
|
|
||||||
/>)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
generateSettingsGroups = (data) => {
|
|
||||||
let groups = {}
|
|
||||||
|
|
||||||
if (!Array.isArray(data)) {
|
|
||||||
console.error("Cannot generate settings groups from non-array data")
|
|
||||||
return groups
|
|
||||||
}
|
|
||||||
|
|
||||||
data.forEach((item) => {
|
|
||||||
if (!groups[item.group]) {
|
|
||||||
groups[item.group] = []
|
|
||||||
}
|
|
||||||
|
|
||||||
groups[item.group].push(item)
|
|
||||||
})
|
|
||||||
|
|
||||||
return Object.keys(groups).map((groupKey) => {
|
|
||||||
return this.renderSettings(groupKey, groups[groupKey])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
generateSettingsTabs = () => {
|
|
||||||
return Object.keys(SettingsList).map((key) => {
|
|
||||||
return <antd.Tabs.TabPane
|
|
||||||
key={key}
|
|
||||||
tab={
|
|
||||||
<span>
|
|
||||||
{createIconRender(SettingsList[key].icon)}
|
|
||||||
{SettingsList[key].label}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{this.generateSettingsGroups(SettingsList[key].settings)}
|
|
||||||
</antd.Tabs.TabPane>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
onClickAppAbout = () => {
|
onClickAppAbout = () => {
|
||||||
window.app.setLocation("/about")
|
window.app.setLocation("/about")
|
||||||
|
|
||||||
@ -437,22 +462,28 @@ export default class SettingsMenu extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeTab = (activeKey) => {
|
||||||
|
this.setState({ activeKey })
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return <div className={
|
return <div
|
||||||
classnames("settings_wrapper", {
|
className={classnames(
|
||||||
["mobile"]: window.isMobile,
|
"settings_wrapper",
|
||||||
})
|
{
|
||||||
}>
|
["mobile"]: window.isMobile,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
>
|
||||||
<div className="settings">
|
<div className="settings">
|
||||||
<antd.Tabs
|
<antd.Tabs
|
||||||
activeKey={this.state.activeKey}
|
activeKey={this.state.activeKey}
|
||||||
onTabClick={this.handlePageTransition}
|
onTabClick={this.changeTab}
|
||||||
tabPosition={window.isMobile ? "top" : "left"}
|
tabPosition={window.isMobile ? "top" : "left"}
|
||||||
centered={window.isMobile}
|
centered={window.isMobile}
|
||||||
destroyInactiveTabPane
|
destroyInactiveTabPane
|
||||||
>
|
items={SettingsTabs}
|
||||||
{this.generateSettingsTabs()}
|
/>
|
||||||
</antd.Tabs>
|
|
||||||
|
|
||||||
<SettingsFooter onClickAppAbout={this.onClickAppAbout} />
|
<SettingsFooter onClickAppAbout={this.onClickAppAbout} />
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user