diff --git a/src/sites/twitch-twilight/modules/css_tweaks/index.js b/src/sites/twitch-twilight/modules/css_tweaks/index.js index e49b2d2b..db440606 100644 --- a/src/sites/twitch-twilight/modules/css_tweaks/index.js +++ b/src/sites/twitch-twilight/modules/css_tweaks/index.js @@ -23,6 +23,7 @@ const CLASSES = { 'pinned-cheer': '.pinned-cheer', 'whispers': '.whispers', + 'dir-live-ind': '.live-channel-card:not([data-a-target*="host"]) .stream-type-indicator.stream-type-indicator--live', 'boxart-hover': '.tw-card .tw-full-width:hover a[data-a-target="live-channel-card-game-link"]', 'boxart-hide': '.tw-card a[data-a-target="live-channel-card-game-link"]', 'profile-hover-following': '.tw-card .tw-full-width:hover .ffz-channel-avatar', diff --git a/src/sites/twitch-twilight/modules/css_tweaks/styles/chat-width.scss b/src/sites/twitch-twilight/modules/css_tweaks/styles/chat-width.scss index 5119ab87..91de4410 100644 --- a/src/sites/twitch-twilight/modules/css_tweaks/styles/chat-width.scss +++ b/src/sites/twitch-twilight/modules/css_tweaks/styles/chat-width.scss @@ -10,4 +10,13 @@ body .channel-page__video-player--theatre-mode { body .video-watch-page__right-column, body .channel-page__right-column { width: var(--ffz-chat-width); +} + +body .video-chat__sync-button { + width: calc(var(--ffz-chat-width) - 4rem); +} + +body .video-chat { + -ms-flex-preferred-size: var(--ffz-chat-width); + flex-basis: var(--ffz-chat-width); } \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/directory/following.js b/src/sites/twitch-twilight/modules/directory/following.js index e2f21dea..1db0a16a 100644 --- a/src/sites/twitch-twilight/modules/directory/following.js +++ b/src/sites/twitch-twilight/modules/directory/following.js @@ -392,114 +392,47 @@ export default class Following extends SiteModule { } updateChannelCard(inst) { - this.parent.updateUptime(inst, 'props.viewerCount.createdAt', '.tw-card .tw-aspect > div'); - const container = this.fine.getHostNode(inst), card = container && container.querySelector && container.querySelector('.tw-card'); - if ( container === null || card === null ) + if ( ! card ) return; - if (inst.props.streamType === 'watch_party') + const hosting = inst.props.channelNameLinkTo.state.content === 'live_host' && this.hosts && this.hosts[inst.props.channelName], + data = { + login: hosting ? this.hosts[inst.props.channelName].channel : inst.props.linkTo.pathname.substr(1), + displayName: inst.props.channelName, + profileImageURL: inst.props.viewerCount && inst.props.viewerCount.profileImageURL + }; + + this.parent.updateUptime(inst, 'props.viewerCount.createdAt', '.tw-card .tw-aspect > div'); + this.parent.addCardAvatar(inst, 'props.viewerCount', '.tw-card', data); + + if (inst.props.streamType === 'rerun') container.parentElement.classList.toggle('tw-hide', this.settings.get('directory.hide-vodcasts')); - // Remove old elements - const hiddenBodyCard = card.querySelector('.tw-card-body.tw-hide'); - if (hiddenBodyCard !== null) hiddenBodyCard.classList.remove('tw-hide'); + if ( hosting && this.settings.get('directory.following.group-hosts') ) { + const host_data = this.hosts[data.displayName]; - const ffzChannelData = card.querySelector('.ffz-channel-data'); - if (ffzChannelData !== null) ffzChannelData.remove(); + const title_link = card.querySelector('a[data-a-target="live-channel-card-title-link"]'), + thumbnail_link = card.querySelector('a[data-a-target="live-channel-card-thumbnail-link"]'), + card_title = card.querySelector('.live-channel-card__title'), - const channelAvatar = card.querySelector('.ffz-channel-avatar'); - if (channelAvatar !== null) channelAvatar.remove(); + text_content = host_data.channels.length !== 1 ? + this.i18n.t('host-menu.multiple', '%{count} hosting %{channel}', { + count: host_data.channels.length, + channel: data.displayName + }) : inst.props.title; - if (inst.props.viewerCount.profileImageURL) { - const hosting = inst.props.channelNameLinkTo.state.content === 'live_host' && this.hosts && this.hosts[inst.props.channelName]; - let channel, displayName; - if (hosting) { - channel = this.hosts[inst.props.channelName].channel; - displayName = inst.props.channelName; - } + if ( card_title ) + card_title.textContent = card_title.title = text_content; - const avatarSetting = this.settings.get('directory.show-channel-avatars'); - const cardDiv = card.querySelector('.tw-card-body'); - const modifiedDiv = e('div', { - innerHTML: cardDiv.innerHTML - }); + if ( title_link ) + title_link.addEventListener('click', this.showHostMenu.bind(this, inst, host_data)); - const broadcasterLogin = inst.props.linkTo.pathname.substring(1); - modifiedDiv.querySelector('.live-channel-card__channel').onclick = event => { - event.preventDefault(); - event.stopPropagation(); - - this.router.navigate('user', { userName: broadcasterLogin }); - }; - modifiedDiv.querySelector('.live-channel-card__videos').onclick = event => { - event.preventDefault(); - event.stopPropagation(); - - this.router.navigate('user-videos', { userName: broadcasterLogin }); - }; - - let avatarDiv; - if (avatarSetting === 1) { - avatarDiv = e('a', { - className: 'ffz-channel-avatar tw-mg-r-05 tw-mg-t-05', - href: hosting ? `/${channel}` : inst.props.linkTo.pathname, - onclick: event => this.parent.hijackUserClick(event, broadcasterLogin) - }, e('img', { - title: inst.props.channelName, - src: inst.props.viewerCount.profileImageURL - })); - } else if (avatarSetting === 2 || avatarSetting === 3) { - const avatarElement = e('a', { - className: 'ffz-channel-avatar', - href: hosting ? `/${channel}` : inst.props.linkTo.pathname, - onclick: event => this.parent.hijackUserClick(event, broadcasterLogin) - }, e('div', 'live-channel-card__boxart tw-bottom-0 tw-absolute', - e('figure', 'tw-aspect tw-aspect--align-top', - e('img', { - title: inst.props.channelName, - src: inst.props.viewerCount.profileImageURL - }) - ) - ) - ); - - const divToAppend = card.querySelector('.tw-aspect > div'); - if (divToAppend.querySelector('.ffz-channel-avatar') === null) divToAppend.appendChild(avatarElement); - } - - const cardDivParent = cardDiv.parentElement; - const ffzChannelData = cardDivParent.querySelector('.ffz-channel-data'); - if (ffzChannelData === null) { - cardDiv.classList.add('tw-hide'); - - const newCardDiv = e('div', 'ffz-channel-data tw-flex tw-flex-nowrap', [ - avatarDiv, modifiedDiv - ]); - cardDivParent.appendChild(newCardDiv); - } - - if (hosting) { - const hostObj = this.hosts[displayName]; - if (this.settings.get('directory.following.group-hosts')) { - const titleLink = card.querySelector('.ffz-channel-data a[data-a-target="live-channel-card-title-link"]'); - const thumbnailLink = card.querySelector('a[data-a-target="live-channel-card-thumbnail-link"]'); - const channelCardTitle = card.querySelector('.ffz-channel-data .live-channel-card__title'); - - const textContent = hostObj.channels.length > 1 ? `${hostObj.channels.length} hosting ${displayName}` : inst.props.title; - if (channelCardTitle !== null) { - channelCardTitle.textContent - = channelCardTitle.title - = textContent; - } - - if (thumbnailLink !== null) thumbnailLink.title = textContent; - - if (titleLink !== null) titleLink.onclick = this.showHostMenu.bind(this, inst, hostObj); - if (thumbnailLink !== null) thumbnailLink.onclick = this.showHostMenu.bind(this, inst, hostObj); - } + if ( thumbnail_link ) { + thumbnail_link.title = text_content; + thumbnail_link.addEventListener('click', this.showHostMenu.bind(this, inst, host_data)); } } } diff --git a/src/sites/twitch-twilight/modules/directory/index.js b/src/sites/twitch-twilight/modules/directory/index.js index 132af9ba..84f1ff94 100644 --- a/src/sites/twitch-twilight/modules/directory/index.js +++ b/src/sites/twitch-twilight/modules/directory/index.js @@ -110,13 +110,24 @@ export default class Directory extends SiteModule { }); + this.settings.add('directory.hide-live', { + default: false, + ui: { + path: 'Directory > Channels >> Appearance', + title: 'Do not show the Live indicator on channels that are live.', + component: 'setting-check-box' + }, + + changed: value => this.css_tweaks.toggleHide('dir-live-ind', value) + }); + + this.settings.add('directory.hide-vodcasts', { default: false, ui: { path: 'Directory > Channels >> Appearance', - title: 'Hide Vodcasts', - description: 'Hide vodcasts in the directories.', + title: 'Do not show reruns in the directory.', component: 'setting-check-box' }, @@ -132,6 +143,7 @@ export default class Directory extends SiteModule { this.css_tweaks.toggleHide('profile-hover-game', avatars === 2); this.css_tweaks.toggleHide('profile-hover-following', avatars === 2); + this.css_tweaks.toggleHide('dir-live-ind', this.settings.get('directory.hide-live')); this.css_tweaks.toggleHide('boxart-hide', boxart === 0); this.css_tweaks.toggleHide('boxart-hover', boxart === 1); @@ -162,7 +174,7 @@ export default class Directory extends SiteModule { const hiddenThumbnails = this.settings.provider.get('directory.game.hidden-thumbnails') || []; const hiddenPreview = 'https://static-cdn.jtvnw.net/ttv-static/404_preview-320x180.jpg'; - if (get('props.streamNode.type', inst) === 'watch_party' || get('props.type', inst) === 'watch_party') + if (get('props.streamNode.type', inst) === 'rerun' || get('props.type', inst) === 'rerun') container.classList.toggle('tw-hide', this.settings.get('directory.hide-vodcasts')); const img = container.querySelector && container.querySelector('.tw-card-img img'); @@ -264,59 +276,50 @@ export default class Directory extends SiteModule { } - addCardAvatar(inst, created_path, selector) { + addCardAvatar(inst, created_path, selector, data) { const container = this.fine.getHostNode(inst), card = container && container.querySelector && container.querySelector(selector), - setting = this.settings.get('directory.show-channel-avatars'), + setting = this.settings.get('directory.show-channel-avatars'); + + if ( ! data ) data = get(created_path, inst); if ( ! card ) return; - // Remove old elements - const hiddenBodyCard = card.querySelector('.tw-card-body.tw-hide'); - if (hiddenBodyCard !== null) - hiddenBodyCard.classList.remove('tw-hide'); + // Get the old element. + let channel_avatar = card.querySelector('.ffz-channel-avatar'); - const ffzChannelData = card.querySelector('.ffz-channel-data'); - if (ffzChannelData !== null) - ffzChannelData.remove(); + if ( ! data || ! data.profileImageURL || setting === 0 ) { + if ( channel_avatar !== null ) + channel_avatar.remove(); - const channelAvatar = card.querySelector('.ffz-channel-avatar'); - if (channelAvatar !== null) - channelAvatar.remove(); - - if ( setting === 0 ) return; + } - if (data) { - if (setting === 1) { - const cardDiv = card.querySelector('.tw-card-body'); - const modifiedDiv = e('div', { - innerHTML: cardDiv.innerHTML - }); + if ( setting !== inst.ffz_av_setting || data.login !== inst.ffz_av_login || data.profileImageURL !== inst.ffz_av_image ) { + if ( channel_avatar ) + channel_avatar.remove(); - const avatarDiv = e('a', { - className: 'ffz-channel-avatar tw-mg-r-05 tw-mg-t-05', - href: `/${data.login}`, - onclick: event => this.hijackUserClick(event, data.login) - }, e('img', { - title: data.displayName, - src: data.profileImageURL - })); + inst.ffz_av_setting = setting; + inst.ffz_av_login = data.login; + inst.ffz_av_image = data.profileImageURL; - const cardDivParent = cardDiv.parentElement; + if ( setting === 1 ) { + const body = card.querySelector('.tw-card-body .tw-flex'), + avatar = e('a', { + className: 'ffz-channel-avatar tw-mg-r-05 tw-mg-t-05', + href: `/${data.login}`, + title: data.displayName, + onclick: event => this.hijackUserClick(event, data.login) + }, e('img', { + src: data.profileImageURL + })); - if (cardDivParent.querySelector('.ffz-channel-data') === null) { - cardDiv.classList.add('tw-hide'); + body.insertBefore(avatar, body.firstElementChild); - const newCardDiv = e('div', 'ffz-channel-data tw-flex tw-flex-nowrap', [ - avatarDiv, modifiedDiv - ]); - cardDivParent.appendChild(newCardDiv); - } - } else if (setting === 2 || setting === 3) { - const avatarElement = e('a', { + } else if ( setting === 2 || setting === 3 ) { + const avatar_el = e('a', { className: 'ffz-channel-avatar', href: `/${data.login}`, onclick: event => this.hijackUserClick(event, data.login) @@ -325,13 +328,12 @@ export default class Directory extends SiteModule { e('img', { title: data.displayName, src: data.profileImageURL - }) - ) - )); + }))) + ); - const divToAppend = card.querySelector('figure.tw-aspect'); - if (divToAppend.querySelector('.ffz-channel-avatar') === null) - divToAppend.appendChild(avatarElement); + const cont = card.querySelector('figure.tw-aspect > div'); + if ( cont ) + cont.appendChild(avatar_el); } } } diff --git a/src/utilities/tooltip.js b/src/utilities/tooltip.js index ed82908f..7d02b22f 100644 --- a/src/utilities/tooltip.js +++ b/src/utilities/tooltip.js @@ -217,6 +217,9 @@ export class Tooltip { arrow.setAttribute('x-arrow', true); + if ( opts.arrowInner ) + arrow.appendChild(e('div', opts.arrowInner)); + if ( tip.add_class ) { inner.classList.add(tip.add_class); tip.add_class = undefined;