1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-07-05 18:48:31 +00:00
* Fixed: Update Switchboard to allow FFZ to load normally on Twitch's latest update, which updated their version of React Router.
* Fixed: Apply the setting to hide Recommended Channels from the sidebar to Popular Channels as well.
This commit is contained in:
SirStendec 2019-06-06 16:33:14 -04:00
parent 4e0539103a
commit 17abc10f7c
5 changed files with 189 additions and 8 deletions

View file

@ -151,7 +151,7 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`
FrankerFaceZ.Logger = Logger;
const VER = FrankerFaceZ.version_info = {
major: 4, minor: 2, revision: 5,
major: 4, minor: 2, revision: 6,
commit: __git_commit__,
build: __webpack_hash__,
toString: () =>

View file

@ -11,11 +11,11 @@ import {has} from 'utilities/object';
const CLASSES = {
'top-discover': '.top-nav__nav-link[data-a-target="discover-link"]',
'side-nav': '.side-nav',
'side-rec-channels': '.side-nav .recommended-channels',
'side-rec-channels': '.side-nav .recommended-channels,.side-nav .ffz--popular-channels',
'side-rec-friends': '.side-nav .recommended-friends',
'side-friends': '.side-nav .online-friends',
'side-closed-friends': '.side-nav--collapsed .online-friends',
'side-closed-rec-channels': '.side-nav--collapsed .recommended-channels',
'side-closed-rec-channels': '.side-nav--collapsed .recommended-channels,.side-nav--collapsed .ffz--popular-channels',
'side-offline-channels': '.side-nav-card__link[href*="/videos/"]',
'prime-offers': '.top-nav__prime',
@ -77,7 +77,7 @@ export default class CSSTweaks extends Module {
default: 1,
ui: {
path: 'Appearance > Layout >> Side Navigation',
title: 'Display Recommended Channels',
title: 'Display Recommended / Popular Channels',
component: 'setting-select-box',
data: [
{value: 0, title: 'Never'},

View file

@ -5,6 +5,7 @@
// ============================================================================
import Module from 'utilities/module';
import {has} from 'utilities/object';
const PORTRAIT_ROUTES = ['user', 'video', 'user-video', 'user-clip', 'user-videos', 'user-clips', 'user-collections', 'user-events', 'user-followers', 'user-following'];
const MINIMAL_ROUTES = ['popout', 'embed-chat'];
@ -24,6 +25,11 @@ export default class Layout extends Module {
n => n.hideOnBreakpoint && n.handleToggleVisibility
);
this.PopularChannels = this.fine.define(
'nav-popular',
n => n.getPopularChannels && n.props && has(n.props, 'locale')
);
this.settings.add('layout.portrait', {
default: false,
ui: {
@ -146,6 +152,14 @@ export default class Layout extends Module {
this.css_tweaks.setVariable('portrait-extra-width', `${this.settings.get('layout.portrait-extra-width')}rem`);
this.css_tweaks.setVariable('portrait-extra-height', `${this.settings.get('layout.portrait-extra-height')}rem`);
this.PopularChannels.ready((cls, instances) => {
for(const inst of instances)
this.updatePopular(inst);
});
this.PopularChannels.on('mount', this.updatePopular, this);
this.PopularChannels.on('update', this.updatePopular, this);
const t = this;
this.RightColumn.ready((cls, instances) => {
cls.prototype.ffzHideOnBreakpoint = function() {
@ -196,6 +210,12 @@ export default class Layout extends Module {
return this.settings.get('layout.is-minimal')
}
updatePopular(inst) {
const node = this.fine.getChildNode(inst);
if ( node )
node.classList.add('ffz--popular-channels');
}
updatePortraitMode() {
for(const inst of this.RightColumn.instances)
inst.hideOnBreakpoint();

View file

@ -33,21 +33,38 @@ export default class Switchboard extends Module {
}
awaitRoute(count = 0) {
const route = this.fine.searchTree(null,
n => n.props && n.props.component && n.props.path,
100);
if ( route )
return Promise.resolve(route);
if ( count > 50 )
return Promise.resolve(null);
return new Promise(r => setTimeout(r, 50)).then(() => this.awaitRoute(count + 1));
}
async onEnable() {
await this.parent.awaitElement('.twilight-minimal-root,.twilight-root,#root>div');
if ( this.web_munch._require || this.web_munch.v4 === false )
return;
const router = await this.awaitRouter(),
da_switch = router && this.fine.searchTree(router, n => n.context && n.context.router && n.props && n.props.children && n.componentWillMount && n.componentWillMount.toString().includes('Switch'));
// Find the current route.
const route = await this.awaitRoute(),
da_switch = route && this.fine.searchParent(route, n => n.props && n.props.children);
if ( ! da_switch )
return new Promise(r => setTimeout(r, 50)).then(() => this.onEnable());
// Identify Router
this.log.info(`Found Router and Switch with ${da_switch.props.children.length} routes.`);
const router = await this.awaitRouter();
const location = da_switch.context.router.route.location.pathname;
this.log.info(`Found Route and Switch with ${da_switch.props.children.length} routes.`);
const location = router.props.location.pathname;
for(const route of da_switch.props.children) {
if ( ! route.props || ! route.props.component )

View file

@ -0,0 +1,144 @@
<template lang="html">
<div class="ffz--icon-picker">
<div class="tw-full-width">
<div class="tw-search-input">
<label for="icon-search" class="tw-hide-accessible">
{{ t('setting.icon.search', 'Search for Icon') }}
</label>
<div class="tw-relative tw-mg-t-05">
<div class="tw-absolute tw-align-items-center tw-c-text-alt-2 tw-flex tw-full-height tw-input__icon tw-justify-content-center tw-left-0 tw-top-0 tw-z-default">
<figure class="ffz-i-search" />
</div>
<input
id="icon-search"
:placeholder="t('setting.actions.icon.search', 'Search for Icon')"
v-model="search"
type="search"
class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-l-3 tw-pd-r-1 tw-pd-y-05"
autocapitalize="off"
autocorrect="off"
autocomplete="off"
>
</div>
</div>
<simplebar classes="tw-c-background-alt-2 tw-border-l tw-border-r tw-border-b ffz--icon-picker__list tw-mg-b-05">
<div v-if="visible.length" role="radiogroup" class="tw-pd-1 tw-flex tw-flex-wrap" >
<div
v-for="i of visible"
:key="i[0]"
:aria-checked="value.icon === i[0]"
:class="{'tw-interactable--selected': value.icon === i[0]}"
class="ffz-icon tw-interactable tw-interactable--inverted"
role="radio"
tabindex="0"
@keydown.space.stop.prevent=""
@keyup.space="change(i[0])"
@keyup.enter="change(i[0])"
@click="change(i[0])"
>
<figure :class="`tw-mg-y-05 tw-mg-x-1 ${i[0]}`" />
</div>
</div>
<div v-else class="tw-align-center tw-pd-1 tw-c-text-alt-2">
{{ t('setting.actions.empty-search', 'no results') }}
</div>
</simplebar>
</div>
</div>
</template>
<script>
import {escape_regex, deep_copy} from 'utilities/object';
import {load, ICONS as FA_ICONS, ALIASES as FA_ALIASES} from 'utilities/font-awesome';
const FFZ_ICONS = [
'zreknarf',
'crown',
'verified',
'inventory',
'ignore',
'pin-outline',
'pin',
'block',
'ok',
'clock',
'eye',
'eye-off',
'trash',
'discord',
'star',
'star-empty',
'twitch',
'twitter',
'download',
'upload',
'download-cloud',
'upload-cloud',
'tag',
'tags',
'retweet',
'thumbs-up',
'thumbs-down',
'bell',
'bell-off',
'pencil',
'info',
'help',
'calendar',
'lock',
'lock-open',
'arrows-cw',
'gift',
'eyedropper',
'github',
'user-secret'
];
const FFZ_ALIASES = {
'block': ['ban', 'block'],
'ok': ['ok', 'unban', 'untimeout', 'checkmark'],
'clock': ['clock', 'clock-o', 'timeout']
};
const ICONS = FFZ_ICONS
.map(x => [`ffz-i-${x}`, FFZ_ALIASES[x] ? FFZ_ALIASES[x].join(' ') : x])
.concat(FA_ICONS.filter(x => ! FFZ_ICONS.includes(x)).map(x => [`ffz-fa fa-${x}`, FA_ALIASES[x] ? FA_ALIASES[x].join(' ') : x]));
export default {
props: ['value'],
data() {
return {
search: '',
icons: deep_copy(ICONS)
}
},
computed: {
visible() {
if ( ! this.search || ! this.search.length )
return this.icons;
const search = this.search.toLowerCase().replace(' ', '-'),
reg = new RegExp('(?:^|-| )' + escape_regex(search), 'i');
return this.icons.filter(x => reg.test(x[1]));
}
},
mounted() {
load();
},
methods: {
change(val) {
this.value.icon = val;
this.$emit('input', this.value);
}
}
}
</script>