1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 05:15:54 +00:00
* 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:
SirStendec 2021-03-02 19:50:25 -05:00
parent 9086230686
commit add9f7a7d5
11 changed files with 212 additions and 24 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"author": "Dan Salvato LLC", "author": "Dan Salvato LLC",
"version": "4.20.72", "version": "4.20.73",
"description": "FrankerFaceZ is a Twitch enhancement suite.", "description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {

View 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>

View file

@ -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."}', path: 'Chat > Actions > Room @{"description": "Here, you can define custom actions that will appear above the chat input box."}',
component: 'chat-actions', component: 'chat-actions',
context: ['room', 'room-mode'], context: ['room', 'room-mode'],
inline: true, inline: false,
data: () => { data: () => {
const chat = this.resolve('site.chat'); 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) { renderRoom(mod_icons, current_user, current_room, is_above, createElement) {
const actions = [], const lines = [],
chat = this.resolve('site.chat'); chat = this.resolve('site.chat');
let line = null;
for(const data of this.parent.context.get('chat.actions.room')) { 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; continue;
let ap = data.appearance || {}; 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), color = has_color && (chat && chat.colors ? chat.colors.process(ap.color) : ap.color),
contents = def.render.call(this, ap, createElement, 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' : ''}`} 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-tooltip-type="action"
data-action={data.action} data-action={data.action}
@ -473,13 +503,18 @@ export default class Actions extends Module {
</button>); </button>);
} }
if ( ! actions.length ) if ( ! lines.length )
return null; 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 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} data-room={room}
> >
{actions} {actions}

View file

@ -91,3 +91,29 @@ export const image = {
return <figure class="mod-icon__image"><img src={data.image} /></figure>; 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>;
}
}*/

View file

