mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.20.73
* Added: Option for changing the chat timestamp font size. * Changed: Allow chat room actions to be spread across multiple lines. * Fixed: The chat action editor not properly displaying spacers. * Fixed: Make `switchboard` wait for `web_munch` before trying to load a route.
This commit is contained in:
parent
9086230686
commit
add9f7a7d5
11 changed files with 212 additions and 24 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "frankerfacez",
|
||||
"author": "Dan Salvato LLC",
|
||||
"version": "4.20.72",
|
||||
"version": "4.20.73",
|
||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
|
|
28
src/modules/chat/actions/components/edit-emoji.vue
Normal file
28
src/modules/chat/actions/components/edit-emoji.vue
Normal file
|
@ -0,0 +1,28 @@
|
|||
<template lang="html">
|
||||
<div class="tw-flex tw-align-items-start">
|
||||
<label class="tw-mg-y-05">
|
||||
{{ t('setting.actions.emoji', 'Emoji') }}
|
||||
</label>
|
||||
|
||||
<emoji-picker
|
||||
:value="value.emoji"
|
||||
class="tw-full-width"
|
||||
@input="change"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
props: ['value'],
|
||||
|
||||
methods: {
|
||||
change(val) {
|
||||
this.value.emoji = val;
|
||||
this.$emit('input', this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
|
@ -158,7 +158,7 @@ export default class Actions extends Module {
|
|||
path: 'Chat > Actions > Room @{"description": "Here, you can define custom actions that will appear above the chat input box."}',
|
||||
component: 'chat-actions',
|
||||
context: ['room', 'room-mode'],
|
||||
inline: true,
|
||||
inline: false,
|
||||
|
||||
data: () => {
|
||||
const chat = this.resolve('site.chat');
|
||||
|
@ -420,11 +420,38 @@ export default class Actions extends Module {
|
|||
|
||||
|
||||
renderRoom(mod_icons, current_user, current_room, is_above, createElement) {
|
||||
const actions = [],
|
||||
const lines = [],
|
||||
chat = this.resolve('site.chat');
|
||||
let line = null;
|
||||
|
||||
for(const data of this.parent.context.get('chat.actions.room')) {
|
||||
if ( ! data || ! data.action || ! data.appearance )
|
||||
if ( ! data )
|
||||
continue;
|
||||
|
||||
const type = data.type;
|
||||
if ( type ) {
|
||||
if ( type === 'new-line' ) {
|
||||
line = null;
|
||||
|
||||
} else if ( type === 'space' ) {
|
||||
if ( ! line )
|
||||
lines.push(line = []);
|
||||
|
||||
line.push(<div class="tw-flex-grow-1" />);
|
||||
|
||||
} else if ( type === 'space-small' ) {
|
||||
if ( ! line )
|
||||
lines.push(line = []);
|
||||
|
||||
line.push(<div class="tw-mg-x-1" />);
|
||||
|
||||
} else
|
||||
this.log.warn('Unknown action type', type);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! data.action || ! data.appearance )
|
||||
continue;
|
||||
|
||||
let ap = data.appearance || {};
|
||||
|
@ -460,7 +487,10 @@ export default class Actions extends Module {
|
|||
color = has_color && (chat && chat.colors ? chat.colors.process(ap.color) : ap.color),
|
||||
contents = def.render.call(this, ap, createElement, color);
|
||||
|
||||
actions.push(<button
|
||||
if ( ! line )
|
||||
lines.push(line = []);
|
||||
|
||||
line.push(<button
|
||||
class={`ffz-tooltip tw-pd-x-05 mod-icon ffz-mod-icon tw-c-text-alt-2${disabled ? ' disabled' : ''}${has_color ? ' colored' : ''}`}
|
||||
data-tooltip-type="action"
|
||||
data-action={data.action}
|
||||
|
@ -473,13 +503,18 @@ export default class Actions extends Module {
|
|||
</button>);
|
||||
}
|
||||
|
||||
if ( ! actions.length )
|
||||
if ( ! lines.length )
|
||||
return null;
|
||||
|
||||
const room = current_room && JSON.stringify(current_room);
|
||||
const room = current_room && JSON.stringify(current_room),
|
||||
multi_line = lines.length > 1;
|
||||
|
||||
const actions = multi_line ?
|
||||
lines.map((line, idx) => <div key={idx} class="tw-flex tw-full-width tw-flex-row tw-flex-wrap">{line}</div>) :
|
||||
lines[0];
|
||||
|
||||
return (<div
|
||||
class={`ffz--room-actions ffz-action-data tw-flex tw-flex-grow-1 tw-flex-wrap tw-align-items-center ${is_above ? 'tw-pd-y-05 tw-border-t' : 'tw-mg-x-05'}`}
|
||||
class={`ffz--room-actions${multi_line ? ' tw-flex-column' : ''} ffz-action-data tw-flex tw-flex-grow-1 tw-flex-wrap tw-align-items-center ${is_above ? 'tw-pd-y-05 tw-border-t' : 'tw-mg-x-05'}`}
|
||||
data-room={room}
|
||||
>
|
||||
{actions}
|
||||
|
|
|
@ -91,3 +91,29 @@ export const image = {
|
|||
return <figure class="mod-icon__image"><img src={data.image} /></figure>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Emoji
|
||||
// ============================================================================
|
||||
|
||||
/*export const emoji = {
|
||||
title: 'Emoji',
|
||||
title_i18n: 'setting.actions.appearance.emoji',
|
||||
|
||||
colored: false,
|
||||
editor: () => import(/* webpackChunkName: 'main-menu' * / './components/edit-emoji.vue'),
|
||||
|
||||
load(data) {
|
||||
if ( data.icon && data.icon.startsWith('ffz-fa') )
|
||||
loadFontAwesome();
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
component: () => import(/* webpackChunkName: 'main-menu' * / './components/preview-emoji.vue'),
|
||||
|
||||
render(data, createElement) {
|
||||
return <figure class="mod-icon__image"><img src={data.image} /></figure>;
|
||||
}
|
||||
}*/
|
|
@ -98,6 +98,23 @@ export default class Chat extends Module {
|
|||
force_seen: true
|
||||
});
|
||||
|
||||
this.settings.add('chat.timestamp-size', {
|
||||
default: null,
|
||||
ui: {
|
||||
path: 'Chat > Appearance >> General',
|
||||
title: 'Timestamp Font Size',
|
||||
description: 'How large should timestamps be, in pixels. Defaults to Font Size if not set.',
|
||||
component: 'setting-text-box',
|
||||
process(val) {
|
||||
val = parseInt(val, 10);
|
||||
if ( isNaN(val) || ! isFinite(val) || val <= 0 )
|
||||
return null;
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.settings.add('chat.font-size', {
|
||||
default: 13,
|
||||
ui: {
|
||||
|
@ -108,7 +125,7 @@ export default class Chat extends Module {
|
|||
process(val) {
|
||||
val = parseInt(val, 10);
|
||||
if ( isNaN(val) || ! isFinite(val) || val <= 0 )
|
||||
return 12;
|
||||
return 13;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -193,15 +193,27 @@
|
|||
:key="idx"
|
||||
class="tw-flex tw-align-items-center tw-justify-content-center"
|
||||
>
|
||||
<action-preview
|
||||
v-for="act in actions"
|
||||
:key="act.id"
|
||||
:act="act.v"
|
||||
:color="color(act.v.appearance.color)"
|
||||
:renderers="data.renderers"
|
||||
tooltip="true"
|
||||
pad="true"
|
||||
/>
|
||||
<template v-for="act in actions">
|
||||
<div
|
||||
v-if="act.type === 'space'"
|
||||
:key="act.id"
|
||||
class="tw-flex-grow-1"
|
||||
/>
|
||||
<div
|
||||
v-else-if="act.type === 'space-small'"
|
||||
:key="act.id"
|
||||
class="tw-mg-x-1"
|
||||
/>
|
||||
<action-preview
|
||||
v-else
|
||||
:key="act.id"
|
||||
:act="act.v"
|
||||
:color="color(act.v.appearance.color)"
|
||||
:renderers="data.renderers"
|
||||
tooltip="true"
|
||||
pad="true"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -254,7 +266,7 @@
|
|||
<div v-else class="tw-pd-y-1">
|
||||
<button
|
||||
class="ffz-interactable ffz-interactable--hover-enabled ffz-interactable--default tw-interactive tw-full-width"
|
||||
@click="add_pasting = true"
|
||||
@click="preparePaste"
|
||||
>
|
||||
<div class="tw-flex tw-align-items-center tw-pd-y-05 tw-pd-x-1">
|
||||
<div class="tw-flex-grow-1 tw-mg-r-1">
|
||||
|
@ -532,6 +544,9 @@ export default {
|
|||
out.push(current);
|
||||
current = [];
|
||||
|
||||
} else if ( type === 'space' || type === 'small-space' ) {
|
||||
current.push(val.v);
|
||||
|
||||
} else if ( this.displayAction(val.v) )
|
||||
current.push(val);
|
||||
}
|
||||
|
@ -593,6 +608,14 @@ export default {
|
|||
this.add_pasting = false;
|
||||
},
|
||||
|
||||
preparePaste() {
|
||||
this.add_open = true;
|
||||
this.add_pasting = true;
|
||||
requestAnimationFrame(() => {
|
||||
this.$refs.paste.focus()
|
||||
});
|
||||
},
|
||||
|
||||
addFromJSON() {
|
||||
let value = this.$refs.paste.value;
|
||||
this.closeAdd();
|
||||
|
|
|
@ -662,6 +662,7 @@ export default class ChatHook extends Module {
|
|||
|
||||
const width = this.chat.context.get('chat.width'),
|
||||
action_size = this.chat.context.get('chat.actions.size'),
|
||||
ts_size = this.chat.context.get('chat.timestamp-size'),
|
||||
size = this.chat.context.get('chat.font-size'),
|
||||
emote_alignment = this.chat.context.get('chat.lines.emote-alignment'),
|
||||
lh = Math.round((20/12) * size);
|
||||
|
@ -670,6 +671,11 @@ export default class ChatHook extends Module {
|
|||
if ( font.indexOf(' ') !== -1 && font.indexOf(',') === -1 && font.indexOf('"') === -1 && font.indexOf("'") === -1 )
|
||||
font = `"${font}"`;
|
||||
|
||||
if ( ts_size )
|
||||
this.css_tweaks.set('ts-size', `.chat-line__timestamp{font-size:${ts_size/10}rem}`);
|
||||
else
|
||||
this.css_tweaks.delete('ts-size');
|
||||
|
||||
this.css_tweaks.setVariable('chat-actions-size', `${action_size/10}rem`);
|
||||
this.css_tweaks.setVariable('chat-font-size', `${size/10}rem`);
|
||||
this.css_tweaks.setVariable('chat-line-height', `${lh/10}rem`);
|
||||
|
@ -796,6 +802,7 @@ export default class ChatHook extends Module {
|
|||
this.settings.main_context.on('changed:chat.use-width', this.updateChatCSS, this);
|
||||
this.chat.context.on('changed:chat.actions.size', this.updateChatCSS, this);
|
||||
this.chat.context.on('changed:chat.font-size', this.updateChatCSS, this);
|
||||
this.chat.context.on('changed:chat.timestamp-size', this.updateChatCSS, this);
|
||||
this.chat.context.on('changed:chat.font-family', this.updateChatCSS, this);
|
||||
this.chat.context.on('changed:chat.lines.emote-alignment', this.updateChatCSS, this);
|
||||
this.chat.context.on('changed:chat.adjustment-mode', this.updateColors, this);
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
}
|
||||
|
||||
.clmgr-table__row,
|
||||
.sunlight-expanded-nav-drop-down-menu-layout__scrollable-area,
|
||||
.stream-manager--page-view .mosaic-window-body,
|
||||
.ach-card,
|
||||
.ach-card--expanded .ach-card__inner,
|
||||
.room-upsell,
|
||||
.chat-room,
|
||||
.qa-vod-chat,
|
||||
|
@ -59,6 +62,18 @@
|
|||
background-color: var(--ffz-color-accent-8) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ach-q-card {
|
||||
box-shadow: 0 0 0 1px var(--color-border-button) !important;
|
||||
}
|
||||
|
||||
.ach-link:active .ach-card, .ach-link:focus .ach-card {
|
||||
outline: .5rem auto var(--color-border-input-focus) !important;
|
||||
}
|
||||
|
||||
.ach-card--expanded .ach-card__inner {
|
||||
border-color: var(--color-border-brand) !important;
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
|
|
|
@ -70,7 +70,12 @@ export default class Switchboard extends Module {
|
|||
this.location = router.props.location.pathname;
|
||||
//const location = router.props.location.pathname;
|
||||
|
||||
this.loadOne();
|
||||
this.web_munch.waitForLoader().then(() => {
|
||||
if ( this.web_munch._require )
|
||||
return;
|
||||
|
||||
this.loadOne();
|
||||
});
|
||||
}
|
||||
|
||||
loadOne() {
|
||||
|
|
|
@ -11,7 +11,8 @@ import { DEBUG } from '../constants';
|
|||
|
||||
const NAMES = [
|
||||
'webpackJsonp',
|
||||
'webpackChunktwitch_twilight'
|
||||
'webpackChunktwitch_twilight',
|
||||
'webpackChunktwitch_sunlight'
|
||||
];
|
||||
|
||||
const HARD_MODULES = [
|
||||
|
@ -46,6 +47,23 @@ export default class WebMunch extends Module {
|
|||
// Loaded Modules
|
||||
// ========================================================================
|
||||
|
||||
waitForLoader() {
|
||||
if ( this._original_loader )
|
||||
return Promise.resolve();
|
||||
|
||||
const waiters = this._load_waiters = this._load_waiters || [];
|
||||
return new Promise((s,f) => waiters.push([s,f]));
|
||||
}
|
||||
|
||||
_resolveLoadWait(errored) {
|
||||
const waiters = this._load_waiters;
|
||||
this._load_waiters = null;
|
||||
|
||||
if ( waiters )
|
||||
for(const pair of waiters)
|
||||
pair[errored ? 1 : 0]();
|
||||
}
|
||||
|
||||
hookLoader(attempts = 0) {
|
||||
if ( this._original_loader )
|
||||
return this.log.warn('Attempted to call hookLoader twice.');
|
||||
|
@ -58,8 +76,11 @@ export default class WebMunch extends Module {
|
|||
}
|
||||
|
||||
if ( ! name ) {
|
||||
if ( attempts > 500 )
|
||||
return this.log.error("Unable to find webpack's loader after two minutes.");
|
||||
if ( attempts > 240 ) {
|
||||
this.log.error("Unable to find webpack's loader after one minute.");
|
||||
this._resolveLoadWait(true);
|
||||
return;
|
||||
}
|
||||
|
||||
return setTimeout(this.hookLoader.bind(this, attempts + 1), 250);
|
||||
}
|
||||
|
@ -75,6 +96,7 @@ export default class WebMunch extends Module {
|
|||
window[name] = this.webpackJsonpv3.bind(this);
|
||||
} catch(err) {
|
||||
this.log.warn('Unable to wrap webpackJsonp due to write protection.');
|
||||
this._resolveLoadWait(true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -93,14 +115,17 @@ export default class WebMunch extends Module {
|
|||
thing.push = this.webpackJsonpv4.bind(this);
|
||||
} catch(err) {
|
||||
this.log.warn('Unable to wrap webpackJsonp (v4) due to write protection.');
|
||||
this._resolveLoadWait(true);
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
this.log.error('webpackJsonp is of an unknown value. Unable to wrap.');
|
||||
this._resolveLoadWait(true);
|
||||
return;
|
||||
}
|
||||
|
||||
this._resolveLoadWait();
|
||||
this.log.info(`Found and wrapped webpack's loader after ${(attempts||0)*250}ms.`);
|
||||
}
|
||||
|
||||
|
|
|
@ -315,6 +315,13 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.ffz--room-actions {
|
||||
.chat-input__buttons-container &.tw-flex-column {
|
||||
margin-top: -1rem;
|
||||
margin-bottom: -1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ffz--modifier-actions {
|
||||
position: absolute;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue