diff --git a/package-lock.json b/package-lock.json index 7483e993..40ed8a15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1378,7 +1378,6 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "dev": true, - "optional": true, "requires": { "tweetnacl": "^0.14.3" } @@ -2001,9 +2000,9 @@ "dev": true }, "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "dev": true, "requires": { "delayed-stream": "~1.0.0" @@ -2718,7 +2717,6 @@ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "dev": true, - "optional": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -3626,6 +3624,11 @@ } } }, + "file-saver": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.1.tgz", + "integrity": "sha512-dCB3K7/BvAcUmtmh1DzFdv0eXSVJ9IAFt1mw3XZfAexodNRoE29l3xB2EX4wH2q8m/UTzwzEPq/ArYk98kUkBQ==" + }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", @@ -3757,13 +3760,13 @@ "dev": true }, "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "1.0.6", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, @@ -4583,13 +4586,54 @@ "dev": true }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", "dev": true, "requires": { - "ajv": "^5.1.0", + "ajv": "^6.5.5", "har-schema": "^2.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + } } }, "has": { @@ -5557,8 +5601,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true + "dev": true }, "jsesc": { "version": "0.5.0", @@ -5757,9 +5800,9 @@ } }, "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, "lodash.assign": { @@ -6328,9 +6371,9 @@ } }, "node-sass": { - "version": "4.9.3", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.3.tgz", - "integrity": "sha512-XzXyGjO+84wxyH7fV6IwBOTrEBe2f0a6SBze9QWWYR/cL74AcQUks2AsqcCZenl/Fp/JVbuEaLpgrLtocwBUww==", + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", + "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==", "dev": true, "requires": { "async-foreach": "^0.1.3", @@ -6348,7 +6391,7 @@ "nan": "^2.10.0", "node-gyp": "^3.8.0", "npmlog": "^4.0.0", - "request": "2.87.0", + "request": "^2.88.0", "sass-graph": "^2.2.4", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" @@ -6448,9 +6491,9 @@ "dev": true }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, "object-assign": { @@ -7588,6 +7631,12 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "dev": true + }, "public-encrypt": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", @@ -7984,31 +8033,60 @@ } }, "request": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "dev": true, "requires": { "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", + "aws4": "^1.8.0", "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "uuid": "^3.3.2" + }, + "dependencies": { + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", + "dev": true + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "dev": true, + "requires": { + "mime-db": "~1.38.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } } }, "require-directory": { @@ -8779,9 +8857,9 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, "sshpk": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", - "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -8832,9 +8910,9 @@ "dev": true }, "stdout-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", - "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", "dev": true, "requires": { "readable-stream": "^2.0.1" @@ -9196,11 +9274,12 @@ } }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { + "psl": "^1.1.24", "punycode": "^1.4.1" } }, @@ -9217,27 +9296,12 @@ "dev": true }, "true-case-path": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", - "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", "dev": true, "requires": { - "glob": "^6.0.4" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } + "glob": "^7.1.2" } }, "tty-browserify": { @@ -9259,8 +9323,7 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true, - "optional": true + "dev": true }, "type-check": { "version": "0.3.2", @@ -10347,9 +10410,9 @@ }, "dependencies": { "lodash": { - "version": "4.17.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true } } diff --git a/package.json b/package.json index c5f76a9d..4a9d9831 100755 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "eslint-plugin-vue": "^4.5.0", "extract-loader": "^1.0.2", "file-loader": "^1.1.11", - "node-sass": "^4.9.3", + "node-sass": "^4.11.0", "raw-loader": "^0.5.1", "sass-loader": "^6.0.7", "style-loader": "^0.18.2", @@ -58,6 +58,7 @@ "dayjs": "^1.7.7", "displacejs": "^1.2.4", "emoji-regex": "^6.5.1", + "file-saver": "^2.0.1", "graphql": "^0.13.2", "graphql-tag": "^2.9.1", "js-cookie": "^2.2.0", diff --git a/res/font/ffz-fontello.eot b/res/font/ffz-fontello.eot index 92503d02..886e3abe 100644 Binary files a/res/font/ffz-fontello.eot and b/res/font/ffz-fontello.eot differ diff --git a/res/font/ffz-fontello.svg b/res/font/ffz-fontello.svg index 1f672a2b..4e2b57a3 100644 --- a/res/font/ffz-fontello.svg +++ b/res/font/ffz-fontello.svg @@ -96,11 +96,15 @@ + + + + - + @@ -108,6 +112,8 @@ + + diff --git a/res/font/ffz-fontello.ttf b/res/font/ffz-fontello.ttf index 05697d85..43ab3c1f 100644 Binary files a/res/font/ffz-fontello.ttf and b/res/font/ffz-fontello.ttf differ diff --git a/res/font/ffz-fontello.woff b/res/font/ffz-fontello.woff index 3b2132b9..d2127e63 100644 Binary files a/res/font/ffz-fontello.woff and b/res/font/ffz-fontello.woff differ diff --git a/res/font/ffz-fontello.woff2 b/res/font/ffz-fontello.woff2 index 025c0b5b..e74652b7 100644 Binary files a/res/font/ffz-fontello.woff2 and b/res/font/ffz-fontello.woff2 differ diff --git a/src/main.js b/src/main.js index e1a9c363..74ad7c2e 100644 --- a/src/main.js +++ b/src/main.js @@ -149,7 +149,7 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}` FrankerFaceZ.Logger = Logger; const VER = FrankerFaceZ.version_info = { - major: 4, minor: 0, revision: 0, extra: '-rc14.2', + major: 4, minor: 0, revision: 0, extra: '-rc15', commit: __git_commit__, build: __webpack_hash__, toString: () => diff --git a/src/modules/main_menu/components/backup-restore.vue b/src/modules/main_menu/components/backup-restore.vue new file mode 100644 index 00000000..c24a9754 --- /dev/null +++ b/src/modules/main_menu/components/backup-restore.vue @@ -0,0 +1,142 @@ + + + \ No newline at end of file diff --git a/src/modules/main_menu/index.js b/src/modules/main_menu/index.js index fa138244..8f73ee48 100644 --- a/src/modules/main_menu/index.js +++ b/src/modules/main_menu/index.js @@ -47,6 +47,12 @@ export default class MainMenu extends Module { component: 'profile-manager' }); + this.settings.addUI('backup', { + path: 'Data Management > Backup and Restore @{"profile_warning": false}', + component: 'backup-restore', + getFFZ: () => this.resolve('core') + }); + this.settings.addUI('home', { path: 'Home @{"sort": -1000, "profile_warning": false}', component: 'home-page' diff --git a/src/settings/index.js b/src/settings/index.js index c786b4cf..36d72cb2 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -95,6 +95,28 @@ export default class SettingsManager extends Module { } + // ======================================================================== + // Backup and Restore + // ======================================================================== + + async getFullBackup() { + // Before we do anything else, make sure the provider is ready. + await this.provider.awaitReady(); + + const out = { + version: 2, + type: 'full', + values: {} + }; + + for(const [k, v] of this.provider.entries()) + out.values[k] = v; + + return out; + } + + + // ======================================================================== // Provider Interaction // ======================================================================== diff --git a/src/settings/providers.js b/src/settings/providers.js index 487011ba..437a03c2 100644 --- a/src/settings/providers.js +++ b/src/settings/providers.js @@ -191,10 +191,14 @@ export class LocalStorageProvider extends SettingsProvider { } clear() { - for(const key of this._cached.keys()) - localStorage.removeItem(this.prefix + key); + const old_cache = this._cached; + this._cached = new Map; + + for(const key of old_cache.keys()) { + localStorage.removeItem(this.prefix + key); + this.emit('changed', key, undefined, true); + } - this._cached.clear(); this.broadcast({type: 'clear'}); } diff --git a/src/sites/twitch-twilight/index.js b/src/sites/twitch-twilight/index.js index a3972fa3..a318cbba 100644 --- a/src/sites/twitch-twilight/index.js +++ b/src/sites/twitch-twilight/index.js @@ -212,6 +212,7 @@ Twilight.ROUTES = { 'prime': '/prime', 'turbo': '/turbo', 'user': '/:userName', + 'squad': '/:userName/squad', 'embed-chat': '/embed/:userName/chat' } diff --git a/src/sites/twitch-twilight/modules/chat/emote_menu.jsx b/src/sites/twitch-twilight/modules/chat/emote_menu.jsx index 106dcf47..d1f13e4a 100644 --- a/src/sites/twitch-twilight/modules/chat/emote_menu.jsx +++ b/src/sites/twitch-twilight/modules/chat/emote_menu.jsx @@ -938,7 +938,7 @@ export default class EmoteMenu extends Module { clickTab(event) { this.setState({ - tab: event.target.dataset.tab + tab: event.currentTarget.dataset.tab }); } @@ -1706,49 +1706,75 @@ export default class EmoteMenu extends Module { />} )} -
-
-
+
+
+
- {this.state.has_channel_tab &&
- {t.i18n.t('emote-menu.channel', 'Channel')} + {this.state.has_channel_tab &&
+
} -
- {t.i18n.t('emote-menu.my-emotes', 'My Emotes')} +
+
- {this.state.has_emoji_tab &&
- {t.i18n.t('emote-menu.emoji', 'Emoji')} + {this.state.has_emoji_tab &&
+
}
- {!loading && (
-
+ {!loading && (
+
)}
diff --git a/src/sites/twitch-twilight/modules/chat/index.js b/src/sites/twitch-twilight/modules/chat/index.js index ad180ad6..90923e83 100644 --- a/src/sites/twitch-twilight/modules/chat/index.js +++ b/src/sites/twitch-twilight/modules/chat/index.js @@ -89,6 +89,7 @@ const CHAT_TYPES = make_enum( 'Resubscription', 'GiftPaidUpgrade', 'AnonGiftPaidUpgrade', + 'PrimePaidUpgrade', 'SubGift', 'AnonSubGift', 'Clear', @@ -274,6 +275,15 @@ export default class ChatHook extends Module { } }); + this.settings.add('chat.subs.merge-gifts-visibility', { + default: false, + ui: { + path: 'Chat > Appearance >> Subscriptions', + title: 'Expand merged mass sub gift messages by default.', + component: 'setting-check-box' + } + }); + this.settings.add('chat.lines.alternate', { default: false, ui: { diff --git a/src/sites/twitch-twilight/modules/chat/line.js b/src/sites/twitch-twilight/modules/chat/line.js index 959a36b5..86f5dc54 100644 --- a/src/sites/twitch-twilight/modules/chat/line.js +++ b/src/sites/twitch-twilight/modules/chat/line.js @@ -416,8 +416,11 @@ export default class ChatLine extends Module { }); } + const expanded = t.chat.context.get('chat.subs.merge-gifts-visibility') ? + ! this.state.ffz_expanded : this.state.ffz_expanded; + let sub_list = null; - if( this.state.ffz_expanded && mystery && mystery.recipients && mystery.recipients.length > 0 ) { + if( expanded && mystery && mystery.recipients && mystery.recipients.length > 0 ) { const the_list = []; for(const x of mystery.recipients) { if ( the_list.length ) @@ -455,7 +458,7 @@ export default class ChatLine extends Module { mystery ? e('div', { className: 'tw-pd-l-05 tw-font-size-4' }, e('figure', { - className: `ffz-i-${this.state.ffz_expanded ? 'down' : 'right'}-dir tw-pd-y-1` + className: `ffz-i-${expanded ? 'down' : 'right'}-dir tw-pd-y-1` })) : null ]), sub_list, diff --git a/src/sites/twitch-twilight/modules/css_tweaks/index.js b/src/sites/twitch-twilight/modules/css_tweaks/index.js index 8b71b19f..146c1f5f 100644 --- a/src/sites/twitch-twilight/modules/css_tweaks/index.js +++ b/src/sites/twitch-twilight/modules/css_tweaks/index.js @@ -12,6 +12,7 @@ import {has} from 'utilities/object'; const PORTRAIT_ROUTES = ['user', 'video', 'user-video', 'user-clip', 'user-videos', 'user-clips', 'user-collections', 'user-events', 'user-followers', 'user-following'] const CLASSES = { + 'top-discover': '.top-nav__nav-link[data-a-target="discover-link"]', 'side-nav': '.side-nav', 'side-rec-channels': '.side-nav .recommended-channels', 'side-rec-friends': '.side-nav .recommended-friends', @@ -30,7 +31,7 @@ const CLASSES = { 'pinned-cheer': '.pinned-cheer,.pinned-cheer-v2', 'whispers': '.whispers', - 'dir-live-ind': '.live-channel-card:not([data-a-target*="host"]) .stream-type-indicator.stream-type-indicator--live,.stream-thumbnail__card .stream-type-indicator.stream-type-indicator--live,.preview-card .stream-type-indicator.stream-type-indicator--live', + 'dir-live-ind': '.live-channel-card:not([data-a-target*="host"]) .stream-type-indicator.stream-type-indicator--live,.stream-thumbnail__card .stream-type-indicator.stream-type-indicator--live,.preview-card .stream-type-indicator.stream-type-indicator--live,.preview-card .preview-card-stat.preview-card-stat--live', 'profile-hover': '.preview-card .tw-relative:hover .ffz-channel-avatar', }; @@ -242,7 +243,17 @@ export default class CSSTweaks extends Module { component: 'setting-check-box' }, changed: val => this.toggle('theatre-nav', val) - }) + }); + + this.settings.add('layout.discover', { + default: true, + ui: { + path: 'Appearance > Layout >> Top Navigation', + title: 'Show Discover link.', + component: 'setting-check-box' + }, + changed: val => this.toggleHide('top-discover', !val) + }); this.settings.add('layout.prime-offers', { default: true, @@ -290,6 +301,7 @@ export default class CSSTweaks extends Module { this.toggleHide('side-nav', !this.settings.get('layout.side-nav.show')); this.toggleHide('side-rec-friends', !this.settings.get('layout.side-nav.show-rec-friends')); this.toggleHide('prime-offers', !this.settings.get('layout.prime-offers')); + this.toggleHide('top-discover', !this.settings.get('layout.discover')); const recs = this.settings.get('layout.side-nav.show-rec-channels'); this.toggleHide('side-rec-channels', recs === 0); diff --git a/src/sites/twitch-twilight/styles/chat.scss b/src/sites/twitch-twilight/styles/chat.scss index 6f847015..722de55d 100644 --- a/src/sites/twitch-twilight/styles/chat.scss +++ b/src/sites/twitch-twilight/styles/chat.scss @@ -188,7 +188,7 @@ } } - .emote-picker__tab > *, + .emote-picker-tab-item button > *, .emote-picker__emote-link > * { pointer-events: none; } diff --git a/src/utilities/dom.js b/src/utilities/dom.js index 2c5b7518..c0779fcc 100644 --- a/src/utilities/dom.js +++ b/src/utilities/dom.js @@ -132,6 +132,33 @@ export function setChildren(el, children, no_sanitize, no_empty) { } +export function openFile(contentType, multiple) { + return new Promise(resolve => { + const input = document.createElement('input'); + input.type = 'file'; + input.accept = contentType; + input.multiple = multiple; + + input.onchange = () => { + const files = Array.from(input.files); + resolve(multiple ? files : files[0]) + } + + input.click(); + }) +} + + +export function readFile(file, encoding = 'utf-8') { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsText(file, encoding); + reader.onload = () => resolve(reader.result); + reader.onerror = e => reject(e); + }); +} + + const el = createElement('span'); export function sanitize(text) { diff --git a/styles/icons.scss b/styles/icons.scss index 69585c85..685ae846 100644 --- a/styles/icons.scss +++ b/styles/icons.scss @@ -119,12 +119,15 @@ .ffz-i-eye-off:before { content: '\e82a'; } /* '' */ .ffz-i-views:before { content: '\e82b'; } /* '' */ .ffz-i-conversations:before { content: '\e82c'; } /* '' */ +.ffz-i-channels:before { content: '\e82d'; } /* '' */ +.ffz-i-camera:before { content: '\e82e'; } /* '' */ .ffz-i-link-ext:before { content: '\f08e'; } /* '' */ .ffz-i-twitter:before { content: '\f099'; } /* '' */ .ffz-i-github:before { content: '\f09b'; } /* '' */ .ffz-i-gauge:before { content: '\f0e4'; } /* '' */ .ffz-i-download-cloud:before { content: '\f0ed'; } /* '' */ .ffz-i-upload-cloud:before { content: '\f0ee'; } /* '' */ +.ffz-i-smile:before { content: '\f118'; } /* '' */ .ffz-i-keyboard:before { content: '\f11c'; } /* '' */ .ffz-i-calendar-empty:before { content: '\f133'; } /* '' */ .ffz-i-ellipsis-vert:before { content: '\f142'; } /* '' */