diff --git a/renderer/src/modules/discordclasses.js b/renderer/src/modules/discordclasses.js deleted file mode 100644 index ed73c0a2..00000000 --- a/renderer/src/modules/discordclasses.js +++ /dev/null @@ -1,51 +0,0 @@ -import ClassName from "@structs/classname"; - -import Utilities from "./utilities"; -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 8eea820f..003ec9d8 100644 --- a/renderer/src/modules/discordmodules.js +++ b/renderer/src/modules/discordmodules.js @@ -12,151 +12,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/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/structs/markdown.js b/renderer/src/structs/markdown.js index 6db0309d..c52f3923 100644 --- a/renderer/src/structs/markdown.js +++ b/renderer/src/structs/markdown.js @@ -3,9 +3,9 @@ import Utilities from "@modules/utilities"; export default class SimpleMarkdownExt { - static parseToReact(str) { + static parseToReact(str, inline = true) { if (!this._parser) this._initialize(); - return this._renderer(this._parse(str, {inline: true})); + return this._renderer(this._parse(str, {inline})); } static _initialize() { diff --git a/renderer/src/styles/buttons.css b/renderer/src/styles/buttons.css index eb06877f..79b0eea0 100644 --- a/renderer/src/styles/buttons.css +++ b/renderer/src/styles/buttons.css @@ -1,4 +1,4 @@ -.bd-button { +/* .bd-button { display: inline-flex; justify-content: center; align-items: center; @@ -59,4 +59,539 @@ .bd-button-disabled:hover { cursor: not-allowed; -} \ No newline at end of file +} */ + + + + + + + + + + + +/* Generic Button Styles */ +.bd-button { + position: relative; + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; + background: none; + border: none; + border-radius: 3px; + font-size: 14px; + font-weight: 500; + line-height: 16px; + padding: 2px 16px; + user-select: none; +} + +.bd-button:disabled { + cursor: not-allowed; + opacity: 0.5; +} + +.bd-button .bd-button-content { + --button--underline-color: transparent; + background-image: linear-gradient(0deg, transparent, transparent 1px, var(--button--underline-color) 0, var(--button--underline-color) 2px, transparent 0); +} + +.bd-button:disabled .bd-button-content { + background-image: none !important; +} + +.bd-button-outlined:disabled { + background-color: transparent !important; +} + + + +/* Button Sizes */ +.bd-button-tiny { + width: 52px; + height: 24px; + min-width: 52px; + min-height: 24px; +} + +.bd-button-small { + width: 60px; + height: 32px; + min-width: 60px; + min-height: 32px; +} + +.bd-button-medium { + width: 96px; + height: 38px; + min-width: 96px; + min-height: 38px; +} + +.bd-button-large { + width: 130px; + height: 44px; + min-width: 130px; + min-height: 44px; +} + +.bd-button-xlarge { + width: 148px; + height: 50px; + min-width: 148px; + min-height: 50px; + font-size: 16px; + line-height: normal; + padding: 2px 20px; +} + +.bd-button-icon { + height: auto; + padding: 4px; +} + +.bd-button-grow, +.bd-button-icon { + width: auto +} + + + +/* Button Looks */ +.bd-button-filled { + -webkit-transition: background-color .17s ease, color .17s ease; + transition: background-color .17s ease, color .17s ease +} + +.bd-button-outlined { + -webkit-transition: color .17s ease, background-color .17s ease, border-color .17s ease; + transition: color .17s ease, background-color .17s ease, border-color .17s ease; + border-width: 1px; + border-style: solid +} + +.bd-button-blank { + background: transparent; + color: currentColor; + border: 0; + padding: 0; + margin: 0 +} + +.bd-button-filled .bd-button-content, +.bd-button-link .bd-button-content, +.bd-button-outlined .bd-button-content { + margin: 0 auto; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + + +/* COLORS */ + +/* Color BD Brand */ +.bd-button-filled.bd-button-color-brand { + color: var(--white-500); + background-color: #3E82E5; /* BD Blue */ +} + +.bd-button-filled.bd-button-color-brand:hover { + background-color: #3875CE; +} + +.bd-button-filled.bd-button-color-brand:active { + background-color: #3268B7; +} + +.bd-button-filled.bd-button-color-brand:disabled { + background-color: #3E82E5; /* BD Blue */ + opacity: 0.4; +} + +.bd-button-outlined.bd-button-color-brand { + color: var(--button-outline-brand-text); + border-color: var(--button-outline-brand-border); +} + +.bd-button-outlined.bd-button-color-brand:hover { + background-color: var(--button-outline-brand-background-hover); + border-color: var(--button-outline-brand-border-hover); + color: var(--button-outline-brand-text-hover); +} + +.bd-button-outlined.bd-button-color-brand:active { + background-color: var(--button-outline-brand-background-active); + border-color: var(--button-outline-brand-border-active); + color: var(--button-outline-brand-text-active); +} + +.bd-button-link.bd-button-color-brand { + color: #3E82E5; /* BD Blue */ +} + +.bd-button-link.bd-button-color-brand:hover .bd-button-content { + --button--underline-color: #3E82E5; /* BD Blue */ +} + + + +/* Color Blurple */ +.bd-button-filled.bd-button-color-blurple { + color: var(--white-500); + background-color: var(--brand-experiment) +} + +.bd-button-filled.bd-button-color-blurple:hover { + background-color: var(--brand-experiment-560) +} + +.bd-button-filled.bd-button-color-blurple:active { + background-color: var(--brand-experiment-600) +} + +.bd-button-filled.bd-button-color-blurple:disabled { + background-color: var(--brand-experiment) +} + +.bd-button-outlined.bd-button-color-blurple { + color: var(--button-outline-brand-text); + border-color: var(--button-outline-brand-border) +} + +.bd-button-outlined.bd-button-color-blurple:hover { + background-color: var(--button-outline-brand-background-hover); + border-color: var(--button-outline-brand-border-hover); + color: var(--button-outline-brand-text-hover) +} + +.bd-button-outlined.bd-button-color-blurple:active { + background-color: var(--button-outline-brand-background-active); + border-color: var(--button-outline-brand-border-active); + color: var(--button-outline-brand-text-active) +} + +.bd-button-link.bd-button-color-blurple { + color: var(--brand-experiment) +} + +.bd-button-link.bd-button-color-blurple:hover .bd-button-content { + --button--underline-color: var(--brand-experiment) +} + + + +/* Color Yellow/Warn */ +.bd-button-filled.bd-button-color-yellow { + color: var(--white-500); + background-color: var(--status-warning) +} + +.bd-button-filled.bd-button-color-yellow:active, +.bd-button-filled.bd-button-color-yellow:hover { + background-color: null; +} + +.bd-button-filled.bd-button-color-yellow:disabled { + background-color: var(--status-warning) +} + +.bd-button-outlined.bd-button-color-yellow { + color: var(--status-warning); + border-color: var(--status-warning) +} + +.bd-button-outlined.bd-button-color-yellow:active { + background-color: hsl(var(--yellow-300-hsl)/.1) +} + +.bd-button-link.bd-button-color-yellow { + color: var(--status-warning) +} + +.bd-button-link.bd-button-color-yellow:hover .bd-button-content { + --button--underline-color: var(--status-warning) +} + + + +/* Color Link */ +.bd-button-filled.bd-button-color-link { + color: var(--white-500); + background-color: var(--text-link) +} + +.bd-button-filled.bd-button-color-link:active, +.bd-button-filled.bd-button-color-link:hover { + background-color: null +} + +.bd-button-filled.bd-button-color-link:disabled { + background-color: var(--text-link) +} + +.bd-button-outlined.bd-button-color-link { + color: var(--text-link); + border-color: var(--text-link) +} + +.bd-button-outlined.bd-button-color-link:active { + background-color: hsl(var(--text-link-hsl)/.1) +} + +.bd-button-link.bd-button-color-link { + color: var(--text-link) +} + +.bd-button-link.bd-button-color-link:hover .bd-button-content { + --button--underline-color: var(--text-link) +} + + + +/* Color White */ +.bd-button-filled.bd-button-color-white { + color: var(--primary-500); + background-color: var(--white-500) +} + +.bd-button-filled.bd-button-color-white:active, +.bd-button-filled.bd-button-color-white:hover { + background-color: null +} + +.bd-button-filled.bd-button-color-white:disabled { + background-color: var(--white-500) +} + +.bd-button-outlined.bd-button-color-white { + color: var(--white-500); + border-color: var(--white-500) +} + +.bd-button-outlined.bd-button-color-white:active { + background-color: hsl(var(--white-500-hsl)/.1) +} + +.bd-button-link.bd-button-color-white { + color: var(--white-500) +} + +.bd-button-link.bd-button-color-white:hover .bd-button-content { + --button--underline-color: var(--white-500) +} + + + +/* Color Red/Danger/Error */ +.bd-button-filled.bd-button-color-red { + color: var(--white-500); + background-color: var(--button-danger-background) +} + +.bd-button-filled.bd-button-color-red:hover { + background-color: var(--button-danger-background-hover) +} + +.bd-button-filled.bd-button-color-red:active { + background-color: var(--button-danger-background-active) +} + +.bd-button-filled.bd-button-color-red:disabled { + background-color: var(--button-danger-background-disabled) +} + +.bd-button-outlined.bd-button-color-red { + color: var(--button-outline-danger-text); + border-color: var(--button-outline-danger-border) +} + +.bd-button-outlined.bd-button-color-red:hover { + background-color: var(--button-outline-danger-background-hover); + border-color: var(--button-outline-danger-border-hover); + color: var(--button-outline-danger-text-hover) +} + +.bd-button-outlined.bd-button-color-red:active { + background-color: var(--button-outline-danger-background-active); + border-color: var(--button-outline-danger-border-active); + color: var(--button-outline-danger-text-active) +} + +.bd-button-link.bd-button-color-red { + color: var(--text-danger) +} + +.bd-button-link.bd-button-color-red:hover .bd-button-content { + --button--underline-color: var(--text-danger) +} + + +/* Color Green Success */ +.bd-button-filled.bd-button-color-green { + color: var(--white-500); + background-color: var(--button-positive-background) +} + +.bd-button-filled.bd-button-color-green:hover { + background-color: var(--button-positive-background-hover) +} + +.bd-button-filled.bd-button-color-green:active { + background-color: var(--button-positive-background-active) +} + +.bd-button-filled.bd-button-color-green:disabled { + background-color: var(--button-positive-background-disabled) +} + +.bd-button-outlined.bd-button-color-green { + color: var(--button-outline-positive-text); + border-color: var(--button-outline-positive-border) +} + +.bd-button-outlined.bd-button-color-green:hover { + background-color: var(--button-outline-positive-background-hover); + border-color: var(--button-outline-positive-border-hover); + color: var(--button-outline-positive-text-hover) +} + +.bd-button-outlined.bd-button-color-green:active { + background-color: var(--button-outline-positive-background-active); + border-color: var(--button-outline-positive-border-active); + color: var(--button-outline-positive-text-active) +} + +.bd-button-link.bd-button-color-green { + color: var(--green-360) +} + +.bd-button-link.bd-button-color-green:hover .bd-button-content { + --button--underline-color: var(--green-360) +} + + + +/* Color Primary/Grey */ +.bd-button-outlined.bd-button-color-primary { + color: var(--button-outline-primary-text); + border-color: var(--button-outline-primary-border) +} + +.bd-button-outlined.bd-button-color-primary:hover { + background-color: var(--button-outline-primary-background-hover); + border-color: var(--button-outline-primary-border-hover); + color: var(--button-outline-primary-text-hover) +} + +.bd-button-outlined.bd-button-color-primary:active { + background-color: var(--button-outline-primary-background-active); + border-color: var(--button-outline-primary-border-active); + color: var(--button-outline-primary-text-active) +} + +.bd-button-filled.bd-button-color-primary { + color: var(--white-500); + background-color: var(--button-secondary-background) +} + +.bd-button-filled.bd-button-color-primary:hover { + background-color: var(--button-secondary-background-hover) +} + +.bd-button-filled.bd-button-color-primary:active { + background-color: var(--button-secondary-background-active) +} + +.bd-button-filled.bd-button-color-primary:disabled { + background-color: var(--button-secondary-background-disabled) +} + +.theme-dark .bd-button-link.bd-button-color-primary { + color: var(--white-500) +} + +.theme-dark .bd-button-link.bd-button-color-primary:hover .bd-button-content { + --button--underline-color: var(--white-500) +} + +.theme-light .bd-button-link.bd-button-color-primary { + color: var(--primary-400) +} + +.theme-light .bd-button-link.bd-button-color-primary:hover .bd-button-content { + --button--underline-color: var(--primary-400) +} + + + +/* Color Transparent */ +.theme-dark .bd-button-filled.bd-button-color-transparent { + color: var(--primary-100); + background-color: hsl(var(--white-500-hsl)/.1) +} + +.theme-dark .bd-button-filled.bd-button-color-transparent:hover { + background-color: hsl(var(--white-500-hsl)/.05) +} + +.theme-dark .bd-button-filled.bd-button-color-transparent:active { + background-color: hsl(var(--white-500-hsl)/.01) +} + +.theme-dark .bd-button-filled.bd-button-color-transparent:disabled { + background-color: hsl(var(--white-500-hsl)/.1) +} + +.theme-dark .bd-button-outlined.bd-button-color-transparent { + color: var(--primary-200); + border-color: var(--primary-200) +} + +.theme-dark .bd-button-outlined.bd-button-color-transparent:active { + background-color: hsl(var(--primary-200-hsl)/.1) +} + +.theme-dark .bd-button-link.bd-button-color-transparent { + color: var(--primary-200) +} + +.theme-dark .bd-button-link.bd-button-color-transparent:hover .bd-button-content { + --button--underline-color: var(--primary-200) +} + +.theme-light .bd-button-filled.bd-button-color-transparent { + color: var(--primary-400); + background-color: hsl(var(--primary-400-hsl)/.01) +} + +.theme-light .bd-button-filled.bd-button-color-transparent:hover { + background-color: hsl(var(--primary-400-hsl)/.2) +} + +.theme-light .bd-button-filled.bd-button-color-transparent:active { + background-color: hsl(var(--primary-400-hsl)/.25) +} + +.theme-light .bd-button-filled.bd-button-color-transparent:disabled { + background-color: hsl(var(--primary-400-hsl)/.01) +} + +.theme-light .bd-button-outlined.bd-button-color-transparent { + color: var(--primary-400); + border-color: var(--primary-400) +} + +.theme-light .bd-button-outlined.bd-button-color-transparent:active { + background-color: hsl(var(--primary-400-hsl)/.1) +} + +.theme-light .bd-button-link.bd-button-color-transparent { + color: var(--primary-400) +} + +.theme-light .bd-button-link.bd-button-color-transparent:hover .bd-button-content { + --button--underline-color: var(--primary-400) +} diff --git a/renderer/src/styles/index.css b/renderer/src/styles/index.css index fd1bc78b..cf0e3945 100644 --- a/renderer/src/styles/index.css +++ b/renderer/src/styles/index.css @@ -6,6 +6,7 @@ @import "./buttons.css"; @import "./spinner.css"; @import "./search.css"; +@import "./text.css"; .bd-chat-badge { vertical-align: bottom; @@ -19,23 +20,6 @@ margin-left: 4px; } -.bd-changelog-modal video, -.bd-changelog-modal img { - width: 100%; - border-radius: 5px; - outline: none; -} - -.bd-changelog-modal code.inline { - padding: 0.2em; - margin: -0.2em 0; - border-radius: 3px; - font-size: 85%; - line-height: 1.125rem; - white-space: pre-wrap; - background: var(--background-secondary); -} - .bd-link { text-decoration: none; } diff --git a/renderer/src/styles/text.css b/renderer/src/styles/text.css new file mode 100644 index 00000000..e29b9de5 --- /dev/null +++ b/renderer/src/styles/text.css @@ -0,0 +1,86 @@ +.bd-text-normal { + color: var(--text-normal); +} + +.bd-text-muted { + color: var(--text-muted); +} + +.bd-text-error { + color: var(--red-400); +} + +.bd-text-brand { + color: var(--text-brand); +} + +.bd-text-link { + color: var(--text-link); +} + +.bd-header-primary { + color: var(--header-primary); +} + +.bd-header-secondary { + color: var(--header-secondary); +} + +.bd-text-yellow { + color: var(--text-warning); +} + +.bd-text-green { + color: var(--text-positive); +} + +.bd-text-red { + color: var(--status-danger); +} + +.bd-text-white { + color: var(--white-500); +} + +.bd-text-10 { + font-size: 10px; + line-height: 12px; +} + +.bd-text-12 { + font-size: 12px; + line-height: 16px; +} + +.bd-text-14 { + font-size: 14px; + line-height: 18px; +} + +.bd-text-16 { + font-size: 16px; + line-height: 20px; +} + +.bd-text-20 { + font-size: 20px; + line-height: 24px; +} + +.bd-text-24 { + font-size: 24px; + line-height: 30px; +} + +.bd-text-32 { + font-size: 32px; + line-height: 40px; +} + +.bd-text-strong { + font-weight: 600; +} + +.bd-selectable { + user-select: text; +} \ No newline at end of file diff --git a/renderer/src/styles/ui/bdsettings.css b/renderer/src/styles/ui/bdsettings.css index abc9c357..0603206c 100644 --- a/renderer/src/styles/ui/bdsettings.css +++ b/renderer/src/styles/ui/bdsettings.css @@ -166,6 +166,7 @@ .bd-settings-title { color: var(--header-primary, #FFFFFF); + display: flex; font-weight: 600; cursor: default; flex: 1; diff --git a/renderer/src/styles/ui/changelog.css b/renderer/src/styles/ui/changelog.css new file mode 100644 index 00000000..aea4237e --- /dev/null +++ b/renderer/src/styles/ui/changelog.css @@ -0,0 +1,217 @@ +.bd-changelog-modal video, +.bd-changelog-modal img { + width: 100%; + border-radius: 5px; + outline: none; +} + +.bd-changelog-modal code.inline { + padding: 0.2em; + margin: -0.2em 0; + border-radius: 3px; + font-size: 85%; + line-height: 1.125rem; + white-space: pre-wrap; + background: var(--background-secondary); +} + +.bd-changelog-modal .bd-modal-content { + font-size: 16px; + line-height: 20px; + padding-bottom: 20px; +} + +.bd-changelog-modal .bd-modal-content .emoji { + object-fit: contain; + width: 22px; + height: 22px; +} + +.bd-changelog-modal .bd-modal-content h1 { + line-height: 20px; + font-size: 16px; +} + +.bd-changelog-modal .bd-modal-content h1, +.bd-changelog-modal .bd-modal-content h2, +.bd-changelog-modal .bd-modal-content strong { + font-weight: 700; +} + +.bd-changelog-modal .bd-modal-content em, +.bd-changelog-modal .bd-modal-content i { + font-style: italic; +} + +.bd-changelog-modal .bd-modal-content p + p { + margin-top: 10px; +} + +.bd-changelog-modal .bd-modal-content ol { + margin: 16px 0 16px 16px; +} + +.bd-changelog-modal .bd-modal-content ol li { + list-style-type: decimal; + margin-bottom: 8px; + margin-left: 20px; +} + +.bd-changelog-modal .bd-modal-content ul { + margin: 20px 0 8px 20px; +} + +.bd-changelog-modal .bd-modal-content ul ul { + margin-top: 8px; +} + +.bd-changelog-modal .bd-modal-content ul li { + position: relative; + list-style: none; + margin-bottom: 8px; + user-select: text; +} + +.bd-changelog-modal .bd-modal-content ul li:last-child { + margin-bottom: 0; +} + +.bd-changelog-modal .bd-modal-content ul li::before { + content: ""; + position: absolute; + top: 10px; + left: -15px; + width: 6px; + height: 6px; + margin-top: -4px; + margin-left: -3px; + border-radius: 50%; + opacity: 0.3; +} + +.bd-changelog-modal .bd-modal-content ul li li::before { + top: 12px; + height: 2px; + border-radius: 0; +} + +.bd-changelog-modal .bd-modal-content img { + width: 100%; +} + +.bd-changelog-modal .bd-modal-content a { + color: hsl(200, calc(var(--saturation-factor, 1) * 100%), 49.4%); + transition: 0.05s; + text-decoration: none; +} + +.bd-changelog-modal .bd-modal-content a:hover { + text-decoration: underline; +} + +.theme-dark .bd-changelog-modal .bd-modal-content ol, +.theme-dark .bd-changelog-modal .bd-modal-content p, +.theme-dark .bd-changelog-modal .bd-modal-content ul li { + color: hsl(210, calc(var(--saturation-factor, 1) * 9.3%), 78.8%); +} + +.theme-dark .bd-changelog-modal .bd-modal-content ul li::before { + background-color: hsl(216, calc(var(--saturation-factor, 1) * 9.8%), 90%); +} + +.theme-light .bd-changelog-modal .bd-modal-content ol, +.theme-light .bd-changelog-modal .bd-modal-content p, +.theme-light .bd-changelog-modal .bd-modal-content ul li { + color: hsl(223, calc(var(--saturation-factor, 1) * 5.8%), 52.9%); +} + +.theme-light .bd-changelog-modal .bd-modal-content ul li::before { + background-color: hsl(223, calc(var(--saturation-factor, 1) * 5.8%), 52.9%); +} + +.bd-changelog-title { + font-weight: 700; + font-size: 16px; + line-height: 20px; + text-transform: uppercase; +} + +.bd-changelog-title { + display: flex; + align-items: center; + margin-top: 40px; +} + +.bd-changelog-title.bd-changelog-first { + margin-top: 20px; +} + +.bd-changelog-title::after { + content: ""; + height: 1px; + flex: 1 1 auto; + margin-left: 4px; + opacity: .6; +} + +.bd-changelog-added { + color: var(--text-positive); +} + +.bd-changelog-added::after { + background-color: var(--info-positive-foreground); +} + +.bd-changelog-fixed { + color: hsl(359, calc(var(--saturation-factor, 1)*87.3%), 59.8%); +} + +.bd-changelog-fixed::after { + background-color: hsl(359, calc(var(--saturation-factor, 1)*87.3%), 59.8%); +} + +.bd-changelog-progress { + color: var(--text-warning); +} + +.bd-changelog-progress::after { + background-color: var(--info-warning-foreground); +} + +.bd-changelog-improved { + color: hsl(235, calc(var(--saturation-factor, 1)*85.6%), 64.7%); +} + +.bd-changelog-improved::after { + background-color: hsl(235, calc(var(--saturation-factor, 1)*85.6%), 64.7%); +} + +.theme-dark .bd-changelog-improved { + color: hsl(235, calc(var(--saturation-factor, 1)*86.1%), 77.5%); +} + +.theme-dark .bd-changelog-improved::after { + background-color: hsl(235, calc(var(--saturation-factor, 1)*86.1%), 77.5%); +} + +.theme-dark .bd-changelog-modal video, +.theme-dark .bd-changelog-modal img { + box-shadow: 0 2px 10px 0 hsl(var(0, calc(var(--saturation-factor, 1)*0%), 0%-hsl)/.2); +} + +.theme-light .bd-changelog-modal video, +.theme-light .bd-changelog-modal img { + box-shadow: 0 2px 10px 0 hsl(var(0, calc(var(--saturation-factor, 1)*0%), 0%-hsl)/.1); +} + +/* .socialLink-1qjJIk { + margin-right: 16px; +} + +.theme-light .socialLink-1qjJIk { + color: hsl(228, calc(var(--saturation-factor, 1)*6%), 32.5%); +} + +.theme-dark .socialLink-1qjJIk { + color: hsl(210, calc(var(--saturation-factor, 1)*9.3%), 78.8%); +} */ \ 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/styles/ui/flex.css b/renderer/src/styles/ui/flex.css new file mode 100644 index 00000000..60d92be2 --- /dev/null +++ b/renderer/src/styles/ui/flex.css @@ -0,0 +1,124 @@ +.bd-flex { + display: flex; +} + +.bd-flex-align-start { + align-items: flex-start; +} + +.bd-flex-align-end { + align-items: flex-end; +} + +.bd-flex-align-center { + align-items: center; +} + +.bd-flex-align-stretch { + align-items: stretch; +} + +.bd-flex-align-baseline { + align-items: baseline +} + +.bd-flex-justify-start { + justify-content: flex-start; +} + +.bd-flex-justify-end { + justify-content: flex-end; +} + +.bd-flex-justify-center { + justify-content: center; +} + +.bd-flex-justify-around { + justify-content: space-around; +} + +.bd-flex-justify-between { + justify-content: space-between; +} + +.bd-flex-no-wrap { + flex-wrap: nowrap; +} + +.bd-flex-wrap { + flex-wrap: wrap; +} + +.bd-flex-wrap-reverse { + flex-wrap: wrap-reverse; +} + +.bd-flex-horizontal { + flex-direction: row; +} + +.bd-flex-reverse { + flex-direction: row-reverse; +} + +.bd-flex-vertical { + flex-direction: column; +} + +.spacer-2upayl { + flex: 1; + overflow: hidden; +} + +.bd-flex-vertical {} + +.bd-flex-horizontal {} + +.bd-flex-reverse {} + +.bd-flex-horizontal > .spacer-2upayl, +.bd-flex-reverse > .spacer-2upayl, +.bd-flex-vertical > .spacer-2upayl { + min-height: 1px; +} + +.flexCenter-1Mwsxg {} + +.bd-flex {} + +.bd-flex-horizontal {} + +.bd-flex-reverse {} + +.bd-flex-horizontal > .bd-flex, +.bd-flex-horizontal > .bd-flex-child { + margin-left: 10px; + margin-right: 10px; +} + +.bd-flex-horizontal > .bd-flex:first-child, +.bd-flex-horizontal > .bd-flex-child:first-child { + margin-left: 0; +} + +.bd-flex-horizontal > .bd-flex:last-child, +.bd-flex-horizontal > .bd-flex-child:last-child { + margin-right: 0; +} + +.bd-flex-reverse > .bd-flex, +.bd-flex-reverse > .bd-flex-child { + margin-left: 10px; + margin-right: 10px; +} + +.bd-flex-reverse > .bd-flex:first-child, +.bd-flex-reverse > .bd-flex-child:first-child { + margin-right: 0; +} + +.bd-flex-reverse > .bd-flex:last-child, +.bd-flex-reverse > .bd-flex-child:last-child { + margin-left: 0; +} \ No newline at end of file diff --git a/renderer/src/styles/ui/modal.css b/renderer/src/styles/ui/modal.css index 1421e5c9..5d05ee6e 100644 --- a/renderer/src/styles/ui/modal.css +++ b/renderer/src/styles/ui/modal.css @@ -71,3 +71,143 @@ @keyframes bd-modal-open { from {transform: scale(0.7);} } + + + +.bd-modal-root { + display: flex; + flex-direction: column; + background-color: var(--modal-background); + border-radius: 4px; + margin: 0 auto; + pointer-events: all; + position: relative; + max-height: 100%; +} + +.bd-close-button { + height: 26px; + padding: 4px; + transition: opacity 0.2s ease-in-out; + opacity: 0.5; + cursor: pointer; + border-radius: 3px; + color: var(--interactive-normal); + box-sizing: content-box; +} + +.bd-close-button:hover { + opacity: 1; + color: var(--interactive-hover); +} + +.bd-modal-small { + width: 440px; + max-height: 720px; + min-height: 200px; +} + +.bd-modal-standard { + font-size: 13px; + white-space: pre-wrap; + word-wrap: break-word; + width: 490px; + max-height: 800px; +} + +.bd-modal-medium { + width: 600px; + max-height: 800px; + min-height: 400px; +} + +.bd-modal-large { + width: 800px; + max-height: 960px; + min-height: 400px; +} + +.bd-modal-header, +.bd-modal-footer { + position: relative; + flex: 0 0 auto; + padding: 16px; + z-index: 1; + overflow-x: hidden; +} + +.bd-modal-header { + border-radius: 4px 4px 0 0; + transition: box-shadow 0.1s ease-out; + word-wrap: break-word; +} + +.bd-modal-footer { + border-radius: 0 0 5px 5px; + background-color: var(--modal-footer-background); + overflow: hidden; + box-shadow: inset 0 1px 0 hsl(var(--primary-630-hsl)/0.6); +} + +.bd-modal-content { + position: relative; + z-index: 0; + border-radius: 5px 5px 0 0; + padding-left: 16px; + /* padding-right: 16px; */ + overflow-x: hidden; + font-size: 16px; + line-height: 20px; + padding-bottom: 20px; + overflow: hidden scroll; + padding-right: 8px; +} + +.bd-modal-backdrop { + position: fixed; + top: 0; + right: var(--devtools-sidebar-width,0); + bottom: 0; + left: 0; + -webkit-transform: translateZ(0); + transform: translateZ(0); + pointer-events: all; +} + +#bd-modal-container { + position: absolute; + top: 0; + left: 0; + right: var(--devtools-sidebar-width,0); + bottom: 0; + background: none!important; + pointer-events: none; + z-index: 1002; +} + +.bd-modal-layer { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.bd-modal-layer { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; + min-height: 0; + padding-top: 40px; + padding-bottom: 40px; +} \ No newline at end of file diff --git a/renderer/src/styles/ui/scroller.css b/renderer/src/styles/ui/scroller.css new file mode 100644 index 00000000..de7c74db --- /dev/null +++ b/renderer/src/styles/ui/scroller.css @@ -0,0 +1,34 @@ +.bd-scroller-base { + position: relative; + box-sizing: border-box; + min-height: 0; + flex: 1 1 auto; +} + +.bd-scroller-thin { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-thin-thumb) var(--scrollbar-thin-track); +} + +.bd-scroller-thin::-webkit-scrollbar-track { + border-color: var(--scrollbar-thin-track); + background-color: var(--scrollbar-thin-track); + border: 2px solid var(--scrollbar-thin-track); +} + +.bd-scroller-thin::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +.bd-scroller-thin::-webkit-scrollbar-corner { + background-color: transparent; +} + +.bd-scroller-thin::-webkit-scrollbar-thumb { + background-clip: padding-box; + border: 2px solid transparent; + border-radius: 4px; + background-color: var(--scrollbar-thin-thumb); + min-height: 40px; +} \ No newline at end of file diff --git a/renderer/src/ui/base/button.jsx b/renderer/src/ui/base/button.jsx new file mode 100644 index 00000000..8e428cb9 --- /dev/null +++ b/renderer/src/ui/base/button.jsx @@ -0,0 +1,103 @@ +import React from "@modules/react"; +import Utilities from "@modules/utilities"; + +// S.Looks = y; +// S.Colors = I; +// S.BorderColors = O; +// S.Hovers = T; +// S.Sizes = v; + +const {useCallback} = React; + +export const Looks = Object.freeze({ + FILLED: "bd-button-filled", + OUTLINED: "bd-button-outlined", + LINK: "bd-button-link", + BLANK: "bd-button-blank" +}); + +export const Colors = Object.freeze({ + BRAND: "bd-button-color-brand", + BLURPLE: "bd-button-color-blurple", + RED: "bd-button-color-red", + GREEN: "bd-button-color-green", + YELLOW: "bd-button-color-yellow", + PRIMARY: "bd-button-color-primary", + LINK: "bd-button-color-link", + WHITE: "bd-button-color-white", + TRANSPARENT: "bd-button-color-transparent", + CUSTOM: "" +}); + + +export const Sizes = Object.freeze({ + NONE: "", + TINY: "bd-button-tiny", + SMALL: "bd-button-small", + MEDIUM: "bd-button-medium", + LARGE: "bd-button-large", + ICON: "bd-button-icon" +}); + + +export default function Button({ + className, + children, + onClick, + onKeyDown, + buttonRef, + disabled = false, + type = "button", + look = Looks.FILLED, + color = Colors.BRAND, + size = Sizes.MEDIUM, + grow = true +}) { + + const handleClick = useCallback(event => { + event.preventDefault(); + event.stopPropagation(); + onClick?.(event); + }, [onClick]); + + return ; +} + +Button.Looks = Looks; +Button.Colors = Colors; +Button.Sizes = Sizes; +// window.BDButton = Button; +// (() => { +// const buttons = []; +// for (const look in window.BDButton.Looks) { +// if (!window.BDButton.Looks[look] || look === "BLANK") continue; +// for (const color in window.BDButton.Colors) { +// if (!window.BDButton.Colors[color]) continue; +// for (const size in window.BDButton.Sizes) { +// if (!window.BDButton.Sizes[size]) continue; +// buttons.push(window.BdApi.React.createElement(window.BDButton, { +// look: window.BDButton.Looks[look], +// color: window.BDButton.Colors[color], +// size: window.BDButton.Sizes[size] +// }, "Hello World!")); +// buttons.push(window.BdApi.React.createElement("br")); +// } +// } +// } +// window.BdApi.showConfirmationModal("Buttons", buttons); +// })(); \ No newline at end of file diff --git a/renderer/src/ui/base/flex.jsx b/renderer/src/ui/base/flex.jsx new file mode 100644 index 00000000..3ef4cabc --- /dev/null +++ b/renderer/src/ui/base/flex.jsx @@ -0,0 +1,76 @@ +import React from "@modules/react"; +import Utilities from "@modules/utilities"; + + +export const Direction = Object.freeze({ + VERTICAL: "bd-flex-vertical", + HORIZONTAL: "bd-flex-horizontal", + HORIZONTAL_REVERSE: "bd-flex-reverse" +}); + +export const Justify = Object.freeze({ + START: "bd-flex-justify-start", + END: "bd-flex-justify-end", + CENTER: "bd-flex-justify-center", + BETWEEN: "bd-flex-justify-between", + AROUND: "bd-flex-justify-around" +}); + +export const Align = Object.freeze({ + START: "bd-flex-align-start", + END: "bd-flex-align-end", + CENTER: "bd-flex-align-center", + STRETCH: "bd-flex-align-stretch", + BASELINE: "bd-flex-align-baseline" +}); + +export const Wrap = Object.freeze({ + NO_WRAP: "bd-flex-no-wrap", + WRAP: "bd-flex-wrap", + WRAP_REVERSE: "bd-flex-wrap-reverse" +}); + + +export function Child(props) { + if (!props.className) props.className = ""; + props.className = Utilities.className(props.className, "bd-flex-child"); + return ; +} + + +export default function Flex({ + children, + className, + style, + shrink = 1, + grow = 1, + basis = "auto", + direction = Direction.HORIZONTAL, + align = Align.STRETCH, + justify = Justify.START, + wrap = Wrap.NO_WRAP + }) { + return
+ {children} +
; +} + +Flex.Child = Child; +Flex.Direction = Direction; +Flex.Align = Align; +Flex.Justify = Justify; +Flex.Wrap = Wrap; \ No newline at end of file diff --git a/renderer/src/ui/base/markdown.jsx b/renderer/src/ui/base/markdown.jsx new file mode 100644 index 00000000..e01902bd --- /dev/null +++ b/renderer/src/ui/base/markdown.jsx @@ -0,0 +1,35 @@ +import React from "@modules/react"; +import WebpackModules from "@modules/webpackmodules"; +import DiscordModules from "@modules/discordmodules"; + + +const DiscordMarkdown = WebpackModules.find(m => m?.prototype?.render && m.rules); +let rules = {}; +if (DiscordMarkdown) { + rules = { + ...DiscordMarkdown.rules, + link: DiscordModules.SimpleMarkdown.defaultRules.link + }; + + const originalLink = rules.link.react; + rules.link.react = function() { + const original = Reflect.apply(originalLink, undefined, arguments); + original.props.className = "bd-link"; + original.props.target = "_blank"; + original.props.rel = "noopener noreferrer"; + return original; + }; +} + + +export default function Markdown({className, children}) { + if (!DiscordMarkdown) return
{children}
; + + return + {children} + ; +} \ No newline at end of file diff --git a/renderer/src/ui/base/text.jsx b/renderer/src/ui/base/text.jsx new file mode 100644 index 00000000..38f706c2 --- /dev/null +++ b/renderer/src/ui/base/text.jsx @@ -0,0 +1,55 @@ +import React from "@modules/react"; +import Utilities from "@modules/utilities"; + + +export const Colors = Object.freeze({ + STANDARD: "bd-text-normal", + MUTED: "bd-text-muted", + ERROR: "bd-text-error", + BRAND: "bd-text-brand", + LINK: "bd-text-link", + HEADER_PRIMARY: "bd-header-primary", + HEADER_SECONDARY: "bd-header-secondary", + STATUS_YELLOW: "bd-text-yellow", + STATUS_GREEN: "bd-text-green", + STATUS_RED: "bd-text-red", + ALWAYS_WHITE: "bd-text-white", + CUSTOM: null +}); + + +export const Sizes = Object.freeze({ + SIZE_10: "bd-text-10", + SIZE_12: "bd-text-12", + SIZE_14: "bd-text-14", + SIZE_16: "bd-text-16", + SIZE_20: "bd-text-20", + SIZE_24: "bd-text-24", + SIZE_32: "bd-text-32" +}); + + +export default function Text({tag: Tag = "div", className, children, color = Colors.STANDARD, size = Sizes.SIZE_14, selectable, strong, style}) { + return + {children} + ; +} + +Text.Colors = Colors; +Text.Sizes = Sizes; + +// te = WebpackModules.getModule(m => m?.Sizes?.SIZE_32 && m.Colors) +// foo = [] +// for (const color in te.Colors) foo.push(BdApi.React.createElement(te, {color: te.Colors[color]}, color)) +// for (const size in te.Sizes) foo.push(BdApi.React.createElement(te, {size: te.Sizes[size]}, size)) +// BdApi.showConfirmationModal("Text Elements", foo) \ No newline at end of file diff --git a/renderer/src/ui/blankslates/emptyimage.jsx b/renderer/src/ui/blankslates/emptyimage.jsx index d88cd6c6..c8aa613c 100644 --- a/renderer/src/ui/blankslates/emptyimage.jsx +++ b/renderer/src/ui/blankslates/emptyimage.jsx @@ -1,13 +1,15 @@ import SimpleMarkdown from "@structs/markdown"; import React from "@modules/react"; -import DiscordClasses from "@modules/discordclasses"; +import WebpackModules from "@modules/webpackmodules"; +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 3e775eed..5e5426a2 100644 --- a/renderer/src/ui/modals.js +++ b/renderer/src/ui/modals.js @@ -7,18 +7,30 @@ import React from "@modules/react"; import ReactDOM from "@modules/reactdom"; import Strings from "@modules/strings"; import Settings from "@modules/settingsmanager"; +import Events from "@modules/emitter"; import DiscordModules from "@modules/discordmodules"; import WebpackModules from "@modules/webpackmodules"; -import DiscordClasses from "@modules/discordclasses"; import DOMManager from "@modules/dommanager"; -import AddonErrorModal from "./addonerrormodal"; +import AddonErrorModal from "./modals/addonerrormodal"; import ErrorBoundary from "./errorboundary"; +import TextElement from "./base/text"; +import ModalRoot from "./modals/root"; +import ModalHeader from "./modals/header"; +import ModalContent from "./modals/content"; +import ModalFooter from "./modals/footer"; + +import ConfirmationModal from "./modals/confirmation"; +import Button from "./base/button"; +import CustomMarkdown from "./base/markdown"; +import ChangelogModal from "./modals/changelog"; +import ModalStack, {generateKey} from "./modals/stack"; export default class Modals { static get shouldShowAddonErrors() {return Settings.get("settings", "addons", "addonErrors");} + static get hasModalOpen() {return !!document.getElementsByClassName("bd-modal").length;} static get ModalActions() { return this._ModalActions ??= { @@ -26,21 +38,11 @@ export default class Modals { closeModal: WebpackModules.getModule(m => typeof m === "function" && m?.toString().includes("onCloseCallback()"), {searchExports: true}) }; } - static get ModalStack() {return this._ModalStack ??= WebpackModules.getByProps("push", "update", "pop", "popWithKey");} - static get ModalComponents() {return this._ModalComponents ??= WebpackModules.getByProps("Header", "Footer");} - static get ModalRoot() {return this._ModalRoot ??= WebpackModules.getModule(m => m?.toString?.()?.includes("ENTERING") && m?.toString?.()?.includes("headerId"), {searchExports: true});} - static get ModalClasses() {return this._ModalClasses ??= WebpackModules.getByProps("modal", "content");} - static get FlexElements() {return this._FlexElements ??= WebpackModules.getByProps("Child", "Align");} - static get TextElement() {return this._TextElement ??= WebpackModules.getModule(m => m?.Sizes?.SIZE_32 && m.Colors);} - static get ConfirmationModal() {return this._ConfirmationModal ??= WebpackModules.getModule(m => m?.toString?.()?.includes(".confirmButtonColor"), {searchExports: true});} - static get Markdown() {return this._Markdown ??= WebpackModules.find(m => m?.prototype?.render && m.rules);} - static get Buttons() {return this._Buttons ??= WebpackModules.getModule(m => m.BorderColors, {searchExports: true});} + static get ModalQueue() {return this._ModalQueue ??= [];} - - static get hasModalOpen() {return !!document.getElementsByClassName("bd-modal").length;} static async initialize() { - const names = ["ConfirmationModal", "ModalActions", "Markdown", "ModalRoot", "ModalComponents", "Buttons", "TextElement", "FlexElements"]; + const names = ["ModalActions"]; for (const name of names) { let value = this[name]; @@ -164,8 +166,6 @@ export default class Modals { * @returns {string} - the key used for this modal */ static showConfirmationModal(title, content, options = {}) { - const Markdown = this.Markdown; - const ConfirmationModal = this.ConfirmationModal; const ModalActions = this.ModalActions; if (content instanceof FormattableString) content = content.toString(); @@ -173,7 +173,7 @@ export default class Modals { const emptyFunction = () => {}; const {onConfirm = emptyFunction, onCancel = emptyFunction, confirmText = Strings.Modals.okay, cancelText = Strings.Modals.cancel, danger = false, key = undefined} = options; - if (!this.ModalActions || !this.ConfirmationModal || !this.Markdown) { + if (!this.ModalActions) { return this.default(title, content, [ confirmText && {label: confirmText, action: onConfirm}, cancelText && {label: cancelText, action: onCancel, danger} @@ -181,9 +181,9 @@ export default class Modals { } if (!Array.isArray(content)) content = [content]; - content = content.map(c => typeof(c) === "string" ? React.createElement(Markdown, null, c) : c); + content = content.map(c => typeof(c) === "string" ? React.createElement(CustomMarkdown, null, c) : c); - const modalKey = ModalActions.openModal(props => { + const modalKey = this.openModal(props => { return React.createElement(ErrorBoundary, { onError: () => { setTimeout(() => { @@ -196,7 +196,7 @@ export default class Modals { } }, React.createElement(ConfirmationModal, Object.assign({ header: title, - confirmButtonColor: danger ? this.Buttons.Colors.RED : this.Buttons.Colors.BRAND, + danger: danger, confirmText: confirmText, cancelText: cancelText, onConfirm: onConfirm, @@ -209,87 +209,22 @@ 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(this.ModalRoot, Object.assign(props, { - size: "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(this.ModalComponents.Footer, { - className: "bd-error-modal-footer", - }, React.createElement(this.Buttons, { - onClick: props.onClose, - className: "bd-button" - }, Strings.Modals.okay)) - ] - })))); + const options = { + ref: this.addonErrorsRef, + pluginErrors: Array.isArray(pluginErrors) ? pluginErrors : [], + themeErrors: Array.isArray(themeErrors) ? themeErrors : [] + }; + this.openModal(props => { + return React.createElement(ErrorBoundary, null, React.createElement(AddonErrorModal, Object.assign(options, props))); + }); } static showChangelogModal(options = {}) { - const OriginalModalClasses = WebpackModules.getByProps("hideOnFullscreen", "root"); - const ChangelogModalClasses = WebpackModules.getModule(m => m.modal && m.maxModalWidth); - const ChangelogClasses = WebpackModules.getByProps("fixed", "improved") ?? {maxModalWidth: "490px",video: "video-8B-TdZ",container: "container-3PVapX",image: "image-ZPv20Y",title: "title-2ftWWc",lead: "lead-2VtcIe",added: "added-mQcv9V title-2ftWWc",fixed: "fixed-cTX7Hp title-2ftWWc",improved: "improved-2SJXHz title-2ftWWc",progress: "progress-1DcfFh title-2ftWWc",marginTop: "marginTop-VGmU1T",footer: "footer-1gMODG",socialLink: "socialLink-1qjJIk",premiumBanner: "premiumBanner-FU1Urp",premiumIcon: "premiumIcon-rhwgnW",date: "date-2tmzZM"}; - const TextElement = this.TextElement; - const FlexChild = this.FlexElements; - const MarkdownParser = WebpackModules.getByProps("defaultRules", "parse"); + options = Object.assign({image: "https://i.imgur.com/wuh5yMK.png", description: "", changes: [], title: "BetterDiscord", subtitle: `v${Config.version}`}, options); - if (!OriginalModalClasses || !ChangelogModalClasses || !ChangelogClasses || !TextElement || !FlexChild || !MarkdownParser) return Logger.warn("Modals", "showChangelogModal missing modules"); - - const {image = "https://i.imgur.com/wuh5yMK.png", description = "", changes = [], title = "BetterDiscord", subtitle = `v${Config.version}`, footer} = options; - const ce = React.createElement; - const changelogItems = [options.video ? ce("video", {src: options.video, poster: options.poster, controls: true, className: ChangelogClasses.video}) : ce("img", {src: image})]; - if (description) changelogItems.push(ce("p", null, MarkdownParser.parse(description))); - for (let c = 0; c < changes.length; c++) { - const entry = changes[c]; - const type = ChangelogClasses[entry.type] ? ChangelogClasses[entry.type] : ChangelogClasses.added; - const margin = c == 0 ? ChangelogClasses.marginTop : ""; - changelogItems.push(ce("h1", {className: `${type} ${margin}`,}, entry.title)); - if (entry.description) changelogItems.push(ce("p", null, MarkdownParser.parse(entry.description))); - const list = ce("ul", null, entry.items.map(i => ce("li", null, MarkdownParser.parse(i)))); - changelogItems.push(list); - } - const renderHeader = function() { - return ce(FlexChild, {className: OriginalModalClasses.header, grow: 0, shrink: 0, direction: FlexChild.Direction.VERTICAL}, - ce(TextElement, {tag: "h1", size: TextElement.Sizes.SIZE_20, strong: true}, title), - ce(TextElement, {size: TextElement.Sizes.SIZE_12, color: TextElement.Colors.STANDARD, className: ChangelogClasses.date}, subtitle) - ); - }; - - const renderFooter = () => { - const AnchorClasses = WebpackModules.getByProps("anchorUnderlineOnHover") || {anchor: "anchor-3Z-8Bb", anchorUnderlineOnHover: "anchorUnderlineOnHover-2ESHQB"}; - const joinSupportServer = (click) => { - click.preventDefault(); - click.stopPropagation(); - DiscordModules.InviteActions.acceptInviteAndTransitionToInviteChannel({inviteKey: "0Tmfo5ZbORCRqbAd"}); - }; - const supportLink = ce("a", {className: `${AnchorClasses.anchor} ${AnchorClasses.anchorUnderlineOnHover}`, onClick: joinSupportServer}, "Join our Discord Server."); - const defaultFooter = ce(TextElement, {size: TextElement.Sizes.SIZE_12, color: TextElement.Colors.STANDARD}, "Need support? ", supportLink); - return ce(FlexChild, {className: OriginalModalClasses.footer + " " + OriginalModalClasses.footerSeparator}, - ce(FlexChild.Child, {grow: 1, shrink: 1}, footer ? footer : defaultFooter) - ); - }; - - const body = ce("div", { - className: `${OriginalModalClasses.content} ${ChangelogClasses.container} ${ChangelogModalClasses.content} ${DiscordClasses.Scrollers.thin}` - }, changelogItems); - - const key = this.ModalActions.openModal(props => { - return React.createElement(ErrorBoundary, null, React.createElement(this.ModalRoot, Object.assign({ - className: `bd-changelog-modal ${OriginalModalClasses.root} ${OriginalModalClasses.small} ${ChangelogModalClasses.modal}`, - selectable: true, - onScroll: _ => _, - onClose: _ => _, - }, props), renderHeader(), body, renderFooter())); + const key = this.openModal(props => { + return React.createElement(ErrorBoundary, null, React.createElement(ChangelogModal, Object.assign(options, props))); }); return key; } @@ -315,7 +250,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 @@ -327,23 +262,35 @@ export default class Modals { } if (typeof(child) === "function") child = React.createElement(child); - const mc = this.ModalComponents; - const modal = props => { - return React.createElement(ErrorBoundary, {}, React.createElement(this.ModalRoot, Object.assign({size: mc.Sizes.MEDIUM, className: "bd-addon-modal" + " " + mc.Sizes.MEDIUM}, props), - React.createElement(mc.Header, {separator: false, className: "bd-addon-modal-header"}, - React.createElement(this.TextElement, {tag: "h1", size: this.TextElement.Sizes.SIZE_20, strong: true}, `${name} Settings`) - ), - React.createElement(mc.Content, {className: "bd-addon-modal-settings"}, - React.createElement(ErrorBoundary, {}, child) - ), - React.createElement(mc.Footer, {className: "bd-addon-modal-footer"}, - React.createElement(this.Buttons, {onClick: props.onClose, className: "bd-button"}, 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)); }); } + + + + static makeStack() { + const div = DOMManager.parseHTML(`
`); + DOMManager.bdBody.append(div); + ReactDOM.render(, div); + this.hasInitialized = true; + } + + static openModal(render, options = {}) { + if (!this.hasInitialized) this.makeStack(); + options.modalKey = generateKey(options.modalKey); + Events.emit("open-modal", render, options); + return options.modalKey; + } } + + +Modals.makeStack(); \ No newline at end of file diff --git a/renderer/src/ui/addonerrormodal.jsx b/renderer/src/ui/modals/addonerrormodal.jsx similarity index 57% rename from renderer/src/ui/addonerrormodal.jsx rename to renderer/src/ui/modals/addonerrormodal.jsx index 6164dace..9eee2ab5 100644 --- a/renderer/src/ui/addonerrormodal.jsx +++ b/renderer/src/ui/modals/addonerrormodal.jsx @@ -1,13 +1,21 @@ import React from "@modules/react"; import Strings from "@modules/strings"; -import DiscordClasses from "@modules/discordclasses"; import WebpackModules from "@modules/webpackmodules"; +import Text from "@ui/base/text"; +import Button from "@ui/base/button"; +import Flex from "@ui/base/flex"; + import Extension from "@ui/icons/extension"; import ThemeIcon from "@ui/icons/theme"; import Divider from "@ui/divider"; +import Header from "./header"; +import Content from "./content"; +import ModalRoot from "./root"; +import Footer from "./footer"; + const Parser = Object(WebpackModules.getByProps("defaultRules", "parse")).defaultRules; const {useState, useCallback, useMemo} = React; @@ -35,12 +43,12 @@ function AddonError({err, index}) { {err.type == "plugin" ? : }
-

{err.name}

-
- + {err.name} +
+ -
{err.message}
+ {err.message}
@@ -56,7 +64,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), @@ -68,17 +76,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/backdrop.jsx b/renderer/src/ui/modals/backdrop.jsx new file mode 100644 index 00000000..38befc11 --- /dev/null +++ b/renderer/src/ui/modals/backdrop.jsx @@ -0,0 +1,35 @@ +import React from "@modules/react"; +import WebpackModules from "@modules/webpackmodules"; +import Utilities from "@modules/utilities"; + +const Spring = WebpackModules.getByProps("useSpring", "animated"); + + +export default function Backdrop({isVisible, className, onClick}) { + const transition = Spring.useTransition(isVisible, { + keys: e => e ? "backdrop" : "empty", + config: {duration: 300}, + from: { + opacity: 0, + background: "var(--black-500)" + }, + enter: { + opacity: 0.85, + background: "var(--black-500)" + }, + leave: { + opacity: 0, + background: "var(--black-500)" + } + }); + + return transition((styles, visible) => { + if (!visible) return null; + + return ; + }); +} \ No newline at end of file diff --git a/renderer/src/ui/modals/changelog.jsx b/renderer/src/ui/modals/changelog.jsx new file mode 100644 index 00000000..7f4083e8 --- /dev/null +++ b/renderer/src/ui/modals/changelog.jsx @@ -0,0 +1,66 @@ +import React from "@modules/react"; +import WebpackModules from "@modules/webpackmodules"; +import DiscordModules from "@modules/discordmodules"; + +import Root from "./root"; +import Header from "./header"; +import Footer from "./footer"; +import Content from "./content"; + +import Flex from "../base/flex"; +import Text from "../base/text"; +import CloseButton from "./close"; + +import SimpleMarkdownExt from "@structs/markdown"; + +const {useMemo} = React; + + +const AnchorClasses = WebpackModules.getByProps("anchorUnderlineOnHover") || {anchor: "anchor-3Z-8Bb", anchorUnderlineOnHover: "anchorUnderlineOnHover-2ESHQB"}; +const joinSupportServer = (click) => { + click.preventDefault(); + click.stopPropagation(); + DiscordModules.InviteActions.acceptInviteAndTransitionToInviteChannel({inviteKey: "0Tmfo5ZbORCRqbAd"}); +}; + +const supportLink = Join our Discord Server.; +const defaultFooter = Need support? {supportLink}; + + +export default function ChangelogModal({transitionState, footer, title, subtitle, onClose, video, poster, image, description, changes}) { + + const ChangelogHeader = useMemo(() =>
+ + {title} + {subtitle} + + +
, [title, subtitle, onClose]); + + const ChangelogFooter = useMemo(() =>
+ + {footer ? footer : defaultFooter} + +
, [footer]); + + const changelogItems = useMemo(() => { + const items = [video ?