Settings: Fix resetting scroll/search when getting a ping (#1106)
This commit is contained in:
parent
0c54b1fa1d
commit
5c5b009c41
15 changed files with 110 additions and 183 deletions
|
@ -37,8 +37,6 @@ import { checkForUpdates, update, UpdateLogger } from "./utils/updater";
|
||||||
import { onceReady } from "./webpack";
|
import { onceReady } from "./webpack";
|
||||||
import { SettingsRouter } from "./webpack/common";
|
import { SettingsRouter } from "./webpack/common";
|
||||||
|
|
||||||
export let Components: any;
|
|
||||||
|
|
||||||
async function syncSettings() {
|
async function syncSettings() {
|
||||||
if (
|
if (
|
||||||
Settings.cloud.settingsSync && // if it's enabled
|
Settings.cloud.settingsSync && // if it's enabled
|
||||||
|
@ -65,7 +63,6 @@ async function syncSettings() {
|
||||||
async function init() {
|
async function init() {
|
||||||
await onceReady;
|
await onceReady;
|
||||||
startAllPlugins();
|
startAllPlugins();
|
||||||
Components = await import("./components");
|
|
||||||
|
|
||||||
syncSettings();
|
syncSettings();
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import * as $MessagePopover from "./MessagePopover";
|
||||||
import * as $Notices from "./Notices";
|
import * as $Notices from "./Notices";
|
||||||
import * as $Notifications from "./Notifications";
|
import * as $Notifications from "./Notifications";
|
||||||
import * as $ServerList from "./ServerList";
|
import * as $ServerList from "./ServerList";
|
||||||
|
import * as $Settings from "./Settings";
|
||||||
import * as $SettingsStore from "./SettingsStore";
|
import * as $SettingsStore from "./SettingsStore";
|
||||||
import * as $Styles from "./Styles";
|
import * as $Styles from "./Styles";
|
||||||
|
|
||||||
|
@ -86,6 +87,10 @@ export const MessageDecorations = $MessageDecorations;
|
||||||
* An API allowing you to add components to member list users, in both DM's and servers
|
* An API allowing you to add components to member list users, in both DM's and servers
|
||||||
*/
|
*/
|
||||||
export const MemberListDecorators = $MemberListDecorators;
|
export const MemberListDecorators = $MemberListDecorators;
|
||||||
|
/**
|
||||||
|
* An API allowing you to persist data
|
||||||
|
*/
|
||||||
|
export const Settings = $Settings;
|
||||||
/**
|
/**
|
||||||
* An API allowing you to read, manipulate and automatically update components based on Discord settings
|
* An API allowing you to read, manipulate and automatically update components based on Discord settings
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,20 +20,18 @@ import "./styles.css";
|
||||||
|
|
||||||
import * as DataStore from "@api/DataStore";
|
import * as DataStore from "@api/DataStore";
|
||||||
import { showNotice } from "@api/Notices";
|
import { showNotice } from "@api/Notices";
|
||||||
import { useSettings } from "@api/Settings";
|
import { Settings, useSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { handleComponentFailed } from "@components/handleComponentFailed";
|
|
||||||
import { Badge } from "@components/PluginSettings/components";
|
import { Badge } from "@components/PluginSettings/components";
|
||||||
import PluginModal from "@components/PluginSettings/PluginModal";
|
import PluginModal from "@components/PluginSettings/PluginModal";
|
||||||
import { Switch } from "@components/Switch";
|
import { Switch } from "@components/Switch";
|
||||||
|
import { SettingsTab } from "@components/VencordSettings/shared";
|
||||||
import { ChangeList } from "@utils/ChangeList";
|
import { ChangeList } from "@utils/ChangeList";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { openModalLazy } from "@utils/modal";
|
import { openModalLazy } from "@utils/modal";
|
||||||
import { onlyOnce } from "@utils/onlyOnce";
|
|
||||||
import { LazyComponent, useAwaiter } from "@utils/react";
|
import { LazyComponent, useAwaiter } from "@utils/react";
|
||||||
import { Plugin } from "@utils/types";
|
import { Plugin } from "@utils/types";
|
||||||
import { findByCode, findByPropsLazy } from "@webpack";
|
import { findByCode, findByPropsLazy } from "@webpack";
|
||||||
|
@ -96,7 +94,7 @@ interface PluginCardProps extends React.HTMLProps<HTMLDivElement> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) {
|
function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) {
|
||||||
const settings = useSettings([`plugins.${plugin.name}.enabled`]).plugins[plugin.name];
|
const settings = Settings.plugins[plugin.name];
|
||||||
|
|
||||||
const isEnabled = () => settings.enabled ?? false;
|
const isEnabled = () => settings.enabled ?? false;
|
||||||
|
|
||||||
|
@ -179,7 +177,7 @@ enum SearchStatus {
|
||||||
DISABLED
|
DISABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ErrorBoundary.wrap(function PluginSettings() {
|
export default function PluginSettings() {
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const changes = React.useMemo(() => new ChangeList<string>(), []);
|
const changes = React.useMemo(() => new ChangeList<string>(), []);
|
||||||
|
|
||||||
|
@ -303,7 +301,7 @@ export default ErrorBoundary.wrap(function PluginSettings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection className={Margins.top16}>
|
<SettingsTab title="Plugins">
|
||||||
<ReloadRequiredCard required={changes.hasChanges} />
|
<ReloadRequiredCard required={changes.hasChanges} />
|
||||||
|
|
||||||
<Forms.FormTitle tag="h5" className={classes(Margins.top20, Margins.bottom8)}>
|
<Forms.FormTitle tag="h5" className={classes(Margins.top20, Margins.bottom8)}>
|
||||||
|
@ -342,12 +340,9 @@ export default ErrorBoundary.wrap(function PluginSettings() {
|
||||||
<div className={cl("grid")}>
|
<div className={cl("grid")}>
|
||||||
{requiredPlugins}
|
{requiredPlugins}
|
||||||
</div>
|
</div>
|
||||||
</Forms.FormSection >
|
</SettingsTab >
|
||||||
);
|
);
|
||||||
}, {
|
}
|
||||||
message: "Failed to render the Plugin Settings. If this persists, try using the installer to reinstall!",
|
|
||||||
onError: onlyOnce(handleComponentFailed),
|
|
||||||
});
|
|
||||||
|
|
||||||
function makeDependencyList(deps: string[]) {
|
function makeDependencyList(deps: string[]) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -16,16 +16,17 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { downloadSettingsBackup, uploadSettingsBackup } from "@utils/settingsSync";
|
import { downloadSettingsBackup, uploadSettingsBackup } from "@utils/settingsSync";
|
||||||
import { Button, Card, Forms, Text } from "@webpack/common";
|
import { Button, Card, Text } from "@webpack/common";
|
||||||
|
|
||||||
|
import { SettingsTab, wrapTab } from "./shared";
|
||||||
|
|
||||||
function BackupRestoreTab() {
|
function BackupRestoreTab() {
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection title="Settings Sync" className={Margins.top16}>
|
<SettingsTab title="Backup & Restore">
|
||||||
<Card className={classes("vc-settings-card", "vc-backup-restore-card")}>
|
<Card className={classes("vc-settings-card", "vc-backup-restore-card")}>
|
||||||
<Flex flexDirection="column">
|
<Flex flexDirection="column">
|
||||||
<strong>Warning</strong>
|
<strong>Warning</strong>
|
||||||
|
@ -59,8 +60,8 @@ function BackupRestoreTab() {
|
||||||
Export Settings
|
Export Settings
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Forms.FormSection>
|
</SettingsTab>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ErrorBoundary.wrap(BackupRestoreTab);
|
export default wrapTab(BackupRestoreTab, "Backup & Restore");
|
|
@ -19,13 +19,14 @@
|
||||||
import { showNotification } from "@api/Notifications";
|
import { showNotification } from "@api/Notifications";
|
||||||
import { Settings, useSettings } from "@api/Settings";
|
import { Settings, useSettings } from "@api/Settings";
|
||||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Link } from "@components/Link";
|
import { Link } from "@components/Link";
|
||||||
import { authorizeCloud, cloudLogger, deauthorizeCloud, getCloudAuth, getCloudUrl } from "@utils/cloud";
|
import { authorizeCloud, cloudLogger, deauthorizeCloud, getCloudAuth, getCloudUrl } from "@utils/cloud";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { deleteCloudSettings, getCloudSettings, putCloudSettings } from "@utils/settingsSync";
|
import { deleteCloudSettings, getCloudSettings, putCloudSettings } from "@utils/settingsSync";
|
||||||
import { Alerts, Button, Forms, Switch, Tooltip } from "@webpack/common";
|
import { Alerts, Button, Forms, Switch, Tooltip } from "@webpack/common";
|
||||||
|
|
||||||
|
import { SettingsTab, wrapTab } from "./shared";
|
||||||
|
|
||||||
function validateUrl(url: string) {
|
function validateUrl(url: string) {
|
||||||
try {
|
try {
|
||||||
new URL(url);
|
new URL(url);
|
||||||
|
@ -114,7 +115,7 @@ function CloudTab() {
|
||||||
const settings = useSettings(["cloud.authenticated", "cloud.url"]);
|
const settings = useSettings(["cloud.authenticated", "cloud.url"]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<SettingsTab title="Vencord Cloud">
|
||||||
<Forms.FormSection title="Cloud Settings" className={Margins.top16}>
|
<Forms.FormSection title="Cloud Settings" className={Margins.top16}>
|
||||||
<Forms.FormText variant="text-md/normal" className={Margins.bottom20}>
|
<Forms.FormText variant="text-md/normal" className={Margins.bottom20}>
|
||||||
Vencord comes with a cloud integration that adds goodies like settings sync across devices.
|
Vencord comes with a cloud integration that adds goodies like settings sync across devices.
|
||||||
|
@ -157,8 +158,8 @@ function CloudTab() {
|
||||||
<Forms.FormDivider className={Margins.top16} />
|
<Forms.FormDivider className={Margins.top16} />
|
||||||
</Forms.FormSection >
|
</Forms.FormSection >
|
||||||
<SettingsSyncSection />
|
<SettingsSyncSection />
|
||||||
</>
|
</SettingsTab>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ErrorBoundary.wrap(CloudTab);
|
export default wrapTab(CloudTab, "Cloud");
|
||||||
|
|
|
@ -16,16 +16,16 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||||
import { debounce } from "@utils/debounce";
|
import { debounce } from "@utils/debounce";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
|
import { canonicalizeMatch, canonicalizeReplace } from "@utils/patches";
|
||||||
import { makeCodeblock } from "@utils/text";
|
import { makeCodeblock } from "@utils/text";
|
||||||
import { ReplaceFn } from "@utils/types";
|
import { ReplaceFn } from "@utils/types";
|
||||||
import { search } from "@webpack";
|
import { search } from "@webpack";
|
||||||
import { Button, Clipboard, Forms, Parser, React, Switch, Text, TextInput } from "@webpack/common";
|
import { Button, Clipboard, Forms, Parser, React, Switch, TextInput } from "@webpack/common";
|
||||||
|
|
||||||
import { CheckedTextInput } from "./CheckedTextInput";
|
import { SettingsTab, wrapTab } from "./shared";
|
||||||
import ErrorBoundary from "./ErrorBoundary";
|
|
||||||
|
|
||||||
// Do not include diff in non dev builds (side effects import)
|
// Do not include diff in non dev builds (side effects import)
|
||||||
if (IS_DEV) {
|
if (IS_DEV) {
|
||||||
|
@ -258,8 +258,7 @@ function PatchHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection>
|
<SettingsTab title="Patch Helper">
|
||||||
<Text variant="heading-md/normal" tag="h2" className={Margins.bottom8}>Patch Helper</Text>
|
|
||||||
<Forms.FormTitle>find</Forms.FormTitle>
|
<Forms.FormTitle>find</Forms.FormTitle>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -304,8 +303,8 @@ function PatchHelper() {
|
||||||
<Button onClick={() => Clipboard.copy(code)}>Copy to Clipboard</Button>
|
<Button onClick={() => Clipboard.copy(code)}>Copy to Clipboard</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Forms.FormSection>
|
</SettingsTab>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default IS_DEV ? ErrorBoundary.wrap(PatchHelper) : null;
|
export default IS_DEV ? wrapTab(PatchHelper, "PatchHelper") : null;
|
|
@ -16,7 +16,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import PluginSettings from "@components/PluginSettings";
|
import PluginSettings from "@components/PluginSettings";
|
||||||
|
|
||||||
export default ErrorBoundary.wrap(PluginSettings);
|
import { wrapTab } from "./shared";
|
||||||
|
|
||||||
|
export default wrapTab(PluginSettings, "Plugins");
|
||||||
|
|
|
@ -17,13 +17,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Link } from "@components/Link";
|
import { Link } from "@components/Link";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { findLazy } from "@webpack";
|
import { findLazy } from "@webpack";
|
||||||
import { Card, Forms, React, TextArea } from "@webpack/common";
|
import { Card, Forms, React, TextArea } from "@webpack/common";
|
||||||
|
|
||||||
|
import { SettingsTab, wrapTab } from "./shared";
|
||||||
|
|
||||||
const TextAreaProps = findLazy(m => typeof m.textarea === "string");
|
const TextAreaProps = findLazy(m => typeof m.textarea === "string");
|
||||||
|
|
||||||
function Validator({ link }: { link: string; }) {
|
function Validator({ link }: { link: string; }) {
|
||||||
|
@ -74,8 +75,8 @@ function Validators({ themeLinks }: { themeLinks: string[]; }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ErrorBoundary.wrap(function () {
|
function ThemesTab() {
|
||||||
const settings = useSettings();
|
const settings = useSettings(["themeLinks"]);
|
||||||
const [themeText, setThemeText] = React.useState(settings.themeLinks.join("\n"));
|
const [themeText, setThemeText] = React.useState(settings.themeLinks.join("\n"));
|
||||||
|
|
||||||
function onBlur() {
|
function onBlur() {
|
||||||
|
@ -89,7 +90,7 @@ export default ErrorBoundary.wrap(function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<SettingsTab title="Themes">
|
||||||
<Card className="vc-settings-card vc-text-selectable">
|
<Card className="vc-settings-card vc-text-selectable">
|
||||||
<Forms.FormTitle tag="h5">Paste links to .theme.css files here</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">Paste links to .theme.css files here</Forms.FormTitle>
|
||||||
<Forms.FormText>One link per line</Forms.FormText>
|
<Forms.FormText>One link per line</Forms.FormText>
|
||||||
|
@ -124,6 +125,8 @@ export default ErrorBoundary.wrap(function () {
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
/>
|
/>
|
||||||
<Validators themeLinks={settings.themeLinks} />
|
<Validators themeLinks={settings.themeLinks} />
|
||||||
</>
|
</SettingsTab>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export default wrapTab(ThemesTab, "Themes");
|
||||||
|
|
|
@ -17,21 +17,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { handleComponentFailed } from "@components/handleComponentFailed";
|
|
||||||
import { Link } from "@components/Link";
|
import { Link } from "@components/Link";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { classes } from "@utils/misc";
|
import { classes } from "@utils/misc";
|
||||||
import { relaunch } from "@utils/native";
|
import { relaunch } from "@utils/native";
|
||||||
import { onlyOnce } from "@utils/onlyOnce";
|
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater";
|
import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater";
|
||||||
import { Alerts, Button, Card, Forms, Parser, React, Switch, Toasts } from "@webpack/common";
|
import { Alerts, Button, Card, Forms, Parser, React, Switch, Toasts } from "@webpack/common";
|
||||||
|
|
||||||
import gitHash from "~git-hash";
|
import gitHash from "~git-hash";
|
||||||
|
|
||||||
|
import { SettingsTab, wrapTab } from "./shared";
|
||||||
|
|
||||||
function withDispatcher(dispatcher: React.Dispatch<React.SetStateAction<boolean>>, action: () => any) {
|
function withDispatcher(dispatcher: React.Dispatch<React.SetStateAction<boolean>>, action: () => any) {
|
||||||
return async () => {
|
return async () => {
|
||||||
dispatcher(true);
|
dispatcher(true);
|
||||||
|
@ -199,7 +198,7 @@ function Updater() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection className={Margins.top16}>
|
<SettingsTab title="Vencord Updater">
|
||||||
<Forms.FormTitle tag="h5">Updater Settings</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">Updater Settings</Forms.FormTitle>
|
||||||
<Switch
|
<Switch
|
||||||
value={settings.notifyAboutUpdates}
|
value={settings.notifyAboutUpdates}
|
||||||
|
@ -246,11 +245,8 @@ function Updater() {
|
||||||
<Forms.FormTitle tag="h5">Updates</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">Updates</Forms.FormTitle>
|
||||||
|
|
||||||
{isNewer ? <Newer {...commonProps} /> : <Updatable {...commonProps} />}
|
{isNewer ? <Newer {...commonProps} /> : <Updatable {...commonProps} />}
|
||||||
</Forms.FormSection >
|
</SettingsTab>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default IS_WEB ? null : ErrorBoundary.wrap(Updater, {
|
export default IS_WEB ? null : wrapTab(Updater, "Updater");
|
||||||
message: "Failed to render the Updater. If this persists, try using the installer to reinstall!",
|
|
||||||
onError: onlyOnce(handleComponentFailed),
|
|
||||||
});
|
|
|
@ -21,7 +21,6 @@ import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
||||||
import { Settings, useSettings } from "@api/Settings";
|
import { Settings, useSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
import DonateButton from "@components/DonateButton";
|
import DonateButton from "@components/DonateButton";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { ErrorCard } from "@components/ErrorCard";
|
import { ErrorCard } from "@components/ErrorCard";
|
||||||
import { Margins } from "@utils/margins";
|
import { Margins } from "@utils/margins";
|
||||||
import { identity } from "@utils/misc";
|
import { identity } from "@utils/misc";
|
||||||
|
@ -29,6 +28,8 @@ import { relaunch, showItemInFolder } from "@utils/native";
|
||||||
import { useAwaiter } from "@utils/react";
|
import { useAwaiter } from "@utils/react";
|
||||||
import { Button, Card, Forms, React, Select, Slider, Switch } from "@webpack/common";
|
import { Button, Card, Forms, React, Select, Slider, Switch } from "@webpack/common";
|
||||||
|
|
||||||
|
import { SettingsTab, wrapTab } from "./shared";
|
||||||
|
|
||||||
const cl = classNameFactory("vc-settings-");
|
const cl = classNameFactory("vc-settings-");
|
||||||
|
|
||||||
const DEFAULT_DONATE_IMAGE = "https://cdn.discordapp.com/emojis/1026533090627174460.png";
|
const DEFAULT_DONATE_IMAGE = "https://cdn.discordapp.com/emojis/1026533090627174460.png";
|
||||||
|
@ -97,7 +98,7 @@ function VencordSettings() {
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<SettingsTab title="Vencord Settings">
|
||||||
<DonateCard image={donateImage} />
|
<DonateCard image={donateImage} />
|
||||||
<Forms.FormSection title="Quick Actions">
|
<Forms.FormSection title="Quick Actions">
|
||||||
<Card className={cl("quick-actions-card")}>
|
<Card className={cl("quick-actions-card")}>
|
||||||
|
@ -153,7 +154,7 @@ function VencordSettings() {
|
||||||
|
|
||||||
|
|
||||||
{typeof Notification !== "undefined" && <NotificationSection settings={settings.notifications} />}
|
{typeof Notification !== "undefined" && <NotificationSection settings={settings.notifications} />}
|
||||||
</React.Fragment>
|
</SettingsTab>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,4 +264,4 @@ function DonateCard({ image }: DonateCardProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ErrorBoundary.wrap(VencordSettings);
|
export default wrapTab(VencordSettings, "Vencord Settings");
|
||||||
|
|
|
@ -1,96 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a modification for Discord's desktop app
|
|
||||||
* Copyright (c) 2022 Vendicated and contributors
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import "./settingsStyles.css";
|
|
||||||
|
|
||||||
import { classNameFactory } from "@api/Styles";
|
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { handleComponentFailed } from "@components/handleComponentFailed";
|
|
||||||
import { isMobile } from "@utils/misc";
|
|
||||||
import { onlyOnce } from "@utils/onlyOnce";
|
|
||||||
import { Forms, SettingsRouter, TabBar, Text } from "@webpack/common";
|
|
||||||
|
|
||||||
import BackupRestoreTab from "./BackupRestoreTab";
|
|
||||||
import CloudTab from "./CloudTab";
|
|
||||||
import PluginsTab from "./PluginsTab";
|
|
||||||
import ThemesTab from "./ThemesTab";
|
|
||||||
import Updater from "./Updater";
|
|
||||||
import VencordSettings from "./VencordTab";
|
|
||||||
|
|
||||||
const cl = classNameFactory("vc-settings-");
|
|
||||||
|
|
||||||
interface SettingsProps {
|
|
||||||
tab: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SettingsTab {
|
|
||||||
name: string;
|
|
||||||
component?: React.ComponentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SettingsTabs: Record<string, SettingsTab> = {
|
|
||||||
VencordSettings: { name: "Vencord", component: () => <VencordSettings /> },
|
|
||||||
VencordPlugins: { name: "Plugins", component: () => <PluginsTab /> },
|
|
||||||
VencordThemes: { name: "Themes", component: () => <ThemesTab /> },
|
|
||||||
VencordUpdater: { name: "Updater" }, // Only show updater if IS_WEB is false
|
|
||||||
VencordCloud: { name: "Cloud", component: () => <CloudTab /> },
|
|
||||||
VencordSettingsSync: { name: "Backup & Restore", component: () => <BackupRestoreTab /> }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!IS_WEB) SettingsTabs.VencordUpdater.component = () => Updater && <Updater />;
|
|
||||||
|
|
||||||
function Settings(props: SettingsProps) {
|
|
||||||
const { tab = "VencordSettings" } = props;
|
|
||||||
|
|
||||||
const CurrentTab = SettingsTabs[tab]?.component ?? null;
|
|
||||||
if (isMobile) {
|
|
||||||
return CurrentTab && <CurrentTab />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Forms.FormSection>
|
|
||||||
<Text variant="heading-lg/semibold" style={{ color: "var(--header-primary)" }} tag="h2">Vencord Settings</Text>
|
|
||||||
|
|
||||||
<TabBar
|
|
||||||
type="top"
|
|
||||||
look="brand"
|
|
||||||
className={cl("tab-bar")}
|
|
||||||
selectedItem={tab}
|
|
||||||
onItemSelect={SettingsRouter.open}
|
|
||||||
>
|
|
||||||
{Object.entries(SettingsTabs).map(([key, { name, component }]) => {
|
|
||||||
if (!component) return null;
|
|
||||||
return <TabBar.Item
|
|
||||||
id={key}
|
|
||||||
className={cl("tab-bar-item")}
|
|
||||||
key={key}>
|
|
||||||
{name}
|
|
||||||
</TabBar.Item>;
|
|
||||||
})}
|
|
||||||
</TabBar>
|
|
||||||
<Forms.FormDivider />
|
|
||||||
{CurrentTab && <CurrentTab />}
|
|
||||||
</Forms.FormSection >;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onError = onlyOnce(handleComponentFailed);
|
|
||||||
|
|
||||||
export default function (props: SettingsProps) {
|
|
||||||
return <ErrorBoundary onError={onError}>
|
|
||||||
<Settings tab={props.tab} />
|
|
||||||
</ErrorBoundary>;
|
|
||||||
}
|
|
|
@ -29,14 +29,12 @@
|
||||||
.vc-settings-card {
|
.vc-settings-card {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
margin-top: 1em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-backup-restore-card {
|
.vc-backup-restore-card {
|
||||||
background-color: var(--info-warning-background);
|
background-color: var(--info-warning-background);
|
||||||
border-color: var(--info-warning-foreground);
|
border-color: var(--info-warning-foreground);
|
||||||
color: var(--info-warning-text);
|
color: var(--info-warning-text);
|
||||||
margin-top: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.vc-settings-theme-links {
|
.vc-settings-theme-links {
|
||||||
|
|
51
src/components/VencordSettings/shared.tsx
Normal file
51
src/components/VencordSettings/shared.tsx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a modification for Discord's desktop app
|
||||||
|
* Copyright (c) 2023 Vendicated and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./settingsStyles.css";
|
||||||
|
|
||||||
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
import { handleComponentFailed } from "@components/handleComponentFailed";
|
||||||
|
import { Margins } from "@utils/margins";
|
||||||
|
import { onlyOnce } from "@utils/onlyOnce";
|
||||||
|
import { Forms, Text } from "@webpack/common";
|
||||||
|
import type { ComponentType, PropsWithChildren } from "react";
|
||||||
|
|
||||||
|
export function SettingsTab({ title, children }: PropsWithChildren<{ title: string; }>) {
|
||||||
|
return (
|
||||||
|
<Forms.FormSection>
|
||||||
|
<Text
|
||||||
|
variant="heading-lg/semibold"
|
||||||
|
tag="h2"
|
||||||
|
className={Margins.bottom16}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{children}
|
||||||
|
</Forms.FormSection>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onError = onlyOnce(handleComponentFailed);
|
||||||
|
|
||||||
|
export function wrapTab(component: ComponentType, tab: string) {
|
||||||
|
return ErrorBoundary.wrap(component, {
|
||||||
|
message: `Failed to render the ${tab} tab. If this issue persists, try using the installer to reinstall!`,
|
||||||
|
onError,
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* Vencord, a modification for Discord's desktop app
|
|
||||||
* Copyright (c) 2022 Vendicated and contributors
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export { default as PatchHelper } from "./PatchHelper";
|
|
||||||
export { default as PluginSettings } from "./PluginSettings";
|
|
||||||
export { default as VencordSettings } from "./VencordSettings";
|
|
|
@ -18,17 +18,13 @@
|
||||||
|
|
||||||
import { addContextMenuPatch } from "@api/ContextMenu";
|
import { addContextMenuPatch } from "@api/ContextMenu";
|
||||||
import { Settings } from "@api/Settings";
|
import { Settings } from "@api/Settings";
|
||||||
import PatchHelper from "@components/PatchHelper";
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
import { Logger } from "@utils/Logger";
|
import { Logger } from "@utils/Logger";
|
||||||
import { LazyComponent } from "@utils/react";
|
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { SettingsRouter } from "@webpack/common";
|
import { React, SettingsRouter } from "@webpack/common";
|
||||||
|
|
||||||
import gitHash from "~git-hash";
|
import gitHash from "~git-hash";
|
||||||
|
|
||||||
const SettingsComponent = LazyComponent(() => require("../components/VencordSettings").default);
|
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
name: "Settings",
|
name: "Settings",
|
||||||
description: "Adds Settings UI and debug info",
|
description: "Adds Settings UI and debug info",
|
||||||
|
@ -95,37 +91,37 @@ export default definePlugin({
|
||||||
{
|
{
|
||||||
section: "VencordSettings",
|
section: "VencordSettings",
|
||||||
label: "Vencord",
|
label: "Vencord",
|
||||||
element: () => <SettingsComponent tab="VencordSettings" />
|
element: require("@components/VencordSettings/VencordTab").default
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
section: "VencordPlugins",
|
section: "VencordPlugins",
|
||||||
label: "Plugins",
|
label: "Plugins",
|
||||||
element: () => <SettingsComponent tab="VencordPlugins" />,
|
element: require("@components/VencordSettings/PluginsTab").default,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
section: "VencordThemes",
|
section: "VencordThemes",
|
||||||
label: "Themes",
|
label: "Themes",
|
||||||
element: () => <SettingsComponent tab="VencordThemes" />,
|
element: require("@components/VencordSettings/ThemesTab").default,
|
||||||
},
|
},
|
||||||
!IS_WEB && {
|
!IS_WEB && {
|
||||||
section: "VencordUpdater",
|
section: "VencordUpdater",
|
||||||
label: "Updater",
|
label: "Updater",
|
||||||
element: () => <SettingsComponent tab="VencordUpdater" />,
|
element: require("@components/VencordSettings/UpdaterTab").default,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
section: "VencordCloud",
|
section: "VencordCloud",
|
||||||
label: "Cloud",
|
label: "Cloud",
|
||||||
element: () => <SettingsComponent tab="VencordCloud" />,
|
element: require("@components/VencordSettings/CloudTab").default,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
section: "VencordSettingsSync",
|
section: "VencordSettingsSync",
|
||||||
label: "Backup & Restore",
|
label: "Backup & Restore",
|
||||||
element: () => <SettingsComponent tab="VencordSettingsSync" />,
|
element: require("@components/VencordSettings/BackupAndRestoreTab").default,
|
||||||
},
|
},
|
||||||
IS_DEV && {
|
IS_DEV && {
|
||||||
section: "VencordPatchHelper",
|
section: "VencordPatchHelper",
|
||||||
label: "Patch Helper",
|
label: "Patch Helper",
|
||||||
element: PatchHelper!,
|
element: require("@components/VencordSettings/PatchHelperTab").default,
|
||||||
},
|
},
|
||||||
IS_VENCORD_DESKTOP && {
|
IS_VENCORD_DESKTOP && {
|
||||||
section: "VencordDesktop",
|
section: "VencordDesktop",
|
||||||
|
|
Loading…
Reference in a new issue