diff --git a/client/src/modules/pluginapi.js b/client/src/modules/pluginapi.js index 953a0ce2..ac5bfae7 100644 --- a/client/src/modules/pluginapi.js +++ b/client/src/modules/pluginapi.js @@ -12,6 +12,7 @@ import { EmoteModule } from 'builtin'; import { SettingsSet, SettingsCategory, Setting, SettingsScheme } from 'structs'; import { BdMenu, Modals, DOM, DOMObserver, VueInjector, Toasts, Notifications, BdContextMenu, DiscordContextMenu } from 'ui'; import * as CommonComponents from 'commoncomponents'; +import { default as Components } from '../ui/components/generic'; import { Utils, Filters, ClientLogger as Logger, ClientIPC, AsyncEventEmitter } from 'common'; import Settings from './settings'; import ExtModuleManager from './extmodulemanager'; @@ -64,6 +65,7 @@ export default class PluginApi { get EventsWrapper() { return EventsWrapper } get CommonComponents() { return CommonComponents } + get Components() { return Components } get Filters() { return Filters } get Discord() { return DiscordApi } get DiscordApi() { return DiscordApi } diff --git a/client/src/ui/components/generic/Button.vue b/client/src/ui/components/generic/Button.vue new file mode 100644 index 00000000..190d5507 --- /dev/null +++ b/client/src/ui/components/generic/Button.vue @@ -0,0 +1,21 @@ +/** + * BetterDiscord Generic Button Component + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / 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. +*/ + + + + diff --git a/client/src/ui/components/generic/ButtonGroup.vue b/client/src/ui/components/generic/ButtonGroup.vue new file mode 100644 index 00000000..d57011cd --- /dev/null +++ b/client/src/ui/components/generic/ButtonGroup.vue @@ -0,0 +1,23 @@ +/** + * BetterDiscord Generic Button Group Component + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / 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. +*/ + + + + diff --git a/client/src/ui/components/generic/index.js b/client/src/ui/components/generic/index.js new file mode 100644 index 00000000..e89b4651 --- /dev/null +++ b/client/src/ui/components/generic/index.js @@ -0,0 +1,29 @@ +import VrWrapper from '../../vrwrapper'; + +import ButtonGroupComponent from './ButtonGroup.vue'; +class ButtonGroupWrapper extends VrWrapper { + get component() { return ButtonGroupComponent } + constructor(props) { + super(); + this.props = props; + } +} + +import ButtonComponent from './Button.vue'; +class ButtonWrapper extends VrWrapper { + get component() { return ButtonComponent } + constructor(props) { + super(); + this.props = props; + } +} + +export default class { + static Button(props) { + return new ButtonWrapper(props); + } + + static ButtonGroup(props) { + return new ButtonGroupWrapper(props); + } +} diff --git a/tests/ext/plugins/Custom Elements Example/index.js b/tests/ext/plugins/Custom Elements Example/index.js index d441bfee..f54c8bda 100644 --- a/tests/ext/plugins/Custom Elements Example/index.js +++ b/tests/ext/plugins/Custom Elements Example/index.js @@ -19,6 +19,7 @@ module.exports = (Plugin, Api, Vendor) => { Logger.log('Custom Elements Example Started'); this.injectStyle(); this.patchGuildTextChannel(); + this.patchMessages(); return true; } @@ -31,6 +32,8 @@ module.exports = (Plugin, Api, Vendor) => { // Force update elements to remove our changes const GuildTextChannel = await ReactComponents.getComponent('GuildTextChannel'); GuildTextChannel.forceUpdateAll(); + const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }); + MessageContent.forceUpdateAll(); return true; } @@ -47,7 +50,14 @@ module.exports = (Plugin, Api, Vendor) => { &:hover { opacity: 1; } - }`; + } + .exampleBtnGroup { + .bd-button { + font-size: 14px; + padding: 5px; + } + } + `; await CssUtils.injectSass(css); } @@ -59,6 +69,14 @@ module.exports = (Plugin, Api, Vendor) => { GuildTextChannel.forceUpdateAll(); } + async patchMessages() { + // Get Message component and patch it's render function + const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: Reflection.resolve('container', 'containerCozy', 'containerCompact', 'edited').selector }); + monkeyPatch(MessageContent.component.prototype).after('render', this.injectGenericComponents.bind(this)); + // Force update to see our changes immediatly + MessageContent.forceUpdateAll(); + } + /* * Injecting a custom React element using React.createElement * https://reactjs.org/docs/react-api.html#createelement @@ -77,6 +95,30 @@ module.exports = (Plugin, Api, Vendor) => { child.children.push(customVueComponent(Vuewrap, { onClick: e => this.handleClick(e, child.channel) })); } + /** + * Inject generic components provided by BD + */ + injectGenericComponents(that, args, returnValue) { + // If children is not an array make it into one + if (!returnValue.props.children instanceof Array) returnValue.props.children = [returnValue.props.children]; + // Add a generic Button component provided by BD + returnValue.props.children.push(Api.Components.ButtonGroup({ + classes: [ 'exampleBtnGroup' ], // Additional classes for button group + buttons: [ + { + classes: ['exampleBtn'], // Additional classes for button + text: 'Hello World!', // Text for button + onClick: e => Logger.log('Hello World!') // Button click handler + }, + { + classes: ['exampleBtn'], + text: 'Button', + onClick: e => Logger.log('Button!') + } + ] + }).render()); // Render will return the wrapped component that can then be displayed + } + /** * Will log the channel object */