1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00

Add info and question icons. Bump version to beta1.7. Add chat badge visibility. Add support for setting inheritance merge strategies.

This commit is contained in:
SirStendec 2018-03-22 22:39:27 -04:00
parent 19c81bb049
commit cc682230e2
16 changed files with 222 additions and 51 deletions

View file

@ -1,3 +1,13 @@
<div class="list-header">4.0.0-beta1.7<span>@a50bda0e204137eb8f28</span> <time datetime="2018-03-22">(2018-03-22)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Chat Badge Visibility. Hide the badges you don't like.</li>
</ul>
<div class="list-header">4.0.0-beta1.7<span>@18be0a772c267953f6e3</span> <time datetime="2018-03-22">(2018-03-22)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Changed: Settings will now open in a new window when accessed from a chat pop-out.</li>
</ul>
<div class="list-header">4.0.0-beta1.6<span>@d2469b218214357ed0c0</span> <time datetime="2018-03-21">(2018-03-21)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Settings are now properly and immediately synchronized across all open windows.</li>

Binary file not shown.

View file

@ -60,6 +60,10 @@
<glyph glyph-name="pencil" unicode="&#xe81a;" d="M203-7l50 51-131 131-51-51v-60h72v-71h60z m291 518q0 12-12 12-5 0-9-4l-303-302q-4-4-4-10 0-12 13-12 5 0 9 4l303 302q3 4 3 10z m-30 107l232-232-464-465h-232v233z m381-54q0-29-20-50l-93-93-232 233 93 92q20 21 50 21 29 0 51-21l131-131q20-22 20-51z" horiz-adv-x="857.1" />
<glyph glyph-name="info" unicode="&#xe81b;" d="M571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
<glyph glyph-name="help" unicode="&#xe81c;" d="M500 82v107q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-107q0-8 5-13t13-5h107q8 0 13 5t5 13z m143 375q0 49-31 91t-77 65-95 23q-136 0-207-119-9-13 4-24l74-55q4-4 10-4 9 0 14 7 30 38 48 51 19 14 48 14 27 0 48-15t21-33q0-21-11-34t-38-25q-35-15-65-48t-29-70v-20q0-8 5-13t13-5h107q8 0 13 5t5 13q0 10 12 27t30 28q18 10 28 16t25 19 25 27 16 34 7 45z m214-107q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
<glyph glyph-name="twitter" unicode="&#xf099;" d="M904 622q-37-54-90-93 0-8 0-23 0-73-21-145t-64-139-103-117-144-82-181-30q-151 0-276 81 19-2 43-2 126 0 224 77-59 1-105 36t-64 89q19-3 34-3 24 0 48 6-63 13-104 62t-41 115v2q38-21 82-23-37 25-59 64t-22 86q0 49 25 91 68-83 164-133t208-55q-5 21-5 41 0 75 53 127t127 53q79 0 132-57 61 12 115 44-21-64-80-100 52 6 104 28z" horiz-adv-x="928.6" />
<glyph glyph-name="gauge" unicode="&#xf0e4;" d="M214 207q0 30-21 51t-50 21-51-21-21-51 21-50 51-21 50 21 21 50z m107 250q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m239-268l57 213q3 14-5 27t-21 16-27-3-17-22l-56-213q-33-3-60-25t-35-55q-11-43 11-81t66-50 81 11 50 66q9 33-4 65t-40 51z m369 18q0 30-21 51t-51 21-50-21-21-51 21-50 50-21 51 21 21 50z m-358 357q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m250-107q0 30-20 51t-51 21-50-21-21-51 21-50 50-21 51 21 20 50z m179-250q0-145-79-269-10-17-30-17h-782q-20 0-30 17-79 123-79 269 0 102 40 194t106 160 160 107 194 39 194-39 160-107 106-160 40-194z" horiz-adv-x="1000" />
@ -74,7 +78,7 @@
<glyph glyph-name="twitch" unicode="&#xf1e8;" d="M500 608v-242h-81v242h81z m222 0v-242h-81v242h81z m0-424l141 141v444h-666v-585h182v-121l121 121h222z m222 666v-565l-242-242h-182l-121-122h-121v122h-222v646l61 161h827z" horiz-adv-x="1000" />
<glyph glyph-name="bell-off-empty" unicode="&#xf1f7;" d="M580-96q0 8-9 8-32 0-56 24t-24 57q0 9-9 9t-9-9q0-41 29-70t69-28q9 0 9 9z m-299 265l489 424q-23 49-74 82t-125 32q-51 0-94-17t-68-45-38-58-14-58q0-215-76-360z m755-105q0-29-21-50t-51-21h-250q0-59-42-101t-101-42-100 42-42 100l83 72h422q-92 105-126 256l61 55q35-199 167-311z m48 777l47-53q4-6 4-14t-6-12l-1045-905q-5-5-13-4t-12 6l-47 53q-4 6-4 14t6 12l104 90q-11 17-11 36 28 24 51 49t47 67 42 89 28 115 11 145q0 84 65 157t171 89q-4 10-4 21 0 23 16 38t37 16 38-16 16-38q0-11-4-21 69-10 122-46t82-88l234 202q5 5 13 4t12-6z" horiz-adv-x="1142.9" />
<glyph glyph-name="bell-off" unicode="&#xf1f7;" d="M580-96q0 8-9 8-32 0-56 24t-24 57q0 9-9 9t-9-9q0-41 29-70t69-28q9 0 9 9z m-299 265l489 424q-23 49-74 82t-125 32q-51 0-94-17t-68-45-38-58-14-58q0-215-76-360z m755-105q0-29-21-50t-51-21h-250q0-59-42-101t-101-42-100 42-42 100l83 72h422q-92 105-126 256l61 55q35-199 167-311z m48 777l47-53q4-6 4-14t-6-12l-1045-905q-5-5-13-4t-12 6l-47 53q-4 6-4 14t6 12l104 90q-11 17-11 36 28 24 51 49t47 67 42 89 28 115 11 145q0 84 65 157t171 89q-4 10-4 21 0 23 16 38t37 16 38-16 16-38q0-11-4-21 69-10 122-46t82-88l234 202q5 5 13 4t12-6z" horiz-adv-x="1142.9" />
<glyph glyph-name="trash" unicode="&#xf1f8;" d="M286 82v393q0 8-5 13t-13 5h-36q-8 0-13-5t-5-13v-393q0-8 5-13t13-5h36q8 0 13 5t5 13z m143 0v393q0 8-5 13t-13 5h-36q-8 0-13-5t-5-13v-393q0-8 5-13t13-5h36q8 0 13 5t5 13z m142 0v393q0 8-5 13t-12 5h-36q-8 0-13-5t-5-13v-393q0-8 5-13t13-5h36q7 0 12 5t5 13z m-303 554h250l-27 65q-4 5-9 6h-177q-6-1-10-6z m518-18v-36q0-8-5-13t-13-5h-54v-529q0-46-26-80t-63-34h-464q-37 0-63 33t-27 79v531h-53q-8 0-13 5t-5 13v36q0 8 5 13t13 5h172l39 93q9 21 31 35t44 15h178q23 0 44-15t30-35l39-93h173q8 0 13-5t5-13z" horiz-adv-x="785.7" />

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -95,7 +95,7 @@ class FrankerFaceZ extends Module {
FrankerFaceZ.Logger = Logger;
const VER = FrankerFaceZ.version_info = {
major: 4, minor: 0, revision: 0, extra: '-beta1.6',
major: 4, minor: 0, revision: 0, extra: '-beta1.7',
build: __webpack_hash__,
toString: () =>
`${VER.major}.${VER.minor}.${VER.revision}${VER.extra || ''}${DEBUG ? '-dev' : ''}`

View file

@ -147,8 +147,9 @@ export default class Badges extends Module {
this.twitch_badges = {};
this.settings.add('chat.badges.hidden', {
default: [],
_ui: {
default: {},
type: 'object_merge',
ui: {
path: 'Chat > Badges >> tabs ~> Visibility',
component: 'badge-visibility',
data: () => {
@ -297,7 +298,7 @@ export default class Badges extends Module {
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'),
custom_mod = this.parent.context.get('chat.badges.custom-mod'),
is_mask = badge_style > 5,
@ -324,7 +325,7 @@ export default class Badges extends Module {
const version = twitch_badges[badge_id],
is_game = badge_id.endsWith('_1');
if ( hidden_badges.includes(badge_id) || (is_game && hidden_badges.includes('game')) )
if ( hidden_badges[badge_id] || (is_game && hidden_badges.game) )
continue;
if ( has(BADGE_POSITIONS, badge_id) )
@ -365,7 +366,7 @@ export default class Badges extends Module {
for(const badge of badges)
if ( badge && badge.id ) {
if ( hidden_badges.includes(badge.id) )
if ( hidden_badges[badge.id] )
continue;
const full_badge = this.badges[badge.id],

View file

@ -1,14 +1,38 @@
<template lang="html">
<div class="ffz--badge-visibility tw-pd-t-05">
<div
class="tw-c-background-accent tw-c-text-overlay tw-pd-1 tw-mg-b-1"
v-if="source && source !== profile"
>
<span class="ffz-i-info" />
{{ t('setting.badge-inheritence', 'These values are being overridden by another profile and may not take effect.') }}
</div>
<div class="tw-mg-b-2 tw-align-right">
<button
class="tw-mg-l-05 tw-button tw-button--hollow tw-tooltip-wrapper"
@click="clear"
:disabled="! has_value"
>
<span class="tw-button__icon tw-button__icon--left">
<figure class="ffz-i-cancel" />
</span>
<span class="tw-button__text">
{{ t('setting.reset-all', 'Reset All to Default') }}
</span>
</button>
</div>
<section class="ffz--menu-container tw-border-t" v-for="sec in data">
<header>{{ sec.title }}</header>
<ul class="tw-flex tw-flex-wrap tw-align-content-start">
<li v-for="i in sort(sec.badges)" class="ffz--badge-info tw-pd-y-1 tw-pd-r-1 tw-flex" :class="{default: isDefault}">
<li v-for="i in sort(sec.badges)" class="ffz--badge-info tw-pd-y-1 tw-pd-r-1 tw-flex" :class="{default: badgeDefault(i.id)}">
<input
type="checkbox"
class="tw-checkbox__input"
checked="checked"
:checked="badgeChecked(i.id)"
:id="i.id"
@click="onChange(i.id, $event)"
>
<label class="tw-checkbox__label tw-flex" :for="i.id">
@ -18,12 +42,16 @@
<section class="tw-mg-t-05" v-if="i.versions && i.versions.length > 1">
<span v-for="v in i.versions" data-tooltip-type="html" class="ffz-badge ffz-tooltip" :title="v.name" :style="{backgroundColor: i.color, backgroundImage: v.styleImage}" />
</section>
<!--button class="tw-mg-t-05 tw-button tw-button--hollow tw-tooltip-wrapper">
<button
class="tw-mg-t-05 tw-button tw-button--hollow tw-tooltip-wrapper"
@click="reset(i.id)"
v-if="! badgeDefault(i.id)"
>
<span class="tw-button__text">Reset</span>
<span class="tw-tooltip tw-tooltip--down tw-tooltip--align-right">
{{ t('setting.reset', 'Reset to Default') }}
</span>
</button-->
</button>
</div>
</label>
</li>
@ -35,12 +63,38 @@
<script>
import SettingMixin from '../setting-mixin';
import {has} from 'utilities/object';
export default {
mixins: [SettingMixin],
props: ['item', 'context'],
methods: {
badgeChecked(id) {
return ! this.value[id];
},
badgeDefault(id) {
return ! has(this.value, id);
},
onChange(id, event) {
const control = event.target,
new_val = {[id]: ! control.checked};
this.set(Object.assign({}, this.value, new_val));
},
reset(id) {
const val = Object.assign({}, this.value);
delete val[id];
if ( ! Object.keys(val).length )
this.clear();
else
this.set(val);
},
sort(items) {
return items.sort((a, b) => {
const an = a.name.toLowerCase(),
@ -50,36 +104,8 @@ export default {
if ( an > bn ) return 1;
return 0;
});
},
onChange() {
this.set(this.$refs.control.checked);
}
}
}
</script>
<style lang="scss" scoped>
.ffz--badge-info {
&.default {
label:before, label:after {
opacity: 0.5
}
}
.tw-checkbox__input:checked+.tw-checkbox__label:after,
label:before, label:after {
top: 1.05rem;
}
.ffz-badge.preview-image {
width: 7.2rem;
height: 7.2rem;
background-size: 7.2rem;
background-repeat: no-repeat;
}
width: 30rem;
}
</style>
</script>

View file

@ -1,5 +1,7 @@
'use strict';
import {deep_copy} from 'utilities/object';
export default {
data() {
return {
@ -65,7 +67,7 @@ export default {
if ( typeof this.item.default === 'function' )
return this.item.default(this.context.context);
return this.item.default;
return deep_copy(this.item.default);
},
isInherited() {
@ -119,7 +121,7 @@ export default {
this.has_value = profile.has(setting);
this.value = this.has_value ?
profile.get(setting) :
deep_copy(profile.get(setting)) :
this.isInherited ?
this.source_value :
this.default_value;
@ -131,7 +133,7 @@ export default {
this.has_value = deleted !== true;
this.value = this.has_value ?
value :
deep_copy(value) :
this.isInherited ?
this.source_value :
this.default_value;
@ -141,7 +143,7 @@ export default {
if ( key !== this.item.setting )
return;
this.source_value = value;
this.source_value = deep_copy(value);
if ( this.isInherited )
this.value = deleted ? this.default_value : value;
},
@ -150,12 +152,15 @@ export default {
if ( this.source )
this.source.off('changed', this._source_setting_changed, this);
// We primarily only care about the main source.
uses = uses ? uses[0] : null;
const source = this.source = this.context.profile_keys[uses],
setting = this.item.setting;
if ( source ) {
source.on('changed', this._source_setting_changed, this);
this.source_value = source.get(setting);
this.source_value = deep_copy(source.get(setting));
} else
this.source_value = undefined;

View file

@ -7,6 +7,8 @@
import {EventEmitter} from 'utilities/events';
import {has, get as getter, array_equals} from 'utilities/object';
import * as DEFINITIONS from './types';
/**
* The SettingsContext class provides a context through which to read
@ -128,7 +130,7 @@ export default class SettingsContext extends EventEmitter {
this.emit(`changed:${key}`, new_value, old_value);
}
if ( new_uses !== old_uses ) {
if ( ! array_equals(new_uses, old_uses) ) {
this.emit('uses_changed', key, new_uses, old_uses);
this.emit(`uses_changed:${key}`, new_uses, old_uses);
}
@ -190,7 +192,7 @@ export default class SettingsContext extends EventEmitter {
old_uses = old_meta ? old_meta.uses : null,
new_uses = new_meta ? new_meta.uses : null;
if ( old_uses !== new_uses ) {
if ( ! array_equals(new_uses, old_uses) ) {
this.emit('uses_changed', key, new_uses, old_uses);
this.emit(`uses_changed:${key}`, new_uses, old_uses);
}
@ -216,9 +218,15 @@ export default class SettingsContext extends EventEmitter {
visited.push(key);
const definition = this.manager.definitions.get(key),
raw_value = this._getRaw(key),
raw_type = definition && definition.type,
type = raw_type ? DEFINITIONS[raw_type] : DEFINITIONS.basic;
if ( ! type )
throw new Error(`non-existent setting type "${raw_type}"`);
const raw_value = this._getRaw(key, type),
meta = {
uses: raw_value ? raw_value[1].id : null
uses: raw_value ? raw_value[1] : null
};
let value = raw_value ? raw_value[0] : undefined;
@ -250,11 +258,22 @@ export default class SettingsContext extends EventEmitter {
}
_getRaw(key) {
*profiles() {
for(const profile of this.__profiles)
yield profile;
}
_getRaw(key, type) {
if ( ! type )
throw new Error(`non-existent `)
return type.get(key, this.profiles(), this.manager.log);
}
/* for(const profile of this.__profiles)
if ( profile.has(key) )
return [profile.get(key), profile]
}
}*/
// ========================================================================

81
src/settings/types.js Normal file
View file

@ -0,0 +1,81 @@
'use strict';
// ============================================================================
// Settings Types
// ============================================================================
export const basic = {
get(key, profiles) {
for(const profile of profiles)
if ( profile.has(key) )
return [
profile.get(key),
[profile.id]
]
}
}
export const object_merge = {
get(key, profiles, log) {
const values = [],
sources = [];
for(const profile of profiles)
if ( profile.has(key) ) {
const val = profile.get(key);
if ( typeof val !== 'object' ) {
log.warn(`Profile #${profile.id} has an invalid value for "${key}" of type ${typeof val}. Skipping.`);
continue;
}
sources.push(profile.id);
values.unshift(val);
}
if ( values.length )
return [
Object.assign({}, ...values),
sources
]
}
}
export const array_merge = {
get(key, profiles, log) {
const values = [],
trailing = [],
sources = [];
for(const profile of profiles)
if ( profile.has(key) ) {
const value = profile.get(key);
if ( ! Array.isArray(value) ) {
log.warn(`Profile #${profile.id} has an invalid value for "${key}" of type ${typeof value}. Skipping.`);
continue;
}
sources.push(profile.id);
let is_trailing = false;
for(const val of value) {
if ( val.t === 'inherit' )
is_trailing = true;
else if ( is_trailing )
trailing.unshift(val.v);
else
values.push(val.v);
}
// If we didn't run into an inherit, don't inherit.
if ( ! is_trailing )
break;
}
if ( values.length || trailing.length )
return [
values.concat(trailing),
sources
]
}
}

View file

@ -40,6 +40,7 @@ export default class ChatLine extends Module {
onEnable() {
this.chat.context.on('changed:chat.bits.stack', this.updateLines, this);
this.chat.context.on('changed:chat.badges.style', this.updateLines, this);
this.chat.context.on('changed:chat.badges.hidden', this.updateLines, this);
this.chat.context.on('changed:chat.badges.custom-mod', this.updateLines, this);
this.chat.context.on('changed:chat.rituals.show', this.updateLines, this);

View file

@ -107,6 +107,8 @@
.ffz-i-thumbs-down:before { content: '\e818'; } /* '' */
.ffz-i-bell:before { content: '\e819'; } /* '' */
.ffz-i-pencil:before { content: '\e81a'; } /* '' */
.ffz-i-info:before { content: '\e81b'; } /* '' */
.ffz-i-help:before { content: '\e81c'; } /* '' */
.ffz-i-twitter:before { content: '\f099'; } /* '' */
.ffz-i-gauge:before { content: '\f0e4'; } /* '' */
.ffz-i-download-cloud:before { content: '\f0ed'; } /* '' */

View file

@ -5,6 +5,7 @@
@import "./widgets/menu-tree.scss";
@import "./widgets/profile-selector.scss";
@import "./widgets/badge-visibility.scss";
.tw-display-inline { display: inline !important }

View file

@ -0,0 +1,21 @@
.ffz--badge-info {
&.default {
label:before, label:after {
opacity: 0.5
}
}
.tw-checkbox__input:checked+.tw-checkbox__label:after,
label:before, label:after {
top: 1.05rem;
}
.ffz-badge.preview-image {
width: 7.2rem;
height: 7.2rem;
background-size: 7.2rem;
background-repeat: no-repeat;
}
width: 30rem;
}