Begin integrating blueprint (#359)

* toast test

* modify webpack build to allow for global CSS; use CSS modules to scope component styling

* remove heatmap

* add label to index resets

* swapping out buttons for blueprint

* adding constants to globals

* swapping out blueprint buttons

* title position, sidebar improvements

* sidebar styles

* adding toasts for validation errors

* zebra section trial

* integrating blueprint, switching buttons over, breaking out scatter

* clean up console
This commit is contained in:
Colin Megill
2018-10-22 15:46:37 -04:00
committed by GitHub
parent 0c271bc815
commit df671192be
34 changed files with 717 additions and 737 deletions
@@ -6,6 +6,8 @@ const HtmlWebpackPlugin = require("html-webpack-plugin");
const src = path.resolve("src"); const src = path.resolve("src");
const nodeModules = path.resolve("node_modules"); const nodeModules = path.resolve("node_modules");
const babelOptions = require("../babel/babel.dev");
module.exports = { module.exports = {
mode: "development", mode: "development",
devtool: "eval", devtool: "eval",
@@ -22,11 +24,12 @@ module.exports = {
test: /\.js$/, test: /\.js$/,
include: src, include: src,
loader: "babel-loader", loader: "babel-loader",
options: require("../babel/babel.dev") options: babelOptions
}, },
{ {
test: /\.css$/, test: /\.css$/,
include: [src, nodeModules], include: src,
exclude: [path.resolve(src, "index.css")],
loader: [ loader: [
{ {
loader: "style-loader" loader: "style-loader"
@@ -35,12 +38,24 @@ module.exports = {
loader: "css-loader", loader: "css-loader",
options: { options: {
modules: true, modules: true,
importLoaders: 1,
localIdentName: "[name]__[local]___[hash:base64:5]" localIdentName: "[name]__[local]___[hash:base64:5]"
} }
} }
] ]
}, },
{
test: /index\.css$/,
include: [path.resolve(src, "index.css")],
loader: [
{
loader: "style-loader"
},
{
loader: "css-loader"
}
]
},
{ test: /\.json$/, include: [src, nodeModules], loader: "json-loader" }, { test: /\.json$/, include: [src, nodeModules], loader: "json-loader" },
{ {
test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/,
@@ -1,6 +1,5 @@
// jshint esversion: 6 // jshint esversion: 6
const path = require("path"); const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const SWPrecacheWebpackPlugin = require("sw-precache-webpack-plugin"); const SWPrecacheWebpackPlugin = require("sw-precache-webpack-plugin");
@@ -9,6 +8,8 @@ const HtmlWebpackInlineSourcePlugin = require("html-webpack-inline-source-plugin
const src = path.resolve("src"); const src = path.resolve("src");
const nodeModules = path.resolve("node_modules"); const nodeModules = path.resolve("node_modules");
const babelOptions = require("../babel/babel.prod");
const publicPath = "/"; const publicPath = "/";
module.exports = { module.exports = {
@@ -16,7 +17,7 @@ module.exports = {
bail: true, bail: true,
cache: false, cache: false,
devtool: "cheap-source-map", devtool: "cheap-source-map",
entry: ["./src/index"], entry: ["./src/index.js"],
output: { output: {
path: path.resolve("build"), path: path.resolve("build"),
filename: "static/js/[name].[chunkhash:8].js", filename: "static/js/[name].[chunkhash:8].js",
@@ -28,15 +29,14 @@ module.exports = {
test: /\.js$/, test: /\.js$/,
include: src, include: src,
loader: "babel-loader", loader: "babel-loader",
options: require("../babel/babel.prod") options: babelOptions
}, },
{ {
test: /\.css$/, test: /\.css$/,
include: [src, nodeModules], include: src,
loader: [ exclude: [path.resolve(src, "index.css")],
{ use: [
loader: MiniCssExtractPlugin.loader MiniCssExtractPlugin.loader,
},
{ {
loader: "css-loader", loader: "css-loader",
options: { options: {
@@ -47,6 +47,19 @@ module.exports = {
} }
] ]
}, },
{
test: /index\.css$/,
include: [path.resolve(src, "index.css")],
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
importLoaders: 1
}
}
]
},
{ {
test: /\.json$/, test: /\.json$/,
include: [src, nodeModules], include: [src, nodeModules],
@@ -57,7 +70,10 @@ module.exports = {
test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/,
include: [src, nodeModules], include: [src, nodeModules],
loader: "file-loader", loader: "file-loader",
query: { name: "static/media/[name].[hash:8].[ext]" } options: {
name: "[name].[hash:8].[ext]",
outputPath: "static/media/"
}
}, },
{ {
test: /\.(mp4|webm)(\?.*)?$/, test: /\.(mp4|webm)(\?.*)?$/,
@@ -97,7 +113,7 @@ module.exports = {
}) })
], ],
performance: { performance: {
maxEntrypointSize: 750000, maxEntrypointSize: 2000000,
maxAssetSize: 750000 maxAssetSize: 2000000
} }
}; };
+2 -2
View File
@@ -6,9 +6,9 @@
<title>cellxgene</title> <title>cellxgene</title>
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,400i,700" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,400i,700" rel="stylesheet">
<style> <style>
html, body, p, h1, h2, h3, h4, h5, h6, span, button, input, text { html, body, p, h1, h2, h3, h4, h5, h6, span, button, input, label, text {
font-family: 'Roboto Condensed','Helvetica Neue','Helvetica','Arial',sans-serif; font-family: 'Roboto Condensed','Helvetica Neue','Helvetica','Arial',sans-serif;
font-size: 16px; font-size: 14px;
} }
body { body {
margin: 0; margin: 0;
+12 -3
View File
@@ -4,10 +4,19 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>cellxgene</title> <title>cellxgene</title>
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,400i,700" rel="stylesheet">
<style> <style>
html, body, p, h1, h2, h3, h4, h5, h6, span, button, input { html, body, p, h1, h2, h3, h4, h5, h6, span, button, input, label, text {
font-family: Helvetica Neue,Helvetica,Arial,sans-serif; font-family: 'Roboto Condensed','Helvetica Neue','Helvetica','Arial',sans-serif;
font-size: 16px; font-size: 14px;
}
body {
margin: 0;
padding: 0;
}
* {
box-sizing: border-box;
} }
</style> </style>
</head> </head>
+231 -40
View File
@@ -913,6 +913,47 @@
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
} }
}, },
"@blueprintjs/core": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/@blueprintjs/core/-/core-3.7.0.tgz",
"integrity": "sha512-fr1jgAY/sPWJ7BorebuyLQKTTk7x+/1suayaxKVh1WMQ7aIi3Zb7HnJPEVFQyaT+9rVl97b7/2DiID3N8/UGMw==",
"requires": {
"@blueprintjs/icons": "^3.2.0",
"@types/dom4": "^2.0.0",
"classnames": "^2.2",
"dom4": "^2.0.1",
"normalize.css": "^8.0.0",
"popper.js": "^1.14.1",
"react-popper": "^1.0.0",
"react-transition-group": "^2.2.1",
"resize-observer-polyfill": "^1.5.0",
"tslib": "^1.9.0"
}
},
"@blueprintjs/icons": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@blueprintjs/icons/-/icons-3.2.0.tgz",
"integrity": "sha512-MoI4TdZ2QMM9DEd+/vJOMSlhuvPID3Zip0TB/MB1J7p7GnUThIRq2FlETMUg6ig1GZweAWNl7cUtYFNHZ3EiUQ==",
"requires": {
"classnames": "^2.2",
"tslib": "^1.9.0"
}
},
"@blueprintjs/select": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@blueprintjs/select/-/select-3.2.0.tgz",
"integrity": "sha512-kieg23ktzCXBUT7oVKBwlnPrjpwH8GgB722BL4nMV+c9cnt9gHuhk6eGORd3w8tK9gI85F/+brVkimbmQShVZg==",
"requires": {
"@blueprintjs/core": "^3.6.0",
"classnames": "^2.2",
"tslib": "^1.9.0"
}
},
"@types/dom4": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@types/dom4/-/dom4-2.0.1.tgz",
"integrity": "sha512-kSkVAvWmMZiCYtvqjqQEwOmvKwcH+V4uiv3qPQ8pAh1Xl39xggGEo8gHUqV4waYGHezdFw0rKBR8Jt0CrQSDZA=="
},
"@webassemblyjs/ast": { "@webassemblyjs/ast": {
"version": "1.7.8", "version": "1.7.8",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.8.tgz", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.8.tgz",
@@ -1632,6 +1673,11 @@
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
"dev": true "dev": true
}, },
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"asn1": { "asn1": {
"version": "0.2.4", "version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -2054,7 +2100,7 @@
}, },
"babel-plugin-syntax-object-rest-spread": { "babel-plugin-syntax-object-rest-spread": {
"version": "6.13.0", "version": "6.13.0",
"resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
"dev": true "dev": true
}, },
@@ -2167,7 +2213,6 @@
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"dev": true,
"requires": { "requires": {
"core-js": "^2.4.0", "core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0" "regenerator-runtime": "^0.11.0"
@@ -2176,8 +2221,7 @@
"regenerator-runtime": { "regenerator-runtime": {
"version": "0.11.1", "version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
"dev": true
} }
} }
}, },
@@ -2489,7 +2533,7 @@
}, },
"browserify-aes": { "browserify-aes": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -2526,7 +2570,7 @@
}, },
"browserify-rsa": { "browserify-rsa": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -2580,7 +2624,7 @@
}, },
"buffer": { "buffer": {
"version": "4.9.1", "version": "4.9.1",
"resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
"integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -2951,6 +2995,11 @@
} }
} }
}, },
"classnames": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
},
"clean-css": { "clean-css": {
"version": "4.2.1", "version": "4.2.1",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
@@ -3228,8 +3277,7 @@
"core-js": { "core-js": {
"version": "2.5.7", "version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
"dev": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@@ -3258,7 +3306,7 @@
}, },
"create-hash": { "create-hash": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -3271,7 +3319,7 @@
}, },
"create-hmac": { "create-hmac": {
"version": "1.1.7", "version": "1.1.7",
"resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -3283,6 +3331,15 @@
"sha.js": "^2.4.8" "sha.js": "^2.4.8"
} }
}, },
"create-react-context": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.3.tgz",
"integrity": "sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==",
"requires": {
"fbjs": "^0.8.0",
"gud": "^1.0.0"
}
},
"cross-spawn": { "cross-spawn": {
"version": "6.0.5", "version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@@ -3945,7 +4002,7 @@
}, },
"diffie-hellman": { "diffie-hellman": {
"version": "5.0.3", "version": "5.0.3",
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -3993,6 +4050,11 @@
"utila": "~0.4" "utila": "~0.4"
} }
}, },
"dom-helpers": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.3.1.tgz",
"integrity": "sha512-2Sm+JaYn74OiTM2wHvxJOo3roiq/h25Yi69Fqk269cNUwIXsCvATB6CRSFC9Am/20G2b28hGv/+7NiWydIrPvg=="
},
"dom-scroll-into-view": { "dom-scroll-into-view": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-1.0.1.tgz", "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-1.0.1.tgz",
@@ -4025,6 +4087,11 @@
"urijs": "^1.16.1" "urijs": "^1.16.1"
} }
}, },
"dom4": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/dom4/-/dom4-2.1.3.tgz",
"integrity": "sha512-begvh4z5GV0kyxx+YgJZ7sIo/jsELx/v7MQxoLZpOvT5yFo18X8dfgtUmKAwdGuyMeugncylarLHlO4gIK6YNw=="
},
"domain-browser": { "domain-browser": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
@@ -4152,6 +4219,14 @@
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
"dev": true "dev": true
}, },
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
"requires": {
"iconv-lite": "~0.4.13"
}
},
"end-of-stream": { "end-of-stream": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
@@ -4539,7 +4614,7 @@
}, },
"load-json-file": { "load-json-file": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -4716,7 +4791,7 @@
}, },
"events": { "events": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "http://registry.npmjs.org/events/-/events-1.1.1.tgz", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
}, },
"evp_bytestokey": { "evp_bytestokey": {
@@ -4950,6 +5025,27 @@
"bser": "^2.0.0" "bser": "^2.0.0"
} }
}, },
"fbjs": {
"version": "0.8.17",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
"integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
"requires": {
"core-js": "^1.0.0",
"isomorphic-fetch": "^2.1.1",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^0.7.18"
},
"dependencies": {
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
}
}
},
"figures": { "figures": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
@@ -5010,7 +5106,7 @@
}, },
"finalhandler": { "finalhandler": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -5734,7 +5830,7 @@
}, },
"get-stream": { "get-stream": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
"dev": true "dev": true
}, },
@@ -5862,6 +5958,11 @@
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
"dev": true "dev": true
}, },
"gud": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz",
"integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw=="
},
"handlebars": { "handlebars": {
"version": "4.0.12", "version": "4.0.12",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz",
@@ -6113,7 +6214,7 @@
}, },
"html-webpack-plugin": { "html-webpack-plugin": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "http://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz",
"integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -6189,7 +6290,7 @@
}, },
"http-errors": { "http-errors": {
"version": "1.6.3", "version": "1.6.3",
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -6412,7 +6513,7 @@
}, },
"is-builtin-module": { "is-builtin-module": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -6645,8 +6746,7 @@
"is-stream": { "is-stream": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
"dev": true
}, },
"is-symbol": { "is-symbol": {
"version": "1.0.2", "version": "1.0.2",
@@ -6696,6 +6796,15 @@
"isarray": "1.0.0" "isarray": "1.0.0"
} }
}, },
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"requires": {
"node-fetch": "^1.0.1",
"whatwg-fetch": ">=0.10.0"
}
},
"isstream": { "isstream": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -7411,7 +7520,7 @@
}, },
"json5": { "json5": {
"version": "0.5.1", "version": "0.5.1",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true "dev": true
}, },
@@ -7501,7 +7610,7 @@
}, },
"load-json-file": { "load-json-file": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -7830,7 +7939,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
} }
@@ -7955,7 +8064,7 @@
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true "dev": true
}, },
@@ -8000,7 +8109,7 @@
}, },
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -8128,6 +8237,15 @@
"lower-case": "^1.1.1" "lower-case": "^1.1.1"
} }
}, },
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
},
"node-int64": { "node-int64": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@@ -8221,6 +8339,11 @@
"remove-trailing-separator": "^1.0.1" "remove-trailing-separator": "^1.0.1"
} }
}, },
"normalize.css": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.0.tgz",
"integrity": "sha512-iXcbM3NWr0XkNyfiSBsoPezi+0V92P9nj84yVV1/UZxRUrGczgX/X91KMAGM0omWLY2+2Q1gKD/XRn4gQRDB2A=="
},
"npm-run-path": { "npm-run-path": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -9712,7 +9835,7 @@
}, },
"parse-asn1": { "parse-asn1": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "http://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz",
"integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -9899,6 +10022,11 @@
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
"dev": true "dev": true
}, },
"popper.js": {
"version": "1.14.4",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz",
"integrity": "sha1-juwdj/AqWjoVLdQ0FKFce3n9abY="
},
"posix-character-classes": { "posix-character-classes": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@@ -10045,6 +10173,14 @@
"integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=",
"dev": true "dev": true
}, },
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
},
"promise-inflight": { "promise-inflight": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@@ -10306,9 +10442,27 @@
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.2.0.tgz", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.2.0.tgz",
"integrity": "sha512-ZWqIiOr5wTqtE6NNM9JgWBgNbq2JRi79rmqf2j50V1ewC6LiwKFhq7J/AjaVKBi5oPE4/9JN/jMKaVrJlIQoiw==" "integrity": "sha512-ZWqIiOr5wTqtE6NNM9JgWBgNbq2JRi79rmqf2j50V1ewC6LiwKFhq7J/AjaVKBi5oPE4/9JN/jMKaVrJlIQoiw=="
}, },
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-popper": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.0.2.tgz",
"integrity": "sha512-vjZ94ki8sfCAg45MMi4uqnUUWdzbnYkb95sR2+HgiMaAPzQcy4DfDKYtYUOhhE+sdtkufWcUHLv09DmH2Js57w==",
"requires": {
"babel-runtime": "6.x.x",
"create-react-context": "^0.2.1",
"popper.js": "^1.14.1",
"prop-types": "^15.6.1",
"typed-styles": "^0.0.5",
"warning": "^3.0.0"
}
},
"react-redux": { "react-redux": {
"version": "5.0.7", "version": "5.0.7",
"resolved": "http://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz",
"integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==", "integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==",
"requires": { "requires": {
"hoist-non-react-statics": "^2.5.0", "hoist-non-react-statics": "^2.5.0",
@@ -10328,6 +10482,17 @@
"shallowequal": "^1.0.1" "shallowequal": "^1.0.1"
} }
}, },
"react-transition-group": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.0.tgz",
"integrity": "sha512-qYB3JBF+9Y4sE4/Mg/9O6WFpdoYjeeYqx0AFb64PTazVy8RPMiE3A47CG9QmM4WJ/mzDiZYslV+Uly6O1Erlgw==",
"requires": {
"dom-helpers": "^3.3.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4"
}
},
"read-pkg": { "read-pkg": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -10372,7 +10537,7 @@
}, },
"readable-stream": { "readable-stream": {
"version": "2.3.6", "version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -10957,6 +11122,11 @@
"resolve-from": "^1.0.0" "resolve-from": "^1.0.0"
} }
}, },
"resize-observer-polyfill": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.0.tgz",
"integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg=="
},
"resolve": { "resolve": {
"version": "1.8.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
@@ -11390,7 +11560,7 @@
}, },
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
}, },
@@ -11566,8 +11736,7 @@
"setimmediate": { "setimmediate": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
"dev": true
}, },
"setprototypeof": { "setprototypeof": {
"version": "1.1.0", "version": "1.1.0",
@@ -11577,7 +11746,7 @@
}, },
"sha.js": { "sha.js": {
"version": "2.4.11", "version": "2.4.11",
"resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -12031,7 +12200,7 @@
}, },
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -12267,7 +12436,7 @@
}, },
"through": { "through": {
"version": "2.3.8", "version": "2.3.8",
"resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true "dev": true
}, },
@@ -12413,8 +12582,7 @@
"tslib": { "tslib": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
"dev": true
}, },
"tty-browserify": { "tty-browserify": {
"version": "0.0.0", "version": "0.0.0",
@@ -12456,12 +12624,22 @@
"mime-types": "~2.1.18" "mime-types": "~2.1.18"
} }
}, },
"typed-styles": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.5.tgz",
"integrity": "sha512-ht+rEe5UsdEBAa3gr64+QjUOqjOLJfWLvl5HZR5Ev9uo/OnD3p43wPeFSB1hNFc13GXQF/JU1Bn0YHLUqBRIlw=="
},
"typedarray": { "typedarray": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true "dev": true
}, },
"ua-parser-js": {
"version": "0.7.18",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz",
"integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA=="
},
"uglify-js": { "uglify-js": {
"version": "3.4.9", "version": "3.4.9",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
@@ -12894,6 +13072,14 @@
"makeerror": "1.0.x" "makeerror": "1.0.x"
} }
}, },
"warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
"requires": {
"loose-envify": "^1.0.0"
}
},
"watch": { "watch": {
"version": "0.18.0", "version": "0.18.0",
"resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz",
@@ -12906,7 +13092,7 @@
"dependencies": { "dependencies": {
"minimist": { "minimist": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true "dev": true
} }
@@ -13501,6 +13687,11 @@
"iconv-lite": "0.4.24" "iconv-lite": "0.4.24"
} }
}, },
"whatwg-fetch": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
"integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q=="
},
"whatwg-mimetype": { "whatwg-mimetype": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz",
@@ -13564,7 +13755,7 @@
}, },
"wrap-ansi": { "wrap-ansi": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
"dev": true, "dev": true,
"requires": { "requires": {
@@ -13672,7 +13863,7 @@
}, },
"yargs": { "yargs": {
"version": "11.1.0", "version": "11.1.0",
"resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz",
"integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==",
"dev": true, "dev": true,
"requires": { "requires": {
+4
View File
@@ -27,6 +27,9 @@
"eslint-scope": "3.7.1" "eslint-scope": "3.7.1"
}, },
"dependencies": { "dependencies": {
"@blueprintjs/core": "^3.7.0",
"@blueprintjs/icons": "^3.2.0",
"@blueprintjs/select": "^3.2.0",
"canvas-fit": "^1.5.0", "canvas-fit": "^1.5.0",
"d3": "^4.10.0", "d3": "^4.10.0",
"d3-scale-chromatic": "^1.3.0", "d3-scale-chromatic": "^1.3.0",
@@ -38,6 +41,7 @@
"memoize-one": "^4.0.0", "memoize-one": "^4.0.0",
"mouse-position": "^2.0.1", "mouse-position": "^2.0.1",
"mouse-pressed": "^1.0.0", "mouse-pressed": "^1.0.0",
"normalize.css": "^8.0.0",
"orbit-camera": "^1.0.0", "orbit-camera": "^1.0.0",
"query-string": "^6.1.0", "query-string": "^6.1.0",
"react": "^16.4.2", "react": "^16.4.2",
@@ -230,9 +230,9 @@ class HistogramBrush extends React.Component {
colorAccessor, colorAccessor,
isUserDefined, isUserDefined,
isDiffExp, isDiffExp,
diffExp_avgDiff, avgDiff,
diffExp_set1AvgExp, set1AvgExp,
diffExp_set2AvgExp, set2AvgExp,
scatterplotXXaccessor, scatterplotXXaccessor,
scatterplotYYaccessor scatterplotYYaccessor
} = this.props; } = this.props;
@@ -269,7 +269,7 @@ class HistogramBrush extends React.Component {
}} }}
> >
<strong>1:</strong> <strong>1:</strong>
{` ${diffExp_set1AvgExp.toPrecision(2)}`} {` ${set1AvgExp.toPrecision(2)}`}
</span> </span>
<span <span
style={{ style={{
@@ -280,7 +280,7 @@ class HistogramBrush extends React.Component {
}} }}
> >
<strong>2:</strong> <strong>2:</strong>
{` ${diffExp_set2AvgExp.toPrecision(2)}`} {` ${set2AvgExp.toPrecision(2)}`}
</span> </span>
<span <span
style={{ style={{
@@ -288,7 +288,7 @@ class HistogramBrush extends React.Component {
marginLeft: 7 marginLeft: 7
}} }}
> >
{`Av. Diff: ${diffExp_avgDiff.toFixed(2)}`} {`Av. Diff: ${avgDiff.toFixed(2)}`}
</span> </span>
<span <span
onClick={this.handleSetGeneAsScatterplotX(field).bind(this)} onClick={this.handleSetGeneAsScatterplotX(field).bind(this)}
@@ -2,6 +2,7 @@
import React from "react"; import React from "react";
import _ from "lodash"; import _ from "lodash";
import { connect } from "react-redux"; import { connect } from "react-redux";
import * as globals from "../../globals";
import * as globals from "../../globals"; import * as globals from "../../globals";
import Category from "./category"; import Category from "./category";
@@ -38,13 +39,16 @@ class Categories extends React.Component {
return ( return (
<div <div
style={{ style={{
width: 310, padding: globals.leftSidebarSectionPadding
marginRight: 40,
paddingRight: 20,
flexShrink: 0
}} }}
> >
<p> Categorical Metadata </p> <p
style={Object.assign({}, globals.leftSidebarSectionHeading, {
marginTop: 4
})}
>
Categorical Metadata
</p>
{_.map(ranges, (value, key) => { {_.map(ranges, (value, key) => {
const isColorField = key.includes("color") || key.includes("Color"); const isColorField = key.includes("color") || key.includes("Color");
const isSelectableCategory = const isSelectableCategory =
+36 -47
View File
@@ -119,34 +119,11 @@ class Category extends React.Component {
<div <div
style={{ style={{
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "flex-start",
alignItems: "baseline" alignItems: "baseline"
}} }}
> >
<p <label className="bp3-control bp3-checkbox">
style={{
// flexShrink: 0,
fontWeight: 500,
// textAlign: "right",
// fontFamily: globals.accentFont,
// fontStyle: "italic",
margin: "3px 10px 3px 0px"
}}
>
<span
style={{
cursor: "pointer",
display: "inline-block",
position: "relative",
top: 2
}}
onClick={() => {
this.setState({ isExpanded: !isExpanded });
}}
>
{isExpanded ? <FaChevronDown /> : <FaChevronRight />}
</span>
{metadataField}
<input <input
onChange={this.handleToggleAllClick.bind(this)} onChange={this.handleToggleAllClick.bind(this)}
ref={el => { ref={el => {
@@ -156,29 +133,41 @@ class Category extends React.Component {
checked={isChecked} checked={isChecked}
type="checkbox" type="checkbox"
/> />
<span <span className="bp3-control-indicator" />
onClick={this.handleColorChange.bind(this)} {""}
style={{ </label>
fontSize: 14,
marginLeft: 4, <span
// padding: this.props.colorAccessor === this.props.metadataField ? 3 : "auto", style={{
borderRadius: 3, cursor: "pointer",
color: display: "inline-block"
colorAccessor === metadataField }}
? globals.brightBlue onClick={() => {
: "black", this.setState({ isExpanded: !isExpanded });
// backgroundColor: this.props.colorAccessor === this.props.metadataField ? globals.brightBlue : "inherit", }}
display: "inline-block", >
position: "relative", {metadataField}
top: 2, {isExpanded ? (
cursor: "pointer" <FaChevronDown style={{ fontSize: 10, marginLeft: 5 }} />
}} ) : (
> <FaChevronRight style={{ fontSize: 10, marginLeft: 5 }} />
<FaPaintBrush /> )}
</span> </span>
</p>
<span
onClick={this.handleColorChange.bind(this)}
style={{
marginLeft: 4,
color:
colorAccessor === metadataField ? globals.brightBlue : "black",
display: "inline-block",
cursor: "pointer"
}}
>
<FaPaintBrush style={{ fontSize: 12, marginLeft: 10 }} />
</span>
</div> </div>
<div>{isExpanded ? this.renderCategoryItems() : null}</div> <div style={{ marginLeft: 26 }}>{isExpanded ? this.renderCategoryItems() : null}</div>
<div> <div>
{isExpanded && isTruncated ? ( {isExpanded && isTruncated ? (
<p style={{ paddingLeft: 15 }}>... truncated list ...</p> <p style={{ paddingLeft: 15 }}>... truncated list ...</p>
+27 -30
View File
@@ -49,42 +49,39 @@ class CategoryValue extends React.Component {
style={{ style={{
display: "flex", display: "flex",
alignItems: "baseline", alignItems: "baseline",
justifyContent: "space-between", justifyContent: "space-between"
fontWeight: selected ? 700 : 400
}} }}
> >
<p <div
style={{ style={{
paddingLeft: 15, margin: 0,
width: 200, padding: 0,
flexShrink: 0, userSelect: "none"
margin: 0
// lineHeight: "1em"
}} }}
> >
<input <label className="bp3-control bp3-checkbox">
style={{ position: "relative", top: 1 }} <input
onChange={ onChange={
selected ? this.toggleOff.bind(this) : this.toggleOn.bind(this) selected ? this.toggleOff.bind(this) : this.toggleOn.bind(this)
} }
checked={selected} checked={selected}
type="checkbox" type="checkbox"
/>
<span className="bp3-control-indicator" />
{value}
</label>
</div>
<span>
<span>{count}</span>
<svg
style={{
marginLeft: 5,
width: 11,
height: 11,
backgroundColor: c ? colorScale(value) : "inherit"
}}
/> />
{value} </span>
</p>
<p
style={{
padding: "1px 10px",
width: 80,
textAlign: "center",
backgroundColor: c ? colorScale(value) : "inherit",
color: c ? "white" : "black",
margin: 0
// lineHeight: "1em"
}}
>
{count}
</p>
</div> </div>
); );
} }
+15 -2
View File
@@ -4,6 +4,7 @@
import React from "react"; import React from "react";
import _ from "lodash"; import _ from "lodash";
import { connect } from "react-redux"; import { connect } from "react-redux";
import * as globals from "../../globals";
import HistogramBrush from "../brushableHistogram"; import HistogramBrush from "../brushableHistogram";
@@ -48,8 +49,20 @@ class Continuous extends React.Component {
} }
return ( return (
<div> <div
{this.hasContinuous ? <p> Continuous metadata </p> : null} style={{
padding: globals.leftSidebarSectionPadding
}}
>
{this.hasContinuous ? (
<p
style={Object.assign({}, globals.leftSidebarSectionHeading, {
marginTop: 40
})}
>
Continuous metadata
</p>
) : null}
{_.map(ranges, (value, key) => { {_.map(ranges, (value, key) => {
const isColorField = key.includes("color") || key.includes("Color"); const isColorField = key.includes("color") || key.includes("Color");
if (value.range && key !== "name" && !isColorField) { if (value.range && key !== "name" && !isColorField) {
@@ -7,24 +7,24 @@ body {
} }
*/ */
.parcoords { :local(.parcoords) {
display: block; display: block;
} }
.parcoords svg, :local(.parcoords) svg,
.parcoords canvas { :local(.parcoords) canvas {
font: 10px sans-serif; font: 10px sans-serif;
position: absolute; position: absolute;
} }
.parcoords canvas { :local(.parcoords) canvas {
opacity: 0.9; opacity: 0.9;
pointer-events: none; pointer-events: none;
} }
.axis .title { :local(.axis .title) {
font-size: 10px; font-size: 10px;
transform: rotate(-21deg) translate(-5px,-6px); transform: rotate(-21deg) translate(-5px, -6px);
fill: #222; fill: #222;
cursor: pointer; cursor: pointer;
} }
@@ -32,14 +32,14 @@ body {
/* -webkit-filter: grayscale(100%); /* -webkit-filter: grayscale(100%);
filter: grayscale(100%); */ filter: grayscale(100%); */
.axis line, :local(.axis) line,
.axis path { :local(.axis) path {
fill: none; fill: none;
stroke: #ccc; stroke: #ccc;
stroke-width: 1px; stroke-width: 1px;
} }
.axis .tick text { :local(.axis .tick) text {
fill: #222; fill: #222;
pointer-events: none; pointer-events: none;
} }
@@ -52,39 +52,39 @@ old, from reference bl.ocks
} }
*/ */
.axis:hover line, :local(.axis:hover) line,
.axis:hover path, :local(.axis:hover) path,
.axis.active line, :local(.axis.active) line,
.axis.active path { :local(.axis.active) path {
fill: none; fill: none;
stroke: #222; stroke: #222;
stroke-width: 1px; stroke-width: 1px;
} }
.axis:hover .title { :local(.axis:hover .title) {
font-weight: bold; font-weight: bold;
} }
.axis:hover .tick text { :local(.axis:hover .tick) text {
opacity: 1; opacity: 1;
} }
.axis.active .title { :local(.axis.active .title) {
font-weight: bold; font-weight: bold;
} }
.axis.active .tick text { :local(.axis.active .tick) text {
opacity: 1; opacity: 1;
font-weight: bold; font-weight: bold;
} }
.brush .extent { :local(.brush .extent) {
fill-opacity: .3; fill-opacity: 0.3;
stroke: #fff; stroke: #fff;
stroke-width: 1px; stroke-width: 1px;
} }
.pre { :local(.pre) {
width: 100%; width: 100%;
height: 300px; height: 300px;
margin: 6px 12px; margin: 6px 12px;
@@ -6,7 +6,7 @@ import { interpolateViridis } from "d3-scale-chromatic";
// create continuous color legend // create continuous color legend
// http://bl.ocks.org/syntagmatic/e8ccca52559796be775553b467593a9f // http://bl.ocks.org/syntagmatic/e8ccca52559796be775553b467593a9f
const continuous = (selectorId, colorscale) => { const continuous = (selectorId, colorscale, colorAccessor) => {
const legendheight = 200; const legendheight = 200;
const legendwidth = 80; const legendwidth = 80;
const margin = { top: 10, right: 60, bottom: 10, left: 2 }; const margin = { top: 10, right: 60, bottom: 10, left: 2 };
@@ -84,6 +84,17 @@ const continuous = (selectorId, colorscale) => {
`translate(${legendwidth - margin.left - margin.right + 3},${margin.top})` `translate(${legendwidth - margin.left - margin.right + 3},${margin.top})`
) )
.call(legendaxis); .call(legendaxis);
// text label for the y axis
// svg
// .append("text")
// .attr("transform", "rotate(-90)")
// .attr("y", 3)
// .attr("x", 0 - legendheight / 2)
// .attr("dy", "1em")
// .style("text-anchor", "middle")
// .style("fill", "white")
// .text(colorAccessor);
}; };
@connect(state => ({ @connect(state => ({
@@ -115,7 +126,8 @@ class ContinuousLegend extends React.Component {
if (colorScale.range()[0][0] !== "#") { if (colorScale.range()[0][0] !== "#") {
continuous( continuous(
"#continuous_legend", "#continuous_legend",
d3.scaleSequential(interpolateViridis).domain(colorScale.domain()) d3.scaleSequential(interpolateViridis).domain(colorScale.domain()),
colorAccessor
); );
} }
} }
@@ -1,71 +0,0 @@
// jshint esversion: 6
import React from "react";
import _ from "lodash";
import { connect } from "react-redux";
import * as globals from "../../globals";
@connect()
class CellSetButton extends React.Component {
set() {
const {
differential,
crossfilter,
dispatch,
eitherCellSetOneOrTwo
} = this.props;
const set = _.map(crossfilter.allFiltered(), "name");
if (!differential.diffExp) {
/* diffexp needs to be cleared before we store a new set */
dispatch({
type: `store current cell selection as differential set ${eitherCellSetOneOrTwo}`,
data: set
});
}
}
render() {
const { differential, eitherCellSetOneOrTwo } = this.props;
const cellListName = `celllist${eitherCellSetOneOrTwo}`;
return (
<span style={{ marginRight: 10 }}>
<button
type="button"
style={{
color: "#FFF",
borderRadius: 2,
padding: "0px 10px",
height: 30,
backgroundColor: !differential.diffExp
? globals.brightBlue
: globals.lightGrey,
border: "none",
cursor: "pointer"
}}
onClick={this.set.bind(this)}
>
<span style={{ fontSize: 14, fontWeight: 700 }}>
{" "}
{eitherCellSetOneOrTwo}
{": "}
</span>
<span
style={{
fontSize: 14,
marginLeft: 8,
position: "relative",
top: 0
}}
>
{differential[cellListName]
? `${differential[cellListName].length} cells`
: "0 cells"}
</span>
</button>
</span>
);
}
}
export default CellSetButton;
@@ -1,83 +0,0 @@
// jshint esversion: 6
import React from "react";
import _ from "lodash";
import { connect } from "react-redux";
import * as d3 from "d3";
import { interpolateGreys } from "d3-scale-chromatic";
import HeatmapRow from "./heatmapRow";
/**********************************
***********************************
***********************************
DiffExp Heatmap
***********************************
***********************************
**********************************/
@connect(state => ({
differential: state.differential,
world: state.controls.world
}))
class Heatmap extends React.Component {
render() {
const { world, differential } = this.props;
if (!differential.diffExp) {
return <p>Select cells & compute differential to see heatmap</p>;
}
// summarize the information for display.
const topGenes = _.map(differential.diffExp, val => ({
varIndex: val[0],
geneName: world.varAnnotations[val[0]].name,
avgDiff: val[1],
set1AvgExp: val[4],
set2AvgExp: val[5]
}));
// average expression extent
const extent = d3.extent(
_.concat(
_.map(differential.diffExp, val => val[4]),
_.map(differential.diffExp, val => val[5])
)
);
const greyColorScale = d3
.scaleSequential()
.domain(extent)
.interpolator(interpolateGreys);
return (
<div>
<div
style={{
display: "flex",
justifyContent: "flex-start",
width: 400,
fontWeight: 700
}}
>
<p style={{ marginRight: 110 }}>Gene</p>
<p style={{ marginRight: 25 }}>1</p>
<p style={{ marginRight: 20 }}>2</p>
<p>ave diff</p>
</div>
{topGenes.map(g => {
const { geneName, avgDiff, set1AvgExp, set2AvgExp } = g;
return (
<HeatmapRow
key={geneName}
gene={geneName}
greyColorScale={greyColorScale}
aveDiff={avgDiff}
set1exp={set1AvgExp}
set2exp={set2AvgExp}
/>
);
})}
</div>
);
}
}
export default Heatmap;
@@ -1,154 +0,0 @@
import React from "react";
import { connect } from "react-redux";
import { FaPaintBrush } from "react-icons/fa";
import HeatmapSquare from "./heatmapSquare";
import * as globals from "../../globals";
import actions from "../../actions";
/**********************************
***********************************
***********************************
Row
***********************************
***********************************
**********************************/
@connect(state => ({
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
colorAccessor: state.controls.colorAccessor
}))
class HeatmapRow extends React.Component {
handleGeneColorScaleClick() {
return () => {
const { dispatch, gene } = this.props;
dispatch(actions.requestSingleGeneExpressionCountsForColoringPOST(gene));
};
}
handleSetGeneAsScatterplotX() {
return () => {
const { dispatch, gene } = this.props;
dispatch({
type: "set scatterplot x",
data: gene
});
};
}
handleSetGeneAsScatterplotY() {
return () => {
const { dispatch, gene } = this.props;
dispatch({
type: "set scatterplot y",
data: gene
});
};
}
render() {
const {
gene,
aveDiff,
set1exp,
set2exp,
greyColorScale,
scatterplotXXaccessor,
scatterplotYYaccessor,
colorAccessor
} = this.props;
return (
<div
style={{
width: 220,
display: "flex",
justifyContent: "flex-start",
alignItems: "baseline"
}}
>
<div style={{ width: 150, flexShrink: 0 }}>
<span
style={{
fontSize: 14
}}
>
{gene}
</span>
</div>
<HeatmapSquare
backgroundColor={greyColorScale(set1exp)}
text={set1exp.toPrecision(2)}
/>
<HeatmapSquare
backgroundColor={greyColorScale(set2exp)}
text={set2exp.toPrecision(2)}
/>
<span
title={aveDiff}
style={{
fontSize: 12,
marginLeft: 10,
marginRight: 10
}}
>
{aveDiff.toFixed(2)}
</span>
<span
onClick={this.handleSetGeneAsScatterplotX(gene).bind(this)}
style={{
fontSize: 16,
color:
scatterplotXXaccessor === gene ? "white" : globals.brightBlue,
cursor: "pointer",
position: "relative",
top: 1,
fontWeight: 700,
marginRight: 4,
borderRadius: 3,
padding: "2px 3px",
backgroundColor:
scatterplotXXaccessor === gene ? globals.brightBlue : "inherit"
}}
>
X
</span>
<span
onClick={this.handleSetGeneAsScatterplotY(gene).bind(this)}
style={{
fontSize: 16,
color:
scatterplotYYaccessor === gene ? "white" : globals.brightBlue,
cursor: "pointer",
position: "relative",
top: 1,
fontWeight: 700,
marginRight: 4,
borderRadius: 3,
padding: "2px 3px",
backgroundColor:
scatterplotYYaccessor === gene ? globals.brightBlue : "inherit"
}}
>
Y
</span>
<span
onClick={this.handleGeneColorScaleClick(gene).bind(this)}
style={{
fontSize: 16,
cursor: "pointer",
position: "relative",
marginRight: 6,
borderRadius: 3,
padding: "0px 2px 2px 2px",
color: colorAccessor === gene ? "white" : "inherit",
backgroundColor:
colorAccessor === gene ? globals.brightBlue : "inherit"
}}
>
<FaPaintBrush style={{ display: "inline-block" }} />
</span>
</div>
);
}
}
export default HeatmapRow;
@@ -1,30 +0,0 @@
import React from "react";
import getContrast from "font-color-contrast"; // https://www.npmjs.com/package/font-color-contrast
const HeatmapSquare = props => {
const { backgroundColor, text } = props;
const contrastColor = getContrast(
backgroundColor
.substring(4, backgroundColor.length - 1)
.replace(/ /g, "")
.split(",")
);
return (
<p
style={{
padding: "12px 6px",
textAlign: "center",
color: contrastColor,
width: 40,
flexShrink: 0,
fontSize: 12,
margin: 0,
backgroundColor
}}
>
{text}
</p>
);
};
export default HeatmapSquare;
+1 -1
View File
@@ -1,4 +1,4 @@
.btn { :local(.btn) {
background: none; background: none;
cursor: pointer; cursor: pointer;
color: "#FFF"; color: "#FFF";
@@ -1,3 +1,3 @@
.container { :local(.container) {
min-height: 100%; min-height: 100%;
} }
@@ -0,0 +1,12 @@
import { Position, Toaster, Intent } from "@blueprintjs/core";
/** Singleton toaster instance. Create separate instances for different options. */
export const ErrorToastTopCenter = Toaster.create({
className: "recipe-toaster",
position: Position.TOP,
intent: Intent.WARNING
});
export default {
ErrorToastTopCenter
};
@@ -0,0 +1,46 @@
// jshint esversion: 6
import React from "react";
import _ from "lodash";
import { Button } from "@blueprintjs/core";
import { connect } from "react-redux";
import * as globals from "../../globals";
@connect()
class CellSetButton extends React.Component {
set() {
const {
differential,
crossfilter,
dispatch,
eitherCellSetOneOrTwo
} = this.props;
const set = _.map(crossfilter.allFiltered(), "name");
if (!differential.diffExp) {
/* diffexp needs to be cleared before we store a new set */
dispatch({
type: `store current cell selection as differential set ${eitherCellSetOneOrTwo}`,
data: set
});
}
}
render() {
const { differential, eitherCellSetOneOrTwo } = this.props;
const cellListName = `celllist${eitherCellSetOneOrTwo}`;
return (
<span style={{ marginRight: 10 }}>
<Button type="button" onClick={this.set.bind(this)}>
{eitherCellSetOneOrTwo}
{": "}
{differential[cellListName]
? `${differential[cellListName].length} cells`
: "0 cells"}
</Button>
</span>
);
}
}
export default CellSetButton;
@@ -1,6 +1,7 @@
// jshint esversion: 6 // jshint esversion: 6
import React from "react"; import React from "react";
import _ from "lodash"; import _ from "lodash";
import { Button } from "@blueprintjs/core";
import { connect } from "react-redux"; import { connect } from "react-redux";
import * as globals from "../../globals"; import * as globals from "../../globals";
import actions from "../../actions"; import actions from "../../actions";
@@ -43,58 +44,32 @@ class Expression extends React.Component {
if (!differential) { if (!differential) {
return null; return null;
} }
const haveBothCellSets =
!!differential.celllist1 && !!differential.celllist2;
return ( return (
<div style={{ marginRight: 10, marginBottom: 10 }}> <div style={{ marginRight: 10, marginBottom: 10 }}>
<CellSetButton {...this.props} eitherCellSetOneOrTwo={1} /> <CellSetButton {...this.props} eitherCellSetOneOrTwo={1} />
<CellSetButton {...this.props} eitherCellSetOneOrTwo={2} /> <CellSetButton {...this.props} eitherCellSetOneOrTwo={2} />
{!differential.diffExp ? ( {!differential.diffExp ? (
<button <Button
style={{ marginTop: 10 }}
disabled={!haveBothCellSets}
intent="primary"
type="button" type="button"
style={{
fontSize: 14,
fontWeight: 400,
color: "#FFF",
padding: "0px 10px",
height: 30,
borderRadius: 2,
backgroundColor:
differential.celllist1 && differential.celllist2
? globals.brightBlue
: globals.lightGrey,
border: "none",
cursor:
differential.celllist1 && differential.celllist2
? "pointer"
: "auto"
}}
onClick={this.computeDiffExp.bind(this)} onClick={this.computeDiffExp.bind(this)}
> >
{" "} Compute Differential Expression
Compute Differential Expression{" "} </Button>
</button>
) : null} ) : null}
{differential.diffExp ? ( {differential.diffExp ? (
<button <Button
type="button" type="button"
style={{ style={{ marginTop: 10 }}
fontSize: 14, intent="warning"
fontWeight: 400,
color: "#FFF",
padding: "0px 10px",
height: 30,
borderRadius: 2,
backgroundColor: globals.brightBlue,
border: "none",
cursor:
differential.celllist1 && differential.celllist2
? "pointer"
: "auto"
}}
onClick={this.clearDifferentialExpression.bind(this)} onClick={this.clearDifferentialExpression.bind(this)}
> >
{" "} Clear Differential Expression
Clear Differential Expression{" "} </Button>
</button>
) : null} ) : null}
</div> </div>
); );
+91 -76
View File
@@ -5,10 +5,11 @@ import React from "react";
import _ from "lodash"; import _ from "lodash";
import * as d3 from "d3"; import * as d3 from "d3";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { FaPlusCircle } from "react-icons/fa";
import HistogramBrush from "../brushableHistogram"; import HistogramBrush from "../brushableHistogram";
import * as globals from "../../globals"; import * as globals from "../../globals";
import actions from "../../actions"; import actions from "../../actions";
import { ErrorToastTopCenter } from "../framework/toasters";
import ExpressionButtons from "./expressionButtons";
@connect(state => { @connect(state => {
const metadata = _.get(state.controls.world, "obsAnnotations", null); const metadata = _.get(state.controls.world, "obsAnnotations", null);
@@ -45,13 +46,18 @@ class GeneExpression extends React.Component {
const { gene } = this.state; const { gene } = this.state;
if (userDefinedGenes.indexOf(gene) !== -1) { if (userDefinedGenes.indexOf(gene) !== -1) {
console.log("That gene already exists"); ErrorToastTopCenter.show({
message: "That gene already exists"
});
} else if (userDefinedGenes.length > 15) { } else if (userDefinedGenes.length > 15) {
console.log( ErrorToastTopCenter.show({
"That's too many genes, you can have at most 15 user defined genes" message:
); "That's too many genes, you can have at most 15 user defined genes"
});
} else if (!_.find(world.varAnnotations, { name: gene })) { } else if (!_.find(world.varAnnotations, { name: gene })) {
console.log("That doesn't appear to be a valid gene name."); ErrorToastTopCenter.show({
message: "That doesn't appear to be a valid gene name."
});
} else { } else {
dispatch(actions.requestUserDefinedGene(gene)); dispatch(actions.requestUserDefinedGene(gene));
dispatch({ dispatch({
@@ -68,79 +74,88 @@ class GeneExpression extends React.Component {
return ( return (
<div> <div>
<input <div
onKeyDown={this.keyPress.bind(this)}
onChange={e => {
this.setState({ gene: e.target.value });
}}
type="text"
value={gene}
/>
<button
type="button"
style={{ style={{
border: "none", padding: globals.leftSidebarSectionPadding,
background: "none", marginTop: 30
cursor: "pointer",
outline: "none",
marginTop: 20,
padding: 0
}} }}
onClick={this.handleClick.bind(this)}
> >
<FaPlusCircle <p style={globals.leftSidebarSectionHeading}>Custom genes</p>
style={{ <div style={{ marginTop: 11 }} className="bp3-control-group">
display: "inline-block", <div className="bp3-input-group">
marginLeft: 7, <span className="bp3-icon bp3-icon-symbol-cross" />
position: "relative", <input
top: 5, onKeyDown={this.keyPress.bind(this)}
color: globals.brightBlue, onChange={e => {
fontSize: 22 this.setState({ gene: e.target.value });
}} }}
/>{" "} value={gene}
add gene{" "} type="text"
</button> className="bp3-input"
{world && userDefinedGenes.length > 0 ? ( placeholder="Add a custom gene"
<p>User defined genes</p> style={{ paddingRight: 94 }}
) : null} />
{world && userDefinedGenes.length > 0 </div>
? _.map(userDefinedGenes, geneName => { <button
const values = world.varDataCache[geneName]; type="button"
if (!values) { className="bp3-button bp3-intent-primary"
return null; onClick={this.handleClick.bind(this)}
} >
return ( Add
<HistogramBrush </button>
key={geneName} </div>
field={geneName} {world && userDefinedGenes.length > 0
ranges={d3.extent(values)} ? _.map(userDefinedGenes, geneName => {
isUserDefined const values = world.varDataCache[geneName];
/> if (!values) {
); return null;
}) }
: null} return (
{differential.diffExp ? <p> Differentially Expressed Genes </p> : null} <HistogramBrush
{differential.diffExp key={geneName}
? _.map(differential.diffExp, value => { field={geneName}
const annotations = world.varAnnotations[value[0]]; ranges={d3.extent(values)}
const { name } = annotations; isUserDefined
const values = world.varDataCache[name]; />
if (!values) { );
return null; })
} : null}
return ( </div>
<HistogramBrush <div
key={name} style={{
field={name} padding: globals.leftSidebarSectionPadding
ranges={d3.extent(values)} }}
isDiffExp >
diffExp_avgDiff={value[1]} <p
diffExp_set1AvgExp={value[4]} style={Object.assign({}, globals.leftSidebarSectionHeading, {
diffExp_set2AvgExp={value[5]} marginTop: 40
/> })}
); >
}) Differentially Expressed Genes
: null} </p>
<ExpressionButtons />
{differential.diffExp
? _.map(differential.diffExp, value => {
const annotations = world.varAnnotations[value[0]];
const { name } = annotations;
const values = world.varDataCache[name];
if (!values) {
return null;
}
return (
<HistogramBrush
key={name}
field={name}
ranges={d3.extent(values)}
isDiffExp
avgDiff={value[1]}
set1AvgExp={value[4]}
set2AvgExp={value[5]}
/>
);
})
: null}
</div>
</div> </div>
); );
} }
+4 -4
View File
@@ -1,4 +1,4 @@
.graphCanvas path { :local(.graphCanvas) path {
shape-rendering: crispEdges; shape-rendering: crispEdges;
} }
@@ -16,8 +16,8 @@
pointer-events: none; pointer-events: none;
} }
.axis path, :local(.axis) path,
.axis line { :local(.axis) line {
fill: none; fill: none;
stroke: #000; stroke: #000;
stroke-width: 1px; stroke-width: 1px;
@@ -29,6 +29,6 @@ circle {
fill: none; fill: none;
} }
.hidden { :local(.hidden) {
display: none; display: none;
} }
+18 -63
View File
@@ -5,10 +5,8 @@ import * as d3 from "d3";
import { connect } from "react-redux"; import { connect } from "react-redux";
import mat4 from "gl-mat4"; import mat4 from "gl-mat4";
import _regl from "regl"; import _regl from "regl";
import { Button } from "@blueprintjs/core";
import { FaCrosshairs, FaSearchPlus } from "react-icons/fa";
import * as globals from "../../globals";
import setupSVGandBrushElements from "./setupSVGandBrush"; import setupSVGandBrushElements from "./setupSVGandBrush";
import actions from "../../actions"; import actions from "../../actions";
import _camera from "../../util/camera"; import _camera from "../../util/camera";
@@ -340,91 +338,48 @@ class Graph extends React.Component {
alignItems: "baseline" alignItems: "baseline"
}} }}
> >
<button <Button
type="button" type="button"
style={{ marginRight: 10 }}
onClick={() => { onClick={() => {
dispatch(actions.resetGraph()); dispatch(actions.resetGraph());
}} }}
style={{
fontSize: 14,
fontWeight: 400,
color: "white",
padding: "0px 10px",
height: 30,
marginRight: 10,
borderRadius: 2,
backgroundColor: globals.brightBlue,
border: "none",
cursor: "pointer"
}}
> >
reset graph reset graph
</button> </Button>
<button <Button
type="button" type="button"
style={{ marginRight: 10 }}
onClick={() => { onClick={() => {
dispatch(actions.regraph()); dispatch(actions.regraph());
}} }}
style={{
fontSize: 14,
fontWeight: 400,
color: "white",
padding: "0px 10px",
height: 30,
marginRight: 10,
borderRadius: 2,
backgroundColor: globals.brightBlue,
border: "none",
cursor: "pointer"
}}
> >
regraph selection regraph selection
</button> </Button>
<div> <div>
<span> <div className="bp3-button-group">
<button <Button
className="bp3-button bp3-icon-locate"
type="button" type="button"
active={mode === "brush"}
onClick={() => { onClick={() => {
this.setState({ mode: "brush" }); this.setState({ mode: "brush" });
}} }}
style={{ />
cursor: "pointer", <Button
border:
mode === "brush" ? "1px solid black" : "1px solid white",
backgroundColor: "white",
padding: "5px 5px 2px 5px",
position: "relative",
top: 2,
marginRight: 10,
borderRadius: 3
}}
>
{" "}
<FaCrosshairs />{" "}
</button>
<button
type="button" type="button"
className="bp3-button bp3-icon-zoom-in"
active={mode === "zoom"}
onClick={() => { onClick={() => {
this.handleBrushDeselectAction(); this.handleBrushDeselectAction();
this.restartReglLoop(); this.restartReglLoop();
this.setState({ mode: "zoom" }); this.setState({ mode: "zoom" });
}} }}
style={{ style={{
cursor: "pointer", cursor: "pointer"
border:
mode === "zoom" ? "1px solid black" : "1px solid white",
backgroundColor: "white",
padding: "5px 5px 2px 5px",
position: "relative",
top: 2,
marginRight: 10,
borderRadius: 3
}} }}
> />
{" "} </div>
<FaSearchPlus />{" "}
</button>
</span>
</div> </div>
</div> </div>
</div> </div>
+20 -27
View File
@@ -5,8 +5,6 @@ import { connect } from "react-redux";
import Categorical from "./categorical/categorical"; import Categorical from "./categorical/categorical";
import Continuous from "./continuous/continuous"; import Continuous from "./continuous/continuous";
import GeneExpression from "./geneExpression"; import GeneExpression from "./geneExpression";
import ExpressionButtons from "./expression/expressionButtons";
import Heatmap from "./expression/diffExpHeatmap";
import * as globals from "../globals"; import * as globals from "../globals";
import DynamicScatterplot from "./scatterplot/scatterplot"; import DynamicScatterplot from "./scatterplot/scatterplot";
@@ -37,30 +35,36 @@ class LeftSideBar extends React.Component {
this magic number should be made less fragile, this magic number should be made less fragile,
if cellxgene logo or tabs change, this must as well if cellxgene logo or tabs change, this must as well
*/ */
const metadataSectionPadding = const metadataSectionPadding = 0;
scatterplotXXaccessor && scatterplotYYaccessor ? 450 : 0; // scatterplotXXaccessor && scatterplotYYaccessor ? 450 : 0;
return ( return (
<div style={{ position: "fixed" }}> <div
style={{
position: "fixed",
backgroundColor: "white",
/* x y blur spread color */
boxShadow: "1px 0px 6px 2px rgba(153,153,153,0.4)"
}}
>
<p <p
style={{ style={{
position: "fixed", position: "fixed",
left: responsive.width / 2, top: globals.cellxgeneTitleTopPadding,
top: 14, left: globals.leftSidebarWidth + globals.cellxgeneTitleLeftPadding,
margin: 0, margin: 0,
fontSize: 24, fontSize: globals.largestFontSize,
color: globals.darkerGrey, color: globals.darkerGrey,
fontWeight: 700,
width: "100%" width: "100%"
}} }}
> >
cellxgene: &nbsp; cellxgene: {datasetTitle}
{datasetTitle}
</p> </p>
<div <div
style={{ style={{
height: responsive.height - metadataSectionPadding, height: responsive.height - metadataSectionPadding,
width: 400, width: globals.leftSidebarWidth,
padding: "0px 10px 10px 10px",
overflowY: "auto", overflowY: "auto",
overflowX: "hidden" overflowX: "hidden"
}} }}
@@ -69,20 +73,9 @@ class LeftSideBar extends React.Component {
<GeneExpression /> <GeneExpression />
<Continuous /> <Continuous />
</div> </div>
<div {scatterplotXXaccessor && scatterplotYYaccessor ? (
style={{ <DynamicScatterplot />
position: "fixed", ) : null}
bottom: 0,
left: 0
}}
>
{scatterplotXXaccessor && scatterplotYYaccessor ? (
<DynamicScatterplot />
) : null}
</div>
<div style={{ position: "fixed", bottom: 0, right: 0 }}>
{currentTab === "metadata" ? <ExpressionButtons /> : null}
</div>
</div> </div>
); );
} }
@@ -1,15 +1,14 @@
:local(.scatterplot) {
.scatterplot {
display: block; display: block;
} }
.scatterplot svg, :local(.scatterplot) svg,
.scatterplot canvas { :local(.scatterplot) canvas {
font: 10px sans-serif; font: 10px sans-serif;
position: absolute; position: absolute;
} }
.scatterplot canvas { :local(.scatterplot) canvas {
opacity: 0.9; opacity: 0.9;
pointer-events: none; pointer-events: none;
} }
@@ -5,8 +5,10 @@
import React from "react"; import React from "react";
import _ from "lodash"; import _ from "lodash";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Button, ButtonGroup } from "@blueprintjs/core";
import _regl from "regl"; import _regl from "regl";
import * as d3 from "d3"; import * as d3 from "d3";
import * as globals from "../../globals";
import _camera from "../../util/camera"; import _camera from "../../util/camera";
@@ -64,6 +66,7 @@ class Scatterplot extends React.Component {
this.axes = false; this.axes = false;
this.state = { this.state = {
svg: null, svg: null,
minimized: null,
xScale: null, xScale: null,
yScale: null yScale: null
}; };
@@ -267,14 +270,48 @@ class Scatterplot extends React.Component {
} }
render() { render() {
const { dispatch } = this.props;
const { minimized } = this.state;
return ( return (
<div <div
style={{ style={{
backgroundColor: "white", position: "fixed",
paddingBottom: 20 bottom: minimized ? -height + -margin.top : 0,
left: globals.leftSidebarWidth + globals.scatterplotPaddingLeft,
paddingBottom: 20,
backgroundColor: "white"
}} }}
id="scatterplot_wrapper" id="scatterplot_wrapper"
> >
<ButtonGroup
minimal
style={{
position: "absolute",
right: 5,
top: 5
}}
>
<Button
type="button"
icon={minimized ? "plus" : "minus"}
onClick={() => {
this.setState({ minimized: !minimized });
}}
/>
<Button
type="button"
icon="cross"
onClick={() => {
dispatch({
type: "clear scatterplot"
});
dispatch({
type: "reset colorscale"
});
}}
/>
</ButtonGroup>
<div <div
className={styles.scatterplot} className={styles.scatterplot}
id="scatterplot" id="scatterplot"
+1 -1
View File
@@ -1,5 +1,5 @@
// jshint esversion: 6 // jshint esversion: 6
export const margin = { top: 66, right: 110, bottom: 20, left: 60 }; export const margin = { top: 40, right: 5, bottom: 20, left: 60 };
export const width = 340; export const width = 340;
export const height = 340 - margin.top - margin.bottom; export const height = 340 - margin.top - margin.bottom;
export const innerHeight = height - 2; export const innerHeight = height - 2;
+28 -9
View File
@@ -46,6 +46,7 @@ export const configDefaults = {
/* colors */ /* colors */
export const blue = "#4a90e2"; export const blue = "#4a90e2";
export const hcaBlue = "#1c7cc7"; export const hcaBlue = "#1c7cc7";
export const lightestGrey = "rgb(249,249,249)";
export const lighterGrey = "rgb(245,245,245)"; export const lighterGrey = "rgb(245,245,245)";
export const lightGrey = "rgb(211,211,211)"; export const lightGrey = "rgb(211,211,211)";
export const mediumGrey = "rgb(153,153,153)"; export const mediumGrey = "rgb(153,153,153)";
@@ -58,9 +59,35 @@ export const darkGreen = "#448C4D";
export const defaultCellColor = "rgb(0,0,0,1)"; export const defaultCellColor = "rgb(0,0,0,1)";
export const tiniestFontSize = 12; /* typography constants */
export const tiniestFontSize = 12;
export const largestFontSize = 24;
export const uppercaseLetterSpacing = "0.04em";
export const bolder = 700; export const bolder = 700;
export const accentFont = "Georgia,Times,Times New Roman,serif";
export const maxParagraphWidth = 600;
/* layout styles constants */
export const cellxgeneTitleLeftPadding = 14;
export const cellxgeneTitleTopPadding = 7;
export const maxControlsWidth = 800;
export const graphMargin = { top: 20, right: 10, bottom: 30, left: 40 };
export const graphWidth = 700;
export const graphHeight = 700;
export const scatterplotPaddingLeft = 14;
export const leftSidebarWidth = 365;
export const leftSidebarSectionHeading = {
fontSize: 18,
textTransform: "uppercase",
fontWeight: 500,
letterSpacing: ".05em"
};
export const leftSidebarSectionPadding = 10;
let _API = { let _API = {
// prefix: "http://api.clustering.czi.technology/api/", // prefix: "http://api.clustering.czi.technology/api/",
@@ -73,14 +100,6 @@ let _API = {
if (window.CELLXGENE && window.CELLXGENE.API) _API = window.CELLXGENE.API; if (window.CELLXGENE && window.CELLXGENE.API) _API = window.CELLXGENE.API;
export const API = _API; export const API = _API;
export const accentFont = "Georgia,Times,Times New Roman,serif";
export const maxParagraphWidth = 600;
export const maxControlsWidth = 800;
export const graphMargin = { top: 20, right: 10, bottom: 30, left: 40 };
export const graphWidth = 700;
export const graphHeight = 700;
export const ordinalColors = [ export const ordinalColors = [
"#0ac115", "#0ac115",
"#c10ab6", "#c10ab6",
+9
View File
@@ -0,0 +1,9 @@
/*
>>>GLOBAL<<< CSS imports & definitions
Do NOT put anything in this file that is not global. We do not perform
namespace mangling on these definitions. See webpack config for specifics.
*/
@import "~@blueprintjs/core/lib/css/blueprint.css";
@import "~@blueprintjs/icons/lib/css/blueprint-icons.css";
@import "~@blueprintjs/select/lib/css/blueprint-select.css";
+2
View File
@@ -4,6 +4,8 @@ import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import "./index.css";
/* our code */ /* our code */
import App from "./components/app"; import App from "./components/app";
import store from "./reducers"; import store from "./reducers";
+6
View File
@@ -516,6 +516,12 @@ const Controls = (
...state, ...state,
scatterplotYYaccessor: action.data scatterplotYYaccessor: action.data
}; };
case "clear scatterplot":
return {
...state,
scatterplotXXaccessor: null,
scatterplotYYaccessor: null
};
default: default:
return state; return state;