diff --git a/src/main.js b/src/main.js
index ddf24ddf..78a5f721 100644
--- a/src/main.js
+++ b/src/main.js
@@ -100,7 +100,7 @@ class FrankerFaceZ extends Module {
FrankerFaceZ.Logger = Logger;
const VER = FrankerFaceZ.version_info = {
- major: 4, minor: 0, revision: 0, extra: '-rc12.2',
+ major: 4, minor: 0, revision: 0, extra: '-rc12.3',
commit: __git_commit__,
build: __webpack_hash__,
toString: () =>
diff --git a/src/modules/metadata.jsx b/src/modules/metadata.jsx
index 6a0fbdb9..31270523 100644
--- a/src/modules/metadata.jsx
+++ b/src/modules/metadata.jsx
@@ -231,6 +231,18 @@ export default class Metadata extends Module {
for(const inst of bar.ChannelBar.instances)
bar.updateMetadata(inst, keys);
}
+
+ const legacy_bar = this.resolve('site.legacy_channel_bar');
+ if ( legacy_bar ) {
+ for(const inst of legacy_bar.ChannelBar.instances)
+ legacy_bar.updateMetadata(inst, keys);
+ }
+
+ const game_header = this.resolve('site.directory.game');
+ if ( game_header ) {
+ for(const inst of game_header.GameHeader.instances)
+ game_header.updateMetadata(inst, keys);
+ }
}
@@ -257,7 +269,7 @@ export default class Metadata extends Module {
}
};
- if ( ! def )
+ if ( ! def || !!data.directory !== def.directory )
return destroy();
try {
@@ -507,6 +519,24 @@ export default class Metadata extends Module {
if ( def.disabled !== undefined )
el.disabled = maybe_call(def.disabled, this, data);
+ if ( typeof def.button === 'function' ) {
+ const btn = el.querySelector('button');
+ if ( btn ) {
+ let cls = maybe_call(def.button, this, data);
+ if ( typeof cls !== 'string' )
+ cls = `tw-button--${cls ? 'hollow' : 'text'}`;
+
+ if ( btn._class !== cls ) {
+ btn._class = cls;
+
+ if ( def.popup && def.click )
+ btn.className = `tw-interactive tw-button tw-button--full-width ${cls} ffz-has-stat-arrow`;
+ else
+ btn.className = `tw-interactive tw-button tw-button--full-width ${cls}`;
+ }
+ }
+ }
+
} catch(err) {
this.log.capture(err, {
tags: {
diff --git a/src/sites/twitch-twilight/modules/directory/game.jsx b/src/sites/twitch-twilight/modules/directory/game.jsx
index cbcb6254..396e0b97 100644
--- a/src/sites/twitch-twilight/modules/directory/game.jsx
+++ b/src/sites/twitch-twilight/modules/directory/game.jsx
@@ -16,27 +16,153 @@ export default class Game extends SiteModule {
this.inject('site.fine');
this.inject('site.apollo');
+ this.inject('metadata');
this.inject('i18n');
this.inject('settings');
- this.GameHeader = this.fine.define(
- 'game-header',
+ this.metadata.definitions.block_game = {
+ directory: true,
+ button(data) {
+ return `ffz-directory-toggle-block${data.blocked ? ' active' : ''}`
+ },
+
+ setup(data) {
+ if ( data.type !== 'GAMES' )
+ return null;
+
+ const blocked_games = this.settings.provider.get('directory.game.blocked-games', []),
+ blocked = blocked_games.includes(data.name);
+
+ data.blocked = blocked;
+ return data;
+ },
+
+ label(data) {
+ if ( ! data )
+ return null;
+
+ return data.blocked ?
+ this.i18n.t('directory.unblock', 'Unblock') :
+ this.i18n.t('directory.block', 'Block')
+ },
+
+ tooltip() {
+ return this.i18n.t('directory.block-explain', 'This will let you block streams playing this game from showing up in the directory.');
+ },
+
+ click: this.generateClickHandler('directory.game.blocked-games')
+ }
+
+ this.metadata.definitions.hide_thumbnails = {
+ directory: true,
+ button(data) {
+ return `ffz-directory-toggle-thumbnail${data.hidden ? ' active' : ''}`
+ },
+
+ setup(data) {
+ if ( data.type !== 'GAMES' )
+ return null;
+
+ const hidden_games = this.settings.provider.get('directory.game.hidden-thumbnails', []);
+
+ data.hidden = hidden_games.includes(data.name);
+ return data;
+ },
+
+ label(data) {
+ if ( ! data )
+ return null;
+
+ return data.hidden ?
+ this.i18n.t('directory.show-thumbnails', 'Show Thumbnails') :
+ this.i18n.t('directory.hide-thumbnails', 'Hide Thumbnails');
+ },
+
+ tooltip() {
+ return this.i18n.t('directory.thumbnails-explain', 'Enabling this will hide thumbnails of this game everywhere in the directory.');
+ },
+
+ click: this.generateClickHandler('directory.game.hidden-thumbnails')
+ }
+
+ this.LegacyGameHeader = this.fine.define(
+ 'legacy-game-header',
n => n.renderFollowButton && n.renderGameDetailsTab,
['dir-game-index', 'dir-community']
);
+ this.GameHeader = this.fine.define(
+ 'game-header',
+ n => n.renderDirectoryMetadata,
+ ['dir-game-index', 'dir-community', 'dir-game-videos', 'dir-game-clips', 'dir-game-details']
+ );
+
this.apollo.registerModifier('GamePage_Game_RENAME2', GAME_QUERY);
}
onEnable() {
+ this.GameHeader.on('unmount', this.unmountGameHeader, this);
+ this.GameHeader.on('mount', this.updateGameHeader, this);
+ this.GameHeader.on('update', this.updateGameHeader, this);
+
this.GameHeader.ready((cls, instances) => {
+ this.settings.updateContext({new_channel: true});
+
+ for(const inst of instances)
+ this.updateGameHeader(inst);
+ });
+
+ this.LegacyGameHeader.ready((cls, instances) => {
for(const inst of instances)
this.updateButtons(inst);
});
- this.GameHeader.on('update', this.updateButtons, this);
+ this.LegacyGameHeader.on('update', this.updateButtons, this);
}
+
+ unmountGameHeader(inst) { // eslint-disable-line class-methods-use-this
+ const timers = inst._ffz_meta_timers;
+ if ( timers )
+ for(const key in timers)
+ if ( timers[key] )
+ clearTimeout(timers[key]);
+ }
+
+
+ updateGameHeader(inst) {
+ this.updateMetadata(inst);
+ }
+
+
+ updateMetadata(inst, keys) {
+ const container = this.fine.getChildNode(inst),
+ wrapper = container && container.querySelector && container.querySelector('.side-nav-directory-info__info-wrapper > div + div');
+
+ if ( ! inst._ffz_mounted || ! wrapper )
+ return;
+
+ const metabar = wrapper;
+
+ if ( ! keys )
+ keys = this.metadata.keys;
+ else if ( ! Array.isArray(keys) )
+ keys = [keys];
+
+ const timers = inst._ffz_meta_timers = inst._ffz_meta_timers || {},
+ refresh_func = key => this.updateMetadata(inst, key),
+ data = {
+ directory: inst.props.data.directory,
+ type: inst.props.directoryType,
+ name: inst.props.directoryName,
+ _inst: inst
+ }
+
+ for(const key of keys)
+ this.metadata.render(key, data, metabar, timers, refresh_func);
+ }
+
+
updateButtons(inst, update = false) {
const container = this.fine.getChildNode(inst);
if ( inst.props.directoryType !== 'GAMES' || ! container || ! container.querySelector )
@@ -69,7 +195,7 @@ export default class Game extends SiteModule {
block_btn = ();
@@ -91,7 +217,7 @@ export default class Game extends SiteModule {
hidden_btn = ()
@@ -104,7 +230,7 @@ export default class Game extends SiteModule {
);
}
- generateClickHandler(setting, game, update_func) {
+ generateLegacyClickHandler(setting, game, update_func) {
return e => {
e.preventDefault();
const values = this.settings.provider.get(setting) || [],
@@ -120,4 +246,20 @@ export default class Game extends SiteModule {
}
}
+ generateClickHandler(setting) {
+ return (data, event, update_func) => {
+ const values = this.settings.provider.get(setting, []),
+ game = data.name,
+ idx = values.indexOf(game);
+
+ if ( idx === -1 )
+ values.push(game)
+ else
+ values.splice(idx, 1);
+
+ this.settings.provider.set(setting, values);
+ this.parent.DirectoryCard.forceUpdate();
+ update_func();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/sites/twitch-twilight/modules/sub_button.jsx b/src/sites/twitch-twilight/modules/sub_button.jsx
index 1d6ae33b..2c31de46 100644
--- a/src/sites/twitch-twilight/modules/sub_button.jsx
+++ b/src/sites/twitch-twilight/modules/sub_button.jsx
@@ -38,9 +38,33 @@ export default class SubButton extends Module {
}
onEnable() {
+ this.settings.on(':changed:layout.swap-sidebars', () => this.SubButton.forceUpdate())
+
this.SubButton.ready((cls, instances) => {
+ const t = this,
+ old_render = cls.prototype.render;
+
+ cls.prototype.render = function() {
+ try {
+ const old_direction = this.props.balloonDirection;
+ if ( old_direction !== undefined ) {
+ const should_be_left = t.settings.get('layout.swap-sidebars'),
+ is_left = old_direction.includes('--left');
+
+ if ( should_be_left && ! is_left )
+ this.props.balloonDirection = old_direction.replace('--right', '--left');
+ else if ( ! should_be_left && is_left )
+ this.props.balloonDirection = old_direction.replace('--left', '--right');
+ }
+ } catch(err) { /* no-op */ }
+
+ return old_render.call(this);
+ }
+
for(const inst of instances)
this.updateSubButton(inst);
+
+ this.SubButton.forceUpdate();
});
this.SubButton.on('mount', this.updateSubButton, this);
@@ -50,7 +74,7 @@ export default class SubButton extends Module {
updateSubButton(inst) {
const container = this.fine.getChildNode(inst),
- btn = container && container.querySelector('button.tw-button--dropmenu');
+ btn = container && container.querySelector('button[data-a-target="subscribe-button"]');
if ( ! btn )
return;
@@ -69,7 +93,13 @@ export default class SubButton extends Module {
/>
, btn.firstElementChild);
- } else if ( ! should_show && icon )
+ btn.appendChild();
+
+ } else if ( ! should_show && icon ) {
icon.remove();
+ const post = btn.querySelector('.ffz--post-prime');
+ if ( post )
+ post.remove();
+ }
}
}
\ No newline at end of file
diff --git a/src/sites/twitch-twilight/styles/channel.scss b/src/sites/twitch-twilight/styles/channel.scss
index 969dfffd..0c05af41 100644
--- a/src/sites/twitch-twilight/styles/channel.scss
+++ b/src/sites/twitch-twilight/styles/channel.scss
@@ -79,4 +79,13 @@
@keyframes ffz-fade-in {
from {opacity: 0}
to {opacity: 1}
+}
+
+
+.side-nav {
+ .ffz--can-prime,
+ .ffz--post-prime {
+ width: 0;
+ flex-grow: 1;
+ }
}
\ No newline at end of file