this.shouldShow(addon));
},
+ listed_addons() {
+ return this.sorted_addons.filter(addon => ! addon.unlisted)
+ },
+
sorted_addons() {
const addons = this.item.getAddons();
diff --git a/src/settings/components/monitor.vue b/src/settings/components/monitor.vue
new file mode 100644
index 00000000..71622a82
--- /dev/null
+++ b/src/settings/components/monitor.vue
@@ -0,0 +1,65 @@
+
+
+
+
+ {{ t(type.i18n, type.title) }}
+
+
+
+
+
+ {{ mon.label }} ({{ mon.width }}×{{ mon.height }})
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/settings/filters.js b/src/settings/filters.js
index d7688c7b..3571b931 100644
--- a/src/settings/filters.js
+++ b/src/settings/filters.js
@@ -37,6 +37,21 @@ export const Invert = {
editor: () => import(/* webpackChunkName: 'main-menu' */ './components/nested.vue')
};
+export const And = {
+ createTest(config, rule_types, rebuild) {
+ return createTester(config, rule_types, false, false, rebuild);
+ },
+
+ childRules: true,
+
+ tall: true,
+ title: 'And',
+ i18n: 'settings.filter.and',
+
+ default: () => [],
+ editor: () => import(/* webpackChunkName: 'main-menu' */ './components/nested.vue')
+};
+
export const Or = {
createTest(config, rule_types, rebuild) {
return createTester(config, rule_types, false, true, rebuild);
@@ -83,7 +98,7 @@ export const Constant = {
default: true,
editor: () => import(/* webpackChunkName: 'main-menu' */ './components/basic-toggle.vue')
-}
+};
// Context Stuff
@@ -374,4 +389,54 @@ export const Title = {
}),
editor: () => import(/* webpackChunkName: 'main-menu' */ './components/title.vue')
-};
\ No newline at end of file
+};
+
+// Monitor Stuff
+
+export let Monitor = null;
+
+if ( window.getScreenDetails ) {
+
+ Monitor = {
+ _used: false,
+ details: undefined,
+
+ used: () => {
+ const out = Monitor._used;
+ Monitor._used = false;
+ return out;
+ },
+
+ createTest(config = {}, _, reload) {
+ if ( ! config.label )
+ return () => false;
+
+ Monitor._used = true;
+ if ( Monitor.details === undefined )
+ FrankerFaceZ.get().resolve('settings').createMonitorUpdate().then(() => {
+ reload();
+ });
+
+ return () => {
+ Monitor._used = true;
+ const details = Monitor.details,
+ screen = details?.currentScreen;
+
+ if ( ! screen )
+ return false;
+
+ return screen.label === config.label;
+ };
+ },
+
+ default: () => ({
+ label: null
+ }),
+
+ title: 'Current Monitor',
+ i18n: 'settings.filter.monitor',
+
+ editor: () => import(/* webpackChunkName: 'main-menu' */ './components/monitor.vue')
+ };
+
+}
diff --git a/src/settings/index.js b/src/settings/index.js
index 083ff1bd..b537da81 100644
--- a/src/settings/index.js
+++ b/src/settings/index.js
@@ -110,7 +110,7 @@ export default class SettingsManager extends Module {
this.filters = {};
for(const key in FILTERS)
- if ( has(FILTERS, key) )
+ if ( has(FILTERS, key) && FILTERS[key] )
this.filters[key] = FILTERS[key];
@@ -247,8 +247,28 @@ export default class SettingsManager extends Module {
}
+ async createMonitorUpdate() {
+ const Monitor = FILTERS?.Monitor;
+ if ( ! Monitor || Monitor.details !== undefined )
+ return;
+
+ Monitor.details = null;
+ try {
+ Monitor.details = await window.getScreenDetails();
+ Monitor.details.addEventListener('currentscreenchange', () => {
+ for(const context of this.__contexts)
+ context.selectProfiles();
+ });
+
+ } catch(err) {
+ this.log.error('Unable to get monitor details', err);
+ Monitor.details = false;
+ }
+ }
+
+
updateClock() {
- const captured = require('./filters').Time.captured();
+ const captured = FILTERS?.Time?.captured?.();
if ( ! captured?.length )
return;
@@ -918,7 +938,19 @@ export default class SettingsManager extends Module {
_saveProfiles() {
- this.provider.set('profiles', this.__profiles.filter(prof => ! prof.ephemeral).map(prof => prof.data));
+ const out = this.__profiles.filter(prof => ! prof.ephemeral).map(prof => prof.data);
+
+ // Ensure that we always have a non-ephemeral profile.
+ if ( ! out ) {
+ this.createProfile({
+ name: 'Default Profile',
+ i18n_key: 'setting.profiles.default',
+ description: 'Settings that apply everywhere on Twitch.'
+ });
+ return;
+ }
+
+ this.provider.set('profiles', out);
for(const context of this.__contexts)
context.selectProfiles();
diff --git a/src/sites/twitch-twilight/modules/chat/emote_menu.jsx b/src/sites/twitch-twilight/modules/chat/emote_menu.jsx
index b8008b11..c020e890 100644
--- a/src/sites/twitch-twilight/modules/chat/emote_menu.jsx
+++ b/src/sites/twitch-twilight/modules/chat/emote_menu.jsx
@@ -1212,7 +1212,7 @@ export default class EmoteMenu extends Module {
requestAnimationFrame(() => {
const el = this.nav_ref?.querySelector?.(`button[data-key="${this.state.active_nav}"]`);
if ( el )
- el.scrollIntoView({block: 'nearest'});
+ el.scrollIntoView({block: 'nearest', inline: 'start'});
});
}
@@ -1342,7 +1342,7 @@ export default class EmoteMenu extends Module {
const el = this.ref?.querySelector?.(`section[data-key="${key}"]`);
if ( el ) {
this.lock_active = true;
- el.scrollIntoView();
+ el.scrollIntoView({block: 'nearest', inline: 'start'});
this.setState({
active_nav: key
});
@@ -1381,7 +1381,7 @@ export default class EmoteMenu extends Module {
el = set && this.ref?.querySelector?.(`section[data-key="${set.key}"]`);
if ( el )
- el.scrollIntoView();
+ el.scrollIntoView({block: 'nearest', inline: 'start'});
return;
}
diff --git a/src/utilities/fonts.js b/src/utilities/fonts.js
index 4d936ea0..aa606839 100644
--- a/src/utilities/fonts.js
+++ b/src/utilities/fonts.js
@@ -22,7 +22,9 @@ const KNOWN_FONTS = [
'Comic Sans MS',
];
-export const VALID_FONTS = KNOWN_FONTS.filter(font => document.fonts.check(`16px ${font}`)).sort();
+export const VALID_FONTS = document.fonts?.check
+ ? KNOWN_FONTS.filter(font => document.fonts.check(`16px ${font}`)).sort()
+ : KNOWN_FONTS.sort();
/* Google Font Handling */