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

Add convenience method for creating CSS variable or setting blocks of CSS directly in css_tweaks. Start using those variables for things like chat width. Add the ability to highlight messages with mentions in them. Fix Sidebar Swap and Theatre Mode. Closes #312

This commit is contained in:
SirStendec 2017-11-17 14:59:46 -05:00
parent a45dc472b7
commit 6da5d4c8b5
14 changed files with 213 additions and 49 deletions

View file

@ -1,4 +1,18 @@
<div class="list-header">4.0.0-beta1.3<span>@c89ba74a13dda449dfec</span> <time datetime="2017-11-16">(2017-11-16)</time></div> <div class="list-header">4.0.0-beta1.3<span>@e82e3deb4ad3e3f1b253</span> <time datetime="2017-11-17">(2017-11-17)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Chat > Behavior > General > Scrollback Length</li>
<li>Added: Chat > Filtering > Appearance > Highlight Mentions</li>
<li>Fixed: Tooltips with the WOT extension installed.</li>
<li>Fixed: Swap Sidebars not working in Theatre Mode.</li>
<li>Fixed: Scroll to Change Volume not allowing you to increase the volume on Firefox.</li>
</ul>
<div class="list-header">4.0.0-beta1.3<span>@0c55f4f15b6397d644f4</span> <time datetime="2017-11-17">(2017-11-17)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: The Stream Uptime display sometimes failing to appear.</li>
</ul>
<div class="list-header">4.0.0-beta1.3<span>@fb9568932222b25ebd88</span> <time datetime="2017-11-16">(2017-11-16)</time></div>
<ul class="chat-menu-content menu-side-padding"> <ul class="chat-menu-content menu-side-padding">
<li>Added: Automatic Theatre Mode</li> <li>Added: Automatic Theatre Mode</li>
<li>Added: Hide Whispers in Theatre Mode</li> <li>Added: Hide Whispers in Theatre Mode</li>

View file

