mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.20.89
* Added: Setting to display timestamps on additional types of chat messages. (Closes #983) * Changed: Do not set a Chat Width by default. * Changed: Have WebMunch dump a list of possible webpack bundle names when failing to find webpack. * Fixed: Appearance issues caused by Twitch's continual migration to procedural CSS class names, requiring duplicate CSS to achieve a native look. * Fixed: Ambiguous input field names in some FFZ Control Center widgets. (Closes #1017) * Fixed: Stop using Algolia for tag search.
This commit is contained in:
parent
fa33491eec
commit
ae90b8e4fe
35 changed files with 306 additions and 222 deletions
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "frankerfacez",
|
"name": "frankerfacez",
|
||||||
"author": "Dan Salvato LLC",
|
"author": "Dan Salvato LLC",
|
||||||
"version": "4.20.87",
|
"version": "4.20.89",
|
||||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template lang="html">
|
<template lang="html">
|
||||||
<div class="ffz--addon-info tw-elevation-1 tw-c-background-base tw-border tw-border-radius-large tw-pd-1 tw-mg-b-1 tw-flex tw-flex-nowrap">
|
<div class="ffz--addon-info tw-elevation-1 tw-c-background-base tw-border tw-border-radius-large tw-pd-1 tw-mg-b-1 tw-flex tw-flex-nowrap">
|
||||||
<div class="tw-flex tw-flex-column tw-align-center tw-flex-shrink-0 tw-mg-r-1">
|
<div class="tw-flex tw-flex-column tw-align-center tw-flex-shrink-0 tw-mg-r-1">
|
||||||
<div class="tw-card-img--size-6 tw-overflow-hidden tw-mg-b-1">
|
<div class="ffz-card-img--size-6 tw-overflow-hidden tw-mg-b-1">
|
||||||
<img :src="icon" class="tw-image">
|
<img :src="icon" class="tw-image">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -191,16 +191,18 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
const this_id = `badge-term$${id++}`;
|
||||||
|
|
||||||
if ( this.adding )
|
if ( this.adding )
|
||||||
return {
|
return {
|
||||||
id: id++,
|
id: this_id,
|
||||||
deleting: false,
|
deleting: false,
|
||||||
editing: true,
|
editing: true,
|
||||||
edit_data: deep_copy(this.term)
|
edit_data: deep_copy(this.term)
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: id++,
|
id: this_id,
|
||||||
deleting: false,
|
deleting: false,
|
||||||
editing: false,
|
editing: false,
|
||||||
edit_data: null
|
edit_data: null
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
:href="commit.author.html_url"
|
:href="commit.author.html_url"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="tw-inline-flex tw-align-items-center tw-link tw-link--inherit tw-mg-x-05 ffz-tooltip"
|
class="tw-inline-flex tw-align-items-center ffz-link ffz-link--inherit tw-mg-x-05 ffz-tooltip"
|
||||||
data-tooltip-type="link"
|
data-tooltip-type="link"
|
||||||
>
|
>
|
||||||
<figure
|
<figure
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
v-if="commit.hash"
|
v-if="commit.hash"
|
||||||
class="tw-font-size-8 tw-c-text-alt-2"
|
class="tw-font-size-8 tw-c-text-alt-2"
|
||||||
>
|
>
|
||||||
@<a :href="commit.link" target="_blank" rel="noopener noreferrer" class="tw-link tw-link--inherit ffz-tooltip" data-tooltip-type="link">{{ commit.hash }}</a>
|
@<a :href="commit.link" target="_blank" rel="noopener noreferrer" class="ffz-link ffz-link--inherit ffz-tooltip" data-tooltip-type="link">{{ commit.hash }}</a>
|
||||||
</div>
|
</div>
|
||||||
<time
|
<time
|
||||||
v-if="commit.date"
|
v-if="commit.date"
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<div class="tw-pd-x-1 tw-pd-y-05">
|
<div class="tw-pd-x-1 tw-pd-y-05">
|
||||||
<div class="tw-card tw-relative">
|
<div class="tw-card tw-relative">
|
||||||
<div class="tw-align-items-center tw-flex tw-flex-nowrap tw-flex-row">
|
<div class="tw-align-items-center tw-flex tw-flex-nowrap tw-flex-row">
|
||||||
<div class="tw-card-img tw-card-img--size-3 tw-flex-shrink-0 tw-overflow-hidden">
|
<div class="ffz-card-img ffz-card-img--size-3 tw-flex-shrink-0 tw-overflow-hidden">
|
||||||
<aspect :ratio="1/1.33">
|
<aspect :ratio="1/1.33">
|
||||||
<img
|
<img
|
||||||
:alt="slot.item.displayName"
|
:alt="slot.item.displayName"
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
<a
|
<a
|
||||||
v-if="can_link"
|
v-if="can_link"
|
||||||
:href="`/directory/game/${i}`"
|
:href="`/directory/game/${i}`"
|
||||||
class="tw-link"
|
class="ffz-link"
|
||||||
@click.prevent="handleLink(i)"
|
@click.prevent="handleLink(i)"
|
||||||
>
|
>
|
||||||
{{ i }}
|
{{ i }}
|
||||||
|
|
|
@ -70,14 +70,14 @@
|
||||||
:key="addon.key"
|
:key="addon.key"
|
||||||
class="tw-mg-b-05 tw-flex tw-align-items-center"
|
class="tw-mg-b-05 tw-flex tw-align-items-center"
|
||||||
>
|
>
|
||||||
<div class="tw-card-img--size-4 tw-overflow-hidden tw-mg-r-1">
|
<div class="ffz-card-img--size-4 tw-overflow-hidden tw-mg-r-1">
|
||||||
<img :src="addon.icon" class="tw-image">
|
<img :src="addon.icon" class="tw-image">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
v-if="addon.enabled && addon.settings"
|
v-if="addon.enabled && addon.settings"
|
||||||
href="#"
|
href="#"
|
||||||
class="tw-strong tw-link--inherit"
|
class="tw-strong ffz-link--inherit"
|
||||||
@click.prevent="item.requestPage(addon.settings)"
|
@click.prevent="item.requestPage(addon.settings)"
|
||||||
>
|
>
|
||||||
{{ addon.name_i18n ? t(addon.name_i18n, addon.name) : addon.name }}
|
{{ addon.name_i18n ? t(addon.name_i18n, addon.name) : addon.name }}
|
||||||
|
@ -114,14 +114,14 @@
|
||||||
:key="addon.key"
|
:key="addon.key"
|
||||||
class="tw-mg-b-05 tw-flex tw-align-items-center"
|
class="tw-mg-b-05 tw-flex tw-align-items-center"
|
||||||
>
|
>
|
||||||
<div class="tw-card-img--size-4 tw-overflow-hidden tw-mg-r-1">
|
<div class="ffz-card-img--size-4 tw-overflow-hidden tw-mg-r-1">
|
||||||
<img :src="addon.icon" class="tw-image">
|
<img :src="addon.icon" class="tw-image">
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a
|
<a
|
||||||
v-if="addon.enabled && addon.settings"
|
v-if="addon.enabled && addon.settings"
|
||||||
href="#"
|
href="#"
|
||||||
class="tw-strong tw-link--inherit"
|
class="tw-strong ffz-link--inherit"
|
||||||
@click.prevent="item.requestPage(addon.settings)"
|
@click.prevent="item.requestPage(addon.settings)"
|
||||||
>
|
>
|
||||||
{{ addon.name_i18n ? t(addon.name_i18n, addon.name) : addon.name }}
|
{{ addon.name_i18n ? t(addon.name_i18n, addon.name) : addon.name }}
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
<a
|
<a
|
||||||
v-if="version.commit"
|
v-if="version.commit"
|
||||||
:href="`https://www.github.com/FrankerFaceZ/FrankerFaceZ/commit/${version.commit}`"
|
:href="`https://www.github.com/FrankerFaceZ/FrankerFaceZ/commit/${version.commit}`"
|
||||||
class="tw-link tw-link--inherit"
|
class="ffz-link ffz-link--inherit"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
|
|
|
@ -262,16 +262,18 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
const this_id = `term$${id++}`;
|
||||||
|
|
||||||
if ( this.adding )
|
if ( this.adding )
|
||||||
return {
|
return {
|
||||||
id: id++,
|
id: this_id,
|
||||||
deleting: false,
|
deleting: false,
|
||||||
editing: true,
|
editing: true,
|
||||||
edit_data: deep_copy(this.term)
|
edit_data: deep_copy(this.term)
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: id++,
|
id: this_id,
|
||||||
deleting: false,
|
deleting: false,
|
||||||
editing: false,
|
editing: false,
|
||||||
edit_data: null
|
edit_data: null
|
||||||
|
|
|
@ -189,7 +189,7 @@ export default {
|
||||||
} else
|
} else
|
||||||
this.source_value = undefined;
|
this.source_value = undefined;
|
||||||
|
|
||||||
this.has_value = this.profile.has(this.item.setting);
|
this.has_value = this.profile && this.profile.has(this.item.setting);
|
||||||
if ( ! this.has_value )
|
if ( ! this.has_value )
|
||||||
this.value = this.isInherited ? this.source_value : this.default_value;
|
this.value = this.isInherited ? this.source_value : this.default_value;
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
:href="`/${login}`"
|
:href="`/${login}`"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="tw-interactive tw-link tw-link--hover-color-inherit tw-link--inherit"
|
class="tw-interactive ffz-link ffz-link--hover-color-inherit ffz-link--inherit"
|
||||||
>
|
>
|
||||||
{{ displayName }}
|
{{ displayName }}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{{ t(type.i18n, type.title) }}
|
{{ t(type.i18n, type.title) }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="ffz--search-avatar tw-mg-x-05 tw-card-img--size-2">
|
<div class="ffz--search-avatar tw-mg-x-05 ffz-card-img--size-2">
|
||||||
<aspect :ratio="1/1.33">
|
<aspect :ratio="1/1.33">
|
||||||
<img
|
<img
|
||||||
v-if="current"
|
v-if="current"
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
<div class="tw-pd-x-1 tw-pd-y-05">
|
<div class="tw-pd-x-1 tw-pd-y-05">
|
||||||
<div class="tw-card tw-relative">
|
<div class="tw-card tw-relative">
|
||||||
<div class="tw-align-items-center tw-flex tw-flex-nowrap tw-flex-row">
|
<div class="tw-align-items-center tw-flex tw-flex-nowrap tw-flex-row">
|
||||||
<div class="tw-card-img tw-card-img--size-3 tw-flex-shrink-0 tw-overflow-hidden">
|
<div class="ffz-card-img ffz-card-img--size-3 tw-flex-shrink-0 tw-overflow-hidden">
|
||||||
<aspect :ratio="1/1.33">
|
<aspect :ratio="1/1.33">
|
||||||
<img
|
<img
|
||||||
:alt="slot.item.displayName"
|
:alt="slot.item.displayName"
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
<div class="tw-pd-x-1 tw-pd-y-05">
|
<div class="tw-pd-x-1 tw-pd-y-05">
|
||||||
<div class="tw-card tw-relative">
|
<div class="tw-card tw-relative">
|
||||||
<div class="tw-align-items-center tw-flex tw-flex-nowrap tw-flex-row">
|
<div class="tw-align-items-center tw-flex tw-flex-nowrap tw-flex-row">
|
||||||
<div class="tw-card-img tw-card-img--size-3 tw-flex-shrink-0 tw-overflow-hidden">
|
<div class="ffz-card-img ffz-card-img--size-3 tw-flex-shrink-0 tw-overflow-hidden">
|
||||||
<aspect :ratio="1">
|
<aspect :ratio="1">
|
||||||
<img
|
<img
|
||||||
:alt="slot.item.displayName"
|
:alt="slot.item.displayName"
|
||||||
|
|
|
@ -89,7 +89,7 @@ export default class Line extends Module {
|
||||||
t.chat.badges.render(msg, createElement)
|
t.chat.badges.render(msg, createElement)
|
||||||
}</span>
|
}</span>
|
||||||
<a
|
<a
|
||||||
class="clip-chat__message-author tw-font-size-5 tw-link notranslate"
|
class="clip-chat__message-author tw-font-size-5 ffz-link notranslate"
|
||||||
href={`https://www.twitch.tv/${user.login}/clips`}
|
href={`https://www.twitch.tv/${user.login}/clips`}
|
||||||
style={{color}}
|
style={{color}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -199,7 +199,7 @@ export default class Channel extends Module {
|
||||||
if ( ! inst._ffz_tips ) {
|
if ( ! inst._ffz_tips ) {
|
||||||
const tt = this.resolve('tooltips');
|
const tt = this.resolve('tooltips');
|
||||||
if ( tt ) {
|
if ( tt ) {
|
||||||
inst._ffz_tips = tt._createInstance(el, 'tw-link', 'link', tt.getRoot());
|
inst._ffz_tips = tt._createInstance(el, 'ffz-link', 'link', tt.getRoot());
|
||||||
inst._ffz_tip_el = el;
|
inst._ffz_tip_el = el;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -440,7 +440,7 @@ export default class ChatHook extends Module {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.settings.add('chat.width', {
|
this.settings.add('chat.width', {
|
||||||
default: 340,
|
default: null,
|
||||||
ui: {
|
ui: {
|
||||||
path: 'Chat > Appearance >> General @{"sort": -1}',
|
path: 'Chat > Appearance >> General @{"sort": -1}',
|
||||||
title: 'Width',
|
title: 'Width',
|
||||||
|
@ -449,20 +449,28 @@ export default class ChatHook 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 340;
|
return null;
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.settings.add('chat.effective-width', {
|
||||||
|
requires: ['chat.width', 'context.ui.rightColumnWidth'],
|
||||||
|
process(ctx) {
|
||||||
|
const val = ctx.get('chat.width');
|
||||||
|
return val == null ? (ctx.get('context.ui.rightColumnWidth') || 340) : val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.settings.add('chat.use-width', {
|
this.settings.add('chat.use-width', {
|
||||||
requires: ['chat.width', 'context.ui.rightColumnExpanded', 'context.isWatchParty'],
|
requires: ['chat.width', 'context.ui.rightColumnExpanded', 'context.isWatchParty'],
|
||||||
process(ctx) {
|
process(ctx) {
|
||||||
if ( ! ctx.get('context.ui.rightColumnExpanded') || ctx.get('context.isWatchParty') )
|
if ( ! ctx.get('context.ui.rightColumnExpanded') || ctx.get('context.isWatchParty') )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ctx.get('chat.width') != 340;
|
return ctx.get('chat.width') != null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -511,6 +519,16 @@ export default class ChatHook extends Module {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.settings.add('chat.extra-timestamps', {
|
||||||
|
default: true,
|
||||||
|
ui: {
|
||||||
|
path: 'Chat > Appearance >> Chat Lines',
|
||||||
|
title: 'Display timestamps on notices.',
|
||||||
|
description: 'When enabled, timestamps will be displayed on point redemptions, subscriptions, etc.',
|
||||||
|
component: 'setting-check-box'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.settings.add('chat.subs.show', {
|
this.settings.add('chat.subs.show', {
|
||||||
default: 3,
|
default: 3,
|
||||||
ui: {
|
ui: {
|
||||||
|
@ -670,7 +688,7 @@ export default class ChatHook extends Module {
|
||||||
cancelAnimationFrame(this._update_css_waiter);
|
cancelAnimationFrame(this._update_css_waiter);
|
||||||
this._update_css_waiter = null;
|
this._update_css_waiter = null;
|
||||||
|
|
||||||
const width = this.chat.context.get('chat.width'),
|
const width = this.chat.context.get('chat.effective-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'),
|
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'),
|
||||||
|
@ -808,7 +826,7 @@ export default class ChatHook extends Module {
|
||||||
this.chat.context.on('changed:chat.banners.prediction', this.cleanHighlights, this);
|
this.chat.context.on('changed:chat.banners.prediction', this.cleanHighlights, this);
|
||||||
|
|
||||||
this.chat.context.on('changed:chat.subs.gift-banner', () => this.GiftBanner.forceUpdate(), this);
|
this.chat.context.on('changed:chat.subs.gift-banner', () => this.GiftBanner.forceUpdate(), this);
|
||||||
this.chat.context.on('changed:chat.width', this.updateChatCSS, this);
|
this.chat.context.on('changed:chat.effective-width', this.updateChatCSS, this);
|
||||||
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);
|
||||||
|
|
|
@ -527,7 +527,8 @@ other {# messages were deleted by a moderator.}
|
||||||
] : user_block)
|
] : user_block)
|
||||||
];
|
];
|
||||||
|
|
||||||
let cls = `chat-line__message${show_class ? ' ffz--deleted-message' : ''}${twitch_clickable ? ' tw-relative' : ''}`,
|
let extra_ts,
|
||||||
|
cls = `chat-line__message${show_class ? ' ffz--deleted-message' : ''}${twitch_clickable ? ' tw-relative' : ''}`,
|
||||||
out = (tokens.length || ! msg.ffz_type) ? [
|
out = (tokens.length || ! msg.ffz_type) ? [
|
||||||
(this.props.showTimestamps || this.props.isHistorical) && e('span', {
|
(this.props.showTimestamps || this.props.isHistorical) && e('span', {
|
||||||
className: 'chat-line__timestamp'
|
className: 'chat-line__timestamp'
|
||||||
|
@ -570,6 +571,9 @@ other {# messages were deleted by a moderator.}
|
||||||
}, JSON.stringify([tokens, msg.emotes], null, 2))*/
|
}, JSON.stringify([tokens, msg.emotes], null, 2))*/
|
||||||
] : null;
|
] : null;
|
||||||
|
|
||||||
|
if ( out == null )
|
||||||
|
extra_ts = t.chat.context.get('chat.extra-timestamps');
|
||||||
|
|
||||||
if ( msg.ffz_type === 'sub_mystery' ) {
|
if ( msg.ffz_type === 'sub_mystery' ) {
|
||||||
const mystery = msg.mystery;
|
const mystery = msg.mystery;
|
||||||
if ( mystery )
|
if ( mystery )
|
||||||
|
@ -640,6 +644,9 @@ other {# messages were deleted by a moderator.}
|
||||||
className: `ffz-i-star${msg.sub_anon ? '-empty' : ''} tw-mg-r-05`
|
className: `ffz-i-star${msg.sub_anon ? '-empty' : ''} tw-mg-r-05`
|
||||||
}),
|
}),
|
||||||
e('div', null, [
|
e('div', null, [
|
||||||
|
out ? null : extra_ts && (this.props.showTimestamps || this.props.isHistorical) && e('span', {
|
||||||
|
className: 'chat-line__timestamp'
|
||||||
|
}, t.chat.formatTime(msg.timestamp)),
|
||||||
(out || msg.sub_anon) ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
(out || msg.sub_anon) ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
||||||
sub_msg
|
sub_msg
|
||||||
]),
|
]),
|
||||||
|
@ -710,6 +717,9 @@ other {# messages were deleted by a moderator.}
|
||||||
className: 'ffz-i-star tw-mg-r-05'
|
className: 'ffz-i-star tw-mg-r-05'
|
||||||
}),
|
}),
|
||||||
e('div', null, [
|
e('div', null, [
|
||||||
|
out ? null : extra_ts && (this.props.showTimestamps || this.props.isHistorical) && e('span', {
|
||||||
|
className: 'chat-line__timestamp'
|
||||||
|
}, t.chat.formatTime(msg.timestamp)),
|
||||||
(out || msg.sub_anon) ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
(out || msg.sub_anon) ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
||||||
sub_msg
|
sub_msg
|
||||||
])
|
])
|
||||||
|
@ -772,6 +782,9 @@ other {# messages were deleted by a moderator.}
|
||||||
className: `ffz-i-${plan.prime ? 'crown' : 'star'} tw-mg-r-05`
|
className: `ffz-i-${plan.prime ? 'crown' : 'star'} tw-mg-r-05`
|
||||||
}),
|
}),
|
||||||
e('div', null, [
|
e('div', null, [
|
||||||
|
out ? null : extra_ts && (this.props.showTimestamps || this.props.isHistorical) && e('span', {
|
||||||
|
className: 'chat-line__timestamp'
|
||||||
|
}, t.chat.formatTime(msg.timestamp)),
|
||||||
out ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
out ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
||||||
sub_msg
|
sub_msg
|
||||||
])
|
])
|
||||||
|
@ -804,6 +817,9 @@ other {# messages were deleted by a moderator.}
|
||||||
if ( system_msg ) {
|
if ( system_msg ) {
|
||||||
cls = `ffz-notice-line user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--ritual-line${show_class ? ' ffz--deleted-message' : ''}${twitch_clickable ? ' tw-relative' : ''}`;
|
cls = `ffz-notice-line user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--ritual-line${show_class ? ' ffz--deleted-message' : ''}${twitch_clickable ? ' tw-relative' : ''}`;
|
||||||
out = [
|
out = [
|
||||||
|
out ? null : extra_ts && (this.props.showTimestamps || this.props.isHistorical) && e('span', {
|
||||||
|
className: 'chat-line__timestamp'
|
||||||
|
}, t.chat.formatTime(msg.timestamp)),
|
||||||
system_msg,
|
system_msg,
|
||||||
out && e('div', {
|
out && e('div', {
|
||||||
className: 'chat-line--inline chat-line__message',
|
className: 'chat-line--inline chat-line__message',
|
||||||
|
@ -825,6 +841,9 @@ other {# messages were deleted by a moderator.}
|
||||||
cls = `ffz-notice-line ffz--points-line tw-pd-l-1 tw-pd-y-05 tw-pd-r-2${ffz_highlight ? ' ffz-custom-color ffz--points-highlight' : ''}${show_class ? ' ffz--deleted-message' : ''}${twitch_clickable ? ' tw-relative' : ''}`;
|
cls = `ffz-notice-line ffz--points-line tw-pd-l-1 tw-pd-y-05 tw-pd-r-2${ffz_highlight ? ' ffz-custom-color ffz--points-highlight' : ''}${show_class ? ' ffz--deleted-message' : ''}${twitch_clickable ? ' tw-relative' : ''}`;
|
||||||
out = [
|
out = [
|
||||||
e('div', {className: 'tw-c-text-alt-2'}, [
|
e('div', {className: 'tw-c-text-alt-2'}, [
|
||||||
|
out ? null : extra_ts && (this.props.showTimestamps || this.props.isHistorical) && e('span', {
|
||||||
|
className: 'chat-line__timestamp'
|
||||||
|
}, t.chat.formatTime(msg.timestamp)),
|
||||||
out ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
out ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
|
||||||
out ?
|
out ?
|
||||||
t.i18n.tList('chat.points.redeemed', 'Redeemed {reward} {cost}', {reward, cost}) :
|
t.i18n.tList('chat.points.redeemed', 'Redeemed {reward} {cost}', {reward, cost}) :
|
||||||
|
|
|
@ -298,7 +298,7 @@ export default class SettingsMenu extends Module {
|
||||||
title: <span class="tw-strong">{this.i18n.t('chat.ffz-badge.title', 'FrankerFaceZ Badge')}</span>
|
title: <span class="tw-strong">{this.i18n.t('chat.ffz-badge.title', 'FrankerFaceZ Badge')}</span>
|
||||||
})}{' '}
|
})}{' '}
|
||||||
{this.i18n.tList('chat.ffz-badge.site', 'Please visit the {website} to change this badge.', {
|
{this.i18n.tList('chat.ffz-badge.site', 'Please visit the {website} to change this badge.', {
|
||||||
website: (<a href="https://www.frankerfacez.com/donate" class="tw-link" rel="noopener noreferrer" target="_blank">
|
website: (<a href="https://www.frankerfacez.com/donate" class="ffz-link" rel="noopener noreferrer" target="_blank">
|
||||||
{this.i18n.t('chat.ffz-badge.site-link', 'FrankerFaceZ website')}
|
{this.i18n.t('chat.ffz-badge.site-link', 'FrankerFaceZ website')}
|
||||||
</a>)
|
</a>)
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
width: calc(var(--ffz-chat-width) - 2rem) !important;
|
width: calc(var(--ffz-chat-width) - 2rem) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.channel-root {
|
||||||
|
width: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
body .whispers--theatre-mode.whispers--right-column-expanded-beside {
|
body .whispers--theatre-mode.whispers--right-column-expanded-beside {
|
||||||
right: var(--ffz-chat-width);
|
right: var(--ffz-chat-width);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,14 @@
|
||||||
.right-column {
|
.right-column {
|
||||||
order: 1;
|
order: 1;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|
||||||
|
#root &:not(.right-column--collapsed) {
|
||||||
|
width: var(--ffz-chat-width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel-root {
|
||||||
|
width: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sideNav .collapse-toggle {
|
#sideNav .collapse-toggle {
|
||||||
|
|
|
@ -267,11 +267,11 @@ export default class Directory extends SiteModule {
|
||||||
channel_url = `/${channel.login}`,
|
channel_url = `/${channel.login}`,
|
||||||
game_url = game && `/directory/game/${stream.game.name}`,
|
game_url = game && `/directory/game/${stream.game.name}`,
|
||||||
|
|
||||||
user_link = <a href={channel_url} data-href={channel_url} title={channel.displayName} class="tw-link tw-link--inherit" onClick={t.routeClick}>{channel.displayName}</a>,
|
user_link = <a href={channel_url} data-href={channel_url} title={channel.displayName} class="ffz-link ffz-link--inherit" onClick={t.routeClick}>{channel.displayName}</a>,
|
||||||
game_link = game && <a href={game_url} data-href={game_url} title={game.name} class="tw-link tw-link--inherit" onClick={t.routeClick}>{game.name}</a>;
|
game_link = game && <a href={game_url} data-href={game_url} title={game.name} class="ffz-link ffz-link--inherit" onClick={t.routeClick}>{game.name}</a>;
|
||||||
|
|
||||||
return (<div>
|
return (<div>
|
||||||
<a href={channel_url} data-href={channel_url} class="tw-link tw-link--inherit" data-test-selector="preview-card-titles__primary-link" onClick={t.routeClick}>
|
<a href={channel_url} data-href={channel_url} class="ffz-link ffz-link--inherit" data-test-selector="preview-card-titles__primary-link" onClick={t.routeClick}>
|
||||||
<h3 class="tw-ellipsis tw-font-size-5 tw-strong" title={stream.title}>{stream.title}</h3>
|
<h3 class="tw-ellipsis tw-font-size-5 tw-strong" title={stream.title}>{stream.title}</h3>
|
||||||
</a>
|
</a>
|
||||||
<div class="preview-card-titles__subtitle-wrapper">
|
<div class="preview-card-titles__subtitle-wrapper">
|
||||||
|
@ -295,7 +295,7 @@ export default class Directory extends SiteModule {
|
||||||
nodes.length > 1 ?
|
nodes.length > 1 ?
|
||||||
t.i18n.t('directory.hosted.by-many', 'Hosted by {count,number} channel{count,en_plural}', nodes.length) :
|
t.i18n.t('directory.hosted.by-many', 'Hosted by {count,number} channel{count,en_plural}', nodes.length) :
|
||||||
t.i18n.tList('directory.hosted.by-one', 'Hosted by {user}', {
|
t.i18n.tList('directory.hosted.by-one', 'Hosted by {user}', {
|
||||||
user: <a href={`/${nodes[0].login}`} data-href={`/${nodes[0].login}`} title={nodes[0].displayName} class="tw-link tw-link--inherit" onClick={t.routeClick}>{nodes[0].displayName}</a>
|
user: <a href={`/${nodes[0].login}`} data-href={`/${nodes[0].login}`} title={nodes[0].displayName} class="ffz-link ffz-link--inherit" onClick={t.routeClick}>{nodes[0].displayName}</a>
|
||||||
})
|
})
|
||||||
}</p>
|
}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -93,6 +93,20 @@ export default class WebMunch extends Module {
|
||||||
if ( ! name ) {
|
if ( ! name ) {
|
||||||
if ( attempts > 240 ) {
|
if ( attempts > 240 ) {
|
||||||
this.log.error("Unable to find webpack's loader after one minute.");
|
this.log.error("Unable to find webpack's loader after one minute.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const possibilities = [];
|
||||||
|
for(const key of Object.keys(window))
|
||||||
|
if ( has(window, key) && typeof key === 'string' && /webpack/i.test(key) && ! /ffz/i.test(key) )
|
||||||
|
possibilities.push(key);
|
||||||
|
|
||||||
|
if ( possibilities.length )
|
||||||
|
this.log.info('Possible Matches: ', possibilities.join(', '));
|
||||||
|
else
|
||||||
|
this.log.info('No possible matches found.');
|
||||||
|
|
||||||
|
} catch(err) { /* no-op */ }
|
||||||
|
|
||||||
this._resolveLoadWait(true);
|
this._resolveLoadWait(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
11
src/utilities/data/search-tags.gql
Normal file
11
src/utilities/data/search-tags.gql
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
query FFZ_SearchLiveTags($query: String!, $categoryID: ID, $limit: Int) {
|
||||||
|
searchLiveTags(userQuery: $query, categoryID: $categoryID, limit: $limit) {
|
||||||
|
id
|
||||||
|
isAutomated
|
||||||
|
isLanguageTag
|
||||||
|
localizedDescription
|
||||||
|
localizedName
|
||||||
|
scope
|
||||||
|
tagName
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
query FFZ_FetchTags($ids: [ID!]) {
|
query FFZ_FetchTags($ids: [ID!]) {
|
||||||
contentTags(ids: $ids) {
|
contentTags(ids: $ids) {
|
||||||
id
|
id
|
||||||
|
isAutomated
|
||||||
isLanguageTag
|
isLanguageTag
|
||||||
tagName
|
|
||||||
localizedName
|
|
||||||
localizedDescription
|
localizedDescription
|
||||||
|
localizedName
|
||||||
|
scope
|
||||||
|
tagName
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
query FFZ_TopTags($limit: Int) {
|
query FFZ_TopTags($limit: Int) {
|
||||||
topTags(limit: $limit) {
|
topTags(limit: $limit) {
|
||||||
id
|
id
|
||||||
|
isAutomated
|
||||||
isLanguageTag
|
isLanguageTag
|
||||||
tagName
|
|
||||||
localizedName
|
|
||||||
localizedDescription
|
localizedDescription
|
||||||
|
localizedName
|
||||||
|
scope
|
||||||
|
tagName
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -825,7 +825,7 @@ TOKEN_TYPES.link = function(token, createElement, ctx) {
|
||||||
klass.push(`tw-block tw-border tw-border-radius-large tw-mg-y-05 tw-pd-05`);
|
klass.push(`tw-block tw-border tw-border-radius-large tw-mg-y-05 tw-pd-05`);
|
||||||
|
|
||||||
if ( token.no_color )
|
if ( token.no_color )
|
||||||
klass.push(`tw-link--inherit`);
|
klass.push(`ffz-link--inherit`);
|
||||||
|
|
||||||
if ( ctx.vue )
|
if ( ctx.vue )
|
||||||
return createElement('a', {
|
return createElement('a', {
|
||||||
|
|
|
@ -6,65 +6,10 @@
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
import Module from 'utilities/module';
|
import Module from 'utilities/module';
|
||||||
import {get, debounce, generateUUID} from 'utilities/object';
|
import {get, debounce} from 'utilities/object';
|
||||||
|
|
||||||
const LANGUAGE_MATCHER = /^auto___lang_(\w+)$/;
|
const LANGUAGE_MATCHER = /^auto___lang_(\w+)$/;
|
||||||
|
|
||||||
const ALGOLIA_LANGUAGES = {
|
|
||||||
bg: 'bg-bg',
|
|
||||||
cs: 'cs-cz',
|
|
||||||
da: 'da-dk',
|
|
||||||
de: 'de-de',
|
|
||||||
el: 'el-gr',
|
|
||||||
en: 'en-us',
|
|
||||||
es: 'es-es',
|
|
||||||
'es-mx': 'es-mx',
|
|
||||||
fi: 'fi-fi',
|
|
||||||
fr: 'fr-fr',
|
|
||||||
hu: 'hu-hu',
|
|
||||||
it: 'it-it',
|
|
||||||
ja: 'ja-jp',
|
|
||||||
ko: 'ko-kr',
|
|
||||||
nl: 'nl-nl',
|
|
||||||
no: 'no-no',
|
|
||||||
pl: 'pl-pl',
|
|
||||||
'pt-br': 'pt-br',
|
|
||||||
pt: 'pt-pt',
|
|
||||||
ro: 'ro-ro',
|
|
||||||
ru: 'ru-ru',
|
|
||||||
sk: 'sk-sk',
|
|
||||||
sv: 'sv-se',
|
|
||||||
th: 'th-th',
|
|
||||||
tr: 'tr-tr',
|
|
||||||
vi: 'vi-vn',
|
|
||||||
'zh-cn': 'zh-cn',
|
|
||||||
'zh-tw': 'zh-tw'
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Algolia Language code for a given locale
|
|
||||||
* @function getAlgoliaLanguage
|
|
||||||
*
|
|
||||||
* @param {string} locale - a string representation of a locale
|
|
||||||
* @returns {string} the Algolia Language code for the given locale
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
*
|
|
||||||
* console.log(getAlgoliaLanguage('en'));
|
|
||||||
*/
|
|
||||||
function getAlgoliaLanguage(locale) {
|
|
||||||
if ( ! locale )
|
|
||||||
return ALGOLIA_LANGUAGES.en;
|
|
||||||
|
|
||||||
locale = locale.toLowerCase();
|
|
||||||
if ( ALGOLIA_LANGUAGES[locale] )
|
|
||||||
return ALGOLIA_LANGUAGES[locale];
|
|
||||||
|
|
||||||
locale = locale.split('-')[0];
|
|
||||||
return ALGOLIA_LANGUAGES[locale] || ALGOLIA_LANGUAGES.en;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TwitchData is a container for getting different types of Twitch data
|
* TwitchData is a container for getting different types of Twitch data
|
||||||
* @class TwitchData
|
* @class TwitchData
|
||||||
|
@ -132,34 +77,6 @@ export default class TwitchData extends Module {
|
||||||
return session && session.locale || 'en-US'
|
return session && session.locale || 'en-US'
|
||||||
}
|
}
|
||||||
|
|
||||||
async searchClient() {
|
|
||||||
if ( this._search )
|
|
||||||
return this._search;
|
|
||||||
|
|
||||||
const apollo = this.apollo.client,
|
|
||||||
core = this.site.getCore(),
|
|
||||||
web_munch = this.resolve('web_munch');
|
|
||||||
|
|
||||||
if ( ! web_munch )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
await web_munch.enable();
|
|
||||||
|
|
||||||
const SearchClient = await this.web_munch.findModule('algolia-search');
|
|
||||||
if ( ! SearchClient || ! apollo || ! core )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
this._search = new SearchClient({
|
|
||||||
appId: core.config.algoliaApplicationID,
|
|
||||||
apiKey: core.config.algoliaAPIKey,
|
|
||||||
apolloClient: apollo,
|
|
||||||
logger: core.logger,
|
|
||||||
config: core.config,
|
|
||||||
stats: core.stats
|
|
||||||
});
|
|
||||||
|
|
||||||
return this._search;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// Badges
|
// Badges
|
||||||
|
@ -350,6 +267,7 @@ export default class TwitchData extends Module {
|
||||||
return get('data.user.lastBroadcast', data);
|
return get('data.user.lastBroadcast', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// Broadcast ID
|
// Broadcast ID
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
@ -665,27 +583,28 @@ export default class TwitchData extends Module {
|
||||||
if ( ! node || ! node.id || ! node.tagName || ! node.localizedName )
|
if ( ! node || ! node.id || ! node.tagName || ! node.localizedName )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let old = null;
|
let tag = this.tag_cache.get(node.id);
|
||||||
if ( this.tag_cache.has(node.id) )
|
if ( ! tag ) {
|
||||||
old = this.tag_cache.get(old);
|
const match = node.isLanguageTag && LANGUAGE_MATCHER.exec(node.tagName),
|
||||||
|
lang = match && match[1] || null;
|
||||||
|
|
||||||
const match = node.isLanguageTag && LANGUAGE_MATCHER.exec(node.tagName),
|
tag = {
|
||||||
lang = match && match[1] || null;
|
id: node.id,
|
||||||
|
value: node.id,
|
||||||
|
is_auto: node.isAutomated,
|
||||||
|
is_language: node.isLanguageTag,
|
||||||
|
language: lang,
|
||||||
|
name: node.tagName,
|
||||||
|
scope: node.scope
|
||||||
|
};
|
||||||
|
|
||||||
const new_tag = {
|
this.tag_cache.set(node.id, tag);
|
||||||
id: node.id,
|
}
|
||||||
value: node.id,
|
|
||||||
is_language: node.isLanguageTag,
|
|
||||||
language: lang,
|
|
||||||
name: node.tagName,
|
|
||||||
label: node.localizedName
|
|
||||||
};
|
|
||||||
|
|
||||||
|
if ( node.localizedName )
|
||||||
|
tag.label = node.localizedName;
|
||||||
if ( node.localizedDescription )
|
if ( node.localizedDescription )
|
||||||
new_tag.description = node.localizedDescription;
|
tag.description = node.localizedDescription;
|
||||||
|
|
||||||
const tag = old ? Object.assign(old, new_tag) : new_tag;
|
|
||||||
this.tag_cache.set(tag.id, tag);
|
|
||||||
|
|
||||||
if ( dispatch && tag.description && this._waiting_tags.has(tag.id) ) {
|
if ( dispatch && tag.description && this._waiting_tags.has(tag.id) ) {
|
||||||
const promises = this._waiting_tags.get(tag.id);
|
const promises = this._waiting_tags.get(tag.id);
|
||||||
|
@ -907,100 +826,36 @@ export default class TwitchData extends Module {
|
||||||
* @async
|
* @async
|
||||||
*
|
*
|
||||||
* @param {string} query - the search string
|
* @param {string} query - the search string
|
||||||
* @param {string} [locale] - the locale to return tags from
|
* @param {string} [locale] - UNUSED. the locale to return tags from
|
||||||
* @param {string} [category=null] - the category to return tags from
|
* @param {string} [category=null] - the category to return tags from
|
||||||
* @returns {string[]} an array containing tags that match the query string
|
* @returns {string[]} an array containing tags that match the query string
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
*
|
*
|
||||||
* console.log(this.twitch_data.getMatchingTags("Rainbo"));
|
* console.log(await this.twitch_data.getMatchingTags("Rainbo"));
|
||||||
*/
|
*/
|
||||||
async getMatchingTags(query, locale, category = null) {
|
async getMatchingTags(query, locale, category = null) {
|
||||||
if ( ! locale )
|
/*if ( ! locale )
|
||||||
locale = this.locale;
|
locale = this.locale;*/
|
||||||
|
|
||||||
const client = await this.searchClient();
|
const data = await this.queryApollo({
|
||||||
|
query: await import(/* webpackChunkName: 'queries' */ './data/search-tags.gql'),
|
||||||
|
variables: {
|
||||||
|
query,
|
||||||
|
categoryID: category || null,
|
||||||
|
limit: 100
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
locale = getAlgoliaLanguage(locale);
|
const nodes = data?.data?.searchLiveTags;
|
||||||
|
if ( ! Array.isArray(nodes) || ! nodes.length )
|
||||||
let nodes;
|
|
||||||
|
|
||||||
if ( category ) {
|
|
||||||
const data = await client.queryForType(
|
|
||||||
'stream_tag', query, generateUUID(), {
|
|
||||||
hitsPerPage: 100,
|
|
||||||
faceFilters: [
|
|
||||||
`category_id:${category}`
|
|
||||||
],
|
|
||||||
restrictSearchableAttributes: [
|
|
||||||
`localizations.${locale}`,
|
|
||||||
'tag_name'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
nodes = get('streamTags.hits', data);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const data = await client.queryForType(
|
|
||||||
'tag', query, generateUUID(), {
|
|
||||||
hitsPerPage: 100,
|
|
||||||
facetFilters: [
|
|
||||||
['tag_scope:SCOPE_ALL', 'tag_scope:SCOPE_CATEGORY']
|
|
||||||
],
|
|
||||||
restrictSearchableAttributes: [
|
|
||||||
`localizations.${locale}`,
|
|
||||||
'tag_name'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
nodes = get('tags.hits', data);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! Array.isArray(nodes) )
|
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
const out = [], seen = new Set;
|
const out = [];
|
||||||
for(const node of nodes) {
|
for(const node of nodes) {
|
||||||
const tag_id = node.tag_id || node.objectID;
|
const tag = this.memorizeTag(node);
|
||||||
if ( ! node || seen.has(tag_id) )
|
if ( tag )
|
||||||
continue;
|
|
||||||
|
|
||||||
seen.add(tag_id);
|
|
||||||
if ( ! this.tag_cache.has(tag_id) ) {
|
|
||||||
const match = node.tag_name && LANGUAGE_MATCHER.exec(node.tag_name),
|
|
||||||
lang = match && match[1] || null;
|
|
||||||
|
|
||||||
const tag = {
|
|
||||||
id: tag_id,
|
|
||||||
value: tag_id,
|
|
||||||
is_language: lang != null,
|
|
||||||
language: lang,
|
|
||||||
label: node.localizations && (node.localizations[locale] || node.localizations['en-us']) || node.tag_name
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( node.description_localizations ) {
|
|
||||||
const desc = node.description_localizations[locale] || node.description_localizations['en-us'];
|
|
||||||
if ( desc )
|
|
||||||
tag.description = desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tag_cache.set(tag.id, tag);
|
|
||||||
out.push(tag);
|
out.push(tag);
|
||||||
|
|
||||||
} else {
|
|
||||||
const tag = this.tag_cache.get(tag_id);
|
|
||||||
if ( ! tag.description && node.description_localizations ) {
|
|
||||||
const desc = node.description_localizations[locale] || node.description_localizations['en-us'];
|
|
||||||
if ( desc ) {
|
|
||||||
tag.description = desc;
|
|
||||||
this.tag_cache.set(tag.id, tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out.push(tag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
@import 'widgets';
|
@import 'widgets';
|
||||||
@import 'dialog';
|
@import 'dialog';
|
||||||
|
|
||||||
@import 'input/index';
|
@import 'native/index';
|
||||||
@import 'structure/index';
|
@import 'structure/index';
|
||||||
|
|
||||||
@import 'chat';
|
@import 'chat';
|
||||||
|
|
15
styles/native/card.scss
Normal file
15
styles/native/card.scss
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
.ffz-card-img {
|
||||||
|
background-color: var(--color-background-placeholder);;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&--size-2 { width: 2rem }
|
||||||
|
&--size-3 { width: 3rem }
|
||||||
|
&--size-4 { width: 4rem }
|
||||||
|
&--size-6 { width: 6rem }
|
||||||
|
&--size-8 { width: 8rem }
|
||||||
|
&--size-12 { width: 12rem }
|
||||||
|
&--size-16 { width: 16rem }
|
||||||
|
&--size-24 { width: 24rem }
|
||||||
|
&--size-32 { width: 32rem }
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
@import "button";
|
@import "button";
|
||||||
@import "checkbox";
|
@import "checkbox";
|
||||||
@import "interactable";
|
@import "interactable";
|
||||||
@import "text";
|
@import "text";
|
||||||
|
@import "link";
|
||||||
|
@import "card";
|
||||||
|
@import "tag";
|
67
styles/native/link.scss
Normal file
67
styles/native/link.scss
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
.ffz-link {
|
||||||
|
color: var(--color-text-link);
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
.tw-root--hover &:hover {
|
||||||
|
color: var(--color-text-link-hover);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active { color: var(--color-text-link-active); }
|
||||||
|
&[data-focus-visible-added], &:focus { color: var(--color-text-link-focus); }
|
||||||
|
&:visited { color: var(--color-text-link-visited); }
|
||||||
|
|
||||||
|
&--overlay {
|
||||||
|
color: var(--color-text-overlay-link);
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tw-root--hover &:hover {
|
||||||
|
color: var(--color-text-overlay-link-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active { color: var(--color-text-overlay-link-active) }
|
||||||
|
&:focus, &[data-focus-visible-added] { color: var(--color-text-overlay-link-focus) }
|
||||||
|
&:visited { color: var(--color-text-overlay-link-visited) }
|
||||||
|
}
|
||||||
|
|
||||||
|
&--underline { text-decoration: underline; }
|
||||||
|
|
||||||
|
&--inherit {
|
||||||
|
&, &:visited, &:focus, &[data-focus-visible-added], &:active {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tw-root--hover &:hover {
|
||||||
|
color: var(--color-text-link-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tw-root--hover &--hover-color-inherit:hover {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tw-root--hover &--hover-underline-none {
|
||||||
|
&, &:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--button {
|
||||||
|
&:active {
|
||||||
|
outline: none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
opacity: .5;
|
||||||
|
|
||||||
|
.tw-root--hover &:hover {
|
||||||
|
cursor: not-allowed;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
62
styles/native/tag.scss
Normal file
62
styles/native/tag.scss
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
.ffz-tag {
|
||||||
|
background-color: var(--color-background-tag-default);
|
||||||
|
border: var(--border-width-tag) solid transparent;
|
||||||
|
color: var(--color-text-tag);
|
||||||
|
height: 2rem;
|
||||||
|
|
||||||
|
&:not(:disabled) {
|
||||||
|
&:focus, &[data-focus-visible-added] {
|
||||||
|
background: var(--color-background-tag-hover);
|
||||||
|
border: var(--border-width-tag) solid var(--color-border-input-focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tw-root--hover &:hover {
|
||||||
|
background: var(--color-background-tag-hover);
|
||||||
|
color: var(--color-text-tag);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: var(--color-background-tag-active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
padding: 0 .8rem;
|
||||||
|
|
||||||
|
&--icon {
|
||||||
|
padding-right: .4rem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
height: 1.6rem;
|
||||||
|
width: 1.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--overlay {
|
||||||
|
background: rgba(0,0,0,0.3);
|
||||||
|
border: var(--border-width-tag) solid var(--color-border-input-overlay);
|
||||||
|
color: var(--color-text-overlay);
|
||||||
|
|
||||||
|
&:not(:disabled) {
|
||||||
|
&:focus, &[data-focus-visible-added] {
|
||||||
|
border: var(--border-width-tag) solid var(--color-border-input-overlay-focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tw-root--hover &:hover {
|
||||||
|
background: var(--color-background-interactable-overlay-hover);
|
||||||
|
color: var(--color-text-overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: var(--color-background-interactable-overlay-active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue