mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
update settigns
This commit is contained in:
parent
108f99c897
commit
34f4623a36
109
packages/app/constants/settings/about/index.jsx
Normal file
109
packages/app/constants/settings/about/index.jsx
Normal file
@ -0,0 +1,109 @@
|
||||
import React from "react"
|
||||
import * as antd from "antd"
|
||||
import moment from "moment"
|
||||
|
||||
import { Icons } from "components/Icons"
|
||||
|
||||
import config from "config"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
const Footer = (props) => {
|
||||
const isDevMode = window.__evite?.env?.NODE_ENV !== "production"
|
||||
|
||||
return <div className="footer">
|
||||
<div>
|
||||
<div>{config.app?.siteName}</div>
|
||||
<div>
|
||||
<antd.Tag>
|
||||
<Icons.Tag />v{window.app.version}
|
||||
</antd.Tag>
|
||||
</div>
|
||||
<div>
|
||||
<antd.Tag color={isDevMode ? "magenta" : "green"}>
|
||||
{isDevMode ? <Icons.Triangle /> : <Icons.Box />}
|
||||
{isDevMode ? "development" : "stable"}
|
||||
</antd.Tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default {
|
||||
id: "about",
|
||||
icon: "Info",
|
||||
label: "About",
|
||||
group: "bottom",
|
||||
render: () => {
|
||||
const isProduction = import.meta.env.PROD
|
||||
|
||||
const [serverManifest, setServerManifest] = React.useState(null)
|
||||
|
||||
const checkServerVersion = async () => {
|
||||
const serverManifest = await app.cores.api.customRequest("main")
|
||||
|
||||
setServerManifest(serverManifest.data)
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
checkServerVersion()
|
||||
}, [])
|
||||
|
||||
return <div className="about_app">
|
||||
<div className="header">
|
||||
<div className="branding">
|
||||
<div className="logo">
|
||||
<img
|
||||
src={config.logo.alt}
|
||||
alt="Logo"
|
||||
/>
|
||||
</div>
|
||||
<div className="texts">
|
||||
<h2>{config.app.siteName}</h2>
|
||||
<span>{config.author}</span>
|
||||
<span> Licensed with {config.package?.license ?? "unlicensed"} </span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="versions">
|
||||
<antd.Tag><Icons.Tag />v{window.app.version ?? "experimental"}</antd.Tag>
|
||||
<antd.Tag color={isProduction ? "green" : "magenta"}>
|
||||
{isProduction ? <Icons.CheckCircle /> : <Icons.Triangle />}
|
||||
{String(import.meta.env.MODE)}
|
||||
</antd.Tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="group">
|
||||
<h3><Icons.Server />Server info</h3>
|
||||
|
||||
<div className="field">
|
||||
Powered by Linebridge™
|
||||
|
||||
<div className="value">
|
||||
<antd.Tag>v{serverManifest?.LINEBRIDGE_SERVER_VERSION ?? "Unknown"}</antd.Tag>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<span>
|
||||
<Icons.Globe /> Origin address
|
||||
</span>
|
||||
|
||||
<div className="value">
|
||||
{app.cores.api?.namespaces.main.origin ?? "Unknown"}
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<span>
|
||||
<Icons.Clock /> Server Time
|
||||
</span>
|
||||
|
||||
<div className="value">
|
||||
{moment(serverManifest?.requestTime).format("YYYY-MM-DD HH:mm:ss")}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
}
|
||||
}
|
93
packages/app/constants/settings/about/index.less
Executable file
93
packages/app/constants/settings/about/index.less
Executable file
@ -0,0 +1,93 @@
|
||||
.about_app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
width: 100%;
|
||||
|
||||
padding: 0 20px 20px 20px;
|
||||
|
||||
background-color: var(--background-color-accent);
|
||||
color: var(--text-color);
|
||||
|
||||
border-radius: 12px;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
justify-content: space-between;
|
||||
align-self: center;
|
||||
|
||||
width: 100%;
|
||||
|
||||
margin-bottom: 20px;
|
||||
|
||||
padding: 20px 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
|
||||
.branding {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
align-items: center;
|
||||
|
||||
.logo {
|
||||
width: 60px;
|
||||
height: 100%;
|
||||
|
||||
margin-right: 20px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.texts {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
height: fit-content;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
span {
|
||||
height: fit-content;
|
||||
color: var(--background-color-contrast);
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
display: inline-flex;
|
||||
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
margin-bottom: 10px;
|
||||
|
||||
.field {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
|
||||
margin-bottom: 10px;
|
||||
|
||||
font-size: 0.9rem;
|
||||
|
||||
.value {
|
||||
font-size: 0.8rem;
|
||||
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,173 +1,477 @@
|
||||
import React from "react"
|
||||
import loadable from "@loadable/component"
|
||||
import { Modal } from "antd"
|
||||
import UploadButton from "../components/uploadButton"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
export default {
|
||||
id: "apparence",
|
||||
icon: "Eye",
|
||||
label: "Apparence",
|
||||
group: "app",
|
||||
settings: [
|
||||
{
|
||||
"id": "compactWidth",
|
||||
"title": "Compact Width",
|
||||
"description": "Sets the width of the app to a compact width to facilitate the vision of components.",
|
||||
"component": "Switch",
|
||||
"icon": "MdCompress",
|
||||
"group": "layout",
|
||||
"experimental": true,
|
||||
"storaged": true
|
||||
id: "sidebar.floating",
|
||||
title: "Floating Sidebar",
|
||||
description: "Make the sidebar float over layout content.",
|
||||
component: "Switch",
|
||||
icon: "MdOutlineLastPage",
|
||||
group: "layout",
|
||||
emitEvent: "app.softReload",
|
||||
storaged: true,
|
||||
},
|
||||
{
|
||||
"id": "sidebar.floating",
|
||||
"title": "Floating Sidebar",
|
||||
"description": "Make the sidebar float over layout content.",
|
||||
"component": "Switch",
|
||||
"icon": "MdOutlineLastPage",
|
||||
"group": "layout",
|
||||
"emitEvent": "app.softReload",
|
||||
"storaged": true
|
||||
id: "style.reduceAnimations",
|
||||
group: "animations",
|
||||
component: "Switch",
|
||||
icon: "MdOutlineSlowMotionVideo",
|
||||
title: "Reduce animations",
|
||||
experimental: true,
|
||||
storaged: true,
|
||||
},
|
||||
{
|
||||
"id": "reduceAnimations",
|
||||
"storaged": true,
|
||||
"group": "animations",
|
||||
"component": "Switch",
|
||||
"icon": "MdOutlineSlowMotionVideo",
|
||||
"title": "Reduce animation",
|
||||
"experimental": true
|
||||
},
|
||||
{
|
||||
"id": "pageTransitionDuration",
|
||||
"storaged": true,
|
||||
"group": "animations",
|
||||
"component": "Slider",
|
||||
"icon": "MdOutlineSpeed",
|
||||
"title": "Page transition duration",
|
||||
"description": "Change the duration of the page transition animation.",
|
||||
"props": {
|
||||
id: "style.pageTransitionDuration",
|
||||
group: "animations",
|
||||
component: "Slider",
|
||||
icon: "MdOutlineSpeed",
|
||||
title: "Page transition duration",
|
||||
description: "Change the duration of the page transition animation.",
|
||||
props: {
|
||||
min: 0,
|
||||
max: 1000,
|
||||
step: 50,
|
||||
marks: {
|
||||
[app.cores.style.defaultVar("page-transition-duration").replace("ms", "")]: " ",
|
||||
},
|
||||
tooltip: {
|
||||
formatter: (value) => `${value / 1000}s`
|
||||
}
|
||||
},
|
||||
"emitEvent": "modifyTheme",
|
||||
"emissionValueUpdate": (value) => {
|
||||
return {
|
||||
defaultValue: () => {
|
||||
const value = app.cores.style.getValue("page-transition-duration")
|
||||
|
||||
return value ? Number(value.replace("ms", "")) : 250
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
"page-transition-duration": `${value}ms`
|
||||
}
|
||||
})
|
||||
},
|
||||
storaged: true,
|
||||
},
|
||||
{
|
||||
"id": "auto_darkMode",
|
||||
"experimental": true,
|
||||
"storaged": true,
|
||||
"group": "aspect",
|
||||
"component": "Switch",
|
||||
"icon": "Moon",
|
||||
"title": "Auto dark mode",
|
||||
"emitEvent": "style.autoDarkModeToogle",
|
||||
id: "style.auto_darkMode",
|
||||
group: "aspect",
|
||||
component: "Switch",
|
||||
icon: "Moon",
|
||||
title: "Sync with system",
|
||||
description: "Automatically switch to dark mode based on your system preference.",
|
||||
emitEvent: "style.autoDarkModeToogle",
|
||||
storaged: true,
|
||||
},
|
||||
{
|
||||
"experimental": true,
|
||||
"dependsOn": {
|
||||
"auto_darkMode": false
|
||||
id: "style.darkMode",
|
||||
group: "aspect",
|
||||
component: "Switch",
|
||||
icon: "Moon",
|
||||
title: "Dark mode",
|
||||
description: "Change the theme variant of the application to dark.",
|
||||
dependsOn: {
|
||||
"style.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"
|
||||
defaultValue: () => {
|
||||
return app.cores.style.currentVariant === "dark"
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
themeVariant: value ? "dark" : "light"
|
||||
})
|
||||
|
||||
return value
|
||||
},
|
||||
storaged: true
|
||||
},
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
id: "style.compactMode",
|
||||
group: "aspect",
|
||||
component: "Switch",
|
||||
icon: "MdOutlineViewCompact",
|
||||
title: "Compact mode",
|
||||
description: "Reduce the size of the application elements.",
|
||||
defaultValue: () => {
|
||||
return app.cores.style.getValue("compact-mode")
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
"compact-mode": value
|
||||
})
|
||||
|
||||
return value
|
||||
},
|
||||
storaged: true
|
||||
},
|
||||
{
|
||||
"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,
|
||||
id: "style.uiFont",
|
||||
group: "aspect",
|
||||
component: "Select",
|
||||
icon: "MdOutlineFontDownload",
|
||||
title: "UI font",
|
||||
description: "Change the font of the application.",
|
||||
props: {
|
||||
style: {
|
||||
width: "100%"
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: "Varela Round (Default)",
|
||||
value: "'Varela Round', sans-serif"
|
||||
},
|
||||
{
|
||||
label: "Inter",
|
||||
value: "'Inter', sans-serif"
|
||||
},
|
||||
]
|
||||
},
|
||||
"emitEvent": "modifyTheme",
|
||||
"emissionValueUpdate": (value) => {
|
||||
return {
|
||||
defaultValue: () => {
|
||||
return app.cores.style.getValue("fontFamily")
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
"fontFamily": value
|
||||
})
|
||||
|
||||
return value
|
||||
},
|
||||
storaged: true
|
||||
},
|
||||
{
|
||||
id: "style.colorPrimary",
|
||||
group: "aspect",
|
||||
component: "SliderColorPicker",
|
||||
title: "Primary color",
|
||||
description: "Change primary color of the application.",
|
||||
defaultValue: () => {
|
||||
return app.cores.style.getValue("colorPrimary")
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
"colorPrimary": value
|
||||
})
|
||||
},
|
||||
storaged: false,
|
||||
},
|
||||
{
|
||||
id: "style.parallaxBackground",
|
||||
group: "aspect",
|
||||
component: "Switch",
|
||||
icon: "MdOutline3DRotation",
|
||||
title: "Parallax background",
|
||||
description: "Create a parallax effect on the background.",
|
||||
storaged: true,
|
||||
},
|
||||
{
|
||||
id: "style.backgroundImage",
|
||||
group: "aspect",
|
||||
icon: "MdOutlineImage",
|
||||
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/urlInput")),
|
||||
props: {
|
||||
noPreview: true,
|
||||
},
|
||||
extraActions: [
|
||||
{
|
||||
id: "delete",
|
||||
icon: "Delete",
|
||||
title: "Remove",
|
||||
onClick: (ctx) => {
|
||||
return ctx.dispatchUpdate("")
|
||||
}
|
||||
},
|
||||
UploadButton
|
||||
],
|
||||
defaultValue: () => {
|
||||
const value = app.cores.style.getValue("backgroundImage")
|
||||
|
||||
console.log(value)
|
||||
|
||||
return value ? value.replace(/url\(|\)/g, "") : ""
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
backgroundImage: `url(${value})`
|
||||
}
|
||||
})
|
||||
},
|
||||
storaged: false,
|
||||
},
|
||||
{
|
||||
"id": "backgroundBlur",
|
||||
"storaged": true,
|
||||
"group": "aspect",
|
||||
"component": "Slider",
|
||||
"icon": "Eye",
|
||||
"title": "Background blur",
|
||||
"description": "Create a blur effect on the background.",
|
||||
"props": {
|
||||
id: "style.backgroundPattern",
|
||||
group: "aspect",
|
||||
icon: "MdGrid4X4",
|
||||
component: loadable(() => import("../components/backgroundSelector")),
|
||||
title: "Background pattern",
|
||||
description: "Change background pattern of the application.",
|
||||
extraActions: [
|
||||
{
|
||||
id: "remove",
|
||||
icon: "Delete",
|
||||
title: "Remove",
|
||||
onClick: () => {
|
||||
app.cores.style.modify({
|
||||
backgroundSVG: "unset"
|
||||
})
|
||||
}
|
||||
}
|
||||
],
|
||||
storaged: false,
|
||||
},
|
||||
{
|
||||
id: "style.backgroundBlur",
|
||||
group: "aspect",
|
||||
component: "Slider",
|
||||
icon: "MdBlurOn",
|
||||
title: "Background blur",
|
||||
description: "Create a blur effect on the background.",
|
||||
props: {
|
||||
min: 0,
|
||||
max: 50,
|
||||
step: 5
|
||||
step: 1
|
||||
},
|
||||
"emitEvent": "modifyTheme",
|
||||
"emissionValueUpdate": (value) => {
|
||||
return {
|
||||
backgroundBlur: `${value}px`,
|
||||
}
|
||||
defaultValue: () => {
|
||||
const value = app.cores.style.getValue("backgroundBlur")
|
||||
|
||||
return value ? parseInt(value.replace("px", "")) : 0
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
backgroundBlur: `${value}px`
|
||||
})
|
||||
},
|
||||
storaged: false,
|
||||
},
|
||||
{
|
||||
"id": "backgroundColorTransparency",
|
||||
"storaged": true,
|
||||
"group": "aspect",
|
||||
"component": "Slider",
|
||||
"icon": "Eye",
|
||||
"title": "Background color transparency",
|
||||
"description": "Adjust the transparency of the background color.",
|
||||
"props": {
|
||||
id: "style.backgroundColorTransparency",
|
||||
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,
|
||||
}
|
||||
defaultValue: () => {
|
||||
const value = app.cores.style.getValue("backgroundColorTransparency")
|
||||
|
||||
return value ? parseFloat(value) : 1
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
backgroundColorTransparency: value
|
||||
})
|
||||
},
|
||||
storaged: false
|
||||
},
|
||||
{
|
||||
"id": "resetTheme",
|
||||
"storaged": true,
|
||||
"group": "aspect",
|
||||
"component": "Button",
|
||||
"title": "Reset theme",
|
||||
"props": {
|
||||
"children": "Default Theme"
|
||||
id: "style.backgroundSize",
|
||||
group: "aspect",
|
||||
component: "Select",
|
||||
icon: "MdOutlineImageAspectRatio",
|
||||
title: "Background size",
|
||||
description: "Adjust the size of the background image.",
|
||||
props: {
|
||||
style: {
|
||||
width: "100%"
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: "Cover",
|
||||
value: "cover"
|
||||
},
|
||||
{
|
||||
label: "Contain",
|
||||
value: "contain"
|
||||
},
|
||||
{
|
||||
label: "Auto",
|
||||
value: "auto"
|
||||
},
|
||||
{
|
||||
label: "50%",
|
||||
value: "50%"
|
||||
},
|
||||
{
|
||||
label: "100%",
|
||||
value: "100%"
|
||||
},
|
||||
{
|
||||
label: "150%",
|
||||
value: "150%"
|
||||
},
|
||||
]
|
||||
},
|
||||
"emitEvent": "resetTheme",
|
||||
"noUpdate": true,
|
||||
defaultValue: () => {
|
||||
return app.cores.style.getValue("backgroundSize")
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
backgroundSize: value
|
||||
})
|
||||
|
||||
return value
|
||||
},
|
||||
storaged: false
|
||||
},
|
||||
{
|
||||
id: "style.backgroundPosition",
|
||||
group: "aspect",
|
||||
component: "Select",
|
||||
icon: "MdOutlineImageAspectRatio",
|
||||
title: "Background position",
|
||||
description: "Adjust the position of the background image.",
|
||||
props: {
|
||||
style: {
|
||||
width: "100%"
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: "Left",
|
||||
value: "left"
|
||||
},
|
||||
{
|
||||
label: "Center",
|
||||
value: "center"
|
||||
},
|
||||
{
|
||||
label: "Right",
|
||||
value: "right"
|
||||
},
|
||||
{
|
||||
label: "Top",
|
||||
value: "top"
|
||||
},
|
||||
]
|
||||
},
|
||||
defaultValue: () => {
|
||||
return app.cores.style.getValue("backgroundPosition")
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
backgroundPosition: value
|
||||
})
|
||||
|
||||
return value
|
||||
},
|
||||
storaged: false
|
||||
},
|
||||
{
|
||||
id: "style.backgroundRepeat",
|
||||
group: "aspect",
|
||||
component: "Select",
|
||||
icon: "MdOutlineImageAspectRatio",
|
||||
title: "Background repeat",
|
||||
description: "Adjust the repeat of the background image.",
|
||||
props: {
|
||||
style: {
|
||||
width: "100%"
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: "Repeat",
|
||||
value: "repeat"
|
||||
},
|
||||
{
|
||||
label: "No repeat",
|
||||
value: "no-repeat"
|
||||
},
|
||||
{
|
||||
label: "Repeat X",
|
||||
value: "repeat-x"
|
||||
},
|
||||
{
|
||||
label: "Repeat Y",
|
||||
value: "repeat-y"
|
||||
},
|
||||
]
|
||||
},
|
||||
defaultValue: () => {
|
||||
return app.cores.style.getValue("backgroundRepeat")
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
backgroundRepeat: value
|
||||
})
|
||||
|
||||
return value
|
||||
},
|
||||
storaged: false
|
||||
},
|
||||
{
|
||||
id: "style.backgroundAttachment",
|
||||
group: "aspect",
|
||||
component: "Select",
|
||||
icon: "MdOutlineImageAspectRatio",
|
||||
title: "Background attachment",
|
||||
description: "Adjust the attachment of the background image.",
|
||||
props: {
|
||||
style: {
|
||||
width: "100%"
|
||||
},
|
||||
options: [
|
||||
{
|
||||
label: "Scroll",
|
||||
value: "scroll"
|
||||
},
|
||||
{
|
||||
label: "Fixed",
|
||||
value: "fixed"
|
||||
},
|
||||
{
|
||||
label: "Local",
|
||||
value: "local"
|
||||
},
|
||||
{
|
||||
label: "Initial",
|
||||
value: "initial"
|
||||
},
|
||||
{
|
||||
label: "Inherit",
|
||||
value: "inherit"
|
||||
},
|
||||
]
|
||||
},
|
||||
defaultValue: () => {
|
||||
return app.cores.style.getValue("backgroundAttachment")
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
app.cores.style.modify({
|
||||
backgroundAttachment: value
|
||||
})
|
||||
|
||||
return value
|
||||
},
|
||||
storaged: false
|
||||
},
|
||||
{
|
||||
id: "resetTheme",
|
||||
group: "aspect",
|
||||
component: "Button",
|
||||
title: "Reset theme",
|
||||
props: {
|
||||
children: "Default Theme"
|
||||
},
|
||||
onUpdate: (value) => {
|
||||
Modal.confirm({
|
||||
title: "Are you sure you want to reset the theme to the default theme ?",
|
||||
description: "This action will reset the theme to the default theme. All your modifications will be lost.",
|
||||
onOk: () => {
|
||||
app.cores.style.setDefault()
|
||||
}
|
||||
})
|
||||
},
|
||||
storaged: false
|
||||
}
|
||||
]
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
import React from "react"
|
||||
import { Button, Input, Upload } from "antd"
|
||||
import { Icons } from "components/Icons"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
export default (props) => {
|
||||
const [value, setValue] = React.useState(props.ctx.currentValue)
|
||||
const [uploading, setUploading] = React.useState(false)
|
||||
|
||||
const uploadImage = async (req) => {
|
||||
setUploading(true)
|
||||
|
||||
const formData = new FormData()
|
||||
|
||||
formData.append("files", req.file)
|
||||
|
||||
const request = await window.app.api.withEndpoints("main").post.upload(formData, undefined).catch((error) => {
|
||||
console.error(error)
|
||||
app.message.error(error)
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
setUploading(false)
|
||||
|
||||
if (request) {
|
||||
setValue(request.files[0].url)
|
||||
props.ctx.dispatchUpdate(request.files[0].url)
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="imageUploader">
|
||||
{
|
||||
!props.noPreview && value && <div className="uploadPreview">
|
||||
<img src={value} />
|
||||
</div>
|
||||
}
|
||||
|
||||
<Input.Group compact>
|
||||
<Input
|
||||
placeholder="Image URL..."
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
onPressEnter={() => props.ctx.dispatchUpdate(value)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon={<Icons.Save />}
|
||||
onClick={() => props.ctx.dispatchUpdate(value)}
|
||||
/>
|
||||
</Input.Group>
|
||||
|
||||
or
|
||||
|
||||
<Upload
|
||||
customRequest={uploadImage}
|
||||
multiple={false}
|
||||
accept="image/*"
|
||||
progress={false}
|
||||
fileList={[]}
|
||||
>
|
||||
<Button
|
||||
icon={<Icons.Upload />}
|
||||
loading={uploading}
|
||||
>
|
||||
Upload
|
||||
</Button>
|
||||
</Upload>
|
||||
</div>
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import React from "react"
|
||||
import SVG from "react-inlinesvg"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
const defaultBackgrounds = [
|
||||
{
|
||||
id: "topography",
|
||||
label: "Topography",
|
||||
src: "/assets/default_bg/topography.svg"
|
||||
},
|
||||
{
|
||||
id: "meteors",
|
||||
label: "Meteors",
|
||||
src: "/assets/default_bg/meteors.svg"
|
||||
},
|
||||
{
|
||||
id: "dots",
|
||||
label: "Dots",
|
||||
src: "/assets/default_bg/dots.svg"
|
||||
},
|
||||
{
|
||||
id: "hideout",
|
||||
label: "Hideout",
|
||||
src: "/assets/default_bg/hideout.svg"
|
||||
}
|
||||
]
|
||||
|
||||
export default (props) => {
|
||||
return <div className="background_selector">
|
||||
<div className="background_selector_defaults">
|
||||
{
|
||||
defaultBackgrounds.map((background) => {
|
||||
return <div className="background_selector_defaults__item">
|
||||
<div className="background_selector_defaults__item_name">
|
||||
<h3>{background.label}</h3>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="background_selector_defaults__item_preview"
|
||||
onClick={() => {
|
||||
app.cores.style.modify({
|
||||
backgroundSVG: `url("${background.src}")`
|
||||
})
|
||||
}}
|
||||
style={{
|
||||
maskImage: `url("${background.src}")`,
|
||||
WebkitMaskImage: `url("${background.src}")`
|
||||
}}
|
||||
/>
|
||||
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
.background_selector {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.background_selector_defaults {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
overflow-x: auto;
|
||||
|
||||
.background_selector_defaults__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
||||
width: 10vw;
|
||||
height: 300px;
|
||||
|
||||
transition: all 150ms ease-in-out;
|
||||
|
||||
margin-right: 20px;
|
||||
|
||||
background-color: var(--background-color-accent);
|
||||
|
||||
border-radius: 10px;
|
||||
|
||||
.background_selector_defaults__item_name {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
|
||||
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
|
||||
margin: 10px;
|
||||
|
||||
}
|
||||
|
||||
.background_selector_defaults__item_preview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
border-radius: 10px;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
background-color: var(--text-color);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import React from "react"
|
||||
import * as antd from "antd"
|
||||
|
||||
import { User } from "models"
|
||||
import { UserModel } from "models"
|
||||
import { Icons } from "components/Icons"
|
||||
|
||||
import "./index.less"
|
||||
@ -31,7 +31,7 @@ const ChangePasswordComponent = (props) => {
|
||||
setError(null)
|
||||
setLoading(true)
|
||||
|
||||
const result = await User.changePassword({ currentPassword, newPassword }).catch((err) => {
|
||||
const result = await UserModel.changePassword({ currentPassword, newPassword }).catch((err) => {
|
||||
console.error(err)
|
||||
setError(err.response.data.message)
|
||||
return null
|
||||
|
@ -0,0 +1,69 @@
|
||||
import React from "react"
|
||||
import { Button, Upload } from "antd"
|
||||
|
||||
import { Icons } from "components/Icons"
|
||||
|
||||
export default (props) => {
|
||||
const [uploading, setUploading] = React.useState(false)
|
||||
|
||||
const handleUpload = async (req) => {
|
||||
console.log(req)
|
||||
|
||||
setUploading(true)
|
||||
|
||||
const formData = new FormData()
|
||||
|
||||
formData.append("files", req.file)
|
||||
|
||||
const request = await window.app.cores.api.customRequest({
|
||||
url: "/upload",
|
||||
method: "POST",
|
||||
data: formData
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
app.message.error(error.respose.data.message)
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
setUploading(false)
|
||||
|
||||
if (request) {
|
||||
// check failed uploads
|
||||
if (request.failed.length > 0) {
|
||||
request.failed.forEach((file) => {
|
||||
app.notification.error({
|
||||
message: "Failed to upload file",
|
||||
description: `Could not upload file ${file.fileName} cause > ${file.error}`
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
props.ctx.dispatchUpdate(request.files[0].url)
|
||||
}
|
||||
}
|
||||
|
||||
return <Upload
|
||||
customRequest={handleUpload}
|
||||
multiple={false}
|
||||
accept="image/*"
|
||||
progress={false}
|
||||
fileList={[]}
|
||||
>
|
||||
<Button
|
||||
icon={props.icon ?? <Icons.Upload
|
||||
style={{
|
||||
margin: 0
|
||||
}}
|
||||
/>}
|
||||
loading={uploading}
|
||||
type={
|
||||
props.type ?? "round"
|
||||
}
|
||||
>
|
||||
{
|
||||
props.children ?? "Upload"
|
||||
}
|
||||
</Button>
|
||||
</Upload>
|
||||
}
|
31
packages/app/constants/settings/components/urlInput/index.jsx
Executable file
31
packages/app/constants/settings/components/urlInput/index.jsx
Executable file
@ -0,0 +1,31 @@
|
||||
import React from "react"
|
||||
import { Button, Input } from "antd"
|
||||
import { Icons } from "components/Icons"
|
||||
|
||||
import "./index.less"
|
||||
|
||||
export default (props) => {
|
||||
const [value, setValue] = React.useState(props.ctx.currentValue)
|
||||
|
||||
return <div className="imageUploader">
|
||||
{
|
||||
!props.noPreview && value && <div className="uploadPreview">
|
||||
<img src={value} />
|
||||
</div>
|
||||
}
|
||||
|
||||
<Input.Group compact>
|
||||
<Input
|
||||
placeholder="Image URL..."
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
onPressEnter={() => props.ctx.dispatchUpdate(value)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
icon={<Icons.Save />}
|
||||
onClick={() => props.ctx.dispatchUpdate(value)}
|
||||
/>
|
||||
</Input.Group>
|
||||
</div>
|
||||
}
|
@ -2,8 +2,10 @@ import React from "react"
|
||||
import loadable from "@loadable/component"
|
||||
|
||||
export default {
|
||||
id: "extensions",
|
||||
icon: "MdOutlineCode",
|
||||
label: "Extensions",
|
||||
group: "advanced",
|
||||
settings: [
|
||||
|
||||
]
|
||||
|
@ -3,8 +3,10 @@ import config from "config"
|
||||
import { Select } from "antd"
|
||||
|
||||
export default {
|
||||
id: "general",
|
||||
icon: "Command",
|
||||
label: "App",
|
||||
label: "General",
|
||||
group: "app",
|
||||
settings: [
|
||||
{
|
||||
"id": "language",
|
@ -1,17 +1,24 @@
|
||||
import AppSettings from "./app"
|
||||
import GeneralSettings from "./general"
|
||||
import ProfileSettings from "./profile"
|
||||
import SecuritySettings from "./security"
|
||||
import SubcriptionsSettings from "./subscriptions"
|
||||
import NotificationsSettings from "./notifications"
|
||||
import ApparenceSettings from "./apparence"
|
||||
import ExtensionsSettings from "./extensions"
|
||||
import SyncSettings from "./sync"
|
||||
import PlayerSettings from "./player"
|
||||
|
||||
import AboutPage from "./about"
|
||||
|
||||
export default {
|
||||
app: AppSettings,
|
||||
general: GeneralSettings,
|
||||
profile: ProfileSettings,
|
||||
apparence: ApparenceSettings,
|
||||
player: PlayerSettings,
|
||||
security: SecuritySettings,
|
||||
notifications: NotificationsSettings,
|
||||
extensions: ExtensionsSettings,
|
||||
sync: SyncSettings,
|
||||
subscriptions: SubcriptionsSettings,
|
||||
about: AboutPage,
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
import React from "react"
|
||||
|
||||
export default {
|
||||
id: "notifications",
|
||||
icon: "Bell",
|
||||
label: "Notifications",
|
||||
group: "basic",
|
||||
settings: [
|
||||
|
||||
]
|
||||
|
40
packages/app/constants/settings/player/index.jsx
Normal file
40
packages/app/constants/settings/player/index.jsx
Normal file
@ -0,0 +1,40 @@
|
||||
export default {
|
||||
id: "player",
|
||||
icon: "PlayCircleOutlined",
|
||||
label: "Player",
|
||||
group: "app",
|
||||
settings: [
|
||||
{
|
||||
id: "player.allowVolumeOver100",
|
||||
label: "Allow volume over 100%",
|
||||
description: "Allow volume amplification over 100% (may cause distortion)",
|
||||
component: "Switch",
|
||||
storaged: true,
|
||||
},
|
||||
{
|
||||
id: "player.crossfade",
|
||||
label: "Crossfade",
|
||||
description: "Enable crossfade between tracks",
|
||||
component: "Slider",
|
||||
props: {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 0.1,
|
||||
marks: {
|
||||
0: "Off",
|
||||
1: "1s",
|
||||
2: "2s",
|
||||
3: "3s",
|
||||
4: "4s",
|
||||
5: "5s",
|
||||
6: "6s",
|
||||
7: "7s",
|
||||
8: "8s",
|
||||
9: "9s",
|
||||
10: "10s",
|
||||
},
|
||||
},
|
||||
storaged: true,
|
||||
}
|
||||
]
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
import React from "react"
|
||||
import { User } from "models"
|
||||
import { UserModel } from "models"
|
||||
import loadable from "@loadable/component"
|
||||
import UploadButton from "../components/uploadButton"
|
||||
|
||||
export default {
|
||||
id: "profile",
|
||||
icon: "User",
|
||||
label: "Profile",
|
||||
group: "basic",
|
||||
ctxData: async () => {
|
||||
const userData = await User.data()
|
||||
const userData = await UserModel.data()
|
||||
|
||||
return {
|
||||
userData
|
||||
@ -26,47 +29,43 @@ export default {
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "fullName",
|
||||
"group": "account.basicInfo",
|
||||
"component": "Input",
|
||||
"icon": "Edit3",
|
||||
"title": "Name",
|
||||
"description": "Change your public name",
|
||||
"props": {
|
||||
id: "fullName",
|
||||
group: "account.basicInfo",
|
||||
component: "Input",
|
||||
icon: "Edit3",
|
||||
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) => {
|
||||
defaultValue: (ctx) => {
|
||||
return ctx.userData.fullName
|
||||
},
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
fullName: value
|
||||
}
|
||||
onUpdate: async (value) => {
|
||||
const result = await UserModel.updateData({
|
||||
fullName: value
|
||||
})
|
||||
|
||||
if (result) {
|
||||
return result
|
||||
}
|
||||
},
|
||||
"extraActions": [
|
||||
extraActions: [
|
||||
{
|
||||
"id": "unset",
|
||||
"icon": "Delete",
|
||||
"title": "Unset",
|
||||
"onClick": async () => {
|
||||
window.app.api.withEndpoints("main").post.unsetPublicName()
|
||||
await UserModel.unsetFullName()
|
||||
}
|
||||
}
|
||||
],
|
||||
"debounced": true,
|
||||
debounced: true,
|
||||
storaged: false,
|
||||
},
|
||||
{
|
||||
"id": "email",
|
||||
@ -85,13 +84,8 @@ export default {
|
||||
return ctx.userData.email
|
||||
},
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
email: value
|
||||
}
|
||||
const result = await UserModel.updateData({
|
||||
email: value
|
||||
})
|
||||
|
||||
if (result) {
|
||||
@ -106,18 +100,16 @@ export default {
|
||||
"icon": "Image",
|
||||
"title": "Avatar",
|
||||
"description": "Change your avatar (Upload an image or use an URL)",
|
||||
"component": loadable(() => import("../components/ImageUploader")),
|
||||
"component": loadable(() => import("../components/urlInput")),
|
||||
extraActions: [
|
||||
UploadButton
|
||||
],
|
||||
"defaultValue": (ctx) => {
|
||||
return ctx.userData.avatar
|
||||
},
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
avatar: value
|
||||
}
|
||||
const result = await UserModel.updateData({
|
||||
avatar: value
|
||||
})
|
||||
|
||||
if (result) {
|
||||
@ -133,18 +125,16 @@ export default {
|
||||
"icon": "Image",
|
||||
"title": "Cover",
|
||||
"description": "Change your profile cover (Upload an image or use an URL)",
|
||||
"component": loadable(() => import("../components/ImageUploader")),
|
||||
"component": loadable(() => import("../components/urlInput")),
|
||||
extraActions: [
|
||||
UploadButton
|
||||
],
|
||||
"defaultValue": (ctx) => {
|
||||
return ctx.userData.cover
|
||||
},
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
cover: value
|
||||
}
|
||||
const result = await UserModel.updateData({
|
||||
cover: value
|
||||
})
|
||||
|
||||
if (result) {
|
||||
@ -171,13 +161,8 @@ export default {
|
||||
return ctx.userData.description
|
||||
},
|
||||
"onUpdate": async (value) => {
|
||||
const selfId = await User.selfUserId()
|
||||
|
||||
const result = window.app.api.withEndpoints("main").post.updateUser({
|
||||
_id: selfId,
|
||||
update: {
|
||||
description: value
|
||||
}
|
||||
const result = await UserModel.updateData({
|
||||
description: value
|
||||
})
|
||||
|
||||
if (result) {
|
||||
@ -185,6 +170,7 @@ export default {
|
||||
}
|
||||
},
|
||||
"debounced": true,
|
||||
storaged: false,
|
||||
},
|
||||
]
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
import React from "react"
|
||||
import loadable from "@loadable/component"
|
||||
import AuthModel from "models/auth"
|
||||
|
||||
// TODO: Make logout button require a valid session to be not disabled
|
||||
|
||||
export default {
|
||||
id: "security",
|
||||
icon: "Shield",
|
||||
label: "Security",
|
||||
group: "basic",
|
||||
settings: [
|
||||
{
|
||||
"id": "change-password",
|
||||
@ -39,7 +42,9 @@ export default {
|
||||
"icon": "LogOut",
|
||||
"title": "Logout",
|
||||
"description": "Logout from your account",
|
||||
"emitEvent": "session.logout",
|
||||
onUpdate: async () => {
|
||||
await AuthModel.logout()
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
8
packages/app/constants/settings/subscriptions/index.jsx
Normal file
8
packages/app/constants/settings/subscriptions/index.jsx
Normal file
@ -0,0 +1,8 @@
|
||||
export default {
|
||||
id: "subscriptions",
|
||||
label: "Subscriptions",
|
||||
icon: "MdLoyalty",
|
||||
group: "other",
|
||||
settings: [
|
||||
]
|
||||
}
|
@ -5,8 +5,10 @@ import SyncModel from "models/sync"
|
||||
// TODO: Make logout button require a valid session to be not disabled
|
||||
|
||||
export default {
|
||||
id: "sync",
|
||||
icon: "MdSync",
|
||||
label: "Sync",
|
||||
group: "advanced",
|
||||
ctxData: async () => {
|
||||
const spotifyAccount = await SyncModel.spotifyCore.getData().catch((err) => {
|
||||
return null
|
||||
|
Loading…
x
Reference in New Issue
Block a user