diff --git a/src/api/Settings.ts b/src/api/Settings.ts
index 73bc9ee6b..2bcc785f9 100644
--- a/src/api/Settings.ts
+++ b/src/api/Settings.ts
@@ -68,6 +68,7 @@ export interface Settings {
plugins: {
[plugin: string]: {
enabled: boolean;
+ isFavorite?: boolean;
[setting: string]: any;
};
};
diff --git a/src/components/Icons.tsx b/src/components/Icons.tsx
index 47a52a82c..ff89b3f48 100644
--- a/src/components/Icons.tsx
+++ b/src/components/Icons.tsx
@@ -639,3 +639,31 @@ export function RightArrow(props: IconProps) {
);
}
+
+export function StarFilled(props: IconProps) {
+ return (
+
+
+
+ );
+}
+
+export function StarOutlined(props: IconProps) {
+ return (
+
+
+
+ );
+}
diff --git a/src/components/settings/tabs/plugins/ContributorModal.tsx b/src/components/settings/tabs/plugins/ContributorModal.tsx
index 9139fe8f3..9ba303864 100644
--- a/src/components/settings/tabs/plugins/ContributorModal.tsx
+++ b/src/components/settings/tabs/plugins/ContributorModal.tsx
@@ -13,12 +13,12 @@ import { classNameFactory } from "@utils/css";
import { fetchUserProfile } from "@utils/discord";
import { classes, pluralise } from "@utils/misc";
import { RenderModalProps, User } from "@vencord/discord-types";
-import { Forms, Modal,openModal, showToast, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common";
+import { Forms, Modal, openModal, showToast, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common";
import Plugins from "~plugins";
-import { GithubButton, WebsiteButton } from "./LinkIconButton";
import { PluginCard } from "./PluginCard";
+import { GithubButton, WebsiteButton } from "./PluginModalButtons";
const cl = classNameFactory("vc-author-modal-");
diff --git a/src/components/settings/tabs/plugins/LinkIconButton.css b/src/components/settings/tabs/plugins/LinkIconButton.css
deleted file mode 100644
index 835206381..000000000
--- a/src/components/settings/tabs/plugins/LinkIconButton.css
+++ /dev/null
@@ -1,13 +0,0 @@
-.vc-settings-modal-link-icon {
- height: 32px;
- width: 32px;
- border-radius: 50%;
- border: 4px solid var(--background-base-lowest);
- box-sizing: border-box
-}
-
-.vc-settings-modal-links {
- display: flex;
- gap: 0.2em;
- margin-left: auto;
-}
\ No newline at end of file
diff --git a/src/components/settings/tabs/plugins/LinkIconButton.tsx b/src/components/settings/tabs/plugins/LinkIconButton.tsx
deleted file mode 100644
index 9f9ecfebb..000000000
--- a/src/components/settings/tabs/plugins/LinkIconButton.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Vencord, a Discord client mod
- * Copyright (c) 2024 Vendicated and contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-import "./LinkIconButton.css";
-
-import { GithubIcon, WebsiteIcon } from "@components/Icons";
-import { getTheme, Theme } from "@utils/discord";
-import { MaskedLink, Tooltip } from "@webpack/common";
-
-export function GithubLinkIcon() {
- const theme = getTheme() === Theme.Light ? "#000000" : "#FFFFFF";
- return ;
-}
-
-export function WebsiteLinkIcon() {
- const theme = getTheme() === Theme.Light ? "#000000" : "#FFFFFF";
- return ;
-}
-
-interface Props {
- text: string;
- href: string;
-}
-
-function LinkIcon({ text, href, Icon }: Props & { Icon: React.ComponentType; }) {
- return (
-
- {props => (
-
-
-
- )}
-
- );
-}
-
-export const WebsiteButton = (props: Props) => ;
-export const GithubButton = (props: Props) => ;
diff --git a/src/components/settings/tabs/plugins/PluginModal.tsx b/src/components/settings/tabs/plugins/PluginModal.tsx
index 0e0422c9a..942c552f3 100644
--- a/src/components/settings/tabs/plugins/PluginModal.tsx
+++ b/src/components/settings/tabs/plugins/PluginModal.tsx
@@ -32,14 +32,14 @@ import { classes } from "@utils/misc";
import { OptionType, Plugin, PluginTag } from "@utils/types";
import { RenderModalProps, User } from "@vencord/discord-types";
import { findCssClassesLazy } from "@webpack";
-import { Clickable, FluxDispatcher, Forms, Modal,openModal, React, Text, Tooltip, useEffect, useMemo, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common";
+import { Clickable, FluxDispatcher, Forms, Modal, openModal, React, Text, Tooltip, useEffect, useMemo, UserStore, UserSummaryItem, UserUtils, useState } from "@webpack/common";
import { Constructor } from "type-fest";
import { PluginMeta } from "~plugins";
import { OptionComponentMap } from "./components";
import { openContributorModal } from "./ContributorModal";
-import { GithubButton, WebsiteButton } from "./LinkIconButton";
+import { FavoriteButton, GithubButton, WebsiteButton } from "./PluginModalButtons";
const cl = classNameFactory("vc-plugin-modal-");
@@ -176,6 +176,10 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
{plugin.name}
{!pluginMeta.userPlugin && (
+ pluginSettings.isFavorite = !pluginSettings.isFavorite}
+ />
getTheme() !== Theme.Light ? "dark" : "light";
+
+interface Props {
+ text: string;
+ href: string;
+}
+
+function LinkIcon({ text, href, Icon }: Props & { Icon: React.ComponentType; }) {
+ return (
+
+ {props =>
+
+
+
+ }
+
+ );
+}
+
+const GithubLinkIcon = () => ;
+const WebsiteLinkIcon = () => ;
+
+export const GithubButton = (props: Props) => ;
+export const WebsiteButton = (props: Props) => ;
+
+export function FavoriteButton({ isFavorite, onClick }: { isFavorite: boolean; onClick: () => void; }) {
+ const Icon = isFavorite ? StarFilled : StarOutlined;
+
+ return (
+
+ {props =>
+
+
+
+ }
+
+ );
+}
diff --git a/src/components/settings/tabs/plugins/index.tsx b/src/components/settings/tabs/plugins/index.tsx
index 69d9a7c08..90ce4311a 100644
--- a/src/components/settings/tabs/plugins/index.tsx
+++ b/src/components/settings/tabs/plugins/index.tsx
@@ -74,6 +74,7 @@ function ReloadRequiredCard({ required }: { required: boolean; }) {
const enum SearchStatus {
ALL,
+ FAVORITES,
ENABLED,
DISABLED,
NEW,
@@ -160,7 +161,8 @@ function PluginSettings() {
const sortedPlugins = useMemo(() =>
Object.values(Plugins).sort((a, b) => a.name.localeCompare(b.name)),
[]
- );
+ )
+ .toSorted((a, b) => Number(settings.plugins[b.name]?.isFavorite ?? false) - Number(settings.plugins[a.name]?.isFavorite ?? false));
const hasUserPlugins = useMemo(() => !IS_STANDALONE && Object.values(PluginMeta).some(m => m.userPlugin), []);
@@ -173,6 +175,9 @@ function PluginSettings() {
const { status, tags } = searchValue;
switch (status) {
+ case SearchStatus.FAVORITES:
+ if (!settings.plugins[plugin.name]?.isFavorite) return false;
+ break;
case SearchStatus.DISABLED:
if (isPluginEnabled(plugin.name)) return false;
break;
@@ -288,6 +293,7 @@ function PluginSettings() {