From 2395fddc80f86b5ed10728f2cde9cae0c8fa527e Mon Sep 17 00:00:00 2001 From: The Hedgehog Date: Mon, 18 Jul 2022 07:33:45 -0400 Subject: [PATCH] home/oldconfig: Add some more config files --- home/oldconfig.nix | 12 + .../BetterDiscord/data/stable/custom.css | 0 .../BetterDiscord/data/stable/emotes.json | 15 + oldconfig/BetterDiscord/data/stable/misc.json | 14 + .../BetterDiscord/data/stable/plugins.json | 55 + .../BetterDiscord/data/stable/settings.json | 40 + .../BetterDiscord/data/stable/themes.json | 8 + .../BetterDiscord/plugins/0BDFDB.config.json | 28 + .../BetterDiscord/plugins/0BDFDB.data.json | 5421 ++++++++++ .../BetterDiscord/plugins/0BDFDB.plugin.js | 9174 +++++++++++++++++ .../BetterDiscord/plugins/0BDFDB.raw.css | 1645 +++ .../plugins/0PluginLibrary.plugin.js | 6488 ++++++++++++ .../plugins/AccountDetailsPlus.config.json | 6 + .../plugins/AccountDetailsPlus.plugin.js | 170 + .../plugins/Animations.config.json | 82 + .../plugins/AutoIdleOnAFK.config.json | 6 + .../plugins/BDContextMenu.config.json | 6 + .../plugins/BDContextMenu.plugin.js | 157 + .../plugins/Better Media Player.config.json | 6 + .../plugins/BetterCodeblocks.config.json | 6 + .../plugins/BetterFolders.config.json | 6 + .../plugins/BetterFormattingRedux.config.json | 58 + .../plugins/BetterFriendList.config.json | 12 + .../plugins/BetterInvites.config.json | 6 + .../plugins/BetterInvites.plugin.js | 279 + .../plugins/BetterMessageLinks.config.json | 6 + .../plugins/BetterMessageLinks.plugin.js | 690 ++ .../plugins/BetterSearchPage.config.json | 8 + .../plugins/BetterSearchPage.plugin.js | 165 + .../plugins/BugReportHelper.config.json | 6 + .../plugins/CallTimeCounter.config.json | 6 + .../plugins/CharCounter.config.json | 7 + .../plugins/CharCounter.plugin.js | 237 + .../plugins/ColorTooltips.config.json | 6 + .../plugins/CompleteTimestamps.config.json | 25 + .../BetterDiscord/plugins/Copier.config.json | 6 + .../plugins/CreationDate.config.json | 14 + .../plugins/DateViewer.config.json | 6 + .../DisableStickerSuggestions.config.json | 6 + .../plugins/DoNotTrack.config.json | 6 + .../plugins/DoNotTrack.plugin.js | 121 + .../DoubleClickVoiceChannels.config.json | 6 + .../DoubleClickVoiceChannels.plugin.js | 168 + .../plugins/GoogleSearchReplace.config.json | 26 + .../plugins/HideChannels.config.json | 16 + .../plugins/HideDisabledEmojis.config.json | 6 + .../plugins/ImageUtilities.config.json | 59 + .../plugins/JoinedAtDate.config.json | 14 + .../plugins/OpenSteamLinksInApp.plugin.js | 109 + .../plugins/PermissionsViewer.config.json | 6 + .../plugins/PlatformIndicators.config.json | 6 + .../plugins/PluginRepo.config.json | 16 + .../plugins/PluginRepo.plugin.js | 1138 ++ .../plugins/PronounDB.config.json | 6 + .../plugins/ServerConfig.config.json | 6 + .../plugins/ServerDetails.config.json | 28 + .../plugins/ServerFolders.config.json | 13 + .../plugins/ServerFolders.plugin.js | 1849 ++++ .../plugins/ShowConnections.config.json | 25 + .../plugins/ShutUpClyde.config.json | 6 + .../plugins/ShutUpClyde.plugin.js | 96 + .../plugins/ThemeRepo.config.json | 16 + .../BetterDiscord/plugins/ThemeRepo.plugin.js | 1698 +++ .../plugins/ThemeSettings.plugin.js | 268 + .../plugins/TypingIndicator.config.json | 7 + .../plugins/TypingIndicator.plugin.js | 342 + .../plugins/UserDetails.config.json | 6 + .../plugins/UserDetails.plugin.js | 2864 +++++ .../plugins/ZeresPluginLibrary.config.json | 6 + .../themes/ModernChannelIndicators.theme.css | 35 + .../themes/SettingsModal.theme.css | 21 + .../themes/tokyo-night.theme.css | 172 + oldconfig/beets/config.yaml | 40 + oldconfig/beets/library.db | Bin 0 -> 45056 bytes oldconfig/beets/spotify_token.json | 1 + oldconfig/beets/state.pickle | Bin 0 -> 8938 bytes oldconfig/btop/btop.conf | 206 + 77 files changed, 34296 insertions(+) create mode 100644 oldconfig/BetterDiscord/data/stable/custom.css create mode 100644 oldconfig/BetterDiscord/data/stable/emotes.json create mode 100644 oldconfig/BetterDiscord/data/stable/misc.json create mode 100644 oldconfig/BetterDiscord/data/stable/plugins.json create mode 100644 oldconfig/BetterDiscord/data/stable/settings.json create mode 100644 oldconfig/BetterDiscord/data/stable/themes.json create mode 100644 oldconfig/BetterDiscord/plugins/0BDFDB.config.json create mode 100644 oldconfig/BetterDiscord/plugins/0BDFDB.data.json create mode 100644 oldconfig/BetterDiscord/plugins/0BDFDB.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/0BDFDB.raw.css create mode 100644 oldconfig/BetterDiscord/plugins/0PluginLibrary.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/AccountDetailsPlus.config.json create mode 100644 oldconfig/BetterDiscord/plugins/AccountDetailsPlus.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/Animations.config.json create mode 100644 oldconfig/BetterDiscord/plugins/AutoIdleOnAFK.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BDContextMenu.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BDContextMenu.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/Better Media Player.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BetterCodeblocks.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BetterFolders.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BetterFormattingRedux.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BetterFriendList.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BetterInvites.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BetterInvites.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/BetterMessageLinks.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BetterMessageLinks.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/BetterSearchPage.config.json create mode 100644 oldconfig/BetterDiscord/plugins/BetterSearchPage.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/BugReportHelper.config.json create mode 100644 oldconfig/BetterDiscord/plugins/CallTimeCounter.config.json create mode 100644 oldconfig/BetterDiscord/plugins/CharCounter.config.json create mode 100644 oldconfig/BetterDiscord/plugins/CharCounter.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/ColorTooltips.config.json create mode 100644 oldconfig/BetterDiscord/plugins/CompleteTimestamps.config.json create mode 100644 oldconfig/BetterDiscord/plugins/Copier.config.json create mode 100644 oldconfig/BetterDiscord/plugins/CreationDate.config.json create mode 100644 oldconfig/BetterDiscord/plugins/DateViewer.config.json create mode 100644 oldconfig/BetterDiscord/plugins/DisableStickerSuggestions.config.json create mode 100644 oldconfig/BetterDiscord/plugins/DoNotTrack.config.json create mode 100644 oldconfig/BetterDiscord/plugins/DoNotTrack.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/DoubleClickVoiceChannels.config.json create mode 100644 oldconfig/BetterDiscord/plugins/DoubleClickVoiceChannels.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/GoogleSearchReplace.config.json create mode 100644 oldconfig/BetterDiscord/plugins/HideChannels.config.json create mode 100644 oldconfig/BetterDiscord/plugins/HideDisabledEmojis.config.json create mode 100644 oldconfig/BetterDiscord/plugins/ImageUtilities.config.json create mode 100644 oldconfig/BetterDiscord/plugins/JoinedAtDate.config.json create mode 100644 oldconfig/BetterDiscord/plugins/OpenSteamLinksInApp.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/PermissionsViewer.config.json create mode 100644 oldconfig/BetterDiscord/plugins/PlatformIndicators.config.json create mode 100644 oldconfig/BetterDiscord/plugins/PluginRepo.config.json create mode 100644 oldconfig/BetterDiscord/plugins/PluginRepo.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/PronounDB.config.json create mode 100644 oldconfig/BetterDiscord/plugins/ServerConfig.config.json create mode 100644 oldconfig/BetterDiscord/plugins/ServerDetails.config.json create mode 100644 oldconfig/BetterDiscord/plugins/ServerFolders.config.json create mode 100644 oldconfig/BetterDiscord/plugins/ServerFolders.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/ShowConnections.config.json create mode 100644 oldconfig/BetterDiscord/plugins/ShutUpClyde.config.json create mode 100644 oldconfig/BetterDiscord/plugins/ShutUpClyde.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/ThemeRepo.config.json create mode 100644 oldconfig/BetterDiscord/plugins/ThemeRepo.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/ThemeSettings.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/TypingIndicator.config.json create mode 100644 oldconfig/BetterDiscord/plugins/TypingIndicator.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/UserDetails.config.json create mode 100644 oldconfig/BetterDiscord/plugins/UserDetails.plugin.js create mode 100644 oldconfig/BetterDiscord/plugins/ZeresPluginLibrary.config.json create mode 100644 oldconfig/BetterDiscord/themes/ModernChannelIndicators.theme.css create mode 100644 oldconfig/BetterDiscord/themes/SettingsModal.theme.css create mode 100644 oldconfig/BetterDiscord/themes/tokyo-night.theme.css create mode 100755 oldconfig/beets/config.yaml create mode 100644 oldconfig/beets/library.db create mode 100644 oldconfig/beets/spotify_token.json create mode 100644 oldconfig/beets/state.pickle create mode 100644 oldconfig/btop/btop.conf diff --git a/home/oldconfig.nix b/home/oldconfig.nix index 848fdbc..9348666 100644 --- a/home/oldconfig.nix +++ b/home/oldconfig.nix @@ -1,5 +1,17 @@ { xdg.configFile = { + "BetterDiscord" = { + source = ../oldconfig/BetterDiscord; + recursive = true; + }; + "beets" = { + source = ../oldconfig/beets; + recursive = true; + }; + "btop" = { + source = ../oldconfig/btop; + recursive = true; + }; "kak" = { source = ../oldconfig/kak; recursive = true; diff --git a/oldconfig/BetterDiscord/data/stable/custom.css b/oldconfig/BetterDiscord/data/stable/custom.css new file mode 100644 index 0000000..e69de29 diff --git a/oldconfig/BetterDiscord/data/stable/emotes.json b/oldconfig/BetterDiscord/data/stable/emotes.json new file mode 100644 index 0000000..b5a0946 --- /dev/null +++ b/oldconfig/BetterDiscord/data/stable/emotes.json @@ -0,0 +1,15 @@ +{ + "general": { + "download": true, + "emoteMenu": true, + "hideEmojiMenu": true, + "modifiers": true, + "animateOnHover": true + }, + "categories": { + "twitchglobal": true, + "twitchsubscriber": true, + "frankerfacez": true, + "bttv": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/data/stable/misc.json b/oldconfig/BetterDiscord/data/stable/misc.json new file mode 100644 index 0000000..858ea74 --- /dev/null +++ b/oldconfig/BetterDiscord/data/stable/misc.json @@ -0,0 +1,14 @@ +{ + "version": "1.5.3", + "drawerStates": { + "settings": { + "addons": false, + "editor": true, + "window": false, + "developer": false, + "general": false, + "customcss": false + } + }, + "emoteVersion": "v1.5.3" +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/data/stable/plugins.json b/oldconfig/BetterDiscord/data/stable/plugins.json new file mode 100644 index 0000000..0ccbf1f --- /dev/null +++ b/oldconfig/BetterDiscord/data/stable/plugins.json @@ -0,0 +1,55 @@ +{ + "PluginRepo": true, + "BDFDB": true, + "ThemeRepo": true, + "AccountDetailsPlus": false, + "ZeresPluginLibrary": true, + "Animations": false, + "AutoIdleOnAFK": false, + "BDContextMenu": true, + "BetterCodeblocks": false, + "BetterFolders": false, + "BetterFormattingRedux": false, + "BetterInvites": true, + "BetterMediaPlayer": false, + "BetterFriendList": false, + "BetterVolume": false, + "BetterSearchPage": true, + "BetterMessageLinks": true, + "CharCounter": true, + "CallTimeCounter": false, + "ChannelPermissions": false, + "CollapsibleUI": false, + "ColorSighted": false, + "CompleteTimestamps": false, + "ColorTooltips": false, + "Copier": false, + "CreationDate": false, + "DateViewer": false, + "DisableStickerSuggestions": false, + "discordExperiments": false, + "DoNotTrack": true, + "DoubleClickVoiceChannels": true, + "EmojiStatistics": false, + "GoogleSearchReplace": false, + "HideDisabledEmojis": false, + "ImageUtilities": false, + "JoinedAtDate": false, + "OpenSteamLinksInApp": true, + "PermissionsViewer": false, + "PlatformIndicators": false, + "PronounDB": false, + "QuickToggler": true, + "ServerCounter": false, + "ServerConfig": false, + "ServerDetails": false, + "ServerFolders": true, + "ShowConnections": false, + "ShutUpClyde": true, + "ThemeSettings": true, + "TypingIndicator": true, + "BugReportHelper": false, + "UserDetails": false, + "CumcordLoader": false, + "HideChannels": false +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/data/stable/settings.json b/oldconfig/BetterDiscord/data/stable/settings.json new file mode 100644 index 0000000..baeef05 --- /dev/null +++ b/oldconfig/BetterDiscord/data/stable/settings.json @@ -0,0 +1,40 @@ +{ + "general": { + "emotes": true, + "publicServers": false, + "voiceDisconnect": true, + "showToasts": true, + "mediaKeys": true + }, + "addons": { + "addonErrors": true, + "autoReload": true, + "editAction": "detached" + }, + "customcss": { + "customcss": true, + "liveUpdate": false, + "openAction": "settings" + }, + "editor": { + "lineNumbers": true, + "minimap": true, + "hover": true, + "quickSuggestions": true, + "fontSize": 14, + "renderWhitespace": "selection" + }, + "window": { + "transparency": false, + "removeMinimumSize": false, + "frame": false + }, + "developer": { + "debugLogs": false, + "devTools": true, + "debuggerHotkey": false, + "reactDevTools": false, + "inspectElement": false, + "devToolsWarning": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/data/stable/themes.json b/oldconfig/BetterDiscord/data/stable/themes.json new file mode 100644 index 0000000..e80ae21 --- /dev/null +++ b/oldconfig/BetterDiscord/data/stable/themes.json @@ -0,0 +1,8 @@ +{ + "Modern Channel Indicators": true, + "Pixelcord": false, + "RadialStatus": false, + "SettingsModal": true, + "Tokyo Night": true, + "Pywal-Discord": false +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/0BDFDB.config.json b/oldconfig/BetterDiscord/plugins/0BDFDB.config.json new file mode 100644 index 0000000..52c8f05 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/0BDFDB.config.json @@ -0,0 +1,28 @@ +{ + "all": { + "changeLogs": { + "BDFDB": "2.3.2", + "BetterSearchPage": "1.2.0", + "CompleteTimestamps": "1.6.1", + "CreationDate": "1.4.6", + "EmojiStatistics": "2.9.8", + "ImageUtilities": "4.7.1", + "JoinedAtDate": "1.3.3", + "OpenSteamLinksInApp": "1.1.4", + "ThemeSettings": "1.3.3" + }, + "choices": { + "toastPosition": "right" + }, + "general": { + "showToasts": true, + "showSupportBadges": true, + "useChromium": false, + "shareData": true + }, + "hashes": { + "0BDFDB.data.json": "bfb5b8a3318a63fd624e036579a5304a9d19e733", + "0BDFDB.raw.css": "96fb638350f77c79c3648050d58a0ea7a700ea1b" + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/0BDFDB.data.json b/oldconfig/BetterDiscord/plugins/0BDFDB.data.json new file mode 100644 index 0000000..081647a --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/0BDFDB.data.json @@ -0,0 +1,5421 @@ +{ + "PluginNameMap": {}, + "LibraryRequires": ["electron", "fs", "path", "process", "request"], + "DiscordObjects": { + "Channel": {"props": ["getRecipientId", "isManaged", "getGuildId"]}, + "Guild": {"props": ["getIconURL", "getMaxEmojiSlots", "getRole"]}, + "Invite": {"props": ["getExpiresAt", "isExpired"]}, + "Message": {"props": ["getReaction", "isEdited", "getChannelId"]}, + "Messages": {"props": ["jumpToMessage", "hasAfterCached", "forEach"]}, + "Relationship": {"strings": ["status", "mutualGuilds", "nickname"], "value": "Row"}, + "Timestamp": {"props": ["add", "dayOfYear", "hasAlignedHourOffset"]}, + "Upload": {"strings": ["this.item", "this.classification", "this.showLargeMessageDialog"], "value": "Upload"}, + "User": {"props": ["hasFlag", "isLocalBot", "isClaimed"]} + }, + "LibraryModules": { + "AckUtils": {"props": ["localAck", "bulkAck"]}, + "ActivityUtils": {"props": ["sendActivityInvite", "updateActivity"]}, + "APIEncodeUtils": {"props": ["stringify", "parse", "encode"]}, + "APIUtils": {"props": ["getAPIBaseURL"]}, + "AnalyticsUtils": {"props": ["isThrottled", "track"]}, + "AnimationUtils": {"props": ["spring", "decay"]}, + "ArrayUtils": {"props": ["isArrayLike", "zipObject"]}, + "AssetUtils": {"props": ["getAssetImage", "getAssetIds"]}, + "AutocompleteOptions": {"props": ["AUTOCOMPLETE_OPTIONS"]}, + "AutocompleteSentinels": {"props": ["CHANNEL_SENTINEL", "COMMAND_SENTINEL"]}, + "BadgeUtils": {"props": ["getBadgeCountString", "getBadgeWidthForValue"]}, + "BannerUtils": {"props": ["getUserBannerURLForContext"]}, + "CallUtils": {"props": ["getCalls", "isCallActive"]}, + "CategoryCollapseStore": {"props": ["getCollapsedCategories", "isCollapsed"]}, + "CategoryCollapseUtils": {"props": ["categoryCollapse", "categoryCollapseAll"]}, + "ChannelIconUtils": {"props": ["getChannelIconComponent", "getChannelIconTooltipText"]}, + "ChannelListStore": {"name": "ChannelListStore"}, + "ChannelUtils": {"props": ["selectChannel", "selectPrivateChannel"]}, + "ChannelStore": {"props": ["getChannel", "getDMFromUserId"]}, + "ChatRestrictionUtils": {"props": ["applyChatRestrictions"]}, + "ColorUtils": {"props": ["hex2int", "hex2rgb"]}, + "ConnectionProviderUtils": {"props": ["get", "isSupported", "filter"]}, + "ConnectionStore": {"props": ["getAccounts", "getLocalAccounts"]}, + "ConnectionUtils": {"props": ["setShowActivity", "setVisibility"]}, + "ContextMenuUtils": {"props": ["closeContextMenu", "openContextMenu"]}, + "CopyLinkUtils": {"props": ["SUPPORTS_COPY", "copy"]}, + "CurrentUserStore": {"props": ["getCurrentUser"]}, + "CurrentVoiceUtils": {"props": ["getAveragePing", "getChannelId"]}, + "DesktopNotificationUtils": {"props": ["showNotification", "requestPermission"]}, + "DirectMessageStore": {"props": ["getPrivateChannelIds"]}, + "DirectMessageUnreadStore": {"props": ["getUnreadPrivateChannelIds"]}, + "DirectMessageUtils": {"props": ["addRecipient", "openPrivateChannel"]}, + "DispatchApiUtils": {"props": ["dirtyDispatch", "isDispatching"]}, + "DispatchUtils": {"props": ["ComponentDispatch"]}, + "EmojiUtils": {"props": ["translateInlineEmojiToSurrogates", "translateSurrogatesToInlineEmoji"]}, + "EmojiStateUtils": {"props": ["getURL", "isEmojiDisabled"]}, + "Env": {"props": ["env"]}, + "FolderStore": {"props": ["getGuildFolderById", "getFlattenedGuilds"]}, + "FolderUtils": {"props": ["isFolderExpanded", "getExpandedFolders"]}, + "GuildBadgeUtils": {"props": ["renderUnavailableBadge", "renderMediaBadge"]}, + "GuildBoostUtils": {"props": ["getTierName", "getUserLevel"]}, + "GuildChannelKeys": {"props": ["GUILD_SELECTABLE_CHANNELS_KEY", "GUILD_VOCAL_CHANNELS_KEY"]}, + "GuildChannelStore": {"props": ["getChannels", "getDefaultChannel"]}, + "GuildEmojiStore": {"props": ["getGuildEmoji", "getDisambiguatedEmojiContext"]}, + "GuildEventStore": {"props": ["getGuildScheduledEventsForGuild", "getGuildScheduledEvent"]}, + "GuildNotificationsUtils": {"props": ["updateChannelOverrideSettings", "updateGuildNotificationSettings"]}, + "GuildSettingsUtils": {"props": ["open", "updateGuild"]}, + "GuildStore": {"props": ["getGuild", "getGuilds"]}, + "GuildUnavailableStore": {"props": ["isUnavailable", "totalUnavailableGuilds"]}, + "GuildUtils": {"props": ["selectGuild", "transitionToGuildSync"]}, + "GuildWelcomeStore": {"props": ["hasSeen", "get"]}, + "GuildWelcomeUtils": {"props": ["welcomeScreenViewed", "resetWelcomeScreen"]}, + "HistoryUtils": {"props": ["transitionTo", "replaceWith", "getHistory"]}, + "IconUtils": {"props": ["getGuildIconURL", "getGuildBannerURL"]}, + "ImageEditUtils": {"props": ["getPrimaryColorForAvatar", "getRatio"]}, + "InboxUtils": {"props": ["InboxTab", "InboxSettings"]}, + "InviteUtils": {"props": ["acceptInvite", "createInvite"]}, + "KeyCodeUtils": {"props": ["toCombo", "keyToCode"], "assign": true}, + "KeyEvents": {"props": ["aliases", "code", "codes"]}, + "LanguageStore": {"props": ["Messages", "getLanguages"]}, + "LastChannelStore": {"props": ["getLastSelectedChannelId"]}, + "LastGuildStore": {"props": ["getLastSelectedGuildId"]}, + "LinkUtils": {"props": ["handleClick", "isLinkTrusted"]}, + "LocalSettingsStore": {"props": ["darkSidebar", "keyboardModeEnabled"]}, + "LoginUtils": {"props": ["login", "logout"]}, + "MediaComponentUtils": {"props": ["renderImageComponent", "renderAudioComponent"]}, + "MediaDeviceSetUtils": {"props": ["setOutputDevice", "setInputDevice"]}, + "MediaDeviceUtils": {"props": ["getOutputDevices", "getInputDevices"]}, + "MemberCountUtils": {"props": ["getMemberCount", "getMemberCounts"]}, + "MemberStore": {"props": ["getMember", "getMembers"]}, + "MentionUtils": {"props": ["isRawMessageMentioned", "isMentioned"]}, + "MessageAuthorUtils": {"props": ["getMessageAuthor", "useNullableMessageAuthor"]}, + "MessageManageUtils": {"props": ["copyLink", "replyToMessage"]}, + "MessageParser": {"props": ["parseEmbedTitle", "defaultRules"]}, + "MessagePinUtils": {"props": ["pinMessage", "unpinMessage"]}, + "MessageReplyStore": {"props": ["getPendingReply"]}, + "MessageReplyUtils": {"props": ["createPendingReply", "deletePendingReply"]}, + "MessageStore": {"props": ["getMessage", "getMessages"]}, + "MessageUtils": {"props": ["receiveMessage", "editMessage"]}, + "ModalUtils": {"props": ["openModal", "hasModalOpen"]}, + "MutedUtils": {"props": ["isGuildOrCategoryOrChannelMuted"]}, + "NitroUtils": {"props": ["canUseIncreasedMessageLength", "canUploadAnimatedAvatar"]}, + "NoteStore": {"props": ["getNote"]}, + "NotificationSettingsStore": {"props": ["getDesktopType", "getTTSType"]}, + "NotificationSettingsUtils": {"props": ["setDesktopType", "setTTSType"]}, + "NotificationUtils": {"props": ["makeTextChatNotification", "shouldNotify"]}, + "PlatformUtils": {"props": ["isWindows", "isLinux"]}, + "PermissionRoleUtils": {"props": ["can", "ALLOW", "DENY"]}, + "PermissionUtils": {"props": ["getChannelPermissions", "can"]}, + "PreferencesContext": {"props": ["AccessibilityPreferencesContext"]}, + "QueryUtils": {"props": ["AutocompleterQuerySymbols", "AutocompleterResultTypes"]}, + "ReactionEmojiUtils": {"props": ["getReactionEmojiName", "getReactionEmojiName"]}, + "ReactionUtils": {"props": ["addReaction", "removeReaction"]}, + "RecentMentionUtils": {"props": ["deleteRecentMention", "fetchRecentMentions"]}, + "RelationshipStore": {"props": ["getFriendIDs", "getRelationships"]}, + "RelationshipSuggestionUtils": {"props": ["getSuggestionCount", "getSuggestions"]}, + "RelationshipUtils": {"props": ["addRelationship", "removeRelationship"]}, + "FriendUtils": {"props": ["getFriendIDs", "getRelationships"]}, + "RoleIconUtils": {"props": ["getRoleIconData"]}, + "SearchPageUtils": {"props": ["searchNextPage", "searchPreviousPage"]}, + "SettingsStore": {"props": ["guildPositions", "theme"]}, + "SettingsUtils": {"props": ["ShowCurrentGame", "DeveloperMode"]}, + "SettingsUtilsOld": {"props": ["updateLocalSettings", "updateRemoteSettings"]}, + "SimpleMarkdownComponents": {"strings": ["customEmoji", "emojiTooltipPosition", "timestampTooltip"]}, + "SimpleMarkdownParser": {"props": ["parseBlock", "parseInline", "defaultOutput"]}, + "SlateDraftUtils": {"props": ["getRecentlyEditedDrafts", "getDraft"]}, + "SlateRichUtils": {"props": ["toRichValue", "createEmptyState"]}, + "SlateTextUtils": {"props": ["toTextValue", "serializeDescendant"]}, + "SlowmodeUtils": {"props": ["getSlowmodeCooldownGuess"]}, + "SoundParser": {"strings": ["discodo", "ddr-down", "mute"]}, + "SoundStateUtils": {"props": ["isSoundDisabled", "getDisabledSounds"]}, + "SoundUtils": {"props": ["playSound", "createSound"]}, + "SpellCheckStore": {"strings": ["SPELLCHECK_LEARN_WORD", "isEnabled"], "value": "default"}, + "SpotifyTrackUtils": {"props": ["hasConnectedAccount", "getLastPlayedTrackId"]}, + "SpotifyUtils": {"props": ["setActiveDevice", "pause"]}, + "StageChannelLiveStore": {"props": ["getAllLiveStageChannels", "useAllLiveStageChannels"]}, + "StageChannelStore": {"props": ["getStageInstanceByChannel", "getAllStageInstances"]}, + "StageChannelUtils": {"props": ["getMutableParticipants", "getParticipantCount"]}, + "StateStoreUtils": {"props": ["useStateFromStores", "useStateFromStoresArray"]}, + "StatusMetaUtils": {"props": ["getApplicationActivity", "getStatus", "getState"]}, + "StoreChangeUtils": {"props": ["get", "set", "clear", "remove"]}, + "StreamerModeStore": {"strings": ["StreamerModeStore", "hidePersonalInformation", "disableSounds"], "value": "default"}, + "StreamUtils": {"props": ["getActiveStreamForUser", "getAllApplicationStreams"]}, + "StringUtils": {"props": ["cssValueToNumber", "upperCaseFirstChar"]}, + "TimestampUtils": {"props": ["fromTimestamp", "extractTimestamp"]}, + "TimeUtils": {"props": ["calendarFormat", "dateFormat"]}, + "ThreadStore": {"props": ["isActive", "getThreadsForGuild"]}, + "UnreadGuildUtils": {"props": ["hasUnread", "getTotalMentionCount"]}, + "UnreadChannelUtils": {"props": ["getUnreadCount", "getOldestUnreadMessageId"]}, + "UnreadStateTypes": {"props": ["ReadStateTypes"], "value": "ReadStateTypes"}, + "UploadUtils": {"props": ["upload", "instantBatchUpload"]}, + "URLParser": {"props": ["parse", "resolveObject"]}, + "UserBadgeKeys": {"props": ["BadgeKeys"], "value": "BadgeKeys"}, + "UserBioParser": {"props": ["parseBioReact"]}, + "UserFetchUtils": {"props": ["fetchCurrentUser", "getUser"]}, + "UserNameUtils": {"props": ["getName", "getNickname"]}, + "UserProfileModalUtils": {"props": ["openUserProfileModal", "closeUserProfileModal"]}, + "UserProfileUtils": {"props": ["fetchMutualFriends", "fetchProfile"]}, + "UserSettingsUtils": {"props": ["open", "updateAccount"]}, + "UserStore": {"props": ["getUser", "getUsers"]}, + "Utilities": {"props": ["flatMap", "cloneDeep"]}, + "VoiceChannelUtils": {"props": ["isFullscreenInContext", "getParticipants"]}, + "VoiceUtils": {"props": ["getAllVoiceStates", "getVoiceStatesForChannel"]}, + "WindowUtils": {"props": ["minimize", "maximize", "close"]}, + "ZoomUtils": {"props": ["setZoom", "setFontSize"]} + }, + "ModuleUtilsConfig": { + "QueuedComponents": [ + "GuildHeaderContextMenu", + "SystemMessageOptionContextMenu", + "SystemMessageOptionToolbar", + "MessageOptionContextMenu", + "MessageOptionToolbar" + ], + "ContextMenuTypes": [ + "UserSettingsCog", + "UserProfileActions", + "Event", + "GroupDMUser", + "GroupDM", + "User", + "Developer", + "Slate", + "GuildSettingsRole", + "GuildDirectoryEntry", + "GuildFolder", + "SystemMessage", + "Message", + "Native", + "Role", + "Guild", + "Channel" + ], + "ContextMenuTypesMap": { + "GroupDMUserContextMenu": "UserContextMenu", + "GroupDMContextMenu": "ChannelContextMenu" + }, + "ContextMenuSubItemsMap": { + "ChannelContextMenu": { + "keys": ["channel"], + "items": ["useChannelLeaveItem", "useChannelDeleteItem", "useChannelFavoriteSetNickname", "useChannelGoToOriginalGuildItem", "useChannelCloneItem", "useChannelCopyLinkItem", "useChannelEditItem", "useChannelMarkAsReadItem"] + }, + "UserContextMenu": { + "keys": ["user", "channel"], + "items": ["useHideNoVideoParticipantsItem", "useHideSelfVideoItem", "usePreviewVideoItem", "useChangeIdentityItem", "useMoveToAudienceItem", "useAddFriendNicknameItem", "useAddNoteItem", "useBlockUserItem", "useUserRelationshipItems", "useUserManagementItems", "useMoveUserVoiceItems", "useCallUserItem", "useFocusVideoItem", "useInviteUserToGuildItems", "useMentionUserItem", "useMessageUserItem", "useUserProfileItem", "useUserRolesItems", "useUserVolumeItem", "useWatchStreamItem", "useCloseDMItem", "useMuteChannelItem"] + } + }, + "PatchTypes": [ + "before", + "instead", + "after" + ], + "InstanceFunctions": [ + "render", + "componentDidMount", + "componentDidUpdate", + "componentWillUnmount" + ], + "PatchMap": { + "AuditLogs": "GuildSettingsAuditLog", + "BannedCard": "BannedUser", + "ChannelWindow": "Channel", + "InvitationCard": "InviteRow", + "InviteCard": "InviteRow", + "MemberCard": "Member", + "PopoutContainer": "Popout", + "QuickSwitchResult": "Result" + }, + "Finder": { + "useMuteChannelItem": {"strings": ["DM", "MenuItem", "Messages.MUTE_CHANNEL"], "lazyLoaded": true}, + "useUserManagementItems": {"strings": ["canManageUser", "MenuItem", "Messages.BAN_USER"], "lazyLoaded": true}, + "useUserRelationshipItems": {"strings": ["ContextMenu", "isFriend", "addRelationship", "Messages.REMOVE_FRIEND"], "lazyLoaded": true}, + "useInviteItem": {"strings": ["CREATE_INSTANT_INVITE", "invite-people"], "lazyLoaded": true}, + "Account": {"class": "accountinfo"}, + "App": {"class": "app"}, + "AppSkeleton": {"class": "app"}, + "AppView": {"strings": ["darkSidebar", "guilds", "GUILD_CHANNEL", "GUILD_DISCOVERY"]}, + "AuditLogs": {"class": "auditlog"}, + "AuthWrapper": {"class": "loginscreen"}, + "Avatar": {"props": ["AnimatedAvatar"]}, + "BannedCard": {"class": "guildsettingsbannedcard"}, + "Category": {"class": "categorycontainerdefault"}, + "ChannelCall": {"class": "callcurrentcontainer"}, + "ChannelCategoryItem": {"strings": ["GUILD_CATEGORY", "CREATE_CHANNEL", "addButtonIcon"], "path": "default.DecoratedComponent"}, + "ChannelMember": {"class": "member"}, + "ChannelMembers": {"class": "members"}, + "Channels": {"class": "guildchannels"}, + "ChannelTextAreaForm": {"class": "chatform"}, + "ChannelWindow": {"class": "chatcontent"}, + "ChatMessage": {"strings": ["childrenMessageContent", "childrenRepliedMessage", "message.id"]}, + "CircleIconButton": {"strings": ["className", ".default.circleIconButton"]}, + "CustomStatusModal": {"class": "customstatusmodal"}, + "DirectMessage": {"class": "guildouter", "forceObserve": true}, + "EmojiPicker": {"strings": ["EMOJI_PICKER_TAB_PANEL_ID", "diversitySelector"]}, + "FocusRing": {"props": ["FocusRingScope"]}, + "GuildFavorites": {"strings": [".favoriteIcon", "FAVORITES_GUILD_NAME"]}, + "GuildFolderSettingsModal": {"lazyLoaded": true, "exported": true}, + "GuildHeader": {"strings": ["bannerVisible", "guildBanner", "onContextMenu"]}, + "GuildIcon": {"class": "avataricon", "forceObserve": true}, + "GuildItem": {"strings": ["renderUnavailableBadge", "guildNode", "lowerBadgeWidth"]}, + "GuildRoleSettings": {"class": "settingswindowcontentregion"}, + "Guilds": {"subComponent": {"type": "type", "children": true, "strings": ["guildsnav", "ListNavigatorProvider"]}}, + "GuildSettings": {"class": "layer"}, + "GuildSettingsBans": {"class": "guildsettingsbannedcard"}, + "GuildSettingsEmoji": {"class": "guildsettingsemojicard"}, + "GuildSettingsMembers": {"class": "guildsettingsmembercard"}, + "GuildSidebar": {"class": "guildchannels"}, + "HomeButton": {"subComponent": {"type": "HomeButton", "strings": ["showDMsOnly", "DefaultHomeButton"]}}, + "I18nLoaderWrapper": {"class": "app"}, + "InboxButton": {"strings": ["inbox-button", "Messages.INBOX"]}, + "InstantInviteModal": {"class": "invitemodalwrapper"}, + "InvitationCard": {"class": "invitemodalinviterow"}, + "InviteGuildName": {"props": ["GuildName", "GuildTemplateName"]}, + "InviteCard": {"class": "guildsettingsinvitecard"}, + "MemberCard": {"class": "guildsettingsmembercard"}, + "MemberListItem": {"class": "member"}, + "MemberRoles": {"props": ["MemberRole"]}, + "Message": {"strings": ["childrenMessageContent", "childrenRepliedMessage", "zalgo"]}, + "MessageHeader": {"strings": ["ANIMATE_CHAT_AVATAR", "showUsernamePopout"]}, + "MessageReply": {"strings": [".referencedMessage", ".useClickReferencedMessageAuthorUsername"]}, + "Messages": {"strings": ["group-spacing-", "canManageMessages"]}, + "MessageToolbar": {"strings": ["renderReactions", "canAddNewReactions", "showMoreUtilities"]}, + "MessageUsername": {"strings": [".default.username", "colorString", "compact"]}, + "ModalLayer": {"class": "modal"}, + "MutualFriends": {"lazyLoaded": true}, + "NicknameSection": {"lazyLoaded": true}, + "Note": {"class": "usernotetextarea"}, + "PeoplePageList": {"strings": ["FriendsSections", "emptyStateContainer"]}, + "PopoutContainer": {"class": "popout"}, + "PrivateChannelCall": {"class": "callcurrentcontainer"}, + "PrivateChannelCallParticipants": {"class": "callcurrentcontainer"}, + "PrivateChannelRecipientsInvitePopout": {"class": "searchpopoutdmaddpopout"}, + "PrivateChannelsList": {"class": "dmchannelsscroller"}, + "QuickSwitchChannelResult": {"class": "quickswitchresult"}, + "QuickSwitchGuildResult": {"class": "quickswitchresult"}, + "QuickSwitchResult": {"class": "quickswitchresult"}, + "Reaction": {"class": "messagereactionme"}, + "Reactor": {"class": "messagereactionsmodalreactor"}, + "ReactorsComponent": {"class": "messagereactionsmodalreactor"}, + "RecentsHeader": {"strings": ["expanded", "CompactRecentsHeader"]}, + "RichChannelMention": {"props": ["ChannelMention"]}, + "RichUserMention": {"props": ["UserMention"]}, + "RTCConnection": {"class": "voicedetails"}, + "SearchBar": {"props": ["SearchIcon"], "path": "default.prototype"}, + "SearchResults": {"class": "searchresultswrap"}, + "SearchResultsInner": {"strings": ["SEARCH_HIDE_BLOCKED_MESSAGES", "totalResults", "SEARCH_PAGE_SIZE"]}, + "SettingsView": {"lazyLoaded": true, "exported": true}, + "StandardSidebarView": {"class": "settingswindowstandardsidebarview"}, + "ThreadCard": {"strings": ["threadId", "gotoThread", "container"]}, + "ThreadSidebar": {"strings": ["channelId", "collectThreadMetadata", "SIDEBAR"]}, + "TypingUsers": {"class": "typing"}, + "UnavailableGuildsButton": {"strings": ["className", ".default.guildsError"]}, + "Upload": {"class": "uploadmodal"}, + "UserHook": {"class": "auditloguserhook"}, + "UserMention": {"strings": ["inlinePreview", "getAvatarURL", "userId", "default.getName"]}, + "UserPopoutAvatar": {"props": ["UserPopoutAvatar"]}, + "UserProfileModal": {"lazyLoaded": true}, + "UserProfileModalHeader": {"lazyLoaded": true}, + "UserSettingsAppearance": {"class": "usersettingsappearancepreview"} + }, + "LoadedInComponents": { + "AutocompleteChannelResult": "LibraryComponents.AutocompleteItems.Channel", + "AutocompleteUserResult": "LibraryComponents.AutocompleteItems.User", + "QuickSwitchChannelResult": "LibraryComponents.QuickSwitchItems.Channel", + "QuickSwitchGroupDMResult": "LibraryComponents.QuickSwitchItems.GroupDM", + "QuickSwitchGuildResult": "LibraryComponents.QuickSwitchItems.Guild", + "QuickSwitchUserResult": "LibraryComponents.QuickSwitchItems.User" + } + }, + "ForceLoadedComponents": {}, + "NativeSubComponents": { + "Button": {"props": ["Colors", "Hovers", "Looks"]}, + "Checkbox": {"name": "Checkbox"}, + "Clickable": {"name": "Clickable"}, + "KeybindRecorder": {"name": "KeybindRecorder"}, + "MenuCheckboxItem": {"name": "MenuCheckboxItem"}, + "MenuControlItem": {"name": "MenuControlItem"}, + "MenuItem": {"name": "MenuItem"}, + "PopoutContainer": {"name": "Popout"}, + "QuickSelect": {"name": "QuickSelectWrapper"}, + "RadioGroup": {"name": "RadioGroup"}, + "SearchBar": {"name": "SearchBar", "protos": ["focus", "blur"]}, + "SearchableSelect": {"name": "SingleSelect"}, + "Slider": {"name": "Slider"}, + "Switch": {"name": "Switch"}, + "TabBar": {"name": "TabBar"}, + "Table": {"name": "Table"}, + "TextArea": {"name": "TextArea"}, + "TextInput": {"name": "TextInput"}, + "TooltipContainer": {"name": "Tooltip"} + }, + "LibraryComponents": { + "Anchor": {"name": "Anchor"}, + "Animations": {"props": ["Controller", "Spring"], "assign": true}, + "AppReferencePositionLayer": {"name": "AppReferencePositionLayer"}, + "AutocompleteItems": {"props": ["Generic", "User", "Command"]}, + "AutocompleteMenu": {"name": "Autocomplete"}, + "AvatarComponents": {"props": ["AnimatedAvatar"]}, + "Badges": {"props": ["IconBadge", "NumberBadge"], "assign": true}, + "ChannelTextAreaTypes": {"props": ["ChatInputTypes"], "value": "ChatInputTypes"}, + "Checkmark": {"name": "Checkmark"}, + "Connectors": {"props": ["Router", "Link"], "assign": true}, + "DiscordTag": {"name": "DiscordTag"}, + "Emoji": {"strings": ["emojiName", "shouldAnimate", "jumboable"], "value": "default"}, + "EmojiButton": {"name": "EmojiButton"}, + "EmojiPicker": {"strings": ["EMOJI_PICKER_TAB_PANEL_ID", "diversitySelector"]}, + "Flex": {"props": ["Wrap", "Direction", "Child"]}, + "FlowerStar": {"name": "FlowerStar"}, + "FocusRingScope": {"props": ["FocusRingScope"], "value": "default"}, + "FormComponents": {"props": ["FormSection", "FormText"], "assign": true}, + "FriendsEmptyState": {"strings": ["FriendsEmptyState", "FriendsSections"], "value": "default"}, + "GuildComponents": { + "children": { + "Badge": {"name": "GuildBadge"}, + "BlobMask": {"name": "BlobMask"}, + "DragPlaceholder": {"name": "DragPlaceholder"}, + "Favorites": {"strings": [".favoriteIcon", "FAVORITES_GUILD_NAME"]}, + "Icon": {"name": "GuildIconWrapper"}, + "MutedText": {"props": ["useMutedUntilText"], "value": "default"}, + "Pill": {"strings": ["opacity:1,height:", "20:8", "default.item"]}, + "Separator": {"strings": ["className", "default.guildSeparator"]}, + "UnavailableGuildsButton": {"strings": ["className", "default.guildsError"]} + } + }, + "Header": {"props": ["Sizes", "Tags"]}, + "HeaderBarComponents": {"name": "HeaderBarContainer"}, + "Image": {"props": ["ImageReadyStates"]}, + "ImageModal": {"name": "ImageModal"}, + "LazyImage": {"name": "LazyImage"}, + "ListHeader": {"name": "ListSectionItem"}, + "Mask": {"name": "Mask"}, + "Menu": {"name": "Menu"}, + "MenuItems": {"props": ["MenuItem", "MenuGroup"], "assign": true, + "children": { + "Colors": {"props": ["MenuItemColor"], "value": "MenuItemColor"} + } + }, + "MessageGroup": {"name": "ChannelMessage"}, + "MessagesPopoutComponents": {"props": ["Header", "EmptyStateBottom"]}, + "ModalComponents": {"props": ["ModalContent", "ModalFooter"], "assign": true}, + "NavItem": {"name": "NavItem"}, + "Paginator": {"name": "Paginator"}, + "PanelButton": {"name": "PanelButton"}, + "PopoutCSSAnimator": {"name": "PopoutCSSAnimator"}, + "PopoutFocusLock": {"strings": ["useFocusLock", "useImperativeHandle"], "value": "default"}, + "PrivateChannelItems": {"props": ["DirectMessage", "GroupDM"]}, + "QuickSwitchItems": {"props": ["Channel", "GroupDM", "Header"]}, + "Scrollers": { + "children": { + "Auto": {"props": ["AdvancedScrollerThin", "AdvancedScrollerAuto"], "value": "AdvancedScrollerAuto"}, + "None": {"props": ["AdvancedScrollerThin", "AdvancedScrollerAuto"], "value": "AdvancedScrollerNone"}, + "Thin": {"props": ["AdvancedScrollerThin", "AdvancedScrollerAuto"], "value": "AdvancedScrollerThin"} + } + }, + "SliderMarkerPositions": {"props": ["MarkerPositions"], "value": "MarkerPositions"}, + "Spinner": {"name": "Spinner"}, + "Status": {"name": "Status"}, + "StatusPickerPopout": {"strings": ["\"StatusPickerPopout\""], "value": "default"}, + "TextElement": {"props": ["Colors", "Sizes"]}, + "UserBadgeKeys": {"props": ["BadgeKeys"], "value": "BadgeKeys"}, + "UserBadges": {"props": ["BadgeSizes"]}, + "UserPopout": {"name": "UserPopoutContainer"}, + "UserSummaryItem": {"name": "UserSummaryItem"}, + "VideoForwardRef": {"strings": ["displayName=\"Video\"", "\"video\"", "HTMLImageElement"], "value": "default"}, + "VoiceSettingsConstants": {"props": ["MediaEngineContextTypes", "DEFAULT_VOLUME"]}, + "VolumeUtils": {"props": ["amplitudeToPerceptual", "perceptualToAmplitude"]} + }, + "SvgIcons": { + "ACTIVITY": { + "defaultProps": { + "width": 16, + "height": 16 + }, + "icon": "" + }, + "ACTIVITY_DISABLED": { + "defaultProps": { + "width": 16, + "height": 16, + "foreground": 16 + }, + "icon": "" + }, + "ARROW_DOWN": { + "defaultProps": { + "width": 18, + "height": 18 + }, + "icon": "" + }, + "ARROW_UP": { + "defaultProps": { + "width": 18, + "height": 18 + }, + "icon": "" + }, + "BOOST": { + "defaultProps": { + "width": 24, + "height": 24, + "foreground": "" + }, + "icon": "" + }, + "CALENDAR": { + "icon": "" + }, + "CHANGELOG": { + "icon": "" + }, + "CHECKBOX": { + "defaultProps": { + "background": "", + "foreground": "" + }, + "icon": "" + }, + "CHECKBOX_EMPTY": { + "defaultProps": { + "foreground": "" + }, + "icon": "" + }, + "CHECKMARK": { + "defaultProps": { + "width": 18, + "height": 18 + }, + "icon": "" + }, + "CHECKMARK_CIRCLE": { + "icon": "" + }, + "CLOCK": { + "icon": "" + }, + "CLOSE": { + "defaultProps": { + "width": 12, + "height": 12 + }, + "icon": "" + }, + "CLOSE_CIRCLE": { + "icon": "" + }, + "COG": { + "icon": "" + }, + "CROWN": { + "icon": "" + }, + "DOWNLOAD": { + "defaultProps": { + "width": 16, + "height": 16 + }, + "icon": "" + }, + "DROPPER": { + "defaultProps": { + "width": 16, + "height": 16, + "foreground": "" + }, + "icon": "" + }, + "EYE": { + "icon": "" + }, + "FAVORITE": { + "icon": "" + }, + "FAVORITE_FILLED": { + "icon": "" + }, + "FOLDER": { + "icon": "" + }, + "GAMEPAD": { + "icon": "" + }, + "GAMEPAD_DISABLED": { + "defaultProps": { + "foreground": "" + }, + "icon": "" + }, + "GITHUB": { + "icon": "" + }, + "GLOBE": { + "defaultProps": { + "width": 20, + "height": 20 + }, + "icon": "" + }, + "GRADIENT": { + "defaultProps": { + "width": 36, + "height": 36 + }, + "icon": "" + }, + "HEART": { + "defaultProps": { + "width": 16, + "height": 16 + }, + "icon": "" + }, + "INFO": { + "icon": "" + }, + "LEFT_CARET": { + "icon": "" + }, + "LEFT_DOUBLE_CARET": { + "icon": "" + }, + "LOCK_CLOSED": { + "icon": "" + }, + "LOCK_OPEN": { + "icon": "" + }, + "MENU_CARET": { + "getClassName": { + "": ["menucaretarrow"], + "props.open": ["menucaretopen"] + }, + "icon": "" + }, + "METAMASK": { + "icon": "" + }, + "MORE": { + "icon": "" + }, + "NOVA_AT": { + "icon": "" + }, + "NOVA_PIN": { + "icon": "" + }, + "NOVA_TRASH": { + "icon": "" + }, + "OPEN_EXTERNAL": { + "icon": "" + }, + "OVERLAY": { + "icon": "" + }, + "OVERLAY_DISABLED": { + "icon": "" + }, + "PATREON": { + "icon": "" + }, + "PAYPAL": { + "icon": "" + }, + "PENCIL": { + "defaultProps": { + "width": 16, + "height": 16 + }, + "icon": "" + }, + "PHANTOM": { + "icon": "" + }, + "PIN": { + "defaultProps": { + "width": 16, + "height": 16 + }, + "icon": "" + }, + "PODIUM": { + "icon": "" + }, + "QUESTIONMARK": { + "icon": "" + }, + "QUESTIONMARK_ACTIVITY": { + "defaultProps": { + "width": 40, + "height": 40 + }, + "icon": "" + }, + "QUOTE": { + "icon": "" + }, + "RAW_TEXT": { + "icon": "" + }, + "RIGHT_CARET": { + "icon": "" + }, + "RIGHT_DOUBLE_CARET": { + "icon": "" + }, + "SEARCH": { + "defaultProps": { + "width": 18, + "height": 18 + }, + "icon": "" + }, + "SPEAKER": { + "icon": "" + }, + "STREAM": { + "icon": "" + }, + "TRASH": { + "icon": "" + }, + "WARNING": { + "icon": "" + } + }, + "CustomClassModules": { + "BDFDB": { + "BDFDBundefined": "BDFDB_undefined", + "avatarDisabled": "disabled-6G33EE", + "badge": "badge-7R_W3s", + "badgeAvatar": "avatar-hF52Er", + "bdControlsCustom": "custom-L9FFs5", + "bdRepoEntry": "entry-9JnAPs", + "bdRepoFooterControls": "controls-p0SrvV", + "bdRepoHeaderControls": "controls-18FQsW", + "bdRepoListHeader": "repoHeader-2KfNvH", + "bdRepoListWrapper": "repoList-9JnAPs", + "cardDisabled": "cardDisabled-wnh5ZW", + "cardHorizontal": "horizontal-0ffRsT", + "cardInner": "inner-OP_8zd", + "cardWrapper": "card-rT4Wbb", + "charCounter": "counter-uAzbKp", + "changeLogModal": "changeLogModal-ny_dHC", + "collapseContainer": "container-fAVkOf", + "collapseContainerCollapsed": "collapsed-2BUBZm", + "collapseContainerHeader": "header-2s6x-5", + "collapseContainerInner": "inner-TkGytd", + "collapseContainerMini": "container-fAVkOf containerMini-_k6Rts", + "collapseContainerTitle": "title-ROsJi-", + "colorPicker": "colorPicker-h5sF8g", + "colorPickerAlpha": "alpha-VcPGeR", + "colorPickerAlphaCheckered": "alpha-checkered", + "colorPickerAlphaCursor": "alpha-cursor", + "colorPickerAlphaHorizontal": "alpha-horizontal", + "colorPickerGradient": "gradient-TJOYTr", + "colorPickerGradientCheckered": "gradient-checkered", + "colorPickerGradientCursor": "gradient-cursor", + "colorPickerGradientCursorEdge": "gradient-cursor-edge", + "colorPickerGradientCursorSelected": "gradient-cursor-selected", + "colorPickerGradientHorizontal": "gradient-horizontal", + "colorPickerGradientButton": "gradientButton-eBBuwD", + "colorPickerGradientButtonEnabled": "enabled-MypHME", + "colorPickerSwatches": "swatches-QxZw_N", + "colorPickerSwatchesDisabled": "disabled-2JgNxl", + "colorPickerSwatchSelected": "selected-f5IVXN", + "colorPickerSwatchSingle": "single-Fbb1wB", + "colorPickerSwatchSingleWrapper": "swatch-7FsRaa", + "confirmModal": "confirmModal-t-WDWJ", + "cursorPointer": "cursorPointer-B3uwDA", + "dateInputButton": "dateInputButton-jTGUJg", + "dateInputButtonSelected": "selected-8F23Ra", + "dateInputControls": "dateInputControls-cgfPf9", + "dateInputField": "dateInputField-2vhGP1", + "dateInputInner": "dateInputInner-ORXFwT", + "dateInputPreview": "dateInputPreview-lG5sMM", + "dateInputPreviewPrefix": "dateInputPreviewPrefix-6Fww21", + "dateInputPreviewSuffix": "dateInputPreviewSuffix-f4Sr32", + "dateInputWrapper": "dateInputWrapper-6tQOYp", + "dev": "dev-A7f2Rx", + "discoveryCard": "card-x5zW6z", + "discoveryCardAuthor": "author-d2JIcl", + "discoveryCardButton": "button-coQXfM", + "discoveryCardControls": "controls-T0w-Wc", + "discoveryCardCover": "cover-qyY86I", + "discoveryCardCoverBadge": "coverBadge-I41ZIY", + "discoveryCardCoverWrapper": "coverWrapper-J-mDGJ", + "discoveryCardDescription": "description-zXiu5E", + "discoveryCardFooter": "footer-C1KpS6", + "discoveryCardHeader": "header-4hHJgv", + "discoveryCardIcon": "icon-0jmVrJ", + "discoveryCardIconLoading": "loading-f8Gs22", + "discoveryCardIconWrapper": "iconWrapper-eK7GO6", + "discoveryCardInfo": "info-xw-o76", + "discoveryCardName": "name-OSUjF9", + "discoveryCards": "list-QuW8QR", + "discoveryCardStat": "stat-eRknnn", + "discoveryCardStatIcon": "statIcon-o40EX1", + "discoveryCardStats": "stats-Pc5tYW", + "discoveryCardTag": "tag-PbPfwP", + "discoveryCardTags": "tags-9KJ-1X", + "discoveryCardTitle": "title-SSzExd", + "discoveryCardTitleButton": "button-SxdSzE", + "favButtonContainer": "favbutton-8Fzu45", + "guild": "guild-r3yAE_", + "guildLowerLeftBadge": "lowerLeftBadge-zr4T_9", + "guildsLabel": "label-2wRs_g", + "guildSummaryClickableIcon": "clickableIcon-7I6aVc", + "guildSummaryContainer": "container-5VyO4t", + "guildSummaryEmptyGuild": "emptyGuild-Am9XfC", + "guildSummaryIcon": "icon-r6DlKo", + "guildSummaryIconContainer": "iconContainer-IBAtWs", + "guildSummaryIconContainerMasked": "iconContainerMasked-G-akdf iconContainer-IBAtWs", + "guildSummaryMoreGuilds": "moreGuilds-c5JVlC", + "guildSummarySvgIcon": "icon-5TsFrr", + "guildUpperLeftBadge": "upperLeftBadge-e35IpL", + "guildVoiceList": "guildVoiceList-9ads4k", + "hasBadge": "hasBadge-4rT8_u", + "hotkeyResetButton": "resetButton-hI9Ax7", + "hotkeyWrapper": "recorder-can0vx", + "inputNumberButton": "button-J9muv5", + "inputNumberButtonDown": "down-cOY7Qp button-J9muv5", + "inputNumberButtonUp": "up-mUs_72 button-J9muv5", + "inputNumberButtons": "buttons-our3p-", + "inputNumberWrapper": "numberInputWrapper-j4svZS", + "inputNumberWrapperDefault": "numberInputWrapperDefault-gRxcuK numberInputWrapper-j4svZS", + "inputNumberWrapperMini": "numberInputWrapperMini-wtUU31 numberInputWrapper-j4svZS", + "layerContainerZIndexDisabled": "zIndexDisabled-Pf4Txx", + "listInput": "listInput-11g5Sr", + "listInputDelete": "delete-M_nPTt", + "listInputItem": "item-wGC8aX", + "listInputItems": "items-D9PGwH", + "listRow": "listRow-7SfZww", + "loadingIcon": "loadingIcon-cOYMPl", + "loadingIconWrapper": "loadingIconWrapper-PsVJ9m", + "overflowEllipsis": "ellipsis-qlo9sA", + "pagination": "pagination-09Sd5R", + "paginationBottom": "bottom-jTb32i", + "paginationList": "list-PIKebU", + "paginationListAlphabet": "alphabet-2ANo0x", + "paginationListAlphabetChar": "alphabetChar-bq-8Go", + "paginationListAlphabetCharDisabled": "disabled-XmhCq2", + "paginationListContent": "listContent-aG3Fq8", + "paginationListMini": "mini-GMiniS", + "paginationMini": "mini-hODxXf", + "paginationTop": "top-v-18jZ", + "popoutArrow": "popoutArrow-g8f4Ss", + "popoutArrowBottom": "popoutArrowBottom-r5Tzui", + "popoutArrowTop": "popoutArrowTop-lK9F3a", + "popoutWrapper": "popout-xwjvsX", + "quickSelectWrapper": "quickSelectWrapper-UCfTKz", + "marginLeft4": "marginLeft4-58StzA", + "marginLeft8": "marginLeft8-3RhhAa", + "menuColorCustom": "colorCustom-44asd2", + "menuItemHint": "hint-BK71lM", + "modalHeaderShade": "shade-h6F4sT", + "modalHeaderHasSibling": "hasSiblings-fRyjyl", + "modalNoScroller": "noScroller-YgPpF3", + "modalSidebar": "sidebar-_0OpfR", + "modalTabContent": "tabContent-nZ-1U5", + "modalTabContentOpen": "open-yICTYu", + "modalSubInner": "inner-t84Frz", + "modalTextContent": "text-8fSrts", + "modalWrapper": "modal-6GHvdM", + "multiInput": "multiInput-Ft9zQo", + "multiInputField": "multiInputField-GfMBpr", + "multiInputFirst": "multiInputFirst-5rMj_O", + "multiInputLast": "multiInputLast-HWxgTr", + "multiInputWrapper": "multiInputWrapper-g6Srtv", + "noticeClosing": "closing-g5Srr2", + "noticeText": "text-kRs522", + "noticeUpdate": "updateNotice-2DjjHs", + "noticeUpdateButtonAll": "all-iF7Saa", + "noticeUpdateButtonReload": "reload-LkMrac", + "noticeUpdateEntries": "entries-Br6Sda", + "noticeUpdateEntry": "entry-oFts5R", + "noticeUpdateText": "notice-message", + "noticeUpdateSeparator": "separator-g5DsaR", + "noticeWrapper": "noticeWrapper-8z511t", + "searchBarWrapper": "searchBarWrapper-1GpKvB", + "selectWrapper": "selectWrapper-yPjeij", + "settingsGuild": "guild-J3Egt5", + "settingsGuildDisabled": "disabled-b2o83O", + "settingsPanel": "settingsPanel-w2ySNR", + "settingsPanelList": "settingsList-eZjkXj", + "settingsPanelListWrapper": "wrapper-kRsR33", + "settingsPanelListWrapperMini": "mini-2Iug3W", + "settingsRow": "settingsRow-o9Ft44", + "settingsTableCard": "settingsTableCard-628t52", + "settingsTableCardConfigs": "settingsTableCardConfigs-w5X9-Z", + "settingsTableCardLabel": "settingsTableCardLabel-MElgIg", + "settingsTableHeaderOptions": "headerOptions-8F_5Ss", + "settingsTableHeaders": "settingsTableHeaders-WKzw9_", + "settingsTableHeaderVertical": "headerVertical-4MNxqk", + "settingsTableList": "settingsTableList-f6sW2y", + "sidebar": "sidebar-frSZx3", + "sidebarContent": "content-1SbgDG", + "sidebarList": "list-VCoBc2", + "sliderBubble": "bubble-3we2di", + "switchMini": "mini-6F2SSa", + "supporter": "supporter-Z3FfwL", + "supporterTier1": "tier1-841W86", + "supporterTier2": "tier2-VDTzC3", + "supporterTier3": "tier3-yTxjsy", + "supporterTier4": "tier4-5RNl6k", + "svgIcon": "icon-GhnIRB", + "svgIconWrapper": "iconWrapper-g20jFn", + "tabBarContainerBottom": "bottom-b8sdfs", + "table": "table-moqjM0", + "tableBodyCell": "bodyCell-dQam9V", + "tableHeaderCell": "headerCell-T6Fo3K", + "textScroller": "textScroller-dc9_kz", + "themedPopout": "themedPopout-1TrfdI", + "tooltipCustom": "tooltipCustom-hH39_Z", + "tooltipNote": "note-e4Jh6_", + "tooltipRowExtra": "extraRow-6F2Dss", + "userInfoDate": "date-YN6TCS" + }, + "BD": { + "bdAddonCard": "bd-addon-card", + "bdAddonList": "bd-addon-list", + "bdAddonModal": "bd-addon-modal", + "bdAddonModalFooter": "bd-addon-modal-footer", + "bdAddonModalHeader": "bd-addon-modal-header", + "bdAddonModalSettings": "bd-addon-modal-settings", + "bdAuthor": "bd-author", + "bdButton": "bd-button", + "bdButtonDanger": "bd-button-danger", + "bdControls": "bd-controls", + "bdControlsButton": "bd-addon-button", + "bdDescription": "bd-description", + "bdDescriptionWrap": "bd-description-wrap", + "bdFolderButton": "bd-pfbtn", + "bdFooter": "bd-footer", + "bdGuild": "bd-guild", + "bdGuildAnimatable": "bd-animatable", + "bdGuildAudio": "bd-audio", + "bdGuildSelected": "bd-selected", + "bdGuildSeparator": "bd-guild-separator", + "bdGuildUnread": "bd-unread", + "bdGuildVideo": "bd-video", + "bdHeader": "bd-addon-header", + "bdHeaderTitle": "bd-title", + "bdIcon": "bd-icon", + "bdLink": "bd-link", + "bdLinks": "bd-links", + "bdMeta": "bd-meta", + "bdMinimalMode": "bd-minimal", + "bdName": "bd-name", + "bdPillSelected": "bd-selected", + "bdPillUnread": "bd-unread", + "bdSwitch": "bd-switch", + "bdSwitchChecked": "bd-switch-checked", + "bdSwitchInner": "bd-checkbox", + "bdUpdatebtn": "bd-updatebtn", + "bdVersion": "bd-version", + "settings": "plugin-settings", + "settingsOpen": "settings-open", + "settingsClosed": "settings-closed", + "switch": "ui-switch", + "switchCheckbox": "ui-switch-checkbox", + "switchChecked": "checked", + "switchItem": "ui-switch-item", + "switchWrapper": "ui-switch-wrapper" + }, + "BetterFriendList": { + "mutualGuilds": "mutualGuilds-s7F2aa", + "nameCell": "nameCell-7F4sRs", + "title": "title-3aDrFs" + }, + "BetterNsfwTag": { + "nsfwTag": "nsfwTag-666omg" + }, + "BetterSearchPage": { + "pagination": "pagination-shit69" + }, + "ChatFilter": { + "blocked": "blocked-jUhayi", + "blockedStamp": "blockedStamp-ijVeNn", + "censored": "censored-UYfeYg", + "censoredStamp": "censoredStamp-fb2cYb" + }, + "CharCounter": { + "charCounter": "charCounter-7fw40k", + "chatCounter": "chatCounter-XOMPsh", + "counterAdded": "charCounterAdded-zz9O4t", + "customStatusCounter": "customStatusCounter-G8FrsT", + "editCounter": "editCounter-pNT1Xe", + "nickCounter": "nickCounter-tJrO_4", + "popoutNoteCounter": "popoutNoteCounter-62U4Rh", + "profileNoteCounter": "profileNoteCounter-p0fWA_", + "threadCreation": "threadCreation-p0fWA_", + "uploadCounter": "uploadCounter-iEGQQk" + }, + "CreationDate": { + "date": "creationDate-CJwdKT" + }, + "CustomStatusPresets": { + "customStatusItem": "customStatusItem-f5Trsa", + "deleteButton": "deleteButton-k8a4Sa", + "deleteIcon": "deleteIcon-22SgHa", + "dragPreview": "dragPreview-3F0ssT", + "sortableCard": "sortableCard-oF6sTT", + "sortDivider": "sortDivider-d8SzzU", + "status": "status-0f5Sr2" + }, + "DisplayServersAsChannels": { + "badge": "badge-fxFrUP", + "muted": "muted-k5Fraa", + "name": "name-z5133D", + "styled": "styledGuildsAsChannels-DNHtg_" + }, + "EmojiStatistics": { + "amountCell": "amountCell-g_W6Rx", + "iconCell": "iconCell--wniOu", + "nameCell": "nameCell-xyXENZ", + "statisticsButton": "statisticsButton-nW2KoM" + }, + "FriendNotifications": { + "friendsOnline": "friendsOnline-2JkivW", + "friendsOnlineWrap": "friendsOnlineWrap-0gZ63m", + "logAvatar": "avatar-GgGssS", + "logContent": "content-_3_FFs", + "logTime": "time-00Fs44", + "timeLogModal": "timeLogModal-9s4Rts", + "typeLabel": "label-9FgsSa" + }, + "GameActivityToggle": { + "added": "gameActivityToggleAdded-Yd-YxC" + }, + "ImageUtilities": { + "details": "details-9dkFPc", + "detailsAdded": "detailsAdded-fHiJlm", + "detailsLabel": "label-mrlccN", + "detailsWrapper": "detailsWrapper-TE1mu5", + "gallery": "gallery-JViwKR", + "imageDetails": "imageDetails-1t6Zms", + "lens": "zoomLens-uOK8xV", + "lensBackdrop": "lensBackdrop-yEm7Om", + "next": "next-SHEZrz", + "operations": "operations-3V47CY", + "previous": "previous-xsNq6B", + "sibling": "sibling-6vI7Pu", + "switchIcon": "switchIcon-QY6cR4" + }, + "JoinedAtDate": { + "date": "joinedAtDate-IawR02" + }, + "LastMessageDate": { + "date": "lastMessageDate-ocEw13" + }, + "OldTitleBar": { + "oldTitleBarEnabled": "oldTitleBarEnabled-D8ppJQ", + "settingsToolbar": "settingsToolbar-wu4yfQ", + "toolbar": "toolbar-hRzFw-" + }, + "PersonalPins": { + "messageTag": "messageTag-yRSUYg", + "messageTagAdd": "messageTagAdd-vKM0VY", + "messageTagAddActive": "active-G0VvAY", + "messageTagDelete": "messageTagDelete-QaGh6V", + "messageTagName": "messageTagName-dT8OZ4" + }, + "PinDMs": { + "dragPreview": "dragPreview-nXiByA", + "dmChannelPinned": "pinned-0lM4wD", + "dmChannelPlaceholder": "placeholder-7bhR5s", + "pinnedChannelsHeaderAmount": "headerAmount-_-7GrS", + "pinnedChannelsHeaderArrow": "pinnedChannelsHeaderArrow-44rrTz", + "pinnedChannelsHeaderCollapsed": "collapsed-3w_-ff", + "pinnedChannelsHeaderColored": "colored-oIzG5s", + "pinnedChannelsHeaderContainer": "pinnedChannelsHeaderContainer-89Gjv4", + "recentPinned": "pinned-jHvFrr", + "recentPlaceholder": "placeholder-Uff-gH", + "unpinButton": "unpinButton-z3-UVO", + "unpinIcon": "unpinIcon-79ZnEr" + }, + "PluginRepo": { + "failNotice": "failNotice-OtHUGb", + "loadingIcon": "loadingIcon-dB3qSe", + "loadingTooltip": "loadingTooltip-SzsTEU", + "newEntriesNotice": "newEntriesNotice-qvvpPx", + "outdatedNotice": "outdatedNotice-9Q9gJv", + "repoNotice": "repoNotice-P5ss6R" + }, + "ReadAllNotificationsButton": { + "button": "button-Jt-tIg", + "frame": "frame-oXWS21", + "innerFrame": "innerFrame-8Hg64E" + }, + "ServerCounter": { + "serverCount": "serverCount-FsTTs1", + "serverCountWrap": "serverCountWrap-k8F5De" + }, + "ServerDetails": { + "details": "details-08FrsT", + "icon": "icon-hSL42R", + "tooltip": "detailsTooltip-G9hSSa" + }, + "ServerFolders": { + "dragPreview": "dragPreview-nXiByA", + "guildPlaceholder": "placeholder-7bhR5s", + "folderContent": "content-Pph8t6", + "folderContentClosed": "closed-j55_T-", + "folderContentIsOpen": "folderContentIsOpen-zz6FgW", + "iconSwatch": "iconSwatch-_78Ghj", + "iconSwatchInner": "iconInner-aOY-qk", + "iconSwatchPreview": "preview-Bbg_24", + "iconSwatchNoPreview": "noPreview-G8SS4t", + "iconSwatchSelected": "selected-P5oePO" + }, + "SpellCheck": { + "error": "error-k9z2IV", + "overlay": "spellCheckOverlay-cNSap5" + }, + "ShowBadgesInChat": { + "badges": "badges-XRnWAp", + "badgesChat": "badgesChat-f_cbR8", + "badgesDMs": "badgesDMs-Aw_p52", + "badgesMembers": "badgesMembers-8Kf3S1", + "badgesSettings": "badgesSettings-ychoGn", + "indicator": "indicator-8F4GGw" + }, + "ShowConnections": { + "connection": "connection-9Gh4sa", + "connectionIcon": "connectionIcon-888F4s", + "connections": "connections-pPr4as", + "verifiedBadge": "verifiedBadge-mH2YpO" + }, + "ShowHiddenChannels": { + "accessModal": "accessModal-w5HjsV", + "hiddenChannel": "hidden-9f2Dsa" + }, + "SpotifyControls": { + "activityButton": "activityButton-5Fs4Aa", + "bar": "bar-g2ZMIm", + "barGabber": "grabber-7sd5f5", + "barFill": "barFill-Dhkah7", + "barText": "barText-lmqc5O", + "buttonActive": "active-6TsW-_", + "container": "container-6sXIoE", + "containerInner": "inner-WRV6k5", + "containerMaximized": "maximized-vv2Wr0", + "containerWithTimeline": "withTimeline-824fT_", + "cover": "cover-SwJ-ck", + "coverMaximizer": "maximizer-RVu85p", + "coverWrapper": "coverWrapper-YAplwJ", + "details": "details-ntX2k5", + "interpret": "interpret-F93iqP", + "settingsIcon": "icon-F4SSra", + "settingsLabel": "label-3f00Sr", + "song": "song-tIdBpF", + "timeline": "timeline-UWmgAx", + "volumeSlider": "volumeSlider-sR5g00" + }, + "StaffTag": { + "adminIcon": "admin-Kv1Hp_", + "groupOwnerIcon": "groupOwner-g6FlmA", + "managementIcon": "management-3fF_o8", + "ownerIcon": "owner-FfFh3B", + "threadCreatorIcon": "threadCreator-lp5sXo" + }, + "ThemeRepo": { + "dragBar": "dragBar-4FsRaa", + "dragCorner": "dragCorner-PgJJk2", + "dragInterface": "dragInterface-OT5s2A", + "failNotice": "failNotice-pZAzjZ", + "loadingIcon": "loadingIcon-h7OqHY", + "loadingTooltip": "loadingTooltip-YszEmb", + "moveBar": "moveBar-lZ555a", + "newEntriesNotice": "newEntriesNotice-abF6e1", + "preview": "preview-7Gh5tS", + "previewFullscreen": "fullscreen-h78TsW", + "previewMoving": "moving-Wa22fA", + "outdatedNotice": "outdatedNotice-fw8ams", + "repoNotice": "repoNotice-TV3RFr" + }, + "ThemeSettings": { + "settingsButton": "settingsButton-h4Rts2" + }, + "TimedLightDarkMode": { + "dateGrabber": "dateGrabber-QrRkIX", + "timerGrabber": "timerGrabber-zpRAIk", + "timerSettings": "timerSettings-wkvEfF" + }, + "TopRolesEverywhere": { + "badgeStyle": "badgeStyle-tFiEQ8", + "chatTag": "chatTag-Y-5TDc", + "memberTag": "memberTag-QVWzGc", + "roleStyle": "roleStyle-jQ7KI2", + "tag": "tag-wWVHyf", + "voiceTag": "voiceTag-0F4Ss0" + }, + "Translator": { + "configButton": "configButton-lLgMs2", + "translateButton": "translateButton-DhP9x8", + "translated": "translated-5YO8i3", + "translating": "translating-Yi-YxC" + }, + "WriteUpperCase": { + "enabled": "enabled-7KI3Q2", + "quickToggleButton": "quickToggleButton-P2xDh8" + }, + "NotFound": { + "_": "", + "emoji": "emoji", + "highlight": "highlight", + "hoverCardButton": "button-1yVL_7", + "loginScreen": "wrapper-1f5byN", + "mention": "mention", + "mentionInteractive": "interactive", + "mentionWrapper": "wrapper-1ZcZW-", + "messagesLoadingWrapper": "wrapper-3HVHpV", + "nameContainerNameContainer": "container-q97qHp", + "hueCursor": "hue-cursor", + "hueHorizontal": "hue-horizontal", + "hueVertical": "hue-vertical", + "saturationBlack": "saturation-black", + "saturationColor": "saturation-color", + "saturationCursor": "saturation-cursor", + "saturationWhite": "saturation-white", + "searchResultsPagination": "container-1-h9mY", + "splashBackground": "splashBackground-1FRCko", + "stopAnimations": "stop-animations", + "subtext": "subtext-2HDqJ7", + "themeDark": "theme-dark", + "themeLight": "theme-light", + "themeUndefined": "theme-undefined", + "voiceDraggable": "draggable-1KoBzC" + }, + "Toast": { + "avatar": "avatar-3xmbmC", + "bar": "bar-95Sdw1", + "barInner": "barInner-u7Frsw", + "bg": "bg-8df5St", + "brand": "colorBrand-WfDfzD", + "center": "center-9SpJeg", + "closable": "closable-7ShrRt", + "closeIcon": "closeIcon-8R553s", + "closing": "closing-K489s7", + "custom": "colorCustom-WKsPgT", + "customBar": "customBar-3RsUzs", + "danger": "colorDanger-O5wq9n", + "default": "colorDefault-XdNdIp", + "icon": "icon-OZgBPQ", + "info": "colorInfo-ujWH4-", + "inner": "inner-6Fsw34", + "left": "left-IXnX5I", + "opening": "opening-3TzSw2", + "right": "right-Eka_pI", + "success": "colorSuccess-6GreWs", + "text": "text-28VADE", + "toast": "toast-g4bfgI", + "toasts": "toasts-tApoHv", + "warning": "colorWarning-qZNMsx" + } + }, + "DiscordClassModules": { + "AccountDetails": {"props": ["usernameContainer", "container"]}, + "AccountDetailsButtons": {"props": ["button", "enabled", "disabled"]}, + "Anchor": {"props": ["anchor", "anchorUnderlineOnHover"]}, + "AnimationContainer": {"props": ["animatorLeft", "didRender"]}, + "AppBase": {"props": ["container", "base"]}, + "AppInner": {"props": ["app", "layers"]}, + "AppMount": {"props": ["appMount"]}, + "ApplicationStore": {"props": ["applicationStore", "navigation"]}, + "AppOuter": {"props": ["app", "mobileApp"]}, + "Attachment": {"props": ["wrapper", "video", "metadataDownload"]}, + "AuditLog": {"props": ["auditLog"]}, + "AuthBox": {"props": ["authBox"]}, + "Autocomplete": {"props": ["autocomplete", "autocompleteRow"]}, + "AutocompleteAliases": {"props": ["autocomplete", "stickerAutoComplete"]}, + "Avatar": {"props": ["avatar", "mask", "wrapper"]}, + "AvatarIcon": {"props": ["iconActiveLarge", "iconActiveMedium"]}, + "Backdrop": {"props": ["backdrop", "withLayer"]}, + "Badge": {"props": ["numberBadge", "textBadge", "iconBadge"]}, + "BotTag": {"props": ["botTag", "botTagInvert"]}, + "Button": {"props": ["colorBrand", "lookBlank"]}, + "CallCurrent": {"props": ["wrapper", "fullScreen"]}, + "CallDetails": {"props": ["container", "hotspot"]}, + "CallIncoming": {"props": ["wrapper", "mainChannelInfo"]}, + "Card": {"props": ["card", "cardBrand"]}, + "Category": {"props": ["wrapper", "children", "addButtonIcon"]}, + "CategoryArrow": {"props": ["arrow", "open"]}, + "ChangeLog": {"props": ["added", "fixed", "improved", "progress"]}, + "Channel": {"props": ["wrapper", "content", "modeSelected"]}, + "ChannelContainer": {"props": ["actionIcon", "containerDefault"]}, + "ChannelLimit": {"props": ["users", "total", "wrapper"]}, + "ChannelTextArea": {"props": ["textArea", "buttons"]}, + "ChannelTextAreaAttachButton": {"props": ["attachButton", "attachWrapper"]}, + "ChannelTextAreaButton": {"props": ["buttonWrapper", "active"]}, + "ChannelTextAreaCharCounter": {"props": ["characterCount", "error"]}, + "ChannelTextAreaSlate": {"props": ["slateContainer", "placeholder"]}, + "ChatThreadSidebar": {"props": ["container", "floating", "resizeHandle"]}, + "ChatWindow": {"props": ["chat", "channelTextArea", "chatContent"]}, + "Checkbox": {"props": ["checkboxWrapper", "round"]}, + "Clamped": {"props": ["clamped"]}, + "ColorPicker": {"props": ["colorPickerCustom", "colorPickerDropper"]}, + "ColorPickerInner": {"props": ["hue", "saturation"]}, + "Combobox": {"props": ["combobox", "itemLabel"]}, + "Cursor": {"props": ["cursorDefault", "userSelectNone"]}, + "CustomStatusIcon": {"props": ["textRuler", "emoji", "icon"]}, + "CustomStatusModal": {"props": ["inputContainer", "emojiButton", "modalRoot"]}, + "CustomStatusPopout": {"props": ["customStatusItem", "customEmoji"]}, + "DmAddPopout": {"props": ["popout", "searchBarComponent"]}, + "DmAddPopoutItems": {"props": ["friendSelected", "friendWrapper"]}, + "DownloadLink": {"props": ["downloadLink"]}, + "Embed": {"props": ["embed", "embedAuthorIcon"]}, + "EmbedActions": {"props": ["iconPlay", "iconWrapperActive"]}, + "Emoji": {"props": ["emoji"], "length": 1}, + "EmojiButton": {"props": ["emojiButton", "sprite"]}, + "EmojiPicker": {"props": ["emojiPicker", "inspector"]}, + "EmojiPickerDiversitySelector": {"props": ["diversityEmojiItemImage", "diversitySelectorOptions"]}, + "EmojiPickerItem": {"props": ["emojiSpriteImage"]}, + "EmojiPickerInspector": {"props": ["inspector", "graphicPrimary"]}, + "EmojiPickerInspectorEmoji": {"props": ["emoji", "glyphEmoji"]}, + "ErrorScreen": {"props": ["wrapper", "flexWrapper", "note"]}, + "ExpressionPicker": {"props": ["contentWrapper", "navButton", "navList"]}, + "FavButton": {"props": ["gifFavoriteButton", "selected", "icon"]}, + "File": {"props": ["downloadButton", "fileNameLink"]}, + "Flex": {"props": ["alignBaseline", "alignCenter"], "length": 24, "smaller": true}, + "FlexChild": {"props": ["flexChild", "flex"]}, + "FlowerStar": {"props": ["flowerStarContainer", "flowerStar"]}, + "FormText": {"props": ["description", "modeDefault"]}, + "Game": {"props": ["game", "gameName"]}, + "GameIcon": {"props": ["gameIcon", "small", "xsmall"]}, + "GameLibraryTable": {"props": ["stickyHeader", "emptyStateText"]}, + "GifFavoriteButton": {"props": ["gifFavoriteButton", "showPulse"]}, + "GoLiveDetails": {"props": ["panel", "gameWrapper"]}, + "Guild": {"props": ["wrapper", "lowerBadge", "svg"]}, + "GuildChannels": {"props": ["positionedContainer", "unreadBar"]}, + "GuildChannelsWrapper": {"props": ["hubContainer", "container"]}, + "GuildDiscovery": {"props": ["pageWrapper", "guildList"]}, + "GuildDm": {"props": ["pill"], "length": 1}, + "GuildEdges": {"props": ["wrapper", "target", "centerTarget"]}, + "GuildFolder": {"props": ["folder", "expandedFolderIconWrapper"]}, + "GuildHeader": {"props": ["header", "name", "bannerImage"]}, + "GuildHeaderButton": {"props": ["button", "open"]}, + "GuildItem": {"props": ["listItem", "participating"], "length": 10, "smaller": true}, + "GuildIcon": {"props": ["acronym", "selected", "wrapper"]}, + "GuildInvite": {"props": ["wrapper", "guildIconJoined"]}, + "GuildsButton": {"props": ["circleIconButton", "circleIcon"], "length": 6, "smaller": true}, + "GuildsDragPlaceholder": {"props": ["dragInner", "placeholderMask"], "length": 6, "smaller": true}, + "GuildSeparator": {"props": ["guildSeparator"]}, + "GuildServer": {"props": ["blobContainer", "pill"]}, + "GuildSettingsBanned": {"props": ["bannedUser", "bannedUserAvatar"]}, + "GuildSettingsEmoji": {"props": ["emojiRow", "emojiAliasPlaceholder"]}, + "GuildSettingsInvite": {"props": ["countdownColumn", "inviteSettingsInviteRow"]}, + "GuildSettingsMember": {"props": ["member", "membersFilterPopout"]}, + "GuildsInbox": {"props": ["listItemWrapper", "listItemTooltip"]}, + "GuildsInboxIcon": {"props": ["iconButton", "selected"]}, + "GuildsItems": {"props": ["circleIcon", "guildsError"]}, + "GuildsWrapper": {"props": ["scroller", "unreadMentionsBar", "wrapper"]}, + "HeaderBar": {"props": ["container", "children", "toolbar"]}, + "HeaderBarExtras": {"props": ["headerBarLoggedOut", "search"]}, + "HeaderBarSearch": {"props": ["search", "searchBar", "open"]}, + "HeaderBarTopic": {"props": ["topic", "expandable", "content"]}, + "HomeIcon": {"props": ["homeIcon"]}, + "HotKeyRecorder": {"props": ["editIcon", "recording"]}, + "HoverCard": {"props": ["card", "active"]}, + "HoverCardRemoveButton": {"props": ["button", "filled", "default"]}, + "IconDirection": {"props": ["directionDown", "directionUp"]}, + "ImageAssets": {"props": ["pngImage", "stickerAsset"]}, + "ImageModal": {"props": ["image", "modal"], "length": 4, "smaller": true}, + "ImageWrapper": {"props": ["clickable", "imageWrapperBackground"]}, + "Input": {"props": ["inputMini", "inputDefault"]}, + "InviteModal": {"props": ["inviteRow", "modal"]}, + "Item": {"props": ["item", "side", "header"]}, + "ItemRole": {"props": ["role", "dragged"]}, + "ItemLayerContainer": {"props": ["layer", "layerContainer"]}, + "Layers": {"props": ["layer", "layers"]}, + "LiveTag": {"props": ["liveLarge", "live"]}, + "LoadingScreen": {"props": ["container", "problemsText", "problems"]}, + "Margins": {"props": ["marginBottom4", "marginCenterHorz"]}, + "Menu": {"props": ["menu", "styleFlexible", "item"]}, + "MenuCaret": {"props": ["arrow", "open"]}, + "MenuReactButton": {"props": ["wrapper", "icon", "focused"]}, + "MenuSlider": {"props": ["slider", "sliderContainer"]}, + "Member": {"props": ["member", "ownerIcon"]}, + "MembersWrapper": {"props": ["membersWrap", "membersGroup"]}, + "Message": {"props": ["message", "mentioned"]}, + "MessageAccessory": {"props": ["embedWrapper", "gifFavoriteButton"]}, + "MessageBlocked": {"props": ["blockedMessageText", "expanded"]}, + "MessageBody": {"props": ["markupRtl", "edited"]}, + "MessageDivider": {"props": ["isUnread", "divider"]}, + "MessageElements": {"props": ["messageGroupBlockedBtn", "dividerRed"]}, + "MessageFile": {"props": ["cancelButton", "filenameLinkWrapper"]}, + "MessageLocalBot": {"props": ["ephemeralMessage", "icon"]}, + "MessageMarkup": {"props": ["markup"]}, + "MessagePopout": {"props": ["message", "spacing"]}, + "MessageOperations": {"props": ["operations"], "length": 1}, + "MessageReactions": {"props": ["reactions", "reactionMe"]}, + "MessageReactionsModal": {"props": ["reactor", "reactionSelected"]}, + "MessageReply": {"props": ["container", "text", "closeButton"]}, + "MessagesPopout": {"props": ["messagesPopoutWrap", "jumpButton"]}, + "MessagesPopoutButtons": {"props": ["secondary", "tertiary", "button"]}, + "MessagesPopoutTabBar": {"props": ["header", "tabBar", "active"]}, + "MessagesLoading": {"props": ["attachment", "blob", "cozy"]}, + "MessagesWelcome": {"props": ["emptyChannelIcon", "description", "header"]}, + "MessagesWelcomeButton": {"props": ["button", "buttonIcon"], "length": 2}, + "MessagesWelcomeThread": {"props": ["iconWrapper", "threadCreatorName"]}, + "MessagesWrap": {"props": ["messagesWrapper", "messageGroupBlocked"]}, + "MessageSystem": {"props": ["container", "actionAnchor"]}, + "MessageSystemAccessories": {"props": ["name", "spine", "cta"]}, + "MessageToolbar": {"props": ["container", "icon", "isHeader"]}, + "MessageToolbarItems": {"props": ["wrapper", "button", "separator"]}, + "Modal": {"props": ["root", "small", "medium"]}, + "ModalDivider": {"props": ["divider"], "length": 1}, + "ModalItems": {"props": ["guildName", "checkboxContainer"]}, + "ModalMiniContent": {"props": ["modal", "content", "maxModalWidth"]}, + "ModalSub": {"props": ["modal", "sizeLarge"]}, + "NameContainer": {"props": ["nameAndDecorators", "name"]}, + "NameContainerState": {"props": ["interactive", "selected", "muted"]}, + "NameTag": {"props": ["bot", "nameTag"]}, + "NitroStore": {"props": ["applicationStore", "marketingHeader"]}, + "NoteTextarea": {"props": ["textarea"], "length": 1}, + "Notice": {"props": ["notice", "platformIcon"]}, + "NoticePlatform": {"props": ["iconAndroid", "textLink"]}, + "Pagination": {"props": ["pageButton", "pageControl"]}, + "PeopleItem": {"props": ["peopleListItem", "active"]}, + "PeopleItemInfo": {"props": ["listItemContents", "actions"], "length": 2}, + "PeopleItemUser": {"props": ["userInfo", "discordTag"]}, + "PeopleList": {"props": ["peopleList", "emptyStateContainer"]}, + "Peoples": {"props": ["peopleColumn", "tabBar"]}, + "PictureInPicture": {"props": ["pictureInPicture", "pictureInPictureWindow"]}, + "PillWrapper": {"props": ["item", "wrapper"], "length": 2}, + "PrivateChannel": {"props": ["channel", "closeButton"]}, + "PrivateChannelList": {"props": ["privateChannels", "searchBar"]}, + "PrivateChannelListScroller": {"props": ["privateChannelsHeaderContainer", "headerText"]}, + "PopoutActivity": {"props": ["ellipsis", "activityActivityFeed"]}, + "QuickMessage": {"props": ["input"], "length": 1}, + "QuickSelect": {"props": ["quickSelectArrow", "selected"]}, + "QuickSwitch": {"props": ["result", "guildIconContainer"]}, + "QuickSwitchWrap": {"props": ["container", "miscContainer"]}, + "RadioGroup": {"props": ["radioBar", "item"]}, + "Reactions": {"props": ["reactionBtn", "reaction"]}, + "RecentMentions": {"props": ["recentMentionsPopout"]}, + "RecentMentionsHeader": {"props": ["channelName", "channelHeader", "dmIcon"]}, + "Role": {"props": ["roleName", "roleRemoveIcon"]}, + "RoleCircle": {"props": ["roleCircle", "flex"]}, + "Scrollbar": {"props": ["scrollbar", "scrollbarGhost"]}, + "Scroller": {"props": ["scrollerBase", "none", "fade"]}, + "SearchBar": {"props": ["clear", "container", "pointer"]}, + "SearchPopout": {"props": ["datePicker", "searchResultChannelIconBackground"]}, + "SearchPopoutWrap": {"props": ["container", "queryContainer"]}, + "SearchResults": {"props": ["noResults", "searchResultsWrap"]}, + "SearchResultsElements": {"props": ["totalResults", "searchHeaderTabList"]}, + "SearchResultsGroup": {"props": ["searchResultGroup", "channelName"]}, + "SearchResultsMessage": {"props": ["message", "searchResult"]}, + "Select": {"props": ["select", "error", "errorMessage"]}, + "SelectFilterPopout": {"props": ["selectFilterPopout", "avatar", "row"]}, + "SelectSearchable": {"props": ["searchable", "option", "selectedIcon"]}, + "SettingsCloseButton": {"props": ["closeButton", "keybind"]}, + "SettingsItems": {"props": ["labelRow", "note"]}, + "SettingsTable": {"props": ["headerOption", "headerName"]}, + "SettingsWindow": {"props": ["contentRegion", "standardSidebarView"]}, + "SettingsWindowScroller": {"props": ["sidebarScrollable", "content", "scroller"]}, + "Slider": {"props": ["slider", "grabber"]}, + "Spinner": {"props": ["spinner", "chasingDots"]}, + "Spoiler": {"props": ["spoilerContainer", "hidden"]}, + "SpoilerEmbed": {"props": ["hiddenSpoilers", "spoiler"]}, + "Switch": {"props": ["container", "slider", "input"]}, + "Table": {"props": ["stickyHeader", "sortIcon"]}, + "Text": {"props": ["defaultColor", "defaultMarginh1"]}, + "TextColor": {"props": ["colorStandard", "colorMuted", "colorError"]}, + "TextColor2": {"props": ["muted", "wrapper", "base"]}, + "TextSize": {"props": ["size10", "size14", "size20"]}, + "TextStyle": {"props": ["strikethrough", "underline", "bold"]}, + "ThreadCard": {"props": ["threadName", "container", "facepile"]}, + "Tip": {"props": ["pro", "inline"]}, + "TitleBar": {"props": ["titleBar", "wordmark"]}, + "Tooltip": {"props": ["tooltip", "tooltipTop"]}, + "TooltipGuild": {"props": ["rowIcon", "rowGuildName"]}, + "Typing": {"props": ["cooldownWrapper", "typing"]}, + "UnreadBar": {"props": ["active", "bar", "unread"]}, + "UploadModal": {"props": ["uploadModal", "bgScale"]}, + "UserBadges": {"props": ["profileBadge", "container"]}, + "UserBanner": {"props": ["popoutBanner", "popoutBannerPremium"]}, + "UserPopout": {"props": ["userPopout", "body"]}, + "UserPopoutBody": {"props": ["rolesList", "note"]}, + "UserPopoutFooter": {"props": ["wumpusTooltip", "footer"]}, + "UserPopoutHeader": {"props": ["headerTop", "profileBadges"]}, + "UserProfile": {"props": ["root", "tabBarContainer"]}, + "UserProfileHeader": {"props": ["header", "additionalActionsIcon"]}, + "UserProfileInfoSection": {"props": ["userInfoSection", "connectedAccounts"]}, + "UserProfileList": {"props": ["listAvatar", "listRow"]}, + "UserProfileListGuild": {"props": ["guildAvatar", "guildAvatarWithoutIcon"]}, + "UserSettingsAppearancePreview": {"props": ["preview", "firstMessage"]}, + "UserSettingsSocialLinks": {"props": ["socialLinks", "link"]}, + "UserSummaryItem": {"props": ["avatarContainerMasked", "container"]}, + "Video": {"props": ["video", "fullScreen"]}, + "VoiceChannel": {"props": ["avatarSpeaking", "voiceUser"]}, + "VoiceChannelLimit": {"props": ["total", "users", "wrapper"]}, + "VoiceChannelList": {"props": ["list", "collapsed"]}, + "VoiceDetails": {"props": ["container", "customStatusContainer"]}, + "VoiceDetailsPing": {"props": ["rtcConnectionQualityBad", "rtcConnectionQualityFine"]}, + "WebhookCard": {"props": ["pulseBorder", "copyButton"]} + }, + "DiscordClasses": { + "_bdguild": ["BD", "bdGuild"], + "_bdguildanimatable": ["BD", "bdGuildAnimatable"], + "_bdguildaudio": ["BD", "bdGuildAudio"], + "_bdguildselected": ["BD", "bdGuildSelected"], + "_bdguildseparator": ["BD", "bdGuildSeparator"], + "_bdguildunread": ["BD", "bdGuildUnread"], + "_bdguildvideo": ["BD", "bdGuildVideo"], + "_bdminimalmode": ["BD", "bdMinimalMode"], + "_bdpillselected": ["BD", "bdPillSelected"], + "_bdpillunread": ["BD", "bdPillUnread"], + "_betterfriendlistmutualguilds": ["BetterFriendList", "mutualGuilds"], + "_betterfriendlistnamecell": ["BetterFriendList", "nameCell"], + "_betterfriendlisttitle": ["BetterFriendList", "title"], + "_betternsfwtagtag": ["BetterNsfwTag", "nsfwTag"], + "_bettersearchpagepagination": ["BetterSearchPage", "pagination"], + "_chatfilterblocked": ["ChatFilter", "blocked"], + "_chatfilterblockedstamp": ["ChatFilter", "blockedStamp"], + "_chatfiltercensored": ["ChatFilter", "censored"], + "_chatfiltercensoredstamp": ["ChatFilter", "censoredStamp"], + "_charcountercounter": ["CharCounter", "charCounter"], + "_charcounterchatcounter": ["CharCounter", "chatCounter"], + "_charcountercounteradded": ["CharCounter", "counterAdded"], + "_charcountercustomstatuscounter": ["CharCounter", "customStatusCounter"], + "_charcountereditcounter": ["CharCounter", "editCounter"], + "_charcounternickcounter": ["CharCounter", "nickCounter"], + "_charcounterpopoutnotecounter": ["CharCounter", "popoutNoteCounter"], + "_charcounterprofilenotecounter": ["CharCounter", "profileNoteCounter"], + "_charcounterthreadcreationcounter": ["CharCounter", "threadCreation"], + "_charcounteruploadcounter": ["CharCounter", "uploadCounter"], + "_creationdatedate": ["CreationDate", "date"], + "_customstatuspresetscustomstatusitem": ["CustomStatusPresets", "customStatusItem"], + "_customstatuspresetsdeletebutton": ["CustomStatusPresets", "deleteButton"], + "_customstatuspresetsdeleteicon": ["CustomStatusPresets", "deleteIcon"], + "_customstatuspresetsdragpreview": ["CustomStatusPresets", "dragPreview"], + "_customstatuspresetssortablecard": ["CustomStatusPresets", "sortableCard"], + "_customstatuspresetssortdivider": ["CustomStatusPresets", "sortDivider"], + "_customstatuspresetsstatus": ["CustomStatusPresets", "status"], + "_displayserversaschannelsbadge": ["DisplayServersAsChannels", "badge"], + "_displayserversaschannelsmuted": ["DisplayServersAsChannels", "muted"], + "_displayserversaschannelsname": ["DisplayServersAsChannels", "name"], + "_displayserversaschannelsstyled": ["DisplayServersAsChannels", "styled"], + "_emojistatisticsstatisticsbutton": ["EmojiStatistics", "statisticsButton"], + "_emojistatisticsamountcell": ["EmojiStatistics", "amountCell"], + "_emojistatisticsiconcell": ["EmojiStatistics", "iconCell"], + "_emojistatisticsnamecell": ["EmojiStatistics", "nameCell"], + "_friendnotificationslogavatar": ["FriendNotifications", "logAvatar"], + "_friendnotificationslogcontent": ["FriendNotifications", "logContent"], + "_friendnotificationslogtime": ["FriendNotifications", "logTime"], + "_friendnotificationsfriendsonline": ["FriendNotifications", "friendsOnline"], + "_friendnotificationsfriendsonlinewrap": ["FriendNotifications", "friendsOnlineWrap"], + "_friendnotificationstimelogmodal": ["FriendNotifications", "timeLogModal"], + "_friendnotificationstypelabel": ["FriendNotifications", "typeLabel"], + "_gameactivitytoggleadded": ["GameActivityToggle", "added"], + "_imageutilitiesdetails": ["ImageUtilities", "details"], + "_imageutilitiesdetailsadded": ["ImageUtilities", "detailsAdded"], + "_imageutilitiesdetailslabel": ["ImageUtilities", "detailsLabel"], + "_imageutilitiesdetailswrapper": ["ImageUtilities", "detailsWrapper"], + "_imageutilitiesgallery": ["ImageUtilities", "gallery"], + "_imageutilitiesimagedetails": ["ImageUtilities", "imageDetails"], + "_imageutilitieslense": ["ImageUtilities", "lens"], + "_imageutilitieslensebackdrop": ["ImageUtilities", "lensBackdrop"], + "_imageutilitiesnext": ["ImageUtilities", "next"], + "_imageutilitiesoperations": ["ImageUtilities", "operations"], + "_imageutilitiesprevious": ["ImageUtilities", "previous"], + "_imageutilitiessibling": ["ImageUtilities", "sibling"], + "_imageutilitiesswitchicon": ["ImageUtilities", "switchIcon"], + "_joinedatdatedate": ["JoinedAtDate", "date"], + "_lastmessagedatedate": ["LastMessageDate", "date"], + "_oldtitlebarenabled": ["OldTitleBar", "oldTitleBarEnabled"], + "_oldtitlebarsettingstoolbar": ["OldTitleBar", "settingsToolbar"], + "_oldtitlebartoolbar": ["OldTitleBar", "toolbar"], + "_personalpinsmessagetag": ["PersonalPins", "messageTag"], + "_personalpinsmessagetagadd": ["PersonalPins", "messageTagAdd"], + "_personalpinsmessagetagaddactive": ["PersonalPins", "messageTagAddActive"], + "_personalpinsmessagetagdelete": ["PersonalPins", "messageTagDelete"], + "_personalpinsmessagetagname": ["PersonalPins", "messageTagName"], + "_pindmsdragpreview": ["PinDMs", "dragPreview"], + "_pindmsdmchannelpinned": ["PinDMs", "dmChannelPinned"], + "_pindmsdmchannelplaceholder": ["PinDMs", "dmChannelPlaceholder"], + "_pindmspinnedchannelsheaderamount": ["PinDMs", "pinnedChannelsHeaderAmount"], + "_pindmspinnedchannelsheaderarrow": ["PinDMs", "pinnedChannelsHeaderArrow"], + "_pindmspinnedchannelsheadercollapsed": ["PinDMs", "pinnedChannelsHeaderCollapsed"], + "_pindmspinnedchannelsheadercolored": ["PinDMs", "pinnedChannelsHeaderColored"], + "_pindmspinnedchannelsheadercontainer": ["PinDMs", "pinnedChannelsHeaderContainer"], + "_pindmsrecentpinned": ["PinDMs", "recentPinned"], + "_pindmsrecentplaceholder": ["PinDMs", "recentPlaceholder"], + "_pindmsunpinbutton": ["PinDMs", "unpinButton"], + "_pindmsunpinicon": ["PinDMs", "unpinIcon"], + "_pluginrepofailnotice": ["PluginRepo", "failNotice"], + "_pluginrepoloadingicon": ["PluginRepo", "loadingIcon"], + "_pluginrepoloadingtooltip": ["PluginRepo", "loadingTooltip"], + "_pluginreponewentriesnotice": ["PluginRepo", "newEntriesNotice"], + "_pluginreponotice": ["PluginRepo", "repoNotice"], + "_pluginrepooutdatednotice": ["PluginRepo", "outdatedNotice"], + "_readallnotificationsbuttonbutton": ["ReadAllNotificationsButton", "button"], + "_readallnotificationsbuttonframe": ["ReadAllNotificationsButton", "frame"], + "_readallnotificationsbuttoninner": ["ReadAllNotificationsButton", "innerFrame"], + "_servercounterservercount": ["ServerCounter", "serverCount"], + "_servercounterservercountwrap": ["ServerCounter", "serverCountWrap"], + "_serverdetailsdetails": ["ServerDetails", "details"], + "_serverdetailsicon": ["ServerDetails", "icon"], + "_serverdetailstooltip": ["ServerDetails", "tooltip"], + "_serverfoldersdragpreview": ["ServerFolders", "dragPreview"], + "_serverfoldersfoldercontent": ["ServerFolders", "folderContent"], + "_serverfoldersfoldercontentclosed": ["ServerFolders", "folderContentClosed"], + "_serverfoldersfoldercontentisopen": ["ServerFolders", "folderContentIsOpen"], + "_serverfoldersguildplaceholder": ["ServerFolders", "guildPlaceholder"], + "_serverfoldersiconswatch": ["ServerFolders", "iconSwatch"], + "_serverfoldersiconswatchinner": ["ServerFolders", "iconSwatchInner"], + "_serverfoldersiconswatchpreview": ["ServerFolders", "iconSwatchPreview"], + "_serverfoldersiconswatchnopreview": ["ServerFolders", "iconSwatchNoPreview"], + "_serverfoldersiconswatchselected": ["ServerFolders", "iconSwatchSelected"], + "_showbadgesinchatbadges": ["ShowBadgesInChat", "badges"], + "_showbadgesinchatbadgeschat": ["ShowBadgesInChat", "badgesChat"], + "_showbadgesinchatbadgesdmslist": ["ShowBadgesInChat", "badgesDMs"], + "_showbadgesinchatbadgesmemberlist": ["ShowBadgesInChat", "badgesMembers"], + "_showbadgesinchatbadgessettings": ["ShowBadgesInChat", "badgesSettings"], + "_showbadgesinchatindicator": ["ShowBadgesInChat", "indicator"], + "_showconnectionsconnection": ["ShowConnections", "connection"], + "_showconnectionsconnections": ["ShowConnections", "connections"], + "_showconnectionsicon": ["ShowConnections", "connectionIcon"], + "_showconnectionsverifiedbadge": ["ShowConnections", "verifiedBadge"], + "_showhiddenchannelsaccessmodal": ["ShowHiddenChannels", "accessModal"], + "_showhiddenchannelshiddenchannel": ["ShowHiddenChannels", "hiddenChannel"], + "_spellcheckerror": ["SpellCheck", "error"], + "_spellcheckoverlay": ["SpellCheck", "overlay"], + "_spotifycontrolsactivitybutton": ["SpotifyControls", "activityButton"], + "_spotifycontrolsbar": ["SpotifyControls", "bar"], + "_spotifycontrolsbarfill": ["SpotifyControls", "barFill"], + "_spotifycontrolsbargrabber": ["SpotifyControls", "barGabber"], + "_spotifycontrolsbartext": ["SpotifyControls", "barText"], + "_spotifycontrolsbuttonactive": ["SpotifyControls", "buttonActive"], + "_spotifycontrolscontainer": ["SpotifyControls", "container"], + "_spotifycontrolscontainerinner": ["SpotifyControls", "containerInner"], + "_spotifycontrolscontainermaximized": ["SpotifyControls", "containerMaximized"], + "_spotifycontrolscontainerwithtimeline": ["SpotifyControls", "containerWithTimeline"], + "_spotifycontrolscover": ["SpotifyControls", "cover"], + "_spotifycontrolscovermaximizer": ["SpotifyControls", "coverMaximizer"], + "_spotifycontrolscoverwrapper": ["SpotifyControls", "coverWrapper"], + "_spotifycontrolsdetails": ["SpotifyControls", "details"], + "_spotifycontrolsinterpret": ["SpotifyControls", "interpret"], + "_spotifycontrolssettingsicon": ["SpotifyControls", "settingsIcon"], + "_spotifycontrolssettingslabel": ["SpotifyControls", "settingsLabel"], + "_spotifycontrolssong": ["SpotifyControls", "song"], + "_spotifycontrolstimeline": ["SpotifyControls", "timeline"], + "_spotifycontrolsvolumeslider": ["SpotifyControls", "volumeSlider"], + "_stafftagadminicon": ["StaffTag", "adminIcon"], + "_stafftaggroupownericon": ["StaffTag", "groupOwnerIcon"], + "_stafftagmanagementicon": ["StaffTag", "managementIcon"], + "_stafftagownericon": ["StaffTag", "ownerIcon"], + "_stafftagthreadcreatoricon": ["StaffTag", "threadCreatorIcon"], + "_themerepodragbar": ["ThemeRepo", "dragBar"], + "_themerepodragcorner": ["ThemeRepo", "dragCorner"], + "_themerepodraginterface": ["ThemeRepo", "dragInterface"], + "_themerepofailnotice": ["ThemeRepo", "failNotice"], + "_themerepoloadingicon": ["ThemeRepo", "loadingIcon"], + "_themerepoloadingtooltip": ["ThemeRepo", "loadingTooltip"], + "_themerepomovebar": ["ThemeRepo", "moveBar"], + "_themereponewentriesnotice": ["ThemeRepo", "newEntriesNotice"], + "_themereponotice": ["ThemeRepo", "repoNotice"], + "_themerepooutdatednotice": ["ThemeRepo", "outdatedNotice"], + "_themerepopreview": ["ThemeRepo", "preview"], + "_themerepopreviewfullscreen": ["ThemeRepo", "previewFullscreen"], + "_themerepopreviewmoving": ["ThemeRepo", "previewMoving"], + "_themesettingsbutton": ["ThemeSettings", "settingsButton"], + "_timedlightdarkmodedategrabber": ["TimedLightDarkMode", "dateGrabber"], + "_timedlightdarkmodetimergrabber": ["TimedLightDarkMode", "timerGrabber"], + "_timedlightdarkmodetimersettings": ["TimedLightDarkMode", "timerSettings"], + "_toproleseverywherebadgestyle": ["TopRolesEverywhere", "badgeStyle"], + "_toproleseverywherechattag": ["TopRolesEverywhere", "chatTag"], + "_toproleseverywheremembertag": ["TopRolesEverywhere", "memberTag"], + "_toproleseverywhererolestyle": ["TopRolesEverywhere", "roleStyle"], + "_toproleseverywheretag": ["TopRolesEverywhere", "tag"], + "_toproleseverywherevoicetag": ["TopRolesEverywhere", "voiceTag"], + "_translatorconfigbutton": ["Translator", "configButton"], + "_translatortranslatebutton": ["Translator", "translateButton"], + "_translatortranslated": ["Translator", "translated"], + "_translatortranslating": ["Translator", "translating"], + "_writeuppercasequicktogglebutton": ["WriteUpperCase", "quickToggleButton"], + "_writeuppercasequicktogglebuttonenabled": ["WriteUpperCase", "enabled"], + "_repoauthor": ["BD", "bdAuthor"], + "_repobutton": ["BD", "bdButton"], + "_repobuttondanger": ["BD", "bdButtonDanger"], + "_repocard": ["BD", "bdAddonCard"], + "_repocheckbox": ["BD", "switchCheckbox"], + "_repocheckboxchecked": ["BD", "switchChecked"], + "_repocheckboxinner": ["BD", "switch"], + "_repocheckboxitem": ["BD", "switchItem"], + "_repocheckboxwrap": ["BD", "switchWrapper"], + "_repocontrols": ["BD", "bdControls"], + "_repocontrolsbutton": ["BD", "bdControlsButton"], + "_repocontrolscustom": ["BDFDB", "bdControlsCustom"], + "_repodescription": ["BD", "bdDescription"], + "_repodescriptionwrap": ["BD", "bdDescriptionWrap"], + "_repoentry": ["BDFDB", "bdRepoEntry"], + "_repofolderbutton": ["BD", "bdFolderButton"], + "_repofooter": ["BD", "bdFooter"], + "_repofootercontrols": ["BDFDB", "bdRepoFooterControls"], + "_repoheader": ["BD", "bdHeader"], + "_repoheadercontrols": ["BDFDB", "bdRepoHeaderControls"], + "_repoheadertitle": ["BD", "bdHeaderTitle"], + "_repoicon": ["BD", "bdIcon"], + "_repolist": ["BD", "bdAddonList"], + "_repolistheader": ["BDFDB", "bdRepoListHeader"], + "_repolistwrapper": ["BDFDB", "bdRepoListWrapper"], + "_repolink": ["BD", "bdLink"], + "_repolinks": ["BD", "bdLinks"], + "_repometa": ["BD", "bdMeta"], + "_repomodal": ["BD", "bdAddonModal"], + "_repomodalfooter": ["BD", "bdAddonModalFooter"], + "_repomodalheader": ["BD", "bdAddonModalHeader"], + "_repomodalsettings": ["BD", "bdAddonModalSettings"], + "_reponame": ["BD", "bdName"], + "_reposettings": ["BD", "settings"], + "_reposettingsopen": ["BD", "settingsOpen"], + "_reposettingsclosed": ["BD", "settingsClosed"], + "_reposwitch": ["BD", "bdSwitch"], + "_reposwitchchecked": ["BD", "bdSwitchChecked"], + "_reposwitchinner": ["BD", "bdSwitchInner"], + "_repoupdatebutton": ["BD", "bdUpdatebtn"], + "_repoversion": ["BD", "bdVersion"], + "accountinfo": ["AccountDetails", "container"], + "accountinfoavatar": ["AccountDetails", "avatar"], + "accountinfoavatarwrapper": ["AccountDetails", "avatarWrapper"], + "accountinfobutton": ["AccountDetailsButtons", "button"], + "accountinfobuttondisabled": ["AccountDetailsButtons", "disabled"], + "accountinfobuttonenabled": ["AccountDetailsButtons", "enabled"], + "accountinfobuttonstrikethrough": ["AccountDetails", "strikethrough"], + "accountinfodetails": ["AccountDetails", "usernameContainer"], + "accountinfonametag": ["AccountDetails", "nameTag"], + "accountinfowithtagasbutton": ["AccountDetails", "withTagAsButton"], + "accountinfowithtagless": ["AccountDetails", "withTagAsButton"], + "aliasautocomplete": ["AutocompleteAliases", "autocomplete"], + "anchor": ["Anchor", "anchor"], + "anchorunderlineonhover": ["Anchor", "anchorUnderlineOnHover"], + "animationcontainerbottom": ["AnimationContainer", "animatorBottom"], + "animationcontainerleft": ["AnimationContainer", "animatorLeft"], + "animationcontainerright": ["AnimationContainer", "animatorRight"], + "animationcontainertop": ["AnimationContainer", "animatorTop"], + "animationcontainerrender": ["AnimationContainer", "didRender"], + "animationcontainerscale": ["AnimationContainer", "scale"], + "animationcontainertranslate": ["AnimationContainer", "translate"], + "app": ["AppOuter", "app"], + "appcontainer": ["AppBase", "container"], + "appinner": ["AppInner", "app"], + "appmount": ["AppMount", "appMount"], + "applayers": ["AppInner", "layers"], + "applicationstore": ["ApplicationStore", "applicationStore"], + "attachment": ["Attachment", "wrapper"], + "attachmentvideo": ["Attachment", "video"], + "auditlog": ["AuditLog", "auditLog"], + "auditlogoverflowellipsis": ["AuditLog", "overflowEllipsis"], + "auditlogtimestamp": ["AuditLog", "timestamp"], + "auditloguserhook": ["AuditLog", "userHook"], + "authbox": ["AuthBox", "authBox"], + "autocomplete": ["Autocomplete", "autocomplete"], + "autocompletecontenttitle": ["Autocomplete", "contentTitle"], + "autocompletedescriptiondiscriminator": ["Autocomplete", "descriptionDiscriminator"], + "autocompleteemoji": ["Autocomplete", "emojiImage"], + "autocompleteicon": ["Autocomplete", "icon"], + "autocompleteiconforeground": ["Autocomplete", "iconForeground"], + "autocompleteinner": ["Autocomplete", "autocompleteInner"], + "autocompleterow": ["Autocomplete", "autocompleteRow"], + "autocompleterowcontent": ["Autocomplete", "autocompleteRowContent"], + "autocompleterowcontentprimary": ["Autocomplete", "autocompleteRowContentPrimary"], + "autocompleterowcontentsecondary": ["Autocomplete", "autocompleteRowContentSecondary"], + "autocompleterowhorizontal": ["Autocomplete", "autocompleteRowHorizontal"], + "autocompleterowicon": ["Autocomplete", "autocompleteRowIcon"], + "autocompleterowsubheading": ["Autocomplete", "autocompleteRowSubheading"], + "autocompleterowvertical": ["Autocomplete", "autocompleteRowVertical"], + "autocompleteselectable": ["Autocomplete", "selectable"], + "autocompleteselected": ["Autocomplete", "selected"], + "avatar": ["Avatar", "avatar"], + "avatarcursordefault": ["Avatar", "cursorDefault"], + "avatardisabled": ["BDFDB", "avatarDisabled"], + "avataricon": ["AvatarIcon", "icon"], + "avatariconactivelarge": ["AvatarIcon", "iconActiveLarge"], + "avatariconactivemedium": ["AvatarIcon", "iconActiveMedium"], + "avatariconactivemini": ["AvatarIcon", "iconActiveMini"], + "avatariconactivesmall": ["AvatarIcon", "iconActiveSmall"], + "avatariconactivexlarge": ["AvatarIcon", "iconActiveXLarge"], + "avatariconinactive": ["AvatarIcon", "iconInactive"], + "avatariconsizelarge": ["AvatarIcon", "iconSizeLarge"], + "avatariconsizemedium": ["AvatarIcon", "iconSizeMedium"], + "avatariconsizemini": ["AvatarIcon", "iconSizeMini"], + "avatariconsizesmol": ["AvatarIcon", "iconSizeSmol"], + "avatariconsizesmall": ["AvatarIcon", "iconSizeSmall"], + "avatariconsizexlarge": ["AvatarIcon", "iconSizeXLarge"], + "avatarmask": ["Avatar", "mask"], + "avatarnoicon": ["AvatarIcon", "noIcon"], + "avatarpointer": ["Avatar", "pointer"], + "avatarpointerevents": ["Avatar", "pointerEvents"], + "avatarstack": ["Avatar", "avatarStack"], + "avatarsvg": ["Avatar", "svg"], + "avatarwrapper": ["Avatar", "wrapper"], + "backdrop": ["Backdrop", "backdrop"], + "backdropwithlayer": ["Backdrop", "withLayer"], + "badgebase": ["Badge", "base"], + "badgeicon": ["Badge", "icon"], + "badgeiconbadge": ["Badge", "iconBadge"], + "badgenumberbadge": ["Badge", "numberBadge"], + "badgeshaperound": ["Badge", "baseShapeRound"], + "badgeshaperoundleft": ["Badge", "baseShapeRoundLeft"], + "badgeshaperoundright": ["Badge", "baseShapeRoundRight"], + "badgetextbadge": ["Badge", "textBadge"], + "bdfdbbadge": ["BDFDB", "badge"], + "bdfdbbadgeavatar": ["BDFDB", "badgeAvatar"], + "bdfdbdev": ["BDFDB", "dev"], + "bdfdbhasbadge": ["BDFDB", "hasBadge"], + "bdfdbsupporter": ["BDFDB", "supporter"], + "bdfdbsupportert1": ["BDFDB", "supporterTier1"], + "bdfdbsupportert2": ["BDFDB", "supporterTier2"], + "bdfdbsupportert3": ["BDFDB", "supporterTier3"], + "bdfdbsupportert4": ["BDFDB", "supporterTier4"], + "bold": ["TextStyle", "bold"], + "bottag": ["BotTag", "botTag"], + "bottaginvert": ["BotTag", "botTagInvert"], + "bottagmember": ["Member", "botTag"], + "bottagnametag": ["NameTag", "bot"], + "bottagpx": ["BotTag", "px"], + "bottagregular": ["BotTag", "botTagRegular"], + "bottagrem": ["BotTag", "rem"], + "bottagtext": ["BotTag", "botText"], + "bottagverified": ["BotTag", "botTagVerified"], + "button": ["Button", "button"], + "buttoncolorbrand": ["Button", "colorBrand"], + "buttoncolorbrandnew": ["Button", "colorBrandNew"], + "buttoncolorgreen": ["Button", "colorGreen"], + "buttoncolorgrey": ["Button", "colorGrey"], + "buttoncolorlink": ["Button", "colorLink"], + "buttoncolorprimary": ["Button", "colorPrimary"], + "buttoncolorred": ["Button", "colorRed"], + "buttoncolortransparent": ["Button", "colorTransparent"], + "buttoncolorwhite": ["Button", "colorWhite"], + "buttoncoloryellow": ["Button", "colorYellow"], + "buttoncontents": ["Button", "contents"], + "buttondisabledoverlay": ["Button", "disabledButtonOverlay"], + "buttondisabledwrapper": ["Button", "disabledButtonWrapper"], + "buttonfullwidth": ["Button", "fullWidth"], + "buttongrow": ["Button", "grow"], + "buttonhashover": ["Button", "hasHover"], + "buttonhoverbrand": ["Button", "hoverBrand"], + "buttonhoverbrandnew": ["Button", "hoverBrandNew"], + "buttonhovergreen": ["Button", "hoverGreen"], + "buttonhovergrey": ["Button", "hoverGrey"], + "buttonhoverlink": ["Button", "hoverLink"], + "buttonhoverprimary": ["Button", "hoverPrimary"], + "buttonhoverred": ["Button", "hoverRed"], + "buttonhovertransparent": ["Button", "hoverTransparent"], + "buttonhoverwhite": ["Button", "hoverWhite"], + "buttonhoveryellow": ["Button", "hoverYellow"], + "buttonlookblank": ["Button", "lookBlank"], + "buttonlookfilled": ["Button", "lookFilled"], + "buttonlookinverted": ["Button", "lookInverted"], + "buttonlooklink": ["Button", "lookLink"], + "buttonlookoutlined": ["Button", "lookOutlined"], + "buttonsizeicon": ["Button", "sizeIcon"], + "buttonsizelarge": ["Button", "sizeLarge"], + "buttonsizemax": ["Button", "sizeMax"], + "buttonsizemedium": ["Button", "sizeMedium"], + "buttonsizemin": ["Button", "sizeMin"], + "buttonsizesmall": ["Button", "sizeSmall"], + "buttonsizexlarge": ["Button", "sizeXlarge"], + "buttonspinner": ["Button", "spinner"], + "buttonspinneritem": ["Button", "spinnerItem"], + "buttonsubmitting": ["Button", "submitting"], + "callcurrentchatsidebaropen": ["Video", "chatSidebarOpen"], + "callcurrentcontainer": ["CallCurrent", "wrapper"], + "callcurrentdetails": ["CallDetails", "container"], + "callcurrentvideo": ["Video", "video"], + "callincomingicon": ["CallIncoming", "icon"], + "callincomingroot": ["CallIncoming", "root"], + "callincomingtitle": ["CallIncoming", "title"], + "callincomingwrapper": ["CallIncoming", "wrapper"], + "card": ["Card", "card"], + "cardbrand": ["Card", "cardBrand"], + "cardbrandoutline": ["Card", "cardBrandOutline"], + "carddanger": ["Card", "cardDanger"], + "carddangeroutline": ["Card", "cardDangerOutline"], + "cardprimary": ["Card", "cardPrimary"], + "cardprimaryeditable": ["Card", "cardPrimaryEditable"], + "cardprimaryoutline": ["Card", "cardPrimaryOutline"], + "cardprimaryoutlineeditable": ["Card", "cardPrimaryOutlineEditable"], + "cardsuccess": ["Card", "cardSuccess"], + "cardsuccessoutline": ["Card", "cardSuccessOutline"], + "cardwarning": ["Card", "cardWarning"], + "cardwarningoutline": ["Card", "cardWarningOutline"], + "categoryarrow": ["CategoryArrow", "arrow"], + "categoryarrowopen": ["CategoryArrow", "open"], + "categoryaddbutton": ["Category", "addButton"], + "categoryaddbuttonicon": ["Category", "addButtonIcon"], + "categorychildren": ["Category", "children"], + "categoryclickable": ["Category", "clickable"], + "categorycollapsed": ["Category", "collapsed"], + "categorycontainerdefault": ["Category", "containerDefault"], + "categoryforcevisible": ["Category", "forceVisible"], + "categoryicon": ["Category", "icon"], + "categoryiconvisibility": ["Category", "iconVisibility"], + "categorymaincontent": ["Category", "mainContent"], + "categorymuted": ["Category", "muted"], + "categoryname": ["Category", "name"], + "categorywrapper": ["Category", "wrapper"], + "changelogadded": ["ChangeLog", "added"], + "changelogcontainer": ["ChangeLog", "container"], + "changelogfixed": ["ChangeLog", "fixed"], + "changelogfooter": ["ChangeLog", "footer"], + "changelogimproved": ["ChangeLog", "improved"], + "changelogprogress": ["ChangeLog", "progress"], + "changelogsociallink": ["ChangeLog", "socialLink"], + "changelogtitle": ["ChangeLog", "title"], + "channelactionicon": ["ChannelContainer", "actionIcon"], + "channelchildicon": ["ChannelContainer", "iconItem"], + "channelchildiconbase": ["ChannelContainer", "iconBase"], + "channelchildren": ["Channel", "children"], + "channelcontainerdefault": ["ChannelContainer", "containerDefault"], + "channelcontent": ["Channel", "content"], + "channeldisabled": ["ChannelContainer", "disabled"], + "channelheaderchannelname": ["ChatWindow", "channelName"], + "channelheaderchildren": ["HeaderBar", "children"], + "channelheaderdivider": ["HeaderBar", "divider"], + "channelheaderheaderbar": ["HeaderBar", "container"], + "channelheaderheaderbarthemed": ["HeaderBar", "themed"], + "channelheaderheaderbartitle": ["HeaderBar", "title"], + "channelheadericon": ["HeaderBar", "icon"], + "channelheadericonbadge": ["HeaderBar", "iconBadge"], + "channelheadericonclickable": ["HeaderBar", "clickable"], + "channelheadericonselected": ["HeaderBar", "selected"], + "channelheadericonwrapper": ["HeaderBar", "iconWrapper"], + "channelheadertitle": ["ChatWindow", "title"], + "channelheadertitlewrapper": ["ChatWindow", "titleWrapper"], + "channelheadersearch": ["HeaderBarExtras", "search"], + "channelheadersearchbar": ["HeaderBarSearch", "searchBar"], + "channelheadersearchicon": ["HeaderBarSearch", "icon"], + "channelheadersearchinner": ["HeaderBarSearch", "search"], + "channelheadertoolbar": ["HeaderBar", "toolbar"], + "channelheadertoolbar2": ["HeaderBarExtras", "toolbar"], + "channelheadertopic": ["HeaderBarTopic", "topic"], + "channelheadertopicexpandable": ["HeaderBarTopic", "expandable"], + "channelicon": ["Channel", "icon"], + "channeliconcontainer": ["Channel", "iconContainer"], + "channeliconitem": ["ChannelContainer", "iconItem"], + "channeliconvisibility": ["ChannelContainer", "iconVisibility"], + "channelinfo": ["ChannelContainer", "channelInfo"], + "channelmaincontent": ["Channel", "mainContent"], + "channelmentionsbadge": ["ChannelContainer", "mentionsBadge"], + "channelmodeconnected": ["Channel", "modeConnected"], + "channelmodelocked": ["Channel", "modeLocked"], + "channelmodemuted": ["Channel", "modeMuted"], + "channelmodeselected": ["Channel", "modeSelected"], + "channelmodeunread": ["Channel", "modeUnread"], + "channelname": ["Channel", "name"], + "channelnameinner": ["Channel", "channelName"], + "channelpanel": ["AppBase", "activityPanel"], + "channelpanels": ["AppBase", "panels"], + "channels": ["AppBase", "sidebar"], + "channelselected": ["ChannelContainer", "selected"], + "channelsscroller": ["GuildChannels", "scroller"], + "channelsunreadbar": ["GuildChannels", "unreadBar"], + "channelsunreadbarcontainer": ["GuildChannels", "positionedContainer"], + "channelsunreadbarbottom": ["GuildChannels", "unreadBottom"], + "channelsunreadbarunread": ["GuildChannels", "unread"], + "channelsunreadbartop": ["GuildChannels", "unreadTop"], + "channelunread": ["Channel", "unread"], + "channeluserlimit": ["ChannelLimit", "wrapper"], + "channeluserlimitcontainer": ["ChannelContainer", "userLimit"], + "channeluserlimittotal": ["ChannelLimit", "total"], + "channeluserlimitusers": ["ChannelLimit", "users"], + "channelwrapper": ["Channel", "wrapper"], + "charcounter": ["BDFDB", "charCounter"], + "chat": ["ChatWindow", "chat"], + "chatbase": ["AppBase", "base"], + "chatcontent": ["ChatWindow", "chatContent"], + "chatform": ["ChatWindow", "form"], + "chatinner": ["ChatWindow", "content"], + "chatspacer": ["AppBase", "content"], + "chatthreadsidebar": ["ChatThreadSidebar", "container"], + "chatthreadsidebaropen": ["ChatWindow", "threadSidebarOpen"], + "checkbox": ["Checkbox", "checkbox"], + "checkboxbox": ["Checkbox", "box"], + "checkboxchecked": ["Checkbox", "checked"], + "checkboxcontainer": ["ModalItems", "checkboxContainer"], + "checkboxinput": ["Checkbox", "input"], + "checkboxinputdefault": ["Checkbox", "inputDefault"], + "checkboxinputdisabled": ["Checkbox", "inputDisabled"], + "checkboxinputreadonly": ["Checkbox", "inputReadonly"], + "checkboxlabel": ["Checkbox", "label"], + "checkboxlabelclickable": ["Checkbox", "labelClickable"], + "checkboxlabeldisabled": ["Checkbox", "labelDisabled"], + "checkboxlabelforward": ["Checkbox", "labelForward"], + "checkboxlabelreversed": ["Checkbox", "labelReversed"], + "checkboxround": ["Checkbox", "round"], + "checkboxwrapper": ["Checkbox", "checkboxWrapper"], + "checkboxwrapperdisabled": ["Checkbox", "checkboxWrapperDisabled"], + "clamped": ["Clamped", "clamped"], + "collapsecontainer": ["BDFDB", "collapseContainer"], + "collapsecontainercollapsed": ["BDFDB", "collapseContainerCollapsed"], + "collapsecontainerheader": ["BDFDB", "collapseContainerHeader"], + "collapsecontainerinner": ["BDFDB", "collapseContainerInner"], + "collapsecontainermini": ["BDFDB", "collapseContainerMini"], + "collapsecontainertitle": ["BDFDB", "collapseContainerTitle"], + "colorbase": ["TextColor2", "base"], + "colormuted": ["TextColor2", "muted"], + "colorpicker": ["ColorPicker", "colorPickerCustom"], + "colorpickeralpha": ["BDFDB", "colorPickerAlpha"], + "colorpickeralphacheckered": ["BDFDB", "colorPickerAlphaCheckered"], + "colorpickeralphacursor": ["BDFDB", "colorPickerAlphaCursor"], + "colorpickeralphahorizontal": ["BDFDB", "colorPickerAlphaHorizontal"], + "colorpickergradient": ["BDFDB", "colorPickerGradient"], + "colorpickergradientbutton": ["BDFDB", "colorPickerGradientButton"], + "colorpickergradientbuttonenabled": ["BDFDB", "colorPickerGradientButtonEnabled"], + "colorpickergradientcheckered": ["BDFDB", "colorPickerGradientCheckered"], + "colorpickergradientcursor": ["BDFDB", "colorPickerGradientCursor"], + "colorpickergradientcursoredge": ["BDFDB", "colorPickerGradientCursorEdge"], + "colorpickergradientcursorselected": ["BDFDB", "colorPickerGradientCursorSelected"], + "colorpickergradienthorizontal": ["BDFDB", "colorPickerGradientHorizontal"], + "colorpickerhexinput": ["ColorPicker", "customColorPickerInput"], + "colorpickerhue": ["ColorPickerInner", "hue"], + "colorpickerhuecursor": ["NotFound", "hueCursor"], + "colorpickerhuehorizontal": ["NotFound", "hueHorizontal"], + "colorpickerhuevertical": ["NotFound", "hueVertical"], + "colorpickerinner": ["ColorPickerInner", "wrapper"], + "colorpickerrow": ["ColorPicker", "colorPickerRow"], + "colorpickersaturation": ["ColorPickerInner", "saturation"], + "colorpickersaturationblack": ["NotFound", "saturationBlack"], + "colorpickersaturationcolor": ["NotFound", "saturationColor"], + "colorpickersaturationcursor": ["NotFound", "saturationCursor"], + "colorpickersaturationwhite": ["NotFound", "saturationWhite"], + "colorpickerswatch": ["ColorPicker", "colorPickerSwatch"], + "colorpickerswatches": ["BDFDB", "colorPickerSwatches"], + "colorpickerswatchescontainer": ["ColorPicker", "container"], + "colorpickerswatchesdisabled": ["BDFDB", "colorPickerSwatchesDisabled"], + "colorpickerswatchcustom": ["ColorPicker", "custom"], + "colorpickerswatchcustomcontainer": ["ColorPicker", "customContainer"], + "colorpickerswatchdefault": ["ColorPicker", "default"], + "colorpickerswatchdefaultcontainer": ["ColorPicker", "defaultContainer"], + "colorpickerswatchdisabled": ["ColorPicker", "disabled"], + "colorpickerswatchdropper": ["ColorPicker", "colorPickerDropper"], + "colorpickerswatchdropperfg": ["ColorPicker", "colorPickerDropperFg"], + "colorpickerswatchnocolor": ["ColorPicker", "noColor"], + "colorpickerswatchselected": ["BDFDB", "colorPickerSwatchSelected"], + "colorpickerswatchsingle": ["BDFDB", "colorPickerSwatchSingle"], + "colorpickerswatchsinglewrapper": ["BDFDB", "colorPickerSwatchSingleWrapper"], + "colorpickerwrapper": ["BDFDB", "colorPicker"], + "colorprimary": ["TextColor", "colorHeaderPrimary"], + "colorred": ["TextColor", "colorStatusRed"], + "colorsecondary": ["TextColor", "colorHeaderSecondary"], + "colorselectable": ["TextColor", "selectable"], + "colorstandard": ["TextColor", "colorStandard"], + "coloryellow": ["TextColor", "colorStatusYellow"], + "combobox": ["Combobox", "combobox"], + "comboboxitem": ["Combobox", "item"], + "comboboxitemlabel": ["Combobox", "itemLabel"], + "cursordefault": ["Cursor", "cursorDefault"], + "cursorpointer": ["BDFDB", "cursorPointer"], + "customstatusemoji": ["CustomStatusIcon", "emoji"], + "customstatusicon": ["CustomStatusIcon", "icon"], + "customstatusitem": ["CustomStatusPopout", "statusItem"], + "customstatusitemclearbutton": ["CustomStatusPopout", "clearStatusButton"], + "customstatusitemclearicon": ["CustomStatusPopout", "clearStatusIcon"], + "customstatusitemcustom": ["CustomStatusPopout", "customStatusItem"], + "customstatusitemcustomtext": ["CustomStatusPopout", "customText"], + "customstatusitemcustomwithemoji": ["CustomStatusPopout", "customStatusWithEmoji"], + "customstatusitememoji": ["CustomStatusPopout", "customEmoji"], + "customstatusmodal": ["CustomStatusModal", "modalRoot"], + "dateinputbutton": ["BDFDB", "dateInputButton"], + "dateinputbuttonselected": ["BDFDB", "dateInputButtonSelected"], + "dateinputcontrols": ["BDFDB", "dateInputControls"], + "dateinputfield": ["BDFDB", "dateInputField"], + "dateinputinner": ["BDFDB", "dateInputInner"], + "dateinputpreview": ["BDFDB", "dateInputPreview"], + "dateinputpreviewprefix": ["BDFDB", "dateInputPreviewPrefix"], + "dateinputpreviewsuffix": ["BDFDB", "dateInputPreviewSuffix"], + "dateinputwrapper": ["BDFDB", "dateInputWrapper"], + "defaultcolor": ["Text", "defaultColor"], + "description": ["FormText", "description"], + "directiondown": ["IconDirection", "directionDown"], + "directionleft": ["IconDirection", "directionLeft"], + "directionright": ["IconDirection", "directionRight"], + "directionup": ["IconDirection", "directionUp"], + "directiontransition": ["IconDirection", "transition"], + "discoverycard": ["BDFDB", "discoveryCard"], + "discoverycardauthor": ["BDFDB", "discoveryCardAuthor"], + "discoverycardbutton": ["BDFDB", "discoveryCardButton"], + "discoverycardcontrols": ["BDFDB", "discoveryCardControls"], + "discoverycardcover": ["BDFDB", "discoveryCardCover"], + "discoverycardcoverbadge": ["BDFDB", "discoveryCardCoverBadge"], + "discoverycardcoverwrapper": ["BDFDB", "discoveryCardCoverWrapper"], + "discoverycarddescription": ["BDFDB", "discoveryCardDescription"], + "discoverycardfooter": ["BDFDB", "discoveryCardFooter"], + "discoverycardheader": ["BDFDB", "discoveryCardHeader"], + "discoverycardicon": ["BDFDB", "discoveryCardIcon"], + "discoverycardiconloading": ["BDFDB", "discoveryCardIconLoading"], + "discoverycardiconwrapper": ["BDFDB", "discoveryCardIconWrapper"], + "discoverycardinfo": ["BDFDB", "discoveryCardInfo"], + "discoverycardname": ["BDFDB", "discoveryCardName"], + "discoverycards": ["BDFDB", "discoveryCards"], + "discoverycardstat": ["BDFDB", "discoveryCardStat"], + "discoverycardstaticon": ["BDFDB", "discoveryCardStatIcon"], + "discoverycardstats": ["BDFDB", "discoveryCardStats"], + "discoverycardtag": ["BDFDB", "discoveryCardTag"], + "discoverycardtags": ["BDFDB", "discoveryCardTags"], + "discoverycardtitle": ["BDFDB", "discoveryCardTitle"], + "discoverycardtitlebutton": ["BDFDB", "discoveryCardTitleButton"], + "divider": ["ModalDivider", "divider"], + "dividerdefault": ["SettingsItems", "dividerDefault"], + "dmchannel": ["PrivateChannel", "channel"], + "dmchannelactivity": ["PrivateChannel", "activity"], + "dmchannelactivityemoji": ["PrivateChannel", "activityEmoji"], + "dmchannelactivitytext": ["PrivateChannel", "activityText"], + "dmchannelclose": ["PrivateChannel", "closeButton"], + "dmchannelheadercontainer": ["PrivateChannelListScroller", "privateChannelsHeaderContainer"], + "dmchannelheadertext": ["PrivateChannelListScroller", "headerText"], + "dmchannels": ["PrivateChannelList", "privateChannels"], + "dmchannelsempty": ["PrivateChannelListScroller", "empty"], + "dmchannelsscroller": ["PrivateChannelListScroller", "scroller"], + "dmpill": ["GuildDm", "pill"], + "downloadlink": ["DownloadLink", "downloadLink"], + "ellipsis": ["PopoutActivity", "ellipsis"], + "embed": ["Embed", "embed"], + "embedauthor": ["Embed", "embedAuthor"], + "embedauthoricon": ["Embed", "embedAuthorIcon"], + "embedauthorname": ["Embed", "embedAuthorName"], + "embedauthornamelink": ["Embed", "embedAuthorNameLink"], + "embedcentercontent": ["Embed", "centerContent"], + "embeddescription": ["Embed", "embedDescription"], + "embedfield": ["Embed", "embedField"], + "embedfieldname": ["Embed", "embedFieldName"], + "embedfields": ["Embed", "embedFields"], + "embedfieldvalue": ["Embed", "embedFieldValue"], + "embedfooter": ["Embed", "embedFooter"], + "embedfootericon": ["Embed", "embedFooterIcon"], + "embedfooterseparator": ["Embed", "embedFooterSeparator"], + "embedfootertext": ["Embed", "embedFooterText"], + "embedfull": ["Embed", "embedFull"], + "embedgiftag": ["Embed", "embedGIFTag"], + "embedgrid": ["Embed", "grid"], + "embedhasthumbnail": ["Embed", "hasThumbnail"], + "embedhiddenspoiler": ["Embed", "hiddenSpoiler"], + "embediframe": ["Embed", "embedIframe"], + "embedimage": ["Embed", "embedImage"], + "embedlink": ["Embed", "embedLink"], + "embedmargin": ["Embed", "embedMargin"], + "embedmedia": ["Embed", "embedMedia"], + "embedprovider": ["Embed", "embedProvider"], + "embedspoilerattachment": ["Embed", "spoilerAttachment"], + "embedspoilerembed": ["Embed", "spoilerEmbed"], + "embedspotify": ["Embed", "embedSpotify"], + "embedthumbnail": ["Embed", "embedThumbnail"], + "embedtitle": ["Embed", "embedTitle"], + "embedtitlelink": ["Embed", "embedTitleLink"], + "embedvideo": ["Embed", "embedVideo"], + "embedvideoaction": ["Embed", "embedVideoAction"], + "embedvideoactions": ["Embed", "embedVideoActions"], + "embedvideoimagecomponent": ["Embed", "embedVideoImageComponent"], + "embedvideoimagecomponentinner": ["Embed", "embedVideoImageComponentInner"], + "embedwrapper": ["MessageAccessory", "embedWrapper"], + "emoji": ["Emoji", "emoji"], + "emojiold": ["NotFound", "emoji"], + "emojibutton": ["EmojiButton", "emojiButton"], + "emojibuttonhovered": ["EmojiButton", "emojiButtonHovered"], + "emojibuttonnormal": ["EmojiButton", "emojiButtonNormal"], + "emojibuttonsprite": ["EmojiButton", "sprite"], + "emojiinput": ["CustomStatusModal", "input"], + "emojiinputbutton": ["CustomStatusModal", "emojiButton"], + "emojiinputbuttoncontainer": ["CustomStatusModal", "emojiButtonContainer"], + "emojiinputclearbutton": ["CustomStatusModal", "clearButton"], + "emojiinputclearicon": ["CustomStatusModal", "clearIcon"], + "emojiinputcontainer": ["CustomStatusModal", "inputContainer"], + "emojipickerbutton": ["Reactions", "reactionBtn"], + "emojipicker": ["EmojiPicker", "emojiPicker"], + "emojipickerdiversityemojiitem": ["EmojiPickerDiversitySelector", "diversityEmojiItem"], + "emojipickerdiversityemojiitemimage": ["EmojiPickerDiversitySelector", "diversityEmojiItemImage"], + "emojipickerdiversityselector": ["EmojiPicker", "diversitySelector"], + "emojipickerdiversityselectoroptions": ["EmojiPickerDiversitySelector", "diversitySelectorOptions"], + "emojipickerdiversityselectorwrapper": ["EmojiPicker", "diversitySelector"], + "emojipickeremojispriteimage": ["EmojiPickerItem", "emojiSpriteImage"], + "emojipickerheader": ["EmojiPicker", "header"], + "emojipickerinspector": ["EmojiPickerInspector", "inspector"], + "emojipickerinspectoremoji": ["EmojiPickerInspectorEmoji", "emoji"], + "errorscreen": ["ErrorScreen", "wrapper"], + "expressionpicker": ["ExpressionPicker", "contentWrapper"], + "expressionpickernav": ["ExpressionPicker", "nav"], + "expressionpickernavbutton": ["ExpressionPicker", "navButton"], + "expressionpickernavbuttonactive": ["ExpressionPicker", "navButtonActive"], + "expressionpickernavitem": ["ExpressionPicker", "navItem"], + "expressionpickernavlist": ["ExpressionPicker", "navList"], + "favbutton": ["FavButton", "gifFavoriteButton"], + "favbuttoncontainer": ["BDFDB", "favButtonContainer"], + "favbuttonicon": ["FavButton", "icon"], + "favbuttonselected": ["FavButton", "selected"], + "fileattachment": ["File", "attachment"], + "fileattachmentinner": ["File", "attachmentInner"], + "filecancelbutton": ["File", "cancelButton"], + "filedownloadbutton": ["File", "downloadButton"], + "filename": ["File", "filename"], + "filenamelink": ["File", "fileNameLink"], + "filenamelinkwrapper": ["File", "filenameLinkWrapper"], + "filenamewrapper": ["File", "filenameWrapper"], + "flex": ["FlexChild", "flex"], + "flex2": ["Flex", "flex"], + "flexalignbaseline": ["Flex", "alignBaseline"], + "flexaligncenter": ["Flex", "alignCenter"], + "flexalignend": ["Flex", "alignEnd"], + "flexalignstart": ["Flex", "alignStart"], + "flexalignstretch": ["Flex", "alignStretch"], + "flexcenter": ["Flex", "flexCenter"], + "flexchild": ["FlexChild", "flexChild"], + "flexdirectioncolumn": ["Flex", "directionColumn"], + "flexdirectionrow": ["Flex", "directionRow"], + "flexdirectionrowreverse": ["Flex", "directionRowReverse"], + "flexhorizontal": ["FlexChild", "horizontal"], + "flexhorizontalreverse": ["FlexChild", "horizontalReverse"], + "flexjustifycenter": ["Flex", "justifyCenter"], + "flexjustifyend": ["Flex", "justifyEnd"], + "flexjustifystart": ["Flex", "justifyStart"], + "flexmarginreset": ["FlexChild", "flexMarginReset"], + "flexnowrap": ["Flex", "noWrap"], + "flexspacer": ["Flex", "spacer"], + "flexvertical": ["Flex", "vertical"], + "flexwrap": ["Flex", "wrap"], + "flexwrapreverse": ["Flex", "wrapReverse"], + "flowerstar": ["FlowerStar", "flowerStar"], + "flowerstarchild": ["FlowerStar", "childContainer"], + "flowerstarcontainer": ["FlowerStar", "flowerStarContainer"], + "formtext": ["FormText", "formText"], + "game": ["Game", "game"], + "gameicon": ["GameIcon", "gameIcon"], + "gameiconlarge": ["GameIcon", "large"], + "gameiconmedium": ["GameIcon", "medium"], + "gameiconsmall": ["GameIcon", "small"], + "gameiconxsmall": ["GameIcon", "xsmall"], + "gamelibrarytable": ["GameLibraryTable", "table"], + "gamelibrarytableheader": ["GameLibraryTable", "header"], + "gamelibrarytableheadercell": ["GameLibraryTable", "headerCell"], + "gamelibrarytableheadercellsorted": ["GameLibraryTable", "headerCellSorted"], + "gamelibrarytablerow": ["GameLibraryTable", "row"], + "gamelibrarytablerowwrapper": ["GameLibraryTable", "rowWrapper"], + "gamelibrarytablestickyheader": ["GameLibraryTable", "stickyHeader"], + "gamename": ["Game", "gameName"], + "gamenameinput": ["Game", "gameNameInput"], + "giffavoritebutton": ["MessageAccessory", "gifFavoriteButton"], + "giffavoritecolor": ["GifFavoriteButton", "gifFavoriteButton"], + "giffavoriteicon": ["GifFavoriteButton", "icon"], + "giffavoriteshowpulse": ["GifFavoriteButton", "showPulse"], + "giffavoritesize": ["GifFavoriteButton", "size"], + "giffavoriteselected": ["GifFavoriteButton", "selected"], + "goliveactions": ["GoLiveDetails", "actions"], + "golivebody": ["GoLiveDetails", "body"], + "goliveclickablegamewrapper": ["GoLiveDetails", "clickableGameWrapper"], + "golivegameicon": ["GoLiveDetails", "gameIcon"], + "golivegamename": ["GoLiveDetails", "gameName"], + "golivegamewrapper": ["GoLiveDetails", "gameWrapper"], + "goliveinfo": ["GoLiveDetails", "info"], + "golivepanel": ["GoLiveDetails", "panel"], + "guild": ["BDFDB", "guild"], + "guildbuttonbase": ["GuildsItems", "circleButtonBase"], + "guildbuttoninner": ["GuildsButton", "circleIconButton"], + "guildbuttonicon": ["GuildsButton", "circleIcon"], + "guildbuttonpill": ["GuildsButton", "pill"], + "guildbuttonselected": ["GuildsButton", "selected"], + "guildchannels": ["GuildChannelsWrapper", "container"], + "guildcontainer": ["GuildServer", "blobContainer"], + "guilddiscovery": ["GuildDiscovery", "pageWrapper"], + "guildfolder": ["GuildFolder", "folder"], + "guildfolderexpandedbackground": ["GuildFolder", "expandedFolderBackground"], + "guildfolderexpandedbackgroundcollapsed": ["GuildFolder", "collapsed"], + "guildfolderexpandedbackgroundhover": ["GuildFolder", "hover"], + "guildfolderguildicon": ["GuildFolder", "guildIcon"], + "guildfoldericonwrapper": ["GuildFolder", "folderIconWrapper"], + "guildfoldericonwrapperclosed": ["GuildFolder", "closedFolderIconWrapper"], + "guildfoldericonwrapperexpanded": ["GuildFolder", "expandedFolderIconWrapper"], + "guildfolderwrapper": ["GuildFolder", "wrapper"], + "guildheader": ["GuildHeader", "container"], + "guildheaderbannerimage": ["GuildHeader", "bannerImage"], + "guildheaderbannerimagecontainer": ["GuildHeader", "animatedContainer"], + "guildheaderbannervisible": ["GuildHeader", "bannerVisible"], + "guildheaderbutton": ["GuildHeaderButton", "button"], + "guildheaderbuttonopen": ["GuildHeaderButton", "open"], + "guildheaderclickable": ["GuildHeader", "clickable"], + "guildheaderhasbanner": ["GuildHeader", "hasBanner"], + "guildheadericoncontainer": ["GuildHeader", "guildIconContainer"], + "guildheadericonbgtiernone": ["GuildHeader", "iconBackgroundTierNone"], + "guildheadericonbgtierone": ["GuildHeader", "iconBackgroundTierOne"], + "guildheadericonbgtierthree": ["GuildHeader", "iconBackgroundTierThree"], + "guildheadericonbgtiertwo": ["GuildHeader", "iconBackgroundTierTwo"], + "guildheadericonpremiumgem": ["GuildHeader", "premiumGuildIconGem"], + "guildheadericontiernone": ["GuildHeader", "iconTierNone"], + "guildheadericontierone": ["GuildHeader", "iconTierOne"], + "guildheadericontierthree": ["GuildHeader", "iconTierThree"], + "guildheadericontiertwo": ["GuildHeader", "iconTierTwo"], + "guildheaderheader": ["GuildHeader", "header"], + "guildheadername": ["GuildHeader", "name"], + "guildicon": ["GuildIcon", "icon"], + "guildiconacronym": ["GuildIcon", "acronym"], + "guildiconbadge": ["GuildsItems", "iconBadge"], + "guildiconchildwrapper": ["GuildIcon", "childWrapper"], + "guildiconselected": ["GuildIcon", "selected"], + "guildiconwrapper": ["GuildIcon", "wrapper"], + "guildinbox": ["GuildsInbox", "listItemWrapper"], + "guildinboxicon": ["GuildsInboxIcon", "iconButton"], + "guildinboxiconmask": ["GuildsInboxIcon", "iconMask"], + "guildinboxiconselected": ["GuildsInboxIcon", "selected"], + "guildinboxtooltip": ["GuildsInbox", "listItemTooltip"], + "guildinner": ["Guild", "wrapper"], + "guildinnerwrapper": ["GuildsItems", "listItemWrapper"], + "guildlowerbadge": ["Guild", "lowerBadge"], + "guildlowerleftbadge": ["BDFDB", "guildLowerLeftBadge"], + "guildouter": ["GuildItem", "listItem"], + "guildpill": ["GuildServer", "pill"], + "guildpillitem": ["PillWrapper", "item"], + "guildpillwrapper": ["PillWrapper", "wrapper"], + "guildplaceholder": ["GuildsDragPlaceholder", "dragInner"], + "guildplaceholdermask": ["GuildsDragPlaceholder", "placeholderMask"], + "guilds": ["AppBase", "guilds"], + "guildseparator": ["GuildSeparator", "guildSeparator"], + "guildserror": ["GuildsItems", "guildsError"], + "guildserrorinner": ["GuildsItems", "errorInner"], + "guildsettingsbannedcard": ["GuildSettingsBanned", "bannedUser"], + "guildsettingsbanneddiscrim": ["GuildSettingsBanned", "discrim"], + "guildsettingsbannedusername": ["GuildSettingsBanned", "username"], + "guildsettingsemojicard": ["GuildSettingsEmoji", "emojiRow"], + "guildsettingsinvitecard": ["GuildSettingsInvite", "inviteSettingsInviteRow"], + "guildsettingsinvitechannelname": ["GuildSettingsInvite", "channelName"], + "guildsettingsinviteusername": ["GuildSettingsInvite", "username"], + "guildsettingsmembercard": ["GuildSettingsMember", "member"], + "guildsettingsmembername": ["GuildSettingsMember", "name"], + "guildsettingsmembernametag": ["GuildSettingsMember", "nameTag"], + "guildslabel": ["BDFDB", "guildsLabel"], + "guildsscroller": ["GuildsWrapper", "scroller"], + "guildstree": ["GuildsWrapper", "tree"], + "guildsummaryclickableicon": ["BDFDB", "guildSummaryClickableIcon"], + "guildsummarycontainer": ["BDFDB", "guildSummaryContainer"], + "guildsummaryemptyguild": ["BDFDB", "guildSummaryEmptyGuild"], + "guildsummaryicon": ["BDFDB", "guildSummaryIcon"], + "guildsummaryiconcontainer": ["BDFDB", "guildSummaryIconContainer"], + "guildsummaryiconcontainermasked": ["BDFDB", "guildSummaryIconContainerMasked"], + "guildsummarymoreguilds": ["BDFDB", "guildSummaryMoreGuilds"], + "guildsummarysvgicon": ["BDFDB", "guildSummarySvgIcon"], + "guildsvg": ["Guild", "svg"], + "guildswrapper": ["GuildsWrapper", "wrapper"], + "guildswrapperhidden": ["GuildsWrapper", "hidden"], + "guildswrapperunreadmentionsbar": ["GuildsWrapper", "unreadMentionsBar"], + "guildswrapperunreadmentionsbarbottom": ["GuildsWrapper", "unreadMentionsIndicatorBottom"], + "guildswrapperunreadmentionsbartop": ["GuildsWrapper", "unreadMentionsIndicatorTop"], + "guildtarget": ["GuildEdges", "target"], + "guildtargetcenter": ["GuildEdges", "centerTarget"], + "guildtargetwrapper": ["GuildEdges", "wrapper"], + "guildtutorialcontainer": ["GuildsItems", "tutorialContainer"], + "guildupperbadge": ["Guild", "upperBadge"], + "guildupperleftbadge": ["BDFDB", "guildUpperLeftBadge"], + "guildvoicelist": ["BDFDB", "guildVoiceList"], + "h1": ["Text", "h1"], + "h1defaultmargin": ["Text", "defaultMarginh1"], + "h2": ["Text", "h2"], + "h2defaultmargin": ["Text", "defaultMarginh2"], + "h3": ["Text", "h3"], + "h3defaultmargin": ["Text", "defaultMarginh3"], + "h4": ["Text", "h4"], + "h4defaultmargin": ["Text", "defaultMarginh4"], + "h5": ["Text", "h5"], + "h5defaultmargin": ["Text", "defaultMarginh5"], + "headertitle": ["Text", "title"], + "headerwrapper": ["TextColor2", "wrapper"], + "highlight": ["NotFound", "highlight"], + "homebuttonicon": ["HomeIcon", "homeIcon"], + "homebuttonpill": ["HomeIcon", "pill"], + "hotkeybutton": ["HotKeyRecorder", "button"], + "hotkeycontainer": ["HotKeyRecorder", "container"], + "hotkeydisabled": ["HotKeyRecorder", "disabled"], + "hotkeyediticon": ["HotKeyRecorder", "editIcon"], + "hotkeyhasvalue": ["HotKeyRecorder", "hasValue"], + "hotkeyinput": ["HotKeyRecorder", "input"], + "hotkeyinput2": ["HotKeyRecorder", "input"], + "hotkeylayout": ["HotKeyRecorder", "layout"], + "hotkeylayout2": ["HotKeyRecorder", "layout"], + "hotkeyrecording": ["HotKeyRecorder", "recording"], + "hotkeyresetbutton": ["BDFDB", "hotkeyResetButton"], + "hotkeyshadowpulse": ["HotKeyRecorder", "shadowPulse"], + "hotkeytext": ["HotKeyRecorder", "text"], + "hotkeywrapper": ["BDFDB", "hotkeyWrapper"], + "hovercard": ["HoverCard", "card"], + "hovercardbutton": ["NotFound", "hoverCardButton"], + "hovercarddisabled": ["BDFDB", "cardDisabled"], + "hovercardhorizontal": ["BDFDB", "cardHorizontal"], + "hovercardinner": ["BDFDB", "cardInner"], + "hovercardremovebutton": ["HoverCardRemoveButton", "button"], + "hovercardremovebuttondefault": ["HoverCardRemoveButton", "default"], + "hovercardremovebuttonfilled": ["HoverCardRemoveButton", "filled"], + "hovercardwrapper": ["BDFDB", "cardWrapper"], + "icon": ["EmbedActions", "icon"], + "iconactionswrapper": ["EmbedActions", "wrapper"], + "iconexternal": ["EmbedActions", "iconExternal"], + "iconexternalmargins": ["EmbedActions", "iconExternalMargins"], + "iconplay": ["EmbedActions", "iconPlay"], + "iconwrapper": ["EmbedActions", "iconWrapper"], + "iconwrapperactive": ["EmbedActions", "iconWrapperActive"], + "imageaccessory": ["ImageWrapper", "imageAccessory"], + "imagealttext": ["MessageElements", "altText"], + "imageclickable": ["ImageWrapper", "clickable"], + "imageerror": ["ImageWrapper", "imageError"], + "imageoriginallink": ["ImageWrapper", "originalLink"], + "imageplaceholder": ["ImageWrapper", "imagePlaceholder"], + "imageplaceholderoverlay": ["ImageWrapper", "imagePlaceholderOverlay"], + "imagemodal": ["ImageModal", "modal"], + "imagemodalimage": ["ImageModal", "image"], + "imagesticker": ["ImageAssets", "stickerAsset"], + "imagewrapper": ["ImageWrapper", "imageWrapper"], + "imagewrapperbackground": ["ImageWrapper", "imageWrapperBackground"], + "imagewrapperinner": ["ImageWrapper", "imageWrapperInner"], + "imagezoom": ["ImageWrapper", "imageZoom"], + "itemlayer": ["ItemLayerContainer", "layer"], + "itemlayercontainer": ["ItemLayerContainer", "layerContainer"], + "itemlayercontainerzindexdisabled": ["BDFDB", "layerContainerZIndexDisabled"], + "itemlayerdisabledpointerevents": ["ItemLayerContainer", "disabledPointerEvents"], + "input": ["Input", "input"], + "inputdefault": ["Input", "inputDefault"], + "inputdisabled": ["Input", "disabled"], + "inputeditable": ["Input", "editable"], + "inputerror": ["Input", "error"], + "inputfocused": ["Input", "focused"], + "inputlist": ["BDFDB", "listInput"], + "inputlistdelete": ["BDFDB", "listInputDelete"], + "inputlistitem": ["BDFDB", "listInputItem"], + "inputlistitems": ["BDFDB", "listInputItems"], + "inputmini": ["Input", "inputMini"], + "inputmulti": ["BDFDB", "multiInput"], + "inputmultifield": ["BDFDB", "multiInputField"], + "inputmultifirst": ["BDFDB", "multiInputFirst"], + "inputmultilast": ["BDFDB", "multiInputLast"], + "inputmultiwrapper": ["BDFDB", "multiInputWrapper"], + "inputnumberbutton": ["BDFDB", "inputNumberButton"], + "inputnumberbuttondown": ["BDFDB", "inputNumberButtonDown"], + "inputnumberbuttonup": ["BDFDB", "inputNumberButtonUp"], + "inputnumberbuttons": ["BDFDB", "inputNumberButtons"], + "inputnumberwrapper": ["BDFDB", "inputNumberWrapper"], + "inputnumberwrapperdefault": ["BDFDB", "inputNumberWrapperDefault"], + "inputnumberwrappermini": ["BDFDB", "inputNumberWrapperMini"], + "inputprefix": ["Input", "inputPrefix"], + "inputsuccess": ["Input", "success"], + "inputwrapper": ["Input", "inputWrapper"], + "invite": ["GuildInvite", "wrapper"], + "invitebutton": ["GuildInvite", "button"], + "invitebuttonfornonmember": ["GuildInvite", "buttonForNonMember"], + "invitebuttonresolving": ["GuildInvite", "invite-button-resolving"], + "invitebuttonsize": ["GuildInvite", "buttonSize"], + "invitechannel": ["GuildInvite", "channel"], + "invitechannelicon": ["GuildInvite", "channelIcon"], + "invitechannelname": ["GuildInvite", "channelName"], + "invitecontent": ["GuildInvite", "content"], + "invitecount": ["GuildInvite", "count"], + "invitecursordefault": ["GuildInvite", "cursorDefault"], + "invitedestination": ["GuildInvite", "inviteDestination"], + "invitedestinationexpired": ["GuildInvite", "inviteDestinationExpired"], + "invitedestinationjoined": ["GuildInvite", "inviteDestinationJoined"], + "inviteguildbadge": ["GuildInvite", "guildBadge"], + "inviteguilddetail": ["GuildInvite", "guildDetail"], + "inviteguildicon": ["GuildInvite", "guildIcon"], + "inviteguildiconexpired": ["GuildInvite", "guildIconExpired"], + "inviteguildiconimage": ["GuildInvite", "guildIconImage"], + "inviteguildiconimagejoined": ["GuildInvite", "guildIconImageJoined"], + "inviteguildiconjoined": ["GuildInvite", "guildIconJoined"], + "inviteguildinfo": ["GuildInvite", "guildInfo"], + "inviteguildname": ["GuildInvite", "guildName"], + "inviteguildnamewrapper": ["GuildInvite", "guildNameWrapper"], + "inviteheader": ["GuildInvite", "header"], + "invitemodal": ["InviteModal", "modal"], + "invitemodalinviterow": ["InviteModal", "inviteRow"], + "invitemodalinviterowname": ["InviteModal", "inviteRowName"], + "invitemodalwrapper": ["InviteModal", "wrapper"], + "invitesplash": ["GuildInvite", "inviteSplash"], + "invitesplashimage": ["GuildInvite", "inviteSplashImage"], + "invitesplashimageloaded": ["GuildInvite", "inviteSplashImageLoaded"], + "inviteresolving": ["GuildInvite", "resolving"], + "inviteresolvingbackground": ["GuildInvite", "resolvingBackground"], + "invitestatus": ["GuildInvite", "status"], + "invitestatuscounts": ["GuildInvite", "statusCounts"], + "invitestatusoffline": ["GuildInvite", "statusOffline"], + "invitestatusonline": ["GuildInvite", "statusOnline"], + "inviteuserselectnone": ["GuildInvite", "userSelectNone"], + "italics": ["TextStyle", "italics"], + "layer": ["Layers", "layer"], + "layerbase": ["Layers", "baseLayer"], + "layers": ["Layers", "layers"], + "layersbg": ["Layers", "bg"], + "listavatar": ["UserProfileList", "listAvatar"], + "listdiscriminator": ["UserProfileList", "listDiscriminator"], + "listguildavatar": ["UserProfileListGuild", "guildAvatar"], + "listguildavatarwithouticon": ["UserProfileListGuild", "guildAvatarWithoutIcon"], + "listname": ["UserProfileList", "listName"], + "listrow": ["UserProfileList", "listRow"], + "listrowcontent": ["UserProfileList", "listRowContent"], + "listrowwrapper": ["BDFDB", "listRow"], + "listscroller": ["UserProfileList", "listScroller"], + "livetag": ["LiveTag", "live"], + "livetaggrey": ["LiveTag", "grey"], + "livetaglarge": ["LiveTag", "liveLarge"], + "livetagsmall": ["LiveTag", "liveSmall"], + "loadingicon": ["BDFDB", "loadingIcon"], + "loadingiconwrapper": ["BDFDB", "loadingIconWrapper"], + "loadingscreen": ["LoadingScreen", "container"], + "loginscreen": ["NotFound", "loginScreen"], + "marginbottom4": ["Margins", "marginBottom4"], + "marginbottom8": ["Margins", "marginBottom8"], + "marginbottom20": ["Margins", "marginBottom20"], + "marginbottom40": ["Margins", "marginBottom40"], + "marginbottom60": ["Margins", "marginBottom60"], + "margincenterhorz": ["Margins", "marginCenterHorz"], + "marginleft4": ["BDFDB", "marginLeft4"], + "marginleft8": ["BDFDB", "marginLeft8"], + "marginreset": ["Margins", "marginReset"], + "margintop4": ["Margins", "marginTop4"], + "margintop8": ["Margins", "marginTop8"], + "margintop20": ["Margins", "marginTop20"], + "margintop40": ["Margins", "marginTop40"], + "margintop60": ["Margins", "marginTop60"], + "member": ["Member", "member"], + "memberactivity": ["Member", "activity"], + "membericon": ["Member", "icon"], + "memberoffline": ["Member", "offline"], + "memberownericon": ["Member", "ownerIcon"], + "memberpremiumicon": ["Member", "premiumIcon"], + "members": ["MembersWrapper", "members"], + "membersgroup": ["MembersWrapper", "membersGroup"], + "memberswrap": ["MembersWrapper", "membersWrap"], + "memberusername": ["Member", "roleColor"], + "mention": ["NotFound", "mention"], + "mentioninteractive": ["NotFound", "mentionInteractive"], + "mentionwrapper": ["NotFound", "mentionWrapper"], + "menu": ["Menu", "menu"], + "menucaret": ["Menu", "caret"], + "menucaretarrow": ["MenuCaret", "arrow"], + "menucaretopen": ["MenuCaret", "open"], + "menucheck": ["Menu", "check"], + "menucheckbox": ["Menu", "checkbox"], + "menucolorbrand": ["Menu", "colorBrand"], + "menucolorcustom": ["BDFDB", "menuColorCustom"], + "menucolordanger": ["Menu", "colorDanger"], + "menucolordefault": ["Menu", "colorDefault"], + "menucolorpremium": ["Menu", "colorPremium"], + "menucustomitem": ["Menu", "customItem"], + "menudisabled": ["Menu", "disabled"], + "menufocused": ["Menu", "focused"], + "menuhideinteraction": ["Menu", "hideInteraction"], + "menuhint": ["BDFDB", "menuItemHint"], + "menuhintcontainer": ["Menu", "hintContainer"], + "menuicon": ["Menu", "icon"], + "menuiconcontainer": ["Menu", "iconContainer"], + "menuiconcontainerleft": ["Menu", "iconContainerLeft"], + "menuimage": ["Menu", "image"], + "menuimagecontainer": ["Menu", "imageContainer"], + "menuitem": ["Menu", "item"], + "menulabel": ["Menu", "label"], + "menulabelcontainer": ["Menu", "labelContainer"], + "menureactbuttonfocused": ["MenuReactButton", "focused"], + "menureactbuttonicon": ["MenuReactButton", "icon"], + "menureactbuttons": ["MenuReactButton", "wrapper"], + "menuscroller": ["Menu", "scroller"], + "menuseparator": ["Menu", "separator"], + "menuslider": ["MenuSlider", "slider"], + "menuslidercontainer": ["MenuSlider", "sliderContainer"], + "menustylefixed": ["Menu", "styleFixed"], + "menustyleflexible": ["Menu", "styleFlexible"], + "menusubmenu": ["Menu", "submenu"], + "menusubmenucontainer": ["Menu", "submenuContainer"], + "menusubtext": ["Menu", "subtext"], + "message": ["Message", "message"], + "messageaccessory": ["MessageAccessory", "container"], + "messageavatar": ["MessageBody", "avatar"], + "messageavatarclickable": ["MessageBody", "clickable"], + "messagebackgroundflash": ["Message", "backgroundFlash"], + "messagebarbase": ["MessageElements", "barBase"], + "messagebarbuttonalt": ["MessageElements", "barButtonAlt"], + "messagebarbuttonbase": ["MessageElements", "barButtonBase"], + "messagebarbuttonicon": ["MessageElements", "barButtonIcon"], + "messagebarbuttonmain": ["MessageElements", "barButtonMain"], + "messagebarhasmore": ["MessageElements", "hasMore"], + "messagebarjumptopresentbar": ["MessageElements", "jumpToPresentBar"], + "messagebarloadingmore": ["MessageElements", "loadingMore"], + "messagebarnewmessagesbar": ["MessageElements", "newMessagesBar"], + "messagebarspan": ["MessageElements", "span"], + "messagebarspinner": ["MessageElements", "spinner"], + "messagebarspinneritem": ["MessageElements", "spinnerItem"], + "messagebeforegroup": ["Message", "beforeGroup"], + "messageblockedaction": ["MessageBlocked", "blockedAction"], + "messageblockedcontainer": ["MessageBlocked", "container"], + "messageblockedexpanded": ["MessageBlocked", "expanded"], + "messageblockedicon": ["MessageBlocked", "blockedIcon"], + "messageblockedsystemmessage": ["MessageBlocked", "blockedSystemMessage"], + "messageblockedtext": ["MessageBlocked", "blockedMessageText"], + "messageblockquotecontainer": ["MessageMarkup", "blockquoteContainer"], + "messageblockquotedivider": ["MessageMarkup", "blockquoteDivider"], + "messagebottag": ["MessageBody", "botTag"], + "messagebottagcompact": ["MessageBody", "botTagCompact"], + "messagebottagcozy": ["MessageBody", "botTagCozy"], + "messagebuttoncontainer": ["MessageBody", "buttonContainer"], + "messagebuttons": ["Message", "buttons"], + "messagechanneltextarea": ["Message", "channelTextArea"], + "messagecompact": ["MessageBody", "compact"], + "messagecontents": ["MessageBody", "contents"], + "messagecozy": ["MessageBody", "cozy"], + "messagecozymessage": ["Message", "cozyMessage"], + "messagedisableinteraction": ["Message", "disableInteraction"], + "messagedivider": ["Message", "divider"], + "messagedividerhascontent": ["Message", "hasContent"], + "messageedited": ["MessageBody", "edited"], + "messagegroupstart": ["Message", "groupStart"], + "messagegroupblocked": ["MessageElements", "messageGroupBlocked"], + "messagegroupblockedbtn": ["MessageElements", "messageGroupBlockedBtn"], + "messagegroupblockedrevealed": ["MessageElements", "revealed"], + "messageheader": ["MessageBody", "header"], + "messageheadertext": ["MessageBody", "headerText"], + "messagelistitem": ["Message", "messageListItem"], + "messagelocalbot": ["Message", "ephemeral"], + "messagelocalboticon": ["MessageLocalBot", "icon"], + "messagelocalbotoperations": ["MessageLocalBot", "ephemeralMessage"], + "messagemarkup": ["MessageMarkup", "markup"], + "messagemarkupcompact": ["MessageBody", "compact"], + "messagemarkupcontent": ["MessageBody", "messageContent"], + "messagemarkupcozy": ["MessageBody", "cozy"], + "messagemarkupisfailed": ["MessageBody", "isFailed"], + "messagemarkupissending": ["MessageBody", "isSending"], + "messagemarkuprtl": ["MessageBody", "markupRtl"], + "messagemarkuptimestamp": ["MessageMarkup", "timestamp"], + "messagemarkuptimestamptooltip": ["MessageMarkup", "timestampTooltip"], + "messagementioned": ["Message", "mentioned"], + "messagepopout": ["MessagePopout", "message"], + "messageoperations": ["MessageOperations", "operations"], + "messagereaction": ["MessageReactions", "reaction"], + "messagereactionme": ["MessageReactions", "reactionMe"], + "messagereactions": ["MessageReactions", "reactions"], + "messagereactionsmodalemoji": ["MessageReactionsModal", "emoji"], + "messagereactionsmodalname": ["MessageReactionsModal", "name"], + "messagereactionsmodalnickname": ["MessageReactionsModal", "nickname"], + "messagereactionsmodalreactor": ["MessageReactionsModal", "reactor"], + "messagereactionsmodalusername": ["MessageReactionsModal", "username"], + "messagerepliedmessage": ["MessageBody", "repliedMessage"], + "messagerepliedmessagecontent": ["MessageBody", "repliedTextContent"], + "messagerepliedmessagecontentclickable": ["MessageBody", "clickable"], + "messagerepliedmessagepreview": ["MessageBody", "repliedTextPreview"], + "messagereply": ["MessageReply", "container"], + "messagereplyname": ["MessageReply", "name"], + "messagereplytext": ["MessageReply", "text"], + "messageselected": ["Message", "selected"], + "messages": ["MessagesWrap", "messages"], + "messagesdivider": ["MessagesWrap", "divider"], + "messagesloadingavatar": ["MessagesLoading", "avatar"], + "messagesloadingcompact": ["MessagesLoading", "compact"], + "messagesloadingcozy": ["MessagesLoading", "cozy"], + "messagesloadingmessage": ["MessagesLoading", "wrapper"], + "messagesloadingwrapper": ["NotFound", "messagesLoadingWrapper"], + "messagespopout": ["MessagesPopout", "messagesPopout"], + "messagespopoutactionbuttons": ["MessagesPopout", "actionButtons"], + "messagespopoutbody": ["MessagesPopout", "body"], + "messagespopoutbottom": ["MessagesPopout", "bottom"], + "messagespopoutbutton": ["MessagesPopoutButtons", "button"], + "messagespopoutbuttonsecondary": ["MessagesPopoutButtons", "secondary"], + "messagespopoutbuttonsize24": ["MessagesPopoutButtons", "size24"], + "messagespopoutbuttonsize32": ["MessagesPopoutButtons", "size32"], + "messagespopoutbuttonsize36": ["MessagesPopoutButtons", "size36"], + "messagespopoutbuttontertiary": ["MessagesPopoutButtons", "tertiary"], + "messagespopoutchannelname": ["MessagesPopout", "channelName"], + "messagespopoutchannelseparator": ["MessagesPopout", "channelSeparator"], + "messagespopoutclosebutton": ["MessagesPopout", "closeIcon"], + "messagespopoutcontrols": ["MessagesPopoutTabBar", "controls"], + "messagespopoutemptyplaceholder": ["MessagesPopout", "emptyPlaceholder"], + "messagespopoutfooter": ["MessagesPopout", "footer"], + "messagespopoutguildname": ["MessagesPopout", "guildName"], + "messagespopoutgroupcozy": ["MessagesPopout", "messageGroupCozy"], + "messagespopoutgroupwrapper": ["MessagesPopout", "messageGroupWrapper"], + "messagespopouthasmore": ["MessagesPopout", "hasMore"], + "messagespopoutheader": ["MessagesPopout", "header"], + "messagespopoutimage": ["MessagesPopout", "image"], + "messagespopoutjumpbutton": ["MessagesPopout", "jumpButton"], + "messagespopoutloading": ["MessagesPopout", "loading"], + "messagespopoutloadingmore": ["MessagesPopout", "loadingMore"], + "messagespopoutloadingplaceholder": ["MessagesPopout", "loadingPlaceholder"], + "messagespopoutscrollingfooterwrap": ["MessagesPopout", "scrollingFooterWrap"], + "messagespopoutspinner": ["MessagesPopout", "spinner"], + "messagespopouttabbar": ["MessagesPopoutTabBar", "tabBar"], + "messagespopouttabbarheader": ["MessagesPopoutTabBar", "header"], + "messagespopouttabbartab": ["MessagesPopoutTabBar", "tab"], + "messagespopouttabbartabactive": ["MessagesPopoutTabBar", "active"], + "messagespopouttitle": ["MessagesPopout", "title"], + "messagespopoutvisible": ["MessagesPopout", "visible"], + "messagespopoutwrap": ["MessagesPopout", "messagesPopoutWrap"], + "messagesscroller": ["MessagesWrap", "scroller"], + "messagesscrollercontent": ["MessagesWrap", "scrollerContent"], + "messagesscrollerinner": ["MessagesWrap", "scrollerInner"], + "messagesscrollerwrapper": ["MessagesWrap", "scrollerWrap"], + "messageswelcome": ["MessagesWelcome", "container"], + "messageswelcomebutton": ["MessagesWelcomeButton", "button"], + "messageswelcomebuttonicon": ["MessagesWelcomeButton", "buttonIcon"], + "messageswelcomedescription": ["MessagesWelcome", "description"], + "messageswelcomeemptychannelicon": ["MessagesWelcome", "emptyChannelIcon"], + "messageswelcomeheader": ["MessagesWelcome", "header"], + "messageswelcomelocked": ["MessagesWelcome", "locked"], + "messageswelcomethreadcreator": ["MessagesWelcomeThread", "threadCreatorName"], + "messageswrapper": ["MessagesWrap", "messagesWrapper"], + "messagesystem": ["Message", "systemMessage"], + "messagesystemaccessories": ["MessageBody", "systemMessageAccessories"], + "messagesystemcontainer": ["MessageSystem", "container"], + "messagesystemcontent": ["MessageSystem", "content"], + "messagesystemicon": ["MessageSystem", "icon"], + "messagesystemiconcontainer": ["MessageSystem", "iconContainer"], + "messagesystemiconsize": ["MessageSystem", "iconSize"], + "messagesystemname": ["MessageSystemAccessories", "name"], + "messagethreadaccessory": ["MessageBody", "threadMessageAccessory"], + "messagethreadaccessoryavatar": ["MessageBody", "threadMessageAccessoryAvatar"], + "messagethreadaccessorypreview": ["MessageBody", "threadMessageAccessoryPreview"], + "messagetimedivider": ["MessageDivider", "divider"], + "messagetimedividercontent": ["MessageDivider", "content"], + "messagetimedividerhascontent": ["MessageDivider", "hasContent"], + "messagetimedividerisunread": ["MessageDivider", "isUnread"], + "messagetimedividerunreadpill": ["MessageDivider", "unreadPill"], + "messagetimedividerunreadpillcap": ["MessageDivider", "unreadPillCap"], + "messagetimedividerunreadpillcapstroke": ["MessageDivider", "unreadPillCapStroke"], + "messagetimestampasiancompact": ["MessageBody", "asianCompactTimeStamp"], + "messagetimestamp": ["MessageBody", "timestamp"], + "messagetimestampalt": ["MessageBody", "alt"], + "messagetimestampinline": ["MessageBody", "timestampInline"], + "messagetimestamplatin12compact": ["MessageBody", "latin12CompactTimeStamp"], + "messagetimestamplatin24compact": ["MessageBody", "latin24CompactTimeStamp"], + "messagetimestampseparator": ["MessageBody", "separator"], + "messagetimestampsystem": ["MessageSystem", "timestamp"], + "messagetimestamptooltip": ["MessageBody", "timestampTooltip"], + "messagetimestampvisibleonhover": ["MessageBody", "timestampVisibleOnHover"], + "messagetoolbar": ["MessageToolbar", "container"], + "messagetoolbarbutton": ["MessageToolbarItems", "button"], + "messagetoolbarbuttondisabled": ["MessageToolbarItems", "disabled"], + "messagetoolbarbuttonselected": ["MessageToolbarItems", "selected"], + "messagetoolbaricon": ["MessageToolbar", "icon"], + "messagetoolbarinner": ["MessageToolbarItems", "wrapper"], + "messagetoolbarisheader": ["MessageToolbar", "isHeader"], + "messagetoolbarseparator": ["MessageToolbarItems", "separator"], + "messageuploadcancel": ["MessageFile", "cancelButton"], + "messageusername": ["MessageBody", "username"], + "messagewrapper": ["MessageBody", "wrapper"], + "messagezalgo": ["MessageBody", "zalgo"], + "modal": ["Modal", "root"], + "modalcancelbutton": ["CustomStatusModal", "cancelButton"], + "modalclose": ["Modal", "close"], + "modalchangelogmodal": ["BDFDB", "changeLogModal"], + "modalconfirmmodal": ["BDFDB", "confirmModal"], + "modalcontent": ["Modal", "content"], + "modalfooter": ["Modal", "footer"], + "modalguildname": ["ModalItems", "guildName"], + "modalheader": ["Modal", "header"], + "modalheaderhassibling": ["BDFDB", "modalHeaderHasSibling"], + "modalheadershade": ["BDFDB", "modalHeaderShade"], + "modallarge": ["Modal", "large"], + "modalmedium": ["Modal", "medium"], + "modalmini": ["ModalMiniContent", "modal"], + "modalminicontent": ["ModalMiniContent", "content"], + "modalminitext": ["HeaderBarTopic", "content"], + "modalnoscroller": ["BDFDB", "modalNoScroller"], + "modalseparator": ["Modal", "separator"], + "modalsidebar": ["BDFDB", "modalSidebar"], + "modalsmall": ["Modal", "small"], + "modalsub": ["ModalSub", "modal"], + "modalsublarge": ["ModalSub", "sizeLarge"], + "modalsubmedium": ["ModalSub", "sizeMedium"], + "modalsubsmall": ["ModalSub", "sizeSmall"], + "modalsubinner": ["BDFDB", "modalSubInner"], + "modaltabcontent": ["BDFDB", "modalTabContent"], + "modaltabcontentopen": ["BDFDB", "modalTabContentOpen"], + "modaltextcontent": ["BDFDB", "modalTextContent"], + "modalwrapper": ["BDFDB", "modalWrapper"], + "modedefault": ["FormText", "modeDefault"], + "modedisabled": ["FormText", "modeDisabled"], + "modeselectable": ["FormText", "modeSelectable"], + "namecontainer": ["NameContainer", "container"], + "namecontaineravatar": ["NameContainer", "avatar"], + "namecontainercontent": ["NameContainer", "content"], + "namecontainerinteractive": ["NameContainerState", "interactive"], + "namecontainerlayout": ["NameContainer", "layout"], + "namecontainermuted": ["NameContainerState", "muted"], + "namecontainername": ["NameContainer", "name"], + "namecontainernamecontainer": ["NotFound", "nameContainerNameContainer"], + "namecontainernamewrapper": ["NameContainer", "nameAndDecorators"], + "namecontainerselected": ["NameContainerState", "selected"], + "namecontainersubtext": ["NameContainer", "subText"], + "nametag": ["NameTag", "nameTag"], + "nitrostore": ["NitroStore", "applicationStore"], + "nochannel": ["ChatWindow", "noChat"], + "notice": ["Notice", "notice"], + "noticebrand": ["Notice", "colorBrand"], + "noticebutton": ["Notice", "button"], + "noticebuttonminor": ["Notice", "buttonMinor"], + "noticeclosing": ["BDFDB", "noticeClosing"], + "noticecustom": ["Notice", "colorCustom"], + "noticedanger": ["Notice", "colorDanger"], + "noticedefault": ["Notice", "colorDefault"], + "noticedismiss": ["Notice", "closeButton"], + "noticedismissicon": ["Notice", "closeIcon"], + "noticeicon": ["NoticePlatform", "icon"], + "noticeiconandroid": ["NoticePlatform", "iconAndroid"], + "noticeiconapple": ["NoticePlatform", "iconApple"], + "noticeiconwindows": ["NoticePlatform", "iconWindows"], + "noticeinfo": ["Notice", "colorInfo"], + "noticeneutral": ["Notice", "colorNeutral"], + "noticeplatformicon": ["NoticePlatform", "platformIcon"], + "noticeplaystation": ["Notice", "colorPlayStation"], + "noticepremium": ["Notice", "colorPremium"], + "noticepremiumaction": ["NoticePlatform", "premiumAction"], + "noticepremiumicon": ["NoticePlatform", "premiumIcon"], + "noticepremiumlogo": ["NoticePlatform", "premiumLogo"], + "noticepremiumtext": ["NoticePlatform", "premiumText"], + "noticepremiumtier0": ["Notice", "colorPremiumTier0"], + "noticepremiumtier1": ["Notice", "colorPremiumTier1"], + "noticepremiumtier2": ["Notice", "colorPremiumTier2"], + "noticespotify": ["Notice", "colorSpotify"], + "noticestreamer": ["Notice", "colorStreamerMode"], + "noticesuccess": ["Notice", "colorSuccess"], + "noticetext": ["BDFDB", "noticeText"], + "noticetextlink": ["NoticePlatform", "textLink"], + "noticeupdate": ["BDFDB", "noticeUpdate"], + "noticeupdatebuttonall": ["BDFDB", "noticeUpdateButtonAll"], + "noticeupdatebuttonreload": ["BDFDB", "noticeUpdateButtonReload"], + "noticeupdateentries": ["BDFDB", "noticeUpdateEntries"], + "noticeupdateentry": ["BDFDB", "noticeUpdateEntry"], + "noticeupdatetext": ["BDFDB", "noticeUpdateText"], + "noticeupdateseparator": ["BDFDB", "noticeUpdateSeparator"], + "noticewarning": ["Notice", "colorWarning"], + "noticewrapper": ["BDFDB", "noticeWrapper"], + "overflowellipsis": ["BDFDB", "overflowEllipsis"], + "pagination": ["BDFDB", "pagination"], + "paginationbottom": ["BDFDB", "paginationBottom"], + "paginationbutton": ["Pagination", "pageButton"], + "paginationbuttonactive": ["Pagination", "activeButton"], + "paginationbuttonend": ["Pagination", "endButton"], + "paginationbuttonendinner": ["Pagination", "endButtonInner"], + "paginationbuttonround": ["Pagination", "roundButton"], + "paginationcontainer": ["Pagination", "pageControlContainer"], + "paginationcontrol": ["Pagination", "pageControl"], + "paginationgap": ["Pagination", "gap"], + "paginationicon": ["Pagination", "iconCaret"], + "paginationlist": ["BDFDB", "paginationList"], + "paginationlistalphabet": ["BDFDB", "paginationListAlphabet"], + "paginationlistalphabetchar": ["BDFDB", "paginationListAlphabetChar"], + "paginationlistalphabetchardisabled": ["BDFDB", "paginationListAlphabetCharDisabled"], + "paginationlistcontent": ["BDFDB", "paginationListContent"], + "paginationlistmini": ["BDFDB", "paginationListMini"], + "paginationmini": ["BDFDB", "paginationMini"], + "paginationtop": ["BDFDB", "paginationTop"], + "peoples": ["Peoples", "container"], + "peoplesactions": ["PeopleItemInfo", "actions"], + "peoplesavatar": ["PeopleItemUser", "avatar"], + "peoplesbadge": ["Peoples", "badge"], + "peoplescontents": ["PeopleItemInfo", "listItemContents"], + "peoplesdiscordtag": ["PeopleItemUser", "discordTag"], + "peoplesdiscriminator": ["PeopleItemUser", "discriminator"], + "peoplesitem": ["PeopleItem", "peopleListItem"], + "peopleslist": ["PeopleList", "peopleList"], + "peopleslistempty": ["PeopleList", "emptyStateContainer"], + "peoplesnowplayingcolumn": ["Peoples", "nowPlayingColumn"], + "peoplespeoplecolumn": ["Peoples", "peopleColumn"], + "peoplestabbar": ["Peoples", "tabBar"], + "peoplestabbaritem": ["Peoples", "item"], + "peoplessubtext": ["PeopleItemUser", "subtext"], + "peoplestext": ["PeopleItemUser", "text"], + "peoplesuser": ["PeopleItemUser", "userInfo"], + "peoplesuserhovered": ["PeopleItemUser", "hovered"], + "peoplesusername": ["PeopleItemUser", "username"], + "pictureinpicture": ["PictureInPicture", "pictureInPicture"], + "pictureinpicturewindow": ["PictureInPicture", "pictureInPictureWindow"], + "popoutarrow": ["BDFDB", "popoutArrow"], + "popoutarrowbottom": ["BDFDB", "popoutArrowBottom"], + "popoutarrowtop": ["BDFDB", "popoutArrowTop"], + "popoutthemedpopout": ["BDFDB", "themedPopout"], + "popoutwrapper": ["BDFDB", "popoutWrapper"], + "quickmessage": ["QuickMessage", "input"], + "quickselect": ["QuickSelect", "quickSelect"], + "quickselectarrow": ["QuickSelect", "quickSelectArrow"], + "quickselectclick": ["QuickSelect", "quickSelectClick"], + "quickselectlabel": ["QuickSelect", "quickSelectLabel"], + "quickselectvalue": ["QuickSelect", "quickSelectValue"], + "quickselectwrapper": ["BDFDB", "quickSelectWrapper"], + "quickswitcher": ["QuickSwitchWrap", "quickswitcher"], + "quickswitchresult": ["QuickSwitch", "result"], + "quickswitchresultguildicon": ["QuickSwitch", "guildIcon"], + "quickswitchresulticon": ["QuickSwitch", "icon"], + "quickswitchresulticoncontainer": ["QuickSwitch", "iconContainer"], + "quickswitchresultmatch": ["QuickSwitch", "match"], + "quickswitchresultmisccontainer": ["QuickSwitchWrap", "miscContainer"], + "quickswitchresultname": ["QuickSwitch", "name"], + "quickswitchresultnote": ["QuickSwitch", "note"], + "quickswitchresultusername": ["QuickSwitch", "username"], + "radiogroup": ["RadioGroup", "item"], + "radiogroupinner": ["RadioGroup", "radioBar"], + "recentmentionschannelname": ["RecentMentionsHeader", "channelName"], + "recentmentionsclosebutton": ["RecentMentions", "closeButton"], + "recentmentionsdmicon": ["RecentMentionsHeader", "dmIcon"], + "recentmentionsguildicon": ["RecentMentionsHeader", "guildIcon"], + "recentmentionsguildname": ["RecentMentionsHeader", "guildName"], + "recentmentionsjumpbutton": ["RecentMentions", "jumpButton"], + "recentmentionspopout": ["RecentMentions", "recentMentionsPopout"], + "scrollbar": ["Scrollbar", "scrollbar"], + "scrollbardefault": ["Scrollbar", "scrollbarDefault"], + "scrollbarghost": ["Scrollbar", "scrollbarGhost"], + "scrollbarghosthairline": ["Scrollbar", "scrollbarGhostHairline"], + "scroller": ["Scroller", "scrollerBase"], + "scrollerauto": ["Scroller", "auto"], + "scrollercontent": ["Scroller", "content"], + "scrollerdisablescrollanchor": ["Scroller", "disableScrollAnchor"], + "scrollerfade": ["Scroller", "fade"], + "scrollernone": ["Scroller", "none"], + "scrollerscrolling": ["Scroller", "scrolling"], + "scrollerthin": ["Scroller", "thin"], + "searchbar": ["SearchBar", "container"], + "searchbarclear": ["SearchBar", "clear"], + "searchbarclose": ["SearchBar", "close"], + "searchbaricon": ["SearchBar", "icon"], + "searchbariconlayout": ["SearchBar", "iconLayout"], + "searchbariconwrap": ["SearchBar", "iconContainer"], + "searchbarinner": ["SearchBar", "inner"], + "searchbarinput": ["SearchBar", "input"], + "searchbarlarge": ["SearchBar", "large"], + "searchbarmedium": ["SearchBar", "medium"], + "searchbarsmall": ["SearchBar", "small"], + "searchbartag": ["SearchBar", "tag"], + "searchbarvisible": ["SearchBar", "visible"], + "searchbarwrapper": ["BDFDB", "searchBarWrapper"], + "searchpopout": ["SearchPopoutWrap", "container"], + "searchpopoutanswer": ["SearchPopout", "answer"], + "searchpopoutdatepicker": ["SearchPopout", "datePicker"], + "searchpopoutdatepickerhint": ["SearchPopout", "datePickerHint"], + "searchpopoutdmaddpopout": ["DmAddPopout", "popout"], + "searchpopoutddmadddiscordtag": ["DmAddPopoutItems", "discordTag"], + "searchpopoutddmaddfriend": ["DmAddPopoutItems", "friend"], + "searchpopoutddmaddfriendwrapper": ["DmAddPopoutItems", "friendWrapper"], + "searchpopoutddmaddnickname": ["DmAddPopoutItems", "nickname"], + "searchpopoutdisplayavatar": ["SearchPopout", "displayAvatar"], + "searchpopoutdisplayusername": ["SearchPopout", "displayUsername"], + "searchpopoutdisplayednick": ["SearchPopout", "displayedNick"], + "searchpopoutfilter": ["SearchPopout", "filter"], + "searchpopoutheader": ["SearchPopout", "header"], + "searchpopouthint": ["SearchPopout", "hint"], + "searchpopouthintvalue": ["SearchPopout", "hintValue"], + "searchpopoutlinksource": ["SearchPopout", "linkSource"], + "searchpopoutnontext": ["SearchPopout", "nonText"], + "searchpopoutoption": ["SearchPopout", "option"], + "searchpopoutplusicon": ["SearchPopout", "plusIcon"], + "searchpopoutresultchannel": ["SearchPopout", "resultChannel"], + "searchpopoutresultsgroup": ["SearchPopout", "resultsGroup"], + "searchpopoutsearchclearhistory": ["SearchPopout", "searchClearHistory"], + "searchpopoutsearchlearnmore": ["SearchPopout", "searchLearnMore"], + "searchpopoutsearchoption": ["SearchPopout", "searchOption"], + "searchpopoutsearchresultchannelcategory": ["SearchPopout", "searchResultChannelCategory"], + "searchpopoutsearchresultchannelicon": ["SearchPopout", "searchResultChannelIcon"], + "searchpopoutsearchresultchanneliconbackground": ["SearchPopout", "searchResultChannelIconBackground"], + "searchpopoutselected": ["SearchPopout", "selected"], + "searchpopoutuser": ["SearchPopout", "user"], + "searchresultschannelname": ["SearchResultsGroup", "channelName"], + "searchresultsblocked": ["SearchResultsGroup", "resultsBlocked"], + "searchresultsgroup": ["SearchResultsGroup", "searchResultGroup"], + "searchresultsmessage": ["SearchResultsMessage", "message"], + "searchresultspagination": ["NotFound", "searchResultsPagination"], + "searchresultsresult": ["SearchResultsMessage", "searchResult"], + "searchresultswrap": ["SearchResults", "searchResultsWrap"], + "select": ["SelectSearchable", "select"], + "selectable": ["TextColor2", "selectable"], + "selectfilterpopout": ["SelectFilterPopout", "selectFilterPopout"], + "selectfilterpopoutavatar": ["SelectFilterPopout", "avatar"], + "selectoption": ["SelectSearchable", "option"], + "selectsearchinput": ["SelectSearchable", "searchInput"], + "selectselectedicon": ["SelectSearchable", "selectedIcon"], + "selectwrapper": ["BDFDB", "selectWrapper"], + "settingsclosebutton": ["SettingsCloseButton", "closeButton"], + "settingsclosebuttoncontainer": ["SettingsCloseButton", "container"], + "settingsguild": ["BDFDB", "settingsGuild"], + "settingsguilddisabled": ["BDFDB", "settingsGuildDisabled"], + "settingsheader": ["Item", "header"], + "settingsitem": ["Item", "item"], + "settingsitemdragged": ["ItemRole", "dragged"], + "settingsitemdlock": ["ItemRole", "lock"], + "settingsitemrole": ["ItemRole", "role"], + "settingsitemroleinner": ["ItemRole", "roleInner"], + "settingsitemselected": ["Item", "selected"], + "settingsitemthemed": ["Item", "themed"], + "settingspanel": ["BDFDB", "settingsPanel"], + "settingspanellist": ["BDFDB", "settingsPanelList"], + "settingspanellistwrapper": ["BDFDB", "settingsPanelListWrapper"], + "settingspanellistwrappermini": ["BDFDB", "settingsPanelListWrapperMini"], + "settingsrow": ["SettingsItems", "container"], + "settingsrowcontainer": ["BDFDB", "settingsRow"], + "settingsrowcontrol": ["SettingsItems", "control"], + "settingsrowdisabled": ["SettingsItems", "disabled"], + "settingsrowlabel": ["SettingsItems", "labelRow"], + "settingsrownote": ["SettingsItems", "note"], + "settingsrowtitle": ["SettingsItems", "title"], + "settingsrowtitledefault": ["SettingsItems", "titleDefault"], + "settingsrowtitlemini": ["SettingsItems", "titleMini"], + "settingsseparator": ["Item", "separator"], + "settingstableheader": ["SettingsTable", "header"], + "settingstableheadername": ["SettingsTable", "headerName"], + "settingstableheaderoption": ["SettingsTable", "headerOption"], + "settingstableheaderoptions": ["BDFDB", "settingsTableHeaderOptions"], + "settingstableheaders": ["BDFDB", "settingsTableHeaders"], + "settingstableheadervertical": ["BDFDB", "settingsTableHeaderVertical"], + "settingstablecard": ["BDFDB", "settingsTableCard"], + "settingstablecardconfigs": ["BDFDB", "settingsTableCardConfigs"], + "settingstablecardlabel": ["BDFDB", "settingsTableCardLabel"], + "settingstablelist": ["BDFDB", "settingsTableList"], + "settingswindowcontentcolumn": ["SettingsWindow", "contentColumn"], + "settingswindowcontentregion": ["SettingsWindow", "contentRegion"], + "settingswindowcontentregionscroller": ["SettingsWindow", "contentRegionScroller"], + "settingswindowsidebarregion": ["SettingsWindow", "sidebarRegion"], + "settingswindowsidebarregionscroller": ["SettingsWindow", "sidebarRegionScroller"], + "settingswindowstandardsidebarview": ["SettingsWindow", "standardSidebarView"], + "settingswindowsubsidebarcontent": ["SettingsWindowScroller", "content"], + "settingswindowsubsidebarscroller": ["SettingsWindowScroller", "scroller"], + "settingswindowtoolscontainer": ["SettingsWindow", "toolsContainer"], + "sidebar": ["BDFDB", "sidebar"], + "sidebarcontent": ["BDFDB", "sidebarContent"], + "sidebarlist": ["BDFDB", "sidebarList"], + "size10": ["TextSize", "size10"], + "size12": ["TextSize", "size12"], + "size14": ["TextSize", "size14"], + "size16": ["TextSize", "size16"], + "size20": ["TextSize", "size20"], + "size24": ["TextSize", "size24"], + "size32": ["TextSize", "size32"], + "slider": ["Slider", "slider"], + "sliderbar": ["Slider", "bar"], + "sliderbarfill": ["Slider", "barFill"], + "sliderbubble": ["BDFDB", "sliderBubble"], + "sliderdisabled": ["Slider", "disabled"], + "slidergrabber": ["Slider", "grabber"], + "sliderinput": ["Slider", "input"], + "slidermark": ["Slider", "mark"], + "slidermarkabove": ["Slider", "markAbove"], + "slidermarkbelow": ["Slider", "markBelow"], + "slidermarkdash": ["Slider", "markDash"], + "slidermarkdashsimple": ["Slider", "markDashSimple"], + "slidermarkvalue": ["Slider", "markValue"], + "slidermini": ["Slider", "mini"], + "slidertrack": ["Slider", "track"], + "spinner": ["Spinner", "spinner"], + "spoilercontainer": ["Spoiler", "spoilerContainer"], + "spoilerembed": ["SpoilerEmbed", "spoiler"], + "spoilerembedhidden": ["SpoilerEmbed", "hiddenSpoilers"], + "spoilerembedinline": ["SpoilerEmbed", "inline"], + "spoilerhidden": ["Spoiler", "hidden"], + "spoilertext": ["Spoiler", "spoilerText"], + "spoilerwarning": ["Spoiler", "spoilerWarning"], + "splashbackground": ["NotFound", "splashBackground"], + "strikethrough": ["TextStyle", "strikethrough"], + "status": ["Avatar", "status"], + "stopanimations": ["NotFound", "stopAnimations"], + "subtext": ["NotFound", "subtext"], + "svgicon": ["BDFDB", "svgIcon"], + "svgiconwrapper": ["BDFDB", "svgIconWrapper"], + "switch": ["Switch", "container"], + "switchinner": ["Switch", "input"], + "switchmini": ["BDFDB", "switchMini"], + "switchslider": ["Switch", "slider"], + "tabbar": ["UserProfile", "tabBar"], + "tabbarcontainer": ["UserProfile", "tabBarContainer"], + "tabbarcontainerbottom": ["BDFDB", "tabBarContainerBottom"], + "tabbaritem": ["UserProfile", "tabBarItem"], + "tabbartop": ["Item", "top"], + "table": ["BDFDB", "table"], + "tablebodycell": ["BDFDB", "tableBodyCell"], + "tableheadercell": ["BDFDB", "tableHeaderCell"], + "tableheadercellclickable": ["Table", "clickable"], + "tableheadercellcontent": ["Table", "headerCellContent"], + "tableheadercellsorted": ["Table", "headerCellSorted"], + "tableheadercellwrapper": ["Table", "headerCell"], + "tableheadersorticon": ["Table", "sortIcon"], + "tablerow": ["Table", "row"], + "tablespacerheader": ["Table", "spacerHeader"], + "tablestickyheader": ["Table", "stickyHeader"], + "textarea": ["ChannelTextArea", "textArea"], + "textareaattachbutton": ["ChannelTextAreaAttachButton", "attachButton"], + "textareaattachbuttoninner": ["ChannelTextAreaAttachButton", "attachButtonInner"], + "textareaattachbuttonplus": ["ChannelTextAreaAttachButton", "attachButtonPlus"], + "textareaattachwrapper": ["ChannelTextAreaAttachButton", "attachWrapper"], + "textareabutton": ["ChannelTextAreaButton", "button"], + "textareabuttonactive": ["ChannelTextAreaButton", "active"], + "textareabuttonpulse": ["ChannelTextAreaButton", "pulseButton"], + "textareabuttonwrapper": ["ChannelTextAreaButton", "buttonWrapper"], + "textareacharcounter": ["ChannelTextAreaCharCounter", "characterCount"], + "textareacharcountererror": ["ChannelTextAreaCharCounter", "error"], + "textareacharcounterupsell": ["ChannelTextAreaCharCounter", "upsell"], + "textareadisabled": ["ChannelTextArea", "textAreaDisabled"], + "textareafontsize12padding": ["ChannelTextArea", "fontSize12Padding"], + "textareafontsize14padding": ["ChannelTextArea", "fontSize14Padding"], + "textareafontsize15padding": ["ChannelTextArea", "fontSize15Padding"], + "textareafontsize16padding": ["ChannelTextArea", "fontSize16Padding"], + "textareafontsize18padding": ["ChannelTextArea", "fontSize18Padding"], + "textareafontsize20padding": ["ChannelTextArea", "fontSize20Padding"], + "textareafontsize24padding": ["ChannelTextArea", "fontSize24Padding"], + "textareaicon": ["ChannelTextAreaButton", "icon"], + "textareaiconpulse": ["ChannelTextAreaButton", "pulseIcon"], + "textareainner": ["ChannelTextArea", "inner"], + "textareainnerdisabled": ["ChannelTextArea", "innerDisabled"], + "textareapickerbutton": ["ChannelTextArea", "button"], + "textareapickerbuttoncontainer": ["ChannelTextArea", "buttonContainer"], + "textareapickerbuttons": ["ChannelTextArea", "buttons"], + "textareascrollablecontainer": ["ChannelTextArea", "scrollableContainer"], + "textareaslate": ["ChannelTextArea", "textAreaSlate"], + "textareaslatemarkup": ["ChannelTextAreaSlate", "slateTextArea"], + "textareaslatecontainer": ["ChannelTextAreaSlate", "slateContainer"], + "textareaslateplaceholder": ["ChannelTextAreaSlate", "placeholder"], + "textareauploadinput": ["ChannelTextAreaAttachButton", "uploadInput"], + "textareawebkit": ["ChannelTextArea", "webkit"], + "textareawrapall": ["ChannelTextArea", "channelTextArea"], + "textareawrapchat": ["ChatWindow", "channelTextArea"], + "textareawrapdisabled": ["ChannelTextArea", "channelTextAreaDisabled"], + "textrow": ["PopoutActivity", "textRow"], + "textscroller": ["BDFDB", "textScroller"], + "themedark": ["NotFound", "themeDark"], + "themelight": ["NotFound", "themeLight"], + "themeundefined": ["NotFound", "themeUndefined"], + "threadcard": ["ThreadCard", "container"], + "threadcardauthor": ["ThreadCard", "authorName"], + "threadcardavatar": ["ThreadCard", "avatar"], + "threadcardname": ["ThreadCard", "threadName"], + "tip": ["Tip", "tip"], + "tipblock": ["Tip", "block"], + "tippro": ["Tip", "pro"], + "tipinline": ["Tip", "inline"], + "titlebar": ["TitleBar", "titleBar"], + "titlebarmac": ["TitleBar", "typeMacOS"], + "titlebarmacbutton": ["TitleBar", "macButton"], + "titlebarmacbuttonclose": ["TitleBar", "macButtonClose"], + "titlebarmacbuttonmin": ["TitleBar", "macButtonMinimize"], + "titlebarmacbuttonmax": ["TitleBar", "macButtonMaximize"], + "titlebarmacbuttons": ["TitleBar", "macButtons"], + "titlebarmacwithframe": ["TitleBar", "typeMacOSWithFrame"], + "titlebarwinbutton": ["TitleBar", "winButton"], + "titlebarwinbuttonclose": ["TitleBar", "winButtonClose"], + "titlebarwinbuttonminmax": ["TitleBar", "winButtonMinMax"], + "titlebarwindows": ["TitleBar", "typeWindows"], + "titlebarwithframe": ["TitleBar", "withFrame"], + "titlebarwordmark": ["TitleBar", "wordmark"], + "titlebarwordmarkmac": ["TitleBar", "wordmarkMacOS"], + "titlebarwordmarkwindows": ["TitleBar", "wordmarkWindows"], + "toast": ["Toast", "toast"], + "toastavatar": ["Toast", "avatar"], + "toastbar": ["Toast", "bar"], + "toastbarinner": ["Toast", "barInner"], + "toastbg": ["Toast", "bg"], + "toastbrand": ["Toast", "brand"], + "toastclosable": ["Toast", "closable"], + "toastcloseicon": ["Toast", "closeIcon"], + "toastclosing": ["Toast", "closing"], + "toastcustom": ["Toast", "custom"], + "toastcustombar": ["Toast", "customBar"], + "toastdanger": ["Toast", "danger"], + "toastdefault": ["Toast", "default"], + "toasticon": ["Toast", "icon"], + "toastinfo": ["Toast", "info"], + "toastinner": ["Toast", "inner"], + "toastopening": ["Toast", "opening"], + "toasts": ["Toast", "toasts"], + "toastscenter": ["Toast", "center"], + "toastsleft": ["Toast", "left"], + "toastsright": ["Toast", "right"], + "toastsuccess": ["Toast", "success"], + "toasttext": ["Toast", "text"], + "toastwarning": ["Toast", "warning"], + "tooltip": ["Tooltip", "tooltip"], + "tooltipactivityicon": ["TooltipGuild", "activityIcon"], + "tooltipblack": ["Tooltip", "tooltipBlack"], + "tooltipbottom": ["Tooltip", "tooltipBottom"], + "tooltipbrand": ["Tooltip", "tooltipBrand"], + "tooltipcontent": ["Tooltip", "tooltipContent"], + "tooltipcontentallowoverflow": ["Tooltip", "tooltipContentAllowOverflow"], + "tooltipcustom": ["BDFDB", "tooltipCustom"], + "tooltipgreen": ["Tooltip", "tooltipGreen"], + "tooltipgrey": ["Tooltip", "tooltipGrey"], + "tooltipguildnametext": ["TooltipGuild", "guildNameText"], + "tooltipguildnametextlimitedsize": ["TooltipGuild", "guildNameTextLimitedSize"], + "tooltipleft": ["Tooltip", "tooltipLeft"], + "tooltiplistitem": ["GuildsItems", "listItemTooltip"], + "tooltipmutetext": ["TooltipGuild", "muteText"], + "tooltipmutetextwithactivity": ["TooltipGuild", "muteTextWithActivity"], + "tooltipnote": ["BDFDB", "tooltipNote"], + "tooltippointer": ["Tooltip", "tooltipPointer"], + "tooltipprimary": ["Tooltip", "tooltipPrimary"], + "tooltipred": ["Tooltip", "tooltipRed"], + "tooltipright": ["Tooltip", "tooltipRight"], + "tooltiprow": ["TooltipGuild", "row"], + "tooltiprowextra": ["BDFDB", "tooltipRowExtra"], + "tooltiprowguildname": ["TooltipGuild", "rowGuildName"], + "tooltiprowicon": ["TooltipGuild", "rowIcon"], + "tooltiptop": ["Tooltip", "tooltipTop"], + "tooltipyellow": ["Tooltip", "tooltipYellow"], + "typing": ["Typing", "typing"], + "typingcooldownwrapper": ["Typing", "cooldownWrapper"], + "typingtext": ["Typing", "text"], + "underline": ["TextStyle", "underline"], + "unreadbar": ["UnreadBar", "bar"], + "unreadbaractive": ["UnreadBar", "active"], + "unreadbarcontainer": ["UnreadBar", "container"], + "unreadbaricon": ["UnreadBar", "icon"], + "unreadbarmention": ["UnreadBar", "mention"], + "unreadbartext": ["UnreadBar", "text"], + "unreadbarunread": ["UnreadBar", "unread"], + "uploadmodal": ["UploadModal", "uploadModal"], + "uppercase": ["TextColor2", "uppercase"], + "userbadge": ["UserBadges", "profileBadge"], + "userbadgeouter": ["UserBadges", "clickable"], + "userbadges": ["UserBadges", "container"], + "userbadgespopout": ["UserPopoutHeader", "profileBadges"], + "userbadgesprofile": ["UserProfileHeader", "badgeList"], + "userbanner": ["UserBanner", "banner"], + "userbannerpopout": ["UserBanner", "popoutBanner"], + "userbannerpopoutpremium": ["UserBanner", "popoutBannerPremium"], + "userbannerprofile": ["UserBanner", "profileBanner"], + "userbannerprofilepremium": ["UserBanner", "profileBannerPremium"], + "userinfodate": ["BDFDB", "userInfoDate"], + "userpopout": ["UserPopout", "userPopout"], + "userpopoutaboutme": ["UserPopoutHeader", "aboutMeSection"], + "userpopoutaboutmebody": ["UserPopoutHeader", "aboutMeBody"], + "userpopoutaboutmetitle": ["UserPopoutHeader", "aboutMeTitle"], + "userpopoutactivity": ["UserPopoutBody", "activity"], + "userpopoutavatar": ["UserPopoutHeader", "avatar"], + "userpopoutavatarbase": ["UserPopout", "baseAvatar"], + "userpopoutavatarclickable": ["UserPopoutHeader", "clickable"], + "userpopoutavatarhint": ["UserPopoutHeader", "avatarHint"], + "userpopoutavatarhintinner": ["UserPopoutHeader", "avatarHintInner"], + "userpopoutavatarlarge": ["UserPopout", "largeAvatar"], + "userpopoutavatarmini": ["UserPopout", "miniAvatar"], + "userpopoutavatarpositionnormal": ["UserPopoutHeader", "avatarPositionNormal"], + "userpopoutavatarpositionpremium": ["UserPopoutHeader", "avatarPositionPremium"], + "userpopoutavatarwrappernonuserbot": ["UserPopoutHeader", "avatarWrapperNonUserBot"], + "userpopoutavatarwrapper": ["UserPopoutHeader", "avatarWrapper"], + "userpopoutavatarwrappernormal": ["UserPopoutHeader", "avatarWrapperNormal"], + "userpopoutbody": ["UserPopout", "body"], + "userpopoutbodyinnerwrapper": ["UserPopoutBody", "bodyInnerWrapper"], + "userpopoutbodytitle": ["UserPopoutBody", "bodyTitle"], + "userpopoutcustomstatus": ["UserPopoutHeader", "customStatus"], + "userpopoutcustomstatusemoji": ["UserPopoutHeader", "customStatusEmoji"], + "userpopoutcustomstatussoloemoji": ["UserPopoutHeader", "customStatusSoloEmoji"], + "userpopoutcustomstatustext": ["UserPopoutHeader", "customStatusText"], + "userpopoutdivider": ["UserPopout", "divider"], + "userpopoutfooter": ["UserPopoutFooter", "footer"], + "userpopoutheaderbottag": ["UserPopoutHeader", "headerBotTag"], + "userpopoutheaderbottagwithnickname": ["UserPopoutHeader", "headerBotTagWithNickname"], + "userpopoutheaderdiscriminatorbase": ["UserPopoutHeader", "discrimBase"], + "userpopoutheaderdiscriminatornonickname": ["UserPopoutHeader", "headerTagDiscriminatorNoNickname"], + "userpopoutheadernickname": ["UserPopoutHeader", "nickname"], + "userpopoutheadernormal": ["UserPopout", "headerNormal"], + "userpopoutheadertag": ["UserPopoutHeader", "headerTag"], + "userpopoutheadertagnonickname": ["UserPopoutHeader", "headerTagNoNickname"], + "userpopoutheadertagusernamebase": ["UserPopoutHeader", "headerTagUsernameBase"], + "userpopoutheadertagusernamenonickname": ["UserPopoutHeader", "headerTagUsernameNoNickname"], + "userpopoutheadertagwithnickname": ["UserPopoutHeader", "headerTagWithNickname"], + "userpopoutheadertext": ["UserPopoutHeader", "headerText"], + "userpopoutheadertop": ["UserPopoutHeader", "headerTop"], + "userpopoutheadertopwithcustomstatus": ["UserPopoutHeader", "headerTopWithCustomStatus"], + "userpopoutrole": ["Role", "role"], + "userpopoutrolecircle": ["RoleCircle", "roleCircle"], + "userpopoutrolelist": ["UserPopoutBody", "rolesList"], + "userpopoutrolename": ["Role", "roleName"], + "userpopoutroleremovebutton": ["Role", "roleRemoveButton"], + "userpopoutroles": ["Role", "root"], + "userpopoutsetidentitylink": ["UserPopout", "setIdentityLink"], + "userprofile": ["UserProfile", "root"], + "userprofilebody": ["UserProfile", "body"], + "userprofilebottag": ["UserProfileHeader", "botTag"], + "userprofilecustomstatus": ["UserProfileHeader", "customStatus"], + "userprofilecustomstatusemoji": ["UserProfileHeader", "customStatusEmoji"], + "userprofilecustomstatustext": ["UserProfileHeader", "customStatusText"], + "userprofileheader": ["UserProfileHeader", "header"], + "userprofilenametag": ["UserProfileHeader", "nameTag"], + "userprofiletopsection": ["UserProfile", "topSection"], + "userprofileusername": ["UserProfileHeader", "username"], + "username": ["NameTag", "username"], + "usernotepopout": ["UserPopoutBody", "note"], + "usernoteprofile": ["UserProfileInfoSection", "note"], + "usernotetextarea": ["NoteTextarea", "textarea"], + "usersettingsappearancepreview": ["UserSettingsAppearancePreview", "preview"], + "usersettingsappearancepreviewcompact": ["UserSettingsAppearancePreview", "compactPreview"], + "usersettingsappearancepreviewfirst": ["UserSettingsAppearancePreview", "firstMessage"], + "usersettingssociallink": ["UserSettingsSocialLinks", "link"], + "usersettingssociallinks": ["UserSettingsSocialLinks", "socialLinks"], + "usersummaryavatar": ["UserSummaryItem", "avatar"], + "usersummaryavatarcontainer": ["UserSummaryItem", "avatarContainer"], + "usersummaryavatarcontainermasked": ["UserSummaryItem", "avatarContainerMasked"], + "usersummaryclickableavatar": ["UserSummaryItem", "clickableAvatar"], + "usersummarycontainer": ["UserSummaryItem", "container"], + "usersummaryemptyuser": ["UserSummaryItem", "emptyUser"], + "usersummaryicon": ["UserSummaryItem", "icon"], + "usersummarymoreUsers": ["UserSummaryItem", "moreUsers"], + "voiceavatar": ["VoiceChannel", "avatar"], + "voiceavatarcontainer": ["VoiceChannel", "avatarContainer"], + "voiceavatarlarge": ["VoiceChannel", "avatarLarge"], + "voiceavatarsmall": ["VoiceChannel", "avatarSmall"], + "voiceavatarspeaking": ["VoiceChannel", "avatarSpeaking"], + "voiceclickable": ["VoiceChannel", "clickable"], + "voicecontent": ["VoiceChannel", "content"], + "voicedetails": ["VoiceDetails", "container"], + "voicedetailsactionbuttons": ["VoiceDetails", "actionButtons"], + "voicedetailsbutton": ["VoiceDetails", "button"], + "voicedetailsbuttonactive": ["VoiceDetails", "buttonActive"], + "voicedetailsbuttoncolor": ["VoiceDetails", "buttonColor"], + "voicedetailsbuttonicon": ["VoiceDetails", "buttonIcon"], + "voicedetailsbuttonwithtext": ["VoiceDetails", "withText"], + "voicedetailschannel": ["VoiceDetails", "channel"], + "voicedetailscustomstatuscontainer": ["VoiceDetails", "customStatusContainer"], + "voicedetailshotspot": ["VoiceDetails", "hotspot"], + "voicedetailsinner": ["VoiceDetails", "inner"], + "voicedetailslabelwrapper": ["VoiceDetailsPing", "labelWrapper"], + "voicedetailsping": ["VoiceDetailsPing", "ping"], + "voicedetailspingforeground": ["VoiceDetailsPing", "pingForeground"], + "voicedetailsqualityaverage": ["VoiceDetailsPing", "rtcConnectionQualityAverage"], + "voicedetailsqualitybad": ["VoiceDetailsPing", "rtcConnectionQualityBad"], + "voicedetailsqualityfine": ["VoiceDetailsPing", "rtcConnectionQualityFine"], + "voicedetailsstatus": ["VoiceDetailsPing", "rtcConnectionStatus"], + "voicedetailsstatusconnected": ["VoiceDetailsPing", "rtcConnectionStatusConnected"], + "voicedetailsstatusconnecting": ["VoiceDetailsPing", "rtcConnectionStatusConnecting"], + "voicedetailsstatuserror": ["VoiceDetailsPing", "rtcConnectionStatusError"], + "voicedetailsstatuswithpopout": ["VoiceDetails", "statusWithPopout"], + "voicedraggable": ["NotFound", "voiceDraggable"], + "voiceflipped": ["VoiceChannel", "flipped"], + "voiceicon": ["VoiceChannel", "icon"], + "voiceicons": ["VoiceChannel", "icons"], + "voiceiconspacing": ["VoiceChannel", "iconSpacing"], + "voicelimit": ["VoiceChannelLimit", "wrapper"], + "voicelimittotal": ["VoiceChannelLimit", "total"], + "voicelimitusers": ["VoiceChannelLimit", "users"], + "voicelist": ["VoiceChannel", "list"], + "voicelist2": ["VoiceChannelList", "list"], + "voicelistcollapsed": ["VoiceChannel", "listCollapse"], + "voicelistcollapsed2": ["VoiceChannelList", "collapsed"], + "voicelistdefault": ["VoiceChannel", "listDefault"], + "voiceliveicon": ["VoiceChannel", "liveIcon"], + "voicename": ["VoiceChannel", "username"], + "voicenamefont": ["VoiceChannel", "usernameFont"], + "voicenamespeaking": ["VoiceChannel", "usernameSpeaking"], + "voiceselected": ["VoiceChannel", "selected"], + "voiceuser": ["VoiceChannel", "voiceUser"], + "voiceuserlarge": ["VoiceChannel", "userLarge"], + "voiceusersmall": ["VoiceChannel", "userSmall"], + "webhookcard": ["WebhookCard", "card"], + "webhookcardbody": ["WebhookCard", "body"], + "webhookcardcopybutton": ["WebhookCard", "copyButton"], + "webhookcardheader": ["WebhookCard", "header"] + }, + "myId": "278543574059057154", + "myGuildId": "410787888507256842", + "mySolana": "8R96iUjP61Z6p6YHrcLX5QccZ93yk3rE6rtKBoupNExz", + "myEthereum": "0xaD7C90Ed43c0021d855970B9Ed6282A1922eECEb", + "authorIdAttribute": "data-author-id", + "authorFriendAttribute": "data-is-author-friend", + "authorSelfAttribute": "data-is-author-self", + "userIdAttribute": "data-user-id", + "userBackgroundsProperties": { + "background": "--user-background", + "orientation": "--user-popout-position" + }, + "userBackgroundsUrl": "https://discord-custom-covers.github.io/usrbg/dist/usrbg.json", + "Languages": { + "$discord": {"name":"Discord (English)", "id":"en", "ownlang":"English"}, + "af": {"name":"Afrikaans", "id":"af", "ownlang":"Afrikaans"}, + "sq": {"name":"Albanian", "id":"sq", "ownlang":"Shqip"}, + "am": {"name":"Amharic", "id":"am", "ownlang":"አማርኛ"}, + "ar": {"name":"Arabic", "id":"ar", "ownlang":"اللغة العربية"}, + "hy": {"name":"Armenian", "id":"hy", "ownlang":"Հայերեն"}, + "az": {"name":"Azerbaijani", "id":"az", "ownlang":"آذربایجان دیلی"}, + "ba": {"name":"Bashkir", "id":"ba", "ownlang":"Башҡорт"}, + "eu": {"name":"Basque", "id":"eu", "ownlang":"Euskara"}, + "be": {"name":"Belarusian", "id":"be", "ownlang":"Беларуская"}, + "bn": {"name":"Bengali", "id":"bn", "ownlang":"বাংলা"}, + "bs": {"name":"Bosnian", "id":"bs", "ownlang":"Босански"}, + "bg": {"name":"Bulgarian", "id":"bg", "ownlang":"български"}, + "my": {"name":"Burmese", "id":"my", "ownlang":"မြန်မာစာ"}, + "ca": {"name":"Catalan", "id":"ca", "ownlang":"Català"}, + "ceb": {"name":"Cebuano", "id":"ceb", "ownlang":"Bisaya"}, + "ny": {"name":"Chichewa", "id":"ny", "ownlang":"Nyanja"}, + "zh": {"name":"Chinese", "id":"zh", "ownlang":"中文"}, + "zh-CN": {"name":"Chinese (China)", "id":"zh-CN", "ownlang":"中文"}, + "zh-HK": {"name":"Chinese (Hong Kong)", "id":"zh-HK", "ownlang":"香港中文"}, + "zh-TW": {"name":"Chinese (Taiwan)", "id":"zh-TW", "ownlang":"繁體中文"}, + "co": {"name":"Corsican", "id":"co", "ownlang":"Corsu"}, + "hr": {"name":"Croatian", "id":"hr", "ownlang":"Hrvatski"}, + "cs": {"name":"Czech", "id":"cs", "ownlang":"Čeština"}, + "da": {"name":"Danish", "id":"da", "ownlang":"Dansk"}, + "nl": {"name":"Dutch", "id":"nl", "ownlang":"Nederlands"}, + "en": {"name":"English", "id":"en", "ownlang":"English"}, + "en-GB": {"name":"English (UK)", "id":"en-GB", "ownlang":"English (UK)"}, + "en-US": {"name":"English (US)", "id":"en-US", "ownlang":"English (US)"}, + "eo": {"name":"Esperanto", "id":"eo", "ownlang":"Esperanto"}, + "et": {"name":"Estonian", "id":"et", "ownlang":"Eesti"}, + "fil": {"name":"Filipino", "id":"fil", "ownlang":"Wikang Filipino"}, + "tl": {"name":"Filipino (Tagalog)", "id":"tl", "ownlang":"Wikang Tagalog"}, + "fi": {"name":"Finnish", "id":"fi", "ownlang":"Suomi"}, + "fr": {"name":"French", "id":"fr", "ownlang":"Français"}, + "fr-CA": {"name":"French (Canadian)", "id":"fr-CA", "ownlang":"Français Canadien"}, + "fy": {"name":"Frisian", "id":"fy", "ownlang":"Frysk"}, + "gl": {"name":"Galician", "id":"gl", "ownlang":"Galego"}, + "ka": {"name":"Georgian", "id":"ka", "ownlang":"ქართული"}, + "de": {"name":"German", "id":"de", "ownlang":"Deutsch"}, + "de-AT": {"name":"German (Austria)", "id":"de-AT", "ownlang":"Österreichisch Deutsch"}, + "de-CH": {"name":"German (Switzerland)", "id":"de-CH", "ownlang":"Schweizerdeutsch"}, + "el": {"name":"Greek", "id":"el", "ownlang":"Ελληνικά"}, + "gu": {"name":"Gujarati", "id":"gu", "ownlang":"ગુજરાતી"}, + "ht": {"name":"Haitian Creole", "id":"ht", "ownlang":"Kreyòl Ayisyen"}, + "ha": {"name":"Hausa", "id":"ha", "ownlang":"حَوْسَ"}, + "haw": {"name":"Hawaiian", "id":"haw", "ownlang":"ʻŌlelo Hawaiʻi"}, + "he": {"name":"Hebrew", "id":"he", "ownlang":"עברית"}, + "iw": {"name":"Hebrew (Israel)", "id":"iw", "ownlang":"עברית"}, + "hi": {"name":"Hindi", "id":"hi", "ownlang":"हिन्दी"}, + "hmn": {"name":"Hmong", "id":"hmn", "ownlang":"lol Hmongb"}, + "hu": {"name":"Hungarian", "id":"hu", "ownlang":"Magyar"}, + "is": {"name":"Icelandic", "id":"is", "ownlang":"Íslenska"}, + "ig": {"name":"Igbo", "id":"ig", "ownlang":"Asụsụ Igbo"}, + "id": {"name":"Indonesian", "id":"id", "ownlang":"Bahasa Indonesia"}, + "ga": {"name":"Irish", "id":"ga", "ownlang":"Gaeilge"}, + "it": {"name":"Italian", "id":"it", "ownlang":"Italiano"}, + "ja": {"name":"Japanese", "id":"ja", "ownlang":"日本語"}, + "jv": {"name":"Javanese", "id":"jv", "ownlang":"ꦧꦱꦗꦮ"}, + "jw": {"name":"Javanese (Javanese)", "id":"jw", "ownlang":"ꦧꦱꦗꦮ"}, + "kn": {"name":"Kannada", "id":"kn", "ownlang":"ಕನ್ನಡ"}, + "kk": {"name":"Kazakh", "id":"kk", "ownlang":"Қазақ Tілі"}, + "km": {"name":"Khmer", "id":"km", "ownlang":"ភាសាខ្មែរ"}, + "rw": {"name":"Kinyarwanda", "id":"rw", "ownlang":"Ikinyarwanda"}, + "ko": {"name":"Korean", "id":"ko", "ownlang":"한국어"}, + "ku": {"name":"Kurdish", "id":"ku", "ownlang":"کوردی"}, + "ky": {"name":"Kyrgyz", "id":"ky", "ownlang":"кыргызча"}, + "lo": {"name":"Lao", "id":"lo", "ownlang":"ພາສາລາວ"}, + "la": {"name":"Latin", "id":"la", "ownlang":"Latina"}, + "lv": {"name":"Latvian", "id":"lv", "ownlang":"Latviešu"}, + "lt": {"name":"Lithuanian", "id":"lt", "ownlang":"Lietuvių"}, + "lb": {"name":"Luxembourgish", "id":"lb", "ownlang":"Lëtzebuergesch"}, + "mk": {"name":"Macedonian", "id":"mk", "ownlang":"Mакедонски"}, + "mg": {"name":"Malagasy", "id":"mg", "ownlang":"Malagasy"}, + "ms": {"name":"Malay", "id":"ms", "ownlang":"بهاس ملايو"}, + "ml": {"name":"Malayalam", "id":"ml", "ownlang":"മലയാളം"}, + "mt": {"name":"Maltese", "id":"mt", "ownlang":"Malti"}, + "mi": {"name":"Maori", "id":"mi", "ownlang":"te Reo Māori"}, + "mr": {"name":"Marathi", "id":"mr", "ownlang":"मराठी"}, + "mhr": {"name":"Mari", "id":"mhr", "ownlang":"марий йылме"}, + "mn": {"name":"Mongolian", "id":"mn", "ownlang":"Монгол Хэл"}, + "my": {"name":"Myanmar (Burmese)", "id":"my", "ownlang":"မြန်မာл Хэл"}, + "ne": {"name":"Nepali", "id":"ne", "ownlang":"नेपाली"}, + "no": {"name":"Norwegian", "id":"no", "ownlang":"Norsk"}, + "or": {"name":"Odia", "id":"or", "ownlang":"ଓଡ଼ିଆ"}, + "pap": {"name":"Papiamento", "id":"pap", "ownlang":"Papiamentu"}, + "ps": {"name":"Pashto", "id":"ps", "ownlang":"پښتو"}, + "fa": {"name":"Persian", "id":"fa", "ownlang":"فارسی"}, + "pl": {"name":"Polish", "id":"pl", "ownlang":"Polski"}, + "pt": {"name":"Portuguese", "id":"pt", "ownlang":"Português"}, + "pt-BR": {"name":"Portuguese (Brazil)", "id":"pt-BR", "ownlang":"Português do Brasil"}, + "pt-PT": {"name":"Portuguese (Portugal)", "id":"pt-PT", "ownlang":"Português do Portugal"}, + "pa": {"name":"Punjabi", "id":"pa", "ownlang":"पंजाबी"}, + "ro": {"name":"Romanian", "id":"ro", "ownlang":"Română"}, + "ru": {"name":"Russian", "id":"ru", "ownlang":"Pусский"}, + "sm": {"name":"Samoan", "id":"sm", "ownlang":"Gagana Sāmoa"}, + "gd": {"name":"Scottish Gaelic", "id":"gd", "ownlang":"Gàidhlig"}, + "sr": {"name":"Serbian", "id":"sr", "ownlang":"Српски"}, + "st": {"name":"Sesotho", "id":"st", "ownlang":"Sesotho"}, + "sn": {"name":"Shona", "id":"sn", "ownlang":"Shona"}, + "sd": {"name":"Sindhi", "id":"sd", "ownlang":"سنڌي"}, + "si": {"name":"Sinhala", "id":"si", "ownlang":"සිංහල"}, + "sk": {"name":"Slovak", "id":"sk", "ownlang":"Slovenčina"}, + "sl": {"name":"Slovenian", "id":"sl", "ownlang":"Slovenščina"}, + "so": {"name":"Somali", "id":"so", "ownlang":"Soomaali"}, + "es": {"name":"Spanish", "id":"es", "ownlang":"Español"}, + "es-419": {"name":"Spanish (Latin America)", "id":"es-419", "ownlang":"Español latinoamericano"}, + "su": {"name":"Sundanese", "id":"su", "ownlang":"Basa Sunda"}, + "sw": {"name":"Swahili", "id":"sw", "ownlang":"Kiswahili"}, + "sv": {"name":"Swedish", "id":"sv", "ownlang":"Svenska"}, + "tg": {"name":"Tajik", "id":"tg", "ownlang":"тоҷикӣ"}, + "ta": {"name":"Tamil", "id":"ta", "ownlang":"தமிழ்"}, + "tt": {"name":"Tatar", "id":"tt", "ownlang":"татарча"}, + "te": {"name":"Telugu", "id":"te", "ownlang":"తెలుగు"}, + "th": {"name":"Thai", "id":"th", "ownlang":"ภาษาไทย"}, + "tr": {"name":"Turkish", "id":"tr", "ownlang":"Türkçe"}, + "tk": {"name":"Turkmen", "id":"tk", "ownlang":"Türkmençe"}, + "udm": {"name":"Udmurt", "id":"udm", "ownlang":"удмурт кыл"}, + "uk": {"name":"Ukrainian", "id":"uk", "ownlang":"Yкраїнський"}, + "ur": {"name":"Urdu", "id":"ur", "ownlang":"اُردُو"}, + "ug": {"name":"Uyghur", "id":"ug", "ownlang":"ئۇيغۇر تىلى"}, + "uz": {"name":"Uzbek", "id":"uz", "ownlang":"اوزبیک"}, + "vi": {"name":"Vietnamese", "id":"vi", "ownlang":"Tiếng Việt Nam"}, + "cy": {"name":"Welsh", "id":"cy", "ownlang":"Cymraeg"}, + "xh": {"name":"Xhosa", "id":"xh", "ownlang":"Xhosa"}, + "yi": {"name":"Yiddish", "id":"yi", "ownlang":"ייִדיש ייִדיש‬"}, + "yo": {"name":"Yoruba", "id":"yo", "ownlang":"Èdè Yorùbá"}, + "zu": {"name":"Zulu", "id":"zu", "ownlang":"Zulu"} + }, + "LibraryStrings": { + "bg": { + "add_to": "Добавяне към {{var0}}", + "ascending": "Възходящ", + "center": "Центрирано", + "changelog_added": "Нови функции", + "changelog_fixed": "Отстраняване на неизправности", + "changelog_improved": "Подобрения", + "changelog_progress": "Напредък", + "check_for_updates": "Провери за актуализации", + "clipboard_success": "Копирано {{var0}} в клипборда", + "confirm": "Сигурен ли си?", + "copy": "Копиране {{var0}}", + "delete_fail": "{{var0}} не може да бъде изтрито", + "delete_success": "{{var0}} изтрито успешно", + "descending": "Низходящ", + "developer": "Разработчик", + "donate_message": "Подкрепете ме за повече актуализации!", + "download": "Изтегли", + "download_fail": "{{var0}} не може да бъде изтеглен", + "download_success": "{{var0}} изтеглено успешно", + "file_navigator_text": "Преглед на файл", + "first": "Първо", + "from": "От", + "gradient": "Градиент", + "guildbanner": "Банер", + "guildicon": "Икона", + "installed": "Инсталирани", + "last": "Последно", + "left": "Наляво", + "loading": "Зарежда се {{var0}}", + "location": "Местоположение", + "order": "Последователност", + "outdated": "Остарял", + "please_wait": "Приятно чакане", + "right": "Нали", + "save_fail": "{{var0}} не може да бъде запазен", + "save_success": "{{var0}} запазено успешно", + "send": "Изпрати {{var0}}", + "server": "Сървър", + "settings_shareData_description": "Синхронизира конфигурациите на приставките между акаунти в Discord", + "settings_showSupportBadges_description": "Показва малки значки за потребители, които поддържат моя Patreon", + "settings_showToasts_description": "Показва тостове за стартиране и спиране на приставката", + "settings_showToasts_note": "Деактивирайте общата настройка '{{var0}}' на BD, преди да ги деактивирате", + "settings_toastPosition_description": "Позиция за тост по подразбиране", + "settings_toastPosition_note": "Променя само позицията на тостове, създадени от моите приставки", + "settings_useChromium_description": "Отворете връзки в Discord вместо вашия браузър", + "sort_by": "Сортиране по", + "status": "Състояние", + "time": "Време", + "timezone": "Часова зона", + "to": "Да се", + "toast_plugin_force_updated": "{{var0}} се актуализира автоматично, тъй като версията ви беше много остаряла", + "toast_plugin_loaded": "{{var0}} е зареден", + "toast_plugin_started": "{{var0}} започна", + "toast_plugin_stopped": "{{var0}} спря", + "toast_plugin_translated": "преведено на {{var0}}", + "toast_plugin_unloaded": "{{var0}} е разтоварен", + "toast_plugin_update_failed": "Актуализацията за {{var0}} не може да бъде изтеглена", + "toast_plugin_updated": "{{var0}} {{var1}} е заменено с {{var2}} {{var3}}", + "update_check_complete": "Проверката за актуализация на приставката завърши", + "update_check_complete_outdated": "Проверката за актуализация на приставката завърши - {{var0}} остаряла!", + "update_check_info": "Проверете приставки, които поддържат проверката на актуализацията", + "update_notice_click": "Щракнете за актуализация!", + "update_notice_reload": "Презаредете, за да завършите актуализацията", + "update_notice_update": "Следните приставки трябва да бъдат актуализирани: ", + "updated": "Актуализирано" + }, + "cs": { + "add_to": "Přidat do {{var0}}", + "ascending": "Vzestupně", + "center": "Na střed", + "changelog_added": "Nové vlastnosti", + "changelog_fixed": "Oprava chyb", + "changelog_improved": "Vylepšení", + "changelog_progress": "Pokrok", + "check_for_updates": "Kontrola aktualizací", + "clipboard_success": "{{var0}} zkopírováno do schránky", + "confirm": "Jsi si jistá?", + "copy": "Kopírovat {{var0}}", + "delete_fail": "Aplikaci {{var0}} nelze smazat", + "delete_success": "{{var0}} úspěšně smazán", + "descending": "Klesající", + "developer": "Vývojář", + "donate_message": "Podpořte mě, abyste získali další aktualizace!", + "download": "Stažení", + "download_fail": "Aplikaci {{var0}} nelze stáhnout", + "download_success": "Aplikace {{var0}} byla úspěšně stažena", + "file_navigator_text": "Procházet soubor", + "first": "První", + "from": "Z", + "gradient": "Spád", + "guildbanner": "Ikona", + "guildicon": "Prapor", + "installed": "Nainstalováno", + "last": "Poslední", + "left": "Vlevo, odjet", + "loading": "Načítání {{var0}}", + "location": "Umístění", + "order": "Objednat", + "outdated": "Zastaralý", + "please_wait": "Prosím, čekejte", + "right": "Že jo", + "save_fail": "{{var0}} nelze uložit", + "save_success": "{{var0}} úspěšně uložen", + "send": "Odeslat {{var0}}", + "server": "Server", + "settings_shareData_description": "Synchronizuje konfigurace zásuvných modulů mezi účty Discord", + "settings_showSupportBadges_description": "Zobrazuje malé odznaky pro uživatele, kteří podporují můj Patreon", + "settings_showToasts_description": "Zobrazuje spuštění a zastavení pluginu", + "settings_showToasts_note": "Před deaktivací deaktivujte obecné nastavení BD {{var0}}", + "settings_toastPosition_description": "Výchozí pozice toastu", + "settings_toastPosition_note": "Změní pouze pozici toastů vytvořených mými pluginy", + "settings_useChromium_description": "Otevřete odkazy v programu Discord namísto v prohlížeči", + "sort_by": "Seřazeno podle", + "status": "Postavení", + "time": "Čas", + "timezone": "Časové pásmo", + "to": "Na", + "toast_plugin_force_updated": "Verze {{var0}} byla automaticky aktualizována, protože vaše verze je silně zastaralá", + "toast_plugin_loaded": "{{var0}} byl načten", + "toast_plugin_started": "Byla spuštěna aplikace {{var0}}", + "toast_plugin_stopped": "Aplikace {{var0}} byla zastavena", + "toast_plugin_translated": "přeloženo do jazyka {{var0}}", + "toast_plugin_unloaded": "Aplikace {{var0}} byla uvolněna", + "toast_plugin_update_failed": "Aktualizaci pro {{var0}} nelze stáhnout", + "toast_plugin_updated": "{{var0}} {{var1}} byl nahrazen {{var2}} {{var3}}", + "update_check_complete": "Kontrola aktualizace pluginu dokončena", + "update_check_complete_outdated": "Kontrola aktualizace pluginu dokončena - {{var0}} zastaralá!", + "update_check_info": "Zkontrolujte doplňky, které podporují kontrolu aktualizace", + "update_notice_click": "Klikněte pro aktualizaci!", + "update_notice_reload": "Aktualizaci dokončete znovu", + "update_notice_update": "Je třeba aktualizovat následující doplňky:", + "updated": "Aktualizováno" + }, + "da": { + "add_to": "Føj til {{var0}}", + "ascending": "Stigende", + "center": "Centreret", + "changelog_added": "Nye funktioner", + "changelog_fixed": "Fejlfinding", + "changelog_improved": "Forbedringer", + "changelog_progress": "Fremskridt", + "check_for_updates": "Søg efter opdateringer", + "clipboard_success": "Kopieret {{var0}} til udklipsholder", + "confirm": "Er du sikker?", + "copy": "Kopiér {{var0}}", + "delete_fail": "{{var0}} kan ikke slettes", + "delete_success": "{{var0}} blev slettet", + "descending": "Aftagende", + "developer": "Udvikler", + "donate_message": "Støt mig for flere opdateringer!", + "download": "Hent", + "download_fail": "{{var0}} kan ikke downloades", + "download_success": "{{var0}} downloadet med succes", + "file_navigator_text": "Gennemse fil", + "first": "Først", + "from": "Fra", + "gradient": "Gradient", + "guildbanner": "Banner", + "guildicon": "Ikon", + "installed": "Installeret", + "last": "Sidst", + "left": "Venstre", + "loading": "Indlæser {{var0}}", + "location": "Beliggenhed", + "order": "Sekvens", + "outdated": "Forældet", + "please_wait": "Vent venligst", + "right": "Ret", + "save_fail": "{{var0}} kan ikke gemmes", + "save_success": "{{var0}} blev gemt", + "send": "Send {{var0}}", + "server": "Server", + "settings_shareData_description": "Synkroniserer plugin-konfigurationerne mellem Discord-konti", + "settings_showSupportBadges_description": "Viser små badges til brugere, der understøtter min Patreon", + "settings_showToasts_description": "Viser plugin start og stop toasts", + "settings_showToasts_note": "Deaktiver den generelle indstilling '{{var0}}' for BD'er, inden du deaktiverer dem", + "settings_toastPosition_description": "Standard skålposition", + "settings_toastPosition_note": "Ændrer kun placeringen af ​​skåle oprettet af mine plugins", + "settings_useChromium_description": "Åbn Links i Discord i stedet for din browser", + "sort_by": "Sorter efter", + "status": "Status", + "time": "Tid", + "timezone": "Tidszone", + "to": "Til", + "toast_plugin_force_updated": "{{var0}} blev automatisk opdateret, fordi din version var meget forældet", + "toast_plugin_loaded": "{{var0}} er indlæst", + "toast_plugin_started": "{{var0}} er startet", + "toast_plugin_stopped": "{{var0}} er stoppet", + "toast_plugin_translated": "oversat til {{var0}}", + "toast_plugin_unloaded": "{{var0}} er blevet aflæst", + "toast_plugin_update_failed": "Opdatering til {{var0}} kan ikke downloades", + "toast_plugin_updated": "{{var0}} {{var1}} er blevet erstattet af {{var2}} {{var3}}", + "update_check_complete": "Kontrollen af plugin-opdatering afsluttet", + "update_check_complete_outdated": "Kontrollen af ​​plugin-opdatering afsluttet - {{var0}} forældet!", + "update_check_info": "Kontroller plugins, der understøtter opdateringskontrollen", + "update_notice_click": "Klik for at opdatere!", + "update_notice_reload": "Genindlæs for at fuldføre opdateringen", + "update_notice_update": "Følgende plugins skal opdateres: ", + "updated": "Opdateret" + }, + "de": { + "add_to": "Zu {{var0}} hinzufügen", + "ascending": "Aufsteigend", + "center": "Zentriert", + "changelog_added": "Neue Features", + "changelog_fixed": "Fehlerbehebung", + "changelog_improved": "Verbesserungen", + "changelog_progress": "Fortschritt", + "check_for_updates": "Suche nach Updates", + "clipboard_success": "{{var0}} in die Zwischenablage kopiert", + "confirm": "Bist du sicher?", + "copy": "{{var0}} kopieren", + "delete_fail": "{{var0}} kann nicht gelöscht werden", + "delete_success": "{{var0}} erfolgreich gelöscht", + "descending": "Absteigend", + "developer": "Entwickler", + "donate_message": "Unterstütze mich, um weitere Updates zu erhalten!", + "download": "Herunterladen", + "download_fail": "{{var0}} kann nicht heruntergeladen werden", + "download_success": "{{var0}} erfolgreich heruntergeladen", + "file_navigator_text": "Datei durchsuchen", + "first": "Zuerst", + "from": "Von", + "gradient": "Gradient", + "guildbanner": "Banner", + "guildicon": "Symbol", + "installed": "Installiert", + "last": "Zuletzt", + "left": "Links", + "loading": "Lädt {{var0}}", + "location": "Ort", + "order": "Reihenfolge", + "outdated": "Veraltet", + "please_wait": "Bitte warten", + "right": "Rechts", + "save_fail": "{{var0}} kann nicht gespeichert werden", + "save_success": "{{var0}} erfolgreich gespeichert", + "send": "{{var0}} senden", + "server": "Server", + "settings_shareData_description": "Synchronisiert die Plugin-Konfigurationen zwischen Discord-Konten", + "settings_showSupportBadges_description": "Zeigt kleine Abzeichen für Benutzer, die meinen Patreon unterstützen", + "settings_showToasts_description": "Zeigt Plugin Start und Stopp Toasts", + "settings_showToasts_note": "Deaktiviere die allgemeine BD Einstellung '{{var0}}', bevor du diese deaktivierst", + "settings_toastPosition_description": "Standard Toast Position", + "settings_toastPosition_note": "Ändert nur die Position von Toasts, die von meinen Plugins erstellt wurden", + "settings_useChromium_description": "Öffne Links in Discord anstelle deines Browsers", + "sort_by": "Sortieren nach", + "status": "Status", + "time": "Zeit", + "timezone": "Zeitzone", + "to": "Zu", + "toast_plugin_force_updated": "{{var0}} wurde automatisch aktualisiert, da deine Version stark veraltet war", + "toast_plugin_loaded": "{{var0}} wurde geladen", + "toast_plugin_started": "{{var0}} wurde gestartet", + "toast_plugin_stopped": "{{var0}} wurde gestoppt", + "toast_plugin_translated": "übersetzt nach {{var0}}", + "toast_plugin_unloaded": "{{var0}} wurde entladen", + "toast_plugin_update_failed": "Update für {{var0}} kann nicht heruntergeladen werden", + "toast_plugin_updated": "{{var0}} {{var1}} wurde durch {{var2}} {{var3}} ersetzt", + "update_check_complete": "Plugin Update Check abgeschlossen", + "update_check_complete_outdated": "Plugin Update Check abgeschlossen - {{var0}} veraltet!", + "update_check_info": "Check Plugins, die den Update Check unterstützen", + "update_notice_click": "Zum Aktualisieren klicken!", + "update_notice_reload": "Neu laden, um die Aktualisierung abzuschließen", + "update_notice_update": "Die folgenden Plugins müssen aktualisiert werden: ", + "updated": "Aktualisiert" + }, + "el": { + "add_to": "Προσθήκη στο {{var0}}", + "ascending": "Ανερχόμενος", + "center": "Στο κέντρο", + "changelog_added": "Νέα χαρακτηριστικά", + "changelog_fixed": "Αντιμετώπιση προβλημάτων", + "changelog_improved": "Βελτιώσεις", + "changelog_progress": "Πρόοδος", + "check_for_updates": "Ελεγχος για ενημερώσεις", + "clipboard_success": "Αντιγράφηκε το {{var0}} στο Πρόχειρο", + "confirm": "Είσαι σίγουρος?", + "copy": "Αντιγραφή {{var0}}", + "delete_fail": "Δεν είναι δυνατή η διαγραφή του {{var0}}", + "delete_success": "Το {{var0}} διαγράφηκε με επιτυχία", + "descending": "Φθίνων", + "developer": "Προγραμματιστής", + "donate_message": "Υποστηρίξτε με για περισσότερες ενημερώσεις!", + "download": "Κατεβάστε", + "download_fail": "Δεν είναι δυνατή η λήψη του {{var0}}", + "download_success": "Η λήψη του {{var0}} ολοκληρώθηκε με επιτυχία", + "file_navigator_text": "Αναζήτηση αρχείου", + "first": "Πρώτα", + "from": "Από", + "gradient": "Βαθμίδα", + "guildbanner": "Πανό", + "guildicon": "Εικόνισμα", + "installed": "Εγκατασταθεί", + "last": "Τελευταίος", + "left": "Αριστερά", + "loading": "Φόρτωση {{var0}}", + "location": "Τοποθεσία", + "order": "Αλληλουχία", + "outdated": "Απαρχαιωμένος", + "please_wait": "Ευχάριστη αναμονή", + "right": "Σωστά", + "save_fail": "Δεν είναι δυνατή η αποθήκευση του {{var0}}", + "save_success": "Το {{var0}} αποθηκεύτηκε με επιτυχία", + "send": "Αποστολή {{var0}}", + "server": "Υπηρέτης", + "settings_shareData_description": "Συγχρονίζει τις ρυθμίσεις παραμέτρων της προσθήκης μεταξύ λογαριασμών Discord", + "settings_showSupportBadges_description": "Εμφανίζει μικρά σήματα για χρήστες που υποστηρίζουν το Patreon μου", + "settings_showToasts_description": "Δείχνει τις προσθήκης έναρξης και διακοπής τοστ", + "settings_showToasts_note": "Απενεργοποιήστε τη γενική ρύθμιση '{{var0}}' των BD πριν απενεργοποιήσετε", + "settings_toastPosition_description": "Προεπιλεγμένη θέση τοστ", + "settings_toastPosition_note": "Αλλάζει μόνο τη θέση των Τοστ που δημιουργήθηκαν από τις προσθήκες μου", + "settings_useChromium_description": "Ανοίξτε τους συνδέσμους στο Discord αντί για το πρόγραμμα περιήγησής σας", + "sort_by": "Ταξινόμηση κατά", + "status": "Κατάσταση", + "time": "Χρόνος", + "timezone": "Ζώνη ώρας", + "to": "Προς το", + "toast_plugin_force_updated": "Το {{var0}} ενημερώθηκε αυτόματα επειδή η έκδοσή σας ήταν πολύ παλιά", + "toast_plugin_loaded": "Το {{var0}} έχει φορτωθεί", + "toast_plugin_started": "Το {{var0}} έχει ξεκινήσει", + "toast_plugin_stopped": "Το {{var0}} έχει σταματήσει", + "toast_plugin_translated": "μεταφράστηκε σε {{var0}}", + "toast_plugin_unloaded": "Το {{var0}} έχει εκφορτωθεί", + "toast_plugin_update_failed": "Δεν είναι δυνατή η λήψη της ενημέρωσης για το {{var0}}", + "toast_plugin_updated": "Το {{var0}} {{var1}} αντικαταστάθηκε από το {{var2}} {{var3}}", + "update_check_complete": "Ο έλεγχος ενημέρωσης προσθήκης ολοκληρώθηκε", + "update_check_complete_outdated": "Ο έλεγχος ενημέρωσης προσθήκης ολοκληρώθηκε - {{var0}} δεν είναι ενημερωμένος!", + "update_check_info": "Έλεγχος προσθήκες που υποστηρίζουν τον έλεγχο ενημέρωσης", + "update_notice_click": "Κάντε κλικ για ενημέρωση!", + "update_notice_reload": "Επαναλάβετε τη φόρτωση για να ολοκληρώσετε την ενημέρωση", + "update_notice_update": "Οι ακόλουθες προσθήκες πρέπει να ενημερωθούν: ", + "updated": "ΕΠΙΚΑΙΡΟΠΟΙΗΜΕΝΟ" + }, + "es": { + "add_to": "Agregar a {{var0}}", + "ascending": "Ascendente", + "center": "Centrado", + "changelog_added": "Nuevas características", + "changelog_fixed": "Solución de problemas", + "changelog_improved": "Mejoras", + "changelog_progress": "Progreso", + "check_for_updates": "Buscar actualizaciones", + "clipboard_success": "Copiado {{var0}} al Portapapeles", + "confirm": "¿Estás seguro?", + "copy": "Copiar {{var0}}", + "delete_fail": "{{var0}} no se puede eliminar", + "delete_success": "{{var0}} eliminado correctamente", + "descending": "Descendiendo", + "developer": "Desarrollador", + "donate_message": "¡Apóyanme para obtener más actualizaciones!", + "download": "Descargar", + "download_fail": "{{var0}} no se puede descargar", + "download_success": "{{var0}} descargado correctamente", + "file_navigator_text": "Buscar Archivo", + "first": "Primero", + "from": "Desde", + "gradient": "Degradado", + "guildbanner": "Bandera", + "guildicon": "Icono", + "installed": "Instalado", + "last": "Último", + "left": "Izquierda", + "loading": "Cargando {{var0}}", + "location": "Localización", + "order": "Secuencia", + "outdated": "Anticuado", + "please_wait": "Por favor espera", + "right": "Correcto", + "save_fail": "{{var0}} no se puede guardar", + "save_success": "{{var0}} guardado correctamente", + "send": "Enviar {{var0}}", + "server": "Servidor", + "settings_shareData_description": "Sincroniza las configuraciones del complemento entre las cuentas de Discord", + "settings_showSupportBadges_description": "Muestra pequeñas insignias para los usuarios que apoyan mi Patreon", + "settings_showToasts_description": "Muestra el inicio y la parada del complemento.", + "settings_showToasts_note": "Desactive la configuración general '{{var0}}' de los BD antes de desactivarlos", + "settings_toastPosition_description": "Posición de tostada predeterminada", + "settings_toastPosition_note": "Solo cambia la posición de los brindis creados por mis complementos", + "settings_useChromium_description": "Abra enlaces en Discord en lugar de su navegador", + "sort_by": "Ordenar por", + "status": "Estado", + "time": "Hora", + "timezone": "Zona horaria", + "to": "A", + "toast_plugin_force_updated": "{{var0}} se actualizó automáticamente porque su versión estaba muy desactualizada", + "toast_plugin_loaded": "Se cargó {{var0}}", + "toast_plugin_started": "{{var0}} ha comenzado", + "toast_plugin_stopped": "{{var0}} se detuvo", + "toast_plugin_translated": "traducido a {{var0}}", + "toast_plugin_unloaded": "{{var0}} se ha descargado", + "toast_plugin_update_failed": "No se puede descargar la actualización para {{var0}}", + "toast_plugin_updated": "{{var0}} {{var1}} ha sido reemplazado por {{var2}} {{var3}}", + "update_check_complete": "Comprobación de actualización del complemento completada", + "update_check_complete_outdated": "Comprobación de actualización del complemento completada: {{var0}} desactualizada.", + "update_check_info": "Verifique los complementos que admiten la verificación de actualizaciones", + "update_notice_click": "¡Haz clic para actualizar!", + "update_notice_reload": "Recargar para completar la actualización", + "update_notice_update": "Los siguientes complementos deben actualizarse: ", + "updated": "Actualizado" + }, + "fi": { + "add_to": "Lisää {{var0}}", + "ascending": "Nouseva", + "center": "Keskitetty", + "changelog_added": "Uudet ominaisuudet", + "changelog_fixed": "Ongelmien karttoittaminen", + "changelog_improved": "Parannuksia", + "changelog_progress": "Edistystä", + "check_for_updates": "Tarkista päivitykset", + "clipboard_success": "Kopioitu {{var0}} leikepöydälle", + "confirm": "Oletko varma?", + "copy": "Kopioi {{var0}}", + "delete_fail": "{{var0}} ei voi poistaa", + "delete_success": "{{var0}} poistettu", + "descending": "Laskeva", + "developer": "Kehittäjä", + "donate_message": "Tue minua lisää päivityksiä varten!", + "download": "Ladata", + "download_fail": "{{var0}} ei voi ladata", + "download_success": "{{var0}} ladattu onnistuneesti", + "file_navigator_text": "Selaa tiedostoa", + "first": "Ensimmäinen", + "from": "Alkaen", + "gradient": "Kaltevuus", + "guildbanner": "Banneri", + "guildicon": "Kuvake", + "installed": "Asennettu", + "last": "Kestää", + "left": "Vasen", + "loading": "Ladataan {{var0}}", + "location": "Sijainti", + "order": "Järjestys", + "outdated": "Vanhentunut", + "please_wait": "Odota", + "right": "Aivan", + "save_fail": "Kohdetta {{var0}} ei voi tallentaa", + "save_success": "{{var0}} tallennettu onnistuneesti", + "send": "Lähetä {{var0}}", + "server": "Palvelin", + "settings_shareData_description": "Synkronoi laajennusasetukset Discord-tilien välillä", + "settings_showSupportBadges_description": "Näyttää pienet merkit käyttäjille, jotka tukevat Patreoniani", + "settings_showToasts_description": "Näyttää laajennuksen aloitus- ja lopetusleivokset", + "settings_showToasts_note": "Poista BD-levyjen yleinen asetus {{var0}} ennen niiden poistamista käytöstä", + "settings_toastPosition_description": "Oletus paahtoleipää", + "settings_toastPosition_note": "Muuttaa vain laajennukset luomien paahtoleivien sijaintia", + "settings_useChromium_description": "Avaa Linkit ristiriidassa selaimen sijaan", + "sort_by": "Järjestä", + "status": "Tila", + "time": "Aika", + "timezone": "Aikavyöhyke", + "to": "Vastaanottaja", + "toast_plugin_force_updated": "{{var0}} päivitettiin automaattisesti, koska versiosi oli vanhentunut", + "toast_plugin_loaded": "{{var0}} on ladattu", + "toast_plugin_started": "{{var0}} on alkanut", + "toast_plugin_stopped": "{{var0}} on pysähtynyt", + "toast_plugin_translated": "käännetty kielelle {{var0}}", + "toast_plugin_unloaded": "{{var0}} on purettu", + "toast_plugin_update_failed": "Verkkotunnuksen {{var0}} päivitystä ei voi ladata", + "toast_plugin_updated": "{{var0}} {{var1}} on korvattu sanalla {{var2}} {{var3}}", + "update_check_complete": "Laajennuksen päivityksen tarkistus valmis", + "update_check_complete_outdated": "Laajennuksen päivityksen tarkistus valmis - {{var0}} vanhentunut!", + "update_check_info": "Tarkista päivitystarkistusta tukevat laajennukset", + "update_notice_click": "Napsauta päivittääksesi!", + "update_notice_reload": "Lataa päivitys loppuun", + "update_notice_update": "Seuraavat laajennukset on päivitettävä: ", + "updated": "Päivitetty" + }, + "fr": { + "add_to": "Ajouter à {{var0}}", + "ascending": "Ascendant", + "center": "Centré", + "changelog_added": "Nouvelles fonctionnalités", + "changelog_fixed": "Dépannage", + "changelog_improved": "Améliorations", + "changelog_progress": "Le progrès", + "check_for_updates": "Rechercher des mises à jour", + "clipboard_success": "{{var0}} copié dans le presse-papiers", + "confirm": "Êtes-vous sûr?", + "copy": "Copiez {{var0}}", + "delete_fail": "{{var0}} ne peut pas être supprimé", + "delete_success": "{{var0}} supprimé avec succès", + "descending": "Descendant", + "developer": "Développeur", + "donate_message": "Soutenez-moi pour plus de mises à jour!", + "download": "Télécharger", + "download_fail": "{{var0}} ne peut pas être téléchargé", + "download_success": "{{var0}} téléchargé avec succès", + "file_navigator_text": "Parcourir le fichier", + "first": "Première", + "from": "De", + "gradient": "Pente", + "guildbanner": "Bannière", + "guildicon": "Icône", + "installed": "Installée", + "last": "Dernier", + "left": "Gauche", + "loading": "Chargement de {{var0}}", + "location": "Emplacement", + "order": "Séquence", + "outdated": "Dépassé", + "please_wait": "S'il vous plaît, attendez", + "right": "Droite", + "save_fail": "{{var0}} ne peut pas être enregistré", + "save_success": "{{var0}} a bien été enregistré", + "send": "Envoyer {{var0}}", + "server": "Serveur", + "settings_shareData_description": "Synchronise les configurations de plugin entre les comptes Discord", + "settings_showSupportBadges_description": "Affiche de petits badges pour les utilisateurs qui soutiennent mon Patreon", + "settings_showToasts_description": "Affiche les toasts de démarrage et d'arrêt du plugin", + "settings_showToasts_note": "Désactivez le paramètre général '{{var0}}' des BD avant de les désactiver", + "settings_toastPosition_description": "Position de toast par défaut", + "settings_toastPosition_note": "Modifie uniquement la position des toasts créés par mes plugins", + "settings_useChromium_description": "Ouvrez les liens dans Discord au lieu de votre navigateur", + "sort_by": "Trier par", + "status": "Statut", + "time": "Temps", + "timezone": "Fuseau horaire", + "to": "À", + "toast_plugin_force_updated": "{{var0}} a été automatiquement mis à jour car votre version était très obsolète", + "toast_plugin_loaded": "{{var0}} a été chargé", + "toast_plugin_started": "{{var0}} a commencé", + "toast_plugin_stopped": "{{var0}} s'est arrêté", + "toast_plugin_translated": "traduit en {{var0}}", + "toast_plugin_unloaded": "{{var0}} a été déchargé", + "toast_plugin_update_failed": "La mise à jour pour {{var0}} ne peut pas être téléchargée", + "toast_plugin_updated": "{{var0}} {{var1}} a été remplacé par {{var2}} {{var3}}", + "update_check_complete": "Vérification de la mise à jour du plugin terminée", + "update_check_complete_outdated": "Vérification de la mise à jour du plugin terminée - {{var0}} obsolète!", + "update_check_info": "Vérifiez les plugins prenant en charge la vérification des mises à jour", + "update_notice_click": "Cliquez pour mettre à jour!", + "update_notice_reload": "Recharger pour terminer la mise à jour", + "update_notice_update": "Les plugins suivants doivent être mis à jour: ", + "updated": "Mis à jour" + }, + "hi": { + "add_to": "{{var0}} में जोड़ें", + "ascending": "आरोही", + "center": "केंद्रित", + "changelog_added": "नए विशेषताएँ", + "changelog_fixed": "कंप्यूटर प्रोग्राम या प्रणाली में बग को दूर करना", + "changelog_improved": "सुधार", + "changelog_progress": "प्रगति", + "check_for_updates": "अद्यतन के लिए जाँच", + "clipboard_success": "{{var0}} को क्लिपबोर्ड पर कॉपी किया गया", + "confirm": "क्या आपको यकीन है?", + "copy": "कॉपी {{var0}}", + "delete_fail": "{{var0}} को हटाया नहीं जा सकता", + "delete_success": "{{var0}} सफलतापूर्वक हटाया गया", + "descending": "अवरोही", + "developer": "डेवलपर", + "donate_message": "आगे के अपडेट प्राप्त करने के लिए मेरा समर्थन करें!", + "download": "डाउनलोड", + "download_fail": "{{var0}} डाउनलोड नहीं किया जा सकता", + "download_success": "{{var0}} सफलतापूर्वक डाउनलोड किया गया", + "file_navigator_text": "फाइल खोजो", + "first": "प्रथम", + "from": "से", + "gradient": "ढाल", + "guildbanner": "बैनर", + "guildicon": "आइकन", + "installed": "स्थापित", + "last": "पिछले", + "left": "बाएं", + "loading": "लोड हो रहा है {{var0}}", + "location": "स्थान", + "order": "गण", + "outdated": "रगड़ा हुआ", + "please_wait": "कृपया प्रतीक्षा करें", + "right": "सही", + "save_fail": "{{var0}} सहेजा नहीं जा सकता", + "save_success": "{{var0}} सफलतापूर्वक सहेजा गया", + "send": "भेजें {{var0}}", + "server": "सर्वर", + "settings_shareData_description": "डिस्कॉर्ड खातों के बीच प्लगइन कॉन्फिग को सिंक्रोनाइज़ करता है", + "settings_showSupportBadges_description": "मेरे Patreon का समर्थन करने वाले उपयोगकर्ताओं के लिए छोटे बैज दिखाता है", + "settings_showToasts_description": "प्लगिन को दिखाता है टोस्ट शुरू और बंद करो", + "settings_showToasts_note": "इसे अक्षम करने से पहले BDs सामान्य '{{var0}}' सेटिंग अक्षम करें", + "settings_toastPosition_description": "डिफ़ॉल्ट टोस्ट स्थिति", + "settings_toastPosition_note": "केवल मेरे प्लगइन्स द्वारा बनाए गए टोस्ट की स्थिति बदलता है", + "settings_useChromium_description": "अपने ब्राउज़र के बजाय डिस्कॉर्ड में लिंक खोलें", + "sort_by": "इसके अनुसार क्रमबद्ध करें", + "status": "स्थिति", + "time": "समय", + "timezone": "समय क्षेत्र", + "to": "सेवा", + "toast_plugin_force_updated": "{{var0}} अपने आप अपडेट हो गया क्योंकि आपका संस्करण काफी पुराना हो गया है", + "toast_plugin_loaded": "{{var0}} लोड कर दिया गया है", + "toast_plugin_started": "{{var0}} शुरू कर दिया गया है", + "toast_plugin_stopped": "{{var0}} रोक दिया गया है", + "toast_plugin_translated": "{{var0}} में अनुवादित", + "toast_plugin_unloaded": "{{var0}} अनलोड कर दिया गया है", + "toast_plugin_update_failed": "{{var0}} के लिए अपडेट डाउनलोड नहीं किया जा सकता", + "toast_plugin_updated": "{{var0}} {{var1}} को {{var2}} {{var3}} से बदल दिया गया है", + "update_check_complete": "प्लगइन अद्यतन जाँच पूर्ण", + "update_check_complete_outdated": "प्लगिन अपडेट जांच पूरी हुई - {{var0}} पुरानी!", + "update_check_info": "चेक प्लगइन्स जो अपडेट चेक का समर्थन करते हैं", + "update_notice_click": "अपडेट करने के लिए क्लिक करें!", + "update_notice_reload": "अद्यतन पूरा करने के लिए पुनः लोड करें", + "update_notice_update": "निम्नलिखित प्लगइन्स को अद्यतन करने की आवश्यकता है:", + "updated": "अद्यतन" + }, + "hr": { + "add_to": "Dodaj u {{var0}}", + "ascending": "Uzlazni", + "center": "Centrirano", + "changelog_added": "Nove značajke", + "changelog_fixed": "Rješavanje problema", + "changelog_improved": "Poboljšanja", + "changelog_progress": "Napredak", + "check_for_updates": "Provjerite ima li ažuriranja", + "clipboard_success": "Kopirano {{var0}} u međuspremnik", + "confirm": "Jesi li siguran?", + "copy": "Kopiraj {{var0}}", + "delete_fail": "{{var0}} nije moguće izbrisati", + "delete_success": "{{var0}} uspješno je izbrisano", + "descending": "Silazni", + "developer": "Programer", + "donate_message": "Podržite me za još novosti!", + "download": "Preuzimanje datoteka", + "download_fail": "{{var0}} nije moguće preuzeti", + "download_success": "{{var0}} uspješno preuzeto", + "file_navigator_text": "Pregledaj datoteku", + "first": "Prvi", + "from": "Iz", + "gradient": "Gradijent", + "guildbanner": "Natpis", + "guildicon": "Ikona", + "installed": "Instaliran", + "last": "Posljednji", + "left": "Lijevo", + "loading": "Učitavanje {{var0}}", + "location": "Mjesto", + "order": "Slijed", + "outdated": "Zastario", + "please_wait": "Drago mi je čekati", + "right": "Pravo", + "save_fail": "{{var0}} nije moguće spremiti", + "save_success": "{{var0}} uspješno spremljeno", + "send": "Pošalji {{var0}}", + "server": "Poslužitelju", + "settings_shareData_description": "Sinkronizira konfiguracije dodataka između Discord računa", + "settings_showSupportBadges_description": "Prikazuje male značke za korisnike koji podržavaju moj Patreon", + "settings_showToasts_description": "Prikazuje tost za pokretanje i zaustavljanje dodatka", + "settings_showToasts_note": "Onemogućite opću postavku '{{var0}}' BD-ova prije nego što ih onemogućite", + "settings_toastPosition_description": "Zadani položaj tosta", + "settings_toastPosition_note": "Mijenja samo položaj zdravica koje su stvorili moji dodatke", + "settings_useChromium_description": "Otvorite veze u Discordu umjesto u pregledniku", + "sort_by": "Poredati po", + "status": "Status", + "time": "Vrijeme", + "timezone": "Vremenska zona", + "to": "Do", + "toast_plugin_force_updated": "{{var0}} je automatski ažuriran jer je vaša verzija bila vrlo zastarjela", + "toast_plugin_loaded": "Učitana je {{var0}}", + "toast_plugin_started": "{{var0}} je započeo", + "toast_plugin_stopped": "{{var0}} je zaustavljen", + "toast_plugin_translated": "prevedeno na {{var0}}", + "toast_plugin_unloaded": "{{var0}} je istovaren", + "toast_plugin_update_failed": "Ažuriranje za {{var0}} nije moguće preuzeti", + "toast_plugin_updated": "{{var0}} {{var1}} zamijenjen je s {{var2}} {{var3}}", + "update_check_complete": "Provjera ažuriranja dodatka dovršena", + "update_check_complete_outdated": "Provjera ažuriranja dodatka dovršena - {{var0}} zastarjelo!", + "update_check_info": "Provjerite dodatke koji podržavaju provjeru ažuriranja", + "update_notice_click": "Kliknite za ažuriranje!", + "update_notice_reload": "Ponovo učitajte da biste dovršili ažuriranje", + "update_notice_update": "Treba ažurirati sljedeće dodatke: ", + "updated": "Ažurirano" + }, + "hu": { + "add_to": "Hozzáadás a következőhöz: {{var0}}", + "ascending": "Növekvő", + "center": "Középre", + "changelog_added": "Új funkciók", + "changelog_fixed": "Hibaelhárítás", + "changelog_improved": "Fejlesztések", + "changelog_progress": "Előrehalad", + "check_for_updates": "Frissítések keresése", + "clipboard_success": "{{var0}} a vágólapra másolva", + "confirm": "Biztos vagy ebben?", + "copy": "Másolás {{var0}}", + "delete_fail": "A {{var0}} nem törölhető", + "delete_success": "{{var0}} sikeresen törölve", + "descending": "Csökkenő", + "developer": "Fejlesztő", + "donate_message": "Támogasson további frissítésekért!", + "download": "Letöltés", + "download_fail": "A {{var0}} nem tölthető le", + "download_success": "A {{var0}} letöltése sikeresen megtörtént", + "file_navigator_text": "Tallózás a fájlban", + "first": "Első", + "from": "Erről", + "gradient": "Gradiens", + "guildbanner": "Banner", + "guildicon": "Ikon", + "installed": "Telepítve", + "last": "Utolsó", + "left": "Bal", + "loading": "{{var0}} betöltése", + "location": "Elhelyezkedés", + "order": "Sorrend", + "outdated": "Elavult", + "please_wait": "Várj", + "right": "Jobb", + "save_fail": "A {{var0}} nem menthető", + "save_success": "{{var0}} sikeresen mentve", + "send": "{{var0}} küldése", + "server": "Szerver", + "settings_shareData_description": "Szinkronizálja a beépülő modulok beállításait a Discord fiókok között", + "settings_showSupportBadges_description": "Apró jelvényeket mutat azoknak a felhasználóknak, akik támogatják a Patreon-t", + "settings_showToasts_description": "Mutatja a bővítmény start és stop pirítósokat", + "settings_showToasts_note": "Mielőtt letiltaná őket, tiltsa le a BD-k '{{var0}} ” általános beállítását", + "settings_toastPosition_description": "Alapértelmezett pirítós pozíció", + "settings_toastPosition_note": "Csak a bővítményeket által létrehozott pirítósok pozícióját változtatja meg", + "settings_useChromium_description": "Nyissa meg a Linkeket a diszkordban a böngészője helyett", + "sort_by": "Sorrend", + "status": "Állapot", + "time": "Idő", + "timezone": "Időzóna", + "to": "Erre", + "toast_plugin_force_updated": "A {{var0}} automatikusan frissült, mert a verziója nagyon elavult", + "toast_plugin_loaded": "{{var0}} betöltve", + "toast_plugin_started": "A {{var0}} elindult", + "toast_plugin_stopped": "A {{var0}} leállt", + "toast_plugin_translated": "lefordítva {{var0}} nyelvre", + "toast_plugin_unloaded": "{{var0}} kirakva", + "toast_plugin_update_failed": "A {{var0}} frissítése nem tölthető le", + "toast_plugin_updated": "A {{var0}} {{var1}} helyébe a következő lépett: {{var2}} {{var3}}", + "update_check_complete": "A bővítmény modul frissítésének ellenőrzése befejeződött", + "update_check_complete_outdated": "A bővítmény modul frissítésének ellenőrzése befejeződött - {{var0}} elavult!", + "update_check_info": "Ellenőrizze a Frissítés ellenőrzését támogató bővítményeket modulokat", + "update_notice_click": "Kattintson a frissítéshez!", + "update_notice_reload": "Töltse be újra a frissítés befejezéséhez", + "update_notice_update": "A következő bővítményeket frissíteni kell: ", + "updated": "Frissítve" + }, + "it": { + "add_to": "Aggiungi a {{var0}}", + "ascending": "Ascendente", + "center": "Centrato", + "changelog_added": "Nuove caratteristiche", + "changelog_fixed": "Risoluzione dei problemi", + "changelog_improved": "Miglioramenti", + "changelog_progress": "Progresso", + "check_for_updates": "Controlla gli aggiornamenti", + "clipboard_success": "{{var0}} copiato negli Appunti", + "confirm": "Sei sicuro?", + "copy": "Copia {{var0}}", + "delete_fail": "{{var0}} non può essere eliminato", + "delete_success": "{{var0}} eliminato correttamente", + "descending": "Discendente", + "developer": "Sviluppatore", + "donate_message": "Supportami per ulteriori aggiornamenti!", + "download": "Scarica", + "download_fail": "{{var0}} non può essere scaricato", + "download_success": "{{var0}} scaricato correttamente", + "file_navigator_text": "Sfoglia file", + "first": "Primo", + "from": "A partire dal", + "gradient": "Pendenza", + "guildbanner": "Banner", + "guildicon": "Icona", + "installed": "Installato", + "last": "Scorso", + "left": "Sinistra", + "loading": "Caricamento di {{var0}}", + "location": "Posizione", + "order": "Sequenza", + "outdated": "Obsoleto", + "please_wait": "Attendere prego", + "right": "Destra", + "save_fail": "{{var0}} non può essere salvato", + "save_success": "{{var0}} salvato correttamente", + "send": "Invia {{var0}}", + "server": "Server", + "settings_shareData_description": "Sincronizza le configurazioni dei plug-in tra gli account Discord", + "settings_showSupportBadges_description": "Mostra piccoli badge per gli utenti che supportano il mio Patreon", + "settings_showToasts_description": "Mostra l'avvio e l'arresto del plugin", + "settings_showToasts_note": "Disabilita l'impostazione generale '{{var0}}' dei BD prima di disabilitarli", + "settings_toastPosition_description": "Posizione predefinita del toast", + "settings_toastPosition_note": "Cambia solo la posizione dei toast creati dai miei plugins", + "settings_useChromium_description": "Apri link in Discord invece che nel tuo browser", + "sort_by": "Ordina per", + "status": "Stato", + "time": "Tempo", + "timezone": "Fuso orario", + "to": "Per", + "toast_plugin_force_updated": "{{var0}} è stato aggiornato automaticamente perché la tua versione era molto obsoleta", + "toast_plugin_loaded": "{{var0}} è stato caricato", + "toast_plugin_started": "{{var0}} è iniziato", + "toast_plugin_stopped": "{{var0}} si è fermato", + "toast_plugin_translated": "tradotto in {{var0}}", + "toast_plugin_unloaded": "{{var0}} è stato scaricato", + "toast_plugin_update_failed": "Impossibile scaricare l'aggiornamento per {{var0}}", + "toast_plugin_updated": "{{var0}} {{var1}} è stato sostituito da {{var2}} {{var3}}", + "update_check_complete": "Controllo dell'aggiornamento del plugin completato", + "update_check_complete_outdated": "Controllo dell'aggiornamento del plugin completato - {{var0}} non aggiornato!", + "update_check_info": "Controlla i plugins che supportano il controllo degli aggiornamenti", + "update_notice_click": "Fare clic per aggiornare!", + "update_notice_reload": "Ricarica per completare l'aggiornamento", + "update_notice_update": "I seguenti plugins devono essere aggiornati: ", + "updated": "Aggiornato" + }, + "ja": { + "add_to": "{{var0}} に追加", + "ascending": "上昇", + "center": "中央揃え", + "changelog_added": "新機能", + "changelog_fixed": "トラブルシューティング", + "changelog_improved": "改善点", + "changelog_progress": "進捗", + "check_for_updates": "アップデートを確認する", + "clipboard_success": "{{var0}}をクリップボードにコピーしました", + "confirm": "本気ですか?", + "copy": "{{var0}}をコピーします", + "delete_fail": "{{var0}} は削除できません", + "delete_success": "{{var0}} が正常に削除されました", + "descending": "降順", + "developer": "開発者", + "donate_message": "より多くのアップデートのために私をサポートしてください!", + "download": "ダウンロード", + "download_fail": "{{var0}} はダウンロードできません", + "download_success": "{{var0}} が正常にダウンロードされました", + "file_navigator_text": "ファイルを参照", + "first": "最初", + "from": "から", + "gradient": "勾配", + "guildbanner": "バナー", + "guildicon": "アイコン", + "installed": "インストール済み", + "last": "最終", + "left": "左", + "loading": "を読み込んでいます {{var0}}", + "location": "ロケーション", + "order": "シーケンス", + "outdated": "古いバージョン", + "please_wait": "お待ちください", + "right": "正しい", + "save_fail": "{{var0}} は保存できません", + "save_success": "{{var0}} は正常に保存されました", + "send": "{{var0}}を送信します", + "server": "サーバ", + "settings_shareData_description": "Discordアカウント間でプラグイン構成を同期します", + "settings_showSupportBadges_description": "私のパトレオンをサポートするユーザーに小さなバッジを表示します", + "settings_showToasts_description": "プラグインの開始と停止のトーストを表示します", + "settings_showToasts_note": "BD を無効にする前に、BD の一般設定 '{{var0}}' を無効にしてください", + "settings_toastPosition_description": "デフォルトのトースト位置", + "settings_toastPosition_note": "プラグインによって作成されたトーストの位置のみを変更します", + "settings_useChromium_description": "ブラウザの代わりに Discord でリンクを開く", + "sort_by": "並び替え", + "status": "状態", + "time": "時間", + "timezone": "タイムゾーン", + "to": "に", + "toast_plugin_force_updated": "バージョンが非常に古くなったため、 {{var0}} は自動的に更新されました", + "toast_plugin_loaded": "{{var0}} が読み込まれました", + "toast_plugin_started": "{{var0}} が開始されました", + "toast_plugin_stopped": "{{var0}} が停止しました", + "toast_plugin_translated": "{{var0}} に変換", + "toast_plugin_unloaded": "{{var0}} がアンロードされました", + "toast_plugin_update_failed": "{{var0}} の更新をダウンロードできません", + "toast_plugin_updated": "{{var0}} {{var1}} は {{var2}} {{var3}} に置き換えられました", + "update_check_complete": "プラグインの更新チェックが完了しました", + "update_check_complete_outdated": "プラグインの更新チェックが完了しました- {{var0}} が古くなっています!", + "update_check_info": "アップデートチェックをサポートするプラグインをチェックします", + "update_notice_click": "クリックして更新してください!", + "update_notice_reload": "リロードして更新を完了します", + "update_notice_update": "次のプラグインを更新する必要があります。", + "updated": "更新しました" + }, + "ko": { + "add_to": "{{var0}}에 추가", + "ascending": "오름차순", + "center": "중앙", + "changelog_added": "새로운 기능", + "changelog_fixed": "문제 해결", + "changelog_improved": "개선됨", + "changelog_progress": "진행중", + "check_for_updates": "업데이트 확인", + "clipboard_success": "{{var0}}을(를) 클립보드에 복사했습니다.", + "confirm": "확실한가요?", + "copy": "{{var0}} 복사", + "delete_fail": "{{var0}}을(를) 삭제할 수 없습니다.", + "delete_success": "{{var0}}이(가) 성공적으로 삭제되었습니다.", + "descending": "내림차순", + "developer": "개발자", + "donate_message": "더 많은 업데이트를 위해 저를 후원해주세요!", + "download": "다운로드", + "download_fail": "{{var0}}을(를) 다운로드 할 수 없습니다.", + "download_success": "{{var0}}을(를) 다운로드 완료했습니다", + "file_navigator_text": "파일 찾아보기", + "first": "먼저", + "from": "에서", + "gradient": "그라데이션", + "guildbanner": "배너", + "guildicon": "상", + "installed": "설치됨", + "last": "마지막", + "left": "좌측", + "loading": "로드 중 {{var0}}", + "location": "위치", + "order": "순서", + "outdated": "구버전", + "please_wait": "잠시만 기다려주세요", + "right": "우측", + "save_fail": "{{var0}}을(를) 저장할 수 없습니다.", + "save_success": "{{var0}}이(가) 성공적으로 저장되었습니다.", + "send": "{{var0}} 보내기", + "server": "서버", + "settings_shareData_description": "Discord 계정 간에 플러그인 구성을 동기화합니다.", + "settings_showSupportBadges_description": "개발자의 Patreon으로 후원해주는 사용자에게 작은 배지를 표시합니다.", + "settings_showToasts_description": "플러그인 시작 및 중지 알림 표시", + "settings_showToasts_note": "BD를 비활성화하기 전에 BD를 일반 설정 '{{var0}}'을(를) 비활성화하세요.", + "settings_toastPosition_description": "기본 토스트창(Toast) 위치", + "settings_toastPosition_note": "위 옵션은 내 플러그인에 의해 생성된 토스트창에만 해당됩니다.", + "settings_useChromium_description": "브라우저 대신 Discord 에서 링크 열기", + "sort_by": "정렬 기준", + "status": "상태", + "time": "시각", + "timezone": "시간대", + "to": "에", + "toast_plugin_force_updated": "버전이 매우 오래되어 {{var0}} 이 자동으로 업데이트되었습니다.", + "toast_plugin_loaded": "{{var0}}이(가) 로드되었습니다.", + "toast_plugin_started": "{{var0}}이(가) 시작되었습니다.", + "toast_plugin_stopped": "{{var0}}이(가) 중지되었습니다.", + "toast_plugin_translated": "{{var0}} 로 번역됨", + "toast_plugin_unloaded": "{{var0}}이(가) 언로드되었습니다.", + "toast_plugin_update_failed": "{{var0}} 에 대한 업데이트를 다운로드 할 수 없습니다.", + "toast_plugin_updated": "{{var0}} {{var1}}이(가) {{var2}} {{var3}}으(로) 교체되었습니다.", + "update_check_complete": "플러그인 업데이트 확인 완료", + "update_check_complete_outdated": "플러그인 업데이트 확인 완료 - {{var0}}이(가) 구버전입니다!", + "update_check_info": "업데이트 기능을 지원하는 모든 플러그인 업데이트", + "update_notice_click": "업데이트하려면 클릭하세요!", + "update_notice_reload": "업데이트를 완료하려면 새로고침하세요.", + "update_notice_update": "다음 플러그인을 업데이트해야합니다: ", + "updated": "업데이트됨" + }, + "lt": { + "add_to": "Pridėti prie {{var0}}", + "ascending": "Kylanti", + "center": "Centruotas", + "changelog_added": "Naujos savybės", + "changelog_fixed": "Problemų sprendimas", + "changelog_improved": "Patobulinimai", + "changelog_progress": "Progresas", + "check_for_updates": "Tikrinti, ar yra atnaujinimų", + "clipboard_success": "{{var0}} nukopijuotas į mainų sritį", + "confirm": "Ar tu tuo tikras?", + "copy": "Kopijuoti {{var0}}", + "delete_fail": "{{var0}} negalima ištrinti", + "delete_success": "{{var0}} sėkmingai ištrinta", + "descending": "Mažėjantis", + "developer": "Programuotojas", + "donate_message": "Palaikykite mane, kad gautumėte daugiau naujinių!", + "download": "Parsisiųsti", + "download_fail": "{{var0}} negalima atsisiųsti", + "download_success": "{{var0}} sėkmingai atsisiųsta", + "file_navigator_text": "Naršyti failą", + "first": "Pirmas", + "from": "Nuo", + "gradient": "Gradientas", + "guildbanner": "Reklamjuostė", + "guildicon": "Piktograma", + "installed": "Įdiegta", + "last": "Paskutinis", + "left": "Kairėje", + "loading": "Įkeliama {{var0}}", + "location": "Vieta", + "order": "Seka", + "outdated": "Pasenęs", + "please_wait": "Maloniai palauk", + "right": "Teisingai", + "save_fail": "{{var0}} negalima išsaugoti", + "save_success": "{{var0}} išsaugota sėkmingai", + "send": "Siųsti {{var0}}", + "server": "Serverio", + "settings_shareData_description": "Sinchronizuoja įskiepio konfigūracijas tarp „Discord“ paskyrų", + "settings_showSupportBadges_description": "Rodo mažus ženklelius vartotojams, palaikantiems mano Patreon", + "settings_showToasts_description": "Parodo įskiepių paleidimo ir sustabdymo tostus", + "settings_showToasts_note": "Prieš išjungdami, išjunkite bendrą BD nustatymą '{{var0}}'", + "settings_toastPosition_description": "Numatytoji skrudintos duonos padėtis", + "settings_toastPosition_note": "Keičia tik mano įskiepiai sukurtų tostų poziciją", + "settings_useChromium_description": "Vietoj savo naršyklės atidarykite nuorodas nesantaikoje", + "sort_by": "Rūšiuoti pagal", + "status": "Būsena", + "time": "Laikas", + "timezone": "Laiko zona", + "to": "Į", + "toast_plugin_force_updated": "'{{var0}}' buvo automatiškai atnaujinta, nes jūsų versija buvo labai pasenusi", + "toast_plugin_loaded": "{{var0}} buvo įkelta", + "toast_plugin_started": "{{var0}} prasidėjo", + "toast_plugin_stopped": "{{var0}} sustabdyta", + "toast_plugin_translated": "išversta į {{var0}}", + "toast_plugin_unloaded": "{{var0}} buvo iškrautas", + "toast_plugin_update_failed": "Negalima atsisiųsti {{var0}} naujinio", + "toast_plugin_updated": "{{var0}} {{var1}} pakeista į {{var2}} {{var3}}", + "update_check_complete": "Įskiepių atnaujinimo patikrinimas baigtas", + "update_check_complete_outdated": "Įskiepių atnaujinimo patikrinimas baigtas - {{var0}} pasenęs!", + "update_check_info": "Patikrinkite įskiepiai, kurie palaiko naujinimo patikrą", + "update_notice_click": "Spustelėkite norėdami atnaujinti!", + "update_notice_reload": "Įkelkite iš naujo, kad užbaigtumėte atnaujinimą", + "update_notice_update": "Reikia atnaujinti šiuos įskiepiai: ", + "updated": "Atnaujinta" + }, + "nl": { + "add_to": "Toevoegen aan {{var0}}", + "ascending": "Oplopend", + "center": "Gecentreerd", + "changelog_added": "Nieuwe features", + "changelog_fixed": "Probleemoplossen", + "changelog_improved": "Verbeteringen", + "changelog_progress": "Vooruitgang", + "check_for_updates": "Controleer op updates", + "clipboard_success": "{{var0}} gekopieerd naar klembord", + "confirm": "Weet je zeker dat?", + "copy": "Kopieer {{var0}}", + "delete_fail": "{{var0}} kan niet worden verwijderd", + "delete_success": "{{var0}} is verwijderd", + "descending": "Aflopend", + "developer": "Ontwikkelaar", + "donate_message": "Steun mij voor meer updates!", + "download": "Downloaden", + "download_fail": "{{var0}} kan niet worden gedownload", + "download_success": "{{var0}} succesvol gedownload", + "file_navigator_text": "Bestand zoeken", + "first": "Eerste", + "from": "Van", + "gradient": "Verloop", + "guildbanner": "Banner", + "guildicon": "Icoon", + "installed": "Geïnstalleerd", + "last": "Laatste", + "left": "Links", + "loading": "Laden {{var0}}", + "location": "Plaats", + "order": "Volgorde", + "outdated": "Verouderd", + "please_wait": "Wacht even", + "right": "Rechtsaf", + "save_fail": "{{var0}} kan niet worden opgeslagen", + "save_success": "{{var0}} succesvol opgeslagen", + "send": "Stuur {{var0}}", + "server": "Server", + "settings_shareData_description": "Synchroniseert de plug-inconfiguraties tussen Discord-accounts", + "settings_showSupportBadges_description": "Toont kleine badges voor gebruikers die mijn Patreon ondersteunen", + "settings_showToasts_description": "Toont plugin start en stop toasts", + "settings_showToasts_note": "Schakel de algemene instelling '{{var0}}' van BD's uit voordat u ze uitschakelt", + "settings_toastPosition_description": "Standaard toastpositie", + "settings_toastPosition_note": "Verandert alleen de positie van toast gemaakt door mijn plugins", + "settings_useChromium_description": "Open links in Discord in plaats van uw browser", + "sort_by": "Sorteer op", + "status": "Toestand", + "time": "Tijd", + "timezone": "Tijdzone", + "to": "Naar", + "toast_plugin_force_updated": "{{var0}} is automatisch bijgewerkt omdat uw versie erg verouderd was", + "toast_plugin_loaded": "{{var0}} is geladen", + "toast_plugin_started": "{{var0}} is gestart", + "toast_plugin_stopped": "{{var0}} is gestopt", + "toast_plugin_translated": "vertaald naar {{var0}}", + "toast_plugin_unloaded": "{{var0}} is verwijderd", + "toast_plugin_update_failed": "Update voor {{var0}} kan niet worden gedownload", + "toast_plugin_updated": "{{var0}} {{var1}} is vervangen door {{var2}} {{var3}}", + "update_check_complete": "Controle op update van plugin voltooid", + "update_check_complete_outdated": "Controle van update van plugin voltooid - {{var0}} verouderd!", + "update_check_info": "Controleer plugins die de updatecontrole ondersteunen", + "update_notice_click": "Klik om te updaten!", + "update_notice_reload": "Laad opnieuw om de update te voltooien", + "update_notice_update": "De volgende plugins moeten worden bijgewerkt: ", + "updated": "Bijgewerkt" + }, + "no": { + "add_to": "Legg til i {{var0}}", + "ascending": "Stigende", + "center": "Sentrert", + "changelog_added": "Nye funksjoner", + "changelog_fixed": "Feilsøking", + "changelog_improved": "Forbedringer", + "changelog_progress": "Framgang", + "check_for_updates": "Se etter oppdateringer", + "clipboard_success": "Kopierte {{var0}} til utklippstavlen", + "confirm": "Er du sikker?", + "copy": "Kopier {{var0}}", + "delete_fail": "{{var0}} kan ikke slettes", + "delete_success": "{{var0}} ble slettet", + "descending": "Fallende", + "developer": "Utvikler", + "donate_message": "Støtt meg for flere oppdateringer!", + "download": "Nedlasting", + "download_fail": "{{var0}} kan ikke lastes ned", + "download_success": "{{var0}} lastet ned", + "file_navigator_text": "Bla gjennom filen", + "first": "Først", + "from": "Fra", + "gradient": "Gradient", + "guildbanner": "Banner", + "guildicon": "Ikon", + "installed": "Installert", + "last": "Siste", + "left": "Venstre", + "loading": "Laster inn {{var0}}", + "location": "Plassering", + "order": "Sekvens", + "outdated": "Utdatert", + "please_wait": "Vennligst vent", + "right": "Ikke sant", + "save_fail": "{{var0}} kan ikke lagres", + "save_success": "{{var0}} lagret", + "send": "Send {{var0}}", + "server": "Server", + "settings_shareData_description": "Synkroniserer plugin-konfigurasjonene mellom Discord-kontoer", + "settings_showSupportBadges_description": "Viser små merker for brukere som støtter min Patreon", + "settings_showToasts_description": "Viser plugin start og stopp toasts", + "settings_showToasts_note": "Deaktiver den generelle innstillingen '{{var0}}' for BD-er før du deaktiverer dem", + "settings_toastPosition_description": "Standard toastposisjon", + "settings_toastPosition_note": "Endrer bare posisjonen for ristet brød opprettet av plugins mine", + "settings_useChromium_description": "Åpne koblinger i Discord i stedet for nettleseren din", + "sort_by": "Sorter etter", + "status": "Status", + "time": "Tid", + "timezone": "Tidssone", + "to": "Til", + "toast_plugin_force_updated": "{{var0}} ble automatisk oppdatert fordi versjonen din var veldig utdatert", + "toast_plugin_loaded": "{{var0}} er lastet inn", + "toast_plugin_started": "{{var0}} har startet", + "toast_plugin_stopped": "{{var0}} har stoppet", + "toast_plugin_translated": "oversatt til {{var0}}", + "toast_plugin_unloaded": "{{var0}} er lastet ut", + "toast_plugin_update_failed": "Oppdatering for {{var0}} kan ikke lastes ned", + "toast_plugin_updated": "{{var0}} {{var1}} er erstattet av {{var2}} {{var3}}", + "update_check_complete": "Sjekk plugin-oppdatering fullført", + "update_check_complete_outdated": "Sjekk plugin-oppdatering fullført - {{var0}} utdatert!", + "update_check_info": "Sjekk plugins som støtter oppdateringskontrollen", + "update_notice_click": "Klikk for å oppdatere!", + "update_notice_reload": "Last inn for å fullføre oppdateringen", + "update_notice_update": "Følgende plugins må oppdateres: ", + "updated": "Oppdatert" + }, + "pl": { + "add_to": "Dodaj do {{var0}}", + "ascending": "Rosnąco", + "center": "Środek", + "changelog_added": "Dodano", + "changelog_fixed": "Naprawiono", + "changelog_improved": "Ulepszono", + "changelog_progress": "Postęp", + "check_for_updates": "Sprawdź aktualizacje", + "clipboard_success": "Skopiowano {{var0}} do schowka", + "confirm": "Na pewno?", + "copy": "Kopiuj {{var0}}", + "delete_fail": "Nie można usunąć {{var0}}", + "delete_success": "Pomyślnie usunięto {{var0}}", + "descending": "Malejąco", + "developer": "Deweloper", + "donate_message": "Wesprzyj mnie, aby uzyskać więcej aktualizacji!", + "download": "Pobieranie", + "download_fail": "Nie można pobrać {{var0}}", + "download_success": "Pomyślnie pobrano {{var0}}", + "file_navigator_text": "Przeglądaj plik", + "first": "Pierwszy", + "from": "Od", + "gradient": "Gradient", + "guildbanner": "Transparent", + "guildicon": "Ikona", + "installed": "Zainstalowany", + "last": "Ostatni", + "left": "Lewo", + "loading": "Ładowanie {{var0}}", + "location": "Lokalizacja", + "order": "Kolejność", + "outdated": "Przestarzały", + "please_wait": "Proszę czekać", + "right": "Prawo", + "save_fail": "Nie można zapisać {{var0}}", + "save_success": "Pomyślnie zapisano {{var0}}", + "send": "Wyślij {{var0}}", + "server": "Serwer", + "settings_shareData_description": "Synchronizuje konfiguracje wtyczek między kontami Discord", + "settings_showSupportBadges_description": "Pokazuje małe odznaki dla wspierających mojego Patreona", + "settings_showToasts_description": "Pokazuje toasty uruchamiające i zatrzymujące wtyczki", + "settings_showToasts_note": "Wyłącz ogólne ustawienie '{{var0}} ” dysków BD przed ich wyłączeniem", + "settings_toastPosition_description": "Domyślna pozycja toastów", + "settings_toastPosition_note": "Zmienia tylko pozycję toastów utworzonych przez moje wtyczki", + "settings_useChromium_description": "Otwieraj linki w Discordzie zamiast w przeglądarce", + "sort_by": "Sortuj według", + "status": "Status", + "time": "Czas", + "timezone": "Strefa czasowa", + "to": "Do", + "toast_plugin_force_updated": "{{var0}} został automatycznie zaktualizowany, ponieważ Twoja wersja była bardzo nieaktualna", + "toast_plugin_loaded": "Załadowano {{var0}}", + "toast_plugin_started": "Rozpoczęto {{var0}}", + "toast_plugin_stopped": "{{var0}} został zatrzymany", + "toast_plugin_translated": "przetłumaczone na {{var0}}", + "toast_plugin_unloaded": "Usunięto {{var0}}", + "toast_plugin_update_failed": "Nie można pobrać aktualizacji dla {{var0}}", + "toast_plugin_updated": "{{var0}} {{var1}} został zastąpiony przez {{var2}} {{var3}}", + "update_check_complete": "Sprawdzanie aktualizacji wtyczki zakończone", + "update_check_complete_outdated": "Sprawdzanie aktualizacji wtyczki zakończone - {{var0}} nieaktualne!", + "update_check_info": "Sprawdź wtyczki obsługujące sprawdzanie aktualizacji", + "update_notice_click": "Kliknij, aby zaktualizować!", + "update_notice_reload": "Załaduj ponownie, aby zakończyć aktualizację", + "update_notice_update": "Należy zaktualizować następujące wtyczki: ", + "updated": "Zaktualizowano" + }, + "pt-BR": { + "add_to": "Adicionar a {{var0}}", + "ascending": "Ascendente", + "center": "Centrado", + "changelog_added": "Novas características", + "changelog_fixed": "Solução de problemas", + "changelog_improved": "Melhorias", + "changelog_progress": "Progresso", + "check_for_updates": "Verifique se há atualizações", + "clipboard_success": "Copiado {{var0}} para a área de transferência", + "confirm": "Você tem certeza?", + "copy": "Copiar {{var0}}", + "delete_fail": "{{var0}} não pode ser excluído", + "delete_success": "{{var0}} excluído com sucesso", + "descending": "Descendente", + "developer": "Desenvolvedor", + "donate_message": "Apoie-me para mais atualizações!", + "download": "Baixar", + "download_fail": "{{var0}} não pode ser baixado", + "download_success": "{{var0}} baixado com sucesso", + "file_navigator_text": "Procurar arquivo", + "first": "Primeiro", + "from": "De", + "gradient": "Gradiente", + "guildbanner": "Bandeira", + "guildicon": "Ícone", + "installed": "Instalado", + "last": "Último", + "left": "Esquerda", + "loading": "Carregando {{var0}}", + "location": "Localização", + "order": "Seqüência", + "outdated": "Desatualizado", + "please_wait": "Por favor espere", + "right": "Direito", + "save_fail": "{{var0}} não pode ser salvo", + "save_success": "{{var0}} salvo com sucesso", + "send": "Enviar {{var0}}", + "server": "Servidor", + "settings_shareData_description": "Sincroniza as configurações de plug-in entre contas do Discord", + "settings_showSupportBadges_description": "Mostra pequenos emblemas para usuários que apóiam meu Patreon", + "settings_showToasts_description": "Mostra o início e o fim do plugin do brinde", + "settings_showToasts_note": "Desative a configuração geral '{{var0}}' de BDs antes de desativá-los", + "settings_toastPosition_description": "Posição padrão do brinde", + "settings_toastPosition_note": "Apenas altera a posição dos brindes criados pelos meus plugins", + "settings_useChromium_description": "Abra links no Discord em vez do seu navegador", + "sort_by": "Ordenar por", + "status": "Status", + "time": "Tempo", + "timezone": "Fuso horário", + "to": "Para", + "toast_plugin_force_updated": "{{var0}} foi atualizado automaticamente porque sua versão estava muito desatualizada", + "toast_plugin_loaded": "{{var0}} foi carregado", + "toast_plugin_started": "{{var0}} começou", + "toast_plugin_stopped": "{{var0}} parou", + "toast_plugin_translated": "traduzido para {{var0}}", + "toast_plugin_unloaded": "{{var0}} foi descarregado", + "toast_plugin_update_failed": "A atualização para {{var0}} não pode ser baixada", + "toast_plugin_updated": "{{var0}} {{var1}} foi substituído por {{var2}} {{var3}}", + "update_check_complete": "Verificação de atualização do plugin concluída", + "update_check_complete_outdated": "Verificação de atualização do plugin concluída - {{var0}} desatualizado!", + "update_check_info": "Verifique os plugins que suportam a verificação de atualização", + "update_notice_click": "Clique para atualizar!", + "update_notice_reload": "Recarregue para completar a atualização", + "update_notice_update": "Os seguintes plugins precisam ser atualizados: ", + "updated": "Atualizada" + }, + "ro": { + "add_to": "Adăugați la {{var0}}", + "ascending": "Ascendent", + "center": "Centrat", + "changelog_added": "Functii noi", + "changelog_fixed": "Depanare", + "changelog_improved": "Îmbunătățiri", + "changelog_progress": "Progres", + "check_for_updates": "Verifică pentru actualizări", + "clipboard_success": "{{var0}} a fost copiat în Clipboard", + "confirm": "Esti sigur?", + "copy": "Copiați {{var0}}", + "delete_fail": "{{var0}} nu poate fi șters", + "delete_success": "{{var0}} șters cu succes", + "descending": "Descendentă", + "developer": "Dezvoltator", + "donate_message": "Sprijină-mă pentru mai multe actualizări!", + "download": "Descarca", + "download_fail": "{{var0}} nu poate fi descărcat", + "download_success": "{{var0}} descărcat cu succes", + "file_navigator_text": "Răsfoiți fișierul", + "first": "Primul", + "from": "Din", + "gradient": "Gradient", + "guildbanner": "Banner", + "guildicon": "Pictogramă", + "installed": "Instalat", + "last": "Ultimul", + "left": "Stânga", + "loading": "Se încarcă {{var0}}", + "location": "Locație", + "order": "Secvenţă", + "outdated": "Învechit", + "please_wait": "Așteptați plăcut", + "right": "Dreapta", + "save_fail": "{{var0}} nu poate fi salvat", + "save_success": "{{var0}} salvat cu succes", + "send": "Trimite {{var0}}", + "server": "Server", + "settings_shareData_description": "Sincronizează configurațiile pluginurilor între conturile Discord", + "settings_showSupportBadges_description": "Afișează insigne mici pentru utilizatorii care acceptă Patreon", + "settings_showToasts_description": "Afișează pornirea și oprirea toastelor pluginului", + "settings_showToasts_note": "Dezactivați setarea generală '{{var0}} ” a BD-urilor înainte de a le dezactiva", + "settings_toastPosition_description": "Poziție implicită Toast", + "settings_toastPosition_note": "Modifică doar poziția toastelor create de pluginuri mele", + "settings_useChromium_description": "Deschideți linkuri în discordie în loc de browser", + "sort_by": "Filtrează după", + "status": "Stare", + "time": "Timp", + "timezone": "Fus orar", + "to": "La", + "toast_plugin_force_updated": "{{var0}} a fost actualizat automat deoarece versiunea dvs. a fost foarte depășită", + "toast_plugin_loaded": "{{var0}} a fost încărcat", + "toast_plugin_started": "{{var0}} a început", + "toast_plugin_stopped": "{{var0}} s-a oprit", + "toast_plugin_translated": "tradus în {{var0}}", + "toast_plugin_unloaded": "{{var0}} a fost descărcat", + "toast_plugin_update_failed": "Actualizarea pentru {{var0}} nu poate fi descărcată", + "toast_plugin_updated": "{{var0}} {{var1}} a fost înlocuit cu {{var2}} {{var3}}", + "update_check_complete": "Verificarea actualizării pluginului s-a finalizat", + "update_check_complete_outdated": "Verificarea actualizării pluginului s-a finalizat - {{var0}} nu este actualizată!", + "update_check_info": "Verificați pluginuri care acceptă verificarea actualizării", + "update_notice_click": "Faceți clic pentru a actualiza!", + "update_notice_reload": "Reîncărcați pentru a finaliza actualizarea", + "update_notice_update": "Următoarele pluginuri trebuie actualizate: ", + "updated": "La curent" + }, + "ru": { + "add_to": "Добавить в {{var0}}", + "ascending": "Возрастанию", + "center": "По центру", + "changelog_added": "Новые возможности", + "changelog_fixed": "Исправления ошибок", + "changelog_improved": "Улучшения", + "changelog_progress": "Прогресс", + "check_for_updates": "Проверить наличие обновлений", + "clipboard_success": "Скопировано {{var0}} в буфер обмена", + "confirm": "Подтвердить?", + "copy": "Копировать {{var0}}", + "delete_fail": "Не удалось удалить: {{var0}}", + "delete_success": "Успешно удалено: {{var0}}", + "descending": "Убыванию", + "developer": "Разработчик", + "donate_message": "Поддержите меня, чтобы получать дальнейшие обновления!", + "download": "Скачать", + "download_fail": "Не удалось скачать: {{var0}}", + "download_success": "Успешно скачено: {{var0}}", + "file_navigator_text": "Посмотреть файл", + "first": "Первый", + "from": "Из", + "gradient": "Градиент", + "guildbanner": "Баннер", + "guildicon": "Икона", + "installed": "Установлено", + "last": "Последний", + "left": "Слева", + "loading": "Загрузка {{var0}}", + "location": "Расположение", + "order": "Порядок", + "outdated": "Устаревшее", + "please_wait": "Подождите", + "right": "Справа", + "save_fail": "Не удалось сохранить: {{var0}}", + "save_success": "Успешно сохранено: {{var0}}", + "send": "Отправить {{var0}}", + "server": "Сервер", + "settings_shareData_description": "Синхронизирует конфигурации плагинов между учетными записями Discord.", + "settings_showSupportBadges_description": "Показывать маленькие значки у пользователей, которые поддерживают мой Patreon", + "settings_showToasts_description": "Показывать всплывающие уведомления запуска и остановки плагинов", + "settings_showToasts_note": "Отключите общий параметр BD '{{var0}}' перед отключением этого параметра", + "settings_toastPosition_description": "Местоположение всплывающего уведомления по умолчанию", + "settings_toastPosition_note": "Изменяет только положение всплывающих уведомлений, созданных моими плагинами", + "settings_useChromium_description": "Открывайте ссылки через Discord вместо браузера", + "sort_by": "Сортировать по", + "status": "Состояние", + "time": "Время", + "timezone": "Часовой пояс", + "to": "В", + "toast_plugin_force_updated": "Было произведено автообновление {{var0}}, так как ваша версия сильно устарела", + "toast_plugin_loaded": "{{var0}} загружен", + "toast_plugin_started": "{{var0}} запущен", + "toast_plugin_stopped": "{{var0}} остановлен", + "toast_plugin_translated": "переведён на {{var0}}", + "toast_plugin_unloaded": "{{var0}} выгружен", + "toast_plugin_update_failed": "Обновление для {{var0}} не может быть загружено", + "toast_plugin_updated": "{{var0}} {{var1}} заменён на {{var2}} {{var3}}", + "update_check_complete": "Проверка плагинов на обновления завершена", + "update_check_complete_outdated": "Проверка плагинов на обновления завершена - {{var0}} устарел!", + "update_check_info": "Проверьте поддерживаемые плагины на обновления", + "update_notice_click": "Нажмите, чтобы обновить!", + "update_notice_reload": "Перезагрузите, чтобы завершить обновление", + "update_notice_update": "Необходимо обновить следующие плагины: ", + "updated": "Обновлено" + }, + "sv": { + "add_to": "Lägg till i {{var0}}", + "ascending": "Stigande", + "center": "Centrerad", + "changelog_added": "Nya egenskaper", + "changelog_fixed": "Felsökning", + "changelog_improved": "Förbättringar", + "changelog_progress": "Framsteg", + "check_for_updates": "Sök efter uppdateringar", + "clipboard_success": "Kopierade {{var0}} till Urklipp", + "confirm": "Är du säker?", + "copy": "Kopiera {{var0}}", + "delete_fail": "{{var0}} kan inte raderas", + "delete_success": "{{var0}} har tagits bort", + "descending": "Nedåtgående", + "developer": "Utvecklaren", + "donate_message": "Stöd mig för fler uppdateringar!", + "download": "Ladda ner", + "download_fail": "{{var0}} kan inte laddas ner", + "download_success": "{{var0}} laddades ner", + "file_navigator_text": "Bläddra i filen", + "first": "Först", + "from": "Från", + "gradient": "Lutning", + "guildbanner": "Baner", + "guildicon": "Ikon", + "installed": "Installerat", + "last": "Sista", + "left": "Vänster", + "loading": "Laddar {{var0}}", + "location": "Plats", + "order": "Sekvens", + "outdated": "Föråldrad", + "please_wait": "Vänligen vänta", + "right": "Höger", + "save_fail": "{{var0}} kan inte sparas", + "save_success": "{{var0}} har sparats", + "send": "Skicka {{var0}}", + "server": "Server", + "settings_shareData_description": "Synkroniserar plugin-konfigurationerna mellan Discord-konton", + "settings_showSupportBadges_description": "Visar små märken för användare som stöder min Patreon", + "settings_showToasts_description": "Visar plugin start och stopp toasts", + "settings_showToasts_note": "Inaktivera den allmänna inställningen '{{var0}}' för BD-skivor innan du inaktiverar dem", + "settings_toastPosition_description": "Standard toastposition", + "settings_toastPosition_note": "Ändrar bara positionen för rostat bröd som skapats av mina plugins", + "settings_useChromium_description": "Öppna Länkar i Discord istället för din webbläsare", + "sort_by": "Sortera efter", + "status": "Status", + "time": "Tid", + "timezone": "Tidszon", + "to": "Till", + "toast_plugin_force_updated": "{{var0}} uppdaterades automatiskt eftersom din version var mycket föråldrad", + "toast_plugin_loaded": "{{var0}} har laddats", + "toast_plugin_started": "{{var0}} har startat", + "toast_plugin_stopped": "{{var0}} har slutat", + "toast_plugin_translated": "översatt till {{var0}}", + "toast_plugin_unloaded": "{{var0}} har lossats", + "toast_plugin_update_failed": "Uppdatering för {{var0}} kan inte laddas ner", + "toast_plugin_updated": "{{var0}} {{var1}} har ersatts med {{var2}} {{var3}}", + "update_check_complete": "Kontrollen av plugin-uppdateringen slutförd", + "update_check_complete_outdated": "Kontrollen av plugin-uppdateringen slutförd - {{var0}} inaktuell!", + "update_check_info": "Kontrollera plugins som stöder uppdateringskontrollen", + "update_notice_click": "Klicka för att uppdatera!", + "update_notice_reload": "Ladda om för att slutföra uppdateringen", + "update_notice_update": "Följande plugins måste uppdateras: ", + "updated": "Uppdaterad" + }, + "th": { + "add_to": "เพิ่มใน{{var0}}", + "ascending": "จากน้อยไปมาก", + "center": "อยู่กึ่งกลาง", + "changelog_added": "คุณสมบัติใหม่", + "changelog_fixed": "การแก้ไขปัญหา", + "changelog_improved": "การปรับปรุง", + "changelog_progress": "ความคืบหน้า", + "check_for_updates": "ตรวจสอบสำหรับการอัพเดต", + "clipboard_success": "คัดลอก {{var0}} ไปยังคลิปบอร์ดแล้ว", + "confirm": "คุณแน่ใจไหม?", + "copy": "คัดลอก {{var0}}", + "delete_fail": "ไม่สามารถลบ{{var0}}ได้", + "delete_success": "ลบ{{var0}}เรียบร้อยแล้ว", + "descending": "จากมากไปน้อย", + "developer": "ผู้พัฒนา", + "donate_message": "สนับสนุนฉันสำหรับการอัปเดตเพิ่มเติม!", + "download": "ดาวน์โหลด", + "download_fail": "ไม่สามารถดาวน์โหลด{{var0}}", + "download_success": "ดาวน์โหลด{{var0}}สำเร็จ", + "file_navigator_text": "เรียกดูไฟล์", + "first": "อันดับแรก", + "from": "จาก", + "gradient": "ไล่ระดับสี", + "guildbanner": "แบนเนอร์", + "guildicon": "ไอคอน", + "installed": "ติดตั้งแล้ว", + "last": "ล่าสุด", + "left": "ซ้าย", + "loading": "กำลังโหลด{{var0}}", + "location": "สถานที่", + "order": "ลำดับ", + "outdated": "เก่า", + "please_wait": "โปรดรอ", + "right": "ขวา", + "save_fail": "ไม่สามารถบันทึก{{var0}}ได้", + "save_success": "บันทึก{{var0}}เรียบร้อยแล้ว", + "send": "ส่ง {{var0}}", + "server": "เซิร์ฟเวอร์", + "settings_shareData_description": "ประสานการกำหนดค่าปลั๊กอินระหว่างบัญชีที่ไม่ลงรอยกัน", + "settings_showSupportBadges_description": "แสดงป้ายขนาดเล็กสำหรับผู้ใช้ที่สนับสนุน Patreon ของฉัน", + "settings_showToasts_description": "แสดงปลั๊กอินเริ่มและหยุดขนมปังปิ้ง", + "settings_showToasts_note": "ปิดการใช้งานการตั้งค่าทั่วไป '{{var0}}' ของ BD ก่อนปิดใช้งาน", + "settings_toastPosition_description": "ตำแหน่งขนมปังเริ่มต้น", + "settings_toastPosition_note": "เปลี่ยนเฉพาะตำแหน่งของขนมปังที่สร้างโดยปลั๊กอินของฉัน", + "settings_useChromium_description": "เปิดลิงค์ใน Discord แทนเบราว์เซอร์ของคุณ", + "sort_by": "จัดเรียงตาม", + "status": "สถานะ", + "time": "เวลา", + "timezone": "เขตเวลา", + "to": "ถึง", + "toast_plugin_force_updated": "{{var0}} ได้รับการอัปเดตโดยอัตโนมัติเนื่องจากเวอร์ชันของคุณล้าสมัยมาก", + "toast_plugin_loaded": "โหลด {{var0}} แล้ว", + "toast_plugin_started": "{{var0}} เริ่มแล้ว", + "toast_plugin_stopped": "{{var0}} หยุดทำงาน", + "toast_plugin_translated": "แปลเป็น {{var0}}", + "toast_plugin_unloaded": "ยกเลิกการโหลด {{var0}} แล้ว", + "toast_plugin_update_failed": "ไม่สามารถดาวน์โหลดการอัปเดตสำหรับ {{var0}}", + "toast_plugin_updated": "{{var0}} {{var1}} ถูกแทนที่ด้วย {{var2}} {{var3}}", + "update_check_complete": "การตรวจสอบการอัปเดตปลั๊กอินเสร็จสมบูรณ์", + "update_check_complete_outdated": "การตรวจสอบการอัปเดตปลั๊กอินเสร็จสมบูรณ์ - {{var0}} ล้าสมัย!", + "update_check_info": "ตรวจสอบปลั๊กอินที่รองรับการตรวจสอบการอัปเดต", + "update_notice_click": "คลิกเพื่ออัพเดท!", + "update_notice_reload": "โหลดซ้ำเพื่ออัปเดตให้เสร็จสมบูรณ์", + "update_notice_update": "จำเป็นต้องอัปเดตปลั๊กอินต่อไปนี้: ", + "updated": "อัปเดตแล้ว" + }, + "tr": { + "add_to": "{{var0}} ekle", + "ascending": "Artan", + "center": "Ortalanmış", + "changelog_added": "Yeni özellikler", + "changelog_fixed": "Sorun giderme", + "changelog_improved": "İyileştirmeler", + "changelog_progress": "Ilerleme", + "check_for_updates": "Güncellemeleri kontrol et", + "clipboard_success": "{{var0}} Panoya kopyalandı", + "confirm": "Emin misiniz?", + "copy": "{{var0}} kopyala", + "delete_fail": "{{var0}} silinemez", + "delete_success": "{{var0}} başarıyla silindi", + "descending": "Azalan", + "developer": "Geliştirici", + "donate_message": "Daha fazla güncelleme için beni destekleyin!", + "download": "İndir", + "download_fail": "{{var0}} indirilemez", + "download_success": "{{var0}} başarıyla indirildi", + "file_navigator_text": "Dosyaya Gözat", + "first": "İlk", + "from": "Nereden", + "gradient": "Gradyan", + "guildbanner": "Afiş", + "guildicon": "Simge", + "installed": "Kurulmuş", + "last": "Son", + "left": "Ayrıldı", + "loading": "Yükleniyor {{var0}}", + "location": "Yer", + "order": "Sıra", + "outdated": "Modası geçmiş", + "please_wait": "Lütfen bekle", + "right": "Sağ", + "save_fail": "{{var0}} kaydedilemez", + "save_success": "{{var0}} başarıyla kaydedildi", + "send": "{{var0}} gönder", + "server": "Sunucu", + "settings_shareData_description": "Eklenti Yapılandırmalarını Discord Hesapları arasında senkronize eder", + "settings_showSupportBadges_description": "Patreon'umu destekleyen kullanıcılar için küçük rozetler gösterir", + "settings_showToasts_description": "Eklenti başlangıç ​​ve bitiş tostlarını gösterir", + "settings_showToasts_note": "Devre dışı bırakmadan önce BD'lerin genel ayarını '{{var0}}' devre dışı bırakın", + "settings_toastPosition_description": "Varsayılan Tost Konumu", + "settings_toastPosition_note": "Yalnızca Eklentileri tarafından oluşturulan Toastların Konumunu değiştirir", + "settings_useChromium_description": "Tarayıcınız yerine Discord'da Bağlantıları Açın", + "sort_by": "Göre sırala", + "status": "Durum", + "time": "Zaman", + "timezone": "Saat dilimi", + "to": "İçin", + "toast_plugin_force_updated": "Sürümünüz çok eski olduğu için {{var0}} otomatik olarak güncellendi", + "toast_plugin_loaded": "{{var0}} yüklendi", + "toast_plugin_started": "{{var0}} başladı", + "toast_plugin_stopped": "{{var0}} durdu", + "toast_plugin_translated": "{{var0}} diline çevrildi", + "toast_plugin_unloaded": "{{var0}} kaldırıldı", + "toast_plugin_update_failed": "{{var0}} için güncelleme indirilemiyor", + "toast_plugin_updated": "{{var0}} {{var1}}, {{var2}} {{var3}} ile değiştirildi", + "update_check_complete": "Eklenti güncelleme kontrolü tamamlandı", + "update_check_complete_outdated": "Eklenti güncelleme kontrolü tamamlandı - {{var0}} güncel değil!", + "update_check_info": "Güncelleme Kontrolünü destekleyen Eklentileri kontrol edin", + "update_notice_click": "Güncellemek için tıklayın!", + "update_notice_reload": "Güncellemeyi tamamlamak için yeniden yükleyin", + "update_notice_update": "Aşağıdaki Eklentileri güncellenmesi gerekiyor: ", + "updated": "Güncellenmiş" + }, + "uk": { + "add_to": "Додати до {{var0}}", + "ascending": "Висхідний", + "center": "По центру", + "changelog_added": "Нові можливості", + "changelog_fixed": "Вирішення проблем", + "changelog_improved": "Покращення", + "changelog_progress": "Прогрес", + "check_for_updates": "Перевірити наявність оновлень", + "clipboard_success": "Скопійовано {{var0}} в буфер обміну", + "confirm": "Ти впевнений?", + "copy": "Копіювати {{var0}}", + "delete_fail": "{{var0}} не можна видалити", + "delete_success": "{{var0}} успішно видалено", + "descending": "За спаданням", + "developer": "Розробник", + "donate_message": "Підтримайте мене, щоб отримати більше оновлень!", + "download": "Завантажити", + "download_fail": "{{var0}} не можна завантажити", + "download_success": "{{var0}} завантажено успішно", + "file_navigator_text": "Переглянути файл", + "first": "Спочатку", + "from": "Від", + "gradient": "Градієнт", + "guildbanner": "Банер", + "guildicon": "Піктограма", + "installed": "Встановлено", + "last": "Останній", + "left": "Ліворуч", + "loading": "Завантаження {{var0}}", + "location": "Розташування", + "order": "Послідовність", + "outdated": "Застарілий", + "please_wait": "Задоволення почекайте", + "right": "Правильно", + "save_fail": "{{var0}} не можна зберегти", + "save_success": "{{var0}} успішно збережено", + "send": "Надіслати {{var0}}", + "server": "Сервер", + "settings_shareData_description": "Синхронізує конфігурації плагінів між обліковими записами Discord", + "settings_showSupportBadges_description": "Показує невеликі значки для користувачів, які підтримують мій Patreon", + "settings_showToasts_description": "Показує тости запуску та зупинки плагіна", + "settings_showToasts_note": "Вимкніть загальне налаштування '{{var0}}' BD, перш ніж їх вимикати", + "settings_toastPosition_description": "Позиція тостів за замовчуванням", + "settings_toastPosition_note": "Змінює лише позицію тостів, створених моїми плагіни", + "settings_useChromium_description": "Відкрийте посилання в Discord замість браузера", + "sort_by": "Сортувати за", + "status": "Статус", + "time": "Час", + "timezone": "Часовий пояс", + "to": "До", + "toast_plugin_force_updated": "{{var0}} було автоматично оновлено, оскільки ваша версія була дуже застарілою", + "toast_plugin_loaded": "{{var0}} завантажено", + "toast_plugin_started": "{{var0}} розпочато", + "toast_plugin_stopped": "{{var0}} зупинено", + "toast_plugin_translated": "перекладено на {{var0}}", + "toast_plugin_unloaded": "{{var0}} вивантажено", + "toast_plugin_update_failed": "Не вдається завантажити оновлення для {{var0}}", + "toast_plugin_updated": "{{var0}} {{var1}} замінено на {{var2}} {{var3}}", + "update_check_complete": "Завершено перевірку оновлення плагіна", + "update_check_complete_outdated": "Завершено перевірку оновлення плагіна - {{var0}} застаріло!", + "update_check_info": "Перевірте плагіни, які підтримують перевірку оновлення", + "update_notice_click": "Натисніть, щоб оновити!", + "update_notice_reload": "Перезавантажте, щоб завершити оновлення", + "update_notice_update": "Потрібно оновити такі плагіни: ", + "updated": "Оновлено" + }, + "vi": { + "add_to": "Thêm vào {{var0}}", + "ascending": "Tăng dần", + "center": "Căn giữa", + "changelog_added": "Các tính năng mới", + "changelog_fixed": "Xử lý sự cố", + "changelog_improved": "Cải tiến", + "changelog_progress": "Phát triển", + "check_for_updates": "Kiểm tra cập nhật", + "clipboard_success": "Đã sao chép {{var0}} vào Clipboard", + "confirm": "Bạn có chắc không?", + "copy": "Sao chép {{var0}}", + "delete_fail": "{{var0}} không thể bị xóa", + "delete_success": "Đã xóa {{var0}} thành công", + "descending": "Giảm dần", + "developer": "Người phát triển", + "donate_message": "Hỗ trợ tôi để cập nhật thêm!", + "download": "Tải xuống", + "download_fail": "Không thể tải xuống {{var0}}", + "download_success": "Đã tải xuống {{var0}} thành công", + "file_navigator_text": "Chọn thư mục", + "first": "Đầu tiên", + "from": "Từ", + "gradient": "Dốc", + "guildbanner": "Ảnh bìa", + "guildicon": "Biểu tượng", + "installed": "Cài đặt", + "last": "Cuối cùng", + "left": "Trái", + "loading": "Đang tải {{var0}}", + "location": "Vị trí", + "order": "Sự nối tiếp", + "outdated": "Lỗi thời", + "please_wait": "Hân hạnh chờ đợi", + "right": "Đúng", + "save_fail": "{{var0}} không thể lưu được", + "save_success": "{{var0}} đã được lưu thành công", + "send": "Gửi cho {{var0}}", + "server": "Người phục vụ", + "settings_shareData_description": "Đồng bộ hóa cấu hình plugin giữa các tài khoản Discord", + "settings_showSupportBadges_description": "Hiển thị các huy hiệu nhỏ cho những người dùng ủng hộ Patreon của tôi", + "settings_showToasts_description": "Hiển thị plugin bắt đầu và dừng nâng cốc", + "settings_showToasts_note": "Tắt cài đặt chung '{{var0}}' của BD trước khi tắt chúng", + "settings_toastPosition_description": "Vị trí bánh mì nướng mặc định", + "settings_toastPosition_note": "Chỉ thay đổi Vị trí của Bánh nướng được tạo bởi plugins của tôi", + "settings_useChromium_description": "Mở Liên kết trong Discord thay vì Trình duyệt của bạn", + "sort_by": "Sắp xếp theo", + "status": "Trạng thái", + "time": "Thời gian", + "timezone": "Múi giờ", + "to": "Đến", + "toast_plugin_force_updated": "{{var0}} đã được cập nhật tự động vì phiên bản của bạn đã rất lỗi thời", + "toast_plugin_loaded": "{{var0}} đã được tải", + "toast_plugin_started": "{{var0}} đã bắt đầu", + "toast_plugin_stopped": "{{var0}} đã dừng", + "toast_plugin_translated": "đã dịch sang {{var0}}", + "toast_plugin_unloaded": "{{var0}} đã được tải xuống", + "toast_plugin_update_failed": "Không thể tải xuống bản cập nhật cho {{var0}}", + "toast_plugin_updated": "{{var0}} {{var1}} đã được thay thế bằng {{var2}} {{var3}}", + "update_check_complete": "Đã hoàn tất kiểm tra cập nhật plugin", + "update_check_complete_outdated": "Đã hoàn tất kiểm tra cập nhật plugin - {{var0}} đã lỗi thời!", + "update_check_info": "Kiểm tra các plugins hỗ trợ Kiểm tra cập nhật", + "update_notice_click": "Bấm để cập nhật!", + "update_notice_reload": "Tải lại để hoàn tất cập nhật", + "update_notice_update": "Các plugins sau cần được cập nhật: ", + "updated": "Đã cập nhật" + }, + "zh-CN": { + "add_to": "添加到 {{var0}}", + "ascending": "上升", + "center": "居中", + "changelog_added": "新的功能", + "changelog_fixed": "故障排除", + "changelog_improved": "改进之处", + "changelog_progress": "进展", + "check_for_updates": "检查更新", + "clipboard_success": "已将 {{var0}} 复制到剪贴板", + "confirm": "你确定吗?", + "copy": "复制 {{var0}}", + "delete_fail": "{{var0}} 无法删除", + "delete_success": "{{var0}} 成功删除", + "descending": "降序", + "developer": "开发商", + "donate_message": "支持我更多更新!", + "download": "下载", + "download_fail": "{{var0}} 无法下载", + "download_success": "{{var0}} 已成功下载", + "file_navigator_text": "浏览文件", + "first": "第一", + "from": "从", + "gradient": "梯度", + "guildbanner": "旗帜", + "guildicon": "图标", + "installed": "已安装", + "last": "持续", + "left": "剩下", + "loading": "正在加载 {{var0}}", + "location": "地点", + "order": "顺序", + "outdated": "过时的", + "please_wait": "请稍等", + "right": "对", + "save_fail": "{{var0}} 无法保存", + "save_success": "{{var0}} 保存成功", + "send": "发送 {{var0}}", + "server": "服务器", + "settings_shareData_description": "在 Discord 帐户之间同步插件配置", + "settings_showSupportBadges_description": "为支持我的 Patreon 的用户显示小徽章", + "settings_showToasts_description": "显示插件开始和停止烤面包", + "settings_showToasts_note": "禁用 BD 的常规设置 '{{var0}}' 之前将其禁用", + "settings_toastPosition_description": "默认吐司位置", + "settings_toastPosition_note": "仅更改由我的插件创建的吐司位置", + "settings_useChromium_description": "在 Discord (而不是浏览器)中打开链接", + "sort_by": "排序方式", + "status": "地位", + "time": "时间", + "timezone": "时区", + "to": "至", + "toast_plugin_force_updated": "{{var0}} 已自动更新,因为您的版本已过时", + "toast_plugin_loaded": "{{var0}} 已加载", + "toast_plugin_started": "{{var0}} 已开始", + "toast_plugin_stopped": "{{var0}} 已停止", + "toast_plugin_translated": "转换为 {{var0}}", + "toast_plugin_unloaded": "{{var0}} 已卸载", + "toast_plugin_update_failed": "无法下载 {{var0}} 的更新", + "toast_plugin_updated": "{{var0}} {{var1}} 已替换为 {{var2}} {{var3}}", + "update_check_complete": "插件更新检查完成", + "update_check_complete_outdated": "插件更新检查完成 - {{var0}} 已过期!", + "update_check_info": "检查支持更新检查的插件", + "update_notice_click": "点击更新!", + "update_notice_reload": "重新加载以完成更新", + "update_notice_update": "以下插件需要更新: ", + "updated": "更新" + }, + "zh-TW": { + "add_to": "添加到 {{var0}}", + "ascending": "上升", + "center": "居中", + "changelog_added": "新的功能", + "changelog_fixed": "故障排除", + "changelog_improved": "改進之處", + "changelog_progress": "進展", + "check_for_updates": "檢查更新", + "clipboard_success": "已將 {{var0}} 複製到剪貼板", + "confirm": "你確定嗎?", + "copy": "複製 {{var0}}", + "delete_fail": "{{var0}} 無法刪除", + "delete_success": "{{var0}} 成功刪除", + "descending": "降序", + "developer": "開發商", + "donate_message": "支持我更多更新!", + "download": "下載", + "download_fail": "{{var0}} 無法下載", + "download_success": "{{var0}} 已成功下載", + "file_navigator_text": "瀏覽文件", + "first": "第一", + "from": "從", + "gradient": "梯度", + "guildbanner": "旗幟", + "guildicon": "圖標", + "installed": "已安裝", + "last": "持續", + "left": "剩下", + "loading": "正在加載 {{var0}}", + "location": "地點", + "order": "順序", + "outdated": "過時的", + "please_wait": "請稍等", + "right": "對", + "save_fail": "{{var0}} 無法保存", + "save_success": "{{var0}} 保存成功", + "send": "發送 {{var0}}", + "server": "服務器", + "settings_shareData_description": "在 Discord 帳戶之間同步插件配置", + "settings_showSupportBadges_description": "為支持我的 Patreon 的用戶顯示小徽章", + "settings_showToasts_description": "顯示插件開始和停止烤麵包", + "settings_showToasts_note": "禁用 BD 的常規設置 '{{var0}}' 之前將其禁用", + "settings_toastPosition_description": "默認吐司位置", + "settings_toastPosition_note": "僅更改由我的插件創建的吐司位置", + "settings_useChromium_description": "在 Discord (而不是瀏覽器)中打開鏈接", + "sort_by": "排序方式", + "status": "地位", + "time": "時間", + "timezone": "時區", + "to": "至", + "toast_plugin_force_updated": "{{var0}} 已自動更新,因為您的版本已過時", + "toast_plugin_loaded": "{{var0}} 已加載", + "toast_plugin_started": "{{var0}} 已開始", + "toast_plugin_stopped": "{{var0}} 已停止", + "toast_plugin_translated": "轉換為 {{var0}}", + "toast_plugin_unloaded": "{{var0}} 已被卸載", + "toast_plugin_update_failed": "無法下載 {{var0}} 的更新", + "toast_plugin_updated": "{{var0}} {{var1}} 已替換為 {{var2}} {{var3}}", + "update_check_complete": "插件更新檢查完成", + "update_check_complete_outdated": "插件更新檢查完成 - {{var0}} 已過期!", + "update_check_info": "檢查支持更新檢查的插件", + "update_notice_click": "點擊更新!", + "update_notice_reload": "重新加載以完成更新", + "update_notice_update": "以下插件需要更新: ", + "updated": "更新" + }, + "default": { + "add_to": "Add to {{var0}}", + "ascending": "Ascending", + "center": "Centered", + "changelog_added": "New Features", + "changelog_fixed": "Bug Fixes", + "changelog_improved": "Improvements", + "changelog_progress": "Progress", + "check_for_updates": "Check for Updates", + "clipboard_success": "Copied {{var0}} to Clipboard", + "confirm": "Are you sure?", + "copy": "Copy {{var0}}", + "delete_fail": "{{var0}} cannot be deleted", + "delete_success": "{{var0}} deleted successfully", + "descending": "Descending", + "developer": "Developer", + "donate_message": "Support me to receive further Updates!", + "download": "Download", + "download_fail": "{{var0}} cannot be downloaded", + "download_success": "{{var0}} downloaded successfully", + "file_navigator_text": "Browse File", + "first": "First", + "from": "From", + "gradient": "Gradient", + "guildbanner": "Banner", + "guildicon": "Icon", + "installed": "Installed", + "last": "Last", + "left": "Left", + "loading": "Loading {{var0}}", + "location": "Location", + "order": "Order", + "outdated": "Outdated", + "please_wait": "Please wait", + "right": "Right", + "save_fail": "{{var0}} cannot be saved", + "save_success": "{{var0}} saved successfully", + "send": "Send {{var0}}", + "server": "Server", + "settings_shareData_description": "Synchronizes the Plugin Configs between Discord Accounts", + "settings_showSupportBadges_description": "Shows small Badges for Users who support my Patreon", + "settings_showToasts_description": "Shows Plugin start and stop Toasts", + "settings_showToasts_note": "Disable BDs general '{{var0}}' setting before disabling this", + "settings_toastPosition_description": "Default Toast Position", + "settings_toastPosition_note": "Only changes Position of Toasts created by my Plugins", + "settings_useChromium_description": "Open Links in Discord instead of your Browser", + "sort_by": "Sort by", + "status": "Status", + "time": "Time", + "timezone": "Timezone", + "to": "To", + "toast_plugin_force_updated": "{{var0}} was automatically updated because your Version is heavily outdated", + "toast_plugin_loaded": "{{var0}} has been loaded", + "toast_plugin_started": "{{var0}} has been started", + "toast_plugin_stopped": "{{var0}} has been stopped", + "toast_plugin_translated": "translated to {{var0}}", + "toast_plugin_unloaded": "{{var0}} has been unloaded", + "toast_plugin_update_failed": "Update for {{var0}} cannot be downloaded", + "toast_plugin_updated": "{{var0}} {{var1}} has been replaced by {{var2}} {{var3}}", + "update_check_complete": "Plugin Update Check completed", + "update_check_complete_outdated": "Plugin Update Check completed - {{var0}} outdated!", + "update_check_info": "Check Plugins that support the Update Check", + "update_notice_click": "Click to update!", + "update_notice_reload": "Reload to complete the Update", + "update_notice_update": "The following Plugins need to be updated: ", + "updated": "Updated" + } + }, + "BDFDB_Patrons": { + "797199624992849960": {"active": true, "tier": "t3", "text": "", "color": "", "id": "blink (AhBo)"}, + "384941155558752258": {"active": true, "tier": "t2", "text": "", "color": "", "id": "jack (j.bev)"}, + "935758254858973224": {"active": true, "tier": "t3", "text": "", "color": "", "id": "SaneVR (rukin)"}, + "870962330417102919": {"active": false, "tier": "t2", "text": "", "color": "", "id": "gobber (pobge)"}, + "335997977938100226": {"active": true, "tier": "t3", "text": "Cloudy Hub Owner", "color": "", "id": "Synax (DaBa)"}, + "558825053668507650": {"active": false, "tier": "t2", "text": "", "color": "", "id": "duh (AshAj)"}, + "779410322187354163": {"active": false, "tier": "t3", "text": "", "color": "", "id": "Liam (LiaHu)"}, + "169931777371144192": {"active": false, "tier": "t3", "text": "", "color": "", "id": "DogGodLog (JHa)"}, + "89482511343702016": {"active": false, "tier": "t3", "text": "", "color": "#0080ff", "id": "AzukiPuddles"}, + "919272398832959598": {"active": false, "tier": "t2", "text": "", "color": "", "id": "w_da_woo (NosiGosi)"}, + "622957773080100875": {"active": true, "tier": "t2", "text": "", "color": "", "id": "ying (KeCa)"}, + "798499176220327966": {"active": true, "tier": "t2", "text": "", "color": "", "id": "void (JaUt)"}, + "276137824460210178": {"active": true, "tier": "t3", "text": "FFXIV DRK Main for life!", "color": "#1f0046", "id": "werewolf (MaMa)"}, + "155552545782235137": {"active": false, "tier": "t3", "text": "i hate everything about u", "color": "", "id": "Umbra (RaKa)"}, + "824768928369606667": {"active": false, "tier": "t2", "text": "", "color": "", "id": "Kubox (HajJa)"}, + "507464069100601363": {"active": true, "tier": "t2", "text": "", "color": "", "id": "Cracky (MiPo)"}, + "264486632525135883": {"active": true, "tier": "t3", "text": "Mr. Morale", "color": "", "id": "strix (A1C)"}, + "363785301195358221": {"active": true, "tier": "t2", "text": "", "color": "", "id": "TRENT (KABEL)"}, + "620397524494057513": {"active": true, "tier": "t2", "text": "", "color": "", "id": "FUSL"} + }, + "BDFDB_Patron_Tiers": { + "t1": { + "text": "" + }, + "t2": { + "text": "BDFDB Patron" + }, + "t3": { + "text": "BDFDB Patron+" + }, + "t4": { + "text": "BDFDB Special Supporter" + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/0BDFDB.plugin.js b/oldconfig/BetterDiscord/plugins/0BDFDB.plugin.js new file mode 100644 index 0000000..856bf10 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/0BDFDB.plugin.js @@ -0,0 +1,9174 @@ +/** + * @name BDFDB + * @author DevilBro + * @authorId 278543574059057154 + * @version 2.4.6 + * @description Required Library for DevilBro's Plugins + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Library/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js + */ + +module.exports = (_ => { + const BdApi = window.BdApi; + + const config = { + "info": { + "name": "BDFDB", + "author": "DevilBro", + "version": "2.4.6", + "description": "Required Library for DevilBro's Plugins" + }, + "rawUrl": "https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js" + }; + + const Cache = {data: {}, modules: {}}; + + var libraryInstance; + var changeLogs = {}; + + if (window.BDFDB_Global && window.BDFDB_Global.PluginUtils && typeof window.BDFDB_Global.PluginUtils.cleanUp == "function") { + window.BDFDB_Global.PluginUtils.cleanUp(window.BDFDB_Global); + } + + const BDFDB = { + started: true + }; + for (let key in config) key == "info" ? Object.assign(BDFDB, config[key]) : (BDFDB[key] = config[key]); + + const Internal = Object.assign({}, BDFDB, { + patchPriority: 0, + forceSyncData: true, + settings: {}, + defaults: { + general: { + shareData: { + value: true, + onChange: _ => Cache.data = {} + }, + showToasts: { + value: true, + isDisabled: data => data.nativeValue, + hasNote: data => data.disabled && data.value + }, + showSupportBadges: { + value: true + }, + useChromium: { + value: false, + isHidden: data => !Internal.LibraryRequires.electron || !Internal.LibraryRequires.electron.remote, + getValue: data => !data.disabled + } + }, + choices: { + toastPosition: { + value: "right", + items: "ToastPositions" + } + } + }, + }); + for (let key in Internal.defaults) Internal.settings[key] = {}; + + const LibraryConstants = { + ToastIcons: { + info: "INFO", + danger: "CLOSE_CIRCLE", + success: "CHECKMARK_CIRCLE", + warning: "WARNING" + }, + ToastPositions: { + center: "toastscenter", + left: "toastsleft", + right: "toastsright" + } + }; + + const PluginStores = { + loaded: {}, + delayed: { + loads: [], + starts: [] + }, + updateData: { + plugins: {}, + timeouts: [], + downloaded: [], + interval: null + }, + patchQueues: {}, + chunkObserver: {}, + contextChunkObserver: {} + }; + const Plugin = function(config) { + return class Plugin { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return config.info.description;} + load () { + this.loaded = true; + this.defaults = {}; + this.labels = {}; + if (window.BDFDB_Global.loading) { + if (!PluginStores.delayed.loads.includes(this)) PluginStores.delayed.loads.push(this); + } + else { + Object.assign(this, config.info, BDFDB.ObjectUtils.exclude(config, "info")); + BDFDB.TimeUtils.suppress(_ => { + PluginStores.loaded[config.info.name] = this; + BDFDB.PluginUtils.load(this); + if (typeof this.onLoad == "function") this.onLoad(); + }, "Failed to load Plugin!", config.info)(); + } + } + start () { + if (!this.loaded) this.load(); + if (window.BDFDB_Global.loading) { + if (!PluginStores.delayed.starts.includes(this)) PluginStores.delayed.starts.push(this); + } + else { + if (this.started) return; + this.started = true; + BDFDB.TimeUtils.suppress(_ => { + BDFDB.PluginUtils.init(this); + if (typeof this.onStart == "function") this.onStart(); + }, "Failed to start Plugin!", config.info)(); + delete this.stopping; + } + } + stop () { + if (window.BDFDB_Global.loading) { + if (PluginStores.delayed.starts.includes(this)) PluginStores.delayed.starts.splice(PluginStores.delayed.starts.indexOf(this), 1); + } + else { + if (this.stopping) return; + this.stopping = true; + BDFDB.TimeUtils.timeout(_ => {delete this.stopping;}); + + BDFDB.TimeUtils.suppress(_ => { + if (typeof this.onStop == "function") this.onStop(); + BDFDB.PluginUtils.clear(this); + }, "Failed to stop Plugin!", config.info)(); + + delete this.started; + } + } + }; + }; + + BDFDB.LogUtils = {}; + Internal.console = function (type, config = {}) { + if (!console[type]) return; + let name, version; + if (typeof config.name == "string" && config.name) { + name = config.name; + version = typeof config.version == "string" ? config.version : ""; + } + else { + name = BDFDB.name; + version = BDFDB.version; + } + console[type](...[[name && `%c[${name}]`, version && `%c(v${version})`].filter(n => n).join(" "), name && "color: #3a71c1; font-weight: 700;", version && "color: #666; font-weight: 600; font-size: 11px;", [config.strings].flat(10).filter(n => n).join(" ").trim()].filter(n => n)); + }; + BDFDB.LogUtils.log = function (strings, config = {}) { + Internal.console("log", Object.assign({}, config, {name: typeof config == "string" ? config : config.name, strings})); + }; + BDFDB.LogUtils.warn = function (strings, config = {}) { + Internal.console("warn", Object.assign({}, config, {name: typeof config == "string" ? config : config.name, strings})); + }; + BDFDB.LogUtils.error = function (strings, config = {}) { + Internal.console("error", Object.assign({}, config, {name: typeof config == "string" ? config : config.name, strings: ["Fatal Error:", strings]})); + }; + + BDFDB.TimeUtils = {}; + BDFDB.TimeUtils.interval = function (callback, delay, ...args) { + if (typeof callback != "function" || typeof delay != "number" || delay < 1) return; + else { + let count = 0, interval = setInterval(_ => BDFDB.TimeUtils.suppress(callback, "Interval")(...[interval, count++, args].flat()), delay); + return interval; + } + }; + BDFDB.TimeUtils.timeout = function (callback, delay, ...args) { + delay = parseFloat(delay); + if (typeof callback != "function") return; + if (isNaN(delay) || typeof delay != "number" || delay < 1) { + let immediate = setImmediate(_ => BDFDB.TimeUtils.suppress(callback, "Immediate")(...[immediate, args].flat())); + return immediate; + } + else { + let start, paused = true, timeout = { + pause: _ => { + if (paused) return; + paused = true; + BDFDB.TimeUtils.clear(timeout.timer); + delay -= performance.now() - start; + }, + resume: _ => { + if (!paused) return; + paused = false; + start = performance.now(); + timeout.timer = setTimeout(_ => BDFDB.TimeUtils.suppress(callback, "Timeout")(...[timeout, args].flat()), delay) + } + }; + timeout.resume(); + return timeout; + } + }; + BDFDB.TimeUtils.clear = function (...timeObjects) { + for (let t of timeObjects.flat(10).filter(n => n)) { + t = t.timer != undefined ? t.timer : t; + if (typeof t == "number") { + clearInterval(t); + clearTimeout(t); + } + else if (typeof t == "object") clearImmediate(t); + } + }; + BDFDB.TimeUtils.suppress = function (callback, strings, config) {return function (...args) { + try {return callback(...args);} + catch (err) {BDFDB.LogUtils.error([strings, err], config);} + }}; + + BDFDB.LogUtils.log("Loading Library"); + + BDFDB.sameProto = function (a, b) { + if (a != null && typeof a == "object") return a.constructor && a.constructor.prototype && typeof a.constructor.prototype.isPrototypeOf == "function" && a.constructor.prototype.isPrototypeOf(b); + else return typeof a == typeof b; + }; + BDFDB.equals = function (mainA, mainB, sorted) { + let i = -1; + if (sorted === undefined || typeof sorted !== "boolean") sorted = false; + return equal(mainA, mainB); + function equal(a, b) { + i++; + let result = true; + if (i > 1000) result = null; + else { + if (typeof a !== typeof b) result = false; + else if (typeof a == "function") result = a.toString() == b.toString(); + else if (typeof a === "undefined") result = true; + else if (typeof a === "symbol") result = true; + else if (typeof a === "boolean") result = a == b; + else if (typeof a === "string") result = a == b; + else if (typeof a === "number") { + if (isNaN(a) || isNaN(b)) result = isNaN(a) == isNaN(b); + else result = a == b; + } + else if (!a && !b) result = true; + else if (!a || !b) result = false; + else if (typeof a === "object") { + let keysA = Object.getOwnPropertyNames(a); + let keysB = Object.getOwnPropertyNames(b); + if (keysA.length !== keysB.length) result = false; + else for (let j = 0; result === true && j < keysA.length; j++) { + if (sorted) result = equal(a[keysA[j]], b[keysB[j]]); + else result = equal(a[keysA[j]], b[keysA[j]]); + } + } + } + i--; + return result; + } + }; + + BDFDB.ObjectUtils = {}; + BDFDB.ObjectUtils.is = function (obj) { + return obj && !Array.isArray(obj) && !Set.prototype.isPrototypeOf(obj) && (typeof obj == "function" || typeof obj == "object"); + }; + BDFDB.ObjectUtils.get = function (nodeOrObj, valuePath) { + if (!nodeOrObj || !valuePath) return null; + let obj = Node.prototype.isPrototypeOf(nodeOrObj) ? BDFDB.ReactUtils.getInstance(nodeOrObj) : nodeOrObj; + if (!BDFDB.ObjectUtils.is(obj)) return null; + let found = obj; + for (const value of valuePath.split(".").filter(n => n)) { + if (!found) return null; + found = found[value]; + } + return found; + }; + BDFDB.ObjectUtils.extract = function (obj, ...keys) { + let newObj = {}; + if (BDFDB.ObjectUtils.is(obj)) for (let key of keys.flat(10).filter(n => n)) if (obj[key] != null) newObj[key] = obj[key]; + return newObj; + }; + BDFDB.ObjectUtils.exclude = function (obj, ...keys) { + let newObj = Object.assign({}, obj); + BDFDB.ObjectUtils.delete(newObj, ...keys) + return newObj; + }; + BDFDB.ObjectUtils.delete = function (obj, ...keys) { + if (BDFDB.ObjectUtils.is(obj)) for (let key of keys.flat(10).filter(n => n)) delete obj[key]; + }; + BDFDB.ObjectUtils.sort = function (obj, sort, except) { + if (!BDFDB.ObjectUtils.is(obj)) return {}; + let newObj = {}; + if (sort === undefined || !sort) for (let key of Object.keys(obj).sort()) newObj[key] = obj[key]; + else { + let values = []; + for (let key in obj) values.push(obj[key]); + values = BDFDB.ArrayUtils.keySort(values, sort, except); + for (let value of values) for (let key in obj) if (BDFDB.equals(value, obj[key])) { + newObj[key] = value; + break; + } + } + return newObj; + }; + BDFDB.ObjectUtils.group = function (obj, key) { + if (!BDFDB.ObjectUtils.is(obj)) return {}; + if (typeof key != "string") return obj; + return Object.entries(obj).reduce((newObj, objPair) => { + if (!newObj[objPair[1][key]]) newObj[objPair[1][key]] = {}; + newObj[objPair[1][key]][objPair[0]] = objPair[1]; + return newObj; + }, {}); + }; + BDFDB.ObjectUtils.reverse = function (obj, sort) { + if (!BDFDB.ObjectUtils.is(obj)) return {}; + let newObj = {}; + for (let key of (sort === undefined || !sort) ? Object.keys(obj).reverse() : Object.keys(obj).sort().reverse()) newObj[key] = obj[key]; + return newObj; + }; + BDFDB.ObjectUtils.filter = function (obj, filter, byKey = false) { + if (!BDFDB.ObjectUtils.is(obj)) return {}; + if (typeof filter != "function") return obj; + return Object.keys(obj).filter(key => filter(byKey ? key : obj[key])).reduce((newObj, key) => (newObj[key] = obj[key], newObj), {}); + }; + BDFDB.ObjectUtils.push = function (obj, value) { + if (BDFDB.ObjectUtils.is(obj)) obj[Object.keys(obj).length] = value; + }; + BDFDB.ObjectUtils.pop = function (obj, value) { + if (BDFDB.ObjectUtils.is(obj)) { + let keys = Object.keys(obj); + if (!keys.length) return; + let value = obj[keys[keys.length-1]]; + delete obj[keys[keys.length-1]]; + return value; + } + }; + BDFDB.ObjectUtils.map = function (obj, mapFunc) { + if (!BDFDB.ObjectUtils.is(obj)) return {}; + if (typeof mapFunc != "string" && typeof mapFunc != "function") return obj; + let newObj = {}; + for (let key in obj) if (BDFDB.ObjectUtils.is(obj[key])) newObj[key] = typeof mapFunc == "string" ? obj[key][mapFunc] : mapFunc(obj[key], key); + return newObj; + }; + BDFDB.ObjectUtils.toArray = function (obj) { + if (!BDFDB.ObjectUtils.is(obj)) return []; + return Object.entries(obj).map(n => n[1]); + }; + BDFDB.ObjectUtils.deepAssign = function (obj, ...objs) { + if (!objs.length) return obj; + let nextObj = objs.shift(); + if (BDFDB.ObjectUtils.is(obj) && BDFDB.ObjectUtils.is(nextObj)) { + for (let key in nextObj) { + if (BDFDB.ObjectUtils.is(nextObj[key])) { + if (!obj[key]) Object.assign(obj, {[key]:{}}); + BDFDB.ObjectUtils.deepAssign(obj[key], nextObj[key]); + } + else Object.assign(obj, {[key]:nextObj[key]}); + } + } + return BDFDB.ObjectUtils.deepAssign(obj, ...objs); + }; + BDFDB.ObjectUtils.isEmpty = function (obj) { + return !BDFDB.ObjectUtils.is(obj) || Object.getOwnPropertyNames(obj).length == 0; + }; + BDFDB.ObjectUtils.mirror = function (obj) { + if (!BDFDB.ObjectUtils.is(obj)) return {}; + let newObj = Object.assign({}, obj); + for (let key in newObj) if (newObj[newObj[key]] == undefined && (typeof key == "number" || typeof key == "string")) newObj[newObj[key]] = key; + return newObj; + }; + + BDFDB.ArrayUtils = {}; + BDFDB.ArrayUtils.is = function (array) { + return array && Array.isArray(array); + }; + BDFDB.ArrayUtils.sum = function (array) { + return Array.isArray(array) ? array.reduce((total, num) => total + Math.round(num), 0) : 0; + }; + BDFDB.ArrayUtils.keySort = function (array, key, except) { + if (!BDFDB.ArrayUtils.is(array)) return []; + if (key == null) return array; + if (except === undefined) except = null; + return array.sort((x, y) => { + let xValue = x[key], yValue = y[key]; + if (xValue !== except) return xValue < yValue ? -1 : xValue > yValue ? 1 : 0; + }); + }; + BDFDB.ArrayUtils.numSort = function (array) { + return array.sort((x, y) => (x < y ? -1 : x > y ? 1 : 0)); + }; + BDFDB.ArrayUtils.includes = function (array, ...values) { + if (!BDFDB.ArrayUtils.is(array)) return null; + if (!array.length) return false; + let all = values.pop(); + if (typeof all != "boolean") { + values.push(all); + all = true; + } + if (!values.length) return false; + let contained = undefined; + for (let v of values) { + if (contained === undefined) contained = all; + if (all && !array.includes(v)) contained = false; + if (!all && array.includes(v)) contained = true; + } + return contained; + }; + BDFDB.ArrayUtils.remove = function (array, value, all = false) { + if (!BDFDB.ArrayUtils.is(array)) return []; + if (!array.includes(value)) return array; + if (!all) array.splice(array.indexOf(value), 1); + else while (array.indexOf(value) > -1) array.splice(array.indexOf(value), 1); + return array; + }; + BDFDB.ArrayUtils.getAllIndexes = function (array, value) { + if (!BDFDB.ArrayUtils.is(array) && typeof array != "string") return []; + var indexes = [], index = -1; + while ((index = array.indexOf(value, index + 1)) !== -1) indexes.push(index); + return indexes; + }; + BDFDB.ArrayUtils.removeCopies = function (array) { + if (!BDFDB.ArrayUtils.is(array)) return []; + return [...new Set(array)]; + }; + + BDFDB.BDUtils = {}; + BDFDB.BDUtils.getPluginsFolder = function () { + if (BdApi && BdApi.Plugins && BdApi.Plugins.folder && typeof BdApi.Plugins.folder == "string") return BdApi.Plugins.folder; + else if (Internal.LibraryRequires.process.env.BETTERDISCORD_DATA_PATH) return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.BETTERDISCORD_DATA_PATH, "plugins/"); + else if (Internal.LibraryRequires.process.env.injDir) return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.injDir, "plugins/"); + else switch (Internal.LibraryRequires.process.platform) { + case "win32": + return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.appdata, "BetterDiscord/plugins/"); + case "darwin": + return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.HOME, "Library/Preferences/BetterDiscord/plugins/"); + default: + if (Internal.LibraryRequires.process.env.XDG_CONFIG_HOME) return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.XDG_CONFIG_HOME, "BetterDiscord/plugins/"); + else if (Internal.LibraryRequires.process.env.HOME) return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.HOME, ".config/BetterDiscord/plugins/"); + else return ""; + } + }; + BDFDB.BDUtils.getThemesFolder = function () { + if (BdApi && BdApi.Themes && BdApi.Themes.folder && typeof BdApi.Themes.folder == "string") return BdApi.Themes.folder; + else if (Internal.LibraryRequires.process.env.BETTERDISCORD_DATA_PATH) return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.BETTERDISCORD_DATA_PATH, "themes/"); + else if (Internal.LibraryRequires.process.env.injDir) return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.injDir, "plugins/"); + else switch (Internal.LibraryRequires.process.platform) { + case "win32": + return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.appdata, "BetterDiscord/themes/"); + case "darwin": + return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.HOME, "Library/Preferences/BetterDiscord/themes/"); + default: + if (Internal.LibraryRequires.process.env.XDG_CONFIG_HOME) return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.XDG_CONFIG_HOME, "BetterDiscord/themes/"); + else if (Internal.LibraryRequires.process.env.HOME) return Internal.LibraryRequires.path.resolve(Internal.LibraryRequires.process.env.HOME, ".config/BetterDiscord/themes/"); + else return ""; + } + }; + BDFDB.BDUtils.isPluginEnabled = function (pluginName) { + if (!BdApi) return null; + else if (BdApi.Plugins && typeof BdApi.Plugins.isEnabled == "function") return BdApi.Plugins.isEnabled(pluginName); + else if (typeof BdApi.isPluginEnabled == "function") return BdApi.isPluginEnabled(pluginName); + }; + BDFDB.BDUtils.reloadPlugin = function (pluginName) { + if (!BdApi) return; + else if (BdApi.Plugins && typeof BdApi.Plugins.reload == "function") BdApi.Plugins.reload(pluginName); + else if (window.pluginModule) window.pluginModule.reloadPlugin(pluginName); + }; + BDFDB.BDUtils.enablePlugin = function (pluginName) { + if (!BdApi) return; + else if (BdApi.Plugins && typeof BdApi.Plugins.enable == "function") BdApi.Plugins.enable(pluginName); + else if (window.pluginModule) window.pluginModule.startPlugin(pluginName); + }; + BDFDB.BDUtils.disablePlugin = function (pluginName) { + if (!BdApi) return; + else if (BdApi.Plugins && typeof BdApi.Plugins.disable == "function") BdApi.Plugins.disable(pluginName); + else if (window.pluginModule) window.pluginModule.stopPlugin(pluginName); + }; + BDFDB.BDUtils.getPlugin = function (pluginName, hasToBeEnabled = false, overHead = false) { + if (BdApi && !hasToBeEnabled || BDFDB.BDUtils.isPluginEnabled(pluginName)) { + if (BdApi.Plugins && typeof BdApi.Plugins.get == "function") { + let plugin = BdApi.Plugins.get(pluginName); + if (!plugin) return null; + if (overHead) return plugin.filename && plugin.exports && plugin.instance ? plugin : {filename: Internal.LibraryRequires.fs.existsSync(Internal.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), `${pluginName}.plugin.js`)) ? `${pluginName}.plugin.js` : null, id: pluginName, name: pluginName, plugin: plugin}; + else return plugin.filename && plugin.exports && plugin.instance ? plugin.instance : plugin; + } + else if (window.bdplugins) overHead ? window.bdplugins[pluginName] : (window.bdplugins[pluginName] || {}).plugin; + } + return null; + }; + BDFDB.BDUtils.isThemeEnabled = function (themeName) { + if (!BdApi) return null; + else if (BdApi.Themes && typeof BdApi.Themes.isEnabled == "function") return BdApi.Themes.isEnabled(themeName); + else if (typeof BdApi.isThemeEnabled == "function") return BdApi.isThemeEnabled(themeName); + }; + BDFDB.BDUtils.enableTheme = function (themeName) { + if (!BdApi) return; + else if (BdApi.Themes && typeof BdApi.Themes.enable == "function") BdApi.Themes.enable(themeName); + else if (window.themeModule) window.themeModule.enableTheme(themeName); + }; + BDFDB.BDUtils.disableTheme = function (themeName) { + if (!BdApi) return; + else if (BdApi.Themes && typeof BdApi.Themes.disable == "function") BdApi.Themes.disable(themeName); + else if (window.themeModule) window.themeModule.disableTheme(themeName); + }; + BDFDB.BDUtils.getTheme = function (themeName, hasToBeEnabled = false) { + if (BdApi && !hasToBeEnabled || BDFDB.BDUtils.isThemeEnabled(themeName)) { + if (BdApi.Themes && typeof BdApi.Themes.get == "function") return BdApi.Themes.get(themeName); + else if (window.bdthemes) window.bdthemes[themeName]; + } + return null; + }; + BDFDB.BDUtils.settingsIds = { + automaticLoading: "settings.addons.autoReload", + coloredText: "settings.appearance.coloredText", + normalizedClasses: "settings.general.classNormalizer", + showToasts: "settings.general.showToasts" + }; + BDFDB.BDUtils.toggleSettings = function (key, state) { + if (BdApi && typeof key == "string") { + let path = key.split("."); + let currentState = BDFDB.BDUtils.getSettings(key); + if (state === true) { + if (currentState === false && typeof BdApi.enableSetting == "function") BdApi.enableSetting(...path); + } + else if (state === false) { + if (currentState === true && typeof BdApi.disableSetting == "function") BdApi.disableSetting(...path); + } + else if (currentState === true || currentState === false) BDFDB.BDUtils.toggleSettings(key, !currentState); + } + }; + BDFDB.BDUtils.getSettings = function (key) { + if (!BdApi) return {}; + if (typeof key == "string") return typeof BdApi.isSettingEnabled == "function" && BdApi.isSettingEnabled(...key.split(".")); + else return BDFDB.ArrayUtils.is(BdApi.settings) ? BdApi.settings.map(n => n.settings.map(m => m.settings.map(l => ({id: [n.id, m.id, l.id].join("."), value: l.value})))).flat(10).reduce((newObj, setting) => (newObj[setting.id] = setting.value, newObj), {}) : {}; + }; + BDFDB.BDUtils.getSettingsProperty = function (property, key) { + if (!BdApi || !BDFDB.ArrayUtils.is(BdApi.settings)) return key ? "" : {}; + else { + let settingsMap = BdApi.settings.map(n => n.settings.map(m => m.settings.map(l => ({id: [n.id, m.id, l.id].join("."), value: l[property]})))).flat(10).reduce((newObj, setting) => (newObj[setting.id] = setting.value, newObj), {}); + return key ? (settingsMap[key] != null ? settingsMap[key] : "") : ""; + } + }; + + + BDFDB.PluginUtils = {}; + BDFDB.PluginUtils.buildPlugin = function (config) { + return [Plugin(config), BDFDB]; + }; + BDFDB.PluginUtils.load = function (plugin) { + if (!PluginStores.updateData.timeouts.includes(plugin.name)) { + PluginStores.updateData.timeouts.push(plugin.name); + const url = Internal.getPluginURL(plugin); + + PluginStores.updateData.plugins[url] = {name: plugin.name, raw: url, version: plugin.version}; + + BDFDB.PluginUtils.checkUpdate(plugin.name, url); + + if (!PluginStores.updateData.interval) PluginStores.updateData.interval = BDFDB.TimeUtils.interval(_ => { + BDFDB.PluginUtils.checkAllUpdates(); + }, 1000*60*60*4); + + BDFDB.TimeUtils.timeout(_ => BDFDB.ArrayUtils.remove(PluginStores.updateData.timeouts, plugin.name, true), 30000); + } + }; + BDFDB.PluginUtils.init = function (plugin) { + BDFDB.PluginUtils.load(plugin); + + plugin.settings = BDFDB.DataUtils.get(plugin); + + BDFDB.LogUtils.log(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_started", ""), plugin); + if (Internal.settings.general.showToasts && !BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.showToasts)) BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_started", `${plugin.name} v${plugin.version}`), { + disableInteractions: true, + barColor: BDFDB.DiscordConstants.Colors.STATUS_GREEN + }); + + if (plugin.css) BDFDB.DOMUtils.appendLocalStyle(plugin.name, plugin.css); + + Internal.patchPlugin(plugin); + Internal.addQueuePatches(plugin); + Internal.addContextChunkObservers(plugin); + + BDFDB.PluginUtils.translate(plugin); + + BDFDB.PluginUtils.checkChangeLog(plugin); + }; + BDFDB.PluginUtils.clear = function (plugin) { + BDFDB.LogUtils.log(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_stopped", ""), plugin); + if (Internal.settings.general.showToasts && !BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.showToasts)) BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_stopped", `${plugin.name} v${plugin.version}`), { + disableInteractions: true, + barColor: BDFDB.DiscordConstants.Colors.STATUS_RED + }); + + const url = Internal.getPluginURL(plugin); + + BDFDB.PluginUtils.cleanUp(plugin); + + for (const type in PluginStores.patchQueues) BDFDB.ArrayUtils.remove(PluginStores.patchQueues[type].query, plugin, true); + for (const type in PluginStores.chunkObserver) BDFDB.ArrayUtils.remove(PluginStores.chunkObserver[type].query, plugin, true); + for (const type in PluginStores.contextChunkObserver) BDFDB.ArrayUtils.remove(PluginStores.contextChunkObserver[type].query, plugin, true); + + for (const modal of document.querySelectorAll(`.${plugin.name}-modal, .${plugin.name.toLowerCase()}-modal, .${plugin.name}-settingsmodal, .${plugin.name.toLowerCase()}-settingsmodal`)) { + const closeButton = modal.querySelector(BDFDB.dotCN.modalclose); + if (closeButton) closeButton.click(); + } + + delete Cache.data[plugin.name] + delete PluginStores.updateData.plugins[url]; + }; + BDFDB.PluginUtils.translate = function (plugin) { + if (typeof plugin.setLabelsByLanguage == "function" || typeof plugin.changeLanguageStrings == "function") { + const translate = _ => { + if (typeof plugin.setLabelsByLanguage == "function") plugin.labels = plugin.setLabelsByLanguage(); + if (typeof plugin.changeLanguageStrings == "function") plugin.changeLanguageStrings(); + }; + if (Internal.LibraryModules.LanguageStore.chosenLocale || Internal.LibraryModules.LanguageStore._chosenLocale || BDFDB.DicordUtils.getSettings("locale")) translate(); + else BDFDB.TimeUtils.interval(interval => { + if (Internal.LibraryModules.LanguageStore.chosenLocale || Internal.LibraryModules.LanguageStore._chosenLocale || BDFDB.DicordUtils.getSettings("locale")) { + BDFDB.TimeUtils.clear(interval); + translate(); + } + }, 100); + } + }; + BDFDB.PluginUtils.cleanUp = function (plugin) { + BDFDB.TimeUtils.suppress(_ => { + if (!BDFDB.ObjectUtils.is(plugin)) return; + if (plugin == window.BDFDB_Global) { + if (Internal.removeChunkObserver) Internal.removeChunkObserver(); + let updateNotice = BDFDB.dotCN && document.querySelector(BDFDB.dotCN.noticeupdate); + if (updateNotice) updateNotice.close(); + BDFDB.TimeUtils.clear(PluginStores && PluginStores.updateData && PluginStores.updateData.interval); + delete window.BDFDB_Global.loaded; + if (PluginStores) BDFDB.TimeUtils.interval((interval, count) => { + if (count > 60 || window.BDFDB_Global.loaded) BDFDB.TimeUtils.clear(interval); + if (window.BDFDB_Global.loaded) for (let pluginName in BDFDB.ObjectUtils.sort(PluginStores.loaded)) BDFDB.TimeUtils.timeout(_ => { + if (PluginStores.loaded[pluginName].started) BDFDB.BDUtils.reloadPlugin(pluginName); + }); + }, 1000); + } + if (BDFDB.DOMUtils && BDFDB.DOMUtils.removeLocalStyle) BDFDB.DOMUtils.removeLocalStyle(plugin.name); + if (BDFDB.ListenerUtils && BDFDB.ListenerUtils.remove) BDFDB.ListenerUtils.remove(plugin); + if (BDFDB.ListenerUtils && BDFDB.ListenerUtils.removeGlobal) BDFDB.ListenerUtils.removeGlobal(plugin); + if (BDFDB.StoreChangeUtils && BDFDB.StoreChangeUtils.remove) BDFDB.StoreChangeUtils.remove(plugin); + if (BDFDB.ObserverUtils && BDFDB.ObserverUtils.disconnect) BDFDB.ObserverUtils.disconnect(plugin); + if (BDFDB.PatchUtils && BDFDB.PatchUtils.unpatch) BDFDB.PatchUtils.unpatch(plugin); + if (BDFDB.WindowUtils && BDFDB.WindowUtils.closeAll) BDFDB.WindowUtils.closeAll(plugin); + if (BDFDB.WindowUtils && BDFDB.WindowUtils.removeListener) BDFDB.WindowUtils.removeListener(plugin); + }, "Failed to clean up Plugin!", plugin)(); + }; + BDFDB.PluginUtils.checkUpdate = function (pluginName, url) { + if (pluginName && url && PluginStores.updateData.plugins[url]) return new Promise(callback => { + Internal.LibraryRequires.request(url, (error, response, body) => { + if (error || !PluginStores.updateData.plugins[url]) return callback(null); + let newName = (body.match(/"name"\s*:\s*"([^"]+)"/) || [])[1] || pluginName; + let newVersion = (body.match(/@version ([0-9]+\.[0-9]+\.[0-9]+)|['"]([0-9]+\.[0-9]+\.[0-9]+)['"]/i) || []).filter(n => n)[1]; + if (!newVersion) return callback(null); + if (pluginName == newName && BDFDB.NumberUtils.getVersionDifference(newVersion, PluginStores.updateData.plugins[url].version) > 0.2) { + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_force_updated", pluginName), { + type: "warning", + disableInteractions: true + }); + BDFDB.PluginUtils.downloadUpdate(pluginName, url); + return callback(2); + } + else if (BDFDB.NumberUtils.compareVersions(newVersion, PluginStores.updateData.plugins[url].version)) { + if (PluginStores.updateData.plugins[url]) PluginStores.updateData.plugins[url].outdated = true; + BDFDB.PluginUtils.showUpdateNotice(pluginName, url); + return callback(1); + } + else { + BDFDB.PluginUtils.removeUpdateNotice(pluginName); + return callback(0); + } + }); + }); + return new Promise(callback => callback(null)); + }; + BDFDB.PluginUtils.checkAllUpdates = function () { + return new Promise(callback => { + let finished = 0, amount = 0; + for (let url in PluginStores.updateData.plugins) { + let plugin = PluginStores.updateData.plugins[url]; + if (plugin) BDFDB.PluginUtils.checkUpdate(plugin.name, plugin.raw).then(state => { + finished++; + if (state == 1) amount++; + if (finished >= Object.keys(PluginStores.updateData.plugins).length) callback(amount); + }); + } + }); + }; + BDFDB.PluginUtils.hasUpdateCheck = function (url) { + if (!url || typeof url != "string") return false; + let updateStore = Object.assign({}, window.PluginUpdates && window.PluginUpdates.plugins, PluginStores.updateData.plugins); + if (updateStore[url]) return true; + else { + let temp = url.replace("//raw.githubusercontent.com", "//").split("/"); + let gitName = temp.splice(3, 1); + temp.splice(4, 1); + temp.splice(2, 1, gitName + ".github.io"); + let pagesUrl = temp.join("/"); + return !!updateStore[pagesUrl]; + } + }; + BDFDB.PluginUtils.showUpdateNotice = function (pluginName, url) { + if (!pluginName || !url) return; + let updateNotice = document.querySelector(BDFDB.dotCN.noticeupdate); + if (!updateNotice) { + let vanishObserver = new MutationObserver(changes => { + if (!document.contains(updateNotice)) { + if (updateNotice.querySelector(BDFDB.dotCN.noticeupdateentry)) { + let layers = document.querySelector(BDFDB.dotCN.layers) || document.querySelector(BDFDB.dotCN.appmount); + if (layers) layers.parentElement.insertBefore(updateNotice, layers); + } + else vanishObserver.disconnect(); + } + else if (document.contains(updateNotice) && !updateNotice.querySelector(BDFDB.dotCNC.noticeupdateentry + BDFDB.dotCN.noticebutton)) vanishObserver.disconnect(); + }); + vanishObserver.observe(document.body, {childList: true, subtree: true}); + updateNotice = BDFDB.NotificationUtils.notice(`${BDFDB.LanguageUtils.LibraryStrings.update_notice_update}    
`, { + type: "info", + className: BDFDB.disCN.noticeupdate, + html: true, + forceStyle: true, + customIcon: ``, + buttons: !BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.automaticLoading) && [{ + className: BDFDB.disCN.noticeupdatebuttonreload, + contents: BDFDB.LanguageUtils.LanguageStrings.ERRORS_RELOAD, + onClick: _ => location.reload(), + onMouseEnter: _ => { + if (PluginStores.updateData.downloaded) BDFDB.TooltipUtils.create(reloadButton, PluginStores.updateData.downloaded.join(", "), { + type: "bottom", + style: "max-width: 420px" + }); + } + }], + buttons: [{ + className: BDFDB.disCN.noticeupdatebuttonall, + contents: BDFDB.LanguageUtils.LanguageStrings.FORM_LABEL_ALL, + onClick: _ => {for (let notice of updateNotice.querySelectorAll(BDFDB.dotCN.noticeupdateentry)) notice.click();} + }], + onClose: _ => vanishObserver.disconnect() + }); + updateNotice.style.setProperty("position", "relative", "important"); + updateNotice.style.setProperty("visibility", "visible", "important"); + updateNotice.style.setProperty("opacity", "1", "important"); + updateNotice.style.setProperty("z-index", "100000", "important"); + let reloadButton = updateNotice.querySelector(BDFDB.dotCN.noticeupdatebuttonreload); + if (reloadButton) BDFDB.DOMUtils.hide(reloadButton); + } + if (updateNotice) { + let updateNoticeList = updateNotice.querySelector(BDFDB.dotCN.noticeupdateentries); + if (updateNoticeList && !updateNoticeList.querySelector(`#${pluginName}-notice`)) { + if (updateNoticeList.childElementCount) updateNoticeList.appendChild(BDFDB.DOMUtils.create(`
,
`)); + let updateEntry = BDFDB.DOMUtils.create(`
${pluginName}
`); + updateEntry.addEventListener("click", _ => { + if (!updateEntry.wasClicked) { + updateEntry.wasClicked = true; + BDFDB.PluginUtils.downloadUpdate(pluginName, url); + } + }); + updateNoticeList.appendChild(updateEntry); + if (!updateNoticeList.hasTooltip) { + updateNoticeList.hasTooltip = true; + updateNotice.tooltip = BDFDB.TooltipUtils.create(updateNoticeList, BDFDB.LanguageUtils.LibraryStrings.update_notice_click, { + type: "bottom", + zIndex: 100001, + delay: 500, + onHide: _ => {updateNoticeList.hasTooltip = false;} + }); + } + } + } + }; + BDFDB.PluginUtils.removeUpdateNotice = function (pluginName, updateNotice = document.querySelector(BDFDB.dotCN.noticeupdate)) { + if (!pluginName || !updateNotice) return; + let updateNoticeList = updateNotice.querySelector(BDFDB.dotCN.noticeupdateentries); + if (updateNoticeList) { + let noticeEntry = updateNoticeList.querySelector(`#${pluginName}-notice`); + if (noticeEntry) { + let nextSibling = noticeEntry.nextSibling; + let prevSibling = noticeEntry.prevSibling; + if (nextSibling && BDFDB.DOMUtils.containsClass(nextSibling, BDFDB.disCN.noticeupdateseparator)) nextSibling.remove(); + else if (prevSibling && BDFDB.DOMUtils.containsClass(prevSibling, BDFDB.disCN.noticeupdateseparator)) prevSibling.remove(); + noticeEntry.remove(); + } + if (!updateNoticeList.childElementCount) { + let reloadButton = updateNotice.querySelector(BDFDB.dotCN.noticeupdatebuttonreload); + if (reloadButton) { + updateNotice.querySelector(BDFDB.dotCN.noticetext).innerText = BDFDB.LanguageUtils.LibraryStrings.update_notice_reload; + BDFDB.DOMUtils.show(reloadButton); + } + else updateNotice.querySelector(BDFDB.dotCN.noticedismiss).click(); + } + } + }; + BDFDB.PluginUtils.downloadUpdate = function (pluginName, url) { + if (pluginName && url) Internal.LibraryRequires.request(url, (error, response, body) => { + if (error) { + BDFDB.PluginUtils.removeUpdateNotice(pluginName); + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_update_failed", pluginName), { + type: "danger", + disableInteractions: true + }); + } + else { + let wasEnabled = BDFDB.BDUtils.isPluginEnabled(pluginName); + let newName = (body.match(/"name"\s*:\s*"([^"]+)"/) || [])[1] || pluginName; + let newVersion = (body.match(/@version ([0-9]+\.[0-9]+\.[0-9]+)|['"]([0-9]+\.[0-9]+\.[0-9]+)['"]/i) || []).filter(n => n)[1]; + let oldVersion = PluginStores.updateData.plugins[url].version; + let fileName = pluginName == "BDFDB" ? "0BDFDB" : pluginName; + let newFileName = newName == "BDFDB" ? "0BDFDB" : newName; + Internal.LibraryRequires.fs.writeFile(Internal.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), newFileName + ".plugin.js"), body, _ => { + if (PluginStores.updateData.plugins[url]) PluginStores.updateData.plugins[url].version = newVersion; + if (fileName != newFileName) { + Internal.LibraryRequires.fs.unlink(Internal.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), fileName + ".plugin.js"), _ => {}); + let configPath = Internal.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), fileName + ".config.json"); + Internal.LibraryRequires.fs.exists(configPath, exists => { + if (exists) Internal.LibraryRequires.fs.rename(configPath, Internal.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), newFileName + ".config.json"), _ => {}); + }); + BDFDB.TimeUtils.timeout(_ => {if (wasEnabled && !BDFDB.BDUtils.isPluginEnabled(newName)) BDFDB.BDUtils.enablePlugin(newName);}, 3000); + } + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_updated", pluginName, "v" + oldVersion, newName, "v" + newVersion), { + disableInteractions: true + }); + let updateNotice = document.querySelector(BDFDB.dotCN.noticeupdate); + if (updateNotice) { + if (updateNotice.querySelector(BDFDB.dotCN.noticebutton) && !PluginStores.updateData.downloaded.includes(pluginName)) { + PluginStores.updateData.downloaded.push(pluginName); + } + BDFDB.PluginUtils.removeUpdateNotice(pluginName, updateNotice); + } + }); + } + }); + }; + BDFDB.PluginUtils.checkChangeLog = function (plugin) { + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ObjectUtils.is(plugin.changeLog)) return; + if (!changeLogs[plugin.name] || BDFDB.NumberUtils.compareVersions(plugin.version, changeLogs[plugin.name])) { + changeLogs[plugin.name] = plugin.version; + BDFDB.DataUtils.save(changeLogs, BDFDB, "changeLogs"); + BDFDB.PluginUtils.openChangeLog(plugin); + } + }; + BDFDB.PluginUtils.openChangeLog = function (plugin) { + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ObjectUtils.is(plugin.changeLog)) return; + let changeLogHTML = "", headers = { + added: "New Features", + fixed: "Bug Fixes", + improved: "Improvements", + progress: "Progress" + }; + for (let type in plugin.changeLog) { + type = type.toLowerCase(); + let className = BDFDB.disCN["changelog" + type]; + if (className) { + changeLogHTML += `

${BDFDB.LanguageUtils && BDFDB.LanguageUtils.LibraryStrings ? BDFDB.LanguageUtils.LibraryStrings["changelog_" + type] : headers[type]}

` + } + } + if (changeLogHTML) BDFDB.ModalUtils.open(plugin, { + header: `${plugin.name} ${BDFDB.LanguageUtils.LanguageStrings.CHANGE_LOG}`, + subHeader: `Version ${plugin.version}`, + className: BDFDB.disCN.modalchangelogmodal, + contentClassName: BDFDB.disCNS.changelogcontainer + BDFDB.disCN.modalminicontent, + footerDirection: Internal.LibraryComponents.Flex.Direction.HORIZONTAL, + children: BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(changeLogHTML)), + footerChildren: (plugin == BDFDB || plugin == libraryInstance || PluginStores.loaded[plugin.name] && PluginStores.loaded[plugin.name] == plugin && plugin.author == "DevilBro") && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.changelogfooter, + children: [{ + href: "https://www.paypal.me/MircoWittrien", + name: "PayPal", + icon: "PAYPAL" + }, { + href: "https://www.patreon.com/MircoWittrien", + name: "Patreon", + icon: "PATREON" + }, { + name: BDFDB.LanguageUtils.LibraryStringsFormat("send", "Solana"), + icon: "PHANTOM", + onClick: _ => { + BDFDB.LibraryRequires.electron.clipboard.write({text: InternalData.mySolana}); + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("clipboard_success", "Phantom Wallet Key"), { + type: "success" + }); + } + }, { + name: BDFDB.LanguageUtils.LibraryStringsFormat("send", "Ethereum"), + icon: "METAMASK", + onClick: _ => { + BDFDB.LibraryRequires.electron.clipboard.write({text: InternalData.myEthereum}); + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("clipboard_success", "MetaMask Wallet Key"), { + type: "success" + }); + } + }].map(data => BDFDB.ReactUtils.createElement(data.href ? Internal.LibraryComponents.Anchor : Internal.LibraryComponents.Clickable, { + className: BDFDB.disCN.changelogsociallink, + href: data.href || "", + onClick: !data.onClick ? (_ => {}) : data.onClick, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: data.name, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names[data.icon], + width: 16, + height: 16 + }) + }) + })).concat(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextElement, { + size: Internal.LibraryComponents.TextElement.Sizes.SIZE_12, + children: BDFDB.LanguageUtils.LibraryStrings.donate_message + })) + }) + }); + }; + BDFDB.PluginUtils.addLoadingIcon = function (icon) { + if (!Node.prototype.isPrototypeOf(icon)) return; + let app = document.querySelector(BDFDB.dotCN.app); + if (!app) return; + BDFDB.DOMUtils.addClass(icon, BDFDB.disCN.loadingicon); + let loadingIconWrapper = document.querySelector(BDFDB.dotCN.app + ">" + BDFDB.dotCN.loadingiconwrapper); + if (!loadingIconWrapper) { + loadingIconWrapper = BDFDB.DOMUtils.create(`
`); + app.appendChild(loadingIconWrapper); + let killObserver = new MutationObserver(changes => {if (!loadingIconWrapper.firstElementChild) BDFDB.DOMUtils.remove(loadingIconWrapper);}); + killObserver.observe(loadingIconWrapper, {childList: true}); + } + loadingIconWrapper.appendChild(icon); + }; + BDFDB.PluginUtils.createSettingsPanel = function (addon, props) { + if (!window.BDFDB_Global.loaded) return "Could not initiate BDFDB Library Plugin! Can not create Settings Panel!"; + addon = addon == BDFDB && Internal || addon; + if (!BDFDB.ObjectUtils.is(addon)) return; + let settingsProps = props; + if (settingsProps && !BDFDB.ObjectUtils.is(settingsProps) && (BDFDB.ReactUtils.isValidElement(settingsProps) || BDFDB.ArrayUtils.is(settingsProps))) settingsProps = { + children: settingsProps + }; + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsPanel, Object.assign({ + addon: addon, + collapseStates: settingsProps && settingsProps.collapseStates + }, settingsProps)); + }; + BDFDB.PluginUtils.refreshSettingsPanel = function (plugin, settingsPanel, ...args) { + if (BDFDB.ObjectUtils.is(plugin)) { + if (settingsPanel && settingsPanel.props && BDFDB.ObjectUtils.is(settingsPanel.props._instance)) { + settingsPanel.props._instance.props = Object.assign({}, settingsPanel.props._instance.props, ...args); + BDFDB.ReactUtils.forceUpdate(settingsPanel.props._instance); + } + else if (typeof plugin.getSettingsPanel == "function" && Node.prototype.isPrototypeOf(settingsPanel) && settingsPanel.parentElement) { + settingsPanel.parentElement.appendChild(plugin.getSettingsPanel(...args)); + settingsPanel.remove(); + } + } + }; + + window.BDFDB_Global = Object.assign({ + started: true, + loading: true, + PluginUtils: { + buildPlugin: BDFDB.PluginUtils.buildPlugin, + cleanUp: BDFDB.PluginUtils.cleanUp + } + }, config, window.BDFDB_Global); + + + const request = require("request"), fs = require("fs"), path = require("path"); + + Internal.writeConfig = function (plugin, path, config) { + let allData = {}; + try {allData = JSON.parse(fs.readFileSync(path));} + catch (err) {allData = {};} + try {fs.writeFileSync(path, JSON.stringify(Object.assign({}, allData, {[Internal.shouldSyncConfig(plugin) ? "all" : BDFDB.UserUtils.me.id]: config}), null, " "));} + catch (err) {} + }; + Internal.readConfig = function (plugin, path) { + let sync = Internal.shouldSyncConfig(plugin); + try { + let config = JSON.parse(fs.readFileSync(path)); + if (config && Object.keys(config).some(n => !(n == "all" || parseInt(n)))) { + config = {[Internal.shouldSyncConfig(plugin) ? "all" : BDFDB.UserUtils.me.id]: config}; + try {fs.writeFileSync(path, JSON.stringify(config, null, " "));} + catch (err) {} + } + return config && config[sync ? "all" : BDFDB.UserUtils.me.id] || {}; + } + catch (err) {return {};} + }; + Internal.shouldSyncConfig = function (plugin) { + return plugin.neverSyncData !== undefined ? !plugin.neverSyncData : (plugin.forceSyncData || Internal.settings.general.shareData); + }; + + BDFDB.DataUtils = {}; + BDFDB.DataUtils.save = function (data, plugin, key, id) { + plugin = plugin == BDFDB && Internal || plugin; + let pluginName = typeof plugin === "string" ? plugin : plugin.name; + let fileName = pluginName == "BDFDB" ? "0BDFDB" : pluginName; + let configPath = path.join(BDFDB.BDUtils.getPluginsFolder(), fileName + ".config.json"); + + let config = Cache.data[pluginName] !== undefined ? Cache.data[pluginName] : (Internal.readConfig(plugin, configPath) || {}); + + if (key === undefined) config = BDFDB.ObjectUtils.is(data) ? BDFDB.ObjectUtils.sort(data) : data; + else { + if (id === undefined) config[key] = BDFDB.ObjectUtils.is(data) ? BDFDB.ObjectUtils.sort(data) : data; + else { + if (!BDFDB.ObjectUtils.is(config[key])) config[key] = {}; + config[key][id] = BDFDB.ObjectUtils.is(data) ? BDFDB.ObjectUtils.sort(data) : data; + } + } + + let configIsObject = BDFDB.ObjectUtils.is(config); + if (key !== undefined && configIsObject && BDFDB.ObjectUtils.is(config[key]) && BDFDB.ObjectUtils.isEmpty(config[key])) delete config[key]; + if (BDFDB.ObjectUtils.isEmpty(config)) { + delete Cache.data[pluginName]; + if (fs.existsSync(configPath)) fs.unlinkSync(configPath); + } + else { + if (configIsObject) config = BDFDB.ObjectUtils.sort(config); + Cache.data[pluginName] = configIsObject ? BDFDB.ObjectUtils.deepAssign({}, config) : config; + Internal.writeConfig(plugin, configPath, config); + } + }; + + BDFDB.DataUtils.load = function (plugin, key, id) { + plugin = plugin == BDFDB && Internal || plugin; + let pluginName = typeof plugin === "string" ? plugin : plugin.name; + let fileName = pluginName == "BDFDB" ? "0BDFDB" : pluginName; + let configPath = path.join(BDFDB.BDUtils.getPluginsFolder(), fileName + ".config.json"); + + let config = Cache.data[pluginName] !== undefined ? Cache.data[pluginName] : (Internal.readConfig(plugin, configPath) || {}); + let configIsObject = BDFDB.ObjectUtils.is(config); + Cache.data[pluginName] = configIsObject ? BDFDB.ObjectUtils.deepAssign({}, config) : config; + + if (key === undefined) return config; + else { + let keyData = configIsObject ? (BDFDB.ObjectUtils.is(config[key]) || config[key] === undefined ? BDFDB.ObjectUtils.deepAssign({}, config[key]) : config[key]) : null; + if (id === undefined) return keyData; + else return !BDFDB.ObjectUtils.is(keyData) || keyData[id] === undefined ? null : keyData[id]; + } + }; + BDFDB.DataUtils.remove = function (plugin, key, id) { + plugin = plugin == BDFDB && Internal || plugin; + let pluginName = typeof plugin === "string" ? plugin : plugin.name; + let fileName = pluginName == "BDFDB" ? "0BDFDB" : pluginName; + let configPath = path.join(BDFDB.BDUtils.getPluginsFolder(), fileName + ".config.json"); + + let config = Cache.data[pluginName] !== undefined ? Cache.data[pluginName] : (Internal.readConfig(plugin, configPath) || {}); + let configIsObject = BDFDB.ObjectUtils.is(config); + + if (key === undefined || !configIsObject) config = {}; + else { + if (id === undefined) delete config[key]; + else if (BDFDB.ObjectUtils.is(config[key])) delete config[key][id]; + } + + if (BDFDB.ObjectUtils.is(config[key]) && BDFDB.ObjectUtils.isEmpty(config[key])) delete config[key]; + if (BDFDB.ObjectUtils.isEmpty(config)) { + delete Cache.data[pluginName]; + if (fs.existsSync(configPath)) fs.unlinkSync(configPath); + } + else { + if (configIsObject) config = BDFDB.ObjectUtils.sort(config); + Cache.data[pluginName] = configIsObject ? BDFDB.ObjectUtils.deepAssign({}, config) : config; + Internal.writeConfig(plugin, configPath, config); + } + }; + BDFDB.DataUtils.get = function (plugin, key, id) { + plugin = plugin == BDFDB && Internal || plugin; + plugin = typeof plugin == "string" ? BDFDB.BDUtils.getPlugin(plugin) : plugin; + const defaults = plugin && plugin.defaults; + if (!BDFDB.ObjectUtils.is(defaults) || key && !BDFDB.ObjectUtils.is(defaults[key])) return id === undefined ? {} : null; + let oldC = BDFDB.DataUtils.load(plugin), newC = {}, update = false; + const checkLayer = (i, j) => { + let isObj = BDFDB.ObjectUtils.is(defaults[i][j].value); + if (!newC[i]) newC[i] = {}; + if (oldC[i] == null || oldC[i][j] == null || isObj && (!BDFDB.ObjectUtils.is(oldC[i][j]) || Object.keys(defaults[i][j].value).some(n => defaults[i][j].value[n] != null && !BDFDB.sameProto(defaults[i][j].value[n], oldC[i][j][n])))) { + newC[i][j] = isObj ? BDFDB.ObjectUtils.deepAssign({}, defaults[i][j].value) : defaults[i][j].value; + update = true; + } + else newC[i][j] = oldC[i][j]; + }; + if (key) {for (let j in defaults[key]) checkLayer(key, j);} + else {for (let i in defaults) if (BDFDB.ObjectUtils.is(defaults[i])) for (let j in defaults[i]) checkLayer(i, j);} + if (update) BDFDB.DataUtils.save(Object.assign({}, oldC, newC), plugin); + + if (key === undefined) return newC; + else if (id === undefined) return newC[key] === undefined ? {} : newC[key]; + else return newC[key] === undefined || newC[key][id] === undefined ? null : newC[key][id]; + }; + + const cssFileName = "0BDFDB.raw.css"; + const dataFileName = "0BDFDB.data.json"; + const cssFilePath = path.join(BDFDB.BDUtils.getPluginsFolder(), cssFileName); + const dataFilePath = path.join(BDFDB.BDUtils.getPluginsFolder(), dataFileName); + let InternalData, libHashes = {}, oldLibHashes = BDFDB.DataUtils.load(BDFDB, "hashes"), libraryCSS; + + const getBackup = (fileName, path) => { + return libHashes[fileName] && oldLibHashes[fileName] && libHashes[fileName] == oldLibHashes[fileName] && fs.existsSync(path) && (fs.readFileSync(path) || "").toString(); + }; + const requestLibraryHashes = tryAgain => { + request("https://api.github.com/repos/mwittrien/BetterDiscordAddons/contents/Library/_res/", {headers: {"user-agent": "node.js"}}, (e, r, b) => { + if ((e || !b || r.statusCode != 200) && tryAgain) return BDFDB.TimeUtils.timeout(_ => requestLibraryHashes(), 10000); + try { + b = JSON.parse(b); + libHashes[cssFileName] = (b.find(n => n && n.name == cssFileName) || {}).sha; + libHashes[dataFileName] = (b.find(n => n && n.name == dataFileName) || {}).sha; + BDFDB.DataUtils.save(libHashes, BDFDB, "hashes") + requestLibraryData(true); + } + catch (err) {requestLibraryData(true);} + }); + }; + const requestLibraryData = tryAgain => { + const parseCSS = css => { + libraryCSS = css; + + const backupData = getBackup(dataFileName, dataFilePath); + if (backupData) parseData(backupData); + else request.get(`https://mwittrien.github.io/BetterDiscordAddons/Library/_res/${dataFileName}`, (e, r, b) => { + if ((e || !b || r.statusCode != 200) && tryAgain) return BDFDB.TimeUtils.timeout(_ => requestLibraryData(), 10000); + if (!e && b && r.statusCode == 200) parseData(b, true); + else parseData(fs.existsSync(dataFilePath) && (fs.readFileSync(dataFilePath) || "").toString()); + }); + }; + const parseData = (dataString, fetched) => { + try {InternalData = JSON.parse(dataString);} + catch (err) { + if (fetched) { + try { + dataString = fs.existsSync(dataFilePath) && (fs.readFileSync(dataFilePath) || "").toString(); + InternalData = JSON.parse(dataString); + } + catch (err2) {BDFDB.LogUtils.error(["Failed to initiate Library!", "Failed Fetch!", dataString ? "Corrupt Backup." : "No Backup.", , err2]);} + } + else BDFDB.LogUtils.error(["Failed to initiate Library!", dataString ? "Corrupt Backup." : "No Backup.", err]); + } + if (fetched && dataString) fs.writeFile(dataFilePath, dataString, _ => {}); + + Internal.getWebModuleReq = function () { + if (!Internal.getWebModuleReq.req) { + const id = "BDFDB-WebModules"; + const req = window.webpackJsonp.push([[], {[id]: (module, exports, req) => module.exports = req}, [[id]]]); + delete req.m[id]; + delete req.c[id]; + Internal.getWebModuleReq.req = req; + } + return Internal.getWebModuleReq.req; + }; + + if (InternalData) loadLibrary(); + else BdApi.alert("Error", "Could not initiate BDFDB Library Plugin. Check your Internet Connection and make sure GitHub isn't blocked by your Network or try disabling your VPN/Proxy."); + }; + + const backupCSS = getBackup(cssFileName, cssFilePath); + if (backupCSS) parseCSS(backupCSS); + else request.get(`https://mwittrien.github.io/BetterDiscordAddons/Library/_res/${cssFileName}`, (e, r, b) => { + if ((e || !b || r.statusCode != 200) && tryAgain) return BDFDB.TimeUtils.timeout(_ => requestLibraryData(), 10000); + if (!e && b && r.statusCode == 200) { + fs.writeFile(cssFilePath, b, _ => {}); + parseCSS(b); + } + else parseCSS(fs.existsSync(cssFilePath) && (fs.readFileSync(cssFilePath) || "").toString()); + }); + }; + const loadLibrary = _ => { + InternalData.UserBackgrounds = {}; + if (InternalData.userBackgroundsUrl && InternalData.userBackgroundsProperties) request(InternalData.userBackgroundsUrl, (e3, r3, b3) => { + if (!e3 && b3 && r3.statusCode == 200) { + const log = BDFDB.UserUtils.me.id == InternalData.myId || BDFDB.UserUtils.me.id == "350635509275557888", notUsedValues = []; + try { + InternalData.UserBackgrounds = JSON.parse(b3); + for (let id in InternalData.UserBackgrounds) { + let user = {}; + for (let key in InternalData.UserBackgrounds[id]) { + if (InternalData.userBackgroundsProperties[key]) user[InternalData.userBackgroundsProperties[key]] = key == "background" ? `url(${InternalData.UserBackgrounds[id][key]})` : InternalData.UserBackgrounds[id][key]; + else if (log && !notUsedValues.includes(key)) notUsedValues.push(key); + } + InternalData.UserBackgrounds[id] = user; + } + if (notUsedValues.length) BDFDB.LogUtils.warn(["Found unused variables in usrbgs!", notUsedValues]); + } + catch (err) { + InternalData.UserBackgrounds = {}; + if (log) BDFDB.LogUtils.error(["Could not load usrbgs!", err]); + } + } + }); + + Internal.getPluginURL = function (plugin) { + plugin = plugin == BDFDB && Internal || plugin; + if (BDFDB.ObjectUtils.is(plugin)) { + if (plugin.rawUrl) return plugin.rawUrl; + else { + let name = InternalData.PluginNameMap && InternalData.PluginNameMap[plugin.name] || plugin.name; + return `https://mwittrien.github.io/BetterDiscordAddons/Plugins/${name}/${name}.plugin.js`; + } + } + else return ""; + }; + + Internal.findModule = function (type, cacheString, filter, useExport, noWarnings = false) { + if (!BDFDB.ObjectUtils.is(Cache.modules[type])) Cache.modules[type] = {module: {}, export: {}}; + if (useExport && Cache.modules[type].export[cacheString]) return Cache.modules[type].export[cacheString]; + else if (!useExport && Cache.modules[type].module[cacheString]) return Cache.modules[type].module[cacheString]; + else { + let m = BDFDB.ModuleUtils.find(filter, {useExport: useExport}); + if (m) { + if (useExport) Cache.modules[type].export[cacheString] = m; + else Cache.modules[type].module[cacheString] = m; + return m; + } + else if (!noWarnings) BDFDB.LogUtils.warn(`${cacheString} [${type}] not found in WebModules`); + } + }; + + Internal.hasModuleStrings = function (module, strings, ignoreCase) { + const toString = n => ignoreCase ? n.toString().toLowerCase() : n.toString(); + return [strings].flat(10).filter(n => typeof n == "string").map(ignoreCase ? (n => n.toLowerCase()) : (n => n)).every(string => typeof module == "function" && (toString(module).indexOf(string) > -1 || typeof module.__originalMethod == "function" && toString(module.__originalMethod).indexOf(string) > -1 || typeof module.__originalFunction == "function" && toString(module.__originalFunction).indexOf(string) > -1) || BDFDB.ObjectUtils.is(module) && typeof module.type == "function" && toString(module.type).indexOf(string) > -1); + }; + + Internal.getModuleString = function (module) { + const id = (BDFDB.ModuleUtils.find(m => m == module && m, {useExport: false}) || {}).id; + if (!id) return ""; + const req = Internal.getWebModuleReq(); + return (req.m[id] || "").toString(); + }; + + Internal.lazyLoadModuleImports = function (moduleString) { + return new Promise(callback => { + if (typeof moduleString !== "string") moduleString = Internal.getModuleString(moduleString); + if (!moduleString || typeof moduleString !== "string") { + BDFDB.LogUtils.error("Trying to lazy load Imports but Module is not a String"); + return callback(null); + } + let run = true, imports = [], menuIndexes = []; + while (run) { + const [matchString, promiseMatch, menuRequest] = moduleString.match(/return (Promise\.all\(.+?\))\.then\((.+?)\)\)/) ?? []; + if (!promiseMatch) run = false; + else { + imports = imports.concat(promiseMatch.match(/\d+/g)?.map(e => Number(e))); + menuIndexes.push(menuRequest.match(/\d+/)?.[0]); + moduleString = moduleString.replace(matchString, ""); + } + } + if (!imports.length || !menuIndexes.length) { + BDFDB.LogUtils.error("Trying to lazy load Imports but could not find Indexes"); + return callback(null); + } + const req = Internal.getWebModuleReq(); + Promise.all(BDFDB.ArrayUtils.removeCopies(imports).map(i => req.e(i))).then(_ => Promise.all(BDFDB.ArrayUtils.removeCopies(menuIndexes).map(i => req(i)))).then(callback); + }); + }; + + BDFDB.ModuleUtils = {}; + BDFDB.ModuleUtils.find = function (filter, config = {}) { + let useExport = typeof config.useExport != "boolean" ? true : config.useExport; + let onlySearchUnloaded = typeof config.onlySearchUnloaded != "boolean" ? false : config.onlySearchUnloaded; + let all = typeof config.all != "boolean" ? false : config.all; + const req = Internal.getWebModuleReq(); + const found = []; + if (!onlySearchUnloaded) for (let i in req.c) if (req.c.hasOwnProperty(i)) { + let m = req.c[i].exports, r = null; + if (m && (typeof m == "object" || typeof m == "function") && !!(r = filter(m))) { + if (all) found.push(useExport ? r : req.c[i]); + else return useExport ? r : req.c[i]; + } + if (m && m.__esModule && m.default && (typeof m.default == "object" || typeof m.default == "function")) { + if (!!(r = filter(m.default))) { + if (all) found.push(useExport ? r : req.c[i]); + else return useExport ? r : req.c[i]; + } + else if (m.default.type && (typeof m.default.type == "object" || typeof m.default.type == "function") && !!(r = filter(m.default.type))) { + if (all) found.push(useExport ? r : req.c[i]); + else return useExport ? r : req.c[i]; + } + } + } + for (let i in req.m) if (req.m.hasOwnProperty(i)) { + let m = req.m[i]; + if (m && typeof m == "function") { + if (req.c[i] && !onlySearchUnloaded && filter(m)) { + if (all) found.push(useExport ? req.c[i].exports : req.c[i]); + else return useExport ? req.c[i].exports : req.c[i]; + } + if (!req.c[i] && onlySearchUnloaded && filter(m)) { + const resolved = {}, resolved2 = {}; + m(resolved, resolved2, req); + const trueResolved = resolved2 && BDFDB.ObjectUtils.isEmpty(resolved2) ? resolved : resolved2; + if (all) found.push(useExport ? trueResolved.exports : trueResolved); + else return useExport ? trueResolved.exports : trueResolved; + } + } + } + if (all) return found; + }; + BDFDB.ModuleUtils.findByProperties = function (...properties) { + properties = properties.flat(10); + let arg2 = properties.pop(); + let arg1 = properties.pop(); + let useExport = true, noWarnings = false; + if (typeof arg2 != "boolean") properties.push(...[arg1, arg2].filter(n => n)); + else { + if (typeof arg1 != "boolean") { + if (arg1) properties.push(arg1); + useExport = arg2; + } + else { + useExport = arg1; + noWarnings = arg2; + } + } + return Internal.findModule("prop", JSON.stringify(properties), m => properties.every(prop => { + const value = m[prop]; + return value !== undefined && !(typeof value == "string" && !value); + }) && m, useExport, noWarnings); + }; + BDFDB.ModuleUtils.findByName = function (name, useExport, noWarnings = false) { + return Internal.findModule("name", JSON.stringify(name), m => m.displayName === name && m || m.render && m.render.displayName === name && m || m.constructor && m.constructor.displayName === name && m || m[name] && m[name].displayName === name && m[name], typeof useExport != "boolean" ? true : useExport, noWarnings); + }; + BDFDB.ModuleUtils.findByString = function (...strings) { + strings = strings.flat(10); + let arg2 = strings.pop(); + let arg1 = strings.pop(); + let useExport = true, noWarnings = false; + if (typeof arg2 != "boolean") strings.push(...[arg1, arg2].filter(n => n)); + else { + if (typeof arg1 != "boolean") { + if (arg1) strings.push(arg1); + useExport = arg2; + } + else { + useExport = arg1; + noWarnings = arg2; + } + } + return Internal.findModule("string", JSON.stringify(strings), m => Internal.hasModuleStrings(m, strings) && m, useExport, noWarnings); + }; + BDFDB.ModuleUtils.findByPrototypes = function (...protoProps) { + protoProps = protoProps.flat(10); + let arg2 = protoProps.pop(); + let arg1 = protoProps.pop(); + let useExport = true, noWarnings = false; + if (typeof arg2 != "boolean") protoProps.push(...[arg1, arg2].filter(n => n)); + else { + if (typeof arg1 != "boolean") { + if (arg1) protoProps.push(arg1); + useExport = arg2; + } + else { + useExport = arg1; + noWarnings = arg2; + } + } + return Internal.findModule("proto", JSON.stringify(protoProps), m => m.prototype && protoProps.every(prop => { + const value = m.prototype[prop]; + return value !== undefined && !(typeof value == "string" && !value); + }) && m, useExport, noWarnings); + }; + BDFDB.ModuleUtils.findStringObject = function (props, config = {}) { + return BDFDB.ModuleUtils.find(m => { + let amount = Object.keys(m).length; + return (!config.length || (config.smaller ? amount < config.length : amount == config.length)) && [props].flat(10).every(prop => typeof m[prop] == "string") && m; + }) || BDFDB.ModuleUtils.find(m => { + if (typeof m != "function") return false; + let stringified = m.toString().replace(/\s/g, ""); + if (stringified.indexOf("e=>{e.exports={") != 0) return false; + let amount = stringified.split(":\"").length - 1; + return (!config.length || (config.smaller ? amount < config.length : amount == config.length)) && [props].flat(10).every(string => stringified.indexOf(`${string}:`) > -1) && m; + }, {onlySearchUnloaded: true}); + }; + + BDFDB.ObserverUtils = {}; + BDFDB.ObserverUtils.connect = function (plugin, eleOrSelec, observer, config = {childList: true}) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !eleOrSelec || !observer) return; + if (BDFDB.ObjectUtils.isEmpty(plugin.observers)) plugin.observers = {}; + if (!BDFDB.ArrayUtils.is(plugin.observers[observer.name])) plugin.observers[observer.name] = []; + if (!observer.multi) for (let subinstance of plugin.observers[observer.name]) subinstance.disconnect(); + if (observer.instance) plugin.observers[observer.name].push(observer.instance); + let instance = plugin.observers[observer.name][plugin.observers[observer.name].length - 1]; + if (instance) { + let node = Node.prototype.isPrototypeOf(eleOrSelec) ? eleOrSelec : typeof eleOrSelec === "string" ? document.querySelector(eleOrSelec) : null; + if (node) instance.observe(node, config); + } + }; + BDFDB.ObserverUtils.disconnect = function (plugin, observer) { + plugin = plugin == BDFDB && Internal || plugin; + if (BDFDB.ObjectUtils.is(plugin) && !BDFDB.ObjectUtils.isEmpty(plugin.observers)) { + let observername = typeof observer == "string" ? observer : (BDFDB.ObjectUtils.is(observer) ? observer.name : null); + if (!observername) { + for (let observer in plugin.observers) for (let instance of plugin.observers[observer]) instance.disconnect(); + delete plugin.observers; + } + else if (!BDFDB.ArrayUtils.is(plugin.observers[observername])) { + for (let instance of plugin.observers[observername]) instance.disconnect(); + delete plugin.observers[observername]; + } + } + }; + + BDFDB.StoreChangeUtils = {}; + BDFDB.StoreChangeUtils.add = function (plugin, store, callback) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ObjectUtils.is(store) || typeof store.addChangeListener != "function" || typeof callback != "function") return; + BDFDB.StoreChangeUtils.remove(plugin, store, callback); + if (!BDFDB.ArrayUtils.is(plugin.changeListeners)) plugin.changeListeners = []; + plugin.changeListeners.push({store, callback}); + store.addChangeListener(callback); + }; + BDFDB.StoreChangeUtils.remove = function (plugin, store, callback) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ArrayUtils.is(plugin.changeListeners)) return; + if (!store) { + while (plugin.changeListeners.length) { + let listener = plugin.changeListeners.pop(); + listener.store.removeChangeListener(listener.callback); + } + } + else if (BDFDB.ObjectUtils.is(store) && typeof store.addChangeListener == "function") { + if (!callback) { + for (let listener of plugin.changeListeners) { + let removedListeners = []; + if (listener.store == store) { + listener.store.removeChangeListener(listener.callback); + removedListeners.push(listener); + } + if (removedListeners.length) plugin.changeListeners = plugin.changeListeners.filter(listener => !removedListeners.includes(listener)); + } + } + else if (typeof callback == "function") { + store.removeChangeListener(callback); + plugin.changeListeners = plugin.changeListeners.filter(listener => listener.store == store && listener.callback == callback); + } + } + }; + + var pressedKeys = [], mousePosition; + BDFDB.ListenerUtils = {}; + BDFDB.ListenerUtils.isPressed = function (key) { + return pressedKeys.includes(key); + }; + BDFDB.ListenerUtils.getPosition = function (key) { + return mousePosition; + }; + BDFDB.ListenerUtils.add = function (plugin, ele, actions, selectorOrCallback, callbackOrNothing) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || (!Node.prototype.isPrototypeOf(ele) && ele !== window) || !actions) return; + let callbackIs4th = typeof selectorOrCallback == "function"; + let selector = callbackIs4th ? undefined : selectorOrCallback; + let callback = callbackIs4th ? selectorOrCallback : callbackOrNothing; + if (typeof callback != "function") return; + BDFDB.ListenerUtils.remove(plugin, ele, actions, selector); + for (let action of actions.split(" ")) { + action = action.split("."); + let eventName = action.shift().toLowerCase(); + if (!eventName) return; + let origEventName = eventName; + eventName = eventName == "mouseenter" || eventName == "mouseleave" ? "mouseover" : eventName; + let namespace = (action.join(".") || "") + plugin.name; + if (!BDFDB.ArrayUtils.is(plugin.eventListeners)) plugin.eventListeners = []; + let eventCallback = null; + if (selector) { + if (origEventName == "mouseenter" || origEventName == "mouseleave") eventCallback = e => { + for (let child of e.path) if (typeof child.matches == "function" && child.matches(selector) && !child[namespace + "BDFDB" + origEventName]) { + child[namespace + "BDFDB" + origEventName] = true; + if (origEventName == "mouseenter") callback(BDFDB.ListenerUtils.copyEvent(e, child)); + let mouseOut = e2 => { + if (e2.target.contains(child) || e2.target == child || !child.contains(e2.target)) { + if (origEventName == "mouseleave") callback(BDFDB.ListenerUtils.copyEvent(e, child)); + delete child[namespace + "BDFDB" + origEventName]; + document.removeEventListener("mouseout", mouseOut); + } + }; + document.addEventListener("mouseout", mouseOut); + break; + } + }; + else eventCallback = e => { + for (let child of e.path) if (typeof child.matches == "function" && child.matches(selector)) { + callback(BDFDB.ListenerUtils.copyEvent(e, child)); + break; + } + }; + } + else eventCallback = e => callback(BDFDB.ListenerUtils.copyEvent(e, ele)); + + let observer; + if (Node.prototype.isPrototypeOf(ele)) { + observer = new MutationObserver(changes => changes.forEach(change => { + const nodes = Array.from(change.removedNodes); + if (nodes.indexOf(ele) > -1 || nodes.some(n => n.contains(ele))) BDFDB.ListenerUtils.remove(plugin, ele, actions, selector); + })); + observer.observe(document.body, {subtree: true, childList: true}); + } + + plugin.eventListeners.push({ele, eventName, origEventName, namespace, selector, eventCallback, observer}); + ele.addEventListener(eventName, eventCallback, true); + } + }; + BDFDB.ListenerUtils.remove = function (plugin, ele, actions = "", selector) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ArrayUtils.is(plugin.eventListeners)) return; + if (!ele) { + while (plugin.eventListeners.length) { + let listener = plugin.eventListeners.pop(); + listener.ele.removeEventListener(listener.eventName, listener.eventCallback, true); + if (listener.observer) listener.observer.disconnect(); + } + } + else if (Node.prototype.isPrototypeOf(ele) || ele === window) { + for (let action of actions.split(" ")) { + action = action.split("."); + let eventName = action.shift().toLowerCase(); + let namespace = (action.join(".") || "") + plugin.name; + for (let listener of plugin.eventListeners) { + let removedListeners = []; + if (listener.ele == ele && (!eventName || listener.origEventName == eventName) && listener.namespace == namespace && (selector === undefined || listener.selector == selector)) { + listener.ele.removeEventListener(listener.eventName, listener.eventCallback, true); + if (listener.observer) listener.observer.disconnect(); + removedListeners.push(listener); + } + if (removedListeners.length) plugin.eventListeners = plugin.eventListeners.filter(listener => !removedListeners.includes(listener)); + } + } + } + }; + BDFDB.ListenerUtils.addGlobal = function (plugin, id, keybind, action) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !id || !BDFDB.ArrayUtils.is(keybind) || typeof action != "function") return; + if (!BDFDB.ObjectUtils.is(plugin.globalKeybinds)) plugin.globalKeybinds = {}; + BDFDB.ListenerUtils.removeGlobal(plugin, id); + plugin.globalKeybinds[id] = BDFDB.NumberUtils.generateId(Object.entries(plugin.globalKeybinds).map(n => n[1])); + BDFDB.LibraryModules.WindowUtils.inputEventRegister(plugin.globalKeybinds[id], keybind.map(n => [0, n]), action, {blurred: true, focused: true, keydown: false, keyup: true}); + return (_ => BDFDB.ListenerUtils.removeGlobal(plugin, id)); + }; + BDFDB.ListenerUtils.removeGlobal = function (plugin, id) { + if (!BDFDB.ObjectUtils.is(plugin) || !plugin.globalKeybinds) return; + if (!id) { + for (let cachedId in plugin.globalKeybinds) BDFDB.LibraryModules.WindowUtils.inputEventUnregister(plugin.globalKeybinds[cachedId]); + plugin.globalKeybinds = {}; + } + else { + BDFDB.LibraryModules.WindowUtils.inputEventUnregister(plugin.globalKeybinds[id]); + delete plugin.globalKeybinds[id]; + } + }; + BDFDB.ListenerUtils.multiAdd = function (node, actions, callback) { + if (!Node.prototype.isPrototypeOf(node) || !actions || typeof callback != "function") return; + for (let action of actions.trim().split(" ").filter(n => n)) node.addEventListener(action, callback, true); + }; + BDFDB.ListenerUtils.multiRemove = function (node, actions, callback) { + if (!Node.prototype.isPrototypeOf(node) || !actions || typeof callback != "function") return; + for (let action of actions.trim().split(" ").filter(n => n)) node.removeEventListener(action, callback, true); + }; + BDFDB.ListenerUtils.addToChildren = function (node, actions, selector, callback) { + if (!Node.prototype.isPrototypeOf(node) || !actions || !selector || !selector.trim() || typeof callback != "function") return; + for (let action of actions.trim().split(" ").filter(n => n)) { + let eventCallback = callback; + if (action == "mouseenter" || action == "mouseleave") eventCallback = e => {if (e.target.matches(selector)) callback(e);}; + node.querySelectorAll(selector.trim()).forEach(child => {child.addEventListener(action, eventCallback, true);}); + } + }; + BDFDB.ListenerUtils.copyEvent = function (e, ele) { + if (!e || !e.constructor || !e.type) return e; + let eCopy = new e.constructor(e.type, e); + Object.defineProperty(eCopy, "originalEvent", {value: e}); + Object.defineProperty(eCopy, "which", {value: e.which}); + Object.defineProperty(eCopy, "keyCode", {value: e.keyCode}); + Object.defineProperty(eCopy, "path", {value: e.path}); + Object.defineProperty(eCopy, "relatedTarget", {value: e.relatedTarget}); + Object.defineProperty(eCopy, "srcElement", {value: e.srcElement}); + Object.defineProperty(eCopy, "target", {value: e.target}); + Object.defineProperty(eCopy, "toElement", {value: e.toElement}); + if (ele) Object.defineProperty(eCopy, "currentTarget", {value: ele}); + return eCopy; + }; + BDFDB.ListenerUtils.stopEvent = function (e) { + if (BDFDB.ObjectUtils.is(e)) { + if (typeof e.preventDefault == "function") e.preventDefault(); + if (typeof e.stopPropagation == "function") e.stopPropagation(); + if (typeof e.stopImmediatePropagation == "function") e.stopImmediatePropagation(); + if (BDFDB.ObjectUtils.is(e.originalEvent)) { + if (typeof e.originalEvent.preventDefault == "function") e.originalEvent.preventDefault(); + if (typeof e.originalEvent.stopPropagation == "function") e.originalEvent.stopPropagation(); + if (typeof e.originalEvent.stopImmediatePropagation == "function") e.originalEvent.stopImmediatePropagation(); + } + } + }; + + var Toasts = [], NotificationBars = []; + var ToastQueues = {}, DesktopNotificationQueue = {queue: [], running: false}; + for (let key in LibraryConstants.ToastPositions) ToastQueues[LibraryConstants.ToastPositions[key]] = {queue: [], full: false}; + + BDFDB.NotificationUtils = {}; + BDFDB.NotificationUtils.toast = function (children, config = {}) { + if (!children) return; + let app = document.querySelector(BDFDB.dotCN.appmount) || document.body; + if (!app) return; + let position = config.position && LibraryConstants.ToastPositions[config.position] || Internal.settings.choices.toastPosition && LibraryConstants.ToastPositions[Internal.settings.choices.toastPosition] || LibraryConstants.ToastPositions.right; + + const runQueue = _ => { + if (ToastQueues[position].full) return; + let data = ToastQueues[position].queue.shift(); + if (!data) return; + + let id = BDFDB.NumberUtils.generateId(Toasts); + let toasts = document.querySelector(BDFDB.dotCN.toasts + BDFDB.dotCN[position]); + if (!toasts) { + toasts = BDFDB.DOMUtils.create(`
`); + app.appendChild(toasts); + } + + if (data.config.id) data.toast.id = data.config.id.split(" ").join(""); + if (data.config.className) BDFDB.DOMUtils.addClass(data.toast, data.config.className); + if (data.config.css) BDFDB.DOMUtils.appendLocalStyle("BDFDBcustomToast" + id, data.config.css); + if (data.config.style) data.toast.style = Object.assign({}, data.toast.style, data.config.style); + + let backgroundColor, fontColor, barColor; + + let type = data.config.type && BDFDB.disCN["toast" + data.config.type]; + if (!type) { + barColor = BDFDB.ColorUtils.getType(data.config.barColor) ? BDFDB.ColorUtils.convert(data.config.barColor, "HEX") : data.config.barColor; + let comp = BDFDB.ColorUtils.convert(data.config.color, "RGBCOMP"); + if (comp) { + backgroundColor = BDFDB.ColorUtils.convert(comp, "HEX"); + fontColor = comp[0] > 180 && comp[1] > 180 && comp[2] > 180 ? "#000" : "#FFF"; + BDFDB.DOMUtils.addClass(data.toast, BDFDB.disCN.toastcustom); + } + else BDFDB.DOMUtils.addClass(data.toast, BDFDB.disCN.toastdefault); + } + else BDFDB.DOMUtils.addClass(data.toast, type); + + let loadingInterval; + let disableInteractions = data.config.disableInteractions && typeof data.config.onClick != "function"; + let timeout = typeof data.config.timeout == "number" && !disableInteractions ? data.config.timeout : 3000; + timeout = (timeout > 0 ? timeout : 600000) + 300; + if (data.config.ellipsis && typeof data.children == "string") loadingInterval = BDFDB.TimeUtils.interval(_ => data.toast.update(data.children.endsWith(".....") ? data.children.slice(0, -5) : data.children + "."), 500); + + let closeTimeout = BDFDB.TimeUtils.timeout(_ => data.toast.close(), timeout); + data.toast.close = _ => { + BDFDB.TimeUtils.clear(closeTimeout); + if (document.contains(data.toast)) { + BDFDB.DOMUtils.addClass(data.toast, BDFDB.disCN.toastclosing); + data.toast.style.setProperty("pointer-events", "none", "important"); + BDFDB.TimeUtils.timeout(_ => { + if (typeof data.config.onClose == "function") data.config.onClose(); + BDFDB.TimeUtils.clear(loadingInterval); + BDFDB.ArrayUtils.remove(Toasts, id); + BDFDB.DOMUtils.removeLocalStyle("BDFDBcustomToast" + id); + data.toast.remove(); + if (!toasts.querySelectorAll(BDFDB.dotCN.toast).length) toasts.remove(); + }, 300); + } + ToastQueues[position].full = false; + runQueue(); + }; + + if (disableInteractions) data.toast.style.setProperty("pointer-events", "none", "important"); + else { + BDFDB.DOMUtils.addClass(data.toast, BDFDB.disCN.toastclosable); + data.toast.addEventListener("click", event => { + if (typeof data.config.onClick == "function" && !BDFDB.DOMUtils.getParent(BDFDB.dotCN.toastcloseicon, event.target)) data.config.onClick(); + data.toast.close(); + }); + if (typeof closeTimeout.pause == "function") { + let paused = false; + data.toast.addEventListener("mouseenter", _ => { + if (paused) return; + paused = true; + closeTimeout.pause(); + }); + data.toast.addEventListener("mouseleave", _ => { + if (!paused) return; + paused = false; + closeTimeout.resume(); + }); + } + } + + toasts.appendChild(data.toast); + BDFDB.TimeUtils.timeout(_ => BDFDB.DOMUtils.removeClass(data.toast, BDFDB.disCN.toastopening)); + + let icon = data.config.avatar ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.AvatarComponents.default, { + src: data.config.avatar, + size: Internal.LibraryComponents.AvatarComponents.Sizes.SIZE_24 + }) : ((data.config.icon || data.config.type && LibraryConstants.ToastIcons[data.config.type]) ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: data.config.type && LibraryConstants.ToastIcons[data.config.type] && Internal.LibraryComponents.SvgIcon.Names[LibraryConstants.ToastIcons[data.config.type]], + iconSVG: data.config.icon, + width: 18, + height: 18, + nativeClass: true + }) : null); + + BDFDB.ReactUtils.render(BDFDB.ReactUtils.createElement(class BDFDB_Toast extends Internal.LibraryModules.React.Component { + componentDidMount() { + data.toast.update = newChildren => { + if (!newChildren) return; + data.children = newChildren; + BDFDB.ReactUtils.forceUpdate(this); + }; + } + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryModules.React.Fragment, { + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.toastbg, + style: {backgroundColor: backgroundColor} + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.toastinner, + style: {color: fontColor}, + children: [ + icon && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(data.config.avatar && BDFDB.disCN.toastavatar, BDFDB.disCN.toasticon, data.config.iconClassName), + children: icon + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.toasttext, data.config.textClassName), + children: data.children + }), + !disableInteractions && BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.toastcloseicon, + name: Internal.LibraryComponents.SvgIcon.Names.CLOSE, + width: 16, + height: 16 + }) + ].filter(n => n) + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.toastbar, barColor && BDFDB.disCN.toastcustombar), + style: { + backgroundColor: barColor, + animation: `toast-bar ${timeout}ms normal linear` + } + }) + ] + }); + } + }, {}), data.toast); + + ToastQueues[position].full = (BDFDB.ArrayUtils.sum(Array.from(toasts.childNodes).map(c => { + let height = BDFDB.DOMUtils.getRects(c).height; + return height > 50 ? height : 50; + })) - 100) > BDFDB.DOMUtils.getRects(app).height; + + if (typeof data.config.onShow == "function") data.config.onShow(); + }; + + let toast = BDFDB.DOMUtils.create(`
`); + toast.update = _ => {}; + ToastQueues[position].queue.push({children, config, toast}); + runQueue(); + return toast; + }; + BDFDB.NotificationUtils.desktop = function (content, config = {}) { + if (!content) return; + + const queue = _ => { + DesktopNotificationQueue.queue.push({content, config}); + runQueue(); + }; + const runQueue = _ => { + if (DesktopNotificationQueue.running) return; + let data = DesktopNotificationQueue.queue.shift(); + if (!data) return; + + DesktopNotificationQueue.running = true; + let muted = data.config.silent; + data.config.silent = data.config.silent || data.config.sound ? true : false; + let audio = new Audio(); + if (!muted && data.config.sound) { + audio.src = data.config.sound; + audio.play(); + } + let notification = new Notification(data.content, data.config); + + let disableInteractions = data.config.disableInteractions && typeof data.config.onClick != "function"; + if (disableInteractions) notification.onclick = _ => {}; + else notification.onclick = _ => { + if (typeof data.config.onClick == "function") data.config.onClick(); + notification.close(); + }; + + notification.onclose = _ => { + audio.pause(); + DesktopNotificationQueue.running = false; + BDFDB.TimeUtils.timeout(runQueue, 1000); + } + }; + + if (!("Notification" in window)) {} + else if (Notification.permission === "granted") queue(); + else if (Notification.permission !== "denied") Notification.requestPermission(function (response) {if (response === "granted") queue();}); + }; + BDFDB.NotificationUtils.notice = function (text, config = {}) { + if (!text) return; + let layers = document.querySelector(BDFDB.dotCN.layers) || document.querySelector(BDFDB.dotCN.appmount); + if (!layers) return; + let id = BDFDB.NumberUtils.generateId(NotificationBars); + let notice = BDFDB.DOMUtils.create(`
`); + layers.parentElement.insertBefore(notice, layers); + let noticeText = notice.querySelector(BDFDB.dotCN.noticetext); + if (config.platform) for (let platform of config.platform.split(" ")) if (DiscordClasses["noticeicon" + platform]) { + let icon = BDFDB.DOMUtils.create(``); + BDFDB.DOMUtils.addClass(icon, BDFDB.disCN.noticeplatformicon); + BDFDB.DOMUtils.removeClass(icon, BDFDB.disCN.noticeicon); + notice.insertBefore(icon, noticeText); + } + if (config.customIcon) { + let icon = document.createElement("i"), iconInner = BDFDB.DOMUtils.create(config.customIcon); + if (iconInner.nodeType == Node.TEXT_NODE) icon.style.setProperty("background", `url(${config.customIcon}) center/cover no-repeat`); + else { + icon = iconInner; + if ((icon.tagName || "").toUpperCase() == "SVG") { + icon.removeAttribute("width"); + icon.setAttribute("height", "100%"); + } + } + BDFDB.DOMUtils.addClass(icon, BDFDB.disCN.noticeplatformicon); + BDFDB.DOMUtils.removeClass(icon, BDFDB.disCN.noticeicon); + notice.insertBefore(icon, noticeText); + } + if (BDFDB.ArrayUtils.is(config.buttons)) for (let data of config.buttons) { + let contents = typeof data.contents == "string" && data.contents; + if (contents) { + let button = BDFDB.DOMUtils.create(``); + button.addEventListener("click", event => { + if (data.close) notice.close(); + if (typeof data.onClick == "function") data.onClick(event, notice); + }); + if (typeof data.onMouseEnter == "function") button.addEventListener("mouseenter", event => data.onMouseEnter(event, notice)); + if (typeof data.onMouseLeave == "function") button.addEventListener("mouseleave", event => data.onMouseLeave(event, notice)); + notice.appendChild(button); + } + } + if (config.id) notice.id = config.id.split(" ").join(""); + if (config.className) BDFDB.DOMUtils.addClass(notice, config.className); + if (config.textClassName) BDFDB.DOMUtils.addClass(noticeText, config.textClassName); + if (config.css) BDFDB.DOMUtils.appendLocalStyle("BDFDBcustomNotificationBar" + id, config.css); + if (config.style) notice.style = config.style; + if (config.html) noticeText.innerHTML = text; + else { + let link = document.createElement("a"); + let newText = []; + for (let word of text.split(" ")) { + let encodedWord = BDFDB.StringUtils.htmlEscape(word); + link.href = word; + newText.push(link.host && link.host !== window.location.host ? `` : encodedWord); + } + noticeText.innerHTML = newText.join(" "); + } + let type = null; + if (config.type && !document.querySelector(BDFDB.dotCNS.chatbase + BDFDB.dotCN.noticestreamer)) { + if (type = BDFDB.disCN["notice" + config.type]) BDFDB.DOMUtils.addClass(notice, type); + if (config.type == "premium") { + let noticeButton = notice.querySelector(BDFDB.dotCN.noticebutton); + if (noticeButton) BDFDB.DOMUtils.addClass(noticeButton, BDFDB.disCN.noticepremiumaction); + BDFDB.DOMUtils.addClass(noticeText, BDFDB.disCN.noticepremiumtext); + notice.insertBefore(BDFDB.DOMUtils.create(``), noticeText); + } + } + if (!type) { + let comp = BDFDB.ColorUtils.convert(config.color, "RGBCOMP"); + if (comp) { + let fontColor = comp[0] > 180 && comp[1] > 180 && comp[2] > 180 ? "#000" : "#FFF"; + let backgroundColor = BDFDB.ColorUtils.convert(comp, "HEX"); + BDFDB.DOMUtils.appendLocalStyle("BDFDBcustomNotificationBarColorCorrection" + id, `${BDFDB.dotCN.noticewrapper}[notice-id="${id}"]{background-color: ${backgroundColor} !important;}${BDFDB.dotCN.noticewrapper}[notice-id="${id}"] ${BDFDB.dotCN.noticetext} {color: ${fontColor} !important;}${BDFDB.dotCN.noticewrapper}[notice-id="${id}"] ${BDFDB.dotCN.noticebutton} {color: ${fontColor} !important;border-color: ${BDFDB.ColorUtils.setAlpha(fontColor, 0.25, "RGBA")} !important;}${BDFDB.dotCN.noticewrapper}[notice-id="${id}"] ${BDFDB.dotCN.noticebutton}:hover {color: ${backgroundColor} !important;background-color: ${fontColor} !important;}${BDFDB.dotCN.noticewrapper}[notice-id="${id}"] ${BDFDB.dotCN.noticedismissicon} path {fill: ${fontColor} !important;}`); + BDFDB.DOMUtils.addClass(notice, BDFDB.disCN.noticecustom); + } + else BDFDB.DOMUtils.addClass(notice, BDFDB.disCN.noticedefault); + } + if (config.forceStyle) { + notice.style.setProperty("display", "flex", "important"); + notice.style.setProperty("height", "36px", "important"); + notice.style.setProperty("min-width", "70vw", "important"); + notice.style.setProperty("left", "unset", "important"); + notice.style.setProperty("right", "unset", "important"); + let sideMargin = ((BDFDB.DOMUtils.getWidth(document.body.firstElementChild) - BDFDB.DOMUtils.getWidth(notice))/2); + notice.style.setProperty("left", `${sideMargin}px`, "important"); + notice.style.setProperty("right", `${sideMargin}px`, "important"); + notice.style.setProperty("min-width", "unset", "important"); + notice.style.setProperty("width", "unset", "important"); + notice.style.setProperty("max-width", `calc(100vw - ${sideMargin*2}px)`, "important"); + } + notice.close = _ => { + BDFDB.DOMUtils.addClass(notice, BDFDB.disCN.noticeclosing); + if (config.forceStyle) { + notice.style.setProperty("overflow", "hidden", "important"); + notice.style.setProperty("height", "0px", "important"); + } + if (notice.tooltip && typeof notice.tooltip.removeTooltip == "function") notice.tooltip.removeTooltip(); + BDFDB.TimeUtils.timeout(_ => { + if (typeof config.onClose == "function") config.onClose(); + BDFDB.ArrayUtils.remove(NotificationBars, id); + BDFDB.DOMUtils.removeLocalStyle("BDFDBcustomNotificationBar" + id); + BDFDB.DOMUtils.removeLocalStyle("BDFDBcustomNotificationBarColorCorrection" + id); + BDFDB.DOMUtils.remove(notice); + }, 500); + }; + notice.querySelector(BDFDB.dotCN.noticedismiss).addEventListener("click", notice.close); + return notice; + }; + BDFDB.NotificationUtils.alert = function (header, body) { + if (typeof header == "string" && typeof header == "string" && BdApi && typeof BdApi.alert == "function") BdApi.alert(header, body); + }; + + var Tooltips = []; + BDFDB.TooltipUtils = {}; + BDFDB.TooltipUtils.create = function (anker, text, config = {}) { + if (!text && !config.guild) return null; + const itemLayerContainer = document.querySelector(BDFDB.dotCN.app + " ~ " + BDFDB.dotCN.itemlayercontainer) || document.querySelector(BDFDB.dotCN.itemlayercontainer); + if (!itemLayerContainer || !Node.prototype.isPrototypeOf(anker) || !document.contains(anker)) return null; + const id = BDFDB.NumberUtils.generateId(Tooltips); + const itemLayer = BDFDB.DOMUtils.create(`
`); + itemLayerContainer.appendChild(itemLayer); + + const tooltip = itemLayer.firstElementChild; + const tooltipContent = itemLayer.querySelector(BDFDB.dotCN.tooltipcontent); + const tooltipPointer = itemLayer.querySelector(BDFDB.dotCN.tooltippointer); + + if (config.id) tooltip.id = config.id.split(" ").join(""); + + if (typeof config.type != "string" || !BDFDB.disCN["tooltip" + config.type.toLowerCase()]) config.type = "top"; + let type = config.type.toLowerCase(); + BDFDB.DOMUtils.addClass(tooltip, BDFDB.disCN["tooltip" + type], config.className); + + let fontColorIsGradient = false, customBackgroundColor = false, style = ""; + if (config.style) style += config.style; + if (config.fontColor) { + fontColorIsGradient = BDFDB.ObjectUtils.is(config.fontColor); + if (!fontColorIsGradient) style = (style ? (style + " ") : "") + `color: ${BDFDB.ColorUtils.convert(config.fontColor, "RGBA")} !important;` + } + if (config.backgroundColor) { + customBackgroundColor = true; + let backgroundColorIsGradient = BDFDB.ObjectUtils.is(config.backgroundColor); + let backgroundColor = !backgroundColorIsGradient ? BDFDB.ColorUtils.convert(config.backgroundColor, "RGBA") : BDFDB.ColorUtils.createGradient(config.backgroundColor); + style = (style ? (style + " ") : "") + `background: ${backgroundColor} !important; border-color: ${backgroundColorIsGradient ? BDFDB.ColorUtils.convert(config.backgroundColor[type == "left" ? 100 : 0], "RGBA") : backgroundColor} !important;`; + } + if (style) tooltip.style = style; + const zIndexed = config.zIndex && typeof config.zIndex == "number"; + if (zIndexed) { + itemLayer.style.setProperty("z-index", config.zIndex, "important"); + tooltip.style.setProperty("z-index", config.zIndex, "important"); + tooltipContent.style.setProperty("z-index", config.zIndex, "important"); + BDFDB.DOMUtils.addClass(itemLayerContainer, BDFDB.disCN.itemlayercontainerzindexdisabled); + } + if (typeof config.width == "number" && config.width > 196) { + tooltip.style.setProperty("width", `${config.width}px`, "important"); + tooltip.style.setProperty("max-width", `${config.width}px`, "important"); + } + if (typeof config.maxWidth == "number" && config.maxWidth > 196) { + tooltip.style.setProperty("max-width", `${config.maxWidth}px`, "important"); + } + if (customBackgroundColor) BDFDB.DOMUtils.addClass(tooltip, BDFDB.disCN.tooltipcustom); + else if (config.color && BDFDB.disCN["tooltip" + config.color.toLowerCase()]) BDFDB.DOMUtils.addClass(tooltip, BDFDB.disCN["tooltip" + config.color.toLowerCase()]); + else BDFDB.DOMUtils.addClass(tooltip, BDFDB.disCN.tooltipprimary); + + if (config.list || BDFDB.ObjectUtils.is(config.guild)) BDFDB.DOMUtils.addClass(tooltip, BDFDB.disCN.tooltiplistitem); + + const removeTooltip = _ => { + document.removeEventListener("wheel", wheel); + document.removeEventListener("mousemove", mouseMove); + document.removeEventListener("mouseleave", mouseLeave); + BDFDB.DOMUtils.remove(itemLayer); + BDFDB.ArrayUtils.remove(Tooltips, id); + observer.disconnect(); + if (zIndexed) BDFDB.DOMUtils.removeClass(itemLayerContainer, BDFDB.disCN.itemlayercontainerzindexdisabled); + if (typeof config.onHide == "function") config.onHide(itemLayer, anker); + }; + const setText = newText => { + if (BDFDB.ObjectUtils.is(config.guild)) { + let isMuted = Internal.LibraryModules.MutedUtils.isMuted(config.guild.id); + let muteConfig = Internal.LibraryModules.MutedUtils.getMuteConfig(config.guild.id); + + let children = [typeof newText == "function" ? newText() : newText].flat(10).filter(n => typeof n == "string" || BDFDB.ReactUtils.isValidElement(n)); + + BDFDB.ReactUtils.render(BDFDB.ReactUtils.createElement(Internal.LibraryModules.React.Fragment, { + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tooltiprow, BDFDB.disCN.tooltiprowguildname), + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.GuildComponents.Badge, { + guild: config.guild, + size: Internal.LibraryModules.StringUtils.cssValueToNumber(Internal.DiscordClassModules.TooltipGuild.iconSize), + className: BDFDB.disCN.tooltiprowicon + }), + BDFDB.ReactUtils.createElement("span", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tooltipguildnametext), + children: fontColorIsGradient ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextGradientElement, { + gradient: BDFDB.ColorUtils.createGradient(config.fontColor), + children: config.guild.toString() + }) : config.guild.toString() + }), + ] + }), + children.length && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tooltiprow, BDFDB.disCN.tooltiprowextra), + children: children + }), + config.note && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tooltiprow, BDFDB.disCN.tooltiprowextra, BDFDB.disCN.tooltipnote), + children: config.note + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.GuildVoiceList, {guild: config.guild}), + isMuted && muteConfig && (muteConfig.end_time == null ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextElement, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tooltipmutetext), + size: Internal.LibraryComponents.TextElement.Sizes.SIZE_12, + color: Internal.LibraryComponents.TextElement.Colors.MUTED, + children: BDFDB.LanguageUtils.LanguageStrings.VOICE_CHANNEL_MUTED + }) : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.GuildComponents.MutedText, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tooltipmutetext), + muteConfig: muteConfig + })) + ].filter(n => n) + }), tooltipContent); + } + else { + let children = [typeof newText == "function" ? newText() : newText].flat(10).filter(n => typeof n == "string" || BDFDB.ReactUtils.isValidElement(n)); + children.length && BDFDB.ReactUtils.render(BDFDB.ReactUtils.createElement(Internal.LibraryModules.React.Fragment, { + children: [ + fontColorIsGradient ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextGradientElement, { + gradient: BDFDB.ColorUtils.createGradient(config.fontColor), + children: children + }) : children, + config.note && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tooltiprow, BDFDB.disCN.tooltiprowextra, BDFDB.disCN.tooltipnote), + children: config.note + }) + ] + }), tooltipContent); + } + }; + const update = newText => { + if (newText) setText(newText); + let left, top; + const tRects = BDFDB.DOMUtils.getRects(anker); + const iRects = BDFDB.DOMUtils.getRects(itemLayer); + const aRects = BDFDB.DOMUtils.getRects(document.querySelector(BDFDB.dotCN.appmount)); + const positionOffsets = {height: 10, width: 10}; + const offset = typeof config.offset == "number" ? config.offset : 0; + switch (type) { + case "top": + top = tRects.top - iRects.height - positionOffsets.height + 2 - offset; + left = tRects.left + (tRects.width - iRects.width) / 2; + break; + case "bottom": + top = tRects.top + tRects.height + positionOffsets.height - 2 + offset; + left = tRects.left + (tRects.width - iRects.width) / 2; + break; + case "left": + top = tRects.top + (tRects.height - iRects.height) / 2; + left = tRects.left - iRects.width - positionOffsets.width + 2 - offset; + break; + case "right": + top = tRects.top + (tRects.height - iRects.height) / 2; + left = tRects.left + tRects.width + positionOffsets.width - 2 + offset; + break; + } + + itemLayer.style.setProperty("top", `${top}px`, "important"); + itemLayer.style.setProperty("left", `${left}px`, "important"); + + tooltipPointer.style.removeProperty("margin-left"); + tooltipPointer.style.removeProperty("margin-top"); + if (type == "top" || type == "bottom") { + if (left < 0) { + itemLayer.style.setProperty("left", "5px", "important"); + tooltipPointer.style.setProperty("margin-left", `${left - 10}px`, "important"); + } + else { + const rightMargin = aRects.width - (left + iRects.width); + if (rightMargin < 0) { + itemLayer.style.setProperty("left", `${aRects.width - iRects.width - 5}px`, "important"); + tooltipPointer.style.setProperty("margin-left", `${-1*rightMargin}px`, "important"); + } + } + } + else if (type == "left" || type == "right") { + if (top < 0) { + const bRects = BDFDB.DOMUtils.getRects(document.querySelector(BDFDB.dotCN.titlebar)); + const barCorrection = (bRects.width || 0) >= Math.round(75 * window.outerWidth / aRects.width) ? (bRects.height + 5) : 0; + itemLayer.style.setProperty("top", `${5 + barCorrection}px`, "important"); + tooltipPointer.style.setProperty("margin-top", `${top - 10 - barCorrection}px`, "important"); + } + else { + const bottomMargin = aRects.height - (top + iRects.height); + if (bottomMargin < 0) { + itemLayer.style.setProperty("top", `${aRects.height - iRects.height - 5}px`, "important"); + tooltipPointer.style.setProperty("margin-top", `${-1*bottomMargin}px`, "important"); + } + } + } + }; + + const wheel = e => { + const tRects1 = BDFDB.DOMUtils.getRects(anker); + BDFDB.TimeUtils.clear(wheel.timeout); + wheel.timeout = BDFDB.TimeUtils.timeout(_ => { + const tRects2 = BDFDB.DOMUtils.getRects(anker); + if (tRects1.x != tRects2.x || tRects1.y != tRects2.y) removeTooltip(); + }, 500); + }; + const mouseMove = e => { + const parent = e.target.parentElement.querySelector(":hover"); + if (parent && anker != parent && !anker.contains(parent)) removeTooltip(); + }; + const mouseLeave = e => removeTooltip(); + if (!config.perssist) { + document.addEventListener("wheel", wheel); + document.addEventListener("mousemove", mouseMove); + document.addEventListener("mouseleave", mouseLeave); + } + + const observer = new MutationObserver(changes => changes.forEach(change => { + const nodes = Array.from(change.removedNodes); + if (nodes.indexOf(itemLayer) > -1 || nodes.indexOf(anker) > -1 || nodes.some(n => n.contains(anker))) removeTooltip(); + })); + observer.observe(document.body, {subtree: true, childList: true}); + + tooltip.removeTooltip = itemLayer.removeTooltip = removeTooltip; + tooltip.setText = itemLayer.setText = setText; + tooltip.update = itemLayer.update = update; + setText(text); + update(); + + if (config.delay) { + BDFDB.DOMUtils.toggle(itemLayer); + BDFDB.TimeUtils.timeout(_ => { + BDFDB.DOMUtils.toggle(itemLayer); + if (typeof config.onShow == "function") config.onShow(itemLayer, anker); + }, config.delay); + } + else { + if (typeof config.onShow == "function") config.onShow(itemLayer, anker); + } + return itemLayer; + }; + + Internal.forceInitiateProcess = function (pluginDataObjs, instance, type) { + pluginDataObjs = [pluginDataObjs].flat(10).filter(n => n); + if (pluginDataObjs.length && instance && type) { + let forceRender = false; + for (let pluginData of pluginDataObjs) { + let plugin = pluginData.plugin == BDFDB && Internal || pluginData.plugin, methodNames = []; + for (let patchType in plugin.patchedModules) { + if (plugin.patchedModules[patchType][type]) methodNames.push(plugin.patchedModules[patchType][type]); + } + methodNames = BDFDB.ArrayUtils.removeCopies(methodNames).flat(10).filter(n => n); + if (methodNames.includes("componentDidMount")) Internal.initiateProcess(plugin, type, { + arguments: [], + instance: instance, + returnvalue: undefined, + component: undefined, + methodname: "componentDidMount", + patchtypes: pluginData.patchTypes[type] + }); + if (methodNames.includes("render")) forceRender = true; + else if (!forceRender && methodNames.includes("componentDidUpdate")) Internal.initiateProcess(plugin, type, { + arguments: [], + instance: instance, + returnvalue: undefined, + component: undefined, + methodname: "componentDidUpdate", + patchtypes: pluginData.patchTypes[type] + }); + } + if (forceRender) BDFDB.ReactUtils.forceUpdate(instance); + } + }; + Internal.initiateProcess = function (plugin, type, e) { + plugin = plugin == BDFDB && Internal || plugin; + if (BDFDB.ObjectUtils.is(plugin) && !plugin.stopping && e.instance) { + type = Internal.LibraryModules.StringUtils.upperCaseFirstChar(type.split(" _ _ ")[1] || type).replace(/[^A-z0-9]|_/g, ""); + if (typeof plugin[`process${type}`] == "function") { + if (typeof e.methodname == "string" && (e.methodname.indexOf("componentDid") == 0 || e.methodname.indexOf("componentWill") == 0)) { + e.node = BDFDB.ReactUtils.findDOMNode(e.instance); + if (e.node) { + let tempReturn = plugin[`process${type}`](e); + return tempReturn !== undefined ? tempReturn : e.returnvalue; + } + else BDFDB.TimeUtils.timeout(_ => { + e.node = BDFDB.ReactUtils.findDOMNode(e.instance); + if (e.node) plugin[`process${type}`](e); + }); + } + else if (e.returnvalue !== undefined || e.patchtypes.includes("before")) { + let tempReturn = plugin[`process${type}`](e); + return tempReturn !== undefined ? tempReturn : e.returnvalue; + } + } + } + }; + Internal.patchObserverData = {observer: null, data: {}}; + Internal.patchPlugin = function (plugin) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ObjectUtils.is(plugin.patchedModules)) return; + BDFDB.PatchUtils.unpatch(plugin); + let patchedModules = {}; + for (let patchType in plugin.patchedModules) for (let type in plugin.patchedModules[patchType]) { + if (!patchedModules[type]) patchedModules[type] = {}; + patchedModules[type][patchType] = plugin.patchedModules[patchType][type]; + } + for (let type in patchedModules) { + let pluginData = {plugin: plugin, patchTypes: patchedModules[type]}; + let unmappedType = type.split(" _ _ ")[1] || type; + + let finderData = InternalData.ModuleUtilsConfig.Finder[unmappedType]; + let config = { + classNames: [finderData && finderData.class].flat(10).filter(n => DiscordClasses[n]), + lazyLoaded: finderData && finderData.lazyLoaded, + stringFind: finderData && finderData.strings, + propertyFind: finderData && finderData.props, + prototypeFind: finderData && finderData.protos, + specialFilter: finderData && finderData.special && Internal.createFilter(finderData.special), + subComponent: finderData && finderData.subComponent, + forceObserve: finderData && finderData.forceObserve, + exported: finderData && finderData.exported || false, + path: finderData && finderData.path, + mapped: InternalData.ModuleUtilsConfig.PatchMap[type] + }; + config.nonRender = config.specialFilter || BDFDB.ObjectUtils.toArray(pluginData.patchTypes).flat(10).filter(n => n && !InternalData.ModuleUtilsConfig.InstanceFunctions.includes(n)).length > 0; + config.nonPrototype = !!(config.subComponent && config.subComponent.strings || config.stringFind || config.subComponent && config.subComponent.props || config.propertyFind || config.subComponent && config.subComponent.protos || config.prototypeFind || config.nonRender); + + config.mappedType = config.mapped ? config.mapped + " _ _ " + type : type; + config.name = config.subComponent && config.subComponent.name || config.mappedType.split(" _ _ ")[0]; + + let component = InternalData.ModuleUtilsConfig.LoadedInComponents[type] && BDFDB.ObjectUtils.get(Internal, InternalData.ModuleUtilsConfig.LoadedInComponents[type]); + if (component) Internal.patchComponent(pluginData, config.nonRender ? (BDFDB.ModuleUtils.find(m => m == component && m, {useExport: config.exported}) || {}).exports : component, config); + else { + if (config.mapped) for (let patchType in plugin.patchedModules) if (plugin.patchedModules[patchType][type]) { + plugin.patchedModules[patchType][config.mappedType] = plugin.patchedModules[patchType][type]; + delete plugin.patchedModules[patchType][type]; + } + + let patchSpecial = (func, argument) => { + let module = BDFDB.ModuleUtils[func](argument, config.exported); + let exports = module && !config.exported && module.exports || module; + exports = config.path && BDFDB.ObjectUtils.get(exports, config.path) || exports; + exports && Internal.patchComponent(pluginData, Internal.isMemoOrForwardRef(exports) ? exports.default : exports, config); + return exports ? true : false; + }; + let found = true; + if (config.lazyLoaded) Internal.addChunkObserver(pluginData, config); + else if (config.classNames.length) Internal.searchComponent(pluginData, config); + else if (config.subComponent && config.subComponent.strings || config.stringFind) found = patchSpecial("findByString", config.subComponent && config.subComponent.strings || config.stringFind); + else if (config.subComponent && config.subComponent.props || config.propertyFind) found = patchSpecial("findByProperties", config.subComponent && config.subComponent.props || config.propertyFind); + else if (config.subComponent && config.subComponent.protos || config.prototypeFind) found = patchSpecial("findByPrototypes", config.subComponent && config.subComponent.protos || config.prototypeFind); + else if (config.nonRender) found = patchSpecial("findByName", config.name); + else { + let module = BDFDB.ModuleUtils.findByName(config.name); + if (module) Internal.patchComponent(pluginData, module, config); + else found = false; + } + if (!found) Internal.addChunkObserver(pluginData, config); + } + } + }; + Internal.patchComponent = function (pluginDataObjs, instance, config) { + pluginDataObjs = [pluginDataObjs].flat(10).filter(n => n); + if (pluginDataObjs.length && instance) { + instance = instance[BDFDB.ReactUtils.instanceKey] && instance[BDFDB.ReactUtils.instanceKey].type ? instance[BDFDB.ReactUtils.instanceKey].type : instance; + if (instance) { + let toBePatched = config.nonPrototype || !instance.prototype ? instance : instance.prototype; + toBePatched = toBePatched && toBePatched.type && typeof toBePatched.type.render == "function" ? toBePatched.type : toBePatched; + if (config.subComponent) { + for (let pluginData of pluginDataObjs) BDFDB.PatchUtils.patch(pluginData.plugin, toBePatched, config.subComponent.type || "default", {after: e => { + for (let patchType in pluginData.patchTypes) BDFDB.PatchUtils.patch(pluginData.plugin, config.subComponent.children && e.returnValue.props && e.returnValue.props.children ? e.returnValue.props.children[0] || e.returnValue.props.children : e.returnValue , "type", { + [patchType]: e2 => Internal.initiateProcess(pluginData.plugin, config.mappedType, { + arguments: e2.methodArguments, + instance: e2.thisObject, + returnvalue: e2.returnValue, + component: toBePatched, + methodname: e.originalMethodName, + patchtypes: [patchType] + }) + }, {name, noCache: true}); + }}, {name: config.name}); + } + else { + for (let pluginData of pluginDataObjs) for (let patchType in pluginData.patchTypes) { + BDFDB.PatchUtils.patch(pluginData.plugin, toBePatched, pluginData.patchTypes[patchType], { + [patchType]: e => Internal.initiateProcess(pluginData.plugin, config.mappedType, { + arguments: e.methodArguments, + instance: e.thisObject, + returnvalue: e.returnValue, + component: toBePatched, + methodname: e.originalMethodName, + patchtypes: [patchType] + }) + }, {name: config.name}); + } + } + } + } + }; + Internal.createFilter = function (config) { + return ins => ins && config.every(prop => { + let value = BDFDB.ObjectUtils.get(ins, prop.path); + return value && (!prop.value || [prop.value].flat(10).filter(n => typeof n == "string").some(n => value.toUpperCase().indexOf(n.toUpperCase()) == 0)); + }) && ins.return.type; + }; + Internal.isMemoOrForwardRef = function (exports) { + return exports && exports.default && typeof exports.default.$$typeof == "symbol" && ((exports.default.$$typeof.toString() || "").indexOf("memo") > -1 || (exports.default.$$typeof.toString() || "").indexOf("forward_ref") > -1); + }; + Internal.checkElementForComponent = function (pluginDataObjs, ele, config) { + pluginDataObjs = [pluginDataObjs].flat(10).filter(n => n); + let ins = BDFDB.ReactUtils.getInstance(ele); + if (typeof config.specialFilter == "function") { + let component = config.specialFilter(ins); + if (component) { + if (config.nonRender) { + let exports = (BDFDB.ModuleUtils.find(m => m == component && m, {useExport: false}) || {}).exports; + Internal.patchComponent(pluginDataObjs, Internal.isMemoOrForwardRef(exports) ? exports.default : exports, config); + } + else Internal.patchComponent(pluginDataObjs, component, config); + BDFDB.PatchUtils.forceAllUpdates(pluginDataObjs.map(n => n.plugin), config.mappedType); + return true; + } + } + else { + let unmappedType = config.mappedType.split(" _ _ ")[1] || config.mappedType; + let constructor = BDFDB.ReactUtils.findConstructor(ins, unmappedType) || BDFDB.ReactUtils.findConstructor(ins, unmappedType, {up: true}); + if (constructor) { + Internal.patchComponent(pluginDataObjs, constructor, config); + BDFDB.PatchUtils.forceAllUpdates(pluginDataObjs.map(n => n.plugin), config.mappedType); + return true; + } + } + return false; + }; + Internal.searchComponent = function (pluginData, config) { + let instanceFound = false; + if (!config.forceObserve) { + const app = document.querySelector(BDFDB.dotCN.app); + if (app) { + let appIns = BDFDB.ReactUtils.findConstructor(app, config.mappedType, {unlimited: true}) || BDFDB.ReactUtils.findConstructor(app, config.mappedType, {unlimited: true, up: true}); + if (appIns && (instanceFound = true)) Internal.patchComponent(pluginData, appIns, config); + } + } + if (!instanceFound) { + let elementFound = false, classes = config.classNames.map(n => BDFDB.disCN[n]), selector = config.classNames.map(n => BDFDB.dotCN[n]).join(", "); + for (let ele of document.querySelectorAll(selector)) { + elementFound = Internal.checkElementForComponent(pluginData, ele, config); + if (elementFound) break; + } + if (!elementFound) { + if (!Internal.patchObserverData.observer) { + let appMount = document.querySelector(BDFDB.dotCN.appmount); + if (appMount) { + Internal.patchObserverData.observer = new MutationObserver(cs => cs.forEach(c => c.addedNodes.forEach(n => { + if (!n || !n.tagName) return; + for (let type in Internal.patchObserverData.data) { + if (!Internal.patchObserverData.data[type] || Internal.patchObserverData.data[type].found) return; + for (let ele of [BDFDB.DOMUtils.containsClass(n, ...Internal.patchObserverData.data[type].classes) && n].concat([...n.querySelectorAll(Internal.patchObserverData.data[type].selector)]).filter(n => n)) { + if (!Internal.patchObserverData.data[type] || Internal.patchObserverData.data[type].found) return; + Internal.patchObserverData.data[type].found = Internal.checkElementForComponent(Internal.patchObserverData.data[type].plugins, ele, Internal.patchObserverData.data[type].config); + if (Internal.patchObserverData.data[type].found) { + delete Internal.patchObserverData.data[type]; + if (BDFDB.ObjectUtils.isEmpty(Internal.patchObserverData.data)) { + Internal.patchObserverData.observer.disconnect(); + Internal.patchObserverData.observer = null; + } + } + } + } + }))); + Internal.patchObserverData.observer.observe(appMount, {childList: true, subtree: true}); + } + } + if (!Internal.patchObserverData.data[config.mappedType]) Internal.patchObserverData.data[config.mappedType] = {selector, classes, found: false, config, plugins: []}; + Internal.patchObserverData.data[config.mappedType].plugins.push(pluginData); + } + } + }; + + BDFDB.PatchUtils = {}; + BDFDB.PatchUtils.isPatched = function (plugin, module, methodName) { + plugin = plugin == BDFDB && Internal || plugin; + if (!plugin || (!BDFDB.ObjectUtils.is(module) && !BDFDB.ArrayUtils.is(module)) || !module.BDFDB_patches || !methodName) return false; + const pluginId = (typeof plugin === "string" ? plugin : plugin.name).toLowerCase(); + return pluginId && module[methodName] && module[methodName].__is_BDFDB_patched && module.BDFDB_patches[methodName] && BDFDB.ObjectUtils.toArray(module.BDFDB_patches[methodName]).some(patchObj => BDFDB.ObjectUtils.toArray(patchObj).some(priorityObj => Object.keys(priorityObj).includes(pluginId))); + }; + BDFDB.PatchUtils.patch = function (plugin, module, methodNames, patchMethods, config = {}) { + plugin = plugin == BDFDB && Internal || plugin; + if (!plugin || (!BDFDB.ObjectUtils.is(module) && !BDFDB.ArrayUtils.is(module)) || !methodNames || !BDFDB.ObjectUtils.is(patchMethods)) return null; + patchMethods = BDFDB.ObjectUtils.filter(patchMethods, type => InternalData.ModuleUtilsConfig.PatchTypes.includes(type), true); + if (BDFDB.ObjectUtils.isEmpty(patchMethods)) return null; + const pluginName = (typeof plugin === "string" ? plugin : plugin.name) || ""; + const pluginVersion = typeof plugin === "string" ? "" : plugin.version; + const pluginId = pluginName.toLowerCase(); + let patchPriority = !isNaN(config.priority) ? config.priority : (BDFDB.ObjectUtils.is(plugin) && !isNaN(plugin.patchPriority) ? plugin.patchPriority : 5); + patchPriority = patchPriority < 1 ? (plugin == Internal ? 0 : 1) : (patchPriority > 9 ? (plugin == Internal ? 10 : 9) : Math.round(patchPriority)); + if (!BDFDB.ObjectUtils.is(module.BDFDB_patches)) module.BDFDB_patches = {}; + methodNames = [methodNames].flat(10).filter(n => n); + let cancel = _ => {BDFDB.PatchUtils.unpatch(plugin, module, methodNames);}; + for (let methodName of methodNames) if (module[methodName] == null || typeof module[methodName] == "function") { + if (!module.BDFDB_patches[methodName] || config.force && (!module[methodName] || !module[methodName].__is_BDFDB_patched)) { + if (!module.BDFDB_patches[methodName]) { + module.BDFDB_patches[methodName] = {}; + for (let type of InternalData.ModuleUtilsConfig.PatchTypes) module.BDFDB_patches[methodName][type] = {}; + } + if (!module[methodName]) module[methodName] = (_ => {}); + const name = config.name || (module.constructor ? (module.constructor.displayName || module.constructor.name) : "module"); + const originalMethod = module[methodName]; + module.BDFDB_patches[methodName].originalMethod = originalMethod; + module[methodName] = function () { + let callInstead = false, stopCall = false; + const data = { + thisObject: this && this !== window ? this : {props: arguments[0]}, + methodArguments: arguments, + originalMethod: originalMethod, + originalMethodName: methodName, + callOriginalMethod: _ => data.returnValue = data.originalMethod.apply(data.thisObject, data.methodArguments), + callOriginalMethodAfterwards: _ => (callInstead = true, data.returnValue), + stopOriginalMethodCall: _ => stopCall = true + }; + if (module.BDFDB_patches && module.BDFDB_patches[methodName]) { + for (let priority in module.BDFDB_patches[methodName].before) for (let id in BDFDB.ObjectUtils.sort(module.BDFDB_patches[methodName].before[priority])) { + BDFDB.TimeUtils.suppress(module.BDFDB_patches[methodName].before[priority][id], `"before" callback of ${methodName} in ${name}`, {name: module.BDFDB_patches[methodName].before[priority][id].pluginName, version: module.BDFDB_patches[methodName].before[priority][id].pluginVersion})(data); + } + + if (!module.BDFDB_patches || !module.BDFDB_patches[methodName]) return (methodName == "render" || methodName == "default") && data.returnValue === undefined ? null : data.returnValue; + let hasInsteadPatches = BDFDB.ObjectUtils.toArray(module.BDFDB_patches[methodName].instead).some(priorityObj => !BDFDB.ObjectUtils.isEmpty(priorityObj)); + if (hasInsteadPatches) for (let priority in module.BDFDB_patches[methodName].instead) for (let id in BDFDB.ObjectUtils.sort(module.BDFDB_patches[methodName].instead[priority])) if (module.BDFDB_patches) { + let tempReturn = BDFDB.TimeUtils.suppress(module.BDFDB_patches[methodName].instead[priority][id], `"instead" callback of ${methodName} in ${name}`, {name: module.BDFDB_patches[methodName].instead[priority][id].pluginName, version: module.BDFDB_patches[methodName].instead[priority][id].pluginVersion})(data); + if (tempReturn !== undefined) data.returnValue = tempReturn; + } + if ((!hasInsteadPatches || callInstead) && !stopCall) BDFDB.TimeUtils.suppress(data.callOriginalMethod, `originalMethod of ${methodName} in ${name}`, {name: "Discord"})(); + + if (!module.BDFDB_patches || !module.BDFDB_patches[methodName]) return methodName == "render" && data.returnValue === undefined ? null : data.returnValue; + for (let priority in module.BDFDB_patches[methodName].after) for (let id in BDFDB.ObjectUtils.sort(module.BDFDB_patches[methodName].after[priority])) if (module.BDFDB_patches) { + let tempReturn = BDFDB.TimeUtils.suppress(module.BDFDB_patches[methodName].after[priority][id], `"after" callback of ${methodName} in ${name}`, {name: module.BDFDB_patches[methodName].after[priority][id].pluginName, version: module.BDFDB_patches[methodName].after[priority][id].pluginVersion})(data); + if (tempReturn !== undefined) data.returnValue = tempReturn; + } + } + else BDFDB.TimeUtils.suppress(data.callOriginalMethod, `originalMethod of ${methodName} in ${name}`)(); + callInstead = false, stopCall = false; + return (methodName == "render" || methodName == "default") && data.returnValue === undefined ? null : data.returnValue; + }; + for (let key of Object.keys(originalMethod)) module[methodName][key] = originalMethod[key]; + if (!module[methodName].__originalFunction) { + let realOriginalMethod = originalMethod.__originalMethod || originalMethod.__originalFunction || originalMethod; + if (typeof realOriginalMethod == "function") { + module[methodName].__originalFunction = realOriginalMethod; + module[methodName].toString = _ => realOriginalMethod.toString(); + } + } + module[methodName].__is_BDFDB_patched = true; + } + for (let type in patchMethods) if (typeof patchMethods[type] == "function") { + if (!BDFDB.ObjectUtils.is(module.BDFDB_patches[methodName][type][patchPriority])) module.BDFDB_patches[methodName][type][patchPriority] = {}; + module.BDFDB_patches[methodName][type][patchPriority][pluginId] = (...args) => { + if (config.once || !plugin.started) cancel(); + return patchMethods[type](...args); + }; + module.BDFDB_patches[methodName][type][patchPriority][pluginId].pluginName = pluginName; + module.BDFDB_patches[methodName][type][patchPriority][pluginId].pluginVersion = pluginVersion; + } + } + if (BDFDB.ObjectUtils.is(plugin) && !config.once && !config.noCache) { + if (!BDFDB.ArrayUtils.is(plugin.patchCancels)) plugin.patchCancels = []; + plugin.patchCancels.push(cancel); + } + return cancel; + }; + BDFDB.PatchUtils.unpatch = function (plugin, module, methodNames) { + plugin = plugin == BDFDB && Internal || plugin; + if (!module && !methodNames) { + if (BDFDB.ObjectUtils.is(plugin) && BDFDB.ArrayUtils.is(plugin.patchCancels)) while (plugin.patchCancels.length) (plugin.patchCancels.pop())(); + } + else { + if ((!BDFDB.ObjectUtils.is(module) && !BDFDB.ArrayUtils.is(module)) || !module.BDFDB_patches) return; + const pluginId = !plugin ? null : (typeof plugin === "string" ? plugin : plugin.name).toLowerCase(); + if (methodNames) { + for (let methodName of [methodNames].flat(10).filter(n => n)) if (module[methodName] && module.BDFDB_patches[methodName]) unpatch(methodName, pluginId); + } + else for (let patchedMethod of module.BDFDB_patches) unpatch(patchedMethod, pluginId); + } + function unpatch (funcName, pluginId) { + for (let type of InternalData.ModuleUtilsConfig.PatchTypes) { + if (pluginId) for (let priority in module.BDFDB_patches[funcName][type]) { + delete module.BDFDB_patches[funcName][type][priority][pluginId]; + if (BDFDB.ObjectUtils.isEmpty(module.BDFDB_patches[funcName][type][priority])) delete module.BDFDB_patches[funcName][type][priority]; + } + else delete module.BDFDB_patches[funcName][type]; + } + if (BDFDB.ObjectUtils.isEmpty(BDFDB.ObjectUtils.filter(module.BDFDB_patches[funcName], key => InternalData.ModuleUtilsConfig.PatchTypes.includes(key) && !BDFDB.ObjectUtils.isEmpty(module.BDFDB_patches[funcName][key]), true))) { + module[funcName] = module.BDFDB_patches[funcName].originalMethod; + delete module.BDFDB_patches[funcName]; + if (BDFDB.ObjectUtils.isEmpty(module.BDFDB_patches)) delete module.BDFDB_patches; + } + } + }; + BDFDB.PatchUtils.forceAllUpdates = function (plugins, selectedTypes) { + plugins = [plugins].flat(10).map(n => n == BDFDB && Internal || n).filter(n => BDFDB.ObjectUtils.is(n.patchedModules)); + if (plugins.length) { + const app = document.querySelector(BDFDB.dotCN.app); + const bdSettings = document.querySelector("#bd-settingspane-container > *"); + if (app) { + selectedTypes = [selectedTypes].flat(10).filter(n => n).map(type => type && InternalData.ModuleUtilsConfig.PatchMap[type] ? InternalData.ModuleUtilsConfig.PatchMap[type] + " _ _ " + type : type); + let updateData = {}; + for (let plugin of plugins) { + updateData[plugin.name] = { + filteredModules: [], + specialModules: [], + specialModuleTypes: [], + patchTypes: {} + }; + for (let patchType in plugin.patchedModules) for (let type in plugin.patchedModules[patchType]) { + let methodNames = [plugin.patchedModules[patchType][type]].flat(10).filter(n => n); + if (BDFDB.ArrayUtils.includes(methodNames, "componentDidMount", "componentDidUpdate", "render", false) && (!selectedTypes.length || selectedTypes.includes(type))) { + let unmappedType = type.split(" _ _ ")[1] || type; + let selector = [InternalData.ModuleUtilsConfig.Finder[unmappedType]].flat(10).filter(n => DiscordClasses[n]).map(n => BDFDB.dotCN[n]).join(", "); + let specialFilter = InternalData.ModuleUtilsConfig.Finder[unmappedType] && InternalData.ModuleUtilsConfig.Finder[unmappedType].special && Internal.createFilter(InternalData.ModuleUtilsConfig.Finder[unmappedType].special); + if (selector && typeof specialFilter == "function") { + for (let ele of document.querySelectorAll(selector)) { + let constro = specialFilter(BDFDB.ReactUtils.getInstance(ele)); + if (constro) { + updateData[plugin.name].specialModules.push([type, constro]); + updateData[plugin.name].specialModuleTypes.push(type); + break; + } + } + } + else updateData[plugin.name].filteredModules.push(type); + let name = type.split(" _ _ ")[0]; + if (!updateData[plugin.name].patchTypes[name]) updateData[plugin.name].patchTypes[name] = []; + updateData[plugin.name].patchTypes[name].push(patchType); + } + } + } + let updateDataArray = BDFDB.ObjectUtils.toArray(updateData); + if (BDFDB.ArrayUtils.sum(updateDataArray.map(n => n.filteredModules.length + n.specialModules.length))) { + try { + let filteredModules = BDFDB.ArrayUtils.removeCopies(updateDataArray.map(n => n.filteredModules).flat(10)); + let specialModules = BDFDB.ArrayUtils.removeCopies(updateDataArray.map(n => n.specialModules).flat(10)); + const appInsDown = BDFDB.ReactUtils.findOwner(app, {name: filteredModules, type: specialModules, all: true, unlimited: true, group: true}); + const appInsUp = BDFDB.ReactUtils.findOwner(app, {name: filteredModules, type: specialModules, all: true, unlimited: true, group: true, up: true}); + for (let type in appInsDown) { + let filteredPlugins = plugins.filter(n => updateData[n.name].filteredModules.includes(type) || updateData[n.name].specialModuleTypes.includes(type)).map(n => ({plugin: n, patchTypes: updateData[n.name].patchTypes})); + for (let ins of appInsDown[type]) Internal.forceInitiateProcess(filteredPlugins, ins, type); + } + for (let type in appInsUp) { + let filteredPlugins = plugins.filter(n => updateData[n.name].filteredModules.includes(type) || updateData[n.name].specialModuleTypes.includes(type)).map(n => ({plugin: n, patchTypes: updateData[n.name].patchTypes})); + for (let ins of appInsUp[type]) Internal.forceInitiateProcess(filteredPlugins, ins, type); + } + if (bdSettings) { + const bdSettingsIns = BDFDB.ReactUtils.findOwner(bdSettings, {name: filteredModules, type: specialModules, all: true, unlimited: true}); + if (bdSettingsIns.length) { + const bdSettingsWrap = BDFDB.ReactUtils.findOwner(BDFDB.ReactUtils.getInstance(document.querySelector("#bd-settingspane-container > *")), {props: "onChange", up: true}); + if (bdSettingsWrap && bdSettingsWrap.props && typeof bdSettingsWrap.props.onChange == "function") bdSettingsWrap.props.onChange(bdSettingsWrap.props.type); + } + } + } + catch (err) {for (let plugin of plugins) BDFDB.LogUtils.error(["Could not force update Components!", err], plugin);} + } + } + } + }; + + BDFDB.DiscordConstants = BDFDB.ModuleUtils.findByProperties("Permissions", "ActivityTypes"); + + const DiscordObjects = {}; + Internal.DiscordObjects = new Proxy(DiscordObjects, { + get: function (_, item) { + if (DiscordObjects[item]) return DiscordObjects[item]; + if (!InternalData.DiscordObjects[item]) return (function () {}); + if (InternalData.DiscordObjects[item].props) DiscordObjects[item] = BDFDB.ModuleUtils.findByPrototypes(InternalData.DiscordObjects[item].props); + else if (InternalData.DiscordObjects[item].strings) DiscordObjects[item] = BDFDB.ModuleUtils.findByString(InternalData.DiscordObjects[item].strings); + if (InternalData.DiscordObjects[item].value) DiscordObjects[item] = (DiscordObjects[item] || {})[InternalData.DiscordObjects[item].value]; + return DiscordObjects[item] ? DiscordObjects[item] : (function () {}); + } + }); + BDFDB.DiscordObjects = Internal.DiscordObjects; + + const LibraryRequires = {}; + Internal.LibraryRequires = new Proxy(LibraryRequires, { + get: function (_, item) { + if (LibraryRequires[item]) return LibraryRequires[item]; + if (InternalData.LibraryRequires.indexOf(item) == -1) return (function () {}); + try {LibraryRequires[item] = require(item);} + catch (err) {} + return LibraryRequires[item] ? LibraryRequires[item] : (function () {}); + } + }); + BDFDB.LibraryRequires = Internal.LibraryRequires; + + const LibraryModules = {}; + LibraryModules.LanguageStore = BDFDB.ModuleUtils.find(m => m.Messages && m.Messages.IMAGE && m); + LibraryModules.React = BDFDB.ModuleUtils.findByProperties("createElement", "cloneElement"); + LibraryModules.ReactDOM = BDFDB.ModuleUtils.findByProperties("render", "findDOMNode"); + Internal.LibraryModules = new Proxy(LibraryModules, { + get: function (_, item) { + if (LibraryModules[item]) return LibraryModules[item]; + if (!InternalData.LibraryModules[item]) return null; + if (InternalData.LibraryModules[item].props) { + if (InternalData.LibraryModules[item].nonProps) { + LibraryModules[item] = BDFDB.ModuleUtils.find(m => InternalData.LibraryModules[item].props.every(prop => { + const value = m[prop]; + return value !== undefined && !(typeof value == "string" && !value); + }) && InternalData.LibraryModules[item].nonProps.every(prop => m[prop] === undefined) && m); + if (!LibraryModules[item]) BDFDB.LogUtils.warn(`${JSON.stringify([InternalData.LibraryModules[item].props, InternalData.LibraryModules[item].nonProps].flat(10))} [props + nonProps] not found in WebModules`); + } + else LibraryModules[item] = BDFDB.ModuleUtils.findByProperties(InternalData.LibraryModules[item].props); + } + else if (InternalData.LibraryModules[item].name) LibraryModules[item] = BDFDB.ModuleUtils.findByName(InternalData.LibraryModules[item].name); + else if (InternalData.LibraryModules[item].strings) LibraryModules[item] = BDFDB.ModuleUtils.findByString(InternalData.LibraryModules[item].strings); + if (InternalData.LibraryModules[item].value) LibraryModules[item] = (LibraryModules[item] || {})[InternalData.LibraryModules[item].value]; + return LibraryModules[item] ? LibraryModules[item] : null; + } + }); + + BDFDB.LibraryModules = Internal.LibraryModules; + + if (Internal.LibraryModules.KeyCodeUtils) Internal.LibraryModules.KeyCodeUtils.getString = function (keyArray) { + return Internal.LibraryModules.KeyCodeUtils.toString([keyArray].flat(10).filter(n => n).map(keyCode => [BDFDB.DiscordConstants.KeyboardDeviceTypes.KEYBOARD_KEY, Internal.LibraryModules.KeyCodeUtils.keyToCode((Object.entries(Internal.LibraryModules.KeyEvents.codes).find(n => n[1] == keyCode && Internal.LibraryModules.KeyCodeUtils.keyToCode(n[0], null)) || [])[0], null) || keyCode]), true); + }; + + BDFDB.ReactUtils = Object.assign({}, Internal.LibraryModules.React, Internal.LibraryModules.ReactDOM); + BDFDB.ReactUtils.childrenToArray = function (parent) { + if (parent && parent.props && parent.props.children && !BDFDB.ArrayUtils.is(parent.props.children)) { + const child = parent.props.children; + parent.props.children = []; + parent.props.children.push(child); + } + return parent.props.children; + } + BDFDB.ReactUtils.createElement = function (component, props = {}, errorWrap = false) { + if (component && component.defaultProps) for (let key in component.defaultProps) if (props[key] == null) props[key] = component.defaultProps[key]; + try { + let child = Internal.LibraryModules.React.createElement(component || "div", props) || null; + if (errorWrap) return Internal.LibraryModules.React.createElement(Internal.ErrorBoundary, {key: child && child.key || ""}, child) || null; + else return child; + } + catch (err) {BDFDB.LogUtils.error(["Could not create React Element!", err]);} + return null; + }; + BDFDB.ReactUtils.objectToReact = function (obj) { + if (!obj) return null; + else if (typeof obj == "string") return obj; + else if (BDFDB.ObjectUtils.is(obj)) return BDFDB.ReactUtils.createElement(obj.type || obj.props && obj.props.href && "a" || "div", !obj.props ? {} : Object.assign({}, obj.props, { + children: obj.props.children ? BDFDB.ReactUtils.objectToReact(obj.props.children) : null + })); + else if (BDFDB.ArrayUtils.is(obj)) return obj.map(n => BDFDB.ReactUtils.objectToReact(n)); + else return null; + }; + BDFDB.ReactUtils.markdownParse = function (str) { + if (!BDFDB.ReactUtils.markdownParse.parser || !BDFDB.ReactUtils.markdownParse.render) { + BDFDB.ReactUtils.markdownParse.parser = Internal.LibraryModules.SimpleMarkdownParser.parserFor(Internal.LibraryModules.SimpleMarkdownParser.defaultRules); + BDFDB.ReactUtils.markdownParse.render = Internal.LibraryModules.SimpleMarkdownParser.reactFor(Internal.LibraryModules.SimpleMarkdownParser.ruleOutput(Internal.LibraryModules.SimpleMarkdownParser.defaultRules, "react")); + } + return BDFDB.ReactUtils.markdownParse.render(BDFDB.ReactUtils.markdownParse.parser(str, {inline: true})); + }; + BDFDB.ReactUtils.elementToReact = function (node, ref) { + if (BDFDB.ReactUtils.isValidElement(node)) return node; + else if (!Node.prototype.isPrototypeOf(node)) return null; + else if (node.nodeType == Node.TEXT_NODE) return node.nodeValue; + let attributes = {}, importantStyles = []; + if (typeof ref == "function") attributes.ref = ref; + if (node.attributes) { + for (let attr of node.attributes) attributes[attr.name] = attr.value; + if (node.attributes.style) attributes.style = BDFDB.ObjectUtils.filter(node.style, n => node.style[n] && isNaN(parseInt(n)), true); + } + attributes.children = []; + if (node.style && node.style.cssText) for (let propStr of node.style.cssText.split(";")) if (propStr.endsWith("!important")) { + let key = propStr.split(":")[0]; + let camelprop = key.replace(/-([a-z]?)/g, (m, g) => g.toUpperCase()); + if (attributes.style[camelprop] != null) importantStyles.push(key); + } + for (let child of node.childNodes) attributes.children.push(BDFDB.ReactUtils.elementToReact(child)); + attributes.className = BDFDB.DOMUtils.formatClassName(attributes.className, attributes.class); + delete attributes.class; + return BDFDB.ReactUtils.forceStyle(BDFDB.ReactUtils.createElement(node.tagName, attributes), importantStyles); + }; + BDFDB.ReactUtils.forceStyle = function (reactEle, styles) { + if (!BDFDB.ReactUtils.isValidElement(reactEle)) return null; + if (!BDFDB.ObjectUtils.is(reactEle.props.style) || !BDFDB.ArrayUtils.is(styles) || !styles.length) return reactEle; + let ref = reactEle.ref; + reactEle.ref = instance => { + if (typeof ref == "function") ref(instance); + let node = BDFDB.ReactUtils.findDOMNode(instance); + if (Node.prototype.isPrototypeOf(node)) for (let key of styles) { + let propValue = reactEle.props.style[key.replace(/-([a-z]?)/g, (m, g) => g.toUpperCase())]; + if (propValue != null) node.style.setProperty(key, propValue, "important"); + } + }; + return reactEle; + }; + BDFDB.ReactUtils.findChild = function (nodeOrInstance, config) { + if (!nodeOrInstance || !BDFDB.ObjectUtils.is(config) || !config.name && !config.key && !config.props && !config.filter) return config.all ? [] : null; + let instance = Node.prototype.isPrototypeOf(nodeOrInstance) ? BDFDB.ReactUtils.getInstance(nodeOrInstance) : nodeOrInstance; + if (!BDFDB.ObjectUtils.is(instance) && !BDFDB.ArrayUtils.is(instance)) return null; + config.name = config.name && [config.name].flat().filter(n => n); + config.key = config.key && [config.key].flat().filter(n => n); + config.props = config.props && [config.props].flat().filter(n => n); + config.filter = typeof config.filter == "function" && config.filter; + let depth = -1; + let start = performance.now(); + let maxDepth = config.unlimited ? 999999999 : (config.depth === undefined ? 30 : config.depth); + let maxTime = config.unlimited ? 999999999 : (config.time === undefined ? 150 : config.time); + + let foundChildren = []; + let singleChild = getChild(instance); + if (config.all) { + for (let i in foundChildren) delete foundChildren[i].BDFDBreactSearch; + return foundChildren; + } + else return singleChild; + + function getChild (children) { + let result = null; + if (!children || depth >= maxDepth || performance.now() - start >= maxTime) return result; + if (!BDFDB.ArrayUtils.is(children)) { + if (check(children)) { + if (config.all === undefined || !config.all) result = children; + else if (config.all) { + if (!children.BDFDBreactSearch) { + children.BDFDBreactSearch = true; + foundChildren.push(children); + } + } + } + else { + if (children.props && children.props.children) { + depth++; + result = getChild(children.props.children); + depth--; + } + if (!result && children.props && children.props.child) { + depth++; + result = getChild(children.props.child); + depth--; + } + } + } + else { + for (let child of children) if (child) { + if (BDFDB.ArrayUtils.is(child)) result = getChild(child); + else if (check(child)) { + if (config.all === undefined || !config.all) result = child; + else if (config.all) { + if (!child.BDFDBreactSearch) { + child.BDFDBreactSearch = true; + foundChildren.push(child); + } + } + } + else { + if (child.props && child.props.children) { + depth++; + result = getChild(child.props.children); + depth--; + } + if (!result && child.props && child.props.child) { + depth++; + result = getChild(child.props.child); + depth--; + } + } + if (result) break; + } + } + return result; + } + function check (instance) { + if (!instance) return false; + let props = instance.stateNode ? instance.stateNode.props : instance.props; + return instance.type && config.name && config.name.some(name => BDFDB.ReactUtils.isCorrectInstance(instance, name)) || config.key && config.key.some(key => instance.key == key) || props && config.props && config.props[config.someProps ? "some" : "every"](prop => BDFDB.ArrayUtils.is(prop) ? (BDFDB.ArrayUtils.is(prop[1]) ? prop[1].some(checkValue => propCheck(props, prop[0], checkValue)) : propCheck(props, prop[0], prop[1])) : props[prop] !== undefined) || config.filter && config.filter(instance); + } + function propCheck (props, key, value) { + return key != null && props[key] != null && value != null && (key == "className" ? (" " + props[key] + " ").indexOf(" " + value + " ") > -1 : BDFDB.equals(props[key], value)); + } + }; + BDFDB.ReactUtils.setChild = function (parent, stringOrChild) { + if (!BDFDB.ReactUtils.isValidElement(parent) || (!BDFDB.ReactUtils.isValidElement(stringOrChild) && typeof stringOrChild != "string" && !BDFDB.ArrayUtils.is(stringOrChild))) return; + let set = false; + checkParent(parent); + function checkParent(child) { + if (set) return; + if (!BDFDB.ArrayUtils.is(child)) checkChild(child); + else for (let subChild of child) checkChild(subChild); + } + function checkChild(child) { + if (!BDFDB.ReactUtils.isValidElement(child)) return; + if (BDFDB.ReactUtils.isValidElement(child.props.children)) checkParent(child.props.children); + else if (BDFDB.ArrayUtils.is(child.props.children)) { + if (child.props.children.every(c => !c || typeof c == "string")) { + set = true; + child.props.children = [stringOrChild].flat(10); + } + else checkParent(child.props.children); + } + else { + set = true; + child.props.children = stringOrChild; + } + } + }; + BDFDB.ReactUtils.findConstructor = function (nodeOrInstance, types, config = {}) { + if (!BDFDB.ObjectUtils.is(config)) return null; + if (!nodeOrInstance || !types) return config.all ? (config.group ? {} : []) : null; + let instance = Node.prototype.isPrototypeOf(nodeOrInstance) ? BDFDB.ReactUtils.getInstance(nodeOrInstance) : nodeOrInstance; + if (!BDFDB.ObjectUtils.is(instance)) return config.all ? (config.group ? {} : []) : null; + types = types && [types].flat(10).filter(n => typeof n == "string"); + if (!types.length) return config.all ? (config.group ? {} : []) : null;; + let depth = -1; + let start = performance.now(); + let maxDepth = config.unlimited ? 999999999 : (config.depth === undefined ? 30 : config.depth); + let maxTime = config.unlimited ? 999999999 : (config.time === undefined ? 150 : config.time); + let whitelist = config.up ? { + return: true, + sibling: true, + default: true + } : { + child: true, + sibling: true, + default: true + }; + whitelist[BDFDB.ReactUtils.instanceKey] = true; + + let foundConstructors = config.group ? {} : []; + let singleConstructor = getConstructor(instance); + if (config.all) { + for (let i in foundConstructors) { + if (config.group) for (let j in foundConstructors[i]) delete foundConstructors[i][j].BDFDBreactSearch; + else delete foundConstructors[i].BDFDBreactSearch; + } + return foundConstructors; + } + else return singleConstructor; + + function getConstructor (instance) { + depth++; + let result = undefined; + if (instance && !Node.prototype.isPrototypeOf(instance) && !BDFDB.ReactUtils.getInstance(instance) && depth < maxDepth && performance.now() - start < maxTime) { + if (instance.type && types.some(name => BDFDB.ReactUtils.isCorrectInstance(instance, name.split(" _ _ ")[0]))) { + if (config.all === undefined || !config.all) result = instance.type; + else if (config.all) { + if (!instance.type.BDFDBreactSearch) { + instance.type.BDFDBreactSearch = true; + if (config.group) { + if (instance.type && (instance.type.render && instance.type.render.displayName || instance.type.displayName || instance.type.name)) { + let group = config.name.find(name => (instance.type.render && instance.type.render.displayName || instance.type.displayName || instance.type.name || instance.type) == name.split(" _ _ ")[0]) || "Default"; + if (!BDFDB.ArrayUtils.is(foundConstructors[group])) foundConstructors[group] = []; + foundConstructors[group].push(instance.stateNode); + } + } + else foundConstructors.push(instance.type); + } + } + } + if (result === undefined) { + let keys = Object.getOwnPropertyNames(instance); + for (let i = 0; result === undefined && i < keys.length; i++) { + let key = keys[i]; + if (key && whitelist[key] && (typeof instance[key] === "object" || typeof instance[key] == "function")) result = getConstructor(instance[key]); + } + } + } + depth--; + return result; + } + }; + BDFDB.ReactUtils.findDOMNode = function (instance) { + if (Node.prototype.isPrototypeOf(instance)) return instance; + if (!instance || !instance.updater || typeof instance.updater.isMounted !== "function" || !instance.updater.isMounted(instance)) return null; + let node = Internal.LibraryModules.ReactDOM.findDOMNode(instance) || BDFDB.ObjectUtils.get(instance, "child.stateNode"); + return Node.prototype.isPrototypeOf(node) ? node : null; + }; + BDFDB.ReactUtils.findOwner = function (nodeOrInstance, config) { + if (!BDFDB.ObjectUtils.is(config)) return null; + if (!nodeOrInstance || !config.name && !config.type && !config.key && !config.props && !config.filter) return config.all ? (config.group ? {} : []) : null; + let instance = Node.prototype.isPrototypeOf(nodeOrInstance) ? BDFDB.ReactUtils.getInstance(nodeOrInstance) : nodeOrInstance; + if (!BDFDB.ObjectUtils.is(instance)) return config.all ? (config.group ? {} : []) : null; + config.name = config.name && [config.name].flat().filter(n => n); + config.type = config.type && [config.type].flat().filter(n => n); + config.key = config.key && [config.key].flat().filter(n => n); + config.props = config.props && [config.props].flat().filter(n => n); + config.filter = typeof config.filter == "function" && config.filter; + let depth = -1; + let start = performance.now(); + let maxDepth = config.unlimited ? 999999999 : (config.depth === undefined ? 30 : config.depth); + let maxTime = config.unlimited ? 999999999 : (config.time === undefined ? 150 : config.time); + let whitelist = config.up ? { + return: true, + sibling: true, + default: true + } : { + child: true, + sibling: true, + default: true + }; + whitelist[BDFDB.ReactUtils.instanceKey] = true; + + let foundInstances = config.group ? {} : []; + let singleInstance = getOwner(instance); + if (config.all) { + for (let i in foundInstances) { + if (config.group) for (let j in foundInstances[i]) delete foundInstances[i][j].BDFDBreactSearch; + else delete foundInstances[i].BDFDBreactSearch; + } + return foundInstances; + } + else return singleInstance; + + function getOwner (instance) { + depth++; + let result = undefined; + if (instance && !Node.prototype.isPrototypeOf(instance) && !BDFDB.ReactUtils.getInstance(instance) && depth < maxDepth && performance.now() - start < maxTime) { + let props = instance.stateNode ? instance.stateNode.props : instance.props; + if (instance.stateNode && !Node.prototype.isPrototypeOf(instance.stateNode) && (instance.type && config.name && config.name.some(name => BDFDB.ReactUtils.isCorrectInstance(instance, name.split(" _ _ ")[0])) || instance.type && config.type && config.type.some(type => BDFDB.ArrayUtils.is(type) ? instance.type === type[1] : instance.type === type) || instance.key && config.key && config.key.some(key => instance.key == key) || props && config.props && config.props.every(prop => BDFDB.ArrayUtils.is(prop) ? (BDFDB.ArrayUtils.is(prop[1]) ? prop[1].some(checkValue => BDFDB.equals(props[prop[0]], checkValue)) : BDFDB.equals(props[prop[0]], prop[1])) : props[prop] !== undefined)) || config.filter && config.filter(instance)) { + if (config.all === undefined || !config.all) result = instance.stateNode; + else if (config.all) { + if (!instance.stateNode.BDFDBreactSearch) { + instance.stateNode.BDFDBreactSearch = true; + if (config.group) { + if (config.name && instance.type && (instance.type.render && instance.type.render.displayName || instance.type.displayName || instance.type.name || instance.type)) { + let group = config.name.find(name => (instance.type.render && instance.type.render.displayName || instance.type.displayName || instance.type.name || instance.type) == name.split(" _ _ ")[0]) || "Default"; + if (!BDFDB.ArrayUtils.is(foundInstances[group])) foundInstances[group] = []; + foundInstances[group].push(instance.stateNode); + } + else if (config.type && instance.type) { + let group = [config.type.find(t => BDFDB.ArrayUtils.is(t) && instance.type === t[1])].flat(10)[0] || "Default"; + if (!BDFDB.ArrayUtils.is(foundInstances[group])) foundInstances[group] = []; + foundInstances[group].push(instance.stateNode); + } + } + else foundInstances.push(instance.stateNode); + } + } + } + if (result === undefined) { + let keys = Object.getOwnPropertyNames(instance); + for (let i = 0; result === undefined && i < keys.length; i++) { + let key = keys[i]; + if (key && whitelist[key] && (typeof instance[key] === "object" || typeof instance[key] == "function")) result = getOwner(instance[key]); + } + } + } + depth--; + return result; + } + }; + BDFDB.ReactUtils.findParent = function (nodeOrInstance, config) { + if (!nodeOrInstance || !BDFDB.ObjectUtils.is(config) || !config.name && !config.key && !config.props && !config.filter) return [null, -1]; + let instance = Node.prototype.isPrototypeOf(nodeOrInstance) ? BDFDB.ReactUtils.getInstance(nodeOrInstance) : nodeOrInstance; + if (!BDFDB.ObjectUtils.is(instance) && !BDFDB.ArrayUtils.is(instance) || instance.props && typeof instance.props.children == "function") return [null, -1]; + config.name = config.name && [config.name].flat().filter(n => n); + config.key = config.key && [config.key].flat().filter(n => n); + config.props = config.props && [config.props].flat().filter(n => n); + config.filter = typeof config.filter == "function" && config.filter; + let parent, firstArray; + parent = firstArray = instance; + while (!BDFDB.ArrayUtils.is(firstArray) && firstArray.props && firstArray.props.children) firstArray = firstArray.props.children; + if (!BDFDB.ArrayUtils.is(firstArray)) { + if (parent && parent.props) { + parent.props.children = [parent.props.children]; + firstArray = parent.props.children; + } + else firstArray = []; + } + return getParent(instance); + function getParent (children) { + let result = [firstArray, -1]; + if (!children) return result; + if (!BDFDB.ArrayUtils.is(children)) { + if (check(children)) result = found(children); + else { + if (children.props && children.props.children) { + parent = children; + result = getParent(children.props.children); + } + if (!(result && result[1] > -1) && children.props && children.props.child) { + parent = children; + result = getParent(children.props.child); + } + } + } + else { + for (let i = 0; result[1] == -1 && i < children.length; i++) if (children[i]) { + if (BDFDB.ArrayUtils.is(children[i])) { + parent = children; + result = getParent(children[i]); + } + else if (check(children[i])) { + parent = children; + result = found(children[i]); + } + else { + if (children[i].props && children[i].props.children) { + parent = children[i]; + result = getParent(children[i].props.children); + } + if (!(result && result[1] > -1) && children[i].props && children[i].props.child) { + parent = children[i]; + result = getParent(children[i].props.child); + } + } + } + } + return result; + } + function found (child) { + if (BDFDB.ArrayUtils.is(parent)) return [parent, parent.indexOf(child)]; + else { + parent.props.children = []; + parent.props.children.push(child); + return [parent.props.children, 0]; + } + } + function check (instance) { + if (!instance || instance == parent) return false; + let props = instance.stateNode ? instance.stateNode.props : instance.props; + return instance.type && config.name && config.name.some(name => BDFDB.ReactUtils.isCorrectInstance(instance, name)) || config.key && config.key.some(key => instance.key == key) || props && config.props && config.props[config.someProps ? "some" : "every"](prop => BDFDB.ArrayUtils.is(prop) ? (BDFDB.ArrayUtils.is(prop[1]) ? prop[1].some(checkValue => propCheck(props, prop[0], checkValue)) : propCheck(props, prop[0], prop[1])) : props[prop] !== undefined) || config.filter && config.filter(instance); + } + function propCheck (props, key, value) { + return key != null && props[key] != null && value != null && (key == "className" ? (" " + props[key] + " ").indexOf(" " + value + " ") > -1 : BDFDB.equals(props[key], value)); + } + }; + BDFDB.ReactUtils.findProps = function (nodeOrInstance, config) { + if (!BDFDB.ObjectUtils.is(config)) return null; + if (!nodeOrInstance || !config.name && !config.key) return null; + let instance = Node.prototype.isPrototypeOf(nodeOrInstance) ? BDFDB.ReactUtils.getInstance(nodeOrInstance) : nodeOrInstance; + if (!BDFDB.ObjectUtils.is(instance)) return null; + config.name = config.name && [config.name].flat().filter(n => n); + config.key = config.key && [config.key].flat().filter(n => n); + let depth = -1; + let start = performance.now(); + let maxDepth = config.unlimited ? 999999999 : (config.depth === undefined ? 30 : config.depth); + let maxTime = config.unlimited ? 999999999 : (config.time === undefined ? 150 : config.time); + let whitelist = config.up ? { + return: true, + sibling: true, + default: true + } : { + child: true, + sibling: true, + default: true + }; + whitelist[BDFDB.ReactUtils.instanceKey] = true; + return findProps(instance); + + function findProps (instance) { + depth++; + let result = undefined; + if (instance && !Node.prototype.isPrototypeOf(instance) && !BDFDB.ReactUtils.getInstance(instance) && depth < maxDepth && performance.now() - start < maxTime) { + if (instance.memoizedProps && (instance.type && config.name && config.name.some(name => BDFDB.ReactUtils.isCorrectInstance(instance, name.split(" _ _ ")[0])) || config.key && config.key.some(key => instance.key == key))) result = instance.memoizedProps; + if (result === undefined) { + let keys = Object.getOwnPropertyNames(instance); + for (let i = 0; result === undefined && i < keys.length; i++) { + let key = keys[i]; + if (key && whitelist[key] && (typeof instance[key] === "object" || typeof instance[key] == "function")) result = findProps(instance[key]); + } + } + } + depth--; + return result; + } + }; + BDFDB.ReactUtils.findValue = function (nodeOrInstance, searchKey, config = {}) { + if (!BDFDB.ObjectUtils.is(config)) return null; + if (!nodeOrInstance || typeof searchKey != "string") return config.all ? [] : null; + let instance = Node.prototype.isPrototypeOf(nodeOrInstance) ? BDFDB.ReactUtils.getInstance(nodeOrInstance) : nodeOrInstance; + if (!BDFDB.ObjectUtils.is(instance)) return config.all ? [] : null; + instance = instance[BDFDB.ReactUtils.instanceKey] || instance; + let depth = -1; + let start = performance.now(); + let maxDepth = config.unlimited ? 999999999 : (config.depth === undefined ? 30 : config.depth); + let maxTime = config.unlimited ? 999999999 : (config.time === undefined ? 150 : config.time); + let whitelist = { + props: true, + state: true, + stateNode: true, + updater: true, + prototype: true, + type: true, + children: config.up ? false : true, + memoizedProps: true, + memoizedState: true, + child: config.up ? false : true, + return: config.up ? true : false, + sibling: config.up ? false : true + }; + let blacklist = { + contextSection: true + }; + if (BDFDB.ObjectUtils.is(config.whitelist)) Object.assign(whitelist, config.whiteList); + if (BDFDB.ObjectUtils.is(config.blacklist)) Object.assign(blacklist, config.blacklist); + let foundKeys = []; + let singleKey = getKey(instance); + if (config.all) return foundKeys; + else return singleKey; + function getKey(instance) { + depth++; + let result = undefined; + if (instance && !Node.prototype.isPrototypeOf(instance) && !BDFDB.ReactUtils.getInstance(instance) && depth < maxDepth && performance.now() - start < maxTime) { + let keys = Object.getOwnPropertyNames(instance); + for (let i = 0; result === undefined && i < keys.length; i++) { + let key = keys[i]; + if (key && !blacklist[key]) { + let value = instance[key]; + if (searchKey === key && (config.value === undefined || BDFDB.equals(config.value, value))) { + if (config.all === undefined || !config.all) result = value; + else if (config.all) { + if (config.noCopies === undefined || !config.noCopies) foundKeys.push(value); + else if (config.noCopies) { + let copy = false; + for (let foundKey of foundKeys) if (BDFDB.equals(value, foundKey)) { + copy = true; + break; + } + if (!copy) foundKeys.push(value); + } + } + } + else if ((typeof value === "object" || typeof value == "function") && (whitelist[key] || key[0] == "." || !isNaN(key[0]))) result = getKey(value); + } + } + } + depth--; + return result; + } + }; + BDFDB.ReactUtils.forceUpdate = function (...instances) { + for (let ins of instances.flat(10).filter(n => n)) if (ins.updater && typeof ins.updater.isMounted == "function" && ins.updater.isMounted(ins)) ins.forceUpdate(); + }; + BDFDB.ReactUtils.getInstance = function (node) { + if (!BDFDB.ObjectUtils.is(node)) return null; + return node[Object.keys(node).find(key => key.startsWith("__reactInternalInstance") || key.startsWith("__reactFiber"))]; + }; + BDFDB.ReactUtils.isCorrectInstance = function (instance, name) { + return instance && ((instance.type && (instance.type.render && instance.type.render.displayName === name || instance.type.displayName === name || instance.type.name === name || instance.type === name)) || instance.render && (instance.render.displayName === name || instance.render.name === name) || instance.displayName == name || instance.name === name); + }; + BDFDB.ReactUtils.render = function (component, node) { + if (!BDFDB.ReactUtils.isValidElement(component) || !Node.prototype.isPrototypeOf(node)) return; + try { + Internal.LibraryModules.ReactDOM.render(component, node); + let observer = new MutationObserver(changes => changes.forEach(change => { + let nodes = Array.from(change.removedNodes); + if (nodes.indexOf(node) > -1 || nodes.some(n => n.contains(node))) { + observer.disconnect(); + BDFDB.ReactUtils.unmountComponentAtNode(node); + } + })); + observer.observe(document.body, {subtree: true, childList: true}); + } + catch (err) {BDFDB.LogUtils.error(["Could not render React Element!", err]);} + }; + BDFDB.ReactUtils.hookCall = function (callback, args) { + if (typeof callback != "function") return null; + let returnValue = null, tempNode = document.createElement("div"); + BDFDB.ReactUtils.render(BDFDB.ReactUtils.createElement(_ => { + returnValue = callback(args); + return null; + }), tempNode); + BDFDB.ReactUtils.unmountComponentAtNode(tempNode); + return returnValue; + }; + + BDFDB.MessageUtils = {}; + BDFDB.MessageUtils.isSystemMessage = function (message) { + return message && !BDFDB.DiscordConstants.USER_MESSAGE_TYPES.has(message.type) && (message.type !== BDFDB.DiscordConstants.MessageTypes.APPLICATION_COMMAND || message.interaction == null); + }; + BDFDB.MessageUtils.rerenderAll = function (instant) { + BDFDB.TimeUtils.clear(BDFDB.MessageUtils.rerenderAll.timeout); + BDFDB.MessageUtils.rerenderAll.timeout = BDFDB.TimeUtils.timeout(_ => { + let channelId = Internal.LibraryModules.LastChannelStore.getChannelId(); + if (channelId) { + if (BDFDB.DMUtils.isDMChannel(channelId)) BDFDB.DMUtils.markAsRead(channelId); + else BDFDB.ChannelUtils.markAsRead(channelId); + } + let LayerProviderIns = BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.messageswrapper), {name: "LayerProvider", unlimited: true, up: true}); + let LayerProviderPrototype = BDFDB.ObjectUtils.get(LayerProviderIns, `${BDFDB.ReactUtils.instanceKey}.type.prototype`); + if (LayerProviderIns && LayerProviderPrototype) { + BDFDB.PatchUtils.patch({name: "BDFDB MessageUtils"}, LayerProviderPrototype, "render", {after: e => { + e.returnValue.props.children = typeof e.returnValue.props.children == "function" ? (_ => {return null;}) : []; + BDFDB.ReactUtils.forceUpdate(LayerProviderIns); + }}, {once: true}); + BDFDB.ReactUtils.forceUpdate(LayerProviderIns); + } + }, instant ? 0 : 1000); + }; + BDFDB.MessageUtils.openMenu = function (message, e = mousePosition, slim = false) { + if (!message) return; + let channel = Internal.LibraryModules.ChannelStore.getChannel(message.channel_id); + if (!channel) return; + e = BDFDB.ListenerUtils.copyEvent(e.nativeEvent || e, (e.nativeEvent || e).currentTarget); + let menu = BDFDB.ModuleUtils.findByName(slim ? "MessageSearchResultContextMenu" : "MessageContextMenu", false, true); + if (menu) Internal.LibraryModules.ContextMenuUtils.openContextMenu(e, e2 => BDFDB.ReactUtils.createElement(menu.exports.default, Object.assign({}, e2, {message, channel}))); + else Internal.lazyLoadModuleImports(BDFDB.ModuleUtils.findByString(slim ? ["SearchResult", "message:", "openContextMenu"] : ["useHoveredMessage", "useContextMenuUser", "openContextMenu"])).then(_ => { + menu = BDFDB.ModuleUtils.findByName(slim ? "MessageSearchResultContextMenu" : "MessageContextMenu", false); + if (menu) Internal.LibraryModules.ContextMenuUtils.openContextMenu(e, e2 => BDFDB.ReactUtils.createElement(menu.exports.default, Object.assign({}, e2, {message, channel}))); + }); + }; + + BDFDB.UserUtils = {}; + BDFDB.UserUtils.is = function (user) { + return user && user instanceof Internal.DiscordObjects.User; + }; + const myDataUser = Internal.LibraryModules.UserStore && Internal.LibraryModules.UserStore.getCurrentUser && Internal.LibraryModules.UserStore.getCurrentUser(); + if (myDataUser && BDFDB.UserUtils._id != myDataUser.id) { + document.body.setAttribute("data-current-user-id", myDataUser.id); + BDFDB.UserUtils._id = myDataUser.id; + } + BDFDB.UserUtils.me = new Proxy(myDataUser || {}, { + get: function (list, item) { + const user = Internal.LibraryModules.UserStore && Internal.LibraryModules.UserStore.getCurrentUser && Internal.LibraryModules.UserStore.getCurrentUser(); + if (user && BDFDB.UserUtils._id != user.id) { + Cache.data = {}; + document.body.setAttribute("data-current-user-id", user.id); + BDFDB.UserUtils._id = user.id; + } + return user ? user[item] : null; + } + }); + BDFDB.UserUtils.getStatus = function (id = BDFDB.UserUtils.me.id) { + id = typeof id == "number" ? id.toFixed() : id; + let activity = BDFDB.UserUtils.getActivity(id); + return activity && activity.type == BDFDB.DiscordConstants.ActivityTypes.STREAMING ? "streaming" : Internal.LibraryModules.StatusMetaUtils.getStatus(id); + }; + BDFDB.UserUtils.getStatusColor = function (status, useColor) { + status = typeof status == "string" ? status.toLowerCase() : null; + switch (status) { + case "online": return useColor ? BDFDB.DiscordConstants.Colors.STATUS_GREEN_600 : "var(--bdfdb-green)"; + case "idle": return useColor ? BDFDB.DiscordConstants.Colors.STATUS_YELLOW : "var(--bdfdb-yellow)"; + case "dnd": return useColor ? BDFDB.DiscordConstants.Colors.STATUS_RED : "var(--bdfdb-red)"; + case "playing": return useColor ? BDFDB.DiscordConstants.Colors.BRAND : "var(--bdfdb-blurple)"; + case "listening": return BDFDB.DiscordConstants.Colors.SPOTIFY; + case "streaming": return BDFDB.DiscordConstants.Colors.TWITCH; + default: return BDFDB.DiscordConstants.Colors.STATUS_GREY; + } + }; + BDFDB.UserUtils.getActivity = function (id = BDFDB.UserUtils.me.id) { + for (let activity of Internal.LibraryModules.StatusMetaUtils.getActivities(id)) if (activity.type != BDFDB.DiscordConstants.ActivityTypes.CUSTOM_STATUS) return activity; + return null; + }; + BDFDB.UserUtils.getCustomStatus = function (id = BDFDB.UserUtils.me.id) { + for (let activity of Internal.LibraryModules.StatusMetaUtils.getActivities(id)) if (activity.type == BDFDB.DiscordConstants.ActivityTypes.CUSTOM_STATUS) return activity; + return null; + }; + BDFDB.UserUtils.getAvatar = function (id = BDFDB.UserUtils.me.id) { + let user = Internal.LibraryModules.UserStore.getUser(id); + if (!user) return window.location.origin + "/assets/1f0bfc0865d324c2587920a7d80c609b.png"; + else return ((user.avatar ? "" : window.location.origin) + Internal.LibraryModules.IconUtils.getUserAvatarURL(user)).split("?")[0]; + }; + BDFDB.UserUtils.getBanner = function (id = BDFDB.UserUtils.me.id, canAnimate = false) { + let user = Internal.LibraryModules.UserStore.getUser(id); + if (!user || !user.banner) return ""; + return Internal.LibraryModules.IconUtils.getUserBannerURL(Object.assign({}, user, {canAnimate})).split("?")[0]; + }; + BDFDB.UserUtils.can = function (permission, id = BDFDB.UserUtils.me.id, channelId = Internal.LibraryModules.LastChannelStore.getChannelId()) { + if (!BDFDB.DiscordConstants.Permissions[permission]) BDFDB.LogUtils.warn([permission, "not found in Permissions"]); + else { + let channel = Internal.LibraryModules.ChannelStore.getChannel(channelId); + if (channel) return Internal.LibraryModules.PermissionRoleUtils.can({permission: BDFDB.DiscordConstants.Permissions[permission], user: id, context: channel}); + } + return false; + }; + BDFDB.UserUtils.openMenu = function (user, guildId, e = mousePosition) { + if (!user || !guildId) return; + e = BDFDB.ListenerUtils.copyEvent(e.nativeEvent || e, (e.nativeEvent || e).currentTarget); + let menu = BDFDB.ModuleUtils.findByName("GuildChannelUserContextMenu", false, true); + if (menu) Internal.LibraryModules.ContextMenuUtils.openContextMenu(e, e2 => BDFDB.ReactUtils.createElement(menu.exports.default, Object.assign({}, e2, {user, guildId}))); + else Internal.lazyLoadModuleImports(BDFDB.ModuleUtils.findByString("openUserContextMenu", "user:", "openContextMenu")).then(_ => { + menu = BDFDB.ModuleUtils.findByName("GuildChannelUserContextMenu", false); + if (menu) Internal.LibraryModules.ContextMenuUtils.openContextMenu(e, e2 => BDFDB.ReactUtils.createElement(menu.exports.default, Object.assign({}, e2, {user, guildId}))); + }); + }; + + BDFDB.GuildUtils = {}; + BDFDB.GuildUtils.is = function (guild) { + if (!BDFDB.ObjectUtils.is(guild)) return false; + let keys = Object.keys(guild); + return guild instanceof Internal.DiscordObjects.Guild || Object.keys(new Internal.DiscordObjects.Guild({})).every(key => keys.indexOf(key) > -1); + }; + BDFDB.GuildUtils.getIcon = function (id) { + let guild = Internal.LibraryModules.GuildStore.getGuild(id); + if (!guild || !guild.icon) return ""; + return Internal.LibraryModules.IconUtils.getGuildIconURL(guild).split("?")[0]; + }; + BDFDB.GuildUtils.getBanner = function (id) { + let guild = Internal.LibraryModules.GuildStore.getGuild(id); + if (!guild || !guild.banner) return ""; + return Internal.LibraryModules.IconUtils.getGuildBannerURL(guild).split("?")[0]; + }; + BDFDB.GuildUtils.getFolder = function (id) { + return Internal.LibraryModules.FolderStore.guildFolders.filter(n => n.folderId).find(n => n.guildIds.includes(id)); + }; + BDFDB.GuildUtils.openMenu = function (guild, e = mousePosition) { + if (!guild) return; + e = BDFDB.ListenerUtils.copyEvent(e.nativeEvent || e, (e.nativeEvent || e).currentTarget); + let menu = BDFDB.ModuleUtils.findByName("GuildContextMenuWrapper", false, true); + if (menu) Internal.LibraryModules.ContextMenuUtils.openContextMenu(e, e2 => BDFDB.ReactUtils.createElement(menu.exports.default, Object.assign({}, e2, {guild}))); + else Internal.lazyLoadModuleImports(BDFDB.ModuleUtils.findByString("renderUnavailableBadge", "guild:", "openContextMenu")).then(_ => { + menu = BDFDB.ModuleUtils.findByName("GuildContextMenuWrapper", false); + if (menu) Internal.LibraryModules.ContextMenuUtils.openContextMenu(e, e2 => BDFDB.ReactUtils.createElement(menu.exports.default, Object.assign({}, e2, {guild}))); + }); + }; + BDFDB.GuildUtils.markAsRead = function (guildIds) { + guildIds = [guildIds].flat(10).filter(id => id && typeof id == "string" && Internal.LibraryModules.GuildStore.getGuild(id)); + if (!guildIds) return; + let channels = guildIds.map(id => [BDFDB.ObjectUtils.toArray(Internal.LibraryModules.GuildChannelStore.getChannels(id)), Internal.LibraryModules.GuildEventStore.getGuildScheduledEventsForGuild(id)]).flat(10).map(n => n && (n.channel && n.channel.id || n.id)).flat().filter(n => n); + if (channels.length) BDFDB.ChannelUtils.markAsRead(channels); + let eventChannels = guildIds.map(id => ({ + channelId: id, + readStateType: Internal.LibraryModules.UnreadStateTypes.GUILD_EVENT, + messageId: Internal.LibraryModules.UnreadChannelUtils.lastMessageId(id, Internal.LibraryModules.UnreadStateTypes.GUILD_EVENT) + })).filter(n => n.messageId); + if (eventChannels.length) Internal.LibraryModules.AckUtils.bulkAck(eventChannels); + }; + BDFDB.GuildUtils.rerenderAll = function (instant) { + BDFDB.TimeUtils.clear(BDFDB.GuildUtils.rerenderAll.timeout); + BDFDB.GuildUtils.rerenderAll.timeout = BDFDB.TimeUtils.timeout(_ => { + let ShakeableIns = BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.appcontainer), {name: "Shakeable", unlimited: true, up: true}); + let ShakeablePrototype = BDFDB.ObjectUtils.get(ShakeableIns, `${BDFDB.ReactUtils.instanceKey}.type.prototype`); + if (ShakeableIns && ShakeablePrototype) { + BDFDB.PatchUtils.patch({name: "BDFDB GuildUtils"}, ShakeablePrototype, "render", {after: e => { + e.returnValue.props.children = typeof e.returnValue.props.children == "function" ? (_ => {return null;}) : []; + BDFDB.ReactUtils.forceUpdate(ShakeableIns); + }}, {once: true}); + BDFDB.ReactUtils.forceUpdate(ShakeableIns); + } + }, instant ? 0 : 1000); + }; + + BDFDB.FolderUtils = {}; + BDFDB.FolderUtils.getId = function (div) { + if (!Node.prototype.isPrototypeOf(div) || !BDFDB.ReactUtils.getInstance(div)) return; + div = BDFDB.DOMUtils.getParent(BDFDB.dotCN.guildfolderwrapper, div); + if (!div) return; + return BDFDB.ReactUtils.findValue(div, "folderId", {up: true}); + }; + BDFDB.FolderUtils.getDefaultName = function (folderId) { + let folder = Internal.LibraryModules.FolderStore.getGuildFolderById(folderId); + if (!folder) return ""; + let rest = 2 * BDFDB.DiscordConstants.MAX_GUILD_FOLDER_NAME_LENGTH; + let names = [], allNames = folder.guildIds.map(guildId => (Internal.LibraryModules.GuildStore.getGuild(guildId) || {}).name).filter(n => n); + for (let name of allNames) if (name.length < rest || names.length === 0) { + names.push(name); + rest -= name.length; + } + return names.join(", ") + (names.length < allNames.length ? ", ..." : ""); + }; + + BDFDB.ChannelUtils = {}; + BDFDB.ChannelUtils.is = function (channel) { + if (!BDFDB.ObjectUtils.is(channel)) return false; + let keys = Object.keys(channel); + return channel instanceof Internal.DiscordObjects.Channel || Object.keys(new Internal.DiscordObjects.Channel({})).every(key => keys.indexOf(key) > -1); + }; + BDFDB.ChannelUtils.isTextChannel = function (channelOrId) { + let channel = typeof channelOrId == "string" ? Internal.LibraryModules.ChannelStore.getChannel(channelOrId) : channelOrId; + return BDFDB.ObjectUtils.is(channel) && (channel.type == BDFDB.DiscordConstants.ChannelTypes.GUILD_TEXT || channel.type == BDFDB.DiscordConstants.ChannelTypes.GUILD_STORE || channel.type == BDFDB.DiscordConstants.ChannelTypes.GUILD_ANNOUNCEMENT); + }; + BDFDB.ChannelUtils.isThread = function (channelOrId) { + let channel = typeof channelOrId == "string" ? Internal.LibraryModules.ChannelStore.getChannel(channelOrId) : channelOrId; + return channel && channel.isThread(); + }; + BDFDB.ChannelUtils.isEvent = function (channelOrId) { + let channel = typeof channelOrId == "string" ? Internal.LibraryModules.GuildEventStore.getGuildScheduledEvent(channelOrId) : channelOrId; + return channel && Internal.LibraryModules.GuildEventStore.getGuildScheduledEvent(channel.id) && true; + }; + BDFDB.ChannelUtils.markAsRead = function (channelIds) { + let unreadChannels = [channelIds].flat(10).filter(id => id && typeof id == "string" && (BDFDB.LibraryModules.ChannelStore.getChannel(id) || {}).type != BDFDB.DiscordConstants.ChannelTypes.GUILD_CATEGORY && (Internal.LibraryModules.UnreadChannelUtils.hasUnread(id) || Internal.LibraryModules.UnreadChannelUtils.getMentionCount(id) > 0)).map(id => ({ + channelId: id, + readStateType: Internal.LibraryModules.UnreadStateTypes.CHANNEL, + messageId: Internal.LibraryModules.UnreadChannelUtils.lastMessageId(id) + })); + if (unreadChannels.length) Internal.LibraryModules.AckUtils.bulkAck(unreadChannels); + }; + BDFDB.ChannelUtils.rerenderAll = function (instant) { + BDFDB.TimeUtils.clear(BDFDB.ChannelUtils.rerenderAll.timeout); + BDFDB.ChannelUtils.rerenderAll.timeout = BDFDB.TimeUtils.timeout(_ => { + let ChannelsIns = BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.guildchannels), {name: "Channels", unlimited: true}); + let ChannelsPrototype = BDFDB.ObjectUtils.get(ChannelsIns, `${BDFDB.ReactUtils.instanceKey}.type.prototype`); + if (ChannelsIns && ChannelsPrototype) { + BDFDB.PatchUtils.patch({name: "BDFDB ChannelUtils"}, ChannelsPrototype, "render", {after: e => { + e.returnValue.props.children = typeof e.returnValue.props.children == "function" ? (_ => {return null;}) : []; + BDFDB.ReactUtils.forceUpdate(ChannelsIns); + }}, {once: true}); + BDFDB.ReactUtils.forceUpdate(ChannelsIns); + } + }, instant ? 0 : 1000); + }; + + BDFDB.DMUtils = {}; + BDFDB.DMUtils.isDMChannel = function (id) { + let channel = Internal.LibraryModules.ChannelStore.getChannel(id); + return BDFDB.ObjectUtils.is(channel) && (channel.isDM() || channel.isGroupDM()); + }; + BDFDB.DMUtils.getIcon = function (id) { + let channel = Internal.LibraryModules.ChannelStore.getChannel(id); + if (!channel) return ""; + if (!channel.icon) return channel.isDM() ? BDFDB.UserUtils.getAvatar(channel.recipients[0]) : (channel.isGroupDM() ? window.location.origin + Internal.LibraryModules.IconUtils.getChannelIconURL(channel).split("?")[0] : null); + return Internal.LibraryModules.IconUtils.getChannelIconURL(channel).split("?")[0]; + }; + BDFDB.DMUtils.markAsRead = function (dmIds) { + let unreadDMs = [dmIds].flat(10).filter(id => id && typeof id == "string" && BDFDB.DMUtils.isDMChannel(id) && (Internal.LibraryModules.UnreadChannelUtils.hasUnread(id) || Internal.LibraryModules.UnreadChannelUtils.getMentionCount(id) > 0)); + if (unreadDMs.length) for (let i in unreadDMs) BDFDB.TimeUtils.timeout(_ => Internal.LibraryModules.AckUtils.ack(unreadDMs[i]), i * 1000); + }; + + BDFDB.ColorUtils = {}; + BDFDB.ColorUtils.convert = function (color, conv, type) { + if (BDFDB.ObjectUtils.is(color)) { + var newColor = {}; + for (let pos in color) newColor[pos] = BDFDB.ColorUtils.convert(color[pos], conv, type); + return newColor; + } + else { + conv = conv === undefined || !conv ? conv = "RGBCOMP" : conv.toUpperCase(); + type = type === undefined || !type || !["RGB", "RGBA", "RGBCOMP", "HSL", "HSLA", "HSLCOMP", "HEX", "HEXA", "INT"].includes(type.toUpperCase()) ? BDFDB.ColorUtils.getType(color) : type.toUpperCase(); + if (conv == "RGBCOMP") { + switch (type) { + case "RGBCOMP": + var rgbComp = [].concat(color); + if (rgbComp.length == 3) return processRGB(rgbComp); + else if (rgbComp.length == 4) { + let a = processA(rgbComp.pop()); + return processRGB(rgbComp).concat(a); + } + break; + case "RGB": + return processRGB(color.replace(/\s/g, "").slice(4, -1).split(",")); + case "RGBA": + var rgbComp = color.replace(/\s/g, "").slice(5, -1).split(","); + var a = processA(rgbComp.pop()); + return processRGB(rgbComp).concat(a); + case "HSLCOMP": + var hslComp = [].concat(color); + if (hslComp.length == 3) return BDFDB.ColorUtils.convert(`hsl(${processHSL(hslComp).join(",")})`, "RGBCOMP"); + else if (hslComp.length == 4) { + let a = processA(hslComp.pop()); + return BDFDB.ColorUtils.convert(`hsl(${processHSL(hslComp).join(",")})`, "RGBCOMP").concat(a); + } + break; + case "HSL": + var hslComp = processHSL(color.replace(/\s/g, "").slice(4, -1).split(",")); + var r, g, b, m, c, x, p, q; + var h = hslComp[0] / 360, l = parseInt(hslComp[1]) / 100, s = parseInt(hslComp[2]) / 100; m = Math.floor(h * 6); c = h * 6 - m; x = s * (1 - l); p = s * (1 - c * l); q = s * (1 - (1 - c) * l); + switch (m % 6) { + case 0: r = s, g = q, b = x; break; + case 1: r = p, g = s, b = x; break; + case 2: r = x, g = s, b = q; break; + case 3: r = x, g = p, b = s; break; + case 4: r = q, g = x, b = s; break; + case 5: r = s, g = x, b = p; break; + } + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; + case "HSLA": + var hslComp = color.replace(/\s/g, "").slice(5, -1).split(","); + return BDFDB.ColorUtils.convert(`hsl(${hslComp.slice(0, 3).join(",")})`, "RGBCOMP").concat(processA(hslComp.pop())); + case "HEX": + var hex = /^#([a-f\d]{1})([a-f\d]{1})([a-f\d]{1})$|^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color); + return [parseInt(hex[1] + hex[1] || hex[4], 16), parseInt(hex[2] + hex[2] || hex[5], 16), parseInt(hex[3] + hex[3] || hex[6], 16)]; + case "HEXA": + var hex = /^#([a-f\d]{1})([a-f\d]{1})([a-f\d]{1})([a-f\d]{1})$|^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color); + return [parseInt(hex[1] + hex[1] || hex[5], 16), parseInt(hex[2] + hex[2] || hex[6], 16), parseInt(hex[3] + hex[3] || hex[7], 16), Math.floor(BDFDB.NumberUtils.mapRange([0, 255], [0, 100], parseInt(hex[4] + hex[4] || hex[8], 16)))/100]; + case "INT": + color = processINT(color); + return [parseInt(color >> 16 & 255), parseInt(color >> 8 & 255), parseInt(color & 255)]; + default: + return null; + } + } + else { + if (conv && type && conv.indexOf("HSL") == 0 && type.indexOf("HSL") == 0) { + if (type == "HSLCOMP") { + let hslComp = [].concat(color); + switch (conv) { + case "HSLCOMP": + if (hslComp.length == 3) return processHSL(hslComp); + else if (hslComp.length == 4) { + var a = processA(hslComp.pop()); + return processHSL(hslComp).concat(a); + } + break; + case "HSL": + return `hsl(${processHSL(hslComp.slice(0, 3)).join(",")})`; + case "HSLA": + hslComp = hslComp.slice(0, 4); + var a = hslComp.length == 4 ? processA(hslComp.pop()) : 1; + return `hsla(${processHSL(hslComp).concat(a).join(",")})`; + } + } + return BDFDB.ColorUtils.convert(color.replace(/\s/g, "").slice(color.toUpperCase().indexOf("HSLA") == 0 ? 5 : 4, -1).split(","), conv, "HSLCOMP"); + } + else { + let rgbComp = type == "RGBCOMP" ? [].concat(color) : BDFDB.ColorUtils.convert(color, "RGBCOMP", type); + if (rgbComp) switch (conv) { + case "RGB": + return `rgb(${processRGB(rgbComp.slice(0, 3)).join(",")})`; + case "RGBA": + rgbComp = rgbComp.slice(0, 4); + var a = rgbComp.length == 4 ? processA(rgbComp.pop()) : 1; + return `rgba(${processRGB(rgbComp).concat(a).join(",")})`; + case "HSLCOMP": + var a = rgbComp.length == 4 ? processA(rgbComp.pop()) : null; + var hslComp = processHSL(BDFDB.ColorUtils.convert(rgbComp, "HSL").replace(/\s/g, "").split(",")); + return a != null ? hslComp.concat(a) : hslComp; + case "HSL": + var r = processC(rgbComp[0]), g = processC(rgbComp[1]), b = processC(rgbComp[2]); + var max = Math.max(r, g, b), min = Math.min(r, g, b), dif = max - min, h, l = max === 0 ? 0 : dif / max, s = max / 255; + switch (max) { + case min: h = 0; break; + case r: h = g - b + dif * (g < b ? 6 : 0); h /= 6 * dif; break; + case g: h = b - r + dif * 2; h /= 6 * dif; break; + case b: h = r - g + dif * 4; h /= 6 * dif; break; + } + return `hsl(${processHSL([Math.round(h * 360), l * 100, s * 100]).join(",")})`; + case "HSLA": + var a = rgbComp.length == 4 ? processA(rgbComp.pop()) : 1; + return `hsla(${BDFDB.ColorUtils.convert(rgbComp, "HSL").slice(4, -1).split(",").concat(a).join(",")})`; + case "HEX": + return ("#" + (0x1000000 + (rgbComp[2] | rgbComp[1] << 8 | rgbComp[0] << 16)).toString(16).slice(1)).toUpperCase(); + case "HEXA": + return ("#" + (0x1000000 + (rgbComp[2] | rgbComp[1] << 8 | rgbComp[0] << 16)).toString(16).slice(1) + (0x100 + Math.round(BDFDB.NumberUtils.mapRange([0, 100], [0, 255], processA(rgbComp[3]) * 100))).toString(16).slice(1)).toUpperCase(); + case "INT": + return processINT(rgbComp[2] | rgbComp[1] << 8 | rgbComp[0] << 16); + default: + return null; + } + } + } + } + return null; + function processC(c) {if (c == null) {return 255;} else {c = parseInt(c.toString().replace(/[^0-9\-]/g, ""));return isNaN(c) || c > 255 ? 255 : c < 0 ? 0 : c;}}; + function processRGB(comp) {return [].concat(comp).map(c => {return processC(c);});}; + function processA(a) {if (a == null) {return 1;} else {a = a.toString();a = (a.indexOf("%") > -1 ? 0.01 : 1) * parseFloat(a.replace(/[^0-9\.\-]/g, ""));return isNaN(a) || a > 1 ? 1 : a < 0 ? 0 : a;}}; + function processSL(sl) {if (sl == null) {return "100%";} else {sl = parseFloat(sl.toString().replace(/[^0-9\.\-]/g, ""));return (isNaN(sl) || sl > 100 ? 100 : sl < 0 ? 0 : sl) + "%";}}; + function processHSL(comp) {comp = [].concat(comp);let h = parseFloat(comp.shift().toString().replace(/[^0-9\.\-]/g, ""));h = isNaN(h) || h > 360 ? 360 : h < 0 ? 0 : h;return [h].concat(comp.map(sl => {return processSL(sl);}));}; + function processINT(c) {if (c == null) {return 16777215;} else {c = parseInt(c.toString().replace(/[^0-9]/g, ""));return isNaN(c) || c > 16777215 ? 16777215 : c < 0 ? 0 : c;}}; + }; + BDFDB.ColorUtils.setAlpha = function (color, a, conv) { + if (BDFDB.ObjectUtils.is(color)) { + let newcolor = {}; + for (let pos in color) newcolor[pos] = BDFDB.ColorUtils.setAlpha(color[pos], a, conv); + return newcolor; + } + else { + let rgbComp = BDFDB.ColorUtils.convert(color, "RGBCOMP"); + if (rgbComp) { + a = a.toString(); + a = (a.indexOf("%") > -1 ? 0.01 : 1) * parseFloat(a.replace(/[^0-9\.\-]/g, "")); + a = isNaN(a) || a > 1 ? 1 : a < 0 ? 0 : a; + rgbComp[3] = a; + conv = (conv || BDFDB.ColorUtils.getType(color)).toUpperCase(); + conv = conv == "RGB" || conv == "HSL" || conv == "HEX" ? conv + "A" : conv; + return BDFDB.ColorUtils.convert(rgbComp, conv); + } + } + return null; + }; + BDFDB.ColorUtils.getAlpha = function (color) { + let rgbComp = BDFDB.ColorUtils.convert(color, "RGBCOMP"); + if (rgbComp) { + if (rgbComp.length == 3) return 1; + else if (rgbComp.length == 4) { + let a = rgbComp[3].toString(); + a = (a.indexOf("%") > -1 ? 0.01 : 1) * parseFloat(a.replace(/[^0-9\.\-]/g, "")); + return isNaN(a) || a > 1 ? 1 : a < 0 ? 0 : a; + } + } + return null; + }; + BDFDB.ColorUtils.change = function (color, value, conv) { + value = parseFloat(value); + if (color != null && typeof value == "number" && !isNaN(value)) { + if (BDFDB.ObjectUtils.is(color)) { + let newColor = {}; + for (let pos in color) newColor[pos] = BDFDB.ColorUtils.change(color[pos], value, conv); + return newColor; + } + else { + let rgbComp = BDFDB.ColorUtils.convert(color, "RGBCOMP"); + if (rgbComp) { + let a = BDFDB.ColorUtils.getAlpha(rgbComp); + if (parseInt(value) !== value) { + value = value.toString(); + value = (value.indexOf("%") > -1 ? 0.01 : 1) * parseFloat(value.replace(/[^0-9\.\-]/g, "")); + value = isNaN(value) ? 0 : value; + return BDFDB.ColorUtils.convert([].concat(rgbComp).slice(0, 3).map(c => { + c = Math.round(c * (1 + value)); + return c > 255 ? 255 : c < 0 ? 0 : c; + }).concat(a), conv || BDFDB.ColorUtils.getType(color)); + } + else return BDFDB.ColorUtils.convert([].concat(rgbComp).slice(0, 3).map(c => { + c = Math.round(c + value); + return c > 255 ? 255 : c < 0 ? 0 : c; + }).concat(a), conv || BDFDB.ColorUtils.getType(color)); + } + } + } + return null; + }; + BDFDB.ColorUtils.invert = function (color, conv) { + if (BDFDB.ObjectUtils.is(color)) { + let newColor = {}; + for (let pos in color) newColor[pos] = BDFDB.ColorUtils.invert(color[pos], conv); + return newColor; + } + else { + let comp = BDFDB.ColorUtils.convert(color, "RGBCOMP"); + if (comp) return BDFDB.ColorUtils.convert([255 - comp[0], 255 - comp[1], 255 - comp[2]], conv || BDFDB.ColorUtils.getType(color)); + } + return null; + }; + BDFDB.ColorUtils.compare = function (color1, color2) { + if (color1 && color2) { + color1 = BDFDB.ColorUtils.convert(color1, "RGBA"); + color2 = BDFDB.ColorUtils.convert(color2, "RGBA"); + if (color1 && color2) return BDFDB.equals(color1, color2); + } + return null; + }; + BDFDB.ColorUtils.isBright = function (color, compare = 160) { + if (!BDFDB.ColorUtils.getType(color)) return false; + color = BDFDB.ColorUtils.convert(color, "RGBCOMP"); + if (!color) return false; + return parseInt(compare) < Math.sqrt(0.299 * color[0]**2 + 0.587 * color[1]**2 + 0.144 * color[2]**2); + }; + BDFDB.ColorUtils.getType = function (color) { + if (color != null) { + if (typeof color === "object" && (color.length == 3 || color.length == 4)) { + if (isRGB(color)) return "RGBCOMP"; + else if (isHSL(color)) return "HSLCOMP"; + } + else if (typeof color === "string") { + if (/^#[a-f\d]{3}$|^#[a-f\d]{6}$/i.test(color)) return "HEX"; + else if (/^#[a-f\d]{4}$|^#[a-f\d]{8}$/i.test(color)) return "HEXA"; + else { + color = color.toUpperCase(); + let comp = color.replace(/[^0-9\.\-\,\%]/g, "").split(","); + if (color.indexOf("RGB(") == 0 && comp.length == 3 && isRGB(comp)) return "RGB"; + else if (color.indexOf("RGBA(") == 0 && comp.length == 4 && isRGB(comp)) return "RGBA"; + else if (color.indexOf("HSL(") == 0 && comp.length == 3 && isHSL(comp)) return "HSL"; + else if (color.indexOf("HSLA(") == 0 && comp.length == 4 && isHSL(comp)) return "HSLA"; + } + } + else if (typeof color === "number" && parseInt(color) == color && color > -1 && color < 16777216) return "INT"; + } + return null; + function isRGB(comp) {return comp.slice(0, 3).every(rgb => rgb.toString().indexOf("%") == -1 && parseFloat(rgb) == parseInt(rgb));}; + function isHSL(comp) {return comp.slice(1, 3).every(hsl => hsl.toString().indexOf("%") == hsl.length - 1);}; + }; + BDFDB.ColorUtils.createGradient = function (colorObj, direction = "to right") { + let gradientString = "linear-gradient(" + direction; + for (let pos of Object.keys(colorObj).sort()) { + let color = BDFDB.ColorUtils.convert(colorObj[pos], "RGBA"); + gradientString += color ? `, ${color} ${pos*100}%` : '' + } + return gradientString += ")"; + }; + + BDFDB.DOMUtils = {}; + BDFDB.DOMUtils.getSelection = function () { + let selection = document.getSelection(); + return selection && selection.anchorNode ? selection.getRangeAt(0).toString() : ""; + }; + BDFDB.DOMUtils.addClass = function (eles, ...classes) { + if (!eles || !classes) return; + for (let ele of [eles].map(n => NodeList.prototype.isPrototypeOf(n) ? Array.from(n) : n).flat(10).filter(n => n)) { + if (Node.prototype.isPrototypeOf(ele)) add(ele); + else if (NodeList.prototype.isPrototypeOf(ele)) for (let e of ele) add(e); + else if (typeof ele == "string") for (let e of ele.split(",")) if (e && (e = e.trim())) for (let n of document.querySelectorAll(e)) add(n); + } + function add(node) { + if (node && node.classList) for (let cla of classes) for (let cl of [cla].flat(10).filter(n => n)) if (typeof cl == "string") for (let c of cl.split(" ")) if (c) node.classList.add(c); + } + }; + BDFDB.DOMUtils.removeClass = function (eles, ...classes) { + if (!eles || !classes) return; + for (let ele of [eles].map(n => NodeList.prototype.isPrototypeOf(n) ? Array.from(n) : n).flat(10).filter(n => n)) { + if (Node.prototype.isPrototypeOf(ele)) remove(ele); + else if (NodeList.prototype.isPrototypeOf(ele)) for (let e of ele) remove(e); + else if (typeof ele == "string") for (let e of ele.split(",")) if (e && (e = e.trim())) for (let n of document.querySelectorAll(e)) remove(n); + } + function remove(node) { + if (node && node.classList) for (let cla of classes) for (let cl of [cla].flat(10).filter(n => n)) if (typeof cl == "string") for (let c of cl.split(" ")) if (c) node.classList.remove(c); + } + }; + BDFDB.DOMUtils.toggleClass = function (eles, ...classes) { + if (!eles || !classes) return; + var force = classes.pop(); + if (typeof force != "boolean") { + classes.push(force); + force = undefined; + } + if (!classes.length) return; + for (let ele of [eles].map(n => NodeList.prototype.isPrototypeOf(n) ? Array.from(n) : n).flat(10).filter(n => n)) { + if (Node.prototype.isPrototypeOf(ele)) toggle(ele); + else if (NodeList.prototype.isPrototypeOf(ele)) for (let e of ele) toggle(e); + else if (typeof ele == "string") for (let e of ele.split(",")) if (e && (e = e.trim())) for (let n of document.querySelectorAll(e)) toggle(n); + } + function toggle(node) { + if (node && node.classList) for (let cla of classes) for (let cl of [cla].flat(10).filter(n => n)) if (typeof cl == "string") for (let c of cl.split(" ")) if (c) node.classList.toggle(c, force); + } + }; + BDFDB.DOMUtils.containsClass = function (eles, ...classes) { + if (!eles || !classes) return; + let all = classes.pop(); + if (typeof all != "boolean") { + classes.push(all); + all = true; + } + if (!classes.length) return; + let contained = undefined; + for (let ele of [eles].map(n => NodeList.prototype.isPrototypeOf(n) ? Array.from(n) : n).flat(10).filter(n => n)) { + if (Node.prototype.isPrototypeOf(ele)) contains(ele); + else if (NodeList.prototype.isPrototypeOf(ele)) for (let e of ele) contains(e); + else if (typeof ele == "string") for (let c of ele.split(",")) if (c && (c = c.trim())) for (let n of document.querySelectorAll(c)) contains(n); + } + return contained; + function contains(node) { + if (node && node.classList) for (let cla of classes) if (typeof cla == "string") for (let c of cla.split(" ")) if (c) { + if (contained === undefined) contained = all; + if (all && !node.classList.contains(c)) contained = false; + if (!all && node.classList.contains(c)) contained = true; + } + } + }; + BDFDB.DOMUtils.replaceClass = function (eles, oldclass, newclass) { + if (!eles || typeof oldclass != "string" || typeof newclass != "string") return; + for (let ele of [eles].map(n => NodeList.prototype.isPrototypeOf(n) ? Array.from(n) : n).flat(10).filter(n => n)) { + if (Node.prototype.isPrototypeOf(ele)) replace(ele); + else if (NodeList.prototype.isPrototypeOf(ele)) for (let e of ele) replace(e); + else if (typeof ele == "string") for (let e of ele.split(",")) if (e && (e = e.trim())) for (let n of document.querySelectorAll(e)) replace(n); + } + function replace(node) { + if (node && node.tagName && node.className) node.className = node.className.replace(new RegExp(oldclass, "g"), newclass).trim(); + } + }; + BDFDB.DOMUtils.formatClassName = function (...classes) { + return BDFDB.ArrayUtils.removeCopies(classes.flat(10).filter(n => n).join(" ").split(" ")).join(" ").trim(); + }; + BDFDB.DOMUtils.removeClassFromDOM = function (...classes) { + for (let c of classes.flat(10).filter(n => n)) if (typeof c == "string") for (let a of c.split(",")) if (a && (a = a.replace(/\.|\s/g, ""))) BDFDB.DOMUtils.removeClass(document.querySelectorAll("." + a), a); + }; + BDFDB.DOMUtils.show = function (...eles) { + BDFDB.DOMUtils.toggle(...eles, true); + }; + BDFDB.DOMUtils.hide = function (...eles) { + BDFDB.DOMUtils.toggle(...eles, false); + }; + BDFDB.DOMUtils.toggle = function (...eles) { + if (!eles) return; + let force = eles.pop(); + if (typeof force != "boolean") { + eles.push(force); + force = undefined; + } + if (!eles.length) return; + for (let ele of eles.flat(10).filter(n => n)) { + if (Node.prototype.isPrototypeOf(ele)) toggle(ele); + else if (NodeList.prototype.isPrototypeOf(ele)) for (let node of ele) toggle(node); + else if (typeof ele == "string") for (let c of ele.split(",")) if (c && (c = c.trim())) for (let node of document.querySelectorAll(c)) toggle(node); + } + function toggle(node) { + if (!node || !Node.prototype.isPrototypeOf(node)) return; + let hide = force === undefined ? !BDFDB.DOMUtils.isHidden(node) : !force; + if (hide) { + let display = node.style.getPropertyValue("display"); + if (display && display != "none") node.BDFDBhideDisplayState = { + display: display, + important: (` ${node.style.cssText} `.split(` display: ${display}`)[1] || "").trim().indexOf("!important") == 0 + }; + node.style.setProperty("display", "none", "important"); + } + else { + if (node.BDFDBhideDisplayState) { + node.style.setProperty("display", node.BDFDBhideDisplayState.display, node.BDFDBhideDisplayState.important ? "important" : ""); + delete node.BDFDBhideDisplayState; + } + else node.style.removeProperty("display"); + } + } + }; + BDFDB.DOMUtils.isHidden = function (node) { + if (Node.prototype.isPrototypeOf(node) && node.nodeType != Node.TEXT_NODE) return getComputedStyle(node, null).getPropertyValue("display") == "none"; + }; + BDFDB.DOMUtils.remove = function (...eles) { + for (let ele of eles.flat(10).filter(n => n)) { + if (Node.prototype.isPrototypeOf(ele)) ele.remove(); + else if (NodeList.prototype.isPrototypeOf(ele)) { + let nodes = Array.from(ele); + while (nodes.length) nodes.shift().remove(); + } + else if (typeof ele == "string") for (let c of ele.split(",")) if (c && (c = c.trim())) { + let nodes = Array.from(document.querySelectorAll(c)); + while (nodes.length) nodes.shift().remove(); + } + } + }; + BDFDB.DOMUtils.create = function (html) { + if (typeof html != "string" || !html.trim()) return null; + let template = document.createElement("template"); + try {template.innerHTML = html.replace(/(?[\t\r\n]+<(?!pre)/g, "><");} + catch (err) {template.innerHTML = html.replace(/>[\t\r\n]+<(?!pre)/g, "><");} + if (template.content.childNodes.length == 1) return template.content.firstElementChild || template.content.firstChild; + else { + let wrapper = document.createElement("span"); + let nodes = Array.from(template.content.childNodes); + while (nodes.length) wrapper.appendChild(nodes.shift()); + return wrapper; + } + }; + BDFDB.DOMUtils.getParent = function (listOrSelector, node) { + let parent = null; + if (Node.prototype.isPrototypeOf(node) && listOrSelector) { + let list = NodeList.prototype.isPrototypeOf(listOrSelector) ? listOrSelector : typeof listOrSelector == "string" ? document.querySelectorAll(listOrSelector) : null; + if (list) for (let listNode of list) if (listNode.contains(node)) { + parent = listNode; + break; + } + } + return parent; + }; + BDFDB.DOMUtils.setText = function (node, stringOrNode) { + if (!node || !Node.prototype.isPrototypeOf(node)) return; + let textnode = node.nodeType == Node.TEXT_NODE ? node : null; + if (!textnode) for (let child of node.childNodes) if (child.nodeType == Node.TEXT_NODE || BDFDB.DOMUtils.containsClass(child, "BDFDB-textnode")) { + textnode = child; + break; + } + if (textnode) { + if (Node.prototype.isPrototypeOf(stringOrNode) && stringOrNode.nodeType != Node.TEXT_NODE) { + BDFDB.DOMUtils.addClass(stringOrNode, "BDFDB-textnode"); + node.replaceChild(stringOrNode, textnode); + } + else if (Node.prototype.isPrototypeOf(textnode) && textnode.nodeType != Node.TEXT_NODE) node.replaceChild(document.createTextNode(stringOrNode), textnode); + else textnode.textContent = stringOrNode; + } + else node.appendChild(Node.prototype.isPrototypeOf(stringOrNode) ? stringOrNode : document.createTextNode(stringOrNode)); + }; + BDFDB.DOMUtils.getText = function (node) { + if (!node || !Node.prototype.isPrototypeOf(node)) return; + for (let child of node.childNodes) if (child.nodeType == Node.TEXT_NODE) return child.textContent; + }; + BDFDB.DOMUtils.getRects = function (node) { + let rects = {}; + if (Node.prototype.isPrototypeOf(node) && node.nodeType != Node.TEXT_NODE) { + let hideNode = node; + while (hideNode) { + let hidden = BDFDB.DOMUtils.isHidden(hideNode); + if (hidden) { + BDFDB.DOMUtils.toggle(hideNode, true); + hideNode.BDFDBgetRectsHidden = true; + } + hideNode = hideNode.parentElement; + } + rects = node.getBoundingClientRect(); + hideNode = node; + while (hideNode) { + if (hideNode.BDFDBgetRectsHidden) { + BDFDB.DOMUtils.toggle(hideNode, false); + delete hideNode.BDFDBgetRectsHidden; + } + hideNode = hideNode.parentElement; + } + } + return rects; + }; + BDFDB.DOMUtils.getHeight = function (node) { + if (Node.prototype.isPrototypeOf(node) && node.nodeType != Node.TEXT_NODE) { + let rects = BDFDB.DOMUtils.getRects(node); + let style = getComputedStyle(node); + return rects.height + parseInt(style.marginTop) + parseInt(style.marginBottom); + } + return 0; + }; + BDFDB.DOMUtils.getInnerHeight = function (node) { + if (Node.prototype.isPrototypeOf(node) && node.nodeType != Node.TEXT_NODE) { + let rects = BDFDB.DOMUtils.getRects(node); + let style = getComputedStyle(node); + return rects.height - parseInt(style.paddingTop) - parseInt(style.paddingBottom); + } + return 0; + }; + BDFDB.DOMUtils.getWidth = function (node) { + if (Node.prototype.isPrototypeOf(node) && node.nodeType != Node.TEXT_NODE) { + let rects = BDFDB.DOMUtils.getRects(node); + let style = getComputedStyle(node); + return rects.width + parseInt(style.marginLeft) + parseInt(style.marginRight); + } + return 0; + }; + BDFDB.DOMUtils.getInnerWidth = function (node) { + if (Node.prototype.isPrototypeOf(node) && node.nodeType != Node.TEXT_NODE) { + let rects = BDFDB.DOMUtils.getRects(node); + let style = getComputedStyle(node); + return rects.width - parseInt(style.paddingLeft) - parseInt(style.paddingRight); + } + return 0; + }; + BDFDB.DOMUtils.appendWebScript = function (url, container) { + if (typeof url != "string") return; + if (!container && !document.head.querySelector("bd-head bd-scripts")) document.head.appendChild(BDFDB.DOMUtils.create(``)); + container = container || document.head.querySelector("bd-head bd-scripts") || document.head; + container = Node.prototype.isPrototypeOf(container) ? container : document.head; + BDFDB.DOMUtils.removeWebScript(url, container); + let script = document.createElement("script"); + script.src = url; + container.appendChild(script); + }; + BDFDB.DOMUtils.removeWebScript = function (url, container) { + if (typeof url != "string") return; + container = container || document.head.querySelector("bd-head bd-scripts") || document.head; + container = Node.prototype.isPrototypeOf(container) ? container : document.head; + BDFDB.DOMUtils.remove(container.querySelectorAll(`script[src="${url}"]`)); + }; + BDFDB.DOMUtils.appendWebStyle = function (url, container) { + if (typeof url != "string") return; + if (!container && !document.head.querySelector("bd-head bd-styles")) document.head.appendChild(BDFDB.DOMUtils.create(``)); + container = container || document.head.querySelector("bd-head bd-styles") || document.head; + container = Node.prototype.isPrototypeOf(container) ? container : document.head; + BDFDB.DOMUtils.removeWebStyle(url, container); + container.appendChild(BDFDB.DOMUtils.create(``)); + }; + BDFDB.DOMUtils.removeWebStyle = function (url, container) { + if (typeof url != "string") return; + container = container || document.head.querySelector("bd-head bd-styles") || document.head; + container = Node.prototype.isPrototypeOf(container) ? container : document.head; + BDFDB.DOMUtils.remove(container.querySelectorAll(`link[href="${url}"]`)); + }; + BDFDB.DOMUtils.appendLocalStyle = function (id, css, container) { + if (typeof id != "string" || typeof css != "string") return; + if (!container && !document.head.querySelector("bd-head bd-styles")) document.head.appendChild(BDFDB.DOMUtils.create(``)); + container = container || document.head.querySelector("bd-head bd-styles") || document.head; + container = Node.prototype.isPrototypeOf(container) ? container : document.head; + BDFDB.DOMUtils.removeLocalStyle(id, container); + container.appendChild(BDFDB.DOMUtils.create(``)); + }; + BDFDB.DOMUtils.removeLocalStyle = function (id, container) { + if (typeof id != "string") return; + container = container || document.head.querySelector("bd-head bd-styles") || document.head; + container = Node.prototype.isPrototypeOf(container) ? container : document.head; + BDFDB.DOMUtils.remove(container.querySelectorAll(`style[id="${id}CSS"]`)); + }; + + BDFDB.ModalUtils = {}; + BDFDB.ModalUtils.open = function (plugin, config) { + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ObjectUtils.is(config)) return; + let modalInstance, modalProps, cancels = [], closeModal = _ => { + if (BDFDB.ObjectUtils.is(modalProps) && typeof modalProps.onClose == "function") modalProps.onClose(); + }; + + let titleChildren = [], headerChildren = [], contentChildren = [], footerChildren = []; + + if (typeof config.text == "string") { + config.contentClassName = BDFDB.DOMUtils.formatClassName(config.contentClassName, BDFDB.disCN.modaltextcontent); + contentChildren.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextElement, { + children: config.text + })); + } + + if (config.children) { + let tabBarItems = [], tabIns = {}; + for (let child of [config.children].flat(10).filter(n => n)) if (Internal.LibraryModules.React.isValidElement(child)) { + if (child.type == Internal.LibraryComponents.ModalComponents.ModalTabContent) { + if (!tabBarItems.length) child.props.open = true; + else delete child.props.open; + let ref = typeof child.ref == "function" ? child.ref : (_ => {}); + child.ref = instance => { + ref(instance); + if (instance) tabIns[child.props.tab] = instance; + }; + tabBarItems.push({value: child.props.tab}); + } + contentChildren.push(child); + } + if (tabBarItems.length) headerChildren.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + className: BDFDB.disCN.tabbarcontainer, + align: Internal.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TabBar, { + className: BDFDB.disCN.tabbar, + itemClassName: BDFDB.disCN.tabbaritem, + type: Internal.LibraryComponents.TabBar.Types.TOP, + items: tabBarItems, + onItemSelect: value => { + for (let key in tabIns) { + if (key == value) tabIns[key].props.open = true; + else delete tabIns[key].props.open; + } + BDFDB.ReactUtils.forceUpdate(BDFDB.ObjectUtils.toArray(tabIns)); + } + }), + config.tabBarChildren + ].flat(10).filter(n => n) + })); + } + + if (BDFDB.ArrayUtils.is(config.buttons)) for (let button of config.buttons) { + let contents = typeof button.contents == "string" && button.contents; + if (contents) { + let color = typeof button.color == "string" && Internal.LibraryComponents.Button.Colors[button.color.toUpperCase()]; + let look = typeof button.look == "string" && Internal.LibraryComponents.Button.Looks[button.look.toUpperCase()]; + let click = typeof button.click == "function" ? button.click : (typeof button.onClick == "function" ? button.onClick : _ => {}); + + if (button.cancel) cancels.push(click); + + footerChildren.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Button, BDFDB.ObjectUtils.exclude(Object.assign({}, button, { + look: look || (color ? Internal.LibraryComponents.Button.Looks.FILLED : Internal.LibraryComponents.Button.Looks.LINK), + color: color || Internal.LibraryComponents.Button.Colors.PRIMARY, + onClick: _ => { + if (button.close) closeModal(); + if (!(button.close && button.cancel)) click(modalInstance); + }, + children: contents + }), "click", "close", "cancel", "contents"))); + } + } + + contentChildren = contentChildren.concat(config.contentChildren).filter(n => n && (typeof n == "string" || BDFDB.ReactUtils.isValidElement(n))); + titleChildren = titleChildren.concat(config.titleChildren).filter(n => n && (typeof n == "string" || BDFDB.ReactUtils.isValidElement(n))); + headerChildren = headerChildren.concat(config.headerChildren).filter(n => n && (typeof n == "string" || BDFDB.ReactUtils.isValidElement(n))); + footerChildren = footerChildren.concat(config.footerChildren).filter(n => n && (typeof n == "string" || BDFDB.ReactUtils.isValidElement(n))); + + if (contentChildren.length) { + if (typeof config.onOpen != "function") config.onOpen = _ => {}; + if (typeof config.onClose != "function") config.onClose = _ => {}; + + let name = plugin.name || (typeof plugin.getName == "function" ? plugin.getName() : null); + name = typeof name == "string" ? name : null; + let oldTransitionState = 0; + Internal.LibraryModules.ModalUtils.openModal(props => { + modalProps = props; + return BDFDB.ReactUtils.createElement(class BDFDB_Modal extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.ModalComponents.ModalRoot, { + className: BDFDB.DOMUtils.formatClassName(name && `${name}-modal`, BDFDB.disCN.modalwrapper, config.className), + size: typeof config.size == "string" && Internal.LibraryComponents.ModalComponents.ModalSize[config.size.toUpperCase()] || Internal.LibraryComponents.ModalComponents.ModalSize.SMALL, + transitionState: props.transitionState, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.ModalComponents.ModalHeader, { + className: BDFDB.DOMUtils.formatClassName(config.headerClassName, config.shade && BDFDB.disCN.modalheadershade, headerChildren.length && BDFDB.disCN.modalheaderhassibling), + separator: config.headerSeparator || false, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex.Child, { + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormTitle, { + tag: Internal.LibraryComponents.FormComponents.FormTitle.Tags.H4, + children: config.header + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextElement, { + size: Internal.LibraryComponents.TextElement.Sizes.SIZE_12, + children: typeof config.subHeader == "string" || BDFDB.ReactUtils.isValidElement(config.subHeader) ? config.subHeader : (name || "") + }) + ] + }), + titleChildren, + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.ModalComponents.ModalCloseButton, { + onClick: closeModal + }) + ].flat(10).filter(n => n) + }), + headerChildren.length ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + grow: 0, + shrink: 0, + children: headerChildren + }) : null, + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.ModalComponents.ModalContent, { + className: config.contentClassName, + scroller: config.scroller, + direction: config.direction, + content: config.content, + children: contentChildren + }), + footerChildren.length ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.ModalComponents.ModalFooter, { + className: config.footerClassName, + direction: config.footerDirection, + children: footerChildren + }) : null + ] + }); + } + componentDidMount() { + modalInstance = this; + if (props.transitionState == 1 && props.transitionState > oldTransitionState) config.onOpen(modalInstance); + oldTransitionState = props.transitionState; + } + componentWillUnmount() { + if (props.transitionState == 3) { + for (let cancel of cancels) cancel(modalInstance); + config.onClose(modalInstance); + } + } + }, props, true); + }, { + onCloseRequest: closeModal + }); + } + }; + BDFDB.ModalUtils.confirm = function (plugin, text, callback) { + if (!BDFDB.ObjectUtils.is(plugin) || typeof text != "string") return; + BDFDB.ModalUtils.open(plugin, { + text: text, + header: BDFDB.LanguageUtils.LibraryStrings.confirm, + className: BDFDB.disCN.modalconfirmmodal, + scroller: false, + buttons: [ + {contents: BDFDB.LanguageUtils.LanguageStrings.OKAY, close: true, color: "RED", onClick: callback}, + {contents: BDFDB.LanguageUtils.LanguageStrings.CANCEL, close: true} + ] + }); + }; + + const RealMenuItems = BDFDB.ModuleUtils.findByProperties("MenuItem", "MenuGroup"); + BDFDB.ContextMenuUtils = {}; + BDFDB.ContextMenuUtils.open = function (plugin, e, children) { + Internal.LibraryModules.ContextMenuUtils.openContextMenu(e, _ => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Menu, { + navId: "bdfdb-context", + onClose: Internal.LibraryModules.ContextMenuUtils.closeContextMenu, + children: children + }, true)); + }; + BDFDB.ContextMenuUtils.close = function (nodeOrInstance) { + if (!BDFDB.ObjectUtils.is(nodeOrInstance)) return; + let instance = BDFDB.ReactUtils.findOwner(nodeOrInstance, {props: "closeContextMenu", up: true}); + if (BDFDB.ObjectUtils.is(instance) && instance.props && typeof instance.props.closeContextMenu == "function") instance.props.closeContextMenu(); + else Internal.LibraryModules.ContextMenuUtils.closeContextMenu(); + }; + BDFDB.ContextMenuUtils.createItem = function (component, props = {}) { + if (!component) return null; + else { + if (props.render || props.persisting || BDFDB.ObjectUtils.is(props.popoutProps) || (typeof props.color == "string" && !DiscordClasses[`menu${props.color.toLowerCase()}`])) component = Internal.MenuItem; + if (BDFDB.ObjectUtils.toArray(RealMenuItems).some(c => c == component)) return BDFDB.ReactUtils.createElement(component, props); + else return BDFDB.ReactUtils.createElement(RealMenuItems.MenuItem, { + id: props.id, + disabled: props.disabled, + customItem: true, + render: menuItemProps => { + if (!props.state) props.state = BDFDB.ObjectUtils.extract(props, "checked", "value"); + return BDFDB.ReactUtils.createElement(Internal.CustomMenuItemWrapper, { + disabled: props.disabled, + childProps: Object.assign({}, props, menuItemProps, {color: props.color}), + children: component + }, true); + } + }); + } + }; + BDFDB.ContextMenuUtils.createItemId = function (...strings) { + return strings.map(s => typeof s == "number" ? s.toString() : s).filter(s => typeof s == "string").map(s => s.toLowerCase().replace(/\s/, "-")).join("-"); + }; + BDFDB.ContextMenuUtils.findItem = function (returnvalue, config) { + if (!returnvalue || !BDFDB.ObjectUtils.is(config) || !config.label && !config.id) return [null, -1]; + config.label = config.label && [config.label].flat().filter(n => n); + config.id = config.id && [config.id].flat().filter(n => n); + let contextMenu = BDFDB.ReactUtils.findChild(returnvalue, {props: "navId"}) || (BDFDB.ArrayUtils.is(returnvalue) ? {props: {children: returnvalue}} : null); + if (contextMenu) { + for (let i in contextMenu.props.children) { + if (contextMenu.props.children[i] && contextMenu.props.children[i].type == RealMenuItems.MenuGroup) { + if (BDFDB.ArrayUtils.is(contextMenu.props.children[i].props.children)) { + for (let j in contextMenu.props.children[i].props.children) if (check(contextMenu.props.children[i].props.children[j])) { + if (config.group) return [contextMenu.props.children, parseInt(i)]; + else return [contextMenu.props.children[i].props.children, parseInt(j)]; + } + } + else if (contextMenu.props.children[i] && contextMenu.props.children[i].props) { + if (check(contextMenu.props.children[i].props.children)) { + if (config.group) return [contextMenu.props.children, parseInt(i)]; + else { + contextMenu.props.children[i].props.children = [contextMenu.props.children[i].props.children]; + return [contextMenu.props.children[i].props.children, 0]; + } + } + else if (contextMenu.props.children[i].props.children && contextMenu.props.children[i].props.children.props && BDFDB.ArrayUtils.is(contextMenu.props.children[i].props.children.props.children)) { + for (let j in contextMenu.props.children[i].props.children.props.children) if (check(contextMenu.props.children[i].props.children.props.children[j])) { + if (config.group) return [contextMenu.props.children, parseInt(i)]; + else return [contextMenu.props.children[i].props.children.props.children, parseInt(j)]; + } + } + } + } + else if (check(contextMenu.props.children[i])) return [contextMenu.props.children, parseInt(i)]; + } + return [contextMenu.props.children, -1]; + } + return [null, -1]; + function check (child) { + if (!child) return false; + let props = child.stateNode ? child.stateNode.props : child.props; + if (!props) return false; + return config.id && config.id.some(key => props.id == key) || config.label && config.label.some(key => props.label == key); + } + }; + + BDFDB.StringUtils = {}; + BDFDB.StringUtils.htmlEscape = function (string) { + let ele = document.createElement("div"); + ele.innerText = string; + return ele.innerHTML; + }; + BDFDB.StringUtils.regEscape = function (string) { + return typeof string == "string" && string.replace(/([\-\/\\\^\$\*\+\?\.\(\)\|\[\]\{\}])/g, "\\$1"); + }; + BDFDB.StringUtils.insertNRST = function (string) { + return typeof string == "string" && string.replace(/\\r/g, "\r").replace(/\\n/g, "\n").replace(/\\t/g, "\t").replace(/\\s/g, " "); + }; + BDFDB.StringUtils.highlight = function (string, searchstring, prefix = ``, suffix = ``) { + if (typeof string != "string" || !searchstring || searchstring.length < 1) return string; + let offset = 0, original = string; + BDFDB.ArrayUtils.getAllIndexes(string.toUpperCase(), searchstring.toUpperCase()).forEach(index => { + let d1 = offset * (prefix.length + suffix.length); + index = index + d1; + let d2 = index + searchstring.length; + let d3 = [-1].concat(BDFDB.ArrayUtils.getAllIndexes(string.substring(0, index), "<")); + let d4 = [-1].concat(BDFDB.ArrayUtils.getAllIndexes(string.substring(0, index), ">")); + if (d3[d3.length - 1] > d4[d4.length - 1]) return; + string = string.substring(0, index) + prefix + string.substring(index, d2) + suffix + string.substring(d2); + offset++; + }); + return string || original; + }; + BDFDB.StringUtils.findMatchCaseless = function (match, string, any) { + if (typeof match != "string" || typeof string != "string" || !match || !string) return ""; + match = BDFDB.StringUtils.regEscape(match); + let exec = (new RegExp(any ? `([\\n\\r\\s]+${match})|(^${match})` : `([\\n\\r\\s]+${match}[\\n\\r\\s]+)|([\\n\\r\\s]+${match}$)|(^${match}[\\n\\r\\s]+)|(^${match}$)`, "i")).exec(string); + return exec && typeof exec[0] == "string" && exec[0].replace(/[\n\r\s]/g, "") || ""; + }; + BDFDB.StringUtils.equalCase = function (match, string) { + if (typeof match != "string" || typeof string != "string") return ""; + let first = match.charAt(0); + return first != first.toUpperCase() ? (string.charAt(0).toLowerCase() + string.slice(1)) : first != first.toLowerCase() ? (string.charAt(0).toUpperCase() + string.slice(1)) : string; + }; + BDFDB.StringUtils.extractSelection = function (original, selection) { + if (typeof original != "string") return ""; + if (typeof selection != "string") return original; + let s = [], f = [], wrong = 0, canceled = false, done = false; + for (let i of BDFDB.ArrayUtils.getAllIndexes(original, selection[0])) if (!done) { + while (i <= original.length && !done) { + let subSelection = selection.slice(s.filter(n => n != undefined).length); + if (!subSelection && s.length - 20 <= selection.length) done = true; + else for (let j in subSelection) if (!done && !canceled) { + if (original[i] == subSelection[j]) { + s[i] = subSelection[j]; + f[i] = subSelection[j]; + wrong = 0; + if (i == original.length) done = true; + } + else { + s[i] = null; + f[i] = original[i]; + wrong++; + if (wrong > 4) { + s = [], f = [], wrong = 0, canceled = true; + break; + } + } + break; + } + canceled = false; + i++; + } + } + if (s.filter(n => n).length) { + let reverseS = [].concat(s).reverse(), i = 0, j = 0; + for (let k in s) { + if (s[k] == null) i = parseInt(k) + 1; + else break; + } + for (let k in reverseS) { + if (reverseS[k] == null) j = parseInt(k) + 1; + else break; + } + return f.slice(i, f.length - j).join(""); + } + else return original; + }; + + BDFDB.SlateUtils = {}; + BDFDB.SlateUtils.isRichValue = function (richValue) { + return richValue && typeof richValue == "object" && BDFDB.SlateUtils.toRichValue("").constructor.prototype.isPrototypeOf(richValue); + }; + BDFDB.SlateUtils.toTextValue = function (richValue) { + return BDFDB.SlateUtils.isRichValue(richValue) ? Internal.LibraryModules.SlateTextUtils.toTextValue(richValue) : ""; + }; + BDFDB.SlateUtils.toRichValue = function (string) { + return typeof string == "string" ? Internal.LibraryModules.SlateRichUtils.toRichValue(string) : null; + }; + + BDFDB.NumberUtils = {}; + BDFDB.NumberUtils.formatBytes = function (bytes, sigDigits) { + bytes = parseInt(bytes); + if (isNaN(bytes) || bytes < 0) return "0 Bytes"; + if (bytes == 1) return "1 Byte"; + let size = Math.floor(Math.log(bytes) / Math.log(1024)); + return parseFloat((bytes / Math.pow(1024, size)).toFixed(sigDigits < 1 ? 0 : sigDigits > 20 ? 20 : sigDigits || 2)) + " " + ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][size]; + }; + BDFDB.NumberUtils.mapRange = function (from, to, value) { + if (parseFloat(value) < parseFloat(from[0])) return parseFloat(to[0]); + else if (parseFloat(value) > parseFloat(from[1])) return parseFloat(to[1]); + else return parseFloat(to[0]) + (parseFloat(value) - parseFloat(from[0])) * (parseFloat(to[1]) - parseFloat(to[0])) / (parseFloat(from[1]) - parseFloat(from[0])); + }; + BDFDB.NumberUtils.generateId = function (array) { + array = BDFDB.ArrayUtils.is(array) ? array : []; + let id = Math.floor(Math.random() * 10000000000000000); + if (array.includes(id)) return BDFDB.NumberUtils.generateId(array); + else { + array.push(id); + return id; + } + }; + BDFDB.NumberUtils.compareVersions = function (newV, oldV) { + if (!newV || !oldV) return true; + newV = newV.toString().replace(/["'`]/g, "").split(/,|\./g).map(n => parseInt(n)).filter(n => (n || n == 0) && !isNaN(n)); + oldV = oldV.toString().replace(/["'`]/g, "").split(/,|\./g).map(n => parseInt(n)).filter(n => (n || n == 0) && !isNaN(n)); + let length = Math.max(newV.length, oldV.length); + if (!length) return true; + if (newV.length > oldV.length) { + let tempArray = new Array(newV.length - oldV.length); + for (let i = 0; i < tempArray.length; i++) tempArray[i] = 0; + oldV = tempArray.concat(oldV); + } + else if (newV.length < oldV.length) { + let tempArray = new Array(oldV.length - newV.length); + for (let i = 0; i < tempArray.length; i++) tempArray[i] = 0; + newV = tempArray.concat(newV); + } + for (let i = 0; i < length; i++) for (let iOutdated = false, j = 0; j <= i; j++) { + if (j == i && newV[j] < oldV[j]) return false; + if (j < i) iOutdated = newV[j] == oldV[j]; + if ((j == 0 || iOutdated) && j == i && newV[j] > oldV[j]) return true; + } + return false; + }; + BDFDB.NumberUtils.getVersionDifference = function (newV, oldV) { + if (!newV || !oldV) return false; + newV = newV.toString().replace(/["'`]/g, "").split(/,|\./g).map(n => parseInt(n)).filter(n => (n || n == 0) && !isNaN(n)); + oldV = oldV.toString().replace(/["'`]/g, "").split(/,|\./g).map(n => parseInt(n)).filter(n => (n || n == 0) && !isNaN(n)); + let length = Math.max(newV.length, oldV.length); + if (!length) return false; + if (newV.length > oldV.length) { + let tempArray = new Array(newV.length - oldV.length); + for (let i = 0; i < tempArray.length; i++) tempArray[i] = 0; + oldV = tempArray.concat(oldV); + } + else if (newV.length < oldV.length) { + let tempArray = new Array(oldV.length - newV.length); + for (let i = 0; i < tempArray.length; i++) tempArray[i] = 0; + newV = tempArray.concat(newV); + } + let oldValue = 0, newValue = 0; + for (let i in oldV.reverse()) oldValue += (oldV[i] * (10 ** i)); + for (let i in newV.reverse()) newValue += (newV[i] * (10 ** i)); + return (newValue - oldValue) / (10 ** (length-1)); + }; + + BDFDB.DiscordUtils = {}; + BDFDB.DiscordUtils.openLink = function (url, config = {}) { + if ((config.inBuilt || config.inBuilt === undefined && Internal.settings.general.useChromium) && Internal.LibraryRequires.electron && Internal.LibraryRequires.electron.remote) { + let browserWindow = new Internal.LibraryRequires.electron.remote.BrowserWindow({ + frame: true, + resizeable: true, + show: true, + darkTheme: BDFDB.DiscordUtils.getTheme() == BDFDB.disCN.themedark, + webPreferences: { + nodeIntegration: false, + nodeIntegrationInWorker: false + } + }); + browserWindow.setMenu(null); + browserWindow.loadURL(url); + if (config.minimized) browserWindow.minimize(null); + } + else window.open(url, "_blank"); + }; + window.DiscordNative && window.DiscordNative.app && window.DiscordNative.app.getPath("appData").then(path => {BDFDB.DiscordUtils.getFolder.base = path;}); + BDFDB.DiscordUtils.getFolder = function () { + if (!BDFDB.DiscordUtils.getFolder.base) return ""; + else if (BDFDB.DiscordUtils.getFolder.folder) return BDFDB.DiscordUtils.getFolder.folder; + else { + let folder; + try { + let build = BDFDB.DiscordUtils.getBuild(); + build = "discord" + (build == "stable" ? "" : build); + folder = Internal.LibraryRequires.path.resolve(BDFDB.DiscordUtils.getFolder.base, build, BDFDB.DiscordUtils.getVersion()); + } + catch (err) {folder = BDFDB.DiscordUtils.getFolder.base;} + return BDFDB.DiscordUtils.getFolder.folder = folder; + } + }; + BDFDB.DiscordUtils.getBuild = function () { + if (BDFDB.DiscordUtils.getBuild.build) return BDFDB.DiscordUtils.getBuild.build; + else { + let build; + try {build = window.DiscordNative.app.getReleaseChannel();} + catch (err) { + let version = BDFDB.DiscordUtils.getVersion(); + if (version) { + version = version.split("."); + if (version.length == 3 && !isNaN(version = parseInt(version[2]))) build = version > 300 ? "stable" : version > 200 ? "canary" : "ptb"; + else build = "stable"; + } + else build = "stable"; + } + return BDFDB.DiscordUtils.getBuild.build = build; + } + }; + BDFDB.DiscordUtils.getVersion = function () { + if (BDFDB.DiscordUtils.getVersion.version) return BDFDB.DiscordUtils.getVersion.version; + else { + let version; + try {version = window.DiscordNative.app.getVersion();} + catch (err) {version = "999.999.9999";} + return BDFDB.DiscordUtils.getVersion.version = version; + } + }; + BDFDB.DiscordUtils.isDevModeEnabled = function () { + return BDFDB.DiscordUtils.getSettings("developerMode"); + }; + BDFDB.DiscordUtils.getExperiment = function (id) { + if (!id) return null; + const module = BDFDB.ModuleUtils.find(m => m.definition && m.definition.defaultConfig && m.definition.defaultConfig[id] != null && typeof m.getCurrentConfig == "function" && m); + return module && (module.getCurrentConfig({}) || {})[id]; + }; + BDFDB.DiscordUtils.getTheme = function () { + return BDFDB.DiscordUtils.getSettings("theme") != "dark" ? BDFDB.disCN.themelight : BDFDB.disCN.themedark; + }; + BDFDB.DiscordUtils.getMode = function () { + return BDFDB.DiscordUtils.getSettings("messageDisplayCompact") ? "compact" : "cozy"; + }; + BDFDB.DiscordUtils.getSettings = function (key) { + if (!key) return null; + else if (Internal.LibraryModules.SettingsUtils && (Internal.LibraryModules.SettingsUtils[key] || Internal.LibraryModules.SettingsUtils[key + "DoNotUseYet"])) return (Internal.LibraryModules.SettingsUtils[key] || Internal.LibraryModules.SettingsUtils[key + "DoNotUseYet"]).getSetting(); + else { + const value = Internal.LibraryModules.SettingsStore.getAllSettings()[key.slice(0, 1).toLowerCase() + key.slice(1)]; + return value != undefined ? value: null; + } + }; + BDFDB.DiscordUtils.setSettings = function (key, value) { + if (!key) return; + else if (Internal.LibraryModules.SettingsUtils && (Internal.LibraryModules.SettingsUtils[key] || Internal.LibraryModules.SettingsUtils[key + "DoNotUseYet"])) (Internal.LibraryModules.SettingsUtils[key] || Internal.LibraryModules.SettingsUtils[key + "DoNotUseYet"]).updateSetting(value); + else Internal.LibraryModules.SettingsUtilsOld.updateRemoteSettings({[key.slice(0, 1).toLowerCase() + key.slice(1)]: value}); + }; + BDFDB.DiscordUtils.getZoomFactor = function () { + let aRects = BDFDB.DOMUtils.getRects(document.querySelector(BDFDB.dotCN.appmount)); + let widthZoom = Math.round(100 * window.outerWidth / aRects.width); + let heightZoom = Math.round(100 * window.outerHeight / aRects.height); + return widthZoom < heightZoom ? widthZoom : heightZoom; + }; + BDFDB.DiscordUtils.getFontScale = function () { + return parseInt(document.firstElementChild.style.fontSize.replace("%", "")); + }; + BDFDB.DiscordUtils.shake = function () { + BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.appcontainer), {name: "Shakeable", unlimited: true, up: true}).shake(); + }; + BDFDB.DiscordUtils.rerenderAll = function (instant) { + BDFDB.TimeUtils.clear(BDFDB.DiscordUtils.rerenderAll.timeout); + BDFDB.DiscordUtils.rerenderAll.timeout = BDFDB.TimeUtils.timeout(_ => { + let ShakeableIns = BDFDB.ReactUtils.findOwner(document.querySelector(BDFDB.dotCN.appcontainer), {name: "Shakeable", unlimited: true, up: true}); + let ShakeablePrototype = BDFDB.ObjectUtils.get(ShakeableIns, `${BDFDB.ReactUtils.instanceKey}.type.prototype`); + if (ShakeableIns && ShakeablePrototype) { + BDFDB.PatchUtils.patch({name: "BDFDB DiscordUtils"}, ShakeablePrototype, "render", {after: e => { + e.returnValue.props.children = typeof e.returnValue.props.children == "function" ? (_ => {return null;}) : []; + BDFDB.ReactUtils.forceUpdate(ShakeableIns); + }}, {once: true}); + BDFDB.ReactUtils.forceUpdate(ShakeableIns); + } + }, instant ? 0 : 1000); + }; + + BDFDB.WindowUtils = {}; + BDFDB.WindowUtils.open = function (plugin, url, config = {}) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !url || !Internal.LibraryRequires.electron || !Internal.LibraryRequires.electron.remote) return; + if (!BDFDB.ArrayUtils.is(plugin.browserWindows)) plugin.browserWindows = []; + config = Object.assign({ + show: false, + webPreferences: { + nodeIntegration: true, + nodeIntegrationInWorker: true + } + }, config); + let browserWindow = new Internal.LibraryRequires.electron.remote.BrowserWindow(BDFDB.ObjectUtils.exclude(config, "showOnReady", "onLoad")); + + if (!config.show && config.showOnReady) browserWindow.once("ready-to-show", browserWindow.show); + if (config.devTools) browserWindow.openDevTools(); + if (typeof config.onLoad == "function") browserWindow.webContents.on("did-finish-load", (...args) => {config.onLoad(...args);}); + if (typeof config.onClose == "function") browserWindow.once("closed", (...args) => {config.onClose(...args);}); + + if (typeof browserWindow.removeMenu == "function") browserWindow.removeMenu(); + else browserWindow.setMenu(null); + browserWindow.loadURL(url); + browserWindow.executeJavaScriptSafe = js => {if (!browserWindow.isDestroyed()) browserWindow.webContents.executeJavaScript(`(_ => {${js}})();`);}; + plugin.browserWindows.push(browserWindow); + return browserWindow; + }; + BDFDB.WindowUtils.close = function (browserWindow) { + if (BDFDB.ObjectUtils.is(browserWindow) && !browserWindow.isDestroyed() && browserWindow.isClosable()) browserWindow.close(); + }; + BDFDB.WindowUtils.closeAll = function (plugin) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ArrayUtils.is(plugin.browserWindows)) return; + while (plugin.browserWindows.length) BDFDB.WindowUtils.close(plugin.browserWindows.pop()); + }; + BDFDB.WindowUtils.addListener = function (plugin, actions, callback) { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !actions || typeof callback != "function") return; + BDFDB.WindowUtils.removeListener(plugin, actions); + for (let action of actions.split(" ")) { + action = action.split("."); + let eventName = action.shift(); + if (!eventName) return; + let namespace = (action.join(".") || "") + plugin.name; + if (!BDFDB.ArrayUtils.is(plugin.ipcListeners)) plugin.ipcListeners = []; + + plugin.ipcListeners.push({eventName, namespace, callback}); + Internal.LibraryRequires.electron.ipcRenderer.on(eventName, callback); + } + }; + BDFDB.WindowUtils.removeListener = function (plugin, actions = "") { + plugin = plugin == BDFDB && Internal || plugin; + if (!BDFDB.ObjectUtils.is(plugin) || !BDFDB.ArrayUtils.is(plugin.ipcListeners)) return; + if (actions) { + for (let action of actions.split(" ")) { + action = action.split("."); + let eventName = action.shift(); + let namespace = (action.join(".") || "") + plugin.name; + for (let listener of plugin.ipcListeners) { + let removedListeners = []; + if (listener.eventName == eventName && listener.namespace == namespace) { + Internal.LibraryRequires.electron.ipcRenderer.off(listener.eventName, listener.callback); + removedListeners.push(listener); + } + if (removedListeners.length) plugin.ipcListeners = plugin.ipcListeners.filter(listener => {return removedListeners.indexOf(listener) < 0;}); + } + } + } + else { + for (let listener of plugin.ipcListeners) Internal.LibraryRequires.electron.ipcRenderer.off(listener.eventName, listener.callback); + plugin.ipcListeners = []; + } + }; + + const DiscordClassModules = Object.assign({}, InternalData.CustomClassModules); + Internal.DiscordClassModules = new Proxy(DiscordClassModules, { + get: function (_, item) { + if (DiscordClassModules[item]) return DiscordClassModules[item]; + if (!InternalData.DiscordClassModules[item]) return; + DiscordClassModules[item] = BDFDB.ModuleUtils.findStringObject(InternalData.DiscordClassModules[item].props, Object.assign({}, InternalData.DiscordClassModules[item])); + return DiscordClassModules[item] ? DiscordClassModules[item] : undefined; + } + }); + BDFDB.DiscordClassModules = Internal.DiscordClassModules; + for (let item in InternalData.DiscordClassModules) if (!DiscordClassModules[item]) DiscordClassModules[item] = undefined; + + const DiscordClasses = Object.assign({}, InternalData.DiscordClasses); + BDFDB.DiscordClasses = Object.assign({}, DiscordClasses); + Internal.getDiscordClass = function (item, selector) { + let className, fallbackClassName; + className = fallbackClassName = Internal.DiscordClassModules.BDFDB.BDFDBundefined + "-" + Internal.generateClassId(); + if (DiscordClasses[item] === undefined) { + BDFDB.LogUtils.warn([item, "not found in DiscordClasses"]); + return className; + } + else if (!BDFDB.ArrayUtils.is(DiscordClasses[item]) || DiscordClasses[item].length != 2) { + BDFDB.LogUtils.warn([item, "is not an Array of Length 2 in DiscordClasses"]); + return className; + } + else if (Internal.DiscordClassModules[DiscordClasses[item][0]] === undefined) { + BDFDB.LogUtils.warn([DiscordClasses[item][0], "not found in DiscordClassModules"]); + return className; + } + else if ([DiscordClasses[item][1]].flat().every(prop => Internal.DiscordClassModules[DiscordClasses[item][0]][prop] === undefined)) { + BDFDB.LogUtils.warn([DiscordClasses[item][1], "not found in", DiscordClasses[item][0], "in DiscordClassModules"]); + return className; + } + else { + for (let prop of [DiscordClasses[item][1]].flat()) { + className = Internal.DiscordClassModules[DiscordClasses[item][0]][prop]; + if (className) break; + else className = fallbackClassName; + } + if (selector) { + className = className.split(" ").filter(n => n.indexOf("da-") != 0).join(selector ? "." : " "); + className = className || fallbackClassName; + } + return BDFDB.ArrayUtils.removeCopies(className.split(" ")).join(" ") || fallbackClassName; + } + }; + const generationChars = "0123456789ABCDEFGHIJKMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_".split(""); + Internal.generateClassId = function () { + let id = ""; + while (id.length < 6) id += generationChars[Math.floor(Math.random() * generationChars.length)]; + return id; + }; + BDFDB.disCN = new Proxy({}, { + get: function (list, item) { + return Internal.getDiscordClass(item, false).replace("#", ""); + } + }); + BDFDB.disCNS = new Proxy({}, { + get: function (list, item) { + return Internal.getDiscordClass(item, false).replace("#", "") + " "; + } + }); + BDFDB.disCNC = new Proxy({}, { + get: function (list, item) { + return Internal.getDiscordClass(item, false).replace("#", "") + ","; + } + }); + BDFDB.dotCN = new Proxy({}, { + get: function (list, item) { + let className = Internal.getDiscordClass(item, true); + return (className.indexOf("#") == 0 ? "" : ".") + className; + } + }); + BDFDB.dotCNS = new Proxy({}, { + get: function (list, item) { + let className = Internal.getDiscordClass(item, true); + return (className.indexOf("#") == 0 ? "" : ".") + className + " "; + } + }); + BDFDB.dotCNC = new Proxy({}, { + get: function (list, item) { + let className = Internal.getDiscordClass(item, true); + return (className.indexOf("#") == 0 ? "" : ".") + className + ","; + } + }); + BDFDB.notCN = new Proxy({}, { + get: function (list, item) { + return `:not(.${Internal.getDiscordClass(item, true).split(".")[0]})`; + } + }); + BDFDB.notCNS = new Proxy({}, { + get: function (list, item) { + return `:not(.${Internal.getDiscordClass(item, true).split(".")[0]}) `; + } + }); + BDFDB.notCNC = new Proxy({}, { + get: function (list, item) { + return `:not(.${Internal.getDiscordClass(item, true).split(".")[0]}),`; + } + }); + + const LanguageStrings = Internal.LibraryModules.LanguageStore && Internal.LibraryModules.LanguageStore._proxyContext ? Object.assign({}, Internal.LibraryModules.LanguageStore._proxyContext.defaultMessages) : {}; + const LibraryStrings = Object.assign({}, InternalData.LibraryStrings); + BDFDB.LanguageUtils = {}; + BDFDB.LanguageUtils.languages = Object.assign({}, InternalData.Languages); + BDFDB.LanguageUtils.getLanguage = function () { + let lang = Internal.LibraryModules.LanguageStore.chosenLocale || Internal.LibraryModules.LanguageStore._chosenLocale || BDFDB.DiscordUtils.getSettings("locale") || "en"; + if (lang == "en-GB" || lang == "en-US") lang = "en"; + let langIds = lang.split("-"); + let langId = langIds[0]; + let langId2 = langIds[1] || ""; + lang = langId2 && langId.toUpperCase() !== langId2.toUpperCase() ? langId + "-" + langId2 : langId; + return BDFDB.LanguageUtils.languages[lang] || BDFDB.LanguageUtils.languages[langId] || BDFDB.LanguageUtils.languages.en; + }; + BDFDB.LanguageUtils.getName = function (language) { + if (!language || typeof language.name != "string") return ""; + if (language.name.startsWith("Discord")) return language.name.slice(0, -1) + (language.ownlang && (BDFDB.LanguageUtils.languages[language.id] || {}).name != language.ownlang ? ` / ${language.ownlang}` : "") + ")"; + else return language.name + (language.ownlang && language.name != language.ownlang ? ` / ${language.ownlang}` : ""); + }; + BDFDB.LanguageUtils.LanguageStrings = new Proxy(LanguageStrings, { + get: function (list, item) { + let stringObj = Internal.LibraryModules.LanguageStore.Messages[item]; + if (!stringObj) BDFDB.LogUtils.warn([item, "not found in BDFDB.LanguageUtils.LanguageStrings"]); + else { + if (stringObj && typeof stringObj == "object" && typeof stringObj.format == "function") return BDFDB.LanguageUtils.LanguageStringsFormat(item); + else return stringObj; + } + return ""; + } + }); + BDFDB.LanguageUtils.LanguageStringsCheck = new Proxy(LanguageStrings, { + get: function (list, item) { + return !!Internal.LibraryModules.LanguageStore.Messages[item]; + } + }); + let parseLanguageStringObj = obj => { + let string = ""; + if (typeof obj == "string") string += obj; + else if (BDFDB.ObjectUtils.is(obj)) { + if (obj.content) string += parseLanguageStringObj(obj.content); + else if (obj.children) string += parseLanguageStringObj(obj.children); + else if (obj.props) string += parseLanguageStringObj(obj.props); + } + else if (BDFDB.ArrayUtils.is(obj)) for (let ele of obj) string += parseLanguageStringObj(ele); + return string; + }; + BDFDB.LanguageUtils.LanguageStringsFormat = function (item, ...values) { + if (item) { + let stringObj = Internal.LibraryModules.LanguageStore.Messages[item]; + if (stringObj && typeof stringObj == "object" && typeof stringObj.format == "function") { + let i = 0, returnvalue, formatVars = {}; + while (!returnvalue && i < 10) { + i++; + try {returnvalue = stringObj.format(formatVars, false);} + catch (err) { + returnvalue = null; + let value = values.shift(); + formatVars[err.toString().split("for: ")[1]] = value != null ? (value === 0 ? "0" : value) : "undefined"; + if (stringObj.intMessage) { + try {for (let hook of stringObj.intMessage.format(formatVars).match(/\([^\(\)]+\)/gi)) formatVars[hook.replace(/[\(\)]/g, "")] = n => n;} + catch (err2) {} + } + } + } + if (returnvalue) return parseLanguageStringObj(returnvalue); + else { + BDFDB.LogUtils.warn([item, "failed to format string in BDFDB.LanguageUtils.LanguageStrings"]); + return ""; + } + } + else return BDFDB.LanguageUtils.LanguageStrings[item]; + } + else BDFDB.LogUtils.warn([item, "enter a valid key to format the string in BDFDB.LanguageUtils.LanguageStrings"]); + return ""; + }; + BDFDB.LanguageUtils.LibraryStrings = new Proxy(LibraryStrings.default || {}, { + get: function (list, item) { + let languageId = BDFDB.LanguageUtils.getLanguage().id; + if (LibraryStrings[languageId] && LibraryStrings[languageId][item]) return LibraryStrings[languageId][item]; + else if (LibraryStrings.default[item]) return LibraryStrings.default[item]; + else BDFDB.LogUtils.warn([item, "not found in BDFDB.LanguageUtils.LibraryStrings"]); + return ""; + } + }); + BDFDB.LanguageUtils.LibraryStringsCheck = new Proxy(LanguageStrings, { + get: function (list, item) { + return !!LibraryStrings.default[item]; + } + }); + BDFDB.LanguageUtils.LibraryStringsFormat = function (item, ...values) { + if (item) { + let languageId = BDFDB.LanguageUtils.getLanguage().id, string = null; + if (LibraryStrings[languageId] && LibraryStrings[languageId][item]) string = LibraryStrings[languageId][item]; + else if (LibraryStrings.default[item]) string = LibraryStrings.default[item]; + if (string) { + for (let i = 0; i < values.length; i++) if (typeof values[i] == "string" || typeof values[i] == "number") string = string.replace(new RegExp(`{{var${i}}}`, "g"), values[i]); + return string; + } + else BDFDB.LogUtils.warn([item, "not found in BDFDB.LanguageUtils.LibraryStrings"]); + } + else BDFDB.LogUtils.warn([item, "enter a valid key to format the string in BDFDB.LanguageUtils.LibraryStrings"]); + return ""; + }; + BDFDB.TimeUtils.interval(interval => { + if (Internal.LibraryModules.LanguageStore.chosenLocale || Internal.LibraryModules.LanguageStore._chosenLocale || BDFDB.DiscordUtils.getSettings("locale")) { + BDFDB.TimeUtils.clear(interval); + let language = BDFDB.LanguageUtils.getLanguage(); + if (language) BDFDB.LanguageUtils.languages.$discord = Object.assign({}, language, {name: `Discord (${language.name})`}); + } + }, 100); + for (let key in BDFDB.LanguageUtils.languages) try { + if (new Date(0).toLocaleString(key, {second: 'numeric'}) != "0") { + BDFDB.LanguageUtils.languages[key].numberMap = {}; + for (let i = 0; i < 10; i++) BDFDB.LanguageUtils.languages[key].numberMap[i] = new Date(i*1000).toLocaleString(key, {second: 'numeric'}); + } + } + catch (err) {} + + const reactInitialized = Internal.LibraryModules.React && Internal.LibraryModules.React.Component; + Internal.setDefaultProps = function (component, defaultProps) { + if (BDFDB.ObjectUtils.is(component)) component.defaultProps = Object.assign({}, component.defaultProps, defaultProps); + }; + let openedItem; + Internal.MenuItem = reactInitialized && class BDFDB_MenuItem extends Internal.LibraryModules.React.Component { + constructor(props) { + super(props); + this.state = {hovered: false}; + } + componentWillUnmount() { + if (openedItem == this.props.id) openedItem = null; + } + render() { + let color = (typeof this.props.color == "string" ? this.props.color : Internal.LibraryComponents.MenuItems.Colors.DEFAULT).toLowerCase(); + let isCustomColor = false; + if (color) { + if (DiscordClasses[`menu${color}`]) color = color; + else if (BDFDB.ColorUtils.getType(color)) { + isCustomColor = true; + color = BDFDB.ColorUtils.convert(color, "RGBA"); + } + else color = (Internal.LibraryComponents.MenuItems.Colors.DEFAULT || "").toLowerCase(); + } + let renderPopout, onClose, hasPopout = BDFDB.ObjectUtils.is(this.props.popoutProps); + if (hasPopout) { + renderPopout = instance => { + openedItem = this.props.id; + return typeof this.props.popoutProps.renderPopout == "function" && this.props.popoutProps.renderPopout(instance); + }; + onClose = instance => { + openedItem = null; + typeof this.props.popoutProps.onClose == "function" && this.props.popoutProps.onClose(instance); + }; + } + let focused = !openedItem ? this.props.isFocused : openedItem == this.props.id; + let themeDark = BDFDB.DiscordUtils.getTheme() == BDFDB.disCN.themedark; + let item = BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, Object.assign({ + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.menuitem, (this.props.label || this.props.subtext) && BDFDB.disCN.menulabelcontainer, color && (isCustomColor ? BDFDB.disCN.menucolorcustom : BDFDB.disCN[`menu${color}`]), this.props.disabled && BDFDB.disCN.menudisabled, focused && BDFDB.disCN.menufocused), + style: { + color: isCustomColor ? ((focused || this.state.hovered) ? (BDFDB.ColorUtils.isBright(color) ? "#000000" : "#ffffff") : color) : (this.state.hovered ? "#ffffff" : null), + background: isCustomColor && (focused || this.state.hovered) && color + }, + onClick: this.props.disabled ? null : e => { + if (!this.props.action) return false; + !this.props.persisting && !hasPopout && this.props.onClose && this.props.onClose(); + this.props.action(e, this); + }, + onMouseEnter: this.props.disabled ? null : e => { + if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this); + this.setState({hovered: true}); + }, + onMouseLeave: this.props.disabled ? null : e => { + if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this); + this.setState({hovered: false}); + }, + "aria-disabled": this.props.disabled, + children: [ + this.props.icon && this.props.showIconFirst && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menuiconcontainerleft, + children: BDFDB.ReactUtils.createElement(this.props.icon, { + className: BDFDB.disCN.menuicon + }) + }), + typeof this.props.render == "function" ? this.props.render(this) : this.props.render, + (this.props.label || this.props.subtext) && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menulabel, + children: [ + typeof this.props.label == "function" ? this.props.label(this) : this.props.label, + this.props.subtext && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menusubtext, + children: typeof this.props.subtext == "function" ? this.props.subtext(this) : this.props.subtext + }) + ].filter(n => n) + }), + this.props.hint && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menuhintcontainer, + children: typeof this.props.hint == "function" ? this.props.hint(this) : this.props.hint + }), + this.props.icon && !this.props.showIconFirst && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menuiconcontainer, + children: BDFDB.ReactUtils.createElement(this.props.icon, { + className: BDFDB.disCN.menuicon + }) + }), + this.props.input && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menuiconcontainer, + children: this.props.input + }), + this.props.imageUrl && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menuimagecontainer, + children: BDFDB.ReactUtils.createElement("img", { + className: BDFDB.disCN.menuimage, + src: typeof this.props.imageUrl == "function" ? this.props.imageUrl(this) : this.props.imageUrl, + alt: "" + }) + }) + ].filter(n => n) + }, this.props.menuItemProps, {isFocused: focused})); + return hasPopout ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PopoutContainer, Object.assign({}, this.props.popoutProps, { + children: item, + renderPopout: renderPopout, + onClose: onClose + })) : item; + } + }; + Internal.CustomMenuItemWrapper = reactInitialized && class BDFDB_CustomMenuItemWrapper extends Internal.LibraryModules.React.Component { + constructor(props) { + super(props); + this.state = {hovered: false}; + } + render() { + let isItem = this.props.children == Internal.MenuItem; + let item = BDFDB.ReactUtils.createElement(this.props.children, Object.assign({}, this.props.childProps, { + onMouseEnter: isItem ? e => { + if (this.props.childProps && typeof this.props.childProps.onMouseEnter == "function") this.props.childProps.onMouseEnter(e, this); + this.setState({hovered: true}); + } : this.props.childProps && this.props.childProps.onMouseEnter, + onMouseLeave: isItem ? e => { + if (this.props.childProps && typeof this.props.childProps.onMouseLeave == "function") this.props.childProps.onMouseLeave(e, this); + this.setState({hovered: false}); + } : this.props.childProps && this.props.childProps.onMouseLeave, + isFocused: this.state.hovered && !this.props.disabled + })); + return isItem ? item : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + onMouseEnter: e => this.setState({hovered: true}), + onMouseLeave: e => this.setState({hovered: false}), + children: item + }); + } + }; + Internal.ErrorBoundary = reactInitialized && class BDFDB_ErrorBoundary extends Internal.LibraryModules.React.PureComponent { + constructor(props) { + super(props); + this.state = {hasError: false}; + } + static getDerivedStateFromError(err) { + return {hasError: true}; + } + componentDidCatch(err, info) { + BDFDB.LogUtils.error(["Could not create React Element!", err]); + } + render() { + if (this.state.hasError) return Internal.LibraryModules.React.createElement("span", { + style: { + background: BDFDB.DiscordConstants && BDFDB.DiscordConstants.Colors && BDFDB.DiscordConstants.Colors.PRIMARY_DARK, + borderRadius: 5, + color: BDFDB.DiscordConstants && BDFDB.DiscordConstants.Colors && BDFDB.DiscordConstants.Colors.STATUS_RED, + fontSize: 12, + fontWeight: 600, + padding: 6, + textAlign: "center", + verticalAlign: "center" + }, + children: "React Component Error" + }); + return this.props.children; + } + }; + + const loadComponents = _ => { + const CustomComponents = {}; + + CustomComponents.AutoFocusCatcher = reactInitialized && class BDFDB_AutoFocusCatcher extends Internal.LibraryModules.React.Component { + render() { + const style = {padding: 0, margin: 0, border: "none", width: 0, maxWidth: 0, height: 0, maxHeight: 0, visibility: "hidden"}; + return BDFDB.ReactUtils.forceStyle(BDFDB.ReactUtils.createElement("input", {style}), Object.keys(style)); + } + }; + + CustomComponents.BadgeAnimationContainer = reactInitialized && class BDFDB_BadgeAnimationContainer extends Internal.LibraryModules.React.Component { + componentDidMount() {BDFDB.ReactUtils.forceUpdate(this);} + componentWillAppear(e) {if (typeof e == "function") e();} + componentWillEnter(e) {if (typeof e == "function") e();} + componentWillLeave(e) {if (typeof e == "function") this.timeoutId = setTimeout(e, 300);} + componentWillUnmount() {BDFDB.TimeUtils.clear(this.timeoutId)} + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Animations.animated.div, { + className: this.props.className, + style: this.props.animatedStyle, + children: this.props.children + }); + } + }; + + CustomComponents.Badges = {}; + CustomComponents.Badges.getBadgePaddingForValue = function (count) { + switch (count) { + case 1: + case 4: + case 6: + return 1; + default: + return 0; + } + }; + CustomComponents.Badges.IconBadge = reactInitialized && class BDFDB_IconBadge extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.badgeiconbadge, this.props.shape && Internal.LibraryComponents.Badges.BadgeShapes[this.props.shape] || Internal.LibraryComponents.Badges.BadgeShapes.ROUND), + style: Object.assign({ + backgroundColor: this.props.disableColor ? null : (this.props.color || BDFDB.DiscordConstants.Colors.STATUS_RED) + }, this.props.style), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.badgeicon, + name: this.props.icon + }) + }); + } + }; + CustomComponents.Badges.NumberBadge = reactInitialized && class BDFDB_NumberBadge extends Internal.LibraryModules.React.Component { + handleClick(e) {if (typeof this.props.onClick == "function") this.props.onClick(e, this);} + handleContextMenu(e) {if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this);} + handleMouseEnter(e) {if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this);} + handleMouseLeave(e) {if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this);} + render() { + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.badgenumberbadge, this.props.shape && Internal.LibraryComponents.Badges.BadgeShapes[this.props.shape] || Internal.LibraryComponents.Badges.BadgeShapes.ROUND), + style: Object.assign({ + backgroundColor: !this.props.disableColor && (this.props.color || BDFDB.DiscordConstants.Colors.STATUS_RED), + width: Internal.LibraryComponents.Badges.getBadgeWidthForValue(this.props.count), + paddingRight: Internal.LibraryComponents.Badges.getBadgePaddingForValue(this.props.count) + }, this.props.style), + onClick: this.handleClick.bind(this), + onContextMenu: this.handleContextMenu.bind(this), + onMouseEnter: this.handleMouseEnter.bind(this), + onMouseLeave: this.handleMouseLeave.bind(this), + children: Internal.LibraryComponents.Badges.getBadgeCountString(this.props.count) + }); + } + }; + + CustomComponents.BotTag = reactInitialized && class BDFDB_BotTag extends Internal.LibraryModules.React.Component { + handleClick(e) {if (typeof this.props.onClick == "function") this.props.onClick(e, this);} + handleContextMenu(e) {if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this);} + handleMouseEnter(e) {if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this);} + handleMouseLeave(e) {if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this);} + render() { + return BDFDB.ReactUtils.createElement("span", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, this.props.invertColor ? BDFDB.disCN.bottaginvert : BDFDB.disCN.bottagregular, this.props.useRemSizes ? BDFDB.disCN.bottagrem : BDFDB.disCN.bottagpx), + style: this.props.style, + onClick: this.handleClick.bind(this), + onContextMenu: this.handleContextMenu.bind(this), + onMouseEnter: this.handleMouseEnter.bind(this), + onMouseLeave: this.handleMouseLeave.bind(this), + children: BDFDB.ReactUtils.createElement("span", { + className: BDFDB.disCN.bottagtext, + children: this.props.tag || BDFDB.LanguageUtils.LanguageStrings.BOT_TAG_BOT + }) + }); + } + }; + + CustomComponents.Button = reactInitialized && class BDFDB_Button extends Internal.LibraryModules.React.Component { + handleClick(e) {if (typeof this.props.onClick == "function") this.props.onClick(e, this);} + handleContextMenu(e) {if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this);} + handleMouseDown(e) {if (typeof this.props.onMouseDown == "function") this.props.onMouseDown(e, this);} + handleMouseUp(e) {if (typeof this.props.onMouseUp == "function") this.props.onMouseUp(e, this);} + handleMouseEnter(e) {if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this);} + handleMouseLeave(e) {if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this);} + render() { + let processingAndListening = (this.props.disabled || this.props.submitting) && (null != this.props.onMouseEnter || null != this.props.onMouseLeave); + let props = BDFDB.ObjectUtils.exclude(this.props, "look", "color", "hover", "size", "fullWidth", "grow", "disabled", "submitting", "type", "style", "wrapperClassName", "className", "innerClassName", "onClick", "onContextMenu", "onMouseDown", "onMouseUp", "onMouseEnter", "onMouseLeave", "children", "rel"); + let button = BDFDB.ReactUtils.createElement("button", Object.assign({}, !this.props.disabled && !this.props.submitting && props, { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.button, this.props.look != null ? this.props.look : Internal.LibraryComponents.Button.Looks.FILLED, this.props.color != null ? this.props.color : Internal.LibraryComponents.Button.Colors.BRAND, this.props.hover, this.props.size != null ? this.props.size : Internal.LibraryComponents.Button.Sizes.MEDIUM, processingAndListening && this.props.wrapperClassName, this.props.fullWidth && BDFDB.disCN.buttonfullwidth, (this.props.grow === undefined || this.props.grow) && BDFDB.disCN.buttongrow, this.props.hover && this.props.hover !== Internal.LibraryComponents.Button.Hovers.DEFAULT && BDFDB.disCN.buttonhashover, this.props.submitting && BDFDB.disCN.buttonsubmitting), + onClick: (this.props.disabled || this.props.submitting) ? e => {return e.preventDefault();} : this.handleClick.bind(this), + onContextMenu: (this.props.disabled || this.props.submitting) ? e => {return e.preventDefault();} : this.handleContextMenu.bind(this), + onMouseUp: !this.props.disabled && this.handleMouseDown.bind(this), + onMouseDown: !this.props.disabled && this.handleMouseUp.bind(this), + onMouseEnter: this.handleMouseEnter.bind(this), + onMouseLeave: this.handleMouseLeave.bind(this), + type: !this.props.type ? "button" : this.props.type, + disabled: this.props.disabled, + style: this.props.style, + rel: this.props.rel, + children: [ + this.props.submitting && !this.props.disabled ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Spinner, { + type: Internal.LibraryComponents.Spinner.Type.PULSING_ELLIPSIS, + className: BDFDB.disCN.buttonspinner, + itemClassName: BDFDB.disCN.buttonspinneritem + }) : null, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.buttoncontents, this.props.innerClassName), + children: this.props.children + }) + ] + })); + return !processingAndListening ? button : BDFDB.ReactUtils.createElement("span", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.buttondisabledwrapper, this.props.wrapperClassName, this.props.size != null ? this.props.size : Internal.LibraryComponents.Button.Sizes.MEDIUM, this.props.fullWidth && BDFDB.disCN.buttonfullwidth, (this.props.grow === undefined || this.props.grow) && BDFDB.disCN.buttongrow), + children: [ + button, + BDFDB.ReactUtils.createElement("span", { + onMouseEnter: this.handleMouseEnter.bind(this), + onMouseLeave: this.handleMouseLeave.bind(this), + className: BDFDB.disCN.buttondisabledoverlay + }) + ] + }); + } + }; + + CustomComponents.Card = reactInitialized && class BDFDB_Card extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement("div", BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.hovercardwrapper, this.props.horizontal && BDFDB.disCN.hovercardhorizontal, this.props.backdrop && BDFDB.disCN.hovercard, this.props.className), + onMouseEnter: e => {if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this);}, + onMouseLeave: e => {if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this);}, + onClick: e => {if (typeof this.props.onClick == "function") this.props.onClick(e, this);}, + onContextMenu: e => {if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this);}, + children: [ + !this.props.noRemove ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + "aria-label": BDFDB.LanguageUtils.LanguageStrings.REMOVE, + className: BDFDB.disCNS.hovercardremovebutton + BDFDB.disCNS.hovercardremovebuttondefault, + onClick: e => { + if (typeof this.props.onRemove == "function") this.props.onRemove(e, this); + BDFDB.ListenerUtils.stopEvent(e); + } + }) : null, + typeof this.props.children == "string" ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextElement, { + className: BDFDB.disCN.hovercardinner, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextScroller, {children: this.props.children}) + }) : this.props.children + ].flat(10).filter(n => n) + }), "backdrop", "horizontal", "noRemove")); + } + }; + Internal.setDefaultProps(CustomComponents.Card, {backdrop: true, noRemove: false}); + + CustomComponents.ChannelTextAreaButton = reactInitialized && class BDFDB_ChannelTextAreaButton extends Internal.LibraryModules.React.Component { + render() { + const inner = BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.textareabuttonwrapper, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: this.props.iconName, + iconSVG: this.props.iconSVG, + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.textareaicon, this.props.iconClassName, this.props.pulse && BDFDB.disCN.textareaiconpulse), + nativeClass: this.props.nativeClass + }) + }); + const button = BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Button, { + look: Internal.LibraryComponents.Button.Looks.BLANK, + size: Internal.LibraryComponents.Button.Sizes.NONE, + "aria-label": this.props.label, + tabIndex: this.props.tabIndex, + className: BDFDB.DOMUtils.formatClassName(this.props.isActive && BDFDB.disCN.textareabuttonactive), + innerClassName: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.textareabutton, this.props.className, this.props.pulse && BDFDB.disCN.textareaattachbuttonplus), + onClick: this.props.onClick, + onContextMenu: this.props.onContextMenu, + onMouseEnter: this.props.onMouseEnter, + onMouseLeave: this.props.onMouseLeave, + children: this.props.tooltip && this.props.tooltip.text ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, Object.assign({}, this.props.tooltip, {children: inner})) : inner + }); + return (this.props.className || "").indexOf(BDFDB.disCN.textareapickerbutton) > -1 ? BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.textareapickerbuttoncontainer, + children: button + }) : button; + } + }; + Internal.setDefaultProps(CustomComponents.ChannelTextAreaButton, {tabIndex: 0}); + + CustomComponents.CharCounter = reactInitialized && class BDFDB_CharCounter extends Internal.LibraryModules.React.Component { + getCounterString() { + let input = this.refElement || {}, string = ""; + if (BDFDB.DOMUtils.containsClass(this.refElement, BDFDB.disCN.textarea)) { + let instance = BDFDB.ReactUtils.findOwner(input, {name: "ChannelEditorContainer", up: true}); + if (instance) string = instance.props.textValue; + else string = input.value || input.textContent || ""; + } + else string = input.value || input.textContent || ""; + if (this.props.max && this.props.showPercentage && (string.length/this.props.max) * 100 < this.props.showPercentage) return ""; + let start = input.selectionStart || 0, end = input.selectionEnd || 0, selectlength = end - start, selection = BDFDB.DOMUtils.getSelection(); + let select = !selectlength && !selection ? 0 : (selectlength || selection.length); + select = !select ? 0 : (select > string.length ? (end || start ? string.length - (string.length - end - start) : string.length) : select); + let children = [ + typeof this.props.renderPrefix == "function" && this.props.renderPrefix(string.length), + `${string.length}${!this.props.max ? "" : "/" + this.props.max}${!select ? "" : " (" + select + ")"}`, + typeof this.props.renderSuffix == "function" && this.props.renderSuffix(string.length) + ].filter(n => n); + if (typeof this.props.onChange == "function") this.props.onChange(this); + return children.length == 1 ? children[0] : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + align: Internal.LibraryComponents.Flex.Align.CENTER, + children: children + }); + } + updateCounter() { + if (!this.refElement) return; + BDFDB.TimeUtils.clear(this.updateTimeout); + this.updateTimeout = BDFDB.TimeUtils.timeout(this.forceUpdateCounter.bind(this), 100); + } + forceUpdateCounter() { + if (!this.refElement) return; + this.props.children = this.getCounterString(); + BDFDB.ReactUtils.forceUpdate(this); + } + handleSelection() { + if (!this.refElement) return; + let mouseMove = _ => { + BDFDB.TimeUtils.timeout(this.forceUpdateCounter.bind(this), 10); + }; + let mouseUp = _ => { + document.removeEventListener("mousemove", mouseMove); + document.removeEventListener("mouseup", mouseUp); + if (this.refElement.selectionEnd - this.refElement.selectionStart) BDFDB.TimeUtils.timeout(_ => { + document.addEventListener("click", click); + }); + }; + let click = _ => { + BDFDB.TimeUtils.timeout(this.forceUpdateCounter.bind(this), 100); + document.removeEventListener("mousemove", mouseMove); + document.removeEventListener("mouseup", mouseUp); + document.removeEventListener("click", click); + }; + document.addEventListener("mousemove", mouseMove); + document.addEventListener("mouseup", mouseUp); + } + componentDidMount() { + if (this.props.refClass) { + let node = BDFDB.ReactUtils.findDOMNode(this); + if (node && node.parentElement) { + this.refElement = node.parentElement.querySelector(this.props.refClass); + if (this.refElement) { + if (!this._updateCounter) this._updateCounter = _ => { + if (!document.contains(node)) BDFDB.ListenerUtils.multiRemove(this.refElement, "keydown click change", this._updateCounter); + else this.updateCounter(); + }; + if (!this._handleSelection) this._handleSelection = _ => { + if (!document.contains(node)) BDFDB.ListenerUtils.multiRemove(this.refElement, "mousedown", this._handleSelection); + else this.handleSelection(); + }; + BDFDB.ListenerUtils.multiRemove(this.refElement, "mousedown", this._handleSelection); + BDFDB.ListenerUtils.multiAdd(this.refElement, "mousedown", this._handleSelection); + if (this.refElement.tagName == "INPUT" || this.refElement.tagName == "TEXTAREA") { + BDFDB.ListenerUtils.multiRemove(this.refElement, "keydown click change", this._updateCounter); + BDFDB.ListenerUtils.multiAdd(this.refElement, "keydown click change", this._updateCounter); + } + else { + if (!this._mutationObserver) this._mutationObserver = new MutationObserver(changes => { + if (!document.contains(node)) this._mutationObserver.disconnect(); + else this.updateCounter(); + }); + else this._mutationObserver.disconnect(); + this._mutationObserver.observe(this.refElement, {childList: true, subtree: true}); + } + this.updateCounter(); + } + else BDFDB.LogUtils.warn(["could not find referenceElement for BDFDB_CharCounter"]); + } + } + else BDFDB.LogUtils.warn(["refClass can not be undefined for BDFDB_CharCounter"]); + } + render() { + let string = this.getCounterString(); + BDFDB.TimeUtils.timeout(_ => string != this.getCounterString() && BDFDB.ReactUtils.forceUpdate(this)); + return BDFDB.ReactUtils.createElement("div", BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.charcounter, this.props.className), + children: string + }), "parsing", "max", "refClass", "renderPrefix", "renderSuffix", "showPercentage")); + } + }; + + CustomComponents.Checkbox = reactInitialized && class BDFDB_Checkbox extends Internal.LibraryModules.React.Component { + handleMouseDown(e) {if (typeof this.props.onMouseDown == "function") this.props.onMouseDown(e, this);} + handleMouseUp(e) {if (typeof this.props.onMouseUp == "function") this.props.onMouseUp(e, this);} + handleMouseEnter(e) {if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this);} + handleMouseLeave(e) {if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this);} + getInputMode() { + return this.props.disabled ? "disabled" : this.props.readOnly ? "readonly" : "default"; + } + getStyle() { + let style = this.props.style || {}; + if (!this.props.value) return style; + style = Object.assign({}, style); + this.props.color = typeof this.props.getColor == "function" ? this.props.getColor(this.props.value) : this.props.color; + if (Internal.LibraryComponents.Checkbox.Types) switch (this.props.type) { + case Internal.LibraryComponents.Checkbox.Types.DEFAULT: + style.borderColor = this.props.color; + break; + case Internal.LibraryComponents.Checkbox.Types.GHOST: + let color = BDFDB.ColorUtils.setAlpha(this.props.color, 0.15, "RGB"); + style.backgroundColor = color; + style.borderColor = color; + break; + case Internal.LibraryComponents.Checkbox.Types.INVERTED: + style.backgroundColor = this.props.color; + style.borderColor = this.props.color; + } + return style; + } + getColor() { + return this.props.value ? (Internal.LibraryComponents.Checkbox.Types && this.props.type === Internal.LibraryComponents.Checkbox.Types.INVERTED ? BDFDB.DiscordConstants.Colors.WHITE : this.props.color) : "transparent"; + } + handleChange(e) { + this.props.value = typeof this.props.getValue == "function" ? this.props.getValue(this.props.value, e, this) : !this.props.value; + if (typeof this.props.onChange == "function") this.props.onChange(this.props.value, this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + let label = this.props.children ? BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.checkboxlabel, this.props.disabled ? BDFDB.disCN.checkboxlabeldisabled : BDFDB.disCN.checkboxlabelclickable, this.props.reverse ? BDFDB.disCN.checkboxlabelreversed : BDFDB.disCN.checkboxlabelforward), + style: { + lineHeight: this.props.size + "px" + }, + children: this.props.children + }) : null; + return BDFDB.ReactUtils.createElement("label", { + className: BDFDB.DOMUtils.formatClassName(this.props.disabled ? BDFDB.disCN.checkboxwrapperdisabled : BDFDB.disCN.checkboxwrapper, this.props.align, this.props.className), + children: [ + this.props.reverse && label, + !this.props.displayOnly && BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FocusRingScope, { + children: BDFDB.ReactUtils.createElement("input", { + className: BDFDB.disCN["checkboxinput" + this.getInputMode()], + type: "checkbox", + onClick: this.props.disabled || this.props.readOnly ? (_ => {}) : this.handleChange.bind(this), + onContextMenu: this.props.disabled || this.props.readOnly ? (_ => {}) : this.handleChange.bind(this), + onMouseUp: !this.props.disabled && this.handleMouseDown.bind(this), + onMouseDown: !this.props.disabled && this.handleMouseUp.bind(this), + onMouseEnter: !this.props.disabled && this.handleMouseEnter.bind(this), + onMouseLeave: !this.props.disabled && this.handleMouseLeave.bind(this), + checked: this.props.value, + style: { + width: this.props.size, + height: this.props.size + } + }) + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.checkbox, BDFDB.disCN["checkbox" + this.props.shape], this.props.value && BDFDB.disCN.checkboxchecked), + style: Object.assign({ + width: this.props.size, + height: this.props.size, + borderColor: this.props.checkboxColor + }, this.getStyle()), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Checkmark, { + width: 18, + height: 18, + color: this.getColor(), + "aria-hidden": true + }) + }), + !this.props.reverse && label + ].filter(n => n) + }); + } + }; + CustomComponents.Checkbox.Types = { + DEFAULT: "DEFAULT", + GHOST: "GHOST", + INVERTED: "INVERTED" + }; + CustomComponents.Checkbox.Shapes = { + BOX: "box", + ROUND: "round" + }; + Internal.setDefaultProps(CustomComponents.Checkbox, {type: CustomComponents.Checkbox.Types.INVERTED, shape: CustomComponents.Checkbox.Shapes.ROUND}); + + CustomComponents.Clickable = reactInitialized && class BDFDB_Clickable extends Internal.LibraryModules.React.Component { + handleClick(e) {if (typeof this.props.onClick == "function") this.props.onClick(e, this);} + handleContextMenu(e) {if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this);} + handleMouseDown(e) {if (typeof this.props.onMouseDown == "function") this.props.onMouseDown(e, this);} + handleMouseUp(e) {if (typeof this.props.onMouseUp == "function") this.props.onMouseUp(e, this);} + handleMouseEnter(e) {if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this);} + handleMouseLeave(e) {if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this);} + render() { + return BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.Clickable, Object.assign({}, this.props, { + className: BDFDB.DOMUtils.formatClassName(this.props.className, (this.props.className || "").toLowerCase().indexOf("disabled") == -1 && BDFDB.disCN.cursorpointer), + onClick: this.handleClick.bind(this), + onContextMenu: this.handleContextMenu.bind(this), + onMouseUp: this.handleMouseDown.bind(this), + onMouseDown: !this.props.disabled && this.handleMouseUp.bind(this), + onMouseEnter: this.handleMouseEnter.bind(this), + onMouseLeave: this.handleMouseLeave.bind(this) + })); + } + }; + + CustomComponents.CollapseContainer = reactInitialized && class BDFDB_CollapseContainer extends Internal.LibraryModules.React.Component { + render() { + if (!BDFDB.ObjectUtils.is(this.props.collapseStates)) this.props.collapseStates = {}; + this.props.collapsed = this.props.collapsed && (this.props.collapseStates[this.props.title] || this.props.collapseStates[this.props.title] === undefined); + this.props.collapseStates[this.props.title] = this.props.collapsed; + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.collapsed && BDFDB.disCN.collapsecontainercollapsed, this.props.mini ? BDFDB.disCN.collapsecontainermini : BDFDB.disCN.collapsecontainer, this.props.className), + id: this.props.id, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + className: BDFDB.disCN.collapsecontainerheader, + align: Internal.LibraryComponents.Flex.Align.CENTER, + onClick: e => { + this.props.collapsed = !this.props.collapsed; + this.props.collapseStates[this.props.title] = this.props.collapsed; + if (typeof this.props.onClick == "function") this.props.onClick(this.props.collapsed, this); + BDFDB.ReactUtils.forceUpdate(this); + }, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormTitle, { + tag: Internal.LibraryComponents.FormComponents.FormTitle.Tags.H5, + className: BDFDB.disCN.collapsecontainertitle, + children: this.props.title + }) + }), + !this.props.collapsed ? BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.collapsecontainerinner, + children: this.props.children + }) : null + ] + }); + } + }; + Internal.setDefaultProps(CustomComponents.CollapseContainer, {collapsed: true, mini: true}); + + CustomComponents.ColorPicker = reactInitialized && class BDFDB_ColorPicker extends Internal.LibraryModules.React.Component { + constructor(props) { + super(props); + if (!this.state) this.state = {}; + this.state.isGradient = props.gradient && props.color && BDFDB.ObjectUtils.is(props.color); + this.state.gradientBarEnabled = this.state.isGradient; + this.state.draggingAlphaCursor = false; + this.state.draggingGradientCursor = false; + this.state.selectedGradientCursor = 0; + } + handleColorChange(color) { + let changed = false; + if (color != null) { + changed = !BDFDB.equals(this.state.isGradient ? this.props.color[this.state.selectedGradientCursor] : this.props.color, color); + if (this.state.isGradient) this.props.color[this.state.selectedGradientCursor] = color; + else this.props.color = color; + } + else changed = true; + if (changed) { + if (typeof this.props.onColorChange == "function") this.props.onColorChange(BDFDB.ColorUtils.convert(this.props.color, "RGBCOMP")); + BDFDB.ReactUtils.forceUpdate(this); + } + } + render() { + if (this.state.isGradient) this.props.color = Object.assign({}, this.props.color); + + let hslFormat = this.props.alpha ? "HSLA" : "HSL"; + let hexRegex = this.props.alpha ? /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i : /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i; + + let selectedColor = BDFDB.ColorUtils.convert(this.state.isGradient ? this.props.color[this.state.selectedGradientCursor] : this.props.color, hslFormat) || BDFDB.ColorUtils.convert("#000000FF", hslFormat); + let currentGradient = (this.state.isGradient ? Object.entries(this.props.color, hslFormat) : [[0, selectedColor], [1, selectedColor]]); + + let [h, s, l] = BDFDB.ColorUtils.convert(selectedColor, "HSLCOMP"); + let a = BDFDB.ColorUtils.getAlpha(selectedColor); + a = a == null ? 1 : a; + + let hexColor = BDFDB.ColorUtils.convert(selectedColor, this.props.alpha ? "HEXA" : "HEX"); + let hexLength = hexColor.length; + + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PopoutFocusLock, { + className: BDFDB.disCNS.colorpickerwrapper + BDFDB.disCN.colorpicker, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickerinner, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickersaturation, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickersaturationcolor, + style: {position: "absolute", top: 0, right: 0, bottom: 0, left: 0, cursor: "crosshair", backgroundColor: BDFDB.ColorUtils.convert([h, "100%", "100%"], "RGB")}, + onClick: event => { + let rects = BDFDB.DOMUtils.getRects(BDFDB.DOMUtils.getParent(BDFDB.dotCN.colorpickersaturationcolor, event.target)); + this.handleColorChange(BDFDB.ColorUtils.convert([h, BDFDB.NumberUtils.mapRange([rects.left, rects.left + rects.width], [0, 100], event.clientX) + "%", BDFDB.NumberUtils.mapRange([rects.top, rects.top + rects.height], [100, 0], event.clientY) + "%", a], hslFormat)); + }, + onMouseDown: event => { + let rects = BDFDB.DOMUtils.getRects(BDFDB.DOMUtils.getParent(BDFDB.dotCN.colorpickersaturationcolor, event.target)); + let mouseUp = _ => { + document.removeEventListener("mouseup", mouseUp); + document.removeEventListener("mousemove", mouseMove); + }; + let mouseMove = event2 => { + this.handleColorChange(BDFDB.ColorUtils.convert([h, BDFDB.NumberUtils.mapRange([rects.left, rects.left + rects.width], [0, 100], event2.clientX) + "%", BDFDB.NumberUtils.mapRange([rects.top, rects.top + rects.height], [100, 0], event2.clientY) + "%", a], hslFormat)); + }; + document.addEventListener("mouseup", mouseUp); + document.addEventListener("mousemove", mouseMove); + }, + children: [ + BDFDB.ReactUtils.createElement("style", { + children: `${BDFDB.dotCN.colorpickersaturationwhite} {background: -webkit-linear-gradient(to right, #fff, rgba(255,255,255,0));background: linear-gradient(to right, #fff, rgba(255,255,255,0));}${BDFDB.dotCN.colorpickersaturationblack} {background: -webkit-linear-gradient(to top, #000, rgba(0,0,0,0));background: linear-gradient(to top, #000, rgba(0,0,0,0));}` + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickersaturationwhite, + style: {position: "absolute", top: 0, right: 0, bottom: 0, left: 0}, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickersaturationblack, + style: {position: "absolute", top: 0, right: 0, bottom: 0, left: 0} + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickersaturationcursor, + style: {position: "absolute", cursor: "crosshair", left: s, top: `${BDFDB.NumberUtils.mapRange([0, 100], [100, 0], parseFloat(l))}%`}, + children: BDFDB.ReactUtils.createElement("div", { + style: {width: 4, height: 4, boxShadow: "rgb(255, 255, 255) 0px 0px 0px 1.5px, rgba(0, 0, 0, 0.3) 0px 0px 1px 1px inset, rgba(0, 0, 0, 0.4) 0px 0px 1px 2px", borderRadius: "50%", transform: "translate(-2px, -2px)"} + }) + }) + ] + }) + ] + }) + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickerhue, + children: BDFDB.ReactUtils.createElement("div", { + style: {position: "absolute", top: 0, right: 0, bottom: 0, left: 0}, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickerhuehorizontal, + style: {padding: "0px 2px", position: "relative", height: "100%"}, + onClick: event => { + let rects = BDFDB.DOMUtils.getRects(BDFDB.DOMUtils.getParent(BDFDB.dotCN.colorpickerhuehorizontal, event.target)); + this.handleColorChange(BDFDB.ColorUtils.convert([BDFDB.NumberUtils.mapRange([rects.left, rects.left + rects.width], [0, 360], event.clientX), s, l, a], hslFormat)); + }, + onMouseDown: event => { + let rects = BDFDB.DOMUtils.getRects(BDFDB.DOMUtils.getParent(BDFDB.dotCN.colorpickerhuehorizontal, event.target)); + let mouseUp = _ => { + document.removeEventListener("mouseup", mouseUp); + document.removeEventListener("mousemove", mouseMove); + }; + let mouseMove = event2 => { + this.handleColorChange(BDFDB.ColorUtils.convert([BDFDB.NumberUtils.mapRange([rects.left, rects.left + rects.width], [0, 360], event2.clientX), s, l, a], hslFormat)); + }; + document.addEventListener("mouseup", mouseUp); + document.addEventListener("mousemove", mouseMove); + }, + children: [ + BDFDB.ReactUtils.createElement("style", { + children: `${BDFDB.dotCN.colorpickerhuehorizontal} {background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);background: -webkit-linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);}${BDFDB.dotCN.colorpickerhuevertical} {background: linear-gradient(to top, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);background: -webkit-linear-gradient(to top, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);}` + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickerhuecursor, + style: {position: "absolute", cursor: "ew-resize", left: `${BDFDB.NumberUtils.mapRange([0, 360], [0, 100], h)}%`}, + children: BDFDB.ReactUtils.createElement("div", { + style: {marginTop: 1, width: 4, borderRadius: 1, height: 8, boxShadow: "rgba(0, 0, 0, 0.6) 0px 0px 2px", background: "rgb(255, 255, 255)", transform: "translateX(-2px)"} + }) + }) + ] + }) + }) + }), + this.props.alpha && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickeralpha, + children: [ + BDFDB.ReactUtils.createElement("div", { + style: {position: "absolute", top: 0, right: 0, bottom: 0, left: 0}, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickeralphacheckered, + style: {padding: "0px 2px", position: "relative", height: "100%"} + }) + }), + BDFDB.ReactUtils.createElement("div", { + style: {position: "absolute", top: 0, right: 0, bottom: 0, left: 0}, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickeralphahorizontal, + style: {padding: "0px 2px", position: "relative", height: "100%", background: `linear-gradient(to right, ${BDFDB.ColorUtils.setAlpha([h, s, l], 0, "RGBA")}, ${BDFDB.ColorUtils.setAlpha([h, s, l], 1, "RGBA")}`}, + onClick: event => { + let rects = BDFDB.DOMUtils.getRects(BDFDB.DOMUtils.getParent(BDFDB.dotCN.colorpickeralphahorizontal, event.target)); + this.handleColorChange(BDFDB.ColorUtils.setAlpha([h, s, l], BDFDB.NumberUtils.mapRange([rects.left, rects.left + rects.width], [0, 1], event.clientX), hslFormat)); + }, + onMouseDown: event => { + let rects = BDFDB.DOMUtils.getRects(BDFDB.DOMUtils.getParent(BDFDB.dotCN.colorpickeralphahorizontal, event.target)); + let mouseUp = _ => { + document.removeEventListener("mouseup", mouseUp); + document.removeEventListener("mousemove", mouseMove); + this.state.draggingAlphaCursor = false; + BDFDB.ReactUtils.forceUpdate(this); + }; + let mouseMove = event2 => { + this.state.draggingAlphaCursor = true; + this.handleColorChange(BDFDB.ColorUtils.setAlpha([h, s, l], BDFDB.NumberUtils.mapRange([rects.left, rects.left + rects.width], [0, 1], event2.clientX), hslFormat)); + }; + document.addEventListener("mouseup", mouseUp); + document.addEventListener("mousemove", mouseMove); + }, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickeralphacursor, + style: {position: "absolute", cursor: "ew-resize", left: `${a * 100}%`}, + children: [ + BDFDB.ReactUtils.createElement("div", { + style: {marginTop: 1, width: 4, borderRadius: 1, height: 8, boxShadow: "rgba(0, 0, 0, 0.6) 0px 0px 2px", background: "rgb(255, 255, 255)", transform: "translateX(-2px)"} + }), + this.state.draggingAlphaCursor && BDFDB.ReactUtils.createElement("span", { + className: BDFDB.disCN.sliderbubble, + style: {opacity: 1, visibility: "visible", left: 2}, + children: `${Math.floor(a * 100)}%` + }) + ].filter(n => n) + }) + }) + }) + ] + }), + this.state.gradientBarEnabled && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickergradient, + children: [ + BDFDB.ReactUtils.createElement("div", { + style: {position: "absolute", top: 0, right: 0, bottom: 0, left: 0}, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickergradientcheckered, + style: {padding: "0px 2px", position: "relative", height: "100%"} + }) + }), + BDFDB.ReactUtils.createElement("div", { + style: {position: "absolute", top: 0, right: 0, bottom: 0, left: 0}, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickergradienthorizontal, + style: {padding: "0px 2px", position: "relative", cursor: "copy", height: "100%", background: BDFDB.ColorUtils.createGradient(currentGradient.reduce((colorObj, posAndColor) => (colorObj[posAndColor[0]] = posAndColor[1], colorObj), {}))}, + onClick: event => { + let rects = BDFDB.DOMUtils.getRects(event.target); + let pos = BDFDB.NumberUtils.mapRange([rects.left, rects.left + rects.width], [0.01, 0.99], event.clientX); + if (Object.keys(this.props.color).indexOf(pos) == -1) { + this.props.color[pos] = BDFDB.ColorUtils.convert("#000000FF", hslFormat); + this.state.selectedGradientCursor = pos; + this.handleColorChange(); + } + }, + children: currentGradient.map(posAndColor => BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.colorpickergradientcursor, (posAndColor[0] == 0 || posAndColor[0] == 1) && BDFDB.disCN.colorpickergradientcursoredge, this.state.selectedGradientCursor == posAndColor[0] && BDFDB.disCN.colorpickergradientcursorselected), + style: {position: "absolute", cursor: "pointer", left: `${posAndColor[0] * 100}%`}, + onMouseDown: posAndColor[0] == 0 || posAndColor[0] == 1 ? _ => {} : event => { + event = event.nativeEvent || event; + let mouseMove = event2 => { + if (Math.sqrt((event.pageX - event2.pageX)**2) > 10) { + document.removeEventListener("mousemove", mouseMove); + document.removeEventListener("mouseup", mouseUp); + + this.state.draggingGradientCursor = true; + let cursor = BDFDB.DOMUtils.getParent(BDFDB.dotCN.colorpickergradientcursor, event.target); + let rects = BDFDB.DOMUtils.getRects(cursor.parentElement); + + let releasing = _ => { + document.removeEventListener("mousemove", dragging); + document.removeEventListener("mouseup", releasing); + BDFDB.TimeUtils.timeout(_ => {this.state.draggingGradientCursor = false;}); + }; + let dragging = event3 => { + let pos = BDFDB.NumberUtils.mapRange([rects.left, rects.left + rects.width], [0.01, 0.99], event3.clientX); + if (Object.keys(this.props.color).indexOf(pos) == -1) { + delete this.props.color[posAndColor[0]]; + posAndColor[0] = pos; + this.props.color[pos] = posAndColor[1]; + this.state.selectedGradientCursor = pos; + this.handleColorChange(); + } + }; + document.addEventListener("mousemove", dragging); + document.addEventListener("mouseup", releasing); + } + }; + let mouseUp = _ => { + document.removeEventListener("mousemove", mouseMove); + document.removeEventListener("mouseup", mouseUp); + }; + document.addEventListener("mousemove", mouseMove); + document.addEventListener("mouseup", mouseUp); + }, + onClick: event => { + BDFDB.ListenerUtils.stopEvent(event); + if (!this.state.draggingGradientCursor) { + this.state.selectedGradientCursor = posAndColor[0]; + BDFDB.ReactUtils.forceUpdate(this); + } + }, + onContextMenu: posAndColor[0] == 0 || posAndColor[0] == 1 ? _ => {} : event => { + BDFDB.ListenerUtils.stopEvent(event); + delete this.props.color[posAndColor[0]]; + this.state.selectedGradientCursor = 0; + this.handleColorChange(); + }, + children: BDFDB.ReactUtils.createElement("div", { + style: {background: BDFDB.ColorUtils.convert(posAndColor[1], "RGBA")} + }) + })) + }) + }) + ] + }) + ].filter(n => n) + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextInput, { + className: BDFDB.disCNS.colorpickerhexinput + BDFDB.disCN.margintop8, + maxLength: this.props.alpha ? 9 : 7, + valuePrefix: "#", + value: hexColor, + autoFocus: true, + onChange: value => { + const oldLength = hexLength; + hexLength = (value || "").length; + if (this.props.alpha && (oldLength > 8 || oldLength < 6) && hexLength == 7) value += "FF"; + if (hexRegex.test(value)) this.handleColorChange(value); + }, + inputChildren: this.props.gradient && BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: BDFDB.LanguageUtils.LibraryStrings.gradient, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.colorpickergradientbutton, this.state.gradientBarEnabled && BDFDB.disCN.colorpickergradientbuttonenabled), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + nativeClass: true, + width: 28, + height: 28, + name: Internal.LibraryComponents.SvgIcon.Names.GRADIENT + }), + onClick: _ => { + this.state.gradientBarEnabled = !this.state.gradientBarEnabled; + if (this.state.gradientBarEnabled && !this.state.isGradient) this.props.color = {0: selectedColor, 1: selectedColor}; + else if (!this.state.gradientBarEnabled && this.state.isGradient) this.props.color = selectedColor; + this.state.isGradient = this.props.color && BDFDB.ObjectUtils.is(this.props.color); + this.handleColorChange(); + } + }) + }) + }), + BDFDB.ReactUtils.createElement("div", { + className: "move-corners", + children: [{top: 0, left: 0}, {top: 0, right: 0}, {bottom: 0, right: 0}, {bottom: 0, left: 0}].map(pos => BDFDB.ReactUtils.createElement("div", { + className: "move-corner", + onMouseDown: e => { + if (!this.domElementRef.current) return; + let rects = BDFDB.DOMUtils.getRects(this.domElementRef.current); + let left = rects.left, top = rects.top; + let oldX = e.pageX, oldY = e.pageY; + let mouseUp = _ => { + document.removeEventListener("mouseup", mouseUp); + document.removeEventListener("mousemove", mouseMove); + }; + let mouseMove = e2 => { + left = left - (oldX - e2.pageX), top = top - (oldY - e2.pageY); + oldX = e2.pageX, oldY = e2.pageY; + this.domElementRef.current.style.setProperty("left", `${left}px`, "important"); + this.domElementRef.current.style.setProperty("top", `${top}px`, "important"); + }; + document.addEventListener("mouseup", mouseUp); + document.addEventListener("mousemove", mouseMove); + }, + style: Object.assign({}, pos, {width: 10, height: 10, cursor: "move", position: "absolute"}) + })) + }) + ] + }); + } + }; + + CustomComponents.ColorSwatches = reactInitialized && class BDFDB_ColorSwatches extends Internal.LibraryModules.React.Component { + ColorSwatch(props) { + const swatches = props.swatches; + let useWhite = !BDFDB.ColorUtils.isBright(props.color); + let swatch = BDFDB.ReactUtils.createElement("button", { + type: "button", + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.colorpickerswatch, props.isSingle && BDFDB.disCN.colorpickerswatchsingle, props.isDisabled && BDFDB.disCN.colorpickerswatchdisabled, props.isSelected && BDFDB.disCN.colorpickerswatchselected, props.isCustom && BDFDB.disCN.colorpickerswatchcustom, props.color == null && BDFDB.disCN.colorpickerswatchnocolor), + number: props.number, + disabled: props.isDisabled, + onClick: _ => { + if (!props.isSelected) { + let color = props.isCustom && props.color == null ? (swatches.props.color || swatches.props.defaultCustomColor || "rgba(0, 0, 0, 1)") : props.color; + if (typeof swatches.props.onColorChange == "function") swatches.props.onColorChange(BDFDB.ColorUtils.convert(color, "RGBCOMP")); + swatches.props.color = color; + swatches.props.customColor = props.isCustom ? color : swatches.props.customColor; + swatches.props.customSelected = props.isCustom; + BDFDB.ReactUtils.forceUpdate(swatches); + } + }, + style: Object.assign({}, props.style, { + background: BDFDB.ObjectUtils.is(props.color) ? BDFDB.ColorUtils.createGradient(props.color) : BDFDB.ColorUtils.convert(props.color, "RGBA") + }), + children: [ + props.isCustom || props.isSingle ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.colorpickerswatchdropper, + foreground: BDFDB.disCN.colorpickerswatchdropperfg, + name: Internal.LibraryComponents.SvgIcon.Names.DROPPER, + width: props.isCustom ? 14 : 10, + height: props.isCustom ? 14 : 10, + color: useWhite ? BDFDB.DiscordConstants.Colors.WHITE : BDFDB.DiscordConstants.Colors.BLACK + }) : null, + props.isSelected && !props.isSingle ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names.CHECKMARK, + width: props.isCustom ? 32 : 16, + height: props.isCustom ? 24 : 16, + color: useWhite ? BDFDB.DiscordConstants.Colors.WHITE : BDFDB.DiscordConstants.Colors.BLACK + }) : null + ] + }); + if (props.isCustom || props.isSingle || props.color == null) swatch = BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: props.isCustom || props.isSingle ? BDFDB.LanguageUtils.LanguageStrings.CUSTOM_COLOR : BDFDB.LanguageUtils.LanguageStrings.DEFAULT, + tooltipConfig: {type: props.isSingle ? "top" : "bottom"}, + children: swatch + }); + if (props.isCustom || props.isSingle) swatch = BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PopoutContainer, { + children: swatch, + wrap: false, + popoutClassName: BDFDB.disCNS.colorpickerwrapper + BDFDB.disCN.colorpicker, + animation: Internal.LibraryComponents.PopoutContainer.Animation.TRANSLATE, + position: Internal.LibraryComponents.PopoutContainer.Positions.BOTTOM, + align: Internal.LibraryComponents.PopoutContainer.Align.CENTER, + open: swatches.props.pickerOpen, + onClick: _ => swatches.props.pickerOpen = true, + onOpen: _ => { + swatches.props.pickerOpen = true; + if (typeof swatches.props.onPickerOpen == "function") swatches.props.onPickerOpen(this); + }, + onClose: _ => { + delete swatches.props.pickerOpen; + if (typeof swatches.props.onPickerClose == "function") swatches.props.onPickerClose(this); + }, + renderPopout: _ => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.ColorPicker, Object.assign({}, swatches.props.pickerConfig, { + color: swatches.props.color, + onColorChange: color => { + if (typeof swatches.props.onColorChange == "function") swatches.props.onColorChange(color); + props.color = color; + swatches.props.color = color; + swatches.props.customColor = color; + swatches.props.customSelected = true; + BDFDB.ReactUtils.forceUpdate(swatches); + } + }), true) + }); + if (props.isCustom) swatch = BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickerswatchcustomcontainer, + children: swatch + }); + return swatch; + } + render() { + this.props.color = BDFDB.ObjectUtils.is(this.props.color) ? this.props.color : BDFDB.ColorUtils.convert(this.props.color, "RGBA"); + this.props.colors = (BDFDB.ArrayUtils.is(this.props.colors) ? this.props.colors : [null, 5433630, 3066993, 1752220, 3447003, 3429595, 8789737, 10181046, 15277667, 15286558, 15158332, 15105570, 15844367, 13094093, 7372936, 6513507, 16777215, 3910932, 2067276, 1146986, 2123412, 2111892, 7148717, 7419530, 11342935, 11345940, 10038562, 11027200, 12745742, 9936031, 6121581, 2894892]).map(c => BDFDB.ColorUtils.convert(c, "RGBA")); + this.props.colorRows = this.props.colors.length ? [this.props.colors.slice(0, parseInt(this.props.colors.length/2)), this.props.colors.slice(parseInt(this.props.colors.length/2))] : []; + this.props.customColor = !this.props.color || !this.props.customSelected && this.props.colors.indexOf(this.props.color) > -1 ? null : this.props.color; + this.props.defaultCustomColor = BDFDB.ObjectUtils.is(this.props.defaultCustomColor) ? this.props.defaultCustomColor : BDFDB.ColorUtils.convert(this.props.defaultCustomColor, "RGBA"); + this.props.customSelected = !!this.props.customColor; + this.props.pickerConfig = BDFDB.ObjectUtils.is(this.props.pickerConfig) ? this.props.pickerConfig : {gradient: true, alpha: true}; + + const isSingle = !this.props.colors.length; + return BDFDB.ReactUtils.createElement("div", { + className: isSingle ? BDFDB.disCN.colorpickerswatchsinglewrapper : BDFDB.DOMUtils.formatClassName(BDFDB.disCN.colorpickerswatches, BDFDB.disCN.colorpickerswatchescontainer, this.props.disabled && BDFDB.disCN.colorpickerswatchesdisabled), + children: [ + BDFDB.ReactUtils.createElement(this.ColorSwatch, { + swatches: this, + color: this.props.customColor, + isSingle: isSingle, + isCustom: !isSingle, + isSelected: this.props.customSelected, + isDisabled: this.props.disabled, + pickerOpen: this.props.pickerOpen, + style: {margin: 0} + }), + !isSingle && BDFDB.ReactUtils.createElement("div", { + children: this.props.colorRows.map(row => BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.colorpickerrow, + children: row.map(color => BDFDB.ReactUtils.createElement(this.ColorSwatch, { + swatches: this, + color: color, + isCustom: false, + isSelected: !this.props.customSelected && color == this.props.color, + isDisabled: this.props.disabled + })) + })) + }) + ] + }); + } + }; + + CustomComponents.DateInput = class BDFDB_DateInput extends Internal.LibraryModules.React.Component { + renderFormatButton(props) { + const button = BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + className: BDFDB.disCN.dateinputbutton, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: props.svgName, + width: 20, + height: 20 + }) + }); + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PopoutContainer, { + width: props.popoutWidth || 350, + padding: 10, + animation: Internal.LibraryComponents.PopoutContainer.Animation.SCALE, + position: Internal.LibraryComponents.PopoutContainer.Positions.TOP, + align: Internal.LibraryComponents.PopoutContainer.Align.RIGHT, + onClose: instance => BDFDB.DOMUtils.removeClass(instance.domElementRef.current, BDFDB.disCN.dateinputbuttonselected), + renderPopout: instance => { + BDFDB.DOMUtils.addClass(instance.domElementRef.current, BDFDB.disCN.dateinputbuttonselected); + return props.children || BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + align: Internal.LibraryComponents.Flex.Align.CENTER, + children: [ + props.name && BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsLabel, { + label: props.name + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextInput, { + className: BDFDB.disCN.dateinputfield, + placeholder: props.placeholder, + value: props.getValue(), + onChange: typeof props.onChange == "function" ? props.onChange : null + }), + props.tooltipText && this.renderInfoButton(props.tooltipText) + ].filter(n => n) + }) + }, + children: props.name ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: props.name, + children: button + }) : button + }); + } + renderInfoButton(text, style) { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: [text].flat(10).filter(n => n).map(n => BDFDB.ReactUtils.createElement("div", {children: n})), + tooltipConfig: { + type: "bottom", + zIndex: 1009, + maxWidth: 560 + }, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.dateinputbutton, + style: Object.assign({}, style), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names.QUESTIONMARK, + width: 24, + height: 24 + }) + }) + }); + } + handleChange() { + if (typeof this.props.onChange == "function") this.props.onChange(BDFDB.ObjectUtils.extract(this.props, "formatString", "dateString", "timeString", "timeOffset", "language")); + } + render() { + let input = this, formatter, preview; + const defaultOffset = ((new Date()).getTimezoneOffset() * (-1/60)); + return BDFDB.ReactUtils.createElement("div", BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.dateinputwrapper, this.props.className), + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsLabel, { + label: this.props.label + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.dateinputinner, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.dateinputcontrols, + children: [ + BDFDB.ReactUtils.createElement(class DateInputPreview extends Internal.LibraryModules.React.Component { + componentDidMount() {formatter = this;} + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextInput, { + className: BDFDB.disCN.dateinputfield, + placeholder: Internal.LibraryComponents.DateInput.getDefaultString(input.props.language), + value: input.props.formatString, + onChange: value => { + input.props.formatString = value; + input.handleChange.apply(input, []); + BDFDB.ReactUtils.forceUpdate(formatter, preview); + } + }); + } + }), + this.renderInfoButton([ + "$date will be replaced with the Date", + "$time will be replaced with the Time", + "$time12 will be replaced with the Time (12h Form)", + "$month will be replaced with the Month Name", + "$monthS will be replaced with the Month Name (Short Form)", + "$day will be replaced with the Weekday Name", + "$dayS will be replaced with the Weekday Name (Short Form)", + "$agoAmount will be replaced with ('Today', 'Yesterday', 'x days/weeks/months ago')", + "$agoDays will be replaced with ('Today', 'Yesterday', 'x days ago')", + "$agoDate will be replaced with ('Today', 'Yesterday', $date)" + ], {marginRight: 6}), + this.renderFormatButton({ + name: BDFDB.LanguageUtils.LanguageStrings.DATE, + svgName: Internal.LibraryComponents.SvgIcon.Names.CALENDAR, + placeholder: this.props.dateString, + getValue: _ => this.props.dateString, + tooltipText: [ + "$d will be replaced with the Day", + "$dd will be replaced with the Day (Forced Zeros)", + "$m will be replaced with the Month", + "$mm will be replaced with the Month (Forced Zeros)", + "$yy will be replaced with the Year (2-Digit)", + "$yyyy will be replaced with the Year (4-Digit)", + "$month will be replaced with the Month Name", + "$monthS will be replaced with the Month Name (Short Form)", + ], + onChange: value => { + this.props.dateString = value; + this.handleChange.apply(this, []); + BDFDB.ReactUtils.forceUpdate(formatter, preview); + } + }), + this.renderFormatButton({ + name: BDFDB.LanguageUtils.LibraryStrings.time, + svgName: Internal.LibraryComponents.SvgIcon.Names.CLOCK, + placeholder: this.props.timeString, + getValue: _ => this.props.timeString, + tooltipText: [ + "$h will be replaced with the Hours", + "$hh will be replaced with the Hours (Forced Zeros)", + "$m will be replaced with the Minutes", + "$mm will be replaced with the Minutes (Forced Zeros)", + "$s will be replaced with the Seconds", + "$ss will be replaced with the Seconds (Forced Zeros)", + "$u will be replaced with the Milliseconds", + "$uu will be replaced with the Milliseconds (Forced Zeros)" + ], + onChange: value => { + this.props.timeString = value; + this.handleChange.apply(this, []); + BDFDB.ReactUtils.forceUpdate(formatter, preview); + } + }), + this.renderFormatButton({ + name: BDFDB.LanguageUtils.LibraryStrings.location, + svgName: Internal.LibraryComponents.SvgIcon.Names.GLOBE, + popoutWidth: 550, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.AutoFocusCatcher, {}), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom4, + align: Internal.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsLabel, { + label: BDFDB.LanguageUtils.LanguageStrings.LANGUAGE + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Select, { + className: BDFDB.disCN.dateinputfield, + value: this.props.language != null ? this.props.language : "$discord", + options: Object.keys(BDFDB.LanguageUtils.languages).map(id => ({ + value: id, + label: BDFDB.LanguageUtils.getName(BDFDB.LanguageUtils.languages[id]) + })), + searchable: true, + optionRenderer: lang => lang.label, + onChange: value => { + this.props.language = value == "$discord" ? undefined : value; + this.handleChange.apply(this, []); + BDFDB.ReactUtils.forceUpdate(formatter, preview); + } + }) + ] + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + align: Internal.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsLabel, { + label: BDFDB.LanguageUtils.LibraryStrings.timezone + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Select, { + className: BDFDB.disCN.dateinputfield, + value: this.props.timeOffset != null ? this.props.timeOffset : defaultOffset, + options: [-12.0, -11.0, -10.0, -9.5, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.5, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 5.75, 6.0, 6.5, 7.0, 8.0, 8.75, 9.0, 9.5, 10.0, 10.5, 11.0, 12.0, 12.75, 13.0, 14.0].map(offset => ({label: offset< 0 ? offset : `+${offset}`, value: offset})), + searchable: true, + onChange: value => { + this.props.timeOffset = value == defaultOffset ? undefined : value; + this.handleChange.apply(this, []); + BDFDB.ReactUtils.forceUpdate(formatter, preview); + } + }) + ] + }) + ] + }) + ] + }), + BDFDB.ReactUtils.createElement(class DateInputPreview extends Internal.LibraryModules.React.Component { + componentDidMount() {preview = this;} + render() { + return !input.props.noPreview && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.dateinputpreview, + children: [ + input.props.prefix && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.dateinputpreviewprefix, + children: typeof input.props.prefix == "function" ? input.props.prefix(input) : input.props.prefix, + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextScroller, { + children: Internal.LibraryComponents.DateInput.format(input.props, new Date((new Date()) - (1000*60*60*24*2))) + }), + input.props.suffix && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.dateinputpreviewsuffix, + children: typeof input.props.suffix == "function" ? input.props.suffix(input) : input.props.suffix, + }) + ].filter(n => n) + }); + } + }) + ] + }) + ] + }), "onChange", "label", "formatString", "dateString", "timeString", "timeOffset", "language", "noPreview", "prefix", "suffix")); + } + }; + CustomComponents.DateInput.getDefaultString = function (language) { + language = language || BDFDB.LanguageUtils.getLanguage().id; + const date = new Date(); + return date.toLocaleString(language).replace(date.toLocaleDateString(language), "$date").replace(date.toLocaleTimeString(language, {hourCycle: "h12"}), "$time12").replace(date.toLocaleTimeString(language, {hourCycle: "h11"}), "$time12").replace(date.toLocaleTimeString(language, {hourCycle: "h24"}), "$time").replace(date.toLocaleTimeString(language, {hourCycle: "h23"}), "$time"); + }; + CustomComponents.DateInput.parseDate = function (date, offset) { + let timeObj = date; + if (typeof timeObj == "string") { + const language = BDFDB.LanguageUtils.getLanguage().id; + for (let i = 0; i < 12; i++) { + const tempDate = new Date(); + tempDate.setMonth(i); + timeObj = timeObj.replace(tempDate.toLocaleDateString(language, {month:"long"}), tempDate.toLocaleDateString("en", {month:"short"})); + } + timeObj = new Date(timeObj); + } + else if (typeof timeObj == "number") timeObj = new Date(timeObj); + + if (timeObj.toString() == "Invalid Date") timeObj = new Date(parseInt(date)); + if (timeObj.toString() == "Invalid Date" || typeof timeObj.toLocaleDateString != "function") timeObj = new Date(); + offset = offset != null && parseFloat(offset); + if ((offset || offset === 0) && !isNaN(offset)) timeObj = new Date(timeObj.getTime() + ((offset - timeObj.getTimezoneOffset() * (-1/60)) * 60*60*1000)); + return timeObj; + }; + CustomComponents.DateInput.format = function (data, time) { + if (typeof data == "string") data = {formatString: data}; + if (data && typeof data.formatString != "string") data.formatString = ""; + if (!data || typeof data.formatString != "string" || !time) return ""; + + const language = data.language || BDFDB.LanguageUtils.getLanguage().id; + const timeObj = Internal.LibraryComponents.DateInput.parseDate(time, data.timeOffset); + const now = new Date(); + const daysAgo = Math.round((Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()) - Date.UTC(timeObj.getFullYear(), timeObj.getMonth(), timeObj.getDate()))/(1000*60*60*24)); + const date = data.dateString && typeof data.dateString == "string" ? Internal.LibraryComponents.DateInput.formatDate({dateString: data.dateString, language: language}, timeObj) : timeObj.toLocaleDateString(language); + + return (data.formatString || Internal.LibraryComponents.DateInput.getDefaultString(language)) + .replace(/\$date/g, date) + .replace(/\$time12/g, data.timeString && typeof data.timeString == "string" ? Internal.LibraryComponents.DateInput.formatTime({timeString: data.timeString, language: language}, timeObj, true) : timeObj.toLocaleTimeString(language, {hourCycle: "h12"})) + .replace(/\$time/g, data.timeString && typeof data.timeString == "string" ? Internal.LibraryComponents.DateInput.formatTime({timeString: data.timeString, language: language}, timeObj) : timeObj.toLocaleTimeString(language, {hourCycle: "h23"})) + .replace(/\$monthS/g, timeObj.toLocaleDateString(language, {month: "short"})) + .replace(/\$month/g, timeObj.toLocaleDateString(language, {month: "long"})) + .replace(/\$dayS/g, timeObj.toLocaleDateString(language, {weekday: "short"})) + .replace(/\$day/g, timeObj.toLocaleDateString(language, {weekday: "long"})) + .replace(/\$agoAmount/g, daysAgo < 0 ? "" : daysAgo > 1 ? Internal.DiscordObjects.Timestamp(timeObj.getTime()).fromNow() : BDFDB.LanguageUtils.LanguageStrings[`SEARCH_SHORTCUT_${daysAgo == 1 ? "YESTERDAY" : "TODAY"}`]) + .replace(/\$agoDays/g, daysAgo < 0 ? "" : daysAgo > 1 ? BDFDB.LanguageUtils.LanguageStringsFormat(`GAME_LIBRARY_LAST_PLAYED_DAYS`, daysAgo) : BDFDB.LanguageUtils.LanguageStrings[`SEARCH_SHORTCUT_${daysAgo == 1 ? "YESTERDAY" : "TODAY"}`]) + .replace(/\$agoDate/g, daysAgo < 0 ? "" : daysAgo > 1 ? date : BDFDB.LanguageUtils.LanguageStrings[`SEARCH_SHORTCUT_${daysAgo == 1 ? "YESTERDAY" : "TODAY"}`]) + .replace(/\(\)|\[\]/g, "").replace(/,\s*$|^\s*,/g, "").replace(/ +/g, " ").trim(); + }; + CustomComponents.DateInput.formatDate = function (data, time) { + if (typeof data == "string") data = {dateString: data}; + if (data && typeof data.dateString != "string") return ""; + if (!data || typeof data.dateString != "string" || !data.dateString || !time) return ""; + + const language = data.language || BDFDB.LanguageUtils.getLanguage().id; + const timeObj = Internal.LibraryComponents.DateInput.parseDate(time, data.timeOffset); + + return data.dateString + .replace(/\$monthS/g, timeObj.toLocaleDateString(language, {month: "short"})) + .replace(/\$month/g, timeObj.toLocaleDateString(language, {month: "long"})) + .replace(/\$dd/g, timeObj.toLocaleDateString(language, {day: "2-digit"})) + .replace(/\$d/g, timeObj.toLocaleDateString(language, {day: "numeric"})) + .replace(/\$mm/g, timeObj.toLocaleDateString(language, {month: "2-digit"})) + .replace(/\$m/g, timeObj.toLocaleDateString(language, {month: "numeric"})) + .replace(/\$yyyy/g, timeObj.toLocaleDateString(language, {year: "numeric"})) + .replace(/\$yy/g, timeObj.toLocaleDateString(language, {year: "2-digit"})) + .trim(); + }; + CustomComponents.DateInput.formatTime = function (data, time, hour12) { + if (typeof data == "string") data = {timeString: data}; + if (data && typeof data.timeString != "string") return ""; + if (!data || typeof data.timeString != "string" || !data.timeString || !time) return ""; + + const language = data.language || BDFDB.LanguageUtils.getLanguage().id; + const timeObj = Internal.LibraryComponents.DateInput.parseDate(time, data.timeOffset); + + let hours = timeObj.getHours(); + if (hour12) { + hours = hours == 0 ? 12 : hours; + if (hours > 12) hours -= 12; + } + const minutes = timeObj.getMinutes(); + const seconds = timeObj.getSeconds(); + const milli = timeObj.getMilliseconds(); + + let string = data.timeString + .replace(/\$hh/g, hours < 10 ? `0${hours}` : hours) + .replace(/\$h/g, hours) + .replace(/\$mm/g, minutes < 10 ? `0${minutes}` : minutes) + .replace(/\$m/g, minutes) + .replace(/\$ss/g, seconds < 10 ? `0${seconds}` : seconds) + .replace(/\$s/g, seconds) + .replace(/\$uu/g, milli < 10 ? `00${seconds}` : milli < 100 ? `0${milli}` : milli) + .replace(/\$u/g, milli) + .trim(); + + let digits = "\\d"; + if (BDFDB.LanguageUtils.languages[language] && BDFDB.LanguageUtils.languages[language].numberMap) { + digits = Object.entries(BDFDB.LanguageUtils.languages[language].numberMap).map(n => n[1]).join(""); + for (let number in BDFDB.LanguageUtils.languages[language].numberMap) string = string.replace(new RegExp(number, "g"), BDFDB.LanguageUtils.languages[language].numberMap[number]); + } + return hour12 ? timeObj.toLocaleTimeString(language, {hourCycle: "h12"}).replace(new RegExp(`[${digits}]{1,2}[^${digits}][${digits}]{1,2}[^${digits}][${digits}]{1,2}`, "g"), string) : string; + }; + + CustomComponents.EmojiPickerButton = reactInitialized && class BDFDB_EmojiPickerButton extends Internal.LibraryModules.React.Component { + handleEmojiChange(emoji) { + if (emoji != null) { + this.props.emoji = emoji.id ? { + id: emoji.id, + name: emoji.name, + animated: emoji.animated + } : { + id: null, + name: emoji.optionallyDiverseSequence, + animated: false + }; + if (typeof this.props.onSelect == "function") this.props.onSelect(this.props.emoji, this); + if (typeof this.close == "function" && !BDFDB.ListenerUtils.isPressed(16)) this.close(); + BDFDB.ReactUtils.forceUpdate(this); + } + } + render() { + let button = this; + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PopoutContainer, { + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.EmojiButton, { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.emojiinputbutton), + renderButtonContents: this.props.emoji ? _ => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Emoji, { + className: BDFDB.disCN.emoji, + emojiId: this.props.emoji.id, + emojiName: this.props.emoji.name + }) : null + }), + wrap: false, + animation: Internal.LibraryComponents.PopoutContainer.Animation.NONE, + position: Internal.LibraryComponents.PopoutContainer.Positions.TOP, + align: Internal.LibraryComponents.PopoutContainer.Align.LEFT, + renderPopout: instance => { + this.close = instance.close; + return [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.EmojiPicker, { + closePopout: this.close, + onSelectEmoji: this.handleEmojiChange.bind(this), + allowManagedEmojis: this.props.allowManagedEmojis, + allowManagedEmojisUsage: this.props.allowManagedEmojisUsage + }), + BDFDB.ReactUtils.createElement(class extends Internal.LibraryModules.React.Component { + componentDidMount() {Internal.LibraryComponents.EmojiPickerButton.current = button;} + componentWillUnmount() {delete Internal.LibraryComponents.EmojiPickerButton.current;} + render() {return null;} + }) + ]; + } + }); + } + }; + Internal.setDefaultProps(CustomComponents.EmojiPickerButton, {allowManagedEmojis: false, allowManagedEmojisUsage: false}); + + CustomComponents.FavButton = reactInitialized && class BDFDB_FavButton extends Internal.LibraryModules.React.Component { + handleClick() { + this.props.isFavorite = !this.props.isFavorite; + if (typeof this.props.onClick == "function") this.props.onClick(this.props.isFavorite, this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.favbuttoncontainer, BDFDB.disCN.favbutton, this.props.isFavorite && BDFDB.disCN.favbuttonselected, this.props.className), + onClick: this.handleClick.bind(this), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names[this.props.isFavorite ? "FAVORITE_FILLED" : "FAVORITE"], + width: this.props.width || 24, + height: this.props.height || 24, + className: BDFDB.disCN.favbuttonicon + }) + }); + } + }; + + CustomComponents.FileButton = reactInitialized && class BDFDB_FileButton extends Internal.LibraryModules.React.Component { + componentDidMount() { + if (this.props.searchFolders) { + let node = BDFDB.ReactUtils.findDOMNode(this); + if (node && (node = node.querySelector("input[type='file']")) != null) { + node.setAttribute("directory", ""); + node.setAttribute("webkitdirectory", ""); + } + } + } + render() { + let filter = this.props.filter && [this.props.filter].flat(10).filter(n => typeof n == "string") || []; + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Button, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + onClick: e => {e.currentTarget.querySelector("input").click();}, + children: [ + BDFDB.LanguageUtils.LibraryStrings.file_navigator_text, + BDFDB.ReactUtils.createElement("input", { + type: "file", + accept: filter.length && (filter.join("/*,") + "/*"), + style: {display: "none"}, + onChange: e => { + let file = e.currentTarget.files[0]; + if (this.refInput && file && (!filter.length || filter.some(n => file.type.indexOf(n) == 0))) { + this.refInput.props.value = this.props.searchFolders ? file.path.split(file.name).slice(0, -1).join(file.name) : `${this.props.mode == "url" ? "url('" : ""}${(this.props.useFilePath) ? file.path : `data:${file.type};base64,${Internal.LibraryRequires.fs.readFileSync(file.path).toString("base64")}`}${this.props.mode ? "')" : ""}`; + BDFDB.ReactUtils.forceUpdate(this.refInput); + this.refInput.handleChange(this.refInput.props.value); + } + } + }) + ] + }), "filter", "mode", "useFilePath", "searchFolders")); + } + }; + + CustomComponents.FormComponents = {}; + CustomComponents.FormComponents.FormItem = reactInitialized && class BDFDB_FormItem extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement("div", { + className: this.props.className, + style: this.props.style, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + align: Internal.LibraryComponents.Flex.Align.BASELINE, + children: [ + this.props.title != null || this.props.error != null ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex.Child, { + wrap: true, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormTitle, { + tag: this.props.tag || Internal.LibraryComponents.FormComponents.FormTitle.Tags.H5, + disabled: this.props.disabled, + required: this.props.required, + error: this.props.error, + className: this.props.titleClassName, + children: this.props.title + }) + }) : null + ].concat([this.props.titleChildren].flat(10)).filter(n => n) + }), + ].concat(this.props.children) + }); + } + }; + + CustomComponents.GuildComponents = {}; + CustomComponents.GuildComponents.Guild = reactInitialized && class BDFDB_Guild extends Internal.LibraryModules.React.Component { + constructor(props) { + super(props); + this.state = {hovered: false}; + } + handleMouseEnter(e) { + if (!this.props.sorting) this.setState({hovered: true}); + if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this); + } + handleMouseLeave(e) { + if (!this.props.sorting) this.setState({hovered: false}); + if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this); + } + handleMouseDown(e) { + if (!this.props.unavailable && this.props.guild && this.props.selectedChannelId) Internal.LibraryModules.DirectMessageUtils.preload(this.props.guild.id, this.props.selectedChannelId); + if (e.button == 0 && typeof this.props.onMouseDown == "function") this.props.onMouseDown(e, this); + } + handleMouseUp(e) { + if (e.button == 0 && typeof this.props.onMouseUp == "function") this.props.onMouseUp(e, this); + } + handleClick(e) { + if (typeof this.props.onClick == "function") this.props.onClick(e, this); + } + handleContextMenu(e) { + if (this.props.menu) BDFDB.GuildUtils.openMenu(this.props.guild, e); + if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this); + } + setRef(e) { + if (typeof this.props.setRef == "function") this.props.setRef(this.props.guild.id, e) + } + componentDidMount() { + let node = BDFDB.ReactUtils.findDOMNode(this); + if (node && node.nodeType != Node.TEXT_NODE) for (let child of node.querySelectorAll("a")) child.setAttribute("draggable", false); + } + render() { + if (!this.props.guild) return null; + + this.props.guildId = this.props.guild.id; + this.props.selectedChannelId = Internal.LibraryModules.LastChannelStore.getChannelId(this.props.guild.id); + + let currentVoiceChannel = Internal.LibraryModules.ChannelStore.getChannel(Internal.LibraryModules.CurrentVoiceUtils.getChannelId()); + let hasVideo = currentVoiceChannel && Internal.LibraryModules.VoiceUtils.hasVideo(currentVoiceChannel); + + this.props.selected = this.props.state ? Internal.LibraryModules.LastGuildStore.getGuildId() == this.props.guild.id : false; + this.props.unread = this.props.state ? Internal.LibraryModules.UnreadGuildUtils.hasUnread(this.props.guild.id) : false; + this.props.badge = this.props.state ? Internal.LibraryModules.UnreadGuildUtils.getMentionCount(this.props.guild.id) : 0; + + this.props.mediaState = Object.assign({}, this.props.mediaState, { + audio: this.props.state ? currentVoiceChannel && currentVoiceChannel.guild_id == this.props.guild.id && !hasVideo : false, + video: this.props.state ? currentVoiceChannel && currentVoiceChannel.guild_id == this.props.guild.id && hasVideo : false, + screenshare: this.props.state ? !!Internal.LibraryModules.StreamUtils.getAllApplicationStreams().filter(stream => stream.guildId == this.props.guild.id)[0] : false, + liveStage: this.props.state ? Object.keys(Internal.LibraryModules.StageChannelStore.getStageInstancesByGuild(this.props.guild.id)).length > 0 : false, + hasLiveVoiceChannel: this.props.state && false ? !Internal.LibraryModules.MutedUtils.isMuted(this.props.guild.id) && BDFDB.ObjectUtils.toArray(Internal.LibraryModules.VoiceUtils.getVoiceStates(this.props.guild.id)).length > 0 : false, + participating: this.props.state ? Internal.LibraryModules.CurrentVoiceUtils.getGuildId() == this.props.guild.id : false, + participatingInStage: this.props.state ? currentVoiceChannel && currentVoiceChannel.guild_id == this.props.guild.id && currentVoiceChannel.isGuildStageVoice() : false + }); + + this.props.animatable = this.props.state ? this.props.guild.icon && Internal.LibraryModules.IconUtils.isAnimatedIconHash(this.props.guild.icon) : false; + this.props.unavailable = this.props.state ? Internal.LibraryModules.GuildUnavailableStore.unavailableGuilds.includes(this.props.guild.id) : false; + + let isDraggedGuild = this.props.draggingGuildId === this.props.guild.id; + let guild = isDraggedGuild ? BDFDB.ReactUtils.createElement("div", { + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.GuildComponents.DragPlaceholder, {}) + }) : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.guildcontainer, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.GuildComponents.BlobMask, { + selected: this.state.isDropHovering || this.props.selected || this.state.hovered, + upperBadge: this.props.unavailable ? Internal.LibraryModules.GuildBadgeUtils.renderUnavailableBadge() : Internal.LibraryModules.GuildBadgeUtils.renderMediaBadge(this.props.mediaState), + lowerBadge: this.props.badge > 0 ? Internal.LibraryModules.GuildBadgeUtils.renderMentionBadge(this.props.badge) : null, + lowerBadgeWidth: Internal.LibraryComponents.Badges.getBadgeWidthForValue(this.props.badge), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.NavItem, { + to: { + pathname: BDFDB.DiscordConstants.Routes.CHANNEL(this.props.guild.id, this.props.selectedChannelId), + state: { + analyticsSource: { + page: BDFDB.DiscordConstants.AnalyticsPages.GUILD_CHANNEL, + section: BDFDB.DiscordConstants.AnalyticsSections.CHANNEL_LIST, + object: BDFDB.DiscordConstants.AnalyticsObjects.CHANNEL + } + } + }, + name: this.props.guild.name, + onMouseEnter: this.handleMouseEnter.bind(this), + onMouseLeave: this.handleMouseLeave.bind(this), + onMouseDown: this.handleMouseDown.bind(this), + onMouseUp: this.handleMouseUp.bind(this), + onClick: this.handleClick.bind(this), + onContextMenu: this.handleContextMenu.bind(this), + icon: this.props.guild.getIconURL(this.props.iconSize || 96, this.state.hovered && this.props.animatable), + selected: this.props.selected || this.state.hovered + }) + }) + }); + + let children = [ + this.props.list || this.props.pill ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.GuildComponents.Pill, { + hovered: !isDraggedGuild && this.state.hovered, + selected: !isDraggedGuild && this.props.selected, + unread: !isDraggedGuild && this.props.unread, + className: BDFDB.disCN.guildpill + }) : null, + !this.props.tooltip ? guild : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + tooltipConfig: Object.assign({type: "right"}, this.props.tooltipConfig, {guild: this.props.list && this.props.guild}), + children: guild + }) + ].filter(n => n); + return this.props.list ? BDFDB.ReactUtils.createElement("div", { + ref: null != this.props.setRef ? this.props.setRef : null, + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.guildouter, BDFDB.disCN._bdguild, this.props.unread && BDFDB.disCN._bdguildunread, this.props.selected && BDFDB.disCN._bdguildselected, this.props.unread && BDFDB.disCN._bdguildunread, this.props.audio && BDFDB.disCN._bdguildaudio, this.props.video && BDFDB.disCN._bdguildvideo), + children: BDFDB.ReactUtils.createElement(Internal.LibraryModules.React.Fragment, { + children: children + }) + }) : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.guild, this.props.className), + children: children + }); + } + }; + Internal.setDefaultProps(CustomComponents.GuildComponents.Guild, {menu: true, tooltip: true, list: false, state: false, draggable: false, sorting: false}); + + CustomComponents.GuildSummaryItem = reactInitialized && class BDFDB_GuildSummaryItem extends Internal.LibraryModules.React.Component { + defaultRenderGuild(guild, isLast) { + if (!guild) return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.guildsummaryemptyguild + }); + let icon = BDFDB.ReactUtils.createElement(Internal.LibraryComponents.GuildComponents.Icon, { + className: BDFDB.disCN.guildsummaryicon, + guild: guild, + showTooltip: this.props.showTooltip, + tooltipPosition: "top", + size: Internal.LibraryComponents.GuildComponents.Icon.Sizes.SMALLER + }); + return this.props.switchOnClick ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + className: BDFDB.disCN.guildsummaryclickableicon, + onClick: _ => Internal.LibraryModules.HistoryUtils.transitionTo(BDFDB.DiscordConstants.Routes.CHANNEL(guild.id, Internal.LibraryModules.LastChannelStore.getChannelId(guild.id))), + key: guild.id, + tabIndex: -1, + children: icon + }) : icon; + } + renderGuilds() { + let elements = []; + let renderGuild = typeof this.props.renderGuild != "function" ? this.defaultRenderGuild : this.props.renderGuild; + let loaded = 0, max = this.props.guilds.length === this.props.max ? this.props.guilds.length : this.props.max - 1; + while (loaded < max && loaded < this.props.guilds.length) { + let isLast = loaded === this.props.guilds.length - 1; + let guild = renderGuild.apply(this, [this.props.guilds[loaded], isLast]); + elements.push(BDFDB.ReactUtils.createElement("div", { + className: isLast ? BDFDB.disCN.guildsummaryiconcontainer : BDFDB.disCN.guildsummaryiconcontainermasked, + children: guild + })); + loaded++; + } + if (loaded < this.props.guilds.length) { + let rest = Math.min(this.props.guilds.length - loaded, 99); + elements.push(BDFDB.ReactUtils.createElement(Internal.LibraryModules.React.Fragment, { + key: "more-guilds", + children: this.props.renderMoreGuilds("+" + rest, rest, this.props.guilds.slice(loaded), this.props) + })); + } + return elements; + } + renderIcon() { + return this.props.renderIcon ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names.WHATISTHIS, + className: BDFDB.disCN.guildsummarysvgicon + }) : null; + } + render() { + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.guildsummarycontainer), + ref: this.props._ref, + children: [ + this.renderIcon.apply(this), + this.renderGuilds.apply(this) + ].flat(10).filter(n => n) + }); + } + }; + Internal.setDefaultProps(CustomComponents.GuildSummaryItem, {max: 10, renderMoreGuilds: (count, amount, restGuilds, props) => { + let icon = BDFDB.ReactUtils.createElement("div", {className: BDFDB.disCN.guildsummarymoreguilds, children: count}); + return props.showTooltip ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: restGuilds.map(guild => guild.name).join(", "), + children: icon + }) : icon; + }, renderIcon: false}); + + CustomComponents.GuildVoiceList = reactInitialized && class BDFDB_GuildVoiceList extends Internal.LibraryModules.React.Component { + render() { + let channels = Internal.LibraryModules.GuildChannelStore.getChannels(this.props.guild.id); + let voiceChannels = (channels[Internal.LibraryModules.GuildChannelKeys.GUILD_VOCAL_CHANNELS_KEY] || []).filter(c => c.channel.type == BDFDB.DiscordConstants.ChannelTypes.GUILD_VOICE).map(c => c.channel.id); + let stageChannels = (channels[Internal.LibraryModules.GuildChannelKeys.GUILD_VOCAL_CHANNELS_KEY] || []).filter(c => c.channel.type == BDFDB.DiscordConstants.ChannelTypes.GUILD_STAGE_VOICE && Internal.LibraryModules.StageChannelStore.getStageInstanceByChannel(c.channel.id)).map(c => c.channel.id); + let streamOwnerIds = Internal.LibraryModules.StreamUtils.getAllApplicationStreams().filter(app => app.guildId === this.props.guild.id).map(app => app.ownerId) || []; + let streamOwners = streamOwnerIds.map(ownerId => Internal.LibraryModules.UserStore.getUser(ownerId)).filter(n => n); + let connectedVoiceUsers = BDFDB.ObjectUtils.toArray(Internal.LibraryModules.VoiceUtils.getVoiceStates(this.props.guild.id)).map(state => voiceChannels.includes(state.channelId) && state.channelId != this.props.guild.afkChannelId && !streamOwnerIds.includes(state.userId) && Internal.LibraryModules.UserStore.getUser(state.userId)).filter(n => n); + let connectedStageUsers = BDFDB.ObjectUtils.toArray(Internal.LibraryModules.VoiceUtils.getVoiceStates(this.props.guild.id)).map(state => stageChannels.includes(state.channelId) && state.channelId != this.props.guild.afkChannelId && !streamOwnerIds.includes(state.userId) && Internal.LibraryModules.UserStore.getUser(state.userId)).filter(n => n); + let children = [ + !connectedStageUsers.length ? null : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.tooltiprow, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names.PODIUM, + className: BDFDB.disCN.tooltipactivityicon + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.UserSummaryItem, { + users: connectedStageUsers, + max: 6 + }) + ] + }), + !connectedVoiceUsers.length ? null : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.tooltiprow, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names.SPEAKER, + className: BDFDB.disCN.tooltipactivityicon + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.UserSummaryItem, { + users: connectedVoiceUsers, + max: 6 + }) + ] + }), + !streamOwners.length ? null : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.tooltiprow, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names.STREAM, + className: BDFDB.disCN.tooltipactivityicon + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.UserSummaryItem, { + users: streamOwners, + max: 6 + }) + ] + }) + ].filter(n => n); + return !children.length ? null : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.guildvoicelist, + children: children + }); + } + }; + + CustomComponents.KeybindRecorder = reactInitialized && class BDFDB_KeybindRecorder extends Internal.LibraryModules.React.Component { + handleChange(arrays) { + this.props.value = arrays.map(platformKey => Internal.LibraryModules.KeyEvents.codes[Internal.LibraryModules.KeyCodeUtils.codeToKey(platformKey)] || platformKey[1]); + if (typeof this.props.onChange == "function") this.props.onChange(this.props.value, this); + } + handleReset() { + this.props.value = []; + if (this.recorder) this.recorder.setState({codes: []}); + if (typeof this.props.onChange == "function") this.props.onChange([], this); + if (typeof this.props.onReset == "function") this.props.onReset(this); + } + componentDidMount() { + if (!this.recorder) this.recorder = BDFDB.ReactUtils.findOwner(this, {name: "KeybindRecorder"}); + } + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + className: BDFDB.disCN.hotkeywrapper, + direction: Internal.LibraryComponents.Flex.Direction.HORIZONTAL, + align: Internal.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.KeybindRecorder, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + defaultValue: [this.props.defaultValue || this.props.value].flat(10).filter(n => n).map(keyCode => [BDFDB.DiscordConstants.KeyboardDeviceTypes.KEYBOARD_KEY, Internal.LibraryModules.KeyCodeUtils.keyToCode((Object.entries(Internal.LibraryModules.KeyEvents.codes).find(n => n[1] == keyCode && Internal.LibraryModules.KeyCodeUtils.keyToCode(n[0], null)) || [])[0], null) || keyCode]), + onChange: this.handleChange.bind(this) + }), "reset", "onReset")), + this.props.reset || this.props.onReset ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: BDFDB.LanguageUtils.LanguageStrings.REMOVE_KEYBIND, + tooltipConfig: {type: "top"}, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + className: BDFDB.disCN.hotkeyresetbutton, + onClick: this.handleReset.bind(this), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + iconSVG: ``, + }) + }) + }) : null + ].filter(n => n) + }); + } + }; + + CustomComponents.ListRow = reactInitialized && class BDFDB_ListRow extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement("div", BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.listrowwrapper, this.props.className, BDFDB.disCN.listrow), + children: [ + this.props.prefix, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.listrowcontent, + style: {flex: "1 1 auto"}, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.listname, this.props.labelClassName), + style: {flex: "1 1 auto"}, + children: this.props.label + }), + typeof this.props.note == "string" ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormText, { + type: Internal.LibraryComponents.FormComponents.FormText.Types.DESCRIPTION, + children: this.props.note + }) : null + ].filter(n => n) + }), + this.props.suffix + ].filter(n => n) + }), "label", "note", "suffix", "prefix", "labelClassName")); + } + }; + + CustomComponents.MemberRole = reactInitialized && class BDFDB_MemberRole extends Internal.LibraryModules.React.Component { + handleClick(e) {if (typeof this.props.onClick == "function") this.props.onClick(e, this);} + handleContextMenu(e) {if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this);} + render() { + let color = BDFDB.ColorUtils.convert(this.props.role.colorString, "RGB") || BDFDB.DiscordConstants.Colors.PRIMARY_DARK_300; + return BDFDB.ReactUtils.createElement("li", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.userpopoutrole, this.props.className), + style: {borderColor: BDFDB.ColorUtils.setAlpha(color, 0.6)}, + onClick: this.handleClick.bind(this), + onContextMenu: this.handleContextMenu.bind(this), + children: [ + !this.props.noCircle ? BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.userpopoutroleremovebutton, + children: BDFDB.ReactUtils.createElement("span", { + className: BDFDB.disCN.userpopoutrolecircle, + style: {backgroundColor: color} + }) + }) : null, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.userpopoutrolename, + children: this.props.role.name + }) + ].filter(n => n) + }); + } + }; + + CustomComponents.MenuItems = {}; + CustomComponents.MenuItems.MenuCheckboxItem = reactInitialized && class BDFDB_MenuCheckboxItem extends Internal.LibraryModules.React.Component { + handleClick() { + if (this.props.state) { + this.props.state.checked = !this.props.state.checked; + if (typeof this.props.action == "function") this.props.action(this.props.state.checked, this); + } + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + return BDFDB.ReactUtils.createElement(Internal.MenuItem, Object.assign({}, this.props, { + input: this.props.state && this.props.state.checked ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.menuicon, + background: BDFDB.disCN.menucheckbox, + foreground: BDFDB.disCN.menucheck, + name: Internal.LibraryComponents.SvgIcon.Names.CHECKBOX + }) : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.menuicon, + name: Internal.LibraryComponents.SvgIcon.Names.CHECKBOX_EMPTY + }), + action: this.handleClick.bind(this) + })); + } + }; + + CustomComponents.MenuItems.MenuHint = reactInitialized && class BDFDB_MenuHint extends Internal.LibraryModules.React.Component { + render() { + return !this.props.hint ? null : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menuhint, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextScroller, { + children: this.props.hint + }) + }); + } + }; + + CustomComponents.MenuItems.MenuIcon = reactInitialized && class BDFDB_MenuIcon extends Internal.LibraryModules.React.Component { + render() { + let isString = typeof this.props.icon == "string"; + return !this.props.icon ? null : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.menuicon, + nativeClass: true, + iconSVG: isString ? this.props.icon : null, + name: !isString ? this.props.icon : null + }); + } + }; + + CustomComponents.MenuItems.MenuSliderItem = reactInitialized && class BDFDB_MenuSliderItem extends Internal.LibraryModules.React.Component { + handleValueChange(value) { + if (this.props.state) { + this.props.state.value = Math.round(BDFDB.NumberUtils.mapRange([0, 100], [this.props.minValue, this.props.maxValue], value) * Math.pow(10, this.props.digits)) / Math.pow(10, this.props.digits); + if (typeof this.props.onValueChange == "function") this.props.onValueChange(this.props.state.value, this); + } + BDFDB.ReactUtils.forceUpdate(this); + } + handleValueRender(value) { + let newValue = Math.round(BDFDB.NumberUtils.mapRange([0, 100], [this.props.minValue, this.props.maxValue], value) * Math.pow(10, this.props.digits)) / Math.pow(10, this.props.digits); + if (typeof this.props.onValueRender == "function") { + let tempReturn = this.props.onValueRender(newValue, this); + if (tempReturn != undefined) newValue = tempReturn; + } + return newValue; + } + render() { + let value = this.props.state && this.props.state.value || 0; + return BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.MenuControlItem, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + label: typeof this.props.renderLabel == "function" ? this.props.renderLabel(Math.round(value * Math.pow(10, this.props.digits)) / Math.pow(10, this.props.digits), this) : this.props.label, + control: (menuItemProps, ref) => { + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.menuslidercontainer, + children: BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.Slider, Object.assign({}, menuItemProps, { + ref: ref, + className: BDFDB.disCN.menuslider, + mini: true, + initialValue: Math.round(BDFDB.NumberUtils.mapRange([this.props.minValue, this.props.maxValue], [0, 100], value) * Math.pow(10, this.props.digits)) / Math.pow(10, this.props.digits), + onValueChange: this.handleValueChange.bind(this), + onValueRender: this.handleValueRender.bind(this) + })) + }); + } + }), "digits", "renderLabel")); + } + }; + Internal.setDefaultProps(CustomComponents.MenuItems.MenuSliderItem, {minValue: 0, maxValue: 100, digits: 0}); + + CustomComponents.ModalComponents = {}; + CustomComponents.ModalComponents.ModalContent = reactInitialized && class BDFDB_ModalContent extends Internal.LibraryModules.React.Component { + render() { + return this.props.scroller ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Scrollers.Thin, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.modalcontent, this.props.className), + ref: this.props.scrollerRef, + children: this.props.children + }) : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + className: BDFDB.DOMUtils.formatClassName(this.props.content && BDFDB.disCN.modalcontent, BDFDB.disCN.modalnoscroller, this.props.className), + direction: this.props.direction || Internal.LibraryComponents.Flex.Direction.VERTICAL, + align: Internal.LibraryComponents.Flex.Align.STRETCH, + children: this.props.children + }); + } + }; + Internal.setDefaultProps(CustomComponents.ModalComponents.ModalContent, {scroller: true, content: true}); + + CustomComponents.ModalComponents.ModalTabContent = reactInitialized && class BDFDB_ModalTabContent extends Internal.LibraryModules.React.Component { + render() { + return !this.props.open ? null : BDFDB.ReactUtils.createElement(this.props.scroller ? Internal.LibraryComponents.Scrollers.Thin : "div", Object.assign(BDFDB.ObjectUtils.exclude(this.props, "scroller", "open"), { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.modaltabcontent, this.props.open && BDFDB.disCN.modaltabcontentopen, this.props.className), + children: this.props.children + })); + } + }; + Internal.setDefaultProps(CustomComponents.ModalComponents.ModalTabContent, {tab: "unnamed"}); + + CustomComponents.ModalComponents.ModalFooter = reactInitialized && class BDFDB_ModalFooter extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.modalfooter, this.props.className), + direction: this.props.direction || Internal.LibraryComponents.Flex.Direction.HORIZONTAL_REVERSE, + align: Internal.LibraryComponents.Flex.Align.STRETCH, + grow: 0, + shrink: 0, + children: this.props.children + }); + } + }; + + CustomComponents.MultiInput = reactInitialized && class BDFDB_MultiInput extends Internal.LibraryModules.React.Component { + constructor(props) { + super(props); + this.state = {focused: false}; + } + render() { + if (this.props.children && this.props.children.props) this.props.children.props.className = BDFDB.DOMUtils.formatClassName(this.props.children.props.className, BDFDB.disCN.inputmultifield); + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.inputwrapper, BDFDB.disCN.inputmultiwrapper), + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.input, BDFDB.disCN.inputmulti, this.state.focused && BDFDB.disCN.inputfocused), + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.innerClassName, BDFDB.disCN.inputwrapper, BDFDB.disCN.inputmultifirst), + children: this.props.children + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextInput, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: BDFDB.disCN.inputmultilast, + inputClassName: BDFDB.disCN.inputmultifield, + onFocus: e => this.setState({focused: true}), + onBlur: e => this.setState({focused: false}) + }), "children", "innerClassName")) + ] + }) + }); + } + }; + + CustomComponents.ListInput = reactInitialized && class BDFDB_ListInput extends Internal.LibraryModules.React.Component { + handleChange() { + if (typeof this.props.onChange) this.props.onChange(this.props.items, this); + } + render() { + if (!BDFDB.ArrayUtils.is(this.props.items)) this.props.items = []; + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.MultiInput, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: BDFDB.disCN.inputlist, + innerClassName: BDFDB.disCN.inputlistitems, + onKeyDown: e => { + if (e.which == 13 && e.target.value && e.target.value.trim()) { + let value = e.target.value.trim(); + this.props.value = ""; + if (!this.props.items.includes(value)) { + this.props.items.push(value); + BDFDB.ReactUtils.forceUpdate(this); + this.handleChange.apply(this, []); + } + } + }, + children: this.props.items.map(item => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Badges.TextBadge, { + className: BDFDB.disCN.inputlistitem, + color: "var(--bdfdb-blurple)", + style: {borderRadius: "3px"}, + text: [ + item, + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.inputlistdelete, + name: Internal.LibraryComponents.SvgIcon.Names.CLOSE, + onClick: _ => { + BDFDB.ArrayUtils.remove(this.props.items, item); + BDFDB.ReactUtils.forceUpdate(this); + this.handleChange.apply(this, []); + } + }) + ] + })) + }), "items")); + } + }; + + CustomComponents.PaginatedList = reactInitialized && class BDFDB_PaginatedList extends Internal.LibraryModules.React.Component { + constructor(props) { + super(props); + this.state = { + offset: props.offset + }; + } + handleJump(offset) { + if (offset > -1 && offset < Math.ceil(this.props.items.length/this.props.amount) && this.state.offset != offset) { + this.state.offset = offset; + if (typeof this.props.onJump == "function") this.props.onJump(offset, this); + BDFDB.ReactUtils.forceUpdate(this); + } + } + renderPagination(bottom) { + let maxOffset = Math.ceil(this.props.items.length/this.props.amount) - 1; + return this.props.items.length > this.props.amount && BDFDB.ReactUtils.createElement("nav", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.pagination, bottom ? BDFDB.disCN.paginationbottom : BDFDB.disCN.paginationtop, this.props.mini && BDFDB.disCN.paginationmini), + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Paginator, { + totalCount: this.props.items.length, + currentPage: this.state.offset + 1, + pageSize: this.props.amount, + maxVisiblePages: this.props.maxVisiblePages, + onPageChange: page => {this.handleJump(isNaN(parseInt(page)) ? -1 : page - 1);} + }), + this.props.jump && BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextInput, { + type: "number", + size: Internal.LibraryComponents.TextInput.Sizes.MINI, + value: this.state.offset + 1, + min: 1, + max: maxOffset + 1, + onKeyDown: (event, instance) => {if (event.which == 13) this.handleJump(isNaN(parseInt(instance.props.value)) ? -1 : instance.props.value - 1);} + }), + ].filter(n => n) + }); + } + render() { + let items = [], alphabet = {}; + if (BDFDB.ArrayUtils.is(this.props.items) && this.props.items.length) { + if (!this.props.alphabetKey) items = this.props.items; + else { + let unsortedItems = [].concat(this.props.items); + for (let key of ["0-9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]) { + let numbers = key == "0-9", alphaItems = []; + for (let item of unsortedItems) if (item && item[this.props.alphabetKey] && (numbers && !isNaN(parseInt(item[this.props.alphabetKey][0])) || item[this.props.alphabetKey].toUpperCase().indexOf(key) == 0)) alphaItems.push(item); + for (let sortedItem of alphaItems) BDFDB.ArrayUtils.remove(unsortedItems, sortedItem); + alphabet[key] = {items: BDFDB.ArrayUtils.keySort(alphaItems, this.props.alphabetKey), disabled: !alphaItems.length}; + } + alphabet["?!"] = {items: BDFDB.ArrayUtils.keySort(unsortedItems, this.props.alphabetKey), disabled: !unsortedItems.length}; + for (let key in alphabet) items.push(alphabet[key].items); + items = items.flat(10); + } + } + return typeof this.props.renderItem != "function" || !items.length ? null : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Scrollers.Thin, { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.paginationlist, this.props.mini && BDFDB.disCN.paginationlistmini), + fade: this.props.fade, + children: [ + this.renderPagination(), + items.length > this.props.amount && this.props.alphabetKey && BDFDB.ReactUtils.createElement("nav", { + className: BDFDB.disCN.paginationlistalphabet, + children: Object.keys(alphabet).map(key => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.paginationlistalphabetchar, alphabet[key].disabled &&BDFDB.disCN.paginationlistalphabetchardisabled), + onClick: _ => {if (!alphabet[key].disabled) this.handleJump(Math.floor(items.indexOf(alphabet[key].items[0])/this.props.amount));}, + children: key + })) + }), + this.props.header, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.paginationlistcontent, + children: items.slice(this.state.offset * this.props.amount, (this.state.offset + 1) * this.props.amount).map((data, i) => {return this.props.renderItem(data, i);}).flat(10).filter(n => n) + }), + this.props.copyToBottom && this.renderPagination(true) + ].flat(10).filter(n => n) + }); + } + }; + Internal.setDefaultProps(CustomComponents.PaginatedList, {amount: 50, offset: 0, mini: true, jump: true, maxVisiblePages: 7, copyToBottom: false, fade: true}); + + CustomComponents.Popout = reactInitialized && class BDFDB_Popout extends Internal.LibraryModules.React.Component { + componentDidMount() { + this.props.containerInstance.popout = this; + if (typeof this.props.onOpen == "function") this.props.onOpen(this.props.containerInstance, this); + } + componentWillUnmount() { + delete this.props.containerInstance.popout; + if (typeof this.props.onClose == "function") this.props.onClose(this.props.containerInstance, this); + } + render() { + if (!this.props.wrap) return this.props.children; + let pos = typeof this.props.position == "string" ? this.props.position.toLowerCase() : null; + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PopoutFocusLock, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.popoutwrapper, this.props.className, this.props.themed && BDFDB.disCN.popoutthemedpopout, this.props.arrow && BDFDB.disCN.popoutarrow, this.props.arrow && (pos == "top" ? BDFDB.disCN.popoutarrowtop : BDFDB.disCN.popoutarrowbottom)), + id: this.props.id, + onClick: e => e.stopPropagation(), + style: BDFDB.ObjectUtils.extract(this.props, "padding", "height", "maxHeight", "minHeight", "width", "maxWidth", "minWidth"), + children: this.props.children + }); + } + }; + Internal.setDefaultProps(CustomComponents.Popout, {themed: true, wrap: true}); + + CustomComponents.PopoutContainer = reactInitialized && class BDFDB_PopoutContainer extends Internal.LibraryModules.React.Component { + componentDidMount() { + this.toggle = this.toggle.bind(this); + this.onDocumentClicked = this.onDocumentClicked.bind(this); + this.domElementRef = BDFDB.ReactUtils.createRef(); + this.domElementRef.current = BDFDB.ReactUtils.findDOMNode(this); + } + onDocumentClicked() { + const node = BDFDB.ReactUtils.findDOMNode(this.popout); + if (!node || !document.contains(node) || node != event.target && document.contains(event.target) && !node.contains(event.target)) this.toggle(); + } + toggle() { + this.props.open = !this.props.open; + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + const child = (BDFDB.ArrayUtils.is(this.props.children) ? this.props.children[0] : this.props.children) || BDFDB.ReactUtils.createElement("div", {style: {height: "100%", width: "100%"}}); + child.props.className = BDFDB.DOMUtils.formatClassName(child.props.className, this.props.className); + const childProps = Object.assign({}, child.props); + child.props.onClick = (e, childThis) => { + if ((this.props.openOnClick || this.props.openOnClick === undefined)) this.toggle(); + if (typeof this.props.onClick == "function") this.props.onClick(e, this); + if (typeof childProps.onClick == "function") childProps.onClick(e, childThis); + if (this.props.killEvent || childProps.killEvent) BDFDB.ListenerUtils.stopEvent(e); + }; + child.props.onContextMenu = (e, childThis) => { + if (this.props.openOnContextMenu) this.toggle(); + if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this); + if (typeof childProps.onContextMenu == "function") childProps.onContextMenu(e, childThis); + if (this.props.killEvent || childProps.killEvent) BDFDB.ListenerUtils.stopEvent(e); + }; + return BDFDB.ReactUtils.createElement(Internal.LibraryModules.React.Fragment, { + onClick: this.toggle, + children: [ + child, + this.props.open && BDFDB.ReactUtils.createElement(Internal.LibraryComponents.AppReferencePositionLayer, { + onMount: _ => BDFDB.TimeUtils.timeout(_ => document.addEventListener("click", this.onDocumentClicked)), + onUnmount: _ => document.removeEventListener("click", this.onDocumentClicked), + position: this.props.position, + align: this.props.align, + reference: this.domElementRef, + children: _ => { + const popout = BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Popout, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: this.props.popoutClassName, + containerInstance: this, + position: this.props.position, + style: this.props.popoutStyle, + onOpen: typeof this.props.onOpen == "function" ? this.props.onOpen.bind(this) : _ => {}, + onClose: typeof this.props.onClose == "function" ? this.props.onClose.bind(this) : _ => {}, + children: typeof this.props.renderPopout == "function" ? this.props.renderPopout(this) : null + }), "popoutStyle", "popoutClassName", "shouldShow", "changing", "renderPopout", "openOnClick", "onClick", "openOnContextMenu", "onContextMenu")); + const animation = Object.entries(Internal.LibraryComponents.PopoutContainer.Animation).find(n => n[1] == this.props.animation); + return !animation || this.props.animation == Internal.LibraryComponents.PopoutContainer.Animation.NONE ? popout : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PopoutCSSAnimator, { + position: this.props.position, + type: Internal.LibraryComponents.PopoutCSSAnimator.Types[animation[0]], + children: popout + }); + } + }) + ] + }); + } + }; + Internal.setDefaultProps(CustomComponents.PopoutContainer, {wrap: true}); + + CustomComponents.QuickSelect = reactInitialized && class BDFDB_QuickSelect extends Internal.LibraryModules.React.Component { + handleChange(option) { + this.props.value = option; + if (typeof this.props.onChange == "function") this.props.onChange(option.value || option.key, this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + let options = (BDFDB.ArrayUtils.is(this.props.options) ? this.props.options : [{}]).filter(n => n); + let selectedOption = BDFDB.ObjectUtils.is(this.props.value) ? this.props.value : (options[0] || {}); + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.quickselectwrapper), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + className: BDFDB.disCN.quickselect, + align: Internal.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.quickselectlabel, + children: this.props.label + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + align: Internal.LibraryComponents.Flex.Align.CENTER, + className: BDFDB.disCN.quickselectclick, + onClick: event => { + Internal.LibraryModules.ContextMenuUtils.openContextMenu(event, _ => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Menu, { + navId: "bdfdb-quickselect", + onClose: Internal.LibraryModules.ContextMenuUtils.closeContextMenu, + className: this.props.popoutClassName, + children: BDFDB.ContextMenuUtils.createItem(Internal.LibraryComponents.MenuItems.MenuGroup, { + children: options.map((option, i) => { + let selected = option.value && option.value === selectedOption.value || option.key && option.key === selectedOption.key; + return BDFDB.ContextMenuUtils.createItem(Internal.LibraryComponents.MenuItems.MenuItem, { + label: option.label, + id: BDFDB.ContextMenuUtils.createItemId("option", option.key || option.value || i), + action: selected ? null : event2 => this.handleChange.bind(this)(option) + }); + }) + }) + })); + }, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.quickselectvalue, + children: typeof this.props.renderValue == "function" ? this.props.renderValue(this.props.value) : this.props.value.label + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.quickselectarrow + }) + ] + }) + ] + }) + }); + } + }; + + CustomComponents.RadioGroup = reactInitialized && class BDFDB_RadioGroup extends Internal.LibraryModules.React.Component { + handleChange(value) { + this.props.value = value.value; + if (typeof this.props.onChange == "function") this.props.onChange(value, this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + return BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.RadioGroup, Object.assign({}, this.props, { + onChange: this.handleChange.bind(this) + })); + } + }; + + CustomComponents.SearchBar = reactInitialized && class BDFDB_SearchBar extends Internal.LibraryModules.React.Component { + handleChange(query) { + this.props.query = query; + if (typeof this.props.onChange == "function") this.props.onChange(query, this); + BDFDB.ReactUtils.forceUpdate(this); + } + handleClear() { + this.props.query = ""; + if (this.props.changeOnClear && typeof this.props.onChange == "function") this.props.onChange("", this); + if (typeof this.props.onClear == "function") this.props.onClear(this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + let props = Object.assign({}, this.props, { + onChange: this.handleChange.bind(this), + onClear: this.handleClear.bind(this) + }); + if (typeof props.query != "string") props.query = ""; + return BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.SearchBar, props); + } + }; + + CustomComponents.Select = reactInitialized && class BDFDB_Select extends Internal.LibraryModules.React.Component { + handleChange(value) { + this.props.value = value.value || value; + if (typeof this.props.onChange == "function") this.props.onChange(value, this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.selectwrapper), + children: BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.SearchableSelect, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: this.props.inputClassName, + autoFocus: this.props.autoFocus ? this.props.autoFocus : false, + maxVisibleItems: this.props.maxVisibleItems || 7, + renderOptionLabel: this.props.optionRenderer, + onChange: this.handleChange.bind(this) + }), "inputClassName", "optionRenderer")) + }); + } + }; + + CustomComponents.SettingsGuildList = reactInitialized && class BDFDB_SettingsGuildList extends Internal.LibraryModules.React.Component { + render() { + this.props.disabled = BDFDB.ArrayUtils.is(this.props.disabled) ? this.props.disabled : []; + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + className: this.props.className, + wrap: Internal.LibraryComponents.Flex.Wrap.WRAP, + children: [this.props.includeDMs && {name: BDFDB.LanguageUtils.LanguageStrings.DIRECT_MESSAGES, acronym: "DMs", id: BDFDB.DiscordConstants.ME, getIconURL: _ => {}}].concat(Internal.LibraryModules.FolderStore.getFlattenedGuilds()).filter(n => n).map(guild => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: guild.name, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.guildClassName, BDFDB.disCN.settingsguild, this.props.disabled.includes(guild.id) && BDFDB.disCN.settingsguilddisabled), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.GuildComponents.Icon, { + guild: guild, + size: this.props.size || Internal.LibraryComponents.GuildComponents.Icon.Sizes.MEDIUM + }), + onClick: e => { + let isDisabled = this.props.disabled.includes(guild.id); + if (isDisabled) BDFDB.ArrayUtils.remove(this.props.disabled, guild.id, true); + else this.props.disabled.push(guild.id); + if (typeof this.props.onClick == "function") this.props.onClick(this.props.disabled, this); + BDFDB.ReactUtils.forceUpdate(this); + } + }) + })) + }); + } + }; + + CustomComponents.SettingsPanel = reactInitialized && class BDFDB_SettingsPanel extends Internal.LibraryModules.React.Component { + componentDidMount() { + this.props._instance = this; + let node = BDFDB.ReactUtils.findDOMNode(this); + if (node) this.props._node = node; + } + componentWillUnmount() { + if (BDFDB.ObjectUtils.is(this.props.addon) && typeof this.props.addon.onSettingsClosed == "function") this.props.addon.onSettingsClosed(); + } + render() { + let panelItems = [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.AutoFocusCatcher, {}), + typeof this.props.children == "function" ? (_ => { + return this.props.children(this.props.collapseStates); + })() : this.props.children + ].flat(10).filter(n => n); + + return BDFDB.ReactUtils.createElement("div", { + key: this.props.addon && this.props.addon.name && `${this.props.addon.name}-settingsPanel`, + id: this.props.addon && this.props.addon.name && `${this.props.addon.name}-settings`, + className: BDFDB.disCN.settingspanel, + children: panelItems + }); + } + }; + + CustomComponents.SettingsPanelList = reactInitialized && class BDFDB_SettingsPanelInner extends Internal.LibraryModules.React.Component { + render() { + return this.props.children ? BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.settingspanellistwrapper, this.props.mini && BDFDB.disCN.settingspanellistwrappermini), + children: [ + this.props.dividerTop ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormDivider, { + className: this.props.mini ? BDFDB.disCN.marginbottom4 : BDFDB.disCN.marginbottom8 + }) : null, + typeof this.props.title == "string" ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormTitle, { + className: BDFDB.disCN.marginbottom4, + tag: Internal.LibraryComponents.FormComponents.FormTitle.Tags.H3, + children: this.props.title + }) : null, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.settingspanellist, + children: this.props.children + }), + this.props.dividerBottom ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormDivider, { + className: this.props.mini ? BDFDB.disCN.margintop4 : BDFDB.disCN.margintop8 + }) : null + ] + }) : null; + } + }; + + CustomComponents.SettingsItem = reactInitialized && class BDFDB_SettingsItem extends Internal.LibraryModules.React.Component { + handleChange(value) { + if (typeof this.props.onChange == "function") this.props.onChange(value, this); + } + render() { + if (typeof this.props.type != "string" || !["BUTTON", "SELECT", "SLIDER", "SWITCH", "TEXTINPUT"].includes(this.props.type.toUpperCase())) return null; + let childComponent = Internal.LibraryComponents[this.props.type]; + if (!childComponent) return null; + if (this.props.mini && childComponent.Sizes) this.props.size = childComponent.Sizes.MINI || childComponent.Sizes.MIN; + let label = this.props.label ? (this.props.tag ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormTitle, { + className: BDFDB.DOMUtils.formatClassName(this.props.labelClassName, BDFDB.disCN.marginreset), + tag: this.props.tag, + children: this.props.label + }) : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsLabel, { + className: BDFDB.DOMUtils.formatClassName(this.props.labelClassName), + mini: this.props.mini, + label: this.props.label + })) : null; + let margin = this.props.margin != null ? this.props.margin : (this.props.mini ? 0 : 8); + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.settingsrow, BDFDB.disCN.settingsrowcontainer, this.props.disabled && BDFDB.disCN.settingsrowdisabled, margin != null && (DiscordClasses[`marginbottom${margin}`] && BDFDB.disCN[`marginbottom${margin}`] || margin == 0 && BDFDB.disCN.marginreset)), + id: this.props.id, + children: [ + this.props.dividerTop ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormDivider, { + className: this.props.mini ? BDFDB.disCN.marginbottom4 : BDFDB.disCN.marginbottom8 + }) : null, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.settingsrowlabel, + children: [ + label && !this.props.basis ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex.Child, { + grow: 1, + shrink: 1, + wrap: true, + children: label + }) : label, + this.props.labelChildren, + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex.Child, { + className: BDFDB.disCNS.settingsrowcontrol + BDFDB.disCN.flexchild, + grow: 0, + shrink: this.props.basis ? 0 : 1, + basis: this.props.basis, + wrap: true, + children: BDFDB.ReactUtils.createElement(childComponent, BDFDB.ObjectUtils.exclude(Object.assign(BDFDB.ObjectUtils.exclude(this.props, "className", "id", "type"), this.props.childProps, { + onChange: this.handleChange.bind(this), + onValueChange: this.handleChange.bind(this) + }), "basis", "margin", "dividerBottom", "dividerTop", "label", "labelClassName", "labelChildren", "tag", "mini", "note", "childProps")) + }) + ].flat(10).filter(n => n) + }), + typeof this.props.note == "string" ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex.Child, { + className: BDFDB.disCN.settingsrownote, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormText, { + disabled: this.props.disabled, + type: Internal.LibraryComponents.FormComponents.FormText.Types.DESCRIPTION, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextScroller, {speed: 2, children: this.props.note}) + }) + }) : null, + this.props.dividerBottom ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FormComponents.FormDivider, { + className: this.props.mini ? BDFDB.disCN.margintop4 : BDFDB.disCN.margintop8 + }) : null + ] + }); + } + }; + + CustomComponents.SettingsLabel = reactInitialized && class BDFDB_SettingsLabel extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextScroller, { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.settingsrowtitle, this.props.mini ? BDFDB.disCN.settingsrowtitlemini : BDFDB.disCN.settingsrowtitledefault, BDFDB.disCN.cursordefault), + speed: 2, + children: this.props.label + }); + } + }; + + CustomComponents.SettingsList = reactInitialized && class BDFDB_SettingsList extends Internal.LibraryModules.React.Component { + componentDidMount() { + this.checkList(); + } + componentDidUpdate() { + this.checkList(); + } + checkList() { + let list = BDFDB.ReactUtils.findDOMNode(this); + if (list && !this.props.configWidth) { + let headers = Array.from(list.querySelectorAll(BDFDB.dotCN.settingstableheader)); + headers.shift(); + if (BDFDB.DOMUtils.getRects(headers[0]).width == 0) BDFDB.TimeUtils.timeout(_ => {this.resizeList(headers);}); + else this.resizeList(headers); + } + } + resizeList(headers) { + let configWidth = 0, biggestWidth = 0; + if (!configWidth) { + for (let header of headers) { + header.style = ""; + let width = BDFDB.DOMUtils.getRects(header).width; + configWidth = width > configWidth ? width : configWidth; + } + configWidth += 4; + biggestWidth = configWidth; + } + if (headers.length * configWidth > 300) { + this.props.vertical = true; + configWidth = parseInt(290 / headers.length); + } + else if (configWidth < 36) { + configWidth = 36; + biggestWidth = configWidth; + } + this.props.configWidth = configWidth; + this.props.biggestWidth = biggestWidth; + BDFDB.ReactUtils.forceUpdate(this); + } + renderHeaderOption(props) { + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(props.className, BDFDB.disCN.colorbase, BDFDB.disCN.size10, props.clickable && BDFDB.disCN.cursorpointer), + onClick: _ => {if (typeof this.props.onHeaderClick == "function") this.props.onHeaderClick(props.label, this);}, + onContextMenu: _ => {if (typeof this.props.onHeaderContextMenu == "function") this.props.onHeaderContextMenu(props.label, this);}, + children: BDFDB.ReactUtils.createElement("span", { + children: props.label + }) + }); + } + renderItem(props) { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Card, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: BDFDB.DOMUtils.formatClassName([this.props.cardClassName, props.className].filter(n => n).join(" ").indexOf(BDFDB.disCN.card) == -1 && BDFDB.disCN.cardprimaryoutline, BDFDB.disCN.settingstablecard, this.props.cardClassName, props.className), + cardId: props.key, + backdrop: false, + horizontal: true, + style: Object.assign({}, this.props.cardStyle, props.style), + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.settingstablecardlabel, + children: this.props.renderLabel(props, this) + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.settingstablecardconfigs, + style: { + width: props.wrapperWidth || null, + minWidth: props.wrapperWidth || null, + maxWidth: props.wrapperWidth || null + }, + children: this.props.settings.map(setting => BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.checkboxcontainer, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: setting.toUpperCase(), + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Checkbox, { + disabled: props.disabled, + cardId: props.key, + settingId: setting, + shape: Internal.LibraryComponents.Checkbox.Shapes && Internal.LibraryComponents.Checkbox.Shapes.ROUND, + type: Internal.LibraryComponents.Checkbox.Types && Internal.LibraryComponents.Checkbox.Types.INVERTED, + color: this.props.checkboxColor, + getColor: this.props.getCheckboxColor, + value: props[setting], + getValue: this.props.getCheckboxValue, + onChange: this.props.onCheckboxChange + }) + }) + })).flat(10).filter(n => n) + }) + ] + }), "title", "data", "settings", "renderLabel", "cardClassName", "cardStyle", "checkboxColor", "getCheckboxColor", "getCheckboxValue", "onCheckboxChange", "configWidth", "biggestWidth", "pagination")); + } + render() { + this.props.settings = BDFDB.ArrayUtils.is(this.props.settings) ? this.props.settings : []; + this.props.renderLabel = typeof this.props.renderLabel == "function" ? this.props.renderLabel : data => data.label; + this.props.data = (BDFDB.ArrayUtils.is(this.props.data) ? this.props.data : [{}]).filter(n => n); + + let wrapperWidth = this.props.configWidth && this.props.configWidth * this.props.settings.length; + let isHeaderClickable = typeof this.props.onHeaderClick == "function" || typeof this.props.onHeaderContextMenu == "function"; + let usePagination = BDFDB.ObjectUtils.is(this.props.pagination); + + let header = BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.settingstableheaders, + style: this.props.vertical && this.props.biggestWidth ? { + marginTop: this.props.biggestWidth - 15 || 0 + } : {}, + children: [ + this.renderHeaderOption({ + className: BDFDB.disCN.settingstableheadername, + clickable: this.props.title && isHeaderClickable, + label: this.props.title || "" + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.settingstableheaderoptions, + style: { + width: wrapperWidth || null, + minWidth: wrapperWidth || null, + maxWidth: wrapperWidth || null + }, + children: this.props.settings.map(setting => this.renderHeaderOption({ + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.settingstableheaderoption, this.props.vertical && BDFDB.disCN.settingstableheadervertical), + clickable: isHeaderClickable, + label: setting + })) + }) + ] + }); + return !this.props.data.length ? null : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.settingstablelist, this.props.className), + children: [ + !usePagination && header, + !usePagination ? this.props.data.map(data => this.renderItem(Object.assign({}, data, {wrapperWidth}))) : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PaginatedList, Object.assign({}, this.props.pagination, { + header: header, + items: this.props.data, + renderItem: data => this.renderItem(Object.assign({}, data, {wrapperWidth})), + onJump: (offset, instance) => { + this.props.pagination.offset = offset; + if (typeof this.props.pagination.onJump == "function") this.props.pagination.onJump(offset, this, instance); + } + })) + ].filter(n => n) + }); + } + }; + + CustomComponents.SettingsSaveItem = reactInitialized && class BDFDB_SettingsSaveItem extends Internal.LibraryModules.React.Component { + saveSettings(value) { + if (!BDFDB.ArrayUtils.is(this.props.keys) || !BDFDB.ObjectUtils.is(this.props.plugin)) return; + let keys = this.props.keys.filter(n => n); + let option = keys.shift(); + if (BDFDB.ObjectUtils.is(this.props.plugin) && option) { + let data = BDFDB.DataUtils.load(this.props.plugin, option); + let newC = ""; + for (let key of keys) newC += `{"${key}":`; + value = value != null && value.value != null ? value.value : value; + let isString = typeof value == "string"; + let marker = isString ? `"` : ``; + newC += (marker + (isString ? value.replace(/\\/g, "\\\\") : value) + marker) + "}".repeat(keys.length); + newC = JSON.parse(newC); + newC = BDFDB.ObjectUtils.is(newC) ? BDFDB.ObjectUtils.deepAssign({}, data, newC) : newC; + BDFDB.DataUtils.save(newC, this.props.plugin, option); + if (!this.props.plugin.settings) this.props.plugin.settings = {}; + this.props.plugin.settings[option] = newC; + this.props.plugin.SettingsUpdated = true; + } + if (typeof this.props.onChange == "function") this.props.onChange(value, this); + } + render() { + if (typeof this.props.type != "string" || !["SELECT", "SLIDER", "SWITCH", "TEXTINPUT"].includes(this.props.type.toUpperCase())) return null; + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsItem, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + onChange: this.saveSettings.bind(this) + }), "keys", "key", "plugin")); + } + }; + + CustomComponents.SidebarList = reactInitialized && class BDFDB_SidebarList extends Internal.LibraryModules.React.Component { + handleItemSelect(item) { + this.props.selectedItem = item; + if (typeof this.props.onItemSelect == "function") this.props.onItemSelect(item, this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + let items = (BDFDB.ArrayUtils.is(this.props.items) ? this.props.items : [{}]).filter(n => n); + let selectedItem = this.props.selectedItem || (items[0] || {}).value; + let selectedElements = (items.find(n => n.value == selectedItem) || {}).elements; + let renderElement = typeof this.props.renderElement == "function" ? this.props.renderElement : (_ => {}); + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(this.props.className, BDFDB.disCN.sidebarlist), + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Scrollers.Thin, { + className: BDFDB.DOMUtils.formatClassName(this.props.sidebarClassName, BDFDB.disCN.sidebar), + fade: true, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TabBar, { + itemClassName: this.props.itemClassName, + type: Internal.LibraryComponents.TabBar.Types.SIDE, + items: items, + selectedItem: selectedItem, + renderItem: this.props.renderItem, + onItemSelect: this.handleItemSelect.bind(this) + }) + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Scrollers.Thin, { + className: BDFDB.DOMUtils.formatClassName(this.props.contentClassName, BDFDB.disCN.sidebarcontent), + fade: true, + children: [selectedElements].flat(10).filter(n => n).map(data => renderElement(data)) + }) + ] + }); + } + }; + + CustomComponents.Slider = reactInitialized && class BDFDB_Slider extends Internal.LibraryModules.React.Component { + handleMarkerRender(marker) { + let newMarker = BDFDB.NumberUtils.mapRange([0, 100], this.props.edges, marker); + if (typeof this.props.digits == "number") newMarker = Math.round(newMarker * Math.pow(10, this.props.digits)) / Math.pow(10, this.props.digits); + return newMarker; + } + handleValueChange(value) { + let newValue = BDFDB.NumberUtils.mapRange([0, 100], this.props.edges, value); + if (typeof this.props.digits == "number") newValue = Math.round(newValue * Math.pow(10, this.props.digits)) / Math.pow(10, this.props.digits); + this.props.defaultValue = this.props.value = newValue; + if (typeof this.props.onValueChange == "function") this.props.onValueChange(newValue, this); + BDFDB.ReactUtils.forceUpdate(this); + } + handleValueRender(value) { + let newValue = BDFDB.NumberUtils.mapRange([0, 100], this.props.edges, value); + if (typeof this.props.digits == "number") newValue = Math.round(newValue * Math.pow(10, this.props.digits)) / Math.pow(10, this.props.digits); + if (typeof this.props.onValueRender == "function") { + let tempReturn = this.props.onValueRender(newValue, this); + if (tempReturn != undefined) newValue = tempReturn; + } + return newValue; + } + render() { + let value = this.props.value || this.props.defaultValue || 0; + if (!BDFDB.ArrayUtils.is(this.props.edges) || this.props.edges.length != 2) this.props.edges = [this.props.min || this.props.minValue || 0, this.props.max || this.props.maxValue || 100]; + this.props.minValue = 0; + this.props.maxValue = 100; + let defaultValue = BDFDB.NumberUtils.mapRange(this.props.edges, [0, 100], value); + if (typeof this.props.digits == "number") defaultValue = Math.round(defaultValue * Math.pow(10, this.props.digits)) / Math.pow(10, this.props.digits); + return BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.Slider, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + initialValue: defaultValue, + markers: typeof this.props.markerAmount == "number" ? Array.from(Array(this.props.markerAmount).keys()).map((_, i) => i * (this.props.maxValue - this.props.minValue)/10) : undefined, + onMarkerRender: this.handleMarkerRender.bind(this), + onValueChange: this.handleValueChange.bind(this), + onValueRender: this.handleValueRender.bind(this) + }), "digits", "edges", "max", "min", "markerAmount")); + } + }; + Internal.setDefaultProps(CustomComponents.Slider, {hideBubble: false, digits: 3}); + + CustomComponents.SvgIcon = reactInitialized && class BDFDB_Icon extends Internal.LibraryModules.React.Component { + render() { + if (BDFDB.ObjectUtils.is(this.props.name)) { + let calcClassName = []; + if (BDFDB.ObjectUtils.is(this.props.name.getClassName)) for (let path in this.props.name.getClassName) { + if (!path || BDFDB.ObjectUtils.get(this, path)) calcClassName.push(BDFDB.disCN[this.props.name.getClassName[path]]); + } + if (calcClassName.length || this.props.className) this.props.nativeClass = true; + this.props.iconSVG = this.props.name.icon; + let props = Object.assign({ + width: 24, + height: 24, + color: "currentColor" + }, this.props.name.defaultProps, this.props, { + className: BDFDB.DOMUtils.formatClassName(calcClassName, this.props.className) + }); + for (let key in props) this.props.iconSVG = this.props.iconSVG.replace(new RegExp(`%%${key}`, "g"), props[key]); + } + if (this.props.iconSVG) { + let icon = BDFDB.ReactUtils.elementToReact(BDFDB.DOMUtils.create(this.props.iconSVG)); + if (BDFDB.ReactUtils.isValidElement(icon)) { + icon.props.className = BDFDB.DOMUtils.formatClassName(!this.props.nativeClass && BDFDB.disCN.svgicon, icon.props.className, this.props.className); + icon.props.style = Object.assign({}, icon.props.style, this.props.style); + icon.props = Object.assign({}, BDFDB.ObjectUtils.extract(this.props, "onClick", "onContextMenu", "onMouseDown", "onMouseUp", "onMouseEnter", "onMouseLeave"), icon.props); + return icon; + } + } + return null; + } + }; + CustomComponents.SvgIcon.Names = InternalData.SvgIcons || {}; + + const SwitchIconPaths = { + a: { + TOP: "M5.13231 6.72963L6.7233 5.13864L14.855 13.2704L13.264 14.8614L5.13231 6.72963Z", + BOTTOM: "M13.2704 5.13864L14.8614 6.72963L6.72963 14.8614L5.13864 13.2704L13.2704 5.13864Z" + }, + b: { + TOP: "M6.56666 11.0013L6.56666 8.96683L13.5667 8.96683L13.5667 11.0013L6.56666 11.0013Z", + BOTTOM: "M13.5582 8.96683L13.5582 11.0013L6.56192 11.0013L6.56192 8.96683L13.5582 8.96683Z" + }, + c: { + TOP: "M7.89561 14.8538L6.30462 13.2629L14.3099 5.25755L15.9009 6.84854L7.89561 14.8538Z", + BOTTOM: "M4.08643 11.0903L5.67742 9.49929L9.4485 13.2704L7.85751 14.8614L4.08643 11.0903Z" + } + }; + const SwitchInner = function (props) { + let reducedMotion = BDFDB.ReactUtils.useContext(Internal.LibraryModules.PreferencesContext.AccessibilityPreferencesContext).reducedMotion; + let ref = BDFDB.ReactUtils.useRef(null); + let state = BDFDB.ReactUtils.useState(false); + let animation = Internal.LibraryComponents.Animations.useSpring({ + config: { + mass: 1, + tension: 250 + }, + opacity: props.disabled ? .3 : 1, + state: state[0] ? (props.value ? .7 : .3) : (props.value ? 1 : 0) + }); + let fill = animation.state.to({ + output: [props.uncheckedColor, props.checkedColor] + }); + let mini = props.size == Internal.LibraryComponents.Switch.Sizes.MINI; + + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Animations.animated.div, { + className: BDFDB.DOMUtils.formatClassName(props.className, BDFDB.disCN.switch, mini && BDFDB.disCN.switchmini), + onMouseDown: _ => { + return !props.disabled && state[1](true); + }, + onMouseUp: _ => { + return state[1](false); + }, + onMouseLeave: _ => { + return state[1](false); + }, + style: { + opacity: animation.opacity, + backgroundColor: animation.state.to({ + output: [props.uncheckedColor, props.checkedColor] + }) + }, + tabIndex: -1, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Animations.animated.svg, { + className: BDFDB.disCN.switchslider, + viewBox: "0 0 28 20", + preserveAspectRatio: "xMinYMid meet", + style: { + left: animation.state.to({ + range: [0, .3, .7, 1], + output: mini ? [-1, 2, 6, 9] : [-3, 1, 8, 12] + }) + }, + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Animations.animated.rect, { + fill: "white", + x: animation.state.to({ + range: [0, .3, .7, 1], + output: [4, 0, 0, 4] + }), + y: animation.state.to({ + range: [0, .3, .7, 1], + output: [0, 1, 1, 0] + }), + height: animation.state.to({ + range: [0, .3, .7, 1], + output: [20, 18, 18, 20] + }), + width: animation.state.to({ + range: [0, .3, .7, 1], + output: [20, 28, 28, 20] + }), + rx: "10" + }), + BDFDB.ReactUtils.createElement("svg", { + viewBox: "0 0 20 20", + fill: "none", + children: [ + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Animations.animated.path, { + fill: fill, + d: animation.state.to({ + range: [0, .3, .7, 1], + output: reducedMotion.enabled ? [SwitchIconPaths.a.TOP, SwitchIconPaths.a.TOP, SwitchIconPaths.c.TOP, SwitchIconPaths.c.TOP] : [SwitchIconPaths.a.TOP, SwitchIconPaths.b.TOP, SwitchIconPaths.b.TOP, SwitchIconPaths.c.TOP] + }) + }), + BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Animations.animated.path, { + fill: fill, + d: animation.state.to({ + range: [0, .3, .7, 1], + output: reducedMotion.enabled ? [SwitchIconPaths.a.BOTTOM, SwitchIconPaths.a.BOTTOM, SwitchIconPaths.c.BOTTOM, SwitchIconPaths.c.BOTTOM] : [SwitchIconPaths.a.BOTTOM, SwitchIconPaths.b.BOTTOM, SwitchIconPaths.b.BOTTOM, SwitchIconPaths.c.BOTTOM] + }) + }) + ] + }) + ] + }), + BDFDB.ReactUtils.createElement("input", BDFDB.ObjectUtils.exclude(Object.assign({}, props, { + id: props.id, + type: "checkbox", + ref: ref, + className: BDFDB.DOMUtils.formatClassName(props.inputClassName, BDFDB.disCN.switchinner), + tabIndex: props.disabled ? -1 : 0, + onKeyDown: e => { + if (!props.disabled && !e.repeat && (e.key == " " || e.key == "Enter")) state[1](true); + }, + onKeyUp: e => { + if (!props.disabled && !e.repeat) { + state[1](false); + if (e.key == "Enter" && ref.current) ref.current.click(); + } + }, + onChange: e => { + state[1](false); + if (typeof props.onChange == "function") props.onChange(e.currentTarget.checked, e); + }, + checked: props.value, + disabled: props.disabled + }), "uncheckedColor", "checkedColor", "size", "value")) + ] + }); + }; + CustomComponents.Switch = reactInitialized && class BDFDB_Switch extends Internal.LibraryModules.React.Component { + handleChange() { + this.props.value = !this.props.value; + if (typeof this.props.onChange == "function") this.props.onChange(this.props.value, this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + return BDFDB.ReactUtils.createElement(SwitchInner, Object.assign({}, this.props, { + onChange: this.handleChange.bind(this) + })); + } + }; + CustomComponents.Switch.Sizes = { + DEFAULT: "default", + MINI: "mini", + }; + Internal.setDefaultProps(CustomComponents.Switch, { + size: CustomComponents.Switch.Sizes.DEFAULT, + uncheckedColor: BDFDB.DiscordConstants.Colors.PRIMARY_DARK_400, + checkedColor: BDFDB.DiscordConstants.Colors.BRAND + }); + + CustomComponents.TabBar = reactInitialized && class BDFDB_TabBar extends Internal.LibraryModules.React.Component { + handleItemSelect(item) { + this.props.selectedItem = item; + if (typeof this.props.onItemSelect == "function") this.props.onItemSelect(item, this); + BDFDB.ReactUtils.forceUpdate(this); + } + render() { + let items = (BDFDB.ArrayUtils.is(this.props.items) ? this.props.items : [{}]).filter(n => n); + let selectedItem = this.props.selectedItem || (items[0] || {}).value; + let renderItem = typeof this.props.renderItem == "function" ? this.props.renderItem : (data => data.label || data.value); + return BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.TabBar, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + selectedItem: selectedItem, + onItemSelect: this.handleItemSelect.bind(this), + children: items.map(data => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TabBar.Item, { + className: BDFDB.DOMUtils.formatClassName(this.props.itemClassName, selectedItem == data.value && this.props.itemSelectedClassName), + itemType: this.props.type, + id: data.value, + children: renderItem(data), + "aria-label": data.label || data.value + })) + }), "itemClassName", "items", "renderItem")); + } + }; + + CustomComponents.Table = reactInitialized && class BDFDB_Table extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.Table, Object.assign({}, this.props, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.table, this.props.className), + headerCellClassName: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tableheadercell, this.props.headerCellClassName), + sortedHeaderCellClassName: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tableheadercellsorted, this.props.sortedHeaderCellClassName), + bodyCellClassName: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.tablebodycell, this.props.bodyCellClassName), + onSort: (sortKey, sortDirection) => { + this.props.sortDirection = this.props.sortKey != sortKey && sortDirection == Internal.LibraryComponents.Table.SortDirection.ASCENDING && this.props.columns.filter(n => n.key == sortKey)[0].reverse ? Internal.LibraryComponents.Table.SortDirection.DESCENDING : sortDirection; + this.props.sortKey = sortKey; + this.props.data = BDFDB.ArrayUtils.keySort(this.props.data, this.props.sortKey); + if (this.props.sortDirection == Internal.LibraryComponents.Table.SortDirection.DESCENDING) this.props.data.reverse(); + if (typeof this.props.onSort == "function") this.props.onSort(this.props.sortKey, this.props.sortDirection); + BDFDB.ReactUtils.forceUpdate(this); + } + })); + } + }; + + CustomComponents.TextArea = reactInitialized && class BDFDB_TextArea extends Internal.LibraryModules.React.Component { + handleChange(e) { + this.props.value = e; + if (typeof this.props.onChange == "function") this.props.onChange(e, this); + BDFDB.ReactUtils.forceUpdate(this); + } + handleBlur(e) {if (typeof this.props.onBlur == "function") this.props.onBlur(e, this);} + handleFocus(e) {if (typeof this.props.onFocus == "function") this.props.onFocus(e, this);} + render() { + return BDFDB.ReactUtils.createElement(Internal.NativeSubComponents.TextArea, Object.assign({}, this.props, { + onChange: this.handleChange.bind(this), + onBlur: this.handleBlur.bind(this), + onFocus: this.handleFocus.bind(this) + })); + } + }; + + CustomComponents.TextGradientElement = reactInitialized && class BDFDB_TextGradientElement extends Internal.LibraryModules.React.Component { + render() { + if (this.props.gradient && this.props.children) return BDFDB.ReactUtils.createElement("span", { + children: this.props.children, + ref: instance => { + let ele = BDFDB.ReactUtils.findDOMNode(instance); + if (ele) { + ele.style.setProperty("background-image", this.props.gradient, "important"); + ele.style.setProperty("color", "transparent", "important"); + ele.style.setProperty("-webkit-background-clip", "text", "important"); + } + } + }); + return this.props.children || null; + } + }; + + CustomComponents.TextInput = reactInitialized && class BDFDB_TextInput extends Internal.LibraryModules.React.Component { + handleChange(e) { + let value = e = BDFDB.ObjectUtils.is(e) ? e.currentTarget.value : e; + this.props.value = this.props.valuePrefix && !value.startsWith(this.props.valuePrefix) ? (this.props.valuePrefix + value) : value; + if (typeof this.props.onChange == "function") this.props.onChange(this.props.value, this); + BDFDB.ReactUtils.forceUpdate(this); + } + handleInput(e) {if (typeof this.props.onInput == "function") this.props.onInput(BDFDB.ObjectUtils.is(e) ? e.currentTarget.value : e, this);} + handleKeyDown(e) {if (typeof this.props.onKeyDown == "function") this.props.onKeyDown(e, this);} + handleBlur(e) {if (typeof this.props.onBlur == "function") this.props.onBlur(e, this);} + handleFocus(e) {if (typeof this.props.onFocus == "function") this.props.onFocus(e, this);} + handleMouseEnter(e) {if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this);} + handleMouseLeave(e) {if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this);} + handleNumberButton(ins, value) { + BDFDB.TimeUtils.clear(this.pressedTimeout); + this.pressedTimeout = BDFDB.TimeUtils.timeout(_ => { + delete this.props.focused; + BDFDB.ReactUtils.forceUpdate(this); + }, 1000); + this.props.focused = true; + this.handleChange.apply(this, [value]); + this.handleInput.apply(this, [value]); + } + componentDidMount() { + if (this.props.type == "file") { + let navigatorInstance = BDFDB.ReactUtils.findOwner(this, {name: "BDFDB_FileButton"}); + if (navigatorInstance) navigatorInstance.refInput = this; + } + let input = BDFDB.ReactUtils.findDOMNode(this); + if (!input) return; + input = input.querySelector("input") || input; + if (input && !input.patched) { + input.addEventListener("keydown", e => { + this.handleKeyDown.apply(this, [e]); + e.stopImmediatePropagation(); + }); + input.patched = true; + } + } + render() { + let inputChildren = [ + BDFDB.ReactUtils.createElement("input", BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + className: BDFDB.DOMUtils.formatClassName(this.props.size && Internal.LibraryComponents.TextInput.Sizes[this.props.size.toUpperCase()] && BDFDB.disCN["input" + this.props.size.toLowerCase()] || BDFDB.disCN.inputdefault, this.props.inputClassName, this.props.focused && BDFDB.disCN.inputfocused, this.props.error || this.props.errorMessage ? BDFDB.disCN.inputerror : (this.props.success && BDFDB.disCN.inputsuccess), this.props.disabled && BDFDB.disCN.inputdisabled, this.props.editable && BDFDB.disCN.inputeditable), + type: this.props.type == "color" || this.props.type == "file" ? "text" : this.props.type, + onChange: this.handleChange.bind(this), + onInput: this.handleInput.bind(this), + onKeyDown: this.handleKeyDown.bind(this), + onBlur: this.handleBlur.bind(this), + onFocus: this.handleFocus.bind(this), + onMouseEnter: this.handleMouseEnter.bind(this), + onMouseLeave: this.handleMouseLeave.bind(this), + maxLength: this.props.type == "file" ? false : this.props.maxLength, + style: this.props.width ? {width: `${this.props.width}px`} : {}, + ref: this.props.inputRef + }), "errorMessage", "focused", "error", "success", "inputClassName", "inputChildren", "valuePrefix", "inputPrefix", "size", "editable", "inputRef", "style", "mode", "colorPickerOpen", "noAlpha", "filter", "useFilePath", "searchFolders")), + this.props.inputChildren, + this.props.type == "color" ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex.Child, { + wrap: true, + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.ColorSwatches, { + colors: [], + color: this.props.value && this.props.mode == "comp" ? BDFDB.ColorUtils.convert(this.props.value.split(","), "RGB") : this.props.value, + onColorChange: color => this.handleChange.apply(this, [!color ? "" : (this.props.mode == "comp" ? BDFDB.ColorUtils.convert(color, "RGBCOMP").slice(0, 3).join(",") : BDFDB.ColorUtils.convert(color, this.props.noAlpha ? "RGB" : "RGBA"))]), + pickerOpen: this.props.colorPickerOpen, + onPickerOpen: _ => this.props.colorPickerOpen = true, + onPickerClose: _ => delete this.props.colorPickerOpen, + ref: this.props.controlsRef, + pickerConfig: {gradient: false, alpha: this.props.mode != "comp" && !this.props.noAlpha} + }) + }) : null, + this.props.type == "file" ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.FileButton, { + filter: this.props.filter, + mode: this.props.mode, + useFilePath: this.props.useFilePath, + searchFolders: this.props.searchFolders, + ref: this.props.controlsRef + }) : null + ].flat(10).filter(n => n); + + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.inputwrapper, this.props.type == "number" && (this.props.size && Internal.LibraryComponents.TextInput.Sizes[this.props.size.toUpperCase()] && BDFDB.disCN["inputnumberwrapper" + this.props.size.toLowerCase()] || BDFDB.disCN.inputnumberwrapperdefault), this.props.className), + style: this.props.style, + children: [ + this.props.inputPrefix ? BDFDB.ReactUtils.createElement("span", { + className: BDFDB.disCN.inputprefix + }) : null, + this.props.type == "number" ? BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.inputnumberbuttons, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.inputnumberbuttonup, + onClick: e => { + let min = parseInt(this.props.min); + let max = parseInt(this.props.max); + let newV = parseInt(this.props.value) + 1 || min || 0; + if (isNaN(max) || !isNaN(max) && newV <= max) this.handleNumberButton.bind(this)(e._targetInst, isNaN(min) || !isNaN(min) && newV >= min ? newV : min); + } + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.inputnumberbuttondown, + onClick: e => { + let min = parseInt(this.props.min); + let max = parseInt(this.props.max); + let newV = parseInt(this.props.value) - 1 || min || 0; + if (isNaN(min) || !isNaN(min) && newV >= min) this.handleNumberButton.bind(this)(e._targetInst, isNaN(max) || !isNaN(max) && newV <= max ? newV : max); + } + }) + ] + }) : null, + inputChildren.length == 1 ? inputChildren[0] : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex, { + align: Internal.LibraryComponents.Flex.Align.CENTER, + children: inputChildren.map((child, i) => i != 0 ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Flex.Child, { + shrink: 0, + children: child + }) : child) + }), + this.props.errorMessage ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TextElement, { + className: BDFDB.disCN.margintop8, + size: Internal.LibraryComponents.TextElement.Sizes.SIZE_12, + color: Internal.LibraryComponents.TextElement.Colors.STATUS_RED, + children: this.props.errorMessage + }) : null + ].filter(n => n) + }); + } + }; + + CustomComponents.TextScroller = reactInitialized && class BDFDB_TextScroller extends Internal.LibraryModules.React.Component { + render() { + let scrolling, scroll = _ => {}; + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.textscroller, this.props.className), + style: Object.assign({}, this.props.style, { + position: "relative", + display: "block", + overflow: "hidden" + }), + ref: instance => { + const ele = BDFDB.ReactUtils.findDOMNode(instance); + if (ele && ele.parentElement) { + const maxWidth = BDFDB.DOMUtils.getInnerWidth(ele.parentElement); + if (maxWidth > 50) ele.style.setProperty("max-width", `${maxWidth}px`); + if (!this.props.initiated) BDFDB.TimeUtils.timeout(_ => { + this.props.initiated = true; + if (document.contains(ele.parentElement)) BDFDB.ReactUtils.forceUpdate(this); + }, 3000); + const Animation = new Internal.LibraryModules.AnimationUtils.Value(0); + Animation.interpolate({inputRange: [0, 1], outputRange: [0, (BDFDB.DOMUtils.getRects(ele.firstElementChild).width - BDFDB.DOMUtils.getRects(ele).width) * -1]}).addListener(v => { + ele.firstElementChild.style.setProperty("display", v.value == 0 ? "inline" : "block", "important"); + ele.firstElementChild.style.setProperty("left", `${v.value}px`, "important"); + }); + scroll = p => { + const display = ele.firstElementChild.style.getPropertyValue("display"); + ele.firstElementChild.style.setProperty("display", "inline", "important"); + const innerWidth = BDFDB.DOMUtils.getRects(ele.firstElementChild).width; + const outerWidth = BDFDB.DOMUtils.getRects(ele).width; + ele.firstElementChild.style.setProperty("display", display, "important"); + + let w = p + parseFloat(ele.firstElementChild.style.getPropertyValue("left")) / (innerWidth - outerWidth); + w = isNaN(w) || !isFinite(w) ? p : w; + w *= innerWidth / (outerWidth * 2); + Internal.LibraryModules.AnimationUtils.parallel([Internal.LibraryModules.AnimationUtils.timing(Animation, {toValue: p, duration: Math.sqrt(w**2) * 4000 / (parseInt(this.props.speed) || 1)})]).start(); + }; + } + }, + onClick: e => { + if (typeof this.props.onClick == "function") this.props.onClick(e, this); + }, + onMouseEnter: e => { + if (BDFDB.DOMUtils.getRects(e.currentTarget).width < BDFDB.DOMUtils.getRects(e.currentTarget.firstElementChild).width || e.currentTarget.firstElementChild.style.getPropertyValue("display") != "inline") { + scrolling = true; + scroll(1); + } + }, + onMouseLeave: e => { + if (scrolling) { + scrolling = false; + scroll(0); + } + }, + children: BDFDB.ReactUtils.createElement("div", { + style: { + left: "0", + position: "relative", + display: "inline", + whiteSpace: "nowrap" + }, + children: this.props.children + }) + }); + } + }; + CustomComponents.TooltipContainer = reactInitialized && class BDFDB_TooltipContainer extends Internal.LibraryModules.React.Component { + updateTooltip(text) { + if (this.tooltip) this.tooltip.update(text); + } + render() { + let child = (typeof this.props.children == "function" ? this.props.children() : (BDFDB.ArrayUtils.is(this.props.children) ? this.props.children[0] : this.props.children)) || BDFDB.ReactUtils.createElement("div", {}); + child.props.className = BDFDB.DOMUtils.formatClassName(child.props.className, this.props.className); + let childProps = Object.assign({}, child.props); + let shown = false; + child.props.onMouseEnter = (e, childThis) => { + if (!shown && !e.currentTarget.__BDFDBtooltipShown && !(this.props.onlyShowOnShift && !e.shiftKey) && !(this.props.onlyShowOnCtrl && !e.ctrlKey)) { + e.currentTarget.__BDFDBtooltipShown = shown = true; + this.tooltip = BDFDB.TooltipUtils.create(e.currentTarget, typeof this.props.text == "function" ? this.props.text(this, e) : this.props.text, Object.assign({ + note: this.props.note, + delay: this.props.delay + }, this.props.tooltipConfig, { + onHide: (tooltip, anker) => { + delete anker.__BDFDBtooltipShown; + shown = false; + if (this.props.tooltipConfig && typeof this.props.tooltipConfig.onHide == "function") this.props.tooltipConfig.onHide(tooltip, anker); + } + })); + if (typeof this.props.onMouseEnter == "function") this.props.onMouseEnter(e, this); + if (typeof childProps.onMouseEnter == "function") childProps.onMouseEnter(e, childThis); + } + }; + child.props.onMouseLeave = (e, childThis) => { + if (typeof this.props.onMouseLeave == "function") this.props.onMouseLeave(e, this); + if (typeof childProps.onMouseLeave == "function") childProps.onMouseLeave(e, childThis); + }; + child.props.onClick = (e, childThis) => { + if (typeof this.props.onClick == "function") this.props.onClick(e, this); + if (typeof childProps.onClick == "function") childProps.onClick(e, childThis); + if (typeof this.props.text == "function") this.updateTooltip(this.props.text(this, e)); + }; + child.props.onContextMenu = (e, childThis) => { + if (typeof this.props.onContextMenu == "function") this.props.onContextMenu(e, this); + if (typeof childProps.onContextMenu == "function") childProps.onContextMenu(e, childThis); + if (typeof this.props.text == "function") this.updateTooltip(this.props.text(this, e)); + }; + return BDFDB.ReactUtils.createElement(Internal.LibraryModules.React.Fragment, { + children: child + }); + } + }; + + CustomComponents.UserPopoutContainer = reactInitialized && class BDFDB_UserPopoutContainer extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement(Internal.LibraryComponents.PopoutContainer, BDFDB.ObjectUtils.exclude(Object.assign({}, this.props, { + wrap: false, + renderPopout: instance => BDFDB.ReactUtils.createElement(Internal.LibraryComponents.UserPopout, { + user: Internal.LibraryModules.UserStore.getUser(this.props.userId), + userId: this.props.userId, + channelId: this.props.channelId, + guildId: this.props.guildId + }), + }), "userId", "channelId", "guildId")); + } + }; + + const VideoInner = function (props) { + let ref = BDFDB.ReactUtils.useRef(null); + BDFDB.ReactUtils.useEffect(_ => { + if (ref.current) props.play ? ref.current.play() : ref.current.pause(); + }, [props.play]); + return props.naturalWidth <= BDFDB.DiscordConstants.MAX_VIDEO_WIDTH && props.naturalHeight <= BDFDB.DiscordConstants.MAX_VIDEO_HEIGHT || props.naturalWidth <= BDFDB.DiscordConstants.MAX_VIDEO_HEIGHT && props.naturalHeight <= BDFDB.DiscordConstants.MAX_VIDEO_WIDTH ? BDFDB.ReactUtils.createElement(Internal.LibraryComponents.VideoForwardRef, { + ref: ref, + className: props.className, + poster: props.poster, + src: props.src, + width: props.width, + height: props.height, + muted: true, + loop: true, + autoPlay: props.play, + preload: "none" + }) : BDFDB.ReactUtils.createElement("img", { + alt: "", + src: props.poster, + width: props.width, + height: props.height + }); + }; + CustomComponents.Video = reactInitialized && class BDFDB_Video extends Internal.LibraryModules.React.Component { + render() { + return BDFDB.ReactUtils.createElement(VideoInner, this.props); + } + }; + + const NativeSubComponents = {}; + Internal.NativeSubComponents = new Proxy(NativeSubComponents, { + get: function (_, item) { + if (NativeSubComponents[item]) return NativeSubComponents[item]; + if (!InternalData.NativeSubComponents[item]) return "div"; + if (InternalData.NativeSubComponents[item].name) { + if (InternalData.NativeSubComponents[item].protos) { + NativeSubComponents[item] = BDFDB.ModuleUtils.find(m => m && m.displayName == InternalData.NativeSubComponents[item].name && m.prototype && InternalData.NativeSubComponents[item].protos.every(proto => m.prototype[proto]) && m); + if (!NativeSubComponents[item]) BDFDB.LogUtils.warn(`${JSON.stringify([InternalData.NativeSubComponents[item].name, InternalData.NativeSubComponents[item].protos].flat(10))} [name + protos] not found in WebModules`); + } + else NativeSubComponents[item] = BDFDB.ModuleUtils.findByName(InternalData.NativeSubComponents[item].name); + } + else if (InternalData.NativeSubComponents[item].props) NativeSubComponents[item] = BDFDB.ModuleUtils.findByProperties(InternalData.NativeSubComponents[item].props); + return NativeSubComponents[item] ? NativeSubComponents[item] : "div"; + } + }); + + const LibraryComponents = {}; + Internal.LibraryComponents = new Proxy(LibraryComponents, { + get: function (_, item) { + if (LibraryComponents[item]) return LibraryComponents[item]; + if (!InternalData.LibraryComponents[item] && !CustomComponents[item]) return "div"; + if (InternalData.LibraryComponents[item]) { + if (InternalData.LibraryComponents[item].name) LibraryComponents[item] = BDFDB.ModuleUtils.findByName(InternalData.LibraryComponents[item].name); + else if (InternalData.LibraryComponents[item].strings) LibraryComponents[item] = BDFDB.ModuleUtils.findByString(InternalData.LibraryComponents[item].strings); + else if (InternalData.LibraryComponents[item].props) LibraryComponents[item] = BDFDB.ModuleUtils.findByProperties(InternalData.LibraryComponents[item].props); + if (InternalData.LibraryComponents[item].value) LibraryComponents[item] = (LibraryComponents[item] || {})[InternalData.LibraryComponents[item].value]; + if (InternalData.LibraryComponents[item].assign) LibraryComponents[item] = Object.assign({}, LibraryComponents[item]); + } + if (CustomComponents[item]) LibraryComponents[item] = LibraryComponents[item] ? Object.assign({}, LibraryComponents[item], CustomComponents[item]) : CustomComponents[item]; + + const NativeComponent = LibraryComponents[item] && Internal.NativeSubComponents[item]; + if (NativeComponent && typeof NativeComponent != "string") { + for (let key in NativeComponent) if (key != "displayName" && key != "name" && (typeof NativeComponent[key] != "function" || key.charAt(0) == key.charAt(0).toUpperCase())) { + if (key == "defaultProps") LibraryComponents[item][key] = Object.assign({}, LibraryComponents[item][key], NativeComponent[key]); + else if (!LibraryComponents[item][key]) LibraryComponents[item][key] = NativeComponent[key]; + } + } + if (InternalData.LibraryComponents[item] && InternalData.LibraryComponents[item].children) { + const SubComponents = LibraryComponents[item] && typeof LibraryComponents[item] == "object" ? LibraryComponents[item] : {}; + const InternalParentData = InternalData.LibraryComponents[item].children; + LibraryComponents[item] = new Proxy(BDFDB.ObjectUtils.is(SubComponents) ? SubComponents : {}, { + get: function (_, item2) { + if (CustomComponents[item] && CustomComponents[item][item2]) return CustomComponents[item][item2]; + if (SubComponents[item2]) return SubComponents[item2]; + if (!InternalParentData[item2]) return "div"; + if (InternalParentData[item2].name) SubComponents[item2] = BDFDB.ModuleUtils.findByName(InternalParentData[item2].name); + else if (InternalParentData[item2].strings) SubComponents[item2] = BDFDB.ModuleUtils.findByString(InternalParentData[item2].strings); + else if (InternalParentData[item2].props) SubComponents[item2] = BDFDB.ModuleUtils.findByProperties(InternalParentData[item2].props); + + if (InternalParentData[item2].value) SubComponents[item2] = (SubComponents[item2] || {})[InternalParentData[item2].value]; + if (InternalParentData[item2].assign) SubComponents[item] = Object.assign({}, SubComponents[item2]); + if (CustomComponents[item2]) SubComponents[item2] = SubComponents[item2] ? Object.assign({}, SubComponents[item2], CustomComponents[item2]) : CustomComponents[item2]; + + const NativeComponent = Internal.NativeSubComponents[item2]; + if (NativeComponent && typeof NativeComponent != "string") { + for (let key in NativeComponent) if (key != "displayName" && key != "name" && (typeof NativeComponent[key] != "function" || key.charAt(0) == key.charAt(0).toUpperCase())) { + if (key == "defaultProps") SubComponents[item2][key] = Object.assign({}, SubComponents[item2][key], NativeComponent[key]); + else if (!SubComponents[item2][key]) SubComponents[item2][key] = NativeComponent[key]; + } + } + return SubComponents[item2] ? SubComponents[item2] : "div"; + } + }); + } + return LibraryComponents[item] ? LibraryComponents[item] : "div"; + } + }); + + BDFDB.LibraryComponents = Internal.LibraryComponents; + + Internal.createCustomControl = function (data) { + let controlButton = BDFDB.DOMUtils.create(``); + BDFDB.ReactUtils.render(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + nativeClass: true, + name: data.svgName, + width: 20, + height: 20 + }), controlButton); + controlButton.addEventListener("click", _ => {if (typeof data.onClick == "function") data.onClick();}); + if (data.tooltipText) controlButton.addEventListener("mouseenter", _ => {BDFDB.TooltipUtils.create(controlButton, data.tooltipText);}); + return controlButton; + }; + Internal.appendCustomControls = function (card) { + if (!card || card.querySelector(BDFDB.dotCN._repocontrolscustom)) return; + let checkbox = card.querySelector(BDFDB.dotCN._reposwitch); + if (!checkbox) return; + let props = BDFDB.ObjectUtils.get(BDFDB.ReactUtils.getInstance(card), "return.stateNode.props"); + let plugin = props && props.addon && (props.addon.plugin || props.addon.instance); + if (plugin && (plugin == libraryInstance || plugin.name && plugin.name && PluginStores.loaded[plugin.name] && PluginStores.loaded[plugin.name] == plugin)) { + let url = Internal.getPluginURL(plugin); + let controls = []; + let footerControls = card.querySelector(BDFDB.dotCNS._repofooter + BDFDB.dotCN._repocontrols); + if (plugin.changeLog) controls.push(Internal.createCustomControl({ + tooltipText: BDFDB.LanguageUtils.LanguageStrings.CHANGE_LOG, + svgName: Internal.LibraryComponents.SvgIcon.Names.CHANGELOG, + onClick: _ => {BDFDB.PluginUtils.openChangeLog(plugin);} + })); + if (PluginStores.updateData.plugins[url] && PluginStores.updateData.plugins[url].outdated) controls.push(Internal.createCustomControl({ + tooltipText: BDFDB.LanguageUtils.LanguageStrings.UPDATE_MANUALLY, + svgName: Internal.LibraryComponents.SvgIcon.Names.DOWNLOAD, + onClick: _ => {BDFDB.PluginUtils.downloadUpdate(plugin.name, url);} + })); + if (footerControls) for (let control of controls) footerControls.insertBefore(control, footerControls.firstElementChild); + else for (let control of controls) checkbox.parentElement.insertBefore(control, checkbox.parentElement.firstElementChild); + } + }; + Internal.addListObserver = function (layer) { + if (!layer) return; + BDFDB.ObserverUtils.connect(BDFDB, layer, {name: "cardObserver", instance: new MutationObserver(changes => {changes.forEach(change => {if (change.addedNodes) {change.addedNodes.forEach(n => { + if (BDFDB.DOMUtils.containsClass(n, BDFDB.disCN._repocard)) Internal.appendCustomControls(n); + if (n.nodeType != Node.TEXT_NODE) for (let c of n.querySelectorAll(BDFDB.dotCN._repocard)) Internal.appendCustomControls(c); + Internal.appendCustomControls(BDFDB.DOMUtils.getParent(BDFDB.dotCN._repocard, n)); + });}});})}, {childList: true, subtree: true}); + for (let c of layer.querySelectorAll(BDFDB.dotCN._repocard)) Internal.appendCustomControls(c); + }; + + const keyDownTimeouts = {}; + BDFDB.ListenerUtils.add(BDFDB, document, "keydown.BDFDBPressedKeys", e => { + if (!pressedKeys.includes(e.which)) { + BDFDB.TimeUtils.clear(keyDownTimeouts[e.which]); + pressedKeys.push(e.which); + keyDownTimeouts[e.which] = BDFDB.TimeUtils.timeout(_ => { + BDFDB.ArrayUtils.remove(pressedKeys, e.which, true); + }, 60000); + } + }); + BDFDB.ListenerUtils.add(BDFDB, document, "keyup.BDFDBPressedKeys", e => { + BDFDB.TimeUtils.clear(keyDownTimeouts[e.which]); + BDFDB.ArrayUtils.remove(pressedKeys, e.which, true); + }); + BDFDB.ListenerUtils.add(BDFDB, document, "mousedown.BDFDBMousePosition", e => { + mousePosition = e; + }); + BDFDB.ListenerUtils.add(BDFDB, window, "focus.BDFDBPressedKeysReset", e => { + pressedKeys = []; + }); + + Internal.patchedModules = { + before: { + SearchBar: "render", + EmojiPicker: "type", + EmojiPickerListRow: "default" + }, + after: { + useCopyIdItem: "default", + Menu: "default", + SettingsView: "componentDidMount", + Shakeable: "render", + Account: ["componentDidMount", "componentDidUpdate"], + Message: "default", + MessageToolbar: "type", + MessageHeader: "default", + MemberListItem: ["componentDidMount", "componentDidUpdate"], + PrivateChannel: ["componentDidMount", "componentDidUpdate"], + AnalyticsContext: ["componentDidMount", "componentDidUpdate"], + UserPopoutAvatar: "UserPopoutAvatar", + PeopleListItem: ["componentDidMount", "componentDidUpdate"], + DiscordTag: "default" + } + }; + + Internal.processUseCopyIdItem = function (e) { + if (!e.returnvalue) e.returnvalue = false; + }; + + const menuExtraPatches = {}; + Internal.processMenu = function (e) { + if (e.instance.props.navId) switch (e.instance.props.navId) { + case "guild-header-popout": + if (menuExtraPatches["guild-header-popout"]) return; + menuExtraPatches["guild-header-popout"] = true; + BDFDB.TimeUtils.interval((interval, count) => { + if (count > 20) return BDFDB.TimeUtils.clear(interval); + else { + let module = BDFDB.ModuleUtils.findByString("guild-header-popout"); + if (module) BDFDB.PatchUtils.patch(BDFDB, module.default.prototype, "render", {after: e2 => { + BDFDB.PatchUtils.patch(BDFDB, e2.returnValue.type, "type", {after: e3 => { + Internal.triggerQueuePatch("GuildHeaderContextMenu", { + arguments: e3.methodArguments, + instance: {props: e3.methodArguments[0]}, + returnvalue: e3.returnValue, + component: e2.returnValue, + methodname: "type", + type: "GuildHeaderContextMenu" + }); + }}, {noCache: true}); + }}); + } + }, 500); + return; + } + if (!e.instance.props.children || BDFDB.ArrayUtils.is(e.instance.props.children) && !e.instance.props.children.length) Internal.LibraryModules.ContextMenuUtils.closeContextMenu(); + }; + + Internal.processSearchBar = function (e) { + if (typeof e.instance.props.query != "string") e.instance.props.query = ""; + }; + + Internal.processSettingsView = function (e) { + if (e.node && e.node.parentElement && e.node.parentElement) Internal.addListObserver(e.node.parentElement); + }; + + let AppViewExport = InternalData.ModuleUtilsConfig.Finder.AppView && BDFDB.ModuleUtils.findByString(InternalData.ModuleUtilsConfig.Finder.AppView.strings, false); + if (AppViewExport) Internal.processShakeable = function (e) { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {filter: n => { + if (!n || typeof n.type != "function") return; + let typeString = n.type.toString(); + return [InternalData.ModuleUtilsConfig.Finder.AppView.strings].flat(10).filter(n => typeof n == "string").every(string => typeString.indexOf(string) > -1); + }}); + if (index > -1) children[index] = BDFDB.ReactUtils.createElement(AppViewExport.exports.default, children[index].props); + }; + + Internal.processMessage = function (e) { + if (e.returnvalue && e.returnvalue.props && e.returnvalue.props.children && e.returnvalue.props.children.props) { + let message; + for (let key in e.instance.props) { + if (!message) message = BDFDB.ObjectUtils.get(e.instance.props[key], "props.message"); + else break; + } + if (message) { + e.returnvalue.props.children.props[InternalData.authorIdAttribute] = message.author.id; + if (Internal.LibraryModules.RelationshipStore.isFriend(message.author.id)) e.returnvalue.props.children.props[InternalData.authorFriendAttribute] = true; + if (message.author.id == BDFDB.UserUtils.me.id) e.returnvalue.props.children.props[InternalData.authorSelfAttribute] = true; + } + } + }; + + Internal.processMessageToolbar = function (e) { + if (document.querySelector(BDFDB.dotCN.emojipicker) || !BDFDB.ObjectUtils.toArray(PluginStores.loaded).filter(p => p.started).some(p => p.onSystemMessageOptionContextMenu || p.onSystemMessageOptionToolbar || p.onMessageOptionContextMenu || p.onMessageOptionToolbar)) return; + let toolbar = BDFDB.ReactUtils.findChild(e.returnvalue, {filter: c => c && c.props && c.props.showMoreUtilities != undefined && c.props.showEmojiPicker != undefined && c.props.setPopout != undefined}); + if (toolbar) BDFDB.PatchUtils.patch(BDFDB, toolbar, "type", {after: e2 => { + let menu = BDFDB.ReactUtils.findChild(e2.returnValue, {filter: c => c && c.props && typeof c.props.onRequestClose == "function" && c.props.onRequestClose.toString().indexOf("moreUtilities") > -1}); + let isSystem = BDFDB.MessageUtils.isSystemMessage(e2.methodArguments[0] && e2.methodArguments[0].message); + Internal.triggerQueuePatch(isSystem ? "SystemMessageOptionToolbar" : "MessageOptionToolbar", { + arguments: e2.methodArguments, + instance: {props: e2.methodArguments[0]}, + returnvalue: e2.returnValue, + methodname: "default", + type: isSystem ? "SystemMessageOptionToolbar" : "MessageOptionToolbar" + }); + if (menu && typeof menu.props.renderPopout == "function") { + let renderPopout = menu.props.renderPopout; + menu.props.renderPopout = BDFDB.TimeUtils.suppress((...args) => { + let renderedPopout = renderPopout(...args); + renderedPopout.props.updatePosition = _ => {}; + BDFDB.PatchUtils.patch(BDFDB, renderedPopout, "type", {after: e3 => { + let isSystem = BDFDB.MessageUtils.isSystemMessage(e3.methodArguments[0] && e3.methodArguments[0].message); + Internal.triggerQueuePatch(isSystem ? "SystemMessageOptionContextMenu" : "MessageOptionContextMenu", { + arguments: e3.methodArguments, + instance: {props: e3.methodArguments[0]}, + returnvalue: e3.returnValue, + methodname: "default", + type: isSystem ? "SystemMessageOptionContextMenu" : "MessageOptionContextMenu" + }); + }}, {noCache: true}); + return renderedPopout; + }, "Error in Popout Render of MessageOptionToolbar!"); + } + }}, {once: true}); + }; + + const BDFDB_Patrons = Object.assign({}, InternalData.BDFDB_Patrons), BDFDB_Patron_Tiers = Object.assign({}, InternalData.BDFDB_Patron_Tiers); + Internal._processAvatarRender = function (user, avatar, wrapper, className) { + if (BDFDB.ReactUtils.isValidElement(avatar) && BDFDB.ObjectUtils.is(user) && (avatar.props.className || "").indexOf(BDFDB.disCN.bdfdbbadgeavatar) == -1) { + if (wrapper) wrapper.props[InternalData.userIdAttribute] = user.id; + avatar.props[InternalData.userIdAttribute] = user.id; + let role = "", note = "", color, link, addBadge = Internal.settings.general.showSupportBadges; + if (BDFDB_Patrons[user.id] && BDFDB_Patrons[user.id].active) { + link = "https://www.patreon.com/MircoWittrien"; + role = BDFDB_Patrons[user.id].text || (BDFDB_Patron_Tiers[BDFDB_Patrons[user.id].tier] || {}).text; + note = BDFDB_Patrons[user.id].text && (BDFDB_Patron_Tiers[BDFDB_Patrons[user.id].tier] || {}).text; + color = BDFDB_Patrons[user.id].color; + className = BDFDB.DOMUtils.formatClassName(avatar.props.className, className, addBadge && BDFDB.disCN.bdfdbhasbadge, BDFDB.disCN.bdfdbbadgeavatar, BDFDB.disCN.bdfdbsupporter, BDFDB.disCN[`bdfdbsupporter${BDFDB_Patrons[user.id].tier}`]); + } + else if (user.id == InternalData.myId) { + addBadge = true; + role = `Theme ${BDFDB.LanguageUtils.LibraryStrings.developer}`; + className = BDFDB.DOMUtils.formatClassName(avatar.props.className, className, BDFDB.disCN.bdfdbhasbadge, BDFDB.disCN.bdfdbbadgeavatar, BDFDB.disCN.bdfdbdev); + } + if (role) { + delete avatar.props[InternalData.userIdAttribute]; + if (avatar.type == "img") avatar = BDFDB.ReactUtils.createElement(Internal.LibraryComponents.AvatarComponents.default, Object.assign({}, avatar.props, { + size: Internal.LibraryComponents.AvatarComponents.Sizes.SIZE_40 + })); + delete avatar.props.className; + let newProps = { + className: className, + children: [avatar] + }; + newProps[InternalData.userIdAttribute] = user.id; + avatar = BDFDB.ReactUtils.createElement("div", newProps); + if (addBadge) avatar.props.children.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.TooltipContainer, { + text: role, + note: note, + tooltipConfig: {backgroundColor: color || ""}, + onClick: link ? (_ => BDFDB.DiscordUtils.openLink(link)) : (_ => {}), + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.bdfdbbadge + }) + })); + return avatar; + } + } + }; + Internal._processAvatarMount = function (user, avatar, wrapper) { + if (!user) return; + if (wrapper) wrapper.setAttribute(InternalData.userIdAttribute, user.id); + if (Node.prototype.isPrototypeOf(avatar) && (avatar.className || "").indexOf(BDFDB.disCN.bdfdbbadgeavatar) == -1) { + avatar.setAttribute(InternalData.userIdAttribute, user.id); + let role = "", note = "", color, link, addBadge = Internal.settings.general.showSupportBadges; + if (BDFDB_Patrons[user.id] && BDFDB_Patrons[user.id].active) { + link = "https://www.patreon.com/MircoWittrien"; + role = BDFDB_Patrons[user.id].text || (BDFDB_Patron_Tiers[BDFDB_Patrons[user.id].tier] || {}).text; + note = BDFDB_Patrons[user.id].text && (BDFDB_Patron_Tiers[BDFDB_Patrons[user.id].tier] || {}).text; + color = BDFDB_Patrons[user.id].color; + avatar.className = BDFDB.DOMUtils.formatClassName(avatar.className, addBadge && BDFDB.disCN.bdfdbhasbadge, BDFDB.disCN.bdfdbbadgeavatar, BDFDB.disCN.bdfdbsupporter, BDFDB.disCN[`bdfdbsupporter${BDFDB_Patrons[user.id].tier}`]); + } + else if (user.id == InternalData.myId) { + addBadge = true; + role = `Theme ${BDFDB.LanguageUtils.LibraryStrings.developer}`; + avatar.className = BDFDB.DOMUtils.formatClassName(avatar.className, addBadge && BDFDB.disCN.bdfdbhasbadge, BDFDB.disCN.bdfdbbadgeavatar, BDFDB.disCN.bdfdbdev); + } + if (addBadge && role && !avatar.querySelector(BDFDB.dotCN.bdfdbbadge)) { + let badge = document.createElement("div"); + badge.className = BDFDB.disCN.bdfdbbadge; + if (link) badge.addEventListener("click", _ => BDFDB.DiscordUtils.openLink(link)); + badge.addEventListener("mouseenter", _ => BDFDB.TooltipUtils.create(badge, role, {position: "top", note: note, backgroundColor: color || ""})); + avatar.appendChild(badge); + } + } + }; + Internal.processAccount = function (e) { + Internal._processAvatarMount(e.instance.props.currentUser, e.node.querySelector(BDFDB.dotCN.avatarwrapper), e.node); + }; + Internal.processMessageHeader = function (e) { + if (e.instance.props.message && e.instance.props.message.author) { + let avatarWrapper = e.returnvalue.props.avatar || BDFDB.ObjectUtils.get(e, "returnvalue.props.children.0"); + if (avatarWrapper && avatarWrapper.props && typeof avatarWrapper.props.children == "function") { + let renderChildren = avatarWrapper.props.children; + avatarWrapper.props.children = BDFDB.TimeUtils.suppress((...args) => { + let renderedChildren = renderChildren(...args); + return Internal._processAvatarRender(e.instance.props.message.author, renderedChildren, null, BDFDB.disCN.messageavatar) || renderedChildren; + }, "Error in Avatar Render of MessageHeader!"); + } + else if (avatarWrapper && avatarWrapper.type == "img") e.returnvalue.props.children[0] = Internal._processAvatarRender(e.instance.props.message.author, avatarWrapper) || avatarWrapper; + } + }; + Internal.processMemberListItem = function (e) { + Internal._processAvatarMount(e.instance.props.user, e.node.querySelector(BDFDB.dotCN.avatarwrapper), e.node); + }; + Internal.processPrivateChannel = function (e) { + Internal._processAvatarMount(e.instance.props.user, e.node.querySelector(BDFDB.dotCN.avatarwrapper), e.node); + }; + Internal.processAnalyticsContext = function (e) { + if (e.instance.props.section != BDFDB.DiscordConstants.AnalyticsSections.PROFILE_MODAL && e.instance.props.section != BDFDB.DiscordConstants.AnalyticsSections.PROFILE_POPOUT) return; + const user = BDFDB.ReactUtils.findValue(e.instance, "user"); + if (!user) return; + const avatar = e.instance.props.section != BDFDB.DiscordConstants.AnalyticsSections.PROFILE_POPOUT && e.node.querySelector(BDFDB.dotCN.avatarwrapper); + const wrapper = e.node.querySelector(BDFDB.dotCNC.userpopout + BDFDB.dotCN.userprofile) || e.node; + if (avatar) Internal._processAvatarMount(user, avatar, wrapper); + if (wrapper) { + wrapper.setAttribute(InternalData.userIdAttribute, user.id); + if (InternalData.UserBackgrounds[user.id]) for (let property in InternalData.UserBackgrounds[user.id]) wrapper.style.setProperty(property, InternalData.UserBackgrounds[user.id][property], "important"); + } + }; + Internal.processUserPopoutAvatar = function (e) { + if (!e.instance.props.user) return; + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["className", BDFDB.disCN.userpopoutavatarwrapper]]}); + if (index > -1) children[index] = Internal._processAvatarRender(e.instance.props.user, children[index], null, e.instance) || children[index]; + }; + Internal.processPeopleListItem = function (e) { + if (e.instance.props.user) e.node.setAttribute(InternalData.userIdAttribute, e.instance.props.user.id); + }; + Internal.processDiscordTag = function (e) { + if (e.instance && e.instance.props && e.returnvalue && e.instance.props.user) e.returnvalue.props.user = e.instance.props.user; + }; + Internal.processEmojiPicker = function (e) { + if (BDFDB.ObjectUtils.toArray(PluginStores.loaded).filter(p => p.started).some(p => p.onSystemMessageOptionContextMenu || p.onSystemMessageOptionToolbar || p.onMessageOptionContextMenu || p.onMessageOptionToolbar)) e.instance.props.persistSearch = true; + }; + Internal.processEmojiPickerListRow = function (e) { + if (e.instance.props.emojiDescriptors && Internal.LibraryComponents.EmojiPickerButton.current && Internal.LibraryComponents.EmojiPickerButton.current.props && Internal.LibraryComponents.EmojiPickerButton.current.props.allowManagedEmojisUsage) for (let i in e.instance.props.emojiDescriptors) e.instance.props.emojiDescriptors[i] = Object.assign({}, e.instance.props.emojiDescriptors[i], {isDisabled: false}); + }; + + Internal.addChunkObserver = function (pluginData, config) { + let module; + if (config.stringFind) module = BDFDB.ModuleUtils.findByString(config.stringFind, config.exported, true); + else if (config.propertyFind) module = BDFDB.ModuleUtils.findByProperties(config.propertyFind, config.exported, true); + else if (config.prototypeFind) module = BDFDB.ModuleUtils.findByPrototypes(config.prototypeFind, config.exported, true); + else module = BDFDB.ModuleUtils.findByName(config.name, config.exported, true); + if (module) { + let exports = !config.exported && module.exports || module; + exports = config.path && BDFDB.ObjectUtils.get(exports, config.path) || exports; + exports && Internal.patchComponent(pluginData, Internal.isMemoOrForwardRef(exports) ? exports.default : exports, config); + } + else { + if (!PluginStores.chunkObserver[config.mappedType]) { + PluginStores.chunkObserver[config.mappedType] = {query: [], config}; + let filter; + if (config.stringFind) filter = m => m && Internal.hasModuleStrings(m, config.stringFind) && m; + else if (config.propertyFind) filter = m => [config.propertyFind].flat(10).filter(n => n).every(prop => { + const value = m[prop]; + return value !== undefined && !(typeof value == "string" && !value); + }) && m; + else if (config.prototypeFind) filter = m => m.prototype && [config.prototypeFind].flat(10).filter(n => n).every(prop => { + const value = m.prototype[prop]; + return value !== undefined && !(typeof value == "string" && !value); + }) && m; + else filter = m => m.displayName === config.name && m || m.render && m.render.displayName === config.name && m || m[config.name] && m[config.name].displayName === name && m[config.name]; + PluginStores.chunkObserver[config.mappedType].filter = filter; + } + PluginStores.chunkObserver[config.mappedType].query.push(pluginData); + } + }; + Internal.addQueuePatches = function (plugin) { + if (!InternalData.ModuleUtilsConfig.QueuedComponents) return; + plugin = plugin == BDFDB && Internal || plugin; + for (let type of InternalData.ModuleUtilsConfig.QueuedComponents) if (typeof plugin[`on${type}`] == "function") { + if (PluginStores.patchQueues[type].query.indexOf(plugin) == -1) { + PluginStores.patchQueues[type].query.push(plugin); + PluginStores.patchQueues[type].query.sort((x, y) => x.name < y.name ? -1 : x.name > y.name ? 1 : 0); + } + } + }; + Internal.triggerQueuePatch = function (type, e) { + if (e.returnvalue && BDFDB.ObjectUtils.is(PluginStores.patchQueues[type]) && BDFDB.ArrayUtils.is(PluginStores.patchQueues[type].query)) { + for (let plugin of PluginStores.patchQueues[type].query) if(typeof plugin[`on${type}`] == "function") plugin[`on${type}`](e); + } + }; + Internal.addContextChunkObservers = function (plugin) { + if (!InternalData.ModuleUtilsConfig.ContextMenuTypes) return; + plugin = plugin == BDFDB && Internal || plugin; + for (let type of InternalData.ModuleUtilsConfig.ContextMenuTypes) { + type = `${type}ContextMenu`; + if (typeof plugin[`on${InternalData.ModuleUtilsConfig.ContextMenuTypesMap[type] || type}`] == "function") { + for (let module of PluginStores.contextChunkObserver[type].modules) Internal.patchContextMenu(plugin, type, module); + if (PluginStores.contextChunkObserver[type].query.indexOf(plugin) == -1) { + PluginStores.contextChunkObserver[type].query.push(plugin); + PluginStores.contextChunkObserver[type].query.sort((x, y) => x.name < y.name ? -1 : x.name > y.name ? 1 : 0); + } + } + } + }; + Internal.patchContextMenu = function (plugin, type, module) { + if (!module || !module.default) return; + plugin = plugin == BDFDB && Internal || plugin; + const mappedType = InternalData.ModuleUtilsConfig.ContextMenuTypesMap[type] || type; + if (!InternalData.ModuleUtilsConfig.ContextMenuSubItemsMap[mappedType]) { + const call = (args, props, returnValue, name) => { + if (!returnValue || !returnValue.props || !returnValue.props.children || returnValue.props.children.__BDFDBPatchesCalled && returnValue.props.children.__BDFDBPatchesCalled[plugin.name]) return; + returnValue.props.children.__BDFDBPatchesCalled = Object.assign({}, returnValue.props.children.__BDFDBPatchesCalled, {[plugin.name]: true}); + return plugin[`on${mappedType}`]({ + arguments: args, + instance: {props: props}, + returnvalue: returnValue, + component: module, + methodname: "default", + type: name + }); + }; + BDFDB.PatchUtils.patch(plugin, module, "default", {after: e => { + if (typeof plugin[`on${mappedType}`] != "function") return; + else if (e.returnValue && e.returnValue.props.children !== undefined) { + if (e.returnValue.props.navId) { + e.returnValue.props.children = [e.returnValue.props.children].flat(10); + call(e.methodArguments, e.methodArguments[0], e.returnValue, module.default.displayName); + } + if (e.returnValue.props.children && e.returnValue.props.children.type && e.returnValue.props.children.type.displayName) { + const name = e.returnValue.props.children.type.displayName; + const originalReturn = e.returnValue.props.children.type(e.returnValue.props.children.props); + if (!originalReturn || !originalReturn.type) return; + let newType = (...args) => { + const returnValue = BDFDB.ReactUtils.createElement(originalReturn.type, originalReturn.props); + if (returnValue.props.children) call(args, args[0], returnValue, name); + else BDFDB.PatchUtils.patch(plugin, returnValue, "type", {after: e2 => { + if (e2.returnValue && typeof plugin[`on${type}`] == "function") call(e2.methodArguments, e2.methodArguments[0], e2.returnValue, name); + }}, {noCache: true}); + return returnValue; + }; + newType.displayName = name; + e.returnValue.props.children = BDFDB.ReactUtils.createElement(newType, e.returnValue.props.children.props); + } + } + else BDFDB.PatchUtils.patch(plugin, e.returnValue, "type", {after: e2 => { + if (e2.returnValue && typeof plugin[`on${mappedType}`] == "function") call(e2.methodArguments, e2.methodArguments[0], e2.returnValue, module.default.displayName); + }}, {noCache: true}); + }}, {name: type}); + } + else { + const getProps = (props, keys) => { + let newProps = Object.assign({}, BDFDB.ObjectUtils.is(props) ? props : typeof props == "string" ? {id: props} : {}); + for (const key of [keys].flat(10).filter(n => n)) { + const store = `${Internal.LibraryModules.StringUtils.upperCaseFirstChar(key)}Store`; + const getter = `get${Internal.LibraryModules.StringUtils.upperCaseFirstChar(key)}`; + const value = props && props[key] || Internal.LibraryModules[store] && typeof Internal.LibraryModules[store][getter] == "function" && Internal.LibraryModules[store][getter](props && props.id || props); + if (value) { + newProps = Object.assign(newProps, {[key]: value}); + break; + } + } + return newProps; + }; + BDFDB.PatchUtils.patch(plugin, module, "default", {after: e => { + if (typeof plugin[`on${mappedType}`] != "function") return; + e.returnValue = [e.returnValue].flat(10).filter(n => n); + return plugin[`on${mappedType}`]({ + arguments: e.methodArguments, + instance: {props: InternalData.ModuleUtilsConfig.ContextMenuSubItemsMap[mappedType].keys && getProps(e.methodArguments[0], InternalData.ModuleUtilsConfig.ContextMenuSubItemsMap[mappedType].keys) || e.methodArguments[0]}, + returnvalue: e.returnValue, + component: module, + methodname: "default", + type: type, + subType: module.__BDFDB_ContextMenu_Patch_Name + }); + }}, {name: type}); + } + }; + + BDFDB.ReactUtils.instanceKey = Object.keys(document.querySelector(BDFDB.dotCN.app) || {}).some(n => n.startsWith("__reactInternalInstance")) ? "_reactInternalFiber" : "_reactInternals"; + + BDFDB.PluginUtils.load(BDFDB); + Internal.settings = BDFDB.DataUtils.get(Internal); + changeLogs = BDFDB.DataUtils.load(BDFDB, "changeLogs"); + BDFDB.PluginUtils.checkChangeLog(BDFDB); + + (_ => { + const chunkName = "webpackChunkdiscord_app"; + const originalPush = window[chunkName].push; + const patches = {}; + const handlePush = chunk => { + for (const id in chunk[1]) { + const origModule = chunk[1][id]; + chunk[1][id] = (module, exports, require) => { + Reflect.apply(origModule, null, [module, exports, require]); + const removedTypes = []; + for (const type in PluginStores.chunkObserver) { + const foundModule = PluginStores.chunkObserver[type].filter(exports) || exports.default && PluginStores.chunkObserver[type].filter(exports.default); + if (foundModule) { + Internal.patchComponent(PluginStores.chunkObserver[type].query, PluginStores.chunkObserver[type].config.exported ? foundModule : exports, PluginStores.chunkObserver[type].config); + removedTypes.push(type); + break; + } + } + while (removedTypes.length) delete PluginStores.chunkObserver[removedTypes.pop()]; + let found = false, funcString = exports && exports.default && typeof exports.default == "function" && exports.default.toString(); + if (funcString && funcString.indexOf(".page") > -1 && funcString.indexOf(".section") > -1 && funcString.indexOf(".objectType") > -1) { + const returnValue = exports.default({}); + if (returnValue && returnValue.props && returnValue.props.object == BDFDB.DiscordConstants.AnalyticsObjects.CONTEXT_MENU) { + for (const type in PluginStores.contextChunkObserver) { + if (PluginStores.contextChunkObserver[type].filter(returnValue.props.children)) { + exports.__BDFDB_ContextMenuWrapper_Patch_Name = exports.__BDFDB_ContextMenu_Patch_Name; + found = true; + if (PluginStores.contextChunkObserver[type].modules.indexOf(exports) == -1) PluginStores.contextChunkObserver[type].modules.push(exports); + for (const plugin of PluginStores.contextChunkObserver[type].query) Internal.patchContextMenu(plugin, type, exports); + break; + } + } + } + } + if (!found) for (const type in PluginStores.contextChunkObserver) { + if (PluginStores.contextChunkObserver[type].filter(exports)) { + if (PluginStores.contextChunkObserver[type].modules.indexOf(exports) == -1) PluginStores.contextChunkObserver[type].modules.push(exports); + for (const plugin of PluginStores.contextChunkObserver[type].query) Internal.patchContextMenu(plugin, type, exports); + break; + } + } + }; + Object.assign(chunk[1][id], origModule, {toString: _ => origModule.toString()}); + patches[id] = [chunk, origModule]; + } + return Reflect.apply(originalPush, window[chunkName], [chunk]); + }; + + Object.defineProperty(window[chunkName], "push", { + configurable: true, + get: _ => handlePush, + set: newPush => { + originalPush = newPush; + Object.defineProperty(window[chunkName], "push", { + value: handlePush, + configurable: true, + writable: true + }); + } + }); + Internal.removeChunkObserver = _ => { + for (let id in patches) { + patches[id][0] = patches[id][1]; + patches[id] = null; + } + Object.defineProperty(window[chunkName], "push", { + configurable: true, + get: _ => (chunk => Reflect.apply(originalPush, window[chunkName], [chunk])) + }); + }; + })(); + + if (InternalData.ModuleUtilsConfig.ContextMenuTypes) for (let type of InternalData.ModuleUtilsConfig.ContextMenuTypes) { + type = `${type}ContextMenu`; + if (!PluginStores.contextChunkObserver[type]) { + const mappedType = InternalData.ModuleUtilsConfig.ContextMenuTypesMap[type] || type; + PluginStores.contextChunkObserver[type] = {query: [], modules: []}; + if (!InternalData.ModuleUtilsConfig.ContextMenuSubItemsMap[mappedType]) PluginStores.contextChunkObserver[type].filter = m => { + if (!m || !(m.default || m.type)) return; + const d = m.default || m.type; + if (d.displayName && (d.displayName.endsWith("ContextMenu") || d.displayName.endsWith("ContextMenuWrapper")) && `${InternalData.ModuleUtilsConfig.ContextMenuTypes.find(t => d.displayName.indexOf(t) > -1)}ContextMenu` == type) { + m.__BDFDB_ContextMenu_Patch_Name = type; + return true; + } + else if (m.__BDFDB_ContextMenuWrapper_Patch_Name && m.__BDFDB_ContextMenuWrapper_Patch_Name.endsWith("ContextMenu") && `${InternalData.ModuleUtilsConfig.ContextMenuTypes.find(t => m.__BDFDB_ContextMenuWrapper_Patch_Name.indexOf(t) > -1)}ContextMenu` == type) { + m.__BDFDB_ContextMenu_Patch_Name = type; + return true; + } + }; + else PluginStores.contextChunkObserver[type].filter = m => { + if (!m || !(m.default || m.type)) return; + const d = m.default || m.type; + if (d.displayName && InternalData.ModuleUtilsConfig.ContextMenuSubItemsMap[mappedType].items.indexOf(d.displayName) > -1) { + m.__BDFDB_ContextMenu_Patch_Name = d.displayName; + return true; + } + else { + const subType = InternalData.ModuleUtilsConfig.ContextMenuSubItemsMap[mappedType].items.find(item => InternalData.ModuleUtilsConfig.Finder[item] && InternalData.ModuleUtilsConfig.Finder[item].strings && Internal.hasModuleStrings(d, InternalData.ModuleUtilsConfig.Finder[item].strings)); + if (subType) { + m.__BDFDB_ContextMenu_Patch_Name = subType; + return true; + } + } + }; + PluginStores.contextChunkObserver[type].modules = BDFDB.ModuleUtils.find(PluginStores.contextChunkObserver[type].filter, {useExport: false, all: true}).map(m => m.exports).filter(n => n); + } + } + + Internal.patchPlugin(BDFDB); + Internal.addQueuePatches(BDFDB); + Internal.addContextChunkObservers(BDFDB); + + if (InternalData.ModuleUtilsConfig.QueuedComponents) for (let type of InternalData.ModuleUtilsConfig.QueuedComponents) if (!PluginStores.patchQueues[type]) PluginStores.patchQueues[type] = {query: [], modules: []}; + + let languageChangeTimeout; + if (Internal.LibraryModules.SettingsUtilsOld) BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryModules.SettingsUtilsOld, ["updateRemoteSettings", "updateLocalSettings"], {after: e => { + if (e.methodArguments[0] && e.methodArguments[0].locale) { + BDFDB.TimeUtils.clear(languageChangeTimeout); + languageChangeTimeout = BDFDB.TimeUtils.timeout(_ => { + for (let pluginName in PluginStores.loaded) if (PluginStores.loaded[pluginName].started) BDFDB.PluginUtils.translate(PluginStores.loaded[pluginName]); + }, 10000); + } + }}); + + Internal.onSettingsClosed = function () { + if (Internal.SettingsUpdated) { + delete Internal.SettingsUpdated; + Internal.forceUpdateAll(); + } + }; + + Internal.forceUpdateAll = function () { + BDFDB.MessageUtils.rerenderAll(); + BDFDB.PatchUtils.forceAllUpdates(BDFDB); + }; + + if (Internal.LibraryComponents.GuildComponents.BlobMask) { + let newBadges = ["lowerLeftBadge", "upperLeftBadge"]; + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryComponents.GuildComponents.BlobMask.prototype, "render", { + before: e => { + e.thisObject.props = Object.assign({}, Internal.LibraryComponents.GuildComponents.BlobMask.defaultProps, e.thisObject.props); + for (let type of newBadges) if (!e.thisObject.state[`${type}Mask`]) e.thisObject.state[`${type}Mask`] = new Internal.LibraryComponents.Animations.Controller({spring: 0}); + }, + after: e => { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnValue, {name: "TransitionGroup"}); + if (index > -1) { + children[index].props.children.push(!e.thisObject.props.lowerLeftBadge ? null : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.BadgeAnimationContainer, { + className: BDFDB.disCN.guildlowerleftbadge, + key: "lower-left-badge", + animatedStyle: e.thisObject.getLowerLeftBadgeStyles(), + children: e.thisObject.props.lowerLeftBadge + })); + children[index].props.children.push(!e.thisObject.props.upperLeftBadge ? null : BDFDB.ReactUtils.createElement(Internal.LibraryComponents.BadgeAnimationContainer, { + className: BDFDB.disCN.guildupperleftbadge, + key: "upper-left-badge", + animatedStyle: e.thisObject.getUpperLeftBadgeStyles(), + children: e.thisObject.props.upperLeftBadge + })); + } + [children, index] = BDFDB.ReactUtils.findParent(e.returnValue, {name: "mask"}); + if (index > -1) { + children[index].props.children.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Animations.animated.rect, { + x: -4, + y: -4, + width: e.thisObject.props.upperLeftBadgeWidth + 8, + height: 24, + rx: 12, + ry: 12, + transform: e.thisObject.getLeftBadgePositionInterpolation(e.thisObject.state.upperLeftBadgeMask, -1), + fill: "black" + })); + children[index].props.children.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Animations.animated.rect, { + x: -4, + y: 28, + width: e.thisObject.props.lowerLeftBadgeWidth + 8, + height: 24, + rx: 12, + ry: 12, + transform: e.thisObject.getLeftBadgePositionInterpolation(e.thisObject.state.lowerLeftBadgeMask), + fill: "black" + })); + } + } + }); + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryComponents.GuildComponents.BlobMask.prototype, "componentDidMount", { + after: e => { + for (let type of newBadges) e.thisObject.state[`${type}Mask`].update({ + spring: e.thisObject.props[type] != null ? 1 : 0, + immediate: true + }).start(); + } + }); + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryComponents.GuildComponents.BlobMask.prototype, "componentWillUnmount", { + after: e => { + for (let type of newBadges) if (e.thisObject.state[`${type}Mask`]) e.thisObject.state[`${type}Mask`].dispose(); + } + }); + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryComponents.GuildComponents.BlobMask.prototype, "componentDidUpdate", { + after: e => { + for (let type of newBadges) if (e.thisObject.props[type] != null && e.methodArguments[0][type] == null) { + e.thisObject.state[`${type}Mask`].update({ + spring: 1, + immediate: !document.hasFocus(), + config: {friction: 30, tension: 900, mass: 1} + }).start(); + } + else if (e.thisObject.props[type] == null && e.methodArguments[0][type] != null) { + e.thisObject.state[`${type}Mask`].update({ + spring: 0, + immediate: !document.hasFocus(), + config: {duration: 150, friction: 10, tension: 100, mass: 1} + }).start(); + } + } + }); + Internal.LibraryComponents.GuildComponents.BlobMask.prototype.getLeftBadgePositionInterpolation = function (e, t) { + return void 0 === t && (t = 1), e.springs.spring.to([0, 1], [20, 0]).to(function (e) { + return "translate(" + e * -1 + " " + e * t + ")"; + }); + }; + Internal.LibraryComponents.GuildComponents.BlobMask.prototype.getLowerLeftBadgeStyles = function () { + var e = this.state.lowerLeftBadgeMask.springs.spring; + return { + opacity: e.to([0, .5, 1], [0, 0, 1]), + transform: e.to(function (e) { + return "translate(" + -1 * (16 - 16 * e) + "px, " + (16 - 16 * e) + "px)"; + }) + }; + }; + Internal.LibraryComponents.GuildComponents.BlobMask.prototype.getUpperLeftBadgeStyles = function () { + var e = this.state.upperLeftBadgeMask.springs.spring; + return { + opacity: e.to([0, .5, 1], [0, 0, 1]), + transform: e.to(function (e) { + return "translate(" + -1 * (16 - 16 * e) + "px, " + -1 * (16 - 16 * e) + "px)"; + }) + }; + }; + let extraDefaultProps = {}; + for (let type of newBadges) extraDefaultProps[`${type}Width`] = 16; + Internal.setDefaultProps(Internal.LibraryComponents.GuildComponents.BlobMask, extraDefaultProps); + } + + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryModules.GuildStore, "getGuild", {after: e => { + if (e.returnValue && e.methodArguments[0] == InternalData.myGuildId) e.returnValue.banner = `https://mwittrien.github.io/BetterDiscordAddons/Library/_res/BDFDB.banner.png`; + }}); + + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryModules.UserStore, "getUser", {after: e => { + if (e.returnValue && e.methodArguments[0] == InternalData.myId) e.returnValue.banner = `https://mwittrien.github.io/BetterDiscordAddons/Library/_res/DevilBro.banner.png`; + }}); + + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryModules.IconUtils, "getGuildBannerURL", {instead: e => { + return e.methodArguments[0].id == InternalData.myGuildId ? e.methodArguments[0].banner : e.callOriginalMethod(); + }}); + + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryModules.IconUtils, "getUserBannerURL", {instead: e => { + return e.methodArguments[0].id == InternalData.myId ? e.methodArguments[0].banner : e.callOriginalMethod(); + }}); + + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryModules.BannerUtils, "getUserBannerURLForContext", {instead: e => { + return e.methodArguments[0].user && e.methodArguments[0].user.id == InternalData.myId ? e.methodArguments[0].user.banner : e.callOriginalMethod(); + }}); + + BDFDB.PatchUtils.patch(BDFDB, Internal.LibraryModules.EmojiStateUtils, "getEmojiUnavailableReason", {after: e => { + if (Internal.LibraryComponents.EmojiPickerButton.current && Internal.LibraryComponents.EmojiPickerButton.current.props && Internal.LibraryComponents.EmojiPickerButton.current.props.allowManagedEmojisUsage) return null; + }}); + + Internal.forceUpdateAll(); + + const pluginQueue = window.BDFDB_Global && BDFDB.ArrayUtils.is(window.BDFDB_Global.pluginQueue) ? window.BDFDB_Global.pluginQueue : []; + + if (BDFDB.UserUtils.me.id == InternalData.myId || BDFDB.UserUtils.me.id == "350635509275557888") { + BDFDB.DevUtils = {}; + BDFDB.DevUtils.generateClassId = Internal.generateClassId; + BDFDB.DevUtils.findByIndex = function (index) { + return BDFDB.DevUtils.req.c[index]; + }; + BDFDB.DevUtils.findPropAny = function (...strings) { + window.t = {"$filter":(prop => [...strings].flat(10).filter(n => typeof n == "string").every(string => prop.toLowerCase().indexOf(string.toLowerCase()) > -1))}; + for (let i in BDFDB.DevUtils.req.c) if (BDFDB.DevUtils.req.c.hasOwnProperty(i)) { + let m = BDFDB.DevUtils.req.c[i].exports; + if (m && typeof m == "object") for (let j in m) if (window.t.$filter(j)) window.t[j + "_" + i] = m; + if (m && typeof m == "object" && typeof m.default == "object") for (let j in m.default) if (window.t.$filter(j)) window.t[j + "_default_" + i] = m.default; + } + console.clear(); + console.log(window.t); + }; + BDFDB.DevUtils.findPropFunc = function (...strings) { + window.t = {"$filter":(prop => [...strings].flat(10).filter(n => typeof n == "string").every(string => prop.toLowerCase().indexOf(string.toLowerCase()) > -1))}; + for (let i in BDFDB.DevUtils.req.c) if (BDFDB.DevUtils.req.c.hasOwnProperty(i)) { + let m = BDFDB.DevUtils.req.c[i].exports; + if (m && typeof m == "object") for (let j in m) if (window.t.$filter(j) && typeof m[j] != "string") window.t[j + "_" + i] = m; + if (m && typeof m == "object" && typeof m.default == "object") for (let j in m.default) if (window.t.$filter(j) && typeof m.default[j] != "string") window.t[j + "_default_" + i] = m.default; + } + console.clear(); + console.log(window.t); + }; + BDFDB.DevUtils.findPropStringLib = function (...strings) { + window.t = {"$filter":(prop => [...strings].flat(10).filter(n => typeof n == "string").every(string => prop.toLowerCase().indexOf(string.toLowerCase()) > -1))}; + for (let i in BDFDB.DevUtils.req.c) if (BDFDB.DevUtils.req.c.hasOwnProperty(i)) { + let m = BDFDB.DevUtils.req.c[i].exports; + if (m && typeof m == "object") for (let j in m) if (window.t.$filter(j) && typeof m[j] == "string" && /^[A-z0-9]+\-[A-z0-9_-]{6}$/.test(m[j])) window.t[j + "_" + i] = m; + if (m && typeof m == "object" && typeof m.default == "object") for (let j in m.default) if (window.t.$filter(j) && typeof m.default[j] == "string" && /^[A-z0-9]+\-[A-z0-9_-]{6}$/.test(m.default[j])) window.t[j + "_default_" + i] = m.default; + } + console.clear(); + console.log(window.t); + }; + BDFDB.DevUtils.findNameAny = function (...strings) { + window.t = {"$filter":(m => [...strings].flat(10).filter(n => typeof n == "string").some(string => typeof m.displayName == "string" && m.displayName.toLowerCase().indexOf(string.toLowerCase()) > -1 || m.name == "string" && m.name.toLowerCase().indexOf(string.toLowerCase()) > -1))}; + for (let i in BDFDB.DevUtils.req.c) if (BDFDB.DevUtils.req.c.hasOwnProperty(i)) { + let m = BDFDB.DevUtils.req.c[i].exports; + if (m && (typeof m == "object" || typeof m == "function") && window.t.$filter(m)) window.t[(m.displayName || m.name) + "_" + i] = m; + if (m && (typeof m == "object" || typeof m == "function") && m.default && (typeof m.default == "object" || typeof m.default == "function") && window.t.$filter(m.default)) window.t[(m.default.displayName || m.default.name) + "_" + i] = m.default; + } + console.clear(); + console.log(window.t); + }; + BDFDB.DevUtils.findCodeAny = function (...strings) { + window.t = {"$filter":(m => Internal.hasModuleStrings(m, strings, true))}; + for (let i in BDFDB.DevUtils.req.c) if (BDFDB.DevUtils.req.c.hasOwnProperty(i)) { + let m = BDFDB.DevUtils.req.c[i].exports; + if (m && typeof m == "function" && window.t.$filter(m)) window.t["module_" + i] = {string: m.toString(), func: m}; + if (m && m.__esModule) { + for (let j in m) if (m[j] && typeof m[j] == "function" && window.t.$filter(m[j])) window.t[j + "_module_" + i] = {string: m[j].toString(), func: m[j], module: m}; + if (m.default && (typeof m.default == "object" || typeof m.default == "function")) for (let j in m.default) if (m.default[j] && typeof m.default[j] == "function" && window.t.$filter(m.default[j])) window.t[j + "_module_" + i + "_default"] = {string: m.default[j].toString(), func: m.default[j], module: m}; + } + } + for (let i in BDFDB.DevUtils.req.m) if (typeof BDFDB.DevUtils.req.m[i] == "function" && window.t.$filter(BDFDB.DevUtils.req.m[i])) window.t["function_" + i] = {string: BDFDB.DevUtils.req.m[i].toString(), func: BDFDB.DevUtils.req.m[i]}; + console.clear(); + console.log(window.t); + }; + BDFDB.DevUtils.getAllModules = function () { + window.t = {}; + for (let i in BDFDB.DevUtils.req.c) if (BDFDB.DevUtils.req.c.hasOwnProperty(i)) { + let m = BDFDB.DevUtils.req.c[i].exports; + if (m && typeof m == "object") window.t[i] = m; + } + console.clear(); + console.log(window.t); + }; + BDFDB.DevUtils.getAllStringLibs = function () { + window.t = []; + for (let i in BDFDB.DevUtils.req.c) if (BDFDB.DevUtils.req.c.hasOwnProperty(i)) { + let m = BDFDB.DevUtils.req.c[i].exports; + if (m && typeof m == "object" && !BDFDB.ArrayUtils.is(m) && Object.keys(m).length) { + var string = true, stringlib = false; + for (let j in m) { + if (typeof m[j] != "string") string = false; + if (typeof m[j] == "string" && /^[A-z0-9]+\-[A-z0-9_-]{6}$/.test(m[j])) stringlib = true; + } + if (string && stringlib) window.t.push(m); + } + if (m && typeof m == "object" && m.default && typeof m.default == "object" && !BDFDB.ArrayUtils.is(m.default) && Object.keys(m.default).length) { + var string = true, stringlib = false; + for (let j in m.default) { + if (typeof m.default[j] != "string") string = false; + if (typeof m.default[j] == "string" && /^[A-z0-9]+\-[A-z0-9_-]{6}$/.test(m.default[j])) stringlib = true; + } + if (string && stringlib) window.t.push(m.default); + } + } + console.clear(); + console.log(window.t); + }; + BDFDB.DevUtils.listen = function (strings) { + strings = BDFDB.ArrayUtils.is(strings) ? strings : Array.from(arguments); + BDFDB.DevUtils.listenStop(); + BDFDB.DevUtils.listen.p = BDFDB.PatchUtils.patch("WebpackSearch", BDFDB.ModuleUtils.findByProperties(strings), strings[0], {after: e => { + console.log(e); + }}); + }; + BDFDB.DevUtils.listenStop = function () { + if (typeof BDFDB.DevUtils.listen.p == "function") BDFDB.DevUtils.listen.p(); + }; + BDFDB.DevUtils.generateLanguageStrings = function (strings, config = {}) { + const language = config.language || "en"; + const languages = BDFDB.ArrayUtils.removeCopies(BDFDB.ArrayUtils.is(config.languages) ? config.languages : ["en"].concat((Internal.LibraryModules.LanguageStore.languages || Internal.LibraryModules.LanguageStore._languages).filter(n => n.enabled).map(n => { + if (BDFDB.LanguageUtils.languages[n.code]) return n.code; + else { + const code = n.code.split("-")[0]; + if (BDFDB.LanguageUtils.languages[code]) return code; + } + })).filter(n => n && !n.startsWith("en-") && !n.startsWith("$") && n != language)).sort(); + let translations = {}; + strings = BDFDB.ObjectUtils.sort(strings); + const stringKeys = Object.keys(strings); + translations[language] = BDFDB.ObjectUtils.toArray(strings); + let text = Object.keys(translations[language]).map(k => translations[language][k]).join("\n\n"); + + let fails = 0, next = lang => { + if (!lang) { + let formatTranslation = (l, s, i) => { + l = l == "en" ? "default" : l; + return config.cached && config.cached[l] && config.cached[l][stringKeys[i]] || (translations[language][i][0] == translations[language][i][0].toUpperCase() ? Internal.LibraryModules.StringUtils.upperCaseFirstChar(s) : s); + }; + let format = config.asObject ? ((l, isNotFirst) => { + return `${isNotFirst ? "," : ""}\n\t\t"${l == "en" ? "default" : l}": {${translations[l].map((s, i) => `\n\t\t\t"${stringKeys[i]}": "${formatTranslation(l, s, i)}"`).join(",")}\n\t\t}`; + }) : ((l, isNotFirst) => { + return `\n\t\t\t\t\t${l == "en" ? "default" : `case "${l}"`}:${l.length > 2 ? "\t" : "\t\t"}// ${BDFDB.LanguageUtils.languages[l].name}\n\t\t\t\t\t\treturn {${translations[l].map((s, i) => `\n\t\t\t\t\t\t\t${stringKeys[i]}:${"\t".repeat(10 - ((stringKeys[i].length + 2) / 4))}"${formatTranslation(l, s, i)}"`).join(",")}\n\t\t\t\t\t\t};`; + }); + let result = Object.keys(translations).filter(n => n != "en").sort().map((l, i) => format(l, i)).join(""); + if (translations.en) result += format("en", result ? 1 : 0); + BDFDB.NotificationUtils.toast("Translation copied to clipboard", { + type: "success" + }); + Internal.LibraryRequires.electron.clipboard.write({text: result}); + } + else { + const callback = translation => { + BDFDB.LogUtils.log(lang); + if (!translation) { + console.warn("No Translation"); + fails++; + if (fails > 10) console.error("Skipped Language"); + else languages.unshift(lang); + } + else { + fails = 0; + translations[lang] = translation.split("\n\n"); + } + next(languages.shift()); + }; + Internal.LibraryRequires.request(`https://translate.googleapis.com/translate_a/single?client=gtx&sl=${language}&tl=${lang}&dt=t&dj=1&source=input&q=${encodeURIComponent(text)}`, (error, response, result) => { + if (!error && result && response.statusCode == 200) { + try {callback(JSON.parse(result).sentences.map(n => n && n.trans).filter(n => n).join(""));} + catch (err) {callback("");} + } + else { + if (response.statusCode == 429) { + BDFDB.NotificationUtils.toast("Too many Requests", { + type: "danger" + }); + } + else { + BDFDB.NotificationUtils.toast("Failed to translate Text", { + type: "danger" + }); + callback(""); + } + } + }); + } + }; + if (stringKeys.length) next(languages.shift()); + }; + BDFDB.DevUtils.req = Internal.getWebModuleReq(); + + window.BDFDB = BDFDB; + } + + window.BDFDB = BDFDB; + + if (libraryCSS) BDFDB.DOMUtils.appendLocalStyle("BDFDB", libraryCSS.replace(/[\n\t\r]/g, "").replace(/\[REPLACE_CLASS_([A-z0-9_]+?)\]/g, (a, b) => BDFDB.dotCN[b])); + + BDFDB.LogUtils.log("Finished loading Library"); + + window.BDFDB_Global = Object.assign({ + started: true, + loaded: true, + PluginUtils: { + buildPlugin: BDFDB.PluginUtils.buildPlugin, + cleanUp: BDFDB.PluginUtils.cleanUp + } + }, config); + + while (PluginStores.delayed.loads.length) PluginStores.delayed.loads.shift().load(); + while (PluginStores.delayed.starts.length) PluginStores.delayed.starts.shift().start(); + while (pluginQueue.length) { + let pluginName = pluginQueue.shift(); + if (pluginName) BDFDB.TimeUtils.timeout(_ => BDFDB.BDUtils.reloadPlugin(pluginName)); + } + }; + + const alreadyLoadedComponents = []; + if (InternalData.ForceLoadedComponents) { + let promises = []; + for (let name in InternalData.ForceLoadedComponents) { + let parentModule; + if (InternalData.ForceLoadedComponents[name].name) { + if (InternalData.ForceLoadedComponents[name].protos) parentModule = BDFDB.ModuleUtils.find(m => m && m.displayName == InternalData.ForceLoadedComponents[name].name && m.prototype && InternalData.ForceLoadedComponents[name].protos.every(proto => m.prototype[proto]) && m, {useExport: false}); + else parentModule = BDFDB.ModuleUtils.findByName(InternalData.ForceLoadedComponents[name].name, false, true); + } + else if (InternalData.ForceLoadedComponents[name].props) parentModule = BDFDB.ModuleUtils.findByProperties(InternalData.ForceLoadedComponents[name].props, false, true); + if (parentModule && parentModule.exports && alreadyLoadedComponents.indexOf(parentModule.id) > -1) { + alreadyLoadedComponents.push(parentModule.id); + promises.push(Internal.lazyLoadModuleImports(parentModule.exports)); + } + } + Promise.all(promises).then(loadComponents); + } + else loadComponents(); + }; + requestLibraryHashes(true); + + return class BDFDB_Frame { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return config.info.description;} + + load () { + this.loaded = true; + libraryInstance = this; + Object.assign(this, config.info, BDFDB.ObjectUtils.exclude(config, "info")); + if (!BDFDB.BDUtils.isPluginEnabled(config.info.name)) BDFDB.BDUtils.enablePlugin(config.info.name); + } + start () { + if (!this.loaded) this.load(); + } + stop () { + if (!BDFDB.BDUtils.isPluginEnabled(config.info.name)) BDFDB.BDUtils.enablePlugin(config.info.name); + } + + getSettingsPanel (collapseStates = {}) { + let settingsPanel; + let getString = (type, key, property) => { + return BDFDB.LanguageUtils.LibraryStringsCheck[`settings_${key}_${property}`] ? BDFDB.LanguageUtils.LibraryStringsFormat(`settings_${key}_${property}`, BDFDB.BDUtils.getSettingsProperty("name", BDFDB.BDUtils.settingsIds[key]) || Internal.LibraryModules.StringUtils.upperCaseFirstChar(key.replace(/([A-Z])/g, " $1"))) : Internal.defaults[type][key][property]; + }; + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(BDFDB, { + collapseStates: collapseStates, + children: _ => { + let settingsItems = []; + + for (let key in Internal.settings.choices) settingsItems.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsSaveItem, { + type: "Select", + plugin: Internal, + keys: ["choices", key], + label: getString("choices", key, "description"), + note: getString("choices", key, "note"), + basis: "50%", + value: Internal.settings.choices[key], + options: Object.keys(LibraryConstants[Internal.defaults.choices[key].items] || {}).map(p => ({ + value: p, + label: BDFDB.LanguageUtils.LibraryStrings[p] || p + })), + searchable: true + })); + for (let key in Internal.settings.general) { + let nativeSetting = BDFDB.BDUtils.settingsIds[key] && BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds[key]); + let disabled = typeof Internal.defaults.general[key].isDisabled == "function" && Internal.defaults.general[key].isDisabled({ + value: Internal.settings.general[key], + nativeValue: nativeSetting + }); + let hidden = typeof Internal.defaults.general[key].isHidden == "function" && Internal.defaults.general[key].isHidden({ + value: Internal.settings.general[key], + nativeValue: nativeSetting + }); + if (!hidden) settingsItems.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsSaveItem, { + type: "Switch", + plugin: Internal, + disabled: disabled, + keys: ["general", key], + label: getString("general", key, "description"), + note: (typeof Internal.defaults.general[key].hasNote == "function" ? Internal.defaults.general[key].hasNote({ + value: Internal.settings.general[key], + nativeValue: nativeSetting, + disabled: disabled + }) : Internal.defaults.general[key].hasNote) && getString("general", key, "note"), + value: (typeof Internal.defaults.general[key].getValue == "function" ? Internal.defaults.general[key].getValue({ + value: Internal.settings.general[key], + nativeValue: nativeSetting, + disabled: disabled + }) : true) && (Internal.settings.general[key] || nativeSetting), + onChange: typeof Internal.defaults.general[key].onChange == "function" ? Internal.defaults.general[key].onChange : (_ => {}) + })); + } + settingsItems.push(BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SettingsItem, { + type: "Button", + label: BDFDB.LanguageUtils.LibraryStrings.update_check_info, + dividerTop: true, + basis: "20%", + children: BDFDB.LanguageUtils.LibraryStrings.check_for_updates, + labelChildren: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.Clickable, { + children: BDFDB.ReactUtils.createElement(Internal.LibraryComponents.SvgIcon, { + name: Internal.LibraryComponents.SvgIcon.Names.QUESTIONMARK, + width: 20, + height: 20, + onClick: _ => BDFDB.ModalUtils.open(Internal, { + header: "Plugins", + subHeader: "", + contentClassName: BDFDB.disCN.marginbottom20, + text: BDFDB.ObjectUtils.toArray(Object.assign({}, window.PluginUpdates && window.PluginUpdates.plugins, PluginStores.updateData.plugins)).map(p => p.name).filter(n => n).sort().join(", ") + }) + }) + }), + onClick: _ => { + let toast = BDFDB.NotificationUtils.toast(`${BDFDB.LanguageUtils.LanguageStrings.CHECKING_FOR_UPDATES} - ${BDFDB.LanguageUtils.LibraryStrings.please_wait}`, { + type: "info", + timeout: 0, + ellipsis: true + }); + BDFDB.PluginUtils.checkAllUpdates().then(outdated => { + toast.close(); + if (outdated > 0) BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("update_check_complete_outdated", outdated), { + type: "danger" + }); + else BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStrings.update_check_complete, { + type: "success" + }); + }); + } + })); + + return settingsItems; + } + }); + } + } +})(); diff --git a/oldconfig/BetterDiscord/plugins/0BDFDB.raw.css b/oldconfig/BetterDiscord/plugins/0BDFDB.raw.css new file mode 100644 index 0000000..96fb638 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/0BDFDB.raw.css @@ -0,0 +1,1645 @@ +@import url(https://mwittrien.github.io/BetterDiscordAddons/Themes/_res/SupporterBadge.css); + +:root { + --bdfdb-blurple: var(--brand-experiment, hsl(235, calc(var(--saturation-factor, 1) * 85.6%), 64.7%)); + --bdfdb-green: hsl(139, calc(var(--saturation-factor, 1) * 47.3%), 43.9%); + --bdfdb-yellow: hsl(38, calc(var(--saturation-factor, 1) * 95.7%), 54.1%); + --bdfdb-red: hsl(359, calc(var(--saturation-factor, 1) * 82.6%), 59.4%); +} + +img:not([src]), img[src=""], img[src="null"] { + opacity: 0; +} + +[REPLACE_CLASS_appmount] > [REPLACE_CLASS_itemlayercontainer] { + position: fixed; + z-index: 1001; +} + +[REPLACE_CLASS_titlebarmac] { + z-index: 1000001; +} + +[REPLACE_CLASS_itemlayercontainerzindexdisabled] { + position: absolute !important; + z-index: unset !important; +} +[REPLACE_CLASS_itemlayercontainerzindexdisabled] > * { + z-index: 1002; +} +[REPLACE_CLASS_itemlayer] ~ [REPLACE_CLASS_itemlayer] [REPLACE_CLASS_menu] { + z-index: 1001; +} +[REPLACE_CLASS_menu] [REPLACE_CLASS_itemlayer] { + z-index: 1002; +} + +[REPLACE_CLASS_loadingiconwrapper] { + position: absolute; + bottom: 0; + right: 0; + z-index: 1000; + animation: loadingwrapper-fade 3s infinite ease; +} +[REPLACE_CLASS_loadingiconwrapper] [REPLACE_CLASS_loadingicon] { + margin: 0 5px; +} +@keyframes loadingwrapper-fade { + from {opacity: 0.1;} + 50% {opacity: 0.9;} + to {opacity: 0.1;} +} + +[REPLACE_CLASS_settingspanellistwrapper] { + margin-bottom: 8px; +} +[REPLACE_CLASS_settingspanellistwrapper][REPLACE_CLASS_settingspanellistwrappermini] { + margin-bottom: 4px; +} +[REPLACE_CLASS_settingspanellist] { + padding-left: 15px; +} +[REPLACE_CLASS_settingspanellistwrapper][REPLACE_CLASS_settingspanellistwrappermini] [REPLACE_CLASS_settingspanellist] { + padding-left: 10px; +} + +[REPLACE_CLASS_settingsrowcontainer][REPLACE_CLASS_marginreset] { + margin-bottom: 0; +} +[REPLACE_CLASS_settingsrowcontainer][REPLACE_CLASS_marginbottom4] { + margin-bottom: 4px; +} +[REPLACE_CLASS_settingsrowcontainer][REPLACE_CLASS_marginbottom8] { + margin-bottom: 8px; +} +[REPLACE_CLASS_settingsrowcontainer][REPLACE_CLASS_marginbottom20] { + margin-bottom: 20px; +} +[REPLACE_CLASS_settingsrowcontainer][REPLACE_CLASS_marginbottom40] { + margin-bottom: 40px; +} +[REPLACE_CLASS_settingsrowcontainer][REPLACE_CLASS_marginbottom60] { + margin-bottom: 60px; +} +[REPLACE_CLASS_flexdirectionrow] > [REPLACE_CLASS_settingsrowcontainer] + [REPLACE_CLASS_settingsrowcontainer] { + margin-left: 8px; +} +[REPLACE_CLASS_settingsrowcontainer] [REPLACE_CLASS_settingsrowlabel] { + align-items: center; +} +[REPLACE_CLASS_settingsrowcontainer] [REPLACE_CLASS_settingsrowcontrol] { + margin-left: 8px; +} +[REPLACE_CLASS_settingsrowcontainer] [REPLACE_CLASS_settingsrowtitlemini] { + line-height: 18px; + font-size: 12px; + font-weight: 400; +} + +[REPLACE_CLASS_switch][REPLACE_CLASS_switchmini] { + width: 26px; + height: 16px; +} +[REPLACE_CLASS_switch][REPLACE_CLASS_switchmini] [REPLACE_CLASS_switchslider] { + width: 16px; + height: 14px; + margin: 1px; +} + +[REPLACE_CLASS_marginleft4] { + margin-left: 4px; +} +[REPLACE_CLASS_marginleft8] { + margin-left: 8px; +} + +[REPLACE_CLASS_collapsecontainer] { + margin-bottom: 20px; +} +[REPLACE_CLASS_collapsecontainermini] { + margin-bottom: 8px; +} +[REPLACE_CLASS_collapsecontainerheader] { + margin-bottom: 4px; +} +[REPLACE_CLASS_collapsecontainercollapsed] [REPLACE_CLASS_collapsecontainertitle] { + margin-bottom: 0; +} +[REPLACE_CLASS_collapsecontainertitle] { + display: flex; + justify-content: space-between; + align-items: center; + cursor: pointer; + order: 1; +} +[REPLACE_CLASS_collapsecontainertitle]:hover { + color: var(--text-normal); +} +[REPLACE_CLASS_collapsecontainertitle]::before { + content: ""; + flex: 1 1 auto; + background-color: currentColor; + height: 2px; + margin: 0 10px 0 15px; + opacity: 0.2; + order: 2; +} +[REPLACE_CLASS_collapsecontainertitle]::after { + content: ""; + -webkit-mask: url('data:image/svg+xml; utf8, ') center/cover no-repeat; + background-color: currentColor; + width: 20px; + height: 20px; + order: 3; + transition: transform .3s ease; + transform: rotate(0); +} +[REPLACE_CLASS_collapsecontainercollapsed] [REPLACE_CLASS_collapsecontainertitle]::after { + transform: rotate(90deg) +} +[REPLACE_CLASS_collapsecontainerinner] { + padding-left: 15px; +} + +[REPLACE_CLASS_settingsguild] { + flex: 0 0 auto; + border-radius: 50%; + border: 3px solid #43b581; + box-sizing: border-box; + cursor: pointer; + margin: 3px; + overflow: hidden; +} +[REPLACE_CLASS_settingsguilddisabled] { + border-color: #747f8d; + filter: grayscale(100%) brightness(50%); +} + +[REPLACE_CLASS_guildslabel] { + color: var(--text-muted); + text-align: center; + text-transform: uppercase; + font-size: 9px; + font-weight: 500; + line-height: 1.3; + width: 70px; + word-wrap: normal; + white-space: nowrap; +} +[REPLACE_CLASS_guildslabel]:hover { + color: var(--header-secondary); +} +[REPLACE_CLASS_guildslabel]:active { + color: var(--header-primary); +} + +[REPLACE_CLASS_searchbarwrapper] { + padding: 10px; +} +[REPLACE_CLASS_popoutwrapper] [REPLACE_CLASS_searchbarwrapper] { + padding: 0 0 5px 0; + border-bottom: 1px solid var(--background-modifier-accent); +} + +[REPLACE_CLASS_pagination] { + display: flex; + justify-content: center; + align-items: center; + width: 100%; +} +[REPLACE_CLASS_paginationtop] { + margin-bottom: 10px; +} +[REPLACE_CLASS_paginationbottom] { + margin-top: 10px; +} +[REPLACE_CLASS_pagination] [REPLACE_CLASS_paginationcontainer] { + width: unset; + margin: 0; +} +[REPLACE_CLASS_paginationmini][REPLACE_CLASS_paginationtop] { + margin-bottom: 5px; +} +[REPLACE_CLASS_paginationmini][REPLACE_CLASS_paginationbottom] { + margin-top: 5px; +} +[REPLACE_CLASS_paginationmini] [REPLACE_CLASS_paginationbutton], +[REPLACE_CLASS_paginationmini] [REPLACE_CLASS_paginationgap] { + font-size: 14px; + margin: 4px 2px; +} +[REPLACE_CLASS_paginationmini] [REPLACE_CLASS_paginationgap] { + width: 20px; +} +[REPLACE_CLASS_paginationmini] [REPLACE_CLASS_inputwrapper] { + min-width: 54px; +} + +[REPLACE_CLASS_paginationlist] { + height: 100%; +} +[REPLACE_CLASS_paginationlistalphabet] { + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + line-height: 20px; + margin-bottom: 10px; + color: var(--text-normal); +} +[REPLACE_CLASS_paginationlistalphabetchar] { + min-width: 12px; + text-align: center; + margin: 0 4px; +} +[REPLACE_CLASS_paginationlistalphabetchar]:not([REPLACE_CLASS_paginationlistalphabetchardisabled]):hover { + color: var(--header-primary); +} +[REPLACE_CLASS_paginationlistalphabetchar][REPLACE_CLASS_paginationlistalphabetchardisabled] { + color: var(--text-muted); +} +[REPLACE_CLASS_paginationlistmini] [REPLACE_CLASS_paginationlistalphabet] { + font-size: 14px; + line-height: 18px; + margin-bottom: 5px; +} +[REPLACE_CLASS_paginationlistmini] [REPLACE_CLASS_paginationlistalphabetchar] { + min-width: 10px; + margin: 0 3px; +} + +[REPLACE_CLASS_discoverycards] { + display: grid; + grid-gap: 16px; + grid-template-columns: repeat(auto-fill, minmax(248px, 1fr)); + padding: 10px 0; +} +[REPLACE_CLASS_discoverycard] { + display: flex; + flex-direction: column; + position: relative; + background-color: var(--activity-card-background); + border: 2px solid var(--activity-card-background); + border-radius: 8px; + box-shadow: var(--elevation-medium); + height: 370px; + width: 100%; + overflow: hidden; + transition: box-shadow .2s ease-out,transform .2s ease-out,background .2s ease-out,border .2s ease-out,opacity .2s ease-in; +} +[REPLACE_CLASS_themedark] [REPLACE_CLASS_discoverycard] { + background-color: var(--background-secondary-alt); + border-color: var(--background-secondary-alt); +} +[REPLACE_CLASS_discoverycard]:focus, +[REPLACE_CLASS_discoverycard]:hover { + background-color: var(--background-tertiary); + border-color: var(--background-tertiary); + box-shadow: var(--elevation-high); + transform: translateY(-1px); +} +[REPLACE_CLASS_discoverycardheader] { + display: block; + flex: 0 0 auto; + position: relative; + height: 143px; + overflow: visible; + margin-bottom: 28px; +} +[REPLACE_CLASS_discoverycardcoverwrapper] { + display: block; + position: absolute; + top: 0; + left: 0; + background: url(https://mwittrien.github.io/_res/imgs/cardplaceholder.svg) center/cover no-repeat; + transform: scale(1); + transition: transform .2s ease-out; +} +[REPLACE_CLASS_discoverycard]:focus [REPLACE_CLASS_discoverycardcoverwrapper], +[REPLACE_CLASS_discoverycard]:hover [REPLACE_CLASS_discoverycardcoverwrapper] { + transform: scale(1.01) translateZ(0); +} +[REPLACE_CLASS_discoverycardcoverwrapper], +[REPLACE_CLASS_discoverycardcover] { + width: 100%; + height: 100%; +} +[REPLACE_CLASS_discoverycardcover] { + object-fit: cover; + cursor: pointer; +} +[REPLACE_CLASS_discoverycardcoverbadge] { + position: absolute; + top: 6px; + right: 8px; +} +[REPLACE_CLASS_discoverycardiconwrapper] { + position: absolute; + bottom: -21px; + left: 12px; + background-color: var(--activity-card-background); + border-radius: 10px; + padding: 6px; + transition: box-shadow .2s ease-out, transform .2s ease-out, background .2s ease-out; +} +[REPLACE_CLASS_themedark] [REPLACE_CLASS_discoverycardiconwrapper] { + background-color: var(--background-secondary-alt); +} +[REPLACE_CLASS_discoverycard]:focus [REPLACE_CLASS_discoverycardiconwrapper], +[REPLACE_CLASS_discoverycard]:hover [REPLACE_CLASS_discoverycardiconwrapper] { + background-color: var(--background-tertiary); +} +[REPLACE_CLASS_discoverycardicon] { + color: var(--header-primary); + border-radius: 10px; + width: 32px; + height: 32px; +} +[REPLACE_CLASS_discoverycardiconloading] { + visibility: hidden; +} +[REPLACE_CLASS_discoverycardinfo] { + display: flex; + flex: 1 1 auto; + position: relative; + flex-direction: column; + align-content: stretch; + padding: 0 16px 16px; + overflow: hidden; +} +[REPLACE_CLASS_discoverycardtitle] { + display: flex; + align-items: center; + color: var(--header-primary); + width: 100%; + font-weight: 600; + font-size: 16px; + line-height: 20px; + flex: 0 0 auto; +} +[REPLACE_CLASS_discoverycardname] { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + flex: 1 1 auto; +} +[REPLACE_CLASS_discoverycardtitlebutton] { + display: flex; + justify-content: center; + align-items: center; + margin-left: 6px; +} +[REPLACE_CLASS_discoverycard] [REPLACE_CLASS_favbuttoncontainer] { + width: 20px; + height: 20px; + flex: 0 0 auto; + margin-left: 3px; +} +[REPLACE_CLASS_discoverycard] [REPLACE_CLASS_favbuttoncontainer] [REPLACE_CLASS_giffavoritesize] { + width: 20px; + height: 20px; +} +[REPLACE_CLASS_discoverycardauthor] { + color: var(--header-secondary); + margin: 3px 0 6px; + font-size: 14px; + flex: 0 0 auto; +} +[REPLACE_CLASS_discoverycarddescription] { + color: var(--header-secondary); + margin: 4px 0 12px; + font-size: 14px; + line-height: 18px; +} +[REPLACE_CLASS_discoverycardfooter] { + flex: 0 0 auto; +} +[REPLACE_CLASS_discoverycardtags] { + display: flex; + flex-wrap: wrap; + align-items: center; + margin-bottom: 4px; +} +[REPLACE_CLASS_discoverycardtag] { + margin-right: 6px; + margin-bottom: 6px; + font-weight: 500; +} +[REPLACE_CLASS_discoverycardcontrols] { + display: flex; + justify-content: space-between; + align-items: flex-end; + align-items: center; + flex: 0 0 auto; +} +[REPLACE_CLASS_discoverycardbutton] { + display: flex; + justify-content: center; + align-items: center; + border-radius: 3px; + color: var(--header-primary); + font-size: 14px; + font-weight: 500; + padding: 6px 8px; +} +[REPLACE_CLASS_discoverycardstats] { + display: flex; + justify-content: center; + align-items: center; + color: var(--header-secondary); + font-size: 14px; +} +[REPLACE_CLASS_discoverycardstat] { + display: flex; + justify-content: center; + align-items: center; + margin-right: 8px; +} +[REPLACE_CLASS_discoverycardstaticon] { + margin-right: 4px; +} + +[REPLACE_CLASS_overflowellipsis] { + overflow: hidden; + text-overflow: ellipsis; +} + + +[REPLACE_CLASS_userpopoutheaderbottag] { + margin-top: 4px !important; +} +[REPLACE_CLASS_userinfodate] { + color: var(--header-secondary); + margin-top: 8px; + user-select: text; +} +[REPLACE_CLASS_userprofilenametag] + [REPLACE_CLASS_userinfodate], +[REPLACE_CLASS_userinfodate] + [REPLACE_CLASS_userinfodate] { + margin-top: 0; +} +[REPLACE_CLASS_userinfodate] + *:not([REPLACE_CLASS_userinfodate]) { + margin-top: 6px; +} +[REPLACE_CLASS_userprofile] [REPLACE_CLASS_userinfodate] { + margin-left: 16px; +} +[REPLACE_CLASS_userprofile] [REPLACE_CLASS_userinfodate]:last-child { + margin-bottom: 16px; +} + +[REPLACE_CLASS_avatardisabled] { + filter: grayscale(100%) brightness(50%); +} + +[REPLACE_CLASS_messagebottag] { + top: .15rem; +} +[REPLACE_CLASS_messageusername] ~ [REPLACE_CLASS_messagebottagcompact] { + margin-right: 0; + margin-left: .25rem; +} + +[REPLACE_CLASS_messageavatar][REPLACE_CLASS_bdfdbbadgeavatar] > :not([REPLACE_CLASS_bdfdbbadge]), +[REPLACE_CLASS_messageavatar][REPLACE_CLASS_bdfdbbadgeavatar] [REPLACE_CLASS_avatarwrapper] { + width: inherit !important; + height: inherit !important; +} +[REPLACE_CLASS_messageavatar][REPLACE_CLASS_bdfdbbadgeavatar] [REPLACE_CLASS_messageavatar] { + position: static !important; + margin: unset !important; +} + +[REPLACE_CLASS_favbuttoncontainer] { + display: flex; + position: relative; + cursor: pointer; + width: 24px; + height: 24px; +} + +[REPLACE_CLASS_menuhint] { + width: 42px; + max-width: 42px; + margin-left: 8px; +} + +[REPLACE_CLASS_cursordefault] { + cursor: default !important; +} +[REPLACE_CLASS_cursorpointer] { + cursor: pointer !important; +} + +[REPLACE_CLASS_slidergrabber]:active [REPLACE_CLASS_sliderbubble], +[REPLACE_CLASS_slidergrabber]:hover [REPLACE_CLASS_sliderbubble] { + visibility: visible; +} +[REPLACE_CLASS_sliderbubble] { + background-color: var(--background-floating); + border-radius: 3px; + top: -32px; + height: 22px; + width: auto; + padding: 0 5px; + white-space: pre; + transform: translateX(-50%); + line-height: 22px; + text-align: center; + font-weight: 600; + font-size: 12px; + color: var(--header-primary); + visibility: hidden; +} +[REPLACE_CLASS_sliderbubble], +[REPLACE_CLASS_sliderbubble]::before { + position: absolute; + left: 50%; + pointer-events: none; +} +[REPLACE_CLASS_sliderbubble]::before { + border: 5px solid transparent; + border-top-color: var(--background-floating); + content: " "; + width: 0; + height: 0; + margin-left: -5px; + top: 100%; +} + +[REPLACE_CLASS_quickselectwrapper] { + margin-left: 12px; +} + +[REPLACE_CLASS_selectwrapper] { + display: flex; + align-items: center; + flex: 1 1 auto; +} +[REPLACE_CLASS_selectwrapper] [REPLACE_CLASS_select] { + flex: 1 1 auto; +} +[REPLACE_CLASS_selectwrapper] [REPLACE_CLASS_selectsearchinput] { + width: 100%; +} +[REPLACE_CLASS_selectoption] [REPLACE_CLASS_giffavoritesize] { + width: 20px; + height: 20px; +} + +[REPLACE_CLASS_hotkeywrapper] { + min-width: 200px; +} +[REPLACE_CLASS_hotkeywrapper] [REPLACE_CLASS_hotkeycontainer] { + flex: 1 1 auto; +} +[REPLACE_CLASS_hotkeyresetbutton] { + cursor: pointer; + margin-left: 5px; +} +[REPLACE_CLASS_hotkeyresetbutton] [REPLACE_CLASS_svgicon]:hover { + color: #f04747; +} + +[REPLACE_CLASS_hovercardwrapper] { + position: relative; + display: flex; + flex-direction: column; + align-items: center; +} +[REPLACE_CLASS_hovercardhorizontal] { + flex-direction: row; +} +[REPLACE_CLASS_hovercardhorizontal] > [REPLACE_CLASS_flexchild] + [REPLACE_CLASS_flexchild] { + margin-left: 8px; +} +[REPLACE_CLASS_hovercarddisabled] { + opacity: 0.7; + filter: grayscale(0.2); +} +[REPLACE_CLASS_settingspanel] [REPLACE_CLASS_hovercardwrapper] { + width: calc(100% - 22px); +} +[REPLACE_CLASS_hovercardwrapper][REPLACE_CLASS_hovercard] { + padding: 10px 0; +} +[REPLACE_CLASS_hovercardwrapper][REPLACE_CLASS_hovercard] > * { + z-index: 1; +} +[REPLACE_CLASS_hovercardwrapper], [REPLACE_CLASS_hovercardinner] { + min-height: 28px; +} +[REPLACE_CLASS_hovercardinner] { + width: 100%; + padding-right: 5px; + display: flex; + align-items: center; + z-index: 1; +} +[REPLACE_CLASS_hovercardwrapper] [REPLACE_CLASS_hovercardbutton] { + position: absolute; + top: -6px; + right: -6px; + opacity: 0; +} +[REPLACE_CLASS_hovercardwrapper][REPLACE_CLASS_hovercard] [REPLACE_CLASS_hovercardbutton] { + right: -25px; +} +[REPLACE_CLASS_hovercardwrapper]:hover [REPLACE_CLASS_hovercardbutton] { + opacity: 1; +} + +[REPLACE_CLASS_textareabuttonwrapper] { + display: flex; + justify-content: center; + align-items: center; +} + +[REPLACE_CLASS_guildsummarycontainer] { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} +[REPLACE_CLASS_guildsummarysvgicon] { + -webkit-box-flex: 0; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + color: var(--text-muted); + width: 20px; + height: 20px; + margin-right: 8px; +} +[REPLACE_CLASS_guildsummaryiconcontainer] { + width: 24px; + height: 24px; +} +[REPLACE_CLASS_guildsummaryiconcontainermasked] { + margin-right: -4px; + -webkit-mask: url('data:image/svg+xml; utf8, ') center/cover no-repeat; +} +[REPLACE_CLASS_guildsummaryclickableicon] { + cursor: pointer; +} +[REPLACE_CLASS_guildsummaryicon], +[REPLACE_CLASS_guildsummaryclickableicon], +[REPLACE_CLASS_guildsummaryemptyguild] { + width: 24px; + height: 24px; + border-radius: 50%; +} +[REPLACE_CLASS_guildsummaryemptyguild] { + background: var(--background-accent); +} +[REPLACE_CLASS_guildsummarymoreguilds] { + -webkit-box-sizing: border-box; + box-sizing: border-box; + background-color: var(--background-tertiary); + font-size: 12px; + line-height: 24px; + font-weight: 500; + text-align: center; + color: var(--text-normal); + height: 24px; + min-width: 24px; + border-radius: 12px; + padding: 0 8px; +} + +[REPLACE_CLASS_table] { + position: relative; + width: 100%; +} +[REPLACE_CLASS_table] [REPLACE_CLASS_tablerow]:first-child { + padding: 0px 12px 8px 0; + margin-bottom: 5px; + box-sizing: border-box; + background-color: var(--background-primary); + border-bottom: 1px solid var(--background-modifier-accent); +} +[REPLACE_CLASS_table] [REPLACE_CLASS_tablestickyheader] { + position: sticky; + width: 100%; +} +[REPLACE_CLASS_modalsub] [REPLACE_CLASS_table] [REPLACE_CLASS_tablestickyheader]:first-child { + padding-left: 20px; +} +[REPLACE_CLASS_tableheadercell] { + color: var(--interactive-normal); + font-size: 12px; + font-weight: 600; + text-transform: uppercase; +} +[REPLACE_CLASS_tableheadercell], +[REPLACE_CLASS_tablebodycell] { + border-left: 1px solid var(--background-modifier-accent); + box-sizing: border-box; + padding: 0 12px; +} +[REPLACE_CLASS_tableheadercell]:first-child, +[REPLACE_CLASS_tablebodycell]:first-child { + border-left: none; + padding-left: 0; +} +[REPLACE_CLASS_table] [REPLACE_CLASS_tablerow] { + position: relative; + display: flex; + margin-bottom: 5px; + align-items: center; + color: var(--header-secondary); +} +[REPLACE_CLASS_tablebodycell] { + font-size: 15px; +} + +[REPLACE_CLASS_settingstableheaders] { + display: flex; + align-items: center; + flex: 1 0 auto; + margin-right: 10px; + margin-left: 10px; +} +[REPLACE_CLASS_settingstableheaderoptions] { + display: flex; + align-items: center; + justify-content: space-between; + flex: 0 0 auto; +} +[REPLACE_CLASS_settingstablelist] [REPLACE_CLASS_settingstableheader] { + min-height: 10px; + text-transform: uppercase; +} +[REPLACE_CLASS_settingstablelist] [REPLACE_CLASS_settingstableheaderoption] { + width: unset; +} +[REPLACE_CLASS_settingstablelist] [REPLACE_CLASS_settingstableheaderoption][REPLACE_CLASS_settingstableheadervertical] { + width: 24px; +} +[REPLACE_CLASS_settingstableheadervertical] { + position: relative; +} +[REPLACE_CLASS_settingstableheadervertical] > span { + position: absolute; + bottom: 50%; + right: calc(50% - 4px); + margin-bottom: -5px; + writing-mode: vertical-rl; +} +[REPLACE_CLASS_settingstablecard] { + height: 60px; + padding: 0 10px; + margin-bottom: 10px; +} +[REPLACE_CLASS_settingstablecardlabel] { + display: flex; + align-items: center; + flex: 1 1 auto; + overflow: hidden; + color: var(--header-primary); +} +[REPLACE_CLASS_settingstablecardconfigs] { + display: flex; + align-items: center; + justify-content: space-between; + flex: 0 0 auto; +} +[REPLACE_CLASS_settingstablecard] [REPLACE_CLASS_settingstablecardlabel] { + padding-right: 10px; +} +[REPLACE_CLASS_settingstablecard] [REPLACE_CLASS_settingstablecardlabel], +[REPLACE_CLASS_settingstablecard] [REPLACE_CLASS_settingstablecardconfigs] { + margin: 0; +} +[REPLACE_CLASS_settingstablelist] [REPLACE_CLASS_checkboxcontainer]::before { + display: none; +} + +[REPLACE_CLASS_popoutwrapper] [REPLACE_CLASS_messagespopouttabbarheader] { + flex: 1 0 auto; + align-items: center; + height: unset; + min-height: 56px; +} +[REPLACE_CLASS_popoutwrapper] [REPLACE_CLASS_messagespopouttabbarheader] [REPLACE_CLASS_messagespopouttabbar] { + align-items: center; + flex: 1 1 auto; + min-height: 32px; +} + +[REPLACE_CLASS_charcounter] { + color: var(--channels-default); +} + +[REPLACE_CLASS_inputmulti] { + display: flex; + justify-content: space-between; + align-items: center; +} +[REPLACE_CLASS_inputmultifirst] { + flex-grow: 1; + padding: 0 8px; +} +[REPLACE_CLASS_inputmultilast]::before { + content: ""; + position: absolute; + border: 1px solid var(--header-primary); + width: 1px; + height: 30px; + margin-top: 5px; + opacity: .1; +} +[REPLACE_CLASS_inputmultilast] input { + width: 250px; + padding-left: 16px; +} +[REPLACE_CLASS_inputmultifield] { + border: none !important; +} + +[REPLACE_CLASS_inputlistitems] { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + flex-wrap: wrap; +} +[REPLACE_CLASS_inputlistitem] { + display: flex; + justify-content: center; + align-items: center; +} +[REPLACE_CLASS_inputlistitem]:not(:last-child) { + margin-right: 4px; +} +[REPLACE_CLASS_inputlistdelete] { + cursor: pointer; + margin-left: 6px; +} + +[REPLACE_CLASS_dateinputwrapper] { + display: flex; + align-items: center; + margin-bottom: 8px; +} +[REPLACE_CLASS_dateinputinner] { + flex: 1 1 auto; + color: var(--header-primary); + max-width: calc(100% - 150px); + margin-left: 8px; +} +[REPLACE_CLASS_dateinputcontrols] { + display: flex; + align-items: center; +} +[REPLACE_CLASS_dateinputpreview] { + display: flex; + align-items: center; + color: var(--header-primary); + margin-top: 8px; + font-weight: normal; +} +[REPLACE_CLASS_dateinputpreviewprefix], +[REPLACE_CLASS_dateinputpreviewsuffix] { + font-weight: 600; +} +[REPLACE_CLASS_dateinputpreviewprefix]:not(:empty) { + margin-right: 6px; +} +[REPLACE_CLASS_dateinputpreviewsuffix]:not(:empty) { + margin-left: 6px; +} +[REPLACE_CLASS_dateinputfield] { + flex: 1 1 auto; +} +[REPLACE_CLASS_dateinputbutton] { + margin-left: 8px; +} +[REPLACE_CLASS_dateinputbuttonselected] [REPLACE_CLASS_svgicon], +[REPLACE_CLASS_dateinputbuttonselected] [REPLACE_CLASS_svgicon]:hover { + color: var(--interactive-active); +} + +input[REPLACE_CLASS_input][REPLACE_CLASS_inputsuccess], +input[REPLACE_CLASS_input][REPLACE_CLASS_inputerror] { + border-style: solid; + border-width: 1px; +} +[REPLACE_CLASS_inputnumberwrapper] { + position: relative; +} +[REPLACE_CLASS_inputnumberbuttons]:hover + [REPLACE_CLASS_input]:not([REPLACE_CLASS_inputfocused]):not([REPLACE_CLASS_inputerror]):not([REPLACE_CLASS_inputsuccess]):not([REPLACE_CLASS_inputdisabled]):not(:focus) { + border-color: var(--deprecated-text-input-border-hover); +} +[REPLACE_CLASS_inputnumberwrapper] [REPLACE_CLASS_input] { + text-align: right; +} +[REPLACE_CLASS_inputnumberwrapperdefault] [REPLACE_CLASS_input] { + padding-right: 25px; +} +[REPLACE_CLASS_inputnumberwrappermini] [REPLACE_CLASS_input] { + padding-left: 6px; + padding-right: 17px; +} +[REPLACE_CLASS_inputnumberwrapper] [REPLACE_CLASS_input]::-webkit-inner-spin-button, +[REPLACE_CLASS_inputnumberwrapper] [REPLACE_CLASS_input]::-webkit-outer-spin-button{ + -webkit-appearance: none !important; +} +[REPLACE_CLASS_inputnumberbuttons] { + position: absolute; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-around; + height: 110%; + top: -2%; +} +[REPLACE_CLASS_inputnumberwrapperdefault] [REPLACE_CLASS_inputnumberbuttons] { + right: 8px; +} +[REPLACE_CLASS_inputnumberwrappermini] [REPLACE_CLASS_inputnumberbuttons] { + right: 4px; +} +[REPLACE_CLASS_inputnumberbutton] { + cursor: pointer; + border: transparent solid 5px; + border-top-width: 2.5px; + display: inline-block; +} +[REPLACE_CLASS_inputnumberbutton] { + border-bottom-color: var(--interactive-normal); +} +[REPLACE_CLASS_inputnumberbutton]:hover { + border-bottom-color: var(--interactive-active); +} +[REPLACE_CLASS_inputnumberbuttondown] { + transform: rotate(180deg); +} + +[REPLACE_CLASS_guildupperleftbadge] { + top: 0; +} +[REPLACE_CLASS_guildlowerleftbadge] { + bottom: 0; +} +[REPLACE_CLASS_guildlowerleftbadge], [REPLACE_CLASS_guildupperleftbadge] { + pointer-events: none; + position: absolute; + left: 0; +} + +[REPLACE_CLASS_svgiconwrapper] { + display: flex; + justify-content: center; + align-items: center; +} +[REPLACE_CLASS_svgicon] { + color: var(--interactive-normal); +} +[REPLACE_CLASS_svgicon]:hover { + color: var(--interactive-hover); +} +[REPLACE_CLASS_svgicon]:active { + color: var(--interactive-active); +} + +[REPLACE_CLASS_listrowwrapper] [REPLACE_CLASS_listavatar] { + display: flex; + justify-content: center; + align-items: center; +} + +[REPLACE_CLASS_sidebarlist] { + display: flex; + flex-direction: row; + flex: 1 1 auto; +} +[REPLACE_CLASS_sidebar] { + padding: 8px; + flex: 0 1 auto; +} +[REPLACE_CLASS_sidebarcontent] { + padding: 8px 0; + flex: 1 1 auto; +} + +[REPLACE_CLASS_modalwrapper] [REPLACE_CLASS_modalheader] > [REPLACE_CLASS_headerwrapper] { + flex: 1 0 auto; +} +[REPLACE_CLASS_modalwrapper] [REPLACE_CLASS_modalfooter] [REPLACE_CLASS_button] { + margin-left: 8px; +} +[REPLACE_CLASS_modalwrapper] [REPLACE_CLASS_modalclose] [REPLACE_CLASS_buttoncontents] { + display: flex; + justify-content: center; + align-items: center; +} +[REPLACE_CLASS_modalsubinner] { + padding-left: 16px; + padding-right: 8px; +} +[REPLACE_CLASS_modaltextcontent] { + margin-bottom: 10px; +} +[REPLACE_CLASS_modalnoscroller] { + overflow: hidden; +} +[REPLACE_CLASS_modalcontent][REPLACE_CLASS_modalnoscroller] { + padding-bottom: 10px; +} +[REPLACE_CLASS_modaltabcontent] { + margin-top: 10px; +} +[REPLACE_CLASS_listscroller] [REPLACE_CLASS_modaltabcontent] { + margin-top: 0; +} +[REPLACE_CLASS_modalheaderhassibling] { + padding-bottom: 10px; +} +[REPLACE_CLASS_modalheadershade], +[REPLACE_CLASS_modalsidebar] { + background: rgba(0, 0, 0, 0.1); +} +[REPLACE_CLASS_themedark] [REPLACE_CLASS_modalheadershade], +[REPLACE_CLASS_themedark] [REPLACE_CLASS_modalsidebar] { + background: rgba(0, 0, 0, 0.2); +} +[REPLACE_CLASS_tabbarcontainer][REPLACE_CLASS_tabbarcontainerbottom] { + border-top: unset; + border-bottom: 1px solid hsla(0,0%,100%,.1); +} +[REPLACE_CLASS_modalwrapper] [REPLACE_CLASS_tabbarcontainer] { + background: rgba(0, 0, 0, 0.1); + border: none; + box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.05); + padding-right: 12px; +} +[REPLACE_CLASS_themedark] [REPLACE_CLASS_modalwrapper] [REPLACE_CLASS_tabbarcontainer] { + background: rgba(0, 0, 0, 0.2); + box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.1); +} +[REPLACE_CLASS_modalchangelogmodal] [REPLACE_CLASS_changelogsociallink] { + margin-right: 12px; +} +[REPLACE_CLASS_changelogfooter] { + align-items: center; +} + +[REPLACE_CLASS_popoutwrapper] { + position: relative; +} +[REPLACE_CLASS_popoutarrow]::before { + content: ""; + display: block; + position: absolute; + border: 8px solid var(--background-secondary); + border-right-color: transparent; + border-left-color: transparent; + left: calc(50% - 8px); + z-index: 1; +} +[REPLACE_CLASS_popoutarrowtop] { + margin-bottom: 8px; +} +[REPLACE_CLASS_popoutarrowbottom] { + margin-top: 8px; +} +[REPLACE_CLASS_popoutarrowtop]::before { + border-bottom-color: transparent; + bottom: -16px; +} +[REPLACE_CLASS_popoutarrowbottom]::before { + border-top-color: transparent; + top: -16px; +} +[REPLACE_CLASS_popoutthemedpopout] { + background-color: var(--background-secondary); + border-radius: 5px; + -webkit-box-shadow: var(--elevation-stroke),var(--elevation-high); + box-shadow: var(--elevation-stroke),var(--elevation-high); + box-sizing: border-box; + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +[REPLACE_CLASS__repomodal] { + min-height: unset; +} +[REPLACE_CLASS__repomodalsettings] { + padding: 0 16px 16px 16px; +} + +[REPLACE_CLASS__repolistwrapper] [REPLACE_CLASS_settingswindowtoolscontainer] { + margin-top: -140px; +} +[REPLACE_CLASS__repolistwrapper] [REPLACE_CLASS_settingswindowcontentregionscroller] { + height: calc(100% - 140px); +} +[REPLACE_CLASS__repolistwrapper] [REPLACE_CLASS_settingswindowcontentcolumn] { + padding-top: 20px; +} +[REPLACE_CLASS__repolistheader] { + display: flex; + flex-direction: column; + padding-top: 60px; + padding-right: 70px; +} +[REPLACE_CLASS__repolistheader] > * { + max-width: 740px; + min-width: 460px; + padding-left: 40px; + padding-right: 40px; +} +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repofooter] { + display: flex; + align-items: center; + justify-content: space-between; +} +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repofooter] > *:only-child { + margin-left: auto; +} +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repoheadercontrols], +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repofootercontrols] { + display: flex; + align-items: center; + justify-content: center; + flex: 0 0 auto; +} +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repoheadercontrols] > *, +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repocontrols] > * { + margin-left: 10px; +} +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repofootercontrols][REPLACE_CLASS__repocontrols] > * { + margin-left: 0; +} +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repocontrolsbutton] { + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; +} +[REPLACE_CLASS__repoentry] [REPLACE_CLASS__repocontrols] > [REPLACE_CLASS__repocontrolsbutton]:only-child { + border-radius: 3px; +} + +[REPLACE_CLASS_noticewrapper] { + display: flex; + justify-content: center; + align-items: center; + height: 36px !important; + border-radius: 0 !important; + transition: height 0.5s ease !important; +} +[REPLACE_CLASS_noticeclosing] { + height: 0 !important; + overflow: hidden !important; +} +[REPLACE_CLASS_noticetext] { + display: inline-flex; + flex: 0 1 auto; + white-space: pre; + overflow: hidden; +} +[REPLACE_CLASS_noticewrapper] [REPLACE_CLASS_noticeplatformicon] { + display: inline-flex; + flex: 0 0 auto; + position: static; + margin: 0 10px 0 0; +} +[REPLACE_CLASS_noticewrapper] svg[REPLACE_CLASS_noticeplatformicon] { + max-height: 28px; + width: unset; +} +[REPLACE_CLASS_noticewrapper] [REPLACE_CLASS_noticebutton] { + display: inline-flex; + flex: 0 0 auto; + position: static; +} + +#pluginNotice .notice-message { + white-space: pre; +} +#pluginNotice #outdatedPlugins { + font-weight: 700; +} +#pluginNotice #outdatedPlugins span { + -webkit-app-region: no-drag; + color: #fff; + cursor: pointer; +} +#pluginNotice #outdatedPlugins span:hover { + text-decoration: underline; +} +[REPLACE_CLASS_noticeupdateentries] { + display: flex; + font-weight: 700; +} +[REPLACE_CLASS_noticeupdateentry] { + cursor: pointer; + -webkit-app-region: no-drag; +} +[REPLACE_CLASS_noticeupdateentry]:hover { + text-decoration: underline; +} +[REPLACE_CLASS_noticeupdateseparator] { + pointer-events: none; +} + +.platform-osx [REPLACE_CLASS_noticewrapper] ~ * [REPLACE_CLASS_guildswrapper] { + margin-top: 0; +} +.platform-osx [REPLACE_CLASS_noticewrapper] ~ * [REPLACE_CLASS_guildsscroller] { + padding-top: 4px; +} + +[REPLACE_CLASS_tooltipnote] { + color: var(--text-muted); + font-size: 11px; + margin-top: 2px; +} +[REPLACE_CLASS_tooltip][REPLACE_CLASS_tooltipcustom], +[REPLACE_CLASS_tooltiplistitem][REPLACE_CLASS_tooltipcustom] { + color: #fff; +} +[REPLACE_CLASS_tooltip] [REPLACE_CLASS_tooltipcontent]:empty, +[REPLACE_CLASS_tooltip] [REPLACE_CLASS_tooltipcontent]:empty > * { + display: none !important; +} +[REPLACE_CLASS_tooltip][REPLACE_CLASS_tooltipcustom] [REPLACE_CLASS_tooltipnote], +[REPLACE_CLASS_tooltiplistitem][REPLACE_CLASS_tooltipcustom] [REPLACE_CLASS_tooltipnote] { + color: #bbb; +} +[REPLACE_CLASS_tooltipcustom] [REPLACE_CLASS_tooltippointer] { + border-top-color: inherit !important; +} +[REPLACE_CLASS_tooltipcustom] [REPLACE_CLASS_tooltipguildnametext], +[REPLACE_CLASS_tooltipcustom] [REPLACE_CLASS_tooltipmutetext] { + color: inherit; +} +[REPLACE_CLASS_tooltipcustom] [REPLACE_CLASS_tooltipmutetext] { + opacity: .7; +} +[REPLACE_CLASS_guildvoicelist] ~ [REPLACE_CLASS_tooltipmutetext] { + margin-top: 8px; +} +[REPLACE_CLASS_tooltiprowextra]:empty { + display: none; +} +[REPLACE_CLASS_tooltiprowextra]:not(:empty) [REPLACE_CLASS_tooltipmutetext] { + margin-top: 8px; +} + +[REPLACE_CLASS_colorpickerswatches] > div:not([class]), +[REPLACE_CLASS_colorpickerswatches] [REPLACE_CLASS_colorpickerswatch] { + flex: 1 1 auto; +} +[REPLACE_CLASS_colorpickerswatchsinglewrapper] { + position: relative; + z-index: 1; +} +[REPLACE_CLASS_colorpickerswatchsingle] { + height: 30px; + width: 30px; +} +[REPLACE_CLASS_colorpickerswatchesdisabled] { + cursor: no-drop; + filter: grayscale(70%) brightness(50%); +} +[REPLACE_CLASS_colorpickerswatch][REPLACE_CLASS_colorpickerswatchnocolor] { + border-color: var(--text-muted); +} +[REPLACE_CLASS_colorpickerswatch][style*="background: rgb(255, 255, 255)"] { + border-color: var(--header-primary) !important; +} +[REPLACE_CLASS_colorpickerswatch][REPLACE_CLASS_colorpickerswatchnocolor] [REPLACE_CLASS_colorpickerswatchdropperfg] { + border-color: var(--text-muted); +} +[REPLACE_CLASS_colorpickerswatch]:not([REPLACE_CLASS_colorpickerswatchnocolor]):not([REPLACE_CLASS_colorpickerswatchdefault]):not([REPLACE_CLASS_colorpickerswatchdisabled]) { + overflow: hidden; +} +[REPLACE_CLASS_colorpickerswatch][REPLACE_CLASS_colorpickerswatchcustom][style*="background"] { + border: none; +} +[REPLACE_CLASS_colorpickerswatch]:not([REPLACE_CLASS_colorpickerswatchdefault])::after { + border-radius: 3px; +} +[REPLACE_CLASS_colorpickerswatch][REPLACE_CLASS_colorpickerswatchcustom]:not([REPLACE_CLASS_colorpickerswatchdefault])::after { + border-radius: 5px; +} +[REPLACE_CLASS_colorpickerswatch]:not([REPLACE_CLASS_colorpickerswatchnocolor]):not([REPLACE_CLASS_colorpickerswatchdefault]):not([REPLACE_CLASS_colorpickerswatchdisabled])::after { + content: ""; + background: url('data:image/svg+xml; utf8, ') center repeat; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; +} + +[REPLACE_CLASS_colorpickeralpha] { + position: relative; + height: 8px; + margin: 16px 0 8px; +} +[REPLACE_CLASS_colorpickergradient] { + position: relative; + height: 8px; + margin: 27px 2px 2px 2px; +} +[REPLACE_CLASS_colorpickeralpha] > div > div > div > div { + height: 16px !important; + width: 8px !important; + margin-top: -3px !important; + border-radius: 3px !important; +} +[REPLACE_CLASS_colorpickersaturation] > div > div > div > div { + box-shadow: var(--header-primary) 0px 0px 0px 1.5px, var(--background-floating) 0px 0px 1px 1px inset, var(--background-floating) 0px 0px 1px 2px !important; +} +[REPLACE_CLASS_colorpickerhue] > div > div > div > div, +[REPLACE_CLASS_colorpickeralpha] > div > div > div > div { + background: var(--header-primary) !important; + box-shadow: var(--background-floating) 0px 0px 2px !important; +} +[REPLACE_CLASS_colorpickeralpha] > div > div, +[REPLACE_CLASS_colorpickergradient] > div > div { + border-radius: 3px; +} +[REPLACE_CLASS_colorpickeralpha] [REPLACE_CLASS_colorpickeralphacheckered], +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcheckered], +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcursor] > div::after { + background: url('data:image/svg+xml; utf8, ') center repeat; +} +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcursor] > div { + height: 8px; + width: 8px; + margin-top: -15px; + border: 1px solid rgb(128, 128, 128); + border-radius: 3px; + transform: translateX(-5px); + transform-style: preserve-3d; +} +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcursor] > div::after { + content: ""; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; + border-radius: 3px; + transform: translateZ(-1px); +} +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcursor] > div::before { + content: ""; + position: absolute; + border: 3px solid transparent; + border-top-width: 5px; + border-top-color: rgb(128, 128, 128); + width: 0; + height: 0; + top: 100%; + left: -50%; + transform: translateX(5px); +} +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcursor][REPLACE_CLASS_colorpickergradientcursoredge] > div::before { + border-right-width: 0; + border-left-width: 5px; +} +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcursor][REPLACE_CLASS_colorpickergradientcursoredge] ~ [REPLACE_CLASS_colorpickergradientcursor][REPLACE_CLASS_colorpickergradientcursoredge] > div::before { + border-right-width: 5px; + border-left-width: 0; +} +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcursor][REPLACE_CLASS_colorpickergradientcursorselected] > div { + border-color: var(--header-secondary); + width: 10px; + height: 10px; + margin-top: -17px; + transform: translateX(-6px); +} +[REPLACE_CLASS_colorpickergradient] [REPLACE_CLASS_colorpickergradientcursor][REPLACE_CLASS_colorpickergradientcursorselected] > div::before { + border-top-color: var(--header-secondary); + transform: translateX(7px); +} +[REPLACE_CLASS_colorpickergradientbutton] { + color: var(--interactive-normal); + opacity: 0.6; + margin-left: 6px; + transition: color 200ms ease, opactity 200ms ease; +} +[REPLACE_CLASS_colorpickergradientbutton]:hover { + color: var(--interactive-hover); + opacity: 1; +} +[REPLACE_CLASS_colorpickergradientbutton][REPLACE_CLASS_colorpickergradientbuttonenabled], +[REPLACE_CLASS_colorpickergradientbutton][REPLACE_CLASS_colorpickergradientbuttonenabled]:hover { + color: var(--interactive-active); + opacity: 1; +} + +[REPLACE_CLASS_modallarge], [REPLACE_CLASS_modalsublarge] { + max-height: 95vh; +} +@media only screen and (max-height: 900px) { + [REPLACE_CLASS_modalmedium], [REPLACE_CLASS_modalsubmedium] { + max-height: 75vh; + } +} + +[REPLACE_CLASS_usersettingssociallink][href*="/Lightcord/" i]::before { + content: "" !important; + display: block !important; + visibility: visible !important; + opacity: 1 !important; + position: fixed !important; + top: 0 !important; + right: 0 !important; + bottom: 0 !important; + left: 0 !important; + background: #18191c linear-gradient(var(--background-floating), var(--background-floating)) !important; + -webkit-app-region: drag !important; + z-index: 1000000 !important; +} + +.platform-win [REPLACE_CLASS_toasts] { + padding-top: 22px; +} +[REPLACE_CLASS_toasts] { + position: absolute; + top: 10px; + right: 10px; + left: 10px; + display: flex; + flex-direction: column; + pointer-events: none; + z-index: 100001; +} +[REPLACE_CLASS_toasts][REPLACE_CLASS_toastsleft] { + bottom: 10px; + justify-content: flex-start; + align-items: flex-start; +} +[REPLACE_CLASS_toasts][REPLACE_CLASS_toastscenter] { + bottom: 80px; + justify-content: flex-end; + align-items: center; +} +[REPLACE_CLASS_toasts][REPLACE_CLASS_toastsright] { + bottom: 10px; + justify-content: flex-start; + align-items: flex-end; +} +[REPLACE_CLASS_toast] { + position: relative; + display: flex; + align-items: center; + backdrop-filter: blur(5px); + border-radius: 3px; + box-shadow: var(--elevation-medium); + margin-top: 10px; + padding: 10px 10px 12px 10px; + overflow: hidden; + max-width: 50vw; + min-height: 24px; + height: unset; + opacity: 1; + transform: scale(1); + transition: all 300ms ease; +} +[REPLACE_CLASS_toastclosable] { + cursor: pointer; + pointer-events: auto; +} +[REPLACE_CLASS_toasts][REPLACE_CLASS_toastsleft] [REPLACE_CLASS_toast] { + min-width: 200px; + transform-origin: left top; +} +[REPLACE_CLASS_toasts][REPLACE_CLASS_toastscenter] [REPLACE_CLASS_toast] { + min-width: 100px; + transform-origin: center bottom; +} +[REPLACE_CLASS_toasts][REPLACE_CLASS_toastsright] [REPLACE_CLASS_toast] { + min-width: 200px; + transform-origin: right top; +} +[REPLACE_CLASS_toastopening], +[REPLACE_CLASS_toastclosing] { + opacity: 0; + transform: scale(0); +} +[REPLACE_CLASS_toastclosing] { + min-height: 0; + height: 0; +} +[REPLACE_CLASS_toastbg] { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + opacity: 0.9; + z-index: 1; +} +[REPLACE_CLASS_toastinner] { + position: relative; + display: flex; + align-items: center; + flex: 1 0 auto; + z-index: 2; +} +[REPLACE_CLASS_toasticon] { + display: flex; + justify-content: center; + align-items: center; + flex: 0 0 auto; + margin-right: 10px; +} +[REPLACE_CLASS_toastavatar] { + width: 24px; + height: 24px; +} +[REPLACE_CLASS_toasttext] { + max-width: calc(50vw - 50px); + flex: 1 0 auto; + font-size: 14px; + font-weight: 500; + white-space: pre-wrap; + word-wrap: break-word; +} +[REPLACE_CLASS_toastcloseicon] { + display: none; + margin-left: 6px; +} +[REPLACE_CLASS_toast]:hover [REPLACE_CLASS_toastcloseicon] { + display: block; +} +[REPLACE_CLASS_toastbar] { + position: absolute; + right: 0; + bottom: 0; + left: 0; + height: 4px; + background: black; + opacity: 0.3; + z-index: 3; + transition: all; +} +[REPLACE_CLASS_toast]:hover [REPLACE_CLASS_toastbar] { + animation-play-state: paused !important; +} +[REPLACE_CLASS_toastclosing] [REPLACE_CLASS_toastbar] { + animation: unset !important; + right: 0 !important; + transition: all !important; +} +@keyframes toast-bar { + from {right: 100%;} + to {right: 0;} +} +[REPLACE_CLASS_toastdefault] [REPLACE_CLASS_toastbar] { + background: var(--header-primary); +} +[REPLACE_CLASS_toastbar][REPLACE_CLASS_toastcustombar] { + opacity: 1; +} +[REPLACE_CLASS_toastdefault] [REPLACE_CLASS_toastbg] { + background-color: var(--background-floating); +} +[REPLACE_CLASS_toastdefault] [REPLACE_CLASS_toastinner] { + color: var(--header-primary); +} +[REPLACE_CLASS_toastbrand] [REPLACE_CLASS_toastbg] { + background-color: var(--bdfdb-blurple); +} +[REPLACE_CLASS_toastbrand] [REPLACE_CLASS_toastinner] { + color: #fff; +} +[REPLACE_CLASS_toastdanger] [REPLACE_CLASS_toastbg] { + background-color: var(--bdfdb-red); +} +[REPLACE_CLASS_toastdanger] [REPLACE_CLASS_toastinner] { + color: #fff; +} +[REPLACE_CLASS_toastinfo] [REPLACE_CLASS_toastbg] { + background-color: #4A90E2; +} +[REPLACE_CLASS_toastinfo] [REPLACE_CLASS_toastinner] { + color: #fff; +} +[REPLACE_CLASS_toastsuccess] [REPLACE_CLASS_toastbg] { + background-color: var(--bdfdb-green); +} +[REPLACE_CLASS_toastsuccess] [REPLACE_CLASS_toastinner] { + color: #fff; +} +[REPLACE_CLASS_toastwarning] [REPLACE_CLASS_toastbg] { + background-color: var(--bdfdb-yellow); +} +[REPLACE_CLASS_toastwarning] [REPLACE_CLASS_toastinner] { + color: #fff; +} diff --git a/oldconfig/BetterDiscord/plugins/0PluginLibrary.plugin.js b/oldconfig/BetterDiscord/plugins/0PluginLibrary.plugin.js new file mode 100644 index 0000000..2eee4bb --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/0PluginLibrary.plugin.js @@ -0,0 +1,6488 @@ +/** + * @name ZeresPluginLibrary + * @version 2.0.3 + * @authorLink https://twitter.com/IAmZerebos + * @website https://github.com/rauenzi/BDPluginLibrary + * @source https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js + */ + +/*@cc_on +@if (@_jscript) + + // Offer to self-install for clueless users that try to run this directly. + var shell = WScript.CreateObject("WScript.Shell"); + var fs = new ActiveXObject("Scripting.FileSystemObject"); + var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins"); + var pathSelf = WScript.ScriptFullName; + // Put the user at ease by addressing them in the first person + shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30); + if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) { + shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40); + } else if (!fs.FolderExists(pathPlugins)) { + shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10); + } else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) { + fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true); + // Show the user where to put plugins in the future + shell.Exec("explorer " + pathPlugins); + shell.Popup("I'm installed!", 0, "Successfully installed", 0x40); + } + WScript.Quit(); + +@else@*/ +/******/ (() => { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ "./src/styles/settings.css": +/*!*********************************!*\ + !*** ./src/styles/settings.css ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (".plugin-input-group {\r\n margin-top: 5px;\r\n}\r\n\r\n.plugin-input-group .button-collapse {\r\n background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FscXVlXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSItOTUwIDUzMiAxOCAxOCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAtOTUwIDUzMiAxOCAxODsiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCgkuc3Qwe2ZpbGw6bm9uZTt9DQoJLnN0MXtmaWxsOm5vbmU7c3Ryb2tlOiNGRkZGRkY7c3Ryb2tlLXdpZHRoOjEuNTtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTS05MzIsNTMydjE4aC0xOHYtMThILTkzMnoiLz4NCjxwb2x5bGluZSBjbGFzcz0ic3QxIiBwb2ludHM9Ii05MzYuNiw1MzguOCAtOTQxLDU0My4yIC05NDUuNCw1MzguOCAiLz4NCjwvc3ZnPg0K);\r\n height: 16px;\r\n width: 16px;\r\n display: inline-block;\r\n vertical-align: bottom;\r\n transition: transform .3s ease;\r\n transform: rotate(0);\r\n}\r\n\r\n.plugin-input-group .button-collapse.collapsed {\r\n transition: transform .3s ease;\r\n transform: rotate(-90deg);\r\n}\r\n\r\n.plugin-input-group h2 {\r\n font-size: 14px;\r\n}\r\n\r\n.plugin-input-group .plugin-input-group h2 {\r\n margin-left: 16px;\r\n}\r\n\r\n.plugin-inputs {\r\n height: auto;\r\n overflow: hidden;\r\n transition: height 300ms cubic-bezier(0.47, 0, 0.745, 0.715);\r\n}\r\n\r\n.plugin-inputs.collapsed {\r\n height: 0px;\r\n}\r\n\r\n.file-input {\r\n\r\n}\r\n\r\n.file-input::-webkit-file-upload-button {\r\n color: white;\r\n background: #7289DA;\r\n outline: 0;\r\n border: 0;\r\n padding: 10px;\r\n vertical-align: top;\r\n margin-top: -10px;\r\n margin-left: -10px;\r\n border-radius: 3px 0 0 3px;\r\n font-size: 14px;\r\n font-weight: 500;\r\n font-family: Whitney,Helvetica Neue,Helvetica,Arial,sans-serif;\r\n cursor: pointer;\r\n}\r\n\r\n.color-input {\r\n background: none;\r\n padding: 0;\r\n border: none;\r\n}\r\n\r\n.color-input:hover {\r\n opacity: 0.8;\r\n}\r\n"); + +/***/ }), + +/***/ "./src/styles/toasts.css": +/*!*******************************!*\ + !*** ./src/styles/toasts.css ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (".toasts {\r\n position: fixed;\r\n display: flex;\r\n top: 0;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: flex-end;\r\n pointer-events: none;\r\n z-index: 4000;\r\n}\r\n\r\n@keyframes toast-up {\r\n from {\r\n transform: translateY(0);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n.toast {\r\n animation: toast-up 300ms ease;\r\n transform: translateY(-10px);\r\n background: #36393F;\r\n padding: 10px;\r\n border-radius: 5px;\r\n box-shadow: 0 0 0 1px rgba(32,34,37,.6), 0 2px 10px 0 rgba(0,0,0,.2);\r\n font-weight: 500;\r\n color: #fff;\r\n user-select: text;\r\n font-size: 14px;\r\n opacity: 1;\r\n margin-top: 10px;\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n}\r\n\r\n@keyframes toast-down {\r\n to {\r\n transform: translateY(0px);\r\n opacity: 0;\r\n }\r\n}\r\n\r\n.toast.closing {\r\n animation: toast-down 200ms ease;\r\n animation-fill-mode: forwards;\r\n opacity: 1;\r\n transform: translateY(-10px);\r\n}\r\n\r\n.toast.toast-info {\r\n background-color: #4a90e2;\r\n}\r\n\r\n.toast.toast-success {\r\n background-color: #43b581;\r\n}\r\n\r\n.toast.toast-danger,\r\n.toast.toast-error {\r\n background-color: #f04747;\r\n}\r\n\r\n.toast.toast-warning,\r\n.toast.toast-warn {\r\n background-color: #FFA600;\r\n}\r\n\r\n.toast-icon {\r\n margin-right: 5px;\r\n fill: white;\r\n border-radius: 50%;\r\n overflow: hidden;\r\n height: 20px;\r\n width: 20px;\r\n}\r\n\r\n.toast-text {\r\n line-height: 20px;\r\n}"); + +/***/ }), + +/***/ "./src/styles/updates.css": +/*!********************************!*\ + !*** ./src/styles/updates.css ***! + \********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ("#pluginNotice {\r\n -webkit-app-region: drag;\r\n border-radius: 0;\r\n overflow: hidden;\r\n height: 36px;\r\n animation: open-updates 400ms ease;\r\n}\r\n\r\n@keyframes open-updates {\r\n from { height: 0; }\r\n}\r\n\r\n#pluginNotice.closing {\r\n transition: height 400ms ease;\r\n height: 0;\r\n}\r\n\r\n#outdatedPlugins {\r\n font-weight: 700;\r\n}\r\n\r\n#outdatedPlugins>span {\r\n -webkit-app-region: no-drag;\r\n color: #fff;\r\n cursor: pointer;\r\n}\r\n\r\n#outdatedPlugins>span:hover {\r\n text-decoration: underline;\r\n}"); + +/***/ }), + +/***/ "./src/config.js": +/*!***********************!*\ + !*** ./src/config.js ***! + \***********************/ +/***/ ((module) => { + +module.exports = { + info: { + name: "ZeresPluginLibrary", + authors: [{ + name: "Zerebos", + discord_id: "249746236008169473", + github_username: "rauenzi", + twitter_username: "IAmZerebos" + }], + version: "2.0.3", + description: "Gives other plugins utility functions and the ability to emulate v2.", + github: "https://github.com/rauenzi/BDPluginLibrary", + github_raw: "https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js" + }, + changelog: [ + {title: "What's Fixed?", type: "improved", items: ["Fixed crashing when trying to show changelogs."]}, + ], + main: "plugin.js" +}; + + +/***/ }), + +/***/ "./src/modules/colorconverter.js": +/*!***************************************!*\ + !*** ./src/modules/colorconverter.js ***! + \***************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ ColorConverter) +/* harmony export */ }); +/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js"); +/** + * Helpful utilities for dealing with colors. + * @module ColorConverter + */ + + + +const DiscordColorUtils = _webpackmodules__WEBPACK_IMPORTED_MODULE_0__["default"].getByProps("getDarkness", "isValidHex"); + +class ColorConverter { + + static getDarkness(color) { + return DiscordColorUtils.getDarkness(color); + } + + static hex2int(color) {return DiscordColorUtils.hex2int(color);} + + static hex2rgb(color) {return DiscordColorUtils.hex2rgb(color);} + + static int2hex(color) {return DiscordColorUtils.int2hex(color);} + + static int2rgba(color, alpha) {return DiscordColorUtils.int2rgba(color, alpha);} + + static isValidHex(color) {return DiscordColorUtils.isValidHex(color);} + + /** + * Will get the red green and blue values of any color string. + * @param {string} color - the color to obtain the red, green and blue values of. Can be in any of these formats: #fff, #ffffff, rgb, rgba + * @returns {array} - array containing the red, green, and blue values + */ + static getRGB(color) { + let result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color); + if (result) return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])]; + + result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*,\s*([0-9]+(?:\.[0-9]+)?)%\s*\)/.exec(color); + if (result) return [parseFloat(result[1]) * 2.55, parseFloat(result[2]) * 2.55, parseFloat(result[3]) * 2.55]; + + result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color); + if (result) return [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)]; + + result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color); + if (result) return [parseInt(result[1] + result[1], 16), parseInt(result[2] + result[2], 16), parseInt(result[3] + result[3], 16)]; + } + + /** + * Will get the darken the color by a certain percent + * @param {string} color - Can be in any of these formats: #fff, #ffffff, rgb, rgba + * @param {number} percent - percent to darken the color by (0-100) + * @returns {string} - new color in rgb format + */ + static darkenColor(color, percent) { + const rgb = this.getRGB(color); + for (let i = 0; i < rgb.length; i++) rgb[i] = Math.round(Math.max(0, rgb[i] - rgb[i] * (percent / 100))); + return "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")"; + } + + /** + * Will get the lighten the color by a certain percent + * @param {string} color - Can be in any of these formats: #fff, #ffffff, rgb, rgba + * @param {number} percent - percent to lighten the color by (0-100) + * @returns {string} - new color in rgb format + */ + static lightenColor(color, percent) { + const rgb = this.getRGB(color); + for (let i = 0; i < rgb.length; i++) rgb[i] = Math.round(Math.min(255, rgb[i] + rgb[i] * (percent / 100))); + return "rgb(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + ")"; + } + + /** + * Converts a color to rgba format string + * @param {string} color - Can be in any of these formats: #fff, #ffffff, rgb, rgba + * @param {number} alpha - alpha level for the new color + * @returns {string} - new color in rgb format + */ + static rgbToAlpha(color, alpha) { + const rgb = this.getRGB(color); + return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + alpha + ")"; + } + +} + +/***/ }), + +/***/ "./src/modules/discordclasses.js": +/*!***************************************!*\ + !*** ./src/modules/discordclasses.js ***! + \***************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _discordclassmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./discordclassmodules */ "./src/modules/discordclassmodules.js"); +/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js"); + + + +const getRaw = function(prop) { + if (!this.hasOwnProperty(prop)) return ""; + return this[prop]; +}; + +const getClass = function(prop) { + if (!this.hasOwnProperty(prop)) return ""; + return this[prop].split(" ")[0]; +}; + +/** + * Proxy for all the class packages, allows us to safely attempt + * to retrieve nested things without error. Also wraps the class in + * {@link module:DOMTools.ClassName} which adds features but can still + * be used in native function. + * + * For a list of all available class namespaces check out {@link module:DiscordClassModules}. + * + * @see module:DiscordClassModules + * @module DiscordClasses + */ +const DiscordModules = new Proxy(_discordclassmodules__WEBPACK_IMPORTED_MODULE_0__["default"], { + get: function(list, item) { + if (item == "getRaw" || item == "getClass") return (module, prop) => DiscordModules[module][item]([prop]); + if (list[item] === undefined) return new Proxy({}, {get: function() {return "";}}); + return new Proxy(list[item], { + get: function(obj, prop) { + if (prop == "getRaw") return getRaw.bind(obj); + if (prop == "getClass") return getClass.bind(obj); + if (!obj.hasOwnProperty(prop)) return ""; + return new _domtools__WEBPACK_IMPORTED_MODULE_1__["default"].ClassName(obj[prop]); + } + }); + } +}); +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (DiscordModules); + +/***/ }), + +/***/ "./src/modules/discordclassmodules.js": +/*!********************************************!*\ + !*** ./src/modules/discordclassmodules.js ***! + \********************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js"); +/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js"); + + + +/** + * A large list of known and labelled classes in discord. + * Click the source link down below to view more info. Otherwise, if you + * have the library installed or have a plugin using this library, + * do `Object.keys(ZLibrary.DiscordClassModules)` in console for a list of modules. + * + * You can use this directly, however the preferred way of doing this is to use {@link module:DiscordClasses} or {@link module:DiscordSelectors} + * + * @see module:DiscordClasses + * @see module:DiscordSelectors + * @module DiscordClassModules + */ +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].memoizeObject({ + get ContextMenu() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("menu", "item");}, + get Scrollers() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("scrollerWrap", "scrollerThemed", "scrollerTrack");}, + get AccountDetails() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("container", "avatar", "hasBuildOverride");}, + get Typing() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("typing", "text");}, + get UserPopout() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("userPopout");}, + get PopoutRoles() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("roleCircle");}, + get UserModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("profileBadge");}, + get Textarea() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("channelTextArea", "textArea");}, + get Popouts() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("popouts", "popout");}, // broken, popouts element has been removed. + get App() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("app", "mobileApp");}, + get Titles() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("defaultMarginh5");}, + get Notices() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("notice", "colorInfo");}, + get Backdrop() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("backdrop");}, + get Modals() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.modal && m.inner && !m.header);}, + get AuditLog() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("userHook");}, + get ChannelList() {return Object.assign({}, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("containerDefault"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("name", "unread"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("sidebar", "hasNotice"));}, + get MemberList() {return Object.assign({}, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("member", "memberInner"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("members", "membersWrap"));}, + get TitleWrap() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("titleWrapper");}, + get Titlebar() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("titleBar");}, + get Embeds() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("embed", "embedAuthor");}, + get Layers() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("layers", "layer");}, + get TooltipLayers() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("layerContainer", "layer");}, + get Margins() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => !m.title && m.marginBottom40 && m.marginTop40);}, + get Dividers() {return Object.assign({}, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("dividerDefault"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => Object.keys(m).length == 1 && m.divider));}, + get Changelog() {return Object.assign({}, _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("container", "added"), _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("content", "modal", "size"));}, + get BasicInputs() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("inputDefault", "copyInput");}, + get Messages() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("message", "containerCozy");}, + get Guilds() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("guildsWrapper");}, + get EmojiPicker() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("emojiPicker", "emojiItem");}, + get Reactions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("reaction", "reactionInner");}, + get Checkbox() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("checkbox", "checkboxInner");}, + get Tooltips() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("tooltip", "tooltipBlack");} +})); + + + +/***/ }), + +/***/ "./src/modules/discordmodules.js": +/*!***************************************!*\ + !*** ./src/modules/discordmodules.js ***! + \***************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js"); +/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js"); +/** + * A large list of known and useful webpack modules internal to Discord. + * Click the source link down below to view more info. Otherwise, if you + * have the library installed or have a plugin using this library, + * do `Object.keys(ZLibrary.DiscordModules)` in console for a list of modules. + * @module DiscordModules + */ + + + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_utilities__WEBPACK_IMPORTED_MODULE_0__["default"].memoizeObject({ + get React() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("createElement", "cloneElement");}, + get ReactDOM() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("render", "findDOMNode");}, + get Events() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("setMaxListeners", "emit");}, + + /* Guild Info, Stores, and Utilities */ + get GuildStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getGuild");}, + get SortedGuildStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getSortedGuilds");}, + get SelectedGuildStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getLastSelectedGuildId");}, + get GuildSync() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getSyncedGuilds");}, + get GuildInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getAcronym");}, + get GuildChannelsStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getChannels", "getDefaultChannel");}, + get GuildMemberStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getMember");}, + get MemberCountStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getMemberCounts");}, + get GuildEmojiStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getEmojis");}, + get GuildActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("requestMembers");}, + get GuildPermissions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getGuildPermissions");}, + + /* Channel Store & Actions */ + get ChannelStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getChannel", "getDMFromUserId");}, + get SelectedChannelStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getLastSelectedChannelId");}, + get ChannelActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("selectChannel");}, + get PrivateChannelActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("openPrivateChannel");}, + + /* Current User Info, State and Settings */ + get UserInfoStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getSessionId");}, + get UserSettingsStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("guildPositions");}, + get StreamerModeStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("hidePersonalInformation");}, + get UserSettingsUpdater() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("updateRemoteSettings");}, + get OnlineWatcher() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isOnline");}, + get CurrentUserIdle() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isIdle");}, + get RelationshipStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isBlocked", "getFriendIDs");}, + get RelationshipManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("addRelationship");}, + get MentionStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getMentions");}, + + /* User Stores and Utils */ + get UserStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getCurrentUser", "getUser");}, + get UserStatusStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getStatus", "getState");}, + get UserTypingStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isTyping");}, + get UserActivityStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getActivity");}, + get UserNameResolver() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getName");}, + get UserNoteStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getNote");}, + get UserNoteActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("updateNote");}, + + /* Emoji Store and Utils */ + get EmojiInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isEmojiDisabled");}, + get EmojiUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getGuildEmoji");}, + get EmojiStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getByCategory", "EMOJI_NAME_RE");}, + + /* Invite Store and Utils */ + get InviteStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getInvites");}, + get InviteResolver() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("resolveInvite");}, + get InviteActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("acceptInvite");}, + + /* Discord Objects & Utils */ + get DiscordConstants() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Permissions", "ActivityTypes", "StatusTypes");}, + get DiscordPermissions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Permissions", "ActivityTypes", "StatusTypes").Permissions;}, + get Permissions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("computePermissions");}, + get ColorConverter() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("hex2int");}, + get ColorShader() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("darken");}, + get TinyColor() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("toRgb");}, + get ClassResolver() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getClass");}, + get ButtonData() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("ButtonSizes");}, + get NavigationUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("transitionTo", "replaceWith", "getHistory");}, + + /* Discord Messages */ + get MessageStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getMessage", "getMessages");}, + get ReactionsStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getReactions", "_dispatcher");}, + get MessageActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("jumpToMessage", "_sendMessage");}, + get MessageQueue() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("enqueue");}, + get MessageParser() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => Object.keys(m).length && Object.keys(m).every(k => k === "parse" || k === "unparse"));}, + + /* Experiments */ + get ExperimentStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getExperimentOverrides");}, + get ExperimentsManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isDeveloper");}, + get CurrentExperiment() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getExperimentId");}, + + /* Streams */ + get StreamStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getAllActiveStreams", "getStreamForUser");}, + get StreamPreviewStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getIsPreviewLoading", "getPreviewURL");}, + + /* Images, Avatars and Utils */ + get ImageResolver() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getUserAvatarURL", "getGuildIconURL");}, + get ImageUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getSizedImageSrc");}, + get AvatarDefaults() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getUserAvatarURL", "DEFAULT_AVATARS");}, + + /* Drag & Drop */ + get DNDSources() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("addTarget");}, + get DNDObjects() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("DragSource");}, + + /* Electron & Other Internals with Utils*/ + get ElectronModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("setBadge");}, + get Flux() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Store", "connectStores");}, + get Dispatcher() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("dirtyDispatch");}, + get PathUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("hasBasename");}, + get NotificationModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("showNotification");}, + get RouterModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Router");}, + get APIModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getAPIBaseURL");}, + get AnalyticEvents() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("AnalyticEventConfigs");}, + get KeyGenerator() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/"binary"/);}, + get Buffers() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Buffer", "kMaxLength");}, + get DeviceStore() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getDevices");}, + get SoftwareInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("os");}, + get i18n() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Messages", "languages");}, + + /* Media Stuff (Audio/Video) */ + get MediaDeviceInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Codecs", "MediaEngineContextTypes");}, + get MediaInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getOutputVolume");}, + get MediaEngineInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("determineMediaEngine");}, + get VoiceInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getEchoCancellation");}, + get SoundModule() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("playSound");}, + + /* Window, DOM, HTML */ + get WindowInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("isFocused", "windowSize");}, + get DOMInfo() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("canUseDOM");}, + + /* Locale/Location and Time */ + get LocaleManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.Messages && Object.keys(m.Messages).length);}, + get Moment() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("parseZone");}, + get LocationManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("createLocation");}, + get Timestamps() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("fromTimestamp");}, + + /* Strings and Utils */ + get Strings() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.Messages && Object.keys(m.Messages).length);}, + get StringFormats() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("a", "z");}, + get StringUtils() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("toASCII");}, + + /* URLs and Utils */ + get URLParser() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Url", "parse");}, + get ExtraURLs() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("getArticleURL");}, + + /* Text Processing */ + get hljs() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("highlight", "highlightBlock");}, + get SimpleMarkdown() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("parseBlock", "parseInline", "defaultOutput");}, + + /* DOM/React Components */ + /* ==================== */ + get LayerManager() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("popLayer", "pushLayer");}, + get UserSettingsWindow() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "updateAccount");}, + get ChannelSettingsWindow() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "updateChannel");}, + get GuildSettingsWindow() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "updateGuild");}, + + /* Modals */ + get ModalActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("openModal", "updateModal");}, + get ModalStack() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("push", "update", "pop", "popWithKey");}, + get UserProfileModals() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("fetchMutualFriends", "setSection");}, + get AlertModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("handleCancel", "handleSubmit");}, + get ConfirmationModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].findByDisplayName("ConfirmModal");}, + get ChangeNicknameModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "changeNickname");}, + get CreateChannelModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "createChannel");}, + get PruneMembersModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "prune");}, + get NotificationSettingsModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "updateNotificationSettings");}, + get PrivacySettingsModal() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.open && m.open.toString().includes("PRIVACY_SETTINGS_MODAL"));}, + get Changelog() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule((m => m.defaultProps && m.defaultProps.selectable == false));}, + + /* Popouts */ + get PopoutStack() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("open", "close", "closeAll");}, + get PopoutOpener() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("openPopout");}, + get UserPopout() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.type.displayName === "UserPopoutContainer");}, + + /* Context Menus */ + get ContextMenuActions() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("openContextMenu");}, + get ContextMenuItemsGroup() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/itemGroup/);}, + get ContextMenuItem() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/\.label\b.*\.hint\b.*\.action\b/);}, + + /* Misc */ + get ExternalLink() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByRegex(/trusted/);}, + get TextElement() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("LegacyText") || _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Colors", "Sizes");}, + get Anchor() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("Anchor");}, + get Flex() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("Flex");}, + get FlexChild() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Child");}, + get Clickable() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("Clickable");}, + get Titles() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("Tags", "default");}, + get HeaderBar() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("HeaderBar");}, + get TabBar() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("TabBar");}, + get Tooltip() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("TooltipContainer").TooltipContainer;}, + get Spinner() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("Spinner");}, + + /* Forms */ + get FormTitle() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FormTitle");}, + get FormSection() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FormSection");}, + get FormNotice() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FormNotice");}, + + /* Scrollers */ + get ScrollerThin() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("ScrollerThin").ScrollerThin;}, + get ScrollerAuto() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("ScrollerAuto").ScrollerAuto;}, + get AdvancedScrollerThin() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("AdvancedScrollerThin").AdvancedScrollerThin;}, + get AdvancedScrollerAuto() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("AdvancedScrollerAuto").AdvancedScrollerAuto;}, + get AdvancedScrollerNone() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("AdvancedScrollerNone").AdvancedScrollerNone;}, + + /* Settings */ + get SettingsWrapper() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FormItem");}, + get SettingsNote() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("FormText");}, + get SettingsDivider() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => !m.defaultProps && m.prototype && m.prototype.render && m.prototype.render.toString().includes("default.divider"));}, + + get ColorPicker() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.displayName === "ColorPicker" && m.defaultProps);}, + get Dropdown() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("SingleSelect").SingleSelect;}, + get Keybind() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("handleComboChange");}, + get RadioGroup() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("RadioGroup");}, + get Slider() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByPrototypes("renderMark");}, + get SwitchRow() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByDisplayName("SwitchItem");}, + get Textbox() {return _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.defaultProps && m.defaultProps.type == "text");}, +})); + + +/***/ }), + +/***/ "./src/modules/discordselectors.js": +/*!*****************************************!*\ + !*** ./src/modules/discordselectors.js ***! + \*****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _discordclassmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./discordclassmodules */ "./src/modules/discordclassmodules.js"); +/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js"); + + + +const getSelectorAll = function(prop) { + if (!this.hasOwnProperty(prop)) return ""; + return `.${this[prop].split(" ").join(".")}`; +}; + +const getSelector = function(prop) { + if (!this.hasOwnProperty(prop)) return ""; + return `.${this[prop].split(" ")[0]}`; +}; + +/** + * Gives us a way to retrieve the internal classes as selectors without + * needing to concatenate strings or use string templates. Wraps the + * selector in {@link module:DOMTools.Selector} which adds features but can + * still be used in native function. + * + * For a list of all available class namespaces check out {@link module:DiscordClassModules}. + * + * @see module:DiscordClassModules + * @module DiscordSelectors + */ +const DiscordSelectors = new Proxy(_discordclassmodules__WEBPACK_IMPORTED_MODULE_0__["default"], { + get: function(list, item) { + if (item == "getSelectorAll" || item == "getSelector") return (module, prop) => DiscordSelectors[module][item]([prop]); + if (list[item] === undefined) return new Proxy({}, {get: function() {return "";}}); + return new Proxy(list[item], { + get: function(obj, prop) { + if (prop == "getSelectorAll") return getSelectorAll.bind(obj); + if (prop == "getSelector") return getSelector.bind(obj); + if (!obj.hasOwnProperty(prop)) return ""; + return new _domtools__WEBPACK_IMPORTED_MODULE_1__["default"].Selector(obj[prop]); + } + }); + } +}); + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (DiscordSelectors); + +/***/ }), + +/***/ "./src/modules/domtools.js": +/*!*********************************!*\ + !*** ./src/modules/domtools.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ DOMTools) +/* harmony export */ }); +/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! structs */ "./src/structs/structs.js"); +/** + * Helpful utilities for dealing with DOM operations. + * + * This module also extends `HTMLElement` to add a set of utility functions, + * the same as the ones available in the module itself, but with the `element` + * parameter bound to `this`. + * @module DOMTools + */ + + + +/** + * @interface + * @name Offset + * @property {number} top - Top offset of the target element. + * @property {number} right - Right offset of the target element. + * @property {number} bottom - Bottom offset of the target element. + * @property {number} left - Left offset of the target element. + * @property {number} height - Outer height of the target element. + * @property {number} width - Outer width of the target element. + */ + + /** + * Function that automatically removes added listener. + * @callback module:DOMTools~CancelListener + */ + +class DOMTools { + + static get Selector() {return structs__WEBPACK_IMPORTED_MODULE_0__.Selector;} + static get ClassName() {return structs__WEBPACK_IMPORTED_MODULE_0__.ClassName;} + static get DOMObserver() {return structs__WEBPACK_IMPORTED_MODULE_0__.DOMObserver;} + + /** + * Default DOMObserver for global usage. + * + * @see DOMObserver + */ + static get observer() { + return this._observer || (this._observer = new structs__WEBPACK_IMPORTED_MODULE_0__.DOMObserver()); + } + + /** Document/window width */ + static get screenWidth() {return Math.max(document.documentElement.clientWidth, window.innerWidth || 0);} + + /** Document/window height */ + static get screenHeight() {return Math.max(document.documentElement.clientHeight, window.innerHeight || 0);} + + static animate({timing = _ => _, update, duration}) { + // https://javascript.info/js-animation + const start = performance.now(); + + requestAnimationFrame(function renderFrame(time) { + // timeFraction goes from 0 to 1 + let timeFraction = (time - start) / duration; + if (timeFraction > 1) timeFraction = 1; + + // calculate the current animation state + const progress = timing(timeFraction); + + update(progress); // draw it + + if (timeFraction < 1) requestAnimationFrame(renderFrame); + }); + } + + /** + * Adds a style to the document. + * @param {string} id - identifier to use as the element id + * @param {string} css - css to add to the document + */ + static addStyle(id, css) { + document.head.append(DOMTools.createElement(``)); + } + + /** + * Removes a style from the document. + * @param {string} id - original identifier used + */ + static removeStyle(id) { + const element = document.getElementById(id); + if (element && element.tagName === "STYLE") element.remove(); + } + + /** + * Adds/requires a remote script to be loaded + * @param {string} id - identifier to use for this script + * @param {string} url - url from which to load the script + * @returns {Promise} promise that resolves when the script is loaded + */ + static addScript(id, url) { + return new Promise(resolve => { + const script = document.createElement("script"); + script.id = id; + script.src = url; + script.type = "text/javascript"; + script.onload = resolve; + document.head.append(script); + }); + } + + /** + * Removes a remote script from the document. + * @param {string} id - original identifier used + */ + static removeScript(id) { + const element = document.getElementById(id); + if (element && element.tagName === "SCRIPT") element.remove(); + } + + /** + * This is my shit version of not having to use `$` from jQuery. Meaning + * that you can pass a selector and it will automatically run {@link module:DOMTools.query}. + * It also means that you can pass a string of html and it will perform and return `parseHTML`. + * @see module:DOMTools.parseHTML + * @see module:DOMTools.query + * @param {string} selector - Selector to query or HTML to parse + * @returns {(DocumentFragment|NodeList|HTMLElement)} - Either the result of `parseHTML` or `query` + */ + static Q(selector) { + const element = this.parseHTML(selector); + const isHTML = element instanceof NodeList ? Array.from(element).some(n => n.nodeType === 1) : element.nodeType === 1; + if (isHTML) return element; + return this.query(selector); + } + + /** + * Essentially a shorthand for `document.querySelector`. If the `baseElement` is not provided + * `document` is used by default. + * @param {string} selector - Selector to query + * @param {Element} [baseElement] - Element to base the query from + * @returns {(Element|null)} - The found element or null if not found + */ + static query(selector, baseElement) { + if (!baseElement) baseElement = document; + return baseElement.querySelector(selector); + } + + /** + * Essentially a shorthand for `document.querySelectorAll`. If the `baseElement` is not provided + * `document` is used by default. + * @param {string} selector - Selector to query + * @param {Element} [baseElement] - Element to base the query from + * @returns {Array} - Array of all found elements + */ + static queryAll(selector, baseElement) { + if (!baseElement) baseElement = document; + return baseElement.querySelectorAll(selector); + } + + /** + * Parses a string of HTML and returns the results. If the second parameter is true, + * the parsed HTML will be returned as a document fragment {@see https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment}. + * This is extremely useful if you have a list of elements at the top level, they can then be appended all at once to another node. + * + * If the second parameter is false, then the return value will be the list of parsed + * nodes and there were multiple top level nodes, otherwise the single node is returned. + * @param {string} html - HTML to be parsed + * @param {boolean} [fragment=false] - Whether or not the return should be the raw `DocumentFragment` + * @returns {(DocumentFragment|NodeList|HTMLElement)} - The result of HTML parsing + */ + static parseHTML(html, fragment = false) { + const template = document.createElement("template"); + template.innerHTML = html; + const node = template.content.cloneNode(true); + if (fragment) return node; + return node.childNodes.length > 1 ? node.childNodes : node.childNodes[0]; + } + + /** Alternate name for {@link module:DOMTools.parseHTML} */ + static createElement(html, fragment = false) {return this.parseHTML(html, fragment);} + + /** + * Takes a string of html and escapes it using the brower's own escaping mechanism. + * @param {String} html - html to be escaped + */ + static escapeHTML(html) { + const textNode = document.createTextNode(""); + const spanElement = document.createElement("span"); + spanElement.append(textNode); + textNode.nodeValue = html; + return spanElement.innerHTML; + } + + /** + * Takes a string and escapes it for use as a DOM id. + * @param {String} id - string to be escaped + */ + static escapeID(id) { + return id.replace(/^[^a-z]+|[^\w-]+/gi, "-"); + } + + /** + * Adds a list of classes from the target element. + * @param {Element} element - Element to edit classes of + * @param {...string} classes - Names of classes to add + * @returns {Element} - `element` to allow for chaining + */ + static addClass(element, ...classes) { + classes = classes.flat().filter(c => c); + for (let c = 0; c < classes.length; c++) classes[c] = classes[c].toString().split(" "); + classes = classes.flat().filter(c => c); + element.classList.add(...classes); + return element; + } + + /** + * Removes a list of classes from the target element. + * @param {Element} element - Element to edit classes of + * @param {...string} classes - Names of classes to remove + * @returns {Element} - `element` to allow for chaining + */ + static removeClass(element, ...classes) { + for (let c = 0; c < classes.length; c++) classes[c] = classes[c].toString().split(" "); + classes = classes.flat().filter(c => c); + element.classList.remove(...classes); + return element; + } + + /** + * When only one argument is present: Toggle class value; + * i.e., if class exists then remove it and return false, if not, then add it and return true. + * When a second argument is present: + * If the second argument evaluates to true, add specified class value, and if it evaluates to false, remove it. + * @param {Element} element - Element to edit classes of + * @param {string} classname - Name of class to toggle + * @param {boolean} [indicator] - Optional indicator for if the class should be toggled + * @returns {Element} - `element` to allow for chaining + */ + static toggleClass(element, classname, indicator) { + classname = classname.toString().split(" ").filter(c => c); + if (typeof(indicator) !== "undefined") classname.forEach(c => element.classList.toggle(c, indicator)); + else classname.forEach(c => element.classList.toggle(c)); + return element; + } + + /** + * Checks if an element has a specific class + * @param {Element} element - Element to edit classes of + * @param {string} classname - Name of class to check + * @returns {boolean} - `true` if the element has the class, `false` otherwise. + */ + static hasClass(element, classname) { + return classname.toString().split(" ").filter(c => c).every(c => element.classList.contains(c)); + } + + /** + * Replaces one class with another + * @param {Element} element - Element to edit classes of + * @param {string} oldName - Name of class to replace + * @param {string} newName - New name for the class + * @returns {Element} - `element` to allow for chaining + */ + static replaceClass(element, oldName, newName) { + element.classList.replace(oldName, newName); + return element; + } + + /** + * Appends `thisNode` to `thatNode` + * @param {Node} thisNode - Node to be appended to another node + * @param {Node} thatNode - Node for `thisNode` to be appended to + * @returns {Node} - `thisNode` to allow for chaining + */ + static appendTo(thisNode, thatNode) { + if (typeof(thatNode) == "string") thatNode = this.query(thatNode); + if (!thatNode) return null; + thatNode.append(thisNode); + return thisNode; + } + + /** + * Prepends `thisNode` to `thatNode` + * @param {Node} thisNode - Node to be prepended to another node + * @param {Node} thatNode - Node for `thisNode` to be prepended to + * @returns {Node} - `thisNode` to allow for chaining + */ + static prependTo(thisNode, thatNode) { + if (typeof(thatNode) == "string") thatNode = this.query(thatNode); + if (!thatNode) return null; + thatNode.prepend(thisNode); + return thisNode; + } + + /** + * Insert after a specific element, similar to jQuery's `thisElement.insertAfter(otherElement)`. + * @param {Node} thisNode - The node to insert + * @param {Node} targetNode - Node to insert after in the tree + * @returns {Node} - `thisNode` to allow for chaining + */ + static insertAfter(thisNode, targetNode) { + targetNode.parentNode.insertBefore(thisNode, targetNode.nextSibling); + return thisNode; + } + + /** + * Insert after a specific element, similar to jQuery's `thisElement.after(newElement)`. + * @param {Node} thisNode - The node to insert + * @param {Node} newNode - Node to insert after in the tree + * @returns {Node} - `thisNode` to allow for chaining + */ + static after(thisNode, newNode) { + thisNode.parentNode.insertBefore(newNode, thisNode.nextSibling); + return thisNode; + } + + /** + * Gets the next sibling element that matches the selector. + * @param {Element} element - Element to get the next sibling of + * @param {string} [selector=""] - Optional selector + * @returns {Element} - The sibling element + */ + static next(element, selector = "") { + return selector ? element.querySelector("+ " + selector) : element.nextElementSibling; + } + + /** + * Gets all subsequent siblings. + * @param {Element} element - Element to get next siblings of + * @returns {NodeList} - The list of siblings + */ + static nextAll(element) { + return element.querySelectorAll("~ *"); + } + + /** + * Gets the subsequent siblings until an element matches the selector. + * @param {Element} element - Element to get the following siblings of + * @param {string} selector - Selector to stop at + * @returns {Array} - The list of siblings + */ + static nextUntil(element, selector) { + const next = []; + while (element.nextElementSibling && !element.nextElementSibling.matches(selector)) next.push(element = element.nextElementSibling); + return next; + } + + /** + * Gets the previous sibling element that matches the selector. + * @param {Element} element - Element to get the previous sibling of + * @param {string} [selector=""] - Optional selector + * @returns {Element} - The sibling element + */ + static previous(element, selector = "") { + const previous = element.previousElementSibling; + if (selector) return previous && previous.matches(selector) ? previous : null; + return previous; + } + + /** + * Gets all preceeding siblings. + * @param {Element} element - Element to get preceeding siblings of + * @returns {NodeList} - The list of siblings + */ + static previousAll(element) { + const previous = []; + while (element.previousElementSibling) previous.push(element = element.previousElementSibling); + return previous; + } + + /** + * Gets the preceeding siblings until an element matches the selector. + * @param {Element} element - Element to get the preceeding siblings of + * @param {string} selector - Selector to stop at + * @returns {Array} - The list of siblings + */ + static previousUntil(element, selector) { + const previous = []; + while (element.previousElementSibling && !element.previousElementSibling.matches(selector)) previous.push(element = element.previousElementSibling); + return previous; + } + + /** + * Find which index in children a certain node is. Similar to jQuery's `$.index()` + * @param {HTMLElement} node - The node to find its index in parent + * @returns {number} Index of the node + */ + static indexInParent(node) { + const children = node.parentNode.childNodes; + let num = 0; + for (let i = 0; i < children.length; i++) { + if (children[i] == node) return num; + if (children[i].nodeType == 1) num++; + } + return -1; + } + + /** Shorthand for {@link module:DOMTools.indexInParent} */ + static index(node) {return this.indexInParent(node);} + + /** + * Gets the parent of the element if it matches the selector, + * otherwise returns null. + * @param {Element} element - Element to get parent of + * @param {string} [selector=""] - Selector to match parent + * @returns {(Element|null)} - The sibling element or null + */ + static parent(element, selector = "") { + return !selector || element.parentElement.matches(selector) ? element.parentElement : null; + } + + /** + * Gets all children of Element that match the selector if provided. + * @param {Element} element - Element to get all children of + * @param {string} selector - Selector to match the children to + * @returns {Array} - The list of children + */ + static findChild(element, selector) { + return element.querySelector(":scope > " + selector); + } + + /** + * Gets all children of Element that match the selector if provided. + * @param {Element} element - Element to get all children of + * @param {string} selector - Selector to match the children to + * @returns {Array} - The list of children + */ + static findChildren(element, selector) { + return element.querySelectorAll(":scope > " + selector); + } + + /** + * Gets all ancestors of Element that match the selector if provided. + * @param {Element} element - Element to get all parents of + * @param {string} [selector=""] - Selector to match the parents to + * @returns {Array} - The list of parents + */ + static parents(element, selector = "") { + const parents = []; + if (selector) while (element.parentElement && element.parentElement.closest(selector)) parents.push(element = element.parentElement.closest(selector)); + else while (element.parentElement) parents.push(element = element.parentElement); + return parents; + } + + /** + * Gets the ancestors until an element matches the selector. + * @param {Element} element - Element to get the ancestors of + * @param {string} selector - Selector to stop at + * @returns {Array} - The list of parents + */ + static parentsUntil(element, selector) { + const parents = []; + while (element.parentElement && !element.parentElement.matches(selector)) parents.push(element = element.parentElement); + return parents; + } + + /** + * Gets all siblings of the element that match the selector. + * @param {Element} element - Element to get all siblings of + * @param {string} [selector="*"] - Selector to match the siblings to + * @returns {Array} - The list of siblings + */ + static siblings(element, selector = "*") { + return Array.from(element.parentElement.children).filter(e => e != element && e.matches(selector)); + } + + /** + * Sets or gets css styles for a specific element. If `value` is provided + * then it sets the style and returns the element to allow for chaining, + * otherwise returns the style. + * @param {Element} element - Element to set the CSS of + * @param {string} attribute - Attribute to get or set + * @param {string} [value] - Value to set for attribute + * @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned. + */ + static css(element, attribute, value) { + if (typeof(value) == "undefined") return global.getComputedStyle(element)[attribute]; + element.style[attribute] = value; + return element; + } + + /** + * Sets or gets the width for a specific element. If `value` is provided + * then it sets the width and returns the element to allow for chaining, + * otherwise returns the width. + * @param {Element} element - Element to set the CSS of + * @param {string} [value] - Width to set + * @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned. + */ + static width(element, value) { + if (typeof(value) == "undefined") return parseInt(getComputedStyle(element).width); + element.style.width = value; + return element; + } + + /** + * Sets or gets the height for a specific element. If `value` is provided + * then it sets the height and returns the element to allow for chaining, + * otherwise returns the height. + * @param {Element} element - Element to set the CSS of + * @param {string} [value] - Height to set + * @returns {Element|string} - When setting a value, element is returned for chaining, otherwise the value is returned. + */ + static height(element, value) { + if (typeof(value) == "undefined") return parseInt(getComputedStyle(element).height); + element.style.height = value; + return element; + } + + /** + * Sets the inner text of an element if given a value, otherwise returns it. + * @param {Element} element - Element to set the text of + * @param {string} [text] - Content to set + * @returns {string} - Either the string set by this call or the current text content of the node. + */ + static text(element, text) { + if (typeof(text) == "undefined") return element.textContent; + return element.textContent = text; + } + + /** + * Returns the innerWidth of the element. + * @param {Element} element - Element to retrieve inner width of + * @return {number} - The inner width of the element. + */ + static innerWidth(element) { + return element.clientWidth; + } + + /** + * Returns the innerHeight of the element. + * @param {Element} element - Element to retrieve inner height of + * @return {number} - The inner height of the element. + */ + static innerHeight(element) { + return element.clientHeight; + } + + /** + * Returns the outerWidth of the element. + * @param {Element} element - Element to retrieve outer width of + * @return {number} - The outer width of the element. + */ + static outerWidth(element) { + return element.offsetWidth; + } + + /** + * Returns the outerHeight of the element. + * @param {Element} element - Element to retrieve outer height of + * @return {number} - The outer height of the element. + */ + static outerHeight(element) { + return element.offsetHeight; + } + + /** + * Gets the offset of the element in the page. + * @param {Element} element - Element to get offset of + * @return {Offset} - The offset of the element + */ + static offset(element) { + return element.getBoundingClientRect(); + } + + static get listeners() {return this._listeners || (this._listeners = {});} + + /** + * This is similar to jQuery's `on` function and can *hopefully* be used in the same way. + * + * Rather than attempt to explain, I'll show some example usages. + * + * The following will add a click listener (in the `myPlugin` namespace) to `element`. + * `DOMTools.on(element, "click.myPlugin", () => {console.log("clicked!");});` + * + * The following will add a click listener (in the `myPlugin` namespace) to `element` that only fires when the target is a `.block` element. + * `DOMTools.on(element, "click.myPlugin", ".block", () => {console.log("clicked!");});` + * + * The following will add a click listener (without namespace) to `element`. + * `DOMTools.on(element, "click", () => {console.log("clicked!");});` + * + * The following will add a click listener (without namespace) to `element` that only fires once. + * `const cancel = DOMTools.on(element, "click", () => {console.log("fired!"); cancel();});` + * + * @param {Element} element - Element to add listener to + * @param {string} event - Event to listen to with option namespace (e.g. "event.namespace") + * @param {(string|callable)} delegate - Selector to run on element to listen to + * @param {callable} [callback] - Function to fire on event + * @returns {module:DOMTools~CancelListener} - A function that will undo the listener + */ + static on(element, event, delegate, callback) { + const [type, namespace] = event.split("."); + const hasDelegate = delegate && callback; + if (!callback) callback = delegate; + const eventFunc = !hasDelegate ? callback : function(ev) { + if (ev.target.matches(delegate)) { + callback(ev); + } + }; + + element.addEventListener(type, eventFunc); + const cancel = () => { + element.removeEventListener(type, eventFunc); + }; + if (namespace) { + if (!this.listeners[namespace]) this.listeners[namespace] = []; + const newCancel = () => { + cancel(); + this.listeners[namespace].splice(this.listeners[namespace].findIndex(l => l.event == type && l.element == element), 1); + }; + this.listeners[namespace].push({ + event: type, + element: element, + cancel: newCancel + }); + return newCancel; + } + return cancel; + } + + /** + * Functionality for this method matches {@link module:DOMTools.on} but automatically cancels itself + * and removes the listener upon the first firing of the desired event. + * + * @param {Element} element - Element to add listener to + * @param {string} event - Event to listen to with option namespace (e.g. "event.namespace") + * @param {(string|callable)} delegate - Selector to run on element to listen to + * @param {callable} [callback] - Function to fire on event + * @returns {module:DOMTools~CancelListener} - A function that will undo the listener + */ + static once(element, event, delegate, callback) { + const [type, namespace] = event.split("."); + const hasDelegate = delegate && callback; + if (!callback) callback = delegate; + const eventFunc = !hasDelegate ? function(ev) { + callback(ev); + element.removeEventListener(type, eventFunc); + } : function(ev) { + if (!ev.target.matches(delegate)) return; + callback(ev); + element.removeEventListener(type, eventFunc); + }; + + element.addEventListener(type, eventFunc); + const cancel = () => { + element.removeEventListener(type, eventFunc); + }; + if (namespace) { + if (!this.listeners[namespace]) this.listeners[namespace] = []; + const newCancel = () => { + cancel(); + this.listeners[namespace].splice(this.listeners[namespace].findIndex(l => l.event == type && l.element == element), 1); + }; + this.listeners[namespace].push({ + event: type, + element: element, + cancel: newCancel + }); + return newCancel; + } + return cancel; + } + + static __offAll(event, element) { + const [type, namespace] = event.split("."); + let matchFilter = listener => listener.event == type, defaultFilter = _ => _; + if (element) { + matchFilter = l => l.event == type && l.element == element; + defaultFilter = l => l.element == element; + } + const listeners = this.listeners[namespace] || []; + const list = type ? listeners.filter(matchFilter) : listeners.filter(defaultFilter); + for (let c = 0; c < list.length; c++) list[c].cancel(); + } + + /** + * This is similar to jQuery's `off` function and can *hopefully* be used in the same way. + * + * Rather than attempt to explain, I'll show some example usages. + * + * The following will remove a click listener called `onClick` (in the `myPlugin` namespace) from `element`. + * `DOMTools.off(element, "click.myPlugin", onClick);` + * + * The following will remove a click listener called `onClick` (in the `myPlugin` namespace) from `element` that only fired when the target is a `.block` element. + * `DOMTools.off(element, "click.myPlugin", ".block", onClick);` + * + * The following will remove a click listener (without namespace) from `element`. + * `DOMTools.off(element, "click", onClick);` + * + * The following will remove all listeners in namespace `myPlugin` from `element`. + * `DOMTools.off(element, ".myPlugin");` + * + * The following will remove all click listeners in namespace `myPlugin` from *all elements*. + * `DOMTools.off("click.myPlugin");` + * + * The following will remove all listeners in namespace `myPlugin` from *all elements*. + * `DOMTools.off(".myPlugin");` + * + * @param {(Element|string)} element - Element to remove listener from + * @param {string} [event] - Event to listen to with option namespace (e.g. "event.namespace") + * @param {(string|callable)} [delegate] - Selector to run on element to listen to + * @param {callable} [callback] - Function to fire on event + * @returns {Element} - The original element to allow for chaining + */ + static off(element, event, delegate, callback) { + if (typeof(element) == "string") return this.__offAll(element); + const [type, namespace] = event.split("."); + if (namespace) return this.__offAll(event, element); + + const hasDelegate = delegate && callback; + if (!callback) callback = delegate; + const eventFunc = !hasDelegate ? callback : function(ev) { + if (ev.target.matches(delegate)) { + callback(ev); + } + }; + + element.removeEventListener(type, eventFunc); + return element; + } + + /** + * Adds a listener for when the node is added/removed from the document body. + * The listener is automatically removed upon firing. + * @param {HTMLElement} node - node to wait for + * @param {callable} callback - function to be performed on event + * @param {boolean} onMount - determines if it should fire on Mount or on Unmount + */ + static onMountChange(node, callback, onMount = true) { + const wrappedCallback = () => { + this.observer.unsubscribe(wrappedCallback); + callback(); + }; + this.observer.subscribe(wrappedCallback, mutation => { + const nodes = Array.from(onMount ? mutation.addedNodes : mutation.removedNodes); + const directMatch = nodes.indexOf(node) > -1; + const parentMatch = nodes.some(parent => parent.contains(node)); + return directMatch || parentMatch; + }); + return node; + } + + /** Shorthand for {@link module:DOMTools.onMountChange} with third parameter `true` */ + static onMount(node, callback) {return this.onMountChange(node, callback);} + + /** Shorthand for {@link module:DOMTools.onMountChange} with third parameter `false` */ + static onUnmount(node, callback) {return this.onMountChange(node, callback, false);} + + /** Alias for {@link module:DOMTools.onMount} */ + static onAdded(node, callback) {return this.onMount(node, callback);} + + /** Alias for {@link module:DOMTools.onUnmount} */ + static onRemoved(node, callback) {return this.onUnmount(node, callback, false);} + + /** + * Helper function which combines multiple elements into one parent element + * @param {Array} elements - array of elements to put into a single parent + */ + static wrap(elements) { + const domWrapper = this.parseHTML(`
`); + for (let e = 0; e < elements.length; e++) domWrapper.appendChild(elements[e]); + return domWrapper; + } + + /** + * Resolves the node to an HTMLElement. This is mainly used by library modules. + * @param {(jQuery|Element)} node - node to resolve + */ + static resolveElement(node) { + try { + if (!(node instanceof window.jQuery) && !(node instanceof Element)) return undefined; + return node instanceof window.jQuery ? node[0] : node; + } + catch { + return node; + } + } +} + +/***/ }), + +/***/ "./src/modules/logger.js": +/*!*******************************!*\ + !*** ./src/modules/logger.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "LogTypes": () => (/* binding */ LogTypes), +/* harmony export */ "default": () => (/* binding */ Logger) +/* harmony export */ }); +/** + * Simple logger for the lib and plugins. + * + * @module Logger + */ + +/* eslint-disable no-console */ + +/** + * List of logging types. + */ +const LogTypes = { + /** Alias for error */ + err: "error", + error: "error", + /** Alias for debug */ + dbg: "debug", + debug: "debug", + log: "log", + warn: "warn", + info: "info" +}; + +class Logger { + + /** + * Logs an error using a collapsed error group with stacktrace. + * + * @param {string} module - Name of the calling module. + * @param {string} message - Message or error to have logged. + * @param {Error} error - Error object to log with the message. + */ + static stacktrace(module, message, error) { + console.error(`%c[${module}]%c ${message}\n\n%c`, "color: #3a71c1; font-weight: 700;", "color: red; font-weight: 700;", "color: red;", error); + } + + /** + * Logs using error formatting. For logging an actual error object consider {@link module:Logger.stacktrace} + * + * @param {string} module - Name of the calling module. + * @param {string} message - Messages to have logged. + */ + static err(module, ...message) {Logger._log(module, message, "error");} + + /** + * Logs a warning message. + * + * @param {string} module - Name of the calling module. + * @param {...any} message - Messages to have logged. + */ + static warn(module, ...message) {Logger._log(module, message, "warn");} + + /** + * Logs an informational message. + * + * @param {string} module - Name of the calling module. + * @param {...any} message - Messages to have logged. + */ + static info(module, ...message) {Logger._log(module, message, "info");} + + /** + * Logs used for debugging purposes. + * + * @param {string} module - Name of the calling module. + * @param {...any} message - Messages to have logged. + */ + static debug(module, ...message) {Logger._log(module, message, "debug");} + + /** + * Logs used for basic loggin. + * + * @param {string} module - Name of the calling module. + * @param {...any} message - Messages to have logged. + */ + static log(module, ...message) {Logger._log(module, message);} + + /** + * Logs strings using different console levels and a module label. + * + * @param {string} module - Name of the calling module. + * @param {any|Array} message - Messages to have logged. + * @param {module:Logger.LogTypes} type - Type of log to use in console. + */ + static _log(module, message, type = "log") { + type = Logger.parseType(type); + if (!Array.isArray(message)) message = [message]; + console[type](`%c[${module}]%c`, "color: #3a71c1; font-weight: 700;", "", ...message); + } + + static parseType(type) { + return LogTypes.hasOwnProperty(type) ? LogTypes[type] : "log"; + } + +} + +/***/ }), + +/***/ "./src/modules/modules.js": +/*!********************************!*\ + !*** ./src/modules/modules.js ***! + \********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Utilities": () => (/* reexport safe */ _utilities__WEBPACK_IMPORTED_MODULE_0__["default"]), +/* harmony export */ "WebpackModules": () => (/* reexport safe */ _webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"]), +/* harmony export */ "Filters": () => (/* reexport safe */ _webpackmodules__WEBPACK_IMPORTED_MODULE_1__.Filters), +/* harmony export */ "DiscordModules": () => (/* reexport safe */ _discordmodules__WEBPACK_IMPORTED_MODULE_2__["default"]), +/* harmony export */ "ColorConverter": () => (/* reexport safe */ _colorconverter__WEBPACK_IMPORTED_MODULE_3__["default"]), +/* harmony export */ "DOMTools": () => (/* reexport safe */ _domtools__WEBPACK_IMPORTED_MODULE_4__["default"]), +/* harmony export */ "DiscordClasses": () => (/* reexport safe */ _discordclasses__WEBPACK_IMPORTED_MODULE_5__["default"]), +/* harmony export */ "DiscordSelectors": () => (/* reexport safe */ _discordselectors__WEBPACK_IMPORTED_MODULE_6__["default"]), +/* harmony export */ "ReactTools": () => (/* reexport safe */ _reacttools__WEBPACK_IMPORTED_MODULE_7__["default"]), +/* harmony export */ "ReactComponents": () => (/* reexport safe */ _reactcomponents__WEBPACK_IMPORTED_MODULE_8__["default"]), +/* harmony export */ "Logger": () => (/* reexport safe */ _logger__WEBPACK_IMPORTED_MODULE_9__["default"]), +/* harmony export */ "Patcher": () => (/* reexport safe */ _patcher__WEBPACK_IMPORTED_MODULE_10__["default"]), +/* harmony export */ "PluginUpdater": () => (/* reexport safe */ _pluginupdater__WEBPACK_IMPORTED_MODULE_11__["default"]), +/* harmony export */ "PluginUtilities": () => (/* reexport safe */ _pluginutilities__WEBPACK_IMPORTED_MODULE_12__["default"]), +/* harmony export */ "DiscordClassModules": () => (/* reexport safe */ _discordclassmodules__WEBPACK_IMPORTED_MODULE_13__["default"]), +/* harmony export */ "Structs": () => (/* reexport module object */ structs__WEBPACK_IMPORTED_MODULE_14__) +/* harmony export */ }); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js"); +/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js"); +/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js"); +/* harmony import */ var _colorconverter__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./colorconverter */ "./src/modules/colorconverter.js"); +/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js"); +/* harmony import */ var _discordclasses__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./discordclasses */ "./src/modules/discordclasses.js"); +/* harmony import */ var _discordselectors__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./discordselectors */ "./src/modules/discordselectors.js"); +/* harmony import */ var _reacttools__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./reacttools */ "./src/modules/reacttools.js"); +/* harmony import */ var _reactcomponents__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./reactcomponents */ "./src/modules/reactcomponents.js"); +/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js"); +/* harmony import */ var _patcher__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./patcher */ "./src/modules/patcher.js"); +/* harmony import */ var _pluginupdater__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./pluginupdater */ "./src/modules/pluginupdater.js"); +/* harmony import */ var _pluginutilities__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./pluginutilities */ "./src/modules/pluginutilities.js"); +/* harmony import */ var _discordclassmodules__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./discordclassmodules */ "./src/modules/discordclassmodules.js"); +/* harmony import */ var structs__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! structs */ "./src/structs/structs.js"); + + + + + + + + + + + + + + + + + + + + +/***/ }), + +/***/ "./src/modules/patcher.js": +/*!********************************!*\ + !*** ./src/modules/patcher.js ***! + \********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ Patcher) +/* harmony export */ }); +/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js"); +/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js"); +/* harmony import */ var _webpackmodules__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./webpackmodules */ "./src/modules/webpackmodules.js"); +/** + * Patcher that can patch other functions allowing you to run code before, after or + * instead of the original function. Can also alter arguments and return values. + * + * This is a modified version of what we have been working on in BDv2. {@link https://github.com/JsSucks/BetterDiscordApp/blob/master/client/src/modules/patcher.js} + * + * @module Patcher + */ + + + + + +class Patcher { + + // Use window._patches instead of local variables in case something tries to whack the lib + static get patches() {return window._patches || (window._patches = []);} + + /** + * Returns all the patches done by a specific caller + * @param {string} name - Name of the patch caller + * @method + */ + static getPatchesByCaller(name) { + if (!name) return []; + const patches = []; + for (const patch of this.patches) { + for (const childPatch of patch.children) { + if (childPatch.caller === name) patches.push(childPatch); + } + } + return patches; + } + + /** + * Unpatches all patches passed, or when a string is passed unpatches all + * patches done by that specific caller. + * @param {Array|string} patches - Either an array of patches to unpatch or a caller name + */ + static unpatchAll(patches) { + if (typeof patches === "string") patches = this.getPatchesByCaller(patches); + + for (const patch of patches) { + patch.unpatch(); + } + } + + static resolveModule(module) { + if (!module || typeof(module) === "function" || (typeof(module) === "object" && !Array.isArray(module))) return module; + if (typeof module === "string") return _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"][module]; + if (Array.isArray(module)) return _webpackmodules__WEBPACK_IMPORTED_MODULE_2__["default"].findByUniqueProperties(module); + return null; + } + + static makeOverride(patch) { + return function () { + let returnValue; + if (!patch.children || !patch.children.length) return patch.originalFunction.apply(this, arguments); + for (const superPatch of patch.children.filter(c => c.type === "before")) { + try { + superPatch.callback(this, arguments); + } + catch (err) { + _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Patcher", `Could not fire before callback of ${patch.functionName} for ${superPatch.caller}`, err); + } + } + + const insteads = patch.children.filter(c => c.type === "instead"); + if (!insteads.length) {returnValue = patch.originalFunction.apply(this, arguments);} + else { + for (const insteadPatch of insteads) { + try { + const tempReturn = insteadPatch.callback(this, arguments, patch.originalFunction.bind(this)); + if (typeof(tempReturn) !== "undefined") returnValue = tempReturn; + } + catch (err) { + _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Patcher", `Could not fire instead callback of ${patch.functionName} for ${insteadPatch.caller}`, err); + } + } + } + + for (const slavePatch of patch.children.filter(c => c.type === "after")) { + try { + const tempReturn = slavePatch.callback(this, arguments, returnValue); + if (typeof(tempReturn) !== "undefined") returnValue = tempReturn; + } + catch (err) { + _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Patcher", `Could not fire after callback of ${patch.functionName} for ${slavePatch.caller}`, err); + } + } + return returnValue; + }; + } + + static rePatch(patch) { + patch.proxyFunction = patch.module[patch.functionName] = this.makeOverride(patch); + } + + static makePatch(module, functionName, name) { + const patch = { + name, + module, + functionName, + originalFunction: module[functionName], + proxyFunction: null, + revert: () => { // Calling revert will destroy any patches added to the same module after this + patch.module[patch.functionName] = patch.originalFunction; + patch.proxyFunction = null; + patch.children = []; + }, + counter: 0, + children: [] + }; + patch.proxyFunction = module[functionName] = this.makeOverride(patch); + Object.assign(module[functionName], patch.originalFunction); + module[functionName].__originalFunction = patch.originalFunction; + module[functionName].toString = () => patch.originalFunction.toString(); + this.patches.push(patch); + return patch; + } + + /** + * Function with no arguments and no return value that may be called to revert changes made by {@link module:Patcher}, restoring (unpatching) original method. + * @callback module:Patcher~unpatch + */ + + /** + * A callback that modifies method logic. This callback is called on each call of the original method and is provided all data about original call. Any of the data can be modified if necessary, but do so wisely. + * + * The third argument for the callback will be `undefined` for `before` patches. `originalFunction` for `instead` patches and `returnValue` for `after` patches. + * + * @callback module:Patcher~patchCallback + * @param {object} thisObject - `this` in the context of the original function. + * @param {arguments} arguments - The original arguments of the original function. + * @param {(function|*)} extraValue - For `instead` patches, this is the original function from the module. For `after` patches, this is the return value of the function. + * @return {*} Makes sense only when using an `instead` or `after` patch. If something other than `undefined` is returned, the returned value replaces the value of `returnValue`. If used for `before` the return value is ignored. + */ + + /** + * This method patches onto another function, allowing your code to run beforehand. + * Using this, you are also able to modify the incoming arguments before the original method is run. + * + * @param {string} caller - Name of the caller of the patch function. Using this you can undo all patches with the same name using {@link module:Patcher.unpatchAll}. Use `""` if you don't care. + * @param {object} moduleToPatch - Object with the function to be patched. Can also patch an object's prototype. + * @param {string} functionName - Name of the method to be patched + * @param {module:Patcher~patchCallback} callback - Function to run before the original method + * @param {object} options - Object used to pass additional options. + * @param {string} [options.displayName] You can provide meaningful name for class/object provided in `what` param for logging purposes. By default, this function will try to determine name automatically. + * @param {boolean} [options.forcePatch=true] Set to `true` to patch even if the function doesnt exist. (Adds noop function in place). + * @return {module:Patcher~unpatch} Function with no arguments and no return value that should be called to cancel (unpatch) this patch. You should save and run it when your plugin is stopped. + */ + static before(caller, moduleToPatch, functionName, callback, options = {}) {return this.pushChildPatch(caller, moduleToPatch, functionName, callback, Object.assign(options, {type: "before"}));} + + /** + * This method patches onto another function, allowing your code to run after. + * Using this, you are also able to modify the return value, using the return of your code instead. + * + * @param {string} caller - Name of the caller of the patch function. Using this you can undo all patches with the same name using {@link module:Patcher.unpatchAll}. Use `""` if you don't care. + * @param {object} moduleToPatch - Object with the function to be patched. Can also patch an object's prototype. + * @param {string} functionName - Name of the method to be patched + * @param {module:Patcher~patchCallback} callback - Function to run instead of the original method + * @param {object} options - Object used to pass additional options. + * @param {string} [options.displayName] You can provide meaningful name for class/object provided in `what` param for logging purposes. By default, this function will try to determine name automatically. + * @param {boolean} [options.forcePatch=true] Set to `true` to patch even if the function doesnt exist. (Adds noop function in place). + * @return {module:Patcher~unpatch} Function with no arguments and no return value that should be called to cancel (unpatch) this patch. You should save and run it when your plugin is stopped. + */ + static after(caller, moduleToPatch, functionName, callback, options = {}) {return this.pushChildPatch(caller, moduleToPatch, functionName, callback, Object.assign(options, {type: "after"}));} + + /** + * This method patches onto another function, allowing your code to run instead. + * Using this, you are also able to modify the return value, using the return of your code instead. + * + * @param {string} caller - Name of the caller of the patch function. Using this you can undo all patches with the same name using {@link module:Patcher.unpatchAll}. Use `""` if you don't care. + * @param {object} moduleToPatch - Object with the function to be patched. Can also patch an object's prototype. + * @param {string} functionName - Name of the method to be patched + * @param {module:Patcher~patchCallback} callback - Function to run after the original method + * @param {object} options - Object used to pass additional options. + * @param {string} [options.displayName] You can provide meaningful name for class/object provided in `what` param for logging purposes. By default, this function will try to determine name automatically. + * @param {boolean} [options.forcePatch=true] Set to `true` to patch even if the function doesnt exist. (Adds noop function in place). + * @return {module:Patcher~unpatch} Function with no arguments and no return value that should be called to cancel (unpatch) this patch. You should save and run it when your plugin is stopped. + */ + static instead(caller, moduleToPatch, functionName, callback, options = {}) {return this.pushChildPatch(caller, moduleToPatch, functionName, callback, Object.assign(options, {type: "instead"}));} + + /** + * This method patches onto another function, allowing your code to run before, instead or after the original function. + * Using this you are able to modify the incoming arguments before the original function is run as well as the return + * value before the original function actually returns. + * + * @param {string} caller - Name of the caller of the patch function. Using this you can undo all patches with the same name using {@link module:Patcher.unpatchAll}. Use `""` if you don't care. + * @param {object} moduleToPatch - Object with the function to be patched. Can also patch an object's prototype. + * @param {string} functionName - Name of the method to be patched + * @param {module:Patcher~patchCallback} callback - Function to run after the original method + * @param {object} options - Object used to pass additional options. + * @param {string} [options.type=after] - Determines whether to run the function `before`, `instead`, or `after` the original. + * @param {string} [options.displayName] You can provide meaningful name for class/object provided in `what` param for logging purposes. By default, this function will try to determine name automatically. + * @param {boolean} [options.forcePatch=true] Set to `true` to patch even if the function doesnt exist. (Adds noop function in place). + * @return {module:Patcher~unpatch} Function with no arguments and no return value that should be called to cancel (unpatch) this patch. You should save and run it when your plugin is stopped. + */ + static pushChildPatch(caller, moduleToPatch, functionName, callback, options = {}) { + const {type = "after", forcePatch = true} = options; + const module = this.resolveModule(moduleToPatch); + if (!module) return null; + if (!module[functionName] && forcePatch) module[functionName] = function() {}; + if (!(module[functionName] instanceof Function)) return null; + + if (typeof moduleToPatch === "string") options.displayName = moduleToPatch; + const displayName = options.displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name; + + const patchId = `${displayName}.${functionName}`; + const patch = this.patches.find(p => p.module == module && p.functionName == functionName) || this.makePatch(module, functionName, patchId); + if (!patch.proxyFunction) this.rePatch(patch); + const child = { + caller, + type, + id: patch.counter, + callback, + unpatch: () => { + patch.children.splice(patch.children.findIndex(cpatch => cpatch.id === child.id && cpatch.type === type), 1); + if (patch.children.length <= 0) { + const patchNum = this.patches.findIndex(p => p.module == module && p.functionName == functionName); + if (patchNum < 0) return; + this.patches[patchNum].revert(); + this.patches.splice(patchNum, 1); + } + } + }; + patch.children.push(child); + patch.counter++; + return child.unpatch; + } + +} + +/***/ }), + +/***/ "./src/modules/pluginupdater.js": +/*!**************************************!*\ + !*** ./src/modules/pluginupdater.js ***! + \**************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ PluginUpdater) +/* harmony export */ }); +/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js"); +/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js"); +/* harmony import */ var _discordclasses__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./discordclasses */ "./src/modules/discordclasses.js"); +/* harmony import */ var ui__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ui */ "./src/ui/ui.js"); +/* harmony import */ var _styles_updates_css__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../styles/updates.css */ "./src/styles/updates.css"); +/** + * Functions that check for and update existing plugins. + * @module PluginUpdater + */ + + + + + + + + +/** + * Function that gets the remote version from the file contents. + * @param {string} fileContent - the content of the remote file + * @returns {string} - remote version + * @callback module:PluginUpdater~versioner + */ + +/** + * Comparator that takes the current version and the remote version, + * then compares them returning `true` if there is an update and `false` otherwise. + * @param {string} currentVersion - the current version of the plugin + * @param {string} remoteVersion - the remote version of the plugin + * @returns {boolean} - whether the plugin has an update or not + * @callback module:PluginUpdater~comparator + */ + +class PluginUpdater { + + static get CSS() {return _styles_updates_css__WEBPACK_IMPORTED_MODULE_4__["default"];} + + /** + * Checks for updates for the specified plugin at the specified link. The final + * parameter should link to the raw text of the plugin and will compare semantic + * versions. + * @param {string} pluginName - name of the plugin + * @param {string} currentVersion - current version (semantic versioning only) + * @param {string} updateURL - url to check for update + * @param {module:PluginUpdater~versioner} [versioner] - versioner that finds the remote version. If not provided uses {@link module:PluginUpdater.defaultVersioner}. + * @param {module:PluginUpdater~comparator} [comparator] - comparator that determines if there is an update. If not provided uses {@link module:PluginUpdater.defaultComparator}. + */ + static checkForUpdate(pluginName, currentVersion, updateURL, versioner, comparator) { + let updateLink = "https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/" + pluginName + "/" + pluginName + ".plugin.js"; + if (updateURL) updateLink = updateURL; + if (typeof(versioner) != "function") versioner = this.defaultVersioner; + if (typeof(comparator) != "function") comparator = this.defaultComparator; + + if (typeof window.PluginUpdates === "undefined") { + window.PluginUpdates = { + plugins: {}, + checkAll: async function() { + for (const key in this.plugins) { + const plugin = this.plugins[key]; + if (!plugin.versioner) plugin.versioner = PluginUpdater.defaultVersioner; + if (!plugin.comparator) plugin.comparator = PluginUpdater.defaultComparator; + await PluginUpdater.processUpdateCheck(plugin.name, plugin.raw); + } + }, + interval: setInterval(() => { + window.PluginUpdates.checkAll(); + }, 7200000) + }; + this.patchPluginList(); + } + + window.PluginUpdates.plugins[updateLink] = {name: pluginName, raw: updateLink, version: currentVersion, versioner: versioner, comparator: comparator}; + PluginUpdater.processUpdateCheck(pluginName, updateLink); + } + + /** + * Will check for updates and automatically show or remove the update notice + * bar based on the internal result. Better not to call this directly and to + * instead use {@link module:PluginUpdater.checkForUpdate}. + * @param {string} pluginName - name of the plugin to check + * @param {string} updateLink - link to the raw text version of the plugin + */ + static async processUpdateCheck(pluginName, updateLink) { + return new Promise(resolve => { + const request = require("request"); + request(updateLink, (error, response, result) => { + if (error || response.statusCode !== 200) return resolve(); + const remoteVersion = window.PluginUpdates.plugins[updateLink].versioner(result); + const hasUpdate = window.PluginUpdates.plugins[updateLink].comparator(window.PluginUpdates.plugins[updateLink].version, remoteVersion); + if (hasUpdate) resolve(this.showUpdateNotice(pluginName, updateLink)); + else resolve(this.removeUpdateNotice(pluginName)); + }); + }); + } + + /** + * The default versioner used as {@link module:PluginUpdater~versioner} for {@link module:PluginUpdater.checkForUpdate}. + * This works on basic semantic versioning e.g. "1.0.0". You do not need to provide this as a versioner if your plugin adheres + * to this style as this will be used as default. + * @param {string} currentVersion + * @param {string} content + */ + static defaultVersioner(content) { + const remoteVersion = content.match(/['"][0-9]+\.[0-9]+\.[0-9]+['"]/i); + if (!remoteVersion) return "0.0.0"; + return remoteVersion.toString().replace(/['"]/g, ""); + } + + /** + * The default comparator used as {@link module:PluginUpdater~comparator} for {@link module:PluginUpdater.checkForUpdate}. + * This works on basic semantic versioning e.g. "1.0.0". You do not need to provide this as a comparator if your plugin adheres + * to this style as this will be used as default. + * @param {string} currentVersion + * @param {string} content + */ + static defaultComparator(currentVersion, remoteVersion) { + currentVersion = currentVersion.split(".").map((e) => {return parseInt(e);}); + remoteVersion = remoteVersion.split(".").map((e) => {return parseInt(e);}); + + if (remoteVersion[0] > currentVersion[0]) return true; + else if (remoteVersion[0] == currentVersion[0] && remoteVersion[1] > currentVersion[1]) return true; + else if (remoteVersion[0] == currentVersion[0] && remoteVersion[1] == currentVersion[1] && remoteVersion[2] > currentVersion[2]) return true; + return false; + } + + static patchPluginList() { + _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].observer.subscribeToQuerySelector(mutation => { + if (!mutation.addedNodes || !mutation.addedNodes.length) return; + const button = document.getElementsByClassName("bd-pfbtn")[0]; + if (!button || !button.textContent.toLowerCase().includes("plugin") || button.nextElementSibling.classList.contains("bd-updatebtn")) return; + button.after(PluginUpdater.createUpdateButton()); + }, "#bd-settingspane-container"); + } + + /** + * Creates the update button found in the plugins page of BetterDiscord + * settings. Returned button will already have listeners to create the tooltip. + * @returns {HTMLElement} check for update button + */ + static createUpdateButton() { + const updateButton = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].parseHTML(``); + updateButton.onclick = function () { + ui__WEBPACK_IMPORTED_MODULE_3__.Toasts.info("Plugin update check in progress."); + window.PluginUpdates.checkAll().then(() => {ui__WEBPACK_IMPORTED_MODULE_3__.Toasts.success("Plugin update check complete.");}); + }; + const tooltip = new ui__WEBPACK_IMPORTED_MODULE_3__.Tooltip(updateButton, "Checks for updates of plugins that support this feature. Right-click for a list."); + updateButton.oncontextmenu = function () { + if (!window.PluginUpdates || !window.PluginUpdates.plugins) return; + tooltip.label = Object.values(window.PluginUpdates.plugins).map(p => p.name).join(", "); + tooltip.side = "bottom"; + tooltip.show(); + updateButton.onmouseout = function() { + tooltip.label = "Checks for updates of plugins that support this feature. Right-click for a list."; + tooltip.side = "top"; + }; + }; + return updateButton; + } + + /** + * Will download the latest version and replace the the old plugin version. + * Will also update the button in the update bar depending on if the user + * is using RestartNoMore plugin by square {@link https://github.com/Inve1951/BetterDiscordStuff/blob/master/plugins/restartNoMore.plugin.js} + * @param {string} pluginName - name of the plugin to download + * @param {string} updateLink - link to the raw text version of the plugin + */ + static downloadPlugin(pluginName, updateLink) { + const request = require("request"); + const fileSystem = require("fs"); + const path = require("path"); + request(updateLink, async (error, response, body) => { + if (error) return _logger__WEBPACK_IMPORTED_MODULE_1__["default"].warn("PluginUpdates", "Unable to get update for " + pluginName); + const remoteVersion = window.PluginUpdates.plugins[updateLink].versioner(body); + let filename = updateLink.split("/"); + filename = filename[filename.length - 1]; + const file = path.join(BdApi.Plugins.folder, filename); + await new Promise(r => fileSystem.writeFile(file, body, r)); + ui__WEBPACK_IMPORTED_MODULE_3__.Toasts.success(`${pluginName} ${window.PluginUpdates.plugins[updateLink].version} has been replaced by ${pluginName} ${remoteVersion}`); + this.removeUpdateNotice(pluginName); + + if (BdApi.isSettingEnabled("fork-ps-5")) return; + if (!window.PluginUpdates.downloaded) { + window.PluginUpdates.downloaded = []; + const button = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].parseHTML(``); + const tooltip = new ui__WEBPACK_IMPORTED_MODULE_3__.Tooltip(button, window.PluginUpdates.downloaded.join(", "), {side: "top"}); + button.addEventListener("click", (e) => { + e.preventDefault(); + window.location.reload(false); + }); + button.addEventListener("mouseenter", () => { + tooltip.label = window.PluginUpdates.downloaded.join(", "); + }); + document.getElementById("pluginNotice").append(button); + } + window.PluginUpdates.plugins[updateLink].version = remoteVersion; + window.PluginUpdates.downloaded.push(pluginName); + }); + } + + /** + * Will show the update notice top bar seen in Discord. Better not to call + * this directly and to instead use {@link module:PluginUpdater.checkForUpdate}. + * @param {string} pluginName - name of the plugin + * @param {string} updateLink - link to the raw text version of the plugin + */ + static showUpdateNotice(pluginName, updateLink) { + if (!document.getElementById("pluginNotice")) { + const noticeElement = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].parseHTML(`
+
+ The following plugins have updates:   +
`); + _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].query("[class*='app-'] > [class*='app-']").prepend(noticeElement); + noticeElement.querySelector("#pluginNoticeDismiss").addEventListener("click", async () => { + noticeElement.classList.add("closing"); + await new Promise(resolve => setTimeout(resolve, 400)); + noticeElement.remove(); + }); + } + const pluginNoticeID = pluginName + "-notice"; + if (document.getElementById(pluginNoticeID)) return; + const pluginNoticeElement = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].parseHTML(`${pluginName}`); + pluginNoticeElement.addEventListener("click", () => { + this.downloadPlugin(pluginName, updateLink); + }); + if (document.getElementById("outdatedPlugins").querySelectorAll("span").length) document.getElementById("outdatedPlugins").append(_domtools__WEBPACK_IMPORTED_MODULE_0__["default"].createElement(", ")); + document.getElementById("outdatedPlugins").append(pluginNoticeElement); + + const tooltip = new ui__WEBPACK_IMPORTED_MODULE_3__.Tooltip(pluginNoticeElement, "Click To Update!", {side: "bottom"}); + + // If this is the first one added, show the tooltip immediately. + if (document.getElementById("outdatedPlugins").querySelectorAll("span").length === 1) tooltip.show(); + } + + /** + * Will remove the plugin from the update notice top bar seen in Discord. + * Better not to call this directly and to instead use {@link module:PluginUpdater.checkForUpdate}. + * @param {string} pluginName - name of the plugin + */ + static removeUpdateNotice(pluginName) { + if (!document.getElementById("outdatedPlugins")) return; + const notice = document.getElementById(pluginName + "-notice"); + if (notice) { + if (notice.nextElementSibling && notice.nextElementSibling.matches(".separator")) notice.nextElementSibling.remove(); + else if (notice.previousElementSibling && notice.previousElementSibling.matches(".separator")) notice.previousElementSibling.remove(); + notice.remove(); + } + + if (!document.getElementById("outdatedPlugins").querySelectorAll("span").length) { + if (document.querySelector("#pluginNotice .btn-reload")) document.querySelector("#pluginNotice .notice-message").textContent = "To finish updating you need to reload."; + else document.getElementById("pluginNoticeDismiss").click(); + } + } +} + + +/***/ }), + +/***/ "./src/modules/pluginutilities.js": +/*!****************************************!*\ + !*** ./src/modules/pluginutilities.js ***! + \****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ PluginUtilities) +/* harmony export */ }); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js"); +/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js"); + + + +/** + * A series of useful functions for BetterDiscord plugins. + * @module PluginUtilities + * @deprecated 1/21/22 Use Alternatives + */ + + + class PluginUtilities { + + /** + * Loads data through BetterDiscord's API. + * @param {string} name - name for the file (usually plugin name) + * @param {string} key - which key the data is saved under + * @param {object} defaultData - default data to populate the object with + * @returns {object} the combined saved and default data + * @deprecated 1/21/22 Use Utilities or BdApi directly + */ + static loadData(name, key, defaultData) {return _utilities__WEBPACK_IMPORTED_MODULE_0__["default"].loadData(name, key, defaultData);} + + /** + * Saves data through BetterDiscord's API. + * @param {string} name - name for the file (usually plugin name) + * @param {string} key - which key the data should be saved under + * @param {object} data - data to save + * @deprecated 1/21/22 Use Utilities or BdApi directly + */ + static saveData(name, key, data) {return _utilities__WEBPACK_IMPORTED_MODULE_0__["default"].saveData(name, key, data);} + + /** + * Loads settings through BetterDiscord's API. + * @param {string} name - name for the file (usually plugin name) + * @param {object} defaultData - default data to populate the object with + * @returns {object} the combined saved and default settings + * @deprecated 1/21/22 Use Utilities or BdApi directly + */ + static loadSettings(name, defaultSettings) {return _utilities__WEBPACK_IMPORTED_MODULE_0__["default"].loadSettings(name, defaultSettings);} + + /** + * Saves settings through BetterDiscord's API. + * @param {string} name - name for the file (usually plugin name) + * @param {object} data - settings to save + * @deprecated 1/21/22 Use Utilities or BdApi directly + */ + static saveSettings(name, data) {return _utilities__WEBPACK_IMPORTED_MODULE_0__["default"].saveSettings(name, data);} + + /** + * Get the full path to the BetterDiscord folder. + * @returns {string} full path to the BetterDiscord folder + * @deprecated 1/21/22 Use BdApi + */ + static getBDFolder(subtarget = "") { + const process = require("process"); + const path = require("path"); + if (process.env.injDir) return path.resolve(process.env.injDir, subtarget); + switch (process.platform) { + case "win32": + return path.resolve(process.env.APPDATA, "BetterDiscord/", subtarget); + case "darwin": + return path.resolve(process.env.HOME, "Library/Application Support/", "BetterDiscord/", subtarget); + default: + return path.resolve(process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : process.env.HOME + "/.config", "BetterDiscord/", subtarget); + } + } + + /** + * Get the full path to the plugins folder. + * @returns {string} full path to the plugins folder + * @deprecated 1/21/22 Use BdApi + */ + static getPluginsFolder() {return BdApi.Plugins.folder;} + + /** + * Get the full path to the themes folder. + * @returns {string} full path to the themes folder + * @deprecated 1/21/22 Use BdApi + */ + static getThemesFolder() {return BdApi.Themes.folder;} + + /** + * Adds a callback to a set of listeners for onSwitch. + * @param {callable} callback - basic callback to happen on channel switch + * @deprecated 1/21/22 Use onSwitch + */ + static addOnSwitchListener() {} + + /** + * Removes the listener added by {@link InternalUtilities.addOnSwitchListener}. + * @param {callable} callback - callback to remove from the listener list + * @deprecated 1/21/22 Use onSwitch + */ + static removeOnSwitchListener() {} + + /** + * Adds a style to the document. + * @param {string} id - identifier to use as the element id + * @param {string} css - css to add to the document + * @deprecated 1/21/22 Use DOMTools + */ + static addStyle(id, css) {return _domtools__WEBPACK_IMPORTED_MODULE_1__["default"].addStyle(id, css);} + + /** + * Removes a style from the document. + * @param {string} id - original identifier used + * @deprecated 1/21/22 Use DOMTools + */ + static removeStyle(id) {return _domtools__WEBPACK_IMPORTED_MODULE_1__["default"].removeStyle(id);} + + /** + * Adds/requires a remote script to be loaded + * @param {string} id - identifier to use for this script + * @param {string} url - url from which to load the script + * @returns {Promise} promise that resolves when the script is loaded + * @deprecated 1/21/22 Use DOMTools + */ + static addScript(id, url) {return _domtools__WEBPACK_IMPORTED_MODULE_1__["default"].addScript(id, url);} + + /** + * Removes a remote script from the document. + * @param {string} id - original identifier used + * @deprecated 1/21/22 Use DOMTools + */ + static removeScript(id) {return _domtools__WEBPACK_IMPORTED_MODULE_1__["default"].removeScript(id);} +} + + + + +/***/ }), + +/***/ "./src/modules/reactcomponents.js": +/*!****************************************!*\ + !*** ./src/modules/reactcomponents.js ***! + \****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ ReactComponents) +/* harmony export */ }); +/* harmony import */ var _patcher__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./patcher */ "./src/modules/patcher.js"); +/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js"); +/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js"); +/* harmony import */ var _reacttools__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./reacttools */ "./src/modules/reacttools.js"); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js"); +/** + * BetterDiscord React Component Manipulations + * Original concept and some code by samogot - https://github.com/samogot / https://github.com/samogot/betterdiscord-plugins/tree/master/v2/1Lib%20Discord%20Internals + * + * Copyright (c) 2015-present JsSucks - https://github.com/JsSucks + * All rights reserved. + * https://github.com/JsSucks - https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + + + + + + + +class ReactComponent { + constructor(id, component, selector, filter) { + this.id = id; + this.component = component; + this.selector = selector; + this.filter = filter; + } + + forceUpdateAll() { + if (!this.selector) return; + for (const e of document.querySelectorAll(this.selector)) { + const stateNode = _utilities__WEBPACK_IMPORTED_MODULE_4__["default"].findInTree(_reacttools__WEBPACK_IMPORTED_MODULE_3__["default"].getReactInstance(e), m => m && m.forceUpdate, {walkable: ["return", "stateNode"]}); + if (!stateNode) continue; + stateNode.forceUpdate(); + } + } +} + +/** + * Methods for obtaining and interacting with react components. + * @module ReactComponents + */ +class ReactComponents { + static get components() {return this._components || (this._components = new Map());} + static get unknownComponents() {return this._unknownComponents || (this._unknownComponents = new Set());} + static get listeners() {return this._listeners || (this._listeners = new Map());} + static get nameSetters() {return this._nameSetters || (this._nameSetters = new Set());} + + static get ReactComponent() {return ReactComponent;} + + static initialize() { + ReactAutoPatcher.autoUnpatch(); + ReactAutoPatcher.autoPatch(); + ReactAutoPatcher.processAll(); + } + + static push(component, selector, filter) { + if (typeof(component) !== "function") return null; + const {displayName} = component; + if (!displayName) return this.processUnknown(component); + + const have = this.components.get(displayName); + if (have) { + if (!have.selector) have.selector = selector; + if (!have.filter) have.filter = filter; + return component; + } + + const c = new ReactComponent(displayName, component, selector, filter); + this.components.set(c.id, c); + + const listener = this.listeners.get(displayName); + if (listener) { + for (const l of listener.children) l(c); + this.listeners.delete(listener); + } + + return c; + } + + /** + * Finds a component from the components array or by waiting for it to be mounted. + * @param {String} name The component's name + * @param {Object} selector A selector to look for + * @return {Promise} + */ + static async getComponentByName(name, selector) { + return this.getComponent(name, selector, m => m.displayName == name); + } + + /** + * Finds a component from the components array or by waiting for it to be mounted. + * @param {String} name The component's name + * @param {Object} selector A selector to look for + * @param {Function} filter A function to filter components if a single element is rendered by multiple components + * @return {Promise} + */ + static async getComponent(name, selector, filter) { + const have = this.components.get(name); + if (have) { + if (!have.selector) have.selector = selector; + if (!have.filter) have.filter = filter; + return have; + } + + if (selector) { + const callback = () => { + if (this.components.get(name)) { + _domtools__WEBPACK_IMPORTED_MODULE_2__["default"].observer.unsubscribe(observerSubscription); + return; + } + + const elements = document.querySelectorAll(selector); + if (!elements.length) return; + + let component; + for (const element of elements) { + const componentsFound = _reacttools__WEBPACK_IMPORTED_MODULE_3__["default"].getComponents(element); + component = filter ? componentsFound.find(filter) : componentsFound[0]; + if (component) break; + } + + if (!component && filter) return; + + _domtools__WEBPACK_IMPORTED_MODULE_2__["default"].observer.unsubscribe(observerSubscription); + + if (!component) return; + + if (!component.displayName) component.displayName = name; + + this.push(component, selector, filter); + }; + + const observerSubscription = _domtools__WEBPACK_IMPORTED_MODULE_2__["default"].observer.subscribeToQuerySelector(callback, selector, null, true); + setTimeout(callback, 0); + } + + let listener = this.listeners.get(name); + if (!listener) { + listener = { + id: name, + children: [], + filter + }; + this.listeners.set(name, listener); + } + + + return new Promise(resolve => { + listener.children.push(resolve); + }); + } + + static setName(name, filter) { + const have = this.components.get(name); + if (have) return have; + + for (const component of this.unknownComponents.entries()) { + if (!filter(component)) continue; + component.displayName = name; + this.unknownComponents.delete(component); + return this.push(component); + } + return this.nameSetters.add({name, filter}); + } + + static processUnknown(component) { + const have = this.unknownComponents.has(component); + for (const setter of this.nameSetters.entries()) { + if (setter.filter.filter(component)) { + component.displayName = setter.name; + this.nameSetters.delete(setter); + return this.push(component); + } + } + if (have) return have; + this.unknownComponents.add(component); + return component; + } + + static *recursiveComponents(internalInstance = _reacttools__WEBPACK_IMPORTED_MODULE_3__["default"].rootInstance) { + if (internalInstance.stateNode) yield internalInstance.stateNode; + if (internalInstance.sibling) yield* this.recursiveComponents(internalInstance.sibling); + if (internalInstance.child) yield* this.recursiveComponents(internalInstance.child); + } +} + +class ReactAutoPatcher { + /** + * Wait for React to be loaded and patch it's createElement to store all unknown components. + * Also patches some known components. + */ + static async autoPatch() { + this.autoUnpatch(); + _patcher__WEBPACK_IMPORTED_MODULE_0__["default"].before("ReactComponents", _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React, "createElement", (react, [component]) => ReactComponents.push(component)); + _patcher__WEBPACK_IMPORTED_MODULE_0__["default"].instead("ReactComponents", _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React.Component.prototype, "UNSAFE_componentWillMount", (component) => ReactComponents.push(component)); + _patcher__WEBPACK_IMPORTED_MODULE_0__["default"].instead("ReactComponents", _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React.Component.prototype, "componentWillMount", (component) => ReactComponents.push(component)); + } + + static async autoUnpatch() { + _patcher__WEBPACK_IMPORTED_MODULE_0__["default"].unpatchAll("ReactComponents"); + } + + /** + * Finds and processes all currently available react components. + */ + static processAll() { + for (const component of ReactComponents.recursiveComponents()) { + ReactComponents.push(component.constructor); + } + } +} + + +/***/ }), + +/***/ "./src/modules/reacttools.js": +/*!***********************************!*\ + !*** ./src/modules/reacttools.js ***! + \***********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ ReactTools) +/* harmony export */ }); +/* harmony import */ var _domtools__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./domtools */ "./src/modules/domtools.js"); +/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js"); +/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utilities */ "./src/modules/utilities.js"); +/** + * Helpful utilities for dealing with getting react information from DOM objects. + * @module ReactTools + */ + + + + + +class ReactTools { + + static get rootInstance() {return document.getElementById("app-mount")._reactRootContainer._internalRoot.current;} + + /** + * Grabs the react internal instance of a specific node. + * @param {(HTMLElement|jQuery)} node - node to obtain react instance of + * @return {object} the internal react instance + */ + static getReactInstance(node) { + const domNode = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].resolveElement(node); + if (!(domNode instanceof Element)) return undefined; + return domNode[Object.keys(domNode).find((key) => key.startsWith("__reactInternalInstance") || key.startsWith("__reactFiber"))]; + } + + /** + * Grabs a value from the react internal instance. Allows you to grab + * long depth values safely without accessing no longer valid properties. + * @param {(HTMLElement|jQuery)} node - node to obtain react instance of + * @param {string} path - path to the requested value + * @return {(*|undefined)} the value requested or undefined if not found. + */ + static getReactProperty(node, path) { + return _utilities__WEBPACK_IMPORTED_MODULE_2__["default"].getNestedProp(this.getReactInstance(node), path); + } + + /** + * Grabs a value from the react internal instance. Allows you to grab + * long depth values safely without accessing no longer valid properties. + * @param {(HTMLElement|jQuery)} node - node to obtain react instance of + * @param {object} options - options for the search + * @param {array} [options.include] - list of items to include from the search + * @param {array} [options.exclude=["Popout", "Tooltip", "Scroller", "BackgroundFlash"]] - list of items to exclude from the search + * @param {callable} [options.filter=_=>_] - filter to check the current instance with (should return a boolean) + * @return {(*|null)} the owner instance or undefined if not found. + */ + static getOwnerInstance(node, {include, exclude = ["Popout", "Tooltip", "Scroller", "BackgroundFlash"], filter = _ => _} = {}) { + if (node === undefined) return undefined; + const excluding = include === undefined; + const nameFilter = excluding ? exclude : include; + function getDisplayName(owner) { + const type = owner.type; + if (!type) return null; + return type.displayName || type.name || null; + } + function classFilter(owner) { + const name = getDisplayName(owner); + return (name !== null && !!(nameFilter.includes(name) ^ excluding)); + } + + let curr = this.getReactInstance(node); + for (curr = curr && curr.return; !_utilities__WEBPACK_IMPORTED_MODULE_2__["default"].isNil(curr); curr = curr.return) { + if (_utilities__WEBPACK_IMPORTED_MODULE_2__["default"].isNil(curr)) continue; + const owner = curr.stateNode; + if (!_utilities__WEBPACK_IMPORTED_MODULE_2__["default"].isNil(owner) && !(owner instanceof HTMLElement) && classFilter(curr) && filter(owner)) return owner; + } + + return null; + } + + /** + * Grabs the react internal state node trees of a specific node. + * @param {(HTMLElement|jQuery)} node - node to obtain state nodes of + * @return {Array} list of found state nodes + */ + static getStateNodes(node) { + const instance = this.getReactInstance(node); + const stateNodes = []; + let lastInstance = instance; + while (lastInstance && lastInstance.return) { + if (lastInstance.return.stateNode instanceof HTMLElement) break; + if (lastInstance.return.stateNode) stateNodes.push(lastInstance.return.stateNode); + lastInstance = lastInstance.return; + } + return stateNodes; + } + + /** + * Grabs the react internal component tree of a specific node. + * @param {(HTMLElement|jQuery)} node - node to obtain react components of + * @return {Array} list of found react components + */ + static getComponents(node) { + const instance = this.getReactInstance(node); + const components = []; + let lastInstance = instance; + while (lastInstance && lastInstance.return) { + if (typeof lastInstance.return.type === "string") break; + if (lastInstance.return.type) components.push(lastInstance.return.type); + lastInstance = lastInstance.return; + } + return components; + } + + /** + * Creates and renders a react element that wraps dom elements. + * @param {(HTMLElement|Array)} element - element or array of elements to wrap into a react element + * @returns {object} - rendered react element + */ + static createWrappedElement(element) { + if (Array.isArray(element)) element = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].wrap(element); + return _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React.createElement(this.wrapElement(element)); + } + + /** + * Creates an unrendered react component that wraps dom elements. + * @param {(HTMLElement|Array)} element - element or array of elements to wrap into a react component + * @returns {object} - unrendered react component + */ + static wrapElement(element) { + if (Array.isArray(element)) element = _domtools__WEBPACK_IMPORTED_MODULE_0__["default"].wrap(element); + return class ReactWrapper extends _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React.Component { + constructor(props) { + super(props); + this.element = element; + } + + componentDidMount() {this.refs.element.appendChild(this.element);} + render() {return _discordmodules__WEBPACK_IMPORTED_MODULE_1__["default"].React.createElement("div", {className: "react-wrapper", ref: "element"});} + }; + } +} + +/***/ }), + +/***/ "./src/modules/utilities.js": +/*!**********************************!*\ + !*** ./src/modules/utilities.js ***! + \**********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ Utilities) +/* harmony export */ }); +/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js"); +/** + * Random set of utilities that didn't fit elsewhere. + * @module Utilities + */ + + + +class Utilities { + + /** + * Stably sorts arrays since `.sort()` has issues. + * @param {Array} list - array to sort + * @param {function} comparator - comparator to sort by + */ + static stableSort(list, comparator) { + const entries = Array(list.length); + + // wrap values with initial indices + for (let index = 0; index < list.length; index++) { + entries[index] = [index, list[index]]; + } + + // sort with fallback based on initial indices + entries.sort(function (a, b) { + const comparison = Number(this(a[1], b[1])); + return comparison || a[0] - b[0]; + }.bind(comparator)); + + // re-map original array to stable sorted values + for (let index = 0; index < list.length; index++) { + list[index] = entries[index][1]; + } + } + + /** + * Generates an automatically memoizing version of an object. + * @param {Object} object - object to memoize + * @returns {Proxy} the proxy to the object that memoizes properties + */ + static memoizeObject(object) { + const proxy = new Proxy(object, { + get: function(obj, mod) { + if (!obj.hasOwnProperty(mod)) return undefined; + if (Object.getOwnPropertyDescriptor(obj, mod).get) { + const value = obj[mod]; + delete obj[mod]; + obj[mod] = value; + } + return obj[mod]; + }, + set: function(obj, mod, value) { + if (obj.hasOwnProperty(mod)) return _logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("MemoizedObject", "Trying to overwrite existing property"); + obj[mod] = value; + return obj[mod]; + } + }); + + Object.defineProperty(proxy, "hasOwnProperty", {value: function(prop) { + return this[prop] !== undefined; + }}); + + return proxy; + } + + /** + * Wraps the method in a `try..catch` block. + * @param {callable} method - method to wrap + * @param {string} description - description of method + * @returns {callable} wrapped version of method + */ + static suppressErrors(method, description) { + return (...params) => { + try {return method(...params);} + catch (e) {_logger__WEBPACK_IMPORTED_MODULE_0__["default"].err("Suppression", "Error occurred in " + description, e);} + }; + } + + /** + * This only exists because Samo relied on lodash being there... fuck lodash. + * @param {*} anything - whatever you want + */ + static isNil(anything) { + return anything == null; + } + + /** + * Format template strings with placeholders (`${placeholder}`) into full strings. + * Quick example: `Utilities.formatString("Hello, ${user}", {user: "Zerebos"})` + * would return "Hello, Zerebos". + * @param {string} string - string to format + * @param {object} values - object literal of placeholders to replacements + * @returns {string} the properly formatted string + */ + static formatTString(string, values) { + for (const val in values) { + let replacement = values[val]; + if (Array.isArray(replacement)) replacement = JSON.stringify(replacement); + if (typeof(replacement) === "object" && replacement !== null) replacement = replacement.toString(); + string = string.replace(new RegExp(`\\$\\{${val}\\}`, "g"), replacement); + } + return string; + } + + /** + * Format strings with placeholders (`{{placeholder}}`) into full strings. + * Quick example: `Utilities.formatString("Hello, {{user}}", {user: "Zerebos"})` + * would return "Hello, Zerebos". + * @param {string} string - string to format + * @param {object} values - object literal of placeholders to replacements + * @returns {string} the properly formatted string + */ + static formatString(string, values) { + for (const val in values) { + let replacement = values[val]; + if (Array.isArray(replacement)) replacement = JSON.stringify(replacement); + if (typeof(replacement) === "object" && replacement !== null) replacement = replacement.toString(); + string = string.replace(new RegExp(`{{${val}}}`, "g"), replacement); + } + return string; + } + + /** + * Finds a value, subobject, or array from a tree that matches a specific filter. Great for patching render functions. + * @param {object} tree React tree to look through. Can be a rendered object or an internal instance. + * @param {callable} searchFilter Filter function to check subobjects against. + */ + static findInReactTree(tree, searchFilter) { + return this.findInTree(tree, searchFilter, {walkable: ["props", "children", "child", "sibling"]}); + } + + /** + * Finds a value, subobject, or array from a tree that matches a specific filter. + * @param {object} tree Tree that should be walked + * @param {callable} searchFilter Filter to check against each object and subobject + * @param {object} options Additional options to customize the search + * @param {Array|null} [options.walkable=null] Array of strings to use as keys that are allowed to be walked on. Null value indicates all keys are walkable + * @param {Array} [options.ignore=[]] Array of strings to use as keys to exclude from the search, most helpful when `walkable = null`. + */ + static findInTree(tree, searchFilter, {walkable = null, ignore = []} = {}) { + if (typeof searchFilter === "string") { + if (tree.hasOwnProperty(searchFilter)) return tree[searchFilter]; + } + else if (searchFilter(tree)) { + return tree; + } + + if (typeof tree !== "object" || tree == null) return undefined; + + let tempReturn; + if (Array.isArray(tree)) { + for (const value of tree) { + tempReturn = this.findInTree(value, searchFilter, {walkable, ignore}); + if (typeof tempReturn != "undefined") return tempReturn; + } + } + else { + const toWalk = walkable == null ? Object.keys(tree) : walkable; + for (const key of toWalk) { + if (!tree.hasOwnProperty(key) || ignore.includes(key)) continue; + tempReturn = this.findInTree(tree[key], searchFilter, {walkable, ignore}); + if (typeof tempReturn != "undefined") return tempReturn; + } + } + return tempReturn; + } + + /** + * Gets a nested property (if it exists) safely. Path should be something like `prop.prop2.prop3`. + * Numbers can be used for arrays as well like `prop.prop2.array.0.id`. + * @param {Object} obj - object to get nested property of + * @param {string} path - representation of the property to obtain + */ + static getNestedProp(obj, path) { + return path.split(".").reduce(function(ob, prop) { + return ob && ob[prop]; + }, obj); + } + + /** + * Builds a classname string from any number of arguments. This includes arrays and objects. + * When given an array all values from the array are added to the list. + * When given an object they keys are added as the classnames if the value is truthy. + * Copyright (c) 2018 Jed Watson https://github.com/JedWatson/classnames MIT License + * @param {...Any} argument - anything that should be used to add classnames. + */ + static className() { + const classes = []; + const hasOwn = {}.hasOwnProperty; + + for (let i = 0; i < arguments.length; i++) { + const arg = arguments[i]; + if (!arg) continue; + + const argType = typeof arg; + + if (argType === "string" || argType === "number") { + classes.push(arg); + } + else if (Array.isArray(arg) && arg.length) { + const inner = this.classNames.apply(null, arg); + if (inner) { + classes.push(inner); + } + } + else if (argType === "object") { + for (const key in arg) { + if (hasOwn.call(arg, key) && arg[key]) { + classes.push(key); + } + } + } + } + + return classes.join(" "); + } + + /** + * Safely adds to the prototype of an existing object by checking if the + * property exists on the prototype. + * @param {object} object - Object whose prototype to extend + * @param {string} prop - Name of the prototype property to add + * @param {callable} func - Function to run + */ + static addToPrototype(object, prop, func) { + if (!object.prototype) return; + if (object.prototype[prop]) return; + return object.prototype[prop] = func; + } + + /** + * Deep extends an object with a set of other objects. Objects later in the list + * of `extenders` have priority, that is to say if one sets a key to be a primitive, + * it will be overwritten with the next one with the same key. If it is an object, + * and the keys match, the object is extended. This happens recursively. + * @param {object} extendee - Object to be extended + * @param {...object} extenders - Objects to extend with + * @returns {object} - A reference to `extendee` + */ + static extend(extendee, ...extenders) { + for (let i = 0; i < extenders.length; i++) { + for (const key in extenders[i]) { + if (extenders[i].hasOwnProperty(key)) { + if (Array.isArray(extendee[key]) && Array.isArray(extenders[i][key])) this.extend(extendee[key], extenders[i][key]); + else if (typeof extendee[key] === "object" && typeof extenders[i][key] === "object") this.extend(extendee[key], extenders[i][key]); + else if (Array.isArray(extenders[i][key])) extendee[key] = [], this.extend(extendee[key], extenders[i][key]); // eslint-disable-line no-sequences + else if (typeof extenders[i][key] === "object") extendee[key] = {}, this.extend(extendee[key], extenders[i][key]); // eslint-disable-line no-sequences + else extendee[key] = extenders[i][key]; + } + } + } + return extendee; + } + + /* Code below comes from our work on BDv2: + * https://github.com/JsSucks/BetterDiscordApp/blob/master/common/modules/utils.js + */ + + /** + * Clones an object and all it's properties. + * @param {Any} value The value to clone + * @return {Any} The cloned value + */ + static deepclone(value) { + if (typeof value === "object") { + if (Array.isArray(value)) return value.map(i => this.deepclone(i)); + + const clone = Object.assign({}, value); + + for (const key in clone) { + clone[key] = this.deepclone(clone[key]); + } + + return clone; + } + + return value; + } + + /** + * Freezes an object and all it's properties. + * @param {Any} object The object to freeze + * @param {Function} exclude A function to filter object that shouldn't be frozen + */ + static deepfreeze(object, exclude) { + if (exclude && exclude(object)) return; + + if (typeof object === "object" && object !== null) { + const properties = Object.getOwnPropertyNames(object); + + for (const property of properties) { + this.deepfreeze(object[property], exclude); + } + + Object.freeze(object); + } + + return object; + } + + /** + * Removes an item from an array. This differs from Array.prototype.filter as it mutates the original array instead of creating a new one. + * @param {Array} array The array to filter + * @param {Any} item The item to remove from the array + * @return {Array} + */ + static removeFromArray(array, item, filter) { + let index; + while ((index = filter ? array.findIndex(item) : array.indexOf(item)) > -1) array.splice(index, 1); + return array; + } + + /** + * Returns a function, that, as long as it continues to be invoked, will not + * be triggered. The function will be called after it stops being called for + * N milliseconds. + * + * Adapted from the version by David Walsh (https://davidwalsh.name/javascript-debounce-function) + * + * @param {function} executor + * @param {number} delay + */ + static debounce(executor, delay) { + let timeout; + return function(...args) { + const callback = () => { + timeout = null; + Reflect.apply(executor, null, args); + }; + clearTimeout(timeout); + timeout = setTimeout(callback, delay); + }; + } + + /** + * Loads data through BetterDiscord's API. + * @param {string} name - name for the file (usually plugin name) + * @param {string} key - which key the data is saved under + * @param {object} defaultData - default data to populate the object with + * @returns {object} the combined saved and default data + */ + static loadData(name, key, defaultData) { + const defaults = this.deepclone(defaultData); + try {return this.extend(defaults ? defaults : {}, BdApi.getData(name, key));} + catch (err) {_logger__WEBPACK_IMPORTED_MODULE_0__["default"].err(name, "Unable to load data: ", err);} + return defaults; + } + + /** + * Saves data through BetterDiscord's API. + * @param {string} name - name for the file (usually plugin name) + * @param {string} key - which key the data should be saved under + * @param {object} data - data to save + */ + static saveData(name, key, data) { + try {BdApi.setData(name, key, data);} + catch (err) {_logger__WEBPACK_IMPORTED_MODULE_0__["default"].err(name, "Unable to save data: ", err);} + } + + /** + * Loads settings through BetterDiscord's API. + * @param {string} name - name for the file (usually plugin name) + * @param {object} defaultData - default data to populate the object with + * @returns {object} the combined saved and default settings + */ + static loadSettings(name, defaultSettings) { + return this.loadData(name, "settings", defaultSettings); + } + + /** + * Saves settings through BetterDiscord's API. + * @param {string} name - name for the file (usually plugin name) + * @param {object} data - settings to save + */ + static saveSettings(name, data) { + this.saveData(name, "settings", data); + } + +} + +/***/ }), + +/***/ "./src/modules/webpackmodules.js": +/*!***************************************!*\ + !*** ./src/modules/webpackmodules.js ***! + \***************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Filters": () => (/* binding */ Filters), +/* harmony export */ "default": () => (/* binding */ WebpackModules) +/* harmony export */ }); +/* harmony import */ var _discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./discordmodules */ "./src/modules/discordmodules.js"); +/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./logger */ "./src/modules/logger.js"); +/** + * Random set of utilities that didn't fit elsewhere. + * @module WebpackModules + */ + + + + /** + * Checks if a given module matches a set of parameters. + * @callback module:WebpackModules.Filters~filter + * @param {*} module - module to check + * @returns {boolean} - True if the module matches the filter, false otherwise + */ + +/** + * Filters for use with {@link module:WebpackModules} but may prove useful elsewhere. + */ +class Filters { + /** + * Generates a {@link module:WebpackModules.Filters~filter} that filters by a set of properties. + * @param {Array} props - Array of property names + * @param {module:WebpackModules.Filters~filter} filter - Additional filter + * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties + */ + static byProperties(props, filter = m => m) { + return module => { + const component = filter(module); + if (!component) return false; + for (let p = 0; p < props.length; p++) { + if (module[props[p]] === undefined) return false; + } + return true; + }; + } + + /** + * Generates a {@link module:WebpackModules.Filters~filter} that filters by a set of properties on the object's prototype. + * @param {Array} fields - Array of property names + * @param {module:WebpackModules.Filters~filter} filter - Additional filter + * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties on the object's prototype + */ + static byPrototypeFields(fields, filter = m => m) { + return module => { + const component = filter(module); + if (!component) return false; + if (!component.prototype) return false; + for (let f = 0; f < fields.length; f++) { + if (module.prototype[fields[f]] === undefined) return false; + } + return true; + }; + } + + /** + * Generates a {@link module:WebpackModules.Filters~filter} that filters by a regex. + * @param {RegExp} search - A RegExp to check on the module + * @param {module:WebpackModules.Filters~filter} filter - Additional filter + * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties + */ + static byCode(search, filter = m => m) { + return module => { + const method = filter(module); + if (!method) return false; + let methodString = ""; + try {methodString = method.toString([]);} + catch (err) {methodString = method.toString();} + return methodString.search(search) !== -1; + }; + } + + /** + * Generates a {@link module:WebpackModules.Filters~filter} that filters by strings. + * @param {...String} search - A RegExp to check on the module + * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of strings + */ + static byString(...strings) { + return module => { + let moduleString = ""; + try {moduleString = module.toString([]);} + catch (err) {moduleString = module.toString();} + for (const s of strings) { + if (!moduleString.includes(s)) return false; + } + return true; + }; + } + + /** + * Generates a {@link module:WebpackModules.Filters~filter} that filters by a set of properties. + * @param {string} name - Name the module should have + * @param {module:WebpackModules.Filters~filter} filter - Additional filter + * @returns {module:WebpackModules.Filters~filter} - A filter that checks for a set of properties + */ + static byDisplayName(name) { + return module => { + return module && module.displayName === name; + }; + } + + /** + * Generates a combined {@link module:WebpackModules.Filters~filter} from a list of filters. + * @param {...module:WebpackModules.Filters~filter} filters - A list of filters + * @returns {module:WebpackModules.Filters~filter} - Combinatory filter of all arguments + */ + static combine(...filters) { + return module => { + return filters.every(filter => filter(module)); + }; + } +} + +class WebpackModules { + + static find(filter, first = true) {return this.getModule(filter, first);} + static findAll(filter) {return this.getModule(filter, false);} + static findByUniqueProperties(props, first = true) {return first ? this.getByProps(...props) : this.getAllByProps(...props);} + static findByDisplayName(name) {return this.getByDisplayName(name);} + + /** + * Finds a module using a filter function. + * @param {Function} filter A function to use to filter modules + * @param {Boolean} first Whether to return only the first matching module + * @return {Any} + */ + static getModule(filter, first = true) { + const wrappedFilter = (m) => { + try {return filter(m);} + catch (err) {return false;} + }; + const modules = this.getAllModules(); + const rm = []; + for (const index in modules) { + if (!modules.hasOwnProperty(index)) continue; + const module = modules[index]; + const {exports} = module; + let foundModule = null; + + if (!exports) continue; + if (exports.__esModule && exports.default && wrappedFilter(exports.default)) foundModule = exports.default; + if (wrappedFilter(exports)) foundModule = exports; + if (!foundModule) continue; + if (first) return foundModule; + rm.push(foundModule); + } + return first || rm.length == 0 ? undefined : rm; + } + + /** + * Gets the index in the webpack require cache of a specific + * module using a filter. + * @param {Function} filter A function to use to filter modules + * @return {Number|null} + */ + static getIndex(filter) { + const wrappedFilter = (m) => { + try {return filter(m);} + catch (err) {return false;} + }; + const modules = this.getAllModules(); + for (const index in modules) { + if (!modules.hasOwnProperty(index)) continue; + const module = modules[index]; + const exports = module.exports; + let foundModule = null; + + if (!exports) continue; + if (exports.__esModule && exports.default && wrappedFilter(exports.default)) foundModule = exports.default; + if (wrappedFilter(exports)) foundModule = exports; + if (!foundModule) continue; + return index; + } + return null; + } + + /** + * Gets the index in the webpack require cache of a specific + * module that was already found. + * @param {Any} module An already acquired module + * @return {Number|null} + */ + static getIndexByModule(module) { + return this.getIndex(m => m == module); + } + + /** + * Finds all modules matching a filter function. + * @param {Function} filter A function to use to filter modules + */ + static getModules(filter) {return this.getModule(filter, false);} + + /** + * Finds a module by its name. + * @param {String} name The name of the module + * @param {Function} fallback A function to use to filter modules if not finding a known module + * @return {Any} + */ + static getModuleByName(name, fallback) { + if (_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].hasOwnProperty(name)) return _discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"][name]; + if (!fallback) return undefined; + const module = this.getModule(fallback, true); + return module ? _discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"][name] = module : undefined; + } + + /** + * Finds a module by its display name. + * @param {String} name The display name of the module + * @return {Any} + */ + static getByDisplayName(name) { + return this.getModule(Filters.byDisplayName(name), true); + } + + /** + * Finds a module using its code. + * @param {RegEx} regex A regular expression to use to filter modules + * @param {Boolean} first Whether to return the only the first matching module + * @return {Any} + */ + static getByRegex(regex, first = true) { + return this.getModule(Filters.byCode(regex), first); + } + + /** + * Finds a single module using properties on its prototype. + * @param {...string} prototypes Properties to use to filter modules + * @return {Any} + */ + static getByPrototypes(...prototypes) { + return this.getModule(Filters.byPrototypeFields(prototypes), true); + } + + /** + * Finds all modules with a set of properties of its prototype. + * @param {...string} prototypes Properties to use to filter modules + * @return {Any} + */ + static getAllByPrototypes(...prototypes) { + return this.getModule(Filters.byPrototypeFields(prototypes), false); + } + + /** + * Finds a single module using its own properties. + * @param {...string} props Properties to use to filter modules + * @return {Any} + */ + static getByProps(...props) { + return this.getModule(Filters.byProperties(props), true); + } + + /** + * Finds all modules with a set of properties. + * @param {...string} props Properties to use to filter modules + * @return {Any} + */ + static getAllByProps(...props) { + return this.getModule(Filters.byProperties(props), false); + } + + /** + * Finds a single module using a set of strings. + * @param {...String} props Strings to use to filter modules + * @return {Any} + */ + static getByString(...strings) { + return this.getModule(Filters.byString(...strings), true); + } + + /** + * Finds all modules with a set of strings. + * @param {...String} strings Strings to use to filter modules + * @return {Any} + */ + static getAllByString(...strings) { + return this.getModule(Filters.byString(...strings), false); + } + + /** + * Gets a specific module by index of the webpack require cache. + * Best used in combination with getIndex in order to patch a + * specific function. + * + * Note: this gives the **raw** module, meaning the actual module + * is in returnValue.exports. This is done in order to be able + * to patch modules which export a single function directly. + * @param {Number} index Index into the webpack require cache + * @return {Any} + */ + static getByIndex(index) { + return WebpackModules.require.c[index].exports; + } + + /** + * Discord's __webpack_require__ function. + */ + static get require() { + if (this._require) return this._require; + const id = "zl-webpackmodules"; + const __nested_webpack_require_11118__ = window.webpackJsonp.push([[], { + [id]: (module, exports, req) => module.exports = req + }, [[id]]]); + delete __nested_webpack_require_11118__.m[id]; + delete __nested_webpack_require_11118__.c[id]; + return this._require = __nested_webpack_require_11118__; + } + + /** + * Returns all loaded modules. + * @return {Array} + */ + static getAllModules() { + return this.require.c; + } + + + + // Webpack Chunk Observing + static get chunkName() {return "webpackChunkdiscord_app";} + + static initialize() { + this.handlePush = this.handlePush.bind(this); + this.listeners = new Set(); + + this.__ORIGINAL_PUSH__ = window[this.chunkName].push; + Object.defineProperty(window[this.chunkName], "push", { + configurable: true, + get: () => this.handlePush, + set: (newPush) => { + this.__ORIGINAL_PUSH__ = newPush; + + Object.defineProperty(window[this.chunkName], "push", { + value: this.handlePush, + configurable: true, + writable: true + }); + } + }); + } + + /** + * Adds a listener for when discord loaded a chunk. Useful for subscribing to lazy loaded modules. + * @param {Function} listener - Function to subscribe for chunks + * @returns {Function} A cancelling function + */ + static addListener(listener) { + this.listeners.add(listener); + return this.removeListener.bind(this, listener); + } + + /** + * Removes a listener for when discord loaded a chunk. + * @param {Function} listener + * @returns {boolean} + */ + static removeListener(listener) {return this.listeners.delete(listener);} + + static handlePush(chunk) { + const [, modules] = chunk; + + for (const moduleId in modules) { + const originalModule = modules[moduleId]; + + modules[moduleId] = (module, exports, require) => { + try { + Reflect.apply(originalModule, null, [module, exports, require]); + + const listeners = [...this.listeners]; + for (let i = 0; i < listeners.length; i++) { + try {listeners[i](exports, originalModule, moduleId);} + catch (error) { + _logger__WEBPACK_IMPORTED_MODULE_1__["default"].err("WebpackModules", "Could not fire callback listener:", error); + } + } + } + catch (error) { + _logger__WEBPACK_IMPORTED_MODULE_1__["default"].stacktrace("WebpackModules", "Error patching chunked module push", error); + } + }; + + Object.assign(modules[moduleId], originalModule, { + toString: () => originalModule.toString() + }); + } + + return Reflect.apply(this.__ORIGINAL_PUSH__, window[this.chunkName], [chunk]); + } + +} + +WebpackModules.initialize(); + +/***/ }), + +/***/ "./src/plugin.js": +/*!***********************!*\ + !*** ./src/plugin.js ***! + \***********************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((BasePlugin, Library) => { + const {PluginUpdater, Patcher, Logger, Settings, Toasts, DOMTools, ReactComponents, DCM, Popouts} = Library; + const PluginLibrary = class PluginLibrary extends BasePlugin { + get Library() {return Library;} + + load() { + super.load(); + const wasLibLoaded = !!document.getElementById("ZLibraryCSS"); + const isBBDLoading = document.getElementsByClassName("bd-loaderv2").length; + DOMTools.removeStyle("ZLibraryCSS"); + DOMTools.addStyle("ZLibraryCSS", Settings.CSS + Toasts.CSS + PluginUpdater.CSS); + ReactComponents.initialize(); + DCM.initialize(); + Popouts.initialize(); + + /** + * Checking if this is the library first being loaded during init + * This means that subsequent loads will cause dependents to reload + * This also means first load when installing for the first time + * will automatically reload the dependent plugins. This is needed + * for those plugins that prompt to download and install the lib. + */ + + if (!wasLibLoaded && isBBDLoading) return; // If the this is the lib's first load AND this is BD's initialization + + /** + * Now we can go ahead and reload any dependent plugins by checking + * for any with instance._config. Both plugins using buildPlugin() + * and plugin skeletons that prompt for download should have this + * instance property. + */ + + // development vs master + const id = BdApi.version ? ["settings", "general", "showToasts"] : ["fork-ps-2"]; + const wasEnabled = BdApi.isSettingEnabled(...id); + if (wasEnabled) BdApi.disableSetting(...id); + this._reloadPlugins(); + if (wasEnabled) BdApi.enableSetting(...id); + } + + _reloadPlugins() { + const list = BdApi.Plugins.getAll().reduce((acc, val) => { + if (!val.instance || !val.instance._config) return acc; + const name = val.name || val.instance.getName(); + if (name === "ZeresPluginLibrary") return acc; + acc.push(name); + return acc; + }, []); + for (let p = 0; p < list.length; p++) BdApi.Plugins.reload(list[p]); + } + + static buildPlugin(config) { + const name = config.info.name; + const BoundAPI = { + Logger: { + stacktrace: (message, error) => Logger.stacktrace(name, message, error), + log: (...message) => Logger.log(name, ...message), + error: (...message) => Logger.err(name, ...message), + err: (...message) => Logger.err(name, ...message), + warn: (...message) => Logger.warn(name, ...message), + info: (...message) => Logger.info(name, ...message), + debug: (...message) => Logger.debug(name, ...message) + }, + Patcher: { + getPatchesByCaller: () => {return Patcher.getPatchesByCaller(name);}, + unpatchAll: () => {return Patcher.unpatchAll(name);}, + before: (moduleToPatch, functionName, callback, options = {}) => {return Patcher.before(name, moduleToPatch, functionName, callback, options);}, + instead: (moduleToPatch, functionName, callback, options = {}) => {return Patcher.instead(name, moduleToPatch, functionName, callback, options);}, + after: (moduleToPatch, functionName, callback, options = {}) => {return Patcher.after(name, moduleToPatch, functionName, callback, options);} + } + }; + const BoundLib = Object.assign({}, Library); + BoundLib.Logger = BoundAPI.Logger; + BoundLib.Patcher = BoundAPI.Patcher; + return [Library.Structs.Plugin(config), BoundLib]; // eslint-disable-line new-cap + } + }; + + Object.assign(PluginLibrary, Library); + Library.buildPlugin = PluginLibrary.buildPlugin; + window.ZLibrary = Library; + window.ZLibraryPromise = new Promise(r => setImmediate(r)); + window.ZeresPluginLibrary = PluginLibrary; + return PluginLibrary; +}); + +/***/ }), + +/***/ "./src/structs/dom/classname.js": +/*!**************************************!*\ + !*** ./src/structs/dom/classname.js ***! + \**************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _selector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./selector */ "./src/structs/dom/selector.js"); + + +/** + * Representation of a Class Name + * @memberof module:DOMTools + **/ +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; + } + + /** + * Returns the classname represented as {@link module:DOMTools.Selector}. + * @returns {Selector} selector representation of this class name. + */ + get selector() { + return new _selector__WEBPACK_IMPORTED_MODULE_0__["default"](this.value); + } + + get single() { + return this.value.split(" ")[0]; + } + + get first() { + return this.value.split(" ")[0]; + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ClassName); + +/***/ }), + +/***/ "./src/structs/dom/observer.js": +/*!*************************************!*\ + !*** ./src/structs/dom/observer.js ***! + \*************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/** + * BetterDiscord Client DOM Module + * Copyright (c) 2015-present JsSucks - https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + + + +/* eslint-disable operator-linebreak */ + +/** + * Representation of a MutationObserver but with helpful utilities. + * @memberof module:DOMTools + **/ +class DOMObserver { + constructor(root, options) { + this.observe = this.observe.bind(this); + this.subscribe = this.subscribe.bind(this); + this.observerCallback = this.observerCallback.bind(this); + + this.active = false; + this.root = root || document.getElementById("app-mount"); + this.options = options || {attributes: true, childList: true, subtree: true}; + + this.observer = new MutationObserver(this.observerCallback); + this.observe(); + } + + observerCallback(mutations) { + for (const sub of Array.from(this.subscriptions)) { + try { + const filteredMutations = sub.filter ? mutations.filter(sub.filter) : mutations; + + if (sub.group) { + if (!filteredMutations.length) continue; + sub.callback.call(sub.bind || sub, filteredMutations); + } + else { + for (const mutation of filteredMutations) sub.callback.call(sub.bind || sub, mutation); + } + } + catch (err) { + modules__WEBPACK_IMPORTED_MODULE_0__.Logger.stacktrace("DOMObserver", "Error in observer callback", err); + } + } + } + + /** + * Starts observing the element. This will be called when attaching a callback. + * You don't need to call this manually. + */ + observe() { + if (this.active) return; + this.observer.observe(this.root, this.options); + this.active = true; + } + + /** + * Disconnects this observer. This stops callbacks being called, but does not unbind them. + * You probably want to use observer.unsubscribeAll instead. + */ + disconnect() { + if (!this.active) return; + this.observer.disconnect(); + this.active = false; + } + + reconnect() { + if (this.active) { + this.disconnect(); + this.observe(); + } + } + + get root() {return this._root;} + set root(root) {this._root = root; this.reconnect();} + + get options() {return this._options;} + set options(options) {this._options = options; this.reconnect();} + + get subscriptions() { + return this._subscriptions || (this._subscriptions = []); + } + + /** + * Subscribes to mutations. + * @param {Function} callback A function to call when on a mutation + * @param {Function} filter A function to call to filter mutations + * @param {Any} bind Something to bind the callback to + * @param {Boolean} group Whether to call the callback with an array of mutations instead of a single mutation + * @return {Object} + */ + subscribe(callback, filter, bind, group) { + const subscription = {callback, filter, bind, group}; + this.subscriptions.push(subscription); + this.observe(); + return subscription; + } + + /** + * Removes a subscription and disconnect if there are none left. + * @param {Object} subscription A subscription object returned by observer.subscribe + */ + unsubscribe(subscription) { + if (!this.subscriptions.includes(subscription)) subscription = this.subscriptions.find(s => s.callback === subscription); + modules__WEBPACK_IMPORTED_MODULE_0__.Utilities.removeFromArray(this.subscriptions, subscription); + if (!this.subscriptions.length) this.disconnect(); + } + + unsubscribeAll() { + this.subscriptions.splice(0, this.subscriptions.length); + this.disconnect(); + } + + /** + * Subscribes to mutations that affect an element matching a selector. + * @param {Function} callback A function to call when on a mutation + * @param {Function} filter A function to call to filter mutations + * @param {Any} bind Something to bind the callback to + * @param {Boolean} group Whether to call the callback with an array of mutations instead of a single mutation + * @return {Object} + */ + subscribeToQuerySelector(callback, selector, bind, group) { + return this.subscribe(callback, mutation => { + return mutation.target.matches(selector) // If the target matches the selector + || Array.from(mutation.addedNodes).concat(Array.from(mutation.removedNodes)) // Or if either an added or removed node + .find(n => n instanceof Element && (n.matches(selector) || n.querySelector(selector))); // match or contain an element matching the selector + }, bind, group); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (DOMObserver); + +/***/ }), + +/***/ "./src/structs/dom/selector.js": +/*!*************************************!*\ + !*** ./src/structs/dom/selector.js ***! + \*************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/** + * Representation of a Selector + * @memberof module:DOMTools + **/ +class Selector { + /** + * + * @param {string} classname - class to create selector for + */ + constructor(className) { + this.value = " ." + className.split(" ").join("."); + } + + /** + * Returns the raw selector, this is how native function get the value. + * @returns {string} raw selector. + */ + toString() { + return this.value; + } + + /** + * Returns the raw selector, this is how native function get the value. + * @returns {string} raw selector. + */ + valueOf() { + return this.value; + } + + selector(symbol, other) { + this.value = `${this.toString()} ${symbol} ${other.toString()}`; + return this; + } + + /** + * Adds another selector as a direct child `>` to this one. + * @param {string|DOMTools.Selector} other - Selector to add as child + * @returns {DOMTools.Selector} returns self to allow chaining + */ + child(other) { + return this.selector(">", other); + } + + /** + * Adds another selector as a adjacent sibling `+` to this one. + * @param {string|DOMTools.Selector} other - Selector to add as adjacent sibling + * @returns {DOMTools.Selector} returns self to allow chaining + */ + adjacent(other) { + return this.selector("+", other); + } + + /** + * Adds another selector as a general sibling `~` to this one. + * @param {string|DOMTools.Selector} other - Selector to add as sibling + * @returns {DOMTools.Selector} returns self to allow chaining + */ + sibling(other) { + return this.selector("~", other); + } + + /** + * Adds another selector as a descendent `(space)` to this one. + * @param {string|DOMTools.Selector} other - Selector to add as descendent + * @returns {DOMTools.Selector} returns self to allow chaining + */ + descend(other) { + return this.selector(" ", other); + } + + /** + * Adds another selector to this one via `,`. + * @param {string|DOMTools.Selector} other - Selector to add + * @returns {DOMTools.Selector} returns self to allow chaining + */ + and(other) { + return this.selector(",", other); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Selector); + +/***/ }), + +/***/ "./src/structs/listenable.js": +/*!***********************************!*\ + !*** ./src/structs/listenable.js ***! + \***********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/** + * Acts as an interface for anything that should be listenable. + */ +class Listenable { + + constructor() { + this.listeners = []; + } + + /** + * Adds a listener to the current object. + * @param {callable} callback - callback for when the event occurs + * @returns {callable} - a way to cancel the listener without needing to call `removeListener` + */ + addListener(callback) { + if (typeof(callback) !== "function") return; + this.listeners.push(callback); + return () => { + this.listeners.splice(this.listeners.indexOf(callback), 1); + }; + } + + /** + * Removes a listener from the current object. + * @param {callable} callback - callback that was originally registered + */ + removeListener(callback) { + if (typeof(callback) !== "function") return; + this.listeners.splice(this.listeners.indexOf(callback), 1); + } + + /** + * Alerts the listeners that an event occurred. Data passed is optional + * @param {*} [...data] - Any data desired to be passed to listeners + */ + alertListeners(...data) { + for (let l = 0; l < this.listeners.length; l++) this.listeners[l](...data); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Listenable); + +/***/ }), + +/***/ "./src/structs/plugin.js": +/*!*******************************!*\ + !*** ./src/structs/plugin.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _modules_pluginupdater__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/pluginupdater */ "./src/modules/pluginupdater.js"); +/* harmony import */ var _modules_logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/logger */ "./src/modules/logger.js"); +/* harmony import */ var _modules_reacttools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/reacttools */ "./src/modules/reacttools.js"); +/* harmony import */ var _ui_modals__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../ui/modals */ "./src/ui/modals.js"); +/* harmony import */ var _modules_utilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/utilities */ "./src/modules/utilities.js"); +/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../modules/discordmodules */ "./src/modules/discordmodules.js"); +/* harmony import */ var _ui_settings__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../ui/settings */ "./src/ui/settings/index.js"); + + + + + + + + +/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__(meta) { + return class Plugin { + constructor() { + this._config = meta; + this._enabled = false; + if (typeof(meta.defaultConfig) != "undefined") { + this.defaultSettings = {}; + for (let s = 0; s < meta.defaultConfig.length; s++) { + const current = meta.defaultConfig[s]; + if (current.type != "category") {this.defaultSettings[current.id] = current.value;} + else { + this.defaultSettings[current.id] = {}; + for (let si = 0; si < current.settings.length; si++) { + const subCurrent = current.settings[si]; + this.defaultSettings[current.id][subCurrent.id] = subCurrent.value; + } + } + } + this._hasConfig = true; + this.settings = _modules_utilities__WEBPACK_IMPORTED_MODULE_4__["default"].deepclone(this.defaultSettings); + } + } + getName() {return this._config.info.name.replace(" ", "");} + getDescription() {return this._config.info.description;} + getVersion() {return this._config.info.version;} + getAuthor() {return this._config.info.authors.map(a => a.name).join(", ");} + load() { + const currentVersionInfo = _modules_utilities__WEBPACK_IMPORTED_MODULE_4__["default"].loadData(this.getName(), "currentVersionInfo", {version: this.getVersion(), hasShownChangelog: false}); + if (currentVersionInfo.version != this.getVersion() || !currentVersionInfo.hasShownChangelog) { + this.showChangelog(); + _modules_utilities__WEBPACK_IMPORTED_MODULE_4__["default"].saveData(this.getName(), "currentVersionInfo", {version: this.getVersion(), hasShownChangelog: true}); + } + _modules_pluginupdater__WEBPACK_IMPORTED_MODULE_0__["default"].checkForUpdate(this.getName(), this.getVersion(), this._config.info.github_raw); + } + async start() { + _modules_logger__WEBPACK_IMPORTED_MODULE_1__["default"].info(this.getName(), `version ${this.getVersion()} has started.`); + if (this.defaultSettings) this.settings = this.loadSettings(); + this._enabled = true; + if (typeof(this.onStart) == "function") this.onStart(); + } + stop() { + _modules_logger__WEBPACK_IMPORTED_MODULE_1__["default"].info(this.getName(), `version ${this.getVersion()} has stopped.`); + this._enabled = false; + if (typeof(this.onStop) == "function") this.onStop(); + } + + get isEnabled() {return this._enabled;} + get strings() { + if (!this._config.strings) return {}; + const locale = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_5__["default"].UserSettingsStore.locale.split("-")[0]; + if (this._config.strings.hasOwnProperty(locale)) return this._config.strings[locale]; + if (this._config.strings.hasOwnProperty("en")) return this._config.strings.en; + return this._config.strings; + } + + set strings(strings) { + this._config.strings = strings; + } + + showSettingsModal() { + if (typeof(this.getSettingsPanel) != "function") return; + _ui_modals__WEBPACK_IMPORTED_MODULE_3__["default"].showModal(this.getName() + " Settings", _modules_reacttools__WEBPACK_IMPORTED_MODULE_2__["default"].createWrappedElement(this.getSettingsPanel()), { + cancelText: "", + confirmText: "Done", + size: _ui_modals__WEBPACK_IMPORTED_MODULE_3__["default"].ModalSizes.MEDIUM + }); + } + + showChangelog(footer) { + if (typeof(this._config.changelog) == "undefined") return; + _ui_modals__WEBPACK_IMPORTED_MODULE_3__["default"].showChangelogModal(this.getName() + " Changelog", this.getVersion(), this._config.changelog, footer); + } + + saveSettings(settings) { + _modules_utilities__WEBPACK_IMPORTED_MODULE_4__["default"].saveSettings(this.getName(), this.settings ? this.settings : settings); + } + + loadSettings(defaultSettings) { + // loadSettings -> loadData -> defaultSettings gets deep cloned + return _modules_utilities__WEBPACK_IMPORTED_MODULE_4__["default"].loadSettings(this.getName(), this.defaultSettings ? this.defaultSettings : defaultSettings); + } + + buildSetting(data) { + const {name, note, type, value, onChange, id} = data; + let setting = null; + if (type == "color") setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.ColorPicker(name, note, value, onChange, {disabled: data.disabled, presetColors: data.presetColors}); + else if (type == "dropdown") setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.Dropdown(name, note, value, data.options, onChange); + else if (type == "file") setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.FilePicker(name, note, onChange); + else if (type == "keybind") setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.Keybind(name, note, value, onChange); + else if (type == "radio") setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.RadioGroup(name, note, value, data.options, onChange, {disabled: data.disabled}); + else if (type == "slider") setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.Slider(name, note, data.min, data.max, value, onChange, data); + else if (type == "switch") setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.Switch(name, note, value, onChange, {disabled: data.disabled}); + else if (type == "textbox") setting = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.Textbox(name, note, value, onChange, {placeholder: data.placeholder || ""}); + if (id) setting.id = id; + return setting; + } + + buildSettingsPanel() { + const config = this._config.defaultConfig; + const buildGroup = (group) => { + const {name, id, collapsible, shown, settings} = group; + // this.settings[id] = {}; + + const list = []; + for (let s = 0; s < settings.length; s++) { + const current = Object.assign({}, settings[s]); + current.value = this.settings[id][current.id]; + current.onChange = (value) => { + this.settings[id][current.id] = value; + }; + if (Object.keys(this.strings).length && this.strings.settings && this.strings.settings[id] && this.strings.settings[id][current.id]) { + const {settingName = name, note} = this.strings.settings[id][current.id]; + current.name = settingName; + current.note = note; + } + list.push(this.buildSetting(current)); + } + + const settingGroup = new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.SettingGroup(name, {shown, collapsible}).append(...list); + settingGroup.id = id; + return settingGroup; + }; + const list = []; + for (let s = 0; s < config.length; s++) { + const current = Object.assign({}, config[s]); + if (current.type != "category") { + current.value = this.settings[current.id]; + current.onChange = (value) => { + this.settings[current.id] = value; + }; + if (Object.keys(this.strings).length && this.strings.settings && this.strings.settings[current.id]) { + const {name, note} = this.strings.settings[current.id]; + current.name = name; + current.note = note; + } + list.push(this.buildSetting(current)); + } + else { + list.push(buildGroup(current)); + } + } + + return new _ui_settings__WEBPACK_IMPORTED_MODULE_6__.SettingPanel(this.saveSettings.bind(this), ...list); + } + }; +} + +/***/ }), + +/***/ "./src/structs/screen.js": +/*!*******************************!*\ + !*** ./src/structs/screen.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/** + * Representation of the screen such as width and height. + * @deprecated 1/21/22 Use DOMTools + */ +class Screen { + /** Document/window width */ + static get width() {return Math.max(document.documentElement.clientWidth, window.innerWidth || 0);} + /** Document/window height */ + static get height() {return Math.max(document.documentElement.clientHeight, window.innerHeight || 0);} +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Screen); + +/***/ }), + +/***/ "./src/structs/structs.js": +/*!********************************!*\ + !*** ./src/structs/structs.js ***! + \********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Screen": () => (/* reexport safe */ _screen__WEBPACK_IMPORTED_MODULE_0__["default"]), +/* harmony export */ "Selector": () => (/* reexport safe */ _dom_selector__WEBPACK_IMPORTED_MODULE_1__["default"]), +/* harmony export */ "ClassName": () => (/* reexport safe */ _dom_classname__WEBPACK_IMPORTED_MODULE_2__["default"]), +/* harmony export */ "DOMObserver": () => (/* reexport safe */ _dom_observer__WEBPACK_IMPORTED_MODULE_3__["default"]), +/* harmony export */ "Listenable": () => (/* reexport safe */ _listenable__WEBPACK_IMPORTED_MODULE_4__["default"]), +/* harmony export */ "Plugin": () => (/* reexport safe */ _plugin__WEBPACK_IMPORTED_MODULE_5__["default"]) +/* harmony export */ }); +/* harmony import */ var _screen__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./screen */ "./src/structs/screen.js"); +/* harmony import */ var _dom_selector__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./dom/selector */ "./src/structs/dom/selector.js"); +/* harmony import */ var _dom_classname__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./dom/classname */ "./src/structs/dom/classname.js"); +/* harmony import */ var _dom_observer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./dom/observer */ "./src/structs/dom/observer.js"); +/* harmony import */ var _listenable__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./listenable */ "./src/structs/listenable.js"); +/* harmony import */ var _plugin__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./plugin */ "./src/structs/plugin.js"); + + + + + + + + +/***/ }), + +/***/ "./src/ui/colorpicker.js": +/*!*******************************!*\ + !*** ./src/ui/colorpicker.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ ColorPicker) +/* harmony export */ }); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + +const React = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.React; + +const Popout = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByDisplayName("Popout"); +const ColorPickerComponents = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("CustomColorPicker"); +const Swatch = ColorPickerComponents?.CustomColorButton.prototype.render.call({props: {}}).type; +const {default: Tooltip, TooltipPositions} = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("TooltipContainer"); +const LocaleManager = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.LocaleManager; + +class ColorPicker extends React.Component { + constructor(props) { + super(props); + + this.state = { + value: props.value || 0 + }; + + this.onChange = this.onChange.bind(this); + this.swatchRef = React.createRef(); + } + + get canCustom() {return this.props.acceptsCustom || true;} + + onChange(value) { + this.setState({value: value}, () => { + if (typeof(this.props.onChange) === "function") this.props.onChange(this.state.value); + }); + } + + render() { + const renderPopout = () => { + return React.createElement(ColorPickerComponents.CustomColorPicker, { + value: this.state.value, + onChange: this.onChange, + }); + }; + + return React.createElement(ColorPickerComponents.default, { + value: this.state.value, + onChange: this.onChange, + colors: this.props.colors, + renderDefaultButton: props => React.createElement(Tooltip, { + position: TooltipPositions.BOTTOM, + text: LocaleManager.Messages.DEFAULT + }, tooltipProps => React.createElement("div", Object.assign(tooltipProps, { + className: "defaultButtonWrapper", + }), React.createElement(ColorPickerComponents.DefaultColorButton, Object.assign(props, {color: this.props.defaultColor})))), + renderCustomButton: () => React.createElement(Popout, { + renderPopout: renderPopout, + animation: Popout.Animation.TRANSLATE, + align: Popout.Align.CENTER, + position: Popout.Positions.BOTTOM + }, props => React.createElement(Tooltip, { + position: TooltipPositions.BOTTOM, + text: LocaleManager.Messages.PICK_A_COLOR + }, tooltipProps => React.createElement("div", Object.assign({}, tooltipProps, props, { + className: "colorPickerButtonWrapper" + }), React.createElement(Swatch, { + isCustom: true, + color: this.state.value, + isSelected: !this.props.colors.includes(this.state.value) && this.props.defaultColor !== this.state.value, + disabled: !this.canCustom + })))) + }); + } +} + +/***/ }), + +/***/ "./src/ui/discordcontextmenu.js": +/*!**************************************!*\ + !*** ./src/ui/discordcontextmenu.js ***! + \**************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ DiscordContextMenu) +/* harmony export */ }); +/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/discordmodules */ "./src/modules/discordmodules.js"); +/* harmony import */ var _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../modules/webpackmodules */ "./src/modules/webpackmodules.js"); +/* harmony import */ var _modules_reacttools__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../modules/reacttools */ "./src/modules/reacttools.js"); +/* harmony import */ var _modules_patcher__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../modules/patcher */ "./src/modules/patcher.js"); +/* harmony import */ var _modules_utilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../modules/utilities */ "./src/modules/utilities.js"); +/* harmony import */ var _modules_discordclasses__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../modules/discordclasses */ "./src/modules/discordclasses.js"); +/* harmony import */ var _modules_domtools__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../modules/domtools */ "./src/modules/domtools.js"); + + + + + + + + +// d = e.label, +// f = e.icon, +// h = e.imageUrl, +// v = e.hint, +// m = e.subtext, +// g = e.hasSubmenu, +// y = e.disabled, +// E = e.isFocused, +// S = e.menuItemProps, +// T = e.action, +// b = e.onClose, + + +const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React; +const ContextMenuActions = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].ContextMenuActions; + +const ce = React.createElement; +const ContextMenu = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getByProps("MenuRadioItem", "MenuItem"); + +/** + * Fires when the item is clicked. + * @param {MouseEvent} event - The event generated on click + * @callback module:DiscordContextMenu~MenuItemOnClick + */ + +/** + * @interface + * @name module:DiscordContextMenu~MenuItem + * @description + * This is the generic context menu item component. It is very extensible and will adapt + * it's type depending on the props. + * + * Note: The item ID should be unique to this item across the entire menu. If no `id` is + * provided, the system will use the `label`. Plugins should ensure there are no `label` + * conflicts if they do not wish to provide `id`. `label` conflicts (when not using + * unique `id`s) can cause multiple items to be hovered at once. + * + * @param {object} props - props to pass to the react renderer + * @param {string} props.label - label to show on the menu item + * @param {string} [props.id] - specific id used for this item + * @param {string} [props.hint] - hint to show on the right hand side (usually keyboard combo) + * @param {string} [props.subtext] - description to show underneath + * @param {string} [props.image] - link to image to show on the side + * @param {function} [props.icon] - react component to render on the side + * @param {function} [props.render] - render function for custom rendering the menu item + * @param {module:DiscordContextMenu~MenuItemOnClick} [props.action] - function to perform on click + * @param {module:DiscordContextMenu~MenuItemOnClick} [props.onClick] - function to perform on click (alias of `action`) + * @param {function} [props.onClose] - function to run when this is closed + * @param {boolean} [props.danger=false] - should the item show as danger (red) + * @param {boolean} [props.disabled=false] - should the item be disabled/unclickable + * + * @param {object} [props.style] - allows you to add custom styles + * @param {boolean} [props.closeOnClick] - allows you to prevent closing on click + */ + +/** + * @interface + * @name module:DiscordContextMenu~MenuToggleItem + * @extends module:DiscordContextMenu~MenuItem + * @description + * This item is used for creating checkboxes in menus. Properties shown here are additional + * to those of the main MenuItem {@link module:DiscordContextMenu~MenuItem} + * + * + * @param {boolean} [props.checked=false] - should the checkbox be checked + * @param {boolean} [props.active=false] - alias of `checked` + */ + +/** + * @interface + * @name module:DiscordContextMenu~MenuRadioItem + * @extends module:DiscordContextMenu~MenuItem + * @description + * This item is used for creating radio selections in menus. Properties shown here are additional + * to those of the main MenuItem {@link module:DiscordContextMenu~MenuItem} + * + * Note: for the `forceUpdate` option... Without this enabled, you will manually need to + * manage the state for the functional component. If you do not the toggle will appear + * to not update. @see {@link https://reactjs.org/docs/hooks-reference.html#usestate} + * + * @param {boolean} [props.checked=false] - should the checkbox be checked + * @param {boolean} [props.active=false] - alias of `checked` + * @param {boolean} [props.forceUpdate=true] - should the menu be force-updated after click + */ + +/** + * @interface + * @name module:DiscordContextMenu~SubMenuItem + * @extends module:DiscordContextMenu~MenuItem + * @description + * This item is used for creating nested submenus. Properties shown here are additional + * to those of the main MenuItem {@link module:DiscordContextMenu~MenuItem} + * + * @param {Array} [props.render] - array of items to render in the submenu + * @param {Array} [props.items] - alias of `render` + * @param {Array} [props.children] - Already rendered elements + */ + +/** + * @interface + * @name module:DiscordContextMenu~MenuControlItem + * @extends module:DiscordContextMenu~MenuItem + * @description + * This item is used for adding custom controls like sliders to the context menu. + * Properties shown here are additional to those of the main MenuItem {@link module:DiscordContextMenu~MenuItem} + * + * @param {function} [props.control] - control function that renders the component + */ + + +/** + * A utility for building and rendering Discord's own menus. + * @module DiscordContextMenu + */ +class DiscordContextMenu { + + /** + * Builds a single menu item. The only prop shown here is the type, the rest should + * match the actual component being built. View those to see what options exist + * for each, they often have less in common than you might think. See {@link module:DiscordContextMenu.MenuItem} + * for the majority of props commonly available. Check the documentation for the + * rest of the components. + * + * @param {object} props - props used to build the item + * @param {string} [props.type="text"] - type of the item, options: text, submenu, toggle, radio, custom, separator + * @returns {object} the created component + * + * @see {@link module:DiscordContextMenu~MenuItem} + * @see {@link module:DiscordContextMenu~MenuToggleItem} + * @see {@link module:DiscordContextMenu~MenuRadioItem} + * @see {@link module:DiscordContextMenu~SubMenuItem} + * @see {@link module:DiscordContextMenu~MenuControlItem} + * + * @example + * // Creates a single menu item that prints "MENU ITEM" on click + * DiscordContextMenu.buildMenuItem({ + * label: "Menu Item", + * action: () => {console.log("MENU ITEM");} + * }); + * + * @example + * // Creates a single toggle item that starts unchecked + * // and print the new value on every toggle + * DiscordContextMenu.buildMenuItem({ + * type: "toggle", + * label: "Item Toggle", + * checked: false, + * action: (newValue) => {console.log(newValue);} + * }); + */ + static buildMenuItem(props) { + const {type} = props; + if (type === "separator") return ce(ContextMenu.MenuSeparator); + + let Component = ContextMenu.MenuItem; + if (type === "submenu") { + if (!props.children) props.children = this.buildMenuChildren(props.render || props.items); + } + else if (type === "toggle" || type === "radio") { + Component = type === "toggle" ? ContextMenu.MenuCheckboxItem : ContextMenu.MenuRadioItem; + if (props.active) props.checked = props.active; + } + else if (type === "control") { + Component = ContextMenu.MenuControlItem; + } + if (!props.id) props.id = `${_modules_domtools__WEBPACK_IMPORTED_MODULE_6__["default"].escapeID(props.label)}`; + if (props.danger) props.color = "colorDanger"; + if (props.onClick && !props.action) props.action = props.onClick; + props.extended = true; + return ce(Component, props); + } + + /** + * Creates the all the items **and groups** of a context menu recursively. + * There is no hard limit to the number of groups within groups or number + * of items in a menu. + * @param {Array} setup - array of item props used to build items. See {@link module:DiscordContextMenu.buildMenuItem} + * @returns {Array} array of the created component + * + * @example + * // Creates a single item group item with a toggle item + * DiscordContextMenu.buildMenuChildren([{ + * type: "group", + * items: [{ + * type: "toggle", + * label: "Item Toggle", + * active: false, + * action: (newValue) => {console.log(newValue);} + * }] + * }]); + * + * @example + * // Creates two item groups with a single toggle item each + * DiscordContextMenu.buildMenuChildren([{ + * type: "group", + * items: [{ + * type: "toggle", + * label: "Item Toggle", + * active: false, + * action: (newValue) => { + * console.log(newValue); + * } + * }] + * }, { + * type: "group", + * items: [{ + * type: "toggle", + * label: "Item Toggle", + * active: false, + * action: (newValue) => { + * console.log(newValue); + * } + * }] + * }]); + */ + static buildMenuChildren(setup) { + const mapper = s => { + if (s.type === "group") return buildGroup(s); + return this.buildMenuItem(s); + }; + const buildGroup = function(group) { + const items = group.items.map(mapper).filter(i => i); + return ce(ContextMenu.MenuGroup, null, items); + }; + return setup.map(mapper).filter(i => i); + } + + /** + * Creates the menu *component* including the wrapping `ContextMenu`. + * Calls {@link module:DiscordContextMenu.buildMenuChildren} under the covers. + * Used to call in combination with {@link module:DiscordContextMenu.openContextMenu}. + * @param {Array} setup - array of item props used to build items. See {@link module:DiscordContextMenu.buildMenuChildren} + * @returns {function} the unique context menu component + */ + static buildMenu(setup) { + return (props) => {return ce(ContextMenu.default, props, this.buildMenuChildren(setup));}; + } + + /** + * + * @param {MouseEvent} event - The context menu event. This can be emulated, requires target, and all X, Y locations. + * @param {function} menuComponent - Component to render. This can be any react component or output of {@link module:DiscordContextMenu.buildMenu} + * @param {object} config - configuration/props for the context menu + * @param {string} [config.position="right"] - default position for the menu, options: "left", "right" + * @param {string} [config.align="top"] - default alignment for the menu, options: "bottom", "top" + * @param {function} [config.onClose] - function to run when the menu is closed + * @param {boolean} [config.noBlurEvent=false] - No clue + */ + static openContextMenu(event, menuComponent, config) { + return ContextMenuActions.openContextMenu(event, function(e) { + return ce(menuComponent, Object.assign({}, e, {onClose: ContextMenuActions.closeContextMenu})); + }, config); + } + + /** + * Attempts to find and return a specific context menu type's module. Useful + * when patching the render of these menus. + * @param {string | Function} nameOrFilter - name of the context menu type + * @returns {Promise} the webpack module the menu was found in + */ + static getDiscordMenu(nameOrFilter) { + if (typeof(nameOrFilter) !== "function") { + const displayName = nameOrFilter; + nameOrFilter = (m) => m && m.displayName === displayName; + } + + const directMatch = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.default && nameOrFilter(m.default)); + if (directMatch) return Promise.resolve(directMatch); + + return new Promise(resolve => { + const cancel = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].addListener(module => { + if (!module.default || !nameOrFilter(module.default)) return; + resolve(module); + cancel(); + }); + }); + } + + /** + * Calls `forceUpdate()` on all context menus it can find. Useful for + * after patching a menu. + */ + static forceUpdateMenus() { + const menus = document.querySelectorAll(`.${_modules_discordclasses__WEBPACK_IMPORTED_MODULE_5__["default"].ContextMenu.menu.first}`); + for (const menu of menus) { + const stateNode = _modules_utilities__WEBPACK_IMPORTED_MODULE_4__["default"].findInTree(_modules_reacttools__WEBPACK_IMPORTED_MODULE_2__["default"].getReactInstance(menu), m=>m && m.forceUpdate && m.updatePosition, {walkable: ["return", "stateNode"]}); + if (!stateNode) continue; + stateNode.forceUpdate(); + stateNode.updatePosition(); + } + } + + static initialize() { + _modules_patcher__WEBPACK_IMPORTED_MODULE_3__["default"].unpatchAll("DCM"); + this.patchMenuItem(); + this.patchToggleItem(); + } + + static patchMenuItem() { + const MenuItem = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.default && m.default.displayName == "MenuItem"); + if (!MenuItem || !MenuItem.default) return; + _modules_patcher__WEBPACK_IMPORTED_MODULE_3__["default"].after("DCM", MenuItem, "default", (_, args, ret) => { + if (!args || !args[0] || !args[0].extended) return; + const [props] = args; + if (props.style) ret.props.style = props.style; + if (props.closeOnClick !== false || !props.action) return; + ret.props.onClick = function(e) { + e.preventDefault(); + e.stopPropagation(); + return props.action(...arguments); + }; + }); + } + + static patchToggleItem() { + const MenuToggleItem = _modules_webpackmodules__WEBPACK_IMPORTED_MODULE_1__["default"].getModule(m => m.default && m.default.displayName == "MenuCheckboxItem"); + if (!MenuToggleItem || !MenuToggleItem.default) return; + _modules_patcher__WEBPACK_IMPORTED_MODULE_3__["default"].before("DCM", MenuToggleItem, "default", (_, args) => { + if (!args || !args[0] || !args[0].extended) return; + const [props] = args; + const [active, doToggle] = React.useState(props.checked || false); + props.checked = active; + const originalAction = props.action; + props.action = function(ev) { + originalAction(ev); + doToggle(!active); + }; + }); + } +} + +/***/ }), + +/***/ "./src/ui/errorboundary.js": +/*!*********************************!*\ + !*** ./src/ui/errorboundary.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ ErrorBoundary), +/* harmony export */ "WrapBoundary": () => (/* binding */ WrapBoundary) +/* harmony export */ }); +/* harmony import */ var _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../modules/discordmodules */ "./src/modules/discordmodules.js"); + + +const React = _modules_discordmodules__WEBPACK_IMPORTED_MODULE_0__["default"].React; +const ce = React.createElement; + +class ErrorBoundary extends React.Component { + constructor(props) { + super(props); + this.state = {hasError: false}; + } + + componentDidCatch() { + this.setState({hasError: true}); + } + + render() { + if (this.state.hasError) return this.props.errorChildren ? this.props.errorChildren : ce("div", {className: "error"}, "Component Error"); + return this.props.children; + } +} + +function WrapBoundary(Original) { + return class ErrorBoundaryWrapper extends React.Component { + render() { + return ce(ErrorBoundary, null, ce(Original, this.props)); + } + }; +} + +/***/ }), + +/***/ "./src/ui/icons.js": +/*!*************************!*\ + !*** ./src/ui/icons.js ***! + \*************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "IconError": () => (/* reexport safe */ _icons_error__WEBPACK_IMPORTED_MODULE_0__["default"]), +/* harmony export */ "IconInfo": () => (/* reexport safe */ _icons_info__WEBPACK_IMPORTED_MODULE_1__["default"]), +/* harmony export */ "IconSuccess": () => (/* reexport safe */ _icons_success__WEBPACK_IMPORTED_MODULE_2__["default"]), +/* harmony export */ "IconWarning": () => (/* reexport safe */ _icons_warning__WEBPACK_IMPORTED_MODULE_3__["default"]) +/* harmony export */ }); +/* harmony import */ var _icons_error__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./icons/error */ "./src/ui/icons/error.js"); +/* harmony import */ var _icons_info__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./icons/info */ "./src/ui/icons/info.js"); +/* harmony import */ var _icons_success__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./icons/success */ "./src/ui/icons/success.js"); +/* harmony import */ var _icons_warning__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./icons/warning */ "./src/ui/icons/warning.js"); + + + + + +/***/ }), + +/***/ "./src/ui/icons/error.js": +/*!*******************************!*\ + !*** ./src/ui/icons/error.js ***! + \*******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/** + * Error Icon + * @param {number} size - Size of the icon. + */ +/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__(size) { + return ` + + `; +} + +/***/ }), + +/***/ "./src/ui/icons/info.js": +/*!******************************!*\ + !*** ./src/ui/icons/info.js ***! + \******************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/** + * Info Icon + * @param {number} size - Size of the icon. + */ +/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__(size) { + return ` + + + `; +} + +/***/ }), + +/***/ "./src/ui/icons/success.js": +/*!*********************************!*\ + !*** ./src/ui/icons/success.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/** + * Success Icon + * @param {number} size - Size of the icon. + */ +/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__(size) { + return ` + + + `; +} + +/***/ }), + +/***/ "./src/ui/icons/warning.js": +/*!*********************************!*\ + !*** ./src/ui/icons/warning.js ***! + \*********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* export default binding */ __WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/** + * Warning Icon + * @param {number} size - Size of the icon. + */ +/* harmony default export */ function __WEBPACK_DEFAULT_EXPORT__(size) { + return ` + + + `; +} + +/***/ }), + +/***/ "./src/ui/modals.js": +/*!**************************!*\ + !*** ./src/ui/modals.js ***! + \**************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ Modals) +/* harmony export */ }); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/** + * Allows an easy way to create and show modals. + * @module Modals + */ + + + +const React = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.React; +const ce = React.createElement; +const Markdown = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getModule(m => m.displayName == "Markdown" && m.rules); + +class Modals { + + /** Sizes of modals. */ + static get ModalSizes() {return {};} + + /** + * Shows the user profile modal for a given user. + * @param {string} userId - id of the user to show profile for + */ + static showUserProfile(userId) { + return modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.UserProfileModal.open(userId); + } + + /** + * Acts as a wrapper for {@link module:Modals.showModal} where the `children` is a text element. + * @param {string} title - title of the modal + * @param {string} content - text to show inside the modal. Can be markdown. + * @param {object} [options] - see {@link module:Modals.showModal} + * @see module:Modals.showModal + */ + static showConfirmationModal(title, content, options = {}) { + this.showModal(title, ce(Markdown, null, content), options); + } + + /** + * Shows a very simple alert modal that has title, content and an okay button. + * @param {string} title - title of the modal + * @param {string} body - text to show inside the modal + */ + static showAlertModal(title, body) { + this.showConfirmationModal(title, body, {cancelText: null}); + } + + /** + * Shows a generic but very customizable modal. + * @param {string} title - title of the modal + * @param {(ReactElement|Array)} children - a single or array of rendered react elements to act as children + * @param {object} [options] - options to modify the modal + * @param {boolean} [options.danger=false] - whether the main button should be red or not + * @param {string} [options.confirmText=Okay] - text for the confirmation/submit button + * @param {string} [options.cancelText=Cancel] - text for the cancel button + * @param {callable} [options.onConfirm=NOOP] - callback to occur when clicking the submit button + * @param {callable} [options.onCancel=NOOP] - callback to occur when clicking the cancel button + */ + static showModal(title, children, options = {}) { + const {danger = false, confirmText = "Okay", cancelText = "Cancel", onConfirm = () => {}, onCancel = () => {}} = options; + return modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.ModalActions.openModal(props => { + return React.createElement(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.ConfirmationModal, Object.assign({ + header: title, + confirmButtonColor: danger ? modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.ButtonData.ButtonColors.RED : modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.ButtonData.ButtonColors.BRAND, + confirmText: confirmText, + cancelText: cancelText, + onConfirm: onConfirm, + onCancel: onCancel + }, props), children); + }); + } + + /** + * @interface + * @name module:Modals~Changelog + * @property {string} title - title of the changelog section + * @property {string} [type=added] - type information of the section. Options: added, improved, fixed, progress. + * @property {Array} items - itemized list of items to show in that section. Can use markdown. + */ + + /** + * Shows a changelog modal based on changelog data. + * @param {string} title - title of the modal + * @param {string} version - subtitle (usually version or date) of the modal + * @param {module:Modals~Changelog} changelog - changelog to show inside the modal + * @param {string} footer - either an html element or text to show in the footer of the modal. Can use markdown. + */ + static showChangelogModal(title, version, changelog, footer) { + const TextElement = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.TextElement; + if (!TextElement) return modules__WEBPACK_IMPORTED_MODULE_0__.Logger.warn("Modals", "Unable to show changelog modal--TextElement not found."); + const changelogItems = []; + for (let c = 0; c < changelog.length; c++) { + const entry = changelog[c]; + const type = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Changelog[entry.type] ? modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Changelog[entry.type] : modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Changelog.added; + const margin = c == 0 ? modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Changelog.marginTop : ""; + changelogItems.push(ce("h1", {className: `${type} ${margin}`,}, entry.title)); + const list = ce("ul", null, entry.items.map(i => ce("li", null, ce(Markdown, null, i)))); + changelogItems.push(list); + } + const renderHeader = function() { + return ce(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.FlexChild.Child, {grow: 1, shrink: 1}, + ce(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.Titles["default"], {tag: modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.Titles.Tags.H4}, title), + ce(TextElement, + {size: TextElement.Sizes.SMALL, color: TextElement.Colors.PRIMARY, className: modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Changelog.date.toString()}, + "Version " + version + ) + ); + }; + const renderFooter = footer ? function() { + return ce(Markdown, null, footer); + } : null; + + return modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.ModalActions.openModal(props => { + return ce(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.Changelog, Object.assign({ + className: modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Changelog.container.toString(), + selectable: true, + onScroll: _ => _, + onClose: _ => _, + renderHeader: renderHeader, + renderFooter: renderFooter, + }, props), changelogItems); + }); + } +} + +/***/ }), + +/***/ "./src/ui/popouts.js": +/*!***************************!*\ + !*** ./src/ui/popouts.js ***! + \***************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ Popouts) +/* harmony export */ }); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/** + * Allows an easy way to create and show popouts. + * @module Popouts + */ + + + +const {React, ReactDOM} = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules; +const {useReducer, useEffect, useRef} = React; +const AccessibilityProvider = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("AccessibilityPreferencesContext").AccessibilityPreferencesContext.Provider; +const Layers = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("AppReferencePositionLayer"); +const PopoutCSSAnimator = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByDisplayName("PopoutCSSAnimator"); +const LayerProvider = Layers.AppLayerProvider().props.layerContext.Provider; // eslint-disable-line new-cap +const LayerModule = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("LayerClassName"); +const {ComponentDispatch} = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("ComponentDispatch"); +const {ComponentActions} = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("ComponentActions"); +const AnalyticsTrackContext = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.find(m => m._currentValue && m._currentValue.toString && m._currentValue.toString().includes("AnalyticsTrackImpressionContext function unimplemented")); +const AnalyticsTracker = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.find(m => m.toString && m.toString().includes("setDebugTrackedData")); +const Popout = modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByDisplayName("Popout"); + +const createStore = state => { + const listeners = new Set(); + + const setState = function (getter = _ => _) { + const partial = getter(state); + if (partial === state) return; + + state = partial; + + [...listeners].forEach(e => e()); + }; + + setState.getState = () => state; + + function storeListener(getter = _ => _) { + const [, forceUpdate] = useReducer(n => !n, true); + + useEffect(() => { + const dispatch = () => {forceUpdate();}; + + listeners.add(dispatch); + + return () => {listeners.delete(dispatch);}; + }); + + return getter(state); + } + + return [ + setState, + storeListener + ]; +}; + +const [setPopouts, usePopouts] = createStore([]); + +const AnimationTypes = {FADE: 3, SCALE: 2, TRANSLATE: 1}; + +class Popouts { + + static get AnimationTypes() {return AnimationTypes;} + + static initialize() { + this.dispose(); + this.popouts = 0; + + this.container = Object.assign(document.createElement("div"), { + className: "ZeresPluginLibraryPopoutsRenderer", + style: "display: none;" + }); + + this.layerContainer = Object.assign(document.createElement("div"), { + id: "ZeresPluginLibraryPopouts", + className: LayerModule.LayerClassName + }); + + document.body.append(this.container, this.layerContainer); + ReactDOM.render(React.createElement(PopoutsContainer), this.container); + + modules__WEBPACK_IMPORTED_MODULE_0__.Patcher.before("Popouts", LayerModule, "getParentLayerContainer", (_, [element]) => { + if (element.parentElement === this.layerContainer) return this.layerContainer; + }); + } + + /** + * Shows the user popout for a user relative to a target element + * @param {HTMLElement} target - Element to show the popout in relation to + * @param {object} user - Discord User object for the user to show + * @param {object} [options] - Options to modify the request + * @param {string} [options.guild="currentGuildId"] - Id of the guild (uses current if not specified) + * @param {string} [options.channel="currentChannelId"] - Id of the channel (uses current if not specified) + * @param {string} [options.position="right"] - Positioning relative to element + * @param {string} [options.align="top"] - Positioning relative to element + */ + static showUserPopout(target, user, options = {}) { + const {position = "right", align = "top", guild = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.SelectedGuildStore.getGuildId(), channel = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.SelectedChannelStore.getChannelId()} = options; + target = modules__WEBPACK_IMPORTED_MODULE_0__.DOMTools.resolveElement(target); + // if (target.getBoundingClientRect().right + 250 >= DOMTools.screenWidth && options.autoInvert) position = "left"; + // if (target.getBoundingClientRect().bottom + 400 >= DOMTools.screenHeight && options.autoInvert) align = "bottom"; + // if (target.getBoundingClientRect().top - 400 >= DOMTools.screenHeight && options.autoInvert) align = "top"; + this.openPopout(target, { + position: position, + align: align, + animation: options.animation || Popouts.AnimationTypes.TRANSLATE, + autoInvert: options.autoInvert, + nudgeAlignIntoViewport: options.nudgeAlignIntoViewport, + spacing: options.spacing, + render: (props) => { + return modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.React.createElement(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordModules.UserPopout, Object.assign({}, props, { + userId: user.id, + guildId: guild, + channelId: channel + })); + } + }); + } + + /** + * Shows a react popout relative to a target element + * @param {HTMLElement} target - Element to show the popout in relation to + * @param {object} [options] - Options to modify the request + * @param {string} [options.position="right"] - General position relative to element + * @param {string} [options.align="top"] - Alignment relative to element + * @param {Popouts.AnimationTypes} [options.animation=Popouts.AnimationTypes.TRANSLATE] - Animation type to use + * @param {boolean} [options.autoInvert=true] - Try to automatically adjust the position if it overflows the screen + * @param {boolean} [options.nudgeAlignIntoViewport=true] - Try to automatically adjust the alignment if it overflows the screen + * @param {number} [options.spacing=8] - Spacing between target and popout + */ + static openPopout(target, options) { + const id = this.popouts++; + + setPopouts(popouts => popouts.concat({ + id: id, + element: React.createElement(PopoutWrapper, Object.assign({}, Popout.defaultProps, { + reference: {current: target}, + popoutId: id, + key: "popout_" + id, + spacing: 50 + }, options)) + })); + + return id; + } + + static closePopout(id) { + const popout = setPopouts.getState().find(e => e.id === id); + + if (!popout) return null; + + setPopouts(popouts => { + const clone = [...popouts]; + clone.splice(clone.indexOf(popout), 1); + return clone; + }); + } + + static dispose() { + modules__WEBPACK_IMPORTED_MODULE_0__.Patcher.unpatchAll("Popouts"); + const container = document.querySelector(".ZeresPluginLibraryPopoutsRenderer"); + const layerContainer = document.querySelector("#ZeresPluginLibraryPopouts"); + if (container) ReactDOM.unmountComponentAtNode(container); + if (container) container.remove(); + if (layerContainer) layerContainer.remove(); + } +} + +function DiscordProviders({children, container}) { + return React.createElement(AccessibilityProvider, { + value: { + reducedMotion: {enabled: false, rawValue: "auto"} + } + }, React.createElement(LayerProvider, { + value: [container] + }, React.createElement(AnalyticsTrackContext.Provider, { + value: AnalyticsTracker + }, children))); +} + +function PopoutsContainer() { + const popouts = usePopouts(); + + return React.createElement(DiscordProviders, + {container: Popouts.layerContainer}, + popouts.map((popout) => popout.element) + ); +} + +function PopoutWrapper({render, animation, popoutId, ...props}) { + const popoutRef = useRef(); + + useEffect(() => { + if (!popoutRef.current) return; + + const node = ReactDOM.findDOMNode(popoutRef.current); + + const handleClick = ({target}) => { + if (target === node || node.contains(target)) return; + + Popouts.closePopout(popoutId); + }; + + document.addEventListener("click", handleClick); + + return () => { + document.removeEventListener("click", handleClick); + }; + }, [popoutRef]); + + switch (animation) { + case PopoutCSSAnimator.Types.FADE: + case PopoutCSSAnimator.Types.SCALE: + case PopoutCSSAnimator.Types.TRANSLATE: { + const renderPopout = render; + render = (renderProps) => { + return React.createElement(PopoutCSSAnimator, { + position: renderProps.position, + type: animation + }, renderPopout(renderProps)); + }; + } + } + + return React.createElement(Layers.AppReferencePositionLayer, Object.assign(props, { + ref: popoutRef, + positionKey: "0", + autoInvert: true, + id: "popout_" + popoutId, + onMount() { + ComponentDispatch.dispatch(ComponentActions.POPOUT_SHOW); + }, + onUnmount() { + ComponentDispatch.dispatch(ComponentActions.POPOUT_HIDE); + }, + children: render + })); +} + + + + +/***/ }), + +/***/ "./src/ui/settings/index.js": +/*!**********************************!*\ + !*** ./src/ui/settings/index.js ***! + \**********************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "CSS": () => (/* reexport safe */ _styles_settings_css__WEBPACK_IMPORTED_MODULE_0__["default"]), +/* harmony export */ "ReactSetting": () => (/* reexport safe */ _settingfield__WEBPACK_IMPORTED_MODULE_1__.ReactSetting), +/* harmony export */ "SettingField": () => (/* reexport safe */ _settingfield__WEBPACK_IMPORTED_MODULE_1__["default"]), +/* harmony export */ "SettingGroup": () => (/* reexport safe */ _settinggroup__WEBPACK_IMPORTED_MODULE_2__["default"]), +/* harmony export */ "SettingPanel": () => (/* reexport safe */ _settingpanel__WEBPACK_IMPORTED_MODULE_3__["default"]), +/* harmony export */ "Textbox": () => (/* reexport safe */ _types_textbox__WEBPACK_IMPORTED_MODULE_4__["default"]), +/* harmony export */ "ColorPicker": () => (/* reexport safe */ _types_color__WEBPACK_IMPORTED_MODULE_5__["default"]), +/* harmony export */ "FilePicker": () => (/* reexport safe */ _types_file__WEBPACK_IMPORTED_MODULE_6__["default"]), +/* harmony export */ "Slider": () => (/* reexport safe */ _types_slider__WEBPACK_IMPORTED_MODULE_7__["default"]), +/* harmony export */ "Switch": () => (/* reexport safe */ _types_switch__WEBPACK_IMPORTED_MODULE_8__["default"]), +/* harmony export */ "Dropdown": () => (/* reexport safe */ _types_dropdown__WEBPACK_IMPORTED_MODULE_9__["default"]), +/* harmony export */ "Keybind": () => (/* reexport safe */ _types_keybind__WEBPACK_IMPORTED_MODULE_10__["default"]), +/* harmony export */ "RadioGroup": () => (/* reexport safe */ _types_radiogroup__WEBPACK_IMPORTED_MODULE_11__["default"]) +/* harmony export */ }); +/* harmony import */ var _styles_settings_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../styles/settings.css */ "./src/styles/settings.css"); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var _settinggroup__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./settinggroup */ "./src/ui/settings/settinggroup.js"); +/* harmony import */ var _settingpanel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./settingpanel */ "./src/ui/settings/settingpanel.js"); +/* harmony import */ var _types_textbox__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./types/textbox */ "./src/ui/settings/types/textbox.js"); +/* harmony import */ var _types_color__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./types/color */ "./src/ui/settings/types/color.js"); +/* harmony import */ var _types_file__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./types/file */ "./src/ui/settings/types/file.js"); +/* harmony import */ var _types_slider__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./types/slider */ "./src/ui/settings/types/slider.js"); +/* harmony import */ var _types_switch__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./types/switch */ "./src/ui/settings/types/switch.js"); +/* harmony import */ var _types_dropdown__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./types/dropdown */ "./src/ui/settings/types/dropdown.js"); +/* harmony import */ var _types_keybind__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./types/keybind */ "./src/ui/settings/types/keybind.js"); +/* harmony import */ var _types_radiogroup__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./types/radiogroup */ "./src/ui/settings/types/radiogroup.js"); +/** + * An object that makes generating settings panel 10x easier. + * @module Settings + */ + + + + + + + + + + + + + + + + +/***/ }), + +/***/ "./src/ui/settings/settingfield.js": +/*!*****************************************!*\ + !*** ./src/ui/settings/settingfield.js ***! + \*****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__), +/* harmony export */ "ReactSetting": () => (/* binding */ ReactSetting) +/* harmony export */ }); +/* harmony import */ var _structs_listenable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../structs/listenable */ "./src/structs/listenable.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + + +const AccessibilityProvider = modules__WEBPACK_IMPORTED_MODULE_1__.WebpackModules.getByProps("AccessibilityPreferencesContext").AccessibilityPreferencesContext.Provider; +const LayerProvider = modules__WEBPACK_IMPORTED_MODULE_1__.WebpackModules.getByProps("AppReferencePositionLayer").AppLayerProvider().props.layerContext.Provider; // eslint-disable-line new-cap + +/** + * Setting field to extend to create new settings + * @memberof module:Settings + */ +class SettingField extends _structs_listenable__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {callable} onChange - callback to perform on setting change + * @param {(ReactComponent|HTMLElement)} settingtype - actual setting to render + * @param {object} [props] - object of props to give to the setting and the settingtype + * @param {boolean} [props.noteOnTop=false] - determines if the note should be shown above the element or not. + */ + constructor(name, note, onChange, settingtype, props = {}) { + super(); + this.name = name; + this.note = note; + if (typeof(onChange) == "function") this.addListener(onChange); + this.inputWrapper = modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.parseHTML(`
`); + this.type = typeof(settingtype) == "function" ? settingtype : modules__WEBPACK_IMPORTED_MODULE_1__.ReactTools.wrapElement(settingtype); + this.props = props; + modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.onAdded(this.getElement(), () => {this.onAdded();}); + modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.onRemoved(this.getElement(), () => {this.onRemoved();}); + } + + /** @returns {HTMLElement} - root element for setting */ + getElement() {return this.inputWrapper;} + + /** Fires onchange to listeners */ + onChange() { + this.alertListeners(...arguments); + } + + /** Fired when root node added to DOM */ + onAdded() { + const reactElement = modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.ReactDOM.render(modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.React.createElement(ReactSetting, Object.assign({ + title: this.name, + type: this.type, + note: this.note, + }, this.props)), this.getElement()); + + if (this.props.onChange) reactElement.props.onChange = this.props.onChange(reactElement); + reactElement.forceUpdate(); + } + + /** Fired when root node removed from DOM */ + onRemoved() { + modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.ReactDOM.unmountComponentAtNode(this.getElement()); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SettingField); + +class ReactSetting extends modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.React.Component { + get noteElement() { + const className = this.props.noteOnTop ? modules__WEBPACK_IMPORTED_MODULE_1__.DiscordClasses.Margins.marginBottom8 : modules__WEBPACK_IMPORTED_MODULE_1__.DiscordClasses.Margins.marginTop8; + return modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.React.createElement(modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.SettingsNote, {children: this.props.note, type: "description", className: className.toString()}); + } + + get dividerElement() {return modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.React.createElement("div", {className: modules__WEBPACK_IMPORTED_MODULE_1__.DiscordClasses.Dividers.divider.add(modules__WEBPACK_IMPORTED_MODULE_1__.DiscordClasses.Dividers.dividerDefault).toString()});} + + render() { + const ce = modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.React.createElement; + const SettingElement = ce(this.props.type, this.props); + const Context = ce(AccessibilityProvider, {value: {reducedMotion: {enabled: false, rawValue: "no-preference"}}}, ce(LayerProvider, {value: [document.querySelector("#app-mount > .layerContainer-2v_Sit")]}, SettingElement)); + if (this.props.inline) { + const Flex = modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.FlexChild; + const titleDefault = modules__WEBPACK_IMPORTED_MODULE_1__.WebpackModules.getByProps("titleDefault") ? modules__WEBPACK_IMPORTED_MODULE_1__.WebpackModules.getByProps("titleDefault").title : "titleDefault-a8-ZSr title-31JmR4 da-titleDefault da-title"; + return ce(Flex, {direction: Flex.Direction.VERTICAL}, + ce(Flex, {align: Flex.Align.START}, + ce(Flex.Child, {wrap: !0}, + ce("div", {className: titleDefault}, this.props.title) + ), + ce(Flex.Child, {grow: 0, shrink: 0}, Context) + ), + this.noteElement, + this.dividerElement + ); + } + + return ce(modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.SettingsWrapper, { + className: modules__WEBPACK_IMPORTED_MODULE_1__.DiscordClasses.Margins.marginBottom20.toString(), + title: this.props.title, + children: [ + this.props.noteOnTop ? this.noteElement : Context, + this.props.noteOnTop ? Context : this.noteElement, + this.dividerElement + ] + }); + } +} + + + +/***/ }), + +/***/ "./src/ui/settings/settinggroup.js": +/*!*****************************************!*\ + !*** ./src/ui/settings/settinggroup.js ***! + \*****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _structs_listenable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../structs/listenable */ "./src/structs/listenable.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./settingfield */ "./src/ui/settings/settingfield.js"); + + + + +/** + * Grouping of controls for easier management in settings panels. + * @memberof module:Settings + */ +class SettingGroup extends _structs_listenable__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} groupName - title for the group of settings + * @param {object} [options] - additional options for the group + * @param {callback} [options.callback] - callback called on settings changed + * @param {boolean} [options.collapsible=true] - determines if the group should be collapsible + * @param {boolean} [options.shown=false] - determines if the group should be expanded by default + */ + constructor(groupName, options = {}) { + super(); + const {collapsible = true, shown = false, callback = () => {}} = options; + this.addListener(callback); + this.onChange = this.onChange.bind(this); + + const collapsed = shown || !collapsible ? "" : "collapsed"; + const group = modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.parseHTML(`
+

+ ${groupName} +

+
+
`); + const label = group.querySelector("h2"); + const controls = group.querySelector(".plugin-inputs"); + + this.group = group; + this.label = label; + this.controls = controls; + + if (!collapsible) return; + label.addEventListener("click", async () => { + const button = label.querySelector(".button-collapse"); + const wasCollapsed = button.classList.contains("collapsed"); + group.parentElement.querySelectorAll(":scope > .plugin-input-group > .collapsible:not(.collapsed)").forEach((element) => { + element.style.setProperty("height", element.scrollHeight + "px"); + element.classList.add("collapsed"); + setImmediate(() => {element.style.setProperty("height", "");}); + }); + group.parentElement.querySelectorAll(":scope > .plugin-input-group > h2 > .button-collapse").forEach(e => e.classList.add("collapsed")); + if (!wasCollapsed) return; + controls.style.setProperty("height", controls.scrollHeight + "px"); + controls.classList.remove("collapsed"); + button.classList.remove("collapsed"); + await new Promise(resolve => setTimeout(resolve, 300)); + controls.style.setProperty("height", ""); + }); + } + + /** @returns {HTMLElement} - root node for the group. */ + getElement() {return this.group;} + + /** + * Adds multiple nodes to this group. + * @param {(...HTMLElement|...jQuery|...module:Settings.SettingField|...module:Settings.SettingGroup)} nodes - list of nodes to add to the group container + * @returns {module:Settings.SettingGroup} - returns self for chaining + */ + append(...nodes) { + for (let i = 0; i < nodes.length; i++) { + if (modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.resolveElement(nodes[i]) instanceof Element) this.controls.append(nodes[i]); + else if (nodes[i] instanceof _settingfield__WEBPACK_IMPORTED_MODULE_2__["default"] || nodes[i] instanceof SettingGroup) this.controls.append(nodes[i].getElement()); + if (nodes[i] instanceof _settingfield__WEBPACK_IMPORTED_MODULE_2__["default"]) { + nodes[i].addListener(((node) => (value) => { + this.onChange(node.id || node.name, value); + })(nodes[i])); + } + else if (nodes[i] instanceof SettingGroup) { + nodes[i].addListener(((node) => (settingId, value) => { + this.onChange(node.id || node.name, settingId, value); + })(nodes[i])); + } + } + return this; + } + + /** + * Appends this node to another + * @param {HTMLElement} node - node to attach the group to. + * @returns {module:Settings.SettingGroup} - returns self for chaining + */ + appendTo(node) { + node.append(this.group); + return this; + } + + /** Fires onchange to listeners */ + onChange() { + this.alertListeners(...arguments); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SettingGroup); + +/***/ }), + +/***/ "./src/ui/settings/settingpanel.js": +/*!*****************************************!*\ + !*** ./src/ui/settings/settingpanel.js ***! + \*****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _structs_listenable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../structs/listenable */ "./src/structs/listenable.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var _settinggroup__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./settinggroup */ "./src/ui/settings/settinggroup.js"); + + + + + +/** + * Grouping of controls for easier management in settings panels. + * @memberof module:Settings + */ +class SettingPanel extends _structs_listenable__WEBPACK_IMPORTED_MODULE_0__["default"] { + + /** + * Creates a new settings panel + * @param {callable} onChange - callback to fire when settings change + * @param {(...HTMLElement|...jQuery|...module:Settings.SettingField|...module:Settings.SettingGroup)} nodes - list of nodes to add to the panel container + */ + constructor(onChange, ...nodes) { + super(); + this.element = modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.parseHTML(`
`); + if (typeof(onChange) == "function") this.addListener(onChange); + this.onChange = this.onChange.bind(this); + this.append(...nodes); + } + + /** + * Creates a new settings panel + * @param {callable} onChange - callback to fire when settings change + * @param {(...HTMLElement|...jQuery|...module:Settings.SettingField|...module:Settings.SettingGroup)} nodes - list of nodes to add to the panel container + * @returns {HTMLElement} - root node for the panel. + */ + static build(onChange, ...nodes) { + return (new SettingPanel(onChange, ...nodes)).getElement(); + } + + /** @returns {HTMLElement} - root node for the panel. */ + getElement() {return this.element;} + + /** + * Adds multiple nodes to this panel. + * @param {(...HTMLElement|...jQuery|...SettingField|...SettingGroup)} nodes - list of nodes to add to the panel container + * @returns {module:Settings.SettingPanel} - returns self for chaining + */ + append(...nodes) { + for (let i = 0; i < nodes.length; i++) { + if (modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.resolveElement(nodes[i]) instanceof Element) this.element.append(nodes[i]); + else if (nodes[i] instanceof _settingfield__WEBPACK_IMPORTED_MODULE_2__["default"] || nodes[i] instanceof _settinggroup__WEBPACK_IMPORTED_MODULE_3__["default"]) this.element.append(nodes[i].getElement()); + if (nodes[i] instanceof _settingfield__WEBPACK_IMPORTED_MODULE_2__["default"]) { + nodes[i].addListener(((node) => (value) => { + this.onChange(node.id || node.name, value); + })(nodes[i])); + } + else if (nodes[i] instanceof _settinggroup__WEBPACK_IMPORTED_MODULE_3__["default"]) { + nodes[i].addListener(((node) => (settingId, value) => { + this.onChange(node.id || node.name, settingId, value); + })(nodes[i])); + } + } + return this; + } + + /** Fires onchange to listeners */ + onChange() { + this.alertListeners(...arguments); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SettingPanel); + +/***/ }), + +/***/ "./src/ui/settings/types/color.js": +/*!****************************************!*\ + !*** ./src/ui/settings/types/color.js ***! + \****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/* harmony import */ var _colorpicker__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../colorpicker */ "./src/ui/colorpicker.js"); + + + + + + +const presetColors = [1752220, 3066993, 3447003, 10181046, 15277667, 15844367, 15105570, 15158332, 9807270, 6323595, 1146986, 2067276, 2123412, 7419530, 11342935, 12745742, 11027200, 10038562, 9936031, 5533306]; + +/** + * Creates a color picker using Discord's built in color picker + * as a base. Input and output using hex strings. + * @memberof module:Settings + * @extends module:Settings.SettingField + */ +class ColorPicker extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {string} value - current hex color + * @param {callable} onChange - callback to perform on setting change, callback receives hex string + * @param {object} [options] - object of options to give to the setting + * @param {boolean} [options.disabled=false] - should the setting be disabled + * @param {string} [options.defaultColor] - default color to show as large option + * @param {Array} [options.colors] - preset colors to show in swatch + */ + constructor(name, note, value, onChange, options = {}) { + const ColorPickerComponents = modules__WEBPACK_IMPORTED_MODULE_1__.WebpackModules.getByProps("CustomColorPicker"); + if (ColorPickerComponents) { + const defaultColor = options.defaultColor; + super(name, note, onChange, _colorpicker__WEBPACK_IMPORTED_MODULE_2__["default"], { + disabled: !!options.disabled, + onChange: reactElement => color => { + reactElement.props.value = color; + reactElement.forceUpdate(); + this.onChange(modules__WEBPACK_IMPORTED_MODULE_1__.ColorConverter.int2hex(color)); + }, + colors: Array.isArray(options.colors) ? options.colors : presetColors, + defaultColor: defaultColor && typeof(defaultColor) !== "number" ? modules__WEBPACK_IMPORTED_MODULE_1__.ColorConverter.hex2int(defaultColor) : defaultColor, + value: typeof(value) == "number" ? value : modules__WEBPACK_IMPORTED_MODULE_1__.ColorConverter.hex2int(value), + customPickerPosition: "right" + }); + } + else { + const classes = ["color-input"]; + if (options.disabled) classes.push(modules__WEBPACK_IMPORTED_MODULE_1__.DiscordClasses.BasicInputs.disabled); + const ReactColorPicker = modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.parseHTML(``); + if (options.disabled) ReactColorPicker.setAttribute("disabled", ""); + if (value) ReactColorPicker.setAttribute("value", value); + ReactColorPicker.addEventListener("change", (event) => { + this.onChange(event.target.value); + }); + super(name, note, onChange, ReactColorPicker, {inline: true}); + } + } + + /** Default colors for ColorPicker */ + static get presetColors() {return presetColors;} +} + + + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (ColorPicker); + +/***/ }), + +/***/ "./src/ui/settings/types/dropdown.js": +/*!*******************************************!*\ + !*** ./src/ui/settings/types/dropdown.js ***! + \*******************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + + +/** + * @interface + * @name module:Settings~DropdownItem + * @property {string} label - label to show in the dropdown + * @property {*} value - actual value represented by label (this is passed via onChange) + */ + +/** + * Creates a dropdown using discord's built in dropdown. + * @memberof module:Settings + * @extends module:Settings.SettingField + */ +class Dropdown extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {*} defaultValue - currently selected value + * @param {Array} values - array of all options available + * @param {callable} onChange - callback to perform on setting change, callback item value + * @param {object} [options] - object of options to give to the setting + * @param {boolean} [options.clearable=false] - should be able to empty the field value + * @param {boolean} [options.searchable=false] - should user be able to search the dropdown + * @param {boolean} [options.disabled=false] - should the setting be disabled + */ + constructor(name, note, defaultValue, values, onChange, options = {}) { + const {clearable = false, searchable = false, disabled = false} = options; + super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.Dropdown, { + clearable: clearable, + searchable: searchable, + disabled: disabled, + options: values, + onChange: dropdown => value => { + dropdown.props.value = value; + dropdown.forceUpdate(); + this.onChange(value); + }, + value: defaultValue + }); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Dropdown); + +/***/ }), + +/***/ "./src/ui/settings/types/file.js": +/*!***************************************!*\ + !*** ./src/ui/settings/types/file.js ***! + \***************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + + +/** + * Creates a file picker using chromium's default. + * @memberof module:Settings + * @extends module:Settings.SettingField + */ +class FilePicker extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {callable} onChange - callback to perform on setting change, callback receives File object + * @param {object} [options] - object of options to give to the setting + * @param {boolean} [options.disabled=false] - should the setting be disabled + * @param {Array|string} [options.accept] - what file types should be accepted + * @param {boolean} [options.multiple=false] - should multiple files be accepted + */ + constructor(name, note, onChange, options = {}) { + const classes = modules__WEBPACK_IMPORTED_MODULE_1__.DiscordClasses.BasicInputs.inputDefault.add("file-input"); + if (options.disabled) classes.add(modules__WEBPACK_IMPORTED_MODULE_1__.DiscordClasses.BasicInputs.disabled); + const ReactFilePicker = modules__WEBPACK_IMPORTED_MODULE_1__.DOMTools.parseHTML(``); + if (options.disabled) ReactFilePicker.setAttribute("disabled", ""); + if (options.multiple) ReactFilePicker.setAttribute("multiple", ""); + if (options.accept) ReactFilePicker.setAttribute("accept", Array.isArray(options.accept) ? options.accept.join(",") : options.accept); + ReactFilePicker.addEventListener("change", (event) => { + this.onChange(event.target.files[0]); + }); + super(name, note, onChange, ReactFilePicker); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (FilePicker); + +/***/ }), + +/***/ "./src/ui/settings/types/keybind.js": +/*!******************************************!*\ + !*** ./src/ui/settings/types/keybind.js ***! + \******************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + + +/** + * Creates a keybind setting using discord's built in keybind recorder. + * @memberof module:Settings= + * @extends module:Settings.SettingField + */ +class Keybind extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {Array} value - array of keycodes + * @param {callable} onChange - callback to perform on setting change, callback receives array of keycodes + * @param {object} [options] - object of options to give to the setting + * @param {boolean} [options.disabled=false] - should the setting be disabled + */ + constructor(label, help, value, onChange, options = {}) { + const {disabled = false} = options; + super(label, help, onChange, modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.Keybind, { + disabled: disabled, + defaultValue: value.map(a => [0, a || 0, 1]), + onChange: element => val => { + if (!Array.isArray(val)) return; + element.props.value = val; + this.onChange(val.map(a => a[1])); + } + }); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Keybind); + +/***/ }), + +/***/ "./src/ui/settings/types/radiogroup.js": +/*!*********************************************!*\ + !*** ./src/ui/settings/types/radiogroup.js ***! + \*********************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + + +/** + * @interface + * @name module:Settings~RadioItem + * @property {string} name - label to show in the dropdown + * @property {*} value - actual value represented by label (this is passed via onChange) + * @property {string} desc - description/help text to show below name + * @property {string} color - hex string to color the item + */ + +/** + * Creates a radio group using discord's built in radios. + * @memberof module:Settings + * @extends module:Settings.SettingField + */ +class RadioGroup extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {*} defaultValue - currently selected value + * @param {Array} values - array of all options available + * @param {callable} onChange - callback to perform on setting change, callback item value + * @param {object} [options] - object of options to give to the setting + * @param {boolean} [options.disabled=false] - should the setting be disabled + */ + constructor(name, note, defaultValue, values, onChange, options = {}) { + super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.RadioGroup, { + noteOnTop: true, + disabled: !!options.disabled, + options: values, + onChange: reactElement => option => { + reactElement.props.value = option.value; + reactElement.forceUpdate(); + this.onChange(option.value); + }, + value: defaultValue + }); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (RadioGroup); + + + +/***/ }), + +/***/ "./src/ui/settings/types/slider.js": +/*!*****************************************!*\ + !*** ./src/ui/settings/types/slider.js ***! + \*****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + + +/** + * Used to render the marker. + * @param {Number} value - The value to render + * @returns {string} the text to show in the marker + * @callback module:Settings~SliderMarkerValue + */ + +/** + * Used to render the grabber tooltip. + * @param {Number} value - The value to render + * @returns {string} the text to show in the tooltip + * @callback module:Settings~SliderRenderValue + */ + +/** + * Creates a slider/range using discord's built in slider. + * @memberof module:Settings + * @extends module:Settings.SettingField + */ +class Slider extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {number} min - minimum value allowed + * @param {number} max - maximum value allowed + * @param {number} value - currently selected value + * @param {callable} onChange - callback to fire when setting is changed, callback receives number + * @param {object} [options] - object of options to give to the setting + * @param {boolean} [options.disabled=false] - should the setting be disabled + * @param {object} [options.fillStyles] - object of css styles to add to active slider + * @param {number} [options.defaultValue] - value highlighted as default + * @param {number} [options.keyboardStep] - step moved when using arrow keys + * @param {Array} [options.markers] - array of vertical markers to show on the slider + * @param {boolean} [options.stickToMarkers] - should the slider be forced to use markers + * @param {boolean} [options.equidistant] - should the markers be scaled to be equidistant + * @param {module:Settings~SliderMarkerValue} [options.onMarkerRender] - function to call to render the value in the marker + * @param {module:Settings~SliderMarkerValue} [options.renderMarker] - alias of `onMarkerRender` + * @param {module:Settings~SliderRenderValue} [options.onValueRender] - function to call to render the value in the tooltip + * @param {module:Settings~SliderRenderValue} [options.renderValue] - alias of `onValueRender` + * @param {string} [options.units] - can be used in place of `onValueRender` will use this string and render Math.round(value) + units + */ + constructor(name, note, min, max, value, onChange, options = {}) { + const props = { + onChange: _ => _, + initialValue: value, + disabled: !!options.disabled, + minValue: min, + maxValue: max, + handleSize: 10 + }; + if (options.fillStyles) props.fillStyles = options.fillStyles; + if (typeof(options.defaultValue) !== "undefined") props.defaultValue = options.defaultValue; + if (options.keyboardStep) props.keyboardStep = options.keyboardStep; + if (options.markers) props.markers = options.markers; + if (options.stickToMarkers) props.stickToMarkers = options.stickToMarkers; + if (typeof(options.equidistant) != "undefined") props.equidistant = options.equidistant; + if (options.units) { + const renderValueLabel = (val) => `${Math.round(val)}${options.units}`; + props.onMarkerRender = renderValueLabel; + props.onValueRender = renderValueLabel; + } + if (options.onMarkerRender || options.renderMarker) props.onMarkerRender = options.onMarkerRender || options.renderMarker; + if (options.onValueRender || options.renderValue) props.onValueRender = options.onValueRender || options.renderValue; + super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.Slider, Object.assign(props, {onValueChange: v => this.onChange(v)})); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Slider); + +/***/ }), + +/***/ "./src/ui/settings/types/switch.js": +/*!*****************************************!*\ + !*** ./src/ui/settings/types/switch.js ***! + \*****************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + + +class SwitchWrapper extends modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.React.Component { + constructor(props) { + super(props); + this.state = {enabled: this.props.value}; + } + + render() { + return modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.React.createElement(modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.SwitchRow, Object.assign({}, this.props, { + value: this.state.enabled, + onChange: e => { + this.props.onChange(e); + this.setState({enabled: e}); + } + })); + } +} + +/** + * Creates a switch using discord's built in switch. + * @memberof module:Settings + * @extends module:Settings.SettingField + */ +class Switch extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {boolean} isChecked - should switch be checked + * @param {callable} onChange - callback to perform on setting change, callback receives boolean + * @param {object} [options] - object of options to give to the setting + * @param {boolean} [options.disabled=false] - should the setting be disabled + */ + constructor(name, note, isChecked, onChange, options = {}) { + super(name, note, onChange); + this.disabled = !!options.disabled; + this.value = !!isChecked; + } + + onAdded() { + modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.ReactDOM.render(modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.React.createElement(SwitchWrapper, { + children: this.name, + note: this.note, + disabled: this.disabled, + hideBorder: false, + value: this.value, + onChange: (e) => {this.onChange(e);} + }), this.getElement()); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Switch); + + +/***/ }), + +/***/ "./src/ui/settings/types/textbox.js": +/*!******************************************!*\ + !*** ./src/ui/settings/types/textbox.js ***! + \******************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _settingfield__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../settingfield */ "./src/ui/settings/settingfield.js"); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); + + + +/** + * Creates a textbox using discord's built in textbox. + * @memberof module:Settings + * @extends module:Settings.SettingField + */ +class Textbox extends _settingfield__WEBPACK_IMPORTED_MODULE_0__["default"] { + /** + * @param {string} name - name label of the setting + * @param {string} note - help/note to show underneath or above the setting + * @param {string} value - current text in box + * @param {callable} onChange - callback to perform on setting change, callback receives text + * @param {object} [options] - object of options to give to the setting + * @param {string} [options.placeholder=""] - placeholder for when textbox is empty + * @param {boolean} [options.disabled=false] - should the setting be disabled + */ + constructor(name, note, value, onChange, options = {}) { + const {placeholder = "", disabled = false} = options; + super(name, note, onChange, modules__WEBPACK_IMPORTED_MODULE_1__.DiscordModules.Textbox, { + onChange: textbox => val => { + textbox.props.value = val; + textbox.forceUpdate(); + this.onChange(val); + }, + value: value, + disabled: disabled, + placeholder: placeholder || "" + }); + } +} + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Textbox); + +/***/ }), + +/***/ "./src/ui/toasts.js": +/*!**************************!*\ + !*** ./src/ui/toasts.js ***! + \**************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ Toast) +/* harmony export */ }); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/* harmony import */ var ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ui */ "./src/ui/ui.js"); +/* harmony import */ var _styles_toasts_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../styles/toasts.css */ "./src/styles/toasts.css"); +/** + * Toast maker similar to Android. + * + * @module Toasts + */ + + + + + +class Toast { + + static get CSS() {return _styles_toasts_css__WEBPACK_IMPORTED_MODULE_2__["default"];} + + /** Shorthand for `type = "success"` for {@link module:Toasts.show} */ + static async success(content, options = {}) {return this.show(content, Object.assign(options, {type: "success"}));} + + /** Shorthand for `type = "info"` for {@link module:Toasts.show} */ + static async info(content, options = {}) {return this.show(content, Object.assign(options, {type: "info"}));} + + /** Shorthand for `type = "warning"` for {@link module:Toasts.show} */ + static async warning(content, options = {}) {return this.show(content, Object.assign(options, {type: "warning"}));} + + /** Shorthand for `type = "error"` for {@link module:Toasts.show} */ + static async error(content, options = {}) {return this.show(content, Object.assign(options, {type: "error"}));} + + /** Shorthand for `type = "default"` for {@link module:Toasts.show} */ + static async default(content, options = {}) {return this.show(content, Object.assign(options, {type: "default"}));} + + + /** + * Shows a simple toast, similar to Android, centered over + * the textarea if it exists, and center screen otherwise. + * Vertically it shows towards the bottom like in Android. + * @param {string} content - The string to show in the toast. + * @param {object} options - additional options for the toast + * @param {string} [options.type] - Changes the type of the toast stylistically and semantically. {@link module:Toasts.ToastTypes} + * @param {string} [options.icon] - URL to an optional icon + * @param {number} [options.timeout=3000] - Adjusts the time (in ms) the toast should be shown for before disappearing automatically + * @returns {Promise} - Promise that resolves when the toast is removed from the DOM + */ + static async show(content, options = {}) { + const {type = "", icon = "", timeout = 3000} = options; + this.ensureContainer(); + const toast = modules__WEBPACK_IMPORTED_MODULE_0__.DOMTools.parseHTML(this.buildToast(content, this.parseType(type), icon)); + document.querySelector(".toasts").appendChild(toast); + await new Promise(resolve => setTimeout(resolve, timeout)); + toast.classList.add("closing"); + await new Promise(resolve => setTimeout(resolve, 300)); + toast.remove(); + if (!document.querySelectorAll(".toasts .toast").length) document.querySelector(".toasts").remove(); + } + + static buildToast(message, type, icon) { + const hasIcon = type || icon; + const className = `toast ${hasIcon ? "toast-has-icon" : ""} ${type && type != "default" ? `toast-${type}` : ""}`; + if (!icon && type) icon = type; + return modules__WEBPACK_IMPORTED_MODULE_0__.Utilities.formatString(`
{{icon}}
{{message}}
`, { + className: className, + icon: hasIcon ? this.getIcon(icon) : "", + message: message + }); + } + + static getIcon(icon) { + let iconInner = ``; + switch (icon) { + case "success": iconInner = ui__WEBPACK_IMPORTED_MODULE_1__.Icons.IconSuccess(20); break; // eslint-disable-line new-cap + case "warning": iconInner = ui__WEBPACK_IMPORTED_MODULE_1__.Icons.IconWarning(20); break; // eslint-disable-line new-cap + case "info": iconInner = ui__WEBPACK_IMPORTED_MODULE_1__.Icons.IconInfo(20); break; // eslint-disable-line new-cap + case "error": iconInner = ui__WEBPACK_IMPORTED_MODULE_1__.Icons.IconError(20); // eslint-disable-line new-cap + } + return modules__WEBPACK_IMPORTED_MODULE_0__.Utilities.formatString(`
{{icon}}
`, {icon: iconInner}); + } + + static ensureContainer() { + if (document.querySelector(".toasts")) return; + const channelClass = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordSelectors.ChannelList.sidebar; + const container = channelClass ? document.querySelector(`${channelClass} ~ div:not([style])`) : null; + const memberlist = container ? container.querySelector(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordSelectors.MemberList.membersWrap) : null; + const form = container ? container.querySelector("form") : null; + const left = container ? container.getBoundingClientRect().left : 310; + const right = memberlist ? memberlist.getBoundingClientRect().left : 0; + const width = right ? right - container.getBoundingClientRect().left : container.offsetWidth; + const bottom = form ? form.offsetHeight : 80; + const toastWrapper = document.createElement("div"); + toastWrapper.classList.add("toasts"); + toastWrapper.style.setProperty("left", left + "px"); + toastWrapper.style.setProperty("width", width + "px"); + toastWrapper.style.setProperty("bottom", bottom + "px"); + document.querySelector("#app-mount").appendChild(toastWrapper); + } + + static parseType(type) { + return this.ToastTypes.hasOwnProperty(type) ? this.ToastTypes[type] : ""; + } + + /** + * Enumeration of accepted types. + */ + static get ToastTypes() { + return { + "default": "", + "error": "error", + "success": "success", + "warning": "warning", + "info": "info" + }; + } +} + +/***/ }), + +/***/ "./src/ui/tooltip.js": +/*!***************************!*\ + !*** ./src/ui/tooltip.js ***! + \***************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (/* binding */ Tooltip) +/* harmony export */ }); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/** + * Tooltip that automatically show and hide themselves on mouseenter and mouseleave events. + * Will also remove themselves if the node to watch is removed from DOM through + * a MutationObserver. + * + * Note this is not using Discord's internals but normal DOM manipulation and emulates + * Discord's own tooltips as closely as possible. + * + * @module Tooltip + */ + + + +const getClass = function(sideOrColor) { + const upperCase = sideOrColor[0].toUpperCase() + sideOrColor.slice(1); + const tooltipClass = modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Tooltips[`tooltip${upperCase}`]; + if (tooltipClass) return tooltipClass.value; + return null; +}; + +const classExists = function(sideOrColor) { + return !!getClass(sideOrColor); +}; + +const toPx = function(value) { + return `${value}px`; +}; + +/*
+
+
+ User Settings +
+
*/ + +class Tooltip { + /** + * + * @constructor + * @param {(HTMLElement|jQuery)} node - DOM node to monitor and show the tooltip on + * @param {string} tip - string to show in the tooltip + * @param {object} options - additional options for the tooltip + * @param {string} [options.style=black] - correlates to the discord styling/colors (black, brand, green, grey, red, yellow) + * @param {string} [options.side=top] - can be any of top, right, bottom, left + * @param {boolean} [options.preventFlip=false] - prevents moving the tooltip to the opposite side if it is too big or goes offscreen + * @param {boolean} [options.isTimestamp=false] - adds the timestampTooltip class (disables text wrapping) + * @param {boolean} [options.disablePointerEvents=false] - disables pointer events + * @param {boolean} [options.disabled=false] - whether the tooltip should be disabled from showing on hover + */ + constructor(node, text, options = {}) { + const {style = "black", side = "top", preventFlip = false, isTimestamp = false, disablePointerEvents = false, disabled = false} = options; + this.node = modules__WEBPACK_IMPORTED_MODULE_0__.DOMTools.resolveElement(node); + this.label = text; + this.style = style.toLowerCase(); + this.side = side.toLowerCase(); + this.preventFlip = preventFlip; + this.isTimestamp = isTimestamp; + this.disablePointerEvents = disablePointerEvents; + this.disabled = disabled; + this.active = false; + + if (!classExists(this.side)) return modules__WEBPACK_IMPORTED_MODULE_0__.Logger.err("Tooltip", `Side ${this.side} does not exist.`); + if (!classExists(this.style)) return modules__WEBPACK_IMPORTED_MODULE_0__.Logger.err("Tooltip", `Style ${this.style} does not exist.`); + + this.element = modules__WEBPACK_IMPORTED_MODULE_0__.DOMTools.createElement(`
`); + this.tooltipElement = modules__WEBPACK_IMPORTED_MODULE_0__.DOMTools.createElement(`
${this.label}
`); + this.labelElement = this.tooltipElement.childNodes[1]; + this.element.append(this.tooltipElement); + + if (this.disablePointerEvents) { + this.element.classList.add(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.TooltipLayers.disabledPointerEvents); + this.tooltipElement.classList.add(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Tooltips.tooltipDisablePointerEvents); + } + if (this.isTimestamp) this.tooltipElement.classList.add(modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("timestampTooltip").timestampTooltip); + + + this.node.addEventListener("mouseenter", () => { + if (this.disabled) return; + this.show(); + }); + + this.node.addEventListener("mouseleave", () => { + this.hide(); + }); + } + + /** Alias for the constructor */ + static create(node, text, options = {}) {return new Tooltip(node, text, options);} + + /** Container where the tooltip will be appended. */ + get container() {return document.querySelector(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordSelectors.App.app.sibling(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordSelectors.TooltipLayers.layerContainer));} + /** Boolean representing if the tooltip will fit on screen above the element */ + get canShowAbove() {return this.node.getBoundingClientRect().top - this.element.offsetHeight >= 0;} + /** Boolean representing if the tooltip will fit on screen below the element */ + get canShowBelow() {return this.node.getBoundingClientRect().top + this.node.offsetHeight + this.element.offsetHeight <= modules__WEBPACK_IMPORTED_MODULE_0__.DOMTools.screenHeight;} + /** Boolean representing if the tooltip will fit on screen to the left of the element */ + get canShowLeft() {return this.node.getBoundingClientRect().left - this.element.offsetWidth >= 0;} + /** Boolean representing if the tooltip will fit on screen to the right of the element */ + get canShowRight() {return this.node.getBoundingClientRect().left + this.node.offsetWidth + this.element.offsetWidth <= modules__WEBPACK_IMPORTED_MODULE_0__.DOMTools.screenWidth;} + + /** Hides the tooltip. Automatically called on mouseleave. */ + hide() { + /** Don't rehide if already inactive */ + if (!this.active) return; + this.active = false; + this.element.remove(); + this.tooltipElement.className = this._className; + } + + /** Shows the tooltip. Automatically called on mouseenter. Will attempt to flip if position was wrong. */ + show() { + /** Don't reshow if already active */ + if (this.active) return; + this.active = true; + this.tooltipElement.className = `${modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Tooltips.tooltip} ${getClass(this.style)}`; + if (this.disablePointerEvents) this.tooltipElement.classList.add(modules__WEBPACK_IMPORTED_MODULE_0__.DiscordClasses.Tooltips.tooltipDisablePointerEvents); + if (this.isTimestamp) this.tooltipElement.classList.add(modules__WEBPACK_IMPORTED_MODULE_0__.WebpackModules.getByProps("timestampTooltip").timestampTooltip); + this.labelElement.textContent = this.label; + this.container.append(this.element); + + if (this.side == "top") { + if (this.canShowAbove || (!this.canShowAbove && this.preventFlip)) this.showAbove(); + else this.showBelow(); + } + + if (this.side == "bottom") { + if (this.canShowBelow || (!this.canShowBelow && this.preventFlip)) this.showBelow(); + else this.showAbove(); + } + + if (this.side == "left") { + if (this.canShowLeft || (!this.canShowLeft && this.preventFlip)) this.showLeft(); + else this.showRight(); + } + + if (this.side == "right") { + if (this.canShowRight || (!this.canShowRight && this.preventFlip)) this.showRight(); + else this.showLeft(); + } + + /** Do not create a new observer each time if one already exists! */ + if (this.observer) return; + /** Use an observer in show otherwise you'll cause unclosable tooltips */ + this.observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + const nodes = Array.from(mutation.removedNodes); + const directMatch = nodes.indexOf(this.node) > -1; + const parentMatch = nodes.some(parent => parent.contains(this.node)); + if (directMatch || parentMatch) { + this.hide(); + this.observer.disconnect(); + } + }); + }); + + this.observer.observe(document.body, {subtree: true, childList: true}); + } + + /** Force showing the tooltip above the node. */ + showAbove() { + this.tooltipElement.classList.add(getClass("top")); + this.element.style.setProperty("top", toPx(this.node.getBoundingClientRect().top - this.element.offsetHeight - 10)); + this.centerHorizontally(); + } + + /** Force showing the tooltip below the node. */ + showBelow() { + this.tooltipElement.classList.add(getClass("bottom")); + this.element.style.setProperty("top", toPx(this.node.getBoundingClientRect().top + this.node.offsetHeight + 10)); + this.centerHorizontally(); + } + + /** Force showing the tooltip to the left of the node. */ + showLeft() { + this.tooltipElement.classList.add(getClass("left")); + this.element.style.setProperty("left", toPx(this.node.getBoundingClientRect().left - this.element.offsetWidth - 10)); + this.centerVertically(); + } + + /** Force showing the tooltip to the right of the node. */ + showRight() { + this.tooltipElement.classList.add(getClass("right")); + this.element.style.setProperty("left", toPx(this.node.getBoundingClientRect().left + this.node.offsetWidth + 10)); + this.centerVertically(); + } + + centerHorizontally() { + const nodecenter = this.node.getBoundingClientRect().left + (this.node.offsetWidth / 2); + this.element.style.setProperty("left", toPx(nodecenter - (this.element.offsetWidth / 2))); + } + + centerVertically() { + const nodecenter = this.node.getBoundingClientRect().top + (this.node.offsetHeight / 2); + this.element.style.setProperty("top", toPx(nodecenter - (this.element.offsetHeight / 2))); + } +} + +/***/ }), + +/***/ "./src/ui/ui.js": +/*!**********************!*\ + !*** ./src/ui/ui.js ***! + \**********************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Tooltip": () => (/* reexport safe */ _tooltip__WEBPACK_IMPORTED_MODULE_2__["default"]), +/* harmony export */ "Toasts": () => (/* reexport safe */ _toasts__WEBPACK_IMPORTED_MODULE_3__["default"]), +/* harmony export */ "Popouts": () => (/* reexport safe */ _popouts__WEBPACK_IMPORTED_MODULE_4__["default"]), +/* harmony export */ "Modals": () => (/* reexport safe */ _modals__WEBPACK_IMPORTED_MODULE_5__["default"]), +/* harmony export */ "DiscordContextMenu": () => (/* reexport safe */ _discordcontextmenu__WEBPACK_IMPORTED_MODULE_6__["default"]), +/* harmony export */ "ErrorBoundary": () => (/* reexport safe */ _errorboundary__WEBPACK_IMPORTED_MODULE_7__["default"]), +/* harmony export */ "ColorPicker": () => (/* reexport safe */ _colorpicker__WEBPACK_IMPORTED_MODULE_8__["default"]), +/* harmony export */ "Settings": () => (/* reexport module object */ _settings__WEBPACK_IMPORTED_MODULE_0__), +/* harmony export */ "Icons": () => (/* reexport module object */ _icons__WEBPACK_IMPORTED_MODULE_1__) +/* harmony export */ }); +/* harmony import */ var _settings__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./settings */ "./src/ui/settings/index.js"); +/* harmony import */ var _icons__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./icons */ "./src/ui/icons.js"); +/* harmony import */ var _tooltip__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./tooltip */ "./src/ui/tooltip.js"); +/* harmony import */ var _toasts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./toasts */ "./src/ui/toasts.js"); +/* harmony import */ var _popouts__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./popouts */ "./src/ui/popouts.js"); +/* harmony import */ var _modals__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./modals */ "./src/ui/modals.js"); +/* harmony import */ var _discordcontextmenu__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./discordcontextmenu */ "./src/ui/discordcontextmenu.js"); +/* harmony import */ var _errorboundary__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./errorboundary */ "./src/ui/errorboundary.js"); +/* harmony import */ var _colorpicker__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./colorpicker */ "./src/ui/colorpicker.js"); + + + + + + + + + + + + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be in strict mode. +(() => { +"use strict"; +/*!**********************!*\ + !*** ./src/index.js ***! + \**********************/ +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var modules__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! modules */ "./src/modules/modules.js"); +/* harmony import */ var ui__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ui */ "./src/ui/ui.js"); + + + +const Library = {}; +Library.DCM = ui__WEBPACK_IMPORTED_MODULE_1__.DiscordContextMenu; +Library.ContextMenu = ui__WEBPACK_IMPORTED_MODULE_1__.DiscordContextMenu; +Library.Tooltip = ui__WEBPACK_IMPORTED_MODULE_1__.Tooltip; +Library.Toasts = ui__WEBPACK_IMPORTED_MODULE_1__.Toasts; +Library.Settings = ui__WEBPACK_IMPORTED_MODULE_1__.Settings; +Library.Popouts = ui__WEBPACK_IMPORTED_MODULE_1__.Popouts; +Library.Modals = ui__WEBPACK_IMPORTED_MODULE_1__.Modals; +for (const mod in modules__WEBPACK_IMPORTED_MODULE_0__) Library[mod] = modules__WEBPACK_IMPORTED_MODULE_0__[mod]; + +Library.Components = {ErrorBoundary: ui__WEBPACK_IMPORTED_MODULE_1__.ErrorBoundary, ColorPicker: ui__WEBPACK_IMPORTED_MODULE_1__.ColorPicker}; + +const config = __webpack_require__(/*! ./src/config.js */ "./src/config.js"); +const baseModule = __webpack_require__(/*! ./src/plugin.js */ "./src/plugin.js"); +const pluginFunction = baseModule.default ? baseModule.default : baseModule; + +const getBoundLibrary = () => { + const name = config.info.name; + const BoundAPI = { + Logger: { + stacktrace: (message, error) => Library.Logger.stacktrace(name, message, error), + log: (...message) => Library.Logger.log(name, ...message), + error: (...message) => Library.Logger.err(name, ...message), + err: (...message) => Library.Logger.err(name, ...message), + warn: (...message) => Library.Logger.warn(name, ...message), + info: (...message) => Library.Logger.info(name, ...message), + debug: (...message) => Library.Logger.debug(name, ...message) + }, + Patcher: { + getPatchesByCaller: () => {return Library.Patcher.getPatchesByCaller(name);}, + unpatchAll: () => {return Library.Patcher.unpatchAll(name);}, + before: (moduleToPatch, functionName, callback, options = {}) => {return Library.Patcher.before(name, moduleToPatch, functionName, callback, options);}, + instead: (moduleToPatch, functionName, callback, options = {}) => {return Library.Patcher.instead(name, moduleToPatch, functionName, callback, options);}, + after: (moduleToPatch, functionName, callback, options = {}) => {return Library.Patcher.after(name, moduleToPatch, functionName, callback, options);} + } + }; + + const BoundLib = Object.assign({}, Library); + BoundLib.Logger = BoundAPI.Logger; + BoundLib.Patcher = BoundAPI.Patcher; + return BoundLib; +}; + +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (pluginFunction(Library.Structs.Plugin(config), false ? 0 : Library)); // eslint-disable-line new-cap +})(); + +module.exports.ZeresPluginLibrary = __webpack_exports__["default"]; +/******/ })() +; +/*@end@*/ \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/AccountDetailsPlus.config.json b/oldconfig/BetterDiscord/plugins/AccountDetailsPlus.config.json new file mode 100644 index 0000000..54b34aa --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/AccountDetailsPlus.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.0.2", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/AccountDetailsPlus.plugin.js b/oldconfig/BetterDiscord/plugins/AccountDetailsPlus.plugin.js new file mode 100644 index 0000000..53f68ef --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/AccountDetailsPlus.plugin.js @@ -0,0 +1,170 @@ +/** + * @name AccountDetailsPlus + * @version 1.0.2 + * @authorLink https://twitter.com/IAmZerebos + * @website https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/AccountDetailsPlus + * @source https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/AccountDetailsPlus/AccountDetailsPlus.plugin.js + * @updateUrl https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/AccountDetailsPlus/AccountDetailsPlus.plugin.js + */ +/*@cc_on +@if (@_jscript) + + // Offer to self-install for clueless users that try to run this directly. + var shell = WScript.CreateObject("WScript.Shell"); + var fs = new ActiveXObject("Scripting.FileSystemObject"); + var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins"); + var pathSelf = WScript.ScriptFullName; + // Put the user at ease by addressing them in the first person + shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30); + if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) { + shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40); + } else if (!fs.FolderExists(pathPlugins)) { + shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10); + } else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) { + fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true); + // Show the user where to put plugins in the future + shell.Exec("explorer " + pathPlugins); + shell.Popup("I'm installed!", 0, "Successfully installed", 0x40); + } + WScript.Quit(); + +@else@*/ + +module.exports = (() => { + const config = {info:{name:"AccountDetailsPlus",authors:[{name:"Zerebos",discord_id:"249746236008169473",github_username:"rauenzi",twitter_username:"ZackRauen"}],version:"1.0.2",description:"Lets you view popout, nickname and more from your account panel at the bottom.",github:"https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/AccountDetailsPlus",github_raw:"https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/AccountDetailsPlus/AccountDetailsPlus.plugin.js"},changelog:[{title:"Fixed",type:"fixed",items:["Fixed username & avatar disappearing."]}],main:"index.js",defaultConfig:[{type:"dropdown",id:"popoutOnClick",name:"Which should be shown on the left click of your avatar? (Opposite will be shown on right click)",value:true,options:[{label:"Status Picker",value:false},{label:"User Popout",value:true}]},{type:"dropdown",id:"nicknameByDefault",name:"Which should be shown by default? (Opposite will be shown on hover)",value:true,options:[{label:"Username",value:false},{label:"Nickname",value:true}]}]}; + + return !global.ZeresPluginLibrary ? class { + constructor() {this._config = config;} + getName() {return config.info.name;} + getAuthor() {return config.info.authors.map(a => a.name).join(", ");} + getDescription() {return config.info.description;} + getVersion() {return config.info.version;} + load() { + BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js"); + await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r)); + }); + } + }); + } + start() {} + stop() {} + } : (([Plugin, Api]) => { + const plugin = (Plugin, Api) => { + const {DiscordModules, DiscordSelectors, WebpackModules, Logger, ReactComponents, Patcher, Utilities} = Api; + + const rawClasses = WebpackModules.getByProps("container", "avatar", "hasBuildOverride"); + const container = DiscordSelectors.AccountDetails.container || `.${rawClasses.container.split(" ").join(".")}`; + const username = `.${rawClasses.usernameContainer.split(" ").join(".")}`; + + const renderUserPopout = (props) => { + const guild = DiscordModules.SelectedGuildStore.getGuildId(); + const channel = DiscordModules.SelectedChannelStore.getChannelId(); + return DiscordModules.React.createElement(DiscordModules.UserPopout, Object.assign({}, props, { + userId: DiscordModules.UserStore.getCurrentUser().id, + guildId: guild, + channelId: channel + })); + }; + + return class AccountDetailsPlus extends Plugin { + + async onStart() { + this.currentUser = DiscordModules.UserStore.getCurrentUser(); + this.promises = {state: {cancelled: false}, cancel() {this.state.cancelled = true;}}; + this.patchAccountAvatar(this.promises.state); + this.patchUsername(); + } + + onStop() { + Patcher.unpatchAll(); + if (this.unpatchUsername) this.unpatchUsername(); + } + + async patchAccountAvatar(promiseState) { + const Account = await ReactComponents.getComponentByName("Account", ".container-YkUktl"); + if (promiseState.cancelled) return; + Patcher.after(Account.component.prototype, "render", (thisObject, _, retAccount) => { + if (!thisObject._renderStatusPickerPopout) thisObject._renderStatusPickerPopout = thisObject.renderStatusPickerPopout; + const popoutWrap = Utilities.findInReactTree(retAccount, (n) => n && typeof(n.children) === "function"); + const popoutWrapRender = popoutWrap.children; + if (!popoutWrap || typeof(popoutWrapRender) !== "function") return retAccount; + popoutWrap.children = (popoutProps) => { + const retPopout = Reflect.apply(popoutWrapRender, thisObject, [popoutProps]); + const avatarWrap = Utilities.getNestedProp(retPopout, "props.children.props"); + const avatarRender = avatarWrap.children; + if (!avatarWrap || !avatarRender) return retPopout; + + avatarWrap.children = avatarProps => { + const originalClick = avatarProps.onClick; + avatarProps.onContextMenu = (e) => { + thisObject.renderStatusPickerPopout = this.settings.popoutOnClick ? thisObject._renderStatusPickerPopout : renderUserPopout; + originalClick(e); + thisObject.forceUpdate(); + }; + avatarProps.onClick = (e) => { + thisObject.renderStatusPickerPopout = this.settings.popoutOnClick ? renderUserPopout : thisObject._renderStatusPickerPopout; + originalClick(e); + thisObject.forceUpdate(); + }; + + return Reflect.apply(avatarRender, thisObject, [avatarProps]); + }; + return retPopout; + }; + }); + } + + getNickname(guildId = DiscordModules.SelectedGuildStore.getGuildId()) { + const nick = DiscordModules.GuildMemberStore.getNick(guildId, this.currentUser.id); + return nick ? nick : this.currentUser.username; + } + + patchUsername() { + this.onSwitch = this.adjustNickname; + const accountDetails = document.querySelector(container); + if (!accountDetails) return Logger.err("Could not find accountDetails element"); + const nameElement = accountDetails.querySelector(username); + + const hoverChange = event => { + const nick = this.getNickname(); + if (this.settings.nicknameByDefault) nameElement.textContent = event.type === "mouseenter" ? this.currentUser.username : nick; + else nameElement.textContent = event.type === "mouseenter" ? nick : this.currentUser.username; + }; + + accountDetails.addEventListener("mouseenter", hoverChange); + accountDetails.addEventListener("mouseleave", hoverChange); + + this.unpatchUsername = () => { + delete this.onSwitch; + accountDetails.removeEventListener("mouseenter", hoverChange); + accountDetails.removeEventListener("mouseleave", hoverChange); + nameElement.textContent = this.currentUser.username; + }; + + this.adjustNickname(); + } + + adjustNickname() { + const accountDetails = document.querySelector(container); + if (!accountDetails) return Logger.err("Could not find accountDetails element"); + const nameElement = accountDetails.querySelector(username); + const nick = this.getNickname(); + if (this.settings.nicknameByDefault) nameElement.textContent = nick; + else nameElement.textContent = this.currentUser.username; + } + + getSettingsPanel() { + return this.buildSettingsPanel().getElement(); + } + + }; +}; + return plugin(Plugin, Api); + })(global.ZeresPluginLibrary.buildPlugin(config)); +})(); +/*@end@*/ \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/Animations.config.json b/oldconfig/BetterDiscord/plugins/Animations.config.json new file mode 100644 index 0000000..8c1a25e --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/Animations.config.json @@ -0,0 +1,82 @@ +{ + "currentVersionInfo": { + "version": "1.2.10.3", + "hasShownChangelog": true + }, + "settings": { + "lists": { + "enabled": true, + "name": "brick-up", + "page": 0, + "sequence": "fromFirst", + "selectors": "", + "custom": { + "enabled": false, + "frames": [ + "", + "", + "", + "" + ], + "page": 0 + }, + "duration": 0.4, + "delay": 0.04, + "limit": 65 + }, + "buttons": { + "enabled": true, + "name": "brick-down", + "page": 0, + "sequence": "fromFirst", + "selectors": "", + "custom": { + "enabled": false, + "frames": [ + "", + "", + "", + "" + ], + "page": 0 + }, + "duration": 0.3, + "delay": 0.2 + }, + "messages": { + "enabled": true, + "name": "brick-down", + "page": 0, + "custom": { + "enabled": false, + "frames": [ + "", + "", + "", + "" + ], + "page": 0 + }, + "duration": 0.4, + "delay": 0.04, + "limit": 30 + }, + "popouts": { + "enabled": true, + "name": "slide-up", + "page": 0, + "selectors": "", + "custom": { + "enabled": false, + "frames": [ + "", + "", + "", + "" + ], + "page": 0 + }, + "duration": 0.5 + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/AutoIdleOnAFK.config.json b/oldconfig/BetterDiscord/plugins/AutoIdleOnAFK.config.json new file mode 100644 index 0000000..07fbccd --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/AutoIdleOnAFK.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.3.0", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BDContextMenu.config.json b/oldconfig/BetterDiscord/plugins/BDContextMenu.config.json new file mode 100644 index 0000000..56adc66 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BDContextMenu.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.1.10", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BDContextMenu.plugin.js b/oldconfig/BetterDiscord/plugins/BDContextMenu.plugin.js new file mode 100644 index 0000000..31f88b4 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BDContextMenu.plugin.js @@ -0,0 +1,157 @@ +/** + * @name BDContextMenu + * @version 0.1.10 + * @authorLink https://twitter.com/IAmZerebos + * @website https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/BDContextMenu + * @source https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/BDContextMenu/BDContextMenu.plugin.js + * @updateUrl https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/BDContextMenu/BDContextMenu.plugin.js + */ +/*@cc_on +@if (@_jscript) + + // Offer to self-install for clueless users that try to run this directly. + var shell = WScript.CreateObject("WScript.Shell"); + var fs = new ActiveXObject("Scripting.FileSystemObject"); + var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins"); + var pathSelf = WScript.ScriptFullName; + // Put the user at ease by addressing them in the first person + shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30); + if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) { + shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40); + } else if (!fs.FolderExists(pathPlugins)) { + shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10); + } else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) { + fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true); + // Show the user where to put plugins in the future + shell.Exec("explorer " + pathPlugins); + shell.Popup("I'm installed!", 0, "Successfully installed", 0x40); + } + WScript.Quit(); + +@else@*/ + +module.exports = (() => { + const config = {info:{name:"BDContextMenu",authors:[{name:"Zerebos",discord_id:"249746236008169473",github_username:"rauenzi",twitter_username:"ZackRauen"}],version:"0.1.10",description:"Adds BD shortcuts to the settings context menu.",github:"https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/BDContextMenu",github_raw:"https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/BDContextMenu/BDContextMenu.plugin.js"},changelog:[{title:"Bugfixes",type:"fixed",items:["Context menu should show up again.","Scrollers in submenus show up again."]}],main:"index.js"}; + + return !global.ZeresPluginLibrary ? class { + constructor() {this._config = config;} + getName() {return config.info.name;} + getAuthor() {return config.info.authors.map(a => a.name).join(", ");} + getDescription() {return config.info.description;} + getVersion() {return config.info.version;} + load() { + BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js"); + await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r)); + }); + } + }); + } + start() {} + stop() {} + } : (([Plugin, Api]) => { + const plugin = (Plugin, Api) => { + const {Patcher, DiscordModules, DCM, PluginUtilities} = Api; + + const collections = window.BdApi.settings; + const css = `#user-settings-cog-BetterDiscord--Settings + .layer-2aCOJ3 .submenu-1apzyU .scroller-1bVxF5 { + max-height: 320px; +} + +#user-settings-cog-BetterDiscord--Emotes + .layer-2aCOJ3 .submenu-1apzyU .scroller-1bVxF5 { + max-height: 320px; +} + +#user-settings-cog-BetterDiscord--Plugins + .layer-2aCOJ3 .submenu-1apzyU .scroller-1bVxF5 { + max-height: 320px; +} + +#user-settings-cog-BetterDiscord--Themes + .layer-2aCOJ3 .submenu-1apzyU .scroller-1bVxF5 { + max-height: 320px; +}`; + + return class BDContextMenu extends Plugin { + + async onStart() { + this.promises = {state: {cancelled: false}, cancel() {this.state.cancelled = true;}}; + this.patchSettingsContextMenu(this.promises.state); + PluginUtilities.addStyle("BDCM", css); + } + + onStop() { + this.promises.cancel(); + PluginUtilities.removeStyle("BDCM"); + Patcher.unpatchAll(); + } + + async patchSettingsContextMenu(promiseState) { + const SettingsContextMenu = await DCM.getDiscordMenu("UserSettingsCogContextMenu"); + if (promiseState.cancelled) return; + Patcher.after(SettingsContextMenu, "default", (component, args, retVal) => { + const items = collections.map(c => this.buildCollectionMenu(c)); + items.push({label: "Custom CSS", action: () => {this.openCategory("custom css");}}); + items.push(this.buildAddonMenu("Plugins", window.BdApi.Plugins)); + items.push(this.buildAddonMenu("Themes", window.BdApi.Themes)); + retVal.props.children.push(DCM.buildMenuItem({type: "separator"})); + retVal.props.children.push(DCM.buildMenuItem({type: "submenu", label: "BetterDiscord", items: items})); + }); + } + + buildCollectionMenu(collection) { + return { + type: "submenu", + label: collection.name, + action: () => {this.openCategory(collection.name.toLowerCase());}, + items: collection.settings.map(category => { + return { + type: "submenu", + label: category.name, + action: () => () => {this.openCategory(collection.name.toLowerCase());}, + items: category.settings.filter(s => s.type === "switch" && !s.hidden).map(setting => { + return { + type: "toggle", + label: setting.name, + active: window.BdApi.isSettingEnabled(collection.id, category.id, setting.id), + action: () => window.BdApi.toggleSetting(collection.id, category.id, setting.id) + }; + }) + }; + }) + }; + } + + buildAddonMenu(label, manager) { + const ids = manager.getAll().map(a => a.name || a.getName()).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())); + return { + type: "submenu", + label: label, + action: () => {this.openCategory(label.toLowerCase());}, + items: ids.map(addon => { + return { + type: "toggle", + label: addon, + active: manager.isEnabled(addon), + action: () => {manager.toggle(addon);} + }; + }) + }; + } + + async openCategory(id) { + DiscordModules.ContextMenuActions.closeContextMenu(); + DiscordModules.UserSettingsWindow.open(DiscordModules.DiscordConstants.UserSettingsSections.ACCOUNT); + while (!document.getElementsByClassName("bd-sidebar-header").length) await new Promise(r => setTimeout(r, 100)); + const tabs = document.querySelectorAll(".bd-sidebar-header ~ .item-PXvHYJ"); + const index = Array.from(tabs).findIndex(e => e.textContent.toLowerCase() === id); + if (tabs[index] && tabs[index].click) tabs[index].click(); + } + }; +}; + return plugin(Plugin, Api); + })(global.ZeresPluginLibrary.buildPlugin(config)); +})(); +/*@end@*/ \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/Better Media Player.config.json b/oldconfig/BetterDiscord/plugins/Better Media Player.config.json new file mode 100644 index 0000000..0f158a3 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/Better Media Player.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.2.4", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BetterCodeblocks.config.json b/oldconfig/BetterDiscord/plugins/BetterCodeblocks.config.json new file mode 100644 index 0000000..b0fccc0 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterCodeblocks.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.3.3", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BetterFolders.config.json b/oldconfig/BetterDiscord/plugins/BetterFolders.config.json new file mode 100644 index 0000000..0821bb1 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterFolders.config.json @@ -0,0 +1,6 @@ +{ + "settings": { + "closeOnOpen": true, + "folders": {} + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BetterFormattingRedux.config.json b/oldconfig/BetterDiscord/plugins/BetterFormattingRedux.config.json new file mode 100644 index 0000000..9a48591 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterFormattingRedux.config.json @@ -0,0 +1,58 @@ +{ + "currentVersionInfo": { + "version": "2.3.12", + "hasShownChangelog": true + }, + "settings": { + "toolbar": { + "bold": true, + "italic": true, + "underline": true, + "strikethrough": true, + "spoiler": true, + "code": true, + "codeblock": true, + "superscript": true, + "smallcaps": true, + "fullwidth": true, + "upsidedown": true, + "varied": true, + "leet": false, + "thicc": false + }, + "formats": { + "superscript": true, + "smallcaps": true, + "fullwidth": true, + "upsidedown": true, + "varied": true, + "leet": false, + "thicc": false + }, + "wrappers": { + "superscript": "^^", + "smallcaps": "%%", + "fullwidth": "##", + "upsidedown": "&&", + "varied": "==", + "leet": "++", + "thicc": "$$" + }, + "formatting": { + "fullWidthMap": true, + "reorderUpsidedown": true, + "fullwidth": true + }, + "plugin": { + "hoverOpen": true, + "chainFormats": true, + "closeOnSend": true + }, + "style": { + "icons": true, + "rightSide": true, + "toolbarOpacity": 1, + "fontSize": 85 + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BetterFriendList.config.json b/oldconfig/BetterDiscord/plugins/BetterFriendList.config.json new file mode 100644 index 0000000..37df72b --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterFriendList.config.json @@ -0,0 +1,12 @@ +{ + "all": { + "general": { + "addTotalAmount": true, + "addFavorizedCategory": true, + "addHiddenCategory": true, + "addSortOptions": true, + "addSearchbar": true, + "addMutualGuild": true + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BetterInvites.config.json b/oldconfig/BetterDiscord/plugins/BetterInvites.config.json new file mode 100644 index 0000000..aa7086a --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterInvites.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.6.1", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BetterInvites.plugin.js b/oldconfig/BetterDiscord/plugins/BetterInvites.plugin.js new file mode 100644 index 0000000..46980a8 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterInvites.plugin.js @@ -0,0 +1,279 @@ +/** + * @name BetterInvites + * @author HypedDomi#1711 + * @authorId 354191516979429376 + * @version 1.6.1 + * @description Shows some useful information in the invitation + * @invite gp2ExK5vc7 + * @source https://github.com/HypedDomi/BetterDiscordStuff/tree/main/Plugins/BetterInvites + * @updateUrl https://betterdiscord.app/gh-redirect/?id=539 + * @donate https://paypal.me/dominik1711 + * @website https://bd.bambus.me/ + */ + +const request = require("request"); +const fs = require("fs"); +const path = require("path"); + +const config = { + info: { + name: "BetterInvites", + authors: [ + { + name: "HypedDomi", + discord_id: "354191516979429376", + }, + ], + version: "1.6.1", + description: + "Shows some useful information in the invitation", + github: + "https://github.com/HypedDomi/BetterDiscordStuff/tree/main/Plugins/BetterInvites", + github_raw: + "https://raw.githubusercontent.com/HypedDomi/BetterDiscordStuff/main/Plugins/BetterInvites/BetterInvites.plugin.js", + }, + changelog: [ + { + title: "What's new", + type: "added", + items: ["Added Option to change Discords Splash to the Guild Banner"], + }, + { + title: "Small Bugfix", + type: "fixed", + items: ["Fixed wrong order"], + } + ], + defaultConfig: [ + { + type: "switch", + id: "showBanner", + name: "Show Banner on Invite", + value: true, + }, + { + type: "dropdown", + id: "bannerType", + name: "Banner Type", + note: "The type of banner to show", + value: 0, + options: [ + { label: "BetterInvites Banner", value: 0 }, + { label: "Discord Invite Splash", value: 1 } + ] + }, + { + type: "switch", + id: "showServerBannerForSplash", + name: "Shows the Server Banner instead of the Invite Banner", + note: "Only works for Discord Invite Splash", + value: false, + }, + { + type: "switch", + id: "showDescription", + name: "Show Guild Description", + value: true, + }, + { + type: "switch", + id: "showBoost", + name: "Show Guild Boost Level", + value: true, + }, + { + type: "switch", + id: "showInviter", + name: "Show the User who invited you", + value: true, + }, + { + type: "switch", + id: "showVerification", + name: "Show Guild Verification Level", + value: true, + }, + { + type: "switch", + id: "showNSFW", + name: "Show Guild NSFW Status", + value: true, + }, + { + type: "switch", + id: "showExpire", + name: "Show Invite Expiration", + value: true, + }, + { + type: "switch", + id: "bigJoinButton", + name: "Shows a bigger join button", + value: true, + }, + + ] +}; + +module.exports = !global.ZeresPluginLibrary + ? class { + constructor() { + this._config = config; + } + + load() { + BdApi.showConfirmationModal( + "Library plugin is needed", + `The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`, + { + confirmText: "Download", + cancelText: "Cancel", + onConfirm: () => { + request.get( + "https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", + (error, response, body) => { + if (error) + return electron.shell.openExternal( + "https://betterdiscord.app/Download?id=9" + ); + + fs.writeFileSync( + path.join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), + body + ); + } + ); + }, + } + ); + } + start() { + this.load(); + } + stop() { } + } + : (([Plugin, Library]) => { + const { Patcher, DiscordModules, PluginUtilities } = Library; + const { React } = DiscordModules; + const Invite = BdApi.findModule(m => m.default?.displayName === "GuildInvite"); + const TooltipContainer = BdApi.findModuleByProps('TooltipContainer').TooltipContainer; + class BetterInvites extends Plugin { + constructor() { + super(); + this.getSettingsPanel = () => { + return this.buildSettingsPanel().getElement(); + }; + } + onStart() { + this.patchInvite(); + PluginUtilities.addStyle(this.getName(), ".content-1r-J1r { flex-wrap: wrap; }"); + } + + patchInvite() { + Patcher.after(Invite, "default", (_, [props], component) => { + const { invite } = props; + if (!invite) return; + const { guild, inviter } = invite; + + let expireTooltip = ""; + if (invite.expires_at != null) { + const inviteExpireDays = Math.floor((new Date(invite.expires_at) - Date.now()) / 1000 / 60 / 60 / 24); + const inviteExpireHours = Math.floor((new Date(invite.expires_at) - Date.now()) / 1000 / 60 / 60); + const inviteExpireMinutes = Math.floor((new Date(invite.expires_at) - Date.now()) / 1000 / 60); + + if (inviteExpireDays > 0) { + inviteExpireDays === 1 ? expireTooltip = `${inviteExpireDays} day` : expireTooltip = `${inviteExpireDays} days`; + } else if (inviteExpireHours > 0) { + inviteExpireHours === 1 ? expireTooltip = `${inviteExpireHours} hour` : expireTooltip = `${inviteExpireHours} hours`; + } else { + inviteExpireMinutes === 1 ? expireTooltip = `${inviteExpireMinutes} minute` : expireTooltip = `${inviteExpireMinutes} minutes`; + } + } + + const boostLevel = component.props.children[2].props.children[0].props.guild?.premiumTier; + component.props.children[2].props.children.splice(2, 0, + this.settings.showBoost || this.settings.showInviter || this.settings.showVerification || this.settings.showNSFW || this.settings.showExpire ? + React.createElement("div", { className: `${config.info.name}-iconWrapper`, style: { display: "grid", grid: "auto / auto auto", direction: "rtl", "grid-gap": "3px" } }, + // Boost + this.settings.showBoost && boostLevel > 0 ? + React.createElement(TooltipContainer, { text: `Boost Level ${boostLevel}` }, + React.createElement("img", { style: { height: "28px", borderRadius: "5px", objectFit: "contain" }, src: "https://discord.com/assets/4a2618502278029ce88adeea179ed435.svg" })) + : null, + // Inviter + this.settings.showInviter && inviter ? + React.createElement(TooltipContainer, { text: `Invited by: ${inviter?.username}#${inviter?.discriminator}` }, + React.createElement("img", { style: { height: "28px", borderRadius: "5px", objectFit: "contain" }, onClick: () => { DiscordNative.clipboard.copy(inviter?.id); window.BdApi.showToast("Copied ID", { type: "info", icon: true, timeout: 4000 }) }, src: `https://cdn.discordapp.com/avatars/${inviter?.id}/${inviter?.avatar}.png?size=1024`, onError: (e) => { e.target.src = "https://cdn.discordapp.com/embed/avatars/0.png"; } })) + : null, + // Verification + this.settings.showVerification && guild?.verification_level > 0 ? + React.createElement(TooltipContainer, { text: `Verification Level ${guild?.verification_level}` }, + React.createElement("img", { style: { height: "28px", borderRadius: "5px", objectFit: "contain" }, src: "https://discord.com/assets/e62b930d873735bbede7ae1785d13233.svg" })) + : null, + // NSFW + this.settings.showNSFW && guild?.nsfw_level > 0 ? + React.createElement(TooltipContainer, { text: `NSFW Level ${guild?.nsfw_level}` }, + React.createElement("img", { style: { height: "28px", borderRadius: "5px", objectFit: "contain" }, src: "https://discord.com/assets/ece853d6c1c1cd81f762db6c26fade40.svg" })) + : null, + // Invite Expiration + this.settings.showExpire && invite.expires_at != null ? + React.createElement(TooltipContainer, { text: `Expires in: ${expireTooltip}` }, + React.createElement("img", { style: { height: "28px", borderRadius: "5px", objectFit: "contain" }, src: "https://discord.com/assets/630f5938948131784285d97d57a3e8a0.svg" })) + : null, + ) : null + ); + + const contentDiv = component.props.children[2]; + + if (this.settings.showDescription && guild?.description) { + contentDiv.props.children.push( + React.createElement("div", { className: `${config.info.name}-guildDescription`, style: { marginTop: "1%" } }, + React.createElement("div", { className: "markup-eYLPri" }, guild.description) + ) + ); + } + + if (this.settings.bigJoinButton) { + const joinButton = contentDiv.props.children[3]; + contentDiv.props.children.splice(3, 1); + joinButton.props.style = { + width: "100%", + margin: "3% 0 0 0" + }; + contentDiv.props.children.push(joinButton); + } + + + if (!this.settings.showBanner && guild.features.includes("INVITE_SPLASH")) { + component.props.children.splice(0, 1); + } else if (this.settings.showBanner && guild?.banner) { + if (this.settings.bannerType === 1 && this.settings.showServerBannerForSplash) { + if (guild.features.includes("INVITE_SPLASH")) component.props.children.splice(0, 1); + component.props.children.splice(0, 0, React.createElement("div", { + className: `${config.info.name}-banner`, + style: { position: "relative", borderRadius: "4px 4px 0 0", height: "64px", margin: "-16px -16px 16px", overflow: "hidden" } + }, + React.createElement("img", { + style: { display: "block", width: "100%", height: "100%", objectFit: "cover" }, + src: `https://cdn.discordapp.com/banners/${guild.id}/${guild.banner}.gif?size=1024`, + onError: (e) => { e.target.onError = null, e.target.src = `https://cdn.discordapp.com/banners/${guild.id}/${guild.banner}.png?size=1024` } + }))); + } else if (this.settings.bannerType === 0) { + component.props.children.splice(2, 0, React.createElement("img", { + className: `${config.info.name}-banner`, + src: `https://cdn.discordapp.com/banners/${guild.id}/${guild.banner}.gif?size=1024`, + style: { width: "100%", height: "auto", maxHeight: "100px", borderRadius: "5px", objectFit: "cover" }, + onError: (e) => { e.target.onError = null, e.target.src = `https://cdn.discordapp.com/banners/${guild.id}/${guild.banner}.png?size=1024` } + })); + if (guild.features.includes("INVITE_SPLASH")) component.props.children.splice(0, 1); + } + } + }); + } + + onStop() { + Patcher.unpatchAll(); + PluginUtilities.removeStyle(this.getName()); + } + } + return BetterInvites; + })(global.ZeresPluginLibrary.buildPlugin(config)); diff --git a/oldconfig/BetterDiscord/plugins/BetterMessageLinks.config.json b/oldconfig/BetterDiscord/plugins/BetterMessageLinks.config.json new file mode 100644 index 0000000..2757c75 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterMessageLinks.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.4.12", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BetterMessageLinks.plugin.js b/oldconfig/BetterDiscord/plugins/BetterMessageLinks.plugin.js new file mode 100644 index 0000000..62012c3 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterMessageLinks.plugin.js @@ -0,0 +1,690 @@ +/** + * @name BetterMessageLinks + * @author AGreenPig + * @updateUrl https://raw.githubusercontent.com/TheGreenPig/BetterDiscordPlugins/main/BetterMessageLinks/BetterMessageLinks.plugin.js + * @authorLink https://github.com/TheGreenPig + * @source https://github.com/TheGreenPig/BetterDiscordPlugins/blob/main/BetterMessageLinks/BetterMessageLinks.plugin.js + * @invite JsqBVSCugb + */ + const config = { + "info": { + "name": "BetterMessageLinks", + "authors": [{ + "name": "AGreenPig", + "discord_id": "427179231164760066", + "github_username": "TheGreenPig" + }], + "version": "1.4.12", + "description": "Instead of just showing the long and useless discord message link, make it smaller and add a preview. Thanks a ton Strencher for helping me refactor my code and Juby for making the message queueing system. ", + "github_raw": "https://raw.githubusercontent.com/TheGreenPig/BetterDiscordPlugins/main/BetterMessageLinks/BetterMessageLinks.plugin.js", + }, + "changelog": [ + { + "title": "Fixed", + "type": "fixed", + "items": [ + "Fixed crashing issue", + ] + }, + ], +} + +/* ----Useful links---- + * + * BetterDiscord BdApi documentation: + * https://github.com/BetterDiscord/BetterDiscord/wiki/Creating-Plugins + * + * Zere's Plugin Library documentation: + * https://rauenzi.github.io/BDPluginLibrary/docs/ +*/ + + +// This plugin was only made possible by the generous help of Strencher and the MessageLinkEmbed plugin by him and Juby210! They definitely deserve all the credit + +module.exports = !global.ZeresPluginLibrary ? class { + constructor() { this._config = config; } + getName() { return config.info.name; } + getAuthor() { return config.info.authors.map(a => a.name).join(", "); } + getDescription() { return config.info.description; } + getVersion() { return config.info.version; } + load() { + BdApi.showConfirmationModal("Library Missing", `The library plugin needed for **${config.info.name}** is missing. Please click Download Now to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://betterdiscord.app/Download?id=9"); + await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r)); + }); + } + }); + } + start() { } + stop() { } +} : (([Plugin, Library]) => { + //Custom css + const customCSS = ` + .betterMessageLinks.Popout { + max-width: 280px; + font-size: 14px; + width: fit-content; + max-height: 450px; + overflow: auto; + -webkit-user-select: text; + background: var(--background-floating); + border-radius: 4px; + padding: 1em; + color: var(--text-normal); + overflow-wrap: break-word; + word-wrap: break-word; + -webkit-box-shadow: var(--elevation-high); + box-shadow: var(--elevation-high); + } + .betterMessageLinks em { + font-style: italic; + } + .betterMessageLinks.Settings.Spinner div.info-2FZci4 { + display: flex; + } + .betterMessageLinks.Settings.Spinner div.size14-3fJ-ot:not(.description-30xx7u){ + margin-left: auto; + } + .betterMessageLinks.Loading { + display: flex; + align-items: center; + } + .betterMessageLinks.Loading.Spinner { + padding-left: 1.5em; + } + .betterMessageLinks.Loading.Text { + vertical-align: middle; + } + .betterMessageLinks strong { + font-weight: bold; + } + .betterMessageLinks code { + white-space: pre-wrap; + } + .betterMessageLinks blockquote { + max-width: calc(100% - 4px); + } + + .betterMessageLinks.Author{ + font-weight: bold; + } + .betterMessageLinks.Image { + border-radius: 10px; + max-width: 250px; + padding-top: 5px; + } + .betterMessageLinks.AlignMiddle{ + vertical-align: middle; + } + .betterMessageLinks.Icon{ + width: 25px; + height: 25px; + } + .betterMessageLinks.Footer{ + color: var(--text-muted); + font-size: 0.6rem; + padding-top: 8px; + } + .betterMessageLinks.BotTag{ + padding-left: 5px; + padding-right: 5px; + } + .betterMessageLinks.List{ + padding-left: 20px; + -webkit-user-select: text; + padding-top: 3px; + } + .betterMessageLinks.ListElement{ + font-weight: bold; + } + .betterMessageLinks.ListElement.Symbol{ + font-size: 1.1em; + padding-right: 3px; + } + ` + + + const defaultSettings = { + ignoreMessage: false, + ignoreAttachment: false, + messageReplaceText: "", + attachmentReplaceText: "", + showAuthorIcon: true, + showGuildIcon: true, + noDisplayIfSameGuild: true, + progressBar: true, + spinner: 0, + mentionStyle: true, + animationType: "TRANSLATE", + advancedFooter: `$guildName, $channelName at $timestamp`, + }; + const validFooterValues = ["authorName", "guildName", "guildId", "channelName", "channelId", "messageId", "timestamp", "nsfw"] + + //Settings and imports + const { WebpackModules, Patcher, Settings, DiscordModules } = { ...BdApi, ...Library }; + const { SettingPanel, Switch, Slider, RadioGroup, Textbox, SettingGroup } = Settings; + /**@type {typeof import("react")} */ + const React = DiscordModules.React; + //Modules + const MessageStore = WebpackModules.getByProps("hasCurrentUserSentMessage", "getMessage"); + const GetGuildModule = DiscordModules.GuildStore; + const GetChannelModule = DiscordModules.ChannelStore; + const User = WebpackModules.find(m => m.prototype && m.prototype.tag); + const Timestamp = WebpackModules.find(m => m.prototype && m.prototype.toDate && m.prototype.month) + const { stringify } = WebpackModules.getByProps('stringify', 'parse', 'encode'); + const ImagePlaceHolder = WebpackModules.findByDisplayName("ImagePlaceholder"); + const BotTag = WebpackModules.getByProps("BotTagTypes").default; + const Popout = WebpackModules.getByDisplayName("Popout"); + const RenderMessageMarkupToASTModule = WebpackModules.getByProps("renderMessageMarkupToAST"); + const RepliedMessage = WebpackModules.getModule(m => m && m.default && m.default.displayName == "RepliedMessage"); + const MarkdownModule = WebpackModules.getByProps("parseTopic"); + const Anchor = WebpackModules.findByDisplayName("Anchor"); + let cache = {}; + let lastFetch = 0; + let linkQueue = []; + const spinnerTypes = Object.values(DiscordModules.Spinner.Type); + + let spinnerSetting = []; + spinnerTypes.forEach((spinnerType, i) => { + let name = spinnerType.replace(/([A-Z])/g, " $1"); + name = name.charAt(0).toUpperCase() + name.slice(1); + spinnerSetting.push({ + name: name, + desc: React.createElement(DiscordModules.Spinner, { type: spinnerType },), + value: i + }) + }) + + const popoutAnimationTypes = Object.keys(Popout.Animation); + + let animationSetting = []; + popoutAnimationTypes.forEach((animationType, i) => { + let name = animationType.toLowerCase(); + name = name.charAt(0).toUpperCase() + name.slice(1); + animationSetting.push({ + name: name, + desc: "", + value: animationType + }) + }) + + + + async function getMsg(channelId, messageId) { + let message = MessageStore.getMessage(channelId, messageId) || cache[messageId] + + if (!message) { + if (lastFetch > Date.now() - 2500) await new Promise(r => setTimeout(r, 2500)) + const data = await DiscordModules.APIModule.get({ + url: DiscordModules.DiscordConstants.Endpoints.MESSAGES(channelId), + query: stringify({ + limit: 1, + around: messageId + }), + retries: 2 + }).catch((error) => { + return error; + }) + lastFetch = Date.now() + if (data.ok) { + message = data.body[0] + + if (!message) return + + message.author = new User(message.author) + message.timestamp = new Timestamp(message.timestamp) + } else { + cache[messageId] = data; + return data; + } + + } + cache[messageId] = message + return message; + } + const getMsgWithQueue = (() => { + let pending = Promise.resolve() + + const run = async (channelId, messageId, component) => { + try { + await pending + } finally { + linkQueue.shift() + linkQueue.forEach(c => { + c.setState({ queue: linkQueue }) + }) + + return getMsg(channelId, messageId) + } + } + + return (channelId, messageId, component) => (pending = run(channelId, messageId, component)) + })() + + class BetterLink extends React.Component { + constructor(props) { + super(props) + this.state = { loaded: false, message: null }; + } + async componentDidMount() { + if (!this.state.loaded) { + let numberMatches = this.props.original.split("/").filter((e) => /^\d+$/.test(e)); + let messageId = numberMatches[numberMatches.length - 1]; + let channelId = numberMatches[numberMatches.length - 2]; + let guildId = numberMatches.length > 2 ? numberMatches[numberMatches.length - 3] : undefined; + + linkQueue.push(this) + this.setState({ originalIndex: linkQueue.length, queue: linkQueue }) + let message = await getMsgWithQueue(channelId, messageId, this) + + if (!message) return + message.guild = guildId ? GetGuildModule.getGuild(guildId) : "@me"; + this.setState({ loaded: true, message }); + + } + } + + renderLoading() { + let loadedPercent = Math.max(Math.min(Math.round(((this.state.originalIndex - this.state.queue.indexOf(this)) / this.state.originalIndex) * 100), 100), 0); + return React.createElement("div", { className: "betterMessageLinks AlignMiddle Loading" }, + React.createElement("span", { className: "betterMessageLinks AlignMiddle Loading Text" }, `Loading ... ${loadedPercent}%`), + React.createElement("span", { className: "betterMessageLinks AlignMiddle Loading Spinner" }, + React.createElement(DiscordModules.Spinner, { type: spinnerTypes[this.props.settings.spinner] }) + ), + ) + + } + + renderError(message) { + let content = "Unknown Error while trying to fetch message." + if (message.body?.message) { + content = `Error: ${message.body?.message}`; + } + return React.createElement("div", { className: "betterMessageLinks AlignMiddle Error" }, + React.createElement("span", { className: "betterMessageLinks AlignMiddle Loading Text" }, content), + ) + + } + + renderHeader(message, hasAttachments) { + const { settings } = this.props; + + return React.createElement("div", { + className: "betterMessageLinks-header", + children: [ + settings.showGuildIcon && message.guild?.id && (message.guild?.id !== DiscordModules.SelectedGuildStore.getGuildId() || !settings.noDisplayIfSameGuild) + ? React.createElement("img", { src: `https://cdn.discordapp.com/icons/${message.guild.id}/${message.guild.icon}.webp`, className: "replyAvatar-sHd2sU betterMessageLinks AlignMiddle Icon" }) + : null, + settings.showAuthorIcon + ? React.createElement("img", { src: message.author.getAvatarURL(), className: "replyAvatar-sHd2sU betterMessageLinks AlignMiddle Icon" }) + : null, + React.createElement("span", { className: "betterMessageLinks Author AlignMiddle" }, message.author.username), + settings.showAuthorIcon && message.author.bot + ? React.createElement("span", { className: "betterMessageLinks AlignMiddle BotTag" }, React.createElement(BotTag, {})) + : null, + React.createElement("span", { className: "betterMessageLinks Author AlignMiddle", style: { paddingLeft: "0px" } }, ":"), + hasAttachments + ? React.createElement(ImagePlaceHolder, { width: "20px", height: "20px", class: "betterMessageLinks AlignMiddle" }) + : null + ] + }) + } + + renderContent(message) { + let content = null; + + if (this.props.attachmentLink) { + content = this.props.original.split("/").pop(); + } else { + content = this.processNewLines(RenderMessageMarkupToASTModule.default(Object.assign({}, message), { renderMediaEmbeds: true, formatInline: false, isInteracting: true }).content); + } + + return React.createElement("span", { + className: "betterMessageLinks AlignMiddle" + }, content); + } + + renderAttachment(message) { + if (message.attachments?.length > 0 || message.embeds?.length > 0 || message.sticker_items?.length > 0) { + let isVideo = false; + let url = ""; + + if (message.attachments[0]?.content_type?.startsWith("video") || message.embeds[0]?.video) { + isVideo = true; + } + + if (message.attachments?.length > 0) { + url = message.attachments[0].url + } + else if (message.embeds?.length > 0) { + if (message.embeds[0]?.video) { + url = message.embeds[0].video.url + } + else if (message.embeds[0]?.image) { + url = message.embeds[0]?.image.proxyURL; + } + } else if (message.sticker_items?.length > 0) { + url = `https://media.discordapp.net/stickers/${message.sticker_items[0].id}.png`; + } + if (!url) return null; + + return isVideo ? + React.createElement("video", { + className: "betterMessageLinks AlignMiddle Image", + src: url, + loop: true, autoPlay: true, muted: true, + }) + : React.createElement("img", { + className: "betterMessageLinks AlignMiddle Image", + src: url, + }) + } + return null; + } + + renderBetterFooter(advancedFooter, message) { + if (advancedFooter === "") return; + let channel = GetChannelModule.getChannel(message.channel_id); + let author = message?.author; + let authorName = author.username; + let authorId = author.id; + let guildName, guildId = ""; + let channelName = ""; + let channelId = channel?.id; + let messageId = message.id; + let timestamp = new Date(message.timestamp).toLocaleString(); + let nsfw = channel?.nsfw; + + if (channel) { + if (channel?.type === DiscordModules.DiscordConstants.ChannelTypes.DM) { + guildName = "DM"; + guildId = "@me"; + channelName = channel.rawRecipients[0].username; + } + else if (channel?.type === DiscordModules.DiscordConstants.ChannelTypes.GROUP_DM) { + guildName = "DMs" + guildId = "@me"; + channelName = channel.rawRecipients.map((e) => e.username).slice(0, 3).join("-"); + } + else { + if (message.guild) { + guildName = message.guild.name; + guildId = message.guild.id; + } + channelName = "#" + channel.name; + } + } + + //not the prettiest solution, but the best I could come up with currently without using eval or writing data.channel, data.guild, etc. 🤷‍♂️ should be ok for now, maybe I can rework it later + const data = { + authorName: authorName, + authorId: authorId, + guildName: guildName, + guildId: guildId, + channelName: channelName, + channelId: channelId, + messageId: messageId, + timestamp: timestamp, + nsfw: nsfw + }; + + let footer = advancedFooter; + validFooterValues.forEach((value) => { + footer = footer.replace("$" + value, data[value]) + }) + if (footer.includes("$")) footer = "Invalid variables set! Make sure you don't use $ unless it's a valid variable." + return React.createElement("div", { + className: "betterMessageLinks Footer" + }, footer); + } + renderAttachmentLink(link) { + let validImageExtensions = ["jpg", "jpeg", "png", "gif", "gifv", "apng", "avif", "jfif", "pjpeg", "pjp", "svg", "webp"] + let validVideoExtensions = ["mp4", "webm", "ogg"]; + let extension = link.split(".").pop(); + + let preview = null; + if (validVideoExtensions.includes(extension)) { + preview = React.createElement("video", { + className: "betterMessageLinks AlignMiddle Image", + src: link, + loop: true, autoPlay: true, muted: true, + }) + } + else if (validImageExtensions.includes(extension)) { + preview = React.createElement("img", { + className: "betterMessageLinks AlignMiddle Image", + src: link, + }) + } + return React.createElement("div", { className: "betterMessageLinks Author AlignMiddle" }, + link.split("/").pop(), + preview + ) + } + + renderMessage() { + if (this.props.attachmentLink) { + return React.createElement("div", { + className: "betterMessageLinks AlignMiddle Container", + children: [ + this.renderAttachmentLink(this.props.original) + ] + }); + } + const { message } = this.state; + if (!message.ok && !message.id) return this.renderError(message); + let hasAttachments = message.attachments?.length > 0 || message.embeds?.length > 0 || message.sticker_items?.length > 0; + return React.createElement("div", { + className: "betterMessageLinks AlignMiddle Container", + children: [ + this.renderHeader(message, hasAttachments), + this.renderContent(message), + this.renderAttachment(message), + this.renderBetterFooter(this.props.settings.advancedFooter, message) + ] + }); + } + + render() { + let { settings } = this.props; + let attachmentLink = this.props.attachmentLink; + + let messageReplace = this.props.original; + if (!this.props.replaceOverride) { + if (settings.messageReplaceText !== "" && !attachmentLink) { + messageReplace = settings.messageReplaceText; + } else if (settings.attachmentReplaceText !== "" && attachmentLink) { + messageReplace = settings.attachmentReplaceText; + } + } else { + messageReplace = this.props.replaceOverride; + } + + return React.createElement(Popout, { + shouldShow: this.state.showPopout, + position: Popout.Positions.TOP, + align: Popout.Align.CENTER, + animation: Popout.Animation[this.props.settings.animationType], + spacing: 0, + renderPopout: () => { + return React.createElement("div", { + className: "thin-31rlnD scrollerBase-_bVAAt betterMessageLinks Popout", + onMouseEnter: () => this.setState({ showPopout: true }), + onMouseLeave: () => this.setState({ showPopout: false }) + }, this.state.loaded || this.props.attachmentLink ? this.renderMessage() : this.renderLoading()) + } + }, () => React.createElement(Anchor, { + className: `betterMessageLinks Link${this.props.settings.mentionStyle ? " wrapper-1ZcZW- mention interactive" : ""}`, + + href: this.props.original, + children: [messageReplace], + onMouseEnter: () => this.setState({ showPopout: true }), + onMouseLeave: () => this.setState({ showPopout: false }) + })) + } + processNewLines(array) { + let processedArray = []; + let tempArray = []; + array.forEach((messageElement) => { + if (!messageElement.type && messageElement.includes("\n")) { + //replaces \n in text with actual newline elements + let split = messageElement.split("\n"); + let newLine = React.createElement("br", {}); + processedArray.push([newLine].concat(...split.map(e => [e, newLine])).slice(1, -1)) + } + else { + processedArray.push(messageElement) + } + }) + if (processedArray.length === 0) return array; + return processedArray; + } + } + return class BetterMessageLinks extends Plugin { + async onStart() { + //inject css + BdApi.injectCSS(config.info.name, customCSS) + this.settings = this.loadSettings(defaultSettings); + + Patcher.after(MarkdownModule.defaultRules.link, "react", (_, [props], ret) => { + return this.handleLink(ret); + }) + + //replied messages get checked extra. This isn't really nice code, but it works I guess. + Patcher.after(RepliedMessage, "default", (_, [props], ret) => { + if (props.content?.length > 0) { + props.content.forEach((element, i) => { + if (element.type?.displayName === "MaskedLink") { + props.content[i] = this.handleLink(element); + } + }); + } + }) + + } + handleLink(ret) { + //check if it already is a masked link (the href and content aren't the same), if so, we don't want to change the text. (Can happen in embeds for example) + let isMaskedLink = ret.props.children[0] !== ret.props.href; + + if (/^https:\/\/(ptb.|canary.)?discord(app)?.com\/channels\/(\d+|@me)\/\d+\/\d+$/gi.test(ret.props.href) && !this.settings.ignoreMessage) { + return React.createElement(BetterLink, { original: ret.props.href, settings: this.settings, key: config.info.name, replaceOverride: isMaskedLink && ret.props.children[0]}) + } else if (/^https:\/\/(media|cdn).discordapp.(com|net)\/attachments\/\d+\/\d+\/.+$/gi.test(ret.props.href) && !this.settings.ignoreAttachment) { + return React.createElement(BetterLink, { original: ret.props.href.split("?")[0], settings: this.settings, attachmentLink: true, key: config.info.name, replaceOverride: isMaskedLink && ret.props.children[0] }); + } + return ret; + } + + getSettingsPanel() { + let listArray = []; + validFooterValues.forEach((value) => { + listArray.push(React.createElement("li", { class: "betterMessageLinks ListElement" }, + React.createElement("span", { class: "betterMessageLinks ListElement Symbol" }, "$"), + value)); + }) + let unorderedList = React.createElement("ul", { + children: listArray, + class: "betterMessageLinks List" + }); + + let messageReplaceGroup = new SettingGroup("Message Replace").append( + new Textbox("", "Replace all Discord message links with the following text. Leave empty to not change the Discord Link at all.", this.settings.messageReplaceText, (i) => { + this.settings.messageReplaceText = i; + }, { placeholder: "" }), + ) + + let attachmentReplaceGroup = new SettingGroup("Attachment Replace").append( + new Textbox("", "Replace all Discord Attachment links with the following text. Leave empty to not change the Discord Link at all.", this.settings.attachmentReplaceText, (i) => { + this.settings.attachmentReplaceText = i; + }, { placeholder: "" }), + ) + + let noDisplayIfSameGuildSwitch = new Switch("Don't display Guild icon, if in same Guild", "If you are currently in the same Guild as the message from the link, the icon of the Guild will not be displayed.", this.settings.noDisplayIfSameGuild, (i) => { + this.settings.noDisplayIfSameGuild = i; + }) + noDisplayIfSameGuildSwitch.inputWrapper.className += " betterMessageLinks Settings noDisplayIfSameGuildSwitch" + + + + let spinnerRadio = new RadioGroup('Spinner', "Choose the spinner that gets displayed when the message is loading", this.settings.spinner || 0, spinnerSetting, (i) => { + this.settings.spinner = i; + }) + spinnerRadio.inputWrapper.className += " betterMessageLinks Settings Spinner"; + + let animationRadio = new RadioGroup('Popup Animation', "Choose the animation type when the popoup get's opened.", this.settings.animationType || "TRANSLATE", animationSetting, (i) => { + this.settings.animationType = i; + }) + animationRadio.inputWrapper.className += " betterMessageLinks Settings Animation"; + + let appearanceSettingsGroup = new SettingGroup("Appearance").append( + new Switch("Show Author icon", "Display the icon of the Message Author.", this.settings.showAuthorIcon, (i) => { + this.settings.showAuthorIcon = i; + }), + new Switch("Show Guild icon", "Display the guild icon of the message next to the author icon if you aren't in the same guild as the linked message.", this.settings.showGuildIcon, (i) => { + this.settings.showGuildIcon = i; + this.updateSettingsCSS(); + }), + noDisplayIfSameGuildSwitch, + new Switch("Show progress bar", "Display a circular progress bar when loading a message.", this.settings.progressBar, (i) => { + this.settings.progressBar = i; + }), + new Switch("Style as mention", "Choose if the link should be styled like a mention (Otherwhise it will be styled like a link).", this.settings.mentionStyle, (i) => { + this.settings.mentionStyle = i; + }), + spinnerRadio, + animationRadio, + new Textbox("Advanced link footer", React.createElement("div", {}, "Add a footer to the popout containing information about the message. Use $value to display specific values. Valid values: ", unorderedList), this.settings.advancedFooter, (i) => { + this.settings.advancedFooter = i; + }), + ) + + messageReplaceGroup.group.className += " betterMessageLinks SettingsGroup Message"; + attachmentReplaceGroup.group.className += " betterMessageLinks SettingsGroup Attachment"; + appearanceSettingsGroup.group.className += " betterMessageLinks SettingsGroup Appearance"; + + this.updateSettingsCSS() + //build the settings panel + return SettingPanel.build(() => this.saveSettings(this.settings), + new Switch("Ignore message links", "Message links will not get replaced or have a preview.", this.settings.ignoreMessage, (i) => { + this.settings.ignoreMessage = i; + this.updateSettingsCSS() + }), + new Switch("Ignore attachment links", "Attachment links will not get replaced or have a preview. (Recommended when using HideEmbedLink for example)", this.settings.ignoreAttachment, (i) => { + this.settings.ignoreAttachment = i; + this.updateSettingsCSS() + }), + messageReplaceGroup, + attachmentReplaceGroup, + appearanceSettingsGroup, + ) + + } + updateSettingsCSS() { + let hideArray = []; + if (this.settings.ignoreMessage && this.settings.ignoreAttachment) { + hideArray.push("SettingsGroup"); + } + else if (this.settings.ignoreMessage) { + hideArray.push("SettingsGroup.Message"); + } + else if (this.settings.ignoreAttachment) { + hideArray.push("SettingsGroup.Attachment"); + } + if (!this.settings.showGuildIcon) { + hideArray.push("Settings.noDisplayIfSameGuildSwitch"); + } + let hideCss = hideArray.length > 0 ? hideArray.map(e => `.betterMessageLinks.${e}`).join(", ") + " {display:none;}" : ""; + BdApi.injectCSS(config.info.name, customCSS + hideCss) + } + + + onStop() { + BdApi.clearCSS(config.info.name) + Patcher.unpatchAll(config.info.name); + } + + } +})(global.ZeresPluginLibrary.buildPlugin(config)); diff --git a/oldconfig/BetterDiscord/plugins/BetterSearchPage.config.json b/oldconfig/BetterDiscord/plugins/BetterSearchPage.config.json new file mode 100644 index 0000000..bef82e1 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterSearchPage.config.json @@ -0,0 +1,8 @@ +{ + "all": { + "settings": { + "addJumpTo": true, + "cloneToTheTop": true + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BetterSearchPage.plugin.js b/oldconfig/BetterDiscord/plugins/BetterSearchPage.plugin.js new file mode 100644 index 0000000..197b209 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BetterSearchPage.plugin.js @@ -0,0 +1,165 @@ +/** + * @name BetterSearchPage + * @author DevilBro + * @authorId 278543574059057154 + * @version 1.2.0 + * @description Adds some extra Controls to the Search Results Page + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/BetterSearchPage/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/BetterSearchPage/BetterSearchPage.plugin.js + */ + +module.exports = (_ => { + const config = { + "info": { + "name": "BetterSearchPage", + "author": "DevilBro", + "version": "1.2.0", + "description": "Adds some extra Controls to the Search Results Page" + }, + "changeLog": { + "fixed": { + "Jump Input": "No longer adds jump input if there is only one page of search results" + } + } + }; + + return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;} + + downloadLibrary () { + require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { + if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"})); + else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library"); + }); + } + + load () { + if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []}); + if (!window.BDFDB_Global.downloadModal) { + window.BDFDB_Global.downloadModal = true; + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, + onConfirm: _ => { + delete window.BDFDB_Global.downloadModal; + this.downloadLibrary(); + } + }); + } + if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + } + start () {this.load();} + stop () {} + getSettingsPanel () { + let template = document.createElement("template"); + template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); + return template.content.firstElementChild; + } + } : (([Plugin, BDFDB]) => { + var settings = {}; + + return class BetterSearchPage extends Plugin { + onLoad () { + this.defaults = { + settings: { + addJumpTo: {value: true, description: "Add a Jump to Input Field (press enter to Jump)"}, + cloneToTheTop: {value: true, description: "Clone the controls to the top of the Results Page"} + } + }; + + this.patchedModules = { + after: { + SearchResultsInner: "default" + } + }; + } + + onStart () { + this.forceUpdateAll(); + } + + onStop () { + this.forceUpdateAll(); + } + + getSettingsPanel (collapseStates = {}) { + let settingsPanel, settingsItems = []; + + for (let key in settings) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + type: "Switch", + plugin: this, + keys: ["settings", key], + label: this.defaults.settings[key].description, + value: settings[key] + })); + + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, settingsItems); + } + + onSettingsClosed (e) { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + this.forceUpdateAll(); + } + } + + forceUpdateAll () { + settings = BDFDB.DataUtils.get(this, "settings"); + + BDFDB.PatchUtils.forceAllUpdates(this); + } + + processSearchResultsInner (e) { + if (e.instance.props.search) { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: "SearchPagination"}); + if (index > -1) { + let currentPage = parseInt(Math.floor(e.instance.props.search.offset / BDFDB.DiscordConstants.SEARCH_PAGE_SIZE)) + 1; + let maxPage = e.instance.props.search.totalResults > 5000 ? parseInt(Math.ceil(5000 / BDFDB.DiscordConstants.SEARCH_PAGE_SIZE)) : parseInt(Math.ceil(e.instance.props.search.totalResults / BDFDB.DiscordConstants.SEARCH_PAGE_SIZE)); + + children[index].props.totalResults = children[index].props.totalResults > 5000 ? 5000 : children[index].props.totalResults; + + let pagination = children[index].type(children[index].props); + if (!pagination || maxPage < 2) return; + pagination.props.className = BDFDB.DOMUtils.formatClassName(pagination.props.className, BDFDB.disCN.pagination, BDFDB.disCN._bettersearchpagepagination, settings.addJumpTo && BDFDB.disCN.paginationmini); + + if (settings.addJumpTo) { + pagination.props.children = [ + pagination.props.children, + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + type: "number", + size: BDFDB.LibraryComponents.TextInput.Sizes.MINI, + value: currentPage, + min: 1, + max: maxPage, + onKeyDown: (event, instance) => { + if (event.which == 13) { + let page = instance.props.value < 1 ? 1 : (instance.props.value > maxPage ? maxPage : instance.props.value); + if (page < currentPage) BDFDB.LibraryModules.SearchPageUtils.searchPreviousPage(e.instance.props.searchId, (currentPage - page) * BDFDB.DiscordConstants.SEARCH_PAGE_SIZE); + else if (page > currentPage) BDFDB.LibraryModules.SearchPageUtils.searchNextPage(e.instance.props.searchId, (page - currentPage) * BDFDB.DiscordConstants.SEARCH_PAGE_SIZE); + } + } + }) + ].flat(10).filter(n => n); + } + children[index] = pagination; + if (settings.cloneToTheTop) { + let topPagination = BDFDB.ReactUtils.cloneElement(pagination); + topPagination.props.className = BDFDB.DOMUtils.formatClassName(topPagination.props.className, BDFDB.disCN.paginationtop); + children.unshift(topPagination); + } + pagination.props.className = BDFDB.DOMUtils.formatClassName(pagination.props.className, BDFDB.disCN.paginationbottom); + } + } + } + }; + })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); +})(); \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/BugReportHelper.config.json b/oldconfig/BetterDiscord/plugins/BugReportHelper.config.json new file mode 100644 index 0000000..2aa8744 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/BugReportHelper.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.0.4", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/CallTimeCounter.config.json b/oldconfig/BetterDiscord/plugins/CallTimeCounter.config.json new file mode 100644 index 0000000..06568aa --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/CallTimeCounter.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.0.3", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/CharCounter.config.json b/oldconfig/BetterDiscord/plugins/CharCounter.config.json new file mode 100644 index 0000000..5977a26 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/CharCounter.config.json @@ -0,0 +1,7 @@ +{ + "all": { + "sliders": { + "showPercentage": 0 + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/CharCounter.plugin.js b/oldconfig/BetterDiscord/plugins/CharCounter.plugin.js new file mode 100644 index 0000000..4bfe91d --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/CharCounter.plugin.js @@ -0,0 +1,237 @@ +/** + * @name CharCounter + * @author DevilBro + * @authorId 278543574059057154 + * @version 1.6.0 + * @description Adds a Character Counter to most Inputs + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/CharCounter/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/CharCounter/CharCounter.plugin.js + */ + +module.exports = (_ => { + const config = { + "info": { + "name": "CharCounter", + "author": "DevilBro", + "version": "1.6.0", + "description": "Adds a Character Counter to most Inputs" + } + }; + + return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;} + + downloadLibrary () { + require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { + if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"})); + else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library"); + }); + } + + load () { + if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []}); + if (!window.BDFDB_Global.downloadModal) { + window.BDFDB_Global.downloadModal = true; + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, + onConfirm: _ => { + delete window.BDFDB_Global.downloadModal; + this.downloadLibrary(); + } + }); + } + if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + } + start () {this.load();} + stop () {} + getSettingsPanel () { + let template = document.createElement("template"); + template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); + return template.content.firstElementChild; + } + } : (([Plugin, BDFDB]) => { + const maxLengths = { + nick: 32, + customstatus: 128, + popoutnote: 256, + profilenote: 256 + }; + const typeMap = { + normal: "chat", + sidebar: "chat", + thread_creation: "threadcreation", + form: "upload" + }; + const nativeCounters = ["profile_bio_input"]; + + return class CharCounter extends Plugin { + onLoad () { + this.patchedModules = { + after: { + ChannelTextAreaContainer: "render", + Note: "render", + NicknameSection: "default", + CustomStatusModal: "render" + } + }; + + this.defaults = { + sliders: { + showPercentage: {value: 0, description: "Only shows Counter after certain % of Max Length is reached"} + } + }; + + this.css = ` + ${BDFDB.dotCN._charcountercounteradded} { + position: relative !important; + } + ${BDFDB.dotCN._charcountercounter} { + display: block; + position: absolute; + font-size: 15px; + z-index: 10; + pointer-events: none; + } + ${BDFDB.dotCN._charcounterchatcounter} { + right: 0; + bottom: -1.3em; + } + ${BDFDB.dotCN._charcountereditcounter} { + right: 0; + bottom: -1.3em; + } + ${BDFDB.dotCN._charcounterthreadcreationcounter} { + right: 0; + bottom: -1.1em; + } + ${BDFDB.dotCN._charcounteruploadcounter} { + right: 0; + bottom: -1.0em; + } + ${BDFDB.dotCN._charcounternickcounter} { + right: 0 !important; + top: -1.5em; + } + ${BDFDB.dotCN._charcountercustomstatuscounter} { + right: 0 !important; + top: -1.5em; + } + ${BDFDB.dotCN._charcounterpopoutnotecounter} { + right: 3px !important; + bottom: -8px !important; + font-size: 10px !important; + } + ${BDFDB.dotCN._charcounterprofilenotecounter} { + right: 0 !important; + bottom: -10px !important; + font-size: 12px !important; + } + ${BDFDB.dotCN.usernotetextarea}:not(:focus) ~ ${BDFDB.dotCN._charcountercounter} { + display: none; + } + `; + } + + onStart () { + BDFDB.PatchUtils.forceAllUpdates(this); + } + + onStop () { + BDFDB.PatchUtils.forceAllUpdates(this); + } + + getSettingsPanel (collapseStates = {}) { + let settingsPanel; + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, { + collapseStates: collapseStates, + children: _ => { + let settingsItems = []; + + for (let key in this.defaults.sliders) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + type: "Slider", + plugin: this, + keys: ["sliders", key], + basis: "30%", + label: this.defaults.sliders[key].description, + value: this.settings.sliders[key] + })); + + return settingsItems; + } + }); + } + + onSettingsClosed () { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + BDFDB.PatchUtils.forceAllUpdates(this); + } + } + + processChannelTextAreaContainer (e) { + let editorContainer = BDFDB.ReactUtils.findChild(e.returnvalue, {name: "ChannelEditorContainer"}); + if (editorContainer && editorContainer.props.type && !editorContainer.props.disabled) { + if (!BDFDB.ArrayUtils.is(e.returnvalue.props.children)) e.returnvalue.props.children = [e.returnvalue.props.children]; + this.injectCounter(e.returnvalue, e.returnvalue.props.children, editorContainer.props.type.analyticsName || editorContainer.props.type, BDFDB.dotCN.textarea); + } + } + + processNote (e) { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: ["TextAreaAutosize", "TextArea", "PlainTextArea"]}); + if (index > -1) this.injectCounter(e.returnvalue, children, e.instance.props.className && e.instance.props.className.indexOf(BDFDB.disCN.usernotepopout) > -1 ? "popoutnote" : "profilenote", "textarea"); + } + + processNicknameSection (e) { + e.returnvalue.props.children = BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._charcountercounteradded, + children: [ + e.returnvalue.props.children, + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.charcounter, BDFDB.disCN._charcountercounter, BDFDB.disCN._charcounternickcounter), + children: `${(e.instance.props.pendingNick || "").length}/${maxLengths.nick}` + }) + ].flat(10) + }); + } + + processCustomStatusModal (e) { + let formItem = BDFDB.ReactUtils.findChild(e.returnvalue, {props: [["className", BDFDB.disCN.emojiinputcontainer]]}); + if (formItem) this.injectCounter(formItem, formItem.props.children, "customstatus", BDFDB.dotCN.input); + } + + injectCounter (parent, children, type, refClass, parsing) { + if (!children || nativeCounters.indexOf(type) > -1) return; + if (parent.props.className) parent.props.className = BDFDB.DOMUtils.formatClassName(parent.props.className, BDFDB.disCN._charcountercounteradded); + else parent.props.children = BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._charcountercounteradded, + children: parent.props.children + }); + children.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CharCounter, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN._charcountercounter, type && BDFDB.DiscordClasses[`_charcounter${typeMap[type] || type}counter`] && BDFDB.disCN[`_charcounter${typeMap[type] || type}counter`]), + refClass: refClass, + parsing: parsing, + max: maxLengths[type] || (BDFDB.LibraryModules.NitroUtils.canUseIncreasedMessageLength(BDFDB.UserUtils.me) ? BDFDB.DiscordConstants.MAX_MESSAGE_LENGTH_PREMIUM : BDFDB.DiscordConstants.MAX_MESSAGE_LENGTH), + showPercentage: this.settings.sliders.showPercentage, + onChange: instance => { + let node = BDFDB.ReactUtils.findDOMNode(instance); + let form = node && BDFDB.DOMUtils.getParent(BDFDB.dotCN.chatform, node); + if (form) { + let typing = form.querySelector(BDFDB.dotCN.typing); + if (typing) typing.style.setProperty("margin-right", `${BDFDB.DOMUtils.getWidth(node) + 10}px`); + } + } + })); + } + }; + })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); +})(); diff --git a/oldconfig/BetterDiscord/plugins/ColorTooltips.config.json b/oldconfig/BetterDiscord/plugins/ColorTooltips.config.json new file mode 100644 index 0000000..be5d12d --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ColorTooltips.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.0.2", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/CompleteTimestamps.config.json b/oldconfig/BetterDiscord/plugins/CompleteTimestamps.config.json new file mode 100644 index 0000000..d706e25 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/CompleteTimestamps.config.json @@ -0,0 +1,25 @@ +{ + "all": { + "dates": { + "timestampDate": { + "formatString": "$time $date", + "dateString": "$dd $monthS $yyyy", + "timeString": "$h:$mm:$ss" + }, + "tooltipDate": { + "formatString": "$time $date", + "dateString": "$dd $monthS $yyyy", + "timeString": "$h:$mm:$ss" + } + }, + "general": { + "showInChat": true, + "showInEmbed": true, + "showInMarkup": true, + "showInAuditLogs": true, + "changeForChat": true, + "changeForEdit": true, + "changeForMarkup": true + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/Copier.config.json b/oldconfig/BetterDiscord/plugins/Copier.config.json new file mode 100644 index 0000000..4da6f97 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/Copier.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.4.1", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/CreationDate.config.json b/oldconfig/BetterDiscord/plugins/CreationDate.config.json new file mode 100644 index 0000000..86a7c0d --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/CreationDate.config.json @@ -0,0 +1,14 @@ +{ + "all": { + "dates": { + "creationDate": {} + }, + "general": { + "displayText": true + }, + "places": { + "userPopout": true, + "userProfile": true + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/DateViewer.config.json b/oldconfig/BetterDiscord/plugins/DateViewer.config.json new file mode 100644 index 0000000..a9d7282 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/DateViewer.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.2.5", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/DisableStickerSuggestions.config.json b/oldconfig/BetterDiscord/plugins/DisableStickerSuggestions.config.json new file mode 100644 index 0000000..1771820 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/DisableStickerSuggestions.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.2.0", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/DoNotTrack.config.json b/oldconfig/BetterDiscord/plugins/DoNotTrack.config.json new file mode 100644 index 0000000..ed399c2 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/DoNotTrack.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.0.7", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/DoNotTrack.plugin.js b/oldconfig/BetterDiscord/plugins/DoNotTrack.plugin.js new file mode 100644 index 0000000..d5f8284 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/DoNotTrack.plugin.js @@ -0,0 +1,121 @@ +/** + * @name DoNotTrack + * @version 0.0.7 + * @authorLink https://twitter.com/IAmZerebos + * @donate https://paypal.me/ZackRauen + * @patreon https://patreon.com/Zerebos + * @website https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/DoNotTrack + * @source https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/DoNotTrack/DoNotTrack.plugin.js + * @updateUrl https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/DoNotTrack/DoNotTrack.plugin.js + */ +/*@cc_on +@if (@_jscript) + + // Offer to self-install for clueless users that try to run this directly. + var shell = WScript.CreateObject("WScript.Shell"); + var fs = new ActiveXObject("Scripting.FileSystemObject"); + var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins"); + var pathSelf = WScript.ScriptFullName; + // Put the user at ease by addressing them in the first person + shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30); + if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) { + shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40); + } else if (!fs.FolderExists(pathPlugins)) { + shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10); + } else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) { + fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true); + // Show the user where to put plugins in the future + shell.Exec("explorer " + pathPlugins); + shell.Popup("I'm installed!", 0, "Successfully installed", 0x40); + } + WScript.Quit(); + +@else@*/ + +module.exports = (() => { + const config = {info:{name:"DoNotTrack",authors:[{name:"Zerebos",discord_id:"249746236008169473",github_username:"rauenzi",twitter_username:"ZackRauen"}],version:"0.0.7",description:"Stops Discord from tracking everything you do like Sentry and Analytics.",github:"https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/DoNotTrack",github_raw:"https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/DoNotTrack/DoNotTrack.plugin.js"},changelog:[{title:"Fixes","type:":"fixed",items:["Fixed for Discord/BetterDiscord changes"]}],main:"index.js",defaultConfig:[{type:"switch",id:"stopProcessMonitor",name:"Stop Process Monitor",note:"This setting stops Discord from monitoring the processes on your PC and prevents your currently played game from showing.",value:true}]}; + + return !global.ZeresPluginLibrary ? class { + constructor() {this._config = config;} + getName() {return config.info.name;} + getAuthor() {return config.info.authors.map(a => a.name).join(", ");} + getDescription() {return config.info.description;} + getVersion() {return config.info.version;} + load() { + BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js"); + await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r)); + }); + } + }); + } + start() {} + stop() {} + } : (([Plugin, Api]) => { + const plugin = (Plugin, Api) => { + const {Patcher, WebpackModules, Modals, DiscordModules} = Api; + return class DoNotTrack extends Plugin { + onStart() { + const Analytics = WebpackModules.getByProps("AnalyticEventConfigs"); + Patcher.instead(Analytics.default, "track", () => {}); + + const Logger = window.__SENTRY__.logger; + Logger.disable(); // Kill sentry logs + + const SentryHub = window.DiscordSentry.getCurrentHub(); + SentryHub.getClient().close(0); // Kill reporting + SentryHub.getStackTop().scope.clear(); // Delete PII + + /* eslint-disable no-console */ + for (const method in console) { + if (!console[method].__sentry_original__) continue; + console[method] = console[method].__sentry_original__; + } + + if (this.settings.stopProcessMonitor) this.disableProcessMonitor(); + } + + onStop() { + Patcher.unpatchAll(); + } + + disableProcessMonitor() { + DiscordModules.UserSettingsUpdater.updateLocalSettings({showCurrentGame: false}); + const NativeModule = WebpackModules.getByProps("getDiscordUtils"); + const DiscordUtils = NativeModule.getDiscordUtils(); + DiscordUtils.setObservedGamesCallback([], () => {}); + } + + enableProcessMonitor() { + DiscordModules.UserSettingsUpdater.updateLocalSettings({showCurrentGame: true}); + Modals.showConfirmationModal("Reload Discord?", "To reenable the process monitor Discord needs to be reloaded.", { + confirmText: "Reload", + cancelText: "Later", + onConfirm: () => { + window.location.reload(); + } + }); + } + + getSettingsPanel() { + const panel = this.buildSettingsPanel(); + panel.addListener(this.updateSettings.bind(this)); + return panel.getElement(); + } + + updateSettings(id, value) { + if (id !== "stopProcessMonitor") return; + if (value) return this.disableProcessMonitor(); + return this.enableProcessMonitor(); + } + + }; +}; + return plugin(Plugin, Api); + })(global.ZeresPluginLibrary.buildPlugin(config)); +})(); +/*@end@*/ \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/DoubleClickVoiceChannels.config.json b/oldconfig/BetterDiscord/plugins/DoubleClickVoiceChannels.config.json new file mode 100644 index 0000000..6c7b5a3 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/DoubleClickVoiceChannels.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.0.0", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/DoubleClickVoiceChannels.plugin.js b/oldconfig/BetterDiscord/plugins/DoubleClickVoiceChannels.plugin.js new file mode 100644 index 0000000..2f45960 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/DoubleClickVoiceChannels.plugin.js @@ -0,0 +1,168 @@ +/** +* @name DoubleClickVoiceChannels +* @description Requires you to double click voice channels to join them. +* @author Qb, Twizzer#0001 & AAGaming#9395 +* @authorId 133659541198864384 +* @version 1.0.0 +* @invite pKx8m6Z +* @license Unlicensed +* @source https://github.com/QbDesu/BetterDiscordAddons/blob/potato/Plugins/DoubleClickVoiceChannels +* @updateUrl https://raw.githubusercontent.com/QbDesu/BetterDiscordAddons/potato/Plugins/DoubleClickVoiceChannels/DoubleClickVoiceChannels.plugin.js +*/ +/*@cc_on +@if (@_jscript) + +// Offer to self-install for clueless users that try to run this directly. +var shell = WScript.CreateObject("WScript.Shell"); +var fs = new ActiveXObject("Scripting.FileSystemObject"); +var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\BetterDiscord\plugins"); +var pathSelf = WScript.ScriptFullName; +// Put the user at ease by addressing them in the first person +shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30); +if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) { + shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40); +} else if (!fs.FolderExists(pathPlugins)) { + shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10); +} else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) { + fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true); + // Show the user where to put plugins in the future + shell.Exec("explorer " + pathPlugins); + shell.Popup("I'm installed!", 0, "Successfully installed", 0x40); +} +WScript.Quit(); + +@else@*/ + +module.exports = (() => { + const config = { + info: { + name: "DoubleClickVoiceChannels", + version: "1.0.0", + github_raw: "https://raw.githubusercontent.com/QbDesu/BetterDiscordAddons/potato/Plugins/DoubleClickVoiceChannels/DoubleClickVoiceChannels.plugin.js" + } + }; + return !global.ZeresPluginLibrary ? class { + constructor() { this._config = config; } + load() { + BdApi.showConfirmationModal("Library plugin is needed", + [`The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`], { + confirmText: "Download", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://betterdiscord.app/Download?id=9"); + await new Promise(r => { + require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r); + window.location.reload(); + }); + }); + } + }); + } + start() { } + stop() { } + } +: (([Plugin, Api]) => { + const plugin = (Plugin, Api) => { + const { + Patcher, + WebpackModules, + Logger + } = Api; + + const ChannelItem = WebpackModules.getModule(m => m?.default?.displayName == "ChannelItem"); + const ChannelMention = WebpackModules.getModule(m => m?.default?.displayName == "Mention"); + + return class GuildNotificationDefaults extends Plugin { + constructor() { + super(); + // remove need for duplication of metadata fields + this.getAuthor = null; + this.getDescription = null; + } + + async onStart() { + Patcher.after(ChannelItem, "default", (that, args, value) => { + const channel = this.getChannel(value); + if (channel) { + if (channel.type === 2 || channel.type === 13) { + const clickable = this.getClickable(value); + if (clickable) { + clickable.onDoubleClick = clickable.onClick; + delete clickable.onClick; + } + } + } else { + Logger.warn('Failed to find channel.'); + } + + return value; + }); + + Patcher.after(ChannelMention, "default", (that, args, value) => { + const label = this.getLabel(value); + if (label && label === 'Voice Channel') { + const { props } = value; + props.onDoubleClick = props.onClick; + delete props.onClick; + } + + return value; + }); + } + + onStop() { + Patcher.unpatchAll(); + } + + shouldDescend(key) { + return key === 'props' || key === 'children' || !isNaN(key); + } + + getChannel(obj) { + for (const key in obj) { + const inner = obj[key]; + if (inner && typeof inner === 'object') { + if (key === 'channel') { + return inner; + } else if (this.shouldDescend(key)) { + return this.getChannel(inner); + } + } + } + return null; + } + + getClickable(obj) { + for (const key in obj) { + const inner = obj[key]; + if (inner && typeof inner === 'object') { + if (inner.onClick && inner.role === 'button') { + return inner; + } else if (this.shouldDescend(key)) { + return this.getClickable(inner); + } + } + } + return null; + } + + getLabel(obj) { + for (const key in obj) { + const inner = obj[key]; + if (inner) { + if (key === 'aria-label') { + return inner; + } else if (typeof inner === 'object' && this.shouldDescend(key)) { + return this.getLabel(inner); + } + } + } + return null; + } + }; + }; + return plugin(Plugin, Api); +})(global.ZeresPluginLibrary.buildPlugin(config)); +})(); +/*@end@*/ \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/GoogleSearchReplace.config.json b/oldconfig/BetterDiscord/plugins/GoogleSearchReplace.config.json new file mode 100644 index 0000000..4e68e45 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/GoogleSearchReplace.config.json @@ -0,0 +1,26 @@ +{ + "all": { + "engines": { + "Ask": false, + "Bing": false, + "DogPile": false, + "DuckDuckGo": false, + "Ecosia": false, + "GitHub": true, + "Google": false, + "GoogleScholar": false, + "Quora": false, + "Qwant": false, + "Searx": false, + "StackOverflow": true, + "Startpage": false, + "UrbanDictionary": false, + "Whoogle": true, + "WolframAlpha": false, + "Yahoo": false, + "Yandex": false, + "YouTube": false, + "_all": true + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/HideChannels.config.json b/oldconfig/BetterDiscord/plugins/HideChannels.config.json new file mode 100644 index 0000000..bd2db35 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/HideChannels.config.json @@ -0,0 +1,16 @@ +{ + "keybind": [ + [ + 0, + 37 + ], + [ + 0, + 50 + ], + [ + 0, + 19 + ] + ] +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/HideDisabledEmojis.config.json b/oldconfig/BetterDiscord/plugins/HideDisabledEmojis.config.json new file mode 100644 index 0000000..ed399c2 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/HideDisabledEmojis.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.0.7", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ImageUtilities.config.json b/oldconfig/BetterDiscord/plugins/ImageUtilities.config.json new file mode 100644 index 0000000..b36f278 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ImageUtilities.config.json @@ -0,0 +1,59 @@ +{ + "all": { + "amounts": { + "hoverDelay": 0 + }, + "detailsSettings": { + "footnote": true, + "tooltip": false, + "tooltipDelay": 0 + }, + "engines": { + "_all": true, + "Baidu": true, + "Bing": true, + "Google": true, + "ImgOps": true, + "IQDB": true, + "Reddit": true, + "SauceNAO": true, + "Sogou": true, + "TinEye": true, + "WhatAnime": true, + "Yandex": true + }, + "general": { + "resizeImage": true, + "addDetails": true, + "showInDescription": true, + "showOnHover": false, + "enableGallery": true, + "enableZoom": true, + "pixelZoom": false, + "enableCopyImg": true, + "enableSaveImg": true + }, + "places": { + "userAvatars": true, + "groupIcons": true, + "guildIcons": true, + "emojis": true + }, + "resizeSettings": { + "messages": false, + "imageViewer": false + }, + "viewerSettings": { + "zoomMode": true, + "galleryMode": true, + "details": true, + "copyImage": true, + "saveImage": true + }, + "zoomSettings": { + "lensSize": 200, + "pixelMode": false, + "zoomLevel": 2 + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/JoinedAtDate.config.json b/oldconfig/BetterDiscord/plugins/JoinedAtDate.config.json new file mode 100644 index 0000000..61c2fdf --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/JoinedAtDate.config.json @@ -0,0 +1,14 @@ +{ + "all": { + "dates": { + "joinedAtDate": {} + }, + "general": { + "displayText": true + }, + "places": { + "userPopout": true, + "userProfile": true + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/OpenSteamLinksInApp.plugin.js b/oldconfig/BetterDiscord/plugins/OpenSteamLinksInApp.plugin.js new file mode 100644 index 0000000..9e26324 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/OpenSteamLinksInApp.plugin.js @@ -0,0 +1,109 @@ +/** + * @name OpenSteamLinksInApp + * @author DevilBro + * @authorId 278543574059057154 + * @version 1.1.4 + * @description Opens Steam Links in Steam instead of your Browser + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/OpenSteamLinksInApp/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/OpenSteamLinksInApp/OpenSteamLinksInApp.plugin.js + */ + +module.exports = (_ => { + const config = { + "info": { + "name": "OpenSteamLinksInApp", + "author": "DevilBro", + "version": "1.1.4", + "description": "Opens Steam Links in Steam instead of your Browser" + }, + "changeLog": { + "fixed": { + "Zoomable Images": "No longer tries to open zoomable Images inside Steam" + } + } + }; + + return (window.Lightcord && !Node.prototype.isPrototypeOf(window.Lightcord) || window.LightCord && !Node.prototype.isPrototypeOf(window.LightCord) || window.Astra && !Node.prototype.isPrototypeOf(window.Astra)) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return "Do not use LightCord!";} + load () {BdApi.alert("Attention!", "By using LightCord you are risking your Discord Account, due to using a 3rd Party Client. Switch to an official Discord Client (https://discord.com/) with the proper BD Injection (https://betterdiscord.app/)");} + start() {} + stop() {} + } : !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;} + + downloadLibrary () { + require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { + if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"})); + else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library"); + }); + } + + load () { + if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []}); + if (!window.BDFDB_Global.downloadModal) { + window.BDFDB_Global.downloadModal = true; + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, + onConfirm: _ => { + delete window.BDFDB_Global.downloadModal; + this.downloadLibrary(); + } + }); + } + if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + } + start () {this.load();} + stop () {} + getSettingsPanel () { + let template = document.createElement("template"); + template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); + return template.content.firstElementChild; + } + } : (([Plugin, BDFDB]) => { + const urls = { + steam: ["https://steamcommunity.", "https://help.steampowered.", "https://store.steampowered.", "https://s.team/", "a.akamaihd.net/"] + }; + + return class OpenSteamLinksInApp extends Plugin { + onLoad () {} + + onStart () { + for (let key in urls) BDFDB.ListenerUtils.add(this, document, "click", BDFDB.ArrayUtils.removeCopies(urls[key].map(url => url.indexOf("http") == 0 ? (url.indexOf("https://") == 0 ? [`a[href^="${url}"]`, `a[href^="${url.replace(/https:\/\//i, "http://")}"]`] : `a[href^="${url}"]`) : `a[href*="${url}"][href*="${key}"]`).flat(10).filter(n => n)).join(", "), e => { + if (!(e.currentTarget.className && e.currentTarget.className.indexOf(BDFDB.disCN.imagezoom) > -1)) this.openIn(e, key, e.currentTarget.href); + }); + } + + onStop () {} + + openIn (e, key, url) { + let platform = BDFDB.LibraryModules.StringUtils.upperCaseFirstChar(key); + if (url && !url.startsWith("https://images-ext-1.discord") && !url.startsWith("https://images-ext-2.discord") && typeof this[`openIn${platform}`] == "function") { + BDFDB.ListenerUtils.stopEvent(e); + this[`openIn${platform}`](url); + return true; + } + return false; + } + + openInSteam (url) { + BDFDB.LibraryRequires.request(url, (error, response, body) => { + if (BDFDB.LibraryRequires.electron.shell.openExternal("steam://openurl/" + response.request.href)); + else BDFDB.DiscordUtils.openLink(response.request.href); + }); + } + }; + })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); +})(); \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/PermissionsViewer.config.json b/oldconfig/BetterDiscord/plugins/PermissionsViewer.config.json new file mode 100644 index 0000000..d66c35a --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/PermissionsViewer.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.2.2", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/PlatformIndicators.config.json b/oldconfig/BetterDiscord/plugins/PlatformIndicators.config.json new file mode 100644 index 0000000..f3b7b24 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/PlatformIndicators.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.2.2", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/PluginRepo.config.json b/oldconfig/BetterDiscord/plugins/PluginRepo.config.json new file mode 100644 index 0000000..adc1267 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/PluginRepo.config.json @@ -0,0 +1,16 @@ +{ + "all": { + "cached": "2 7 8 9 11 14 15 17 28 29 30 31 59 60 61 62 63 64 65 66 67 68 69 70 71 73 74 75 76 77 78 80 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 116 120 122 126 127 131 132 133 134 137 138 139 146 157 158 159 160 162 164 171 173 176 179 181 182 183 184 185 186 188 189 190 192 193 195 196 197 200 201 206 220 228 234 236 237 238 240 245 247 253 262 272 274 278 284 287 291 292 293 295 301 306 312 314 317 318 323 331 336 337 338 340 344 349 350 351 352 353 354 356 361 364 366 368 370 377 379 381 382 383 390 395 398 401 404 407 420 421 429 438 441 442 476 479 489 509 518 519 520 521 523 525 534 535 538 539 547 554 557 566 577 579 589 592 593 598 599 606 608 611 614 620 621 627 638 644 645 670 671 686 692 694", + "filters": { + "updated": true, + "outdated": true, + "downloadable": true + }, + "general": { + "notifyOutdated": true, + "notifyNewEntries": true, + "startDownloaded": false, + "startUpdated": false + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/PluginRepo.plugin.js b/oldconfig/BetterDiscord/plugins/PluginRepo.plugin.js new file mode 100644 index 0000000..532a3bf --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/PluginRepo.plugin.js @@ -0,0 +1,1138 @@ +/** + * @name PluginRepo + * @author DevilBro + * @authorId 278543574059057154 + * @version 2.3.4 + * @description Allows you to download all Plugins from BD's Website within Discord + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/PluginRepo/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/PluginRepo/PluginRepo.plugin.js + */ + +module.exports = (_ => { + const config = { + "info": { + "name": "PluginRepo", + "author": "DevilBro", + "version": "2.3.4", + "description": "Allows you to download all Plugins from BD's Website within Discord" + } + }; + + return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;} + + downloadLibrary () { + require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { + if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"})); + else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library"); + }); + } + + load () { + if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []}); + if (!window.BDFDB_Global.downloadModal) { + window.BDFDB_Global.downloadModal = true; + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, + onConfirm: _ => { + delete window.BDFDB_Global.downloadModal; + this.downloadLibrary(); + } + }); + } + if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + } + start () {this.load();} + stop () {} + getSettingsPanel () { + let template = document.createElement("template"); + template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); + return template.content.firstElementChild; + } + } : (([Plugin, BDFDB]) => { + var _this; + + var list, header; + + var loading, cachedPlugins, grabbedPlugins, updateInterval; + var searchString, searchTimeout, forcedSort, forcedOrder, showOnlyOutdated; + + var favorites = []; + + const pluginStates = { + INSTALLED: 0, + OUTDATED: 1, + DOWNLOADABLE: 2 + }; + const buttonData = { + INSTALLED: { + backgroundColor: "var(--bdfdb-green)", + icon: "CHECKMARK", + text: "installed" + }, + OUTDATED: { + backgroundColor: "var(--bdfdb-red)", + icon: "CLOSE", + text: "outdated" + }, + DOWNLOADABLE: { + backgroundColor: "var(--bdfdb-blurple)", + icon: "DOWNLOAD", + text: "download" + } + }; + const reverseSorts = [ + "RELEASEDATE", "DOWNLOADS", "LIKES", "FAV" + ]; + const sortKeys = { + NAME: "Name", + AUTHORNAME: "Author", + VERSION: "Version", + DESCRIPTION: "Description", + RELEASEDATE: "Release Date", + STATE: "Update State", + DOWNLOADS: "Downloads", + LIKES: "Likes", + FAV: "Favorites" + }; + const orderKeys = { + ASC: "ascending", + DESC: "descending" + }; + + const pluginRepoIcon = ``; + + const RepoListComponent = class PluginList extends BdApi.React.Component { + componentDidMount() { + list = this; + BDFDB.TimeUtils.timeout(_ => { + forcedSort = null; + forcedOrder = null; + showOnlyOutdated = false; + }, 5000); + } + componentWillUnmount() { + list = null; + } + filterPlugins() { + let plugins = grabbedPlugins.map(plugin => { + const installedPlugin = _this.getInstalledPlugin(plugin); + const state = installedPlugin ? (plugin.version && _this.compareVersions(plugin.version, _this.getString(installedPlugin.version)) ? pluginStates.OUTDATED : pluginStates.INSTALLED) : pluginStates.DOWNLOADABLE; + return Object.assign(plugin, { + search: [plugin.name, plugin.version, plugin.authorname, plugin.description, plugin.tags].flat(10).filter(n => typeof n == "string").join(" ").toUpperCase(), + description: plugin.description || "No Description found", + fav: favorites.includes(plugin.id) && 1, + new: state == pluginStates.DOWNLOADABLE && !cachedPlugins.includes(plugin.id) && 1, + state: state + }); + }); + if (!this.props.updated) plugins = plugins.filter(plugin => plugin.state != pluginStates.INSTALLED); + if (!this.props.outdated) plugins = plugins.filter(plugin => plugin.state != pluginStates.OUTDATED); + if (!this.props.downloadable) plugins = plugins.filter(plugin => plugin.state != pluginStates.DOWNLOADABLE); + if (searchString) { + let usedSearchString = searchString.toUpperCase(); + let spacelessUsedSearchString = usedSearchString.replace(/\s/g, ""); + plugins = plugins.filter(plugin => plugin.search.indexOf(usedSearchString) > -1 || plugin.search.indexOf(spacelessUsedSearchString) > -1); + } + + BDFDB.ArrayUtils.keySort(plugins, this.props.sortKey.toLowerCase()); + if (this.props.orderKey == "DESC") plugins.reverse(); + if (reverseSorts.includes(this.props.sortKey)) plugins.reverse(); + return plugins; + } + render() { + let automaticLoading = BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.automaticLoading); + if (!this.props.tab) this.props.tab = "Plugins"; + + this.props.entries = (!loading.is && grabbedPlugins.length ? this.filterPlugins() : []).map(plugin => BDFDB.ReactUtils.createElement(RepoCardComponent, { + data: plugin + })).filter(n => n); + + BDFDB.TimeUtils.timeout(_ => { + if (!loading.is && header && this.props.entries.length != header.props.amount) { + header.props.amount = this.props.entries.length; + BDFDB.ReactUtils.forceUpdate(header); + } + }); + + return [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: "Plugins", + open: this.props.tab == "Plugins", + render: false, + children: loading.is ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + direction: BDFDB.LibraryComponents.Flex.Direction.VERTICAL, + justify: BDFDB.LibraryComponents.Flex.Justify.CENTER, + style: {marginTop: "50%"}, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Spinner, { + type: BDFDB.LibraryComponents.Spinner.Type.WANDERING_CUBES + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextElement, { + className: BDFDB.disCN.margintop20, + style: {textAlign: "center"}, + children: `${BDFDB.LanguageUtils.LibraryStringsFormat("loading", "Plugin Repo")} - ${BDFDB.LanguageUtils.LibraryStrings.please_wait}` + }) + ] + }) : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycards, + children: this.props.entries + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: BDFDB.LanguageUtils.LanguageStrings.SETTINGS, + open: this.props.tab == BDFDB.LanguageUtils.LanguageStrings.SETTINGS, + render: false, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { + title: "Show following Plugins", + children: Object.keys(_this.defaults.filters).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + type: "Switch", + plugin: _this, + keys: ["filters", key], + label: _this.defaults.filters[key].description, + value: _this.settings.filters[key], + onChange: value => { + this.props[key] = _this.settings.filters[key] = value; + BDFDB.ReactUtils.forceUpdate(this); + } + })) + }), + Object.keys(_this.defaults.general).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + type: "Switch", + plugin: _this, + keys: ["general", key], + label: _this.defaults.general[key].description, + note: _this.defaults.general[key].autoload && !automaticLoading && "Automatic Loading has to be enabled", + disabled: _this.defaults.general[key].autoload && !automaticLoading, + value: _this.settings.general[key], + onChange: value => { + _this.settings.general[key] = value; + BDFDB.ReactUtils.forceUpdate(this); + } + })), + !automaticLoading && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS.settingsrowtitle + BDFDB.disCNS.settingsrowtitledefault + BDFDB.disCN.cursordefault, + children: "To experience Plugin Repo in the best way. I would recommend you to enable BD's intern Automatic-Loading Feature, that way all downloaded Files are loaded into Discord without the need to reload." + }) + }) + ].flat(10).filter(n => n) + }) + ]; + } + }; + + const RepoCardComponent = class PluginCard extends BdApi.React.Component { + render() { + if (this.props.data.thumbnailUrl && !this.props.data.thumbnailChecked) { + if (!window.Buffer) this.props.data.thumbnailChecked = true; + else BDFDB.LibraryRequires.request(this.props.data.thumbnailUrl, {encoding: null}, (error, response, body) => { + if (response && response.headers["content-type"] && response.headers["content-type"] == "image/gif") { + const throwAwayImg = new Image(), instance = this; + throwAwayImg.onload = function() { + const canvas = document.createElement("canvas"); + canvas.getContext("2d").drawImage(throwAwayImg, 0, 0, canvas.width = this.width, canvas.height = this.height); + try { + const oldUrl = instance.props.data.thumbnailUrl; + instance.props.data.thumbnailUrl = canvas.toDataURL("image/png"); + instance.props.data.thumbnailGifUrl = oldUrl; + instance.props.data.thumbnailChecked = true; + BDFDB.ReactUtils.forceUpdate(instance); + } + catch (err) { + instance.props.data.thumbnailChecked = true; + BDFDB.ReactUtils.forceUpdate(instance); + } + }; + throwAwayImg.onerror = function() { + instance.props.data.thumbnailChecked = true; + BDFDB.ReactUtils.forceUpdate(instance); + }; + throwAwayImg.src = "data:" + response.headers["content-type"] + ";base64," + (new Buffer(body).toString("base64")); + } + else { + this.props.data.thumbnailChecked = true; + BDFDB.ReactUtils.forceUpdate(this); + } + }); + } + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycard, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardheader, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardcoverwrapper, + children: [ + this.props.data.thumbnailUrl && this.props.data.thumbnailChecked && BDFDB.ReactUtils.createElement("img", { + className: BDFDB.disCN.discoverycardcover, + src: this.props.data.thumbnailUrl, + loading: "lazy", + onMouseEnter: this.props.data.thumbnailGifUrl && (e => e.target.src = this.props.data.thumbnailGifUrl), + onMouseLeave: this.props.data.thumbnailGifUrl && (e => e.target.src = this.props.data.thumbnailUrl), + onClick: _ => { + const url = this.props.data.thumbnailGifUrl || this.props.data.thumbnailUrl; + const img = document.createElement("img"); + img.addEventListener("load", function() { + BDFDB.LibraryModules.ModalUtils.openModal(modalData => { + return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalRoot, Object.assign({ + className: BDFDB.disCN.imagemodal + }, modalData, { + size: BDFDB.LibraryComponents.ModalComponents.ModalSize.DYNAMIC, + "aria-label": BDFDB.LanguageUtils.LanguageStrings.IMAGE, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ImageModal, { + animated: false, + src: url, + original: url, + width: this.width, + height: this.height, + className: BDFDB.disCN.imagemodalimage, + shouldAnimate: true, + renderLinkComponent: props => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Anchor, props) + }) + }), true); + }); + }); + img.src = url; + } + }), + this.props.data.new && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.TextBadge, { + className: BDFDB.disCN.discoverycardcoverbadge, + style: { + borderRadius: 3, + textTransform: "uppercase", + background: BDFDB.DiscordConstants.Colors.STATUS_YELLOW + }, + text: BDFDB.LanguageUtils.LanguageStrings.NEW + }) + ] + }), + BDFDB.ReactUtils.createElement(class extends BDFDB.ReactUtils.Component { + render() { + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardiconwrapper, + children: this.props.data.author && this.props.data.author.discord_avatar_hash && this.props.data.author.discord_snowflake && !this.props.data.author.discord_avatar_failed ? BDFDB.ReactUtils.createElement("img", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.discoverycardicon, !this.props.data.author.discord_avatar_loaded && BDFDB.disCN.discoverycardiconloading), + src: `https://cdn.discordapp.com/avatars/${this.props.data.author.discord_snowflake}/${this.props.data.author.discord_avatar_hash}.webp?size=128`, + loading: "lazy", + onLoad: _ => { + this.props.data.author.discord_avatar_loaded = true; + BDFDB.ReactUtils.forceUpdate(this); + }, + onError: _ => { + this.props.data.author.discord_avatar_failed = true; + BDFDB.ReactUtils.forceUpdate(this); + } + }) : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardicon, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + nativeClass: true, + iconSVG: `` + }) + }) + }); + } + }, this.props) + ] + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardinfo, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardtitle, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardname, + children: this.props.data.name + }), + this.props.data.latestSourceUrl && + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: BDFDB.LanguageUtils.LanguageStrings.SCREENSHARE_SOURCE, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, { + className: BDFDB.disCN.discoverycardtitlebutton, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + nativeClass: true, + width: 16, + height: 16, + name: BDFDB.LibraryComponents.SvgIcon.Names.GITHUB + }) + }), + onClick: _ => BDFDB.DiscordUtils.openLink(this.props.data.latestSourceUrl) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FavButton, { + className: BDFDB.disCN.discoverycardtitlebutton, + isFavorite: this.props.data.fav, + onClick: value => { + this.props.data.fav = value && 1; + if (value) favorites.push(this.props.data.id); + else BDFDB.ArrayUtils.remove(favorites, this.props.data.id, true); + BDFDB.DataUtils.save(BDFDB.ArrayUtils.numSort(favorites).join(" "), _this, "favorites"); + } + }) + ] + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardauthor, + children: `by ${this.props.data.authorname}` + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Scrollers.Thin, { + className: BDFDB.disCN.discoverycarddescription, + children: this.props.data.description + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardfooter, + children: [ + BDFDB.ArrayUtils.is(this.props.data.tags) && this.props.data.tags.length && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardtags, + children: this.props.data.tags.map(tag => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.TextBadge, { + className: BDFDB.disCN.discoverycardtag, + style: {background: "var(--background-accent)"}, + text: tag + })) + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardcontrols, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardstats, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardstat, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.discoverycardstaticon, + width: 16, + height: 16, + name: BDFDB.LibraryComponents.SvgIcon.Names.DOWNLOAD + }), + this.props.data.downloads + ] + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardstat, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.discoverycardstaticon, + width: 16, + height: 16, + name: BDFDB.LibraryComponents.SvgIcon.Names.HEART + }), + this.props.data.likes + ] + }) + ] + }), + BDFDB.ReactUtils.createElement(RepoCardDownloadButtonComponent, { + ...buttonData[(Object.entries(pluginStates).find(n => n[1] == this.props.data.state) || [])[0]], + installed: this.props.data.state == pluginStates.INSTALLED, + outdated: this.props.data.state == pluginStates.OUTDATED, + onDownload: _ => { + if (this.props.downloading) return; + this.props.downloading = true; + let loadingToast = BDFDB.NotificationUtils.toast(`${BDFDB.LanguageUtils.LibraryStringsFormat("loading", this.props.data.name)} - ${BDFDB.LanguageUtils.LibraryStrings.please_wait}`, {timeout: 0, ellipsis: true}); + let autoloadKey = this.props.data.state == pluginStates.OUTDATED ? "startUpdated" : "startDownloaded"; + BDFDB.LibraryRequires.request(this.props.data.rawSourceUrl, (error, response, body) => { + if (error) { + delete this.props.downloading; + loadingToast.close(); + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("download_fail", `Plugin "${this.props.data.name}"`), {type: "danger"}); + } + else { + BDFDB.LibraryRequires.fs.writeFile(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), this.props.data.rawSourceUrl.split("/").pop()), body, error2 => { + delete this.props.downloading; + loadingToast.close(); + if (error2) BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("save_fail", `Plugin "${this.props.data.name}"`), {type: "danger"}); + else { + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("save_success", `Plugin "${this.props.data.name}"`), {type: "success"}); + if (_this.settings.general[autoloadKey]) BDFDB.TimeUtils.timeout(_ => { + if (this.props.data.state == pluginStates.INSTALLED && BDFDB.BDUtils.isPluginEnabled(this.props.data.name) == false) { + BDFDB.BDUtils.enablePlugin(this.props.data.name, false); + BDFDB.LogUtils.log(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_started", this.props.data.name), _this); + } + }, 3000); + this.props.data.state = pluginStates.INSTALLED; + BDFDB.ReactUtils.forceUpdate(this); + } + }); + } + }); + }, + onDelete: _ => { + if (this.props.deleting) return; + this.props.deleting = true; + BDFDB.LibraryRequires.fs.unlink(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), this.props.data.rawSourceUrl.split("/").pop()), error => { + delete this.props.deleting; + if (error) BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("delete_fail", `Plugin "${this.props.data.name}"`), {type: "danger"}); + else { + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("delete_success", `Plugin "${this.props.data.name}"`)); + this.props.data.state = pluginStates.DOWNLOADABLE; + BDFDB.ReactUtils.forceUpdate(this); + } + }); + } + }) + ] + }) + ] + }) + ] + }) + ] + }); + } + }; + + const RepoCardDownloadButtonComponent = class PluginCardDownloadButton extends BdApi.React.Component { + render() { + const backgroundColor = this.props.doDelete ? buttonData.OUTDATED.backgroundColor : this.props.doUpdate ? buttonData.INSTALLED.backgroundColor : this.props.backgroundColor; + return BDFDB.ReactUtils.createElement("button", { + className: BDFDB.disCN.discoverycardbutton, + style: {backgroundColor: BDFDB.DiscordConstants.Colors[backgroundColor] || backgroundColor}, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.discoverycardstaticon, + width: 16, + height: 16, + name: this.props.doDelete ? BDFDB.LibraryComponents.SvgIcon.Names.TRASH : this.props.doUpdate ? BDFDB.LibraryComponents.SvgIcon.Names.DOWNLOAD : BDFDB.LibraryComponents.SvgIcon.Names[this.props.icon] + }), + this.props.doDelete ? BDFDB.LanguageUtils.LanguageStrings.APPLICATION_CONTEXT_MENU_UNINSTALL : this.props.doUpdate ? BDFDB.LanguageUtils.LanguageStrings.GAME_ACTION_BUTTON_UPDATE : (BDFDB.LanguageUtils.LibraryStringsCheck[this.props.text] ? BDFDB.LanguageUtils.LibraryStrings[this.props.text] : BDFDB.LanguageUtils.LanguageStrings[this.props.text]) + ], + onClick: _ => { + if (this.props.doDelete) typeof this.props.onDelete == "function" && this.props.onDelete(); + else if (!this.props.installed) typeof this.props.onDownload == "function" && this.props.onDownload(); + }, + onMouseEnter: this.props.installed ? (_ => { + this.props.doDelete = true; + BDFDB.ReactUtils.forceUpdate(this); + }) : this.props.outdated ? (_ => { + this.props.doUpdate = true; + BDFDB.ReactUtils.forceUpdate(this); + }) : (_ => {}), + onMouseLeave: this.props.installed ? (_ => { + this.props.doDelete = false; + BDFDB.ReactUtils.forceUpdate(this); + }) : this.props.outdated ? (_ => { + this.props.doUpdate = false; + BDFDB.ReactUtils.forceUpdate(this); + }) : (_ => {}) + }); + } + }; + + const RepoListHeaderComponent = class PluginListHeader extends BdApi.React.Component { + componentDidMount() { + header = this; + } + render() { + if (!this.props.tab) this.props.tab = "Plugins"; + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._repolistheader, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom4, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + grow: 1, + shrink: 0, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormTitle, { + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H2, + className: BDFDB.disCN.marginreset, + children: `Plugin Repo — ${loading.is ? 0 : this.props.amount || 0}/${loading.is ? 0 : grabbedPlugins.length}` + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SearchBar, { + autoFocus: true, + query: searchString, + onChange: (value, instance) => { + if (loading.is) return; + BDFDB.TimeUtils.clear(searchTimeout); + searchTimeout = BDFDB.TimeUtils.timeout(_ => { + searchString = value.replace(/[<|>]/g, ""); + BDFDB.ReactUtils.forceUpdate(this, list); + }, 1000); + }, + onClear: instance => { + if (loading.is) return; + searchString = ""; + BDFDB.ReactUtils.forceUpdate(this, list); + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { + size: BDFDB.LibraryComponents.Button.Sizes.TINY, + children: BDFDB.LanguageUtils.LibraryStrings.check_for_updates, + onClick: _ => { + if (loading.is) return; + loading = {is: false, timeout: null, amount: 0}; + _this.loadPlugins(); + } + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCNS.tabbarcontainer + BDFDB.disCN.tabbarcontainerbottom, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TabBar, { + className: BDFDB.disCN.tabbar, + itemClassName: BDFDB.disCN.tabbaritem, + type: BDFDB.LibraryComponents.TabBar.Types.TOP, + selectedItem: this.props.tab, + items: [{value: "Plugins"}, {value: BDFDB.LanguageUtils.LanguageStrings.SETTINGS}], + onItemSelect: value => { + this.props.tab = list.props.tab = value; + BDFDB.ReactUtils.forceUpdate(list); + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.QuickSelect, { + label: BDFDB.LanguageUtils.LibraryStrings.sort_by + ":", + value: { + label: sortKeys[this.props.sortKey], + value: this.props.sortKey + }, + options: Object.keys(sortKeys).map(key => ({ + label: sortKeys[key], + value: key + })), + onChange: key => { + this.props.sortKey = list.props.sortKey = key; + BDFDB.ReactUtils.forceUpdate(this, list); + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.QuickSelect, { + label: BDFDB.LanguageUtils.LibraryStrings.order + ":", + value: { + label: BDFDB.LanguageUtils.LibraryStrings[orderKeys[this.props.orderKey]], + value: this.props.orderKey + }, + options: Object.keys(orderKeys).map(key => ({ + label: BDFDB.LanguageUtils.LibraryStrings[orderKeys[key]], + value: key + })), + onChange: key => { + this.props.orderKey = list.props.orderKey = key; + BDFDB.ReactUtils.forceUpdate(this, list); + } + }) + }) + ] + }) + ] + }); + } + }; + + return class PluginRepo extends Plugin { + onLoad () { + _this = this; + + loading = {is: false, timeout: null, amount: 0}; + + cachedPlugins = []; + grabbedPlugins = []; + searchString = ""; + + this.defaults = { + general: { + notifyOutdated: {value: true, autoload: false, description: "Get a Notification when one of your Plugins is outdated"}, + notifyNewEntries: {value: true, autoload: false, description: "Get a Notification when there are new Entries in the Repo"}, + startDownloaded: {value: false, autoload: true, description: "Start new Plugins after Download"}, + startUpdated: {value: false, autoload: true, description: "Start updated Plugins after Download"} + }, + filters: { + updated: {value: true, description: "Updated"}, + outdated: {value: true, description: "Outdated"}, + downloadable: {value: true, description: "Downloadable"}, + } + }; + + this.patchedModules = { + before: { + SettingsView: ["render", "componentWillUnmount"] + }, + after: { + StandardSidebarView: "render" + } + }; + + } + + onStart () { + this.forceUpdateAll(); + + this.loadPlugins(); + + updateInterval = BDFDB.TimeUtils.interval(_ => this.checkForNewPlugins(), 1000*60*30); + } + + onStop () { + BDFDB.TimeUtils.clear(updateInterval); + BDFDB.TimeUtils.clear(loading.timeout); + + this.forceUpdateAll(); + + BDFDB.DOMUtils.remove(BDFDB.dotCN._pluginreponotice, BDFDB.dotCN._pluginrepoloadingicon); + } + + onSettingsClosed () { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + this.forceUpdateAll(); + } + } + + forceUpdateAll () { + favorites = BDFDB.DataUtils.load(this, "favorites"); + favorites = (typeof favorites == "string" ? favorites.split(" ") : []).map(n => parseInt(n)).filter(n => !isNaN(n)); + + BDFDB.PatchUtils.forceAllUpdates(this); + } + + onUserSettingsCogContextMenu (e) { + BDFDB.TimeUtils.timeout(_ => { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["label", ["BandagedBD", "BetterDiscord"]]]}); + if (index > -1 && BDFDB.ArrayUtils.is(children[index].props.children)) children[index].props.children.push(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: "Plugin Repo", + id: BDFDB.ContextMenuUtils.createItemId(this.name, "repo"), + action: _ => { + BDFDB.LibraryModules.UserSettingsUtils.open("pluginrepo"); + } + })); + }); + } + + processSettingsView (e) { + if (e.node) searchString = ""; + else { + if (!BDFDB.PatchUtils.isPatched(this, e.component, "getPredicateSections")) BDFDB.PatchUtils.patch(this, e.component, "getPredicateSections", {after: e2 => { + if (BDFDB.ArrayUtils.is(e2.returnValue) && e2.returnValue.findIndex(n => n.section && (n.section.toLowerCase() == "changelog" || n.section == BDFDB.DiscordConstants.UserSettingsSections.CHANGE_LOG || n.section.toLowerCase() == "logout" || n.section == BDFDB.DiscordConstants.UserSettingsSections.LOGOUT))) { + e2.returnValue = e2.returnValue.filter(n => n.section != "pluginrepo"); + let index = e2.returnValue.indexOf(e2.returnValue.find(n => n.section == "themes") || e2.returnValue.find(n => n.section == BDFDB.DiscordConstants.UserSettingsSections.DEVELOPER_OPTIONS) || e2.returnValue.find(n => n.section == BDFDB.DiscordConstants.UserSettingsSections.HYPESQUAD_ONLINE)); + if (index > -1) { + e2.returnValue.splice(index + 1, 0, { + section: "pluginrepo", + label: "Plugin Repo", + element: _ => { + let options = Object.assign({}, this.settings.filters); + options.updated = options.updated && !showOnlyOutdated; + options.outdated = options.outdated || showOnlyOutdated; + options.downloadable = options.downloadable && !showOnlyOutdated; + options.sortKey = forcedSort || Object.keys(sortKeys)[0]; + options.orderKey = forcedOrder || Object.keys(orderKeys)[0]; + + return BDFDB.ReactUtils.createElement(RepoListComponent, options, true); + } + }); + if (!e2.returnValue.find(n => n.section == "plugins")) e2.returnValue.splice(index + 1, 0, {section: "DIVIDER"}); + } + } + }}); + } + } + + processStandardSidebarView (e) { + if (e.instance.props.section == "pluginrepo") { + let content = BDFDB.ReactUtils.findChild(e.returnvalue, {props: [["className", BDFDB.disCN.settingswindowcontentregion]]}); + if (content) content.props.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repolistwrapper, content.props.className); + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["className", BDFDB.disCN.settingswindowcontentregionscroller]]}); + if (index > -1) { + let options = {}; + options.sortKey = forcedSort || Object.keys(sortKeys)[0]; + options.orderKey = forcedOrder || Object.keys(orderKeys)[0]; + children[index] = [ + BDFDB.ReactUtils.createElement(RepoListHeaderComponent, options, true), + children[index] + ]; + } + } + } + + loadPlugins () { + BDFDB.DOMUtils.remove(BDFDB.dotCN._pluginrepoloadingicon); + cachedPlugins = BDFDB.DataUtils.load(this, "cached"); + cachedPlugins = (typeof cachedPlugins == "string" ? cachedPlugins.split(" ") : []).map(n => parseInt(n)).filter(n => !isNaN(n)); + + let loadingIcon; + let newEntries = 0, outdatedEntries = 0, checkIndex = 0, checksRunning = 0, callbackCalled = false; + + const checkPlugin = _ => { + if (checksRunning > 20) return; + else if (grabbedPlugins.every(p => p.loaded || (!p.latestSourceUrl && !p.latest_source_url)) || !this.started || !loading.is) { + if (!callbackCalled) { + callbackCalled = true; + if (!this.started) return BDFDB.TimeUtils.clear(loading.timeout); + BDFDB.TimeUtils.clear(loading.timeout); + BDFDB.DOMUtils.remove(loadingIcon, BDFDB.dotCN._pluginrepoloadingicon); + loading = {is: false, timeout: null, amount: loading.amount}; + + BDFDB.LogUtils.log("Finished fetching Plugins", this); + BDFDB.ReactUtils.forceUpdate(list); + + if (this.settings.general.notifyOutdated && outdatedEntries > 0) { + let notice = document.querySelector(BDFDB.dotCN._pluginrepooutdatednotice); + if (notice) notice.close(); + BDFDB.NotificationUtils.notice(this.labels.notice_outdated_plugins.replace("{{var0}}", outdatedEntries), { + type: "danger", + className: BDFDB.disCNS._pluginreponotice + BDFDB.disCN._pluginrepooutdatednotice, + customIcon: pluginRepoIcon.replace(/COLOR_[0-9]+/gi, "currentColor"), + buttons: [{ + contents: BDFDB.LanguageUtils.LanguageStrings.OPEN, + close: true, + onClick: _ => { + showOnlyOutdated = true; + BDFDB.LibraryModules.UserSettingsUtils.open("pluginrepo"); + } + }] + }); + } + + if (this.settings.general.notifyNewEntries && newEntries > 0) { + let notice = document.querySelector(BDFDB.dotCN._pluginreponewentriesnotice); + if (notice) notice.close(); + BDFDB.NotificationUtils.notice(this.labels.notice_new_plugins.replace("{{var0}}", newEntries), { + type: "success", + className: BDFDB.disCNS._pluginreponotice + BDFDB.disCN._pluginreponewentriesnotice, + customIcon: pluginRepoIcon.replace(/COLOR_[0-9]+/gi, "currentColor"), + buttons: [{ + contents: BDFDB.LanguageUtils.LanguageStrings.OPEN, + close: true, + onClick: _ => { + forcedSort = "RELEASEDATE"; + forcedOrder = "ASC"; + BDFDB.LibraryModules.UserSettingsUtils.open("pluginrepo"); + } + }] + }); + } + } + return; + } + else if (checkIndex > grabbedPlugins.length) return; + + const plugin = grabbedPlugins[checkIndex++]; + if (!plugin || (!plugin.latestSourceUrl && !plugin.latest_source_url)) checkPlugin(); + else { + checksRunning++; + plugin.releasedate = new Date(plugin.releaseDate || plugin.release_date || 0).getTime(); + plugin.latestSourceUrl = plugin.latestSourceUrl || plugin.latest_source_url; + plugin.rawSourceUrl = plugin.latestSourceUrl.replace("https://github.com/", "https://raw.githubusercontent.com/").replace(/\/blob\/(.{32,})/i, "/$1"); + plugin.thumbnailUrl = plugin.thumbnailUrl || plugin.thumbnail_url; + plugin.thumbnailUrl = plugin.thumbnailUrl ? (plugin.thumbnailUrl.startsWith("https://") ? plugin.thumbnailUrl : `https://betterdiscord.app${plugin.thumbnailUrl}`) : ""; + delete plugin.release_date; + delete plugin.latest_source_url; + delete plugin.thumbnail_url; + BDFDB.LibraryRequires.request(plugin.rawSourceUrl, (error, response, body) => { + if (body && body.indexOf("404: Not Found") != 0 && response.statusCode == 200) { + plugin.name = BDFDB.LibraryModules.StringUtils.upperCaseFirstChar((/@name\s+([^\t^\r^\n]+)|\/\/\**META.*["']name["']\s*:\s*["'](.+?)["']/i.exec(body) || []).filter(n => n)[1] || plugin.name || ""); + plugin.authorname = (/@author\s+(.+)|\/\/\**META.*["']author["']\s*:\s*["'](.+?)["']/i.exec(body) || []).filter(n => n)[1] || plugin.author.display_name || plugin.author; + const version = (/@version\s+(.+)|\/\/\**META.*["']version["']\s*:\s*["'](.+?)["']/i.exec(body) || []).filter(n => n)[1]; + if (version) { + plugin.version = version; + const installedPlugin = this.getInstalledPlugin(plugin); + if (installedPlugin && this.compareVersions(version, this.getString(installedPlugin.version))) outdatedEntries++; + } + } + if (!cachedPlugins.includes(plugin.id)) newEntries++; + + plugin.loaded = true; + + let loadingTooltip = document.querySelector(BDFDB.dotCN._pluginrepoloadingtooltip); + if (loadingTooltip) loadingTooltip.update(this.getLoadingTooltipText()); + + checksRunning--; + checkPlugin(); + }); + } + }; + + BDFDB.LibraryRequires.request("https://api.betterdiscord.app/v1/store/plugins", (error, response, body) => { + if (!error && body && response.statusCode == 200) try { + grabbedPlugins = BDFDB.ArrayUtils.keySort(JSON.parse(body).filter(n => n), "name"); + BDFDB.DataUtils.save(BDFDB.ArrayUtils.numSort(grabbedPlugins.map(n => n.id)).join(" "), this, "cached"); + + loading = {is: true, timeout: BDFDB.TimeUtils.timeout(_ => { + BDFDB.TimeUtils.clear(loading.timeout); + if (this.started) { + if (loading.is && loading.amount < 4) BDFDB.TimeUtils.timeout(_ => this.loadPlugins(), 10000); + loading = {is: false, timeout: null, amount: loading.amount}; + } + }, 1200000), amount: loading.amount + 1}; + + loadingIcon = BDFDB.DOMUtils.create(pluginRepoIcon.replace(/COLOR_1/gi, "var(--bdfdb-blurple)").replace(/COLOR_2/gi, "#72767d")); + BDFDB.DOMUtils.addClass(loadingIcon, BDFDB.disCN._pluginrepoloadingicon); + loadingIcon.addEventListener("mouseenter", _ => { + BDFDB.TooltipUtils.create(loadingIcon, this.getLoadingTooltipText(), { + type: "left", + className: BDFDB.disCN._pluginrepoloadingtooltip, + delay: 500, + style: "max-width: unset;" + }); + }); + BDFDB.PluginUtils.addLoadingIcon(loadingIcon); + + BDFDB.ReactUtils.forceUpdate(list, header); + + for (let i = 0; i <= 20; i++) checkPlugin(); + } + catch (err) {BDFDB.NotificationUtils.toast("Failed to load Plugin Store", {type: "danger"});} + if (response && response.statusCode == 403) BDFDB.NotificationUtils.toast("Failed to fetch Plugin Store from the Website Api due to DDoS Protection", {type: "danger"}); + else if (response && response.statusCode == 404) BDFDB.NotificationUtils.toast("Failed to fetch Plugin Store from the Website Api due to Connection Issue", {type: "danger"}); + }); + } + + getLoadingTooltipText () { + return BDFDB.LanguageUtils.LibraryStringsFormat("loading", `Plugin Repo - [${grabbedPlugins.filter(n => n.loaded).length}/${grabbedPlugins.length}]`); + } + + getString (obj) { + let string = ""; + if (typeof obj == "string") string = obj; + else if (obj && obj.props) { + if (typeof obj.props.children == "string") string = obj.props.children; + else if (Array.isArray(obj.props.children)) for (let c of obj.props.children) string += typeof c == "string" ? c : this.getString(c); + } + return string; + } + + compareVersions (v1, v2) { + return !(v1 == v2 || !BDFDB.NumberUtils.compareVersions(v1, v2)); + } + + getInstalledPlugin (plugin) { + if (!plugin || typeof plugin.authorname != "string") return; + const iPlugin = BDFDB.BDUtils.getPlugin(plugin.name, false, true); + if (iPlugin && plugin.authorname.toUpperCase() == this.getString(iPlugin.author).toUpperCase()) return iPlugin; + else if (plugin.rawSourceUrl && window.BdApi && BdApi.Plugins && typeof BdApi.Plugins.getAll == "function") { + const filename = plugin.rawSourceUrl.split("/").pop(); + for (let p of BdApi.Plugins.getAll()) if (p.filename == filename && plugin.authorname.toUpperCase() == this.getString(p.author).toUpperCase()) return p; + } + } + + checkForNewPlugins () { + BDFDB.LibraryRequires.request("https://api.betterdiscord.app/v1/store/plugins", (error, response, body) => { + if (!error && body) try { + if (JSON.parse(body).filter(n => n).length != grabbedPlugins.length) { + loading = {is: false, timeout: null, amount: 0}; + this.loadPlugins(); + } + } + catch (err) {BDFDB.NotificationUtils.toast("Failed to load Plugin Store", {type: "danger"});} + }); + } + + setLabelsByLanguage () { + switch (BDFDB.LanguageUtils.getLanguage().id) { + case "bg": // Bulgarian + return { + list: "Списък", + notice_failed_plugins: "Някои Plugins [{{var0}}] не можаха да бъдат заредени", + notice_new_plugins: "Новите Plugins [{{var0}}] бяха добавени към Plugin Repo", + notice_outdated_plugins: "Някои Plugins [{{var0}}] са остарели" + }; + case "da": // Danish + return { + list: "Liste", + notice_failed_plugins: "Nogle Plugins [{{var0}}] kunne ikke indlæses", + notice_new_plugins: "Nye Plugins [{{var0}}] er blevet føjet til Plugin Repo", + notice_outdated_plugins: "Nogle Plugins [{{var0}}] er forældede" + }; + case "de": // German + return { + list: "Liste", + notice_failed_plugins: "Einige Plugins [{{var0}}] konnten nicht geladen werden", + notice_new_plugins: "Neue Plugins [{{var0}}] wurden zur Plugin Repo hinzugefügt", + notice_outdated_plugins: "Einige Plugins [{{var0}}] sind veraltet" + }; + case "el": // Greek + return { + list: "Λίστα", + notice_failed_plugins: "Δεν ήταν δυνατή η φόρτωση ορισμένων Plugins [{{var0}}] ", + notice_new_plugins: "Προστέθηκαν νέα Plugins [{{var0}}] στο Plugin Repo", + notice_outdated_plugins: "Ορισμένα Plugins [{{var0}}] είναι παλιά" + }; + case "es": // Spanish + return { + list: "Lista", + notice_failed_plugins: "Algunos Plugins [{{var0}}] no se pudieron cargar", + notice_new_plugins: "Se han agregado nuevos Plugins [{{var0}}] a Plugin Repo", + notice_outdated_plugins: "Algunas Plugins [{{var0}}] están desactualizadas" + }; + case "fi": // Finnish + return { + list: "Lista", + notice_failed_plugins: "Joitain kohdetta Plugins [{{var0}}] ei voitu ladata", + notice_new_plugins: "Uusi Plugins [{{var0}}] on lisätty Plugin Repo", + notice_outdated_plugins: "Jotkut Plugins [{{var0}}] ovat vanhentuneita" + }; + case "fr": // French + return { + list: "Liste", + notice_failed_plugins: "Certains Plugins [{{var0}}] n'ont pas pu être chargés", + notice_new_plugins: "De nouveaux Plugins [{{var0}}] ont été ajoutés à Plugin Repo", + notice_outdated_plugins: "Certains Plugins [{{var0}}] sont obsolètes" + }; + case "hr": // Croatian + return { + list: "Popis", + notice_failed_plugins: "Neke datoteke Plugins [{{var0}}] nije moguće učitati", + notice_new_plugins: "Novi Plugins [{{var0}}] dodani su u Plugin Repo", + notice_outdated_plugins: "Neki su Plugins [{{var0}}] zastarjeli" + }; + case "hu": // Hungarian + return { + list: "Lista", + notice_failed_plugins: "Néhány Plugins [{{var0}}] nem sikerült betölteni", + notice_new_plugins: "Új Plugins [{{var0}}] hozzáadva a következőhöz: Plugin Repo", + notice_outdated_plugins: "Néhány Plugins [{{var0}}] elavult" + }; + case "it": // Italian + return { + list: "Elenco", + notice_failed_plugins: "Impossibile caricare alcuni Plugins [{{var0}}] ", + notice_new_plugins: "Il nuovo Plugins [{{var0}}] è stato aggiunto a Plugin Repo", + notice_outdated_plugins: "Alcuni Plugins [{{var0}}] non sono aggiornati" + }; + case "ja": // Japanese + return { + list: "リスト", + notice_failed_plugins: "一部の Plugins [{{var0}}] を読み込めませんでした", + notice_new_plugins: "新しい Plugins [{{var0}}] が Plugin Repo に追加されました", + notice_outdated_plugins: "一部の Plugins [{{var0}}] は古くなっています" + }; + case "ko": // Korean + return { + list: "명부", + notice_failed_plugins: "일부 Plugins [{{var0}}] 을 (를)로드 할 수 없습니다.", + notice_new_plugins: "새 Plugins [{{var0}}] 이 Plugin Repo 에 추가되었습니다.", + notice_outdated_plugins: "일부 Plugins [{{var0}}] 이 오래되었습니다." + }; + case "lt": // Lithuanian + return { + list: "Sąrašas", + notice_failed_plugins: "Kai kurių Plugins [{{var0}}] nepavyko įkelti", + notice_new_plugins: "Naujas Plugins [{{var0}}] pridėtas prie Plugin Repo", + notice_outdated_plugins: "Kai kurie Plugins [{{var0}}] yra pasenę" + }; + case "nl": // Dutch + return { + list: "Lijst", + notice_failed_plugins: "Sommige Plugins [{{var0}}] konden niet worden geladen", + notice_new_plugins: "Nieuwe Plugins [{{var0}}] zijn toegevoegd aan de Plugin Repo", + notice_outdated_plugins: "Sommige Plugins [{{var0}}] zijn verouderd" + }; + case "no": // Norwegian + return { + list: "Liste", + notice_failed_plugins: "Noen Plugins [{{var0}}] kunne ikke lastes inn", + notice_new_plugins: "Nye Plugins [{{var0}}] er lagt til i Plugin Repo", + notice_outdated_plugins: "Noen Plugins [{{var0}}] er utdaterte" + }; + case "pl": // Polish + return { + list: "Lista", + notice_failed_plugins: "Nie można załadować niektórych Plugins [{{var0}}] ", + notice_new_plugins: "Nowe Plugins [{{var0}}] zostały dodane do Plugin Repo", + notice_outdated_plugins: "Niektóre Plugins [{{var0}}] są nieaktualne" + }; + case "pt-BR": // Portuguese (Brazil) + return { + list: "Lista", + notice_failed_plugins: "Algum Plugins [{{var0}}] não pôde ser carregado", + notice_new_plugins: "Novo Plugins [{{var0}}] foi adicionado ao Plugin Repo", + notice_outdated_plugins: "Alguns Plugins [{{var0}}] estão desatualizados" + }; + case "ro": // Romanian + return { + list: "Listă", + notice_failed_plugins: "Unele Plugins [{{var0}}] nu au putut fi încărcate", + notice_new_plugins: "Plugins [{{var0}}] nou au fost adăugate la Plugin Repo", + notice_outdated_plugins: "Unele Plugins [{{var0}}] sunt învechite" + }; + case "ru": // Russian + return { + list: "Список", + notice_failed_plugins: "Не удалось загрузить некоторые Plugins [{{var0}}] ", + notice_new_plugins: "Новые Plugins [{{var0}}] добавлены в Plugin Repo", + notice_outdated_plugins: "Некоторые Plugins [{{var0}}] устарели" + }; + case "sv": // Swedish + return { + list: "Lista", + notice_failed_plugins: "Vissa Plugins [{{var0}}] kunde inte laddas", + notice_new_plugins: "Nya Plugins [{{var0}}] har lagts till i Plugin Repo", + notice_outdated_plugins: "Vissa Plugins [{{var0}}] är föråldrade" + }; + case "th": // Thai + return { + list: "รายการ", + notice_failed_plugins: "ไม่สามารถโหลด Plugins [{{var0}}] บางรายการได้", + notice_new_plugins: "เพิ่ม Plugins [{{var0}}] ใหม่ใน Plugin Repo แล้ว", + notice_outdated_plugins: "Plugins [{{var0}}] บางรายการล้าสมัย" + }; + case "tr": // Turkish + return { + list: "Liste", + notice_failed_plugins: "Bazı Plugins [{{var0}}] yüklenemedi", + notice_new_plugins: "Yeni Plugins [{{var0}}], Plugin Repo 'ye eklendi", + notice_outdated_plugins: "Bazı Plugins [{{var0}}] güncel değil" + }; + case "uk": // Ukrainian + return { + list: "Список", + notice_failed_plugins: "Деякі Plugins [{{var0}}] не вдалося завантажити", + notice_new_plugins: "Нові Plugins [{{var0}}] були додані до Plugin Repo", + notice_outdated_plugins: "Деякі Plugins [{{var0}}] застарілі" + }; + case "vi": // Vietnamese + return { + list: "Danh sách", + notice_failed_plugins: "Không thể tải một số Plugins [{{var0}}] ", + notice_new_plugins: "Plugins [{{var0}}] mới đã được thêm vào Plugin Repo", + notice_outdated_plugins: "Một số Plugins [{{var0}}] đã lỗi thời" + }; + case "zh-CN": // Chinese (China) + return { + list: "清单", + notice_failed_plugins: "某些 Plugins [{{var0}}] 无法加载", + notice_new_plugins: "新的 Plugins [{{var0}}] 已添加到 Plugin Repo", + notice_outdated_plugins: "一些 Plugins [{{var0}}] 已过时" + }; + case "zh-TW": // Chinese (Taiwan) + return { + list: "清單", + notice_failed_plugins: "某些 Plugins [{{var0}}] 無法加載", + notice_new_plugins: "新的 Plugins [{{var0}}] 已添加到 Plugin Repo", + notice_outdated_plugins: "一些 Plugins [{{var0}}] 已過時" + }; + default: // English + return { + list: "List", + notice_failed_plugins: "Some Plugins [{{var0}}] could not be loaded", + notice_new_plugins: "New Plugins [{{var0}}] have been added to the Plugin Repo", + notice_outdated_plugins: "Some Plugins [{{var0}}] are outdated" + }; + } + } + }; + })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); +})(); diff --git a/oldconfig/BetterDiscord/plugins/PronounDB.config.json b/oldconfig/BetterDiscord/plugins/PronounDB.config.json new file mode 100644 index 0000000..1a43713 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/PronounDB.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.2.1", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ServerConfig.config.json b/oldconfig/BetterDiscord/plugins/ServerConfig.config.json new file mode 100644 index 0000000..6c7b5a3 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ServerConfig.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "1.0.0", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ServerDetails.config.json b/oldconfig/BetterDiscord/plugins/ServerDetails.config.json new file mode 100644 index 0000000..ff778fb --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ServerDetails.config.json @@ -0,0 +1,28 @@ +{ + "all": { + "amounts": { + "tooltipDelay": 0, + "tooltipWidth": 300 + }, + "colors": { + "tooltipColor": "" + }, + "dates": { + "tooltipDates": {} + }, + "general": { + "onlyShowOnShift": false + }, + "items": { + "icon": true, + "owner": true, + "creationDate": true, + "joinDate": true, + "members": true, + "channels": true, + "roles": true, + "boosts": true, + "language": true + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ServerFolders.config.json b/oldconfig/BetterDiscord/plugins/ServerFolders.config.json new file mode 100644 index 0000000..8b4bd70 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ServerFolders.config.json @@ -0,0 +1,13 @@ +{ + "all": { + "general": { + "closeOtherFolders": false, + "closeTheFolder": false, + "closeAllFolders": false, + "forceOpenFolder": false, + "showCountBadge": true, + "extraColumn": true, + "addSeparators": true + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ServerFolders.plugin.js b/oldconfig/BetterDiscord/plugins/ServerFolders.plugin.js new file mode 100644 index 0000000..3e2c751 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ServerFolders.plugin.js @@ -0,0 +1,1849 @@ +/** + * @name ServerFolders + * @author DevilBro + * @authorId 278543574059057154 + * @version 7.0.1 + * @description Changes Discord's Folders, Servers open in a new Container, also adds extra Features to more easily organize, customize and manage your Folders + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/ServerFolders/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/ServerFolders/ServerFolders.plugin.js + */ + +module.exports = (_ => { + const config = { + "info": { + "name": "ServerFolders", + "author": "DevilBro", + "version": "7.0.1", + "description": "Changes Discord's Folders, Servers open in a new Container, also adds extra Features to more easily organize, customize and manage your Folders" + } + }; + + return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;} + + downloadLibrary () { + require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { + if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"})); + else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library"); + }); + } + + load () { + if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []}); + if (!window.BDFDB_Global.downloadModal) { + window.BDFDB_Global.downloadModal = true; + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, + onConfirm: _ => { + delete window.BDFDB_Global.downloadModal; + this.downloadLibrary(); + } + }); + } + if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + } + start () {this.load();} + stop () {} + getSettingsPanel () { + let template = document.createElement("template"); + template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); + return template.content.firstElementChild; + } + } : (([Plugin, BDFDB]) => { + var _this; + var folderStates, folderReads, guildStates, currentGuild, forceCloseTimeout; + var folderConfigs = {}, customIcons = {}; + + const folderIcons = [ + {openicon: ``, + closedicon: ``}, + {openicon: ``, + closedicon: ``}, + {openicon: ``, + closedicon: ``}, + {openicon: ``, + closedicon: ``}, + {openicon: ``, + closedicon: ``}, + {openicon: ``, + closedicon: ``}, + {openicon: ``, + closedicon: ``} + ]; + + var folderGuildContent = null; + const FolderGuildContentComponent = class FolderGuildContent extends BdApi.React.Component { + componentDidMount() { + folderGuildContent = this; + } + render() { + let closing = this.props.closing; + delete this.props.closing; + let folders = Array.from(BDFDB.LibraryModules.FolderUtils.getExpandedFolders()).map(folderId => BDFDB.LibraryModules.FolderStore.getGuildFolderById(folderId)).filter(folder => folder && folder.guildIds); + this.props.folders = folders.length || closing ? folders : (this.props.folders || []); + BDFDB.TimeUtils.clear(this._rerenderTimeout); + if (!folders.length && this.props.folders.length && !closing) this._rerenderTimeout = BDFDB.TimeUtils.timeout(_ => { + this.props.closing = true; + BDFDB.ReactUtils.forceUpdate(this); + }, 300); + return BDFDB.ReactUtils.createElement("nav", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.guildswrapper, BDFDB.disCN.guilds, this.props.isAppFullscreen && BDFDB.disCN.guildswrapperhidden, this.props.themeOverride && BDFDB.disCN.themedark, BDFDB.disCN._serverfoldersfoldercontent, (!folders.length || closing) && BDFDB.disCN._serverfoldersfoldercontentclosed), + children: BDFDB.ReactUtils.createElement("ul", { + role: "tree", + tabindex: 0, + "data-list-id": "guildfoldersnav", + className: BDFDB.disCN.guildstree, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Scrollers.None, { + className: BDFDB.disCN.guildsscroller, + children: this.props.folders.map(folder => { + let data = _this.getFolderConfig(folder.folderId); + return folder.guildIds.map(guildId => { + return [ + this.draggedGuild == guildId ? null : BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.GuildComponents.Guild, { + guild: BDFDB.LibraryModules.GuildStore.getGuild(guildId), + state: true, + list: true, + tooltipConfig: Object.assign({ + offset: 12 + }, data.copyTooltipColor && { + backgroundColor: data.color3, + fontColor: data.color4, + }), + onClick: event => { + if (BDFDB.ListenerUtils.isPressed(46)) { + BDFDB.ListenerUtils.stopEvent(event); + _this.removeGuildFromFolder(folder.folderId, guildId); + } + else { + if (_this.settings.general.closeAllFolders) { + for (let openFolderId of BDFDB.LibraryModules.FolderUtils.getExpandedFolders()) if (openFolderId != folder.folderId || !_this.settings.general.forceOpenFolder) BDFDB.LibraryModules.GuildUtils.toggleGuildFolderExpand(openFolderId); + } + else if (_this.settings.general.closeTheFolder && !_this.settings.general.forceOpenFolder && BDFDB.LibraryModules.FolderUtils.isFolderExpanded(folder.folderId)) BDFDB.LibraryModules.GuildUtils.toggleGuildFolderExpand(folder.folderId); + else BDFDB.ReactUtils.forceUpdate(this); + } + }, + onMouseDown: (event, instance) => { + event = event.nativeEvent || event; + let mouseMove = event2 => { + if (Math.sqrt((event.pageX - event2.pageX)**2) > 20 || Math.sqrt((event.pageY - event2.pageY)**2) > 20) { + BDFDB.ListenerUtils.stopEvent(event); + this.draggedGuild = guildId; + let dragPreview = _this.createDragPreview(BDFDB.ReactUtils.findDOMNode(instance).cloneNode(true), event2); + BDFDB.ReactUtils.forceUpdate(this); + document.removeEventListener("mousemove", mouseMove); + document.removeEventListener("mouseup", mouseUp); + let dragging = event3 => { + _this.updateDragPreview(dragPreview, event3); + let placeholder = BDFDB.DOMUtils.getParent(BDFDB.dotCN._serverfoldersguildplaceholder, event3.target); + let hoveredGuild = (BDFDB.ReactUtils.findValue(BDFDB.DOMUtils.getParent(BDFDB.dotCNS._serverfoldersfoldercontent + BDFDB.dotCN.guildouter, placeholder ? placeholder.previousSibling : event3.target), "guild", {up: true}) || {}).id; + if (hoveredGuild) { + let hoveredGuildFolder = BDFDB.GuildUtils.getFolder(hoveredGuild); + if (!hoveredGuildFolder || hoveredGuildFolder.folderId != folder.folderId) hoveredGuild = null; + } + let update = hoveredGuild != this.hoveredGuild; + if (hoveredGuild) this.hoveredGuild = hoveredGuild; + else delete this.hoveredGuild; + if (update) BDFDB.ReactUtils.forceUpdate(this); + }; + let releasing = event3 => { + BDFDB.ListenerUtils.stopEvent(event3); + BDFDB.DOMUtils.remove(dragPreview); + if (this.hoveredGuild) { + let guildIds = [].concat(folder.guildIds); + BDFDB.ArrayUtils.remove(guildIds, this.draggedGuild, true); + guildIds.splice(guildIds.indexOf(this.hoveredGuild) + 1, 0, this.draggedGuild); + _this.updateFolder(Object.assign({}, folder, {guildIds})); + } + delete this.draggedGuild; + delete this.hoveredGuild; + BDFDB.ReactUtils.forceUpdate(this); + document.removeEventListener("mousemove", dragging); + document.removeEventListener("mouseup", releasing); + }; + document.addEventListener("mousemove", dragging); + document.addEventListener("mouseup", releasing); + } + }; + let mouseUp = _ => { + document.removeEventListener("mousemove", mouseMove); + document.removeEventListener("mouseup", mouseUp); + }; + document.addEventListener("mousemove", mouseMove); + document.addEventListener("mouseup", mouseUp); + } + }), + this.hoveredGuild != guildId ? null : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS.guildouter + BDFDB.disCN._serverfoldersguildplaceholder, + children: BDFDB.ReactUtils.createElement("div", { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.GuildComponents.DragPlaceholder, {}) + }) + }) + ] + }); + }).filter(n => n).reduce((r, a) => r.concat(a, _this.settings.general.addSeparators ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.GuildComponents.Separator, {}) : null), [0]).slice(1, -1).flat(10).filter(n => n) + }) + }) + }); + } + }; + + const FolderIconPickerComponent = class FolderIconPicker extends BdApi.React.Component { + render() { + let folderIcons = _this.loadAllIcons(); + for (let id in folderIcons) if (!folderIcons[id].customID) { + folderIcons[id].openicon = _this.createBase64SVG(folderIcons[id].openicon); + folderIcons[id].closedicon = _this.createBase64SVG(folderIcons[id].closedicon); + } + folderIcons["-1"] = {}; + return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + wrap: BDFDB.LibraryComponents.Flex.Wrap.WRAP, + children: Object.keys(folderIcons).sort().map(id => { + return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Card, { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN._serverfoldersiconswatch, this.props.selectedIcon == id && BDFDB.disCN._serverfoldersiconswatchselected), + backdrop: false, + iconID: id, + grow: 0, + shrink: 0, + noRemove: !folderIcons[id].customID || this.props.selectedIcon == id, + onMouseEnter: _ => { + this.props.hoveredIcon = id; + BDFDB.ReactUtils.forceUpdate(this); + }, + onMouseLeave: _ => { + delete this.props.hoveredIcon; + BDFDB.ReactUtils.forceUpdate(this); + }, + onClick: _ => { + this.props.selectedIcon = id; + this.props.onSelect(this.props.selectedIcon); + BDFDB.ReactUtils.forceUpdate(this); + }, + onRemove: _ => { + delete customIcons[id]; + BDFDB.DataUtils.save(customIcons, _this, "customicons"); + BDFDB.ReactUtils.forceUpdate(this); + }, + children: folderIcons[id].closedicon ? BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._serverfoldersiconswatchinner, + style: {background: `url(${this.props.hoveredIcon == id ? folderIcons[id].openicon : folderIcons[id].closedicon}) center/cover no-repeat`} + }) : BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN._serverfoldersiconswatchinner, + name: BDFDB.LibraryComponents.SvgIcon.Names.FOLDER, + style: {color: "rbg(0, 0, 0)"} + }) + }); + }) + }) + } + }; + + const FolderIconCustomPreviewComponent = class FolderIconCustomPreview extends BdApi.React.Component { + componentDidMount() { + this._previewInterval = BDFDB.TimeUtils.interval(_ => { + this.props.tick = !this.props.tick; + if (this.props.open || this.props.closed) BDFDB.ReactUtils.forceUpdate(this); + }, 2000); + } + componentWillUnmount () { + BDFDB.TimeUtils.clear(this._previewInterval); + } + checkImage(base64OrUrl, callback) { + if (base64OrUrl.indexOf("https://") == 0 || base64OrUrl.indexOf("http://") == 0) BDFDB.LibraryRequires.request(base64OrUrl.trim(), {encoding: null}, (error, response, body) => { + if (response && response.headers["content-type"] && response.headers["content-type"].indexOf("image") != -1 && response.headers["content-type"] != "image/gif") { + this.resizeImage("data:" + response.headers["content-type"] + ";base64," + (new Buffer(body).toString("base64")), callback); + } + else callback(base64OrUrl); + }); + else this.resizeImage(base64OrUrl, callback); + } + resizeImage(base64, callback) { + let type = base64.split("data:").slice(1).join(" ").split(";")[0]; + if (type == "image/gif") callback(base64); + else { + let img = new Image(); + img.onload = function() { + let width = 0, height = 0; + if (this.width >= this.height) { + width = (128 / this.height) * this.width; + height = 128; + } + else { + width = 128; + height = (128 / this.width) * this.height; + } + let canvas = document.createElement("canvas"); + let ctx = canvas.getContext("2d"); + ctx.canvas.width = width; + ctx.canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); + callback(canvas.toDataURL(type)); + }; + img.onerror = function() { + callback(base64); + }; + img.src = base64; + } + } + render() { + let openInput, closeInput; + return [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: _this.labels.modal_customopen, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + type: "file", + filter: "image", + value: this.props.open, + ref: instance => {if (instance) openInput = instance;}, + onChange: value => { + this.props.open = value; + BDFDB.ReactUtils.forceUpdate(this); + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: _this.labels.modal_customclosed, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + type: "file", + filter: "image", + value: this.props.closed, + ref: instance => {if (instance) closeInput = instance;}, + onChange: value => { + this.props.closed = value; + BDFDB.ReactUtils.forceUpdate(this); + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: _this.labels.modal_custompreview, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + justify: BDFDB.LibraryComponents.Flex.Justify.BETWEEN, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN._serverfoldersiconswatch, BDFDB.disCN._serverfoldersiconswatchpreview, !this.props.open && BDFDB.disCN._serverfoldersiconswatchnopreview), + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._serverfoldersiconswatchinner, + style: this.props.open && {background: `url(${this.props.open}) center/cover no-repeat`} || {} + }) + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN._serverfoldersiconswatch, BDFDB.disCN._serverfoldersiconswatchpreview, !this.props.closed && BDFDB.disCN._serverfoldersiconswatchnopreview), + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._serverfoldersiconswatchinner, + style: this.props.closed && {background: `url(${this.props.closed}) center/cover no-repeat`} || {} + }) + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN._serverfoldersiconswatch, BDFDB.disCN._serverfoldersiconswatchpreview, !(this.props.tick ? this.props.open : this.props.closed) && BDFDB.disCN._serverfoldersiconswatchnopreview), + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._serverfoldersiconswatchinner, + style: (this.props.tick ? this.props.open : this.props.closed) && {background: `url(${(this.props.tick ? this.props.open : this.props.closed)}) center/cover no-repeat`} || {} + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { + children: BDFDB.LanguageUtils.LanguageStrings.ADD, + onClick: _ => { + if (openInput.props.value && closeInput.props.value) { + this.checkImage(openInput.props.value, openIcon => { + this.checkImage(closeInput.props.value, closedIcon => { + customIcons[_this.generateId("customicon")] = {openicon: openIcon, closedicon: closedIcon}; + BDFDB.DataUtils.save(customIcons, _this, "customicons"); + this.props.open = null; + this.props.closed = null; + BDFDB.PatchUtils.forceAllUpdates(_this, "GuildFolderSettingsModal"); + BDFDB.NotificationUtils.toast("Custom Icon was added to Selection", {type: "success"}); + }); + }) + } + else BDFDB.NotificationUtils.toast("Add an Image for the open and closed Icon", {type: "danger"}); + } + }) + ] + }) + }) + ] + } + }; + + return class ServerFolders extends Plugin { + onLoad () { + _this = this; + + folderStates = {}; + folderReads = {}; + guildStates = {}; + + this.defaults = { + general: { + closeOtherFolders: {value: false, description: "Closes other Folders when opening a Folder"}, + closeTheFolder: {value: false, description: "Closes the Folder when selecting a Server"}, + closeAllFolders: {value: false, description: "Closes all Folders when selecting a Server"}, + forceOpenFolder: {value: false, description: "Forces a Folder to open when switching to a Server of that Folder"}, + showCountBadge: {value: true, description: "Displays Badge for Amount of Servers in a Folder"}, + extraColumn: {value: true, description: "Moves the Servers from opened Folders in an extra Column"}, + addSeparators: {value: true, description: "Adds Separators between Servers of different Folders in extra Column"} + } + }; + + this.patchedModules = { + after: { + AppView: "default", + Guilds: "type", + FolderItem: "default", + FolderHeader: "default", + GuildItem: "default", + GuildFolderSettingsModal: ["componentDidMount", "render"] + } + }; + + this.css = ` + ${BDFDB.dotCN._serverfoldersiconswatch} { + position: relative; + margin: 3px 3px; + padding: 3px 3px; + width: 55px; + height: 55px; + border-radius: 12px; + cursor: pointer; + } + ${BDFDB.dotCN._serverfoldersiconswatch + BDFDB.dotCN._serverfoldersiconswatchpreview} { + width: 95px; + height: 95px; + cursor: default; + } + ${BDFDB.dotCN._serverfoldersiconswatch}:hover { + background-color: var(--background-modifier-hover); + } + ${BDFDB.dotCN._serverfoldersiconswatch + BDFDB.dotCN._serverfoldersiconswatchselected} { + background-color: var(--background-modifier-selected); + } + ${BDFDB.dotCNS._serverfoldersiconswatch + BDFDB.dotCN._serverfoldersiconswatchinner} { + width: 100%; + height: 100%; + border-radius: 12px; + background-position: center; + background-size: cover; + background-repeat: no-repeat; + } + ${BDFDB.dotCN._serverfoldersiconswatchnopreview}, + ${BDFDB.dotCN._serverfoldersiconswatchnopreview}:hover { + background-color: transparent; + } + ${BDFDB.dotCNS._serverfoldersiconswatchnopreview + BDFDB.dotCN._serverfoldersiconswatchinner} { + background-image: url('data:image/svg+xml; utf8, '); + } + ${BDFDB.dotCN._serverfoldersiconswatch} svg${BDFDB.dotCN._serverfoldersiconswatchinner} { + transform: translateY(-2px) scale(0.8); + } + ${BDFDB.dotCNS._serverfoldersiconswatch + BDFDB.dotCN.hovercardbutton} { + position: absolute; + top: -10px; + right: -10px; + } + ${BDFDB.dotCN._serverfoldersdragpreview} { + pointer-events: none !important; + position: absolute !important; + opacity: 0.5 !important; + z-index: 10000 !important; + } + ${BDFDB.dotCN._serverfoldersfoldercontent + BDFDB.notCN.guildswrapperhidden} { + transition: width 0.2s cubic-bezier(.44,1.04,1,1.01) !important; + } + ${BDFDB.dotCN._serverfoldersfoldercontent + BDFDB.dotCN._serverfoldersfoldercontentclosed} { + width: 0 !important; + } + `; + } + + onStart () { + currentGuild = BDFDB.LibraryModules.LastGuildStore.getGuildId(); + + let forceClosing = false; + BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.GuildUtils, "toggleGuildFolderExpand", {after: e => { + if (this.settings.general.closeOtherFolders && !forceClosing) { + forceClosing = true; + for (let openFolderId of BDFDB.LibraryModules.FolderUtils.getExpandedFolders()) if (openFolderId != e.methodArguments[0]) BDFDB.LibraryModules.GuildUtils.toggleGuildFolderExpand(openFolderId); + forceClosing = false; + } + }}); + + this.forceUpdateAll(); + } + + onStop () { + this.forceUpdateAll(); + + BDFDB.DOMUtils.removeClassFromDOM(BDFDB.disCN._serverfoldersfoldercontentisopen); + } + + onSwitch () { + if (typeof BDFDB === "object" && BDFDB.loaded && this.settings.general.forceOpenFolder) { + let folder = BDFDB.GuildUtils.getFolder(BDFDB.LibraryModules.LastGuildStore.getGuildId()); + if (folder && !BDFDB.LibraryModules.FolderUtils.isFolderExpanded(folder.folderId)) BDFDB.LibraryModules.GuildUtils.toggleGuildFolderExpand(folder.folderId); + } + } + + getSettingsPanel (collapseStates = {}) { + let settingsPanel; + return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, { + collapseStates: collapseStates, + children: _ => { + let settingsItems = []; + + for (let key in this.defaults.general) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + type: "Switch", + plugin: this, + keys: ["general", key], + label: this.defaults.general[key].description, + value: this.settings.general[key] + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + color: BDFDB.LibraryComponents.Button.Colors.RED, + label: "Reset all Folders", + onClick: _ => BDFDB.ModalUtils.confirm(this, "Are you sure you want to reset all Folders?", _ => BDFDB.DataUtils.remove(this, "folders")), + children: BDFDB.LanguageUtils.LanguageStrings.RESET + })); + settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + color: BDFDB.LibraryComponents.Button.Colors.RED, + label: "Remove all custom Icons", + onClick: _ => BDFDB.ModalUtils.confirm(this, "Are you sure you want to remove all custom Icons?", _ => BDFDB.DataUtils.remove(this, "customicons")), + children: BDFDB.LanguageUtils.LanguageStrings.REMOVE + })); + + return settingsItems; + } + }); + } + + onSettingsClosed () { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + folderStates = {}; + this.forceUpdateAll(); + } + } + + forceUpdateAll () { + folderConfigs = BDFDB.DataUtils.load(this, "folders"); + customIcons = BDFDB.DataUtils.load(this, "customicons"); + + BDFDB.ReactUtils.forceUpdate(folderGuildContent); + BDFDB.PatchUtils.forceAllUpdates(this); + BDFDB.DiscordUtils.rerenderAll(); + } + + onGuildContextMenu (e) { + if (document.querySelector(BDFDB.dotCN.modalwrapper)) return; + if (e.instance.props.guild) { + let folders = BDFDB.LibraryModules.FolderStore.guildFolders.filter(n => n.folderId); + let folder = BDFDB.GuildUtils.getFolder(e.instance.props.guild.id); + let unfolderedGuilds = BDFDB.LibraryModules.FolderStore.getSortedGuilds().filter(n => !n.folderId).map(n => n.guilds[0]).filter(n => n); + let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "devmode-copy-id", group: true}); + children.splice(index > -1 ? index : children.length, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.servercontext_serverfolders, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "submenu-add"), + children: folder ? [ + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.serversubmenu_removefromfolder, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "remove-from-folder"), + color: BDFDB.LibraryComponents.MenuItems.Colors.DANGER, + action: _ => this.removeGuildFromFolder(folder.folderId, e.instance.props.guild.id) + }) + ] : [ + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.serversubmenu_createfolder, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "create-folder"), + disabled: !unfolderedGuilds.length, + action: _ => this.openFolderCreationMenu(unfolderedGuilds, e.instance.props.guild.id) + }), + BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.serversubmenu_addtofolder, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "submenu-add-to-folder"), + disabled: !folders.length, + children: folders.map((folder, i) => BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: folder.folderName || `${BDFDB.LanguageUtils.LanguageStrings.SERVER_FOLDER_PLACEHOLDER} #${i + 1}`, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "add-to-folder", i + 1), + action: _ => this.addGuildToFolder(folder.folderId, e.instance.props.guild.id) + })) + }) + ] + }) + })); + } + } + + onGuildFolderContextMenu (e) { + if (document.querySelector(BDFDB.dotCN.modalwrapper)) return; + if (e.instance.props.target && e.instance.props.folderId) { + let folder = BDFDB.LibraryModules.FolderStore.getGuildFolderById(e.instance.props.folderId); + let data = this.getFolderConfig(e.instance.props.folderId); + let muted = data.muteFolder && folder.guildIds.every(guildid => BDFDB.LibraryModules.MutedUtils.isGuildOrCategoryOrChannelMuted(guildid)); + if (data.muteFolder != muted) { + data.muteFolder = muted; + BDFDB.DataUtils.save(data, this, "folders", e.instance.props.folderId); + } + let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "mark-folder-read"}); + children.splice(index > -1 ? index + 1 : children.length, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuCheckboxItem, { + label: this.labels.foldercontext_autoreadfolder, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "auto-read-folder"), + checked: data.autoRead, + action: state => { + data.autoRead = state; + BDFDB.DataUtils.save(data, this, "folders", e.instance.props.folderId); + } + })); + e.returnvalue.props.children.splice(e.returnvalue.props.children.length - 1, 0, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuCheckboxItem, { + label: this.labels.foldercontext_mutefolder, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "mute-folder"), + checked: muted, + action: state => { + data.muteFolder = state; + BDFDB.DataUtils.save(data, this, "folders", e.instance.props.folderId); + for (let guildId of folder.guildIds) if (BDFDB.LibraryModules.MutedUtils.isGuildOrCategoryOrChannelMuted(guildId) != state) BDFDB.LibraryModules.GuildNotificationsUtils.updateGuildNotificationSettings(guildId, {muted: state, suppress_everyone: state, suppress_roles: state}); + } + }) + })); + e.returnvalue.props.children.push(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { + children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: this.labels.foldercontext_removefolder, + id: BDFDB.ContextMenuUtils.createItemId(this.name, "remove-folder"), + color: BDFDB.LibraryComponents.MenuItems.Colors.DANGER, + action: event => { + BDFDB.ModalUtils.confirm(this, `Are you sure you want to remove the folder${folder.folderName ? ` '${folder.folderName}'` : ""}?`, _ => { + this.removeFolder(e.instance.props.folderId); + }); + } + }) + })); + } + } + + processAppView (e) { + if (this.settings.general.extraColumn) { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["className", BDFDB.disCN.guilds]]}); + if (index > -1) children.splice(index + 1, 0, BDFDB.ReactUtils.createElement(FolderGuildContentComponent, { + isAppFullscreen: BDFDB.LibraryModules.VoiceChannelUtils.isFullscreenInContext(), + themeOverride: BDFDB.LibraryModules.LocalSettingsStore.darkSidebar + }, true)); + } + } + + processGuilds (e) { + if (this.settings.general.extraColumn) { + let fullscreen = BDFDB.LibraryModules.VoiceChannelUtils.isFullscreenInContext(); + if (folderGuildContent && (fullscreen != folderGuildContent.props.isAppFullscreen || e.instance.props.themeOverride != folderGuildContent.props.themeOverride)) { + folderGuildContent.props.isAppFullscreen = fullscreen; + folderGuildContent.props.themeOverride = e.instance.props.themeOverride; + BDFDB.ReactUtils.forceUpdate(folderGuildContent); + } + let topBar = BDFDB.ReactUtils.findChild(e.returnvalue, {props: [["className", BDFDB.disCN.guildswrapperunreadmentionsbartop]]}); + if (topBar) { + let topIsVisible = topBar.props.isVisible; + topBar.props.isVisible = BDFDB.TimeUtils.suppress((...args) => { + let ids = BDFDB.LibraryModules.FolderStore.guildFolders.filter(n => n.folderId).map(n => n.guildIds).flat(10); + args[2] = args[2].filter(id => !ids.includes(id)); + return topIsVisible(...args) || BDFDB.LibraryModules.UnreadGuildUtils.getMentionCount(args[0]) == 0; + }, "Error in isVisible of Top Bar in Guild List!"); + } + let bottomBar = BDFDB.ReactUtils.findChild(e.returnvalue, {props: [["className", BDFDB.disCN.guildswrapperunreadmentionsbarbottom]]}); + if (bottomBar) { + let bottomIsVisible = bottomBar.props.isVisible; + bottomBar.props.isVisible = BDFDB.TimeUtils.suppress((...args) => { + let ids = BDFDB.LibraryModules.FolderStore.guildFolders.filter(n => n.folderId).map(n => n.guildIds).flat(10); + args[2] = args[2].filter(id => !ids.includes(id)); + return bottomIsVisible(...args) || BDFDB.LibraryModules.UnreadGuildUtils.getMentionCount(args[0]) == 0; + }, "Error in isVisible of Bottom Bar in Guild List!"); + } + } + } + + processFolderItem (e) { + if (!e.instance.props.folderNode) return; + let expandedFolders = BDFDB.LibraryModules.FolderUtils.getExpandedFolders(); + if (expandedFolders.size) BDFDB.DOMUtils.addClass(document.body, BDFDB.disCN._serverfoldersfoldercontentisopen); + else BDFDB.DOMUtils.removeClassFromDOM(BDFDB.disCN._serverfoldersfoldercontentisopen); + + let data = this.getFolderConfig(e.instance.props.folderNode.id); + if (data.muteFolder) for (let guildId of e.instance.props.folderNode.children.map(n => n.id)) if (!BDFDB.LibraryModules.MutedUtils.isGuildOrCategoryOrChannelMuted(guildId)) BDFDB.LibraryModules.GuildNotificationsUtils.updateGuildNotificationSettings(guildId, {muted: true, suppress_everyone: true}); + + let state = this.getState(e.instance); + if (folderStates[e.instance.props.folderNode.id] && !BDFDB.equals(state, folderStates[e.instance.props.folderNode.id])) { + if (data.autoRead && (state.unread || state.badge > 0)) { + BDFDB.TimeUtils.clear(folderReads[e.instance.props.folderNode.id]); + folderReads[e.instance.props.folderNode.id] = BDFDB.TimeUtils.timeout(_ => { + BDFDB.GuildUtils.markAsRead(e.instance.props.folderNode.children.map(n => n.id)); + }, 10000); + } + BDFDB.ReactUtils.forceUpdate(folderGuildContent); + } + folderStates[e.instance.props.folderNode.id] = state; + + let [tooltipParent, tooltipIndex] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: ["ListItemTooltip", "BDFDB_TooltipContainer"]}); + if (tooltipIndex > -1) tooltipParent[tooltipIndex] = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: e.instance.props.folderNode.name || e.instance.props.defaultFolderName, + tooltipConfig: { + type: "right", + list: true, + offset: 12, + backgroundColor: data.color3, + fontColor: data.color4 + }, + children: tooltipParent[tooltipIndex].props.children + }); + if (this.settings.general.extraColumn) { + e.returnvalue.props.children[0] = null; + e.returnvalue.props.children[2] = BDFDB.ReactUtils.createElement("div", { + children: e.returnvalue.props.children[2], + style: {display: "none"} + }); + } + } + + processFolderHeader (e) { + if (!e.instance.props.folderNode) return; + let data = this.getFolderConfig(e.instance.props.folderNode.id); + if (e.instance.props.expanded || data.useCloseIcon) { + let folderIcons = this.loadAllIcons(), icontype = e.instance.props.expanded ? "openicon" : "closedicon"; + let icon = folderIcons[data.iconID] ? (!folderIcons[data.iconID].customID ? this.createBase64SVG(folderIcons[data.iconID][icontype], data.color1, data.color2) : folderIcons[data.iconID][icontype]) : null; + if (icon) { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: "FolderIconContent"}); + if (index > -1) children[index] = BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.guildfoldericonwrapper, + style: {background: `url(${icon}) center/cover no-repeat`} + }); + } + } + if (this.settings.general.showCountBadge) { + let mask = BDFDB.ReactUtils.findChild(e.returnvalue, {name: "BlobMask"}); + if (mask) { + mask.props.upperLeftBadgeWidth = BDFDB.LibraryComponents.Badges.getBadgeWidthForValue(e.instance.props.folderNode.children.length); + mask.props.upperLeftBadge = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.NumberBadge, { + count: e.instance.props.folderNode.children.length, + style: {backgroundColor: "var(--bdfdb-blurple)"} + }); + } + } + } + + processGuildItem (e) { + BDFDB.TimeUtils.clear(forceCloseTimeout); + forceCloseTimeout = BDFDB.TimeUtils.timeout(_ => { + let newCurrentGuild = BDFDB.LibraryModules.LastGuildStore.getGuildId(); + if (newCurrentGuild != currentGuild && newCurrentGuild) { + let folder = BDFDB.GuildUtils.getFolder(newCurrentGuild); + if (this.settings.general.closeAllFolders) for (let openFolderId of BDFDB.LibraryModules.FolderUtils.getExpandedFolders()) if (!folder || openFolderId != folder.folderId || !this.settings.general.forceOpenFolder) BDFDB.LibraryModules.GuildUtils.toggleGuildFolderExpand(openFolderId); + else if (folder && this.settings.general.closeTheFolder && !this.settings.general.forceOpenFolder && BDFDB.LibraryModules.FolderUtils.isFolderExpanded(folder.folderId)) BDFDB.LibraryModules.GuildUtils.toggleGuildFolderExpand(folder.folderId); + } + currentGuild = newCurrentGuild; + }, 1000); + + let folder = BDFDB.GuildUtils.getFolder(e.instance.props.guild.id); + if (folder) { + let state = this.getState(e.instance); + if (guildStates[e.instance.props.guild.id] && !BDFDB.equals(state, guildStates[e.instance.props.guild.id])) { + BDFDB.ReactUtils.forceUpdate(folderGuildContent); + } + guildStates[e.instance.props.guild.id] = state; + if (e.returnvalue) { + let data = this.getFolderConfig(folder.folderId); + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: ["GuildTooltip", "BDFDB_TooltipContainer"]}); + if (index > -1) children[index] = BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + tooltipConfig: Object.assign({ + type: "right", + list: true, + guild: e.instance.props.guild, + offset: 12 + }, data.copyTooltipColor && { + backgroundColor: data.color3, + fontColor: data.color4, + }), + children: children[index].props.children + }); + } + } + } + + processGuildFolderSettingsModal (e) { + if (e.node) { + let root = e.node.parentElement.querySelector(BDFDB.dotCN.layermodal); + BDFDB.DOMUtils.addClass(root, BDFDB.disCN.layermodalmedium, BDFDB.disCN.modalwrapper, `${this.name}-modal`); + BDFDB.DOMUtils.removeClass(root, BDFDB.disCN.layermodalsmall); + } + if (e.returnvalue) { + let folder = BDFDB.LibraryModules.FolderStore.getGuildFolderById(e.instance.props.folderId); + let data = this.getFolderConfig(e.instance.props.folderId); + let newData = Object.assign({}, data, {folderName: folder.folderName}); + + let tabs = {}; + + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: ["ModalHeader", "Header"]}); + if (index > -1) { + children[index].props.className = BDFDB.DOMUtils.formatClassName(children[index].props.className, BDFDB.disCN.modalheaderhassibling), + children.splice(index + 1, 0, BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + grow: 0, + shrink: 0, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.tabbarcontainer, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TabBar, { + className: BDFDB.disCN.tabbar, + itemClassName: BDFDB.disCN.tabbaritem, + type: BDFDB.LibraryComponents.TabBar.Types.TOP, + items: [ + {value: this.labels.modal_tabheader1}, + {value: this.labels.modal_tabheader2}, + {value: this.labels.modal_tabheader3}, + {value: this.labels.modal_tabheader4} + ], + onItemSelect: (value, instance) => { + let tabsArray = BDFDB.ObjectUtils.toArray(tabs); + for (let ins of tabsArray) { + if (ins.props.tab == value) ins.props.open = true; + else delete ins.props.open; + } + BDFDB.ReactUtils.forceUpdate(tabsArray); + } + }) + }) + })); + } + [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: ["ModalContent", "Content"]}); + if (index > -1) children[index].props.children = [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: this.labels.modal_tabheader1, + open: true, + ref: instance => {if (instance) tabs[this.labels.modal_tabheader1] = instance;}, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: BDFDB.LanguageUtils.LanguageStrings.GUILD_FOLDER_NAME, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, { + value: folder.folderName, + placeholder: folder.folderName || BDFDB.LanguageUtils.LanguageStrings.SERVER_FOLDER_PLACEHOLDER, + autoFocus: true, + onChange: value => {newData.folderName = value;} + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_iconpicker, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(FolderIconPickerComponent, { + selectedIcon: data.iconID, + onSelect: value => {newData.iconID = value;} + }, true) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + margin: 20, + label: this.labels.modal_usecloseicon, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + value: data.useCloseIcon, + onChange: value => {newData.useCloseIcon = value;} + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: this.labels.modal_tabheader2, + ref: instance => {if (instance) tabs[this.labels.modal_tabheader2] = instance;}, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker1, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color1, + defaultFallback: !data.color1 && !data.swapColors, + onColorChange: value => {newData.color1 = value;} + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker2, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color2, + defaultFallback: !data.color2 && data.swapColors, + onColorChange: value => {newData.color2 = value;} + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + margin: 20, + label: this.labels.modal_swapcolor, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + value: data.swapColors, + onChange: value => {newData.swapColors = value;} + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: this.labels.modal_tabheader3, + ref: instance => {if (instance) tabs[this.labels.modal_tabheader3] = instance;}, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker3, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color3, + onColorChange: value => {newData.color3 = value;} + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, { + title: this.labels.modal_colorpicker4, + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, { + color: data.color4, + onColorChange: value => {newData.color4 = value;} + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + margin: 20, + label: this.labels.modal_copytooltipcolor, + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5, + value: data.copyTooltipColor, + onChange: value => {newData.copyTooltipColor = value;} + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: this.labels.modal_tabheader4, + ref: instance => {if (instance) tabs[this.labels.modal_tabheader4] = instance;}, + children: BDFDB.ReactUtils.createElement(FolderIconCustomPreviewComponent, {}, true) + }) + ]; + [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: ["ModalFooter", "Footer"]}); + if (index > -1) children[index].props.children = [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { + children: BDFDB.LanguageUtils.LanguageStrings.SAVE, + onClick: _ => { + let folderColor = newData[newData.swapColors ? "color2" : "color1"]; + this.updateFolder({ + folderId: e.instance.props.folderId, + folderName: newData.folderName, + folderColor: folderColor ? BDFDB.ColorUtils.convert(folderColor && BDFDB.ObjectUtils.is(folderColor) ? folderColor[Object.keys(folderColor)[0]] : folderColor, "INT") : null + }); + if (!BDFDB.equals(newData, data)) { + BDFDB.DataUtils.save(newData, this, "folders", e.instance.props.folderId); + this.forceUpdateAll(); + } + e.instance.close(); + } + }) + ] + } + } + + loadAllIcons () { + let icons = {}; + folderIcons.forEach((array, i) => { + icons[i] = { + openicon: array.openicon, + closedicon: array.closedicon, + customID: null + }; + }); + for (let id in customIcons) icons[id] = Object.assign({customID: id}, customIcons[id]); + return icons; + } + + generateId (prefix) { + if (prefix == "folder") { + let id = Math.floor(Math.random() * 4294967296); + return BDFDB.LibraryModules.FolderStore.guildFolders.every(n => !n.folderId || n.folderId != id) ? id : this.generateId(prefix); + } + else { + let data = BDFDB.DataUtils.load(this, prefix + "s"); + let id = prefix + "_" + Math.round(Math.random()*10000000000000000); + return data[id] ? this.generateId(prefix) : id; + } + } + + getState (instance) { + let state = {}; + for (let key in instance.props) { + if (typeof instance.props[key] != "object" && typeof instance.props[key] != "function") state[key] = instance.props[key]; + else if (Array.isArray(instance.props[key])) state[key] = instance.props[key].length; + else if (key == "mediaState") Object.assign(state, instance.props[key]); + } + return state; + } + + getFolderConfig (folderId) { + let folder = BDFDB.LibraryModules.FolderStore.getGuildFolderById(folderId) || {}; + let data = folderConfigs[folderId] || { + iconID: "-1", + muteFolder: false, + autoRead: false, + useCloseIcon: true, + swapColors: false, + copyTooltipColor: false, + color1: null, + color2: ["255","255","255"], + color3: null, + color4: null + }; + let nativeColor = data.swapColors ? "color2" : "color1"; + if (!data[nativeColor]) data[nativeColor] = BDFDB.ColorUtils.convert(folder.folderColor, "RGBCOMP"); + else if (folder.folderColor && !BDFDB.ColorUtils.compare(folder.folderColor, BDFDB.ColorUtils.convert(BDFDB.ObjectUtils.is(data[nativeColor]) ? data[nativeColor][Object.keys(data[nativeColor])[0]] : data[nativeColor], "INT"))) { + data[nativeColor] = BDFDB.ColorUtils.convert(folder.folderColor, "RGBCOMP"); + BDFDB.DataUtils.save(data, this, "folders", folderId); + } + folderConfigs[folderId] = data; + return data; + } + + createBase64SVG (paths, color1 = "#000000", color2 = "#FFFFFF") { + if (paths.indexOf("`; + if (isGradient1) { + color1 = BDFDB.ColorUtils.convert(color1, "RGBA"); + svg += ``; + for (let pos of Object.keys(color1).sort()) svg += ``; + svg += ``; + } + if (isGradient2) { + color2 = BDFDB.ColorUtils.convert(color2, "RGBA"); + svg += ``; + for (let pos of Object.keys(color2).sort()) svg += ``; + svg += ``; + } + svg += `${paths.replace("REPLACE_FILL1", isGradient1 ? "url(#grad1)" : BDFDB.ColorUtils.convert(color1, "RGBA")).replace("REPLACE_FILL2", isGradient2 ? "url(#grad2)" : BDFDB.ColorUtils.convert(color2, "RGBA"))}`; + return `data:image/svg+xml;base64,${btoa(svg)}`; + } + + openFolderCreationMenu (guilds, initGuildId) { + let targetedGuildIds = [].concat(initGuildId || []); + + BDFDB.ModalUtils.open(this, { + size: "MEDIUM", + header: this.labels.serversubmenu_createfolder, + subHeader: "", + contentClassName: BDFDB.disCN.listscroller, + children: guilds.map((guild, i) => { + return [ + i == 0 ? null : BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, { + className: BDFDB.disCNS.margintop4 + BDFDB.disCN.marginbottom4 + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ListRow, { + prefix: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.GuildComponents.Guild, { + className: BDFDB.disCN.listavatar, + guild: guild, + menu: false, + tooltip: false + }), + label: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextScroller, { + children: guild.name + }), + suffix: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Switch, { + value: targetedGuildIds.includes(guild.id), + onChange: value => { + if (value) targetedGuildIds.push(guild.id); + else BDFDB.ArrayUtils.remove(targetedGuildIds, guild.id, true); + } + }) + }) + ]; + }).flat(10).filter(n => n), + buttons: [{ + contents: BDFDB.LanguageUtils.LanguageStrings.DONE, + color: "BRAND", + close: true, + onClick: (modal, instance) => { + this.createFolder(BDFDB.ArrayUtils.removeCopies(targetedGuildIds)); + } + }] + }); + } + + updateFolder (folder) { + let oldGuildFolders = [].concat(BDFDB.LibraryModules.FolderStore.guildFolders), guildFolders = [], guildPositions = []; + for (let oldFolder of oldGuildFolders) { + if (oldFolder.folderId == folder.folderId) guildFolders.push(Object.assign({}, oldFolder, folder)); + else guildFolders.push(oldFolder); + } + for (let folder of guildFolders) for (let fGuildId of folder.guildIds) guildPositions.push(fGuildId); + BDFDB.LibraryModules.SettingsUtilsOld.updateRemoteSettings({guildPositions, guildFolders}); + } + + createFolder (guildIds) { + if (!guildIds) return; + guildIds = [guildIds].flat(10); + if (!guildIds.length) return; + let oldGuildFolders = [].concat(BDFDB.LibraryModules.FolderStore.guildFolders), guildFolders = [], guildPositions = [], added = false; + for (let oldFolder of oldGuildFolders) { + if (!oldFolder.folderId && guildIds.includes(oldFolder.guildIds[0])) { + if (!added) { + added = true; + guildFolders.push({ + guildIds: guildIds, + folderId: this.generateId("folder") + }); + } + } + else guildFolders.push(oldFolder); + } + for (let folder of guildFolders) for (let fGuildId of folder.guildIds) guildPositions.push(fGuildId); + BDFDB.LibraryModules.SettingsUtilsOld.updateRemoteSettings({guildPositions, guildFolders}); + } + + removeFolder (folderId) { + let oldGuildFolders = [].concat(BDFDB.LibraryModules.FolderStore.guildFolders), guildFolders = [], guildPositions = []; + for (let oldFolder of oldGuildFolders) { + if (oldFolder.folderId == folderId) { + for (let guildId of oldFolder.guildIds) guildFolders.push({guildIds: [guildId]}); + } + else guildFolders.push(oldFolder); + } + for (let folder of guildFolders) for (let fGuildId of folder.guildIds) guildPositions.push(fGuildId); + BDFDB.LibraryModules.SettingsUtilsOld.updateRemoteSettings({guildPositions, guildFolders}); + } + + addGuildToFolder (folderId, guildId) { + let oldGuildFolders = [].concat(BDFDB.LibraryModules.FolderStore.guildFolders), guildFolders = [], guildPositions = []; + for (let oldFolder of oldGuildFolders) { + if (oldFolder.folderId) { + let newFolder = Object.assign({}, oldFolder); + if (oldFolder.folderId == folderId) newFolder.guildIds.push(guildId); + else BDFDB.ArrayUtils.remove(newFolder.guildIds, guildId); + guildFolders.push(newFolder); + } + else if (oldFolder.guildIds[0] != guildId) guildFolders.push(oldFolder); + } + for (let folder of guildFolders) for (let fGuildId of folder.guildIds) guildPositions.push(fGuildId); + BDFDB.LibraryModules.SettingsUtilsOld.updateRemoteSettings({guildPositions, guildFolders}); + } + + removeGuildFromFolder (folderId, guildId) { + let oldGuildFolders = [].concat(BDFDB.LibraryModules.FolderStore.guildFolders), guildFolders = [], guildPositions = []; + for (let oldFolder of oldGuildFolders) { + if (oldFolder.folderId == folderId) { + let newFolder = Object.assign({}, oldFolder); + BDFDB.ArrayUtils.remove(newFolder.guildIds, guildId); + guildFolders.push(newFolder); + guildFolders.push({guildIds: [guildId]}); + } + else guildFolders.push(oldFolder); + } + for (let folder of guildFolders) for (let fGuildId of folder.guildIds) guildPositions.push(fGuildId); + BDFDB.LibraryModules.SettingsUtilsOld.updateRemoteSettings({guildPositions, guildFolders}); + } + + createDragPreview (div, event) { + if (!Node.prototype.isPrototypeOf(div)) return; + let dragPreview = div.cloneNode(true); + BDFDB.DOMUtils.addClass(dragPreview, BDFDB.disCN._serverfoldersdragpreview); + BDFDB.DOMUtils.remove(dragPreview.querySelector(BDFDB.dotCNC.guildlowerbadge + BDFDB.dotCNC.guildupperbadge + BDFDB.dotCN.guildpillwrapper)); + BDFDB.DOMUtils.hide(dragPreview); + dragPreview.style.setProperty("pointer-events", "none", "important"); + dragPreview.style.setProperty("left", event.clientX - 25 + "px", "important"); + dragPreview.style.setProperty("top", event.clientY - 25 + "px", "important"); + document.querySelector(BDFDB.dotCN.appmount).appendChild(dragPreview); + return dragPreview; + } + + updateDragPreview (dragPreview, event) { + if (!Node.prototype.isPrototypeOf(dragPreview)) return; + BDFDB.DOMUtils.show(dragPreview); + dragPreview.style.setProperty("left", event.clientX - 25 + "px", "important"); + dragPreview.style.setProperty("top", event.clientY - 25 + "px", "important"); + } + + setLabelsByLanguage () { + switch (BDFDB.LanguageUtils.getLanguage().id) { + case "bg": // Bulgarian + return { + foldercontext_autoreadfolder: "Авто: Маркиране като прочетено", + foldercontext_mutefolder: "Без звук папка", + foldercontext_removefolder: "Изтриване на папка", + modal_colorpicker1: "Основен цвят на папката", + modal_colorpicker2: "Вторичен цвят на папката", + modal_colorpicker3: "Цвят на подсказка", + modal_colorpicker4: "Цвят на шрифта", + modal_copytooltipcolor: "Използвайте един и същи цвят за всички сървъри в папка", + modal_customclosed: "Затворена икона", + modal_customopen: "Отворете иконата", + modal_custompreview: "Визуализация на иконата", + modal_iconpicker: "Избор на папка", + modal_swapcolor: "Използвайте втория цвят за оригиналната папка", + modal_tabheader1: "Папка", + modal_tabheader2: "Цвят на папката", + modal_tabheader3: "Цвят на подсказка", + modal_tabheader4: "Собствени символи", + modal_usecloseicon: "Използвайте затворена икона вместо минисервъра", + servercontext_serverfolders: "Папка на сървъра", + serversubmenu_addtofolder: "Добавете сървъра към папката", + serversubmenu_createfolder: "Създай папка", + serversubmenu_removefromfolder: "Премахнете сървъра от папката" + }; + case "da": // Danish + return { + foldercontext_autoreadfolder: "Auto: Marker som læst", + foldercontext_mutefolder: "Dæmp mappe", + foldercontext_removefolder: "Slet mappe", + modal_colorpicker1: "Primær mappefarve", + modal_colorpicker2: "Sekundær mappefarve", + modal_colorpicker3: "Værktøjstipfarve", + modal_colorpicker4: "Skriftfarve", + modal_copytooltipcolor: "Brug den samme farve til alle servere i en mappe", + modal_customclosed: "Lukket ikon", + modal_customopen: "Åbn ikonet", + modal_custompreview: "Eksempel på ikon", + modal_iconpicker: "Mappevalg", + modal_swapcolor: "Brug den anden farve til den originale mappe", + modal_tabheader1: "Folder", + modal_tabheader2: "Mappefarve", + modal_tabheader3: "Værktøjstipfarve", + modal_tabheader4: "Egne symboler", + modal_usecloseicon: "Brug et lukket ikon i stedet for miniserver", + servercontext_serverfolders: "Servermappe", + serversubmenu_addtofolder: "Føj serveren til mappen", + serversubmenu_createfolder: "Opret mappe", + serversubmenu_removefromfolder: "Fjern serveren fra mappen" + }; + case "de": // German + return { + foldercontext_autoreadfolder: "Auto: Als gelesen markieren", + foldercontext_mutefolder: "Ordner stummschalten", + foldercontext_removefolder: "Ordner löschen", + modal_colorpicker1: "Primäre Ordnerfarbe", + modal_colorpicker2: "Sekundäre Ordnerfarbe", + modal_colorpicker3: "Tooltipfarbe", + modal_colorpicker4: "Schriftfarbe", + modal_copytooltipcolor: "Dieselbe Farbe für alle Server eines Ordners verwenden", + modal_customclosed: "Geschlossenes Icon", + modal_customopen: "Geöffnetes Icon", + modal_custompreview: "Symbolvorschau", + modal_iconpicker: "Ordnerauswahl", + modal_swapcolor: "Die zweite Farbe für den ursprünglichen Ordner verwenden", + modal_tabheader1: "Ordner", + modal_tabheader2: "Ordnerfarbe", + modal_tabheader3: "Tooltipfarbe", + modal_tabheader4: "Eigene Symbole", + modal_usecloseicon: "Anstelle der Miniserver ein geschlossenes Symbol verwenden", + servercontext_serverfolders: "Serverordner", + serversubmenu_addtofolder: "Server zum Ordner hinzufügen", + serversubmenu_createfolder: "Ordner erzeugen", + serversubmenu_removefromfolder: "Server aus Ordner entfernen" + }; + case "el": // Greek + return { + foldercontext_autoreadfolder: "Αυτόματο: Επισήμανση ως αναγνωσμένου", + foldercontext_mutefolder: "Σίγαση φακέλου", + foldercontext_removefolder: "Διαγραφή φακέλου", + modal_colorpicker1: "Κύριο χρώμα φακέλου", + modal_colorpicker2: "Χρώμα δευτερεύοντος φακέλου", + modal_colorpicker3: "Χρώμα επεξήγησης εργαλείου", + modal_colorpicker4: "Χρώμα γραμματοσειράς", + modal_copytooltipcolor: "Χρησιμοποιήστε το ίδιο χρώμα για όλους τους διακομιστές σε ένα φάκελο", + modal_customclosed: "Κλειστό εικονίδιο", + modal_customopen: "Άνοιγμα εικονιδίου", + modal_custompreview: "Προεπισκόπηση εικονιδίου", + modal_iconpicker: "Επιλογή φακέλου", + modal_swapcolor: "Χρησιμοποιήστε το δεύτερο χρώμα για τον αρχικό φάκελο", + modal_tabheader1: "Ντοσιέ", + modal_tabheader2: "Χρώμα φακέλου", + modal_tabheader3: "Χρώμα επεξήγησης εργαλείου", + modal_tabheader4: "Ίδια σύμβολα", + modal_usecloseicon: "Χρησιμοποιήστε ένα κλειστό εικονίδιο αντί για το miniserver", + servercontext_serverfolders: "Φάκελος διακομιστή", + serversubmenu_addtofolder: "Προσθέστε το διακομιστή στο φάκελο", + serversubmenu_createfolder: "ΔΗΜΙΟΥΡΓΩ φακελο", + serversubmenu_removefromfolder: "Κατάργηση διακομιστή από φάκελο" + }; + case "es": // Spanish + return { + foldercontext_autoreadfolder: "Automático: marcar como leído", + foldercontext_mutefolder: "Silenciar carpeta", + foldercontext_removefolder: "Eliminar carpeta", + modal_colorpicker1: "Color de carpeta principal", + modal_colorpicker2: "Color de carpeta secundaria", + modal_colorpicker3: "Color de la información sobre herramientas", + modal_colorpicker4: "Color de fuente", + modal_copytooltipcolor: "Use el mismo color para todos los servidores de una carpeta", + modal_customclosed: "Icono cerrado", + modal_customopen: "Abrir icono", + modal_custompreview: "Vista previa del icono", + modal_iconpicker: "Selección de carpeta", + modal_swapcolor: "Use el segundo color para la carpeta original", + modal_tabheader1: "Carpeta", + modal_tabheader2: "Color de la carpeta", + modal_tabheader3: "Color de la información sobre herramientas", + modal_tabheader4: "Símbolos propios", + modal_usecloseicon: "Use un icono cerrado en lugar del miniserver", + servercontext_serverfolders: "Carpeta del servidor", + serversubmenu_addtofolder: "Agrega el servidor a la carpeta", + serversubmenu_createfolder: "Crear carpeta", + serversubmenu_removefromfolder: "Quitar servidor de carpeta" + }; + case "fi": // Finnish + return { + foldercontext_autoreadfolder: "Automaattinen: Merkitse luetuksi", + foldercontext_mutefolder: "Mykistä kansio", + foldercontext_removefolder: "Poista kansio", + modal_colorpicker1: "Ensisijaisen kansion väri", + modal_colorpicker2: "Toissijaisen kansion väri", + modal_colorpicker3: "Työkaluvinkin väri", + modal_colorpicker4: "Fontin väri", + modal_copytooltipcolor: "Käytä samaa väriä kaikille kansion palvelimille", + modal_customclosed: "Suljettu kuvake", + modal_customopen: "Avaa kuvake", + modal_custompreview: "Kuvakkeen esikatselu", + modal_iconpicker: "Kansion valinta", + modal_swapcolor: "Käytä alkuperäisen kansion toista väriä", + modal_tabheader1: "Kansio", + modal_tabheader2: "Kansion väri", + modal_tabheader3: "Työkaluvinkin väri", + modal_tabheader4: "Omat symbolit", + modal_usecloseicon: "Käytä suljetun kuvaketta minipalvelimen sijaan", + servercontext_serverfolders: "Palvelinkansio", + serversubmenu_addtofolder: "Lisää palvelin kansioon", + serversubmenu_createfolder: "Luo kansio", + serversubmenu_removefromfolder: "Poista palvelin kansiosta" + }; + case "fr": // French + return { + foldercontext_autoreadfolder: "Auto: marquer comme lu", + foldercontext_mutefolder: "Dossier muet", + foldercontext_removefolder: "Supprimer le dossier", + modal_colorpicker1: "Couleur du dossier primaire", + modal_colorpicker2: "Couleur du dossier secondaire", + modal_colorpicker3: "Couleur de l'info-bulle", + modal_colorpicker4: "Couleur de la police", + modal_copytooltipcolor: "Utilisez la même couleur pour tous les serveurs d'un dossier", + modal_customclosed: "Icône fermée", + modal_customopen: "Icône ouverte", + modal_custompreview: "Aperçu de l'icône", + modal_iconpicker: "Sélection de dossier", + modal_swapcolor: "Utilisez la deuxième couleur pour le dossier d'origine", + modal_tabheader1: "Dossier", + modal_tabheader2: "Couleur du dossier", + modal_tabheader3: "Couleur de l'info-bulle", + modal_tabheader4: "Propres symboles", + modal_usecloseicon: "Utilisez une icône fermée au lieu du miniserver", + servercontext_serverfolders: "Dossier du serveur", + serversubmenu_addtofolder: "Ajouter le serveur au dossier", + serversubmenu_createfolder: "Créer le dossier", + serversubmenu_removefromfolder: "Supprimer le serveur du dossier" + }; + case "hr": // Croatian + return { + foldercontext_autoreadfolder: "Automatski: Označi kao pročitano", + foldercontext_mutefolder: "Isključi mapu", + foldercontext_removefolder: "Izbriši mapu", + modal_colorpicker1: "Boja primarne mape", + modal_colorpicker2: "Boja sekundarne mape", + modal_colorpicker3: "Boja opisa", + modal_colorpicker4: "Boja fonta", + modal_copytooltipcolor: "Koristite istu boju za sve poslužitelje u mapi", + modal_customclosed: "Zatvorena ikona", + modal_customopen: "Otvori ikonu", + modal_custompreview: "Pregled ikone", + modal_iconpicker: "Odabir mape", + modal_swapcolor: "Upotrijebite drugu boju za izvornu mapu", + modal_tabheader1: "Mapu", + modal_tabheader2: "Boja mape", + modal_tabheader3: "Boja opisa", + modal_tabheader4: "Vlastiti simboli", + modal_usecloseicon: "Upotrijebite zatvorenu ikonu umjesto miniservera", + servercontext_serverfolders: "Mapa poslužitelja", + serversubmenu_addtofolder: "Dodajte poslužitelj u mapu", + serversubmenu_createfolder: "Stvori mapu", + serversubmenu_removefromfolder: "Uklonite poslužitelj iz mape" + }; + case "hu": // Hungarian + return { + foldercontext_autoreadfolder: "Automatikus: Megjelölés olvasottként", + foldercontext_mutefolder: "Mappa némítása", + foldercontext_removefolder: "Mappa törlése", + modal_colorpicker1: "Elsődleges mappa színe", + modal_colorpicker2: "Másodlagos mappa színe", + modal_colorpicker3: "Eszköztár színe", + modal_colorpicker4: "Betű szín", + modal_copytooltipcolor: "Használja ugyanazt a színt egy mappa összes kiszolgálójához", + modal_customclosed: "Zárt ikonra", + modal_customopen: "Megnyitás ikonra", + modal_custompreview: "Ikon előnézet", + modal_iconpicker: "Mappa kiválasztása", + modal_swapcolor: "Használja az eredeti mappa második színét", + modal_tabheader1: "Mappába", + modal_tabheader2: "Mappa színe", + modal_tabheader3: "Eszköztár színe", + modal_tabheader4: "Saját szimbólumok", + modal_usecloseicon: "Használjon zárt ikont a miniszerver helyett", + servercontext_serverfolders: "Szerver mappa", + serversubmenu_addtofolder: "Adja hozzá a szervert a mappához", + serversubmenu_createfolder: "Mappa létrehozás", + serversubmenu_removefromfolder: "Távolítsa el a szervert a mappából" + }; + case "it": // Italian + return { + foldercontext_autoreadfolder: "Auto: contrassegna come letto", + foldercontext_mutefolder: "Disattiva cartella", + foldercontext_removefolder: "Elimina cartella", + modal_colorpicker1: "Colore cartella principale", + modal_colorpicker2: "Colore cartella secondaria", + modal_colorpicker3: "Colore della descrizione comando", + modal_colorpicker4: "Colore del carattere", + modal_copytooltipcolor: "Usa lo stesso colore per tutti i server in una cartella", + modal_customclosed: "Icona chiusa", + modal_customopen: "Icona Apri", + modal_custompreview: "Anteprima icona", + modal_iconpicker: "Selezione della cartella", + modal_swapcolor: "Usa il secondo colore per la cartella originale", + modal_tabheader1: "Cartella", + modal_tabheader2: "Colore cartella", + modal_tabheader3: "Colore della descrizione comando", + modal_tabheader4: "Simboli propri", + modal_usecloseicon: "Utilizza un'icona chiusa al posto del miniserver", + servercontext_serverfolders: "Cartella del server", + serversubmenu_addtofolder: "Aggiungi il server alla cartella", + serversubmenu_createfolder: "Creare una cartella", + serversubmenu_removefromfolder: "Rimuovi il server dalla cartella" + }; + case "ja": // Japanese + return { + foldercontext_autoreadfolder: "自動:既読としてマーク", + foldercontext_mutefolder: "ミュートフォルダ", + foldercontext_removefolder: "フォルダを削除", + modal_colorpicker1: "プライマリフォルダの色", + modal_colorpicker2: "セカンダリフォルダの色", + modal_colorpicker3: "ツールチップの色", + modal_colorpicker4: "フォントの色", + modal_copytooltipcolor: "フォルダ内のすべてのサーバーに同じ色を使用する", + modal_customclosed: "閉じたアイコン", + modal_customopen: "アイコンを開く", + modal_custompreview: "アイコンプレビュー", + modal_iconpicker: "フォルダの選択", + modal_swapcolor: "元のフォルダに2番目の色を使用します", + modal_tabheader1: "フォルダ", + modal_tabheader2: "フォルダーの色", + modal_tabheader3: "ツールチップの色", + modal_tabheader4: "独自のシンボル", + modal_usecloseicon: "ミニサーバーの代わりに閉じたアイコンを使用する", + servercontext_serverfolders: "サーバーフォルダ", + serversubmenu_addtofolder: "サーバーをフォルダーに追加します", + serversubmenu_createfolder: "フォルダーを作る", + serversubmenu_removefromfolder: "フォルダからサーバーを削除します" + }; + case "ko": // Korean + return { + foldercontext_autoreadfolder: "자동 : 읽은 상태로 표시", + foldercontext_mutefolder: "폴더 음소거", + foldercontext_removefolder: "폴더 삭제", + modal_colorpicker1: "기본 폴더 색상", + modal_colorpicker2: "보조 폴더 색상", + modal_colorpicker3: "툴팁 색상", + modal_colorpicker4: "글자 색", + modal_copytooltipcolor: "폴더의 모든 서버에 동일한 색상 사용", + modal_customclosed: "닫힌 아이콘", + modal_customopen: "열기 아이콘", + modal_custompreview: "아이콘 미리보기", + modal_iconpicker: "폴더 선택", + modal_swapcolor: "원본 폴더에 두 번째 색상 사용", + modal_tabheader1: "폴더", + modal_tabheader2: "폴더 색상", + modal_tabheader3: "툴팁 색상", + modal_tabheader4: "자신의 기호", + modal_usecloseicon: "미니 서버 대신 닫힌 아이콘 사용", + servercontext_serverfolders: "서버 폴더", + serversubmenu_addtofolder: "폴더에 서버 추가", + serversubmenu_createfolder: "폴더 생성", + serversubmenu_removefromfolder: "폴더에서 서버 제거" + }; + case "lt": // Lithuanian + return { + foldercontext_autoreadfolder: "Automatinis: pažymėti kaip perskaitytą", + foldercontext_mutefolder: "Nutildyti aplanką", + foldercontext_removefolder: "Ištrinti aplanką", + modal_colorpicker1: "Pagrindinio aplanko spalva", + modal_colorpicker2: "Antrinio aplanko spalva", + modal_colorpicker3: "Patarimo spalva", + modal_colorpicker4: "Šrifto spalva", + modal_copytooltipcolor: "Naudokite tą pačią spalvą visiems aplanko serveriams", + modal_customclosed: "Uždaryta piktograma", + modal_customopen: "Atidaryti piktogramą", + modal_custompreview: "Piktogramos peržiūra", + modal_iconpicker: "Aplanko pasirinkimas", + modal_swapcolor: "Originalo aplankui naudokite antrą spalvą", + modal_tabheader1: "Aplanką", + modal_tabheader2: "Aplanko spalva", + modal_tabheader3: "Patarimo spalva", + modal_tabheader4: "Savo simbolius", + modal_usecloseicon: "Vietoj miniserverio naudokite uždarą piktogramą", + servercontext_serverfolders: "Serverio aplankas", + serversubmenu_addtofolder: "Pridėkite serverį prie aplanko", + serversubmenu_createfolder: "Sukurti aplanką", + serversubmenu_removefromfolder: "Pašalinti serverį iš aplanko" + }; + case "nl": // Dutch + return { + foldercontext_autoreadfolder: "Auto: Markeer als gelezen", + foldercontext_mutefolder: "Mute map", + foldercontext_removefolder: "Verwijder map", + modal_colorpicker1: "Kleur primaire map", + modal_colorpicker2: "Kleur secundaire map", + modal_colorpicker3: "Tooltipkleur", + modal_colorpicker4: "Letterkleur", + modal_copytooltipcolor: "Gebruik dezelfde kleur voor alle servers in een map", + modal_customclosed: "Gesloten pictogram", + modal_customopen: "Open icoon", + modal_custompreview: "Pictogramvoorbeeld", + modal_iconpicker: "Map selecteren", + modal_swapcolor: "Gebruik de tweede kleur voor de originele map", + modal_tabheader1: "Map", + modal_tabheader2: "Mapkleur", + modal_tabheader3: "Tooltipkleur", + modal_tabheader4: "Eigen symbolen", + modal_usecloseicon: "Gebruik een gesloten pictogram in plaats van de miniserver", + servercontext_serverfolders: "Servermap", + serversubmenu_addtofolder: "Voeg de server toe aan de map", + serversubmenu_createfolder: "Map aanmaken", + serversubmenu_removefromfolder: "Verwijder de server uit de map" + }; + case "no": // Norwegian + return { + foldercontext_autoreadfolder: "Auto: Merk som lest", + foldercontext_mutefolder: "Demp mappe", + foldercontext_removefolder: "Slett mappe", + modal_colorpicker1: "Primær mappefarge", + modal_colorpicker2: "Sekundær mappefarge", + modal_colorpicker3: "Verktøytipsfarge", + modal_colorpicker4: "Skriftfarge", + modal_copytooltipcolor: "Bruk samme farge for alle servere i en mappe", + modal_customclosed: "Lukket ikon", + modal_customopen: "Åpne ikonet", + modal_custompreview: "Forhåndsvisning av ikon", + modal_iconpicker: "Mappevalg", + modal_swapcolor: "Bruk den andre fargen for den originale mappen", + modal_tabheader1: "Mappe", + modal_tabheader2: "Mappefarge", + modal_tabheader3: "Verktøytipsfarge", + modal_tabheader4: "Egne symboler", + modal_usecloseicon: "Bruk et lukket ikon i stedet for miniserver", + servercontext_serverfolders: "Servermappe", + serversubmenu_addtofolder: "Legg til serveren i mappen", + serversubmenu_createfolder: "Lag mappe", + serversubmenu_removefromfolder: "Fjern serveren fra mappen" + }; + case "pl": // Polish + return { + foldercontext_autoreadfolder: "Auto: oznacz jako przeczytane", + foldercontext_mutefolder: "Wycisz folder", + foldercontext_removefolder: "Usunięty folder", + modal_colorpicker1: "Główny kolor folderu", + modal_colorpicker2: "Kolor folderu dodatkowego", + modal_colorpicker3: "Kolor podpowiedzi", + modal_colorpicker4: "Kolor czcionki", + modal_copytooltipcolor: "Użyj tego samego koloru dla wszystkich serwerów w folderze", + modal_customclosed: "Ikona zamknięta", + modal_customopen: "Otwórz ikonę", + modal_custompreview: "Podgląd ikon", + modal_iconpicker: "Wybór folderu", + modal_swapcolor: "Użyj drugiego koloru dla oryginalnego folderu", + modal_tabheader1: "Teczka", + modal_tabheader2: "Kolor folderu", + modal_tabheader3: "Kolor podpowiedzi", + modal_tabheader4: "Własne symbole", + modal_usecloseicon: "Użyj zamkniętej ikony zamiast miniserwera", + servercontext_serverfolders: "Folder serwera", + serversubmenu_addtofolder: "Dodaj serwer do folderu", + serversubmenu_createfolder: "Utwórz folder", + serversubmenu_removefromfolder: "Usuń serwer z folderu" + }; + case "pt-BR": // Portuguese (Brazil) + return { + foldercontext_autoreadfolder: "Auto: Marcar como lido", + foldercontext_mutefolder: "Pasta sem som", + foldercontext_removefolder: "Excluir pasta", + modal_colorpicker1: "Cor da pasta primária", + modal_colorpicker2: "Cor secundária da pasta", + modal_colorpicker3: "Cor da dica de ferramenta", + modal_colorpicker4: "Cor da fonte", + modal_copytooltipcolor: "Use a mesma cor para todos os servidores em uma pasta", + modal_customclosed: "Ícone fechado", + modal_customopen: "Ícone aberto", + modal_custompreview: "Antevisão do ícone", + modal_iconpicker: "Seleção de pasta", + modal_swapcolor: "Use a segunda cor para a pasta original", + modal_tabheader1: "Pasta", + modal_tabheader2: "Cor da pasta", + modal_tabheader3: "Cor da dica de ferramenta", + modal_tabheader4: "Símbolos próprios", + modal_usecloseicon: "Use um ícone fechado em vez do miniserver", + servercontext_serverfolders: "Pasta do servidor", + serversubmenu_addtofolder: "Adicione o servidor à pasta", + serversubmenu_createfolder: "Criar pasta", + serversubmenu_removefromfolder: "Remover servidor da pasta" + }; + case "ro": // Romanian + return { + foldercontext_autoreadfolder: "Automat: marcați ca citit", + foldercontext_mutefolder: "Dezactivați folderul", + foldercontext_removefolder: "Ștergeți folderul", + modal_colorpicker1: "Culoarea folderului principal", + modal_colorpicker2: "Culoare dosar secundar", + modal_colorpicker3: "Culoarea sfatului de instrumente", + modal_colorpicker4: "Culoarea fontului", + modal_copytooltipcolor: "Utilizați aceeași culoare pentru toate serverele dintr-un folder", + modal_customclosed: "Pictogramă închisă", + modal_customopen: "Pictogramă Deschidere", + modal_custompreview: "Previzualizare pictogramă", + modal_iconpicker: "Selectarea dosarelor", + modal_swapcolor: "Utilizați a doua culoare pentru folderul original", + modal_tabheader1: "Pliant", + modal_tabheader2: "Culoare dosar", + modal_tabheader3: "Culoarea sfatului de instrumente", + modal_tabheader4: "Simboluri proprii", + modal_usecloseicon: "Folosiți o pictogramă închisă în locul miniserverului", + servercontext_serverfolders: "Dosar server", + serversubmenu_addtofolder: "Adăugați serverul în dosar", + serversubmenu_createfolder: "Creeaza dosar", + serversubmenu_removefromfolder: "Eliminați serverul din dosar" + }; + case "ru": // Russian + return { + foldercontext_autoreadfolder: "Авто: Отметить как прочитанное", + foldercontext_mutefolder: "Отключить папку", + foldercontext_removefolder: "Удалить папку", + modal_colorpicker1: "Цвет основной папки", + modal_colorpicker2: "Цвет вторичной папки", + modal_colorpicker3: "Цвет всплывающей подсказки", + modal_colorpicker4: "Цвет шрифта", + modal_copytooltipcolor: "Используйте один цвет для всех серверов в папке", + modal_customclosed: "Закрытый значок", + modal_customopen: "Открыть значок", + modal_custompreview: "Предварительный просмотр значков", + modal_iconpicker: "Выбор папки", + modal_swapcolor: "Используйте второй цвет для исходной папки", + modal_tabheader1: "Папка", + modal_tabheader2: "Цвет папки", + modal_tabheader3: "Цвет всплывающей подсказки", + modal_tabheader4: "Собственные символы", + modal_usecloseicon: "Используйте закрытый значок вместо минисервера", + servercontext_serverfolders: "Папка сервера", + serversubmenu_addtofolder: "Добавьте сервер в папку", + serversubmenu_createfolder: "Создать папку", + serversubmenu_removefromfolder: "Удалить сервер из папки" + }; + case "sv": // Swedish + return { + foldercontext_autoreadfolder: "Auto: Markera som läst", + foldercontext_mutefolder: "Tyst mapp", + foldercontext_removefolder: "Ta bort mapp", + modal_colorpicker1: "Primär mappfärg", + modal_colorpicker2: "Sekundär mappfärg", + modal_colorpicker3: "Verktygstipsfärg", + modal_colorpicker4: "Fontfärg", + modal_copytooltipcolor: "Använd samma färg för alla servrar i en mapp", + modal_customclosed: "Stängd ikon", + modal_customopen: "Öppna ikonen", + modal_custompreview: "Ikonförhandsvisning", + modal_iconpicker: "Mappval", + modal_swapcolor: "Använd den andra färgen för den ursprungliga mappen", + modal_tabheader1: "Mapp", + modal_tabheader2: "Mappfärg", + modal_tabheader3: "Verktygstipsfärg", + modal_tabheader4: "Egna symboler", + modal_usecloseicon: "Använd en stängd ikon istället för miniserver", + servercontext_serverfolders: "Servermapp", + serversubmenu_addtofolder: "Lägg till servern i mappen", + serversubmenu_createfolder: "Skapa mapp", + serversubmenu_removefromfolder: "Ta bort servern från mappen" + }; + case "th": // Thai + return { + foldercontext_autoreadfolder: "อัตโนมัติ: ทำเครื่องหมายว่าอ่านแล้ว", + foldercontext_mutefolder: "ปิดเสียงโฟลเดอร์", + foldercontext_removefolder: "ลบโฟลเดอร์", + modal_colorpicker1: "สีโฟลเดอร์หลัก", + modal_colorpicker2: "สีโฟลเดอร์รอง", + modal_colorpicker3: "สีคำแนะนำเครื่องมือ", + modal_colorpicker4: "สีตัวอักษร", + modal_copytooltipcolor: "ใช้สีเดียวกันสำหรับเซิร์ฟเวอร์ทั้งหมดในโฟลเดอร์", + modal_customclosed: "ไอคอนปิด", + modal_customopen: "เปิดไอคอน", + modal_custompreview: "ดูตัวอย่างไอคอน", + modal_iconpicker: "การเลือกโฟลเดอร์", + modal_swapcolor: "ใช้สีที่สองสำหรับโฟลเดอร์เดิม", + modal_tabheader1: "โฟลเดอร์", + modal_tabheader2: "สีโฟลเดอร์", + modal_tabheader3: "สีคำแนะนำเครื่องมือ", + modal_tabheader4: "สัญลักษณ์ของตัวเอง", + modal_usecloseicon: "ใช้ไอคอนปิดแทน miniserver", + servercontext_serverfolders: "โฟลเดอร์เซิร์ฟเวอร์", + serversubmenu_addtofolder: "เพิ่มเซิร์ฟเวอร์ลงในโฟลเดอร์", + serversubmenu_createfolder: "สร้างโฟลเดอร์", + serversubmenu_removefromfolder: "ลบเซิร์ฟเวอร์ออกจากโฟลเดอร์" + }; + case "tr": // Turkish + return { + foldercontext_autoreadfolder: "Otomatik: Okundu olarak işaretle", + foldercontext_mutefolder: "Klasörü sessize al", + foldercontext_removefolder: "Klasörü sil", + modal_colorpicker1: "Birincil klasör rengi", + modal_colorpicker2: "İkincil klasör rengi", + modal_colorpicker3: "Araç ipucu rengi", + modal_colorpicker4: "Yazı rengi", + modal_copytooltipcolor: "Bir klasördeki tüm sunucular için aynı rengi kullanın", + modal_customclosed: "Kapalı simge", + modal_customopen: "Aç simgesi", + modal_custompreview: "Simge önizlemesi", + modal_iconpicker: "Klasör seçimi", + modal_swapcolor: "Orijinal klasör için ikinci rengi kullanın", + modal_tabheader1: "Klasör", + modal_tabheader2: "Klasör rengi", + modal_tabheader3: "Araç ipucu rengi", + modal_tabheader4: "Kendi sembolleri", + modal_usecloseicon: "Miniserver yerine kapalı bir simge kullanın", + servercontext_serverfolders: "Sunucu klasörü", + serversubmenu_addtofolder: "Sunucuyu klasöre ekleyin", + serversubmenu_createfolder: "Klasör oluşturun", + serversubmenu_removefromfolder: "Sunucuyu klasörden kaldır" + }; + case "uk": // Ukrainian + return { + foldercontext_autoreadfolder: "Авто: Позначити як прочитане", + foldercontext_mutefolder: "Вимкнути папку", + foldercontext_removefolder: "Видалити папку", + modal_colorpicker1: "Основний колір папки", + modal_colorpicker2: "Колір вторинної папки", + modal_colorpicker3: "Колір підказки", + modal_colorpicker4: "Колір шрифту", + modal_copytooltipcolor: "Використовуйте однаковий колір для всіх серверів у папці", + modal_customclosed: "Закритий значок", + modal_customopen: "Відкрити значок", + modal_custompreview: "Попередній перегляд піктограми", + modal_iconpicker: "Вибір папки", + modal_swapcolor: "Використовуйте другий колір для вихідної папки", + modal_tabheader1: "Папку", + modal_tabheader2: "Колір папки", + modal_tabheader3: "Колір підказки", + modal_tabheader4: "Власні символи", + modal_usecloseicon: "Використовуйте закритий значок замість мінісервера", + servercontext_serverfolders: "Папка сервера", + serversubmenu_addtofolder: "Додайте сервер до папки", + serversubmenu_createfolder: "Створити папку", + serversubmenu_removefromfolder: "Видалити сервер з папки" + }; + case "vi": // Vietnamese + return { + foldercontext_autoreadfolder: "Tự động: Đánh dấu là đã đọc", + foldercontext_mutefolder: "Thư mục ẩn", + foldercontext_removefolder: "Xóa thư mục", + modal_colorpicker1: "Màu thư mục chính", + modal_colorpicker2: "Màu thư mục phụ", + modal_colorpicker3: "Màu chú giải công cụ", + modal_colorpicker4: "Màu phông chữ", + modal_copytooltipcolor: "Sử dụng cùng một màu cho tất cả các máy chủ trong một thư mục", + modal_customclosed: "Biểu tượng đã đóng", + modal_customopen: "Mở biểu tượng", + modal_custompreview: "Xem trước biểu tượng", + modal_iconpicker: "Lựa chọn thư mục", + modal_swapcolor: "Sử dụng màu thứ hai cho thư mục gốc", + modal_tabheader1: "Thư mục", + modal_tabheader2: "Màu thư mục", + modal_tabheader3: "Màu chú giải công cụ", + modal_tabheader4: "Ký hiệu riêng", + modal_usecloseicon: "Sử dụng biểu tượng đã đóng thay vì trình thu nhỏ", + servercontext_serverfolders: "Thư mục máy chủ", + serversubmenu_addtofolder: "Thêm máy chủ vào thư mục", + serversubmenu_createfolder: "Tạo thư mục", + serversubmenu_removefromfolder: "Xóa máy chủ khỏi thư mục" + }; + case "zh-CN": // Chinese (China) + return { + foldercontext_autoreadfolder: "自动:标记为已读", + foldercontext_mutefolder: "静音文件夹", + foldercontext_removefolder: "删除文件夹", + modal_colorpicker1: "文件夹主色", + modal_colorpicker2: "文件夹辅色", + modal_colorpicker3: "工具提示颜色", + modal_colorpicker4: "字体颜色", + modal_copytooltipcolor: "对文件夹中的所有服务器使用相同颜色", + modal_customclosed: "文件夹收起图标", + modal_customopen: "文件夹展开图标", + modal_custompreview: "图标预览", + modal_iconpicker: "文件夹选择", + modal_swapcolor: "将文件夹副色应用于原始文件夹", + modal_tabheader1: "文件夹", + modal_tabheader2: "文件夹颜色", + modal_tabheader3: "工具提示颜色", + modal_tabheader4: "自定义图标", + modal_usecloseicon: "使用文件夹收起图标代替服务器缩略图", + servercontext_serverfolders: "服务器文件夹", + serversubmenu_addtofolder: "将服务器添加到文件夹", + serversubmenu_createfolder: "创建文件夹", + serversubmenu_removefromfolder: "从文件夹中移除服务器" + }; + case "zh-TW": // Chinese (Taiwan) + return { + foldercontext_autoreadfolder: "自動:標記為已讀", + foldercontext_mutefolder: "靜音資料夾", + foldercontext_removefolder: "刪除資料夾", + modal_colorpicker1: "資料夾主色", + modal_colorpicker2: "資料夾輔色", + modal_colorpicker3: "工具提示顏色", + modal_colorpicker4: "字體顏色", + modal_copytooltipcolor: "對資料夾中的所有伺服器使用相同顏色", + modal_customclosed: "資料夾收起圖標", + modal_customopen: "資料夾展開圖標", + modal_custompreview: "圖標預覽", + modal_iconpicker: "資料夾選擇", + modal_swapcolor: "將文件夾輔色應用於原始資料夾", + modal_tabheader1: "資料夾", + modal_tabheader2: "資料夾顏色", + modal_tabheader3: "工具提示顏色", + modal_tabheader4: "客製化圖標", + modal_usecloseicon: "使用資料夾收起圖標代替伺服器縮略圖", + servercontext_serverfolders: "伺服器資料夾", + serversubmenu_addtofolder: "將伺服器添加到資料夾", + serversubmenu_createfolder: "創建資料夾", + serversubmenu_removefromfolder: "從資料夾中移除伺服器" + }; + default: // English + return { + foldercontext_autoreadfolder: "Auto: Mark As Read", + foldercontext_mutefolder: "Mute Folder", + foldercontext_removefolder: "Delete Folder", + modal_colorpicker1: "Primary Folder Color", + modal_colorpicker2: "Secondary Folder Color", + modal_colorpicker3: "Tooltip Color", + modal_colorpicker4: "Font Color", + modal_copytooltipcolor: "Use the same Color for all Servers in a Folder", + modal_customclosed: "Closed Icon", + modal_customopen: "Open Icon", + modal_custompreview: "Icon Preview", + modal_iconpicker: "Folder Selection", + modal_swapcolor: "Use the second Color for the original Folder", + modal_tabheader1: "Folder", + modal_tabheader2: "Folder Color", + modal_tabheader3: "Tooltip Color", + modal_tabheader4: "Custom Icons", + modal_usecloseicon: "Use a closed Icon instead of the Mini-Servers", + servercontext_serverfolders: "Server Folder", + serversubmenu_addtofolder: "Add the Server to the Folder", + serversubmenu_createfolder: "Create Folder", + serversubmenu_removefromfolder: "Remove Server from Folder" + }; + } + } + }; + })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); +})(); diff --git a/oldconfig/BetterDiscord/plugins/ShowConnections.config.json b/oldconfig/BetterDiscord/plugins/ShowConnections.config.json new file mode 100644 index 0000000..05ebbed --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ShowConnections.config.json @@ -0,0 +1,25 @@ +{ + "connections": { + "battlenet": true, + "facebook": true, + "github": true, + "leagueoflegends": true, + "playstation": true, + "reddit": true, + "samsung": true, + "skype": true, + "spotify": true, + "steam": true, + "twitch": true, + "twitter": true, + "xbox": true, + "youtube": true + }, + "general": { + "useColoredIcons": true, + "useColoredTooltips": true, + "placeAtTop": false, + "showVerifiedBadge": true, + "openWebpage": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ShutUpClyde.config.json b/oldconfig/BetterDiscord/plugins/ShutUpClyde.config.json new file mode 100644 index 0000000..563dfff --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ShutUpClyde.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "0.0.1", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ShutUpClyde.plugin.js b/oldconfig/BetterDiscord/plugins/ShutUpClyde.plugin.js new file mode 100644 index 0000000..50cbbf9 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ShutUpClyde.plugin.js @@ -0,0 +1,96 @@ +//META{"name":"ShutUpClyde","displayName":"ShutUpClyde"}*// +/*@cc_on +@if (@_jscript) + + // Offer to self-install for clueless users that try to run this directly. + var shell = WScript.CreateObject("WScript.Shell"); + var fs = new ActiveXObject("Scripting.FileSystemObject"); + var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\BetterDiscord\plugins"); + var pathSelf = WScript.ScriptFullName; + // Put the user at ease by addressing them in the first person + shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30); + if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) { + shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40); + } else if (!fs.FolderExists(pathPlugins)) { + shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10); + } else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) { + fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true); + // Show the user where to put plugins in the future + shell.Exec("explorer " + pathPlugins); + shell.Popup("I'm installed!", 0, "Successfully installed", 0x40); + } + WScript.Quit(); + +@else@*/ + +module.exports = (() => { + const config = { + info: { + name: "ShutUpClyde", + authors: [ + { + name: "Strencher", + discord_id: "415849376598982656", + github_username: "Strencher", + twitter_username: "Strencher3" + } + ], + version: "0.0.1", + description: "Prevents Clyde from disturbing you.", + github: "https://github.com/Strencher/BetterDiscordStuff/ShutUpClyde/ShutUpClyde.plugin.js", + github_raw: "https://raw.githubusercontent.com/Strencher/BetterDiscordStuff/master/ShutUpClyde/ShutUpClyde.plugin.js" + }, + changelog: [ + { + title: "Yeah", + type: "added", + items: ["The plugin exist"] + } + ] + }; + + return !global.ZeresPluginLibrary ? class { + constructor() { this._config = config; } + getName() { return config.info.name; } + getAuthor() { return config.info.authors.map(a => a.name).join(", "); } + getDescription() { return config.info.description; } + getVersion() { return config.info.version; } + load() { + BdApi.showConfirmationModal("Library plugin is needed", + [`The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`], { + confirmText: "Download", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js"); + await new Promise(r => require("fs").writeFile(require("path").join(ContentManager.pluginsFolder, "0PluginLibrary.plugin.js"), body, r)); + }); + } + }); + } + start() { } + stop() { } + } : (([Plugin, Api]) => { + const plugin = (Plugin, Api) => { + + const { WebpackModules, DiscordModules, Patcher } = Api; + return class ShutUpClyde extends Plugin { + constructor() { + super(); + } + + onStart() { + Patcher.instead(DiscordModules.MessageActions, "sendBotMessage", () => {}) + Patcher.instead(WebpackModules.getByProps("sendClydeError"), "sendClydeError", () => {}) + } + onStop() { + Patcher.unpatchAll() + } + + } + + }; + return plugin(Plugin, Api); + })(global.ZeresPluginLibrary.buildPlugin(config)); +})(); +/*@end@*/ diff --git a/oldconfig/BetterDiscord/plugins/ThemeRepo.config.json b/oldconfig/BetterDiscord/plugins/ThemeRepo.config.json new file mode 100644 index 0000000..3147523 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ThemeRepo.config.json @@ -0,0 +1,16 @@ +{ + "all": { + "cached": "1 3 4 16 18 22 23 26 32 33 39 40 41 45 46 47 48 49 52 53 56 112 124 125 140 142 144 147 153 155 156 161 166 172 174 177 204 205 209 211 212 213 216 218 222 226 231 233 252 256 257 258 286 296 300 308 315 320 329 342 359 362 369 371 374 384 385 394 399 405 411 412 422 439 468 482 483 485 507 508 515 517 530 541 553 572 576 580 581 597 601 607 613 626 636 637 641 642 643 653 659 662 664 665 695 712 713 714 719 733 734 735 737", + "filters": { + "updated": true, + "outdated": true, + "downloadable": true + }, + "general": { + "notifyOutdated": true, + "notifyNewEntries": true, + "startDownloaded": false, + "startUpdated": false + } + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ThemeRepo.plugin.js b/oldconfig/BetterDiscord/plugins/ThemeRepo.plugin.js new file mode 100644 index 0000000..0cf0e28 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ThemeRepo.plugin.js @@ -0,0 +1,1698 @@ +/** + * @name ThemeRepo + * @author DevilBro + * @authorId 278543574059057154 + * @version 2.3.5 + * @description Allows you to download all Themes from BD's Website within Discord + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/ThemeRepo/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/ThemeRepo.plugin.js + */ + +module.exports = (_ => { + const config = { + "info": { + "name": "ThemeRepo", + "author": "DevilBro", + "version": "2.3.5", + "description": "Allows you to download all Themes from BD's Website within Discord" + } + }; + + return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;} + + downloadLibrary () { + require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { + if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"})); + else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library"); + }); + } + + load () { + if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []}); + if (!window.BDFDB_Global.downloadModal) { + window.BDFDB_Global.downloadModal = true; + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, + onConfirm: _ => { + delete window.BDFDB_Global.downloadModal; + this.downloadLibrary(); + } + }); + } + if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + } + start () {this.load();} + stop () {} + getSettingsPanel () { + let template = document.createElement("template"); + template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); + return template.content.firstElementChild; + } + } : (([Plugin, BDFDB]) => { + var _this; + + var list, header, preview; + + var loading, cachedThemes, grabbedThemes, generatorThemes, updateInterval; + var searchString, searchTimeout, forcedSort, forcedOrder, showOnlyOutdated; + var updateGeneratorTimeout, forceRerenderGenerator, nativeCSS, nativeCSSvars; + + var favorites = []; + + const themeStates = { + INSTALLED: 0, + OUTDATED: 1, + DOWNLOADABLE: 2 + }; + const buttonData = { + INSTALLED: { + backgroundColor: "var(--bdfdb-green)", + icon: "CHECKMARK", + text: "installed" + }, + OUTDATED: { + backgroundColor: "var(--bdfdb-red)", + icon: "CLOSE", + text: "outdated" + }, + DOWNLOADABLE: { + backgroundColor: "var(--bdfdb-blurple)", + icon: "DOWNLOAD", + text: "download" + } + }; + const reverseSorts = [ + "RELEASEDATE", "DOWNLOADS", "LIKES", "FAV" + ]; + const sortKeys = { + NAME: "Name", + AUTHORNAME: "Author", + VERSION: "Version", + DESCRIPTION: "Description", + RELEASEDATE: "Release Date", + STATE: "Update State", + DOWNLOADS: "Downloads", + LIKES: "Likes", + FAV: "Favorites" + }; + const orderKeys = { + ASC: "ascending", + DESC: "descending" + }; + + const themeRepoIcon = ``; + + const RepoListComponent = class ThemeList extends BdApi.React.Component { + componentDidMount() { + list = this; + BDFDB.TimeUtils.timeout(_ => { + forcedSort = null; + forcedOrder = null; + showOnlyOutdated = false; + }, 5000); + } + componentWillUnmount() { + list = null; + this.closePreview(); + } + filterThemes() { + let themes = grabbedThemes.map(theme => { + const installedTheme = _this.getInstalledTheme(theme); + const state = installedTheme ? (theme.version && _this.compareVersions(theme.version, _this.getString(installedTheme.version)) ? themeStates.OUTDATED : themeStates.INSTALLED) : themeStates.DOWNLOADABLE; + return Object.assign(theme, { + search: [theme.name, theme.version, theme.authorname, theme.description, theme.tags].flat(10).filter(n => typeof n == "string").join(" ").toUpperCase(), + description: theme.description || "No Description found", + fav: favorites.includes(theme.id) && 1, + new: state == themeStates.DOWNLOADABLE && !cachedThemes.includes(theme.id) && 1, + state: state + }); + }); + if (!this.props.updated) themes = themes.filter(theme => theme.state != themeStates.INSTALLED); + if (!this.props.outdated) themes = themes.filter(theme => theme.state != themeStates.OUTDATED); + if (!this.props.downloadable) themes = themes.filter(theme => theme.state != themeStates.DOWNLOADABLE); + if (searchString) { + let usedSearchString = searchString.toUpperCase(); + let spacelessUsedSearchString = usedSearchString.replace(/\s/g, ""); + themes = themes.filter(theme => theme.search.indexOf(usedSearchString) > -1 || theme.search.indexOf(spacelessUsedSearchString) > -1); + } + + BDFDB.ArrayUtils.keySort(themes, this.props.sortKey.toLowerCase()); + if (this.props.orderKey == "DESC") themes.reverse(); + if (reverseSorts.includes(this.props.sortKey)) themes.reverse(); + return themes; + } + openPreview() { + preview = BDFDB.DOMUtils.create(`
+
+
+
+ +
+
+
+
+
+
+
+
`); + preview.frame = document.createElement("iframe"); + preview.frame.src = "https://mwittrien.github.io/BetterDiscordAddons/Plugins/_res/DiscordPreview.html"; + preview.querySelector(BDFDB.dotCN._themerepomovebar).addEventListener("mousedown", e => { + let moving = false; + let rects = BDFDB.DOMUtils.getRects(preview).toJSON(); + let oldX = e.pageX, oldY = e.pageY; + let mouseUp = _ => { + BDFDB.DOMUtils.removeClass(preview, BDFDB.disCN._themerepopreviewmoving); + document.removeEventListener("mouseup", mouseUp); + document.removeEventListener("mousemove", mouseMove); + }; + let mouseMove = e2 => { + if (moving || Math.sqrt((e.pageX - e2.pageX)**2) > 20 || Math.sqrt((e.pageY - e2.pageY)**2) > 20) { + if (!moving) BDFDB.DOMUtils.addClass(preview, BDFDB.disCN._themerepopreviewmoving); + moving = true; + BDFDB.ListenerUtils.stopEvent(e); + rects.top = rects.top - (oldY - e2.pageY); + rects.left = rects.left - (oldX - e2.pageX); + oldX = e2.pageX, oldY = e2.pageY; + preview.style.setProperty("top", `${rects.top}px`); + preview.style.setProperty("left", `${rects.left}px`); + } + }; + document.addEventListener("mouseup", mouseUp); + document.addEventListener("mousemove", mouseMove); + }); + for (let ele of preview.querySelectorAll(BDFDB.dotCNC._themerepodragbar + BDFDB.dotCN._themerepodragcorner)) ele.addEventListener("mousedown", e => { + let moving = false; + let rects = BDFDB.DOMUtils.getRects(preview).toJSON(); + let oldX = e.pageX, oldY = e.pageY; + let mouseUp = _ => { + BDFDB.DOMUtils.removeClass(preview, BDFDB.disCN._themerepopreviewmoving); + document.removeEventListener("mouseup", mouseUp); + document.removeEventListener("mousemove", mouseMove); + }; + let vertical = ele.getAttribute("vertical"); + let horizontal = ele.getAttribute("horizontal"); + let mouseMove = e2 => { + if (moving || Math.sqrt((e.pageX - e2.pageX)**2) > 20 || Math.sqrt((e.pageY - e2.pageY)**2) > 20) { + if (!moving) BDFDB.DOMUtils.addClass(preview, BDFDB.disCN._themerepopreviewmoving); + moving = true; + BDFDB.ListenerUtils.stopEvent(e); + if (vertical) switch (vertical) { + case "top": + rects.top = rects.top - (oldY - e2.pageY); + if (rects.bottom - rects.top > 25) { + preview.style.setProperty("top", `${rects.top}px`); + preview.style.setProperty("height", `${rects.bottom - rects.top}px`); + } + break; + case "bottom": + rects.bottom = rects.bottom - (oldY - e2.pageY); + if (rects.bottom - rects.top > 25) preview.style.setProperty("height", `${rects.bottom - rects.top}px`); + break; + } + if (horizontal) switch (horizontal) { + case "right": + rects.right = rects.right - (oldX - e2.pageX); + if (rects.right - rects.left > 200) preview.style.setProperty("width", `${rects.right - rects.left}px`); + break; + case "left": + rects.left = rects.left - (oldX - e2.pageX); + if (rects.right - rects.left > 200) { + preview.style.setProperty("left", `${rects.left}px`); + preview.style.setProperty("width", `${rects.right - rects.left}px`); + } + break; + } + oldX = e2.pageX, oldY = e2.pageY; + } + }; + document.addEventListener("mouseup", mouseUp); + document.addEventListener("mousemove", mouseMove); + }); + preview.frame.addEventListener("load", _ => { + let titleBar = document.querySelector(BDFDB.dotCN.titlebar); + this.runInPreview({ + reason: "OnLoad", + username: BDFDB.UserUtils.me.username, + id: BDFDB.UserUtils.me.id, + discriminator: BDFDB.UserUtils.me.discriminator, + avatar: BDFDB.UserUtils.getAvatar(), + classes: JSON.stringify(BDFDB.DiscordClasses), + classModules: JSON.stringify(BDFDB.DiscordClassModules), + nativeCSS: (nativeCSS || "").replace(/\/assets\//g, document.location.origin + "/assets/").replace(/[\t\r\n]/g, ""), + bdCSS: (document.querySelector("#bd-stylesheet") || {}).innerText || "", + htmlClassName: document.documentElement.className, + titleBar: titleBar && titleBar.outerHTML || "" + }); + if (this.props.currentTheme) this.runInPreview({ + reason: "NewTheme", + checked: true, + css: this.props.currentTheme.css + }); + if (this.props.currentGenerator) this.runInPreview({ + reason: "NewTheme", + checked: true, + css: (generatorThemes.find(t => t.id == this.props.currentGenerator) || {}).fullCSS + }); + if (this.props.useLightMode) this.runInPreview({ + reason: "DarkLight", + checked: true + }); + if (this.props.useCustomCSS) this.runInPreview({ + reason: "CustomCSS", + checked: true + }); + if (this.props.useThemeFixer) this.runInPreview({ + reason: "ThemeFixer", + checked: true + }); + }); + preview.appendChild(preview.frame); + document.body.appendChild(preview); + let outerRects = BDFDB.DOMUtils.getRects(document.body); + preview.style.setProperty("top", `${outerRects.width/4}px`); + preview.style.setProperty("left", `${outerRects.height/4}px`); + preview.style.setProperty("width", `${outerRects.width/2}px`); + preview.style.setProperty("height", `${outerRects.height/2}px`); + window.removeEventListener("message", list.onPreviewMessage); + window.addEventListener("message", list.onPreviewMessage); + } + closePreview() { + if (list) window.removeEventListener("message", list.onPreviewMessage); + if (preview) preview.remove(); + preview = null; + } + runInPreview(data) { + if (preview && preview.frame) preview.frame.contentWindow.postMessage(Object.assign({origin: "ThemeRepo"}, data), "*"); + } + onPreviewMessage(e) { + let rects, outerRects; + if (preview && e.data && e.data.origin == "DiscordPreview") switch (e.data.reason) { + case "close": + list.closePreview(); + break; + case "minimize": + outerRects = BDFDB.DOMUtils.getRects(document.body); + preview.style.setProperty("top", `${outerRects.height - 25}px`); + preview.style.setProperty("left", "0px"); + preview.style.setProperty("width", "520px"); + preview.style.setProperty("height", "25px"); + break; + case "maximize": + rects = BDFDB.DOMUtils.getRects(preview), outerRects = BDFDB.DOMUtils.getRects(document.body); + if (!(rects.x == 0 && rects.y == 0 && outerRects.width - rects.width == 0 && outerRects.height - rects.height == 0)) { + preview.rects = rects; + BDFDB.DOMUtils.addClass(preview, BDFDB.disCN._themerepopreviewfullscreen); + preview.style.setProperty("top", "0px"); + preview.style.setProperty("left", "0px"); + preview.style.setProperty("width", `${outerRects.width}px`); + preview.style.setProperty("height", `${outerRects.height}px`); + } + else { + BDFDB.DOMUtils.removeClass(preview, BDFDB.disCN._themerepopreviewfullscreen); + if (!preview.rects || (outerRects.width - preview.rects.width == 0 && outerRects.height - preview.rects.height == 0)) { + preview.style.setProperty("top", `${outerRects.width/4}px`); + preview.style.setProperty("left", `${outerRects.height/4}px`); + preview.style.setProperty("width", `${outerRects.width/2}px`); + preview.style.setProperty("height", `${outerRects.height/2}px`); + } + else { + preview.style.setProperty("top", `${preview.rects.x}px`); + preview.style.setProperty("left", `${preview.rects.y}px`); + preview.style.setProperty("width", `${preview.rects.width}px`); + preview.style.setProperty("height", `${preview.rects.height}px`); + } + } + break; + } + } + createThemeFile(name, filename, body, autoloadKey) { + return new Promise(callback => BDFDB.LibraryRequires.fs.writeFile(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getThemesFolder(), filename), body, error => { + if (error) { + callback(true); + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("save_fail", `Theme "${name}"`), {type: "danger"}); + } + else { + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("save_success", `Theme "${name}"`), {type: "success"}); + if (_this.settings.general[autoloadKey]) BDFDB.TimeUtils.timeout(_ => { + if (BDFDB.BDUtils.isThemeEnabled(name) == false) { + BDFDB.BDUtils.enableTheme(name, false); + BDFDB.LogUtils.log(BDFDB.LanguageUtils.LibraryStringsFormat("toast_plugin_started", name), _this); + } + }, 3000); + callback(); + } + })); + } + generateTheme(css) { + if (!css || !BDFDB.ObjectUtils.is(this.props.generatorValues)) return ""; + for (let inputId in this.props.generatorValues) if (this.props.generatorValues[inputId].value && this.props.generatorValues[inputId].value.trim() && this.props.generatorValues[inputId].value != this.props.generatorValues[inputId].oldValue) css = css.replace(new RegExp(`--${BDFDB.StringUtils.regEscape(inputId)}(\\s*):(\\s*)${BDFDB.StringUtils.regEscape(this.props.generatorValues[inputId].oldValue)}`,"g"),`--${inputId}$1: $2${this.props.generatorValues[inputId].value}`); + return css; + } + createFixerCSS(body) { + let oldCSS = body.replace(/\n/g, "\\n").replace(/\t/g, "\\t").replace(/\r/g, "\\r").split("REPLACE_CLASS_"); + let newCSS = oldCSS.shift(); + for (let str of oldCSS) { + let reg = /([A-z0-9_]+)(.*)/.exec(str); + newCSS += BDFDB.dotCN[reg[1]] + reg[2]; + } + return newCSS.replace(/\\n/g, "\n").replace(/\\t/g, "\t").replace(/\\r/g, "\r"); + } + render() { + let automaticLoading = BDFDB.BDUtils.getSettings(BDFDB.BDUtils.settingsIds.automaticLoading); + if (!this.props.tab) this.props.tab = "Themes"; + + this.props.entries = (!loading.is && grabbedThemes.length ? this.filterThemes() : []).map(theme => BDFDB.ReactUtils.createElement(RepoCardComponent, { + data: theme + })).filter(n => n); + + BDFDB.TimeUtils.timeout(_ => { + if (!loading.is && header && this.props.entries.length != header.props.amount) { + header.props.amount = this.props.entries.length; + BDFDB.ReactUtils.forceUpdate(header); + } + }); + + if (forceRerenderGenerator && this.props.tab == "Generator") BDFDB.TimeUtils.timeout(_ => { + forceRerenderGenerator = false; + BDFDB.ReactUtils.forceUpdate(this); + }); + + return [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: "Themes", + open: this.props.tab == "Themes", + render: false, + children: loading.is ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + direction: BDFDB.LibraryComponents.Flex.Direction.VERTICAL, + justify: BDFDB.LibraryComponents.Flex.Justify.CENTER, + style: {marginTop: "50%"}, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Spinner, { + type: BDFDB.LibraryComponents.Spinner.Type.WANDERING_CUBES + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextElement, { + className: BDFDB.disCN.margintop20, + style: {textAlign: "center"}, + children: `${BDFDB.LanguageUtils.LibraryStringsFormat("loading", "Theme Repo")} - ${BDFDB.LanguageUtils.LibraryStrings.please_wait}` + }) + ] + }) : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycards, + children: this.props.entries + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: "Generator", + open: this.props.tab == "Generator", + render: false, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Select", + margin: 20, + label: "Choose a Generator Theme", + basis: "60%", + value: this.props.currentGenerator || "-----", + options: [{value: "-----", label: "-----"}, nativeCSSvars && {value: "nativediscord", label: "Discord"}].concat(generatorThemes.map(t => ({value: t.id, label: t.name || "-----"})).sort((x, y) => (x.label < y.label ? -1 : x.label > y.label ? 1 : 0))).filter(n => n), + onChange: value => { + let generatorTheme = generatorThemes.find(t => t.id == value); + if (generatorTheme || value == "nativediscord") { + if (this.props.currentGenerator) forceRerenderGenerator = true; + this.props.currentGenerator = value; + this.props.currentGeneratorIsNative = value == "nativediscord"; + this.props.generatorValues = {}; + } + else { + delete this.props.currentGenerator; + delete this.props.currentGeneratorIsNative; + delete this.props.generatorValues; + } + delete this.props.currentTheme; + if (preview) this.runInPreview({ + reason: "NewTheme", + checked: true, + css: (generatorTheme || {}).fullCSS + }); + else this.openPreview(); + BDFDB.ReactUtils.forceUpdate(this); + } + }), + !this.props.currentGenerator ? null : (forceRerenderGenerator ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + direction: BDFDB.LibraryComponents.Flex.Direction.VERTICAL, + justify: BDFDB.LibraryComponents.Flex.Justify.CENTER, + style: {marginTop: "50%"}, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Spinner, { + type: BDFDB.LibraryComponents.Spinner.Type.WANDERING_CUBES + }) + }) : [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + className: BDFDB.disCN.marginbottom20, + type: "Button", + label: "Download generated Theme", + children: "Download", + onClick: _ => { + if (this.props.currentGeneratorIsNative) { + this.createThemeFile("Discord", "Discord.theme.css", `/**\n * @name Discord\n * @description Allow you to easily customize Discord's native Look \n * @author DevilBro\n * @version 1.0.0\n * @authorId 278543574059057154\n * @invite Jx3TjNS\n * @donate https://www.paypal.me/MircoWittrien\n * @patreon https://www.patreon.com/MircoWittrien\n */\n\n` + this.generateTheme(nativeCSSvars), "startDownloaded"); + } + else { + let generatorTheme = generatorThemes.find(t => t.id == this.props.currentGenerator); + if (generatorTheme) this.createThemeFile(generatorTheme.name, generatorTheme.name + ".theme.css", this.generateTheme(generatorTheme.fullCSS), "startDownloaded"); + } + } + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, { + className: BDFDB.disCN.marginbottom20 + }), + (_ => { + let generatorTheme = generatorThemes.find(t => t.id == this.props.currentGenerator); + let vars = this.props.currentGeneratorIsNative ? nativeCSSvars.split(".theme-dark, .theme-light") : ((generatorTheme || {}).fullCSS || "").split(":root"); + if (vars.length < 2) return null; + vars = vars[1].replace(/\t\(/g, " (").replace(/\r|\t| {2,}/g, "").replace(/\/\*\n*((?!\/\*|\*\/).|\n)*\n+((?!\/\*|\*\/).|\n)*\n*\*\//g, "").replace(/\n\/\*.*?\*\//g, "").replace(/\n/g, ""); + vars = vars.split("{"); + vars.shift(); + vars = vars.join("{").replace(/\s*(:|;|--|\*)\s*/g, "$1"); + vars = vars.split("}")[0]; + vars = (vars.endsWith(";") ? vars.slice(0, -1) : vars).slice(2).split(/;--|\*\/--/); + let inputRefs = []; + for (let varStr of vars) { + varStr = varStr.split(":"); + let varName = varStr.shift().trim(); + varStr = varStr.join(":").split(/;[^A-z0-9]|\/\*/); + let oldValue = varStr.shift().trim(); + if (oldValue) { + let childType = "text", childMode = ""; + let isColor = BDFDB.ColorUtils.getType(oldValue); + let isComp = !isColor && /^[0-9 ]+,[0-9 ]+,[0-9 ]+$/g.test(oldValue); + if (isColor || isComp) { + childType = "color"; + childMode = isComp && "comp"; + } + else { + let isUrlFile = /url\(.+\)/gi.test(oldValue); + let isFile = !isUrlFile && /(http(s)?):\/\/[(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test(oldValue); + if (isFile || isUrlFile) { + childType = "file"; + childMode = isUrlFile && "url"; + } + } + let varDescription = varStr.join("").replace(/\*\/|\/\*/g, "").replace(/:/g, ": ").replace(/: \//g, ":/").replace(/--/g, " --").replace(/\( --/g, "(--").trim(); + this.props.generatorValues[varName] = {value: oldValue, oldValue}; + inputRefs.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + dividerBottom: vars[vars.length-1] != varStr, + type: "TextInput", + childProps: { + type: childType, + mode: childMode, + filter: childType == "file" && "image" + }, + label: varName.split("-").map(BDFDB.LibraryModules.StringUtils.upperCaseFirstChar).join(" "), + note: varDescription && varDescription.indexOf("*") == 0 ? varDescription.slice(1) : varDescription, + basis: "70%", + value: oldValue, + placeholder: oldValue, + onChange: value => { + BDFDB.TimeUtils.clear(updateGeneratorTimeout); + updateGeneratorTimeout = BDFDB.TimeUtils.timeout(_ => { + this.props.generatorValues[varName] = {value, oldValue}; + if (preview) this.runInPreview({ + reason: "NewTheme", + checked: true, + css: this.generateTheme(this.props.currentGeneratorIsNative ? nativeCSSvars : (generatorTheme || {}).fullCSS) + }); + }, 1000); + } + })); + } + } + return inputRefs; + })() + ]) + ].flat(10).filter(n => n) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalTabContent, { + tab: BDFDB.LanguageUtils.LanguageStrings.SETTINGS, + open: this.props.tab == BDFDB.LanguageUtils.LanguageStrings.SETTINGS, + render: false, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { + title: "Show following Themes", + children: Object.keys(_this.defaults.filters).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + type: "Switch", + plugin: _this, + keys: ["filters", key], + label: _this.defaults.filters[key].description, + value: _this.settings.filters[key], + onChange: value => { + this.props[key] = _this.settings.filters[key] = value; + BDFDB.ReactUtils.forceUpdate(this); + } + })) + }), + Object.keys(_this.defaults.general).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, { + type: "Switch", + plugin: _this, + keys: ["general", key], + label: _this.defaults.general[key].description, + note: _this.defaults.general[key].autoload && !automaticLoading && "Automatic Loading has to be enabled", + disabled: _this.defaults.general[key].autoload && !automaticLoading, + value: _this.settings.general[key], + onChange: value => { + _this.settings.general[key] = value; + BDFDB.ReactUtils.forceUpdate(this); + } + })), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { + title: "Preview Settings", + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + label: "Use Light Mode", + value: this.props.useLightMode, + onChange: value => { + this.props.useLightMode = value; + if (preview) this.runInPreview({ + reason: "DarkLight", + checked: this.props.useLightMode + }); + } + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + label: "Include Custom CSS", + value: this.props.useCustomCSS, + onChange: value => { + this.props.useCustomCSS = value; + let customCSS = document.querySelector("style#customcss"); + if (preview && customCSS && customCSS.innerText.length > 0) this.runInPreview({ + reason: "CustomCSS", + checked: this.props.useCustomCSS, + css: customCSS.innerText + }); + } + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + margin: 20, + label: "Include ThemeFixer", + value: this.props.useThemeFixer, + onChange: value => { + this.props.useThemeFixer = value; + BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeFixer.css", (error, response, body) => { + if (preview) this.runInPreview({ + reason: "ThemeFixer", + checked: this.props.useThemeFixer, + css: this.createFixerCSS(body) + }); + }); + } + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Button", + margin: 20, + label: "Download ThemeFixer", + children: "Download", + onClick: _ => { + BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/ThemeFixer.css", (error, response, body) => { + this.createThemeFile("ThemeFixer", "ThemeFixer.theme.css", `/**\n * @name ThemeFixer\n * @description ThemeFixerCSS for transparent themes\n * @author DevilBro\n * @version 1.0.3\n * @authorId 278543574059057154\n * @invite Jx3TjNS\n * @donate https://www.paypal.me/MircoWittrien\n * @patreon https://www.patreon.com/MircoWittrien\n */\n\n` + this.createFixerCSS(body), "startDownloaded"); + }); + } + }), + !automaticLoading && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom20, + children: BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCNS.settingsrowtitle + BDFDB.disCNS.settingsrowtitledefault + BDFDB.disCN.cursordefault, + children: "To experience Theme Repo in the best way. I would recommend you to enable BD's intern Automatic-Loading Feature, that way all downloaded Files are loaded into Discord without the need to reload." + }) + }) + ].flat(10).filter(n => n) + }) + ]; + } + }; + + const RepoCardComponent = class ThemeCard extends BdApi.React.Component { + render() { + if (this.props.data.thumbnailUrl && !this.props.data.thumbnailChecked) { + if (!window.Buffer) this.props.data.thumbnailChecked = true; + else BDFDB.LibraryRequires.request(this.props.data.thumbnailUrl, {encoding: null}, (error, response, body) => { + if (response && response.headers["content-type"] && response.headers["content-type"] == "image/gif") { + const throwAwayImg = new Image(), instance = this; + throwAwayImg.onload = function() { + const canvas = document.createElement("canvas"); + canvas.getContext("2d").drawImage(throwAwayImg, 0, 0, canvas.width = this.width, canvas.height = this.height); + try { + const oldUrl = instance.props.data.thumbnailUrl; + instance.props.data.thumbnailUrl = canvas.toDataURL("image/png"); + instance.props.data.thumbnailGifUrl = oldUrl; + instance.props.data.thumbnailChecked = true; + BDFDB.ReactUtils.forceUpdate(instance); + } + catch (err) { + instance.props.data.thumbnailChecked = true; + BDFDB.ReactUtils.forceUpdate(instance); + } + }; + throwAwayImg.onerror = function() { + instance.props.data.thumbnailChecked = true; + BDFDB.ReactUtils.forceUpdate(instance); + }; + throwAwayImg.src = "data:" + response.headers["content-type"] + ";base64," + (new Buffer(body).toString("base64")); + } + else { + this.props.data.thumbnailChecked = true; + BDFDB.ReactUtils.forceUpdate(this); + } + }); + } + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycard, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardheader, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardcoverwrapper, + children: [ + this.props.data.thumbnailUrl && this.props.data.thumbnailChecked && BDFDB.ReactUtils.createElement("img", { + className: BDFDB.disCN.discoverycardcover, + src: this.props.data.thumbnailUrl, + loading: "lazy", + onMouseEnter: this.props.data.thumbnailGifUrl && (e => e.target.src = this.props.data.thumbnailGifUrl), + onMouseLeave: this.props.data.thumbnailGifUrl && (e => e.target.src = this.props.data.thumbnailUrl), + onClick: _ => { + const url = this.props.data.thumbnailGifUrl || this.props.data.thumbnailUrl; + console.log(this.props.data); + const img = document.createElement("img"); + img.addEventListener("load", function() { + BDFDB.LibraryModules.ModalUtils.openModal(modalData => { + return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ModalComponents.ModalRoot, Object.assign({ + className: BDFDB.disCN.imagemodal + }, modalData, { + size: BDFDB.LibraryComponents.ModalComponents.ModalSize.DYNAMIC, + "aria-label": BDFDB.LanguageUtils.LanguageStrings.IMAGE, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ImageModal, { + animated: false, + src: url, + original: url, + width: this.width, + height: this.height, + className: BDFDB.disCN.imagemodalimage, + shouldAnimate: true, + renderLinkComponent: props => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Anchor, props) + }) + }), true); + }); + }); + img.src = url; + } + }), + this.props.data.new && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.TextBadge, { + className: BDFDB.disCN.discoverycardcoverbadge, + style: { + borderRadius: 3, + textTransform: "uppercase", + background: BDFDB.DiscordConstants.Colors.STATUS_YELLOW + }, + text: BDFDB.LanguageUtils.LanguageStrings.NEW + }) + ] + }), + BDFDB.ReactUtils.createElement(class extends BDFDB.ReactUtils.Component { + render() { + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardiconwrapper, + children: this.props.data.author && this.props.data.author.discord_avatar_hash && this.props.data.author.discord_snowflake && !this.props.data.author.discord_avatar_failed ? BDFDB.ReactUtils.createElement("img", { + className: BDFDB.DOMUtils.formatClassName(BDFDB.disCN.discoverycardicon, !this.props.data.author.discord_avatar_loaded && BDFDB.disCN.discoverycardiconloading), + src: `https://cdn.discordapp.com/avatars/${this.props.data.author.discord_snowflake}/${this.props.data.author.discord_avatar_hash}.webp?size=128`, + loading: "lazy", + onLoad: _ => { + this.props.data.author.discord_avatar_loaded = true; + BDFDB.ReactUtils.forceUpdate(this); + }, + onError: _ => { + this.props.data.author.discord_avatar_failed = true; + BDFDB.ReactUtils.forceUpdate(this); + } + }) : BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardicon, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + nativeClass: true, + iconSVG: `` + }) + }) + }); + } + }, this.props) + ] + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardinfo, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardtitle, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardname, + children: this.props.data.name + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: BDFDB.LanguageUtils.LanguageStrings.FORM_LABEL_VIDEO_PREVIEW, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, { + className: BDFDB.disCN.discoverycardtitlebutton, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + nativeClass: true, + width: 16, + height: 16, + name: BDFDB.LibraryComponents.SvgIcon.Names.EYE + }) + }), + onClick: _ => { + if (!list) return; + + list.props.currentTheme = this.props.data; + delete list.props.currentGenerator; + delete list.props.generatorValues; + + if (preview) list.runInPreview({ + reason: "NewTheme", + checked: value, + css: this.props.data.css + }); + else list.openPreview(); + + BDFDB.ReactUtils.forceUpdate(this); + } + }), + this.props.data.latestSourceUrl && + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, { + text: BDFDB.LanguageUtils.LanguageStrings.SCREENSHARE_SOURCE, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Clickable, { + className: BDFDB.disCN.discoverycardtitlebutton, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + nativeClass: true, + width: 16, + height: 16, + name: BDFDB.LibraryComponents.SvgIcon.Names.GITHUB + }) + }), + onClick: _ => BDFDB.DiscordUtils.openLink(this.props.data.latestSourceUrl) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FavButton, { + className: BDFDB.disCN.discoverycardtitlebutton, + isFavorite: this.props.data.fav, + onClick: value => { + this.props.data.fav = value && 1; + if (value) favorites.push(this.props.data.id); + else BDFDB.ArrayUtils.remove(favorites, this.props.data.id, true); + BDFDB.DataUtils.save(BDFDB.ArrayUtils.numSort(favorites).join(" "), _this, "favorites"); + } + }) + ] + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardauthor, + children: `by ${this.props.data.authorname}` + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Scrollers.Thin, { + className: BDFDB.disCN.discoverycarddescription, + children: this.props.data.description + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardfooter, + children: [ + BDFDB.ArrayUtils.is(this.props.data.tags) && this.props.data.tags.length && BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardtags, + children: this.props.data.tags.map(tag => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Badges.TextBadge, { + className: BDFDB.disCN.discoverycardtag, + style: {background: "var(--background-accent)"}, + text: tag + })) + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardcontrols, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardstats, + children: [ + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardstat, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.discoverycardstaticon, + name: BDFDB.LibraryComponents.SvgIcon.Names.DOWNLOAD + }), + this.props.data.downloads + ] + }), + BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN.discoverycardstat, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.discoverycardstaticon, + name: BDFDB.LibraryComponents.SvgIcon.Names.HEART + }), + this.props.data.likes + ] + }) + ] + }), + BDFDB.ReactUtils.createElement(RepoCardDownloadButtonComponent, { + ...buttonData[(Object.entries(themeStates).find(n => n[1] == this.props.data.state) || [])[0]], + installed: this.props.data.state == themeStates.INSTALLED, + outdated: this.props.data.state == themeStates.OUTDATED, + onDownload: _ => { + if (!list || this.props.downloading) return; + this.props.downloading = true; + let loadingToast = BDFDB.NotificationUtils.toast(`${BDFDB.LanguageUtils.LibraryStringsFormat("loading", this.props.data.name)} - ${BDFDB.LanguageUtils.LibraryStrings.please_wait}`, {timeout: 0, ellipsis: true}); + let autoloadKey = this.props.data.state == themeStates ? "startUpdated" : "startDownloaded"; + BDFDB.LibraryRequires.request(this.props.data.rawSourceUrl, (error, response, body) => { + if (error) { + delete this.props.downloading; + loadingToast.close(); + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("download_fail", `Theme "${this.props.data.name}"`), {type: "danger"}); + } + else list.createThemeFile(this.props.data.name, this.props.data.rawSourceUrl.split("/").pop(), body, autoloadKey).then(error2 => { + delete this.props.downloading; + loadingToast.close(); + if (!error2) { + this.props.data.state = themeStates.INSTALLED; + BDFDB.ReactUtils.forceUpdate(this); + } + }); + }); + }, + onDelete: _ => { + if (this.props.deleting) return; + this.props.deleting = true; + BDFDB.LibraryRequires.fs.unlink(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getThemesFolder(), this.props.data.rawSourceUrl.split("/").pop()), error => { + delete this.props.deleting; + if (error) BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("delete_fail", `Theme "${this.props.data.name}"`), {type: "danger"}); + else { + BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LibraryStringsFormat("delete_success", `Theme "${this.props.data.name}"`)); + this.props.data.state = themeStates.DOWNLOADABLE; + BDFDB.ReactUtils.forceUpdate(this); + } + }); + } + }) + ] + }) + ] + }) + ] + }) + ] + }); + } + }; + + const RepoCardDownloadButtonComponent = class ThemeCardDownloadButton extends BdApi.React.Component { + render() { + const backgroundColor = this.props.doDelete ? buttonData.OUTDATED.backgroundColor : this.props.doUpdate ? buttonData.INSTALLED.backgroundColor : this.props.backgroundColor; + return BDFDB.ReactUtils.createElement("button", { + className: BDFDB.disCN.discoverycardbutton, + style: {backgroundColor: BDFDB.DiscordConstants.Colors[backgroundColor] || backgroundColor}, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { + className: BDFDB.disCN.discoverycardstaticon, + width: 16, + height: 16, + name: this.props.doDelete ? BDFDB.LibraryComponents.SvgIcon.Names.TRASH : this.props.doUpdate ? BDFDB.LibraryComponents.SvgIcon.Names.DOWNLOAD : BDFDB.LibraryComponents.SvgIcon.Names[this.props.icon] + }), + this.props.doDelete ? BDFDB.LanguageUtils.LanguageStrings.APPLICATION_CONTEXT_MENU_UNINSTALL : this.props.doUpdate ? BDFDB.LanguageUtils.LanguageStrings.GAME_ACTION_BUTTON_UPDATE : (BDFDB.LanguageUtils.LibraryStringsCheck[this.props.text] ? BDFDB.LanguageUtils.LibraryStrings[this.props.text] : BDFDB.LanguageUtils.LanguageStrings[this.props.text]) + ], + onClick: _ => { + if (this.props.doDelete) typeof this.props.onDelete == "function" && this.props.onDelete(); + else if (!this.props.installed) typeof this.props.onDownload == "function" && this.props.onDownload(); + }, + onMouseEnter: this.props.installed ? (_ => { + this.props.doDelete = true; + BDFDB.ReactUtils.forceUpdate(this); + }) : this.props.outdated ? (_ => { + this.props.doUpdate = true; + BDFDB.ReactUtils.forceUpdate(this); + }) : (_ => {}), + onMouseLeave: this.props.installed ? (_ => { + this.props.doDelete = false; + BDFDB.ReactUtils.forceUpdate(this); + }) : this.props.outdated ? (_ => { + this.props.doUpdate = false; + BDFDB.ReactUtils.forceUpdate(this); + }) : (_ => {}) + }); + } + }; + + const RepoListHeaderComponent = class ThemeListHeader extends BdApi.React.Component { + componentDidMount() { + header = this; + } + render() { + if (!this.props.tab) this.props.tab = "Themes"; + return BDFDB.ReactUtils.createElement("div", { + className: BDFDB.disCN._repolistheader, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCN.marginbottom4, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + grow: 1, + shrink: 0, + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormTitle, { + tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H2, + className: BDFDB.disCN.marginreset, + children: `Theme Repo — ${loading.is ? 0 : this.props.amount || 0}/${loading.is ? 0 : grabbedThemes.length}` + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SearchBar, { + autoFocus: true, + query: searchString, + onChange: (value, instance) => { + if (loading.is) return; + BDFDB.TimeUtils.clear(searchTimeout); + searchTimeout = BDFDB.TimeUtils.timeout(_ => { + searchString = value.replace(/[<|>]/g, ""); + BDFDB.ReactUtils.forceUpdate(this, list); + }, 1000); + }, + onClear: instance => { + if (loading.is) return; + searchString = ""; + BDFDB.ReactUtils.forceUpdate(this, list); + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, { + size: BDFDB.LibraryComponents.Button.Sizes.TINY, + children: BDFDB.LanguageUtils.LibraryStrings.check_for_updates, + onClick: _ => { + if (loading.is) return; + loading = {is: false, timeout: null, amount: 0}; + _this.loadThemes(); + } + }) + ] + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, { + className: BDFDB.disCNS.tabbarcontainer + BDFDB.disCN.tabbarcontainerbottom, + align: BDFDB.LibraryComponents.Flex.Align.CENTER, + children: [ + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TabBar, { + className: BDFDB.disCN.tabbar, + itemClassName: BDFDB.disCN.tabbaritem, + type: BDFDB.LibraryComponents.TabBar.Types.TOP, + selectedItem: this.props.tab, + items: [{value: "Themes"}, {value: "Generator"}, {value: BDFDB.LanguageUtils.LanguageStrings.SETTINGS}], + onItemSelect: value => { + this.props.tab = list.props.tab = value; + BDFDB.ReactUtils.forceUpdate(list); + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.QuickSelect, { + label: BDFDB.LanguageUtils.LibraryStrings.sort_by + ":", + value: { + label: sortKeys[this.props.sortKey], + value: this.props.sortKey + }, + options: Object.keys(sortKeys).map(key => ({ + label: sortKeys[key], + value: key + })), + onChange: key => { + this.props.sortKey = list.props.sortKey = key; + BDFDB.ReactUtils.forceUpdate(this, list); + } + }) + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, { + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.QuickSelect, { + label: BDFDB.LanguageUtils.LibraryStrings.order + ":", + value: { + label: BDFDB.LanguageUtils.LibraryStrings[orderKeys[this.props.orderKey]], + value: this.props.orderKey + }, + options: Object.keys(orderKeys).map(key => ({ + label: BDFDB.LanguageUtils.LibraryStrings[orderKeys[key]], + value: key + })), + onChange: key => { + this.props.orderKey = list.props.orderKey = key; + BDFDB.ReactUtils.forceUpdate(this, list); + } + }) + }) + ] + }) + ] + }); + } + }; + + return class ThemeRepo extends Plugin { + onLoad () { + _this = this; + + loading = {is: false, timeout: null, amount: 0}; + + cachedThemes = []; + grabbedThemes = []; + generatorThemes = []; + searchString = ""; + + this.defaults = { + general: { + notifyOutdated: {value: true, autoload: false, description: "Get a Notification when one of your Themes is outdated"}, + notifyNewEntries: {value: true, autoload: false, description: "Get a Notification when there are new Entries in the Repo"}, + startDownloaded: {value: false, autoload: true, description: "Start new Themes after Download"}, + startUpdated: {value: false, autoload: true, description: "Start updated Themes after Download"} + }, + filters: { + updated: {value: true, description: "Updated"}, + outdated: {value: true, description: "Outdated"}, + downloadable: {value: true, description: "Downloadable"}, + } + }; + + this.patchedModules = { + before: { + SettingsView: ["render", "componentWillUnmount"] + }, + after: { + StandardSidebarView: "render" + } + }; + + this.css = ` + ${BDFDB.dotCN._themerepopreview} { + border: 2px solid transparent; + box-shadow: var(--elevation-medium); + box-sizing: border-box; + position: absolute; + z-index: 10000000; + } + ${BDFDB.dotCN._themerepopreviewfullscreen} { + border: none; + } + ${BDFDB.dotCN._themerepomovebar} { + position: absolute; + height: 21px; + right: 100px; + left: 100px; + cursor: move; + z-index: 10000002; + } + ${BDFDB.dotCN._themerepodragbar} { + position: absolute; + z-index: 10000002; + } + ${BDFDB.dotCN._themerepodragcorner} { + position: absolute; + z-index: 10000003; + } + ${BDFDB.dotCN._themerepodragbar}#top { + top: -2px; + width: 100%; + height: 2px; + cursor: n-resize; + } + ${BDFDB.dotCN._themerepodragbar}#right { + right: -2px; + width: 2px; + height: 100%; + cursor: e-resize; + } + ${BDFDB.dotCN._themerepodragbar}#bottom { + bottom: -2px; + width: 100%; + height: 2px; + cursor: s-resize; + } + ${BDFDB.dotCN._themerepodragbar}#left { + left: -2px; + width: 2px; + height: 100%; + cursor: w-resize; + } + ${BDFDB.dotCN._themerepodragcorner} { + width: 4px; + height: 4px; + } + ${BDFDB.dotCN._themerepodragcorner}#top-left { + top: -2px; + left: -2px; + cursor: nw-resize; + } + ${BDFDB.dotCN._themerepodragcorner}#top-right { + top: -2px; + right: -2px; + cursor: ne-resize; + } + ${BDFDB.dotCN._themerepodragcorner}#bottom-right { + right: -2px; + bottom: -2px; + cursor: se-resize; + } + ${BDFDB.dotCN._themerepodragcorner}#bottom-left { + bottom: -2px; + left: -2px; + cursor: sw-resize; + } + ${BDFDB.dotCNS._themerepopreviewfullscreen + BDFDB.dotCN._themerepomovebar}, + ${BDFDB.dotCNS._themerepopreviewfullscreen + BDFDB.dotCN._themerepodraginterface} { + display: none; + } + ${BDFDB.dotCN._themerepopreview} iframe { + width: 100%; + height: 100%; + z-index: 10000001; + } + ${BDFDB.dotCN._themerepopreviewmoving} iframe { + pointer-events: none; + } + `; + } + + onStart () { + this.forceUpdateAll(); + + this.loadThemes(); + + updateInterval = BDFDB.TimeUtils.interval(_ => this.checkForNewThemes(), 1000*60*30); + } + + onStop () { + BDFDB.TimeUtils.clear(updateInterval); + BDFDB.TimeUtils.clear(loading.timeout); + + this.forceUpdateAll(); + + BDFDB.DOMUtils.remove(BDFDB.dotCN._themereponotice, BDFDB.dotCN._themerepoloadingicon); + } + + onSettingsClosed () { + if (this.SettingsUpdated) { + delete this.SettingsUpdated; + this.forceUpdateAll(); + } + } + + forceUpdateAll () { + favorites = BDFDB.DataUtils.load(this, "favorites"); + favorites = (typeof favorites == "string" ? favorites.split(" ") : []).map(n => parseInt(n)).filter(n => !isNaN(n)); + + BDFDB.PatchUtils.forceAllUpdates(this); + } + + onUserSettingsCogContextMenu (e) { + BDFDB.TimeUtils.timeout(_ => { + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["label", ["BandagedBD", "BetterDiscord"]]]}); + if (index > -1 && BDFDB.ArrayUtils.is(children[index].props.children)) children[index].props.children.push(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { + label: "Theme Repo", + id: BDFDB.ContextMenuUtils.createItemId(this.name, "repo"), + action: _ => { + BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); + } + })); + }); + } + + processSettingsView (e) { + if (e.node) searchString = ""; + else { + if (!BDFDB.PatchUtils.isPatched(this, e.component, "getPredicateSections")) BDFDB.PatchUtils.patch(this, e.component, "getPredicateSections", {after: e2 => { + if (BDFDB.ArrayUtils.is(e2.returnValue) && e2.returnValue.findIndex(n => n.section && (n.section.toLowerCase() == "changelog" || n.section == BDFDB.DiscordConstants.UserSettingsSections.CHANGE_LOG || n.section.toLowerCase() == "logout" || n.section == BDFDB.DiscordConstants.UserSettingsSections.LOGOUT))) { + e2.returnValue = e2.returnValue.filter(n => n.section != "themerepo"); + let index = e2.returnValue.indexOf(e2.returnValue.find(n => n.section == "pluginrepo") || e2.returnValue.find(n => n.section == "themes") || e2.returnValue.find(n => n.section == BDFDB.DiscordConstants.UserSettingsSections.DEVELOPER_OPTIONS) || e2.returnValue.find(n => n.section == BDFDB.DiscordConstants.UserSettingsSections.HYPESQUAD_ONLINE)); + if (index > -1) { + e2.returnValue.splice(index + 1, 0, { + section: "themerepo", + label: "Theme Repo", + element: _ => { + let options = Object.assign({}, this.settings.filters); + options.updated = options.updated && !showOnlyOutdated; + options.outdated = options.outdated || showOnlyOutdated; + options.downloadable = options.downloadable && !showOnlyOutdated; + options.sortKey = forcedSort || Object.keys(sortKeys)[0]; + options.orderKey = forcedOrder || Object.keys(orderKeys)[0]; + options.useLightMode = BDFDB.DiscordUtils.getTheme() == BDFDB.disCN.themelight; + options.useThemeFixer = false; + options.useCustomCSS = false; + + return BDFDB.ReactUtils.createElement(RepoListComponent, options); + } + }); + if (!e2.returnValue.find(n => n.section == "plugins" || n.section == "pluginrepo")) e2.returnValue.splice(index + 1, 0, {section: "DIVIDER"}); + } + } + }}); + } + } + + processStandardSidebarView (e) { + if (e.instance.props.section == "themerepo") { + let content = BDFDB.ReactUtils.findChild(e.returnvalue, {props: [["className", BDFDB.disCN.settingswindowcontentregion]]}); + if (content) content.props.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repolistwrapper, content.props.className); + let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {props: [["className", BDFDB.disCN.settingswindowcontentregionscroller]]}); + if (index > -1) { + let options = {}; + options.sortKey = forcedSort || Object.keys(sortKeys)[0]; + options.orderKey = forcedOrder || Object.keys(orderKeys)[0]; + children[index] = [ + BDFDB.ReactUtils.createElement(RepoListHeaderComponent, options), + children[index] + ]; + } + } + } + + generateTheme (fullCSS, generatorValues) { + if (!fullCSS || !BDFDB.ObjectUtils.is(generatorValues)) return ""; + for (let inputId in generatorValues) if (generatorValues[inputId].value && generatorValues[inputId].value.trim() && generatorValues[inputId].value != generatorValues[inputId].oldValue) fullCSS = fullCSS.replace(new RegExp(`--${BDFDB.StringUtils.regEscape(inputId)}(\\s*):(\\s*)${BDFDB.StringUtils.regEscape(generatorValues[inputId].oldValue)}`,"g"),`--${inputId}$1: $2${generatorValues[inputId].value}`); + return fullCSS; + } + + loadThemes () { + BDFDB.DOMUtils.remove(BDFDB.dotCN._themerepoloadingicon); + cachedThemes = BDFDB.DataUtils.load(this, "cached"); + cachedThemes = (typeof cachedThemes == "string" ? cachedThemes.split(" ") : []).map(n => parseInt(n)).filter(n => !isNaN(n)); + + let loadingIcon; + let newEntries = 0, outdatedEntries = 0, checkIndex = 0, checksRunning = 0, callbackCalled = false; + + const checkTheme = _ => { + if (checksRunning > 20) return; + else if (grabbedThemes.every(t => t.loaded || (!t.latestSourceUrl && !t.latest_source_url)) || !this.started || !loading.is) { + if (!callbackCalled) { + callbackCalled = true; + if (!this.started) return BDFDB.TimeUtils.clear(loading.timeout); + BDFDB.TimeUtils.clear(loading.timeout); + BDFDB.DOMUtils.remove(loadingIcon, BDFDB.dotCN._themerepoloadingicon); + loading = {is: false, timeout: null, amount: loading.amount}; + + BDFDB.LogUtils.log("Finished fetching Themes", this); + BDFDB.ReactUtils.forceUpdate(list); + + if (this.settings.general.notifyOutdated && outdatedEntries > 0) { + let notice = document.querySelector(BDFDB.dotCN._themerepooutdatednotice); + if (notice) notice.close(); + BDFDB.NotificationUtils.notice(this.labels.notice_outdated_themes.replace("{{var0}}", outdatedEntries), { + type: "danger", + className: BDFDB.disCNS._themereponotice + BDFDB.disCN._themerepooutdatednotice, + customIcon: themeRepoIcon.replace(/COLOR_[0-9]+/gi, "currentColor"), + buttons: [{ + contents: BDFDB.LanguageUtils.LanguageStrings.OPEN, + close: true, + onClick: _ => { + showOnlyOutdated = true; + BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); + } + }] + }); + } + + if (this.settings.general.notifyNewEntries && newEntries > 0) { + let notice = document.querySelector(BDFDB.dotCN._themereponewentriesnotice); + if (notice) notice.close(); + BDFDB.NotificationUtils.notice(this.labels.notice_new_themes.replace("{{var0}}", newEntries), { + type: "success", + className: BDFDB.disCNS._themereponotice + BDFDB.disCN._themereponewentriesnotice, + customIcon: themeRepoIcon.replace(/COLOR_[0-9]+/gi, "currentColor"), + buttons: [{ + contents: BDFDB.LanguageUtils.LanguageStrings.OPEN, + close: true, + onClick: _ => { + forcedSort = "RELEASEDATE"; + forcedOrder = "ASC"; + BDFDB.LibraryModules.UserSettingsUtils.open("themerepo"); + } + }] + }); + } + + BDFDB.LibraryRequires.request("https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeRepo/_res/GeneratorList.txt", (error, response, body) => { + if (!error && body) for (let id of body.replace(/[\r\t]/g, "").split(" ").map(n => parseInt(n)).filter(n => n != null)) { + let theme = grabbedThemes.find(t => t.id == id); + if (theme) generatorThemes.push(theme); + } + }); + + BDFDB.LibraryRequires.request(document.querySelector("head link[rel='stylesheet'][integrity]").href, (error, response, body) => { + if (!error && body) { + nativeCSS = body; + let theme = BDFDB.DiscordUtils.getTheme(); + let vars = (nativeCSS.split(`.${theme}{`)[1] || "").split("}")[0]; + nativeCSSvars = vars ? `.theme-dark, .theme-light {${vars}}` : ""; + } + else nativeCSS = nativeCSSvars = ""; + }); + } + return; + } + else if (checkIndex > grabbedThemes.length) return; + + const theme = grabbedThemes[checkIndex++]; + if (!theme || (!theme.latestSourceUrl && !theme.latest_source_url)) checkTheme(); + else { + checksRunning++; + theme.releasedate = new Date(theme.releaseDate || theme.release_date || 0).getTime(); + theme.latestSourceUrl = theme.latestSourceUrl || theme.latest_source_url; + theme.rawSourceUrl = theme.latestSourceUrl.replace("https://github.com/", "https://raw.githubusercontent.com/").replace(/\/blob\/(.{32,})/i, "/$1"); + theme.thumbnailUrl = theme.thumbnailUrl || theme.thumbnail_url; + theme.thumbnailUrl = theme.thumbnailUrl ? (theme.thumbnailUrl.startsWith("https://") ? theme.thumbnailUrl : `https://betterdiscord.app${theme.thumbnailUrl}`) : ""; + delete theme.release_date; + delete theme.latest_source_url; + delete theme.thumbnail_url; + BDFDB.LibraryRequires.request(theme.rawSourceUrl, (error, response, body) => { + if (body && body.indexOf("404: Not Found") != 0 && response.statusCode == 200) { + theme.name = BDFDB.LibraryModules.StringUtils.upperCaseFirstChar((/@name\s+([^\t^\r^\n]+)|\/\/\**META.*["']name["']\s*:\s*["'](.+?)["']/i.exec(body) || []).filter(n => n)[1] || theme.name || ""); + theme.authorname = (/@author\s+(.+)|\/\/\**META.*["']author["']\s*:\s*["'](.+?)["']/i.exec(body) || []).filter(n => n)[1] || theme.author.display_name || theme.author; + const version = (/@version\s+(.+)|\/\/\**META.*["']version["']\s*:\s*["'](.+?)["']/i.exec(body) || []).filter(n => n)[1]; + if (version) theme.version = version; + if (theme.version) { + const installedTheme = this.getInstalledTheme(theme); + if (installedTheme && this.compareVersions(version, this.getString(installedTheme.version))) outdatedEntries++; + } + let text = body.trim(); + let hasMETAline = text.replace(/\s/g, "").indexOf("//META{"), newMeta = ""; + if (hasMETAline < 20 && hasMETAline > -1) { + let i = 0, j = 0, metaString = ""; + try { + for (let c of `{${text.split("{").slice(1).join("{")}`) { + metaString += c; + if (c == "{") i++; + else if (c == "}") j++; + if (i > 0 && i == j) break; + } + let metaObj = JSON.parse(metaString); + newMeta = "/**\n"; + for (let key in metaObj) newMeta += ` * @${key} ${metaObj[key]}\n`; + newMeta += "*/"; + } + catch (err) {newMeta = "";} + } + theme.fullCSS = [newMeta, newMeta ? text.split("\n").slice(1).join("\n") : text].filter(n => n).join("\n"); + theme.css = (hasMETAline < 20 && hasMETAline > -1 ? text.split("\n").slice(1).join("\n") : text).replace(/[\r|\n|\t]/g, ""); + } + if (!cachedThemes.includes(theme.id)) newEntries++; + + theme.loaded = true; + + let loadingTooltip = document.querySelector(BDFDB.dotCN._themerepoloadingtooltip); + if (loadingTooltip) loadingTooltip.update(this.getLoadingTooltipText()); + + checksRunning--; + checkTheme(); + }); + } + }; + + BDFDB.LibraryRequires.request("https://api.betterdiscord.app/v1/store/themes", (error, response, body) => { + if (!error && body && response.statusCode == 200) try { + grabbedThemes = BDFDB.ArrayUtils.keySort(JSON.parse(body).filter(n => n), "name"); + + BDFDB.DataUtils.save(BDFDB.ArrayUtils.numSort(grabbedThemes.map(n => n.id)).join(" "), this, "cached"); + + loading = {is: true, timeout: BDFDB.TimeUtils.timeout(_ => { + BDFDB.TimeUtils.clear(loading.timeout); + if (this.started) { + if (loading.is && loading.amount < 4) BDFDB.TimeUtils.timeout(_ => this.loadThemes(), 10000); + loading = {is: false, timeout: null, amount: loading.amount}; + } + }, 1200000), amount: loading.amount + 1}; + + loadingIcon = BDFDB.DOMUtils.create(themeRepoIcon.replace(/COLOR_1/gi, "var(--bdfdb-blurple)").replace(/COLOR_2/gi, "#72767d")); + BDFDB.DOMUtils.addClass(loadingIcon, BDFDB.disCN._themerepoloadingicon); + loadingIcon.addEventListener("mouseenter", _ => { + BDFDB.TooltipUtils.create(loadingIcon, this.getLoadingTooltipText(), { + type: "left", + className: BDFDB.disCN._themerepoloadingtooltip, + delay: 500, + style: "max-width: unset;" + }); + }); + BDFDB.PluginUtils.addLoadingIcon(loadingIcon); + + BDFDB.ReactUtils.forceUpdate(list, header); + + for (let i = 0; i <= 20; i++) checkTheme(); + } + catch (err) {BDFDB.NotificationUtils.toast("Failed to load Theme Store", {type: "danger"});} + if (response && response.statusCode == 403) BDFDB.NotificationUtils.toast("Failed to fetch Theme Store from the Website Api due to DDoS Protection", {type: "danger"}); + else if (response && response.statusCode == 404) BDFDB.NotificationUtils.toast("Failed to fetch Theme Store from the Website Api due to Connection Issue", {type: "danger"}); + }); + } + + getLoadingTooltipText () { + return BDFDB.LanguageUtils.LibraryStringsFormat("loading", `Theme Repo - [${grabbedThemes.filter(n => n.loaded).length}/${grabbedThemes.length}]`); + } + + getString (obj) { + let string = ""; + if (typeof obj == "string") string = obj; + else if (obj && obj.props) { + if (typeof obj.props.children == "string") string = obj.props.children; + else if (Array.isArray(obj.props.children)) for (let c of obj.props.children) string += typeof c == "string" ? c : this.getString(c); + } + return string; + } + + compareVersions (v1, v2) { + return !(v1 == v2 || !BDFDB.NumberUtils.compareVersions(v1, v2)); + } + + getInstalledTheme (theme) { + if (!theme || typeof theme.authorname != "string") return; + const iTheme = BDFDB.BDUtils.getTheme(theme.name, false, true); + if (iTheme && theme.authorname.toUpperCase() == this.getString(iTheme.author).toUpperCase()) return iTheme; + else if (theme.rawSourceUrl && window.BdApi && BdApi.Themes && typeof BdApi.Themes.getAll == "function") { + const filename = theme.rawSourceUrl.split("/").pop(); + for (let t of BdApi.Themes.getAll()) if (t.filename == filename && theme.authorname.toUpperCase() == this.getString(t.author).toUpperCase()) return t; + } + } + + checkForNewThemes () { + BDFDB.LibraryRequires.request("https://api.betterdiscord.app/v1/store/themes", (error, response, body) => { + if (!error && body) try { + if (JSON.parse(body).filter(n => n).length != grabbedThemes.length) { + loading = {is: false, timeout: null, amount: 0}; + this.loadThemes(); + } + } + catch (err) {BDFDB.NotificationUtils.toast("Failed to load Theme Store", {type: "danger"});} + }); + } + + setLabelsByLanguage () { + switch (BDFDB.LanguageUtils.getLanguage().id) { + case "bg": // Bulgarian + return { + list: "Списък", + notice_failed_themes: "Някои Themes [{{var0}}] не можаха да бъдат заредени", + notice_new_themes: "Новите Themes [{{var0}}] бяха добавени към Theme Repo", + notice_outdated_themes: "Някои Themes [{{var0}}] са остарели" + }; + case "da": // Danish + return { + list: "Liste", + notice_failed_themes: "Nogle Themes [{{var0}}] kunne ikke indlæses", + notice_new_themes: "Nye Themes [{{var0}}] er blevet føjet til Theme Repo", + notice_outdated_themes: "Nogle Themes [{{var0}}] er forældede" + }; + case "de": // German + return { + list: "Liste", + notice_failed_themes: "Einige Themes [{{var0}}] konnten nicht geladen werden", + notice_new_themes: "Neue Themes [{{var0}}] wurden zur Theme Repo hinzugefügt", + notice_outdated_themes: "Einige Themes [{{var0}}] sind veraltet" + }; + case "el": // Greek + return { + list: "Λίστα", + notice_failed_themes: "Δεν ήταν δυνατή η φόρτωση ορισμένων Themes [{{var0}}] ", + notice_new_themes: "Προστέθηκαν νέα Themes [{{var0}}] στο Theme Repo", + notice_outdated_themes: "Ορισμένα Themes [{{var0}}] είναι παλιά" + }; + case "es": // Spanish + return { + list: "Lista", + notice_failed_themes: "Algunos Themes [{{var0}}] no se pudieron cargar", + notice_new_themes: "Se han agregado nuevos Themes [{{var0}}] a Theme Repo", + notice_outdated_themes: "Algunas Themes [{{var0}}] están desactualizadas" + }; + case "fi": // Finnish + return { + list: "Lista", + notice_failed_themes: "Joitain kohdetta Themes [{{var0}}] ei voitu ladata", + notice_new_themes: "Uusi Themes [{{var0}}] on lisätty Theme Repo", + notice_outdated_themes: "Jotkut Themes [{{var0}}] ovat vanhentuneita" + }; + case "fr": // French + return { + list: "Liste", + notice_failed_themes: "Certains Themes [{{var0}}] n'ont pas pu être chargés", + notice_new_themes: "De nouveaux Themes [{{var0}}] ont été ajoutés à Theme Repo", + notice_outdated_themes: "Certains Themes [{{var0}}] sont obsolètes" + }; + case "hr": // Croatian + return { + list: "Popis", + notice_failed_themes: "Neke datoteke Themes [{{var0}}] nije moguće učitati", + notice_new_themes: "Novi Themes [{{var0}}] dodani su u Theme Repo", + notice_outdated_themes: "Neki su Themes [{{var0}}] zastarjeli" + }; + case "hu": // Hungarian + return { + list: "Lista", + notice_failed_themes: "Néhány Themes [{{var0}}] nem sikerült betölteni", + notice_new_themes: "Új Themes [{{var0}}] hozzáadva a következőhöz: Theme Repo", + notice_outdated_themes: "Néhány Themes [{{var0}}] elavult" + }; + case "it": // Italian + return { + list: "Elenco", + notice_failed_themes: "Impossibile caricare alcuni Themes [{{var0}}] ", + notice_new_themes: "Il nuovo Themes [{{var0}}] è stato aggiunto a Theme Repo", + notice_outdated_themes: "Alcuni Themes [{{var0}}] non sono aggiornati" + }; + case "ja": // Japanese + return { + list: "リスト", + notice_failed_themes: "一部の Themes [{{var0}}] を読み込めませんでした", + notice_new_themes: "新しい Themes [{{var0}}] が Theme Repo に追加されました", + notice_outdated_themes: "一部の Themes [{{var0}}] は古くなっています" + }; + case "ko": // Korean + return { + list: "명부", + notice_failed_themes: "일부 Themes [{{var0}}] 을 (를)로드 할 수 없습니다.", + notice_new_themes: "새 Themes [{{var0}}] 이 Theme Repo 에 추가되었습니다.", + notice_outdated_themes: "일부 Themes [{{var0}}] 이 오래되었습니다." + }; + case "lt": // Lithuanian + return { + list: "Sąrašas", + notice_failed_themes: "Kai kurių Themes [{{var0}}] nepavyko įkelti", + notice_new_themes: "Naujas Themes [{{var0}}] pridėtas prie Theme Repo", + notice_outdated_themes: "Kai kurie Themes [{{var0}}] yra pasenę" + }; + case "nl": // Dutch + return { + list: "Lijst", + notice_failed_themes: "Sommige Themes [{{var0}}] konden niet worden geladen", + notice_new_themes: "Nieuwe Themes [{{var0}}] zijn toegevoegd aan de Theme Repo", + notice_outdated_themes: "Sommige Themes [{{var0}}] zijn verouderd" + }; + case "no": // Norwegian + return { + list: "Liste", + notice_failed_themes: "Noen Themes [{{var0}}] kunne ikke lastes inn", + notice_new_themes: "Nye Themes [{{var0}}] er lagt til i Theme Repo", + notice_outdated_themes: "Noen Themes [{{var0}}] er utdaterte" + }; + case "pl": // Polish + return { + list: "Lista", + notice_failed_themes: "Nie można załadować niektórych Themes [{{var0}}] ", + notice_new_themes: "Nowe Themes [{{var0}}] zostały dodane do Theme Repo", + notice_outdated_themes: "Niektóre Themes [{{var0}}] są nieaktualne" + }; + case "pt-BR": // Portuguese (Brazil) + return { + list: "Lista", + notice_failed_themes: "Algum Themes [{{var0}}] não pôde ser carregado", + notice_new_themes: "Novo Themes [{{var0}}] foi adicionado ao Theme Repo", + notice_outdated_themes: "Alguns Themes [{{var0}}] estão desatualizados" + }; + case "ro": // Romanian + return { + list: "Listă", + notice_failed_themes: "Unele Themes [{{var0}}] nu au putut fi încărcate", + notice_new_themes: "Themes [{{var0}}] nou au fost adăugate la Theme Repo", + notice_outdated_themes: "Unele Themes [{{var0}}] sunt învechite" + }; + case "ru": // Russian + return { + list: "Список", + notice_failed_themes: "Не удалось загрузить некоторые Themes [{{var0}}] ", + notice_new_themes: "Новые Themes [{{var0}}] добавлены в Theme Repo", + notice_outdated_themes: "Некоторые Themes [{{var0}}] устарели" + }; + case "sv": // Swedish + return { + list: "Lista", + notice_failed_themes: "Vissa Themes [{{var0}}] kunde inte laddas", + notice_new_themes: "Nya Themes [{{var0}}] har lagts till i Theme Repo", + notice_outdated_themes: "Vissa Themes [{{var0}}] är föråldrade" + }; + case "th": // Thai + return { + list: "รายการ", + notice_failed_themes: "ไม่สามารถโหลด Themes [{{var0}}] บางรายการได้", + notice_new_themes: "เพิ่ม Themes [{{var0}}] ใหม่ใน Theme Repo แล้ว", + notice_outdated_themes: "Themes [{{var0}}] บางรายการล้าสมัย" + }; + case "tr": // Turkish + return { + list: "Liste", + notice_failed_themes: "Bazı Themes [{{var0}}] yüklenemedi", + notice_new_themes: "Yeni Themes [{{var0}}], Theme Repo 'ye eklendi", + notice_outdated_themes: "Bazı Themes [{{var0}}] güncel değil" + }; + case "uk": // Ukrainian + return { + list: "Список", + notice_failed_themes: "Деякі Themes [{{var0}}] не вдалося завантажити", + notice_new_themes: "Нові Themes [{{var0}}] були додані до Theme Repo", + notice_outdated_themes: "Деякі Themes [{{var0}}] застарілі" + }; + case "vi": // Vietnamese + return { + list: "Danh sách", + notice_failed_themes: "Không thể tải một số Themes [{{var0}}] ", + notice_new_themes: "Themes [{{var0}}] mới đã được thêm vào Theme Repo", + notice_outdated_themes: "Một số Themes [{{var0}}] đã lỗi thời" + }; + case "zh-CN": // Chinese (China) + return { + list: "清单", + notice_failed_themes: "某些 Themes [{{var0}}] 无法加载", + notice_new_themes: "新的 Themes [{{var0}}] 已添加到 Theme Repo", + notice_outdated_themes: "一些 Themes [{{var0}}] 已过时" + }; + case "zh-TW": // Chinese (Taiwan) + return { + list: "清單", + notice_failed_themes: "某些 Themes [{{var0}}] 無法加載", + notice_new_themes: "新的 Themes [{{var0}}] 已添加到 Theme Repo", + notice_outdated_themes: "一些 Themes [{{var0}}] 已過時" + }; + default: // English + return { + list: "List", + notice_failed_themes: "Some Themes [{{var0}}] could not be loaded", + notice_new_themes: "New Themes [{{var0}}] have been added to the Theme Repo", + notice_outdated_themes: "Some Themes [{{var0}}] are outdated" + }; + } + } + }; + })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); +})(); diff --git a/oldconfig/BetterDiscord/plugins/ThemeSettings.plugin.js b/oldconfig/BetterDiscord/plugins/ThemeSettings.plugin.js new file mode 100644 index 0000000..a57a02c --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ThemeSettings.plugin.js @@ -0,0 +1,268 @@ +/** + * @name ThemeSettings + * @author DevilBro + * @authorId 278543574059057154 + * @version 1.3.4 + * @description Allows you to change Theme Variables within Discord. Adds a Settings button (similar to Plugins) to customizable Themes in your Themes Page + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/ThemeSettings/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/ThemeSettings/ThemeSettings.plugin.js + */ + +module.exports = (_ => { + const config = { + "info": { + "name": "ThemeSettings", + "author": "DevilBro", + "version": "1.3.4", + "description": "Allows you to change Theme Variables within Discord. Adds a Settings button (similar to Plugins) to customizable Themes in your Themes Page" + } + }; + + return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + getName () {return config.info.name;} + getAuthor () {return config.info.author;} + getVersion () {return config.info.version;} + getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;} + + downloadLibrary () { + require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { + if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"})); + else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library"); + }); + } + + load () { + if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []}); + if (!window.BDFDB_Global.downloadModal) { + window.BDFDB_Global.downloadModal = true; + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, + onConfirm: _ => { + delete window.BDFDB_Global.downloadModal; + this.downloadLibrary(); + } + }); + } + if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + } + start () {this.load();} + stop () {} + getSettingsPanel () { + let template = document.createElement("template"); + template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); + return template.content.firstElementChild; + } + } : (([Plugin, BDFDB]) => { + var dir; + + return class ThemeSettings extends Plugin { + onLoad () { + dir = BDFDB.BDUtils.getThemesFolder(); + + this.patchedModules = { + after: { + SettingsView: "componentDidMount" + } + }; + } + + onStart () { + for (let settingsView of document.querySelectorAll(BDFDB.dotCN.layer + BDFDB.dotCN.settingswindowstandardsidebarview)) this.addListObserver(BDFDB.DOMUtils.getParent(BDFDB.dotCN.layer, settingsView)); + BDFDB.ReactUtils.forceUpdate(this); + } + + onStop () { + BDFDB.DOMUtils.remove(BDFDB.dotCN._themesettingsbutton); + } + + processSettingsView (e) { + this.addListObserver(BDFDB.DOMUtils.getParent(BDFDB.dotCN.layer, e.node)); + } + + addListObserver (layer) { + if (!layer) return; + BDFDB.ObserverUtils.connect(this, layer, {name: "cardObserver", instance: new MutationObserver(changes => changes.forEach(change => change.addedNodes.forEach(node => { + if (BDFDB.DOMUtils.containsClass(node, BDFDB.disCN._repocard)) this.appendSettingsButton(node); + if (node.nodeType != Node.TEXT_NODE) for (let child of node.querySelectorAll(BDFDB.dotCN._repocard)) this.appendSettingsButton(child); + })))}, {childList: true, subtree: true}); + for (let child of layer.querySelectorAll(BDFDB.dotCN._repocard)) this.appendSettingsButton(child); + + } + + appendSettingsButton (card) { + if (card.querySelector(BDFDB.dotCN._themesettingsbutton)) return; + let addon = BDFDB.ObjectUtils.get(BDFDB.ReactUtils.getInstance(card), "return.stateNode.props.addon"); + if (addon && !addon.plugin && !addon.instance && addon.css) { + let css = addon.css.replace(/\r/g, ""); + let imports = css.split("\n@import url(").splice(1).map(n => [n.split(");")[0], true]).concat(css.split("\n/* @import url(").splice(1).map(n => [n.split("); */")[0], false])); + let vars = css.split(":root"); + if (vars.length > 1) { + vars = vars[1].replace(/\t\(/g, " (").replace(/\t| {2,}/g, "").replace(/\/\*\n*((?!\/\*|\*\/).|\n)*\n+((?!\/\*|\*\/).|\n)*\n*\*\//g, "").replace(/\n\/\*.*?\*\//g, "").replace(/\n/g, ""); + vars = vars.split("{"); + vars.shift(); + vars = vars.join("{").replace(/\s*(:|;|--|\*)\s*/g, "$1"); + vars = vars.split("}")[0]; + vars = (vars.endsWith(";") ? vars.slice(0, -1) : vars).slice(2).split(/;--|\*\/--/); + } + else vars = []; + + if (imports.length || vars.length) { + let footerControls = card.querySelector(BDFDB.dotCNS._repofooter + BDFDB.dotCN._repocontrols); + let settingsButton = document.createElement("button"); + settingsButton.className = BDFDB.DOMUtils.formatClassName(BDFDB.disCN._repobutton, BDFDB.disCN._repocontrolsbutton, BDFDB.disCN._themesettingsbutton); + settingsButton.appendChild(BDFDB.DOMUtils.create(``)); + footerControls.insertBefore(settingsButton, footerControls.firstElementChild); + settingsButton.addEventListener("click", _ => { + let importInstances = {}, inputInstances = {}; + BDFDB.ModalUtils.open(this, { + header: `${addon.name} ${BDFDB.LanguageUtils.LanguageStrings.SETTINGS}`, + subHeader: "", + className: BDFDB.disCN._repomodal, + headerClassName: BDFDB.disCN._repomodalheader, + contentClassName: BDFDB.disCN._repomodalsettings, + footerClassName: BDFDB.disCN._repomodalfooter, + size: "MEDIUM", + children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanel, { + addon: addon, + children: _ => { + let settingsItems = []; + + let varInputs = []; + for (let i in vars) { + let varStr = vars[i].split(":"); + let varName = varStr.shift().trim(); + varStr = varStr.join(":").split(/;[^A-z0-9]|\/\*/); + let varValue = varStr.shift().trim(); + if (varValue) { + let childType = "text", childMode = ""; + let isColor = BDFDB.ColorUtils.getType(varValue); + let isComp = !isColor && /^[0-9 ]+,[0-9 ]+,[0-9 ]+$/g.test(varValue); + if (isColor || isComp) { + childType = "color"; + childMode = isComp && "comp"; + } + else { + let isUrlFile = /url\(.+\)/gi.test(varValue); + let isFile = !isUrlFile && /(http(s)?):\/\/[(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test(varValue); + if (isFile || isUrlFile) { + childType = "file"; + childMode = isUrlFile && "url"; + } + } + let varDescription = varStr.join("").replace(/\*\/|\/\*/g, "").replace(/:/g, ": ").replace(/: \//g, ":/").replace(/--/g, " --").replace(/\( --/g, "(--").trim(); + varInputs.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "TextInput", + margin: 8, + childProps: { + type: childType, + mode: childMode, + filter: childType == "file" && "image", + ref: instance => {if (instance) inputInstances[i] = instance;} + }, + label: varName.split("-").map(BDFDB.LibraryModules.StringUtils.upperCaseFirstChar).join(" "), + note: varDescription && varDescription.indexOf("*") == 0 ? varDescription.slice(1) : varDescription, + basis: "70%", + name: varName, + value: varValue, + oldValue: varValue, + defaultValue: varValue, + placeholder: varValue + })); + } + }; + + if (imports.length) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { + title: "Imports:", + dividerBottom: varInputs.length, + children: imports.map((impo, i) => { + let name = impo[0].split("/").pop().replace(/"/g, ""); + return BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, { + type: "Switch", + margin: 8, + childProps: {ref: instance => {if (instance) importInstances[i] = instance;}}, + label: name[0].toUpperCase() + name.slice(1), + note: impo[0].replace(/"/g, ""), + name: impo[0], + value: impo[1], + oldValue: impo[1].toString(), + defaultValue: impo[1].toString() + }); + }) + })); + if (varInputs.length) settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, { + title: "Variables:", + children: varInputs + })); + + return settingsItems; + } + }), + buttons: [{ + contents: BDFDB.LanguageUtils.LanguageStrings.SAVE, + color: "BRAND", + onClick: _ => this.updateTheme(addon, {imports: importInstances, inputs: inputInstances}, false) + }, { + contents: BDFDB.LanguageUtils.LanguageStrings.RESET, + look: "LINK", + onClick: _ => this.updateTheme(addon, {imports: importInstances, inputs: inputInstances}, true) + }] + }); + }); + settingsButton.addEventListener("mouseenter", _ => { + BDFDB.TooltipUtils.create(settingsButton, BDFDB.LanguageUtils.LanguageStrings.SETTINGS); + }); + } + } + } + + updateTheme (addon, instances, reset) { + let path = BDFDB.LibraryRequires.path.join(dir, addon.filename); + let css = BDFDB.LibraryRequires.fs.readFileSync(path).toString(); + if (css) { + let amount = 0; + for (let i in instances.imports) { + let input = instances.imports[i]; + let oldValue = input.props.oldValue; + let newValue = reset ? input.props.defaultValue : input.props.value; + if (newValue.toString() != oldValue.toString()) { + let trueValue = typeof newValue == "string" ? newValue == "true" : newValue; + let importUrl = input.props.name; + if (trueValue) css = css.replace(new RegExp(`\\n${BDFDB.StringUtils.regEscape("/* @import url(" + importUrl + "); */")}`, "g"), `\n@import url(${importUrl});`); + else css = css.replace(new RegExp(`\\n${BDFDB.StringUtils.regEscape("@import url(" + importUrl + ");")}`, "g"), `\n/* @import url(${importUrl}); */`); + input.props.value = trueValue; + input.props.oldValue = newValue; + amount++; + } + } + for (let i in instances.inputs) { + let input = instances.inputs[i]; + let oldValue = input.props.oldValue; + let newValue = reset ? input.props.defaultValue : input.props.value; + if (newValue && newValue.trim() && newValue != oldValue) { + let varName = input.props.name; + css = css.replace(new RegExp(`--${BDFDB.StringUtils.regEscape(varName)}(\\s*):(\\s*)${BDFDB.StringUtils.regEscape(oldValue)}`,"g"), `--${varName}$1: $2${newValue}`); + input.props.value = newValue; + input.props.oldValue = newValue; + input.props.placeholder = newValue; + amount++; + } + } + if (amount > 0) { + BDFDB.ReactUtils.forceUpdate(BDFDB.ObjectUtils.toArray(instances.imports), BDFDB.ObjectUtils.toArray(instances.inputs)); + BDFDB.LibraryRequires.fs.writeFileSync(path, css); + BDFDB.NotificationUtils.toast(`Updated ${amount} Variable${amount == 1 ? "" : "s"} in '${addon.filename}'`, {type: "success"}); + } + else BDFDB.NotificationUtils.toast(`There are no changed Variables to be updated in '${addon.filename}'`, {type: "warning"}); + } + else BDFDB.NotificationUtils.toast(`Could not find Theme File '${addon.filename}'`, {type: "danger"}); + } + }; + })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); +})(); \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/TypingIndicator.config.json b/oldconfig/BetterDiscord/plugins/TypingIndicator.config.json new file mode 100644 index 0000000..b0fa477 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/TypingIndicator.config.json @@ -0,0 +1,7 @@ +{ + "didShowIssueHelperPopup": true, + "currentVersionInfo": { + "version": "0.5.4", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/TypingIndicator.plugin.js b/oldconfig/BetterDiscord/plugins/TypingIndicator.plugin.js new file mode 100644 index 0000000..b740bd5 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/TypingIndicator.plugin.js @@ -0,0 +1,342 @@ +/** + * @name TypingIndicator + * @displayName TypingIndicator + * @website https://twitter.com/l0c4lh057/ + * @source https://github.com/l0c4lh057/BetterDiscordStuff/blob/master/Plugins/TypingIndicator/TypingIndicator.plugin.js + * @patreon https://www.patreon.com/l0c4lh057 + * @invite YzzeuJPpyj + * @authorId 226677096091484160 + */ + +module.exports = (() => { + const config = { + info:{ + name: "TypingIndicator", + authors: [{name: "l0c4lh057", github_username: "l0c4lh057", twitter_username: "l0c4lh057", discord_id: "226677096091484160"}], + description: "Shows an indicator in the guild/channel list when someone is typing there", + version: "0.5.4", + github: "https://github.com/l0c4lh057/BetterDiscordStuff/blob/master/Plugins/TypingIndicator/", + github_raw: "https://raw.githubusercontent.com/l0c4lh057/BetterDiscordStuff/master/Plugins/TypingIndicator/TypingIndicator.plugin.js" + }, + defaultConfig: [ + { + type: "switch", + id: "channels", + name: "Show on channels", + note: "With this option enabled all channels have the typing indicator when someone is typing in them (default: true)", + value: true + }, + { + type: "switch", + id: "includeMuted", + name: "Include muted channels/guilds", + note: "With this option enabled even muted channels have the typing indicator (default: false)", + value: false + }, + { + type: "switch", + id: "includeBlocked", + name: "Include blocked users", + note: "With this option enabled the indicator will also show for users you have blocked (default: false)", + value: false + }, + { + type: "switch", + id: "guilds", + name: "Show on guilds", + note: "With this option enabled the indicator is shown on guild icons when someone is typing in any of the channels of it (default: false)", + value: false + }, + { + type: "switch", + id: "folders", + name: "Show on folders", + note: "With this option enabled the indicator is shown on discord native guild folders when someone is typing in any of the guilds (default: false)", + value: false + }, + { + type: "switch", + id: "dms", + name: "Show on home icon", + note: "With this option enabled the indicator is shown on the home icon above the guild list (default: false)", + value: false + } + ], + changelog:[ + { + "title": "Fixed", + "type": "fixed", + "items": ["Indicator visible again when using light theme (those were the worst two minutes of this year, even with my health issues rn)"] + } + ] + }; + + return !global.ZeresPluginLibrary ? class { + constructor(){this._config = config;} + getName(){return config.info.name;} + getAuthor(){return config.info.authors.map(a => a.name).join(", ");} + getDescription(){return config.info.description + " **Install [ZeresPluginLibrary](https://betterdiscord.app/Download?id=9) and restart discord to use this plugin!**";} + getVersion(){return config.info.version;} + load(){ + BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://betterdiscord.app/Download?id=9"); + await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r)); + }); + } + }); + } + start(){} + stop(){} + } : (([Plugin, Api]) => { + const plugin = (Plugin, Api) => { + const { WebpackModules, DiscordModules, Patcher, ReactComponents, PluginUtilities, Utilities, ReactTools, Logger } = Api; + const { React, ChannelStore, UserStore, UserTypingStore, RelationshipStore, SelectedGuildStore, DiscordConstants, WindowInfo } = DiscordModules; + const Flux = WebpackModules.getByProps("connectStores"); + const FluxUtils = WebpackModules.getByProps("useStateFromStores"); + const MutedStore = WebpackModules.getByProps("isMuted", "isChannelMuted"); + const Spinner = WebpackModules.getByDisplayName("Spinner"); + const Tooltip = WebpackModules.getByDisplayName("Tooltip"); + + if(!BdApi.Plugins.get("BugReportHelper") && !BdApi.getData(config.info.name, "didShowIssueHelperPopup")){ + BdApi.saveData(config.info.name, "didShowIssueHelperPopup", true); + BdApi.showConfirmationModal("Do you want to download a helper plugin?", `Do you want to download a helper plugin that makes it easier for you to report issues? That plugin is not needed to anything else to function correctly but nice to have when reporting iissues, shortening the time until the problem gets resolved by asking you for specific information and also including additional information you did not provide.`, { + confirmText: "Download", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://raw.githubusercontent.com/l0c4lh057/BetterDiscordStuff/master/Plugins/BugReportHelper/BugReportHelper.plugin.js", (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/l0c4lh057/BetterDiscordStuff/master/Plugins/BugReportHelper/BugReportHelper.plugin.js"); + else require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "BugReportHelper.plugin.js"), body, ()=>{ + window.setTimeout(()=>BdApi.Plugins.enable("BugReportHelper"), 1000); + }); + }); + } + }); + } + + const renderElement = ({userIds, opacity, type, isFocused, id})=>{ + userIds = [...new Set(userIds)]; + if(userIds.length === 0) return null; + const usernames = userIds.map(userId => UserStore.getUser(userId)).filter(user => user).map(user => user.tag); + const remainingUserCount = userIds.length - usernames.length; + const text = (()=>{ + if(usernames.length === 0){ + return `${remainingUserCount} user${remainingUserCount > 1 ? "s" : ""}`; + }else if(userIds.length > 2){ + const otherCount = usernames.length - 1 + remainingUserCount; + return `${usernames[0]} and ${otherCount} other${otherCount > 1 ? "s" : ""}`; + }else if(remainingUserCount === 0){ + return usernames.join(", "); + }else{ + return `${usernames.join(", ")} and ${remainingUserCount} other${remainingUserCount > 1 ? "s" : ""}`; + } + })(); + return React.createElement( + Tooltip, + { + text, + position: type === "channel" ? "top" : "right" + }, + tooltipProps => React.createElement(Spinner, { + ...tooltipProps, + type: "pulsingEllipsis", + className: `ti-indicator typingindicator-${type}`, + [`data-${type}-id`]: id, + animated: isFocused, + style: { + marginLeft: 5, + opacity: opacity + } + }) + ); + } + + return class TypingIndicator extends Plugin { + onStart(){ + PluginUtilities.addStyle("typingindicator-css", ` + .typingindicator-guild, .typingindicator-dms, .typingindicator-folder { + position: absolute; + bottom: 0; + padding: 3px; + border-radius: 6px; + background-color: var(--background-tertiary); + right: 14px; + } + .ti-indicator span.pulsingEllipsisItem-3pNmEc { + background-color: var(--channels-default); + } + .ti-indicator .pulsingEllipsis-3YiXRF { + width: 22px; + } + .ti-indicator .pulsingEllipsisItem-3pNmEc:nth-of-type(3) { + margin-right: 0; + } + `); + this.promises = {state:{cancelled: false}, cancel(){this.state.cancelled = true;}}; + this.patchChannelList(); + this.patchGuildList(this.promises.state); + this.patchHomeIcon(this.promises.state); + this.patchFolders(this.promises.state); + } + onStop(){ + PluginUtilities.removeStyle("typingindicator-css"); + this.promises.cancel(); + Patcher.unpatchAll(); + } + + getGuildChannels(...guildIds){ + const channels = ChannelStore.getGuildChannels ? Object.values(ChannelStore.getGuildChannels()) : ChannelStore.getMutableGuildChannels ? Object.values(ChannelStore.getMutableGuildChannels()) : []; + return channels.filter(c => guildIds.includes(c.guild_id) && c.type !== DiscordConstants.ChannelTypes.GUILD_VOICE && c.type !== DiscordConstants.ChannelTypes.GUILD_CATEGORY); + } + + getPrivateChannels(){ + return ChannelStore.getPrivateChannels ? Object.values(ChannelStore.getPrivateChannels()) : ChannelStore.getMutablePrivateChannels ? Object.values(ChannelStore.getMutablePrivateChannels()) : []; + } + + patchChannelList(){ + const ChannelItem = WebpackModules.getModule(m => Object(m.default).displayName==="ChannelItem"); + Patcher.after(ChannelItem, "default", (_, [props], returnValue) => { + if(props.channel.type!==DiscordConstants.ChannelTypes.GUILD_TEXT) return; + if(props.selected) return; + if(props.muted && !this.settings.includeMuted) return; + const selfId = UserStore.getCurrentUser()?.id; + if(!selfId) return setTimeout(()=>this.patchChannelList(), 100); + const fluxWrapper = Flux.connectStores([UserTypingStore, WindowInfo], ()=>({userIds: Object.keys(UserTypingStore.getTypingUsers(props.channel.id)) + .filter(uId => (uId !== selfId) && (this.settings.includeBlocked || !RelationshipStore.isBlocked(uId))) + })); + const wrappedCount = fluxWrapper(({userIds}) => { + return React.createElement(renderElement, {userIds, opacity: 0.7, type: "channel", isFocused: WindowInfo.isFocused(), id: props.channel.id}); + }); + const itemList = Utilities.getNestedProp(returnValue, "props.children.props.children.1.props"); + if(itemList) itemList.children = [...(Array.isArray(itemList.children) ? itemList.children : [itemList.children]), React.createElement(wrappedCount)]; + }); + } + + onAdded(selector, callback) { + if (document.body.querySelector(selector)) return callback(document.body.querySelector(selector)); + const observer = new MutationObserver((mutations) => { + for (let m = 0; m < mutations.length; m++) { + for (let i = 0; i < mutations[m].addedNodes.length; i++) { + const mutation = mutations[m].addedNodes[i]; + if (mutation.nodeType === 3) continue; // ignore text + const directMatch = mutation.matches(selector) && mutation; + const childrenMatch = mutation.querySelector(selector); + if (directMatch || childrenMatch) { + observer.disconnect(); + return callback(directMatch ?? childrenMatch); + } + } + } + }); + observer.observe(document.body, {subtree: true, childList: true}); + return () => {observer.disconnect();}; + } + + async forceUpdateGuilds(promiseState) { + document.getElementsByClassName("scroller-1Bvpku none-2Eo-qx scrollerBase-289Jih")[0]?.dispatchEvent(new CustomEvent("scroll")); + } + + // this still doesnt work but it was an attempt to fix it and im too lazy to undo it for release + patchGuildList(promiseState){ + const GuildComponents = WebpackModules.getModule(m => m?.default?.displayName === "GuildNode"); + if (!GuildComponents || typeof GuildComponents.default !== "function") return console.error("[TypingIndicator] Could not find Guild components"); + const selfId = UserStore.getCurrentUser()?.id; + if(!selfId) return setTimeout(()=>this.patchGuildList(promiseState), 100); + const Indicator = guildId => { + const props = FluxUtils.useStateFromStoresObject([UserStore, RelationshipStore, WindowInfo, UserTypingStore, MutedStore, UserStore], () => { + const selfId = UserStore.getCurrentUser().id; + return { + userIds: this.getGuildChannels(guildId) + .filter(channel => this.settings.includeMuted || !MutedStore.isChannelMuted(channel.guild_id, channel.id)) + .flatMap(channel => Object.keys(UserTypingStore.getTypingUsers(channel.id))) + .filter(userId => (userId !== selfId) && (this.settings.includeBlocked || !RelationshipStore.isBlocked(userId))), + isFocused: WindowInfo.isFocused() + }; + }); + return React.createElement(renderElement, {...props, opacity: 1, id: guildId, type: "guild"}); + }; + const PatchedGuild = ({__TI_original, ...props}) => { + const returnValue = __TI_original(props); + try{ + if(props.selected) return returnValue; + if(!this.settings.guilds) return returnValue; + if(!props.guild) return returnValue; + if(MutedStore.isMuted(props.guild.id) && !this.settings.includeMuted) return returnValue; + returnValue.props.children.props.children.push(Indicator({guildId: props.guild.id})); + }catch(err){ + Logger.error("Error in Guild patch", err); + } + return returnValue; + } + Patcher.after(GuildComponents, "default", (_, [args], returnValue)=>{ + const original = returnValue.type; + returnValue.type = PatchedGuild; + returnValue.props.__TI_original = original; + }); + this.forceUpdateGuilds(promiseState); + } + + async patchHomeIcon(promiseState){ + const Home = await ReactComponents.getComponentByName("TutorialIndicator", "." + WebpackModules.getByProps("badgeIcon", "circleIcon", "listItem", "pill").listItem.replace(/ /g, ".")); + if(promiseState.cancelled) return; + const selfId = UserStore.getCurrentUser()?.id; + if(!selfId) return setTimeout(()=>this.patchHomeIcon(promiseState), 100); + Patcher.after(Home.component.prototype, "render", (thisObject, _, returnValue) => { + if(!returnValue.props.children) return; + let children = returnValue.props.children[0] || returnValue.props.children; + if(!children.props) return; + if(!children.props.children || !children.props.className) return; + if(!children.props.children.props || !children.props.children.props.children) return; + children = children.props.children.props.children[1]; + if(!children) return; + if(!this.settings.dms) return; + if(!SelectedGuildStore.getGuildId()) return; + const fluxWrapper = Flux.connectStores([UserTypingStore, WindowInfo], ()=>({userIds: this.getPrivateChannels() + .filter(c => this.settings.includeMuted || !MutedStore.isChannelMuted(null, c.id)) + .flatMap(c => Object.keys(UserTypingStore.getTypingUsers(c.id)) + .filter(uId => (uId !== selfId) && (this.settings.includeBlocked || !RelationshipStore.isBlocked(uId))) + ) + })); + const wrappedCount = fluxWrapper(({userIds}) => { + return React.createElement(renderElement, {userIds, opacity: 1, type: "dms", isFocused: WindowInfo.isFocused()}); + }); + children.props.children = React.Children.toArray(children.props.children); + if(children.props.children.push) children.props.children.push(React.createElement(wrappedCount)); + }); + Home.forceUpdateAll(); + } + + async patchFolders(promiseState){ + const Folder = WebpackModules.find(m=>m?.type?.render && (m?.type?.render||m?.type?.__powercordOriginal_render)?.toString()?.indexOf("SERVER_FOLDER")!==-1); + if(promiseState.cancelled || !Folder) return; + const selfId = UserStore.getCurrentUser()?.id; + if(!selfId) return setTimeout(()=>this.patchFolders(promiseState), 100); + Patcher.after(Folder.type, "render", (_, [props], returnValue) => { + if(props.expanded) return; + if(!this.settings.folders) return; + const fluxWrapper = Flux.connectStores([UserTypingStore, WindowInfo], ()=>({userIds: this.getGuildChannels(...props.guildIds) + .filter(c => (this.settings.includeMuted || !MutedStore.isMuted(c.guild_id)) + && (this.settings.includeMuted || !MutedStore.isChannelMuted(c.guild_id, c.id)) + && (SelectedGuildStore.getGuildId() !== c.guild_id)) + .flatMap(c => Object.keys(UserTypingStore.getTypingUsers(c.id)) + .filter(uId => (uId !== selfId) && (this.settings.includeBlocked || !RelationshipStore.isBlocked(uId))) + ) + })); + const wrappedCount = fluxWrapper(({userIds}) => { + return React.createElement(renderElement, {userIds, opacity: 1, type: "folder", isFocused: WindowInfo.isFocused(), id: props.folderId}); + }); + returnValue.props.children.push(React.createElement(wrappedCount)); + }); + } + + getSettingsPanel(){ + return this.buildSettingsPanel().getElement(); + } + }; + }; + return plugin(Plugin, Api); + })(global.ZeresPluginLibrary.buildPlugin(config)); +})(); diff --git a/oldconfig/BetterDiscord/plugins/UserDetails.config.json b/oldconfig/BetterDiscord/plugins/UserDetails.config.json new file mode 100644 index 0000000..279628a --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/UserDetails.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "2.9.0", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/UserDetails.plugin.js b/oldconfig/BetterDiscord/plugins/UserDetails.plugin.js new file mode 100644 index 0000000..9e58298 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/UserDetails.plugin.js @@ -0,0 +1,2864 @@ +/** + * @name UserDetails + * @version 2.9.0 + * @author Strencher + * @description Shows you a lot information about users in both the UserPopout and UserProfile Modal. To enumerate: Creation Date, Joined At Date, Last Message Date, Mutual Friends, Mutual Servers & Connections. It also shows the Roles List in the UserProfile Modal. + * @source https://github.com/Strencher/BetterDiscordStuff/tree/development/UserDetails + * @updateUrl https://raw.githubusercontent.com/Strencher/BetterDiscordStuff/master/UserDetails/UserDetails.plugin.js + * @invite gvA2ree + */ +/*@cc_on +@if (@_jscript) + + // Offer to self-install for clueless users that try to run this directly. + var shell = WScript.CreateObject("WScript.Shell"); + var fs = new ActiveXObject("Scripting.FileSystemObject"); + var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\BetterDiscord\plugins"); + var pathSelf = WScript.ScriptFullName; + // Put the user at ease by addressing them in the first person + shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30); + if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) { + shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40); + } else if (!fs.FolderExists(pathPlugins)) { + shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10); + } else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) { + fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true); + // Show the user where to put plugins in the future + shell.Exec("explorer " + pathPlugins); + shell.Popup("I'm installed!", 0, "Successfully installed", 0x40); + } + WScript.Quit(); +@else@*/ +/* Generated Code */ +const config = { + "info": { + "name": "UserDetails", + "version": "2.9.0", + "authors": [{ + "name": "Strencher", + "discord_id": "415849376598982656", + "github_username": "Strencher", + "twitter_username": "Strencher3" + }], + "description": "Shows you a lot information about users in both the UserPopout and UserProfile Modal. To enumerate: Creation Date, Joined At Date, Last Message Date, Mutual Friends, Mutual Servers & Connections. It also shows the Roles List in the UserProfile Modal.", + "github": "https://github.com/Strencher/BetterDiscordStuff/tree/development/UserDetails", + "github_raw": "https://raw.githubusercontent.com/Strencher/BetterDiscordStuff/master/UserDetails/UserDetails.plugin.js", + "invite": "gvA2ree" + }, + "changelog": [{ + "title": "Bug Fixes", + "type": "fixed", + "items": [ + "Fixed MutualFriends & MutualServers showing up in the UserPopout." + ] + }, + { + "title": "Improvements", + "type": "improved", + "items": [ + "Improved badge for the EpicGames connection.", + "Improved tooltip color in the UserPopout." + ] + } + ], + "build": { + "zlibrary": true, + "copy": true, + "production": false, + "scssHash": false, + "alias": { + "icons": "components/icons", + "stores": "./modules/stores" + }, + "release": { + "public": true, + "source": true, + "readme": true + } + } +}; +function buildPlugin([BasePlugin, PluginApi]) { + const module = { + exports: {} + }; + (() => { + "use strict"; + class StyleLoader { + static styles = ""; + static element = null; + static append(module, css) { + this.styles += `/* ${module} */\n${css}`; + } + static inject(name = config.info.name) { + if (this.element) this.element.remove(); + this.element = document.head.appendChild(Object.assign(document.createElement("style"), { + id: name, + textContent: this.styles + })); + } + static remove() { + if (this.element) { + this.element.remove(); + this.element = null; + } + } + } + function ___createMemoize___(instance, name, value) { + value = value(); + Object.defineProperty(instance, name, { + value, + configurable: true + }); + return value; + }; + const Modules = { + get 'react-spring'() { + return ___createMemoize___(this, 'react-spring', () => BdApi.findModuleByProps('useSpring')) + }, + '@discord/utils': { + get 'joinClassNames'() { + return ___createMemoize___(this, 'joinClassNames', () => BdApi.findModule(e => e.toString().indexOf('return e.join(" ")') > 200)) + }, + get 'useForceUpdate'() { + return ___createMemoize___(this, 'useForceUpdate', () => BdApi.findModuleByProps('useForceUpdate')?.useForceUpdate) + }, + get 'Logger'() { + return ___createMemoize___(this, 'Logger', () => BdApi.findModuleByProps('setLogFn')?.default) + }, + get 'Navigation'() { + return ___createMemoize___(this, 'Navigation', () => BdApi.findModuleByProps('replaceWith', 'currentRouteIsPeekView')) + } + }, + '@discord/components': { + get 'Tooltip'() { + return ___createMemoize___(this, 'Tooltip', () => BdApi.findModuleByDisplayName('Tooltip')) + }, + get 'TooltipContainer'() { + return ___createMemoize___(this, 'TooltipContainer', () => BdApi.findModuleByProps('TooltipContainer')?.TooltipContainer) + }, + get 'TextInput'() { + return ___createMemoize___(this, 'TextInput', () => BdApi.findModuleByDisplayName('TextInput')) + }, + get 'SlideIn'() { + return ___createMemoize___(this, 'SlideIn', () => BdApi.findModuleByDisplayName('SlideIn')) + }, + get 'SettingsNotice'() { + return ___createMemoize___(this, 'SettingsNotice', () => BdApi.findModuleByDisplayName('SettingsNotice')) + }, + get 'TransitionGroup'() { + return ___createMemoize___(this, 'TransitionGroup', () => BdApi.findModuleByDisplayName('TransitionGroup')) + }, + get 'Button'() { + return ___createMemoize___(this, 'Button', () => BdApi.findModule(m => 'DropdownSizes' in m && typeof(m) === 'function')) + }, + get 'Popout'() { + return ___createMemoize___(this, 'Popout', () => BdApi.findModuleByDisplayName('Popout')) + }, + get 'Flex'() { + return ___createMemoize___(this, 'Flex', () => BdApi.findModuleByDisplayName('Flex')) + }, + get 'Text'() { + return ___createMemoize___(this, 'Text', () => BdApi.findModuleByDisplayName('Text')) + }, + get 'Card'() { + return ___createMemoize___(this, 'Card', () => BdApi.findModuleByDisplayName('Card')) + } + }, + '@discord/modules': { + get 'Dispatcher'() { + return ___createMemoize___(this, 'Dispatcher', () => BdApi.findModuleByProps('dirtyDispatch', 'subscribe')) + }, + get 'ComponentDispatcher'() { + return ___createMemoize___(this, 'ComponentDispatcher', () => BdApi.findModuleByProps('ComponentDispatch')?.ComponentDispatch) + }, + get 'EmojiUtils'() { + return ___createMemoize___(this, 'EmojiUtils', () => BdApi.findModuleByProps('uploadEmoji')) + }, + get 'PermissionUtils'() { + return ___createMemoize___(this, 'PermissionUtils', () => BdApi.findModuleByProps('computePermissions', 'canManageUser')) + }, + get 'DMUtils'() { + return ___createMemoize___(this, 'DMUtils', () => BdApi.findModuleByProps('openPrivateChannel')) + } + }, + '@discord/stores': { + get 'Messages'() { + return ___createMemoize___(this, 'Messages', () => BdApi.findModuleByProps('getMessage', 'getMessages')) + }, + get 'Channels'() { + return ___createMemoize___(this, 'Channels', () => BdApi.findModuleByProps('getChannel', 'getDMFromUserId')) + }, + get 'Guilds'() { + return ___createMemoize___(this, 'Guilds', () => BdApi.findModuleByProps('getGuild')) + }, + get 'SelectedGuilds'() { + return ___createMemoize___(this, 'SelectedGuilds', () => BdApi.findModuleByProps('getGuildId', 'getLastSelectedGuildId')) + }, + get 'SelectedChannels'() { + return ___createMemoize___(this, 'SelectedChannels', () => BdApi.findModuleByProps('getChannelId', 'getLastSelectedChannelId')) + }, + get 'Info'() { + return ___createMemoize___(this, 'Info', () => BdApi.findModuleByProps('getSessionId')) + }, + get 'Status'() { + return ___createMemoize___(this, 'Status', () => BdApi.findModuleByProps('getStatus', 'getActivities', 'getState')) + }, + get 'Users'() { + return ___createMemoize___(this, 'Users', () => BdApi.findModuleByProps('getUser', 'getCurrentUser')) + }, + get 'SettingsStore'() { + return ___createMemoize___(this, 'SettingsStore', () => BdApi.findModuleByProps('afkTimeout', 'status')) + }, + get 'UserProfile'() { + return ___createMemoize___(this, 'UserProfile', () => BdApi.findModuleByProps('getUserProfile')) + }, + get 'Members'() { + return ___createMemoize___(this, 'Members', () => BdApi.findModuleByProps('getMember')) + }, + get 'Activities'() { + return ___createMemoize___(this, 'Activities', () => BdApi.findModuleByProps('getActivities')) + }, + get 'Games'() { + return ___createMemoize___(this, 'Games', () => BdApi.findModuleByProps('getGame', 'games')) + }, + get 'Auth'() { + return ___createMemoize___(this, 'Auth', () => BdApi.findModuleByProps('getId', 'isGuest')) + }, + get 'TypingUsers'() { + return ___createMemoize___(this, 'TypingUsers', () => BdApi.findModuleByProps('isTyping')) + } + }, + '@discord/actions': { + get 'ProfileActions'() { + return ___createMemoize___(this, 'ProfileActions', () => BdApi.findModuleByProps('fetchProfile')) + }, + get 'GuildActions'() { + return ___createMemoize___(this, 'GuildActions', () => BdApi.findModuleByProps('requestMembersById')) + } + }, + get '@discord/i18n'() { + return ___createMemoize___(this, '@discord/i18n', () => BdApi.findModule(m => m.Messages?.CLOSE && typeof(m.getLocale) === 'function')) + }, + get '@discord/constants'() { + return ___createMemoize___(this, '@discord/constants', () => BdApi.findModuleByProps('API_HOST')) + }, + get '@discord/contextmenu'() { + return ___createMemoize___(this, '@discord/contextmenu', () => { + const ctx = Object.assign({}, BdApi.findModuleByProps('openContextMenu'), BdApi.findModuleByProps('MenuItem')); + ctx.Menu = ctx.default; + return ctx; + }) + }, + get '@discord/forms'() { + return ___createMemoize___(this, '@discord/forms', () => BdApi.findModuleByProps('FormItem')) + }, + get '@discord/scrollbars'() { + return ___createMemoize___(this, '@discord/scrollbars', () => BdApi.findModuleByProps('ScrollerAuto')) + }, + get '@discord/native'() { + return ___createMemoize___(this, '@discord/native', () => BdApi.findModuleByProps('requireModule')) + }, + get '@discord/flux'() { + return ___createMemoize___(this, '@discord/flux', () => Object.assign({}, BdApi.findModuleByProps('useStateFromStores').default, BdApi.findModuleByProps('useStateFromStores'))) + }, + get '@discord/modal'() { + return ___createMemoize___(this, '@discord/modal', () => Object.assign({}, BdApi.findModuleByProps('ModalRoot'), BdApi.findModuleByProps('openModal', 'closeAllModals'))) + }, + get '@discord/connections'() { + return ___createMemoize___(this, '@discord/connections', () => BdApi.findModuleByProps('get', 'isSupported', 'map')) + }, + get '@discord/sanitize'() { + return ___createMemoize___(this, '@discord/sanitize', () => BdApi.findModuleByProps('stringify', 'parse', 'encode')) + }, + get '@discord/icons'() { + return ___createMemoize___(this, '@discord/icons', () => BdApi.findAllModules(m => m.displayName && ~m.toString().indexOf('currentColor')).reduce((icons, icon) => (icons[icon.displayName] = icon, icons), {})) + }, + '@discord/classes': { + get 'Timestamp'() { + return ___createMemoize___(this, 'Timestamp', () => BdApi.findModuleByPrototypes('toDate', 'month')) + }, + get 'Message'() { + return ___createMemoize___(this, 'Message', () => BdApi.findModuleByPrototypes('getReaction', 'isSystemDM')) + }, + get 'User'() { + return ___createMemoize___(this, 'User', () => BdApi.findModuleByPrototypes('tag')) + }, + get 'Channel'() { + return ___createMemoize___(this, 'Channel', () => BdApi.findModuleByPrototypes('isOwner', 'isCategory')) + } + } + }; + var __webpack_modules__ = { + 597: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-connections-header{font-weight:700;text-transform:uppercase;font-size:12px;margin-bottom:8px;color:var(--header-secondary)}.UserDetails-connections-connectionsBody div:not(.UserDetails-connections-connections,.UserDetails-connections-container){display:inline-flex;margin:2px}.UserDetails-connections-connectionsBody .UserDetails-connections-loading{fill:var(--interactive-muted);animation:UserDetails-connections-blink infinite 2s;width:30px;height:30px;margin:5px;margin-top:0;margin-left:0}.UserDetails-connections-connectionsBody .UserDetails-connections-connections{display:flex;flex-wrap:wrap;margin-bottom:8px}.UserDetails-connections-connectionsBody .UserDetails-connections-connections img{width:30px;height:30px}.UserDetails-connections-connectionsBody .UserDetails-connections-errorIcon{width:35px;height:35px;margin-top:-5px}.UserDetails-connections-connectionsBody .UserDetails-connections-errorIcon{fill:#ed4245 !important}@keyframes UserDetails-connections-blink{0%{opacity:.6}50%{opacity:.3}100%{opacity:.6}}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + header: "UserDetails-connections-header", + connectionsBody: "UserDetails-connections-connectionsBody", + connections: "UserDetails-connections-connections", + container: "UserDetails-connections-container", + loading: "UserDetails-connections-loading", + blink: "UserDetails-connections-blink", + errorIcon: "UserDetails-connections-errorIcon" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 242: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".customStatus-oN4ZZY:not(:empty){padding-top:10px;border-top:thin solid var(--background-modifier-accent)}.UserDetails-dates-container{display:flex;max-width:-webkit-fill-available;margin-bottom:-5px}.UserDetails-dates-container.UserDetails-dates-text{flex-direction:column;margin-top:10px;border-top:thin solid var(--background-modifier-accent);padding-top:10px}.UserDetails-dates-container.UserDetails-dates-icons{flex-direction:row}.UserDetails-dates-container.UserDetails-dates-icons.UserDetails-dates-userProfile{padding-left:13px}.UserDetails-dates-container.UserDetails-dates-icons .UserDetails-dates-loading{animation:UserDetails-dates-blink infinite 2s ease-in-out}.UserDetails-dates-container svg{fill:#ddd;margin:5px;width:20px;height:20px}.UserDetails-dates-container.UserDetails-dates-text .UserDetails-dates-scrollableText{color:var(--text-normal);white-space:nowrap;position:relative;font-size:14px;width:-webkit-fill-available;text-align:left;line-height:18px}.UserDetails-dates-container.UserDetails-dates-text.UserDetails-dates-userProfile{padding-left:18px}.UserDetails-dates-container.UserDetails-dates-text.UserDetails-dates-userProfile .UserDetails-dates-scrollableText{text-align:left !important}.UserDetails-dates-container .UserDetails-dates-errorIcon{fill:#ed4245 !important}.UserDetails-dates-wrapper{display:block}@keyframes UserDetails-dates-blink{0%{opacity:.6}50%{opacity:.3}100%{opacity:.6}}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + container: "UserDetails-dates-container", + text: "UserDetails-dates-text", + icons: "UserDetails-dates-icons", + userProfile: "UserDetails-dates-userProfile", + loading: "UserDetails-dates-loading", + blink: "UserDetails-dates-blink", + scrollableText: "UserDetails-dates-scrollableText", + errorIcon: "UserDetails-dates-errorIcon", + wrapper: "UserDetails-dates-wrapper" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 675: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-mutualFriends-header{font-weight:700;text-transform:uppercase;font-size:12px;margin-bottom:8px;color:var(--header-secondary)}.UserDetails-mutualFriends-body{display:block;margin-bottom:8px}.UserDetails-mutualFriends-friends{display:flex;flex-wrap:wrap}.UserDetails-mutualFriends-mutualFriend{margin:2px;cursor:pointer}.UserDetails-mutualFriends-stack .UserDetails-mutualFriends-mutualFriend{margin:0;margin-right:-10px;background:var(--background-floating)}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + header: "UserDetails-mutualFriends-header", + body: "UserDetails-mutualFriends-body", + friends: "UserDetails-mutualFriends-friends", + mutualFriend: "UserDetails-mutualFriends-mutualFriend", + stack: "UserDetails-mutualFriends-stack" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 416: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-mutualServers-header{font-weight:700;text-transform:uppercase;font-size:12px;margin-bottom:8px;color:var(--header-secondary)}.UserDetails-mutualServers-body{display:block;margin-bottom:8px}.UserDetails-mutualServers-guilds{display:flex;flex-wrap:wrap}.UserDetails-mutualServers-mutualGuild{margin:2px}.UserDetails-mutualServers-mutualGuild,.UserDetails-mutualServers-guildAcronym{width:30px;height:30px;border-radius:50%;overflow:hidden;transition:border-radius .3s}.UserDetails-mutualServers-mutualGuild:hover,.UserDetails-mutualServers-guildAcronym:hover{border-radius:20%}.UserDetails-mutualServers-mutualGuild img{width:30px;height:30px}.UserDetails-mutualServers-guildAcronym{display:flex;background:var(--background-floating);align-items:center;justify-content:center;white-space:nowrap;font-size:12px}.UserDetails-mutualServers-stack .UserDetails-mutualServers-mutualGuild{margin:0;margin-right:-10px;background:var(--background-floating)}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + header: "UserDetails-mutualServers-header", + body: "UserDetails-mutualServers-body", + guilds: "UserDetails-mutualServers-guilds", + mutualGuild: "UserDetails-mutualServers-mutualGuild", + guildAcronym: "UserDetails-mutualServers-guildAcronym", + stack: "UserDetails-mutualServers-stack" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 965: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-styles-body:first-child{margin-top:8px}.UserDetails-styles-tooltip{--background-floating: var(--background-secondary)}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + body: "UserDetails-styles-body", + tooltip: "UserDetails-styles-tooltip" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 755: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-activity-icon{display:flex;float:right}.UserDetails-activity-container{display:flex}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + icon: "UserDetails-activity-icon", + container: "UserDetails-activity-container" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 173: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-badge-connection{width:30px;height:30px;position:relative}.UserDetails-badge-connection.UserDetails-badge-verified .UserDetails-badge-verifiedBadge{width:12px;height:12px;position:absolute;bottom:-3px;right:-3px;background:var(--background-floating);border-radius:50%;overflow:hidden;padding:2px}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + connection: "UserDetails-badge-connection", + verified: "UserDetails-badge-verified", + verifiedBadge: "UserDetails-badge-verifiedBadge" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 564: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-flowerstar-wrapper{position:relative;display:flex;align-items:center;justify-content:center}.UserDetails-flowerstar-wrapper .UserDetails-flowerstar-container{display:block}.UserDetails-flowerstar-wrapper .UserDetails-flowerstar-tick{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + wrapper: "UserDetails-flowerstar-wrapper", + container: "UserDetails-flowerstar-container", + tick: "UserDetails-flowerstar-tick" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 128: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-settings-settingsPanel .UserDetails-settings-descriptionItem{margin-top:8px}.UserDetails-settings-settingsPanel .UserDetails-settings-translation{width:27px;height:18px;margin-right:8px}.UserDetails-settings-settingsPanel .UserDetails-settings-marginBottom8{margin-bottom:8px}.UserDetails-settings-settingsPanel .UserDetails-settings-formItem{margin-bottom:10px}.UserDetails-settings-settingsPanel .UserDetails-settings-cardItem{display:flex;position:relative}.UserDetails-settings-settingsPanel .UserDetails-settings-cardItem>div{flex-grow:1}.UserDetails-settings-settingsPanel .UserDetails-settings-cardItem .UserDetails-settings-textBadge{position:absolute;top:-5px;right:-5px;display:inline-block;text-transform:uppercase;vertical-align:middle}.UserDetails-settings-settingsPanel .UserDetails-settings-icons{flex-wrap:wrap}.UserDetails-settings-settingsPanel .UserDetails-settings-icons .UserDetails-settings-settingsBadgeContainer{display:inline-flex;cursor:pointer}.UserDetails-settings-settingsPanel .UserDetails-settings-icons .UserDetails-settings-settingsBadgeContainer .UserDetails-settings-settingsBadgeIcon{width:40px;height:40px}.UserDetails-settings-settingsPanel .UserDetails-settings-icons .UserDetails-settings-settingsBadgeContainer .UserDetails-settings-settingsBadgeIcon.UserDetails-settings-disabled{opacity:.4}.UserDetails-settings-settingsPanel .UserDetails-settings-category{color:#ddd}.UserDetails-settings-settingsPanel .UserDetails-settings-category.UserDetails-settings-opened .UserDetails-settings-categoryContent{padding:10px;padding:10px}.UserDetails-settings-settingsPanel .UserDetails-settings-category.UserDetails-settings-opened .UserDetails-settings-categoryContent .UserDetails-settings-replacementVariable{user-select:text;margin-bottom:6px;padding-bottom:6px;border-bottom:thin solid var(--background-modifier-accent)}.UserDetails-settings-settingsPanel .UserDetails-settings-category.UserDetails-settings-opened .UserDetails-settings-categoryContent .UserDetails-settings-replacementVariable b{margin-right:3px}.UserDetails-settings-settingsPanel .UserDetails-settings-category .UserDetails-settings-categoryHeader{cursor:pointer;padding:10px;font-size:15px;background:var(--background-tertiary);font-weight:600;text-transform:uppercase;display:flex;align-items:center}.UserDetails-settings-settingsPanel .UserDetails-settings-category .UserDetails-settings-categoryHeader .UserDetails-settings-categoryCaret{margin-left:auto}.UserDetails-settings-settingsPanel .UserDetails-settings-pageIcon{color:var(--interactive-normal);fill:var(--interactive-normal)}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + settingsPanel: "UserDetails-settings-settingsPanel", + descriptionItem: "UserDetails-settings-descriptionItem", + translation: "UserDetails-settings-translation", + marginBottom8: "UserDetails-settings-marginBottom8", + formItem: "UserDetails-settings-formItem", + cardItem: "UserDetails-settings-cardItem", + textBadge: "UserDetails-settings-textBadge", + icons: "UserDetails-settings-icons", + settingsBadgeContainer: "UserDetails-settings-settingsBadgeContainer", + settingsBadgeIcon: "UserDetails-settings-settingsBadgeIcon", + disabled: "UserDetails-settings-disabled", + category: "UserDetails-settings-category", + opened: "UserDetails-settings-opened", + categoryContent: "UserDetails-settings-categoryContent", + replacementVariable: "UserDetails-settings-replacementVariable", + categoryHeader: "UserDetails-settings-categoryHeader", + categoryCaret: "UserDetails-settings-categoryCaret", + pageIcon: "UserDetails-settings-pageIcon" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 562: (module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.d(__webpack_exports__, { + Z: () => __WEBPACK_DEFAULT_EXPORT__ + }); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645); + var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__); + var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) { + return i[1]; + })); + ___CSS_LOADER_EXPORT___.push([module.id, ".UserDetails-style-loadingText{color:var(--text-normal);text-align:center}.UserDetails-style-scrollableText{color:var(--text-normal);white-space:nowrap;position:relative;font-size:14px;width:-webkit-fill-available;text-align:center;line-height:18px}", ""]); + ___CSS_LOADER_EXPORT___.locals = { + loadingText: "UserDetails-style-loadingText", + scrollableText: "UserDetails-style-scrollableText" + }; + StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString()); + const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals); + }, + 645: module => { + module.exports = function(cssWithMappingToString) { + var list = []; + list.toString = function toString() { + return this.map((function(item) { + var content = cssWithMappingToString(item); + if (item[2]) return "@media ".concat(item[2], " {").concat(content, "}"); + return content; + })).join(""); + }; + list.i = function(modules, mediaQuery, dedupe) { + if ("string" === typeof modules) modules = [ + [null, modules, ""] + ]; + var alreadyImportedModules = {}; + if (dedupe) + for (var i = 0; i < this.length; i++) { + var id = this[i][0]; + if (null != id) alreadyImportedModules[id] = true; + } + for (var _i = 0; _i < modules.length; _i++) { + var item = [].concat(modules[_i]); + if (dedupe && alreadyImportedModules[item[0]]) continue; + if (mediaQuery) + if (!item[2]) item[2] = mediaQuery; + else item[2] = "".concat(mediaQuery, " and ").concat(item[2]); + list.push(item); + } + }; + return list; + }; + }, + 113: module => { + module.exports = BdApi.React; + } + }; + var __webpack_module_cache__ = {}; + function __webpack_require__(moduleId) { + var cachedModule = __webpack_module_cache__[moduleId]; + if (void 0 !== cachedModule) return cachedModule.exports; + var module = __webpack_module_cache__[moduleId] = { + id: moduleId, + exports: {} + }; + __webpack_modules__[moduleId](module, module.exports, __webpack_require__); + return module.exports; + } + (() => { + __webpack_require__.n = module => { + var getter = module && module.__esModule ? () => module["default"] : () => module; + __webpack_require__.d(getter, { + a: getter + }); + return getter; + }; + })(); + (() => { + var getProto = Object.getPrototypeOf ? obj => Object.getPrototypeOf(obj) : obj => obj.__proto__; + var leafPrototypes; + __webpack_require__.t = function(value, mode) { + if (1 & mode) value = this(value); + if (8 & mode) return value; + if ("object" === typeof value && value) { + if (4 & mode && value.__esModule) return value; + if (16 & mode && "function" === typeof value.then) return value; + } + var ns = Object.create(null); + __webpack_require__.r(ns); + var def = {}; + leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)]; + for (var current = 2 & mode && value; + "object" == typeof current && !~leafPrototypes.indexOf(current); current = getProto(current)) Object.getOwnPropertyNames(current).forEach((key => def[key] = () => value[key])); + def["default"] = () => value; + __webpack_require__.d(ns, def); + return ns; + }; + })(); + (() => { + __webpack_require__.d = (exports, definition) => { + for (var key in definition) + if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, { + enumerable: true, + get: definition[key] + }); + }; + })(); + (() => { + __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); + })(); + (() => { + __webpack_require__.r = exports => { + if ("undefined" !== typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, { + value: "Module" + }); + Object.defineProperty(exports, "__esModule", { + value: true + }); + }; + })(); + var __webpack_exports__ = {}; + (() => { + __webpack_require__.r(__webpack_exports__); + __webpack_require__.d(__webpack_exports__, { + default: () => Plugin + }); + var modules_stores_namespaceObject = {}; + __webpack_require__.r(modules_stores_namespaceObject); + __webpack_require__.d(modules_stores_namespaceObject, { + JoinedAt: () => joinedAt, + LastMessage: () => stores_lastMessage + }); + const constants_namespaceObject = Modules["@discord/constants"]; + const flux_namespaceObject = Modules["@discord/flux"]; + const i18n_namespaceObject = Modules["@discord/i18n"]; + var i18n_default = __webpack_require__.n(i18n_namespaceObject); + const modules_namespaceObject = Modules["@discord/modules"]; + const stores_namespaceObject = Modules["@discord/stores"]; + const external_PluginApi_namespaceObject = PluginApi; + const external_BasePlugin_namespaceObject = BasePlugin; + var external_BasePlugin_default = __webpack_require__.n(external_BasePlugin_namespaceObject); + const DefaultMessage = { + state: "SENT", + author: { + avatar: "betterdiscord", + id: "81388395867156480", + bot: true, + discriminator: "5000", + username: "BetterDiscord" + }, + content: "Hello <:zere_zoom:477825238172958730>" + }; + const MessageCreators = BdApi.findModuleByProps("createBotMessage"); + const MessageActions = BdApi.findModuleByProps("receiveMessage"); + const AvatarDefaults = BdApi.findModuleByProps("BOT_AVATARS"); + if (AvatarDefaults?.BOT_AVATARS && !AvatarDefaults.BOT_AVATARS.betterdiscord) AvatarDefaults.BOT_AVATARS.betterdiscord = "https://github.com/BetterDiscord.png"; + function sendMessage(channelId, message) { + MessageActions.receiveMessage(channelId, Object.assign({}, MessageCreators.createBotMessage(channelId, message?.content), DefaultMessage, message)); + } + const Clyde = { + sendMessage, + DefaultMessage + }; + const clyde = Clyde; + const DiscordCommands = BdApi.findModuleByProps("BUILT_IN_COMMANDS"); + const DiscordCommandTypes = BdApi.findModuleByProps("ApplicationCommandType"); + const Types = DiscordCommandTypes.ApplicationCommandType; + const OptionTypes = DiscordCommandTypes.ApplicationCommandOptionType; + const PermissionTypes = DiscordCommandTypes.ApplicationCommandPermissionType; + if (!DiscordCommands.BUILT_IN_SECTIONS["betterdiscord"]) DiscordCommands.BUILT_IN_SECTIONS["betterdiscord"] = { + icon: "https://github.com/BetterDiscord.png", + id: "betterdiscord", + name: "BetterDiscord", + type: 0 + }; + function registerCommand(caller, options) { + const cmd = Object.assign({}, options, { + __registerId: caller, + applicationId: "betterdiscord", + type: Types.BOT, + target: 1 + }); + DiscordCommands.BUILT_IN_COMMANDS.push(cmd); + return () => { + const index = DiscordCommands.BUILT_IN_COMMANDS.indexOf(cmd); + if (index < 0) return false; + DiscordCommands.BUILT_IN_COMMANDS.splice(index, 1); + }; + } + function unregisterAllCommands(caller) { + let index = DiscordCommands.BUILT_IN_COMMANDS.findIndex((cmd => cmd.__registerId === caller)); + while (index > -1) { + DiscordCommands.BUILT_IN_COMMANDS.splice(index, 1); + index = DiscordCommands.BUILT_IN_COMMANDS.findIndex((cmd => cmd.__registerId === caller)); + } + } + const Commands = { + registerCommand, + unregisterAllCommands + }; + const commands = Commands; + function SuppressErrors(func, onError = (() => {})) { + const wrapped = function() { + try { + return func.apply(this, arguments); + } catch (error) { + onError(error); + } + }; + Object.assign(wrapped, func); + wrapped.toString = () => func.toString(); + return wrapped; + } + var external_BdApi_React_ = __webpack_require__(113); + var external_BdApi_React_default = __webpack_require__.n(external_BdApi_React_); + const external_StyleLoader_namespaceObject = StyleLoader; + var external_StyleLoader_default = __webpack_require__.n(external_StyleLoader_namespaceObject); + const components_namespaceObject = Modules["@discord/components"]; + const connections_namespaceObject = Modules["@discord/connections"]; + var connections_default = __webpack_require__.n(connections_namespaceObject); + var badge = __webpack_require__(173); + const utils_namespaceObject = Modules["@discord/utils"]; + const package_namespaceObject = JSON.parse('{"um":{"u2":"UserDetails"}}'); + function _defineProperty(obj, key, value) { + if (key in obj) Object.defineProperty(obj, key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else obj[key] = value; + return obj; + } + class SettingsManager extends flux_namespaceObject.Store { + constructor(pluginName, defaultSettings = {}) { + super(modules_namespaceObject.Dispatcher, {}); + _defineProperty(this, "settings", void 0); + _defineProperty(this, "pluginName", void 0); + _defineProperty(this, "get", ((key, defaultValue) => this.settings[key] ?? defaultValue)); + _defineProperty(this, "set", ((key, value) => { + this.settings[key] = value; + external_PluginApi_namespaceObject.PluginUtilities.saveSettings(this.pluginName, this.settings); + this.emitChange(); + return value; + })); + this.pluginName = pluginName; + this.settings = external_PluginApi_namespaceObject.PluginUtilities.loadSettings(pluginName, defaultSettings); + } + } + const Settings = new SettingsManager(package_namespaceObject.um.u2); + const modules_Settings = Settings; + var flowerstar = __webpack_require__(564); + function _extends() { + _extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return _extends.apply(this, arguments); + } + const icons_flowerstar = props => external_BdApi_React_default().createElement("div", _extends({}, props, { + className: (0, utils_namespaceObject.joinClassNames)(flowerstar.Z.wrapper, props.className) + }), external_BdApi_React_default().createElement("svg", { + width: "16", + height: "16", + viewBox: "0 0 16 15.2", + className: flowerstar.Z.container + }, external_BdApi_React_default().createElement("path", { + fill: "#4f545c", + "fill-rule": "evenodd", + d: "m16 7.6c0 .79-1.28 1.38-1.52 2.09s.44 2 0 2.59-1.84.35-2.46.8-.79 1.84-1.54 2.09-1.67-.8-2.47-.8-1.75 1-2.47.8-.92-1.64-1.54-2.09-2-.18-2.46-.8.23-1.84 0-2.59-1.54-1.3-1.54-2.09 1.28-1.38 1.52-2.09-.44-2 0-2.59 1.85-.35 2.48-.8.78-1.84 1.53-2.12 1.67.83 2.47.83 1.75-1 2.47-.8.91 1.64 1.53 2.09 2 .18 2.46.8-.23 1.84 0 2.59 1.54 1.3 1.54 2.09z" + })), external_BdApi_React_default().createElement("svg", { + className: flowerstar.Z.tick, + width: "16", + height: "16", + viewBox: "0 0 16 15.2" + }, external_BdApi_React_default().createElement("path", { + d: "M7.4,11.17,4,8.62,5,7.26l2,1.53L10.64,4l1.36,1Z", + fill: "#ffffff" + }))); + const contextmenu_namespaceObject = Modules["@discord/contextmenu"]; + const native_namespaceObject = Modules["@discord/native"]; + const external_window_namespaceObject = window._; + var external_window_default = __webpack_require__.n(external_window_namespaceObject); + function Utilities_extends() { + Utilities_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return Utilities_extends.apply(this, arguments); + } + const FormItem = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("FormItem"); + const FormText = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("FormText"); + const FormDivider = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("FormDivider"); + const Flex = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("Flex"); + const { + marginBottom8 + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("marginBottom8"); + class Utilities extends external_PluginApi_namespaceObject.Utilities { + static getIconURL(type, colored = modules_Settings.get("coloredConnectionsIcons", true)) { + switch (type) { + case "steam": + return colored ? "lightSVG" : "darkSVG"; + case "xbox": + return colored ? "customPNG" : "whiteSVG"; + case "youtube": + return colored ? "darkSVG" : "whitePNG"; + case "epicgames": + return colored ? "lightSVG" : "whitePNG"; + default: + return colored ? "darkSVG" : "whitePNG"; + } + } + static joinClassNames(...classNames) { + return classNames.filter((e => e)).join(" "); + } + static get useForceUpdate() { + return () => (0, external_BdApi_React_.useReducer)((n => n + 1), 0)[1]; + } + static createUpdateWrapper(Component, form = true, valueProp = "value") { + return props => { + const [state, setState] = (0, external_BdApi_React_.useState)(props[valueProp]); + props[valueProp] = state; + if (form) return external_BdApi_React_default().createElement(Flex, { + className: marginBottom8, + direction: Flex.Direction.VERTICAL + }, external_BdApi_React_default().createElement(FormItem, { + title: props.name + }, external_BdApi_React_default().createElement(Component, Utilities_extends({}, props, { + onChange: value => { + value = value.value ?? value; + setState(value); + props.onChange(value); + } + })), external_BdApi_React_default().createElement(FormText, { + type: "description", + disabled: Boolean(props.note) + }, props.note)), external_BdApi_React_default().createElement(FormDivider, null)); + else return external_BdApi_React_default().createElement(Component, Utilities_extends({}, props, { + onChange: value => { + value = value.value ?? value; + setState(value); + props.onChange(value); + } + })); + }; + } + static makeLazy(factory) { + let cache = { + value: null, + ran: false + }; + return () => cache.ran ? cache.value : (cache.ran = true, cache.value = factory()); + } + static getLazy(filter) { + const fromCache = external_PluginApi_namespaceObject.WebpackModules.getModule(filter); + if (fromCache) return Promise.resolve(fromCache); + return new Promise((resolve => { + const cancel = external_PluginApi_namespaceObject.WebpackModules.addListener((m => { + const matches = [m, m?.default]; + for (let i = 0; i < matches.length; i++) { + if (!matches[i] || !filter(matches[i])) continue; + resolve(matches[i]); + cancel(); + break; + } + })); + })); + } + } + var styles = __webpack_require__(965); + function badge_extends() { + badge_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return badge_extends.apply(this, arguments); + } + function Badge({ + item + }) { + const connection = connections_default().get(item.type); + const onClick = () => { + try { + open(connection.getPlatformUserUrl(item), "_blank"); + } catch {} + }; + const onContextMenu = e => { + (0, contextmenu_namespaceObject.openContextMenu)(e, (() => external_BdApi_React_default().createElement(contextmenu_namespaceObject.Menu, { + navId: "connections-context", + onClose: contextmenu_namespaceObject.closeContextMenu + }, external_BdApi_React_default().createElement(contextmenu_namespaceObject.MenuGroup, null, external_BdApi_React_default().createElement(contextmenu_namespaceObject.MenuItem, { + id: "copy-connection-id", + label: i18n_namespaceObject.Messages.COPY_ID, + action: () => (0, native_namespaceObject.copy)(item.id) + }))))); + }; + const shouldVerified = modules_Settings.get("showVerifiedConnections", true) && item.verified; + return external_BdApi_React_default().createElement(components_namespaceObject.Tooltip, { + text: `${external_window_default().upperFirst(item.type)}: ${item.name}`, + tooltipClassName: styles.Z.tooltip + }, (props => external_BdApi_React_default().createElement("div", badge_extends({}, props, { + onClick, + className: (0, utils_namespaceObject.joinClassNames)(badge.Z.connection, { + [badge.Z.verified]: shouldVerified + }) + }), external_BdApi_React_default().createElement("img", { + onContextMenu, + src: connection.icon[Utilities.getIconURL(item.type)] + }), shouldVerified && external_BdApi_React_default().createElement(icons_flowerstar, { + className: badge.Z.verifiedBadge + })))); + } + function circle_extends() { + circle_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return circle_extends.apply(this, arguments); + } + const circle = props => external_BdApi_React_default().createElement("svg", circle_extends({}, props, { + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 36 36" + }), external_BdApi_React_default().createElement("circle", { + cx: "18", + cy: "18", + r: "18" + })); + function error_extends() { + error_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return error_extends.apply(this, arguments); + } + const error = props => external_BdApi_React_default().createElement("svg", error_extends({ + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 24 24", + fill: "#ddd", + width: "24", + height: "24" + }, props), external_BdApi_React_default().createElement("path", { + d: "M0 0h24v24H0z", + fill: "none" + }), external_BdApi_React_default().createElement("path", { + d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z" + })); + var apis_connections = __webpack_require__(597); + const actions_namespaceObject = Modules["@discord/actions"]; + const nl_namespaceObject = JSON.parse('{"CONNECTIONS":"Verbindingen","NO_CONNECTIONS":"Geen verbindingen!","LOADING_CONNECTIONS":"Verbindingen aan het laden...","LOADING_LAST_MESSAGE":"Laatste bericht aan het laden...","LOADING_JOINED_AT":"Lid geworden op aan het laden...","MEMBER_WAS_NOT_FOUND":"Lid kon niet worden gevonden!","FAILED_TO_FETCH":"Gefaald om op te halen!","USERINFO_CMD_DESC":"Laat bepaalde informatie zien over een bepaald lid.","NO_MUTUAL_GUILDS":"Geen gemeenschappelijke servers","LOADING_MUTUAL_GUILDS":"Gemeenschappelijke servers aan het laden...","LOADING_MUTUAL_FRIENDS":"Gemeenschappelijke vrienden aan het laden...","NO_MUTUAL_FRIENDS":"Geen gemeenschappelijke vrienden"}'); + var locales_nl_namespaceObject = __webpack_require__.t(nl_namespaceObject, 2); + const de_namespaceObject = JSON.parse('{"CONNECTIONS":"Verknüpfungen","NO_CONNECTIONS":"Keine Verknüpfungen","LOADING_CONNECTIONS":"Lade Verknüpfungen...","LOADING_LAST_MESSAGE":"Lade letzte Nachricht...","LOADING_JOINED_AT":"Lade Beitrittsdatum...","MEMBER_WAS_NOT_FOUND":"Mitglied konnte nicht gefunden werden.","FAILED_TO_FETCH":"Fehler beim Laden","USERINFO_CMD_DESC":"Zeigt einige Informationen über einen bestimmten Nutzer.","NO_MUTUAL_GUILDS":"Keine gemeinsamen Server","LOADING_MUTUAL_GUILDS":"Gemeinsame Server werden geladen.","LOADING_MUTUAL_FRIENDS":"Gemeinsame Freunde werden geladen...","NO_MUTUAL_FRIENDS":"Keine gemeinsamen Freunde"}'); + var locales_de_namespaceObject = __webpack_require__.t(de_namespaceObject, 2); + const en_US_namespaceObject = JSON.parse('{"CONNECTIONS":"Connections","NO_CONNECTIONS":"No Connections","LOADING_CONNECTIONS":"Loading Connections...","LOADING_LAST_MESSAGE":"Loading Last Message","LOADING_JOINED_AT":"Loading Joined At","MEMBER_WAS_NOT_FOUND":"Member Was Not Found!","FAILED_TO_FETCH":"Failed To Fetch","USERINFO_CMD_DESC":"User Information","NO_MUTUAL_GUILDS":"No mutual guilds","LOADING_MUTUAL_GUILDS":"Loading mutual guilds...","LOADING_MUTUAL_FRIENDS":"Loading mutual friends...","NO_MUTUAL_FRIENDS":"No mutual friends"}'); + var locales_en_US_namespaceObject = __webpack_require__.t(en_US_namespaceObject, 2); + const tr_namespaceObject = JSON.parse('{"CONNECTIONS":"Bağlantılar","NO_CONNECTIONS":"Bağlantı yok!","LOADING_CONNECTIONS":"Bağlantılar yükleniyor..","LOADING_LAST_MESSAGE":"Son mesaj yükleniyor..","LOADING_JOINED_AT":"Giriş tarihi yükleniyor..","MEMBER_WAS_NOT_FOUND":"Kullanıcı bulunamadı!","FAILED_TO_FETCH":"Alınamadı!","USERINFO_CMD_DESC":"Belirli bir kullanıcı hakkında bazı bilgiler verir.","NO_MUTUAL_GUILDS":"Ortak sunucu yok!","LOADING_MUTUAL_GUILDS":"Ortak sunucular yükleniyor!","LOADING_MUTUAL_FRIENDS":"Ortak arkadaşları yüklüyorum...","NO_MUTUAL_FRIENDS":"Ortak arkadaş yok"}'); + var locales_tr_namespaceObject = __webpack_require__.t(tr_namespaceObject, 2); + const fr_namespaceObject = JSON.parse('{"CONNECTIONS":"Connexions","NO_CONNECTIONS":"Pas de connexion!","LOADING_CONNECTIONS":"Chargement des connexions...","LOADING_LAST_MESSAGE":"Chargement du dernier message...","LOADING_JOINED_AT":"Chargement de la date d\'entrée...","MEMBER_WAS_NOT_FOUND":"Membre non trouvé","FAILED_TO_FETCH":"Échec de la récupération","USERINFO_CMD_DESC":"Informations sur un utilisateur spécifique","NO_MUTUAL_GUILDS":"Pas de serveur en commun","LOADING_MUTUAL_GUILDS":"Chargement des serveurs en communs...","LOADING_MUTUAL_FRIENDS":"Chargement des amis en communs...","NO_MUTUAL_FRIENDS":"Aucun ami en commun"}'); + const vi_namespaceObject = JSON.parse('{"CONNECTIONS":"Kết nối","NO_CONNECTIONS":"Không có kết nối!","LOADING_CONNECTIONS":"Đang tải các kết nối...","LOADING_LAST_MESSAGE":"Đang tải tin nhắn cuối cùng...","LOADING_JOINED_AT":"Đang tải ngày tham gia...","MEMBER_WAS_NOT_FOUND":"Không tìm thấy thành viên!","FAILED_TO_FETCH":"Nạp dữ liệu thất bại!","USERINFO_CMD_DESC":"Hiển thị một số thông tin về một người dùng cụ thể.","NO_MUTUAL_GUILDS":"Không có server chung nào","LOADING_MUTUAL_GUILDS":"Đang tải server chung...","LOADING_MUTUAL_FRIENDS":"Đang tải bạn chung...","NO_MUTUAL_FRIENDS":"Không có bạn chung nào"}'); + const es_ES_namespaceObject = JSON.parse('{"CONNECTIONS":"Conexiones","NO_CONNECTIONS":"Sin conexiones","LOADING_CONNECTIONS":"Cargando conexiones...","LOADING_LAST_MESSAGE":"Cargando el último mensaje...","LOADING_JOINED_AT":"Cargando la fecha de ingreso...","MEMBER_WAS_NOT_FOUND":"¡El miembro no fue encontrado!","FAILED_TO_FETCH":"¡No se pudo obtener!","USERINFO_CMD_DESC":"Muestra información sobre un usuario en específico.","NO_MUTUAL_GUILDS":"Sin servidores en común","LOADING_MUTUAL_GUILDS":"Cargando los servidores en común...","LOADING_MUTUAL_FRIENDS":"Cargando amigos mútuos...","NO_MUTUAL_FRIENDS":"Sin amigos mútuos"}'); + const sv_SE_namespaceObject = JSON.parse('{"CONNECTIONS":"anslutningar","NO_CONNECTIONS":"inga anslutningar","LOADING_CONNECTIONS":"laddar anslutningar","LOADING_LAST_MESSAGE":"läser in det senaste meddelandet","LOADING_JOINED_AT":"lastning gick med vid","MEMBER_WAS_NOT_FOUND":"medlem hittades inte","FAILED_TO_FETCH":"misslyckades med att hämta","USERINFO_CMD_DESC":"visar lite information om en specifik användare","NO_MUTUAL_GUILDS":"inga ömsesidiga servrar","LOADING_MUTUAL_GUILDS":"laddar ömsesidiga servrar"}'); + const pt_BR_namespaceObject = JSON.parse('{"CONNECTIONS":"Conexões","NO_CONNECTIONS":"Sem conexões","LOADING_CONNECTIONS":"Carregando conexões","LOADING_LAST_MESSAGE":"Carregando última mensagem","LOADING_JOINED_AT":"Carregando entrou há","MEMBER_WAS_NOT_FOUND":"Membro não encontrado!","FAILED_TO_FETCH":"Falha na busca","USERINFO_CMD_DESC":"Mostra algumas informações de um usuário específico.","NO_MUTUAL_GUILDS":"Sem servidores em comum","LOADING_MUTUAL_GUILDS":"Carregando os servidores em comum","LOADING_MUTUAL_FRIENDS":"Carregando amigos em comum...","NO_MUTUAL_FRIENDS":"Sem amigos em comum."}'); + const locales = { + "en-US": locales_en_US_namespaceObject, + "es-ES": es_ES_namespaceObject, + "sv-SE": sv_SE_namespaceObject, + "pt-BR": pt_BR_namespaceObject, + nl: locales_nl_namespaceObject, + de: locales_de_namespaceObject, + tr: locales_tr_namespaceObject, + fr: fr_namespaceObject, + vi: vi_namespaceObject + }; + function strings_defineProperty(obj, key, value) { + if (key in obj) Object.defineProperty(obj, key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else obj[key] = value; + return obj; + } + class Strings { + static init() { + this.setLanguage(i18n_default().getLocale()); + modules_namespaceObject.Dispatcher.subscribe(constants_namespaceObject.ActionTypes.USER_SETTINGS_UPDATE, this.handleLocaleChange); + } + static shutdown() { + modules_namespaceObject.Dispatcher.unsubscribe(constants_namespaceObject.ActionTypes.USER_SETTINGS_UPDATE, this.handleLocaleChange); + } + static setLanguage(lang) { + this._strings = locales[lang] ?? locales["en-US"]; + } + static hasString(key) { + return null != this._strings[key] || null != locales["en-US"][key]; + } + static get(key) { + return this._strings[key] ?? locales["en-US"][key] ?? "String not found."; + } + } + strings_defineProperty(Strings, "_strings", void 0); + strings_defineProperty(Strings, "handleLocaleChange", (() => { + Strings.setLanguage(i18n_default().getLocale()); + })); + const { + Heading + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("Heading") ?? { + Heading: () => null + }; + const defaultConnections = Object.fromEntries(connections_default().map((item => [item.type, true]))); + function UserConnections({ + user + }) { + if (!connections_default().filter((c => modules_Settings.get("shownConnections", defaultConnections)[c.type])).length || user.bot || !modules_Settings.get("showConnectionsSection", true)) return null; + const connections = (0, flux_namespaceObject.useStateFromStores)([stores_namespaceObject.UserProfile], (() => stores_namespaceObject.UserProfile.getUserProfile(user.id)?.connectedAccounts)); + const [message, setMessage] = (0, external_BdApi_React_.useState)(""); + (0, external_BdApi_React_.useEffect)((() => { + if (Array.isArray(connections) || stores_namespaceObject.UserProfile.isFetching(user.id)) return; + modules_namespaceObject.Dispatcher.wait((() => { + actions_namespaceObject.ProfileActions.fetchProfile(user.id).catch((error => { + if (~error?.message?.indexOf("Already dispatching")) return; + external_PluginApi_namespaceObject.Logger.error(`Failed to fetch profile for ${user.id}:\n`, error); + setMessage(Strings.get("FAILED_TO_FETCH")); + })); + })); + }), []); + return external_BdApi_React_default().createElement("div", { + className: external_PluginApi_namespaceObject.Utilities.className(apis_connections.Z.connectionsBody, styles.Z.body) + }, !connections?.length && modules_Settings.get("showEmptyConnections", true) || connections?.length ? external_BdApi_React_default().createElement(Heading, { + level: 3, + variant: "eyebrow", + className: (0, utils_namespaceObject.joinClassNames)(apis_connections.Z.container, apis_connections.Z.header), + uppercase: true, + muted: true + }, Strings.get(connections?.length ? "CONNECTIONS" : "NO_CONNECTIONS")) : null, Array.isArray(connections) ? connections?.length ? external_BdApi_React_default().createElement("div", { + className: apis_connections.Z.connections + }, connections.filter((e => modules_Settings.get("shownConnections", defaultConnections)[e.type])).map((badge => external_BdApi_React_default().createElement(Badge, { + item: badge, + key: badge.type + })))) : null : message ? external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: message + }, external_BdApi_React_default().createElement(error, { + className: apis_connections.Z.errorIcon + })) : external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: Strings.get("LOADING_CONNECTIONS") + }, connections_default().filter((e => modules_Settings.get("shownConnections", defaultConnections)[e.type])).map((() => external_BdApi_React_default().createElement(circle, { + className: apis_connections.Z.loading + }))))); + } + function cake_extends() { + cake_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return cake_extends.apply(this, arguments); + } + const cake = props => external_BdApi_React_default().createElement("svg", cake_extends({}, props, { + xmlns: "http://www.w3.org/2000/svg", + height: "24", + viewBox: "0 0 24 24", + width: "24" + }), external_BdApi_React_default().createElement("g", null, external_BdApi_React_default().createElement("rect", { + fill: "none", + height: "24", + width: "24" + }), external_BdApi_React_default().createElement("g", null, external_BdApi_React_default().createElement("polygon", { + points: "2,22 16,17 7,8" + }), external_BdApi_React_default().createElement("path", { + d: "M14.53,12.53l5.59-5.59c0.49-0.49,1.28-0.49,1.77,0l0.59,0.59l1.06-1.06l-0.59-0.59c-1.07-1.07-2.82-1.07-3.89,0 l-5.59,5.59L14.53,12.53z" + }), external_BdApi_React_default().createElement("path", { + d: "M10.06,6.88L9.47,7.47l1.06,1.06l0.59-0.59c1.07-1.07,1.07-2.82,0-3.89l-0.59-0.59L9.47,4.53l0.59,0.59 C10.54,5.6,10.54,6.4,10.06,6.88z" + }), external_BdApi_React_default().createElement("path", { + d: "M17.06,11.88l-1.59,1.59l1.06,1.06l1.59-1.59c0.49-0.49,1.28-0.49,1.77,0l1.61,1.61l1.06-1.06l-1.61-1.61 C19.87,10.81,18.13,10.81,17.06,11.88z" + }), external_BdApi_React_default().createElement("path", { + d: "M15.06,5.88l-3.59,3.59l1.06,1.06l3.59-3.59c1.07-1.07,1.07-2.82,0-3.89l-1.59-1.59l-1.06,1.06l1.59,1.59 C15.54,4.6,15.54,5.4,15.06,5.88z" + })))); + const external_BdApi_ReactDOM_namespaceObject = BdApi.ReactDOM; + var external_BdApi_ReactDOM_default = __webpack_require__.n(external_BdApi_ReactDOM_namespaceObject); + var dates = __webpack_require__(242); + function textscroller_defineProperty(obj, key, value) { + if (key in obj) Object.defineProperty(obj, key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else obj[key] = value; + return obj; + } + const Animations = external_PluginApi_namespaceObject.WebpackModules.getByProps("Value"); + class TextScroller extends external_BdApi_React_default().Component { + constructor(...args) { + super(...args); + textscroller_defineProperty(this, "_ref", (instance => { + let element = external_BdApi_ReactDOM_default().findDOMNode(instance); + if (element && element.parentElement) { + let maxWidth = element.parentElement.innerWidth; + if (maxWidth > 50) element.style.setProperty("max-width", `${maxWidth}px`); + setTimeout((() => { + if (document.contains(element.parentElement)) { + let newMaxWidth = element.parentElement.innerWidth; + if (newMaxWidth > maxWidth) element.style.setProperty("max-width", `${newMaxWidth}px`); + } + }), 3e3); + let Animation = new Animations.Value(0); + Animation.interpolate({ + inputRange: [0, 1], + outputRange: [0, -1 * (element.firstElementChild.offsetWidth - element.offsetWidth)] + }).addListener((v => { + element.firstElementChild.style.setProperty("left", `${v.value}px`); + })); + this.scroll = p => { + let w = p + parseFloat(element.firstElementChild.style.getPropertyValue("left")) / (element.firstElementChild.offsetWidth - element.offsetWidth); + w = isNaN(w) || !isFinite(w) ? p : w; + w *= element.firstElementChild.offsetWidth / (2 * element.offsetWidth); + Animations.parallel([Animations.timing(Animation, { + toValue: p, + duration: 4e3 * Math.sqrt(w ** 2) / (parseInt(this.props.speed) || 1) + })]).start(); + }; + } + })); + textscroller_defineProperty(this, "_onClick", (e => { + if ("function" == typeof this.props.onClick) this.props.onClick(e, this); + })); + textscroller_defineProperty(this, "_onMouseEnter", (e => { + if (e.currentTarget.offsetWidth < e.currentTarget.firstElementChild.offsetWidth) { + this.scrolling = true; + e.currentTarget.firstElementChild.style.setProperty("display", "block"); + this.scroll(1); + } + })); + textscroller_defineProperty(this, "_onMouseLeave", (e => { + if (this.scrolling) { + delete this.scrolling; + e.currentTarget.firstElementChild.style.setProperty("display", "inline"); + this.scroll(0); + } + })); + } + render() { + const style = Object.assign({}, this.props.style, { + position: "relative", + display: "block", + overflow: "hidden" + }); + return external_BdApi_React_default().createElement("div", { + className: Utilities.joinClassNames(this.props.className, dates.Z.scrollableText), + style, + ref: this._ref, + onClick: this._onClick, + onMouseEnter: this._onMouseEnter, + onMouseLeave: this._onMouseLeave + }, external_BdApi_React_default().createElement("div", { + style: { + left: "0", + position: "relative", + display: "inline", + whiteSpace: "nowrap" + } + }, this.props.children)); + } + } + function useSettings(settings) { + return (0, flux_namespaceObject.useStateFromStores)([modules_Settings], (() => Object.fromEntries(Object.keys(settings).map((key => [key, modules_Settings.get(key, settings[key])]))))); + } + function extractDate(id) { + return new Date(id / 4194304 + 14200704e5); + } + function parseZeroPadding(zeroable) { + return zeroable <= 9 ? "0" + zeroable : zeroable; + } + function monthsAgo(date1, date2) { + let months = 12 * (date2.getFullYear() - date1.getFullYear()); + months -= date1.getMonth(); + months += date2.getMonth(); + months = Math.abs(months); + return months <= 0 ? 0 : months; + } + function daysAgo(date1, date2) { + return Math.floor((date1.getTime() - date2.getTime()) / (1e3 * 60 * 60 * 24)); + } + function yearsAgo(date1, date2) { + return monthsAgo(date2, date1) / 12; + } + function parseTime(format, date) { + if ("object" !== typeof date) date = new Date(date); + const today = new Date, + daysago = daysAgo(today, date), + hour12 = 0 === modules_Settings.get("12hour", 1); + return format.replace(/\$timelabel/g, date.getHours() >= 12 ? "PM" : "AM").replace(/\$daysago/g, daysago.toString()).replace(/\$dayname/g, date.toLocaleDateString("default", { + weekday: "short", + hour12 + })).replace(/\$day/g, date.toLocaleDateString("default", { + day: "2-digit", + hour12 + })).replace(/\$monthname/g, date.toLocaleDateString("default", { + month: "short", + hour12 + })).replace(/\$monthsago/g, monthsAgo(today, date).toString()).replace(/\$month/g, date.toLocaleDateString("default", { + month: "2-digit", + hour12 + })).replace(/\$weeksago/g, Math.floor(daysago / 7).toString()).replace(/\$yearsago/g, Math.floor(yearsAgo(today, date)).toString()).replace(/\$year/g, date.getFullYear().toString()).replace(/\$hour/g, parseZeroPadding(hour12 ? date.getHours() % 12 : date.getHours()).toString()).replace(/\$minute/g, parseZeroPadding(date.getMinutes()).toString()).replace(/\$second/g, parseZeroPadding(date.getSeconds()).toString()); + } + const DEFAULT_FORMAT = "Created At: $hour:$minute:$second, $day.$month.$year $daysago days"; + function CreatedAt({ + userId + }) { + const format = modules_Settings.get("created_format", DEFAULT_FORMAT); + const text = parseTime(format, extractDate(userId)); + return modules_Settings.get("useIcons", true) ? external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text + }, external_BdApi_React_default().createElement(cake, null)) : external_BdApi_React_default().createElement(TextScroller, null, text); + } + function calendar_extends() { + calendar_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return calendar_extends.apply(this, arguments); + } + const calendar = props => external_BdApi_React_default().createElement("svg", calendar_extends({}, props, { + xmlns: "http://www.w3.org/2000/svg", + height: "24", + viewBox: "0 0 24 24", + width: "24" + }), external_BdApi_React_default().createElement("path", { + d: "M0 0h24v24H0z", + fill: "none" + }), external_BdApi_React_default().createElement("path", { + d: "M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z" + })); + function cube_extends() { + cube_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return cube_extends.apply(this, arguments); + } + const cube = props => external_BdApi_React_default().createElement("svg", cube_extends({}, props, { + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 36 36" + }), external_BdApi_React_default().createElement("path", { + d: "M36 32c0 2.209-1.791 4-4 4H4c-2.209 0-4-1.791-4-4V4c0-2.209 1.791-4 4-4h28c2.209 0 4 1.791 4 4v28z" + })); + var style = __webpack_require__(562); + function reducer(state) { + if (state >= 3) return 1; + else return state + 1; + } + function LoadingText() { + const [state, dispatch] = (0, external_BdApi_React_.useReducer)(reducer, 1); + (0, external_BdApi_React_.useEffect)((() => { + const interval = setInterval((() => { + dispatch(); + }), 500); + return () => { + clearInterval(interval); + }; + }), []); + return external_BdApi_React_default().createElement("div", { + className: style.Z.loadingText + }, ".".repeat(state)); + } + function joinedAt_defineProperty(obj, key, value) { + if (key in obj) Object.defineProperty(obj, key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else obj[key] = value; + return obj; + } + const resolveId = function(guildId, userId) { + return `${guildId}_${userId}`; + }; + const JoinedAtDates = new Map, + fetchingQueue = new Set; + let stopped = false; + const handleGuildMembersChunk = function(data) { + if (stopped || !data || !Array.isArray(data.members)) return; + if (data.notFound?.length) + for (let i = 0; i < data.notFound.length; i++) { + const userId = data.notFound[i]; + fetchingQueue.delete(userId); + JoinedAtDates.set(resolveId(data.guildId, data.notFound[i]), { + data: "MEMBER_WAS_NOT_FOUND", + fetch: Date.now(), + status: "failure" + }); + } + for (let i = 0; i < data.members.length; i++) { + const member = data.members[i]; + if (!member || !member.user) continue; + fetchingQueue.delete(member.user.id); + JoinedAtDates.set(resolveId(data.guildId, member.user.id), { + data: new Date(member.joined_at), + fetch: Date.now(), + status: "success" + }); + } + }; + class JoinedAtStore extends flux_namespaceObject.Store { + constructor(...args) { + super(...args); + joinedAt_defineProperty(this, "logger", new utils_namespaceObject.Logger("JoinedAtStore")); + } + get fetching() { + return fetchingQueue; + } + getState() { + return JoinedAtDates; + } + clear() { + JoinedAtDates.clear(); + fetchingQueue.clear(); + } + has(guildId, userId) { + return null !== this.getDate(guildId, userId) && JoinedAtDates.has(resolveId(guildId, userId)); + } + isFetching(guildId, userId) { + return fetchingQueue.has(resolveId(guildId, userId)); + } + getDate(guildId, userId) { + const data = JoinedAtDates.get(resolveId(guildId, userId)); + if (!data || Date.now() - data.fetch > 6e5) return null; + return data; + } + destroy() { + stopped = true; + } + async fetch(guildId, userId) { + const id = resolveId(guildId, userId); + if (fetchingQueue.has(id)) return; + fetchingQueue.add(id); + if (stores_namespaceObject.Members.getMember(guildId, userId)) { + fetchingQueue.delete(id); + JoinedAtDates.set(id, { + data: new Date(stores_namespaceObject.Members.getMember(guildId, userId).joinedAt), + fetch: Date.now(), + status: "success" + }); + return this.emitChange(); + } + setTimeout((() => { + if (this.has(guildId, userId)) return; + JoinedAtDates.set(id, { + data: "FAILED_TO_FETCH", + fetch: Date.now(), + status: "failure" + }); + this.logger.error("Request timed out, didn't got a response after 1 minute."); + }), 6 * 1e4); + actions_namespaceObject.GuildActions.requestMembersById(guildId, userId); + } + } + const JoinedAt = new JoinedAtStore(modules_namespaceObject.Dispatcher, { + [constants_namespaceObject.ActionTypes.GUILD_MEMBERS_CHUNK]: handleGuildMembersChunk + }); + const joinedAt = JoinedAt; + const joinedDate_DEFAULT_FORMAT = "Joined At: $hour:$minute:$second, $day.$month.$year $daysago days"; + function JoinedAtDate({ + userId + }) { + const format = modules_Settings.get("joined_format", joinedDate_DEFAULT_FORMAT); + const guildId = stores_namespaceObject.SelectedGuilds.getGuildId(); + const joined = (0, flux_namespaceObject.useStateFromStores)([joinedAt], (() => joinedAt.getDate(guildId, userId))); + const [message, setMessage] = (0, external_BdApi_React_.useState)(""); + (0, external_BdApi_React_.useEffect)((() => { + if (joinedAt.has(guildId, userId) || joinedAt.isFetching(guildId, userId)) return; + if (!guildId) return void setMessage(Strings.get("FAILED_TO_FETCH")); + joinedAt.fetch(guildId, userId); + }), []); + const useIcons = modules_Settings.get("useIcons", true); + const isFailed = !joined || "failure" === joined.status; + return !isFailed ? useIcons ? external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: parseTime(format, joined.data) + }, external_BdApi_React_default().createElement(calendar, null)) : external_BdApi_React_default().createElement(TextScroller, null, parseTime(format, joined.data)) : message || isFailed && Strings.hasString(joined?.data) ? useIcons ? external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: message || Strings.get(joined.data) + }, external_BdApi_React_default().createElement(error, { + className: dates.Z.errorIcon + })) : external_BdApi_React_default().createElement(TextScroller, { + style: { + color: "red" + } + }, message || Strings.get(joined.data)) : external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: Strings.get("LOADING_JOINED_AT") + }, useIcons ? external_BdApi_React_default().createElement(cube, { + className: dates.Z.loading + }) : external_BdApi_React_default().createElement(LoadingText, null)); + } + function textbubble_extends() { + textbubble_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return textbubble_extends.apply(this, arguments); + } + const textbubble = props => external_BdApi_React_default().createElement("svg", textbubble_extends({}, props, { + xmlns: "http://www.w3.org/2000/svg", + height: "24", + viewBox: "0 0 24 24", + width: "24" + }), external_BdApi_React_default().createElement("path", { + d: "M0 0h24v24H0z", + fill: "none" + }), external_BdApi_React_default().createElement("path", { + d: "M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9 11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z" + })); + const sanitize_namespaceObject = Modules["@discord/sanitize"]; + const external_PluginApi_DiscordModules_namespaceObject = PluginApi.DiscordModules; + function lastMessage_defineProperty(obj, key, value) { + if (key in obj) Object.defineProperty(obj, key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else obj[key] = value; + return obj; + } + function lastMessage_resolveId(...args) { + return args.join("_"); + } + const lastMessage_fetchingQueue = new Set, + lastMessages = new Map; + function handleMessageCreate({ + message, + channelId + }) { + lastMessages.set(lastMessage_resolveId(message.author.id, channelId), { + channelId, + messageId: message.id, + data: new Date(message.timestamp), + fetch: Date.now(), + status: "success" + }); + } + function handleMessageDelete({ + messageId, + channelId + }) { + for (const [userId, result] of lastMessages) { + if (result.messageId !== messageId || result.channelId !== channelId) continue; + lastMessages.delete(lastMessage_resolveId(userId, channelId)); + } + } + class LastMessageStore extends flux_namespaceObject.Store { + constructor(...args) { + super(...args); + lastMessage_defineProperty(this, "paused", false); + lastMessage_defineProperty(this, "logger", new utils_namespaceObject.Logger("LastMessageStore")); + lastMessage_defineProperty(this, "MAX_RETRIES", 5); + } + get _users() { + return lastMessages; + } + get fetching() { + return lastMessage_fetchingQueue; + } + isFetching(userId, channelId) { + return lastMessage_fetchingQueue.has(lastMessage_resolveId(userId, channelId)); + } + get(userId, channelId) { + const cached = lastMessages.get(lastMessage_resolveId(userId, channelId)); + if (!cached || Date.now() - cached.fetch > 6e5) return null; + return cached; + } + has(userId, channelId) { + return null != this.get(userId, channelId) && lastMessages.has(lastMessage_resolveId(userId, channelId)); + } + fetch(userId, roomId, isGuild = false, attempt = 1) { + const id = lastMessage_resolveId(userId, roomId); + if (lastMessage_fetchingQueue.has(id) || this.paused) return Promise.resolve(); + if (attempt > this.MAX_RETRIES) { + lastMessage_fetchingQueue.delete(id); + lastMessages.set(id, { + channelId: roomId, + data: "FAILED_TO_FETCH", + fetch: Date.now(), + messageId: null, + status: "failure" + }); + this.logger.error(`Request failed after ${this.MAX_RETRIES} attempts.`); + this.emitChange(); + return Promise.resolve(); + } + lastMessage_fetchingQueue.add(id); + return new Promise(((resolve, reject) => { + external_PluginApi_DiscordModules_namespaceObject.APIModule.get({ + url: isGuild ? constants_namespaceObject.Endpoints.SEARCH_GUILD(roomId) : constants_namespaceObject.Endpoints.SEARCH_CHANNEL(roomId), + query: (0, sanitize_namespaceObject.stringify)({ + author_id: userId + }) + }).then((data => { + lastMessage_fetchingQueue.delete(id); + let message = null; + if (data?.body?.messages?.length) + for (const result of data.body.messages[0]) + if (result.hit && result.author.id === userId) { + message = result; + break; + } + if (message) lastMessages.set(id, { + data: new Date(message.timestamp), + fetch: Date.now(), + channelId: message.channel_id, + messageId: message.id, + status: "success" + }); + else { + lastMessages.set(id, { + data: "FAILED_TO_FETCH", + fetch: Date.now(), + channelId: roomId, + messageId: null, + status: "failure" + }); + this.logger.info(`No messages for ${userId} were found in ${roomId}.`); + } + this.emitChange(); + resolve(); + })).catch((error => { + if (429 === error.status) { + this.paused = true; + setTimeout((() => { + this.paused = false; + this.fetch(userId, roomId, isGuild, attempt).then(resolve).catch(reject); + }), error.body.retry_after + 1e3); + } else reject(error); + lastMessage_fetchingQueue.delete(id); + })); + })); + } + } + const LastMessage = new LastMessageStore(modules_namespaceObject.Dispatcher, { + MESSAGE_CREATE: handleMessageCreate, + MESSAGE_DELETE: handleMessageDelete + }); + const stores_lastMessage = LastMessage; + const lastMessage_DEFAULT_FORMAT = "Last Message: $hour:$minute:$second, $day.$month.$year $daysago days"; + function LastMessageDate({ + user + }) { + const format = modules_Settings.get("lastmessage_format", lastMessage_DEFAULT_FORMAT); + const roomId = stores_namespaceObject.SelectedGuilds.getGuildId() || stores_namespaceObject.SelectedChannels.getChannelId(); + const isGuild = Boolean(stores_namespaceObject.SelectedGuilds.getGuildId()); + const lastMessage = (0, flux_namespaceObject.useStateFromStores)([stores_lastMessage], (() => stores_lastMessage.get(user.id, roomId))); + const [errorMessage, setErrorMessage] = (0, external_BdApi_React_.useState)(""); + (0, external_BdApi_React_.useEffect)((() => { + if (stores_lastMessage.isFetching(user.id, roomId) || stores_lastMessage.has(user.id, roomId)) return; + if (!roomId) return setErrorMessage("Cannot resolve channel/guild id."); + stores_lastMessage.fetch(user.id, roomId, isGuild).catch((error => { + external_PluginApi_namespaceObject.Logger.error(`Failed to fetch LastMessage from ${user.tag}:\n`, error); + })); + }), []); + const transitionToMessage = () => { + if (!lastMessage.channelId || !lastMessage.messageId) return; + utils_namespaceObject.Navigation.replaceWith(isGuild ? `/channels/${stores_namespaceObject.SelectedGuilds.getGuildId()}/${lastMessage.channelId}/${lastMessage.messageId}` : `/channels/@me/${lastMessage.channelId}/${lastMessage.messageId}`); + }; + const failed = "failure" === lastMessage?.status; + const shouldUseIcon = modules_Settings.get("useIcons", true); + return lastMessage?.data && !failed ? shouldUseIcon ? external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: parseTime(format, lastMessage.data) + }, external_BdApi_React_default().createElement(textbubble, { + onClick: transitionToMessage + })) : external_BdApi_React_default().createElement(TextScroller, { + onClick: transitionToMessage + }, parseTime(format, lastMessage.data)) : errorMessage || failed && Strings.hasString(lastMessage.data) ? shouldUseIcon ? external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: errorMessage || Strings.get(lastMessage.data) + }, external_BdApi_React_default().createElement(error, { + className: dates.Z.errorIcon + })) : external_BdApi_React_default().createElement(TextScroller, { + style: { + color: "red" + } + }, errorMessage || Strings.get(lastMessage.data)) : external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: Strings.get("LOADING_LAST_MESSAGE") + }, shouldUseIcon ? external_BdApi_React_default().createElement(cube, { + className: dates.Z.loading + }) : external_BdApi_React_default().createElement(LoadingText, null)); + } + var apis_mutualFriends = __webpack_require__(675); + const { + Heading: mutualFriends_Heading + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("Heading") ?? { + Heading: () => null + }; + const WindowStore = external_PluginApi_namespaceObject.WebpackModules.getByProps("isFocused"); + const { + AnimatedAvatar, + Sizes + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("AnimatedAvatar"); + const UserProfileModal = external_PluginApi_namespaceObject.WebpackModules.getByProps("openUserProfileModal"); + const { + ComponentDispatch + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("ComponentDispatch") ?? {}; + function MutualFriend({ + user + }) { + const [isMouseOver, setMouseOver] = (0, external_BdApi_React_.useState)(false); + const isWindowFocused = (0, flux_namespaceObject.useStateFromStores)([WindowStore], (() => WindowStore.isFocused())); + return external_BdApi_React_default().createElement(components_namespaceObject.Tooltip, { + text: user.tag, + position: "top", + tooltipClassName: styles.Z.tooltip + }, (props => external_BdApi_React_default().createElement("div", { + className: apis_mutualFriends.Z.mutualFriend, + onMouseOver: () => (setMouseOver(true), props.onMouseEnter()), + onMouseLeave: () => (setMouseOver(false), props.onMouseLeave()), + onClick: () => { + UserProfileModal.openUserProfileModal({ + userId: user.id, + guildId: stores_namespaceObject.SelectedGuilds.getGuildId() + }); + ComponentDispatch.dispatchToLastSubscribed("POPOUT_CLOSE"); + } + }, external_BdApi_React_default().createElement(AnimatedAvatar, { + status: stores_namespaceObject.Status.getStatus(user.id), + size: Sizes.SIZE_32, + src: user.getAvatarURL(stores_namespaceObject.SelectedGuilds.getGuildId(), 32, isMouseOver && isWindowFocused) + })))); + } + function MutualFriends({ + user + }) { + const settings = useSettings({ + showMutualFriends: true, + hideMutualFriendsCurrentUser: true, + showEmptyMutualFriends: true, + stackMutualFriends: false + }); + if (!settings.showMutualFriends || settings.hideMutualFriendsCurrentUser && user.id === stores_namespaceObject.Users.getCurrentUser().id) return null; + const mutualFriends = (0, flux_namespaceObject.useStateFromStores)([stores_namespaceObject.UserProfile], (() => stores_namespaceObject.UserProfile.getMutualFriends(user.id))); + (0, external_BdApi_React_.useEffect)((() => { + if (Array.isArray(mutualFriends)) return; + modules_namespaceObject.Dispatcher.wait((() => actions_namespaceObject.ProfileActions.fetchMutualFriends(user.id))); + }), []); + return Array.isArray(mutualFriends) ? mutualFriends.length ? external_BdApi_React_default().createElement("div", { + className: external_PluginApi_namespaceObject.Utilities.className(apis_mutualFriends.Z.body, styles.Z.body) + }, external_BdApi_React_default().createElement(mutualFriends_Heading, { + level: 3, + variant: "eyebrow", + className: apis_mutualFriends.Z.header, + uppercase: true, + muted: true + }, i18n_namespaceObject.Messages.MUTUAL_FRIENDS), external_BdApi_React_default().createElement("div", { + className: (0, utils_namespaceObject.joinClassNames)(apis_mutualFriends.Z.friends, settings.stackMutualFriends && apis_mutualFriends.Z.stack) + }, mutualFriends.map((props => external_BdApi_React_default().createElement(MutualFriend, props))))) : settings.showEmptyMutualFriends && external_BdApi_React_default().createElement(mutualFriends_Heading, { + level: 3, + variant: "eyebrow", + className: apis_mutualFriends.Z.header, + uppercase: true, + muted: true + }, Strings.get("NO_MUTUAL_FRIENDS")) : external_BdApi_React_default().createElement(mutualFriends_Heading, { + level: 3, + variant: "eyebrow", + className: apis_mutualFriends.Z.header, + uppercase: true, + muted: true + }, Strings.get("LOADING_MUTUAL_FRIENDS")); + } + var mutualServers = __webpack_require__(416); + function mutualServers_extends() { + mutualServers_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return mutualServers_extends.apply(this, arguments); + } + const FriendsStore = external_PluginApi_namespaceObject.WebpackModules.getByProps("getMutualGuilds"); + const { + Heading: mutualServers_Heading + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("Heading") ?? { + Heading: () => null + }; + const mutualServers_WindowStore = external_PluginApi_namespaceObject.WebpackModules.getByProps("isFocused"); + function MutualServer({ + guild, + nick, + onClick + }) { + const [isMouseOver, setMouseOver] = (0, external_BdApi_React_.useState)(false); + const isWindowFocused = (0, flux_namespaceObject.useStateFromStores)([mutualServers_WindowStore], (() => mutualServers_WindowStore.isFocused())); + return external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + key: guild.id, + text: nick ? `${guild.name} (${nick})` : guild.name, + position: "top", + className: mutualServers.Z.mutualGuild, + tooltipClassName: styles.Z.tooltip + }, guild.icon ? external_BdApi_React_default().createElement("img", { + onMouseOver: () => setMouseOver(true), + onMouseLeave: () => setMouseOver(false), + src: guild.getIconURL(128, isMouseOver && isWindowFocused), + onClick: () => onClick(guild.id) + }) : external_BdApi_React_default().createElement("div", { + className: mutualServers.Z.guildAcronym, + onClick: () => onClick(guild.id) + }, guild.acronym)); + } + function MutualServers({ + user + }) { + const settings = useSettings({ + showMutualGuilds: true, + hideMutualGuildsCurrentUser: true, + stackMutualServers: false, + showEmptyMutualGuilds: true + }); + if (!settings.showMutualGuilds || settings.hideMutualGuildsCurrentUser && user.id === stores_namespaceObject.Users.getCurrentUser().id) return null; + const mutualGuilds = (0, flux_namespaceObject.useStateFromStores)([FriendsStore], (() => FriendsStore.getMutualGuilds(user.id))); + const [message, setMessage] = (0, external_BdApi_React_.useState)(""); + (0, external_BdApi_React_.useEffect)((() => { + if (Array.isArray(mutualGuilds) || stores_namespaceObject.UserProfile.isFetching(user.id)) return; + modules_namespaceObject.Dispatcher.wait((() => { + actions_namespaceObject.ProfileActions.fetchProfile(user.id).catch((error => { + if (~error?.message?.indexOf("Already dispatching")) return; + external_PluginApi_namespaceObject.Logger.error(`Failed to fetch profile for ${user.id}:\n`, error); + setMessage(Strings.get("FAILED_TO_FETCH")); + })); + })); + }), []); + return Array.isArray(mutualGuilds) ? mutualGuilds.length ? external_BdApi_React_default().createElement("div", { + className: external_PluginApi_namespaceObject.Utilities.className(mutualServers.Z.body, styles.Z.body) + }, external_BdApi_React_default().createElement(mutualServers_Heading, { + level: 3, + variant: "eyebrow", + className: mutualServers.Z.header, + uppercase: true, + muted: true + }, i18n_namespaceObject.Messages.MUTUAL_GUILDS), external_BdApi_React_default().createElement("div", { + className: (0, utils_namespaceObject.joinClassNames)(mutualServers.Z.guilds, settings.stackMutualServers && mutualServers.Z.stack) + }, mutualGuilds.map((props => external_BdApi_React_default().createElement(MutualServer, mutualServers_extends({}, props, { + onClick: actions_namespaceObject.GuildActions.transitionToGuildSync + })))))) : settings.showEmptyMutualGuilds && external_BdApi_React_default().createElement(mutualServers_Heading, { + level: 3, + variant: "eyebrow", + className: mutualServers.Z.header, + uppercase: true, + muted: true + }, Strings.get("NO_MUTUAL_GUILDS")) : external_BdApi_React_default().createElement(external_BdApi_React_default().Fragment, null, external_BdApi_React_default().createElement(mutualServers_Heading, { + level: 3, + variant: "eyebrow", + className: mutualServers.Z.header, + uppercase: true, + muted: true + }, Strings.get(message ? "NO_MUTUAL_GUILDS" : "LOADING_MUTUAL_GUILDS")), message && external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + text: message, + position: "top" + }, external_BdApi_React_default().createElement(error, null))); + } + var React = __webpack_require__(113); + function spotify_extends() { + spotify_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return spotify_extends.apply(this, arguments); + } + const spotify = props => React.createElement("svg", spotify_extends({}, props, { + width: "20", + height: "20", + viewBox: "0 0 65 65" + }), React.createElement("path", { + fill: "#1ED760", + d: "M32.5,0.5 C14.826888,0.5 0.5,14.826888 0.5,32.5 C0.5,50.173112 14.826888,64.5 32.5,64.5 C50.173112,64.5 64.5,50.173112 64.5,32.5 C64.5,14.826888 50.173112,0.5 32.5,0.5 Z M47.18,46.66 C46.6031412,47.595466 45.3795381,47.8902025 44.44,47.32 C36.93,42.73 27.44,41.69 16.33,44.23 C15.6145818,44.4464575 14.8381683,44.245926 14.3170501,43.7100969 C13.7959319,43.1742677 13.6170868,42.3925738 13.8533716,41.6834571 C14.0896564,40.9743403 14.7016337,40.4561564 15.44,40.34 C27.63,37.55 38.09,38.75 46.52,43.91 C47.4615306,44.487221 47.7569974,45.7183323 47.18,46.66 Z M51.1,37.95 C50.3770773,39.1205793 48.8441907,39.487042 47.67,38.77 C39.07,33.48 25.96,31.95 15.78,35.04 C14.9279216,35.2990176 14.0023844,35.0837812 13.3520294,34.4753684 C12.7016744,33.8669556 12.425306,32.9577988 12.6270294,32.0903684 C12.8287528,31.2229381 13.4779216,30.5290176 14.33,30.27 C25.95,26.74 40.4,28.45 50.28,34.52 C51.445766,35.2424019 51.8079122,36.7714637 51.09,37.94 L51.1,37.95 Z M51.44,28.88 C41.13,22.75 24.11,22.19 14.26,25.18 C13.2140022,25.5702637 12.0378133,25.3474036 11.207084,24.6015444 C10.3763547,23.8556852 10.0285164,22.7102178 10.3042349,21.6283692 C10.5799535,20.5465206 11.4336155,19.707266 12.52,19.45 C23.82,16.02 42.61,16.68 54.52,23.73 C55.8401426,24.6185116 56.2368626,26.3831995 55.4240137,27.7512295 C54.6111649,29.1192595 52.8715856,29.6146124 51.46,28.88 L51.44,28.88 Z" + })); + var twitch_React = __webpack_require__(113); + function twitch_extends() { + twitch_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return twitch_extends.apply(this, arguments); + } + const twitch = props => twitch_React.createElement("svg", twitch_extends({ + width: "20", + height: "20", + viewBox: "0 0 128 128" + }, props), twitch_React.createElement("defs", null, twitch_React.createElement("path", { + id: "color-a", + d: "M8.5542826,0 L0,22 L0,111.8 L30.7954173,111.8 L30.7954173,128 L48.1052598,128 L64.408716,111.8 L89.3670935,111.8 L122.980392,78.4 L122.980392,0 L8.5542826,0 Z M111.406951,72.6 L92.0843362,91.8 L61.2889188,91.8 L44.9854626,108 L44.9854626,91.8 L19.020699,91.8 L19.020699,11.4 L111.406951,11.4 L111.406951,72.6 Z M92.2856134,33.4 L92.2856134,66.8 L80.8128109,66.8 L80.8128109,33.4 L92.2856134,33.4 Z M61.4901961,33.4 L61.4901961,66.8 L50.0173935,66.8 L50.0173935,33.4 L61.4901961,33.4 Z" + })), twitch_React.createElement("g", { + fill: "none", + "fill-rule": "evenodd", + transform: "translate(3)" + }, twitch_React.createElement("polygon", { + fill: "#FFF", + "fill-rule": "nonzero", + points: "110.431 72.512 91.272 91.717 60.736 91.717 44.57 107.922 44.57 91.717 18.824 91.717 18.824 11.294 110.431 11.294" + }), twitch_React.createElement("mask", { + id: "color-b", + fill: "#fff" + }, twitch_React.createElement("use", { + xlinkHref: "#color-a" + })), twitch_React.createElement("use", { + fill: "#563194", + "fill-rule": "nonzero", + xlinkHref: "#color-a" + }))); + var youtube_React = __webpack_require__(113); + function youtube_extends() { + youtube_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return youtube_extends.apply(this, arguments); + } + const youtube = props => youtube_React.createElement("svg", youtube_extends({ + height: "20", + width: "20", + viewBox: "0 0 576 512" + }, props), youtube_React.createElement("path", { + fill: "#FF1A1A", + d: "M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z" + })); + var gamepad_React = __webpack_require__(113); + function gamepad_extends() { + gamepad_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return gamepad_extends.apply(this, arguments); + } + const gamepad = props => gamepad_React.createElement("svg", gamepad_extends({ + width: "20", + height: "20", + viewBox: "0 0 24 24" + }, props), gamepad_React.createElement("g", { + fill: "none", + "fill-rule": "evenodd" + }, gamepad_React.createElement("path", { + fill: "currentColor", + d: "M5.79335761,5 L18.2066424,5 C19.7805584,5 21.0868816,6.21634264 21.1990185,7.78625885 L21.8575059,17.0050826 C21.9307825,18.0309548 21.1585512,18.9219909 20.132679,18.9952675 C20.088523,18.9984215 20.0442685,19 20,19 C18.8245863,19 17.8000084,18.2000338 17.5149287,17.059715 L17,15 L7,15 L6.48507125,17.059715 C6.19999155,18.2000338 5.1754137,19 4,19 C2.97151413,19 2.13776159,18.1662475 2.13776159,17.1377616 C2.13776159,17.0934931 2.1393401,17.0492386 2.1424941,17.0050826 L2.80098151,7.78625885 C2.91311838,6.21634264 4.21944161,5 5.79335761,5 Z M14.5,10 C15.3284271,10 16,9.32842712 16,8.5 C16,7.67157288 15.3284271,7 14.5,7 C13.6715729,7 13,7.67157288 13,8.5 C13,9.32842712 13.6715729,10 14.5,10 Z M18.5,13 C19.3284271,13 20,12.3284271 20,11.5 C20,10.6715729 19.3284271,10 18.5,10 C17.6715729,10 17,10.6715729 17,11.5 C17,12.3284271 17.6715729,13 18.5,13 Z M6,9 L4,9 L4,11 L6,11 L6,13 L8,13 L8,11 L10,11 L10,9 L8,9 L8,7 L6,7 L6,9 Z" + }), gamepad_React.createElement("rect", { + width: "24", + height: "24" + }))); + var components_activity = __webpack_require__(755); + var googleChrome_React = __webpack_require__(113); + function googleChrome_extends() { + googleChrome_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return googleChrome_extends.apply(this, arguments); + } + const googleChrome = props => googleChrome_React.createElement("svg", googleChrome_extends({ + width: "20", + height: "20", + viewBox: "0 0 48 48" + }, props), googleChrome_React.createElement("path", { + fill: "#4caf50", + d: "M44,24c0,11.044-8.956,20-20,20S4,35.044,4,24S12.956,4,24,4S44,12.956,44,24z" + }), googleChrome_React.createElement("path", { + fill: "#ffc107", + d: "M24,4v20l8,4l-8.843,16c0.317,0,0.526,0,0.843,0c11.053,0,20-8.947,20-20S35.053,4,24,4z" + }), googleChrome_React.createElement("path", { + fill: "#4caf50", + d: "M44,24c0,11.044-8.956,20-20,20S4,35.044,4,24S12.956,4,24,4S44,12.956,44,24z" + }), googleChrome_React.createElement("path", { + fill: "#ffc107", + d: "M24,4v20l8,4l-8.843,16c0.317,0,0.526,0,0.843,0c11.053,0,20-8.947,20-20S35.053,4,24,4z" + }), googleChrome_React.createElement("path", { + fill: "#f44336", + d: "M41.84,15H24v13l-3-1L7.16,13.26H7.14C10.68,7.69,16.91,4,24,4C31.8,4,38.55,8.48,41.84,15z" + }), googleChrome_React.createElement("path", { + fill: "#dd2c00", + d: "M7.158,13.264l8.843,14.862L21,27L7.158,13.264z" + }), googleChrome_React.createElement("path", { + fill: "#558b2f", + d: "M23.157,44l8.934-16.059L28,25L23.157,44z" + }), googleChrome_React.createElement("path", { + fill: "#f9a825", + d: "M41.865,15H24l-1.579,4.58L41.865,15z" + }), googleChrome_React.createElement("path", { + fill: "#fff", + d: "M33,24c0,4.969-4.031,9-9,9s-9-4.031-9-9s4.031-9,9-9S33,19.031,33,24z" + }), googleChrome_React.createElement("path", { + fill: "#2196f3", + d: "M31,24c0,3.867-3.133,7-7,7s-7-3.133-7-7s3.133-7,7-7S31,20.133,31,24z" + })); + var activity_React = __webpack_require__(113); + const byName = [ + [/spotify/i, spotify], + [/youtube/i, () => activity_React.createElement("img", { + src: connections_default().get("youtube").icon.darkSVG, + width: "20", + height: "20" + })], + [/twitch/i, twitch], + [/google\schrome/i, googleChrome] + ]; + function ActivityIcon({ + activity + }) { + const { + game, + showGamepad + } = (0, flux_namespaceObject.useStateFromStoresObject)([stores_namespaceObject.Games, modules_Settings], (() => ({ + showGamepad: modules_Settings.get("showGamepad", true), + game: stores_namespaceObject.Games.getGame(activity.application_id) + })), [activity]); + const icon = (0, external_BdApi_React_.useMemo)((() => byName.find((([regex]) => regex.test(activity.name || activity.id)))), [game]); + if (icon) { + const Icon = icon[1]; + return activity_React.createElement(Icon, null); + } + if (game && game.getIconURL()) return activity_React.createElement("img", { + src: game.getIconURL(), + width: "20", + height: "20" + }); + return showGamepad ? activity_React.createElement(gamepad, null) : null; + } + function noopNull() { + return null; + } + function ActivitiesFilter(activity, index, target) { + if (4 === activity?.type) return false; + return target.indexOf(activity) === index; + } + function Activity({ + user + }) { + const { + activity, + showActivityIcons, + disabled + } = (0, flux_namespaceObject.useStateFromStoresObject)([stores_namespaceObject.Status, modules_Settings], (() => ({ + activity: stores_namespaceObject.Status.getActivities(user.id).filter(ActivitiesFilter)[0], + showActivityIcons: modules_Settings.get("activityIcons", true), + disabled: user?.bot && modules_Settings.get("disableIconsForBots", true) + })), [user]); + if (!showActivityIcons || !activity || disabled) return null; + return activity_React.createElement(components_namespaceObject.TooltipContainer, { + text: activity.name, + className: components_activity.Z.container, + position: "left" + }, activity_React.createElement(ActivityIcon, { + className: components_activity.Z.icon, + activity + })); + } + class Logger { + static error(...message) { + this._log("error", ...message); + } + static warn(...message) { + this._log("warn", ...message); + } + static info(...message) { + this._log("info", ...message); + } + static log(...message) { + this._log("log", ...message); + } + static _log(level = "log", ...message) { + console[level](`%c[${package_namespaceObject.um.u2}]%c`, "color: #0870f3; font-weight: 700;", "", ...message); + } + } + function errorboundary_defineProperty(obj, key, value) { + if (key in obj) Object.defineProperty(obj, key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else obj[key] = value; + return obj; + } + class ErrorBoundary extends external_BdApi_React_default().Component { + constructor(...args) { + super(...args); + errorboundary_defineProperty(this, "state", { + hasError: false, + error: null, + info: null + }); + } + componentDidCatch(error, info) { + this.setState({ + error, + info, + hasError: true + }); + Logger.error(`[ErrorBoundary:${this.props.id}] HI OVER HERE!! SHOW THIS SCREENSHOT TO THE DEVELOPER.\n`, error); + } + render() { + if (this.state.hasError) return this.props.mini ? external_BdApi_React_default().createElement(error, { + fill: "#f04747" + }) : external_BdApi_React_default().createElement("div", null, external_BdApi_React_default().createElement("span", null, "An error has occured while rendering ", this.props.id, "."), external_BdApi_React_default().createElement("span", null, "Open console (", external_BdApi_React_default().createElement("code", null, "Ctrl + shift + i / Cmd + shift + i"), ') - Select the "Console" tab and screenshot the big red error.')); + else return this.props.children; + } + } + var headphones_React = __webpack_require__(113); + function headphones_extends() { + headphones_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return headphones_extends.apply(this, arguments); + } + const headphones = props => headphones_React.createElement("svg", headphones_extends({ + width: "20", + height: "20", + viewBox: "0 0 24 24" + }, props), headphones_React.createElement("svg", { + width: "24", + height: "24", + viewBox: "0 0 24 24" + }, headphones_React.createElement("path", { + d: "M12 2.00305C6.486 2.00305 2 6.48805 2 12.0031V20.0031C2 21.1071 2.895 22.0031 4 22.0031H6C7.104 22.0031 8 21.1071 8 20.0031V17.0031C8 15.8991 7.104 15.0031 6 15.0031H4V12.0031C4 7.59105 7.589 4.00305 12 4.00305C16.411 4.00305 20 7.59105 20 12.0031V15.0031H18C16.896 15.0031 16 15.8991 16 17.0031V20.0031C16 21.1071 16.896 22.0031 18 22.0031H20C21.104 22.0031 22 21.1071 22 20.0031V12.0031C22 6.48805 17.514 2.00305 12 2.00305Z", + fill: "currentColor" + }))); + var memberroles_React = __webpack_require__(113); + const textNames = new Set(["Text", "LegacyText"]); + const Text = external_PluginApi_namespaceObject.WebpackModules.getModule((m => textNames.has(m.displayName))); + const { + default: MemberRolesList + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("MemberRole") ?? { + default: () => null + }; + const classes = Utilities.makeLazy((() => external_PluginApi_namespaceObject.WebpackModules.getByProps("userInfoSectionHeader"))); + const { + Heading: memberroles_Heading + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("Heading") ?? { + Heading: () => null + }; + function MemberRolesSection({ + userId, + guildId = stores_namespaceObject.SelectedGuilds.getGuildId() + }) { + const roles = (0, flux_namespaceObject.useStateFromStoresArray)([stores_namespaceObject.Members], (() => stores_namespaceObject.Members.getMember(guildId, userId)?.roles)); + const guild = (0, flux_namespaceObject.useStateFromStores)([stores_namespaceObject.Guilds], (() => stores_namespaceObject.Guilds.getGuild(guildId))); + const user = (0, flux_namespaceObject.useStateFromStores)([stores_namespaceObject.Users], (() => stores_namespaceObject.Users.getUser(userId))); + if (!roles || !guild || !user) return null; + return memberroles_React.createElement(ErrorBoundary, { + id: "MemberRolesSection" + }, memberroles_React.createElement("div", { + className: (0, utils_namespaceObject.joinClassNames)(classes()?.userInfoSection, Text?.Colors?.STANDARD) + }, memberroles_React.createElement(memberroles_Heading, { + level: 3, + variant: "eyebrow", + uppercase: true, + className: classes()?.userInfoSectionHeader + }, i18n_namespaceObject.Messages.ROLES_LIST.format({ + numRoles: roles.length + })), memberroles_React.createElement(MemberRolesList, { + guild, + user, + userRoles: roles + }))); + } + const pages_namespaceObject = JSON.parse('[{"name":"General","icon":"Wrench","items":[{"type":"switch","name":"Use Icons","note":"Defines if icons should be used to show any date.","id":"useIcons","value":true},{"type":"radio","name":"Time Format","value":1,"id":"12hour","options":[{"value":1,"name":"24 hour"},{"value":0,"name":"12 hour"}]},{"type":"divider"},{"type":"category","name":"Variables","items":[{"type":"replacement","prefix":"$timelabel","description":"Replaces the current time label. eg AM or PM."},{"type":"replacement","prefix":"$day","description":"Replaces the current day."},{"type":"replacement","prefix":"$daysago","description":"Replaces with a number of how many days it\'s ago."},{"type":"replacement","prefix":"$dayname","description":"Replaces the shorted dayname."},{"type":"replacement","prefix":"$weeksago","description":"Replaces with a number of how many weeks it\'s ago."},{"type":"replacement","prefix":"$month","description":"Replaces the month."},{"type":"replacement","prefix":"$monthname","description":"Replaces the shorted monthname."},{"type":"replacement","prefix":"$monthsago","description":"Replaces with a number of how many months it\'s ago."},{"type":"replacement","prefix":"$year","description":"Replaces the year."},{"type":"replacement","prefix":"$yearsago","description":"Replaces with a number of how many years it\'s ago."},{"type":"replacement","prefix":"$hour","description":"Replaces the hour(s)"},{"type":"replacement","prefix":"$minute","description":"Replaces the minute(s)"},{"type":"replacement","prefix":"$second","description":"Replaces the second(s)"}]}]},{"name":"Panel Popout","icon":"User","added":"2021-10-14T22:00:00.000Z","items":[{"type":"switch","name":"Enable","id":"showPanelPopout","value":true},{"type":"radio","name":"Open on","id":"panelPopoutType","value":"click","options":[{"name":"Right Click","value":"contextmenu"},{"name":"Left Click","value":"click"}]}]},{"name":"Created At","icon":"Cake","items":[{"type":"switch","name":"Show in UserPopout","id":"created_show_up","note":"Defines if the creation date should be shown in the UserPopout.","value":true},{"type":"switch","name":"Show in UserProfile","id":"created_show_profile","note":"Defines if the creation date should be shown in the UserProfile.","value":true},{"type":"text","name":"Created At","note":"Format of the Created at date. Read the variables section in the general settings to understand how it works.","id":"created_format","value":"Created At: $hour:$minute:$second, $day.$month.$year $daysago days"}]},{"name":"Joined At","icon":"Calendar","items":[{"type":"switch","name":"Show in UserPopout","id":"joined_show_up","note":"Defines if the joined date should be shown in the UserPopout.","value":true},{"type":"switch","name":"Show in UserProfile","id":"joined_show_profile","note":"Defines if the joined date should be shown in the UserProfile.","value":true},{"type":"text","name":"Joined At","note":"Format of the joined at date. Read the variables section in the general settings to understand how it works.","id":"joined_format","value":"Joined At: $hour:$minute:$second, $day.$month.$year $daysago days"}]},{"name":"Last Message At","icon":"TextBubble","items":[{"type":"switch","name":"Show in UserPopout","id":"lastmessage_show_up","note":"Defines if the last message date should be shown in the UserPopout.","value":true},{"type":"switch","name":"Show in UserProfile","id":"lastmessage_show_profile","note":"Defines if the last message date should be shown in the UserProfile.","value":true},{"type":"text","name":"Last Message","note":"Format of the LastMessage at date. Read the variables section in the general settings to understand how it works.","id":"lastmessage_format","value":"Last Message At: $hour:$minute:$second, $day.$month.$year $daysago days"}]},{"name":"Connections","icon":"Chain","items":[{"type":"switch","name":"Enable Section","note":"Enables this section in the user popout.","id":"showConnectionsSection","value":true},{"type":"switch","name":"Colored Icons","note":"Colored/White icons for the connections.","id":"coloredConnectionsIcons","value":true},{"type":"switch","name":"Show Empty","note":"Show a \\"NO CONNECTIONS\\" placeholder if the user has no connections.","id":"showEmptyConnections","value":true},{"type":"switch","name":"Show Verified","note":"Shows a little verified badge below the icon if the connection is verified.","id":"showVerifiedConnections","value":true},{"type":"icons"}]},{"name":"Activity Icons","icon":"GamePad","items":[{"type":"switch","name":"Enable Activity Icons","note":null,"id":"activityIcons","value":true},{"type":"switch","name":"Disable Bots","note":"Disables the icon for bots, since the most always have something with \'Playing: {...}\' in their statuses.","id":"disableIconsForBots","value":true},{"type":"radio","name":"Activity Icon State","note":"Replaces the activity icon in the activity text of the member list.","id":"activityIconState","value":0,"disabled":false,"options":[{"name":"Replace with associated icon","value":0},{"name":"Don\'t do anything","value":1},{"name":"Hide it","value":2}]},{"type":"switch","name":"Show Gamepad","note":"This shows a gamepad icon if an icon for the activity isn\'t available.","id":"showGamepad","value":true}]},{"name":"Profile Roles","icon":"Profile","added":"2021-10-05T22:00:00.000Z","items":[{"type":"switch","name":"Enable","note":"Adds the roles section (if available) to the profile modal.","id":"profileRoles","value":true}]},{"name":"Mutual Friends","icon":"Friends","added":"2021-10-15T18:59:12.897Z","items":[{"type":"switch","name":"Enable","note":"Adds the mutuals friends section to the user popout.","id":"showMutualFriends","value":true},{"type":"switch","name":"Disable for yourself","note":"Disables the mutual friends section for you.","id":"hideMutualFriendsCurrentUser","value":true},{"type":"switch","name":"Show empty message","note":"This defines if an empty message \'no mutual friends\' should be shown if the user has no mutual friends with you","id":"showEmptyMutualFriends","value":true},{"type":"switch","name":"Stack Icons","note":"Stacks the icons so it takes less space.","id":"stackMutualFriends","value":false}]},{"name":"Mutual Servers","icon":"Mutual","items":[{"type":"switch","name":"Enable Mutual Servers","note":"This enables/disables the mutual servers section in the user popout","id":"showMutualGuilds","value":true},{"type":"switch","name":"Disable for yourself","note":"Disables the mutual servers section for you. (it will just show all your guilds)","id":"hideMutualGuildsCurrentUser","value":true},{"type":"switch","name":"Show empty message","note":"This defines if an empty message \'no mutual servers\' should be shown if the user has no mutual servers with you","id":"showEmptyMutualGuilds","value":true},{"type":"switch","name":"Stack Icons","note":"Stacks the icons so it takes less space.","id":"stackMutualServers","value":false}]},{"name":"Translation Credits","icon":"Language","items":[{"type":"translation","name":"Turkish","id":"tr","note":"@IMaWeebツ#6931"},{"type":"translation","name":"English","id":"en-US","note":"@It\'s Rad, Not Red#0001"},{"type":"translation","name":"German","id":"de","note":"@l0c4lh057#9748, @SteffoSpieler#1868"},{"type":"translation","name":"Dutch","id":"nl","note":"@th0masterharambe#0001"},{"type":"translation","name":"Vietnamese","id":"vi","note":"@MH#5893"},{"type":"translation","name":"Spanish","id":"es-ES","note":"@DrPuc##2048"},{"type":"translation","name":"Swedish","id":"sv-SE","note":"@toatl#7460"},{"type":"translation","name":"Portuguese (Brazil)","id":"pt-BR","note":"@Dominic#1111"},{"type":"translation","name":"French","id":"fr","note":"@LemCent321#1663"}]}]'); + var settings = __webpack_require__(128); + const forms_namespaceObject = Modules["@discord/forms"]; + function chain_extends() { + chain_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return chain_extends.apply(this, arguments); + } + const chain = props => external_BdApi_React_default().createElement("svg", chain_extends({ + viewBox: "0 0 512 512", + width: "24", + height: "24" + }, props), external_BdApi_React_default().createElement("path", { + d: "M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z" + })); + function wrench_extends() { + wrench_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return wrench_extends.apply(this, arguments); + } + const wrench = props => external_BdApi_React_default().createElement("svg", wrench_extends({}, props, { + viewBox: "0 0 512 512", + height: "24", + width: "24" + }), external_BdApi_React_default().createElement("path", { + d: "M501.1 395.7L384 278.6c-23.1-23.1-57.6-27.6-85.4-13.9L192 158.1V96L64 0 0 64l96 128h62.1l106.6 106.6c-13.6 27.8-9.2 62.3 13.9 85.4l117.1 117.1c14.6 14.6 38.2 14.6 52.7 0l52.7-52.7c14.5-14.6 14.5-38.2 0-52.7zM331.7 225c28.3 0 54.9 11 74.9 31l19.4 19.4c15.8-6.9 30.8-16.5 43.8-29.5 37.1-37.1 49.7-89.3 37.9-136.7-2.2-9-13.5-12.1-20.1-5.5l-74.4 74.4-67.9-11.3L334 98.9l74.4-74.4c6.6-6.6 3.4-17.9-5.7-20.2-47.4-11.7-99.6.9-136.6 37.9-28.5 28.5-41.9 66.1-41.2 103.6l82.1 82.1c8.1-1.9 16.5-2.9 24.7-2.9zm-103.9 82l-56.7-56.7L18.7 402.8c-25 25-25 65.5 0 90.5s65.5 25 90.5 0l123.6-123.6c-7.6-19.9-9.9-41.6-5-62.7zM64 472c-13.2 0-24-10.8-24-24 0-13.3 10.7-24 24-24s24 10.7 24 24c0 13.2-10.7 24-24 24z" + })); + var valorant_React = __webpack_require__(113); + function valorant_extends() { + valorant_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return valorant_extends.apply(this, arguments); + } + const valorant = props => valorant_React.createElement("svg", valorant_extends({ + width: "20", + height: "20", + viewBox: "0 0 216.000000 216.000000" + }, props), valorant_React.createElement("g", { + transform: "translate(0.000000,216.000000) scale(0.100000,-0.100000)", + fill: "#000000", + stroke: "none" + }, valorant_React.createElement("path", { + d: "M0 1080 l0 -1080 1080 0 1080 0 0 1080 0 1080 -1080 0 -1080 0 0-1080z" + }))); + var language_React = __webpack_require__(113); + function language_extends() { + language_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return language_extends.apply(this, arguments); + } + const language = props => language_React.createElement("svg", language_extends({ + xmlns: "http://www.w3.org/2000/svg", + height: "24px", + viewBox: "0 0 24 24", + width: "24px", + fill: "currentColor" + }, props), language_React.createElement("path", { + d: "M21 4H11l-1-3H3c-1.1 0-2 .9-2 2v15c0 1.1.9 2 2 2h8l1 3h9c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zM7 16c-2.76 0-5-2.24-5-5s2.24-5 5-5c1.35 0 2.48.5 3.35 1.3L9.03 8.57c-.38-.36-1.04-.78-2.03-.78-1.74 0-3.15 1.44-3.15 3.21S5.26 14.21 7 14.21c2.01 0 2.84-1.44 2.92-2.41H7v-1.71h4.68c.07.31.12.61.12 1.02C11.8 13.97 9.89 16 7 16zm6.17-5.42h3.7c-.43 1.25-1.11 2.43-2.05 3.47-.31-.35-.6-.72-.86-1.1l-.79-2.37zm8.33 9.92c0 .55-.45 1-1 1H14l2-2.5-1.04-3.1 3.1 3.1.92-.92-3.3-3.25.02-.02c1.13-1.25 1.93-2.69 2.4-4.22H20v-1.3h-4.53V8h-1.29v1.29h-1.44L11.46 5.5h9.04c.55 0 1 .45 1 1v14z" + }), language_React.createElement("path", { + d: "M0 0h24v24H0zm0 0h24v24H0z", + fill: "none" + })); + var mutual_React = __webpack_require__(113); + function mutual_extends() { + mutual_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return mutual_extends.apply(this, arguments); + } + const mutual = props => mutual_React.createElement("svg", mutual_extends({ + xmlns: "http://www.w3.org/2000/svg", + height: "24px", + viewBox: "0 0 24 24", + width: "24px", + fill: "currentColor" + }, props), mutual_React.createElement("g", null, mutual_React.createElement("rect", { + fill: "none", + height: "24", + width: "24", + x: "0" + })), mutual_React.createElement("g", null, mutual_React.createElement("g", null, mutual_React.createElement("g", null, mutual_React.createElement("path", { + d: "M9.01,14H2v2h7.01v3L13,15l-3.99-4V14z M14.99,13v-3H22V8h-7.01V5L11,9L14.99,13z" + }))))); + var user_React = __webpack_require__(113); + function user_extends() { + user_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return user_extends.apply(this, arguments); + } + const user = props => user_React.createElement("svg", user_extends({ + width: "24", + height: "24", + role: "img", + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 448 512" + }, props), user_React.createElement("path", { + fill: "currentColor", + d: "M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z" + })); + var friends_React = __webpack_require__(113); + function friends_extends() { + friends_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return friends_extends.apply(this, arguments); + } + const friends = props => friends_React.createElement("svg", friends_extends({ + width: "24", + height: "24", + viewBox: "0 0 640 512" + }, props), friends_React.createElement("g", null, friends_React.createElement("path", { + fill: "currentColor", + d: "M480 256a96 96 0 1 0-96-96 96 96 0 0 0 96 96zm48 32h-3.8c-13.9 4.8-28.6 8-44.2 8s-30.3-3.2-44.2-8H432c-20.4 0-39.2 5.9-55.7 15.4 24.4 26.3 39.7 61.2 39.7 99.8v38.4c0 2.2-.5 4.3-.6 6.4H592a48 48 0 0 0 48-48 111.94 111.94 0 0 0-112-112z" + }), friends_React.createElement("path", { + fill: "currentColor", + d: "M192 256A112 112 0 1 0 80 144a111.94 111.94 0 0 0 112 112zm76.8 32h-8.3a157.53 157.53 0 0 1-68.5 16c-24.6 0-47.6-6-68.5-16h-8.3A115.23 115.23 0 0 0 0 403.2V432a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48v-28.8A115.23 115.23 0 0 0 268.8 288z" + }))); + var profile_React = __webpack_require__(113); + function profile_extends() { + profile_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return profile_extends.apply(this, arguments); + } + const profile = props => profile_React.createElement("svg", profile_extends({ + width: "24", + height: "24", + viewBox: "0 0 384 512" + }, props), profile_React.createElement("path", { + fill: "currentColor", + d: "M224 136V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24V160H248c-13.2 0-24-10.8-24-24zm80 273.6v19.2c0 10.61-10.03 19.2-22.4 19.2H102.4c-12.37 0-22.4-8.6-22.4-19.2v-19.2c0-31.81 30.09-57.6 67.2-57.6h4.95c12.29 5.12 25.73 8 39.85 8s27.56-2.88 39.85-8h4.95c37.11 0 67.2 25.79 67.2 57.6zM192 320c-35.35 0-64-28.65-64-64s28.65-64 64-64 64 28.65 64 64-28.65 64-64 64zm185-215L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1c0-6.3-2.5-12.4-7-16.9z" + })); + var icons_React = __webpack_require__(113); + const Icons = { + Cake: cake, + Calendar: calendar, + Error: error, + TextBubble: textbubble, + Chain: chain, + Wrench: wrench, + Flowerstar: icons_flowerstar, + Spotify: spotify, + Twitch: twitch, + Valorant: valorant, + YouTube: youtube, + GamePad: gamepad, + GoogleChrome: googleChrome, + Headphones: headphones, + Language: language, + Mutual: mutual, + User: user, + Friends: friends, + Profile: profile + }; + function noop() { + return null; + } + function Icon({ + name, + ...props + }) { + const IconComponent = Icons[name] ?? noop; + return icons_React.createElement(IconComponent, props); + } + function settings_extends() { + settings_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return settings_extends.apply(this, arguments); + } + const RadioGroup = Utilities.createUpdateWrapper(external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("RadioGroup")); + const SwitchItem = Utilities.createUpdateWrapper(external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("SwitchItem"), false); + const TextInput = Utilities.createUpdateWrapper(external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("TextInput")); + const BadgesModule = external_PluginApi_namespaceObject.WebpackModules.getByProps("TextBadge"); + const breadCrumbs = external_PluginApi_namespaceObject.WebpackModules.getByProps("breadcrumbActive"); + const { + marginBottom8: settings_marginBottom8 + } = external_PluginApi_namespaceObject.WebpackModules.getByProps("marginBottom8"); + const Breadcrumbs = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("Breadcrumbs"); + const { + default: CardItem + } = external_PluginApi_namespaceObject.WebpackModules.find((m => m?.default?.toString().indexOf("hasNextSection") > -1)) ?? { + default: () => null + }; + const Card = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("Card"); + const Caret = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("Caret"); + const Clickable = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("Clickable"); + const FlagsStore = external_PluginApi_namespaceObject.WebpackModules.getModule((m => "function" === typeof m.keys && m.resolve && m.keys().some((e => e.includes("en-US"))))); + const TextItem = ({ + value, + onChange, + name, + note + }) => external_BdApi_React_default().createElement(components_namespaceObject.Flex, { + className: settings_marginBottom8, + direction: components_namespaceObject.Flex.Direction.VERTICAL + }, external_BdApi_React_default().createElement(forms_namespaceObject.FormItem, { + title: name, + className: settings.Z.formItem + }, external_BdApi_React_default().createElement(TextInput, { + value, + onChange + }), external_BdApi_React_default().createElement(forms_namespaceObject.FormText, { + type: "description", + disabled: false + }, note)), external_BdApi_React_default().createElement(forms_namespaceObject.FormDivider, null)); + const IconSetting = () => { + const colored = (0, flux_namespaceObject.useStateFromStores)([modules_Settings], (() => modules_Settings.get("coloredConnectionsIcons", true))); + const forceUpdate = Utilities.useForceUpdate(); + const shownIcons = (0, flux_namespaceObject.useStateFromStores)([modules_Settings], (() => modules_Settings.get("shownConnections", Object.fromEntries(connections_default().map((e => [e.type, true])))))); + return external_BdApi_React_default().createElement(components_namespaceObject.Flex, { + className: settings.Z.icons + }, connections_default().filter((e => e.enabled)).map((k => external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, { + className: settings.Z.settingsBadgeContainer, + text: shownIcons[k.type] ? "Enabled" : "Disabled", + hideOnClick: false + }, external_BdApi_React_default().createElement("img", { + src: k.icon[Utilities.getIconURL(k.type, colored)], + className: Utilities.joinClassNames(settings.Z.settingsBadgeIcon, shownIcons[k.type] ? "enabled" : settings.Z.disabled), + onClick: () => { + modules_Settings.set("shownConnections", (shownIcons[k.type] = !shownIcons[k.type], + shownIcons)); + forceUpdate(); + } + }))))); + }; + const Translation = ({ + name, + note, + id + }) => { + const icon = (0, external_BdApi_React_.useMemo)((() => { + try { + return external_BdApi_React_default().createElement("img", { + src: FlagsStore("./" + id + ".png"), + className: (0, utils_namespaceObject.joinClassNames)(settings.Z.translation, settings.Z.marginBottom8) + }); + } catch { + return null; + } + }), [id]); + return external_BdApi_React_default().createElement(external_BdApi_React_default().Fragment, null, external_BdApi_React_default().createElement(components_namespaceObject.Flex, { + direction: components_namespaceObject.Flex.Direction.HORIZONTAL, + justify: components_namespaceObject.Flex.Justify.BETWEEN, + align: components_namespaceObject.Flex.Align.CENTER, + className: settings.Z.descriptionItem + }, icon, external_BdApi_React_default().createElement(forms_namespaceObject.FormTitle, { + tag: forms_namespaceObject.FormTitle.Tags.H5 + }, name), external_BdApi_React_default().createElement(components_namespaceObject.Flex, { + justify: components_namespaceObject.Flex.Justify.END, + align: components_namespaceObject.Flex.Align.START, + className: settings.Z.marginBottom8 + }, external_BdApi_React_default().createElement(forms_namespaceObject.FormText, null, note))), external_BdApi_React_default().createElement(forms_namespaceObject.FormDivider, null)); + }; + const Category = props => { + const [opened, setOpened] = (0, external_BdApi_React_.useState)(false); + return external_BdApi_React_default().createElement(Card, { + className: Utilities.joinClassNames(settings.Z.category, opened && settings.Z.opened) + }, external_BdApi_React_default().createElement(Clickable, { + onClick: () => setOpened(!opened) + }, external_BdApi_React_default().createElement(components_namespaceObject.Flex, { + className: settings.Z.categoryHeader, + direction: components_namespaceObject.Flex.Direction.HORIZONTAL + }, props.name, external_BdApi_React_default().createElement(Caret, { + className: settings.Z.categoryCaret, + direction: Caret.Directions[opened ? "DOWN" : "LEFT"] + }))), external_BdApi_React_default().createElement("div", { + className: settings.Z.categoryContent + }, opened && props.items.map(renderSetting))); + }; + const renderSetting = setting => { + setting = _.cloneDeep(setting); + switch (setting.type) { + case "switch": + return external_BdApi_React_default().createElement(SwitchItem, settings_extends({}, setting, { + value: modules_Settings.get(setting.id, setting.value), + onChange: modules_Settings.set.bind(modules_Settings, setting.id) + }), setting.name); + case "replacement": + return external_BdApi_React_default().createElement(components_namespaceObject.Flex, { + direction: components_namespaceObject.Flex.Direction.HORIZONTAL, + className: settings.Z.replacementVariable + }, external_BdApi_React_default().createElement("b", null, setting.prefix), external_BdApi_React_default().createElement("span", null, setting.description)); + case "radio": + const { + name, note + } = setting; + delete setting.name; + delete setting.note; + return external_BdApi_React_default().createElement(forms_namespaceObject.FormItem, { + title: name + }, note && external_BdApi_React_default().createElement(forms_namespaceObject.FormText, { + type: "description", + className: settings.Z.marginBottom8 + }, note), external_BdApi_React_default().createElement(RadioGroup, settings_extends({}, setting, { + value: modules_Settings.get(setting.id, setting.value), + onChange: modules_Settings.set.bind(modules_Settings, setting.id) + }))); + case "text": + return external_BdApi_React_default().createElement(TextItem, settings_extends({}, setting, { + value: modules_Settings.get(setting.id, setting.value), + onChange: modules_Settings.set.bind(modules_Settings, setting.id) + })); + case "icons": + return external_BdApi_React_default().createElement(IconSetting, null); + case "category": + return external_BdApi_React_default().createElement(Category, setting); + case "translation": + return external_BdApi_React_default().createElement(Translation, setting); + case "divider": + return external_BdApi_React_default().createElement(forms_namespaceObject.FormDivider, null); + } + }; + const renderCustomcrumb = ({ + label + }, isActive) => external_BdApi_React_default().createElement(forms_namespaceObject.FormTitle, { + tag: forms_namespaceObject.FormTitle.Tags.H2, + className: Utilities.joinClassNames(breadCrumbs.breadcrumb, isActive ? breadCrumbs.breadcrumbActive : breadCrumbs.breadcrumbInactive) + }, label); + const mainPages = [{ + id: "main", + label: "Modules" + }]; + function SettingsPanel() { + const [activeItem, setActiveItem] = (0, external_BdApi_React_.useState)("main"); + return external_BdApi_React_default().createElement(ErrorBoundary, { + id: "SettingsPanel" + }, external_BdApi_React_default().createElement("div", { + className: settings.Z.settingsPanel + }, external_BdApi_React_default().createElement(components_namespaceObject.Flex, { + align: components_namespaceObject.Flex.Align.CENTER, + basis: "auto", + className: breadCrumbs.breadcrumbs, + grow: 1, + shrink: 1 + }, "main" === activeItem ? external_BdApi_React_default().createElement(forms_namespaceObject.FormTitle, { + className: breadCrumbs.breakcrumb, + tag: forms_namespaceObject.FormTitle.Tags.H2 + }, "Modules") : external_BdApi_React_default().createElement(Breadcrumbs, { + activeId: activeItem, + breadcrumbs: mainPages.concat({ + id: activeItem, + label: pages_namespaceObject[activeItem].name + }), + renderCustomBreadcrumb: renderCustomcrumb, + onBreadcrumbClick: e => setActiveItem(e.id) + })), "main" === activeItem ? pages_namespaceObject.map(((page, index) => external_BdApi_React_default().createElement("div", { + className: settings.Z.cardItem + }, external_BdApi_React_default().createElement(CardItem, { + buttonDisabled: false, + buttonText: "Configure", + details: [{ + text: `${page.items.length} setting${page.items.length > 1 ? "s" : ""}.` + }], + hasNextSection: true, + icon: () => external_BdApi_React_default().createElement(Icon, { + className: settings.Z.pageIcon, + name: page.icon + }), + name: page.name, + onButtonClick: () => setActiveItem(index) + }), daysAgo(new Date, new Date(page.added)) < 60 && null != page.added && external_BdApi_React_default().createElement(BadgesModule.TextBadge, { + text: i18n_namespaceObject.Messages.NEW, + color: constants_namespaceObject.Colors.STATUS_RED_500, + className: settings.Z.textBadge + })))) : pages_namespaceObject[activeItem].items.map(renderSetting))); + } + function UserDetails_extends() { + UserDetails_extends = Object.assign ? Object.assign.bind() : function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) + if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key]; + } + return target; + }; + return UserDetails_extends.apply(this, arguments); + } + function UserDetails_defineProperty(obj, key, value) { + if (key in obj) Object.defineProperty(obj, key, { + value, + enumerable: true, + configurable: true, + writable: true + }); + else obj[key] = value; + return obj; + } + const getClass = (props = [], items = props, exclude = [], selector = false) => { + const module = external_PluginApi_namespaceObject.WebpackModules.find((m => m && props.every((prop => void 0 !== m[prop])) && exclude.every((e => void 0 == m[e])))); + if (!module) return ""; + return (selector ? "." : "") + items.map((item => module[item])).join(selector ? "." : " "); + }; + class Plugin extends(external_BasePlugin_default()) { + constructor(...args) { + super(...args); + UserDetails_defineProperty(this, "promises", { + cancelled: false, + cancel() { + this.cancelled = true; + } + }); + } + get Stores() { + return modules_stores_namespaceObject; + } + get Settings() { + return modules_Settings; + } + getSettingsPanel() { + return external_BdApi_React_default().createElement(SettingsPanel, null); + } + onStart() { + external_StyleLoader_default().inject(); + Strings.init(); + this.patchUserPopout(); + this.patchUserProfile(); + this.patchMemberListItem(); + this.patchUserActivityStatus(); + commands.registerCommand(this.getName(), { + id: "user-info", + name: "userinfo", + get description() { + return i18n_namespaceObject.Messages.USERINFO_CMD_DESC; + }, + predicate: () => true, + execute: (props, { + channel, + guild + }) => { + const users = props.user.map((e => stores_namespaceObject.Users.getUser(e.userId))).filter((e => e)); + if (!users.length) return clyde.sendMessage(channel.id, { + content: "Sorry, but I can't resolve that user." + }); + clyde.sendMessage(channel.id, { + content: "That's what I've found so far:", + embeds: users.map((user => this.createEmbedForUser(user, guild, channel))) + }); + }, + options: [{ + name: "user", + type: 6, + description: "The user" + }], + type: 3 + }); + } + createEmbedForUser(user, guild) { + const member = stores_namespaceObject.Members.getMember(guild.id, user.id); + const largeUrl = user.getAvatarURL().split("?size")[0] + "?size=2048"; + const activities = stores_namespaceObject.Activities.getActivities(user.id); + return { + color: member?.colorString ? external_PluginApi_namespaceObject.ColorConverter.hex2int(member.colorString) : void 0, + author: { + name: user.tag, + icon_url: user.getAvatarURL(), + proxy_icon_url: user.getAvatarURL() + }, + thumbnail: { + height: 128, + proxy_url: largeUrl, + url: largeUrl, + width: 128 + }, + footer: { + text: "ID: " + user.id + }, + timestamp: (new Date).toISOString(), + type: "rich", + description: `<@!${user.id}>`, + fields: [{ + name: "Creation Date", + inline: true, + value: extractDate(user.id).toGMTString() + }, member && { + name: "Joined Date", + inline: true, + value: new Date(member.joinedAt).toGMTString() + }, member && { + name: "Roles [" + member.roles.length + "]", + value: member.roles.map((role => `<@&${role}>`)).join(" | ") + }, activities.length && { + name: "Activities", + value: activities.map((ac => `- **${ac.name}**: \`${ac.state}\``)).join("\n") + }].filter((e => e)) + }; + } + async patchUserPopout() { + const UserPopoutComponents = external_PluginApi_namespaceObject.WebpackModules.getByProps("UserPopoutInfo"); + const UserPopoutBody = external_PluginApi_namespaceObject.WebpackModules.getModule((m => "UserPopoutBody" === m?.default?.displayName && m.default.toString().indexOf("ROLES_LIST") > -1)); + external_PluginApi_namespaceObject.Patcher.after(UserPopoutComponents, "UserPopoutInfo", ((_, [{ + user + }], returnValue) => { + if (this.promises.cancelled) return; + const tree = Utilities.findInReactTree(returnValue, (e => e?.className?.indexOf("headerText") > -1)); + if (!Array.isArray(tree?.children) || !user) return; + tree.children.push(external_BdApi_React_default().createElement(ErrorBoundary, { + key: "UserPopoutHeader", + id: "UserPopoutHeader", + mini: true + }, external_BdApi_React_default().createElement("div", { + className: Utilities.joinClassNames(dates.Z.container, modules_Settings.get("useIcons", true) ? dates.Z.icons : dates.Z.text) + }, modules_Settings.get("created_show_up", true) && external_BdApi_React_default().createElement(CreatedAt, { + userId: user.id, + key: "created-date" + }), modules_Settings.get("joined_show_up", true) && external_BdApi_React_default().createElement(JoinedAtDate, { + userId: user.id, + key: "joined-date" + }), modules_Settings.get("lastmessage_show_up", true) && external_BdApi_React_default().createElement(LastMessageDate, { + user, + key: "lastmessage-date" + })))); + })); + external_PluginApi_namespaceObject.Patcher.after(UserPopoutBody, "default", ((_, [{ + user + }], returnValue) => { + if (this.promises.cancelled) return; + if (!Array.isArray(returnValue?.props?.children) || returnValue.props.children.some((child => child?.type === ErrorBoundary))) return returnValue; + returnValue.props.children.splice(-1, 0, external_BdApi_React_default().createElement(ErrorBoundary, { + id: "UserPopoutBody", + mini: true, + key: "connections" + }, external_BdApi_React_default().createElement(UserConnections, { + user + })), external_BdApi_React_default().createElement(ErrorBoundary, { + id: "UserPopoutBody", + mini: true, + key: "mutual_servers" + }, external_BdApi_React_default().createElement(MutualServers, { + user + })), external_BdApi_React_default().createElement(ErrorBoundary, { + id: "UserPopoutBody", + mini: true, + key: "mutual_friends" + }, external_BdApi_React_default().createElement(MutualFriends, { + user + }))); + })); + } + async patchUserProfile() { + const UserProfileModalHeader = await Utilities.getLazy((m => "UserProfileModalHeader" === m.default?.displayName)); + const UserInfoBase = external_PluginApi_namespaceObject.WebpackModules.getModule((m => "UserInfoBase" === m.default?.displayName)); + external_PluginApi_namespaceObject.Patcher.after(UserInfoBase, "default", ((_, [props], returnValue) => { + if (!Array.isArray(returnValue?.props?.children) || !modules_Settings.get("profileRoles", true)) return; + returnValue.props.children.unshift(external_BdApi_React_default().createElement(MemberRolesSection, { + userId: props.user.id, + key: "roles" + })); + })); + external_PluginApi_namespaceObject.Patcher.after(UserProfileModalHeader, "default", ((_, [{ + user + }], res) => { + if (this.promises.cancelled) return; + const tree = Utilities.findInReactTree(res, SuppressErrors((res => "DiscordTag" === res.type.displayName))); + if (!tree || tree.type?.__patched) return; + const original = tree.type; + tree.type = (...args) => { + const ret = original.apply(this, args); + try { + return external_BdApi_React_default().createElement("div", { + className: dates.Z.wrapper + }, ret, external_BdApi_React_default().createElement(ErrorBoundary, { + id: "UserProfile", + mini: true + }, external_BdApi_React_default().createElement("div", { + className: Utilities.joinClassNames(dates.Z.container, dates.Z.userProfile, modules_Settings.get("useIcons", true) ? dates.Z.icons : dates.Z.text) + }, modules_Settings.get("created_show_profile", true) && external_BdApi_React_default().createElement(CreatedAt, { + userId: user.id, + key: "created-at" + }), modules_Settings.get("joined_show_profile", true) && external_BdApi_React_default().createElement(JoinedAtDate, { + userId: user.id, + key: "joined-at" + }), modules_Settings.get("lastmessage_show_profile", true) && external_BdApi_React_default().createElement(LastMessageDate, { + user, + key: "last-message" + })))); + } catch (error) { + Logger.error("Failed to inject into ProfileModal:", error); + } + return ret; + }; + tree.type.__patched = true; + tree.name = "DiscordTag"; + })); + } + async patchMemberListItem() { + const MemberListItem = await external_PluginApi_namespaceObject.ReactComponents.getComponentByName("MemberListItem", getClass(["member", "activity"], ["member"], [], true)); + const ActivityStatus = external_PluginApi_namespaceObject.WebpackModules.getModule((m => "ActivityStatus" === m.default.displayName)); + const ConnectedActivity = (0, flux_namespaceObject.connectStores)([modules_Settings], (e => e))(Activity); + external_PluginApi_namespaceObject.Patcher.after(MemberListItem.component.prototype, "render", ((that, _, res) => { + if (this.promises.cancelled) return; + if (!modules_Settings.get("activityIcon", true)) return; + res.props.children = external_BdApi_React_default().createElement(ConnectedActivity, { + user: that.props.user + }); + })); + external_PluginApi_namespaceObject.Patcher.after(ActivityStatus, "default", ((_, [{ + activities + }], res) => { + const element = res?.props?.children?.[2]; + if (!element) return; + Object.assign(element.props, { + type: activities.filter(ActivitiesFilter)[0].type + }); + })); + MemberListItem.forceUpdateAll(); + } + async patchUserActivityStatus() { + const RichActivity = external_PluginApi_namespaceObject.WebpackModules.getModule((m => "RichActivity" === m?.default?.displayName)); + external_PluginApi_namespaceObject.Patcher.after(RichActivity, "default", ((_, [props]) => { + const shouldShow = (0, flux_namespaceObject.useStateFromStores)([modules_Settings], (() => modules_Settings.get("activityIconState", 0))); + switch (shouldShow) { + case 1: + return; + case 2: + return null; + } + switch (props.type) { + case constants_namespaceObject.ActivityTypes.PLAYING: + return external_BdApi_React_default().createElement(gamepad, props); + case constants_namespaceObject.ActivityTypes.LISTENING: + return external_BdApi_React_default().createElement(headphones, props); + } + })); + } + async patchAccountSection() { + const classes = external_PluginApi_namespaceObject.WebpackModules.getByProps("copySuccess", "container"); + const AccountSection = await external_PluginApi_namespaceObject.ReactComponents.getComponentByName("Account", `.${classes.container}`); + const UserPopoutContainer = external_PluginApi_namespaceObject.WebpackModules.getModule((m => "UserPopoutContainer" === m.type.displayName)); + const Popout = external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("Popout"); + external_PluginApi_namespaceObject.Patcher.after(AccountSection.component.prototype, "render", ((_this, _, res) => { + if (this.promises.cancelled) return; + if (!_this.state.hasOwnProperty("showUserPopout")) _this.state.showUserPopout = false; + res.props.onClick = res.props.onContextMenu = function(e) { + if (modules_Settings.get("panelPopoutType", "click") !== e.type) return; + e.preventDefault(); + e.stopPropagation(); + if (e.target?.classList?.contains(classes.container) || e.target?.parentElement?.classList?.contains(classes.nameTag) || e.target?.classList?.contains(classes.usernameContainer) || e.target?.parentElement?.classList?.contains(classes.usernameContainer)) this.setState({ + showUserPopout: !_this.state.showUserPopout + }); + }.bind(_this); + return external_BdApi_React_default().createElement(ErrorBoundary, { + id: "AccountSection" + }, external_BdApi_React_default().createElement(Popout, { + child: res, + shouldShow: _this.state.showUserPopout && modules_Settings.get("showPanelPopout", true), + animation: Popout.Animation.TRANSLATE, + onRequestClose: () => _this.setState({ + showUserPopout: false + }), + position: Popout.Positions.TOP, + align: Popout.Align.CENTER, + renderPopout: props => external_BdApi_React_default().createElement(ErrorBoundary, { + id: "UserPopoutContainer" + }, external_BdApi_React_default().createElement(UserPopoutContainer, UserDetails_extends({}, props, { + channelId: stores_namespaceObject.SelectedChannels.getChannelId(), + guildId: stores_namespaceObject.SelectedGuilds.getGuildId(), + userId: stores_namespaceObject.Users.getCurrentUser().id, + position: "top" + }))) + }, (() => res))); + })); + AccountSection.forceUpdateAll(); + } + destroyStore(dispatchToken) { + modules_namespaceObject.Dispatcher._dependencyGraph.removeNode(dispatchToken); + modules_namespaceObject.Dispatcher._invalidateCaches(); + } + onStop() { + Strings.shutdown(); + external_PluginApi_namespaceObject.Patcher.unpatchAll(); + external_StyleLoader_default().remove(); + this.promises.cancel(); + commands.unregisterAllCommands(this.getName()); + this.destroyStore(joinedAt.getDispatchToken()); + this.destroyStore(stores_lastMessage.getDispatchToken()); + } + } + })(); + module.exports.LibraryPluginHack = __webpack_exports__; + })(); + const PluginExports = module.exports.LibraryPluginHack; + return PluginExports?.__esModule ? PluginExports.default : PluginExports; +} +module.exports = window.hasOwnProperty("ZeresPluginLibrary") ? + buildPlugin(window.ZeresPluginLibrary.buildPlugin(config)) : + class { + getName() { + return config.info.name; + } + getAuthor() { + return config.info.authors.map(a => a.name).join(", "); + } + getDescription() { + return `${config.info.description}. __**ZeresPluginLibrary was not found! This plugin will not work!**__`; + } + getVersion() { + return config.info.version; + } + load() { + BdApi.showConfirmationModal( + "Library plugin is needed", + [`The library plugin needed for ${config.info.name} is missing. Please click Download to install it.`], { + confirmText: "Download", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => { + if (error) return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js"); + await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r)); + }); + } + } + ); + } + start() {} + stop() {} + }; +/*@end@*/ \ No newline at end of file diff --git a/oldconfig/BetterDiscord/plugins/ZeresPluginLibrary.config.json b/oldconfig/BetterDiscord/plugins/ZeresPluginLibrary.config.json new file mode 100644 index 0000000..18cc149 --- /dev/null +++ b/oldconfig/BetterDiscord/plugins/ZeresPluginLibrary.config.json @@ -0,0 +1,6 @@ +{ + "currentVersionInfo": { + "version": "2.0.3", + "hasShownChangelog": true + } +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/themes/ModernChannelIndicators.theme.css b/oldconfig/BetterDiscord/themes/ModernChannelIndicators.theme.css new file mode 100644 index 0000000..4c7287d --- /dev/null +++ b/oldconfig/BetterDiscord/themes/ModernChannelIndicators.theme.css @@ -0,0 +1,35 @@ +/** + * @name Modern Channel Indicators + * @version 1.2.1 + * @description Adds a nice touch to Discord's current channel indicators. + * @author LuckFire#4800 + * + * @website https://github.com/Discord-Theme-Addons + * @source https://github.com/Discord-Theme-Addons/modern-channel-indicators/tree/main/src +**/ + +@import url('https://discord-theme-addons.github.io/modern-channel-indicators/src/support/compiled.css'); + +:root { + /* ---- base -- */ + --indicator-hovered: rgba(79, 84, 92, 0.25); + --indicator-rounding: 0; + --indicator-border-info: 2px solid; + + /* ---- selected -- */ + --indicator-selected: 88, 101, 242; + --indicator-selected-border: rgba(var(--indicator-selected)); + --indicator-selected-background: rgba(var(--indicator-selected), 0.1); + --indicator-selected-hover: rgba(var(--indicator-selected), 0.18); + + /* ---- unreads -- */ + --indicator-unread: 255, 255, 255; + --indicator-unread-border: rgba(var(--indicator-unread), 0.6); + --indicator-unread-background: rgba(var(--indicator-unread), 0.01); + + /* ---- connected -- */ + --indicator-connected: 87, 242, 135; + --indicator-connected-border: rgba(var(--indicator-connected)); + --indicator-connected-background: rgba(var(--indicator-connected), 0.1); + --indicator-connected-hover: rgba(var(--indicator-connected), 0.18); +} diff --git a/oldconfig/BetterDiscord/themes/SettingsModal.theme.css b/oldconfig/BetterDiscord/themes/SettingsModal.theme.css new file mode 100644 index 0000000..07b0ede --- /dev/null +++ b/oldconfig/BetterDiscord/themes/SettingsModal.theme.css @@ -0,0 +1,21 @@ +/** + * @name SettingsModal + * @description Turns Settings Windows like User-/Channel-/Serversettings and Boost Overview into Modals + * @author DevilBro + * @version 1.0.0 + * @authorId 278543574059057154 + * @invite Jx3TjNS + * @donate https://www.paypal.me/MircoWittrien + * @patreon https://www.patreon.com/MircoWittrien + * @website https://mwittrien.github.io/ + * @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Themes/SettingsModal/ + * @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Themes/SettingsModal/SettingsModal.theme.css + */ + +@import url(https://mwittrien.github.io/BetterDiscordAddons/Themes/SettingsModal/SettingsModal.css); + +:root { + --settingsmodalbackground: transparent; /* default: transparent (lowest bg color of changed windows, change it in case another theme turns them transparent) */ + --settingsmodalwidth: 960px; /* default: 960px (width of the settings modal, px/vw) */ + --settingsmodalheight: 80vh; /* default: 80vh (height of the settings modal, px/vh) */ +} \ No newline at end of file diff --git a/oldconfig/BetterDiscord/themes/tokyo-night.theme.css b/oldconfig/BetterDiscord/themes/tokyo-night.theme.css new file mode 100644 index 0000000..bccbe45 --- /dev/null +++ b/oldconfig/BetterDiscord/themes/tokyo-night.theme.css @@ -0,0 +1,172 @@ +/** + * @name Tokyo Night + * @description Discord Port of Visual Studio Code Theme + * @author Ashtrath + * @version 2.0.0 + * @authorId 2354831939099688962 + */ + +/* DONT TOUCH THIS!!! */ +@import url("https://dyzean.github.io/Tokyo-Night/main.css"); + +/* Read this before editing stuff!!! +* +* > To comment or uncomment a line you need to put those "/" and "*" characters as you can see at the beginning and ending of my comments. +* (You don't need to put a * at each line like I do, it's just for readability). See more here : https://developer.mozilla.org/en-US/docs/Web/CSS/Comments +* +* > You can play with the values and see how it goes, don't delete "px" after the value if you don't have knowledges in CSS. +* +* > To change the colors, replace the HEX code with the one you picked here : https://htmlcolorcodes.com +*/ + +/* ====== Optional Addons ====== */ +@import url("https://mr-miner1.github.io/cooler-activity-status/theme[bd].theme.css"); +@import url("https://dyzean.github.io/Tokyo-Night/addons/revert-rebrand.css"); +@import url("https://nyri4.github.io/Discolored/main.css"); + +/* VSCode User Area, get Visual Studio like user area (Enabled by default) + note: this addons doesn't works well with Compact Mode addon, + please disable this when using Compact Mode addon */ +@import url("https://dyzean.github.io/Tokyo-Night/addons/vscode-user-area.css"); + +/* Syntax Highlight, get hljs styling with Tokyo Night scheme (Enabled by default) */ +@import url("https://dyzean.github.io/Tokyo-Night/addons/syntax-highlight.css"); + +/* Username Background, get colorful background behind username on chat, works best with Monospace addon. (Enabled by default) */ +@import url("https://dyzean.github.io/Tokyo-Night/addons/username-background.css"); + +/* Mac Like Titlebar (windows only), get mac style titlebar on windows client (Enabled by default) */ +@import url("https://dyzean.github.io/Tokyo-Night/addons/mac-titlebar.css"); + +/* Compact Mode, hide some UI part on specific windows size, + <920px Channel sidebar and member list get hidden, <600px Chat window only. (Disabled by default) */ +/* @import url("https://dyzean.github.io/Tokyo-Night/addons/compact-mode.css"); */ + +/* Monospace, use monospaced font (JetBrains Mono) instead the default one (Disabled by default) */ +/* @import url("https://dyzean.github.io/Tokyo-Night/addons/monospace-fonts.css"); */ + +/* Square Avatar, get square avatar on chat memberlist and user area (Disabled by default) */ +/* @import url("https://dyzean.github.io/Tokyo-Night/addons/square-avatar.css"); */ + + +/* ==== Discord Variables ==== */ +.theme-dark { /* Dark Mode */ + + /* Header Color */ + --header-primary: var(--text-normal); + --header-secondary: var(--text-muted); + + /* Text Color */ + --text-normal: #b1bae6; + --text-muted: #565f89; + --interactive-normal: #5f647e; + --interactive-hover: #a2a6c2; + --interactive-active: #b5bad1; + --interactive-muted: #55576b; + + /* Background Color */ + --background-primary: #1a1b26; + --background-secondary: #171722; + --background-secondary-alt: #13131a; + --background-tertiary: #16161e; + --background-tertiary-alt: var(--background-secondary-alt); + --background-accent: #434461; + --background-floating: #161620; + --background-modifier-hover: #212331c0; + --background-modifier-active: #282a3680; + --background-modifier-selected: #24263171; + --background-modifier-accent: #1e1e29; + --background-mentioned: #252836; + --border-mentioned: #474c64; + --background-mentioned-hover: #2f3344; + --accent-color: #7aa2f7; + + /* Folder Color */ + --folder-color: #202332d0; + --folder-color-light: #2f3342d0; + + /* Scrollbars Color */ + --scrollbar-thin-thumb: transparent; + --scrollbar-thin-track: transparent; + --scrollbar-auto-thumb: #2b2b46af; + --scrollbar-auto-thumb-hover: #27273d85; + --scrollba-auto-track: transparent; + --scrollbar-auto-scrollbar-color-thumb: var(--scrollbar-auto-thumb); + --scrollbar-auto-scrollbar-color-track: var(--scrollbar-auto-track); + + /* Chat Box Color */ + --channeltextarea-background: var(--background-secondary); + --channeltextarea-background-hover: var(--background-tertiary); + + /* Square avatar addons */ + --avatar-roundess: 5px; + + /* Mac Titlebar addons */ + --close-button-color: #e92a2ade; + --maximize-button-color: #f7bc1bde; + --minimize-button-color: #12db33de; +} + +.theme-light { /* Light Mode */ + + /* Header Color */ + --header-primary: var(--text-normal); + --header-secondary: var(--text-muted); + + /* Text Color */ + --text-normal: #2e3338; + --text-muted: #747f8d; + --interactive-normal: #4c505e; + --interactive-hover: #404350; + --interactive-active: #373a44; + --interactive-muted: #77797c; + + /* Background Color */ + --background-primary: #d5d6db; + --background-secondary: #cecfd4; + --background-secondary-alt: #b6b7bd; + --background-tertiary: #c5c6cc; + --background-tertiary-alt: #bbbbc2; + --background-accent: #9ca3bb; + --background-floating: #c2c2c9; + --background-mentioned: #c4c7da; + --background-modifier-hover: #2c2a2a25; + --background-modifier-active: #5a525229; + --background-modifier-selected: #555e693d; + --background-modifier-accent: #06060714; + --border-mentioned: #a9afcf; + --background-mentioned-hover: #cfd2e9; + --accent-color: #365aaa; + + /* Folder Color */ + --folder-color: #a7a6a6d0; + --folder-color-light: #afafafd0; + + /* Input Box Color */ + --input-box-bg: #c2c2c7; + --input-box-border: #b3b4b8; + --input-box-border-focus: #959699; + + /* Scrollbars Color */ + --scrollbar-thin-thumb: transparent; + --scrollbar-thin-track: transparent; + --scrollbar-auto-thumb: #a0a0a0af; + --scrollbar-auto-thumb-hover: #77777785; + --scrollbar-auto-track: transparent; + --scrollbar-auto-scrollbar-color-thumb: var(--scrollbar-auto-thumb); + --scrollbar-auto-scrollbar-color-track: var(--scrollbar-auto-track); + + /* Chat Box Color */ + --channeltextarea-background: var(--background-secondary); + --channeltextarea-background-hover: var(--background-tertiary); + + /* Square avatar addons */ + --avatar-roundess: 5px; + + /* Mac Titlebar addons */ + --close-button-color: #e92a2ade; + --maximize-button-color: #f7bc1bde; + --minimize-button-color: #12db33de; + --button-position: row; + +} diff --git a/oldconfig/beets/config.yaml b/oldconfig/beets/config.yaml new file mode 100755 index 0000000..9291544 --- /dev/null +++ b/oldconfig/beets/config.yaml @@ -0,0 +1,40 @@ +directory: ~/Music/ +library: ~/Music/library.db + +threaded: yes +sort_case_insensitive: yes + +ui: + color: yes + +import: + write: yes + move: yes + resume: yes + from_scratch: yes + default_action: apply + language: en + group_albums: yes + autotag: yes + duplicate_action: keep + bell: no + incremental: yes + + +match: + strong_rec_thresh: 0.04 + medium_rec_thresh: 0.10 + +paths: + default: $artist/$album/$disc-$track $title + +plugins: chroma lyrics mbsync fetchart lastgenre deezer spotify + +lyrics: + sources: genius + +chroma: + auto: yes + +acoustid: + apikey: 6KzkSx8Lcp diff --git a/oldconfig/beets/library.db b/oldconfig/beets/library.db new file mode 100644 index 0000000000000000000000000000000000000000..c9d6283a701946d6924d844507a5f04c89d498eb GIT binary patch literal 45056 zcmeI5%dg{DTEOqE>h4?Bqnetb8I^_+5UB*3R+pz8$98O5Xy({Hek5`H&Pzy^V>`AJ zJI;-hILT^yMo0)GV8e

{ufqBzCZ9B-p?T&5HR8keJ16Sa9z9)}88}Mhr+jeS9mA z^PSgse&?L;vweNPa;#pqi5s(WT?Cs(>*Q-Er>7_1Ycx(yPTobYuUvngqR)5G>n-%U zIWA;B?|Ap*J45x^yMJ)< z0f^I&#cUbH`yiig3qROw*4cEsi7S74@Z;qs+Z-O|JQZyST-eb15*#%i=HAtNxABI< z=>JTO#<#Ef@w4dtAN=||XDC%L5mMcS3bY%h zt?9rXH@a~A>WyV@HM^S1^57kXR}IwO`wfIjH2QK+ z6WxXl%^ncp``O@o?K2@b)F+@><8OTd71Vf;_;ggB~N~T@b=k@Z+`RikIwD@ zSC^%#cYYRT)%fp03@%ebza#LM+HyhgP-J6iJ#p*6qOm8*1To8>L!4(kH>y`Kt(&n(b8P09Gx-M|3 znzEZ zLGHgk5x3$8Gjc1xH#P5n{MEP4UVQh1(~rMP4w-%n$1`E~bs7P(^3^7b{8@HEd$rD% zH}2pz>%O}84g9S;FT)_NtLBvrUG4!tU>2Oqrm?8%cS z&z?Q|$U|?Bo;*24$FpZoo_ZI@vzN{H{`MvMtiJV)_rCt@>!`@Z^&~n_$&<6k-+27w z^sTcG)3S&^EY@ipC2?9NAL`pG3qKUmeWxrBHd(o>K9tHW`sGkVDf7s0xM|!FV)VNP zDOiSaL(GE;Rj59s$VNZjp}PS}xm*SfCELY~ak*`HtM8PnZS^U6c82aLfePL8J6yfL zYFvo!iSKp(JD=A1AXsPU?n?t)-U6yVJ871yPf>>D+YA#-n*>erG0_U5Ho=qB41MET zJV{e+o)6DH`PJWe^oX0a=yr3;5bc-^2%3umf@1@o2%90<4#*kZ4q}!M+U*$`5VLlh zCFoYj5U81em`2kmrh+(Nnrt-Xsi4U;iDnQ|s0=qHrXk%TrW}Rl=_?oW_2~J(o;?2# z^o9>i029CjFab;e6Tk#80ZafBzyvS>OaK%3f)M!Dqqk3Cpyq0J==8{U*2yK z*62~bOaK$W z1TX4S=ib|DT>b|F7pieOMKzF#${f6Tk#8 z0ZafBzyvS>OaK$W1TXx`CV&ZG0+;|M@TDd2gO{hjeR6V!Vi@r-zWvl`u1^<@+ zJNYMnwfgM8>3@*>d13~jFaT$tJo-F;q|fm|LwUpr8RfYQG(~*=C#PP-9dt z*ep@R!G7=TlgoGwIQHL{c9-CRV*;1}CV&ZG0+;|MfC*p%m;fe#34A#STs;4e{?k8v zU;>x`CV&ZG0+;|MfC*p%m;fe#319-4z%MZYeEt7RJh^yim;fe#319-4049J5U;>x` zCV&ZG0+;|MfC*p%m;fe#319-4049J5U;>x`CV&ZG0$(Zuag*kwC}POZ6NZ3o^CZc! z3_&(qZK6f;En+&OBO(q_uz{EiD5_1}3rz6FPzAsO(gvP8U2oxZCf!A?Ch}y}FBoY> zGD<4y6W5knWI^=hy-FSk8t{kF*kA=WKgv2Kt2Eg(IyS}Y&|GtItCWa=P+x0%2otJFk(z|u7(Y(h>=ZAw^1xz~C7J6*5JArBHv*mb{ z8Lc{FRQY_Qar`_2wZ!sii_o08+M*1<4A<(s?n%d4sBu)Uw_e$XyV4cA?6t@7PI37o z3tf&r9=VZ`b^IOhN3eJ78KSwV!9VEu8g5pP;j>dFZ8#FYXCKI66JC zvnTq6d7dswb$Sr}^<0trZF|BwX-wMkAr;+dIj1$lw}o~y;g8yORd#347^-v5UL}(l z&V)tV6$)9MQ>5G3l3Ir~TI6uP9AyVJ9m#Y}#IO@myr#^?I-$Z=s(HE-ITC2WCS~vG z?r=rw#-ycMGt@#)^GtKMtDzwu`x0@k5~0m5=XS)WYEv!uBX3n#7lytG@$z`ceGLxi{826lrvN7caFk{u>AJi3I=(d zxvO}+P?~B+ND4=e7|kjN-h>tks_60atUUUM8O%J1^$%s6Fc>;pjr!nxZ)I*O9b@{? zIuC7!nY0Og3kBlC>s@K}Pl|oMDY17)zM03stNpo@>faTGd3dez(^kzl6ZK}t8nX8&A zhlDsC$4jZliQY`?TiLFJE3&S5r)7fHz;L<|sZ^FHLwY@5o+p3^^A(a@ZnFC7}~hj}h>L1~SdNo_GlKQ3#I_n|Wvnz86{ z@tiKBwKy1UGzYC69ZFMfCXaMS75SOfp)1L!<`ix8_PU(g#(rC=Z~xFWyN}#Ho_Lixf(q zTKjb7r$-7dsu9?6Ws_>gT`!JH zWggOWyGHx?JVo|P3Y2kARgy!UwuE8el{F#Rhpu{9E>o6BCXCc1NBTLO(_=yiTN5!* zsGgb)YmN{-(pl`tgofM6Jl80VpytM2=&>~H45TouCNm-RdwJbmrfHW%b_WvBA>F1T z#1fk=f=RlF>5XFQFwR_S5!iMI@rM&0WO7H?G=1?H@AahFf~v?6^S#^4ZPr!{m5L2% zzirW6*W4dW!4z{b<3-ao;_lv0_i<^e<(yDQJK;F%r=hQkWlxVcWBT0Dr|H3m!4`Q7 zKQIHEp;C%Im{cj+tC=22t4u%NNisVUv~8+$<}5t)M@AOR zR<5lQ%a%oO_Pz>ou^A5qznQ8o6^q??%!Y|+hC6$%M^jf04s=$SDzZ$iIvT0X39&QR z7QK(-gPtDxJ*r>w9cKksTVd$aG}L&}8JcP506AS5^{K=otARuqnHkY@+VTmz*Ggry zW`YS99#>(nrH*+xfPBq{dLE1Q`NYk)Ep0YaM>+Cu&bSNNE=PBxN>5C?RTSb#KET~< zpGp%0lI?<)&SNu5C2yA2{jOK;0V(xE$}WA`&f3eG?I9aa62r2clYPLmX5W#x{g#rC zMcU!KzUl0Wwoqo1aK@-Q(Ptw?k-1_bDl+XW$)xXWG5mzT?mS9c07tI z0ez#}v<=RbP~Su;GiwqLe7{d;pt&}ZDi5{+M>RQn^Lp6sF(71Cv3ved1mllSn-Q2mMo&rP;*6f zMv~0W_KdVK_;`M#-8EMlLxZcS?MO*IW}6jlJ#Dgp2)YVU`(aO_$rZiQR$DO|Fusu- zCoMsblw-|=V^=2F6)1M%oBJX1loiYpwN3S=rR z3SZ9#)`2I@QQAuNqd~ieSZ&3~->bB!=b8_VHQnq`gI?QW_0UyaF7AZc!08Cho|UXP zyIW1ILZ;_lJolnq+}Cnb+H-1`IgEPiBnBD)!T^fnI2_AhT!MpZ&*dD7vIxh@80e+A zN`WhZBu$3Ef}#a=ORGC$$p(TTXp#UtcBlal&|}R$%;$?lL2Zg4gizK>3miNLWC=QN z6+vZ+DhEE^1AX6a$?^0mp)xZPn0$3J}Gf0F=H4YhX#Km1jVfQdJUx z2$8?i5=#SuD^1;62Oep+7`gY59|i92CT8hlt8Fcs3rgc1prT9lmK*6A<;BcR}(>32fAfx zFc1{1iZe57(mf{JKWKu>5i4Q_6W za{$GTqUav*I<^M(2n*t$z%K9d@n3PJ;QKwH+>vFdq+mX!&iWgwLi zvhl)3rDYu;G4Iw_q}_$P@FLu4ieX3o-gKt(g8+S^FmN+nw3bUoC;_q=sh3SCk3YQd{P%+pP77Dq&DHVp`x z4+A0~DVm^oDxS5ta7u>!=ZS2m2*B=OgU%uM{{|yAs B;CBE3 literal 0 HcmV?d00001 diff --git a/oldconfig/beets/spotify_token.json b/oldconfig/beets/spotify_token.json new file mode 100644 index 0000000..4b3df53 --- /dev/null +++ b/oldconfig/beets/spotify_token.json @@ -0,0 +1 @@ +{"access_token": "BQAC19DYpV_T_Ml3Jrew7iaxnW54YhzbVI7VXPy0eFp3qi_nPSg8hmV-be3OV_JahQXmL-TObvVBZyq6u3E"} \ No newline at end of file diff --git a/oldconfig/beets/state.pickle b/oldconfig/beets/state.pickle new file mode 100644 index 0000000000000000000000000000000000000000..6e8fea10482c20026b8b19f289f0c5ddc644cd2b GIT binary patch literal 8938 zcmcIq%W~sN8D_x>UZP=hoJEpxk~wn*PEpu$e2L@4$MQ^OGEkyzb*vssYSWV9I52QF zu$qFi2vxiSZ@``h;Z^urm$nkcMsdb7RgQJ(|JMKI`~UX$KmNymfBvKR->19E=bwgj zGLvE=SrFWPy8HYSTsu4ng^s6^`<`@|Jzx;Yu1&4F2rodmkBt~J%jCB3HPLoiqWS&!`UvD; zsjDk%AY4}yyC@LLZNY$Ye2z|E|8X6Y0UwVAX;V28 zGNYDwVqyq0@&kwaO#5W{1zO90t`p!?1R+t88f5H4hmpjEh`1t&3z73NBGISn&X9Xc zaW-A9h4UU4uH)|yA%__v4fr;Xy!f&SOAzJ9AyH4yqmW4mFI`A)B8tc^Y4Bi5s@N@j zSMMyB?0K_8mD^4W99KkV&F3CNv*;U1%f%ZuSd#_XuwF4 z#WE}BH#yC3JEUR=#C(>1Hd(5L`gK956#F}Aq;`*UK zl-*5EOh?R=(LJ^|r`O8XcaIZDmJg8$kd2#ktjbkpm|Oz5;M~fLLf$eNaN%dh*=(`a z?AU=`#ZlnuDbN7--p+j)hV@Y_@`R6)Y7^?)vDvhtHd(5LDxL82 zMm%f)b-;44V)C~x=0Pr0|GmzTZ+t}cM2ZM{r26HfG$u$6Eb?9;CBtz$feV#adgzxT zr!BI!S~XoEu}{rt8A(}WXCbrh70u*t>nzmdE^;z+**JX6LaJb=IqYG$Zm?2|bh}QZ zTIjeeN|zpvSUQ((U$llG9V42SwYTSB6fvWrjX?X7h}$5Tm1BObzm zha9lOO44bD%X?+Xoko1Z1K?+0B~9x9^iKImQn|4Doccm*_r5H}1d1zQX2tlgDd}tm zIO&Ud90sPtG;=khtLhFV&Qh zR6m=1Fx&mJldE}^zk0J&?-vF2Ryd-u@I!}FYrs5yqpkC{uzY1Pf7lVBzUO)&OLtIN zng3;h^inbf60klY2|6^G!a@yZ8;0uu#JhQalXY|AJRbV%@4f=#u` zMd!}ZZOOZ`bj@Cbb1cI*2Q-a=pkAQO0_^n!iHb z3#CxSK#iq}t`}`}>&OXJ#?X3xG=) z_2RYwqgRADruFJ`Im|A94j_C!wrV!8au`V#cQVJpn4MP* z<4-AyvTBL6j^CE0(xq&Mxd6^e7(gP`1kOqmP-i2S$s}h=Ej8%266_v4XidWc$((1l z95rT+hl?5Z%=_j27QNidS{J9t7^gjMj2p>-tI;iRWqRgAaRfrn%^|w84g>e2-rxojsM zKpTfoB#^9XJaHA`kG!lFn7`hLOd`S)HLn+#7kz)N>FU_EHf9V9?49ak)%gCAgUSCx zV-%q=REK`R6CKI1B_A=}edearH?oNFT(-tWY#YyI+t`Th@pIW8Z^X9wT(-@P*tVX_ zwiUBQg)d(jb0_5I_96(FIwC)byqWc8W+hW`b)2me<>x~1=Q8vV86!Y}B}0ibD54Ic zvP}J8{_)_H>gfx$K*g?RWvNc)_z2^8z`aY%G4=2R0d?erpFSW{m@c20Q;MSy(-kwO zGCocM7vutoeTo;8VSQHT*B2`hVTupmTdr3rRx=4_daA zBIy}~y0vny{*)zJh|<4Lz?mw*mx5UB^yee+umsPwF`}?8g}*#3>=fK<1++H)O*A literal 0 HcmV?d00001 diff --git a/oldconfig/btop/btop.conf b/oldconfig/btop/btop.conf new file mode 100644 index 0000000..6cc3932 --- /dev/null +++ b/oldconfig/btop/btop.conf @@ -0,0 +1,206 @@ +#? Config file for btop v. 1.2.8 + +#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes. +#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes" +color_theme = "/nix/store/yg60rrdvsfd0vfxmiy5kjd91vcmzih9z-btop-1.2.8/share/btop/themes/tokyo-night.theme" + +#* If the theme set background should be shown, set to False if you want terminal background transparency. +theme_background = True + +#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false. +truecolor = True + +#* Set to true to force tty mode regardless if a real tty has been detected or not. +#* Will force 16-color mode and TTY theme, set all graph symbols to "tty" and swap out other non tty friendly symbols. +force_tty = False + +#* Define presets for the layout of the boxes. Preset 0 is always all boxes shown with default settings. Max 9 presets. +#* Format: "box_name:P:G,box_name:P:G" P=(0 or 1) for alternate positions, G=graph symbol to use for box. +#* Use withespace " " as separator between different presets. +#* Example: "cpu:0:default,mem:0:tty,proc:1:default cpu:0:braille,proc:0:tty" +presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:default cpu:0:block,net:0:tty" + +#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists. +#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift. +vim_keys = False + +#* Rounded corners on boxes, is ignored if TTY mode is ON. +rounded_corners = False + +#* Default symbols to use for graph creation, "braille", "block" or "tty". +#* "braille" offers the highest resolution but might not be included in all fonts. +#* "block" has half the resolution of braille but uses more common characters. +#* "tty" uses only 3 different symbols but will work with most fonts and should work in a real TTY. +#* Note that "tty" only has half the horizontal resolution of the other two, so will show a shorter historical view. +graph_symbol = "braille" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_cpu = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_mem = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_net = "default" + +# Graph symbol to use for graphs in cpu box, "default", "braille", "block" or "tty". +graph_symbol_proc = "default" + +#* Manually set which boxes to show. Available values are "cpu mem net proc", separate values with whitespace. +shown_boxes = "proc cpu net mem" + +#* Update time in milliseconds, recommended 2000 ms or above for better sample times for graphs. +update_ms = 300 + +#* Processes sorting, "pid" "program" "arguments" "threads" "user" "memory" "cpu lazy" "cpu direct", +#* "cpu lazy" sorts top process over time (easier to follow), "cpu direct" updates top process directly. +proc_sorting = "cpu lazy" + +#* Reverse sorting order, True or False. +proc_reversed = False + +#* Show processes as a tree. +proc_tree = False + +#* Use the cpu graph colors in the process list. +proc_colors = True + +#* Use a darkening gradient in the process list. +proc_gradient = True + +#* If process cpu usage should be of the core it's running on or usage of the total available cpu power. +proc_per_core = True + +#* Show process memory as bytes instead of percent. +proc_mem_bytes = True + +#* Use /proc/[pid]/smaps for memory information in the process info box (very slow but more accurate) +proc_info_smaps = False + +#* Show proc box on left side of screen instead of right. +proc_left = False + +#* (Linux) Filter processes tied to the Linux kernel(similar behavior to htop). +proc_filter_kernel = False + +#* Sets the CPU stat shown in upper half of the CPU graph, "total" is always available. +#* Select from a list of detected attributes from the options menu. +cpu_graph_upper = "total" + +#* Sets the CPU stat shown in lower half of the CPU graph, "total" is always available. +#* Select from a list of detected attributes from the options menu. +cpu_graph_lower = "total" + +#* Toggles if the lower CPU graph should be inverted. +cpu_invert_lower = True + +#* Set to True to completely disable the lower CPU graph. +cpu_single_graph = False + +#* Show cpu box at bottom of screen instead of top. +cpu_bottom = False + +#* Shows the system uptime in the CPU box. +show_uptime = True + +#* Show cpu temperature. +check_temp = True + +#* Which sensor to use for cpu temperature, use options menu to select from list of available sensors. +cpu_sensor = "Auto" + +#* Show temperatures for cpu cores also if check_temp is True and sensors has been found. +show_coretemp = True + +#* Set a custom mapping between core and coretemp, can be needed on certain cpus to get correct temperature for correct core. +#* Use lm-sensors or similar to see which cores are reporting temperatures on your machine. +#* Format "x:y" x=core with wrong temp, y=core with correct temp, use space as separator between multiple entries. +#* Example: "4:0 5:1 6:3" +cpu_core_map = "" + +#* Which temperature scale to use, available values: "celsius", "fahrenheit", "kelvin" and "rankine". +temp_scale = "celsius" + +#* Use base 10 for bits/bytes sizes, KB = 1000 instead of KiB = 1024. +base_10_sizes = False + +#* Show CPU frequency. +show_cpu_freq = True + +#* Draw a clock at top of screen, formatting according to strftime, empty string to disable. +#* Special formatting: /host = hostname | /user = username | /uptime = system uptime +clock_format = "%X" + +#* Update main ui in background when menus are showing, set this to false if the menus is flickering too much for comfort. +background_update = True + +#* Custom cpu model name, empty string to disable. +custom_cpu_name = "" + +#* Optional filter for shown disks, should be full path of a mountpoint, separate multiple values with whitespace " ". +#* Begin line with "exclude=" to change to exclude filter, otherwise defaults to "most include" filter. Example: disks_filter="exclude=/boot /home/user". +disks_filter = "" + +#* Show graphs instead of meters for memory values. +mem_graphs = True + +#* Show mem box below net box instead of above. +mem_below_net = False + +#* Count ZFS ARC in cached and available memory. +zfs_arc_cached = True + +#* If swap memory should be shown in memory box. +show_swap = True + +#* Show swap as a disk, ignores show_swap value above, inserts itself after first disk. +swap_disk = True + +#* If mem box should be split to also show disks info. +show_disks = True + +#* Filter out non physical disks. Set this to False to include network disks, RAM disks and similar. +only_physical = True + +#* Read disks list from /etc/fstab. This also disables only_physical. +use_fstab = True + +#* Set to true to show available disk space for privileged users. +disk_free_priv = False + +#* Toggles if io activity % (disk busy time) should be shown in regular disk usage view. +show_io_stat = True + +#* Toggles io mode for disks, showing big graphs for disk read/write speeds. +io_mode = False + +#* Set to True to show combined read/write io graphs in io mode. +io_graph_combined = False + +#* Set the top speed for the io graphs in MiB/s (100 by default), use format "mountpoint:speed" separate disks with whitespace " ". +#* Example: "/mnt/media:100 /:20 /boot:1". +io_graph_speeds = "" + +#* Set fixed values for network graphs in Mebibits. Is only used if net_auto is also set to False. +net_download = 100 + +net_upload = 100 + +#* Use network graphs auto rescaling mode, ignores any values set above and rescales down to 10 Kibibytes at the lowest. +net_auto = False + +#* Sync the auto scaling for download and upload to whichever currently has the highest scale. +net_sync = False + +#* Starts with the Network Interface specified here. +net_iface = "" + +#* Show battery stats in top right if battery is present. +show_battery = True + +#* Which battery to use if multiple are present. "Auto" for auto detection. +selected_battery = "Auto" + +#* Set loglevel for "~/.config/btop/btop.log" levels are: "ERROR" "WARNING" "INFO" "DEBUG". +#* The level set includes all lower levels, i.e. "DEBUG" will show all logging info. +log_level = "WARNING" \ No newline at end of file