mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-07-01 16:48:32 +00:00
4.0.0-rc4.5
* Added: Whisper Support * Fixed: UI missing hover state for a few elements added by FrankerFaceZ. * Fixed: Handle missing badge definition when rendering FFZ badges. * Fixed: Update static chat message type mappings. * Fixed: Error in metadata when unable to get the proper player. * Fixed: Incorrectly applying dark theme to products page. A bit more work on getting enhanced viewer cards ready.
This commit is contained in:
parent
4a326823b9
commit
17fb41f083
26 changed files with 396 additions and 80 deletions
|
@ -1,4 +1,14 @@
|
||||||
<div class="list-header">4.0.0-rc4.4<span>@9e5af5443a7601d78faf</span> <time datetime="2018-07-09">(2018-07-09)</time></div>
|
<div class="list-header">4.0.0-rc4.5<span>@f47412afa7703e2d3b18</span> <time datetime="2018-07-13">(2018-07-13)</time></div>
|
||||||
|
<ul class="chat-menu-content menu-side-padding">
|
||||||
|
<li>Added: Whisper Support</li>
|
||||||
|
<li>Fixed: UI missing hover state for a few elements added by FrankerFaceZ.</li>
|
||||||
|
<li>Fixed: Handle missing badge definition when rendering FFZ badges.</li>
|
||||||
|
<li>Fixed: Update static chat message type mappings.</li>
|
||||||
|
<li>Fixed: Error in metadata when unable to get the proper player.</li>
|
||||||
|
<li>Fixed: Incorrectly applying dark theme to products page.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="list-header">4.0.0-rc4.4<span>@46f98c4cd4559eaa9828</span> <time datetime="2018-07-05">(2018-07-05)</time></div>
|
||||||
<ul class="chat-menu-content menu-side-padding">
|
<ul class="chat-menu-content menu-side-padding">
|
||||||
<li>Changed: Make usernames clickable in resub notifications in chat, to match with native subscription messages.</li>
|
<li>Changed: Make usernames clickable in resub notifications in chat, to match with native subscription messages.</li>
|
||||||
<li>Fixed: Make the code to automatically leave raids more robust.</li>
|
<li>Fixed: Make the code to automatically leave raids more robust.</li>
|
||||||
|
|
11
src/i18n.js
11
src/i18n.js
|
@ -135,9 +135,11 @@ export class TranslationManager extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnable() {
|
onEnable() {
|
||||||
this._ = new TranslationCore; /*({
|
this._ = new TranslationCore({
|
||||||
awarn: (...args) => this.log.info(...args)
|
formatters: {
|
||||||
});*/
|
'humanTime': n => this.toHumanTime(n)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this._.transformation = TRANSFORMATIONS[this.settings.get('i18n.debug.transform')];
|
this._.transformation = TRANSFORMATIONS[this.settings.get('i18n.debug.transform')];
|
||||||
this.locale = this.settings.get('i18n.locale');
|
this.locale = this.settings.get('i18n.locale');
|
||||||
|
@ -162,6 +164,9 @@ export class TranslationManager extends Module {
|
||||||
toHumanTime(duration, factor = 1) {
|
toHumanTime(duration, factor = 1) {
|
||||||
// TODO: Make this better. Make all time handling better in fact.
|
// TODO: Make this better. Make all time handling better in fact.
|
||||||
|
|
||||||
|
if ( duration instanceof Date )
|
||||||
|
duration = (Date.now() - duration.getTime()) / 1000;
|
||||||
|
|
||||||
duration = Math.floor(duration);
|
duration = Math.floor(duration);
|
||||||
|
|
||||||
const years = Math.floor((duration * factor) / 31536000) / factor;
|
const years = Math.floor((duration * factor) / 31536000) / factor;
|
||||||
|
|
|
@ -100,7 +100,7 @@ class FrankerFaceZ extends Module {
|
||||||
FrankerFaceZ.Logger = Logger;
|
FrankerFaceZ.Logger = Logger;
|
||||||
|
|
||||||
const VER = FrankerFaceZ.version_info = {
|
const VER = FrankerFaceZ.version_info = {
|
||||||
major: 4, minor: 0, revision: 0, extra: '-rc4.4',
|
major: 4, minor: 0, revision: 0, extra: '-rc4.5',
|
||||||
build: __webpack_hash__,
|
build: __webpack_hash__,
|
||||||
toString: () =>
|
toString: () =>
|
||||||
`${VER.major}.${VER.minor}.${VER.revision}${VER.extra || ''}${DEBUG ? '-dev' : ''}`
|
`${VER.major}.${VER.minor}.${VER.revision}${VER.extra || ''}${DEBUG ? '-dev' : ''}`
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
:key="i[0]"
|
:key="i[0]"
|
||||||
:aria-checked="value.icon === i[0]"
|
:aria-checked="value.icon === i[0]"
|
||||||
:class="{'tw-interactable--selected': value.icon === i[0]}"
|
:class="{'tw-interactable--selected': value.icon === i[0]}"
|
||||||
class="ffz-icon tw-interactable"
|
class="ffz-icon tw-interactable tw-interactable--inverted"
|
||||||
role="radio"
|
role="radio"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@keydown.space.stop.prevent=""
|
@keydown.space.stop.prevent=""
|
||||||
|
|
|
@ -57,6 +57,42 @@ export default class Actions extends Module {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.settings.add('chat.actions.viewer-card', {
|
||||||
|
// Filter out actions
|
||||||
|
process: (ctx, val) =>
|
||||||
|
val.filter(x => x.appearance &&
|
||||||
|
this.renderers[x.appearance.type] &&
|
||||||
|
(! this.renderers[x.appearance.type].load || this.renderers[x.appearance.type].load(x.appearance)) &&
|
||||||
|
(! x.action || this.actions[x.action])
|
||||||
|
),
|
||||||
|
|
||||||
|
default: [
|
||||||
|
{v: {action: 'friend'}},
|
||||||
|
{v: {action: 'whisper', appearance: {type: 'text', text: 'Whisper', button: true}}},
|
||||||
|
{v: {type: 'space'}},
|
||||||
|
{v: {action: 'card_menu'}},
|
||||||
|
{v: {type: 'new-line'}},
|
||||||
|
{v: {action: 'ban', appearance: {type: 'icon', icon: 'ffz-i-block'}, display: {mod: true}}},
|
||||||
|
{v: {action: 'timeout', appearance: {type: 'icon', icon: 'ffz-i-clock'}, display: {mod: true}}}
|
||||||
|
],
|
||||||
|
|
||||||
|
type: 'array_merge',
|
||||||
|
_ui: {
|
||||||
|
path: 'Chat > Viewer Cards >> tabs ~> Actions @{"description": "Here, you define what actions are available on viewer cards."}',
|
||||||
|
component: 'chat-actions',
|
||||||
|
|
||||||
|
data: () => {
|
||||||
|
const chat = this.resolve('site.chat');
|
||||||
|
|
||||||
|
return {
|
||||||
|
color: val => chat && chat.colors ? chat.colors.process(val) : val,
|
||||||
|
actions: deep_copy(this.actions),
|
||||||
|
renderers: deep_copy(this.renderers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
this.handleClick = this.handleClick.bind(this);
|
this.handleClick = this.handleClick.bind(this);
|
||||||
this.handleContext = this.handleContext.bind(this);
|
this.handleContext = this.handleContext.bind(this);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +252,7 @@ export default class Actions extends Module {
|
||||||
});
|
});
|
||||||
|
|
||||||
return (<div
|
return (<div
|
||||||
class="ffz--inline-actions tw-inline tw-mg-r-05"
|
class="ffz--inline-actions ffz-action-data tw-inline tw-mg-r-05"
|
||||||
data-msg-id={msg.id}
|
data-msg-id={msg.id}
|
||||||
data-user={user}
|
data-user={user}
|
||||||
data-room={room}
|
data-room={room}
|
||||||
|
@ -228,7 +264,7 @@ export default class Actions extends Module {
|
||||||
|
|
||||||
getData(element) {
|
getData(element) {
|
||||||
const ds = element.dataset,
|
const ds = element.dataset,
|
||||||
parent = element.parentElement,
|
parent = element.closest('.ffz-action-data'),
|
||||||
pds = parent && parent.dataset,
|
pds = parent && parent.dataset,
|
||||||
action = ds && ds.action,
|
action = ds && ds.action,
|
||||||
definition = this.actions[action];
|
definition = this.actions[action];
|
||||||
|
|
|
@ -387,7 +387,7 @@ export default class Badges extends Module {
|
||||||
if ( hidden_badges[badge.id] )
|
if ( hidden_badges[badge.id] )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const full_badge = this.badges[badge.id],
|
const full_badge = this.badges[badge.id] || {},
|
||||||
slot = has(badge, 'slot') ? badge.slot : full_badge.slot,
|
slot = has(badge, 'slot') ? badge.slot : full_badge.slot,
|
||||||
old_badge = slotted[slot],
|
old_badge = slotted[slot],
|
||||||
urls = badge.urls || (badge.image ? {1: badge.image} : null),
|
urls = badge.urls || (badge.image ? {1: badge.image} : null),
|
||||||
|
|
|
@ -566,6 +566,43 @@ export default class Chat extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
standardizeWhisper(msg) { // eslint-disable-line class-methods-use-this
|
||||||
|
if ( ! msg )
|
||||||
|
return msg;
|
||||||
|
|
||||||
|
if ( msg._ffz_message )
|
||||||
|
return msg._ffz_message;
|
||||||
|
|
||||||
|
const emotes = {},
|
||||||
|
is_action = msg.content.startsWith('/me '),
|
||||||
|
offset = is_action ? 4 : 0,
|
||||||
|
|
||||||
|
out = msg._ffz_message = {
|
||||||
|
user: msg.from,
|
||||||
|
message: msg.content.slice(offset),
|
||||||
|
is_action,
|
||||||
|
emotes,
|
||||||
|
timestamp: msg.sentAt && msg.sentAt.getTime(),
|
||||||
|
deleted: false
|
||||||
|
};
|
||||||
|
|
||||||
|
out.user.color = out.user.chatColor;
|
||||||
|
|
||||||
|
if ( Array.isArray(msg.emotes) && msg.emotes.length )
|
||||||
|
for(const emote of msg.emotes) {
|
||||||
|
const id = emote.emoteID,
|
||||||
|
em = emotes[id] = emotes[id] || [];
|
||||||
|
|
||||||
|
em.push({
|
||||||
|
startIndex: emote.from - offset,
|
||||||
|
endIndex: emote.to - offset
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
standardizeMessage(msg) { // eslint-disable-line class-methods-use-this
|
standardizeMessage(msg) { // eslint-disable-line class-methods-use-this
|
||||||
if ( ! msg )
|
if ( ! msg )
|
||||||
return msg;
|
return msg;
|
||||||
|
@ -574,6 +611,9 @@ export default class Chat extends Module {
|
||||||
if ( msg.sender && ! msg.user )
|
if ( msg.sender && ! msg.user )
|
||||||
msg.user = msg.sender;
|
msg.user = msg.sender;
|
||||||
|
|
||||||
|
if ( msg.from && ! msg.user )
|
||||||
|
msg.user = msg.from;
|
||||||
|
|
||||||
let user = msg.user;
|
let user = msg.user;
|
||||||
if ( ! user )
|
if ( ! user )
|
||||||
user = msg.user = {};
|
user = msg.user = {};
|
||||||
|
|
|
@ -20,6 +20,7 @@ export default class Room {
|
||||||
this.style = new ManagedStyle(`room--${login}`);
|
this.style = new ManagedStyle(`room--${login}`);
|
||||||
|
|
||||||
this.emote_sets = new SourcedSet;
|
this.emote_sets = new SourcedSet;
|
||||||
|
this.badges = null;
|
||||||
this.users = {};
|
this.users = {};
|
||||||
this.user_ids = {};
|
this.user_ids = {};
|
||||||
|
|
||||||
|
|
|
@ -928,7 +928,8 @@ export const TwitchEmotes = {
|
||||||
emotes = [];
|
emotes = [];
|
||||||
|
|
||||||
for(const emote_id in data)
|
for(const emote_id in data)
|
||||||
if ( has(data, emote_id) ) {
|
// Disable fix for now so we can see what Twitch is sending for emote data.
|
||||||
|
if ( has(data, emote_id) ) { // && Array.isArray(data[emote_id]) ) {
|
||||||
for(const match of data[emote_id])
|
for(const match of data[emote_id])
|
||||||
emotes.push([emote_id, match.startIndex, match.endIndex + 1]);
|
emotes.push([emote_id, match.startIndex, match.endIndex + 1]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,7 +254,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
canEdit() {
|
canEdit() {
|
||||||
return this.action.v != null;
|
return this.action.v != null && ! this.action.v.type;
|
||||||
},
|
},
|
||||||
|
|
||||||
canPreview() {
|
canPreview() {
|
||||||
|
@ -268,6 +268,17 @@ export default {
|
||||||
else if ( ! this.display )
|
else if ( ! this.display )
|
||||||
return this.t('setting.unknown', 'Unknown Value');
|
return this.t('setting.unknown', 'Unknown Value');
|
||||||
|
|
||||||
|
const type = this.display.type;
|
||||||
|
|
||||||
|
if ( type === 'new-line' )
|
||||||
|
return this.t('setting.new-line', 'New Line');
|
||||||
|
|
||||||
|
else if ( type === 'space-small' )
|
||||||
|
return this.t('setting.space-small', 'Space (Small)');
|
||||||
|
|
||||||
|
else if ( type === 'space' )
|
||||||
|
return this.t('setting.space', 'Space');
|
||||||
|
|
||||||
const def = this.data.actions[this.display.action];
|
const def = this.data.actions[this.display.action];
|
||||||
if ( ! def )
|
if ( ! def )
|
||||||
return this.t('setting.actions.unknown', 'Unknown Action Type: %{action}', this.display);
|
return this.t('setting.actions.unknown', 'Unknown Action Type: %{action}', this.display);
|
||||||
|
@ -289,6 +300,17 @@ export default {
|
||||||
if ( this.action.t === 'inherit' )
|
if ( this.action.t === 'inherit' )
|
||||||
return this.t('setting.inheritance.desc', 'Inherit values from lower priority profiles at this position.');
|
return this.t('setting.inheritance.desc', 'Inherit values from lower priority profiles at this position.');
|
||||||
|
|
||||||
|
const type = this.display && this.display.type;
|
||||||
|
|
||||||
|
if ( type === 'new-line' )
|
||||||
|
return this.t('setting.new-line.desc', 'Place all items following this on a new line.');
|
||||||
|
|
||||||
|
else if ( type === 'space-small' )
|
||||||
|
return this.t('setting.space-small.desc', 'Place a small space between the previous item and the next item.');
|
||||||
|
|
||||||
|
else if ( type === 'space' )
|
||||||
|
return this.t('setting.space.desc', 'Place as large a space as possible between the previous item and the next item.');
|
||||||
|
|
||||||
const def = this.display && this.data.actions[this.display.action];
|
const def = this.display && this.data.actions[this.display.action];
|
||||||
if ( ! def || ! def.description )
|
if ( ! def || ! def.description )
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tw-pd-x-1">
|
<div v-if="item.inline" class="tw-pd-x-1">
|
||||||
<input
|
<input
|
||||||
id="is_deleted"
|
id="is_deleted"
|
||||||
ref="is_deleted"
|
ref="is_deleted"
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tw-pd-x-1">
|
<div v-if="item.inline" class="tw-pd-x-1">
|
||||||
<input
|
<input
|
||||||
id="with_mod_icons"
|
id="with_mod_icons"
|
||||||
ref="with_mod_icons"
|
ref="with_mod_icons"
|
||||||
|
@ -76,18 +76,23 @@
|
||||||
<div
|
<div
|
||||||
:data-user="JSON.stringify(sample_user)"
|
:data-user="JSON.stringify(sample_user)"
|
||||||
:data-room="JSON.stringify(sample_room)"
|
:data-room="JSON.stringify(sample_room)"
|
||||||
class="tw-flex tw-align-items-center tw-justify-content-center tw-pd-t-1"
|
class="ffz-action-data tw-pd-t-1"
|
||||||
data-msg-id="1234-5678"
|
data-msg-id="1234-5678"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="! display.length"
|
v-if="! display.length"
|
||||||
class="tw-c-text-alt-2 tw-pd-05 tw-font-size-4"
|
class="tw-align-center tw-c-text-alt-2 tw-pd-05 tw-font-size-4"
|
||||||
>
|
>
|
||||||
{{ t('setting.actions.no-visible', 'no visible actions') }}
|
{{ t('setting.actions.no-visible', 'no visible actions') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-for="(actions, idx) in display"
|
||||||
|
:key="idx"
|
||||||
|
class="tw-flex tw-align-items-center tw-justify-content-center"
|
||||||
|
>
|
||||||
<action-preview
|
<action-preview
|
||||||
v-for="act in display"
|
v-for="act in actions"
|
||||||
:key="act.id"
|
:key="act.id"
|
||||||
:act="act.v"
|
:act="act.v"
|
||||||
:color="color(act.v.appearance.color)"
|
:color="color(act.v.appearance.color)"
|
||||||
|
@ -97,6 +102,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="tw-flex tw-align-items-center tw-pd-b-05">
|
<div class="tw-flex tw-align-items-center tw-pd-b-05">
|
||||||
<div class="tw-flex-grow-1">
|
<div class="tw-flex-grow-1">
|
||||||
|
@ -135,7 +141,7 @@
|
||||||
v-else
|
v-else
|
||||||
:key="idx"
|
:key="idx"
|
||||||
:disabled="preset.disabled"
|
:disabled="preset.disabled"
|
||||||
class="tw-interactable tw-full-width"
|
class="tw-interactable tw-interactable--inverted tw-full-width"
|
||||||
@click="add(preset.value)"
|
@click="add(preset.value)"
|
||||||
>
|
>
|
||||||
<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">
|
||||||
|
@ -299,13 +305,25 @@ export default {
|
||||||
|
|
||||||
display() {
|
display() {
|
||||||
const out = [];
|
const out = [];
|
||||||
|
let current = [];
|
||||||
|
|
||||||
if ( this.val )
|
if ( this.val )
|
||||||
for(const val of this.val) {
|
for(const val of this.val) {
|
||||||
if ( val.v && this.displayAction(val.v) )
|
if ( ! val.v )
|
||||||
out.push(val);
|
continue;
|
||||||
|
|
||||||
|
const type = val.v.type;
|
||||||
|
if ( type === 'new-line' ) {
|
||||||
|
out.push(current);
|
||||||
|
current = [];
|
||||||
|
|
||||||
|
} else if ( this.displayAction(val.v) )
|
||||||
|
current.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( current.length )
|
||||||
|
out.push(current);
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -386,8 +404,8 @@ export default {
|
||||||
this.show_all = this.$refs.show_all.checked;
|
this.show_all = this.$refs.show_all.checked;
|
||||||
this.is_moderator = this.$refs.as_mod.checked;
|
this.is_moderator = this.$refs.as_mod.checked;
|
||||||
this.is_staff = false; //this.$refs.as_staff.checked;
|
this.is_staff = false; //this.$refs.as_staff.checked;
|
||||||
this.with_mod_icons = this.$refs.with_mod_icons.checked;
|
this.with_mod_icons = this.item.inline && this.$refs.with_mod_icons.checked;
|
||||||
this.is_deleted = this.$refs.is_deleted.checked;
|
this.is_deleted = this.item.inline && this.$refs.is_deleted.checked;
|
||||||
},
|
},
|
||||||
|
|
||||||
displayAction(action) {
|
displayAction(action) {
|
||||||
|
|
|
@ -220,6 +220,7 @@ export default class MainMenu extends Module {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const tree = this._settings_tree,
|
const tree = this._settings_tree,
|
||||||
|
expanded = this.settings.provider.get('settings-expanded', {}),
|
||||||
tokens = def.ui.path_tokens,
|
tokens = def.ui.path_tokens,
|
||||||
len = tokens.length;
|
len = tokens.length;
|
||||||
|
|
||||||
|
@ -244,6 +245,10 @@ export default class MainMenu extends Module {
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(token, raw_token);
|
Object.assign(token, raw_token);
|
||||||
|
|
||||||
|
if ( has(expanded, key) )
|
||||||
|
token.expanded = expanded[key];
|
||||||
|
|
||||||
prefix = key;
|
prefix = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ export default class Metadata extends Module {
|
||||||
const Player = this.resolve('site.player'),
|
const Player = this.resolve('site.player'),
|
||||||
socket = this.resolve('socket'),
|
socket = this.resolve('socket'),
|
||||||
player = Player.current,
|
player = Player.current,
|
||||||
stats = player && player.getVideoInfo();
|
stats = player && maybe_call(player.getVideoInfo, player);
|
||||||
|
|
||||||
if ( ! stats )
|
if ( ! stats )
|
||||||
return {stats};
|
return {stats};
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
{{ login }}
|
{{ login }}
|
||||||
</a>
|
</a>
|
||||||
</h5>
|
</h5>
|
||||||
<div v-if="loaded">
|
<div v-if="loaded" class="tw-pd-t-05">
|
||||||
<span
|
<span
|
||||||
:data-title="t('viewer-card.views', 'Views')"
|
:data-title="t('viewer-card.views', 'Views')"
|
||||||
class="ffz-tooltip tw-mg-r-05 ffz-i-views"
|
class="ffz-tooltip tw-mg-r-05 ffz-i-views"
|
||||||
|
@ -47,10 +47,11 @@
|
||||||
{{ t(null, '%{followers|number}', {followers: user.followers.totalCount}) }}
|
{{ t(null, '%{followers|number}', {followers: user.followers.totalCount}) }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
data-title="rawUserAge"
|
v-if="userAge"
|
||||||
|
:data-title="t('viewer-card.age-tip', 'Member Since: %{age}', {age: userAge.toLocaleString()})"
|
||||||
class="ffz-tooltip ffz-i-clock"
|
class="ffz-tooltip ffz-i-clock"
|
||||||
>
|
>
|
||||||
{ userAge }
|
{{ t('viewer-card.age', '%{age|humanTime}', {age: userAge}) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -154,6 +155,13 @@ export default {
|
||||||
return this.raw_user.displayName || this.raw_user.login;
|
return this.raw_user.displayName || this.raw_user.login;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
userAge() {
|
||||||
|
if ( this.loaded )
|
||||||
|
return new Date(this.user.createdAt);
|
||||||
|
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
|
||||||
current_tab() {
|
current_tab() {
|
||||||
return this.tabs[this.active_tab];
|
return this.tabs[this.active_tab];
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,10 +54,12 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import TabMixin from '../tab-mixin';
|
import TabMixin from '../tab-mixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [TabMixin],
|
mixins: [TabMixin],
|
||||||
props: ['tab', 'user', 'room', 'currentUser']
|
props: ['tab', 'user', 'room', 'currentUser']
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
|
@ -4,8 +4,17 @@
|
||||||
<loading-tab v-else-if="loading" />
|
<loading-tab v-else-if="loading" />
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="entry in data" :key="entry[1]">
|
<li
|
||||||
<span>{{ entry[0] }}</span>
|
v-for="(entry, idx) in data"
|
||||||
|
:key="entry[1]"
|
||||||
|
:class="idx === 0 ? '' : 'tw-border-t'"
|
||||||
|
class="tw-pd-x-1 tw-pd-y-05"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
:data-title="fullTime(entry[0])"
|
||||||
|
data-tooltip-type="text"
|
||||||
|
class="ffz-tooltip tw-pd-r-1"
|
||||||
|
>{{ formatTime(entry[0]) }}: </span>
|
||||||
{{ entry[1] }}
|
{{ entry[1] }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -44,12 +53,36 @@ export default {
|
||||||
|
|
||||||
socket.call('get_name_history', this.user.login).then(data => {
|
socket.call('get_name_history', this.user.login).then(data => {
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
|
|
||||||
|
if ( Array.isArray(data) )
|
||||||
|
data = data.reverse();
|
||||||
|
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.error(err);
|
this.getFFZ().log.error('Error loading name history.', err);
|
||||||
this.errored = true;
|
this.errored = true;
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
fullTime(time) {
|
||||||
|
try {
|
||||||
|
const date = new Date(time);
|
||||||
|
return date.toLocaleString();
|
||||||
|
} catch(err) {
|
||||||
|
return 'Unknown'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
formatTime(time) {
|
||||||
|
try {
|
||||||
|
const date = new Date(time);
|
||||||
|
return date.toLocaleDateString();
|
||||||
|
} catch(err) {
|
||||||
|
return 'Unknown'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,10 +55,18 @@ export default class Twilight extends BaseSite {
|
||||||
this.router.on(':route', (route, match) => {
|
this.router.on(':route', (route, match) => {
|
||||||
this.log.info('Navigation', route && route.name, match && match[0]);
|
this.log.info('Navigation', route && route.name, match && match[0]);
|
||||||
this.fine.route(route && route.name);
|
this.fine.route(route && route.name);
|
||||||
|
this.settings.updateContext({
|
||||||
|
route,
|
||||||
|
route_data: match
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const current = this.router.current;
|
const current = this.router.current;
|
||||||
this.fine.route(current && current.name);
|
this.fine.route(current && current.name);
|
||||||
|
this.settings.updateContext({
|
||||||
|
route: current,
|
||||||
|
route_data: this.router.match
|
||||||
|
});
|
||||||
|
|
||||||
document.head.appendChild(createElement('link', {
|
document.head.appendChild(createElement('link', {
|
||||||
href: MAIN_URL,
|
href: MAIN_URL,
|
||||||
|
@ -171,5 +179,6 @@ Twilight.ROUTES = {
|
||||||
'user-events': '/:userName/events',
|
'user-events': '/:userName/events',
|
||||||
'user-followers': '/:userName/followers',
|
'user-followers': '/:userName/followers',
|
||||||
'user-following': '/:userName/following',
|
'user-following': '/:userName/following',
|
||||||
|
'product': '/products/:productName',
|
||||||
'user': '/:userName'
|
'user': '/:userName'
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
import {ColorAdjuster} from 'utilities/color';
|
import {ColorAdjuster} from 'utilities/color';
|
||||||
import {setChildren} from 'utilities/dom';
|
import {setChildren} from 'utilities/dom';
|
||||||
import {has, split_chars} from 'utilities/object';
|
import {has, split_chars, shallow_object_equals} from 'utilities/object';
|
||||||
import {FFZEvent} from 'utilities/events';
|
import {FFZEvent} from 'utilities/events';
|
||||||
|
|
||||||
import Module from 'utilities/module';
|
import Module from 'utilities/module';
|
||||||
|
@ -73,31 +73,33 @@ const CHAT_TYPES = ((e = {}) => {
|
||||||
e[e.ModerationAction = 2] = 'ModerationAction';
|
e[e.ModerationAction = 2] = 'ModerationAction';
|
||||||
e[e.TargetedModerationAction = 3] = 'TargetedModerationAction';
|
e[e.TargetedModerationAction = 3] = 'TargetedModerationAction';
|
||||||
e[e.AutoMod = 4] = 'AutoMod';
|
e[e.AutoMod = 4] = 'AutoMod';
|
||||||
e[e.Connected = 5] = 'Connected';
|
e[e.SubscriberOnlyMode = 5] = 'SubscriberOnlyMode';
|
||||||
e[e.Disconnected = 6] = 'Disconnected';
|
e[e.FollowerOnlyMode = 6] = 'FollowerOnlyMode';
|
||||||
e[e.Reconnect = 7] = 'Reconnect';
|
e[e.SlowMode = 7] = 'SlowMode';
|
||||||
e[e.Hosting = 8] = 'Hosting';
|
e[e.EmoteOnlyMode = 8] = 'EmoteOnlyMode';
|
||||||
e[e.Unhost = 9] = 'Unhost';
|
e[e.R9KMode = 9] = 'R9KMode';
|
||||||
e[e.Hosted = 10] = 'Hosted';
|
e[e.Connected = 10] = 'Connected';
|
||||||
e[e.Subscription = 11] = 'Subscription';
|
e[e.Disconnected = 11] = 'Disconnected';
|
||||||
e[e.Resubscription = 12] = 'Resubscription';
|
e[e.Reconnect = 12] = 'Reconnect';
|
||||||
e[e.SubGift = 13] = 'SubGift';
|
e[e.Hosting = 13] = 'Hosting';
|
||||||
e[e.Clear = 14] = 'Clear';
|
e[e.Unhost = 14] = 'Unhost';
|
||||||
e[e.SubscriberOnlyMode = 15] = 'SubscriberOnlyMode';
|
e[e.Hosted = 15] = 'Hosted';
|
||||||
e[e.FollowerOnlyMode = 16] = 'FollowerOnlyMode';
|
e[e.Subscription = 16] = 'Subscription';
|
||||||
e[e.SlowMode = 17] = 'SlowMode';
|
e[e.Resubscription = 17] = 'Resubscription';
|
||||||
e[e.EmoteOnlyMode = 18] = 'EmoteOnlyMode';
|
e[e.SubGift = 18] = 'SubGift';
|
||||||
e[e.RoomMods = 19] = 'RoomMods';
|
e[e.Clear = 19] = 'Clear';
|
||||||
e[e.RoomState = 20] = 'RoomState';
|
e[e.RoomMods = 20] = 'RoomMods';
|
||||||
e[e.Raid = 21] = 'Raid';
|
e[e.RoomState = 21] = 'RoomState';
|
||||||
e[e.Unraid = 22] = 'Unraid';
|
e[e.Raid = 22] = 'Raid';
|
||||||
e[e.Ritual = 23] = 'Ritual';
|
e[e.Unraid = 23] = 'Unraid';
|
||||||
e[e.Notice = 24] = 'Notice';
|
e[e.Ritual = 24] = 'Ritual';
|
||||||
e[e.Info = 25] = 'Info';
|
e[e.Notice = 25] = 'Notice';
|
||||||
e[e.BadgesUpdated = 26] = 'BadgesUpdated';
|
e[e.Info = 26] = 'Info';
|
||||||
e[e.Purchase = 27] = 'Purchase';
|
e[e.BadgesUpdated = 27] = 'BadgesUpdated';
|
||||||
e[e.BitsCharity = 28] = 'BitsCharity';
|
e[e.Purchase = 28] = 'Purchase';
|
||||||
e[e.CrateGift = 29] = 'CrateGift'
|
e[e.BitsCharity = 29] = 'BitsCharity';
|
||||||
|
e[e.CrateGift = 30] = 'CrateGift';
|
||||||
|
e[e.RewardGift = 31] = 'RewardGift';
|
||||||
return e;
|
return e;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
@ -354,12 +356,34 @@ export default class ChatHook extends Module {
|
||||||
|
|
||||||
|
|
||||||
async grabTypes() {
|
async grabTypes() {
|
||||||
const ct = await this.web_munch.findModule('chat-types');
|
const ct = await this.web_munch.findModule('chat-types'),
|
||||||
|
changes = [];
|
||||||
|
|
||||||
this.automod_types = ct && ct.a || AUTOMOD_TYPES;
|
if ( ! ct )
|
||||||
this.chat_types = ct && ct.b || CHAT_TYPES;
|
return;
|
||||||
this.message_types = ct && ct.c || MESSAGE_TYPES;
|
|
||||||
this.mod_types = ct && ct.e || MOD_TYPES;
|
if ( ct.a && ! shallow_object_equals(ct.a, AUTOMOD_TYPES) ) {
|
||||||
|
changes.push('AUTOMOD_TYPES');
|
||||||
|
this.automod_types = ct.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ct.b && ! shallow_object_equals(ct.b, CHAT_TYPES) ) {
|
||||||
|
changes.push('CHAT_TYPES');
|
||||||
|
this.chat_types = ct.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ct.c && ! shallow_object_equals(ct.c, MESSAGE_TYPES) ) {
|
||||||
|
changes.push('MESSAGE_TYPES');
|
||||||
|
this.message_types = ct.c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ct.e && ! shallow_object_equals(ct.e, MOD_TYPES) ) {
|
||||||
|
changes.push('MOD_TYPES');
|
||||||
|
this.mod_types = ct.e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( changes.length )
|
||||||
|
this.log.info('Chat Types have changed from static mappings for categories:', changes.join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,11 @@ export default class ChatLine extends Module {
|
||||||
n => n.renderMessageBody && n.props && n.props.roomID,
|
n => n.renderMessageBody && n.props && n.props.roomID,
|
||||||
Twilight.CHAT_ROUTES
|
Twilight.CHAT_ROUTES
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.WhisperLine = this.fine.define(
|
||||||
|
'whisper-line',
|
||||||
|
n => n.props && n.props.message && n.props.reportOutgoingWhisperRendered
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async onEnable() {
|
async onEnable() {
|
||||||
|
@ -157,7 +162,50 @@ export default class ChatLine extends Module {
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
|
|
||||||
|
this.WhisperLine.ready(cls => {
|
||||||
|
const old_render = cls.prototype.render;
|
||||||
|
|
||||||
|
cls.prototype.render = function() {
|
||||||
|
if ( ! this.props.message || ! this.props.message.content )
|
||||||
|
return old_render.call(this);
|
||||||
|
|
||||||
|
const msg = t.chat.standardizeWhisper(this.props.message),
|
||||||
|
|
||||||
|
is_action = msg.is_action,
|
||||||
|
user = msg.user,
|
||||||
|
color = t.parent.colors.process(user.color),
|
||||||
|
|
||||||
|
tokens = msg.ffz_tokens = msg.ffz_tokens || t.chat.tokenizeMessage(msg, null, null),
|
||||||
|
contents = t.chat.renderTokens(tokens, e);
|
||||||
|
|
||||||
|
return e('div', {className: 'thread-message__message'},
|
||||||
|
e('div', {className: 'tw-pd-x-1 tw-pd-y-05'}, [
|
||||||
|
e('span', {
|
||||||
|
className: 'thread-message__message--user-name notranslate',
|
||||||
|
style: {
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}, user.displayName),
|
||||||
|
e('span', null, is_action ? ' ' : ': '),
|
||||||
|
e('span', {
|
||||||
|
className: 'message',
|
||||||
|
style: {
|
||||||
|
color: is_action && color
|
||||||
|
}
|
||||||
|
}, contents)
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do this after a short delay to hopefully reduce the chance of React
|
||||||
|
// freaking out on us.
|
||||||
|
setTimeout(() => this.WhisperLine.forceUpdate());
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
this.ChatLine.ready(cls => {
|
this.ChatLine.ready(cls => {
|
||||||
|
const old_render = cls.prototype.render;
|
||||||
|
|
||||||
cls.prototype.shouldComponentUpdate = function(props, state) {
|
cls.prototype.shouldComponentUpdate = function(props, state) {
|
||||||
const show = state.alwaysShowMessage || ! props.message.deleted,
|
const show = state.alwaysShowMessage || ! props.message.deleted,
|
||||||
old_show = this._ffz_show;
|
old_show = this._ffz_show;
|
||||||
|
@ -176,6 +224,8 @@ export default class ChatLine extends Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
cls.prototype.render = function() {
|
cls.prototype.render = function() {
|
||||||
|
try {
|
||||||
|
|
||||||
const types = t.parent.message_types || {},
|
const types = t.parent.message_types || {},
|
||||||
|
|
||||||
msg = t.chat.standardizeMessage(this.props.message),
|
msg = t.chat.standardizeMessage(this.props.message),
|
||||||
|
@ -233,7 +283,7 @@ export default class ChatLine extends Module {
|
||||||
bg_css = msg.mentioned && msg.mention_color ? t.parent.inverse_colors.process(msg.mention_color) : null;
|
bg_css = msg.mentioned && msg.mention_color ? t.parent.inverse_colors.process(msg.mention_color) : null;
|
||||||
|
|
||||||
if ( ! this.ffz_user_click_handler )
|
if ( ! this.ffz_user_click_handler )
|
||||||
this.ffz_user_click_handler = this.usernameClickHandler; // event => event.ctrlKey ? this.usernameClickHandler(event) : t.viewer_cards.openCard(r, user, event);
|
this.ffz_user_click_handler = this.usernameClickHandler; // event => ! event.ctrlKey ? this.usernameClickHandler(event) : t.viewer_cards.openCard(r, user, event);
|
||||||
|
|
||||||
let cls = `chat-line__message${show_class ? ' ffz--deleted-message' : ''}`,
|
let cls = `chat-line__message${show_class ? ' ffz--deleted-message' : ''}`,
|
||||||
out = (tokens.length || ! msg.ffz_type) ? [
|
out = (tokens.length || ! msg.ffz_type) ? [
|
||||||
|
@ -363,6 +413,16 @@ export default class ChatLine extends Module {
|
||||||
'data-user-id': user.userID,
|
'data-user-id': user.userID,
|
||||||
'data-user': user.userLogin && user.userLogin.toLowerCase(),
|
'data-user': user.userLogin && user.userLogin.toLowerCase(),
|
||||||
}, out);
|
}, out);
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
t.log.capture(err, {
|
||||||
|
extra: {
|
||||||
|
props: this.props
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return old_render.call(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do this after a short delay to hopefully reduce the chance of React
|
// Do this after a short delay to hopefully reduce the chance of React
|
||||||
|
@ -389,7 +449,14 @@ export default class ChatLine extends Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(const inst of this.WhisperLine.instances) {
|
||||||
|
const msg = inst.props.message;
|
||||||
|
if ( msg && msg._ffz_message )
|
||||||
|
msg._ffz_message = null;
|
||||||
|
}
|
||||||
|
|
||||||
this.ChatLine.forceUpdate();
|
this.ChatLine.forceUpdate();
|
||||||
this.ChatRoomLine.forceUpdate();
|
this.ChatRoomLine.forceUpdate();
|
||||||
|
this.WhisperLine.forceUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -260,8 +260,11 @@ export default class Scroller extends Module {
|
||||||
let step = this.ffz_smooth_scroll,
|
let step = this.ffz_smooth_scroll,
|
||||||
old_time = Date.now();
|
old_time = Date.now();
|
||||||
|
|
||||||
const scroll_content = this.scroll.scrollContent,
|
const scroll_content = this.scroll.scrollContent;
|
||||||
target_top = scroll_content.scrollHeight - scroll_content.clientHeight,
|
if ( ! scroll_content )
|
||||||
|
return;
|
||||||
|
|
||||||
|
const target_top = scroll_content.scrollHeight - scroll_content.clientHeight,
|
||||||
difference = target_top - scroll_content.scrollTop;
|
difference = target_top - scroll_content.scrollTop;
|
||||||
|
|
||||||
// If we are falling behind speed us up
|
// If we are falling behind speed us up
|
||||||
|
|
|
@ -61,7 +61,7 @@ export default class Following extends SiteModule {
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
changed: () => this.ChannelCard.forceUpdate()
|
changed: () => this.parent.DirectoryCard.forceUpdate()
|
||||||
});
|
});
|
||||||
|
|
||||||
this.apollo.registerModifier('FollowedChannels_RENAME2', FOLLOWED_CHANNELS);
|
this.apollo.registerModifier('FollowedChannels_RENAME2', FOLLOWED_CHANNELS);
|
||||||
|
@ -219,7 +219,7 @@ export default class Following extends SiteModule {
|
||||||
|
|
||||||
// Hosted Channel Content
|
// Hosted Channel Content
|
||||||
simplebarContentChildren.push(<a
|
simplebarContentChildren.push(<a
|
||||||
class="tw-interactable"
|
class="tw-interactable tw-interactable--inverted"
|
||||||
href={`/${hostData.channel}`}
|
href={`/${hostData.channel}`}
|
||||||
onClick={e => this.parent.hijackUserClick(e, hostData.channel, this.destroyHostMenu.bind(this))} // eslint-disable-line react/jsx-no-bind
|
onClick={e => this.parent.hijackUserClick(e, hostData.channel, this.destroyHostMenu.bind(this))} // eslint-disable-line react/jsx-no-bind
|
||||||
>
|
>
|
||||||
|
@ -242,7 +242,7 @@ export default class Following extends SiteModule {
|
||||||
for (let i = 0; i < hostData.nodes.length; i++) {
|
for (let i = 0; i < hostData.nodes.length; i++) {
|
||||||
const node = hostData.nodes[i];
|
const node = hostData.nodes[i];
|
||||||
simplebarContentChildren.push(<a
|
simplebarContentChildren.push(<a
|
||||||
class="tw-interactable"
|
class="tw-interactable tw-interactable--inverted"
|
||||||
href={`/${node.login}`}
|
href={`/${node.login}`}
|
||||||
onClick={e => this.parent.hijackUserClick(e, node.login, this.destroyHostMenu.bind(this))} // eslint-disable-line react/jsx-no-bind
|
onClick={e => this.parent.hijackUserClick(e, node.login, this.destroyHostMenu.bind(this))} // eslint-disable-line react/jsx-no-bind
|
||||||
>
|
>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
:data-id="host._id"
|
:data-id="host._id"
|
||||||
class="tw-border-t ffz--host-user"
|
class="tw-border-t ffz--host-user"
|
||||||
>
|
>
|
||||||
<div class="tw-interactable">
|
<div class="tw-interactable tw-interactable--inverted">
|
||||||
<div class="tw-align-items-center tw-flex tw-flex-row tw-flex-nowrap tw-mg-x-1">
|
<div class="tw-align-items-center tw-flex tw-flex-row tw-flex-nowrap tw-mg-x-1">
|
||||||
<figure class="ffz-i-ellipsis-vert handle" />
|
<figure class="ffz-i-ellipsis-vert handle" />
|
||||||
<div class="ffz-channel-avatar">
|
<div class="ffz-channel-avatar">
|
||||||
|
|
|
@ -9,6 +9,8 @@ import {createElement} from 'utilities/dom';
|
||||||
|
|
||||||
import THEME_CSS_URL from 'site/styles/theme.scss';
|
import THEME_CSS_URL from 'site/styles/theme.scss';
|
||||||
|
|
||||||
|
const BAD_ROUTES = ['product'];
|
||||||
|
|
||||||
|
|
||||||
export default class ThemeEngine extends Module {
|
export default class ThemeEngine extends Module {
|
||||||
constructor(...args) {
|
constructor(...args) {
|
||||||
|
@ -17,14 +19,15 @@ export default class ThemeEngine extends Module {
|
||||||
|
|
||||||
this.inject('site');
|
this.inject('site');
|
||||||
this.inject('site.css_tweaks');
|
this.inject('site.css_tweaks');
|
||||||
|
this.inject('site.router');
|
||||||
|
|
||||||
this.should_enable = true;
|
this.should_enable = true;
|
||||||
|
|
||||||
this.settings.add('theme.dark', {
|
this.settings.add('theme.dark', {
|
||||||
requires: ['context.ui.theme'],
|
requires: ['theme.is-dark'],
|
||||||
default: false,
|
default: false,
|
||||||
process(ctx, val) {
|
process(ctx, val) {
|
||||||
return ctx.get('context.ui.theme') === 1 ? val : false
|
return ctx.get('theme.is-dark') ? val : false
|
||||||
},
|
},
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
|
@ -37,10 +40,17 @@ export default class ThemeEngine extends Module {
|
||||||
changed: val => this.updateSetting(val)
|
changed: val => this.updateSetting(val)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.settings.add('theme.is-dark', {
|
this.settings.add('theme.can-dark', {
|
||||||
requires: ['context.ui.theme'],
|
requires: ['context.route.name'],
|
||||||
process(ctx) {
|
process(ctx) {
|
||||||
return ctx.get('context.ui.theme') === 1;
|
return ! BAD_ROUTES.includes(ctx.get('context.route.name'))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.settings.add('theme.is-dark', {
|
||||||
|
requires: ['theme.can-dark', 'context.ui.theme'],
|
||||||
|
process(ctx) {
|
||||||
|
return ctx.get('theme.can-dark') && ctx.get('context.ui.theme') === 1;
|
||||||
},
|
},
|
||||||
changed: () => this.updateCSS()
|
changed: () => this.updateCSS()
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
z-index: 9001;
|
z-index: 9001;
|
||||||
|
|
||||||
> header {
|
> header {
|
||||||
|
cursor: move;
|
||||||
|
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: top;
|
background-position: top;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,18 @@ export function array_equals(a, b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function shallow_object_equals(a, b) {
|
||||||
|
if ( typeof a !== 'object' || typeof b !== 'object' || ! array_equals(Object.keys(a), Object.keys(b)) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for(const key in a)
|
||||||
|
if ( a[key] !== b[key] )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function set_equals(a,b) {
|
export function set_equals(a,b) {
|
||||||
if ( !(a instanceof Set) || !(b instanceof Set) || a.size !== b.size )
|
if ( !(a instanceof Set) || !(b instanceof Set) || a.size !== b.size )
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -71,6 +71,11 @@ export class Vue extends Module {
|
||||||
return t.i18n.t(key, phrase, options);
|
return t.i18n.t(key, phrase, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
tList_(key, phrase, options) {
|
||||||
|
this.locale && this.phrases[key];
|
||||||
|
return t.i18n.tList(key, phrase, options);
|
||||||
|
},
|
||||||
|
|
||||||
setLocale(locale) {
|
setLocale(locale) {
|
||||||
t.i18n.locale = locale;
|
t.i18n.locale = locale;
|
||||||
}
|
}
|
||||||
|
@ -96,6 +101,9 @@ export class Vue extends Module {
|
||||||
methods: {
|
methods: {
|
||||||
t(key, phrase, options) {
|
t(key, phrase, options) {
|
||||||
return this.$i18n.t_(key, phrase, options);
|
return this.$i18n.t_(key, phrase, options);
|
||||||
|
},
|
||||||
|
tList(key, phrase, options) {
|
||||||
|
return this.$i18n.tList_(key, phrase, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue