mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.20.85
* Added: Option to display modified Twitch emotes in the emote menu. * Fixed: Use parenthesis counting to ensure links surrounded in `)` don't include the `)`, matching Twitch behavior. Closes #1015 * Fixed: Issue with Native Sorting for the emote menu where the first emote is sent to the end of the list. * Fixed: Emote Menu not appearing correctly in whispers. * Fixed: Favorites section not appearing in the Emote Menu when emoji are disabled. * Fixed: The Stream Latency and Up-time metadata unnecessarily changing width due to Twitch's default font.
This commit is contained in:
parent
1cdff0ec67
commit
c03c2e48b5
6 changed files with 183 additions and 209 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.20.84",
|
"version": "4.20.85",
|
||||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
|
|
@ -162,41 +162,39 @@ export const Links = {
|
||||||
const text = token.text;
|
const text = token.text;
|
||||||
let idx = 0, match;
|
let idx = 0, match;
|
||||||
|
|
||||||
//if ( use_new ) {
|
|
||||||
while((match = NEW_LINK_REGEX.exec(text))) {
|
while((match = NEW_LINK_REGEX.exec(text))) {
|
||||||
const nix = match.index;
|
const nix = match.index;
|
||||||
if ( idx !== nix )
|
if ( idx !== nix )
|
||||||
out.push({type: 'text', text: text.slice(idx, nix)});
|
out.push({type: 'text', text: text.slice(idx, nix)});
|
||||||
|
|
||||||
|
let url = match[0];
|
||||||
|
if ( url.endsWith(')') ) {
|
||||||
|
let open = 1, i = url.length - 1;
|
||||||
|
while(i--) {
|
||||||
|
const chr = url[i];
|
||||||
|
if ( chr === ')' )
|
||||||
|
open++;
|
||||||
|
else if ( chr === '(' )
|
||||||
|
open--;
|
||||||
|
|
||||||
|
if ( ! open )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( open )
|
||||||
|
url = url.slice(0, url.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
out.push({
|
out.push({
|
||||||
type: 'link',
|
type: 'link',
|
||||||
url: `${match[1] ? '' : 'https://'}${match[0]}`,
|
url: `${match[1] ? '' : 'https://'}${url}`,
|
||||||
is_mail: false,
|
is_mail: false,
|
||||||
text: match[0]
|
text: url
|
||||||
});
|
});
|
||||||
|
|
||||||
idx = nix + match[0].length;
|
idx = nix + url.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*} else {
|
|
||||||
while((match = LINK_REGEX.exec(text))) {
|
|
||||||
const nix = match.index + (match[1] ? match[1].length : 0);
|
|
||||||
if ( idx !== nix )
|
|
||||||
out.push({type: 'text', text: text.slice(idx, nix)});
|
|
||||||
|
|
||||||
const is_mail = ! match[3] && match[2].indexOf('/') === -1 && match[2].indexOf('@') !== -1;
|
|
||||||
|
|
||||||
out.push({
|
|
||||||
type: 'link',
|
|
||||||
url: (match[3] ? '' : is_mail ? 'mailto:' : 'https://') + match[2],
|
|
||||||
is_mail,
|
|
||||||
text: match[2]
|
|
||||||
});
|
|
||||||
|
|
||||||
idx = nix + match[2].length;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if ( idx < text.length )
|
if ( idx < text.length )
|
||||||
out.push({type: 'text', text: text.slice(idx)});
|
out.push({type: 'text', text: text.slice(idx)});
|
||||||
}
|
}
|
||||||
|
@ -1521,6 +1519,16 @@ export const AddonEmotes = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*AddonEmotes.tooltip.interactive = function(target) {
|
||||||
|
const mods = target.dataset.modifiers;
|
||||||
|
return mods && mods.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddonEmotes.tooltip.delayHide = function(target) {
|
||||||
|
const mods = target.dataset.modifiers;
|
||||||
|
return mods && mods.length > 0 ? 100 : 0;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Emoji
|
// Emoji
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Twilight from 'site';
|
||||||
import Module from 'utilities/module';
|
import Module from 'utilities/module';
|
||||||
|
|
||||||
import SUB_STATUS from './sub_status.gql';
|
import SUB_STATUS from './sub_status.gql';
|
||||||
|
import Tooltip from 'src/utilities/tooltip';
|
||||||
|
|
||||||
const TIERS = {
|
const TIERS = {
|
||||||
1000: 'Tier 1',
|
1000: 'Tier 1',
|
||||||
|
@ -95,9 +96,9 @@ const EMOTE_SORTERS = [
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
function native_asc(a, b) {
|
function native_asc(a, b) {
|
||||||
if ( a.order || b.order ) {
|
if ( a.order != null || b.order != null ) {
|
||||||
if ( a.order && ! b.order ) return -1;
|
if ( a.order && b.order == null ) return -1;
|
||||||
if ( b.order && ! a.order ) return 1;
|
if ( b.order && a.order == null ) return 1;
|
||||||
|
|
||||||
if ( a.order < b.order ) return -1;
|
if ( a.order < b.order ) return -1;
|
||||||
if ( a.order > b.order ) return 1;
|
if ( a.order > b.order ) return 1;
|
||||||
|
@ -111,9 +112,9 @@ const EMOTE_SORTERS = [
|
||||||
return 0;
|
return 0;
|
||||||
},
|
},
|
||||||
function native_desc(a, b) {
|
function native_desc(a, b) {
|
||||||
if ( a.order || b.order ) {
|
if ( a.order != null || b.order != null ) {
|
||||||
if ( a.order && ! b.order ) return 1;
|
if ( a.order && b.order == null ) return 1;
|
||||||
if ( b.order && ! a.order ) return -1;
|
if ( b.order && a.order == null ) return -1;
|
||||||
|
|
||||||
if ( a.order < b.order ) return 1;
|
if ( a.order < b.order ) return 1;
|
||||||
if ( a.order > b.order ) return -1;
|
if ( a.order > b.order ) return -1;
|
||||||
|
@ -174,6 +175,19 @@ export default class EmoteMenu extends Module {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.settings.add('chat.emote-menu.modifiers', {
|
||||||
|
default: 0,
|
||||||
|
ui: {
|
||||||
|
path: 'Chat > Emote Menu >> General',
|
||||||
|
title: 'Emote Modifiers',
|
||||||
|
component: 'setting-select-box',
|
||||||
|
data: [
|
||||||
|
{value: 0, title: 'Disabled'},
|
||||||
|
{value: 1, title: 'In-Line'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.settings.add('chat.emote-menu.enabled', {
|
this.settings.add('chat.emote-menu.enabled', {
|
||||||
default: true,
|
default: true,
|
||||||
ui: {
|
ui: {
|
||||||
|
@ -349,6 +363,7 @@ export default class EmoteMenu extends Module {
|
||||||
inst.rebuildData();
|
inst.rebuildData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.chat.context.on('changed:chat.emote-menu.modifiers', rebuild);
|
||||||
this.chat.context.on('changed:chat.emote-menu.show-emoji', rebuild);
|
this.chat.context.on('changed:chat.emote-menu.show-emoji', rebuild);
|
||||||
this.chat.context.on('changed:chat.fix-bad-emotes', rebuild);
|
this.chat.context.on('changed:chat.fix-bad-emotes', rebuild);
|
||||||
this.chat.context.on('changed:chat.emote-menu.sort-emotes', rebuild);
|
this.chat.context.on('changed:chat.emote-menu.sort-emotes', rebuild);
|
||||||
|
@ -394,6 +409,7 @@ export default class EmoteMenu extends Module {
|
||||||
|
|
||||||
return (<t.MenuErrorWrapper visible={this.props.visible}>
|
return (<t.MenuErrorWrapper visible={this.props.visible}>
|
||||||
<t.MenuComponent
|
<t.MenuComponent
|
||||||
|
source={this.props.emotePickerSource}
|
||||||
visible={this.props.visible}
|
visible={this.props.visible}
|
||||||
toggleVisibility={this.props.toggleVisibility}
|
toggleVisibility={this.props.toggleVisibility}
|
||||||
channel_data={this.props.channelData}
|
channel_data={this.props.channelData}
|
||||||
|
@ -449,40 +465,6 @@ export default class EmoteMenu extends Module {
|
||||||
React = this.web_munch.getModule('react'),
|
React = this.web_munch.getModule('react'),
|
||||||
createElement = React && React.createElement;
|
createElement = React && React.createElement;
|
||||||
|
|
||||||
this.EmoteModifierPicker = class FFZEmoteModifierPicker extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.onClickOutside = () => this.props.close();
|
|
||||||
|
|
||||||
this.element = null;
|
|
||||||
this.saveRef = element => this.element = element;
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if ( this.element )
|
|
||||||
this._clicker = new ClickOutside(this.element, this.onClickOutside);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
if ( this._clicker ) {
|
|
||||||
this._clicker.destroy();
|
|
||||||
this._clicker = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (<div ref={this.saveRef} class="ffz--modifier-picker tw-absolute ffz-balloon tw-tooltip-down tw-tooltip--align-center ffz-balloon tw-block">
|
|
||||||
<div class="tw-border-b tw-border-l tw-border-r tw-border-t tw-border-radius-medium tw-c-background-base tw-elevation-1">
|
|
||||||
</div>
|
|
||||||
</div>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.EmojiTonePicker = class FFZEmojiTonePicker extends React.Component {
|
this.EmojiTonePicker = class FFZEmojiTonePicker extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -617,7 +599,6 @@ export default class EmoteMenu extends Module {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
active: false,
|
active: false,
|
||||||
open_menu: null,
|
|
||||||
activeEmote: -1,
|
activeEmote: -1,
|
||||||
hidden: hidden && props.data && hidden.includes(props.data.hide_key || props.data.key),
|
hidden: hidden && props.data && hidden.includes(props.data.hide_key || props.data.key),
|
||||||
collapsed: collapsed && props.data && collapsed.includes(props.data.key),
|
collapsed: collapsed && props.data && collapsed.includes(props.data.key),
|
||||||
|
@ -627,8 +608,6 @@ export default class EmoteMenu extends Module {
|
||||||
this.keyHeading = this.keyHeading.bind(this);
|
this.keyHeading = this.keyHeading.bind(this);
|
||||||
this.clickHeading = this.clickHeading.bind(this);
|
this.clickHeading = this.clickHeading.bind(this);
|
||||||
this.clickEmote = this.clickEmote.bind(this);
|
this.clickEmote = this.clickEmote.bind(this);
|
||||||
this.contextEmote = this.contextEmote.bind(this);
|
|
||||||
this.closeEmoteModMenu = this.closeEmoteModMenu.bind(this);
|
|
||||||
|
|
||||||
this.mouseEnter = () => this.state.intersecting || this.setState({intersecting: true});
|
this.mouseEnter = () => this.state.intersecting || this.setState({intersecting: true});
|
||||||
|
|
||||||
|
@ -684,29 +663,6 @@ export default class EmoteMenu extends Module {
|
||||||
this.props.onClickToken(event.currentTarget.dataset.name)
|
this.props.onClickToken(event.currentTarget.dataset.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
contextEmote(event) {
|
|
||||||
if ( event.ctrlKey || event.shiftKey )
|
|
||||||
return;
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const ds = event.currentTarget.dataset;
|
|
||||||
if ( ds.provider !== 'twitch' )
|
|
||||||
return;
|
|
||||||
|
|
||||||
const modifiers = this.props.emote_modifiers[ds.id];
|
|
||||||
if ( Array.isArray(modifiers) && modifiers.length )
|
|
||||||
this.setState({
|
|
||||||
open_menu: ds.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
closeEmoteModMenu() {
|
|
||||||
this.setState({
|
|
||||||
open_menu: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
keyHeading(event) {
|
keyHeading(event) {
|
||||||
if ( event.keyCode === KEYS.Enter || event.keyCode === KEYS.Space )
|
if ( event.keyCode === KEYS.Enter || event.keyCode === KEYS.Space )
|
||||||
this.clickHeading();
|
this.clickHeading();
|
||||||
|
@ -889,7 +845,7 @@ export default class EmoteMenu extends Module {
|
||||||
const visibility = this.props.visibility_control,
|
const visibility = this.props.visibility_control,
|
||||||
modifiers = this.props.emote_modifiers[emote.id],
|
modifiers = this.props.emote_modifiers[emote.id],
|
||||||
has_modifiers = Array.isArray(modifiers) && modifiers.length > 0,
|
has_modifiers = Array.isArray(modifiers) && modifiers.length > 0,
|
||||||
has_menu = has_modifiers && this.state.open_menu == emote.id,
|
//has_menu = has_modifiers && this.state.open_menu == emote.id,
|
||||||
animated = this.props.animated,
|
animated = this.props.animated,
|
||||||
hidden = visibility && emote.hidden;
|
hidden = visibility && emote.hidden;
|
||||||
|
|
||||||
|
@ -910,6 +866,7 @@ export default class EmoteMenu extends Module {
|
||||||
data-id={emote.id}
|
data-id={emote.id}
|
||||||
data-set={emote.set_id}
|
data-set={emote.set_id}
|
||||||
data-code={emote.code}
|
data-code={emote.code}
|
||||||
|
data-modifiers={modifiers}
|
||||||
data-variant={emote.variant}
|
data-variant={emote.variant}
|
||||||
data-no-source={source}
|
data-no-source={source}
|
||||||
data-name={emote.name}
|
data-name={emote.name}
|
||||||
|
@ -917,7 +874,6 @@ export default class EmoteMenu extends Module {
|
||||||
data-locked={emote.locked}
|
data-locked={emote.locked}
|
||||||
data-sellout={sellout}
|
data-sellout={sellout}
|
||||||
onClick={(this.props.visibility_control || !emote.locked) && this.clickEmote}
|
onClick={(this.props.visibility_control || !emote.locked) && this.clickEmote}
|
||||||
onContextMenu={this.contextEmote}
|
|
||||||
>
|
>
|
||||||
<figure class="emote-picker__emote-figure">
|
<figure class="emote-picker__emote-figure">
|
||||||
<img
|
<img
|
||||||
|
@ -933,11 +889,6 @@ export default class EmoteMenu extends Module {
|
||||||
{! visibility && emote.favorite && <figure class="ffz--favorite ffz-i-star" />}
|
{! visibility && emote.favorite && <figure class="ffz--favorite ffz-i-star" />}
|
||||||
{! visibility && locked && <figure class="ffz-i-lock" />}
|
{! visibility && locked && <figure class="ffz-i-lock" />}
|
||||||
{hidden && <figure class="ffz-i-eye-off" />}
|
{hidden && <figure class="ffz-i-eye-off" />}
|
||||||
{has_menu && <t.EmoteModifierPicker
|
|
||||||
emote={emote}
|
|
||||||
modifiers={modifiers}
|
|
||||||
close={this.closeEmoteModMenu}
|
|
||||||
/>}
|
|
||||||
</button>)
|
</button>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1549,78 +1500,75 @@ export default class EmoteMenu extends Module {
|
||||||
tone_choices = state.tone_emoji = [],
|
tone_choices = state.tone_emoji = [],
|
||||||
categories = {};
|
categories = {};
|
||||||
|
|
||||||
if ( ! t.chat.context.get('chat.emote-menu.show-emoji') ) {
|
if ( t.chat.context.get('chat.emote-menu.show-emoji') ) {
|
||||||
state.has_emoji_tab = false;
|
let style = t.chat.context.get('chat.emoji.style') || 'twitter';
|
||||||
return state;
|
if ( ! IMAGE_PATHS[style] )
|
||||||
}
|
style = 'twitter';
|
||||||
|
|
||||||
let style = t.chat.context.get('chat.emoji.style') || 'twitter';
|
for(const emoji of Object.values(t.emoji.emoji)) {
|
||||||
if ( ! IMAGE_PATHS[style] )
|
if ( ! emoji || ! emoji.has[style] || HIDDEN_CATEGORIES.includes(emoji.category) )
|
||||||
style = 'twitter';
|
continue;
|
||||||
|
|
||||||
for(const emoji of Object.values(t.emoji.emoji)) {
|
if ( emoji.variants ) {
|
||||||
if ( ! emoji || ! emoji.has[style] || HIDDEN_CATEGORIES.includes(emoji.category) )
|
for(const name of emoji.names)
|
||||||
continue;
|
if ( TONE_EMOJI.includes(name) ) {
|
||||||
|
tone_choices.push(emoji);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( emoji.variants ) {
|
const is_fav = emoji_favorites.includes(emoji.code),
|
||||||
for(const name of emoji.names)
|
toned = emoji.variants && emoji.variants[tone],
|
||||||
if ( TONE_EMOJI.includes(name) ) {
|
has_tone = toned && toned.has[style],
|
||||||
tone_choices.push(emoji);
|
source = has_tone ? toned : emoji;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const is_fav = emoji_favorites.includes(emoji.code),
|
let cat = categories[emoji.category];
|
||||||
toned = emoji.variants && emoji.variants[tone],
|
if ( ! cat ) {
|
||||||
has_tone = toned && toned.has[style],
|
cat = categories[emoji.category] = [];
|
||||||
source = has_tone ? toned : emoji;
|
|
||||||
|
|
||||||
let cat = categories[emoji.category];
|
sets.push({
|
||||||
if ( ! cat ) {
|
key: `emoji-${emoji.category}`,
|
||||||
cat = categories[emoji.category] = [];
|
sort_key: CATEGORY_SORT.indexOf(emoji.category),
|
||||||
|
emoji: true,
|
||||||
|
image: t.emoji.getFullImage(source.image),
|
||||||
|
i18n: `emoji.category.${emoji.category.toSnakeCase()}`,
|
||||||
|
title: CATEGORIES[emoji.category] || emoji.category,
|
||||||
|
src: 'emoji',
|
||||||
|
source: 'Emoji',
|
||||||
|
source_i18n: 'emote-menu.emoji',
|
||||||
|
emotes: cat
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
sets.push({
|
const em = {
|
||||||
key: `emoji-${emoji.category}`,
|
provider: 'emoji',
|
||||||
sort_key: CATEGORY_SORT.indexOf(emoji.category),
|
id: emoji.sort,
|
||||||
emoji: true,
|
emoji: true,
|
||||||
image: t.emoji.getFullImage(source.image),
|
code: emoji.code,
|
||||||
i18n: `emoji.category.${emoji.category.toSnakeCase()}`,
|
name: source.raw,
|
||||||
title: CATEGORIES[emoji.category] || emoji.category,
|
variant: has_tone && tone,
|
||||||
src: 'emoji',
|
hidden: emoji.hidden,
|
||||||
source: 'Emoji',
|
|
||||||
source_i18n: 'emote-menu.emoji',
|
search: emoji.names[0],
|
||||||
emotes: cat
|
extra: emoji.names.length > 1 ? emoji.names.map(x => x.toLowerCase()) : null,
|
||||||
});
|
|
||||||
|
height: 18,
|
||||||
|
width: 18,
|
||||||
|
|
||||||
|
x: source.sheet_x,
|
||||||
|
y: source.sheet_y,
|
||||||
|
|
||||||
|
favorite: is_fav,
|
||||||
|
|
||||||
|
src: t.emoji.getFullImage(source.image),
|
||||||
|
srcSet: t.emoji.getFullImageSet(source.image)
|
||||||
|
};
|
||||||
|
|
||||||
|
cat.push(em);
|
||||||
|
|
||||||
|
if ( is_fav )
|
||||||
|
favorites.push(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
const em = {
|
|
||||||
provider: 'emoji',
|
|
||||||
id: emoji.sort,
|
|
||||||
emoji: true,
|
|
||||||
code: emoji.code,
|
|
||||||
name: source.raw,
|
|
||||||
variant: has_tone && tone,
|
|
||||||
hidden: emoji.hidden,
|
|
||||||
|
|
||||||
search: emoji.names[0],
|
|
||||||
extra: emoji.names.length > 1 ? emoji.names.map(x => x.toLowerCase()) : null,
|
|
||||||
|
|
||||||
height: 18,
|
|
||||||
width: 18,
|
|
||||||
|
|
||||||
x: source.sheet_x,
|
|
||||||
y: source.sheet_y,
|
|
||||||
|
|
||||||
favorite: is_fav,
|
|
||||||
|
|
||||||
src: t.emoji.getFullImage(source.image),
|
|
||||||
srcSet: t.emoji.getFullImageSet(source.image)
|
|
||||||
};
|
|
||||||
|
|
||||||
cat.push(em);
|
|
||||||
|
|
||||||
if ( is_fav )
|
|
||||||
favorites.push(em);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.has_emoji_tab = sets.length > 0;
|
state.has_emoji_tab = sets.length > 0;
|
||||||
|
@ -1871,51 +1819,63 @@ export default class EmoteMenu extends Module {
|
||||||
|
|
||||||
const id = emote.id,
|
const id = emote.id,
|
||||||
name = KNOWN_CODES[emote.token] || emote.token,
|
name = KNOWN_CODES[emote.token] || emote.token,
|
||||||
mapped = emote_map && emote_map[name],
|
mapped = emote_map && emote_map[name];
|
||||||
overridden = mapped && mapped.id != id,
|
|
||||||
replacement = REPLACEMENTS[id],
|
|
||||||
is_fav = twitch_favorites.includes(id);
|
|
||||||
|
|
||||||
let src, srcSet;
|
|
||||||
|
|
||||||
if ( replacement && t.chat.context.get('chat.fix-bad-emotes') )
|
|
||||||
src = `${REPLACEMENT_BASE}${replacement}`;
|
|
||||||
else {
|
|
||||||
const base = `${TWITCH_EMOTE_BASE}${id}`;
|
|
||||||
src = `${base}/1.0`;
|
|
||||||
srcSet = `${src} 1x, ${base}/2.0 2x`
|
|
||||||
}
|
|
||||||
|
|
||||||
/*if ( Array.isArray(emote.modifiers) && emote.modifiers.length )
|
|
||||||
modifiers[id] = emote.modifiers;*/
|
|
||||||
|
|
||||||
const em = {
|
|
||||||
provider: 'twitch',
|
|
||||||
id,
|
|
||||||
set_id,
|
|
||||||
name,
|
|
||||||
src,
|
|
||||||
srcSet,
|
|
||||||
order: order++,
|
|
||||||
overridden: overridden ? mapped.id : null,
|
|
||||||
misc: ! chan,
|
|
||||||
bits: is_bits,
|
|
||||||
hidden: twitch_hidden.includes(id),
|
|
||||||
favorite: is_fav
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( ! is_points )
|
if ( ! is_points )
|
||||||
t.emotes.setTwitchEmoteSet(id, set_id);
|
t.emotes.setTwitchEmoteSet(id, set_id);
|
||||||
|
|
||||||
emotes.push(em);
|
//if ( Array.isArray(emote.modifiers) && emote.modifiers.length )
|
||||||
|
// modifiers[id] = emote.modifiers.map(x => x.code);
|
||||||
|
|
||||||
if ( is_current_bits )
|
const modes = [''];
|
||||||
bits_unlocked.push(em);
|
if ( Array.isArray(emote.modifiers) && emote.modifiers.length ) {
|
||||||
|
if ( t.chat.context.get('chat.emote-menu.modifiers') === 1 )
|
||||||
|
for(const mod of emote.modifiers)
|
||||||
|
modes.push(`_${mod.code}`);
|
||||||
|
}
|
||||||
|
|
||||||
if ( is_fav && ! twitch_seen.has(id) )
|
for(const mode of modes) {
|
||||||
favorites.push(em);
|
const new_id = `${id}${mode}`,
|
||||||
|
new_name = `${name}${mode}`,
|
||||||
|
is_fav = twitch_favorites.includes(new_id),
|
||||||
|
overridden = mapped && mapped.id != new_id,
|
||||||
|
replacement = REPLACEMENTS[new_id];
|
||||||
|
|
||||||
twitch_seen.add(id);
|
let src, srcSet;
|
||||||
|
|
||||||
|
if ( replacement && t.chat.context.get('chat.fix-bad-emotes') )
|
||||||
|
src = `${REPLACEMENT_BASE}${replacement}`;
|
||||||
|
else {
|
||||||
|
const base = `${TWITCH_EMOTE_BASE}${new_id}`;
|
||||||
|
src = `${base}/1.0`;
|
||||||
|
srcSet = `${src} 1x, ${base}/2.0 2x`
|
||||||
|
}
|
||||||
|
|
||||||
|
const em = {
|
||||||
|
provider: 'twitch',
|
||||||
|
id: new_id,
|
||||||
|
set_id,
|
||||||
|
name: new_name,
|
||||||
|
src,
|
||||||
|
srcSet,
|
||||||
|
order: order++,
|
||||||
|
overridden: overridden ? mapped.id : null,
|
||||||
|
misc: ! chan,
|
||||||
|
bits: is_bits,
|
||||||
|
hidden: twitch_hidden.includes(new_id),
|
||||||
|
favorite: is_fav
|
||||||
|
};
|
||||||
|
|
||||||
|
emotes.push(em);
|
||||||
|
|
||||||
|
if ( is_current_bits )
|
||||||
|
bits_unlocked.push(em);
|
||||||
|
|
||||||
|
if ( is_fav && ! twitch_seen.has(new_id) )
|
||||||
|
favorites.push(em);
|
||||||
|
|
||||||
|
twitch_seen.add(new_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( emotes.length ) {
|
if ( emotes.length ) {
|
||||||
|
@ -1998,9 +1958,6 @@ export default class EmoteMenu extends Module {
|
||||||
seen = twitch_seen.has(id),
|
seen = twitch_seen.has(id),
|
||||||
is_fav = twitch_favorites.includes(id);
|
is_fav = twitch_favorites.includes(id);
|
||||||
|
|
||||||
/*if ( Array.isArray(emote.modifiers) && emote.modifiers.length )
|
|
||||||
modifiers[id] = emote.modifiers;*/
|
|
||||||
|
|
||||||
const em = {
|
const em = {
|
||||||
provider: 'twitch',
|
provider: 'twitch',
|
||||||
id,
|
id,
|
||||||
|
@ -2337,7 +2294,8 @@ export default class EmoteMenu extends Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const visibility = this.state.visibility_control;
|
const visibility = this.state.visibility_control,
|
||||||
|
whisper = this.props.source === 'whisper';
|
||||||
|
|
||||||
return (<div class={`tw-block${this.props.visible ? '' : ' tw-hide'}`} style={{display: this.props.visible ? null : 'none !important'}}>
|
return (<div class={`tw-block${this.props.visible ? '' : ' tw-hide'}`} style={{display: this.props.visible ? null : 'none !important'}}>
|
||||||
<div class="tw-absolute tw-attached tw-attached--right tw-attached--up">
|
<div class="tw-absolute tw-attached tw-attached--right tw-attached--up">
|
||||||
|
@ -2346,10 +2304,10 @@ export default class EmoteMenu extends Module {
|
||||||
data-a-target="emote-picker"
|
data-a-target="emote-picker"
|
||||||
role="dialog"
|
role="dialog"
|
||||||
>
|
>
|
||||||
<div class="emote-picker">
|
<div class={`emote-picker${whisper ? '__whisper' : ''}`}>
|
||||||
<div class="tw-flex">
|
<div class="tw-flex">
|
||||||
<div
|
<div
|
||||||
class="emote-picker__tab-content tw-full-width scrollable-area scrollable-area--suppress-scroll-x"
|
class={`emote-picker__tab-content${whisper ? '-whisper' : ''} tw-full-width scrollable-area scrollable-area--suppress-scroll-x`}
|
||||||
data-test-selector="scrollable-area-wrapper"
|
data-test-selector="scrollable-area-wrapper"
|
||||||
data-simplebar
|
data-simplebar
|
||||||
>
|
>
|
||||||
|
@ -2379,9 +2337,9 @@ export default class EmoteMenu extends Module {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{(! loading && this.state.quickNav && ! is_favs) && (<div class="emote-picker__nav_content tw-block tw-border-radius-none tw-c-background-alt-2">
|
{(! loading && this.state.quickNav && ! is_favs) && (<div class={`emote-picker__nav_content${whisper ? '-whisper' : ''} tw-block tw-border-radius-none tw-c-background-alt-2`}>
|
||||||
<div
|
<div
|
||||||
class="emote-picker__nav-content-overflow scrollable-area scrollable-area--suppress-scroll-x"
|
class={`emote-picker__nav-content-overflow${whisper ? '-whisper' : ''} scrollable-area scrollable-area--suppress-scroll-x`}
|
||||||
data-test-selector="scrollable-area-wrapper"
|
data-test-selector="scrollable-area-wrapper"
|
||||||
data-simplebar
|
data-simplebar
|
||||||
>
|
>
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
.ffz-stat-text {
|
.ffz-stat-text {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
|
font-family: "Helvetica Neue",sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-stat--fix-padding {
|
.ffz-stat--fix-padding {
|
||||||
|
|
|
@ -289,6 +289,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz--emote-picker {
|
.ffz--emote-picker {
|
||||||
|
white-space: normal;
|
||||||
|
|
||||||
section:not(.filtered) heading {
|
section:not(.filtered) heading {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,14 @@
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
line-height: 3rem;
|
line-height: 3rem;
|
||||||
margin-right: .5rem;
|
margin-right: .5rem;
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
|
||||||
&:hover, &.active {
|
&.active {
|
||||||
border-top: 1px solid #6441a4;
|
border-top-color: var(--color-border-tab-active);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,&:focus {
|
||||||
|
border-top-color: var(--color-border-top-hover)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue