aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/components/PluginSettings/index.tsx86
-rw-r--r--src/components/PluginSettings/styles.css47
-rw-r--r--src/components/Switch.css3
-rw-r--r--src/components/Switch.tsx76
-rw-r--r--src/preload.ts6
5 files changed, 161 insertions, 57 deletions
diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx
index 3b283d0..58058b1 100644
--- a/src/components/PluginSettings/index.tsx
+++ b/src/components/PluginSettings/index.tsx
@@ -23,25 +23,25 @@ import { showNotice } from "@api/Notices";
import { useSettings } from "@api/settings";
import { classNameFactory } from "@api/Styles";
import ErrorBoundary from "@components/ErrorBoundary";
-import { ErrorCard } from "@components/ErrorCard";
import { Flex } from "@components/Flex";
import { handleComponentFailed } from "@components/handleComponentFailed";
import { Badge } from "@components/PluginSettings/components";
import PluginModal from "@components/PluginSettings/PluginModal";
+import { Switch } from "@components/Switch";
import { ChangeList } from "@utils/ChangeList";
import Logger from "@utils/Logger";
import { classes, LazyComponent, useAwaiter } from "@utils/misc";
import { openModalLazy } from "@utils/modal";
import { Plugin } from "@utils/types";
import { findByCode, findByPropsLazy } from "@webpack";
-import { Alerts, Button, Forms, Margins, Parser, React, Select, Switch, Text, TextInput, Toasts, Tooltip } from "@webpack/common";
+import { Alerts, Button, Card, Forms, Margins, Parser, React, Select, Text, TextInput, Toasts, Tooltip } from "@webpack/common";
import Plugins from "~plugins";
-const cl = classNameFactory("vc-plugins-");
-
import { startDependenciesRecursive, startPlugin, stopPlugin } from "../../plugins";
+
+const cl = classNameFactory("vc-plugins-");
const logger = new Logger("PluginSettings", "#a6d189");
const InputStyles = findByPropsLazy("inputDefault", "inputWrapper");
@@ -60,23 +60,27 @@ function showErrorToast(message: string) {
});
}
-interface ReloadRequiredCardProps extends React.HTMLProps<HTMLDivElement> {
- plugins: string[];
-}
-
-function ReloadRequiredCard({ plugins, ...props }: ReloadRequiredCardProps) {
- if (plugins.length === 0) return null;
-
- const pluginPrefix = plugins.length === 1 ? "The plugin" : "The following plugins require a reload to apply changes:";
- const pluginSuffix = plugins.length === 1 ? " requires a reload to apply changes." : ".";
-
+function ReloadRequiredCard({ required }: { required: boolean; }) {
return (
- <ErrorCard {...props} className={cl("reload-card")}>
- <span className={cl("dep-text")}>
- {pluginPrefix} <code>{plugins.join(", ")}</code>{pluginSuffix}
- </span>
- <Button look={Button.Looks.INVERTED} onClick={() => location.reload()}>Reload</Button>
- </ErrorCard>
+ <Card className={cl("info-card", { "restart-card": required })}>
+ {required ? (
+ <>
+ <Forms.FormTitle tag="h5">Restart required!</Forms.FormTitle>
+ <Forms.FormText className={cl("dep-text")}>
+ Restart now to apply new plugins and their settings
+ </Forms.FormText>
+ <Button color={Button.Colors.YELLOW} onClick={() => location.reload()}>
+ Restart
+ </Button>
+ </>
+ ) : (
+ <>
+ <Forms.FormTitle tag="h5">Plugin Management</Forms.FormTitle>
+ <Forms.FormText>Press the cog wheel or info icon to get more info on a plugin</Forms.FormText>
+ <Forms.FormText>Plugins with a cog wheel have settings you can modify!</Forms.FormText>
+ </>
+ )}
+ </Card>
);
}
@@ -147,26 +151,24 @@ function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLe
}
return (
- <Flex className={cl("card")} flexDirection="column" onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
- <Switch
- onChange={toggleEnabled}
- disabled={disabled}
- value={isEnabled()}
- note={<Text className={cl("note")} variant="text-sm/normal">{plugin.description}</Text>}
- hideBorder={true}
- >
- <Flex className={cl("flex")}>
- <Text variant="text-md/bold" className={cl("name")}>
- {plugin.name}{isNew && <Badge text="NEW" color="#ED4245" />}
- </Text>
- <button role="switch" onClick={() => openModal()} className={classes("button-12Fmur", cl("info-button"))}>
- {plugin.options
- ? <CogWheel />
- : <InfoIcon width="24" height="24" />}
- </button>
- </Flex>
- </Switch>
- </Flex>
+ <Flex className={cl("card", { "card-disabled": disabled })} flexDirection="column" onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave}>
+ <div className={cl("card-header")}>
+ <Text variant="text-md/bold" className={cl("name")}>
+ {plugin.name}{isNew && <Badge text="NEW" color="#ED4245" />}
+ </Text>
+ <button role="switch" onClick={() => openModal()} className={classes("button-12Fmur", cl("info-button"))}>
+ {plugin.options
+ ? <CogWheel />
+ : <InfoIcon width="24" height="24" />}
+ </button>
+ <Switch
+ checked={isEnabled()}
+ onChange={toggleEnabled}
+ disabled={disabled}
+ />
+ </div>
+ <Text className={cl("note")} variant="text-sm/normal">{plugin.description}</Text>
+ </Flex >
);
}
@@ -298,12 +300,12 @@ export default ErrorBoundary.wrap(function PluginSettings() {
return (
<Forms.FormSection>
+ <ReloadRequiredCard required={changes.hasChanges} />
+
<Forms.FormTitle tag="h5" className={classes(Margins.marginTop20, Margins.marginBottom8)}>
Filters
</Forms.FormTitle>
- <ReloadRequiredCard plugins={[...changes.getChanges()]} className={Margins.marginBottom20} />
-
<div className={cl("filter-controls")}>
<TextInput autoFocus value={searchValue.value} placeholder="Search for a plugin..." onChange={onSearch} className={Margins.marginBottom20} />
<div className={InputStyles.inputWrapper}>
diff --git a/src/components/PluginSettings/styles.css b/src/components/PluginSettings/styles.css
index fe8dc94..1626d7d 100644
--- a/src/components/PluginSettings/styles.css
+++ b/src/components/PluginSettings/styles.css
@@ -29,18 +29,32 @@
border-radius: 8px;
display: block;
height: 100%;
- padding: 10px;
+ padding: 12px;
width: 100%;
transition: 0.1s ease-out;
transition-property: box-shadow, transform, background, opacity;
}
+.vc-plugins-card-disabled {
+ opacity: 0.6;
+}
+
.vc-plugins-card:hover {
background-color: var(--background-tertiary);
transform: translateY(-1px);
box-shadow: var(--elevation-high);
}
+.vc-plugins-card-header {
+ margin-top: auto;
+ display: flex;
+ width: 100%;
+ justify-content: flex-end;
+ height: 1.5rem;
+ align-items: center;
+ gap: 8px;
+}
+
.vc-plugins-info-button {
height: 24px;
width: 24px;
@@ -92,23 +106,30 @@
cursor: "default";
}
-.vc-plugins-flex {
- margin-top: auto;
- width: 100%;
- height: 100%;
- align-items: center;
- gap: 8px;
-}
-
.vc-plugins-dep-name {
margin: 0 auto;
}
-.vc-plugins-reload-card {
+.vc-plugins-info-card {
padding: 1em;
- display: grid;
- grid-template-columns: 1fr auto;
- gap: 1em;
+ height: 8em;
+ display: flex;
+ flex-direction: column;
+}
+
+.vc-plugins-info-card div {
+ line-height: 32px;
+}
+
+.vc-plugins-restart-card {
+ padding: 1em;
+ background: var(--info-warning-background);
+ border: 1px solid var(--info-warning-foreground);
+ color: var(--info-warning-text);
+}
+
+.vc-plugins-restart-card button {
+ margin-top: 0.5em;
}
.vc-plugins-info-button svg:not(:hover):not(:focus) {
diff --git a/src/components/Switch.css b/src/components/Switch.css
new file mode 100644
index 0000000..e6dcf56
--- /dev/null
+++ b/src/components/Switch.css
@@ -0,0 +1,3 @@
+.vc-switch-slider {
+ transition: 100ms transform ease-in-out;
+}
diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx
new file mode 100644
index 0000000..a18a7e4
--- /dev/null
+++ b/src/components/Switch.tsx
@@ -0,0 +1,76 @@
+/*
+ * 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 "./Switch.css";
+
+import { findByPropsLazy } from "@webpack";
+
+interface SwitchProps {
+ checked: boolean;
+ onChange: (checked: boolean) => void;
+ disabled?: boolean;
+}
+
+const SWITCH_ON = "var(--status-green-600)";
+const SWITCH_OFF = "var(--primary-dark-400)";
+const SwitchClasses = findByPropsLazy("slider", "input", "container");
+
+export function Switch({ checked, onChange, disabled }: SwitchProps) {
+ return (
+ <div>
+ <div className={`${SwitchClasses.container} default-colors`} style={{
+ backgroundColor: checked ? SWITCH_ON : SWITCH_OFF,
+ opacity: disabled ? 0.3 : 1
+ }}>
+ <svg
+ className={SwitchClasses.slider + " vc-switch-slider"}
+ viewBox="0 0 28 20"
+ preserveAspectRatio="xMinYMid meet"
+ aria-hidden="true"
+ style={{
+ transform: checked ? "translateX(12px)" : "translateX(-3px)",
+ }}
+ >
+ <rect fill="white" x="4" y="0" height="20" width="20" rx="10" />
+ <svg viewBox="0 0 20 20" fill="none">
+ {checked ? (
+ <>
+ <path fill={SWITCH_ON} d="M7.89561 14.8538L6.30462 13.2629L14.3099 5.25755L15.9009 6.84854L7.89561 14.8538Z" />
+ <path fill={SWITCH_ON} d="M4.08643 11.0903L5.67742 9.49929L9.4485 13.2704L7.85751 14.8614L4.08643 11.0903Z" />
+ </>
+ ) : (
+ <>
+ <path fill={SWITCH_OFF} d="M5.13231 6.72963L6.7233 5.13864L14.855 13.2704L13.264 14.8614L5.13231 6.72963Z" />
+ <path fill={SWITCH_OFF} d="M13.2704 5.13864L14.8614 6.72963L6.72963 14.8614L5.13864 13.2704L13.2704 5.13864Z" />
+ </>
+ )}
+
+ </svg>
+ </svg>
+ <input
+ disabled={disabled}
+ type="checkbox"
+ className={SwitchClasses.input}
+ tabIndex={0}
+ checked={checked}
+ onChange={e => onChange(e.currentTarget.checked)}
+ />
+ </div>
+ </div>
+ );
+}
diff --git a/src/preload.ts b/src/preload.ts
index 33f2410..3867f33 100644
--- a/src/preload.ts
+++ b/src/preload.ts
@@ -49,9 +49,11 @@ if (location.protocol !== "data:") {
const css = readFileSync(rendererCss, "utf-8");
insertCss(css);
if (IS_DEV) {
- watch(rendererCss, debounce(() => {
+ // persistent means keep process running if watcher is the only thing still running
+ // which we obviously don't want
+ watch(rendererCss, { persistent: false }, () => {
document.getElementById("vencord-css-core")!.textContent = readFileSync(rendererCss, "utf-8");
- }, 30));
+ });
}
} catch (err) {
if ((err as NodeJS.ErrnoException)?.code !== "ENOENT")