diff --git a/browser/manifest.json b/browser/manifest.json
index c527c75b8..357312b09 100644
--- a/browser/manifest.json
+++ b/browser/manifest.json
@@ -1,6 +1,6 @@
{
"manifest_version": 3,
- "minimum_chrome_version": "91",
+ "minimum_chrome_version": "111",
"name": "Vencord Web",
"description": "The cutest Discord mod now in your browser",
diff --git a/browser/manifestv2.json b/browser/manifestv2.json
index f5b08571a..0cb7cb32a 100644
--- a/browser/manifestv2.json
+++ b/browser/manifestv2.json
@@ -43,7 +43,7 @@
"browser_specific_settings": {
"gecko": {
"id": "vencord-firefox@vendicated.dev",
- "strict_min_version": "91.0"
+ "strict_min_version": "128.0"
}
}
}
diff --git a/src/api/Notifications/notificationLog.tsx b/src/api/Notifications/notificationLog.tsx
index 6f79ef70a..5df31d4cd 100644
--- a/src/api/Notifications/notificationLog.tsx
+++ b/src/api/Notifications/notificationLog.tsx
@@ -19,6 +19,8 @@
import * as DataStore from "@api/DataStore";
import { Settings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
+import { Flex } from "@components/Flex";
+import { openNotificationSettingsModal } from "@components/VencordSettings/NotificationSettings";
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { useAwaiter } from "@utils/react";
import { Alerts, Button, Forms, React, Text, Timestamp, useEffect, useReducer, useState } from "@webpack/common";
@@ -170,24 +172,31 @@ function LogModal({ modalProps, close }: { modalProps: ModalProps; close(): void
-
+
+
+
+
+
);
diff --git a/src/components/Grid.tsx b/src/components/Grid.tsx
new file mode 100644
index 000000000..1f757f457
--- /dev/null
+++ b/src/components/Grid.tsx
@@ -0,0 +1,28 @@
+/*
+ * Vencord, a Discord client mod
+ * Copyright (c) 2024 Vendicated and contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+import { CSSProperties } from "react";
+
+interface Props {
+ columns: number;
+ gap?: string;
+ inline?: boolean;
+}
+
+export function Grid(props: Props & JSX.IntrinsicElements["div"]) {
+ const style: CSSProperties = {
+ display: props.inline ? "inline-grid" : "grid",
+ gridTemplateColumns: `repeat(${props.columns}, 1fr)`,
+ gap: props.gap,
+ ...props.style
+ };
+
+ return (
+
+ {props.children}
+
+ );
+}
diff --git a/src/components/Icons.tsx b/src/components/Icons.tsx
index d076df75b..d82ce0b00 100644
--- a/src/components/Icons.tsx
+++ b/src/components/Icons.tsx
@@ -18,19 +18,17 @@
import "./iconStyles.css";
+import { getTheme, Theme } from "@utils/discord";
import { classes } from "@utils/misc";
import { i18n } from "@webpack/common";
-import type { PropsWithChildren, SVGProps } from "react";
+import type { PropsWithChildren } from "react";
interface BaseIconProps extends IconProps {
viewBox: string;
}
-interface IconProps extends SVGProps {
- className?: string;
- height?: string | number;
- width?: string | number;
-}
+type IconProps = JSX.IntrinsicElements["svg"];
+type ImageProps = JSX.IntrinsicElements["img"];
function Icon({ height = 24, width = 24, className, children, viewBox, ...svgProps }: PropsWithChildren) {
return (
@@ -329,3 +327,88 @@ export function NotesIcon(props: IconProps) {
);
}
+
+export function FolderIcon(props: IconProps) {
+ return (
+
+
+
+ );
+}
+
+export function LogIcon(props: IconProps) {
+ return (
+
+
+
+ );
+}
+
+export function RestartIcon(props: IconProps) {
+ return (
+
+
+
+ );
+}
+
+export function PaintbrushIcon(props: IconProps) {
+ return (
+
+
+
+ );
+}
+
+const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg";
+const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg";
+const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg";
+const GithubIconDark = "/assets/6a853b4c87fce386cbfef4a2efbacb09.svg";
+
+export function GithubIcon(props: ImageProps) {
+ const src = getTheme() === Theme.Light
+ ? GithubIconLight
+ : GithubIconDark;
+
+ return ;
+}
+
+export function WebsiteIcon(props: ImageProps) {
+ const src = getTheme() === Theme.Light
+ ? WebsiteIconLight
+ : WebsiteIconDark;
+
+ return ;
+}
diff --git a/src/components/PluginSettings/LinkIconButton.tsx b/src/components/PluginSettings/LinkIconButton.tsx
index ea36dda24..dd840f52e 100644
--- a/src/components/PluginSettings/LinkIconButton.tsx
+++ b/src/components/PluginSettings/LinkIconButton.tsx
@@ -6,22 +6,16 @@
import "./LinkIconButton.css";
-import { getTheme, Theme } from "@utils/discord";
import { MaskedLink, Tooltip } from "@webpack/common";
-const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg";
-const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg";
-const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg";
-const GithubIconDark = "/assets/6a853b4c87fce386cbfef4a2efbacb09.svg";
+import { GithubIcon, WebsiteIcon } from "..";
-export function GithubIcon() {
- const src = getTheme() === Theme.Light ? GithubIconLight : GithubIconDark;
- return ;
+export function GithubLinkIcon() {
+ return ;
}
-export function WebsiteIcon() {
- const src = getTheme() === Theme.Light ? WebsiteIconLight : WebsiteIconDark;
- return ;
+export function WebsiteLinkIcon() {
+ return ;
}
interface Props {
@@ -41,5 +35,5 @@ function LinkIcon({ text, href, Icon }: Props & { Icon: React.ComponentType; })
);
}
-export const WebsiteButton = (props: Props) => ;
-export const GithubButton = (props: Props) => ;
+export const WebsiteButton = (props: Props) => ;
+export const GithubButton = (props: Props) => ;
diff --git a/src/components/PluginSettings/PluginModal.tsx b/src/components/PluginSettings/PluginModal.tsx
index e5da01f36..8b14283b8 100644
--- a/src/components/PluginSettings/PluginModal.tsx
+++ b/src/components/PluginSettings/PluginModal.tsx
@@ -27,7 +27,7 @@ import { gitRemote } from "@shared/vencordUserAgent";
import { proxyLazy } from "@utils/lazy";
import { Margins } from "@utils/margins";
import { classes, isObjectEmpty } from "@utils/misc";
-import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize } from "@utils/modal";
+import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { OptionType, Plugin } from "@utils/types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common";
@@ -310,3 +310,13 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
);
}
+
+export function openPluginModal(plugin: Plugin, onRestartNeeded?: (pluginName: string) => void) {
+ openModal(modalProps => (
+ onRestartNeeded?.(plugin.name)}
+ />
+ ));
+}
diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx
index c659e7838..38ddc4a90 100644
--- a/src/components/PluginSettings/index.tsx
+++ b/src/components/PluginSettings/index.tsx
@@ -23,7 +23,7 @@ import { showNotice } from "@api/Notices";
import { Settings, useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { CogWheel, InfoIcon } from "@components/Icons";
-import PluginModal from "@components/PluginSettings/PluginModal";
+import { openPluginModal } from "@components/PluginSettings/PluginModal";
import { AddonCard } from "@components/VencordSettings/AddonCard";
import { SettingsTab } from "@components/VencordSettings/shared";
import { ChangeList } from "@utils/ChangeList";
@@ -31,7 +31,6 @@ import { proxyLazy } from "@utils/lazy";
import { Logger } from "@utils/Logger";
import { Margins } from "@utils/margins";
import { classes, isObjectEmpty } from "@utils/misc";
-import { openModalLazy } from "@utils/modal";
import { useAwaiter } from "@utils/react";
import { Plugin } from "@utils/types";
import { findByPropsLazy } from "@webpack";
@@ -45,7 +44,7 @@ const { startDependenciesRecursive, startPlugin, stopPlugin } = proxyLazy(() =>
const cl = classNameFactory("vc-plugins-");
const logger = new Logger("PluginSettings", "#a6d189");
-const InputStyles = findByPropsLazy("inputDefault", "inputWrapper");
+const InputStyles = findByPropsLazy("inputWrapper", "inputDefault", "error");
const ButtonClasses = findByPropsLazy("button", "disabled", "enabled");
@@ -96,14 +95,6 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on
const isEnabled = () => settings.enabled ?? false;
- function openModal() {
- openModalLazy(async () => {
- return modalProps => {
- return onRestartNeeded(plugin.name)} />;
- };
- });
- }
-
function toggleEnabled() {
const wasEnabled = isEnabled();
@@ -160,7 +151,11 @@ export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, on
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
infoButton={
-