1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-02 16:08:31 +00:00

3.5.203. Improved styling for balloon elements in dark theme. Support the new badge system. Add support for hiding badges. Add support for hiding badges when BetterTTV is present. Remove silly duplicate code from channel.js. Fix the Chat button showing a silly message when you're perma-banned.

This commit is contained in:
SirStendec 2016-06-05 22:12:54 -04:00
parent 04a8f5dae7
commit 2f7dc1d8d3
14 changed files with 396 additions and 84 deletions

View file

@ -200,10 +200,19 @@ body.ffz-dark:not([data-page="teams#show"]),
box-shadow: rgba(255,255,255,0.2) 0 0 0 1px inset;
}
.ffz-dark #flyout .content,
.ffz-dark .ffz-ui-popup.emoticon-selector .emoticon-selector-box { border: none }
.ffz-dark .balloon--up:after { box-shadow: 1px 1px 0 rgba(255,255,255,0.2) }
.ffz-dark .balloon--down:after { box-shadow: -1px -1px 0 rgba(255,255,255,0.2) }
.ffz-dark .balloon--left:after { box-shadow: 1px -1px 0 rgba(255,255,255,0.2) }
.ffz-dark .balloon--right:after { box-shadow: -1px 1px 0 rgba(255,255,255,0.2) }
.ffz-dark .player-menu__header { color: #c3c3c3 }
.ffz-dark .player-menu__section { border-bottom-color: rgba(255,255,255,0.2) }
.ffz-dark .balloon:after { box-shadow: none }
/*.ffz-dark .balloon:after { box-shadow: none }*/
.ffz-dark .st-autocomplete-sidebar .label,
.ffz-dark .st-autocomplete-small .label,
@ -287,6 +296,9 @@ body.ffz-dark:not([data-page="teams#show"]),
color: #8c8c9c;
}
.ffz-dark .balloon .balloon__link { color: #a68ed2 !important }
.ffz-dark .balloon .balloon__link:hover { color: #fff !important }
.ffz-dark .st-autocomplete-sidebar .all p:not(.active),
.ffz-dark .st-autocomplete-small .all p:not(.active),
.ffz-dark .st-autocomplete .all p:not(.active),

View file

@ -2,16 +2,36 @@ var FFZ = window.FrankerFaceZ,
constants = require('./constants'),
utils = require('./utils'),
SPECIAL_BADGES = [
['staff', 'staff', 'Staff'],
['admin', 'admin', 'Admin'],
['global_mod', 'global-moderator', 'Global Moderator']
],
SPECIAL_BADGES = ['staff', 'admin', 'global_mod'],
OTHER_KNOWN = ['turbo', 'warcraft'],
badge_css = function(badge) {
var out = ".badges .ffz-badge-" + badge.id + " { background-color: " + badge.color + '; background-image: url("' + badge.image + '"); ' + (badge.css || "") + '}';
BTTV_TYPE_REPLACEMENTS = {
'global-moderator': 'global_mod'
},
BADGE_POSITIONS = {
'broadcaster': 0,
'staff': 0,
'admin': 0,
'global_mod': 0,
'mod': 1,
'moderator': 1,
'subscriber': 10,
},
BADGE_NAMES = {
'global_mod': 'Global Moderator'
},
BADGE_KLASSES = {
'global_mod': 'global-moderator'
},
badge_css = function(badge, klass) {
klass = klass || ('ffz-badge-' + badge.id);
var out = ".badges ." + klass + " { background-color: " + badge.color + '; background-image: url("' + badge.image + '"); ' + (badge.css || "") + '}';
if ( badge.alpha_image )
out += ".badges .badge.alpha.ffz-badge-" + badge.id + ",.ffz-transparent-badges .badges .ffz-badge-" + badge.id + ' { background-image: url("' + badge.alpha_image + '"); }';
out += ".badges .badge.alpha." + klass + ",.ffz-transparent-badges .badges ." + klass + ' { background-image: url("' + badge.alpha_image + '"); }';
return out;
};
@ -27,7 +47,80 @@ FFZ.settings_info.show_badges = {
category: "Chat Appearance",
name: "Additional Badges",
help: "Show additional badges for bots, FrankerFaceZ donors, and other special users."
};
};
FFZ.settings_info.hidden_badges = {
type: "button",
value: [],
category: "Chat Appearance",
name: "Hidden Badges",
help: "Any badges added to this list will not be displayed in chat.",
on_update: function(val) {
if ( this.has_bttv )
return;
var controller = utils.ember_lookup('controller:chat'),
messages = controller && controller.get('currentRoom.messages');
if ( ! messages )
return;
for(var i=0; i < messages.length; i++)
messages[i]._line && messages[i]._line.ffzUpdateBadges();
},
method: function() {
var f = this,
service = utils.ember_lookup('service:badges'),
badgeCollection = service && service.badgeCollection,
old_val = f.settings.hidden_badges.join(", "),
values = [];
if ( badgeCollection ) {
if ( badgeCollection.global )
for(var badge in badgeCollection.global)
if ( badgeCollection.global.hasOwnProperty(badge) && badge !== 'broadcasterName' )
values.push('<code>' + badge + '</code>');
if ( badgeCollection.channel )
for(var badge in badgeCollection.channel)
if ( badgeCollection.channel.hasOwnProperty(badge) && badge !== 'broadcasterName' )
values.push('<code>' + badge + '</code>');
}
for(var badge_id in f.badges) {
if ( f.badges.hasOwnProperty(badge_id) && f.badges[badge_id].name )
values.push('<code>ffz-' + f.badges[badge_id].name + '</code>');
}
if ( this.has_bttv && window.BetterTTV ) {
try {
for(var badge_id in BetterTTV.chat.store.__badgeTypes)
values.push('<code>bttv-' + badge_id + '</code>');
values.push('<code>bot</code>');
} catch(err) {
this.error("Unable to load known BetterTTV badges.", err);
}
}
utils.prompt(
"Hidden Badges",
"Please enter a comma-separated list of badges that you would like to be hidden in chat.</p><p><b>Possible Values:</b> " + _.unique(values).join(", "),
old_val,
function(new_val) {
if ( new_val === null || new_val === undefined )
return;
f.settings.set("hidden_badges", _.unique(new_val.trim().toLowerCase().split(/\s*,\s*/)));
}, 600
)
}
};
FFZ.settings_info.sub_notice_badges = {
@ -39,10 +132,10 @@ FFZ.settings_info.sub_notice_badges = {
help: "Display a subscriber badge on chat messages about new subscribers.",
on_update: function(val) {
this.toggle_style('badges-sub-notice', ! val);
this.toggle_style('badges-sub-notice-on', val);
}
};
this.toggle_style('badges-sub-notice', ! val);
this.toggle_style('badges-sub-notice-on', val);
}
};
FFZ.settings_info.legacy_badges = {
@ -71,11 +164,11 @@ FFZ.settings_info.legacy_badges = {
},
on_update: function(val) {
this.toggle_style('badges-legacy', val === 3);
this.toggle_style('badges-legacy-mod', val !== 0);
this.toggle_style('badges-legacy-turbo', val > 1);
}
};
this.toggle_style('badges-legacy', val === 3);
this.toggle_style('badges-legacy-mod', val !== 0);
this.toggle_style('badges-legacy-turbo', val > 1);
}
};
FFZ.settings_info.transparent_badges = {
@ -108,17 +201,17 @@ FFZ.settings_info.transparent_badges = {
},
on_update: function(val) {
if ( this.has_bttv )
return;
if ( this.has_bttv )
return;
this.toggle_style('badges-rounded', val === 1);
this.toggle_style('badges-circular', val === 2 || val === 3 || val === 4);
this.toggle_style('badges-blank', val === 3 || val === 4);
this.toggle_style('badges-circular-small', val === 4);
this.toggle_style('badges-transparent', val === 5);
document.body.classList.toggle('ffz-transparent-badges', val === 5);
}
};
this.toggle_style('badges-rounded', val === 1);
this.toggle_style('badges-circular', val === 2 || val === 3 || val === 4);
this.toggle_style('badges-blank', val === 3 || val === 4);
this.toggle_style('badges-circular-small', val === 4);
this.toggle_style('badges-transparent', val === 5);
document.body.classList.toggle('ffz-transparent-badges', val === 5);
}
};
// --------------------
@ -187,7 +280,9 @@ FFZ.ws_commands.set_badge = function(data) {
// --------------------
FFZ.prototype.get_badges = function(user, room_id, badges, msg) {
var data = this.users[user];
var data = this.users[user],
hidden_badges = this.settings.hidden_badges;
if ( ! data || ! data.badges || ! this.settings.show_badges )
return badges;
@ -199,6 +294,9 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) {
full_badge = this.badges[badge.id] || {},
old_badge = badges[slot];
if ( hidden_badges.indexOf('ffz-' + full_badge.name) !== -1 )
continue;
if ( full_badge.visible !== undefined ) {
var visible = full_badge.visible;
if ( typeof visible === "function" )
@ -223,6 +321,7 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) {
klass: 'ffz-badge-' + badge.id,
title: badge.title || full_badge.title,
image: badge.image,
full_image: full_badge.image,
color: badge.color,
extra_css: badge.extra_css
};
@ -234,30 +333,77 @@ FFZ.prototype.get_badges = function(user, room_id, badges, msg) {
FFZ.prototype.get_line_badges = function(msg) {
var badges = {},
hidden_badges = this.settings.hidden_badges,
last_id = -1,
had_last = false,
room = msg.get && msg.get('room') || msg.room,
from = msg.get && msg.get('from') || msg.from,
tags = msg.get && msg.get('tags') || msg.tags || {},
labels = msg.labels || [];
badge_tag = tags.badges || {},
if ( room && from === room )
badges[0] = {klass: 'broadcaster', title: 'Broadcaster'};
else {
for(var i=0, l = SPECIAL_BADGES.length; i < l; i++) {
var mb = SPECIAL_BADGES[i];
if ( tags['user-type'] === mb[0] || labels.indexOf(mb[0]) !== -1 ) {
badges[0] = {klass: mb[1], title: mb[2]}
break;
}
}
service = utils.ember_lookup('service:badges'),
badgeCollection = service && service.badgeCollection,
if ( tags.mod || labels.indexOf('mod') !== -1 )
badges[1] = {klass: 'moderator', title: 'Moderator'};
}
globals = badgeCollection && badgeCollection.global || {},
channel = badgeCollection && badgeCollection.channel || {};
if ( tags.subscriber || labels.indexOf('subscriber') !== -1 )
badges[10] = {klass: 'subscriber', title: 'Subscriber'}
if ( tags.turbo || labels.indexOf('turbo') !== -1 )
badges[15] = {klass: 'turbo', title: 'Turbo'};
// VoD Chat lines don't have the badges pre-parsed for some reason.
if ( typeof badge_tag === 'string' ) {
var val = badge_tag.split(',');
badge_tag = {};
for(var i=0; i < val.length; i++) {
var parts = val[i].split('/');
if ( parts.length === 2 )
badge_tag[parts[0]] = parts[1];
}
}
for(var badge in badge_tag) {
var version = badge_tag[badge];
if ( ! badge_tag.hasOwnProperty(badge) || ! version )
continue;
var versions = channel[badge] || globals[badge],
binfo = versions && versions.versions && versions.versions[version];
if ( from === 'sirstendec' && badge === 'turbo' && globals.warcraft ) {
badge = 'warcraft';
version = 'protoss';
binfo = {
click_action: 'visit_url',
click_url: 'https://www.youtube.com/watch?v=dpBM2FIHprM',
description: 'My life for Aiur!',
title: 'Protoss',
image_url_1x: 'https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/1.png',
image_url_2x: 'https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/2.png',
image_url_3x: 'https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/4.png'
}
}
if ( hidden_badges.indexOf(badge) !== -1 )
continue;
if ( BADGE_POSITIONS.hasOwnProperty(badge) )
last_id = BADGE_POSITIONS[badge];
else {
last_id = had_last ? last_id + 1 : 15;
had_last = true;
}
var is_known = BADGE_POSITIONS.hasOwnProperty(badge) || OTHER_KNOWN.indexOf(badge) !== -1;
badges[last_id] = {
klass: (BADGE_KLASSES[badge] || badge) + (is_known ? '' : ' unknown-badge') + ' version-' + version,
title: binfo && binfo.title || BADGE_NAMES[badge] || badge.capitalize(),
click_url: binfo && binfo.click_action === 'visit_url' && binfo.click_url
};
if ( ! is_known && binfo ) {
badges[last_id].image = binfo.image_url_1x;
badges[last_id].srcSet = 'url("' + binfo.image_url_1x + '") 1x, url("' + binfo.image_url_2x + '") 2x, url("' + binfo.image_url_3x + '") 4x';
}
}
// FFZ Badges
return this.get_badges(from, room, badges, msg);
@ -272,8 +418,8 @@ FFZ.prototype.get_other_badges = function(user_id, room_id, user_type, has_sub,
else
for(var i=0, l = SPECIAL_BADGES.length; i < l; i++) {
var mb = SPECIAL_BADGES[i];
if ( user_type === mb[0] ) {
badges[0] = {klass: mb[1], title: mb[2]};
if ( user_type === mb ) {
badges[0] = {klass: BADGE_KLASSES[mb] || mb, title: BADGE_TITLES[mb] || mb.capitalize()};
break;
}
}
@ -295,15 +441,22 @@ FFZ.prototype.render_badges = function(badges) {
var out = [];
for(var key in badges) {
var badge = badges[key],
klass = badge.klass,
css = badge.image ? 'background-image:url("' + utils.quote_attr(badge.image) + '");' : '';
if ( badge.srcSet )
css += 'background-image:-webkit-image-set(' + badge.srcSet + ');background-image:image-set(' + badge.srcSet + ');'
if ( badge.color )
css += 'background-color:' + badge.color + ';'
if ( badge.extra_css )
css += badge.extra_css;
out.push('<div class="badge float-left tooltip ' + utils.quote_attr(badge.klass) + '"' + (css ? ' style="' + utils.quote_attr(css) + '"' : '') + ' title="' + utils.quote_attr(badge.title) + '"></div>');
if ( badge.click_url )
klass += ' click_url';
out.push('<div class="badge float-left tooltip ' + utils.quote_attr(klass) + '"' + (badge.click_url ? ' data-url="' + utils.quote_attr(badge.click_url) + '"' : '') + (css ? ' style="' + utils.quote_attr(css) + '"' : '') + ' title="' + utils.quote_attr(badge.title) + '"></div>');
}
return out.join("");
@ -322,23 +475,38 @@ FFZ.prototype.bttv_badges = function(data) {
user = this.users[user_id],
badges_out = [],
insert_at = -1,
hidden_badges = this.settings.hidden_badges,
alpha = BetterTTV.settings.get('alphaTags');
if ( ! user || ! user.badges )
return;
if ( ! data.badges )
data.badges = [];
// Determine where in the list to insert these badges.
// Also, strip out banned badges while we're at it.
for(var i=0; i < data.badges.length; i++) {
var badge = data.badges[i];
if ( badge.type == "subscriber" || badge.type == "turbo" ) {
var badge = data.badges[i],
space_ind = badge.type.indexOf(' '),
hidden_key = BTTV_TYPE_REPLACEMENTS[badge.type] || (space_ind === -1 ? badge.type : badge.type.substr(0, space_ind));
if ( hidden_badges.indexOf(hidden_key) !== -1 ) {
data.badges.splice(i, 1);
continue;
}
if ( badge.type === "subscriber" || badge.type === "turbo" || badge.type.substr(0, 8) === 'warcraft' ) {
insert_at = i;
break;
}
}
// If there's no user, we're done now.
if ( ! user || ! user.badges )
return;
// We have a user. Start replacing badges.
for (var slot in user.badges) {
if ( ! user.badges.hasOwnProperty(slot) )
continue;
@ -348,9 +516,12 @@ FFZ.prototype.bttv_badges = function(data) {
desc = badge.title || full_badge.title,
style = "";
if ( hidden_badges.indexOf('ffz-' + full_badge.name) !== -1 )
continue;
if ( full_badge.visible !== undefined ) {
var visible = full_badge.visible;
if ( typeof visible == "function" )
if ( typeof visible === "function" )
visible = visible.call(this, null, user_id);
if ( ! visible )
@ -400,6 +571,8 @@ FFZ.prototype.bttv_badges = function(data) {
while(badges_out.length)
data.badges.insertAt(insert_at, badges_out.shift()[1]);
}
}

View file

@ -18,11 +18,6 @@ FFZ.prototype.setup_channel = function() {
document.body.classList.toggle("ffz-hide-view-count", !this.settings.channel_views);
document.body.classList.toggle('ffz-theater-stats', this.settings.theater_stats);
this.log("Creating channel style element.");
var s = this._channel_style = document.createElement('style');
s.id = "ffz-channel-css";
document.head.appendChild(s);
this.log("Hooking the Ember Channel Index view.");
var Channel = utils.ember_resolve('view:channel/index'),
f = this;

View file

@ -138,22 +138,22 @@ FFZ.prototype._modify_conversation_window = function(component) {
component.reopen({
headerBadges: Ember.computed("thread.participants", "currentUsername", function() {
var e = this.get("otherUser"),
badges = f.get_other_badges(e.get('username'), null, e.get('userType'), false, e.get('hasTurbo')),
out = [];
// It wants slightly different output from us.
for(var slot in badges) {
var badge = badges[slot];
out.push({
classes: 'badge ' + badge.klass,
title: badge.title
});
}
return out;
return [];
}),
ffzHeaderBadges: Ember.computed("thread.participants", "currentUsername", function() {
var e = this.get("otherUser");
return f.get_other_badges(e.get('username'), null, e.get('userType'), false, e.get('hasTurbo'));
}),
ffzReplaceBadges: function() {
var el = this.get('element'),
badge_el = el && el.querySelector('.badges'),
badges = this.get('ffzHeaderBadges');
badge_el.innerHTML = f.render_badges(badges);
}.observes('ffzHeaderBadges'),
didInsertElement: function() {
var el = this.get('element'),
header = el && el.querySelector('.conversation-header'),
@ -164,6 +164,8 @@ FFZ.prototype._modify_conversation_window = function(component) {
is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch;
this.ffzReplaceBadges();
if ( header_name && raw_color ) {
header_name.style.color = (is_dark ? colors[1] : colors[0]);
header_name.classList.add('has-color');

View file

@ -662,6 +662,10 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
this.$(".deleted,.message").replaceWith(this.buildMessageHTML());
}),
ffzUpdateBadges: function() {
this.$(".badges").html(f.render_badges(f.get_line_badges(this.get('msgObject'))));
},
ffzUserLevel: function() {
if ( this.get('isStaff') )
return 5;
@ -755,7 +759,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
output += this.buildModIconsHTML();
// Badges
output += '<span class="badges float-left">' + f.render_badges(f.get_line_badges(this.get('msgObject'), is_whisper)) + '</span>';
output += '<span class="badges float-left">' + f.render_badges(f.get_line_badges(this.get('msgObject'))) + '</span>';
// Alias Support
var alias = f.aliases[user],
@ -915,7 +919,10 @@ FFZ.prototype._modify_chat_subline = function(component) {
this.sendAction("timeoutUser", {user:from});
} else if ( cl.contains('badge') ) {
if ( cl.contains('turbo') )
if ( cl.contains('click_url') )
window.open(e.target.getAttribute('data-url'), "_blank");
else if ( cl.contains('turbo') )
window.open("/products/turbo?ref=chat_badge", "_blank");
else if ( cl.contains('subscriber') )
@ -1015,7 +1022,19 @@ FFZ.prototype._modify_vod_line = function(component) {
},
click: function(e) {
if ( e.target.classList.contains('delete') ) {
var cl = e.target.classList;
if ( cl.contains('badge') ) {
if ( cl.contains('click_url') )
window.open(e.target.getAttribute('data-url'), "_blank");
else if ( cl.contains('turbo') )
window.open("/products/turbo?ref=chat_badge", "_blank");
else if ( cl.contains('subscriber') )
this.sendAction("clickSubscriber");
} else if ( cl.contains('delete') ) {
e.preventDefault();
this.sendAction("timeoutUser", this.get("msgObject.id"));
}

View file

@ -995,7 +995,7 @@ FFZ.prototype._modify_room = function(room) {
// If we were banned, set the state and update the UI.
if ( is_me ) {
t.set('ffz_banned', true);
if ( typeof duration === "number" && duration )
if ( typeof duration === "number" && duration && isFinite(duration) && !isNaN(duration) )
t.updateWait(duration)
else if ( duration ) {
t.set('slowWait', 0);
@ -1308,6 +1308,9 @@ FFZ.prototype._modify_room = function(room) {
if ( msg.from === 'twitchnotify' && msg.message.indexOf('subscribed to') === -1 && msg.message.indexOf('subscribed') !== -1 ) {
if ( ! msg.tags )
msg.tags = {};
if ( ! msg.tags.badges )
msg.tags.badges = {};
msg.tags.badges.subscriber = '1';
msg.tags.subscriber = true;
if ( msg.labels && msg.labels.indexOf("subscriber") === -1 )
msg.labels.push("subscriber");

View file

@ -37,7 +37,7 @@ FFZ.msg_commands = {};
// Version
var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 196,
major: 3, minor: 5, revision: 203,
toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
}

View file

@ -1,3 +1,3 @@
.badges .badge:not(.subscriber) {
.badges .badge:not(.subscriber):not(.unknown-badge) {
background-size: 0px;
}

View file

@ -1,4 +1,4 @@
.badges .badge:not(.subscriber) {
.badges .badge:not(.subscriber):not(.unknown-badge) {
height: 10px;
min-width: 10px;
margin: 5px 3px 5px 0;

View file

@ -1,4 +1,4 @@
.badges .badge:not(.subscriber) {
.badges .badge:not(.subscriber):not(.unknown-badge) {
border-radius: 9px;
background-size: 16px;
background-repeat: no-repeat;

View file

@ -1,4 +1,4 @@
/* Rounded Badges */
.badges .badge:not(.subscriber) {
.badges .badge:not(.subscriber):not(.unknown-badge) {
border-radius: 2px;
}

View file

@ -1139,6 +1139,9 @@ FFZ.prototype.parse_history = function(history, purged, room_id, delete_links, t
if ( msg.tags && typeof msg.tags.emotes === "string" )
msg.tags.emotes = utils.uncompressEmotes(msg.tags.emotes);
if ( msg.tags && typeof msg.tags.badges === "string" )
msg.tags.badges = utils.uncompressBadges(msg.tags.badges);
if ( ! msg.cachedTokens || ! msg.cachedTokens.length )
this.tokenize_chat_line(msg, true, delete_links);

View file

@ -76,6 +76,34 @@ var sanitize_el = document.createElement('span'),
return new Date(unix);
},
BADGE_REV = {
'b': 'broadcaster',
's': 'staff',
'a': 'admin',
'g': 'global_mod',
'm': 'moderator',
'u': 'subscriber',
't': 'turbo'
},
uncompressBadges = function(value) {
if ( value === true )
return {};
var output = {},
badges = value.split(","),
l = badges.length;
for(var i=0; i < l; i++) {
var parts = badges[i].split('/');
if ( parts.length !== 2 )
return {};
output[BADGE_REV[parts[0]] || parts[0].substr(1)] = parts[1];
}
return output;
},
uncompressEmotes = function(value) {
var output = {},
@ -373,6 +401,7 @@ module.exports = FFZ.utils = {
}
},
uncompressBadges: uncompressBadges,
uncompressEmotes: uncompressEmotes,
emoji_to_codepoint: emoji_to_codepoint,

View file

@ -2910,3 +2910,79 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
/* Chat Pane Overhaul */
.ember-chat.ffz-chat-pane .chat-messages { bottom: 0 }
/* Hide Outlines */
.conversation-header,
.conversations-list-icon,
.toggle-notification-menu {
outline: none !important
}
/* Badges */
/*.badges .badge {
height: 18px;
min-width: 18px;
display: inline-block;
vertical-align: middle;
float: left;
margin: 1px 3px 1px 0
}
.badges .broadcaster {
background: #e71818 url(/images/xarth/badge_broadcaster.svg);
background-size: 100%
}
.badges .turbo {
cursor: pointer;
background: #6441a5 url(/images/xarth/badge_turbo.svg);
background-size: 100%
}
.badges .subscriber {
cursor: pointer
}
.badges .staff {
background: #200f33 url(/images/xarth/badge_staff.svg);
background-size: 100%
}
.badges .global-moderator {
background: #0c6f20 url(/images/xarth/badge_globalmod.svg);
background-size: 100%
}
.badges .moderator {
background: #34ae0a url(/images/xarth/badge_mod.svg);
background-size: 100%
}
.badges .admin {
background: #faaf19 url(/images/xarth/badge_admin.svg);
background-size: 100%
}*/
/* Odd Badges */
.badge.click_url { cursor: pointer }
.badge.warcraft.version-alliance {
background: url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/1.png") #004094;
background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/4.png") 4x);
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/alliance/4.png") 4x);
}
.badge.warcraft.version-horde {
background: url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/1.png") #ab0016;
background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/4.png") 4x);
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/horde/4.png") 4x);
}
.badge.warcraft.version-protoss {
background: url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/1.png") #5bc7ff;
background-image: -webkit-image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/4.png") 4x);
background-image: image-set(url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/1.png") 1x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/2.png") 2x,url("https://cdn.frankerfacez.com/badges/twitch/warcraft/protoss/4.png") 4x);
}