mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-07-28 13:38:30 +00:00
4.20.5
* Added: Chat Action for editing a user's displayed name and color. Only applies to chat. * Changed: Re-enable the setting for hiding offline channels from the side-bar. * Changed: Updated dependencies. * Fixed: Issue with multiple copies of FFZ emotes appearing in tab-completion. * Fixed: Issue with tab-completion crashing sometimes in mod view. (Closes #839) * Fixed: Support for swapping sidebars with the latest Twitch changes. * Fixed: Hiding Recommended Channels from the sidebar. (Closes #840) * Removed: Setting for hiding Recommended Friends from the sidebar, since that section no longer exists.
This commit is contained in:
parent
50378bb3dc
commit
7638a885f2
16 changed files with 2862 additions and 2420 deletions
4810
package-lock.json
generated
4810
package-lock.json
generated
File diff suppressed because it is too large
Load diff
64
package.json
64
package.json
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.20.4",
|
"version": "4.20.5",
|
||||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -24,38 +24,38 @@
|
||||||
"font:update": "node bin/update_fonts"
|
"font:update": "node bin/update_fonts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.7.7",
|
"@babel/core": "^7.10.4",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.7.4",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.7.7",
|
"@babel/plugin-proposal-object-rest-spread": "^7.10.4",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.7.5",
|
"@babel/plugin-proposal-optional-chaining": "^7.10.4",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
"@babel/plugin-transform-react-jsx": "^7.7.7",
|
"@babel/plugin-transform-react-jsx": "^7.10.4",
|
||||||
"@ffz/fontello-cli": "^1.0.3",
|
"@ffz/fontello-cli": "^1.0.3",
|
||||||
"babel-eslint": "^10.0.3",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.1.0",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
"copy-webpack-plugin": "^5.1.1",
|
"copy-webpack-plugin": "^5.1.1",
|
||||||
"cross-env": "^6.0.3",
|
"cross-env": "^7.0.2",
|
||||||
"css-loader": "^3.1.0",
|
"css-loader": "^3.1.0",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^7.3.1",
|
||||||
"eslint-plugin-react": "^7.17.0",
|
"eslint-plugin-react": "^7.20.3",
|
||||||
"eslint-plugin-vue": "^6.1.2",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
"extract-loader": "^2.0.1",
|
"extract-loader": "^2.0.1",
|
||||||
"file-loader": "^4.1.0",
|
"file-loader": "^4.1.0",
|
||||||
"json-loader": "^0.5.7",
|
"json-loader": "^0.5.7",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^4.14.1",
|
||||||
"raw-loader": "^3.1.0",
|
"raw-loader": "^3.1.0",
|
||||||
"rimraf": "^3.0.0",
|
"rimraf": "^3.0.2",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"semver": "^7.1.1",
|
"semver": "^7.3.2",
|
||||||
"terser-webpack-plugin": "^2.3.1",
|
"terser-webpack-plugin": "^3.0.6",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-loader": "^15.8.3",
|
"vue-loader": "^15.8.3",
|
||||||
"vue-observe-visibility": "^0.4.6",
|
"vue-observe-visibility": "^0.4.6",
|
||||||
"vue-template-compiler": "^2.6.11",
|
"vue-template-compiler": "^2.6.11",
|
||||||
"webpack": "^4.41.5",
|
"webpack": "^4.43.0",
|
||||||
"webpack-cli": "^3.3.10",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.10.1",
|
"webpack-dev-server": "^3.11.0",
|
||||||
"webpack-manifest-plugin": "^2.2.0",
|
"webpack-manifest-plugin": "^2.2.0",
|
||||||
"webpack-merge": "^4.2.2"
|
"webpack-merge": "^4.2.2"
|
||||||
},
|
},
|
||||||
|
@ -65,26 +65,26 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ffz/icu-msgparser": "^1.0.2",
|
"@ffz/icu-msgparser": "^1.0.2",
|
||||||
"crypto-js": "^3.1.9-1",
|
"crypto-js": "^4.0.0",
|
||||||
"dayjs": "^1.8.18",
|
"dayjs": "^1.8.29",
|
||||||
"displacejs": "^1.4.0",
|
"displacejs": "^1.4.1",
|
||||||
"emoji-regex": "^8.0.0",
|
"emoji-regex": "^8.0.0",
|
||||||
"file-saver": "^2.0.1",
|
"file-saver": "^2.0.1",
|
||||||
"graphql": "^14.5.8",
|
"graphql": "^15.2.0",
|
||||||
"graphql-tag": "^2.9.1",
|
"graphql-tag": "^2.10.3",
|
||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"markdown-it": "^9.0.1",
|
"markdown-it": "^11.0.0",
|
||||||
"markdown-it-link-attributes": "^2.1.0",
|
"markdown-it-link-attributes": "^3.0.0",
|
||||||
"path-to-regexp": "^3.0.0",
|
"path-to-regexp": "^3.0.0",
|
||||||
"popper.js": "^1.14.3",
|
"popper.js": "^1.14.3",
|
||||||
"raven-js": "^3.24.2",
|
"raven-js": "^3.24.2",
|
||||||
"react": "^16.4.1",
|
"react": "^16.13.1",
|
||||||
"safe-regex": "^2.0.2",
|
"safe-regex": "^2.1.1",
|
||||||
"sortablejs": "^1.10.0-rc3",
|
"sortablejs": "^1.10.2",
|
||||||
"sourcemapped-stacktrace": "^1.1.11",
|
"sourcemapped-stacktrace": "^1.1.11",
|
||||||
"text-diff": "^1.0.1",
|
"text-diff": "^1.0.1",
|
||||||
"vue-clickaway": "^2.2.2",
|
"vue-clickaway": "^2.2.2",
|
||||||
"vue-color": "^2.4.6",
|
"vue-color": "^2.7.1",
|
||||||
"vuedraggable": "^2.23.0"
|
"vuedraggable": "^2.23.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -328,7 +328,10 @@ export default class Actions extends Module {
|
||||||
fp.destroy();
|
fp.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
target._ffz_destroy = target._ffz_outside = null;
|
if ( target._ffz_on_destroy )
|
||||||
|
target._ffz_on_destroy();
|
||||||
|
|
||||||
|
target._ffz_destroy = target._ffz_outside = target._ffz_on_destroy = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parent = document.body.querySelector('#root>div') || document.body,
|
const parent = document.body.querySelector('#root>div') || document.body,
|
||||||
|
@ -496,8 +499,8 @@ export default class Actions extends Module {
|
||||||
let line = null;
|
let line = null;
|
||||||
|
|
||||||
const handle_click = event => {
|
const handle_click = event => {
|
||||||
tip.hide();
|
|
||||||
this.handleClick(event);
|
this.handleClick(event);
|
||||||
|
tip.hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
for(const data of actions) {
|
for(const data of actions) {
|
||||||
|
|
|
@ -1,6 +1,32 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import {createElement} from 'utilities/dom';
|
// ============================================================================
|
||||||
|
// Edit Overrides
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
export const edit_overrides = {
|
||||||
|
presets: [{
|
||||||
|
appearance: {
|
||||||
|
type: 'icon',
|
||||||
|
icon: 'ffz-i-pencil'
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
|
||||||
|
required_context: ['user'],
|
||||||
|
|
||||||
|
title: 'Change Name & Color',
|
||||||
|
description: 'Allows you to set local overrides for a user\'s name and color in chat.',
|
||||||
|
|
||||||
|
tooltip() {
|
||||||
|
return this.i18n.t('chat.actions.edit_overrides', 'Change Name & Color')
|
||||||
|
},
|
||||||
|
|
||||||
|
click(event, data) {
|
||||||
|
//const ref = makeReference(event.clientX, event.clientY);
|
||||||
|
this.resolve('chat.overrides').renderUserEditor(data.user, event.target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Open URL
|
// Open URL
|
||||||
|
|
129
src/modules/chat/override-editor.vue
Normal file
129
src/modules/chat/override-editor.vue
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
<template>
|
||||||
|
<div class="ffz-override-editor tw-c-background-base tw-c-text-base tw-pd-05 tw-pd-l-1">
|
||||||
|
<div class="tw-flex tw-align-items-center tw-pd-b-05 tw-border-b tw-mg-b-05">
|
||||||
|
<div class="tw-flex-grow-1">
|
||||||
|
{{ t('chat.overrides.editing', 'Editing {user.login}...', {user}) }}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="tw-mg-l-05 tw-button tw-button--text"
|
||||||
|
@click="close"
|
||||||
|
>
|
||||||
|
<span class="tw-button__text ffz-i-window-close" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tw-flex tw-align-items-center">
|
||||||
|
<label for="user-name" class="tw-mg-r-1">
|
||||||
|
{{ t('chat.overrides.name', 'Name') }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<input
|
||||||
|
id="user-name"
|
||||||
|
ref="name"
|
||||||
|
class="tw-border-radius-medium tw-font-size-6 tw-pd-x-1 tw-pd-y-05 tw-input tw-flex-grow-1"
|
||||||
|
:value="name"
|
||||||
|
@change="updateName"
|
||||||
|
>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="tw-mg-l-05 tw-button tw-button--text tw-tooltip-wrapper"
|
||||||
|
:class="{'tw-button--disabled': name == null}"
|
||||||
|
@click="clearName"
|
||||||
|
>
|
||||||
|
<span class="tw-button__text ffz-i-cancel" />
|
||||||
|
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
|
||||||
|
{{ t('setting.reset', 'Reset to Default') }}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tw-flex tw-align-items-center">
|
||||||
|
<label for="user-color" class="tw-mg-r-1">
|
||||||
|
{{ t('chat.overrides.color', 'Color') }}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<color-picker
|
||||||
|
id="user-color"
|
||||||
|
ref="color"
|
||||||
|
:alpha="false"
|
||||||
|
:nullable="true"
|
||||||
|
:value="editColor"
|
||||||
|
@input="updateColor"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="tw-mg-l-05 tw-button tw-button--text tw-tooltip-wrapper"
|
||||||
|
:class="{'tw-button--disabled': color == null}"
|
||||||
|
@click="clearColor"
|
||||||
|
>
|
||||||
|
<span class="tw-button__text ffz-i-cancel" />
|
||||||
|
<div class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
|
||||||
|
{{ t('setting.reset', 'Reset to Default') }}
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { debounce } from 'utilities/object';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return this.$vnode.data
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
editColor() {
|
||||||
|
if ( ! this.color )
|
||||||
|
return '';
|
||||||
|
|
||||||
|
return this.color;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.updateName = debounce(this.updateName, 250);
|
||||||
|
this.updateColor = debounce(this.updateColor, 250);
|
||||||
|
},
|
||||||
|
|
||||||
|
updated() {
|
||||||
|
this.updateTip();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
clearName() {
|
||||||
|
this.name = null;
|
||||||
|
this.deleteName();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateName() {
|
||||||
|
const value = this.$refs.name.value;
|
||||||
|
if ( value == null || ! value.length ) {
|
||||||
|
this.clearName();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.name = value;
|
||||||
|
this.setName(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
clearColor() {
|
||||||
|
this.color = null;
|
||||||
|
this.deleteColor();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateColor(value) {
|
||||||
|
if ( value == null || ! value.length ) {
|
||||||
|
this.clearColor();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.color = value;
|
||||||
|
this.setColor(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
|
@ -5,6 +5,8 @@
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
import Module from 'utilities/module';
|
import Module from 'utilities/module';
|
||||||
|
import { createElement, ClickOutside } from 'utilities/dom';
|
||||||
|
import Tooltip from 'utilities/tooltip';
|
||||||
|
|
||||||
|
|
||||||
export default class Overrides extends Module {
|
export default class Overrides extends Module {
|
||||||
|
@ -12,14 +14,126 @@ export default class Overrides extends Module {
|
||||||
super(...args);
|
super(...args);
|
||||||
|
|
||||||
this.inject('settings');
|
this.inject('settings');
|
||||||
|
|
||||||
this.color_cache = null;
|
this.color_cache = null;
|
||||||
this.name_cache = null;
|
this.name_cache = null;
|
||||||
|
|
||||||
|
/*this.settings.addUI('chat.overrides', {
|
||||||
|
path: 'Chat > Overrides @{"profile_warning": false}',
|
||||||
|
component: 'chat-overrides',
|
||||||
|
|
||||||
|
on: (...args) => this.on(...args),
|
||||||
|
off: (...args) => this.off(...args),
|
||||||
|
|
||||||
|
setColor: (...args) => this.setColor(...args),
|
||||||
|
setName: (...args) => this.setName(...args),
|
||||||
|
deleteColor: id => this.deleteColor(id),
|
||||||
|
deleteName: id => this.deleteName(id),
|
||||||
|
|
||||||
|
getColors: () => this.colors,
|
||||||
|
getNames: () => this.names
|
||||||
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
onEnable() {
|
||||||
this.settings.provider.on('changed', this.onProviderChange, this);
|
this.settings.provider.on('changed', this.onProviderChange, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderUserEditor(user, target) {
|
||||||
|
let outside, popup, ve;
|
||||||
|
|
||||||
|
const destroy = () => {
|
||||||
|
const o = outside, p = popup, v = ve;
|
||||||
|
outside = popup = ve = null;
|
||||||
|
|
||||||
|
if ( o )
|
||||||
|
o.destroy();
|
||||||
|
|
||||||
|
if ( p )
|
||||||
|
p.destroy();
|
||||||
|
|
||||||
|
if ( v )
|
||||||
|
v.$destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const parent = document.body.querySelector('#root>div') || document.body;
|
||||||
|
|
||||||
|
popup = new Tooltip(parent, [], {
|
||||||
|
logger: this.log,
|
||||||
|
manual: true,
|
||||||
|
live: false,
|
||||||
|
html: true,
|
||||||
|
hover_events: true,
|
||||||
|
no_update: true,
|
||||||
|
no_auto_remove: true,
|
||||||
|
|
||||||
|
tooltipClass: 'ffz-action-balloon tw-balloon tw-block tw-border tw-elevation-1 tw-border-radius-small tw-c-background-base',
|
||||||
|
arrowClass: '', //tw-balloon__tail tw-overflow-hidden tw-absolute',
|
||||||
|
arrowInner: '', //tw-balloon__tail-symbol tw-border-t tw-border-r tw-border-b tw-border-l tw-border-radius-small tw-c-background-base tw-absolute',
|
||||||
|
innerClass: '',
|
||||||
|
|
||||||
|
popper: {
|
||||||
|
placement: 'bottom',
|
||||||
|
modifiers: {
|
||||||
|
preventOverflow: {
|
||||||
|
boundariesElement: parent
|
||||||
|
},
|
||||||
|
flip: {
|
||||||
|
behavior: ['bottom', 'top', 'left', 'right']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
content: async (t, tip) => {
|
||||||
|
const vue = this.resolve('vue'),
|
||||||
|
_editor = import(/* webpackChunkName: "overrides" */ './override-editor.vue');
|
||||||
|
|
||||||
|
const [, editor] = await Promise.all([vue.enable(), _editor]);
|
||||||
|
vue.component('override-editor', editor.default);
|
||||||
|
|
||||||
|
ve = new vue.Vue({
|
||||||
|
el: createElement('div'),
|
||||||
|
render: h => h('override-editor', {
|
||||||
|
user,
|
||||||
|
|
||||||
|
name: this.getName(user.id),
|
||||||
|
color: this.getColor(user.id),
|
||||||
|
|
||||||
|
updateTip: () => tip.update(),
|
||||||
|
setColor: val => this.setColor(user.id, val),
|
||||||
|
deleteColor: () => this.deleteColor(user.id),
|
||||||
|
setName: val => this.setName(user.id, val),
|
||||||
|
deleteName: () => this.deleteName(user.id),
|
||||||
|
|
||||||
|
close: () => tip.hide()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
return ve.$el;
|
||||||
|
},
|
||||||
|
|
||||||
|
onShow: async (t, tip) => {
|
||||||
|
await tip.waitForDom();
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
outside = new ClickOutside(tip.outer, destroy)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onMove: (target, tip, event) => {
|
||||||
|
this.emit('tooltips:mousemove', target, tip, event)
|
||||||
|
},
|
||||||
|
|
||||||
|
onLeave: (target, tip, event) => {
|
||||||
|
this.emit('tooltips:leave', target, tip, event);
|
||||||
|
},
|
||||||
|
|
||||||
|
onHide: destroy
|
||||||
|
});
|
||||||
|
|
||||||
|
popup._enter(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
onProviderChange(key) {
|
onProviderChange(key) {
|
||||||
if ( key === 'overrides.colors' )
|
if ( key === 'overrides.colors' )
|
||||||
this.loadColors();
|
this.loadColors();
|
||||||
|
|
|
@ -613,6 +613,8 @@ export default class MainMenu extends Module {
|
||||||
|
|
||||||
deleteProfile: profile => settings.deleteProfile(profile),
|
deleteProfile: profile => settings.deleteProfile(profile),
|
||||||
|
|
||||||
|
getFFZ: () => t.resolve('core'),
|
||||||
|
|
||||||
context: {
|
context: {
|
||||||
_users: 0,
|
_users: 0,
|
||||||
|
|
||||||
|
|
|
@ -37,11 +37,11 @@ export default class Channel extends Module {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/*this.SideNav = this.elemental.define(
|
this.SideNav = this.elemental.define(
|
||||||
'side-nav', '.side-bar-contents .side-nav-section:first-child',
|
'side-nav', '.side-bar-contents .side-nav-section:first-child',
|
||||||
null,
|
null,
|
||||||
{childNodes: true, subtree: true}, 1
|
{childNodes: true, subtree: true}, 1
|
||||||
);*/
|
);
|
||||||
|
|
||||||
this.ChannelRoot = this.elemental.define(
|
this.ChannelRoot = this.elemental.define(
|
||||||
'channel-root', '.channel-root',
|
'channel-root', '.channel-root',
|
||||||
|
@ -59,8 +59,9 @@ export default class Channel extends Module {
|
||||||
onEnable() {
|
onEnable() {
|
||||||
this.updateChannelColor();
|
this.updateChannelColor();
|
||||||
|
|
||||||
//this.SideNav.on('mount', this.updateHidden, this);
|
this.SideNav.on('mount', this.updateHidden, this);
|
||||||
//this.SideNav.on('mutate', this.updateHidden, this);
|
this.SideNav.on('mutate', this.updateHidden, this);
|
||||||
|
this.SideNav.each(el => this.updateHidden(el));
|
||||||
|
|
||||||
this.ChannelRoot.on('mount', this.updateRoot, this);
|
this.ChannelRoot.on('mount', this.updateRoot, this);
|
||||||
this.ChannelRoot.on('mutate', this.updateRoot, this);
|
this.ChannelRoot.on('mutate', this.updateRoot, this);
|
||||||
|
@ -87,18 +88,21 @@ export default class Channel extends Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*updateHidden(el) { // eslint-disable-line class-methods-use-this
|
updateHidden(el) { // eslint-disable-line class-methods-use-this
|
||||||
if ( ! el._ffz_raf )
|
if ( ! el._ffz_raf )
|
||||||
el._ffz_raf = requestAnimationFrame(() => {
|
el._ffz_raf = requestAnimationFrame(() => {
|
||||||
el._ffz_raf = null;
|
el._ffz_raf = null;
|
||||||
const nodes = el.querySelectorAll('.side-nav-card__avatar--offline');
|
const nodes = el.querySelectorAll('.side-nav-card');
|
||||||
for(const node of nodes) {
|
for(const node of nodes) {
|
||||||
const par = node.closest('.tw-transition');
|
const react = this.fine.getReactInstance(node),
|
||||||
if ( par && el.contains(par) )
|
props = react?.return?.return?.return?.memoizedProps;
|
||||||
par.classList.add('tw-hide');
|
|
||||||
|
const offline = props?.offline ?? node.querySelector('.side-nav-card__avatar--offline') != null;
|
||||||
|
node.classList.toggle('ffz--offline-side-nav', offline);
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}*/
|
}
|
||||||
|
|
||||||
updateSubscription(login) {
|
updateSubscription(login) {
|
||||||
if ( this._subbed_login === login )
|
if ( this._subbed_login === login )
|
||||||
|
|
|
@ -405,16 +405,23 @@ export default class Input extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
inst.doesEmoteMatchTerm = function(emote, term) {
|
inst.doesEmoteMatchTerm = function(emote, term) {
|
||||||
const emote_name = emote.name || emote.token,
|
const emote_name = emote.name || emote.token;
|
||||||
emote_lower = emote_name.toLowerCase(),
|
if ( ! emote_name )
|
||||||
term_lower = term.toLowerCase();
|
return false;
|
||||||
|
|
||||||
|
let emote_lower = emote.tokenLower;
|
||||||
|
if ( ! emote_lower )
|
||||||
|
emote_lower = emote_name.toLowerCase();
|
||||||
|
|
||||||
|
const term_lower = term.toLowerCase();
|
||||||
if (emote_lower.startsWith(term_lower))
|
if (emote_lower.startsWith(term_lower))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const idx = emote_name.indexOf(term.charAt(0).toUpperCase());
|
const idx = emote_name.indexOf(term.charAt(0).toUpperCase());
|
||||||
if (idx !== -1)
|
if (idx !== -1)
|
||||||
return emote_lower.slice(idx + 1).startsWith(term_lower.slice(1));
|
return emote_lower.slice(idx + 1).startsWith(term_lower.slice(1));
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inst.getMatchedEmotes = function(input) {
|
inst.getMatchedEmotes = function(input) {
|
||||||
|
@ -532,8 +539,12 @@ export default class Input extends Module {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const id = emote.id,
|
const id = emote.id,
|
||||||
replacement = REPLACEMENTS[id];
|
token = KNOWN_CODES[emote.token] || emote.token;
|
||||||
|
|
||||||
|
if ( ! token )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const replacement = REPLACEMENTS[id];
|
||||||
let src, srcSet;
|
let src, srcSet;
|
||||||
|
|
||||||
if ( replacement && this.chat.context.get('chat.fix-bad-emotes') ) {
|
if ( replacement && this.chat.context.get('chat.fix-bad-emotes') ) {
|
||||||
|
@ -548,7 +559,8 @@ export default class Input extends Module {
|
||||||
out.push({
|
out.push({
|
||||||
id,
|
id,
|
||||||
setID: set.id,
|
setID: set.id,
|
||||||
token: KNOWN_CODES[emote.token] || emote.token,
|
token,
|
||||||
|
tokenLower: token.toLowerCase(),
|
||||||
srcSet,
|
srcSet,
|
||||||
favorite: favorites.includes(id)
|
favorite: favorites.includes(id)
|
||||||
});
|
});
|
||||||
|
@ -653,7 +665,8 @@ export default class Input extends Module {
|
||||||
|
|
||||||
const out = [],
|
const out = [],
|
||||||
hidden_sets = this.settings.provider.get('emote-menu.hidden-sets'),
|
hidden_sets = this.settings.provider.get('emote-menu.hidden-sets'),
|
||||||
has_hidden = Array.isArray(hidden_sets) && hidden_sets.length > 0;
|
has_hidden = Array.isArray(hidden_sets) && hidden_sets.length > 0,
|
||||||
|
added_emotes = new Set;
|
||||||
|
|
||||||
for(const set of sets) {
|
for(const set of sets) {
|
||||||
if ( ! set || ! set.emotes )
|
if ( ! set || ! set.emotes )
|
||||||
|
@ -669,12 +682,18 @@ export default class Input extends Module {
|
||||||
favorites = this.emotes.getFavorites(source);
|
favorites = this.emotes.getFavorites(source);
|
||||||
|
|
||||||
for(const emote of Object.values(set.emotes)) {
|
for(const emote of Object.values(set.emotes)) {
|
||||||
if ( ! emote || ! emote.id || hidden_emotes.includes(emote.id) )
|
if ( ! emote || ! emote.id || emote.hidden || hidden_emotes.includes(emote.id) || added_emotes.has(emote.name) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if ( ! emote.name )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
added_emotes.add(emote.name);
|
||||||
|
|
||||||
out.push({
|
out.push({
|
||||||
id: `${source}-${emote.id}`,
|
id: `${source}-${emote.id}`,
|
||||||
token: emote.name,
|
token: emote.name,
|
||||||
|
tokenLower: emote.name.toLowerCase(),
|
||||||
srcSet: emote.srcSet,
|
srcSet: emote.srcSet,
|
||||||
favorite: favorites.includes(emote.id)
|
favorite: favorites.includes(emote.id)
|
||||||
});
|
});
|
||||||
|
@ -711,11 +730,10 @@ export default class Input extends Module {
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
const search = input.startsWith(':') ? input.slice(1) : input,
|
const search = input.startsWith(':') ? input.slice(1) : input,
|
||||||
results = [],
|
results = [];
|
||||||
added_emotes = new Set();
|
|
||||||
|
|
||||||
for(const emote of emotes) {
|
for(const emote of emotes) {
|
||||||
if ( inst.doesEmoteMatchTerm(emote, search) && ! added_emotes.has(emote.name) ) {
|
if ( inst.doesEmoteMatchTerm(emote, search) )
|
||||||
results.push({
|
results.push({
|
||||||
current: input,
|
current: input,
|
||||||
replacement: emote.token,
|
replacement: emote.token,
|
||||||
|
@ -723,7 +741,6 @@ export default class Input extends Module {
|
||||||
favorite: emote.favorite,
|
favorite: emote.favorite,
|
||||||
count: 0 // TODO: Count stuff?
|
count: 0 // TODO: Count stuff?
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
|
|
|
@ -333,7 +333,7 @@ other {# messages were deleted by a moderator.}
|
||||||
onContextMenu: t.actions.handleUserContext
|
onContextMenu: t.actions.handleUserContext
|
||||||
}, override_name ? [
|
}, override_name ? [
|
||||||
e('span', {
|
e('span', {
|
||||||
className: 'chat-author__display_name'
|
className: 'chat-author__display-name'
|
||||||
}, override_name),
|
}, override_name),
|
||||||
e('div', {
|
e('div', {
|
||||||
className: 'tw-tooltip tw-tooltip--down tw-tooltip--align-center'
|
className: 'tw-tooltip tw-tooltip--down tw-tooltip--align-center'
|
||||||
|
|
|
@ -13,12 +13,12 @@ const STYLE_VALIDATOR = document.createElement('span');
|
||||||
const CLASSES = {
|
const CLASSES = {
|
||||||
'top-discover': '.navigation-link[data-a-target="discover-link"]',
|
'top-discover': '.navigation-link[data-a-target="discover-link"]',
|
||||||
'side-nav': '.side-nav',
|
'side-nav': '.side-nav',
|
||||||
'side-rec-channels': '.side-nav .recommended-channels',
|
'side-rec-channels': '.side-nav .recommended-channels,.side-nav .side-nav-section + .side-nav-section',
|
||||||
'side-rec-friends': '.side-nav .recommended-friends',
|
//'side-rec-friends': '.side-nav .recommended-friends',
|
||||||
'side-friends': '.side-nav .online-friends',
|
'side-friends': '.side-nav .online-friends',
|
||||||
'side-closed-friends': '.side-nav--collapsed .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 .side-nav-section + .side-nav-section',
|
||||||
//'side-offline-channels': '.side-nav-card__link[href*="/videos/"],.side-nav-card[href*="/videos/"]',
|
'side-offline-channels': '.side-nav-card.ffz--offline-side-nav',
|
||||||
'side-rerun-channels': '.side-nav .ffz--side-nav-card-rerun',
|
'side-rerun-channels': '.side-nav .ffz--side-nav-card-rerun',
|
||||||
|
|
||||||
'community-highlights': '.community-highlight-stack__card',
|
'community-highlights': '.community-highlight-stack__card',
|
||||||
|
@ -37,7 +37,7 @@ const CLASSES = {
|
||||||
'dir-live-ind': '.preview-card[data-ffz-type="live"] .tw-channel-status-text-indicator,.live-channel-card:not([data-a-target*="host"]) .stream-type-indicator.stream-type-indicator--live,.stream-thumbnail__card .stream-type-indicator.stream-type-indicator--live,.preview-card .stream-type-indicator.stream-type-indicator--live,.preview-card .preview-card-stat.preview-card-stat--live',
|
'dir-live-ind': '.preview-card[data-ffz-type="live"] .tw-channel-status-text-indicator,.live-channel-card:not([data-a-target*="host"]) .stream-type-indicator.stream-type-indicator--live,.stream-thumbnail__card .stream-type-indicator.stream-type-indicator--live,.preview-card .stream-type-indicator.stream-type-indicator--live,.preview-card .preview-card-stat.preview-card-stat--live',
|
||||||
'profile-hover': '.preview-card .tw-relative:hover .ffz-channel-avatar',
|
'profile-hover': '.preview-card .tw-relative:hover .ffz-channel-avatar',
|
||||||
'not-live-bar': 'div[data-test-selector="non-live-video-banner-layout"]',
|
'not-live-bar': 'div[data-test-selector="non-live-video-banner-layout"]',
|
||||||
'channel-live-ind': '.channel-header__user .tw-channel-status-text-indicator',
|
'channel-live-ind': '.channel-header__user .tw-channel-status-text-indicator,.channel-info-content .user-avatar-animated__live',
|
||||||
'celebration': 'body .celebration__overlay',
|
'celebration': 'body .celebration__overlay',
|
||||||
'mod-view': '.chat-input__buttons-container .tw-core-button[href*="/moderator"]'
|
'mod-view': '.chat-input__buttons-container .tw-core-button[href*="/moderator"]'
|
||||||
};
|
};
|
||||||
|
@ -153,7 +153,7 @@ export default class CSSTweaks extends Module {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.settings.add('layout.side-nav.show-rec-friends', {
|
/*this.settings.add('layout.side-nav.show-rec-friends', {
|
||||||
default: true,
|
default: true,
|
||||||
ui: {
|
ui: {
|
||||||
path: 'Appearance > Layout >> Side Navigation',
|
path: 'Appearance > Layout >> Side Navigation',
|
||||||
|
@ -161,9 +161,9 @@ export default class CSSTweaks extends Module {
|
||||||
component: 'setting-check-box'
|
component: 'setting-check-box'
|
||||||
},
|
},
|
||||||
changed: val => this.toggleHide('side-rec-friends', !val)
|
changed: val => this.toggleHide('side-rec-friends', !val)
|
||||||
});
|
});*/
|
||||||
|
|
||||||
/*this.settings.add('layout.side-nav.hide-offline', {
|
this.settings.add('layout.side-nav.hide-offline', {
|
||||||
default: false,
|
default: false,
|
||||||
ui: {
|
ui: {
|
||||||
path: 'Appearance > Layout >> Side Navigation',
|
path: 'Appearance > Layout >> Side Navigation',
|
||||||
|
@ -171,7 +171,7 @@ export default class CSSTweaks extends Module {
|
||||||
component: 'setting-check-box'
|
component: 'setting-check-box'
|
||||||
},
|
},
|
||||||
changed: val => this.toggleHide('side-offline-channels', val)
|
changed: val => this.toggleHide('side-offline-channels', val)
|
||||||
});*/
|
});
|
||||||
|
|
||||||
this.settings.add('layout.side-nav.rerun-style', {
|
this.settings.add('layout.side-nav.rerun-style', {
|
||||||
default: 1,
|
default: 1,
|
||||||
|
@ -351,8 +351,8 @@ export default class CSSTweaks extends Module {
|
||||||
|
|
||||||
this.toggle('hide-side-nav-avatars', ! this.settings.get('layout.side-nav.show-avatars'));
|
this.toggle('hide-side-nav-avatars', ! this.settings.get('layout.side-nav.show-avatars'));
|
||||||
this.toggle('hide-side-nav', !this.settings.get('layout.side-nav.show'));
|
this.toggle('hide-side-nav', !this.settings.get('layout.side-nav.show'));
|
||||||
this.toggleHide('side-rec-friends', !this.settings.get('layout.side-nav.show-rec-friends'));
|
//this.toggleHide('side-rec-friends', !this.settings.get('layout.side-nav.show-rec-friends'));
|
||||||
//this.toggleHide('side-offline-channels', this.settings.get('layout.side-nav.hide-offline'));
|
this.toggleHide('side-offline-channels', this.settings.get('layout.side-nav.hide-offline'));
|
||||||
this.toggleHide('prime-offers', !this.settings.get('layout.prime-offers'));
|
this.toggleHide('prime-offers', !this.settings.get('layout.prime-offers'));
|
||||||
this.toggleHide('top-discover', !this.settings.get('layout.discover'));
|
this.toggleHide('top-discover', !this.settings.get('layout.discover'));
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
.twilight-main { order: 2 }
|
.twilight-main { order: 2 }
|
||||||
|
#sideNav,
|
||||||
.side-nav { order: 3 }
|
.side-nav { order: 3 }
|
||||||
.right-column {
|
.right-column {
|
||||||
order: 1;
|
order: 1;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-nav__toggle-visibility {
|
#sideNav .collapse-toggle {
|
||||||
right: unset !important;
|
svg {
|
||||||
left: -2.5rem;
|
transform: rotate(180deg);
|
||||||
z-index: 10 !important;
|
}
|
||||||
svg { transform: rotate(180deg) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-column__toggle-visibility {
|
.right-column__toggle-visibility {
|
||||||
//left: unset !important;
|
.tw-tooltip--left {
|
||||||
//right: -2.5rem;
|
left: 100% !important;
|
||||||
//z-index: 10 !important;
|
right: auto !important;
|
||||||
|
margin-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
svg { transform: rotate(180deg) }
|
svg { transform: rotate(180deg) }
|
||||||
|
|
||||||
.right-column--collapsed & {
|
.right-column--collapsed & {
|
||||||
|
@ -24,14 +27,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.channel-header {
|
|
||||||
padding-left: 4rem !important;
|
|
||||||
|
|
||||||
.tw-sm-pd-r-4 {
|
|
||||||
padding-right: 1rem !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.side-nav__theme-wrapper.tw-border-r {
|
.side-nav__theme-wrapper.tw-border-r {
|
||||||
border-right: none !important;
|
border-right: none !important;
|
||||||
|
|
|
@ -128,6 +128,9 @@ export class Tooltip {
|
||||||
|
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
|
if ( this.options.manual )
|
||||||
|
return;
|
||||||
|
|
||||||
for(const el of this.elements) {
|
for(const el of this.elements) {
|
||||||
const tip = el[this._accessor];
|
const tip = el[this._accessor];
|
||||||
if ( document.body.contains(el) )
|
if ( document.body.contains(el) )
|
||||||
|
|
|
@ -62,6 +62,7 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ffz-action-balloon,
|
||||||
.ffz-metadata-balloon,
|
.ffz-metadata-balloon,
|
||||||
.ffz__tooltip {
|
.ffz__tooltip {
|
||||||
.loader {
|
.loader {
|
||||||
|
|
|
@ -375,6 +375,16 @@ textarea.tw-input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ffz-override-editor {
|
||||||
|
label {
|
||||||
|
min-width: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz--color-widget {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ffz--report-upload {
|
.ffz--report-upload {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue