diff --git a/.gitignore b/.gitignore index ec82ea5f..4a3daa1f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ test-results.xml test_config.json .idea testUserData + +src/browser/*.png +src/browser/*.svg +src/browser/*.woff2 \ No newline at end of file diff --git a/electron-builder.json b/electron-builder.json index 454f6459..1d2bdfb4 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -12,7 +12,7 @@ }, "files": [ "main_bundle.js", - "browser/**/*{.html,.css,_bundle.js}", + "browser/**/*{.html,.css,_bundle.js,.svg,.png}", "assets/**/*", "node_modules/bootstrap/dist/**", "node_modules/simple-spellchecker/dict/*.dic" diff --git a/package-lock.json b/package-lock.json index f9b3a2cf..ea89b3a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1396,6 +1396,13 @@ "integrity": "sha512-wuJwN2KV4tIRz1bu9vq5kSPasJ8IsEjZaP1ZR7KlmdUZvGF/rXy8DmXOVwUD0kAtvtJ7aqMKPqUXC0NUTDbrDg==", "dev": true }, + "@types/q": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz", + "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==", + "dev": true, + "optional": true + }, "@webassemblyjs/ast": { "version": "1.7.11", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz", @@ -1879,6 +1886,32 @@ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true }, + "arch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.1.tgz", + "integrity": "sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg==", + "dev": true, + "optional": true + }, + "archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=", + "dev": true, + "optional": true, + "requires": { + "file-type": "^4.2.0" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", + "dev": true, + "optional": true + } + } + }, "archiver": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/archiver/-/archiver-2.1.1.tgz", @@ -2619,6 +2652,297 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, + "bin-build": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz", + "integrity": "sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA==", + "dev": true, + "optional": true, + "requires": { + "decompress": "^4.0.0", + "download": "^6.2.2", + "execa": "^0.7.0", + "p-map-series": "^1.0.0", + "tempfile": "^2.0.0" + } + }, + "bin-check": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", + "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", + "dev": true, + "optional": true, + "requires": { + "execa": "^0.7.0", + "executable": "^4.1.0" + } + }, + "bin-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz", + "integrity": "sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ==", + "dev": true, + "optional": true, + "requires": { + "execa": "^1.0.0", + "find-versions": "^3.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "optional": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "optional": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "optional": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "bin-version-check": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz", + "integrity": "sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ==", + "dev": true, + "optional": true, + "requires": { + "bin-version": "^3.0.0", + "semver": "^5.6.0", + "semver-truncate": "^1.1.2" + } + }, + "bin-wrapper": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz", + "integrity": "sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q==", + "dev": true, + "optional": true, + "requires": { + "bin-check": "^4.1.0", + "bin-version-check": "^4.0.0", + "download": "^7.1.0", + "import-lazy": "^3.1.0", + "os-filter-obj": "^2.0.0", + "pify": "^4.0.1" + }, + "dependencies": { + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true, + "optional": true + }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "optional": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true, + "optional": true + } + } + }, + "download": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz", + "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==", + "dev": true, + "optional": true, + "requires": { + "archive-type": "^4.0.0", + "caw": "^2.0.1", + "content-disposition": "^0.5.2", + "decompress": "^4.2.0", + "ext-name": "^5.0.0", + "file-type": "^8.1.0", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^8.3.1", + "make-dir": "^1.2.0", + "p-event": "^2.1.0", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "optional": true + } + } + }, + "file-type": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz", + "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==", + "dev": true, + "optional": true + }, + "got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "dev": true, + "optional": true, + "requires": { + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "optional": true + } + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true, + "optional": true + }, + "import-lazy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz", + "integrity": "sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ==", + "dev": true, + "optional": true + }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "optional": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "optional": true, + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + } + }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "dev": true, + "optional": true + }, + "p-event": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz", + "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==", + "dev": true, + "optional": true, + "requires": { + "p-timeout": "^2.0.1" + } + }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "optional": true, + "requires": { + "p-finally": "^1.0.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "optional": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + } + } + }, "binary-extensions": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", @@ -3250,6 +3574,19 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "dev": true, + "optional": true, + "requires": { + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" + } + }, "chai": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", @@ -3521,6 +3858,18 @@ "mimic-response": "^1.0.0" } }, + "coa": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz", + "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==", + "dev": true, + "optional": true, + "requires": { + "@types/q": "^1.5.1", + "chalk": "^2.4.1", + "q": "^1.1.2" + } + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -3663,6 +4012,17 @@ "typedarray": "^0.0.6" } }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dev": true, + "optional": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "configstore": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/configstore/-/configstore-4.0.0.tgz", @@ -3698,6 +4058,13 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, + "console-stream": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/console-stream/-/console-stream-0.1.1.tgz", + "integrity": "sha1-oJX+B7IEZZVfL6/Si11yvM2UnUQ=", + "dev": true, + "optional": true + }, "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", @@ -4013,6 +4380,13 @@ "nth-check": "~1.0.1" } }, + "css-select-base-adapter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", + "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==", + "dev": true, + "optional": true + }, "css-selector-tokenizer": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", @@ -4058,6 +4432,17 @@ } } }, + "css-tree": { + "version": "1.0.0-alpha.33", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.33.tgz", + "integrity": "sha512-SPt57bh5nQnpsTBsx/IXbO14sRc9xXu5MtMAVuo0BaQQmyf0NupNPPSoMaqiAF5tDFafYsTkfeH4Q/HCKXkg4w==", + "dev": true, + "optional": true, + "requires": { + "mdn-data": "2.0.4", + "source-map": "^0.5.3" + } + }, "css-value": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/css-value/-/css-value-0.0.1.tgz", @@ -4076,6 +4461,36 @@ "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", "dev": true }, + "csso": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz", + "integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==", + "dev": true, + "optional": true, + "requires": { + "css-tree": "1.0.0-alpha.29" + }, + "dependencies": { + "css-tree": { + "version": "1.0.0-alpha.29", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", + "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", + "dev": true, + "optional": true, + "requires": { + "mdn-data": "~1.1.0", + "source-map": "^0.5.3" + } + }, + "mdn-data": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", + "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", + "dev": true, + "optional": true + } + } + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -4085,6 +4500,18 @@ "array-find-index": "^1.0.1" } }, + "cwebp-bin": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cwebp-bin/-/cwebp-bin-5.1.0.tgz", + "integrity": "sha512-BsPKStaNr98zfxwejWWLIGELbPERULJoD2v5ijvpeutSAGsegX7gmABgnkRK7MUucCPROXXfaPqkLAwI509JzA==", + "dev": true, + "optional": true, + "requires": { + "bin-build": "^3.0.0", + "bin-wrapper": "^4.0.1", + "logalot": "^2.1.0" + } + }, "cyclist": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", @@ -4127,6 +4554,32 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "dev": true, + "optional": true, + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "optional": true + } + } + }, "decompress-response": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", @@ -4136,6 +4589,132 @@ "mimic-response": "^1.0.0" } }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "optional": true, + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true, + "optional": true + } + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "optional": true, + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true, + "optional": true + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dev": true, + "optional": true, + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true, + "optional": true + } + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "dev": true, + "optional": true, + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "optional": true, + "requires": { + "pend": "~1.2.0" + } + }, + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "dev": true, + "optional": true + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "dev": true, + "optional": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "optional": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "optional": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } + }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -4603,6 +5182,82 @@ "dotenv-expand": "^4.0.1" } }, + "download": { + "version": "6.2.5", + "resolved": "https://registry.npmjs.org/download/-/download-6.2.5.tgz", + "integrity": "sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA==", + "dev": true, + "optional": true, + "requires": { + "caw": "^2.0.0", + "content-disposition": "^0.5.2", + "decompress": "^4.0.0", + "ext-name": "^5.0.0", + "file-type": "5.2.0", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^7.0.0", + "make-dir": "^1.0.0", + "p-event": "^1.0.0", + "pify": "^3.0.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true, + "optional": true + }, + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "optional": true, + "requires": { + "decompress-response": "^3.2.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-plain-obj": "^1.1.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "p-cancelable": "^0.3.0", + "p-timeout": "^1.1.1", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "url-parse-lax": "^1.0.0", + "url-to-options": "^1.0.1" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true, + "optional": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true, + "optional": true + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "optional": true, + "requires": { + "prepend-http": "^1.0.1" + } + } + } + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -5590,6 +6245,20 @@ "safe-buffer": "^5.1.1" } }, + "exec-buffer": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz", + "integrity": "sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==", + "dev": true, + "optional": true, + "requires": { + "execa": "^0.7.0", + "p-finally": "^1.0.0", + "pify": "^3.0.0", + "rimraf": "^2.5.4", + "tempfile": "^2.0.0" + } + }, "execa": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", @@ -5605,6 +6274,25 @@ "strip-eof": "^1.0.0" } }, + "executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "optional": true, + "requires": { + "pify": "^2.2.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "optional": true + } + } + }, "exenv": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", @@ -5731,6 +6419,27 @@ } } }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "optional": true, + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "optional": true, + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -5994,6 +6703,31 @@ "ramda": "^0.21.0" } }, + "file-type": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz", + "integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw==", + "dev": true + }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", + "dev": true, + "optional": true + }, + "filenamify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "dev": true, + "optional": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + } + }, "filesize": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", @@ -6075,6 +6809,26 @@ "locate-path": "^2.0.0" } }, + "find-versions": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.1.0.tgz", + "integrity": "sha512-NCTfNiVzeE/xL+roNDffGuRbrWI6atI18lTJ22vKp7rs2OhYzMK3W1dIdO2TUndH/QMcacM4d1uWwgcZcHK69Q==", + "dev": true, + "optional": true, + "requires": { + "array-uniq": "^2.1.0", + "semver-regex": "^2.0.0" + }, + "dependencies": { + "array-uniq": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-2.1.0.tgz", + "integrity": "sha512-bdHxtev7FN6+MXI1YFW0Q8mQ8dTJc2S8AMfju+ZR77pbg2yAdVyDlwkaUI7Har0LyOMRFPHrJ9lYdyjZZswdlQ==", + "dev": true, + "optional": true + } + } + }, "flat-cache": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", @@ -6828,6 +7582,16 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, + "get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "dev": true, + "optional": true, + "requires": { + "npm-conf": "^1.1.0" + } + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -6855,6 +7619,61 @@ "assert-plus": "^1.0.0" } }, + "gifsicle": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/gifsicle/-/gifsicle-4.0.1.tgz", + "integrity": "sha512-A/kiCLfDdV+ERV/UB+2O41mifd+RxH8jlRG8DMxZO84Bma/Fw0htqZ+hY2iaalLRNyUu7tYZQslqUBJxBggxbg==", + "dev": true, + "optional": true, + "requires": { + "bin-build": "^3.0.0", + "bin-wrapper": "^4.0.0", + "execa": "^1.0.0", + "logalot": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "optional": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "optional": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "optional": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, "glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", @@ -7013,6 +7832,13 @@ "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true, + "optional": true + }, "grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", @@ -7081,12 +7907,29 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true, + "optional": true + }, "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "optional": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -7213,6 +8056,13 @@ "wbuf": "^1.1.0" } }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true, + "optional": true + }, "html-entities": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", @@ -7440,6 +8290,191 @@ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true }, + "image-webpack-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/image-webpack-loader/-/image-webpack-loader-5.0.0.tgz", + "integrity": "sha512-Ov7xyNTpeKqF31UTnFPNxLohsYVGUJA4lKU0Tjld5iIGfqzUMtkaU3/3MDE/QGPV6jfm0ai+vekJHp+VujUpFw==", + "dev": true, + "requires": { + "imagemin": "^6.1.0", + "imagemin-gifsicle": "^6.0.0", + "imagemin-mozjpeg": "^8.0.0", + "imagemin-optipng": "^6.0.0", + "imagemin-pngquant": "^6.0.0", + "imagemin-svgo": "^7.0.0", + "imagemin-webp": "^5.0.0", + "loader-utils": "^1.2.3", + "object-assign": "^4.1.1" + } + }, + "imagemin": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/imagemin/-/imagemin-6.1.0.tgz", + "integrity": "sha512-8ryJBL1CN5uSHpiBMX0rJw79C9F9aJqMnjGnrd/1CafegpNuA81RBAAru/jQQEOWlOJJlpRnlcVFF6wq+Ist0A==", + "dev": true, + "requires": { + "file-type": "^10.7.0", + "globby": "^8.0.1", + "make-dir": "^1.0.0", + "p-pipe": "^1.1.0", + "pify": "^4.0.1", + "replace-ext": "^1.0.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "imagemin-gifsicle": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/imagemin-gifsicle/-/imagemin-gifsicle-6.0.1.tgz", + "integrity": "sha512-kuu47c6iKDQ6R9J10xCwL0lgs0+sMz3LRHqRcJ2CRBWdcNmo3T5hUaM8hSZfksptZXJLGKk8heSAvwtSdB1Fng==", + "dev": true, + "optional": true, + "requires": { + "exec-buffer": "^3.0.0", + "gifsicle": "^4.0.0", + "is-gif": "^3.0.0" + } + }, + "imagemin-mozjpeg": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/imagemin-mozjpeg/-/imagemin-mozjpeg-8.0.0.tgz", + "integrity": "sha512-+EciPiIjCb8JWjQNr1q8sYWYf7GDCNDxPYnkD11TNIjjWNzaV+oTg4DpOPQjl5ZX/KRCPMEgS79zLYAQzLitIA==", + "dev": true, + "optional": true, + "requires": { + "execa": "^1.0.0", + "is-jpg": "^2.0.0", + "mozjpeg": "^6.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "optional": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "optional": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "optional": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "imagemin-optipng": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/imagemin-optipng/-/imagemin-optipng-6.0.0.tgz", + "integrity": "sha512-FoD2sMXvmoNm/zKPOWdhKpWdFdF9qiJmKC17MxZJPH42VMAp17/QENI/lIuP7LCUnLVAloO3AUoTSNzfhpyd8A==", + "dev": true, + "optional": true, + "requires": { + "exec-buffer": "^3.0.0", + "is-png": "^1.0.0", + "optipng-bin": "^5.0.0" + } + }, + "imagemin-pngquant": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/imagemin-pngquant/-/imagemin-pngquant-6.0.1.tgz", + "integrity": "sha512-Stk+fZCLxZznV8MFNA/T3AY/VRKevsiP9uZOLV0RCXoi0vUUFriySYuz/83IGp9D254EW8miGyyQ69zKouFr7w==", + "dev": true, + "optional": true, + "requires": { + "execa": "^0.10.0", + "is-png": "^1.0.0", + "is-stream": "^1.1.0", + "pngquant-bin": "^5.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "optional": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", + "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "dev": true, + "optional": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + } + } + }, + "imagemin-svgo": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/imagemin-svgo/-/imagemin-svgo-7.0.0.tgz", + "integrity": "sha512-+iGJFaPIMx8TjFW6zN+EkOhlqcemdL7F3N3Y0wODvV2kCUBuUtZK7DRZc1+Zfu4U2W/lTMUyx2G8YMOrZntIWg==", + "dev": true, + "optional": true, + "requires": { + "is-svg": "^3.0.0", + "svgo": "^1.0.5" + } + }, + "imagemin-webp": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/imagemin-webp/-/imagemin-webp-5.1.0.tgz", + "integrity": "sha512-BsPTpobgbDPFBBsI3UflnU/cpIVa15qInEDBcYBw16qI/6XiB4vDF/dGp9l4aM3pfFDDYqR0mANMcKpBD7wbCw==", + "dev": true, + "optional": true, + "requires": { + "cwebp-bin": "^5.0.0", + "exec-buffer": "^3.0.0", + "is-cwebp-readable": "^2.0.1" + } + }, "immer": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/immer/-/immer-1.7.2.tgz", @@ -7682,6 +8717,17 @@ "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", "dev": true }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "optional": true, + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + } + }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -7780,6 +8826,25 @@ "ci-info": "^2.0.0" } }, + "is-cwebp-readable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-cwebp-readable/-/is-cwebp-readable-2.0.1.tgz", + "integrity": "sha1-r7k7DAq9CiUQEBauM66ort+SbSY=", + "dev": true, + "optional": true, + "requires": { + "file-type": "^4.3.0" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", + "dev": true, + "optional": true + } + } + }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", @@ -7867,6 +8932,16 @@ "number-is-nan": "^1.0.0" } }, + "is-gif": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-gif/-/is-gif-3.0.0.tgz", + "integrity": "sha512-IqJ/jlbw5WJSNfwQ/lHEDXF8rxhRgF6ythk2oiEvhpG29F704eX9NO6TvPfMiq9DrbwgcEDnETYNcZDPewQoVw==", + "dev": true, + "optional": true, + "requires": { + "file-type": "^10.4.0" + } + }, "is-glob": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", @@ -7886,6 +8961,20 @@ "is-path-inside": "^1.0.0" } }, + "is-jpg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-jpg/-/is-jpg-2.0.0.tgz", + "integrity": "sha1-LhmX+m6RZuqsAkLarkQ0A+TvHZc=", + "dev": true, + "optional": true + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", + "dev": true, + "optional": true + }, "is-npm": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-3.0.0.tgz", @@ -7918,6 +9007,13 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true, + "optional": true + }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -7942,6 +9038,13 @@ "path-is-inside": "^1.0.1" } }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "optional": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -7951,6 +9054,13 @@ "isobject": "^3.0.1" } }, + "is-png": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-png/-/is-png-1.1.0.tgz", + "integrity": "sha1-1XSxK/J1wDUEVVcLDltXqwYgd84=", + "dev": true, + "optional": true + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -7972,6 +9082,13 @@ "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true, + "optional": true + }, "is-root": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.0.0.tgz", @@ -7984,6 +9101,16 @@ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, + "is-svg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz", + "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==", + "dev": true, + "optional": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, "is-symbol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", @@ -8075,6 +9202,17 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "optional": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, "js-levenshtein": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz", @@ -8388,12 +9526,43 @@ "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", "dev": true }, + "logalot": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz", + "integrity": "sha1-X46MkNME7fElMJUaVVSruMXj9VI=", + "dev": true, + "optional": true, + "requires": { + "figures": "^1.3.5", + "squeak": "^1.0.0" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "optional": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + } + } + }, "loglevel": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", "dev": true }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true, + "optional": true + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -8425,6 +9594,19 @@ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, + "lpad-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.2.tgz", + "integrity": "sha1-IfYArBwwlcPG5JfuZyce4ISB/p4=", + "dev": true, + "optional": true, + "requires": { + "get-stdin": "^4.0.1", + "indent-string": "^2.1.0", + "longest": "^1.0.0", + "meow": "^3.3.0" + } + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -8502,6 +9684,19 @@ "safe-buffer": "^5.1.2" } }, + "mdi-react": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mdi-react/-/mdi-react-6.2.0.tgz", + "integrity": "sha512-IM1+/YjJ5DJ4rWKDqphfxra6RM52T6Yiki1pr7dJzoE8B5SoPln0D3wwPMWuwEm9fd8oqsM8eMwAYuim3tgmzg==", + "dev": true + }, + "mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true, + "optional": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -8878,6 +10073,18 @@ "run-queue": "^1.0.3" } }, + "mozjpeg": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/mozjpeg/-/mozjpeg-6.0.1.tgz", + "integrity": "sha512-9Z59pJMi8ni+IUvSH5xQwK5tNLw7p3dwDNCZ3o1xE+of3G5Hc/yOz6Ue/YuLiBXU3ZB5oaHPURyPdqfBX/QYJA==", + "dev": true, + "optional": true, + "requires": { + "bin-build": "^3.0.0", + "bin-wrapper": "^4.0.0", + "logalot": "^2.1.0" + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -9085,6 +10292,17 @@ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", "dev": true }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "optional": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + } + }, "npm-install-package": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/npm-install-package/-/npm-install-package-2.1.0.tgz", @@ -9425,6 +10643,18 @@ "wordwrap": "~1.0.0" } }, + "optipng-bin": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/optipng-bin/-/optipng-bin-5.1.0.tgz", + "integrity": "sha512-9baoqZTNNmXQjq/PQTWEXbVV3AMO2sI/GaaqZJZ8SExfAzjijeAP7FEeT+TtyumSw7gr0PZtSUYB/Ke7iHQVKA==", + "dev": true, + "optional": true, + "requires": { + "bin-build": "^3.0.0", + "bin-wrapper": "^4.0.0", + "logalot": "^2.0.0" + } + }, "original": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", @@ -9440,6 +10670,16 @@ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, + "os-filter-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", + "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", + "dev": true, + "optional": true, + "requires": { + "arch": "^2.1.0" + } + }, "os-locale": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", @@ -9508,6 +10748,16 @@ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, + "p-event": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz", + "integrity": "sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU=", + "dev": true, + "optional": true, + "requires": { + "p-timeout": "^1.1.1" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -9544,6 +10794,39 @@ "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", "dev": true }, + "p-map-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-map-series/-/p-map-series-1.0.0.tgz", + "integrity": "sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco=", + "dev": true, + "optional": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-pipe": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-1.2.0.tgz", + "integrity": "sha1-SxoROZoRUgpneQ7loMHViB1r7+k=", + "dev": true + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true, + "optional": true + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "dev": true, + "optional": true, + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -9785,6 +11068,51 @@ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, + "pngquant-bin": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/pngquant-bin/-/pngquant-bin-5.0.2.tgz", + "integrity": "sha512-OLdT+4JZx5BqE1CFJkrvomYV0aSsv6x2Bba+aWaVc0PMfWlE+ZByNKYAdKeIqsM4uvW1HOSEHnf8KcOnykPNxA==", + "dev": true, + "optional": true, + "requires": { + "bin-build": "^3.0.0", + "bin-wrapper": "^4.0.1", + "execa": "^0.10.0", + "logalot": "^2.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "optional": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", + "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", + "dev": true, + "optional": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + } + } + }, "portfinder": { "version": "1.0.20", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", @@ -10163,6 +11491,13 @@ "object-assign": "^4.1.1" } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true, + "optional": true + }, "proxy-addr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", @@ -10256,6 +11591,18 @@ "integrity": "sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==", "dev": true }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "optional": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -10644,6 +11991,15 @@ "warning": "^3.0.0" } }, + "react-smooth-dnd": { + "version": "github:mattermost/react-smooth-dnd#af6b471295007274560a375799622c1cd52d678a", + "from": "github:mattermost/react-smooth-dnd#af6b471295007274560a375799622c1cd52d678a", + "dev": true, + "requires": { + "prop-types": ">=15.6.0", + "smooth-dnd": "0.12.1" + } + }, "react-split-pane": { "version": "0.1.85", "resolved": "https://registry.npmjs.org/react-split-pane/-/react-split-pane-0.1.85.tgz", @@ -11065,6 +12421,12 @@ "is-finite": "^1.0.0" } }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -11347,6 +12709,28 @@ "ajv-keywords": "^3.1.0" } }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.8.1" + }, + "dependencies": { + "commander": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "dev": true, + "optional": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + } + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -11377,6 +12761,23 @@ "semver": "^5.0.3" } }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "dev": true, + "optional": true + }, + "semver-truncate": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz", + "integrity": "sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g=", + "dev": true, + "optional": true, + "requires": { + "semver": "^5.3.0" + } + }, "send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -11621,6 +13022,12 @@ } } }, + "smooth-dnd": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/smooth-dnd/-/smooth-dnd-0.12.1.tgz", + "integrity": "sha512-Dndj/MOG7VP83mvzfGCLGzV2HuK1lWachMtWl/Iuk6zV7noDycIBnflwaPuDzoaapEl3Pc4+ybJArkkx9sxPZg==", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -11795,6 +13202,26 @@ } } }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "optional": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", + "dev": true, + "optional": true, + "requires": { + "sort-keys": "^1.0.0" + } + }, "source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -11959,6 +13386,48 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "squeak": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/squeak/-/squeak-1.3.0.tgz", + "integrity": "sha1-MwRQN7ZDiLVnZ0uEMiplIQc5FsM=", + "dev": true, + "optional": true, + "requires": { + "chalk": "^1.0.0", + "console-stream": "^0.1.1", + "lpad-align": "^1.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "optional": true + } + } + }, "sshpk": { "version": "1.16.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.0.tgz", @@ -11985,6 +13454,13 @@ "figgy-pudding": "^3.5.1" } }, + "stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "dev": true, + "optional": true + }, "stat-mode": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.3.0.tgz", @@ -12057,6 +13533,13 @@ "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "dev": true }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true, + "optional": true + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -12130,6 +13613,16 @@ "is-utf8": "^0.2.0" } }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "optional": true, + "requires": { + "is-natural-number": "^4.0.1" + } + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -12151,6 +13644,16 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "optional": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "style-loader": { "version": "0.23.1", "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.23.1.tgz", @@ -12251,6 +13754,54 @@ } } }, + "svgo": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz", + "integrity": "sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ==", + "dev": true, + "optional": true, + "requires": { + "chalk": "^2.4.1", + "coa": "^2.0.2", + "css-select": "^2.0.0", + "css-select-base-adapter": "^0.1.1", + "css-tree": "1.0.0-alpha.33", + "csso": "^3.5.1", + "js-yaml": "^3.13.1", + "mkdirp": "~0.5.1", + "object.values": "^1.1.0", + "sax": "~1.2.4", + "stable": "^0.1.8", + "unquote": "~1.1.1", + "util.promisify": "~1.0.0" + }, + "dependencies": { + "css-select": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz", + "integrity": "sha512-dSpYaDVoWaELjvZ3mS6IKZM/y2PMPa/XYoEfYNZePL4U/XgyxZNroHEHReDx/d+VgXh9VbCTtFqLkFbmeqeaRQ==", + "dev": true, + "optional": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^2.1.2", + "domutils": "^1.7.0", + "nth-check": "^1.0.2" + } + }, + "domutils": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz", + "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==", + "dev": true, + "optional": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + } + } + }, "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", @@ -12332,6 +13883,13 @@ "xtend": "^4.0.0" } }, + "temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true, + "optional": true + }, "temp-file": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.4.tgz", @@ -12370,6 +13928,17 @@ } } }, + "tempfile": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", + "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", + "dev": true, + "optional": true, + "requires": { + "temp-dir": "^1.0.0", + "uuid": "^3.0.1" + } + }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", @@ -12525,6 +14094,13 @@ "integrity": "sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==", "dev": true }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true, + "optional": true + }, "timers-browserify": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", @@ -12639,6 +14215,16 @@ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "optional": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -12754,6 +14340,30 @@ "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", "dev": true }, + "unbzip2-stream": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "dev": true, + "optional": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + }, + "dependencies": { + "buffer": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", + "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", + "dev": true, + "optional": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -12856,6 +14466,13 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, + "unquote": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz", + "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=", + "dev": true, + "optional": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -13061,6 +14678,13 @@ "prepend-http": "^2.0.0" } }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true, + "optional": true + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", diff --git a/package.json b/package.json index b693b725..7f07bf63 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "url": "git://github.com/mattermost/desktop.git" }, "scripts": { - "postinstall": "electron-builder install-app-deps && npm run extract-dict", + "postinstall": "electron-builder install-app-deps && npm run extract-dict && npm run fix-catalina-dark-mode", + "fix-catalina-dark-mode": "node scripts/fix_catalina_dark_mode_debug.js", "extract-dict": "node scripts/extract_dict.js src/node_modules/simple-spellchecker/dict", "build": "npm-run-all build:*", "build:main": "webpack-cli --bail --config webpack.config.main.js", @@ -64,11 +65,14 @@ "eslint-plugin-import": "^2.14.0", "eslint-plugin-react": "^7.11.1", "file-loader": "^2.0.0", + "image-webpack-loader": "5.0.0", + "mdi-react": "^6.2.0", "mocha": "^5.2.0", "mocha-circleci-reporter": "0.0.3", "npm-run-all": "^4.1.5", "react": "^16.6.3", "react-dom": "^16.6.3", + "react-smooth-dnd": "github:mattermost/react-smooth-dnd#af6b471295007274560a375799622c1cd52d678a", "spectron": "^6.0.0", "style-loader": "^0.23.1", "url-loader": "^1.1.2", diff --git a/scripts/fix_catalina_dark_mode_debug.js b/scripts/fix_catalina_dark_mode_debug.js new file mode 100644 index 00000000..358a7118 --- /dev/null +++ b/scripts/fix_catalina_dark_mode_debug.js @@ -0,0 +1,13 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +const {exec} = require('child_process'); + +if (process.platform === 'darwin') { + exec('plutil -insert NSRequiresAquaSystemAppearance -bool NO ./node_modules/electron/dist/Electron.app/Contents/Info.plist', (err) => { + if (err) { + console.error(err); + } + }); +} + diff --git a/src/assets/fonts/open-sans-v13-latin-ext_latin_cyrillic-ext_greek-ext_greek_cyrillic_vietnamese-600.woff2 b/src/assets/fonts/open-sans-v13-latin-ext_latin_cyrillic-ext_greek-ext_greek_cyrillic_vietnamese-600.woff2 new file mode 100644 index 00000000..d088697a Binary files /dev/null and b/src/assets/fonts/open-sans-v13-latin-ext_latin_cyrillic-ext_greek-ext_greek_cyrillic_vietnamese-600.woff2 differ diff --git a/src/assets/icon-session-expired.svg b/src/assets/icon-session-expired.svg new file mode 100644 index 00000000..1a48f58d --- /dev/null +++ b/src/assets/icon-session-expired.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/linux/dark/MenuIconMentionTemplate.png b/src/assets/linux/dark/MenuIconMentionTemplate.png old mode 100644 new mode 100755 index 24395599..dd4eaa03 Binary files a/src/assets/linux/dark/MenuIconMentionTemplate.png and b/src/assets/linux/dark/MenuIconMentionTemplate.png differ diff --git a/src/assets/linux/dark/MenuIconTemplate.png b/src/assets/linux/dark/MenuIconTemplate.png old mode 100644 new mode 100755 index 284e4502..c1f634af Binary files a/src/assets/linux/dark/MenuIconTemplate.png and b/src/assets/linux/dark/MenuIconTemplate.png differ diff --git a/src/assets/linux/dark/MenuIconUnreadTemplate.png b/src/assets/linux/dark/MenuIconUnreadTemplate.png old mode 100644 new mode 100755 index 01676f7c..345cd8ec Binary files a/src/assets/linux/dark/MenuIconUnreadTemplate.png and b/src/assets/linux/dark/MenuIconUnreadTemplate.png differ diff --git a/src/assets/linux/light/MenuIconMentionTemplate.png b/src/assets/linux/light/MenuIconMentionTemplate.png old mode 100644 new mode 100755 index 2c9b2d45..dd51262e Binary files a/src/assets/linux/light/MenuIconMentionTemplate.png and b/src/assets/linux/light/MenuIconMentionTemplate.png differ diff --git a/src/assets/linux/light/MenuIconTemplate.png b/src/assets/linux/light/MenuIconTemplate.png old mode 100644 new mode 100755 index ea15e9dc..1cbbb063 Binary files a/src/assets/linux/light/MenuIconTemplate.png and b/src/assets/linux/light/MenuIconTemplate.png differ diff --git a/src/assets/linux/light/MenuIconUnreadTemplate.png b/src/assets/linux/light/MenuIconUnreadTemplate.png old mode 100644 new mode 100755 index b03f7b54..857e7d6b Binary files a/src/assets/linux/light/MenuIconUnreadTemplate.png and b/src/assets/linux/light/MenuIconUnreadTemplate.png differ diff --git a/src/assets/osx/ClickedMenuIcon.png b/src/assets/osx/ClickedMenuIcon.png old mode 100644 new mode 100755 index 29647d73..b0e18062 Binary files a/src/assets/osx/ClickedMenuIcon.png and b/src/assets/osx/ClickedMenuIcon.png differ diff --git a/src/assets/osx/ClickedMenuIcon@2x.png b/src/assets/osx/ClickedMenuIcon@2x.png old mode 100644 new mode 100755 index be81be83..c97e02af Binary files a/src/assets/osx/ClickedMenuIcon@2x.png and b/src/assets/osx/ClickedMenuIcon@2x.png differ diff --git a/src/assets/osx/ClickedMenuIconMention.png b/src/assets/osx/ClickedMenuIconMention.png old mode 100644 new mode 100755 index 4c0b8f54..695e0190 Binary files a/src/assets/osx/ClickedMenuIconMention.png and b/src/assets/osx/ClickedMenuIconMention.png differ diff --git a/src/assets/osx/ClickedMenuIconMention@2x.png b/src/assets/osx/ClickedMenuIconMention@2x.png old mode 100644 new mode 100755 index acf093bb..20b75ebc Binary files a/src/assets/osx/ClickedMenuIconMention@2x.png and b/src/assets/osx/ClickedMenuIconMention@2x.png differ diff --git a/src/assets/osx/ClickedMenuIconUnread.png b/src/assets/osx/ClickedMenuIconUnread.png old mode 100644 new mode 100755 index 0fe41ebb..0593ea37 Binary files a/src/assets/osx/ClickedMenuIconUnread.png and b/src/assets/osx/ClickedMenuIconUnread.png differ diff --git a/src/assets/osx/ClickedMenuIconUnread@2x.png b/src/assets/osx/ClickedMenuIconUnread@2x.png old mode 100644 new mode 100755 index 1e31bac4..04d3cfe8 Binary files a/src/assets/osx/ClickedMenuIconUnread@2x.png and b/src/assets/osx/ClickedMenuIconUnread@2x.png differ diff --git a/src/assets/osx/MenuIcon.png b/src/assets/osx/MenuIcon.png old mode 100644 new mode 100755 index 4bbbcd47..6a51c1bf Binary files a/src/assets/osx/MenuIcon.png and b/src/assets/osx/MenuIcon.png differ diff --git a/src/assets/osx/MenuIcon@2x.png b/src/assets/osx/MenuIcon@2x.png old mode 100644 new mode 100755 index 63bbae58..d6317c1f Binary files a/src/assets/osx/MenuIcon@2x.png and b/src/assets/osx/MenuIcon@2x.png differ diff --git a/src/assets/osx/MenuIconMention.png b/src/assets/osx/MenuIconMention.png old mode 100644 new mode 100755 index 945f2d6f..5453b009 Binary files a/src/assets/osx/MenuIconMention.png and b/src/assets/osx/MenuIconMention.png differ diff --git a/src/assets/osx/MenuIconMention@2x.png b/src/assets/osx/MenuIconMention@2x.png old mode 100644 new mode 100755 index a9fd2635..be97e00e Binary files a/src/assets/osx/MenuIconMention@2x.png and b/src/assets/osx/MenuIconMention@2x.png differ diff --git a/src/assets/osx/MenuIconUnread.png b/src/assets/osx/MenuIconUnread.png old mode 100644 new mode 100755 index 476b68c9..cfff033b Binary files a/src/assets/osx/MenuIconUnread.png and b/src/assets/osx/MenuIconUnread.png differ diff --git a/src/assets/osx/MenuIconUnread@2x.png b/src/assets/osx/MenuIconUnread@2x.png old mode 100644 new mode 100755 index 7b0e3386..21d8955d Binary files a/src/assets/osx/MenuIconUnread@2x.png and b/src/assets/osx/MenuIconUnread@2x.png differ diff --git a/src/assets/titlebar/chrome-close.svg b/src/assets/titlebar/chrome-close.svg new file mode 100644 index 00000000..cb148f5a --- /dev/null +++ b/src/assets/titlebar/chrome-close.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/titlebar/chrome-maximize.svg b/src/assets/titlebar/chrome-maximize.svg new file mode 100644 index 00000000..0d991756 --- /dev/null +++ b/src/assets/titlebar/chrome-maximize.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/titlebar/chrome-minimize.svg b/src/assets/titlebar/chrome-minimize.svg new file mode 100644 index 00000000..62f72c70 --- /dev/null +++ b/src/assets/titlebar/chrome-minimize.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/titlebar/chrome-restore.svg b/src/assets/titlebar/chrome-restore.svg new file mode 100644 index 00000000..7dc8f55b --- /dev/null +++ b/src/assets/titlebar/chrome-restore.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/windows/tray.ico b/src/assets/windows/tray.ico index 4277e0f3..1f7102f0 100644 Binary files a/src/assets/windows/tray.ico and b/src/assets/windows/tray.ico differ diff --git a/src/assets/windows/tray_mention.ico b/src/assets/windows/tray_mention.ico index 53e49de0..6b56c7aa 100644 Binary files a/src/assets/windows/tray_mention.ico and b/src/assets/windows/tray_mention.ico differ diff --git a/src/assets/windows/tray_unread.ico b/src/assets/windows/tray_unread.ico index 8a0d5a33..55c08026 100644 Binary files a/src/assets/windows/tray_unread.ico and b/src/assets/windows/tray_unread.ico differ diff --git a/src/browser/components/ErrorView.jsx b/src/browser/components/ErrorView.jsx index 51397b0f..4fa07464 100644 --- a/src/browser/components/ErrorView.jsx +++ b/src/browser/components/ErrorView.jsx @@ -14,9 +14,6 @@ export default function ErrorView(props) { if (!props.active) { classNames.push('ErrorView-hidden'); } - if (props.withTab) { - classNames.push('ErrorView-with-tab'); - } function handleClick(event) { event.preventDefault(); shell.openExternal(props.errorInfo.validatedURL); @@ -84,5 +81,4 @@ ErrorView.propTypes = { errorInfo: PropTypes.object, id: PropTypes.number, active: PropTypes.bool, - withTab: PropTypes.bool, }; diff --git a/src/browser/components/Finder.jsx b/src/browser/components/Finder.jsx index 5f13cdcf..c37cb7f6 100644 --- a/src/browser/components/Finder.jsx +++ b/src/browser/components/Finder.jsx @@ -77,7 +77,7 @@ export default class Finder extends React.Component { render() { return (
-
+
{ + if (event.target === self.topBar.current) { + const upEvent = document.createEvent('MouseEvents'); + upEvent.initMouseEvent('mouseup'); + document.dispatchEvent(upEvent); + } + }); + + // Hack for when it leaves the electron window because apparently mouseleave isn't good enough there... + self.topBar.current.addEventListener('mousemove', () => { + if (event.clientY === 0 || event.clientX === 0 || event.clientX >= window.innerWidth) { + const upEvent = document.createEvent('MouseEvents'); + upEvent.initMouseEvent('mouseup'); + document.dispatchEvent(upEvent); + } + }); + } + ipcRenderer.on('login-request', (event, request, authInfo) => { self.setState({ loginRequired: true, @@ -115,14 +147,32 @@ export default class MainPage extends React.Component { function focusListener() { self.handleOnTeamFocused(self.state.key); self.refs[`mattermostView${self.state.key}`].focusOnWebView(); + self.setState({unfocused: false}); + } + + function blurListener() { + self.setState({unfocused: true}); } const currentWindow = remote.getCurrentWindow(); currentWindow.on('focus', focusListener); + currentWindow.on('blur', blurListener); window.addEventListener('beforeunload', () => { currentWindow.removeListener('focus', focusListener); }); + if (currentWindow.isMaximized()) { + self.setState({maximized: true}); + } + currentWindow.on('maximize', this.handleMaximizeState); + currentWindow.on('unmaximize', this.handleMaximizeState); + + if (currentWindow.isFullScreen()) { + self.setState({fullScreen: true}); + } + currentWindow.on('enter-full-screen', this.handleFullScreenState); + currentWindow.on('leave-full-screen', this.handleFullScreenState); + // https://github.com/mattermost/desktop/pull/371#issuecomment-263072803 currentWindow.webContents.on('devtools-closed', () => { focusListener(); @@ -246,6 +296,32 @@ export default class MainPage extends React.Component { ipcRenderer.on('toggle-find', () => { this.activateFinder(true); }); + + if (process.platform === 'darwin') { + self.setState({ + isDarkMode: remote.systemPreferences.isDarkMode(), + }); + remote.systemPreferences.subscribeNotification('AppleInterfaceThemeChangedNotification', () => { + self.setState({ + isDarkMode: remote.systemPreferences.isDarkMode(), + }); + }); + } else { + self.setState({ + isDarkMode: this.props.getDarkMode(), + }); + + ipcRenderer.on('set-dark-mode', () => { + this.setDarkMode(); + }); + + this.threeDotMenu = React.createRef(); + ipcRenderer.on('focus-three-dot-menu', () => { + if (this.threeDotMenu.current) { + this.threeDotMenu.current.focus(); + } + }); + } } componentDidUpdate(prevProps, prevState) { @@ -254,6 +330,16 @@ export default class MainPage extends React.Component { } } + handleMaximizeState = () => { + const win = remote.getCurrentWindow(); + this.setState({maximized: win.isMaximized()}); + } + + handleFullScreenState = () => { + const win = remote.getCurrentWindow(); + this.setState({fullScreen: win.isFullScreen()}); + } + handleSelect = (key) => { const newKey = (this.props.teams.length + key) % this.props.teams.length; this.setState({ @@ -269,6 +355,14 @@ export default class MainPage extends React.Component { this.handleOnTeamFocused(newKey); } + handleDragAndDrop = (dropResult) => { + const {removedIndex, addedIndex} = dropResult; + if (removedIndex !== addedIndex) { + const teamIndex = this.props.moveTabs(removedIndex, addedIndex < this.props.teams.length ? addedIndex : this.props.teams.length - 1); + this.handleSelect(teamIndex); + } + } + handleBadgeChange = (index, sessionExpired, unreadCount, mentionCount, isUnread, isMentioned) => { const sessionsExpired = this.state.sessionsExpired; const unreadCounts = this.state.unreadCounts; @@ -362,16 +456,52 @@ export default class MainPage extends React.Component { } } + handleClose = () => { + const win = remote.getCurrentWindow(); + win.close(); + } + + handleMinimize = () => { + const win = remote.getCurrentWindow(); + win.minimize(); + } + + handleMaximize = () => { + const win = remote.getCurrentWindow(); + win.maximize(); + } + + handleRestore = () => { + const win = remote.getCurrentWindow(); + win.restore(); + } + + openMenu = () => { + // @eslint-ignore + this.threeDotMenu.current.blur(); + this.props.openMenu(); + } + + handleDoubleClick = () => { + const doubleClickAction = remote.systemPreferences.getUserDefault('AppleActionOnDoubleClick', 'string'); + const win = remote.getCurrentWindow(); + if (doubleClickAction === 'Minimize') { + win.minimize(); + } else if (doubleClickAction === 'Maximize' && !win.isMaximized()) { + win.maximize(); + } else if (doubleClickAction === 'Maximize' && win.isMaximized()) { + win.unmaximize(); + } + } + addServer = () => { this.setState({ showNewTeamModal: true, }); } - focusOnWebView = (e) => { - if (e.target.className !== 'finder-input') { - this.refs[`mattermostView${this.state.key}`].focusOnWebView(); - } + focusOnWebView = () => { + this.refs[`mattermostView${this.state.key}`].focusOnWebView(); } activateFinder = () => { @@ -393,29 +523,116 @@ export default class MainPage extends React.Component { }); } + setDarkMode() { + this.setState({ + isDarkMode: this.props.setDarkMode(), + }); + } + render() { const self = this; - let tabsRow; - if (this.props.teams.length > 1) { - tabsRow = ( - - - + const tabsRow = ( + + ); + + let topBarClassName = 'topBar'; + if (process.platform === 'darwin') { + topBarClassName += ' macOS'; + } + if (this.state.isDarkMode) { + topBarClassName += ' darkMode'; + } + if (this.state.fullScreen) { + topBarClassName += ' fullScreen'; + } + + let maxButton; + if (this.state.maximized) { + maxButton = ( +
+ +
+ ); + } else { + maxButton = ( +
+ +
); } + let overlayGradient; + if (process.platform !== 'darwin') { + overlayGradient = ( + + ); + } + + let titleBarButtons; + if (process.platform !== 'darwin') { + titleBarButtons = ( + +
+ +
+ {maxButton} +
+ +
+
+ ); + } + + const topRow = ( + +
+ + {tabsRow} + {overlayGradient} + {titleBarButtons} +
+
+ ); + const views = this.props.teams.map((team, index) => { function handleBadgeChange(sessionExpired, unreadCount, mentionCount, isUnread, isMentioned) { self.handleBadgeChange(index, sessionExpired, unreadCount, mentionCount, isUnread, isMentioned); @@ -439,7 +656,7 @@ export default class MainPage extends React.Component { 1} + useSpellChecker={this.props.useSpellChecker} onSelectSpellCheckerLocale={this.props.onSelectSpellCheckerLocale} src={teamUrl} @@ -467,7 +684,9 @@ export default class MainPage extends React.Component { } const modal = ( { this.setState({ showNewTeamModal: false, @@ -498,7 +717,7 @@ export default class MainPage extends React.Component { onCancel={this.handleLoginCancel} /> - { tabsRow } + { topRow } { viewsRow } { this.state.finderVisible ? ( { const webview = this.webviewRef.current; const webContents = webview.getWebContents(); // webContents might not be created yet. - if (webContents && !webContents.isFocused()) { + if (webContents) { webview.focus(); webContents.focus(); } } + handleMouseMove = (event) => { + const moveEvent = document.createEvent('MouseEvents'); + moveEvent.initMouseEvent('mousemove', null, null, null, null, null, null, event.clientX, event.clientY); + document.dispatchEvent(moveEvent); + } + + handleMouseUp = () => { + const upEvent = document.createEvent('MouseEvents'); + upEvent.initMouseEvent('mouseup'); + document.dispatchEvent(upEvent); + } + canGoBack = () => { const webview = this.webviewRef.current; return webview.getWebContents().canGoBack(); @@ -301,7 +319,6 @@ export default class MattermostView extends React.Component { className='errorView' errorInfo={this.state.errorInfo} active={this.props.active} - withTab={this.props.withTab} />) : null; // Need to keep webview mounted when failed to load. @@ -309,7 +326,7 @@ export default class MattermostView extends React.Component { if (this.props.withTab) { classNames.push('mattermostView-with-tab'); } - if (!this.props.active) { + if (!this.props.active || this.state.errorInfo) { classNames.push('mattermostView-hidden'); } @@ -342,11 +359,11 @@ export default class MattermostView extends React.Component { MattermostView.propTypes = { name: PropTypes.string, id: PropTypes.string, + withTab: PropTypes.bool, onTargetURLChange: PropTypes.func, onBadgeChange: PropTypes.func, src: PropTypes.string, active: PropTypes.bool, - withTab: PropTypes.bool, useSpellChecker: PropTypes.bool, onSelectSpellCheckerLocale: PropTypes.func, }; diff --git a/src/browser/components/NewTeamModal.jsx b/src/browser/components/NewTeamModal.jsx index f340c155..3b7bcd67 100644 --- a/src/browser/components/NewTeamModal.jsx +++ b/src/browser/components/NewTeamModal.jsx @@ -9,13 +9,18 @@ import {Modal, Button, FormGroup, FormControl, ControlLabel, HelpBlock} from 're import Utils from '../../utils/util'; export default class NewTeamModal extends React.Component { - constructor() { - super(); + static defaultProps = { + restoreFocus: true, + }; + + constructor(props) { + super(props); this.wasShown = false; this.state = { teamName: '', teamUrl: '', + teamOrder: props.currentOrder || 0, saveStarted: false, }; } @@ -25,6 +30,7 @@ export default class NewTeamModal extends React.Component { teamName: this.props.team ? this.props.team.name : '', teamUrl: this.props.team ? this.props.team.url : '', teamIndex: this.props.team ? this.props.team.index : false, + teamOrder: this.props.team ? this.props.team.order : (this.props.currentOrder || 0), saveStarted: false, }); } @@ -100,6 +106,7 @@ export default class NewTeamModal extends React.Component { url: this.state.teamUrl, name: this.state.teamName, index: this.state.teamIndex, + order: this.state.teamOrder, }); } }); @@ -132,6 +139,8 @@ export default class NewTeamModal extends React.Component { show={this.props.show} id='newServerModal' onHide={this.props.onClose} + container={this.props.modalContainer} + restoreFocus={this.props.restoreFocus} onKeyDown={(e) => { switch (e.key) { case 'Enter': @@ -221,4 +230,7 @@ NewTeamModal.propTypes = { team: PropTypes.object, editMode: PropTypes.bool, show: PropTypes.bool, + modalContainer: PropTypes.object, + restoreFocus: PropTypes.bool, + currentOrder: PropTypes.number, }; diff --git a/src/browser/components/SettingsPage.jsx b/src/browser/components/SettingsPage.jsx index 75b414e2..f76cc77f 100644 --- a/src/browser/components/SettingsPage.jsx +++ b/src/browser/components/SettingsPage.jsx @@ -342,6 +342,7 @@ export default class SettingsPage extends React.Component { onTeamClick={(index) => { backToIndex(index + this.state.buildTeams.length + this.state.registryTeams.length); }} + modalContainer={this} /> @@ -605,7 +606,7 @@ export default class SettingsPage extends React.Component { ) : null; return ( -
+
{ + const orderedTabs = this.props.teams.concat().sort((a, b) => a.order - b.order); + const tabs = orderedTabs.map((team) => { + const index = this.props.teams.indexOf(team); const sessionExpired = this.props.sessionsExpired[index]; let unreadCount = 0; @@ -29,7 +34,7 @@ export default class TabBar extends React.Component { // need "this" let badgeDiv; if (sessionExpired) { badgeDiv = ( -
+
); } else if (mentionCount !== 0) { badgeDiv = ( @@ -37,29 +42,45 @@ export default class TabBar extends React.Component { // need "this" {mentionCount}
); + } else if (unreadCount !== 0) { + badgeDiv = ( +
+ ); } - const id = 'teamTabItem' + index; - // draggable=false is a workaround for https://github.com/mattermost/desktop/issues/667 - // It would obstruct https://github.com/mattermost/desktop/issues/478 - return ( + const id = `teamTabItem${index}`; + const navItem = () => ( { + this.props.onSelect(index); + }} + onSelect={() => { + this.props.onSelect(index); + }} + title={team.name} > - - {team.name} - - { ' ' } - { badgeDiv } - ); +
+ + {team.name} + + { badgeDiv } +
+ + ); + + return ( + ); }); if (this.props.showAddServerButton === true) { tabs.push( @@ -68,36 +89,50 @@ export default class TabBar extends React.Component { // need "this" key='addServerButton' id='addServerButton' eventKey='addServerButton' - title='Add new server' draggable={false} + title='Add new server' + activeKey={this.props.activeKey} + onSelect={() => { + this.props.onAddServer(); + }} > - +
+ +
); } - return ( + + const navContainer = (ref) => ( ); + return ( + { + return !(remote.getCurrentWindow().registryConfigData.teams && remote.getCurrentWindow().registryConfigData.teams.length > 0); + }} + /> + ); } } TabBar.propTypes = { activeKey: PropTypes.number, id: PropTypes.string, + isDarkMode: PropTypes.bool, onSelect: PropTypes.func, teams: PropTypes.array, sessionsExpired: PropTypes.array, @@ -107,4 +142,5 @@ TabBar.propTypes = { mentionAtActiveCounts: PropTypes.array, showAddServerButton: PropTypes.bool, onAddServer: PropTypes.func, + onDrop: PropTypes.func, }; diff --git a/src/browser/components/TeamList.jsx b/src/browser/components/TeamList.jsx index ba845be3..b9e8088c 100644 --- a/src/browser/components/TeamList.jsx +++ b/src/browser/components/TeamList.jsx @@ -20,6 +20,7 @@ export default class TeamList extends React.Component { url: '', name: '', index: false, + order: props.teams.length, }, }; } @@ -27,7 +28,13 @@ export default class TeamList extends React.Component { handleTeamRemove = (index) => { console.log(index); const teams = this.props.teams; + const removedOrder = this.props.teams[index].order; teams.splice(index, 1); + teams.forEach((value) => { + if (value.order > removedOrder) { + value.order--; + } + }); this.props.onTeamsChange(teams); } @@ -38,6 +45,7 @@ export default class TeamList extends React.Component { if ((typeof team.index !== 'undefined') && teams[team.index]) { teams[team.index].name = team.name; teams[team.index].url = team.url; + teams[team.index].order = team.order; } else { teams.push(team); } @@ -48,19 +56,21 @@ export default class TeamList extends React.Component { url: '', name: '', index: false, + order: teams.length, }, }); this.props.onTeamsChange(teams); } - handleTeamEditing = (teamName, teamUrl, teamIndex) => { + handleTeamEditing = (teamName, teamUrl, teamIndex, teamOrder) => { this.setState({ showEditTeamForm: true, team: { url: teamUrl, name: teamName, index: teamIndex, + order: teamOrder, }, }); } @@ -83,7 +93,7 @@ export default class TeamList extends React.Component { function handleTeamEditing() { document.activeElement.blur(); - self.handleTeamEditing(team.name, team.url, i); + self.handleTeamEditing(team.name, team.url, i, team.order); } function handleTeamClick() { @@ -105,6 +115,7 @@ export default class TeamList extends React.Component { const addServerForm = ( { @@ -114,6 +125,7 @@ export default class TeamList extends React.Component { name: '', url: '', index: false, + order: this.props.teams.length, }, }); this.props.setAddTeamFormVisibility(false); @@ -122,6 +134,7 @@ export default class TeamList extends React.Component { const teamData = { name: newTeam.name, url: newTeam.url, + order: newTeam.order, }; if (this.props.showAddTeamForm) { this.props.addServer(teamData); @@ -135,12 +148,14 @@ export default class TeamList extends React.Component { name: '', url: '', index: false, + order: newTeam.order + 1, }, }); this.render(); this.props.setAddTeamFormVisibility(false); }} team={this.state.team} + modalContainer={this.props.modalContainer} />); const removeServer = this.props.teams[this.state.indexToRemoveServer]; @@ -154,6 +169,7 @@ export default class TeamList extends React.Component { this.handleTeamRemove(this.state.indexToRemoveServer); this.closeServerRemoveModal(); }} + modalContainer={this.props.modalContainer} /> ); @@ -176,4 +192,5 @@ TeamList.propTypes = { toggleAddTeamForm: PropTypes.func, setAddTeamFormVisibility: PropTypes.func, onTeamClick: PropTypes.func, + modalContainer: PropTypes.object, }; diff --git a/src/browser/css/components/ErrorView.css b/src/browser/css/components/ErrorView.css index 9a51706d..2abfc61a 100644 --- a/src/browser/css/components/ErrorView.css +++ b/src/browser/css/components/ErrorView.css @@ -1,15 +1,11 @@ .ErrorView { position: absolute; - top: 0px; + top: 32px; right: 0px; bottom: 0px; left: 0px; } -.ErrorView-with-tab { - top: 32px; -} - .ErrorView-hidden { visibility: hidden; } diff --git a/src/browser/css/components/Finder.css b/src/browser/css/components/Finder.css index 8ab08d8e..021c2108 100644 --- a/src/browser/css/components/Finder.css +++ b/src/browser/css/components/Finder.css @@ -8,7 +8,6 @@ border: none; background: #d2d2d2; outline: none; - cursor: pointer; font-size: 18px; height: 26px; } diff --git a/src/browser/css/components/MainPage.css b/src/browser/css/components/MainPage.css index e3518a11..37f3641f 100644 --- a/src/browser/css/components/MainPage.css +++ b/src/browser/css/components/MainPage.css @@ -15,7 +15,7 @@ div[id*="-permissionDialog"] { .finder { position: fixed; top: 0; - right: 20px; + right: 200px; padding: 4px; background: #eee; border: 1px solid #d7d7d7; @@ -24,4 +24,9 @@ div[id*="-permissionDialog"] { border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; font-size: 0px; + -webkit-app-region: no-drag; +} + +.finder.macOS { + right: 20px; } diff --git a/src/browser/css/components/MattermostView.css b/src/browser/css/components/MattermostView.css index 3ab9bc42..98ad72d7 100644 --- a/src/browser/css/components/MattermostView.css +++ b/src/browser/css/components/MattermostView.css @@ -8,16 +8,12 @@ .mattermostView webview, .mattermostView .mattermostView-loadingScreen { position: absolute; - top: 0px; + top: 40px; right: 0px; bottom: 0px; left: 0px; } -.mattermostView-with-tab webview, .mattermostView-with-tab .mattermostView-loadingScreen { - top: 31px; -} - .mattermostView-hidden webview { visibility: hidden; z-index: -1; diff --git a/src/browser/css/components/TabBar.css b/src/browser/css/components/TabBar.css index dd8d785f..6667239e 100644 --- a/src/browser/css/components/TabBar.css +++ b/src/browser/css/components/TabBar.css @@ -1,27 +1,189 @@ +.TabBar { + border: none; + max-height: 36px; + flex: 1 1 auto; + display: flex !important; + flex-wrap: nowrap; + justify-content: flex-start; +} + +.TabBar.darkMode { + background-color: #202124; +} + .TabBar .teamTabItem span { - display: inline-block; + flex: 0 1 auto; overflow: hidden; - text-overflow: ellipsis; white-space: nowrap; - max-width: 170px; + text-align: center; +} + +.TabBar>li { + -webkit-app-region: no-drag; + -webkit-user-select: none; + min-width: 48px; } .TabBar>li>a { - background: rgba(0, 0, 0, 0.05); - border-radius: 2px 2px 0 0; - border: 1px solid #ddd; - color: #888; - height: 31px; - line-height: 29px; + border: none; + border-radius: 0; + height: 32px; + max-height: 32px; + line-height: 16px; margin-right: -1px; - margin-top: 0px; - padding: 0 15px; + margin-top: 4px; + padding: 6px 0; + color: rgba(61,60,64,0.7); + font-family: Arial; + font-size: 14px; + letter-spacing: -0.2px; + transition: 0.3s; } -.TabBar>li.teamTabItem:not(.active)>a:hover { - background-color: #e6e6e6; - border: 1px solid #ddd; - transition: background-color 0.2s ease; +.TabBar.darkMode>li>a { + color: rgba(243,243,243,0.7); +} + +.TabBar>li>a:hover { + background-color: rgba(255,255,255,0.4); + text-decoration: none; + border-radius: 6px 6px 0 0; +} + +.TabBar.darkMode>li>a:hover { + background-color: rgba(50, 54, 57, 0.4); +} + +.TabBar>li>a:focus { + background-color: #fff; + color: rgba(61,60,64,1); + text-decoration: none; + border-radius: 6px 6px 0 0; +} + +.TabBar.darkMode>li>a:focus { + background-color: #323639; + color: rgba(243,243,243,1); +} + +.TabBar>li:before, .TabBar>li:after { + position: absolute; + bottom: -1px; + width: 6px; + height: 6px; + content: ""; + background-color: inherit; + z-index: 9; + flex: 0 0 6px; +} + +.TabBar>li.teamTabItem.active:before, .TabBar>li.teamTabItem.smooth-dnd-ghost:before { + left: -4px; + border-bottom-right-radius: 6px; + border-right: 2px solid #fff; + border-bottom: 2px solid #fff; + z-index: 9; +} + +.TabBar.darkMode>li.teamTabItem.active:before, .TabBar.darkMode>li.teamTabItem.smooth-dnd-ghost:before { + border-right: 2px solid #323639; + border-bottom: 2px solid #323639; +} + +.TabBar>li.teamTabItem.active:after, .TabBar>li.teamTabItem.smooth-dnd-ghost:after { + border-bottom-left-radius: 6px; + right: -5px; + border-left: 2px solid #fff; + border-bottom: 2px solid #fff; + z-index: 9; +} + +.TabBar.darkMode>li.teamTabItem.active:after, .TabBar.darkMode>li.teamTabItem.smooth-dnd-ghost:after { + border-left: 2px solid #323639; + border-bottom: 2px solid #323639; +} + +.TabBar>li>a>div.TabBar-tabSeperator { + padding: 2px 16px; + max-height: 20px; + display: flex; +} + +.TabBar>li.TabBar-addServerButton{ + transition: none !important; + transform: none !important; + flex: 0 0 auto; + min-width: 40px; +} + +.TabBar>li.TabBar-addServerButton>a{ + color: rgba(61,60,64,0.7); + transition: opacity 0.3s ease-in; +} + +.TabBar>li.TabBar-addServerButton svg{ + margin: -2px; +} + +.TabBar.darkMode>li.TabBar-addServerButton>a{ + color: rgba(243,243,243,0.7); +} + +.TabBar>li.teamTabItem.active>a, .TabBar>li.teamTabItem.smooth-dnd-ghost>a { + border: none; + border-radius: 6px 6px 0 0; + color: rgba(61,60,64,1); + background-color: #fff; + z-index: 9; +} + +.smooth-dnd-no-user-select li.TabBar-addServerButton>a { + opacity: 0; +} + +.TabBar.darkMode>li.teamTabItem.active>a, .TabBar.darkMode>li.teamTabItem.smooth-dnd-ghost>a { + color: #f3f3f3; + background-color: #323639; +} + +.TabBar>li.teamTabItem:not(.active)+.TabBar-addServerButton>a>div.TabBar-tabSeperator { + border-left: 1px solid rgba(61,60,64,0.2); + margin-left: -1px; +} + +.TabBar>li.teamTabItem:not(.active)+li.teamTabItem:not(.active)>a>div.TabBar-tabSeperator { + border-left: 1px solid rgba(61,60,64,0.2); + margin-left: -1px; +} + +.TabBar.darkMode>li.teamTabItem:not(.active)+.TabBar-addServerButton>a>div.TabBar-tabSeperator { + border-left: 1px solid rgba(243,243,243,0.2); + margin-left: -1px; +} + +.TabBar.darkMode>li.teamTabItem:not(.active)+li.teamTabItem:not(.active)>a>div.TabBar-tabSeperator { + border-left: 1px solid rgba(243,243,243,0.2); + margin-left: -1px; +} + +.TabBar>li.teamTabItem:not(.active):hover+.TabBar-addServerButton>a>div.TabBar-tabSeperator { + border-left: none; + margin-left: 0px; +} + +.TabBar>li.teamTabItem:not(.active):hover+li.teamTabItem:not(.active)>a>div.TabBar-tabSeperator { + border-left: none; + margin-left: 0px; +} + +.TabBar>li.teamTabItem:not(.active)+.TabBar-addServerButton>a:hover>div.TabBar-tabSeperator { + border-left: none; + margin-left: 0px; +} + +.TabBar>li.teamTabItem:not(.active)+li.teamTabItem:not(.active)>a:hover>div.TabBar-tabSeperator { + border-left: none; + margin-left: 0px; } .TabBar .TabBar-addServerButton>a { @@ -29,34 +191,59 @@ background: transparent; color: #999; font-size: 10px; - line-height: 31px; + line-height: 16px; } -.TabBar .TabBar-addServerButton>a:hover { - color: #333; - background-color: #e6e6e6; - border-color: #adadad; - transition: background-color 0.2s ease; +.TabBar.darkMode .TabBar-addServerButton>a { + color: rgba(243,243,243,0.7); +} + +.TabBar .TabBar-dot { + background: #579EFF; + float: right; + height: 6px; + width: 6px; + margin-top: 5px; + margin-left: 8px; + border-radius: 4px; + flex: 0 0 6px; +} + +.TabBar .TabBar-expired { + float: right; + height: 16px; + width: 16px; + margin-left: 8px; + background-image: url(../../../assets/icon-session-expired.svg); + flex: 0 0 16px; +} + +.TabBar.darkMode .TabBar-expired { + filter: invert(100%); + -webkit-filter: invert(100%); } .TabBar .TabBar-badge { - background: #FF1744; + background: #CB2431; float: right; color: white; - min-width: 18px; - font-size: 12px; + font-size: 11px; text-align: center; - line-height: 20px; + line-height: 18px; height: 18px; - margin-left: 5px; - margin-top: 5px; + margin-left: 8px; + border-radius: 100px; padding: 0 5px; - border-radius: 9px; display: flex; justify-content: center; align-items: center; - font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; - font-weight: 600; + font-family: "Open Sans", sans-serif; + font-weight: bold; + min-width: 18px; + margin-top: -1px; + letter-spacing: normal; + -webkit-font-smoothing: antialiased; + flex: 1 0 18px; } .TabBar .TabBar-badge.TabBar-badge-nomention:after { diff --git a/src/browser/css/components/TeamListItem.css b/src/browser/css/components/TeamListItem.css index 28b9449c..2a61a250 100644 --- a/src/browser/css/components/TeamListItem.css +++ b/src/browser/css/components/TeamListItem.css @@ -5,5 +5,4 @@ .TeamListItem-left { display: inline-block; width: calc(100% - 100px); - cursor: pointer; } diff --git a/src/browser/css/index.css b/src/browser/css/index.css index e2287735..1a75ac25 100644 --- a/src/browser/css/index.css +++ b/src/browser/css/index.css @@ -1,5 +1,19 @@ @import url("components/index.css"); +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: url('../../assets/fonts/open-sans-v13-latin-ext_latin_cyrillic-ext_greek-ext_greek_cyrillic_vietnamese-600.woff2') format('woff2'); +} + +html { + height: 100%; +} +body { + min-height: 100%; +} + .hovering-enter { opacity: 0.01; } @@ -26,3 +40,177 @@ .modal-error { color: #a94442; } + +.topBar { + height: 40px; + -webkit-app-region: drag; +} + +.topBar>.topBar-bg { + display: flex; + overflow: hidden; + -webkit-app-region: drag; + height: 36px; + background-color: rgba(0,0,0,0.1); +} + +.topBar>.topBar-bg.unfocused { + opacity: 0.4; +} + +.topBar.darkMode { + background-color: #323639; + color: #fff; +} + +.topBar.darkMode>.topBar-bg { + background-color: #202124; +} + +.topBar .three-dot-menu { + font-size: 20px; + line-height: 20px; + height: 36px; + float: left; + padding-top: 5px; + border: none; + flex: 0 0 40px; + z-index: 9; + color: rgba(61,60,64,0.7); + -webkit-app-region: no-drag; + background-color: rgba(229, 229, 229, 1); +} + +.topBar .three-dot-menu svg { + border-radius: 100px; + padding: 4px; + height: 28px; + width: 28px; +} + +.topBar .three-dot-menu:focus { + outline: none; +} + +.topBar .three-dot-menu:hover svg, .topBar .three-dot-menu:focus svg, .topBar .three-dot-menu:active svg { + outline: none; + background-color: #c8c8c8; +} + +.topBar.darkMode .three-dot-menu:hover svg, .topBar.darkMode .three-dot-menu:focus svg, .topBar.darkMode .three-dot-menu:active svg { + background-color: #383A3F; +} + +.topBar.macOS .three-dot-menu:hover svg, .topBar.macOS .three-dot-menu:focus svg, .topBar.macOS .three-dot-menu:active svg { + background: none !important; +} + +.topBar.macOS .three-dot-menu { + flex-basis: 80px; +} + +.topBar.macOS.fullScreen .three-dot-menu { + flex-basis: 0px; +} + +.topBar.macOS .three-dot-menu>svg { + display: none; +} + +.topBar.darkMode .three-dot-menu { + background-color: #202124; + color: rgba(243,243,243,0.7); +} + +.topBar.darkMode .title-bar-btns { + color: rgba(243,243,243,0.7); + background-color: #202124; +} + +.topBar .title-bar-btns { + position: relative; + line-height: 36px; + height: 36px; + z-index: 9; + color: rgba(61,60,64,0.7); + -webkit-app-region: no-drag; + display: grid; + grid-template-columns: repeat(3, 46px); + background-color: #e5e5e5; +} + +.topBar .title-bar-btns>.button { + grid-row: 1 / span 1; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + user-select: none; +} + +.topBar.darkMode .title-bar-btns>.button:hover { + background: rgba(255,255,255,0.1); +} + +.topBar.darkMode .title-bar-btns>.button:active { + background: rgba(255,255,255,0.2); +} + +.topBar .title-bar-btns>.button:hover { + background: rgba(0,0,0,0.1); +} + +.topBar .title-bar-btns>.button:active { + background: rgba(0,0,0,0.2); +} + +.topBar .title-bar-btns>.close-button:hover { + background: #E81123 !important; +} + +.topBar .title-bar-btns>.close-button:hover>img { + filter: invert(100%); + -webkit-filter: invert(100%); + opacity: 1; +} + +.topBar .title-bar-btns>.close-button:active { + background: #f1707a !important; +} + +.topBar .title-bar-btns>.close-button:active>img { + filter: invert(100%); + -webkit-filter: invert(100%); +} + +.topBar .title-bar-btns img { + opacity: 0.7; +} + +.topBar.darkMode .title-bar-btns img { + filter: invert(100%); + -webkit-filter: invert(100%); +} + +.topBar .title-bar-btns>.min-button { + grid-column: 1; +} +.topBar .title-bar-btns>.max-button, .topBar .title-bar-btns>.restore-button { + grid-column: 2; +} + +.topBar .title-bar-btns>.close-button { + grid-column: 3; +} + +.topBar .overlay-gradient { + flex: 0 0 40px; + z-index: 9; + background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, #e5e5e5 100%); + -webkit-app-region: drag; +} + +.topBar.darkMode .overlay-gradient { + background: linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, #202124 100%); +} \ No newline at end of file diff --git a/src/browser/index.jsx b/src/browser/index.jsx index f4c28269..7c945295 100644 --- a/src/browser/index.jsx +++ b/src/browser/index.jsx @@ -26,6 +26,14 @@ const config = new Config(remote.app.getPath('userData') + '/config.json', remot const teams = config.teams; +// Make sure teams have an order +if (teams.every((team) => !team.order)) { + teams.forEach((team, index) => { + team.order = index; + }); + teamConfigChange(teams); +} + remote.getCurrentWindow().removeAllListeners('focus'); if (teams.length === 0) { @@ -33,7 +41,7 @@ if (teams.length === 0) { } const parsedURL = url.parse(window.location.href, true); -const initialIndex = parsedURL.query.index ? parseInt(parsedURL.query.index, 10) : 0; +const initialIndex = parsedURL.query.index ? parseInt(parsedURL.query.index, 10) : getInitialIndex(); let deeplinkingUrl = null; if (!parsedURL.query.index || parsedURL.query.index === null) { @@ -52,6 +60,11 @@ ipcRenderer.on('reload-config', () => { config.reload(); }); +function getInitialIndex() { + const element = teams.find((e) => e.order === 0); + return element ? teams.indexOf(element) : 0; +} + function showBadgeWindows(sessionExpired, unreadCount, mentionCount) { function sendBadge(dataURL, description) { // window.setOverlayIcon() does't work with NativeImage across remote boundaries. @@ -136,6 +149,50 @@ function handleSelectSpellCheckerLocale(locale) { ipcRenderer.send('update-dict', locale); } +function moveTabs(originalOrder, newOrder) { + const tabOrder = teams.concat().map((team, index) => { + return { + index, + order: team.order, + }; + }).sort((a, b) => (a.order - b.order)); + + const team = tabOrder.splice(originalOrder, 1); + tabOrder.splice(newOrder, 0, team[0]); + + let teamIndex; + tabOrder.forEach((t, order) => { + if (order === newOrder) { + teamIndex = t.index; + } + teams[t.index].order = order; + }); + teamConfigChange(teams); + return teamIndex; +} + +function getDarkMode() { + if (process.platform !== 'darwin') { + return config.darkMode; + } + return null; +} + +function setDarkMode() { + if (process.platform !== 'darwin') { + const darkMode = Boolean(config.darkMode); + config.set('darkMode', !darkMode); + return !darkMode; + } + return null; +} + +function openMenu() { + if (process.platform !== 'darwin') { + ipcRenderer.send('open-app-menu'); + } +} + ReactDOM.render( , document.getElementById('content') ); diff --git a/src/browser/webview/mattermost.js b/src/browser/webview/mattermost.js index 5826a3cf..e167cb4e 100644 --- a/src/browser/webview/mattermost.js +++ b/src/browser/webview/mattermost.js @@ -47,6 +47,15 @@ window.addEventListener('load', () => { }); }); +// Sent for drag and drop tabs to work properly +document.addEventListener('mousemove', (event) => { + ipcRenderer.sendToHost('mouse-move', {clientX: event.clientX, clientY: event.clientY}); +}); + +document.addEventListener('mouseup', () => { + ipcRenderer.sendToHost('mouse-up'); +}); + // listen for messages from the webapp window.addEventListener('message', ({origin, data: {type, message = {}} = {}} = {}) => { if (origin !== window.location.origin) { diff --git a/src/common/config/RegistryConfig.js b/src/common/config/RegistryConfig.js index c4724592..4af09019 100644 --- a/src/common/config/RegistryConfig.js +++ b/src/common/config/RegistryConfig.js @@ -72,6 +72,7 @@ export default class RegistryConfig extends EventEmitter { teams.push({ name: team.name, url: team.value, + order: team.order, }); } return teams; diff --git a/src/common/config/defaultPreferences.js b/src/common/config/defaultPreferences.js index 76b95a5c..7658a1f0 100644 --- a/src/common/config/defaultPreferences.js +++ b/src/common/config/defaultPreferences.js @@ -7,7 +7,7 @@ * @param {number} version - Scheme version. (Not application version) */ const defaultPreferences = { - version: 1, + version: 2, teams: [], showTrayIcon: false, trayIconTheme: 'light', @@ -22,6 +22,7 @@ const defaultPreferences = { enableHardwareAcceleration: true, autostart: true, spellCheckerLocale: 'en-US', + darkMode: false, }; export default defaultPreferences; diff --git a/src/common/config/index.js b/src/common/config/index.js index ec086a7e..46b7e95f 100644 --- a/src/common/config/index.js +++ b/src/common/config/index.js @@ -144,6 +144,9 @@ export default class Config extends EventEmitter { get teams() { return this.combinedData.teams; } + get darkMode() { + return this.combinedData.darkMode; + } get localTeams() { return this.localConfigData.teams; } @@ -209,10 +212,16 @@ export default class Config extends EventEmitter { configData = this.readFileSync(this.configFilePath); // validate based on config file version - if (configData.version > 0) { - configData = Validator.validateV1ConfigData(configData); + if (configData.version > 1) { + configData = Validator.validateV2ConfigData(configData); } else { - configData = Validator.validateV0ConfigData(configData); + switch (configData.version) { + case 1: + configData = Validator.validateV1ConfigData(configData); + break; + default: + configData = Validator.validateV0ConfigData(configData); + } } if (!configData) { throw new Error('Provided configuration file does not validate, using defaults instead.'); diff --git a/src/common/config/pastDefaultPreferences.js b/src/common/config/pastDefaultPreferences.js index 20724f45..b47b284d 100644 --- a/src/common/config/pastDefaultPreferences.js +++ b/src/common/config/pastDefaultPreferences.js @@ -7,6 +7,23 @@ const pastDefaultPreferences = { 0: { url: '', }, + 1: { + version: 1, + teams: [], + showTrayIcon: false, + trayIconTheme: 'light', + minimizeToTray: false, + notifications: { + flashWindow: 0, + bounceIcon: false, + bounceIconType: 'informational', + }, + showUnreadBadge: true, + useSpellChecker: true, + enableHardwareAcceleration: true, + autostart: true, + spellCheckerLocale: 'en-US', + }, }; pastDefaultPreferences[`${defaultPreferences.version}`] = defaultPreferences; diff --git a/src/common/config/upgradePreferences.js b/src/common/config/upgradePreferences.js index ca9668aa..38ebadf2 100644 --- a/src/common/config/upgradePreferences.js +++ b/src/common/config/upgradePreferences.js @@ -19,9 +19,21 @@ function upgradeV0toV1(configV0) { return config; } +function upgradeV1toV2(configV1) { + const config = deepCopy(configV1); + config.version = 2; + config.teams.forEach((value, index) => { + value.order = index; + }); + config.darkMode = false; + return config; +} + export default function upgradeToLatest(config) { const configVersion = config.version ? config.version : 0; switch (configVersion) { + case 1: + return upgradeToLatest(upgradeV1toV2(config)); case 0: return upgradeToLatest(upgradeV0toV1(config)); default: diff --git a/src/main.js b/src/main.js index 316d9a07..e43f76e0 100644 --- a/src/main.js +++ b/src/main.js @@ -66,6 +66,7 @@ let registryConfig = null; let config = null; let trayIcon = null; let trayImages = null; +let altLastPressed = false; // supported custom login paths (oath, saml) const customLoginRegexPaths = [ @@ -216,6 +217,9 @@ function initializeInterCommunicationEventListeners() { if (shouldShowTrayIcon()) { ipcMain.on('update-unread', handleUpdateUnreadEvent); } + if (process.platform !== 'darwin') { + ipcMain.on('open-app-menu', handleOpenAppMenu); + } } function initializeMainWindowListeners() { @@ -462,6 +466,19 @@ function handleAppWebContentsCreated(dc, contents) { // implemented to temporarily help solve for https://community-daily.mattermost.com/core/pl/b95bi44r4bbnueqzjjxsi46qiw contents.on('before-input-event', (event, input) => { + if (input.key === 'Alt' && input.type === 'keyUp' && altLastPressed) { + altLastPressed = false; + mainWindow.webContents.send('focus-three-dot-menu'); + return; + } + + // Hack to detect keyPress so that alt+ combinations don't default back to the 3-dot menu + if (input.key === 'Alt' && input.type === 'keyDown') { + altLastPressed = true; + } else { + altLastPressed = false; + } + if (!input.shift && !input.control && !input.alt && !input.meta) { // hacky fix for https://mattermost.atlassian.net/browse/MM-19226 if ((input.key === 'Escape' || input.key === 'f') && input.type === 'keyDown') { @@ -755,9 +772,21 @@ function handleUpdateUnreadEvent(event, arg) { } } +function handleOpenAppMenu() { + Menu.getApplicationMenu().popup({ + x: 18, + y: 18, + }); +} + +function handleCloseAppMenu(event) { + mainWindow.webContents.send('focus-on-webview', event); +} + function handleUpdateMenuEvent(event, configData) { const aMenu = appMenu.createMenu(mainWindow, configData, global.isDev); Menu.setApplicationMenu(aMenu); + aMenu.addListener('menu-will-close', handleCloseAppMenu); // set up context menu for tray icon if (shouldShowTrayIcon()) { diff --git a/src/main/Validator.js b/src/main/Validator.js index 6a615d5b..dd74d43e 100644 --- a/src/main/Validator.js +++ b/src/main/Validator.js @@ -61,6 +61,29 @@ const configDataSchemaV1 = Joi.object({ spellCheckerLocale: Joi.string().regex(/^[a-z]{2}-[A-Z]{2}$/).default('en-US'), }); +const configDataSchemaV2 = Joi.object({ + version: Joi.number().min(2).default(2), + teams: Joi.array().items(Joi.object({ + name: Joi.string().required(), + url: Joi.string().required(), + order: Joi.number().integer().min(0), + })).default([]), + showTrayIcon: Joi.boolean().default(false), + trayIconTheme: Joi.any().allow('').valid('light', 'dark').default('light'), + minimizeToTray: Joi.boolean().default(false), + notifications: Joi.object({ + flashWindow: Joi.any().valid(0, 2).default(0), + bounceIcon: Joi.boolean().default(false), + bounceIconType: Joi.any().allow('').valid('informational', 'critical').default('informational'), + }), + showUnreadBadge: Joi.boolean().default(true), + useSpellChecker: Joi.boolean().default(true), + enableHardwareAcceleration: Joi.boolean().default(true), + autostart: Joi.boolean().default(true), + spellCheckerLocale: Joi.string().regex(/^[a-z]{2}-[A-Z]{2}$/).default('en-US'), + darkMode: Joi.boolean().default(false), +}); + // eg. data['community.mattermost.com'] = { data: 'certificate data', issuerName: 'COMODO RSA Domain Validation Secure Server CA'}; const certificateStoreSchema = Joi.object().pattern( Joi.string().uri(), @@ -113,6 +136,26 @@ export function validateV1ConfigData(data) { return validateAgainstSchema(data, configDataSchemaV1); } +export function validateV2ConfigData(data) { + if (Array.isArray(data.teams) && data.teams.length) { + // first replace possible backslashes with forward slashes + let teams = data.teams.map(({name, url, order}) => { + let updatedURL = url; + if (updatedURL.includes('\\')) { + updatedURL = updatedURL.toLowerCase().replace(/\\/gi, '/'); + } + return {name, url: updatedURL, order}; + }); + + // next filter out urls that are still invalid so all is not lost + teams = teams.filter(({url}) => Utils.isValidURL(url)); + + // replace original teams + data.teams = teams; + } + return validateAgainstSchema(data, configDataSchemaV2); +} + // validate certificate.json export function validateCertificateStore(data) { return validateAgainstSchema(data, certificateStoreSchema); diff --git a/src/main/mainWindow.js b/src/main/mainWindow.js index 39675b09..55a92c54 100644 --- a/src/main/mainWindow.js +++ b/src/main/mainWindow.js @@ -51,7 +51,9 @@ function createMainWindow(config, options) { show: hideOnStartup || false, minWidth: minimumWindowWidth, minHeight: minimumWindowHeight, + frame: false, fullscreen: false, + titleBarStyle: 'hiddenInset', backgroundColor: '#fff', // prevents blurry text: https://electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do webPreferences: { nodeIntegration: true, @@ -156,10 +158,6 @@ function createMainWindow(config, options) { } }); - mainWindow.on('sheet-end', () => { - mainWindow.webContents.send('focus-on-webview'); - }); - // Register keyboard shortcuts mainWindow.webContents.on('before-input-event', (event, input) => { // Add Alt+Cmd+(Right|Left) as alternative to switch between servers diff --git a/src/main/menus/app.js b/src/main/menus/app.js index 12f76d93..e8f694b9 100644 --- a/src/main/menus/app.js +++ b/src/main/menus/app.js @@ -116,79 +116,92 @@ function createTemplate(mainWindow, config, isDev) { role: 'selectall', }], }); + + const viewSubMenu = [{ + label: 'Find..', + accelerator: 'CmdOrCtrl+F', + click(item, focusedWindow) { + focusedWindow.webContents.send('toggle-find'); + }, + }, { + label: 'Reload', + accelerator: 'CmdOrCtrl+R', + click(item, focusedWindow) { + if (focusedWindow) { + if (focusedWindow === mainWindow) { + mainWindow.webContents.send('reload-tab'); + } else { + focusedWindow.reload(); + } + } + }, + }, { + label: 'Clear Cache and Reload', + accelerator: 'Shift+CmdOrCtrl+R', + click(item, focusedWindow) { + if (focusedWindow) { + if (focusedWindow === mainWindow) { + mainWindow.webContents.send('clear-cache-and-reload-tab'); + } else { + focusedWindow.webContents.session.clearCache(() => { + focusedWindow.reload(); + }); + } + } + }, + }, { + role: 'togglefullscreen', + }, separatorItem, { + label: 'Actual Size', + accelerator: 'CmdOrCtrl+0', + click() { + mainWindow.webContents.send('zoom-reset'); + }, + }, { + label: 'Zoom In', + accelerator: 'CmdOrCtrl+SHIFT+=', + click() { + mainWindow.webContents.send('zoom-in'); + }, + }, { + label: 'Zoom Out', + accelerator: 'CmdOrCtrl+-', + click() { + mainWindow.webContents.send('zoom-out'); + }, + }, separatorItem, { + label: 'Developer Tools for Application Wrapper', + accelerator: (() => { + if (process.platform === 'darwin') { + return 'Alt+Command+I'; + } + return 'Ctrl+Shift+I'; + })(), + click(item, focusedWindow) { + if (focusedWindow) { + focusedWindow.toggleDevTools(); + } + }, + }, { + label: 'Developer Tools for Current Server', + click() { + mainWindow.webContents.send('open-devtool'); + }, + }]; + + if (process.platform !== 'darwin') { + viewSubMenu.push(separatorItem); + viewSubMenu.push({ + label: 'Toggle Dark Mode', + click() { + mainWindow.webContents.send('set-dark-mode'); + }, + }); + } + template.push({ label: '&View', - submenu: [{ - label: 'Find..', - accelerator: 'CmdOrCtrl+F', - click(item, focusedWindow) { - focusedWindow.webContents.send('toggle-find'); - }, - }, { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click(item, focusedWindow) { - if (focusedWindow) { - if (focusedWindow === mainWindow) { - mainWindow.webContents.send('reload-tab'); - } else { - focusedWindow.reload(); - } - } - }, - }, { - label: 'Clear Cache and Reload', - accelerator: 'Shift+CmdOrCtrl+R', - click(item, focusedWindow) { - if (focusedWindow) { - if (focusedWindow === mainWindow) { - mainWindow.webContents.send('clear-cache-and-reload-tab'); - } else { - focusedWindow.webContents.session.clearCache(() => { - focusedWindow.reload(); - }); - } - } - }, - }, { - role: 'togglefullscreen', - }, separatorItem, { - label: 'Actual Size', - accelerator: 'CmdOrCtrl+0', - click() { - mainWindow.webContents.send('zoom-reset'); - }, - }, { - label: 'Zoom In', - accelerator: 'CmdOrCtrl+SHIFT+=', - click() { - mainWindow.webContents.send('zoom-in'); - }, - }, { - label: 'Zoom Out', - accelerator: 'CmdOrCtrl+-', - click() { - mainWindow.webContents.send('zoom-out'); - }, - }, separatorItem, { - label: 'Developer Tools for Application Wrapper', - accelerator: (() => { - if (process.platform === 'darwin') { - return 'Alt+Command+I'; - } - return 'Ctrl+Shift+I'; - })(), - click(item, focusedWindow) { - if (focusedWindow) { - focusedWindow.toggleDevTools(); - } - }, - }, { - label: 'Developer Tools for Current Server', - click() { - mainWindow.webContents.send('open-devtool'); - }, - }], + submenu: viewSubMenu, }); template.push({ label: '&History', diff --git a/test/specs/app_test.js b/test/specs/app_test.js index 0e9dc17d..76457c6a 100644 --- a/test/specs/app_test.js +++ b/test/specs/app_test.js @@ -72,13 +72,15 @@ describe('application', function desc() { it('should show index.html when there is config file', async () => { const config = { - version: 1, + version: 2, teams: [{ name: 'example', url: env.mattermostURL, + order: 0, }, { name: 'github', url: 'https://github.com/', + order: 1, }], showTrayIcon: false, trayIconTheme: 'light', @@ -92,6 +94,7 @@ describe('application', function desc() { useSpellChecker: true, enableHardwareAcceleration: true, autostart: true, + darkMode: false, }; fs.writeFileSync(env.configFilePath, JSON.stringify(config)); await this.app.restart(); diff --git a/test/specs/browser/index_test.js b/test/specs/browser/index_test.js index b2e2e15c..bc584a05 100644 --- a/test/specs/browser/index_test.js +++ b/test/specs/browser/index_test.js @@ -14,13 +14,15 @@ describe('browser/index.html', function desc() { this.timeout(30000); const config = { - version: 1, + version: 2, teams: [{ name: 'example', url: env.mattermostURL, + order: 0, }, { name: 'github', url: 'https://github.com/', + order: 1, }], showTrayIcon: false, trayIconTheme: 'light', @@ -34,6 +36,7 @@ describe('browser/index.html', function desc() { useSpellChecker: true, enableHardwareAcceleration: true, autostart: true, + darkMode: false, }; const serverPort = 8181; @@ -65,16 +68,6 @@ describe('browser/index.html', function desc() { this.server.close(done); }); - it('should NOT show tabs when there is one team', async () => { - fs.writeFileSync(env.configFilePath, JSON.stringify({ - url: env.mattermostURL, - })); - await this.app.restart(); - - const existing = await this.app.client.isExisting('#tabBar'); - existing.should.be.false; - }); - it('should set src of webview from config file', async () => { const src0 = await this.app.client.getAttribute('#mattermostView0', 'src'); src0.should.equal(config.teams[0].url); @@ -107,10 +100,11 @@ describe('browser/index.html', function desc() { it.skip('should show error when using incorrect URL', async () => { this.timeout(30000); fs.writeFileSync(env.configFilePath, JSON.stringify({ - version: 1, + version: 2, teams: [{ name: 'error_1', url: 'http://false', + order: 0, }], })); await this.app.restart(); @@ -120,10 +114,11 @@ describe('browser/index.html', function desc() { it('should set window title by using webview\'s one', async () => { fs.writeFileSync(env.configFilePath, JSON.stringify({ - version: 1, + version: 2, teams: [{ name: 'title_test', url: `http://localhost:${serverPort}`, + order: 0, }], })); await this.app.restart(); @@ -135,13 +130,15 @@ describe('browser/index.html', function desc() { // Skip because it's very unstable in CI it.skip('should update window title when the activated tab\'s title is updated', async () => { fs.writeFileSync(env.configFilePath, JSON.stringify({ - version: 1, + version: 2, teams: [{ name: 'title_test_0', url: `http://localhost:${serverPort}`, + order: 0, }, { name: 'title_test_1', url: `http://localhost:${serverPort}`, + order: 1, }], })); await this.app.restart(); @@ -171,13 +168,15 @@ describe('browser/index.html', function desc() { // Skip because it's very unstable in CI it.skip('should update window title when a tab is selected', async () => { fs.writeFileSync(env.configFilePath, JSON.stringify({ - version: 1, + version: 2, teams: [{ name: 'title_test_0', url: `http://localhost:${serverPort}`, + order: 0, }, { name: 'title_test_1', url: `http://localhost:${serverPort}`, + order: 1, }], })); await this.app.restart(); diff --git a/test/specs/browser/settings_test.js b/test/specs/browser/settings_test.js index 28ff1aa6..4d749275 100644 --- a/test/specs/browser/settings_test.js +++ b/test/specs/browser/settings_test.js @@ -12,13 +12,15 @@ describe('browser/settings.html', function desc() { this.timeout(30000); const config = { - version: 1, + version: 2, teams: [{ name: 'example', url: env.mattermostURL, + order: 0, }, { name: 'github', url: 'https://github.com/', + order: 1, }], showTrayIcon: false, trayIconTheme: 'light', @@ -32,6 +34,7 @@ describe('browser/settings.html', function desc() { useSpellChecker: true, enableHardwareAcceleration: true, autostart: true, + darkMode: false, }; beforeEach(async () => { @@ -357,8 +360,13 @@ describe('browser/settings.html', function desc() { await this.app.client.waitForVisible('#serversSaveIndicator', 10000, true); + const expectedConfig = JSON.parse(JSON.stringify(config.teams.slice(1))); + expectedConfig.forEach((value) => { + value.order--; + }); + const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8')); - savedConfig.teams.should.deep.equal(config.teams.slice(1)); + savedConfig.teams.should.deep.equal(expectedConfig); }); it('should NOT remove existing team on click Cancel', async () => { @@ -512,6 +520,7 @@ describe('browser/settings.html', function desc() { savedConfig.teams.should.deep.contain({ name: 'TestTeam', url: 'http://example.org', + order: 2, }); }); }); diff --git a/test/specs/security_test.js b/test/specs/security_test.js index 9e53c671..02f5169e 100644 --- a/test/specs/security_test.js +++ b/test/specs/security_test.js @@ -16,13 +16,15 @@ describe.skip('security', function desc() { const testURL = `http://localhost:${serverPort}`; const config = { - version: 1, + version: 2, teams: [{ name: 'example_1', url: testURL, + order: 0, }, { name: 'example_2', url: testURL, + order: 1, }], }; diff --git a/webpack.config.renderer.js b/webpack.config.renderer.js index b06382a0..5d2008de 100644 --- a/webpack.config.renderer.js +++ b/webpack.config.renderer.js @@ -41,6 +41,18 @@ module.exports = merge(base, { use: { loader: 'url-loader', }, + }, { + test: /\.(svg|woff2)$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[hash].[ext]', + publicPath: './', + }, + }, + {loader: 'image-webpack-loader'}, + ], }], }, node: {