diff --git a/src/builtins/appearance/hidegifbutton.js b/src/builtins/appearance/hidegifbutton.js index 341a09f2..3d7dc07e 100644 --- a/src/builtins/appearance/hidegifbutton.js +++ b/src/builtins/appearance/hidegifbutton.js @@ -9,7 +9,7 @@ export default new class HideGIFButton extends Builtin { enabled() { this.after(WebpackModules.find(m => m.type && m.type.render && m.type.render.displayName === "ChannelTextAreaContainer").type, "render", (_, __, returnValue) => { - const buttons = Utilities.getNestedProp(returnValue, "props.children.props.children.props.children.1.props.children.props.children.2.props.children"); + const buttons = Utilities.getNestedProp(returnValue, "props.children.props.children.1.props.children.props.children.2.props.children"); if (Array.isArray(buttons)) { for (const button of buttons) { if (!button) continue; diff --git a/src/builtins/appearance/hidegiftbutton.js b/src/builtins/appearance/hidegiftbutton.js index 225240bb..104de326 100644 --- a/src/builtins/appearance/hidegiftbutton.js +++ b/src/builtins/appearance/hidegiftbutton.js @@ -9,7 +9,7 @@ export default new class HideGiftButton extends Builtin { enabled() { this.after(WebpackModules.find(m => m.type && m.type.render && m.type.render.displayName === "ChannelTextAreaContainer").type, "render", (_, __, returnValue) => { - const buttons = Utilities.getNestedProp(returnValue, "props.children.props.children.props.children.1.props.children.props.children.2.props.children"); + const buttons = Utilities.getNestedProp(returnValue, "props.children.props.children.1.props.children.props.children.2.props.children"); if (Array.isArray(buttons)) { for (const button of buttons) { if (!button || !button.props) continue; diff --git a/src/builtins/emotes/category.jsx b/src/builtins/emotes/category.jsx new file mode 100644 index 00000000..c6b8adee --- /dev/null +++ b/src/builtins/emotes/category.jsx @@ -0,0 +1,27 @@ +import {React} from "modules"; +import DownArrow from "../../ui/icons/downarrow"; + +export default class Category extends React.Component { + constructor(props) { + super(props); + this.state = { + opened: true + }; + } + render() { + return
+
+
this.setState({opened: !this.state.opened})}> +
+ {this.props.icon ? this.props.icon : null} +
+
{this.props.label}
+
+ +
+
+
+ {this.state.opened && this.props.children} +
; + } +} \ No newline at end of file diff --git a/src/builtins/emotes/emotemenu.js b/src/builtins/emotes/emotemenu.js index b716b24b..81958f6f 100644 --- a/src/builtins/emotes/emotemenu.js +++ b/src/builtins/emotes/emotemenu.js @@ -1,8 +1,13 @@ import Builtin from "../../structs/builtin"; import {Utilities, WebpackModules, React} from "modules"; -import Tabs from "./tabs"; - +import EmoteModule from "./emotes"; +import EmoteMenuCard from "../../ui/emotemenucard"; +import EmoteIcon from "../../ui/emoteicon"; +import Category from "./category"; +import Favorite from "../../ui/icons/favorite"; +import Twitch from "../../ui/icons/twitch"; const EmojiPicker = WebpackModules.find(m => m.type && m.type.displayName == "ExpressionPicker"); + export default new class EmoteMenu extends Builtin { get name() {return "EmoteMenu";} get collection() {return "emotes";} @@ -11,32 +16,57 @@ export default new class EmoteMenu extends Builtin { get hideEmojisID() {return "hideEmojiMenu";} get hideEmojis() {return this.get(this.hideEmojisID);} + getSelected(body) { + if (body[1]) return {id: "stickers", index: 1}; + else if (body[2]) return {id: "gif", index: 2}; + else if (body[3]) return {id: "emoji", index: 3}; + return {id: "bd-emotes", index: 3}; + } + enabled() { - this.before(EmojiPicker, "type", (_, [props]) => { - if (props.expressionPickerView == "emoji" && this.hideEmojis) props.expressionPickerView = "gif"; - }); - this.after(EmojiPicker, "type", (_, [props], returnValue) => { + this.after(EmojiPicker, "type", (_, __, returnValue) => { const head = Utilities.getNestedProp(returnValue, "props.children.props.children.props.children.1.props.children.0.props.children.props.children"); const body = Utilities.getNestedProp(returnValue, "props.children.props.children.props.children.1.props.children"); if (!head || !body) return returnValue; - - const selected = props.expressionPickerView; - const currentTab = Tabs.find(e => e.id === selected); + + let activePicker = this.getSelected(body); + let isActive = activePicker.id == "bd-emotes"; const tabProps = head[0].props; + if (!isActive && activePicker.id == "emoji" && this.hideEmojis) { + activePicker = {id: "bd-emotes", index: 3}; + isActive = true; + } + if (this.hideEmojis) head.splice(head.findIndex(e => e && e.props && e.props.id == "emoji-picker-tab"), 1); head.push( - ...Tabs.map(e => React.createElement("div", { - "id": e.id + "-tab", + React.createElement("div", { + "id": "bd-emotes-tab", "role": "tab", - "aria-selected": selected == e.id, + "aria-selected": isActive, "className": tabProps.className, }, React.createElement(tabProps.children.type, { - viewType: e.id, - isActive: selected == e.id, - setActiveView: tabProps.children.props.setActiveView - }, e.label)) + viewType: "bd-emotes", + isActive: isActive, + }, "Twitch") )); - if (currentTab) body[2] = currentTab.element(); - if (this.hideEmojis) head.splice(head.findIndex(e => e && e.props && e.props.id == "emoji-picker-tab"), 1); + if (isActive) { + body[activePicker.index] = React.createElement(EmoteMenuCard, { + type: "twitch", + }, [ + React.createElement(Category, { + label: "Favorites", + icon: React.createElement(Favorite, {}), + }, Object.entries(EmoteModule.favorites).map(([emote, url]) => { + return React.createElement(EmoteIcon, {emote, url}); + })), + React.createElement(Category, { + label: "Twitch Emotes", + icon: React.createElement(Twitch, {}) + }, Object.keys(EmoteModule.getCategory("TwitchGlobal")).map(emote=> { + const url = EmoteModule.getUrl("TwitchGlobal", emote); + return React.createElement(EmoteIcon, {emote, url}); + })) + ]); + } }); } diff --git a/src/builtins/emotes/tabs.js b/src/builtins/emotes/tabs.js deleted file mode 100644 index e886c8a6..00000000 --- a/src/builtins/emotes/tabs.js +++ /dev/null @@ -1,25 +0,0 @@ -import {React} from "modules"; -import EmoteModule from "./emotes"; -import EmoteMenuCard from "../../ui/emotemenucard"; -import EmoteIcon from "../../ui/emoteicon"; -export default [ - { - id: "twitchEmotes", - label: "Twitch Emotes", - element: () => React.createElement(EmoteMenuCard, { - type: "twitch" - }, Object.keys(EmoteModule.getCategory("TwitchGlobal")).map(emote=> { - const url = EmoteModule.getUrl("TwitchGlobal", emote); - return React.createElement(EmoteIcon, {emote, url}); - })) - }, - { - id: "favoriteEmotes", - label: "Favorite Emotes", - element: () => React.createElement(EmoteMenuCard, { - type: "favourite" - }, Object.entries(EmoteModule.favorites).map(([emote, url]) => { - return React.createElement(EmoteIcon, {emote, url}); - })) - } -]; \ No newline at end of file diff --git a/src/styles/builtins/emotemenu.css b/src/styles/builtins/emotemenu.css index 9621438e..baf151b2 100644 --- a/src/styles/builtins/emotemenu.css +++ b/src/styles/builtins/emotemenu.css @@ -108,20 +108,18 @@ background-color: #e2e2e2; } -#bd-qem-twitch-container, -#bd-qem-favourite-container { +#bd-emote-menu { width: 346px; height: 329px; background-color: #fff; border-radius: 0 0 5px 5px; } -#bd-qem-twitch-container .scroller-wrap, -#bd-qem-favourite-container .scroller-wrap { +#bd-emote-menu .scrollerBase-289Jih { height: 100%; } -.emote-menu-inner { +.bd-emote-menu-inner { padding: 5px 0 0 15px; } diff --git a/src/styles/builtins/emotes.css b/src/styles/builtins/emotes.css index 65a2e018..38a637b9 100644 --- a/src/styles/builtins/emotes.css +++ b/src/styles/builtins/emotes.css @@ -1,3 +1,64 @@ +.bd-emote-header { + color: var(--header-secondary); + justify-content: flex-start; + font-size: 12px; + font-weight: 600; + transition: color 0.125s; + align-items: center; + display: flex; +} + +.bd-emote-scroller { + max-height: 380px; +} + +.bd-emote-category { + margin-bottom: 12px; +} + +.bd-emote-content { + cursor: pointer; + position: sticky; + top: 0; + background: var(--background-secondary); + z-index: 2; +} + +.bd-emote-wrapper { + background-color: var(--background-secondary); + box-sizing: border-box; + height: 32px; + padding: 0 4px; + z-index: 1; +} + +.bd-emote-headerIcon { + width: 14px; + height: 14px; + margin-right: 8px; +} + +.bd-emote-headerLabel { + overflow: hidden; + text-overflow: ellipsis; + text-transform: uppercase; + white-space: nowrap; + margin-right: 8px; +} + +.bd-emote-headerIcon + .bd-emote-headerLabel { + margin-left: 8px; +} + +.bd-emote-headerCollapseIcon .bd-emote-opened { + transition: 0.3s; +} + +.bd-emote-headerCollapseIcon .bd-emote-closed { + transform: rotate(90deg); + transition: 0.3s; +} + #emote-container { padding: 10px; } diff --git a/src/ui/emotemenucard.jsx b/src/ui/emotemenucard.jsx index 8b9a82f5..b50ffe69 100644 --- a/src/ui/emotemenucard.jsx +++ b/src/ui/emotemenucard.jsx @@ -1,10 +1,10 @@ import {React, WebpackModules} from "modules"; -const Scroller = WebpackModules.getByDisplayName("VerticalScroller"); +const {ScrollerAuto: Scroller} = WebpackModules.getByProps("ScrollerAuto"); export default class EmoteMenuCard extends React.Component { render() { - return
- -
+ return
+ +
{this.props.children}
diff --git a/src/ui/icons/favorite.jsx b/src/ui/icons/favorite.jsx new file mode 100644 index 00000000..1d85e40b --- /dev/null +++ b/src/ui/icons/favorite.jsx @@ -0,0 +1,9 @@ +import {React} from "modules"; + +export default class Favorite extends React.Component { + render() { + return + + ; + } +} \ No newline at end of file diff --git a/src/ui/icons/twitch.jsx b/src/ui/icons/twitch.jsx new file mode 100644 index 00000000..1c7182c3 --- /dev/null +++ b/src/ui/icons/twitch.jsx @@ -0,0 +1,9 @@ +import {React} from "modules"; + +export default class Twitch extends React.Component { + render() { + return + + ; + } +} \ No newline at end of file