From 9ef7c2aee3e9102df909e6611c7a3930a138e2f3 Mon Sep 17 00:00:00 2001 From: Lordmau5 Date: Mon, 30 Apr 2018 20:27:14 +0200 Subject: [PATCH] Basic mod cards support (#423) * More work on mod cards * More work on mod cards! Some sort of dynamic component thingy madoohickey * Change up implementation of tabs * Implement focus and tabindex * Remove unused GQL queries / mutations * Implement user info * Only show use rlogin if an international name was detected Also attempt to fix line height * Remove testing memes * Remove derps... whoops --- .../twitch-twilight/modules/chat/index.js | 3 + .../twitch-twilight/modules/chat/line.js | 3 +- .../chat/mod_cards/components/main.vue | 63 ++++++++ .../modules/chat/mod_cards/get_user_info.gql | 25 ++++ .../modules/chat/mod_cards/index.js | 117 +++++++++++++++ .../modules/chat/mod_cards/mod-card.vue | 139 ++++++++++++++++++ .../modules/chat/mod_cards/tab-mixin.js | 19 +++ .../modules/directory/following.jsx | 2 +- src/sites/twitch-twilight/styles/main.scss | 3 +- .../twitch-twilight/styles/mod_card.scss | 40 +++++ 10 files changed, 411 insertions(+), 3 deletions(-) create mode 100644 src/sites/twitch-twilight/modules/chat/mod_cards/components/main.vue create mode 100644 src/sites/twitch-twilight/modules/chat/mod_cards/get_user_info.gql create mode 100644 src/sites/twitch-twilight/modules/chat/mod_cards/index.js create mode 100644 src/sites/twitch-twilight/modules/chat/mod_cards/mod-card.vue create mode 100644 src/sites/twitch-twilight/modules/chat/mod_cards/tab-mixin.js create mode 100644 src/sites/twitch-twilight/styles/mod_card.scss diff --git a/src/sites/twitch-twilight/modules/chat/index.js b/src/sites/twitch-twilight/modules/chat/index.js index b26fb87d..ebbe6cb2 100644 --- a/src/sites/twitch-twilight/modules/chat/index.js +++ b/src/sites/twitch-twilight/modules/chat/index.js @@ -17,6 +17,7 @@ import ChatLine from './line'; import SettingsMenu from './settings_menu'; import EmoteMenu from './emote_menu'; import TabCompletion from './tab_completion'; +import ModCards from './mod_cards'; const MESSAGE_TYPES = ((e = {}) => { @@ -119,6 +120,8 @@ export default class ChatHook extends Module { this.inject(SettingsMenu); this.inject(EmoteMenu); this.inject(TabCompletion); + + this.inject(ModCards); this.ChatController = this.fine.define( diff --git a/src/sites/twitch-twilight/modules/chat/line.js b/src/sites/twitch-twilight/modules/chat/line.js index 6562922c..3d96b41f 100644 --- a/src/sites/twitch-twilight/modules/chat/line.js +++ b/src/sites/twitch-twilight/modules/chat/line.js @@ -25,6 +25,7 @@ export default class ChatLine extends Module { this.inject('site'); this.inject('site.fine'); this.inject('site.web_munch'); + this.inject('site.apollo'); this.inject(RichContent); this.inject('chat.actions'); @@ -138,7 +139,7 @@ export default class ChatLine extends Module { e('a', { className: 'chat-author__display-name notranslate', style: { color }, - onClick: this.usernameClickHandler + onClick: t.parent.mod_cards.openCustomModCard.bind(t.parent.mod_cards, this, user) }, [ user.userDisplayName, user.isIntl && e('span', { diff --git a/src/sites/twitch-twilight/modules/chat/mod_cards/components/main.vue b/src/sites/twitch-twilight/modules/chat/mod_cards/components/main.vue new file mode 100644 index 00000000..1c9cb2fc --- /dev/null +++ b/src/sites/twitch-twilight/modules/chat/mod_cards/components/main.vue @@ -0,0 +1,63 @@ + + + \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/chat/mod_cards/get_user_info.gql b/src/sites/twitch-twilight/modules/chat/mod_cards/get_user_info.gql new file mode 100644 index 00000000..3041f5f3 --- /dev/null +++ b/src/sites/twitch-twilight/modules/chat/mod_cards/get_user_info.gql @@ -0,0 +1,25 @@ +query($userLogin: String) { + user(login: $userLogin) { + bannerImageURL + displayName + id + login + profileImageURL(width: 50) + createdAt + followers { + totalCount + } + profileViewCount + self { + friendship { + ... on FriendEdge { + node { + displayName + id + login + } + } + } + } + } +} \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/chat/mod_cards/index.js b/src/sites/twitch-twilight/modules/chat/mod_cards/index.js new file mode 100644 index 00000000..2321204d --- /dev/null +++ b/src/sites/twitch-twilight/modules/chat/mod_cards/index.js @@ -0,0 +1,117 @@ +'use strict'; + +// ============================================================================ +// Mod Cards Component +// ============================================================================ + +import Module from 'utilities/module'; + +import {createElement} from 'utilities/dom'; + +import GET_USER_INFO from './get_user_info.gql'; + +export default class ModCards extends Module { + constructor(...args) { + super(...args); + + this.inject('site.apollo'); + this.inject('i18n'); + + this.lastZIndex = 9001; + this.open_mod_cards = {}; + this.tabs = {}; + + this.addTab('main', { + visible: () => true, + + label: 'Main', + pill: 0, + + data: (user, room) => ({ + + }), + component: () => import('./components/main.vue') + }); + } + + addTab(key, data) { + if (this.tabs[key]) return; + + this.tabs[key] = data; + } + + async openCustomModCard(t, user, e) { + // Old mod-card + // t.usernameClickHandler(e); + + const posX = Math.min(window.innerWidth - 300, e.clientX), + posY = Math.min(window.innerHeight - 300, e.clientY), + room = { + id: t.props.channelID, + login: t.props.message.roomLogin + }, + currentUser = { + isModerator: t.props.isCurrentUserModerator, + isStaff: t.props.isCurrentUserStaff + }; + + if (this.open_mod_cards[user.userLogin]) { + this.open_mod_cards[user.userLogin].style.zIndex = ++this.lastZIndex; + return; + } + + const vue = this.resolve('vue'), + _mod_card_vue = import(/* webpackChunkName: "mod-card" */ './mod-card.vue'), + _user_info = this.apollo.client.query({ + query: GET_USER_INFO, + variables: { + userLogin: user.userLogin + } + }); + + const [, mod_card_vue, user_info] = await Promise.all([vue.enable(), _mod_card_vue, _user_info]); + + vue.component('mod-card', mod_card_vue.default); + + const mod_card = this.open_mod_cards[user.userLogin] = this.buildModCard(vue, user_info.data.user, room, currentUser); + + const main = document.querySelector('.twilight-root>.tw-full-height'); + main.appendChild(mod_card); + + mod_card.style.left = `${posX}px`; + mod_card.style.top = `${posY}px`; + } + + buildModCard(vue, user, room, currentUser) { + this.log.info(user); + const vueEl = new vue.Vue({ + el: createElement('div'), + render: h => { + const vueModCard = h('mod-card', { + activeTab: Object.keys(this.tabs)[0], + tabs: this.tabs, + user, + room, + currentUser, + + rawUserAge: this.i18n.toLocaleString(new Date(user.createdAt)), + userAge: this.i18n.toHumanTime((new Date() - new Date(user.createdAt)) / 1000), + + setActiveTab: tab => vueModCard.data.activeTab = tab, + + focus: el => { + el.style.zIndex = ++this.lastZIndex; + }, + + close: () => { + this.open_mod_cards[user.login].remove(); + this.open_mod_cards[user.login] = null; + } + }); + return vueModCard; + } + }); + + return vueEl.$el; + } +} \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/chat/mod_cards/mod-card.vue b/src/sites/twitch-twilight/modules/chat/mod_cards/mod-card.vue new file mode 100644 index 00000000..0b371eb5 --- /dev/null +++ b/src/sites/twitch-twilight/modules/chat/mod_cards/mod-card.vue @@ -0,0 +1,139 @@ + + + \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/chat/mod_cards/tab-mixin.js b/src/sites/twitch-twilight/modules/chat/mod_cards/tab-mixin.js new file mode 100644 index 00000000..9d4c39ea --- /dev/null +++ b/src/sites/twitch-twilight/modules/chat/mod_cards/tab-mixin.js @@ -0,0 +1,19 @@ +'use strict'; + +export default { + computed: { + data() { + const data = this.tab.data; + if ( typeof data === 'function' ) + return data.call(this, this.user, this.room, this.currentUser); + + return data; + } + }, + + methods: { + close() { + this.$emit('close'); + } + } +} \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/directory/following.jsx b/src/sites/twitch-twilight/modules/directory/following.jsx index 287f7bcd..10b9d25d 100644 --- a/src/sites/twitch-twilight/modules/directory/following.jsx +++ b/src/sites/twitch-twilight/modules/directory/following.jsx @@ -357,4 +357,4 @@ export default class Following extends SiteModule { } } } -} \ No newline at end of file +} diff --git a/src/sites/twitch-twilight/styles/main.scss b/src/sites/twitch-twilight/styles/main.scss index 8bfcb811..5fb7e555 100644 --- a/src/sites/twitch-twilight/styles/main.scss +++ b/src/sites/twitch-twilight/styles/main.scss @@ -11,4 +11,5 @@ @import 'fixes'; @import 'host_options'; -@import 'featured_follow'; \ No newline at end of file +@import 'featured_follow'; +@import 'mod_card'; \ No newline at end of file diff --git a/src/sites/twitch-twilight/styles/mod_card.scss b/src/sites/twitch-twilight/styles/mod_card.scss new file mode 100644 index 00000000..def7c955 --- /dev/null +++ b/src/sites/twitch-twilight/styles/mod_card.scss @@ -0,0 +1,40 @@ +.ffz-mod-card { + width: 340px; + z-index: 9001; + + > header { + background-size: cover; + background-position: top; + } + + .ffz-tooltip { + > * { + pointer-events: none; + } + } + + .ffz--background-dimmer { + background-color: rgba(0, 0, 0, 0.8); + } + + .ffz--info-lines > * { + line-height: 1.2; + } + + .mod-cards__tabs-container { + height: 3rem; + + > .mod-cards__tab { + position: relative; + top: -.1rem; + cursor: pointer; + display: inline-block; + line-height: 3rem; + margin-right: .5rem; + + &:hover, &.active { + border-top: 1px solid #6441a4; + } + } + } +} \ No newline at end of file