├── ErrorBoundary.jsx ├── LICENSE ├── Preview.jsx ├── README.md ├── Settings.jsx ├── index.js ├── manifest.json └── style.css /ErrorBoundary.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 Cynthia K. Rey, All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 3. Neither the name of the copyright holder nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software without 14 | * specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | const { resolve } = require('path') 29 | const { React, getModule } = require('powercord/webpack') 30 | const { Card } = require('powercord/components') 31 | const { DISCORD_INVITE, SpecialChannels: { SUPPORT_PLUGINS }, SETTINGS_FOLDER } = require('powercord/constants') 32 | const { gotoOrJoinServer } = require('powercord/util') 33 | 34 | const REPO = 'cyyynthia/better-replies' 35 | 36 | class ErrorBoundary extends React.PureComponent { 37 | constructor (props) { 38 | super(props) 39 | 40 | this.state = { crashed: false } 41 | } 42 | 43 | componentDidCatch (e) { 44 | const basePath = resolve(SETTINGS_FOLDER, '..') 45 | 46 | this.setState({ 47 | crashed: true, 48 | error: (e.stack || '') 49 | .split('\n') 50 | .filter(l => !l.includes('discordapp.com/assets/') && !l.includes('discord.com/assets/')) 51 | .join('\n') 52 | .split(basePath) 53 | .join('') 54 | }) 55 | } 56 | 57 | render () { 58 | if (this.state.crashed) { 59 | return ( 60 | 61 |

62 | An error occurred while rendering the preview. Please let Cynthia know by sending her a message with the 63 | error message on the Powercord server, or by opening an issue 64 | on the GitHub repository. 65 |

66 | {this.state.error} 67 |
68 | ) 69 | } 70 | 71 | return this.props.children 72 | } 73 | 74 | joinPorkord () { 75 | getModule([ 'popLayer' ], false).popLayer() 76 | gotoOrJoinServer(DISCORD_INVITE, SUPPORT_PLUGINS) 77 | } 78 | } 79 | 80 | module.exports = ErrorBoundary 81 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020-2021 Cynthia K. Rey, All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. Neither the name of the copyright holder nor the names of its contributors 12 | may be used to endorse or promote products derived from this software without 13 | specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Preview.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 Cynthia K. Rey, All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 3. Neither the name of the copyright holder nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software without 14 | * specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | const { React, getModule } = require('powercord/webpack'); 29 | 30 | const ChannelMessage = getModule([ 'getElementFromMessageId' ], false).default; 31 | const Message = getModule(m => m.prototype && m.prototype.getReaction && m.prototype.isSystemDM, false); 32 | const DiscordSettings = getModule([ 'MessageDisplayCompact' ], false); 33 | 34 | const CHANNEL = { 35 | isPrivate: () => false, 36 | isSystemDM: () => false, 37 | getGuildId: () => 'uwu', 38 | isArchivedThread: () => false, 39 | isThread: () => false, 40 | isForumPost: () => false, 41 | }; 42 | 43 | const MESSAGE_REF = new Message({ 44 | id: 'owo', 45 | author: { 46 | id: 'a', 47 | username: 'Ben', 48 | toString: () => 'Ben', 49 | isSystemUser: () => false, 50 | isVerifiedBot: () => false, 51 | isNonUserBot: () => false, 52 | getAvatarURL: () => 'https://powercord.dev/api/v2/avatar/465668689920917534.png' 53 | }, 54 | content: 'Cynthia be droppin another hot plugin soon™️', 55 | }); 56 | 57 | const MESSAGE = new Message({ 58 | id: 'uwu', 59 | type: 19, 60 | author: { 61 | id: 'b', 62 | username: 'Cynthia 🌹', 63 | toString: () => 'Cynthia 🌹', 64 | isSystemUser: () => false, 65 | isVerifiedBot: () => false, 66 | isNonUserBot: () => false, 67 | getAvatarURL: () => 'https://powercord.dev/api/v2/avatar/94762492923748352.png' 68 | }, 69 | content: 'Heck yeah 😎', 70 | messageReference: { __betterRepliesFakeMessage: MESSAGE_REF }, 71 | }); 72 | 73 | function Settings ({ appearance }) { 74 | const compact = DiscordSettings.MessageDisplayCompact.useSetting() 75 | 76 | return ( 77 |
    78 | 85 |
86 | ); 87 | } 88 | 89 | module.exports = React.memo(Settings); 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Better Replies 2 | 3 | Enhances replies and gives them the customization they need. Change their appearance and behavior easily, to your 4 | likings. 5 | -------------------------------------------------------------------------------- /Settings.jsx: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 Cynthia K. Rey, All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 3. Neither the name of the copyright holder nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software without 14 | * specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | const { React } = require('powercord/webpack'); 29 | const { FormTitle } = require('powercord/components'); 30 | const { RadioGroup, SwitchItem } = require('powercord/components/settings'); 31 | 32 | const ErrorBoundary = require('./ErrorBoundary.jsx') 33 | const Preview = require('./Preview.jsx') 34 | 35 | function Settings ({ getSetting, updateSetting, toggleSetting }) { 36 | return ( 37 | <> 38 | 39 | 40 | 41 | 42 | Settings 43 |
44 | updateSetting('appearance', e.value)} 46 | value={getSetting('appearance', 'default')} 47 | options={[ 48 | { 49 | name: 'Default', 50 | desc: 'Shows above the entire message.', 51 | value: 'default' 52 | }, 53 | { 54 | name: 'Quote', 55 | desc: 'Will show as a quote, just above the message contents.', 56 | value: 'quote' 57 | }, 58 | { 59 | name: 'Hidden', 60 | desc: 'This will completely disable inline replies from showing up.', 61 | value: 'hidden' 62 | } 63 | ]} 64 | > 65 | Appearance 66 | 67 | updateSetting('mention', e.value)} 70 | value={getSetting('mention', 'always')} 71 | options={[ 72 | { 73 | name: 'Always mention', 74 | desc: 'Default behavior. When replying, the mention will always be enabled.', 75 | value: 'always' 76 | }, 77 | { 78 | name: 'Remember', 79 | desc: 'Will remember your last setting and re-apply it. If you disabled it it\'ll remain disabled and vice-versa.', 80 | value: 'remember' 81 | }, 82 | { 83 | name: 'Never mention', 84 | desc: 'When replying, the mention will never be enabled.', 85 | value: 'never' 86 | } 87 | ]} 88 | > 89 | Outgoing replies settings 90 | 91 | updateSetting('ping', e.value)} 94 | value={getSetting('ping', 'default')} 95 | options={[ 96 | { 97 | name: 'Default', 98 | desc: 'Honors the set behavior by the sender.', 99 | value: 'default' 100 | }, 101 | { 102 | name: 'Never ping', 103 | desc: 'Suppress ping from replies sent with ping enabled. Note: this has no effect on mobile notifications.', 104 | value: 'never' 105 | }, 106 | { 107 | name: 'Always ping', 108 | desc: 'Ping even if the sender disabled the ping. Note: this has no effect on mobile notifications.', 109 | value: 'always' 110 | } 111 | ]} 112 | > 113 | Incoming replies settings 114 | 115 | toggleSetting('quick-toggle')} 119 | note2={'Whether the mention should be toggled when pressing backspace while you\'re at the beginning of the message. Currently a bit buggy :('} 120 | note={'This setting has been disabled due to a bug. Will be hopefully back before 2030.'} 121 | > 122 | Quick toggle 123 | 124 | 125 | ); 126 | } 127 | 128 | module.exports = React.memo(Settings); 129 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 Cynthia K. Rey, All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 3. Neither the name of the copyright holder nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software without 14 | * specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | const { React, getModule } = require('powercord/webpack'); 29 | const { Tooltip } = require('powercord/components'); 30 | const { findInReactTree } = require('powercord/util'); 31 | const { inject, uninject } = require('powercord/injector'); 32 | const { Plugin } = require('powercord/entities'); 33 | 34 | const Settings = require('./Settings'); 35 | 36 | module.exports = class BetterReplies extends Plugin { 37 | async startPlugin () { 38 | this.loadStylesheet('style.css'); 39 | powercord.api.settings.registerSettings(this.entityID, { 40 | category: this.entityID, 41 | label: 'Better Replies', 42 | render: Settings 43 | }); 44 | 45 | this.injectOutgoingReplies() 46 | this.injectIncomingReplies() 47 | this.injectFakeReference() 48 | } 49 | 50 | async injectOutgoingReplies () { 51 | const userStore = await getModule([ 'getCurrentUser', 'getUser' ]); 52 | const replierMdl = await getModule([ 'createPendingReply' ]); 53 | const Message = await getModule(m => (m.__powercordOriginal_default || m.default)?.toString().includes('childrenRepliedMessage')); 54 | const ChannelReply = await getModule(m => m.default?.displayName === 'ChannelReply'); 55 | const ChannelTextAreaContainer = await getModule((m) => m.type?.render?.displayName === 'ChannelTextAreaContainer'); 56 | 57 | inject('brep-reply-mention-setting', replierMdl, 'createPendingReply', (args) => { 58 | const mode = this.settings.get('mention', 'always'); 59 | if (mode === 'never') { 60 | args[0].shouldMention = false; 61 | } 62 | 63 | if (mode === 'remember') { 64 | const u = userStore.getCurrentUser(); 65 | args[0].shouldMention = args[0].message.author.id !== u.id && this.settings.get('--mention-cache', true); 66 | } 67 | 68 | return args; 69 | }, true); 70 | 71 | inject('brep-reply-mention-toggle', ChannelReply, 'default', (_, res) => { 72 | const tooltip = findInReactTree(res, n => n.disableTooltipPointerEvents); 73 | const renderer = tooltip.children; 74 | tooltip.children = (e) => { 75 | const res = renderer(e); 76 | const checked = res.props['aria-checked']; 77 | const handler = res.props.onClick; 78 | res.props.onClick = (e) => { 79 | this.settings.set('--mention-cache', !checked); 80 | handler(e); 81 | }; 82 | return res; 83 | }; 84 | return res; 85 | }); 86 | 87 | inject('brep-reply-appearance', Message, 'default', (_, res) => { 88 | const appearance = this.settings.get('appearance', 'default'); 89 | if (appearance === 'quote') { 90 | res.props.children.props.children[2].props.children.splice(2, 0, res.props.children.props.children[0]); 91 | } 92 | if (appearance !== 'default') { 93 | res.props.children.props.children[0] = null; 94 | } 95 | 96 | return res; 97 | }); 98 | 99 | /* 100 | inject('brep-reply-quick-toggle', ChannelTextAreaContainer.type, 'render', (args, res) => { 101 | const ta = findInReactTree(res, n => n.richValue && n.onKeyDown); 102 | if (ta.onKeyDown !== prevFn) { 103 | prevFn = ta.onKeyDown; 104 | injectedFn = ((prev, e) => { 105 | // I cba to do something decent, DOM access is enough 106 | const quickToggle = this.settings.get('quick-toggle', false); 107 | const toggler = document.querySelector('.channelTextArea-rNsIhG .mentionButton-3710-W'); 108 | const reactInstance = getReactInstance(document.querySelector('.channelTextArea-rNsIhG')); 109 | const textarea = findInReactTree(reactInstance.memoizedProps, n => n.richValue && n.onKeyDown); 110 | const { selection } = textarea.richValue; 111 | 112 | // todo: fix this shit 113 | if (quickToggle && toggler && e.key === 'Backspace' && selection.start.offset === 0 && selection.end.offset === 0) { 114 | toggler.click(); 115 | return; 116 | } 117 | prev(e); 118 | }).bind(null, prevFn); 119 | } 120 | 121 | ta.onKeyDown = injectedFn; 122 | return res; 123 | }); 124 | */ 125 | 126 | ChannelReply.default.displayName = 'ChannelReply'; 127 | ChannelTextAreaContainer.type.render.displayName = 'ChannelTextAreaContainer'; 128 | } 129 | 130 | async injectIncomingReplies () { 131 | const userStore = await getModule([ 'getCurrentUser', 'getUser' ]); 132 | const messageHandler = await getModule([ 'createMessageRecord' ]) 133 | const RepliedMessage = await getModule((m) => m.default?.displayName === 'RepliedMessage') 134 | 135 | inject('brep-notif-receive', messageHandler, 'createMessageRecord', (args) => { 136 | const msg = args[0] 137 | const user = userStore.getCurrentUser() 138 | const mode = this.settings.get('ping', 'default') 139 | 140 | if (mode === 'default' || msg.state === 'SENDING' || !msg.referenced_message) { 141 | return args 142 | } 143 | 144 | const isMentioned = Boolean(msg.mentions.find((u) => u.id === user.id)) 145 | if (mode === 'never' && !msg.mention_everyone && isMentioned && !msg.content.includes(user.id)) { 146 | msg.message_reference.__brepSuppressed = true 147 | msg.mentions = msg.mentions.filter((u) => u.id !== user.id) 148 | } 149 | 150 | if (mode === 'always' && !isMentioned && msg.referenced_message.author.id === user.id && msg.author.id !== user.id) { 151 | msg.message_reference.__brepEnforced = true 152 | msg.mentions.push(user) 153 | } 154 | 155 | return args 156 | }, true) 157 | 158 | inject('brep-notif-visual', RepliedMessage, 'default', ([ { baseMessage: { messageReference } } ], res) => { 159 | if (messageReference.__brepEnforced || messageReference.__brepSuppressed) { 160 | const idx = res.props.children.findIndex((n) =>'withMentionPrefix' in n.props) 161 | const username = res.props.children[idx] 162 | username.props.withMentionPrefix = false 163 | 164 | if (messageReference.__brepSuppressed) { 165 | res.props.children[idx] = [ 166 | React.createElement(Tooltip, { text: 'Ping suppressed' }, 167 | React.createElement('span', { style: { color: 'var(--text-muted)' } }, '@')), 168 | username 169 | ] 170 | } 171 | } 172 | return res 173 | }) 174 | 175 | RepliedMessage.default.displayName = 'RepliedMessage' 176 | } 177 | 178 | async injectFakeReference () { 179 | const referenceStore = await getModule([ 'getMessageByReference' ]); 180 | 181 | inject('brep-fake-ref', referenceStore, 'getMessageByReference', (args, res) => { 182 | if (args[0]?.__betterRepliesFakeMessage) { 183 | return { 184 | message: args[0].__betterRepliesFakeMessage, 185 | state: 0 186 | }; 187 | } 188 | 189 | return res; 190 | }); 191 | } 192 | 193 | pluginWillUnload () { 194 | powercord.api.settings.unregisterSettings(this.entityID); 195 | uninject('brep-reply-mention-setting'); 196 | uninject('brep-reply-mention-toggle'); 197 | uninject('brep-reply-appearance'); 198 | uninject('brep-reply-quick-toggle'); 199 | 200 | uninject('brep-notif-receive') 201 | uninject('brep-notif-visual') 202 | 203 | uninject('brep-fake-ref'); 204 | } 205 | }; 206 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Better Replies", 3 | "version": "1.2.0", 4 | "description": "Enhances replies and gives them the customization they need. Change their appearance and behavior easily, to your likings.", 5 | "author": "Cynthia", 6 | "license": "BSD-3-Clause" 7 | } 8 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021 Cynthia K. Rey, All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright notice, 10 | * this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 3. Neither the name of the copyright holder nor the names of its contributors 13 | * may be used to endorse or promote products derived from this software without 14 | * specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /* If it's tucked there, it's meant to be shown as a quote */ 29 | .contents-2MsGLg .repliedMessage-3Z6XBG { 30 | padding: 4px 14px; 31 | margin: 4px 0; 32 | } 33 | 34 | .contents-2MsGLg .repliedMessage-3Z6XBG::before { 35 | left: 0; 36 | top: 0; 37 | bottom: 0; 38 | margin: 0; 39 | right: auto; 40 | } 41 | 42 | .compact-2Nkcau .contents-2MsGLg .repliedMessage-3Z6XBG { 43 | margin: 0; 44 | padding: 2px 8px; 45 | } 46 | 47 | .compact-2Nkcau .contents-2MsGLg .repliedMessage-3Z6XBG .username-h_Y3Us, 48 | .compact-2Nkcau .contents-2MsGLg .repliedMessage-3Z6XBG .repliedTextPreview-1bvxun { 49 | text-indent: 0; 50 | } 51 | 52 | .better-replies-hidden, .better-replies-hidden + span { 53 | display: none; 54 | } 55 | 56 | .better-replies-preview-container { 57 | margin-bottom: 20px; 58 | pointer-events: none; 59 | } 60 | 61 | .better-replies-preview-container * { 62 | pointer-events: none !important; 63 | } 64 | 65 | .better-replies-error { 66 | padding: 20px; 67 | margin-bottom: 20px; 68 | color: var(--text-normal); 69 | border-color: #f04747; 70 | background-color: #f0474730; 71 | } 72 | 73 | .better-replies-error p { 74 | margin: 0; 75 | margin-bottom: 8px; 76 | } 77 | 78 | .better-replies-error code { 79 | user-select: text; 80 | } 81 | --------------------------------------------------------------------------------