@ -52,6 +52,41 @@ export default class Chat extends Module {
// Settings // Settings
// ======================================================================== // ========================================================================
this.settings.add('chat.scrollback-length', {
default: 150,
ui: {
path: 'Chat > Behavior >> General',
title: 'Scrollback Length',
description: 'Keep up to this many lines in chat. Setting this too high will create lage.',
component: 'setting-text-box',
process(val) {
val = parseInt(val, 10);
if ( isNaN(val) || ! isFinite(val) || val < 1 )
val = 150;
return val;
}
}
});
this.settings.add('chat.filtering.highlight-mentions', {
default: false,
ui: {
path: 'Chat > Filtering >> Appearance',
title: 'Highlight messages that mention you.',
component: 'setting-check-box'
}
});
this.settings.add('chat.filtering.highlight-tokens', {
default: false,
ui: {
path: 'Chat > Filtering >> Appearance',
title: 'Highlight matched words in chat.',
component: 'setting-check-box'
}
});
this.settings.add('tooltip.images', { this.settings.add('tooltip.images', {
default: true, default: true,
ui: { ui: {
@ -417,11 +452,11 @@ export default class Chat extends Module {
} }
tokenizeMessage(msg) { tokenizeMessage(msg, user) {
let tokens = [{type: 'text', text: msg.message}]; let tokens = [{type: 'text', text: msg.message}];
for(const tokenizer of this.__tokenizers) for(const tokenizer of this.__tokenizers)
tokens = tokenizer.process.call(this, tokens, msg); tokens = tokenizer.process.call(this, tokens, msg, user);
return tokens; return tokens;
} }

View file

@ -201,14 +201,25 @@ export const Mentions = {
render(token, e) { render(token, e) {
return e('strong', { return e('strong', {
className: 'chat-line__message-mention' className: `chat-line__message-mention${token.me ? ' ffz--mention-me' : ''}`
}, `@${token.recipient}`); }, `${token.text}`);
}, },
process(tokens, msg) { process(tokens, msg, user) {
if ( ! tokens || ! tokens.length ) if ( ! tokens || ! tokens.length )
return tokens; return tokens;
let regex, login, display;
if ( user && user.login ) {
login = user.login.toLowerCase();
display = user.display && user.display.toLowerCase();
if ( display === login )
display = null;
regex = new RegExp(`([^\\w@#%\\-+=:~]|\\b)?(@?(${user.login.toLowerCase()}${display ? `|${display}` : ''})|@([^\\u0000-\\u007F]+|\\w+)+)([^\\w.\\/@#%&()\\-+=:?~]|\\s|\\b|$)`, 'gi');
} else
regex = MENTION_REGEX;
const out = []; const out = [];
for(const token of tokens) { for(const token of tokens) {
if ( token.type !== 'text' ) { if ( token.type !== 'text' ) {
@ -216,19 +227,27 @@ export const Mentions = {
continue; continue;
} }
MENTION_REGEX.lastIndex = 0; regex.lastIndex = 0;
const text = token.text; const text = token.text;
let idx = 0, match; let idx = 0, match;
while((match = MENTION_REGEX.exec(text))) { while((match = regex.exec(text))) {
const nix = match.index + (match[1] ? match[1].length : 0); const nix = match.index + (match[1] ? match[1].length : 0),
m = match[3] || match[4],
ml = m.toLowerCase(),
me = ml === login || ml === display;
if ( idx !== nix ) if ( idx !== nix )
out.push({type: 'text', text: text.slice(idx, nix)}); out.push({type: 'text', text: text.slice(idx, nix)});
if ( me )
msg.mentioned = true;
out.push({ out.push({
type: 'mention', type: 'mention',
recipient: match[3], text: match[2],
length: match[3].length + 1 me,
recipient: m
}); });
idx = nix + match[2].length; idx = nix + match[2].length;

View file

@ -17,7 +17,7 @@ import SettingsMenu from './settings_menu';
const ChatTypes = (e => { const ChatTypes = (e => {
/*e[e.Post = 0] = 'Post'; e[e.Post = 0] = 'Post';
e[e.Action = 1] = 'Action'; e[e.Action = 1] = 'Action';
e[e.PostWithMention = 2] = 'PostWithMention'; e[e.PostWithMention = 2] = 'PostWithMention';
e[e.Ban = 3] = 'Ban'; e[e.Ban = 3] = 'Ban';
@ -27,9 +27,9 @@ const ChatTypes = (e => {
e[e.AutoModMessageAllowed = 7] = 'AutoModMessageAllowed'; e[e.AutoModMessageAllowed = 7] = 'AutoModMessageAllowed';
e[e.AutoModMessageDenied = 8] = 'AutoModMessageDenied'; e[e.AutoModMessageDenied = 8] = 'AutoModMessageDenied';
e[e.Connected = 9] = 'Connected'; e[e.Connected = 9] = 'Connected';
e[e.Disconnected = 10] = 'Disconnected';*/ e[e.Disconnected = 10] = 'Disconnected';
e[e.Reconnect = 11] = 'Reconnect'; e[e.Reconnect = 11] = 'Reconnect';
/*e[e.Hosting = 12] = 'Hosting'; e[e.Hosting = 12] = 'Hosting';
e[e.Unhost = 13] = 'Unhost'; e[e.Unhost = 13] = 'Unhost';
e[e.Subscription = 14] = 'Subscription'; e[e.Subscription = 14] = 'Subscription';
e[e.Resubscription = 15] = 'Resubscription'; e[e.Resubscription = 15] = 'Resubscription';
@ -38,14 +38,14 @@ const ChatTypes = (e => {
e[e.SubscriberOnlyMode = 18] = 'SubscriberOnlyMode'; e[e.SubscriberOnlyMode = 18] = 'SubscriberOnlyMode';
e[e.FollowerOnlyMode = 19] = 'FollowerOnlyMode'; e[e.FollowerOnlyMode = 19] = 'FollowerOnlyMode';
e[e.SlowMode = 20] = 'SlowMode'; e[e.SlowMode = 20] = 'SlowMode';
e[e.RoomMods = 21] = 'RoomMods';*/ e[e.RoomMods = 21] = 'RoomMods';
e[e.RoomState = 22] = 'RoomState'; e[e.RoomState = 22] = 'RoomState';
/*e[e.Raid = 23] = 'Raid'; e[e.Raid = 23] = 'Raid';
e[e.Unraid = 24] = 'Unraid'; e[e.Unraid = 24] = 'Unraid';
e[e.Notice = 25] = 'Notice'; e[e.Notice = 25] = 'Notice';
e[e.Info = 26] = 'Info';*/ e[e.Info = 26] = 'Info';
e[e.BadgesUpdated = 27] = 'BadgesUpdated'; e[e.BadgesUpdated = 27] = 'BadgesUpdated';
//e[e.Purchase = 28] = 'Purchase'; e[e.Purchase = 28] = 'Purchase';
return e; return e;
})({}); })({});
@ -239,29 +239,19 @@ export default class ChatHook extends Module {
updateChatCSS() { updateChatCSS() {
const width = this.chat.context.get('chat.width'), const width = this.chat.context.get('chat.width'),
size = this.chat.context.get('chat.font-size'), size = this.chat.context.get('chat.font-size'),
font = this.chat.context.get('chat.font-family'); lh = Math.round((20/12) * size);
if ( size === 12 ) let font = this.chat.context.get('chat.font-family') || 'inherit';
this.css_tweaks.style.delete('chat-font-size'); if ( font.indexOf(' ') !== -1 && font.indexOf(',') === -1 && font.indexOf('"') === -1 && font.indexOf("'") === -1 )
else { font = `"${font}"`;
const lh = Math.round((20/12) * size);
this.css_tweaks.style.set('chat-font-size',`.chat-list{font-size:${size}px;line-height:${lh}px}`);
}
if ( ! font ) this.css_tweaks.setVariable('chat-font-size', `${size}px`);
this.css_tweaks.style.delete('chat-font-family'); this.css_tweaks.setVariable('chat-line-height', `${lh}px`);
else { this.css_tweaks.setVariable('chat-font-family', font);
let val = font; this.css_tweaks.setVariable('chat-width', `${width}px`);
if ( font.indexOf(' ') !== -1 && val.indexOf(',') === -1 && val.indexOf('"') === -1 && val.indexOf("'") === -1 )
val = `"${val}"`;
this.css_tweaks.style.set('chat-font-family', `.chat-list{font-family:${val}}`);
}
this.css_tweaks.toggle('chat-font', size === 12 && ! font);
if ( width === 340 ) this.css_tweaks.toggle('chat-width', width !== 340);
this.css_tweaks.style.delete('chat-width');
else
this.css_tweaks.style.set('chat-width', `.whispers--theatre-mode.whispers--right-column-expanded{right:${width}px!important}.persistent-player--theatre,.channel-page__video-player--theatre-mode{width:calc(100% - ${width}px)!important}.channel-page__right-column{width:${width}px!important}`);
} }
updateLineBorders() { updateLineBorders() {
@ -273,6 +263,13 @@ export default class ChatHook extends Module {
this.css_tweaks.toggle('chat-borders-wide', mode === 4); this.css_tweaks.toggle('chat-borders-wide', mode === 4);
} }
updateMentionCSS() {
const enabled = this.chat.context.get('chat.filtering.highlight-mentions');
this.css_tweaks.toggle('chat-mention-token', this.chat.context.get('chat.filtering.highlight-tokens'));
this.css_tweaks.toggle('chat-mention-bg', enabled);
this.css_tweaks.toggle('chat-mention-bg-alt', enabled && this.chat.context.get('chat.lines.alternate'));
}
onEnable() { onEnable() {
this.on('site.web_munch:loaded', () => { this.on('site.web_munch:loaded', () => {
@ -290,9 +287,13 @@ export default class ChatHook extends Module {
this.chat.context.on('changed:chat.adjustment-contrast', this.updateColors, this); this.chat.context.on('changed:chat.adjustment-contrast', this.updateColors, this);
this.chat.context.on('changed:theme.is-dark', this.updateColors, this); this.chat.context.on('changed:theme.is-dark', this.updateColors, this);
this.chat.context.on('changed:chat.lines.borders', this.updateLineBorders, this); this.chat.context.on('changed:chat.lines.borders', this.updateLineBorders, this);
this.chat.context.on('changed:chat.filtering.highlight-mentions', this.updateMentionCSS, this);
this.chat.context.on('changed:chat.filtering.highlight-tokens', this.updateMentionCSS, this);
this.chat.context.on('changed:chat.lines.alternate', val => this.chat.context.on('changed:chat.lines.alternate', val => {
this.css_tweaks.toggle('chat-rows', val)); this.css_tweaks.toggle('chat-rows', val);
this.updateMentionCSS();
});
this.chat.context.on('changed:chat.lines.padding', val => this.chat.context.on('changed:chat.lines.padding', val =>
this.css_tweaks.toggle('chat-padding', val)); this.css_tweaks.toggle('chat-padding', val));
@ -310,6 +311,7 @@ export default class ChatHook extends Module {
this.updateChatCSS(); this.updateChatCSS();
this.updateColors(); this.updateColors();
this.updateLineBorders(); this.updateLineBorders();
this.updateMentionCSS();
this.ChatController.on('mount', this.chatMounted, this); this.ChatController.on('mount', this.chatMounted, this);
this.ChatController.on('unmount', this.removeRoom, this); this.ChatController.on('unmount', this.removeRoom, this);
@ -360,8 +362,9 @@ export default class ChatHook extends Module {
cls.prototype.toArray = function() { cls.prototype.toArray = function() {
const buf = this.buffer, const buf = this.buffer,
size = t.chat.context.get('chat.scrollback-length'),
ct = t.chatTypes || ChatTypes, ct = t.chatTypes || ChatTypes,
target = buf.length - this.maxSize; target = buf.length - size;
if ( target > 0 ) { if ( target > 0 ) {
let removed = 0, last; let removed = 0, last;

View file

@ -53,8 +53,10 @@ export default class ChatLine extends Module {
cls.prototype.render = function() { cls.prototype.render = function() {
const msg = this.props.message, const types = t.chat.chatTypes || {},
is_action = msg.type === 1,
msg = this.props.message,
is_action = msg.type === types.Action,
user = msg.user, user = msg.user,
color = t.parent.colors.process(user.color), color = t.parent.colors.process(user.color),
/*bg_rgb = Color.RGBA.fromHex(user.color), /*bg_rgb = Color.RGBA.fromHex(user.color),
@ -67,11 +69,11 @@ export default class ChatLine extends Module {
if ( ! msg.message && msg.messageParts ) if ( ! msg.message && msg.messageParts )
detokenizeMessage(msg); detokenizeMessage(msg);
const tokens = t.chat.tokenizeMessage(msg), const tokens = t.chat.tokenizeMessage(msg, {login: this.props.currentUserLogin, display: this.props.currentUserDisplayName}),
fragment = t.chat.renderTokens(tokens, e); fragment = t.chat.renderTokens(tokens, e);
const out = e('div', { const out = e('div', {
className: 'chat-line__message', className: `chat-line__message ${msg.mentioned ? 'ffz-mentioned' : ''}`,
//style: { backgroundColor: bg_css }, //style: { backgroundColor: bg_css },
'data-room-id': this.props.channelID, 'data-room-id': this.props.channelID,
'data-room': room, 'data-room': room,

View file

@ -199,6 +199,16 @@ export default class CSSTweaks extends Module {
} }
set(key, val) { return this.style.set(key, val) }
delete(key) { return this.style.delete(key) }
setVariable(key, val, scope = 'body') {
this.style.set(`var--${key}`, `${scope} { --ffz-${key}: ${val}; }`);
}
deleteVariable(key) { this.style.delete(`var--${key}`) }
populate() { populate() {
if ( this.chunks_loaded ) if ( this.chunks_loaded )
return; return;

View file

@ -0,0 +1,5 @@
.chat-list {
font-size: var(--ffz-chat-font-size);
line-height: var(--ffz-chat-line-height);
font-family: var(--ffz-chat-font-family);
}

View file

@ -0,0 +1,9 @@
.chat-line__message.ffz-mentioned {
&:nth-child(2n+0) {
background-color: rgba(255,127,127,.4);
.theme--dark & {
background-color: rgba(255,0,0,.3);
}
}
}

View file

@ -0,0 +1,7 @@
.chat-line__message.ffz-mentioned {
background-color: rgba(255,127,127,.2);
.theme--dark & {
background-color: rgba(255,0,0,.2);
}
}

View file

@ -0,0 +1,13 @@
.ffz--mention-me {
border-radius: .5rem;
padding: .3rem;
font-weight: 700;
color: #fff;
background: rgba(0,0,0,0.5);
.theme--dark & {
color: #000;
background-color: rgba(255,255,255,0.5);
}
}

View file

@ -3,13 +3,13 @@
.chat-line__raid, .chat-line__raid,
.chat-line__subscribe, .chat-line__subscribe,
.chat-line__message { .chat-line__message {
background-color: transparent !important; background-color: transparent;
&:nth-child(2n+0) { &:nth-child(2n+0) {
background-color: rgba(0,0,0,0.1) !important; background-color: rgba(0,0,0,0.1);
.theme--dark & { .theme--dark & {
background-color: rgba(255,255,255,0.05) !important; background-color: rgba(255,255,255,0.05);
} }
} }
} }

View file

@ -0,0 +1,12 @@
body .whispers--theatre-mode.whispers--right-column-expanded {
right: var(--ffz-chat-width);
}
body .persistent-player--theatre,
body .channel-page__video-player--theatre-mode {
width: calc(100% - var(--ffz-chat-width));
}
body .channel-page__right-column {
width: var(--ffz-chat-width);
}

View file

@ -31,3 +31,19 @@
border-right-color: #2c2541; border-right-color: #2c2541;
} }
} }
.right-column.right-column--theatre {
right: unset !important;
left: 0 !important;
}
.channel-page__video-player--theatre-mode {
left: unset !important;
right: 0;
}
body .whispers--theatre-mode.whispers--right-column-expanded {
left: var(--ffz-chat-width) !important;
right: 0 !important;
}

View file

@ -7,6 +7,7 @@
font-style: normal; font-style: normal;
} }
//[data-a-target="emote-picker-button"] figure:before,
[class^="ffz-i-"]:before, [class*=" ffz-i-"]:before { [class^="ffz-i-"]:before, [class*=" ffz-i-"]:before {
font-family: "ffz-fontello"; font-family: "ffz-fontello";
font-style: normal; font-style: normal;
@ -49,13 +50,31 @@
} }
} }
//[data-a-target="emote-picker-button"] figure:before,
.ffz-i-zreknarf:before { .ffz-i-zreknarf:before {
content: '\e801'; /* '' */ content: '\e801'; /* '' */
width: 1.3em; width: 1.3em;
margin: .5rem .05rem 0; margin: .5rem .05rem 0;
} }
/*[data-a-target="emote-picker-button"] {
.tw-button-icon__icon {
padding: .25rem .4rem;
figure {
display: inline;
&:before {
font-size: 14px;
}
svg {
display: none
}
}
}
}*/
.ffz-i-cancel:before { content: '\e800'; } /* '' */ .ffz-i-cancel:before { content: '\e800'; } /* '' */
.ffz-i-search:before { content: '\e802'; } /* '' */ .ffz-i-search:before { content: '\e802'; } /* '' */