@ -98,6 +98,23 @@ export default class Chat extends Module {
force_seen: true 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', { this.settings.add('chat.font-size', {
default: 13, default: 13,
ui: { ui: {
@ -108,7 +125,7 @@ export default class Chat extends Module {
process(val) { process(val) {
val = parseInt(val, 10); val = parseInt(val, 10);
if ( isNaN(val) || ! isFinite(val) || val <= 0 ) if ( isNaN(val) || ! isFinite(val) || val <= 0 )
return 12; return 13;
return val; return val;
} }

View file

@ -193,15 +193,27 @@
:key="idx" :key="idx"
class="tw-flex tw-align-items-center tw-justify-content-center" class="tw-flex tw-align-items-center tw-justify-content-center"
> >
<action-preview <template v-for="act in actions">
v-for="act in actions" <div
:key="act.id" v-if="act.type === 'space'"
:act="act.v" :key="act.id"
:color="color(act.v.appearance.color)" class="tw-flex-grow-1"
:renderers="data.renderers" />
tooltip="true" <div
pad="true" 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> </div>
</div> </div>
@ -254,7 +266,7 @@
<div v-else class="tw-pd-y-1"> <div v-else class="tw-pd-y-1">
<button <button
class="ffz-interactable ffz-interactable--hover-enabled ffz-interactable--default tw-interactive tw-full-width" 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 tw-align-items-center tw-pd-y-05 tw-pd-x-1">
<div class="tw-flex-grow-1 tw-mg-r-1"> <div class="tw-flex-grow-1 tw-mg-r-1">
@ -532,6 +544,9 @@ export default {
out.push(current); out.push(current);
current = []; current = [];
} else if ( type === 'space' || type === 'small-space' ) {
current.push(val.v);
} else if ( this.displayAction(val.v) ) } else if ( this.displayAction(val.v) )
current.push(val); current.push(val);
} }
@ -593,6 +608,14 @@ export default {
this.add_pasting = false; this.add_pasting = false;
}, },
preparePaste() {
this.add_open = true;
this.add_pasting = true;
requestAnimationFrame(() => {
this.$refs.paste.focus()
});
},
addFromJSON() { addFromJSON() {
let value = this.$refs.paste.value; let value = this.$refs.paste.value;
this.closeAdd(); this.closeAdd();

View file

@ -662,6 +662,7 @@ export default class ChatHook extends Module {
const width = this.chat.context.get('chat.width'), const width = this.chat.context.get('chat.width'),
action_size = this.chat.context.get('chat.actions.size'), 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'), size = this.chat.context.get('chat.font-size'),
emote_alignment = this.chat.context.get('chat.lines.emote-alignment'), emote_alignment = this.chat.context.get('chat.lines.emote-alignment'),
lh = Math.round((20/12) * size); 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 ) if ( font.indexOf(' ') !== -1 && font.indexOf(',') === -1 && font.indexOf('"') === -1 && font.indexOf("'") === -1 )
font = `"${font}"`; 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-actions-size', `${action_size/10}rem`);
this.css_tweaks.setVariable('chat-font-size', `${size/10}rem`); this.css_tweaks.setVariable('chat-font-size', `${size/10}rem`);
this.css_tweaks.setVariable('chat-line-height', `${lh/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.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.actions.size', this.updateChatCSS, this);
this.chat.context.on('changed:chat.font-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.font-family', this.updateChatCSS, this);
this.chat.context.on('changed:chat.lines.emote-alignment', 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); this.chat.context.on('changed:chat.adjustment-mode', this.updateColors, this);

View file

@ -10,7 +10,10 @@
} }
.clmgr-table__row, .clmgr-table__row,
.sunlight-expanded-nav-drop-down-menu-layout__scrollable-area,
.stream-manager--page-view .mosaic-window-body, .stream-manager--page-view .mosaic-window-body,
.ach-card,
.ach-card--expanded .ach-card__inner,
.room-upsell, .room-upsell,
.chat-room, .chat-room,
.qa-vod-chat, .qa-vod-chat,
@ -59,6 +62,18 @@
background-color: var(--ffz-color-accent-8) !important; 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 { html {

View file

@ -70,7 +70,12 @@ export default class Switchboard extends Module {
this.location = router.props.location.pathname; this.location = router.props.location.pathname;
//const 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() { loadOne() {

View file

@ -11,7 +11,8 @@ import { DEBUG } from '../constants';
const NAMES = [ const NAMES = [
'webpackJsonp', 'webpackJsonp',
'webpackChunktwitch_twilight' 'webpackChunktwitch_twilight',
'webpackChunktwitch_sunlight'
]; ];
const HARD_MODULES = [ const HARD_MODULES = [
@ -46,6 +47,23 @@ export default class WebMunch extends Module {
// Loaded Modules // 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) { hookLoader(attempts = 0) {
if ( this._original_loader ) if ( this._original_loader )
return this.log.warn('Attempted to call hookLoader twice.'); return this.log.warn('Attempted to call hookLoader twice.');
@ -58,8 +76,11 @@ export default class WebMunch extends Module {
} }
if ( ! name ) { if ( ! name ) {
if ( attempts > 500 ) if ( attempts > 240 ) {
return this.log.error("Unable to find webpack's loader after two minutes."); 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); 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); window[name] = this.webpackJsonpv3.bind(this);
} catch(err) { } catch(err) {
this.log.warn('Unable to wrap webpackJsonp due to write protection.'); this.log.warn('Unable to wrap webpackJsonp due to write protection.');
this._resolveLoadWait(true);
return; return;
} }
@ -93,14 +115,17 @@ export default class WebMunch extends Module {
thing.push = this.webpackJsonpv4.bind(this); thing.push = this.webpackJsonpv4.bind(this);
} catch(err) { } catch(err) {
this.log.warn('Unable to wrap webpackJsonp (v4) due to write protection.'); this.log.warn('Unable to wrap webpackJsonp (v4) due to write protection.');
this._resolveLoadWait(true);
return; return;
} }
} else { } else {
this.log.error('webpackJsonp is of an unknown value. Unable to wrap.'); this.log.error('webpackJsonp is of an unknown value. Unable to wrap.');
this._resolveLoadWait(true);
return; return;
} }
this._resolveLoadWait();
this.log.info(`Found and wrapped webpack's loader after ${(attempts||0)*250}ms.`); this.log.info(`Found and wrapped webpack's loader after ${(attempts||0)*250}ms.`);
} }

View file

@ -315,6 +315,13 @@
position: relative; position: relative;
} }
.ffz--room-actions {
.chat-input__buttons-container &.tw-flex-column {
margin-top: -1rem;
margin-bottom: -1rem;
}
}
.ffz--modifier-actions { .ffz--modifier-actions {
position: absolute; position: absolute;