diff options
author | V <vendicated@riseup.net> | 2023-09-08 03:42:20 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-08 03:42:20 +0200 |
commit | 885c75fdaad811017dd8645c0ed3a7234371897d (patch) | |
tree | 45d7eb166d225ba8156a634677d7efd9e70c9703 /src/components/PluginSettings | |
parent | f2a22c5e57515fd6fc41cece083444d4cbc11ebc (diff) | |
download | Vencord-885c75fdaad811017dd8645c0ed3a7234371897d.tar.gz Vencord-885c75fdaad811017dd8645c0ed3a7234371897d.tar.bz2 Vencord-885c75fdaad811017dd8645c0ed3a7234371897d.zip |
add custom plugin author popouts (#1712)
Diffstat (limited to 'src/components/PluginSettings')
-rw-r--r-- | src/components/PluginSettings/ContributorModal.tsx | 113 | ||||
-rw-r--r-- | src/components/PluginSettings/PluginModal.tsx | 29 | ||||
-rw-r--r-- | src/components/PluginSettings/contributorModal.css | 57 | ||||
-rw-r--r-- | src/components/PluginSettings/index.tsx | 2 | ||||
-rw-r--r-- | src/components/PluginSettings/userPopoutHideBotTag.css | 3 |
5 files changed, 186 insertions, 18 deletions
diff --git a/src/components/PluginSettings/ContributorModal.tsx b/src/components/PluginSettings/ContributorModal.tsx new file mode 100644 index 0000000..82c2302 --- /dev/null +++ b/src/components/PluginSettings/ContributorModal.tsx @@ -0,0 +1,113 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import "./contributorModal.css"; + +import { useSettings } from "@api/Settings"; +import { classNameFactory } from "@api/Styles"; +import ErrorBoundary from "@components/ErrorBoundary"; +import { DevsById } from "@utils/constants"; +import { fetchUserProfile, getTheme, Theme } from "@utils/discord"; +import { ModalContent, ModalRoot, openModal } from "@utils/modal"; +import { Forms, MaskedLink, showToast, useEffect, useMemo, UserProfileStore, useStateFromStores } from "@webpack/common"; +import { User } from "discord-types/general"; + +import Plugins from "~plugins"; + +import { PluginCard } from "."; + +const WebsiteIconDark = "/assets/e1e96d89e192de1997f73730db26e94f.svg"; +const WebsiteIconLight = "/assets/730f58bcfd5a57a5e22460c445a0c6cf.svg"; +const GithubIconLight = "/assets/3ff98ad75ac94fa883af5ed62d17c459.svg"; +const GithubIconDark = "/assets/6a853b4c87fce386cbfef4a2efbacb09.svg"; + +const cl = classNameFactory("vc-author-modal-"); + +export function openContributorModal(user: User) { + openModal(modalProps => + <ModalRoot {...modalProps}> + <ErrorBoundary> + <ModalContent className={cl("root")}> + <ContributorModal user={user} /> + </ModalContent> + </ErrorBoundary> + </ModalRoot> + ); +} + +function GithubIcon() { + const src = getTheme() === Theme.Light ? GithubIconLight : GithubIconDark; + return <img src={src} alt="GitHub" />; +} + +function WebsiteIcon() { + const src = getTheme() === Theme.Light ? WebsiteIconLight : WebsiteIconDark; + return <img src={src} alt="Website" />; +} + +function ContributorModal({ user }: { user: User; }) { + useSettings(); + + const profile = useStateFromStores([UserProfileStore], () => UserProfileStore.getUserProfile(user.id)); + + useEffect(() => { + if (!profile && !user.bot && user.id) + fetchUserProfile(user.id); + }, [user.id]); + + const githubName = profile?.connectedAccounts?.find(a => a.type === "github")?.name; + const website = profile?.connectedAccounts?.find(a => a.type === "domain")?.name; + + const plugins = useMemo(() => { + const allPlugins = Object.values(Plugins); + const pluginsByAuthor = DevsById[user.id] + ? allPlugins.filter(p => p.authors.includes(DevsById[user.id])) + : allPlugins.filter(p => p.authors.some(a => a.name === user.username)); + + return pluginsByAuthor + .filter(p => !p.name.endsWith("API")) + .sort((a, b) => Number(a.required ?? false) - Number(b.required ?? false)); + }, [user.id, user.username]); + + return ( + <> + <div className={cl("header")}> + <img + className={cl("avatar")} + src={user.getAvatarURL(void 0, 512, true)} + alt="" + /> + <Forms.FormTitle tag="h2" className={cl("name")}>{user.username}</Forms.FormTitle> + + <div className={cl("links")}> + {website && ( + <MaskedLink + href={"https://" + website} + > + <WebsiteIcon /> + </MaskedLink> + )} + {githubName && ( + <MaskedLink href={`https://github.com/${githubName}`}> + <GithubIcon /> + </MaskedLink> + )} + </div> + </div> + + <div className={cl("plugins")}> + {plugins.map(p => + <PluginCard + key={p.name} + plugin={p} + disabled={p.required ?? false} + onRestartNeeded={() => showToast("Restart to apply changes!")} + /> + )} + </div> + </> + ); +} diff --git a/src/components/PluginSettings/PluginModal.tsx b/src/components/PluginSettings/PluginModal.tsx index f30cede..78f3c9d 100644 --- a/src/components/PluginSettings/PluginModal.tsx +++ b/src/components/PluginSettings/PluginModal.tsx @@ -18,7 +18,6 @@ import { generateId } from "@api/Commands"; import { useSettings } from "@api/Settings"; -import { disableStyle, enableStyle } from "@api/Styles"; import ErrorBoundary from "@components/ErrorBoundary"; import { Flex } from "@components/Flex"; import { proxyLazy } from "@utils/lazy"; @@ -28,7 +27,7 @@ import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, M import { LazyComponent } from "@utils/react"; import { OptionType, Plugin } from "@utils/types"; import { findByCode, findByPropsLazy } from "@webpack"; -import { Button, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common"; +import { Button, Clickable, FluxDispatcher, Forms, React, Text, Tooltip, UserStore, UserUtils } from "@webpack/common"; import { User } from "discord-types/general"; import { Constructor } from "type-fest"; @@ -41,7 +40,7 @@ import { SettingSliderComponent, SettingTextComponent } from "./components"; -import hideBotTagStyle from "./userPopoutHideBotTag.css?managed"; +import { openContributorModal } from "./ContributorModal"; const UserSummaryItem = LazyComponent(() => findByCode("defaultRenderUser", "showDefaultAvatarsForNullUsers")); const AvatarStyles = findByPropsLazy("moreUsers", "emptyUser", "avatarContainer", "clickableAvatar"); @@ -92,27 +91,16 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti const hasSettings = Boolean(pluginSettings && plugin.options && !isObjectEmpty(plugin.options)); React.useEffect(() => { - enableStyle(hideBotTagStyle); - - let originalUser: User; (async () => { for (const user of plugin.authors.slice(0, 6)) { const author = user.id ? await UserUtils.fetchUser(`${user.id}`) - // only show name & pfp and no actions so users cannot harass plugin devs for support (send dms, add as friend, etc) - .then(u => (originalUser = u, makeDummyUser(u))) .catch(() => makeDummyUser({ username: user.name })) : makeDummyUser({ username: user.name }); setAuthors(a => [...a, author]); } })(); - - return () => { - disableStyle(hideBotTagStyle); - if (originalUser) - FluxDispatcher.dispatch({ type: "USER_UPDATE", user: originalUser }); - }; }, []); async function saveAndClose() { @@ -214,6 +202,19 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti showDefaultAvatarsForNullUsers showUserPopout renderMoreUsers={renderMoreUsers} + renderUser={(user: User) => ( + <Clickable + className={AvatarStyles.clickableAvatar} + onClick={() => openContributorModal(user)} + > + <img + className={AvatarStyles.avatar} + src={user.getAvatarURL(void 0, 80, true)} + alt={user.username} + title={user.username} + /> + </Clickable> + )} /> </div> </Forms.FormSection> diff --git a/src/components/PluginSettings/contributorModal.css b/src/components/PluginSettings/contributorModal.css new file mode 100644 index 0000000..a8af8c8 --- /dev/null +++ b/src/components/PluginSettings/contributorModal.css @@ -0,0 +1,57 @@ +.vc-author-modal-root { + padding: 1em; +} + +.vc-author-modal-header { + display: flex; + align-items: center; + margin-bottom: 1em; +} + +.vc-author-modal-name { + text-transform: none; + flex-grow: 0; + background: var(--background-tertiary); + border-radius: 0 9999px 9999px 0; + padding: 6px 0.8em 6px 0.5em; + font-size: 20px; + height: 20px; + position: relative; +} + +.vc-author-modal-name::before { + content: ""; + display: block; + position: absolute; + height: 100%; + width: 16px; + background: var(--background-tertiary); + z-index: -1; + left: -16px; + top: 0; +} + +.vc-author-modal-avatar { + height: 32px; + width: 32px; + border-radius: 50%; +} + +.vc-author-modal-links { + margin-left: auto; + display: flex; + gap: 0.2em; +} + +.vc-author-modal-links img { + height: 32px; + width: 32px; + border-radius: 50%; + border: 4px solid var(--background-tertiary); + box-sizing: border-box +} + +.vc-author-modal-plugins { + display: grid; + gap: 0.5em; +} diff --git a/src/components/PluginSettings/index.tsx b/src/components/PluginSettings/index.tsx index f19d326..3712f3d 100644 --- a/src/components/PluginSettings/index.tsx +++ b/src/components/PluginSettings/index.tsx @@ -91,7 +91,7 @@ interface PluginCardProps extends React.HTMLProps<HTMLDivElement> { isNew?: boolean; } -function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) { +export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) { const settings = Settings.plugins[plugin.name]; const isEnabled = () => settings.enabled ?? false; diff --git a/src/components/PluginSettings/userPopoutHideBotTag.css b/src/components/PluginSettings/userPopoutHideBotTag.css deleted file mode 100644 index 5e33e4b..0000000 --- a/src/components/PluginSettings/userPopoutHideBotTag.css +++ /dev/null @@ -1,3 +0,0 @@ -[class|="userPopoutOuter"] [class*="botTag"] { - display: none; -} |