1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-07-01 08:38:32 +00:00

Make badge tooltips better. Add support for overriding image, title, and color to per-user badges. Automatically regenerate badge CSS when loading new badge data unless told not to. Also fix a minor bug in directory/following that can occur if we're rendering a host card before host data has been processed.

This commit is contained in:
SirStendec 2018-02-02 16:00:01 -05:00
parent b79e910100
commit 7a92d7968f
2 changed files with 86 additions and 61 deletions

View file

@ -4,7 +4,7 @@
// Badge Handling // Badge Handling
// ============================================================================ // ============================================================================
import {API_SERVER, WEBKIT_CSS as WEBKIT} from 'utilities/constants'; import {API_SERVER, IS_WEBKIT, WEBKIT_CSS as WEBKIT} from 'utilities/constants';
import {createElement as e, ManagedStyle} from 'utilities/dom'; import {createElement as e, ManagedStyle} from 'utilities/dom';
import {has} from 'utilities/object'; import {has} from 'utilities/object';
@ -39,6 +39,8 @@ export const BADGE_POSITIONS = {
const NO_REPEAT = 'background-repeat:no-repeat;background-position:center;', const NO_REPEAT = 'background-repeat:no-repeat;background-position:center;',
BASE_IMAGE = 'https://cdn.frankerfacez.com/badges/twitch/', BASE_IMAGE = 'https://cdn.frankerfacez.com/badges/twitch/',
CSS_MASK_IMAGE = IS_WEBKIT ? 'webkitMaskImage' : 'maskImage',
CSS_TEMPLATES = { CSS_TEMPLATES = {
0: data => `background:${data.image} ${data.color};background-size:${data.scale*1.8}rem;${data.svg ? '' : `background-image:${data.image_set};`}${NO_REPEAT}`, 0: data => `background:${data.image} ${data.color};background-size:${data.scale*1.8}rem;${data.svg ? '' : `background-image:${data.image_set};`}${NO_REPEAT}`,
1: data => `${CSS_TEMPLATES[0](data)}border-radius:${data.scale*.2}rem;`, 1: data => `${CSS_TEMPLATES[0](data)}border-radius:${data.scale*.2}rem;`,
@ -103,7 +105,7 @@ export function generateBadgeCSS(badge, version, data, style, is_dark, scale = 1
image = `url("${svg ? base_image : `${base_image}${scale}${trans ? '_trans' : ''}.png`}")`; image = `url("${svg ? base_image : `${base_image}${scale}${trans ? '_trans' : ''}.png`}")`;
if ( data.urls ) { if ( data.urls ) {
image_set = `${WEBKIT}image-set(${image} 1x${data.urls[2] ? `, url("${data.urls[2]}") 2x` : ''}${data.urls[4] ? `url("${data.urls[4]}") 4x` : ''})` image_set = `${WEBKIT}image-set(${image} 1x${data.urls[2] ? `, url("${data.urls[2]}") 2x` : ''}${data.urls[4] ? `, url("${data.urls[4]}") 4x` : ''})`
} else if ( ! svg && scale < 4 ) { } else if ( ! svg && scale < 4 ) {
if ( scale === 1 ) if ( scale === 1 )
@ -169,71 +171,58 @@ export default class Badges extends Module {
this.rebuildAllCSS(); this.rebuildAllCSS();
this.loadGlobalBadges(); this.loadGlobalBadges();
// TODO: Better tooltips. Especially support for custom colors, titles, etc. from
// user-specific badges.
this.tooltips.types.badge = (target, tip) => { this.tooltips.types.badge = (target, tip) => {
const container = target.parentElement.parentElement, const show_previews = this.parent.context.get('tooltip.badge-images'),
provider = target.dataset.provider, container = target.parentElement.parentElement,
replaced = target.dataset.replaced,
badge = target.dataset.badge,
version = target.dataset.version,
room_id = container.dataset.roomId, room_id = container.dataset.roomId,
room_login = container.dataset.room, room_login = container.dataset.room,
data = JSON.parse(target.dataset.badgeData),
out = [];
replaced_data = replaced && this.badges[replaced]; for(const d of data) {
const p = d.provider;
if ( p === 'twitch' ) {
const bd = this.getTwitchBadge(d.badge, d.version, room_id, room_login);
if ( ! bd )
continue;
let preview, title; out.push(e('div', {className: 'ffz-badge-tip'}, [
show_previews && e('img', {
className: 'preview-image ffz-badge',
src: bd.image4x
}),
bd.title
]));
if ( provider === 'twitch' ) { } else if ( p === 'ffz' ) {
const data = this.getTwitchBadge(badge, version, room_id, room_login); out.push(e('div', {className: 'ffz-badge-tip'}, [
if ( ! data ) show_previews && e('img', {
return;
preview = data.image4x;
title = data.title;
} else if ( provider === 'ffz' ) {
const data = this.badges[badge];
if ( ! data )
return;
preview = e('span', {
className: 'preview-image ffz-badge', className: 'preview-image ffz-badge',
style: { style: {
height: '7.2rem', height: '7.2rem',
width: '7.2rem', width: '7.2rem',
backgroundColor: data.color, backgroundSize: '7.2rem',
backgroundImage: `url("${data.urls[4]}")` backgroundColor: d.color,
backgroundImage: `url("${d.image}")`
}
}),
d.title
]));
}
} }
})
title = this.i18n.t(`badges.${data.name}`, data.title); return out;
}
} else
title = `Unknown Badge`;
if ( preview )
if ( this.parent.context.get('tooltip.badge-images') ) {
if ( typeof preview === 'string' )
preview = e('img', {
className: 'preview-image ffz-badge',
src: preview,
});
} else
preview = null;
return [
preview,
title
];
};
} }
render(msg, e) { // eslint-disable-line class-methods-use-this render(msg, e) { // eslint-disable-line class-methods-use-this
const hidden_badges = this.parent.context.get('chat.badges.hidden') || [], const hidden_badges = this.parent.context.get('chat.badges.hidden') || [],
badge_style = this.parent.context.get('chat.badges.style'),
is_mask = badge_style >= 5,
is_colored = badge_style !== 5,
has_image = badge_style !== 3 && badge_style !== 4,
out = [], out = [],
slotted = {}, slotted = {},
twitch_badges = msg.badges || {}, twitch_badges = msg.badges || {},
@ -261,13 +250,20 @@ export default class Badges extends Module {
else else
slot = last_slot++; slot = last_slot++;
const badges = [{
provider: 'twitch',
badge: badge_id,
version
}];
slotted[slot] = { slotted[slot] = {
id: badge_id, id: badge_id,
props: { props: {
'data-provider': 'twitch', 'data-provider': 'twitch',
'data-badge': badge_id, 'data-badge': badge_id,
'data-version': version 'data-version': version
} },
badges
}; };
} }
@ -278,7 +274,16 @@ export default class Badges extends Module {
const full_badge = this.badges[badge.id], const full_badge = this.badges[badge.id],
slot = has(badge, 'slot') ? badge.slot : full_badge.slot, slot = has(badge, 'slot') ? badge.slot : full_badge.slot,
old_badge = slotted[slot]; old_badge = slotted[slot],
urls = badge.urls || (badge.image ? {1: badge.image} : null),
bu = (urls || full_badge.urls || {1: full_badge.image}),
bd = {
provider: 'ffz',
image: bu[4] || bu[2] || bu[1],
color: badge.color || full_badge.color,
title: badge.title || full_badge.title
};
if ( old_badge ) { if ( old_badge ) {
const replaces = has(badge, 'replaces') ? badge.replaces : full_badge.replaces, const replaces = has(badge, 'replaces') ? badge.replaces : full_badge.replaces,
@ -286,6 +291,7 @@ export default class Badges extends Module {
if ( replaces && (!replaces_type || replaces_type === old_badge.id) ) if ( replaces && (!replaces_type || replaces_type === old_badge.id) )
old_badge.replaced = badge.id; old_badge.replaced = badge.id;
old_badge.badges.push(bd);
continue; continue;
} else if ( ! slot ) } else if ( ! slot )
@ -300,9 +306,24 @@ export default class Badges extends Module {
style style
}; };
// TODO: Render styles for badges with overrides. if ( has_image && urls ) {
let image_set, image = `url("${urls[1]}")`;
if ( urls[2] || urls[4] )
image_set = `${WEBKIT}image-set(${image} 1x${urls[2] ? `, url("${urls[2]}") 2x` : ''}${urls[4] ? `, url("${urls[4]}") 4x` : ''})`;
slotted[slot] = { id: badge.id, props }; style[is_mask ? CSS_MASK_IMAGE : 'backgroundImage'] = image;
if ( image_set )
style[is_mask ? CSS_MASK_IMAGE : 'backgroundImage'] = image_set;
}
if ( is_colored && badge.color ) {
if ( is_mask )
style.backgroundImage = `linear-gradient(${badge.color},${badge.color})`;
else
style.backgroundColor = badge.color;
}
slotted[slot] = { id: badge.id, props, badges: [bd] };
} }
for(const slot in slotted) for(const slot in slotted)
@ -312,6 +333,7 @@ export default class Badges extends Module {
props.className = 'ffz-tooltip ffz-badge'; props.className = 'ffz-tooltip ffz-badge';
props['data-tooltip-type'] = 'badge'; props['data-tooltip-type'] = 'badge';
props['data-badge-data'] = JSON.stringify(data.badges);
if ( data.replaced ) if ( data.replaced )
props['data-replaced'] = data.replaced; props['data-replaced'] = data.replaced;
@ -375,7 +397,7 @@ export default class Badges extends Module {
if ( data.badges ) if ( data.badges )
for(const badge of data.badges) for(const badge of data.badges)
if ( badge && badge.id ) { if ( badge && badge.id ) {
this.loadBadgeData(badge.id, badge); this.loadBadgeData(badge.id, badge, false);
badges++; badges++;
} }
@ -401,7 +423,7 @@ export default class Badges extends Module {
} }
loadBadgeData(badge_id, data) { loadBadgeData(badge_id, data, generate_css = true) {
this.badges[badge_id] = data; this.badges[badge_id] = data;
if ( data.replaces && ! data.replaces_type ) { if ( data.replaces && ! data.replaces_type ) {
@ -411,6 +433,9 @@ export default class Badges extends Module {
if ( data.name === 'developer' || data.name === 'supporter' ) if ( data.name === 'developer' || data.name === 'supporter' )
data.click_url = 'https://www.frankerfacez.com/donate'; data.click_url = 'https://www.frankerfacez.com/donate';
if ( generate_css )
this.buildBadgeCSS();
} }

View file

@ -414,7 +414,7 @@ export default class Following extends SiteModule {
if (channelAvatar !== null) channelAvatar.remove(); if (channelAvatar !== null) channelAvatar.remove();
if (inst.props.viewerCount.profileImageURL) { if (inst.props.viewerCount.profileImageURL) {
const hosting = inst.props.channelNameLinkTo.state.content === 'live_host' && this.hosts[inst.props.channelName]; const hosting = inst.props.channelNameLinkTo.state.content === 'live_host' && this.hosts && this.hosts[inst.props.channelName];
let channel, displayName; let channel, displayName;
if (hosting) { if (hosting) {
channel = this.hosts[inst.props.channelName].channel; channel = this.hosts[inst.props.channelName].channel;