From b5ad46a63fe3698068763694ad74d18c98f74cbd Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Fri, 31 Mar 2023 15:53:36 -0400 Subject: [PATCH] Reduce reliance on internals --- renderer/src/modules/discordclasses.js | 49 ------- renderer/src/modules/discordmodules.js | 138 ------------------ renderer/src/modules/modules.js | 3 +- renderer/src/structs/classname.js | 50 ------- renderer/src/styles/ui/errormodal.css | 12 ++ renderer/src/ui/blankslates/emptyimage.jsx | 10 +- renderer/src/ui/modals.js | 54 +++---- .../src/ui/{ => modals}/addonerrormodal.jsx | 56 ++++--- renderer/src/ui/modals/changelog.jsx | 2 +- renderer/src/ui/modals/confirmation.jsx | 10 +- renderer/src/ui/modals/footer.jsx | 2 +- 11 files changed, 78 insertions(+), 308 deletions(-) delete mode 100644 renderer/src/modules/discordclasses.js delete mode 100644 renderer/src/structs/classname.js rename renderer/src/ui/{ => modals}/addonerrormodal.jsx (52%) diff --git a/renderer/src/modules/discordclasses.js b/renderer/src/modules/discordclasses.js deleted file mode 100644 index b8136036..00000000 --- a/renderer/src/modules/discordclasses.js +++ /dev/null @@ -1,49 +0,0 @@ -import Utilities from "./utilities"; -import ClassName from "../structs/classname"; -import WebpackModules from "./webpackmodules"; - -const combineClasses = function (...props) { - return Object.assign({}, ...props.map(prop => WebpackModules.getByProps(...prop))); -}; - -const DiscordClassModules = Utilities.memoizeObject({ - get Text() { - return combineClasses( - ["size20", "size12"], - ["selectable", "colorMuted"] - ); - }, - get Titles() { - return combineClasses( - ["wrapper", "base"], - ["defaultColor", "h4"] - ); - }, - get EmptyImage() {return WebpackModules.getByProps("emptyImage", "emptyHeader");}, - get Modal() {return WebpackModules.getByProps("content", "root", "header", "close");}, - get Scrollers() {return WebpackModules.getByProps("thin", "scrollerBase", "content");}, - get Margins() {return WebpackModules.getByProps("marginXSmall", "marginBottom8");}, - get Integrations() {return WebpackModules.getByProps("secondaryHeader", "detailsWrapper");}, - get Card() {return WebpackModules.getByProps("card", "topDivider", "description");}, -}); - -const emptyClassModule = new Proxy({}, { - get() {return "";} -}); - -const DiscordClasses = new Proxy(DiscordClassModules, { - get(list, item) { - if (list[item] === undefined) return emptyClassModule; - if (typeof(list[item]) === "string") return list[item]; - - return new Proxy(list[item], { - get(obj, prop) { - if (!(prop in obj)) return ""; - - return new ClassName(obj[prop]); - } - }); - } -}); - -export default DiscordClasses; \ No newline at end of file diff --git a/renderer/src/modules/discordmodules.js b/renderer/src/modules/discordmodules.js index 059aaf27..83286d4c 100644 --- a/renderer/src/modules/discordmodules.js +++ b/renderer/src/modules/discordmodules.js @@ -11,151 +11,13 @@ import WebpackModules, {Filters} from "./webpackmodules"; export default Utilities.memoizeObject({ get React() {return WebpackModules.getByProps("createElement", "cloneElement");}, get ReactDOM() {return WebpackModules.getByProps("render", "findDOMNode");}, - get Flux() {return WebpackModules.getByProps("connectStores");}, - get Events() {return WebpackModules.getByPrototypes("setMaxListeners", "emit");}, - - /* Guild Info, Stores, and Utilities */ - get GuildStore() {return WebpackModules.getByProps("getGuild");}, - get SortedGuildStore() {return WebpackModules.getByProps("getSortedGuilds");}, - get SelectedGuildStore() {return WebpackModules.getByProps("getLastSelectedGuildId");}, - get GuildSync() {return WebpackModules.getByProps("getSyncedGuilds");}, - get GuildInfo() {return WebpackModules.getByProps("getAcronym");}, - get GuildChannelsStore() {return WebpackModules.getByProps("getChannels", "getDefaultChannel");}, - get GuildMemberStore() {return WebpackModules.getByProps("getMember");}, - get MemberCountStore() {return WebpackModules.getByProps("getMemberCounts");}, - get GuildEmojiStore() {return WebpackModules.getByProps("getEmojis");}, - get GuildActions() {return WebpackModules.getByProps("markGuildAsRead");}, - get GuildPermissions() {return WebpackModules.getByProps("getGuildPermissions");}, - - /* Channel Store & Actions */ - get ChannelStore() {return WebpackModules.getByProps("getChannel", "getDMFromUserId");}, - get SelectedChannelStore() {return WebpackModules.getByProps("getLastSelectedChannelId");}, get ChannelActions() {return WebpackModules.getByProps("selectChannel");}, - get PrivateChannelActions() {return WebpackModules.getByProps("openPrivateChannel");}, - get ChannelSelector() {return WebpackModules.getByProps("selectGuild", "selectChannel");}, - - /* Current User Info, State and Settings */ - get UserInfoStore() {return WebpackModules.getByProps("getToken");}, get LocaleStore() {return WebpackModules.getByProps("locale", "initialize");}, - get ThemeStore() {return WebpackModules.getByProps("theme", "initialize");}, - get AccountManager() {return WebpackModules.getByProps("register", "login");}, - get UserSettingsUpdater() {return WebpackModules.getByProps("updateRemoteSettings");}, - get OnlineWatcher() {return WebpackModules.getByProps("isOnline");}, - get CurrentUserIdle() {return WebpackModules.getByProps("getIdleTime");}, - get RelationshipStore() {return WebpackModules.getByProps("isBlocked", "getFriendIDs");}, - get RelationshipManager() {return WebpackModules.getByProps("addRelationship");}, - get MentionStore() {return WebpackModules.getByProps("getMentions");}, - - /* User Stores and Utils */ get UserStore() {return WebpackModules.getByProps("getCurrentUser", "getUser");}, - get UserStatusStore() {return WebpackModules.getByProps("getStatus", "getState");}, - get UserTypingStore() {return WebpackModules.getByProps("isTyping");}, - get UserActivityStore() {return WebpackModules.getByProps("getActivity");}, - get UserNameResolver() {return WebpackModules.getByProps("getName");}, - get UserNoteStore() {return WebpackModules.getByProps("getNote");}, - get UserNoteActions() {return WebpackModules.getByProps("updateNote");}, - - /* Emoji Store and Utils */ - get EmojiInfo() {return WebpackModules.getByProps("isEmojiDisabled");}, - get EmojiUtils() {return WebpackModules.getByProps("getGuildEmoji");}, - get EmojiStore() {return WebpackModules.getByProps("getByCategory", "EMOJI_NAME_RE");}, - - /* Invite Store and Utils */ - get InviteStore() {return WebpackModules.getByProps("getInvites");}, - get InviteResolver() {return WebpackModules.getByProps("findInvite");}, get InviteActions() {return WebpackModules.getByProps("acceptInvite");}, - - /* Discord Objects & Utils */ - get DiscordConstants() {return WebpackModules.getByProps("Permissions", "ActivityTypes", "StatusTypes");}, - get DiscordPermissions() {return WebpackModules.getByProps("Permissions", "ActivityTypes", "StatusTypes").Permissions;}, - get PermissionUtils() {return WebpackModules.getByProps("getHighestRole");}, - get ColorConverter() {return WebpackModules.getByProps("hex2int");}, - get ColorShader() {return WebpackModules.getByProps("darken");}, - get TinyColor() {return WebpackModules.getByPrototypes("toRgb");}, - get ClassResolver() {return WebpackModules.getByProps("getClass");}, - get ButtonData() {return WebpackModules.getByProps("ButtonSizes");}, - get IconNames() {return WebpackModules.getByProps("IconNames");}, - get NavigationUtils() {return WebpackModules.getByProps("transitionTo", "replaceWith", "getHistory");}, - - /* Discord Messages */ - get MessageStore() {return WebpackModules.getByProps("getMessages");}, - get MessageActions() {return WebpackModules.getByProps("jumpToMessage", "_sendMessage");}, - get MessageQueue() {return WebpackModules.getByProps("enqueue");}, - get MessageParser() {return WebpackModules.getByProps("createMessage", "parse", "unparse");}, - - /* Text Processing */ - get hljs() {return WebpackModules.getByProps("highlight", "highlightBlock");}, get SimpleMarkdown() {return WebpackModules.getByProps("parseBlock", "parseInline", "defaultOutput");}, - - /* Experiments */ - get ExperimentStore() {return WebpackModules.getByProps("getExperimentOverrides");}, - get ExperimentsManager() {return WebpackModules.getByProps("isDeveloper");}, - get CurrentExperiment() {return WebpackModules.getByProps("getExperimentId");}, - - /* Images, Avatars and Utils */ - get ImageResolver() {return WebpackModules.getByProps("getUserAvatarURL", "getGuildIconURL");}, - get ImageUtils() {return WebpackModules.getByProps("getSizedImageSrc");}, - get AvatarDefaults() {return WebpackModules.getByProps("getUserAvatarURL", "DEFAULT_AVATARS");}, - - /* Window, DOM, HTML */ - get WindowInfo() {return WebpackModules.getByProps("isFocused", "windowSize");}, - get TagInfo() {return WebpackModules.getByProps("VALID_TAG_NAMES");}, - get DOMInfo() {return WebpackModules.getByProps("canUseDOM");}, - - /* Locale/Location and Time */ - get LocaleManager() {return WebpackModules.getByProps("setLocale");}, - get Moment() {return WebpackModules.getByProps("parseZone");}, - get LocationManager() {return WebpackModules.getByProps("createLocation");}, - get Timestamps() {return WebpackModules.getByProps("fromTimestamp");}, - get TimeFormatter() {return WebpackModules.getByProps("dateFormat");}, - - /* Strings and Utils */ get Strings() {return WebpackModules.getByProps("Messages").Messages;}, - get StringFormats() {return WebpackModules.getByProps("a", "z");}, - get StringUtils() {return WebpackModules.getByProps("toASCII");}, - - /* URLs and Utils */ - get URLParser() {return WebpackModules.getByProps("Url", "parse");}, - get ExtraURLs() {return WebpackModules.getByProps("getArticleURL");}, - - /* Drag & Drop */ - get DNDActions() {return WebpackModules.getByProps("beginDrag");}, - get DNDSources() {return WebpackModules.getByProps("addTarget");}, - get DNDObjects() {return WebpackModules.getByProps("DragSource");}, - - /* Media Stuff (Audio/Video) */ - get MediaDeviceInfo() {return WebpackModules.getByProps("Codecs", "SUPPORTED_BROWSERS");}, - get MediaInfo() {return WebpackModules.getByProps("getOutputVolume");}, - get MediaEngineInfo() {return WebpackModules.getByProps("MediaEngineFeatures");}, - get VoiceInfo() {return WebpackModules.getByProps("EchoCancellation");}, - get VideoStream() {return WebpackModules.getByProps("getVideoStream");}, - get SoundModule() {return WebpackModules.getByProps("playSound");}, - - /* Electron & Other Internals with Utils*/ - get ElectronModule() {return WebpackModules.getByProps("setBadge");}, get Dispatcher() {return WebpackModules.getByProps("dispatch", "subscribe", "register");}, - get PathUtils() {return WebpackModules.getByProps("hasBasename");}, - get NotificationModule() {return WebpackModules.getByProps("showNotification");}, - get RouterModule() {return WebpackModules.getByProps("Router");}, - get APIModule() {return WebpackModules.getByProps("getAPIBaseURL");}, - get AnalyticEvents() {return WebpackModules.getByProps("AnalyticEventConfigs");}, - get KeyGenerator() {return WebpackModules.getByRegex(/"binary"/);}, - get Buffers() {return WebpackModules.getByProps("INSPECT_MAX_BYTES", "kMaxLength");}, - get DeviceStore() {return WebpackModules.getByProps("getDevices");}, - get SoftwareInfo() {return WebpackModules.getByProps("os");}, - get CurrentContext() {return WebpackModules.getByProps("setTagsContext");}, - - /* Commonly Used Classes */ - get GuildClasses() { - const guildsWrapper = WebpackModules.getByProps("base", "guilds"); - const guilds = WebpackModules.getByProps("wrapper", "acronym"); - const pill = WebpackModules.getByProps("circleIconButton"); - const listItem = WebpackModules.getModule(m => m.listItem && !m.pill && !m.sidebar); - return Object.assign({}, guildsWrapper, guilds, pill, listItem); - }, - - get LayerStack() {return WebpackModules.getByProps("pushLayer");}, - get Tooltip() { // Make fallback component just pass children, so it can at least render that. const fallback = props => props.children?.({}) ?? null; diff --git a/renderer/src/modules/modules.js b/renderer/src/modules/modules.js index b1377797..fe30a27c 100644 --- a/renderer/src/modules/modules.js +++ b/renderer/src/modules/modules.js @@ -14,5 +14,4 @@ export {default as Patcher} from "./patcher"; export {default as LocaleManager} from "./localemanager"; export {default as Strings} from "./strings"; export {default as IPC} from "./ipc"; -export {default as Logger} from "common/logger"; -export {default as DiscordClasses} from "./discordclasses"; \ No newline at end of file +export {default as Logger} from "common/logger"; \ No newline at end of file diff --git a/renderer/src/structs/classname.js b/renderer/src/structs/classname.js deleted file mode 100644 index 418d6aa9..00000000 --- a/renderer/src/structs/classname.js +++ /dev/null @@ -1,50 +0,0 @@ -// import Selector from "./selector"; - -/** - * Representation of a Class Name - **/ -class ClassName { - /** - * - * @param {string} name - name of the class to represent - */ - constructor(name) { - this.value = name; - } - - /** - * Concatenates new class names to the current one using spaces. - * @param {string} classNames - list of class names to add to this class name - * @returns {ClassName} returns self to allow chaining - */ - add(...classNames) { - for (let i = 0; i < classNames.length; i++) this.value += " " + classNames[i]; - return this; - } - - /** - * Returns the raw class name, this is how native function get the value. - * @returns {string} raw class name. - */ - toString() { - return this.value; - } - - /** - * Returns the raw class name, this is how native function get the value. - * @returns {string} raw class name. - */ - valueOf() { - return this.value; - } - - get single() { - return this.value.split(" ")[0]; - } - - get first() { - return this.value.split(" ")[0]; - } -} - -export default ClassName; \ No newline at end of file diff --git a/renderer/src/styles/ui/errormodal.css b/renderer/src/styles/ui/errormodal.css index 45af31d7..12a02c4b 100644 --- a/renderer/src/styles/ui/errormodal.css +++ b/renderer/src/styles/ui/errormodal.css @@ -78,4 +78,16 @@ scrollbar-color: var(--background-tertiary) var(--background-secondary); background: var(--background-secondary); border: 1px solid var(--background-tertiary); +} + +.bd-addon-error-details { + display: flex; + flex-grow: 0; + justify-content: flex-start; + margin-top: 4px; +} + +.bd-addon-error-details-icon { + margin-right: 4px; + color: var(--interactive-normal); } \ No newline at end of file diff --git a/renderer/src/ui/blankslates/emptyimage.jsx b/renderer/src/ui/blankslates/emptyimage.jsx index 7fd77004..b4bb66a2 100644 --- a/renderer/src/ui/blankslates/emptyimage.jsx +++ b/renderer/src/ui/blankslates/emptyimage.jsx @@ -1,10 +1,12 @@ -import {React, DiscordClasses} from "modules"; +import {React, WebpackModules} from "modules"; import SimpleMarkdown from "../../structs/markdown"; +const EmptyImageClasses = WebpackModules.getByProps("emptyImage", "emptyHeader") ?? {emptyContainer: "emptyContainer-poti7J", emptyImage: "emptyImage-2pCD2j", emptyHeader: "emptyHeader-2cxTFP"}; + export default function EmptyImage(props) { - return
-
-
+ return
+
+
{props.title || "You don't have anything!"}
diff --git a/renderer/src/ui/modals.js b/renderer/src/ui/modals.js index e458a78f..0e094b0f 100644 --- a/renderer/src/ui/modals.js +++ b/renderer/src/ui/modals.js @@ -2,7 +2,7 @@ import {Config} from "data"; import Logger from "common/logger"; import {WebpackModules, React, ReactDOM, Settings, Strings, DOMManager} from "modules"; import FormattableString from "../structs/string"; -import AddonErrorModal from "./addonerrormodal"; +import AddonErrorModal from "./modals/addonerrormodal"; import ErrorBoundary from "./errorboundary"; import TextElement from "./base/text"; import ModalRoot from "./modals/root"; @@ -198,29 +198,15 @@ export default class Modals { static showAddonErrors({plugins: pluginErrors = [], themes: themeErrors = []}) { if (!pluginErrors || !themeErrors || !this.shouldShowAddonErrors) return; if (!pluginErrors.length && !themeErrors.length) return; - - if (this.addonErrorsRef && this.addonErrorsRef.current) { - return this.addonErrorsRef.current.refreshTabs(Array.isArray(pluginErrors) ? pluginErrors : [], Array.isArray(themeErrors) ? themeErrors : []); - } - this.addonErrorsRef = React.createRef(); - this.ModalActions.openModal(props => React.createElement(ErrorBoundary, null, React.createElement(ModalRoot, Object.assign(props, { - size: ModalRoot.Sizes.MEDIUM, - className: "bd-error-modal", - children: [ - React.createElement(AddonErrorModal, { - ref: this.addonErrorsRef, - pluginErrors: Array.isArray(pluginErrors) ? pluginErrors : [], - themeErrors: Array.isArray(themeErrors) ? themeErrors : [], - onClose: props.onClose - }), - React.createElement(ModalFooter, { - className: "bd-error-modal-footer", - }, React.createElement(Button, { - onClick: props.onClose - }, Strings.Modals.okay)) - ] - })))); + const options = { + ref: this.addonErrorsRef, + pluginErrors: Array.isArray(pluginErrors) ? pluginErrors : [], + themeErrors: Array.isArray(themeErrors) ? themeErrors : [] + }; + this.ModalActions.openModal(props => { + return React.createElement(ErrorBoundary, null, React.createElement(AddonErrorModal, Object.assign(options, props))); + }); } static showChangelogModal(options = {}) { @@ -253,7 +239,7 @@ export default class Modals { } render() { - if (this.state.hasError) return null; + if (this.state.hasError) return React.createElement(TextElement, {color: TextElement.Colors.STATUS_RED}, Strings.Addons.settingsError); const props = { className: "bd-addon-settings-wrap", ref: this.elementRef @@ -265,22 +251,16 @@ export default class Modals { } if (typeof(child) === "function") child = React.createElement(child); - const modal = props => { - return React.createElement(ErrorBoundary, {}, React.createElement(ModalRoot, Object.assign({size: ModalRoot.Sizes.MEDIUM, className: "bd-addon-modal" + " " + ModalRoot.Sizes.MEDIUM}, props), - React.createElement(ModalHeader, null, - React.createElement(TextElement, {tag: "h1", size: TextElement.Sizes.SIZE_20, strong: true}, `${name} Settings`) - ), - React.createElement(ModalContent, null, - React.createElement(ErrorBoundary, {}, child) - ), - React.createElement(ModalFooter, null, - React.createElement(Button, {onClick: props.onClose}, Strings.Modals.done) - ) - )); + const options = { + className: "bd-addon-modal", + size: ModalRoot.Sizes.MEDIUM, + header: `${name} Settings`, + cancelText: null, + confirmText: Strings.Modals.done }; return this.ModalActions.openModal(props => { - return React.createElement(ErrorBoundary, null, React.createElement(modal, props)); + return React.createElement(ErrorBoundary, null, React.createElement(ConfirmationModal, Object.assign(options, props), child)); }); } } diff --git a/renderer/src/ui/addonerrormodal.jsx b/renderer/src/ui/modals/addonerrormodal.jsx similarity index 52% rename from renderer/src/ui/addonerrormodal.jsx rename to renderer/src/ui/modals/addonerrormodal.jsx index 5ac9bfaa..07e70a01 100644 --- a/renderer/src/ui/addonerrormodal.jsx +++ b/renderer/src/ui/modals/addonerrormodal.jsx @@ -1,7 +1,14 @@ -import {React, Strings, WebpackModules, DiscordClasses} from "modules"; -import Extension from "./icons/extension"; -import ThemeIcon from "./icons/theme"; -import Divider from "./divider"; +import {React, Strings, WebpackModules} from "modules"; +import Extension from "../icons/extension"; +import ThemeIcon from "../icons/theme"; +import Divider from "../divider"; +import Text from "../base/text"; +import Header from "./header"; +import Content from "./content"; +import Flex from "../base/flex"; +import ModalRoot from "./root"; +import Footer from "./footer"; +import Button from "../base/button"; const Parser = Object(WebpackModules.getByProps("defaultRules", "parse")).defaultRules; @@ -30,12 +37,12 @@ function AddonError({err, index}) { {err.type == "plugin" ? : }
-

{err.name}

-
- + {err.name} +
+ -
{err.message}
+ {err.message}
@@ -51,7 +58,7 @@ function generateTab(id, errors) { return {id, errors, name: Strings.Panels[id]}; } -export default function AddonErrorModal({pluginErrors, themeErrors}) { +export default function AddonErrorModal({transitionState, onClose, pluginErrors, themeErrors}) { const tabs = useMemo(() => { return [ pluginErrors.length && generateTab("plugins", pluginErrors), @@ -63,17 +70,22 @@ export default function AddonErrorModal({pluginErrors, themeErrors}) { const switchToTab = useCallback((id) => setTab(id), []); const selectedTab = tabs.find(e => e.id === tabId); - return <> -
-

{Strings.Modals.addonErrors}

-
- {tabs.map(tab =>
{switchToTab(tab.id);}} className={joinClassNames("bd-tab-item", tab.id === selectedTab.id && "selected")}>{tab.name}
)} -
-
-
-
- {selectedTab.errors.map((error, index) => )} -
-
- ; + return +
+ + {Strings.Modals.addonErrors} +
+ {tabs.map(tab =>
{switchToTab(tab.id);}} className={joinClassNames("bd-tab-item", tab.id === selectedTab.id && "selected")}>{tab.name}
)} +
+
+
+ +
+ {selectedTab.errors.map((error, index) => )} +
+
+
+ +
+
; } \ No newline at end of file diff --git a/renderer/src/ui/modals/changelog.jsx b/renderer/src/ui/modals/changelog.jsx index 3e9fb800..ac948771 100644 --- a/renderer/src/ui/modals/changelog.jsx +++ b/renderer/src/ui/modals/changelog.jsx @@ -47,7 +47,7 @@ export default function ChangelogModal({transitionState, footer, title, subtitle const entry = changes[c]; const type = "bd-changelog-" + entry.type; const margin = c == 0 ? " bd-changelog-first" : ""; - items.push(

entry.title

); + items.push(

{entry.title}

); if (entry.description) items.push(

{SimpleMarkdownExt.parseToReact(entry.description)}

); const list =
    {entry.items.map(i =>
  • {SimpleMarkdownExt.parseToReact(i)}
  • )}
; items.push(list); diff --git a/renderer/src/ui/modals/confirmation.jsx b/renderer/src/ui/modals/confirmation.jsx index eed10534..ceb9eb57 100644 --- a/renderer/src/ui/modals/confirmation.jsx +++ b/renderer/src/ui/modals/confirmation.jsx @@ -1,4 +1,4 @@ -import {React} from "modules"; +import {React, Strings} from "modules"; import Root from "./root"; import Header from "./header"; import Footer from "./footer"; @@ -10,7 +10,7 @@ import Button from "../base/button"; const {useRef, useEffect} = React; -export default function ConfirmationModal({transitionState, onClose, header, children, danger = false, onCancel = () => {}, onConfirm = () => {}, cancelText = "Cancel", confirmText = "Okay"}) { +export default function ConfirmationModal({transitionState, onClose, className, size = Root.Sizes.SMALL, header, children, danger = false, onCancel = () => {}, onConfirm = () => {}, cancelText = Strings.Modals.cancel, confirmText = Strings.Modals.okay}) { useEffect(() => { setTimeout(() => buttonRef?.current?.focus?.(), 0); @@ -19,8 +19,10 @@ export default function ConfirmationModal({transitionState, onClose, header, chi const buttonRef = useRef(null); - return -
{header}
+ return +
+ {header} +
{children}