aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.stylelintignore10
-rw-r--r--.stylelintrc50
-rw-r--r--app/fonts/DIN Next/DIN Next W01 Bold.otfbin0 -> 106032 bytes
-rw-r--r--app/fonts/DIN Next/DIN Next W01 Regular.otfbin0 -> 106580 bytes
-rw-r--r--app/fonts/DIN Next/DIN Next W10 Black.otfbin0 -> 105972 bytes
-rw-r--r--app/fonts/DIN Next/DIN Next W10 Italic.otfbin0 -> 115984 bytes
-rw-r--r--app/fonts/DIN Next/DIN Next W10 Light.otfbin0 -> 108672 bytes
-rw-r--r--app/fonts/DIN Next/DIN Next W10 Medium.otfbin0 -> 105684 bytes
-rw-r--r--app/fonts/DIN_OT/DINOT-2.otfbin0 -> 44144 bytes
-rw-r--r--app/fonts/DIN_OT/DINOT-Bold 2.otfbin0 -> 45564 bytes
-rw-r--r--app/fonts/DIN_OT/DINOT-BoldItalic.otfbin0 -> 49684 bytes
-rw-r--r--app/fonts/DIN_OT/DINOT-Italic 2.otfbin0 -> 47956 bytes
-rw-r--r--app/fonts/DIN_OT/DINOT-Medium 2.otfbin0 -> 44652 bytes
-rw-r--r--app/fonts/DIN_OT/DINOT-MediumItalic 2.otfbin0 -> 47732 bytes
-rw-r--r--app/fonts/Roboto/Roboto-Black.ttfbin0 -> 142472 bytes
-rw-r--r--app/fonts/Roboto/Roboto-BlackItalic.ttfbin0 -> 149644 bytes
-rw-r--r--app/fonts/Roboto/Roboto-Bold.ttfbin0 -> 135820 bytes
-rw-r--r--app/fonts/Roboto/Roboto-BoldItalic.ttfbin0 -> 144700 bytes
-rw-r--r--app/fonts/Roboto/Roboto-Italic.ttfbin0 -> 148540 bytes
-rw-r--r--app/fonts/Roboto/Roboto-Light.ttfbin0 -> 140276 bytes
-rw-r--r--app/fonts/Roboto/Roboto-LightItalic.ttfbin0 -> 145932 bytes
-rw-r--r--app/fonts/Roboto/Roboto-Medium.ttfbin0 -> 137308 bytes
-rw-r--r--app/fonts/Roboto/Roboto-MediumItalic.ttfbin0 -> 147876 bytes
-rw-r--r--app/fonts/Roboto/Roboto-Regular.ttfbin0 -> 145348 bytes
-rw-r--r--app/fonts/Roboto/Roboto-Thin.ttfbin0 -> 130044 bytes
-rw-r--r--app/fonts/Roboto/Roboto-ThinItalic.ttfbin0 -> 132376 bytes
-rw-r--r--app/fonts/Roboto/RobotoCondensed-Bold.ttfbin0 -> 141796 bytes
-rw-r--r--app/fonts/Roboto/RobotoCondensed-BoldItalic.ttfbin0 -> 145256 bytes
-rw-r--r--app/fonts/Roboto/RobotoCondensed-Italic.ttfbin0 -> 144404 bytes
-rw-r--r--app/fonts/Roboto/RobotoCondensed-Light.ttfbin0 -> 141384 bytes
-rw-r--r--app/fonts/Roboto/RobotoCondensed-LightItalic.ttfbin0 -> 145104 bytes
-rw-r--r--app/fonts/Roboto/RobotoCondensed-Regular.ttfbin0 -> 140396 bytes
-rw-r--r--app/images/eth_logo.svg11
-rw-r--r--app/notification.html2
-rw-r--r--app/popup.html2
-rw-r--r--app/scripts/lib/environment-type.js10
-rw-r--r--app/scripts/lib/is-popup-or-notification.js2
-rw-r--r--gulpfile.js50
-rw-r--r--package.json8
-rw-r--r--test/unit/components/balance-component-test.js32
-rw-r--r--ui/app/account-and-transaction-details.js38
-rw-r--r--ui/app/account-detail.js178
-rw-r--r--ui/app/actions.js53
-rw-r--r--ui/app/add-token.js1
-rw-r--r--ui/app/app.js457
-rw-r--r--ui/app/components/balance-component.js95
-rw-r--r--ui/app/components/buy-options.js80
-rw-r--r--ui/app/components/dropdowns/account-options-dropdown.js28
-rw-r--r--ui/app/components/dropdowns/account-selection-dropdown.js28
-rw-r--r--ui/app/components/dropdowns/components/account-dropdowns.js (renamed from ui/app/components/account-dropdowns.js)102
-rw-r--r--ui/app/components/dropdowns/components/dropdown.js (renamed from ui/app/components/dropdown.js)7
-rw-r--r--ui/app/components/dropdowns/index.js18
-rw-r--r--ui/app/components/dropdowns/network-dropdown.js268
-rw-r--r--ui/app/components/ens-input.js7
-rw-r--r--ui/app/components/modals/buy-modal.js23
-rw-r--r--ui/app/components/modals/index.js9
-rw-r--r--ui/app/components/modals/modal.js100
-rw-r--r--ui/app/components/network.js2
-rw-r--r--ui/app/components/pending-tx.js634
-rw-r--r--ui/app/components/tx-list.js166
-rw-r--r--ui/app/components/tx-view.js124
-rw-r--r--ui/app/components/wallet-content-display.js56
-rw-r--r--ui/app/components/wallet-view.js172
-rw-r--r--ui/app/conf-tx.js79
-rw-r--r--ui/app/css/debug.css21
-rw-r--r--ui/app/css/fonts.css36
-rw-r--r--ui/app/css/index.scss13
-rw-r--r--ui/app/css/itcss/base/index.scss1
-rw-r--r--ui/app/css/itcss/components/buttons.scss83
-rw-r--r--ui/app/css/itcss/components/footer.scss4
-rw-r--r--ui/app/css/itcss/components/header.scss52
-rw-r--r--ui/app/css/itcss/components/hero-balance.scss107
-rw-r--r--ui/app/css/itcss/components/index.scss21
-rw-r--r--ui/app/css/itcss/components/modal.scss128
-rw-r--r--ui/app/css/itcss/components/network.scss11
-rw-r--r--ui/app/css/itcss/components/newui-sections.scss166
-rw-r--r--ui/app/css/itcss/components/sections.scss (renamed from ui/app/css/index.css)379
-rw-r--r--ui/app/css/itcss/components/transaction-list.scss141
-rw-r--r--ui/app/css/itcss/components/wallet-balance.scss66
-rw-r--r--ui/app/css/itcss/generic/index.scss68
-rw-r--r--ui/app/css/itcss/generic/reset.scss146
-rw-r--r--ui/app/css/itcss/objects/index.scss1
-rw-r--r--ui/app/css/itcss/settings/index.scss3
-rw-r--r--ui/app/css/itcss/settings/typography.scss43
-rw-r--r--ui/app/css/itcss/settings/variables.scss51
-rw-r--r--ui/app/css/itcss/tools/index.scss1
-rw-r--r--ui/app/css/itcss/tools/utilities.scss (renamed from ui/app/css/lib.css)90
-rw-r--r--ui/app/css/itcss/trumps/index.scss (renamed from ui/app/css/transitions.css)40
-rw-r--r--ui/app/css/reset.css48
-rw-r--r--ui/app/main-container.js71
-rw-r--r--ui/app/reducers/app.js36
-rw-r--r--ui/app/selectors.js45
-rw-r--r--ui/app/send.js490
-rw-r--r--ui/app/unlock.js2
-rw-r--r--ui/css.js6
-rw-r--r--ui/lib/is-mobile-view.js5
97 files changed, 3779 insertions, 1501 deletions
diff --git a/.gitignore b/.gitignore
index 1806b1932..08a544449 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,9 @@ test/background.js
test/bundle.js
test/test-bundle.js
+#ignore css output and sourcemaps
+ui/app/css/output/
+
notes.txt
.coveralls.yml
diff --git a/.stylelintignore b/.stylelintignore
new file mode 100644
index 000000000..854829a54
--- /dev/null
+++ b/.stylelintignore
@@ -0,0 +1,10 @@
+app/
+development/
+dist/
+docs/
+fonts/
+images/
+mascara/
+node_modules/
+notices/
+test/
diff --git a/.stylelintrc b/.stylelintrc
new file mode 100644
index 000000000..d080d68d9
--- /dev/null
+++ b/.stylelintrc
@@ -0,0 +1,50 @@
+{
+ "extends": "stylelint-config-standard",
+ "rules": {
+ "color-named": "never",
+ "font-family-name-quotes": "always-where-recommended",
+ "font-weight-notation": "numeric",
+ "function-url-quotes": "always",
+ "number-leading-zero": "never",
+ "value-no-vendor-prefix": true,
+ "value-list-comma-newline-before": "never-multi-line",
+ "custom-property-empty-line-before": "never",
+ "property-no-unknown": [
+ true,
+ {
+ "ignoreProperties": [
+ "composes",
+ "all",
+ "-webkit-appearance"
+ ]
+ }
+ ],
+ "declaration-block-semicolon-newline-after": "always",
+ "block-opening-brace-newline-after": "always",
+ "selector-attribute-quotes": "always",
+ "selector-max-specificity": "0,5,2",
+ "selector-pseudo-class-no-unknown": [
+ true,
+ {
+ "ignorePseudoClasses": ["local", "global"]
+ }
+ ],
+ "at-rule-empty-line-before": [
+ "always",
+ {
+ "ignore": [
+ "after-comment",
+ ]
+ }
+ ],
+ "indentation": [
+ 2,
+ {
+ "indentInsideParens": "once-at-root-twice-in-block"
+ }
+ ],
+ "max-nesting-depth": 3,
+ "no-duplicate-selectors": true,
+ "no-unknown-animations": true
+ }
+}
diff --git a/app/fonts/DIN Next/DIN Next W01 Bold.otf b/app/fonts/DIN Next/DIN Next W01 Bold.otf
new file mode 100644
index 000000000..2b78d1ff4
--- /dev/null
+++ b/app/fonts/DIN Next/DIN Next W01 Bold.otf
Binary files differ
diff --git a/app/fonts/DIN Next/DIN Next W01 Regular.otf b/app/fonts/DIN Next/DIN Next W01 Regular.otf
new file mode 100644
index 000000000..09f6ee297
--- /dev/null
+++ b/app/fonts/DIN Next/DIN Next W01 Regular.otf
Binary files differ
diff --git a/app/fonts/DIN Next/DIN Next W10 Black.otf b/app/fonts/DIN Next/DIN Next W10 Black.otf
new file mode 100644
index 000000000..08eb73373
--- /dev/null
+++ b/app/fonts/DIN Next/DIN Next W10 Black.otf
Binary files differ
diff --git a/app/fonts/DIN Next/DIN Next W10 Italic.otf b/app/fonts/DIN Next/DIN Next W10 Italic.otf
new file mode 100644
index 000000000..73f2b9e8c
--- /dev/null
+++ b/app/fonts/DIN Next/DIN Next W10 Italic.otf
Binary files differ
diff --git a/app/fonts/DIN Next/DIN Next W10 Light.otf b/app/fonts/DIN Next/DIN Next W10 Light.otf
new file mode 100644
index 000000000..700450e49
--- /dev/null
+++ b/app/fonts/DIN Next/DIN Next W10 Light.otf
Binary files differ
diff --git a/app/fonts/DIN Next/DIN Next W10 Medium.otf b/app/fonts/DIN Next/DIN Next W10 Medium.otf
new file mode 100644
index 000000000..b73f2e43f
--- /dev/null
+++ b/app/fonts/DIN Next/DIN Next W10 Medium.otf
Binary files differ
diff --git a/app/fonts/DIN_OT/DINOT-2.otf b/app/fonts/DIN_OT/DINOT-2.otf
new file mode 100644
index 000000000..4a5e13127
--- /dev/null
+++ b/app/fonts/DIN_OT/DINOT-2.otf
Binary files differ
diff --git a/app/fonts/DIN_OT/DINOT-Bold 2.otf b/app/fonts/DIN_OT/DINOT-Bold 2.otf
new file mode 100644
index 000000000..6ed5b6c3d
--- /dev/null
+++ b/app/fonts/DIN_OT/DINOT-Bold 2.otf
Binary files differ
diff --git a/app/fonts/DIN_OT/DINOT-BoldItalic.otf b/app/fonts/DIN_OT/DINOT-BoldItalic.otf
new file mode 100644
index 000000000..148c90588
--- /dev/null
+++ b/app/fonts/DIN_OT/DINOT-BoldItalic.otf
Binary files differ
diff --git a/app/fonts/DIN_OT/DINOT-Italic 2.otf b/app/fonts/DIN_OT/DINOT-Italic 2.otf
new file mode 100644
index 000000000..e365e77ab
--- /dev/null
+++ b/app/fonts/DIN_OT/DINOT-Italic 2.otf
Binary files differ
diff --git a/app/fonts/DIN_OT/DINOT-Medium 2.otf b/app/fonts/DIN_OT/DINOT-Medium 2.otf
new file mode 100644
index 000000000..a87a2df37
--- /dev/null
+++ b/app/fonts/DIN_OT/DINOT-Medium 2.otf
Binary files differ
diff --git a/app/fonts/DIN_OT/DINOT-MediumItalic 2.otf b/app/fonts/DIN_OT/DINOT-MediumItalic 2.otf
new file mode 100644
index 000000000..14eddfc76
--- /dev/null
+++ b/app/fonts/DIN_OT/DINOT-MediumItalic 2.otf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-Black.ttf b/app/fonts/Roboto/Roboto-Black.ttf
new file mode 100644
index 000000000..71f01ac2b
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-Black.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-BlackItalic.ttf b/app/fonts/Roboto/Roboto-BlackItalic.ttf
new file mode 100644
index 000000000..ec309c785
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-BlackItalic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-Bold.ttf b/app/fonts/Roboto/Roboto-Bold.ttf
new file mode 100644
index 000000000..aaf374d2c
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-Bold.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-BoldItalic.ttf b/app/fonts/Roboto/Roboto-BoldItalic.ttf
new file mode 100644
index 000000000..dcd0f8007
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-Italic.ttf b/app/fonts/Roboto/Roboto-Italic.ttf
new file mode 100644
index 000000000..f382c6874
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-Italic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-Light.ttf b/app/fonts/Roboto/Roboto-Light.ttf
new file mode 100644
index 000000000..664e1b2f9
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-Light.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-LightItalic.ttf b/app/fonts/Roboto/Roboto-LightItalic.ttf
new file mode 100644
index 000000000..b8f529637
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-LightItalic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-Medium.ttf b/app/fonts/Roboto/Roboto-Medium.ttf
new file mode 100644
index 000000000..aa00de0ef
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-Medium.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-MediumItalic.ttf b/app/fonts/Roboto/Roboto-MediumItalic.ttf
new file mode 100644
index 000000000..67e25f019
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-MediumItalic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-Regular.ttf b/app/fonts/Roboto/Roboto-Regular.ttf
new file mode 100644
index 000000000..3e6e2e761
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-Regular.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-Thin.ttf b/app/fonts/Roboto/Roboto-Thin.ttf
new file mode 100644
index 000000000..d262d1446
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-Thin.ttf
Binary files differ
diff --git a/app/fonts/Roboto/Roboto-ThinItalic.ttf b/app/fonts/Roboto/Roboto-ThinItalic.ttf
new file mode 100644
index 000000000..63e9f9718
--- /dev/null
+++ b/app/fonts/Roboto/Roboto-ThinItalic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/RobotoCondensed-Bold.ttf b/app/fonts/Roboto/RobotoCondensed-Bold.ttf
new file mode 100644
index 000000000..48dd63534
--- /dev/null
+++ b/app/fonts/Roboto/RobotoCondensed-Bold.ttf
Binary files differ
diff --git a/app/fonts/Roboto/RobotoCondensed-BoldItalic.ttf b/app/fonts/Roboto/RobotoCondensed-BoldItalic.ttf
new file mode 100644
index 000000000..ad728646a
--- /dev/null
+++ b/app/fonts/Roboto/RobotoCondensed-BoldItalic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/RobotoCondensed-Italic.ttf b/app/fonts/Roboto/RobotoCondensed-Italic.ttf
new file mode 100644
index 000000000..a232513d5
--- /dev/null
+++ b/app/fonts/Roboto/RobotoCondensed-Italic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/RobotoCondensed-Light.ttf b/app/fonts/Roboto/RobotoCondensed-Light.ttf
new file mode 100644
index 000000000..a6e368d40
--- /dev/null
+++ b/app/fonts/Roboto/RobotoCondensed-Light.ttf
Binary files differ
diff --git a/app/fonts/Roboto/RobotoCondensed-LightItalic.ttf b/app/fonts/Roboto/RobotoCondensed-LightItalic.ttf
new file mode 100644
index 000000000..5b2b6ae08
--- /dev/null
+++ b/app/fonts/Roboto/RobotoCondensed-LightItalic.ttf
Binary files differ
diff --git a/app/fonts/Roboto/RobotoCondensed-Regular.ttf b/app/fonts/Roboto/RobotoCondensed-Regular.ttf
new file mode 100644
index 000000000..65bf32a19
--- /dev/null
+++ b/app/fonts/Roboto/RobotoCondensed-Regular.ttf
Binary files differ
diff --git a/app/images/eth_logo.svg b/app/images/eth_logo.svg
new file mode 100644
index 000000000..894bd70dd
--- /dev/null
+++ b/app/images/eth_logo.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="256px" height="417px" viewBox="0 0 256 417" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
+ <g>
+ <polygon fill="#343434" points="127.9611 0 125.1661 9.5 125.1661 285.168 127.9611 287.958 255.9231 212.32"/>
+ <polygon fill="#8C8C8C" points="127.962 0 0 212.32 127.962 287.959 127.962 154.158"/>
+ <polygon fill="#3C3C3B" points="127.9611 312.1866 126.3861 314.1066 126.3861 412.3056 127.9611 416.9066 255.9991 236.5866"/>
+ <polygon fill="#8C8C8C" points="127.962 416.9052 127.962 312.1852 0 236.5852"/>
+ <polygon fill="#141414" points="127.9611 287.9577 255.9211 212.3207 127.9611 154.1587"/>
+ <polygon fill="#393939" points="0.0009 212.3208 127.9609 287.9578 127.9609 154.1588"/>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/notification.html b/app/notification.html
index cc485da7f..be38f4aa3 100644
--- a/app/notification.html
+++ b/app/notification.html
@@ -9,7 +9,7 @@
}
</style>
</head>
- <body>
+ <body style="width:350px; height:500px;">
<div id="app-content"></div>
<script src="./scripts/popup.js" type="text/javascript" charset="utf-8"></script>
</body>
diff --git a/app/popup.html b/app/popup.html
index d09b09315..fddf01841 100644
--- a/app/popup.html
+++ b/app/popup.html
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=no">
<title>MetaMask Plugin</title>
</head>
- <body style="width:357px; height:500px;">
+ <body style="width:350px; height:500px;">
<div id="app-content"></div>
<script src="./scripts/popup.js" type="text/javascript" charset="utf-8"></script>
</body>
diff --git a/app/scripts/lib/environment-type.js b/app/scripts/lib/environment-type.js
new file mode 100644
index 000000000..7966926eb
--- /dev/null
+++ b/app/scripts/lib/environment-type.js
@@ -0,0 +1,10 @@
+module.exports = function environmentType () {
+ const url = window.location.href
+ if (url.match(/popup.html$/)) {
+ return 'popup'
+ } else if (url.match(/home.html$/)) {
+ return 'responsive'
+ } else {
+ return 'notification'
+ }
+}
diff --git a/app/scripts/lib/is-popup-or-notification.js b/app/scripts/lib/is-popup-or-notification.js
index 693fa8751..73a812d5f 100644
--- a/app/scripts/lib/is-popup-or-notification.js
+++ b/app/scripts/lib/is-popup-or-notification.js
@@ -1,6 +1,6 @@
module.exports = function isPopupOrNotification () {
const url = window.location.href
- if (url.match(/popup.html$/)) {
+ if (url.match(/popup.html$/) || url.match(/home.html$/)) {
return 'popup'
} else {
return 'notification'
diff --git a/gulpfile.js b/gulpfile.js
index ac36cf983..f8ed456b0 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -19,10 +19,16 @@ var manifest = require('./app/manifest.json')
var gulpif = require('gulp-if')
var replace = require('gulp-replace')
var mkdirp = require('mkdirp')
+var sass = require('gulp-sass')
+var autoprefixer = require('gulp-autoprefixer')
+var gulpStylelint = require('gulp-stylelint')
+var stylefmt = require('gulp-stylefmt')
+
var disableDebugTools = gutil.env.disableDebugTools
var debug = gutil.env.debug
+
// browser reload
gulp.task('dev:reload', function() {
@@ -159,13 +165,7 @@ gulp.task('lint', function () {
// To have the process exit with an error code (1) on
// lint error, return the stream and pipe to failAfterError last.
.pipe(eslint.failAfterError())
-});
-
-/*
-gulp.task('default', ['lint'], function () {
- // This will only run if the lint task is successful...
-});
-*/
+})
// build js
@@ -176,6 +176,36 @@ const jsFiles = [
'popup',
]
+// scss compilation and autoprefixing tasks
+
+gulp.task('build:scss', function () {
+ return gulp.src('ui/app/css/index.scss')
+ .pipe(sourcemaps.init())
+ .pipe(sass().on('error', sass.logError))
+ .pipe(sourcemaps.write())
+ .pipe(autoprefixer())
+ .pipe(gulp.dest('ui/app/css/output'))
+})
+gulp.task('watch:scss', function() {
+ gulp.watch(['ui/app/css/**/*.scss'], gulp.series(['build:scss']))
+})
+
+gulp.task('lint-scss', function() {
+ return gulp
+ .src('ui/app/css/itcss/**/*.scss')
+ .pipe(gulpStylelint({
+ reporters: [
+ {formatter: 'string', console: true}
+ ]
+ }));
+});
+
+gulp.task('fmt-scss', function () {
+ return gulp.src('ui/app/css/itcss/**/*.scss')
+ .pipe(stylefmt())
+ .pipe(gulp.dest('ui/app/css/itcss'));
+});
+
// bundle tasks
var jsDevStrings = jsFiles.map(jsFile => `dev:js:${jsFile}`)
@@ -214,9 +244,9 @@ gulp.task('zip', gulp.parallel('zip:chrome', 'zip:firefox', 'zip:edge', 'zip:ope
// high level tasks
-gulp.task('dev', gulp.series('dev:js', 'copy', gulp.parallel('copy:watch', 'dev:reload')))
+gulp.task('dev', gulp.series('build:scss', 'dev:js', 'copy', gulp.parallel('watch:scss', 'copy:watch', 'dev:reload')))
-gulp.task('build', gulp.series('clean', gulp.parallel('build:js', 'copy')))
+gulp.task('build', gulp.series('clean', 'build:scss', gulp.parallel('build:js', 'copy')))
gulp.task('dist', gulp.series('build', 'zip'))
// task generators
@@ -244,7 +274,7 @@ function zipTask(target) {
return () => {
return gulp.src(`dist/${target}/**`)
.pipe(zip(`metamask-${target}-${manifest.version}.zip`))
- .pipe(gulp.dest('builds'));
+ .pipe(gulp.dest('builds'))
}
}
diff --git a/package.json b/package.json
index f3cf2882a..8092e03c5 100644
--- a/package.json
+++ b/package.json
@@ -43,6 +43,7 @@
]
}
],
+ "reactify",
"envify",
"brfs"
]
@@ -54,6 +55,7 @@
"bip39": "^2.2.0",
"bluebird": "^3.5.0",
"bn.js": "^4.11.7",
+ "boron": "^0.2.3",
"browser-passworder": "^2.0.3",
"browserify-derequire": "^0.9.4",
"client-sw-ready-event": "^3.3.0",
@@ -84,7 +86,9 @@
"extensionizer": "^1.0.0",
"fast-levenshtein": "^2.0.6",
"gulp": "github:gulpjs/gulp#4.0",
+ "gulp-autoprefixer": "^4.0.0",
"gulp-eslint": "^4.0.0",
+ "gulp-sass": "^3.1.0",
"hat": "0.0.3",
"idb-global": "^2.1.0",
"identicon.js": "^2.3.1",
@@ -118,6 +122,8 @@
"react-select": "^1.0.0-rc.2",
"react-simple-file-input": "^1.0.0",
"react-tooltip-component": "^0.3.0",
+ "react-transition-group": "^2.2.0",
+ "reactify": "^1.1.1",
"readable-stream": "^2.1.2",
"redux": "^3.0.5",
"redux-logger": "^3.0.6",
@@ -163,6 +169,8 @@
"gulp-livereload": "^3.8.1",
"gulp-replace": "^0.6.1",
"gulp-sourcemaps": "^2.6.0",
+ "gulp-stylefmt": "^1.1.0",
+ "gulp-stylelint": "^4.0.0",
"gulp-util": "^3.0.7",
"gulp-watch": "^4.3.5",
"gulp-zip": "^4.0.0",
diff --git a/test/unit/components/balance-component-test.js b/test/unit/components/balance-component-test.js
new file mode 100644
index 000000000..c32a8ab2b
--- /dev/null
+++ b/test/unit/components/balance-component-test.js
@@ -0,0 +1,32 @@
+var assert = require('assert')
+var BalanceComponent = require('../../../ui/app/components/balance-component')
+
+describe('BalanceComponent', function () {
+ let balanceComponent
+
+ beforeEach(function () {
+ balanceComponent = new BalanceComponent()
+ })
+
+ it('shows token balance and convert to fiat value based on conversion rate', function () {
+ const formattedBalance = '1.23 ETH'
+
+ const tokenBalance = balanceComponent.getTokenBalance(formattedBalance, false)
+ const fiatDisplayNumber = balanceComponent.getFiatDisplayNumber(formattedBalance, 2)
+
+ assert.equal('1.23 ETH', tokenBalance)
+ assert.equal(2.46, fiatDisplayNumber)
+ })
+
+ it('shows only the token balance when conversion rate is not available', function () {
+ const formattedBalance = '1.23 ETH'
+
+ const tokenBalance = balanceComponent.getTokenBalance(formattedBalance, false)
+ const fiatDisplayNumber = balanceComponent.getFiatDisplayNumber(formattedBalance, 0)
+
+ assert.equal('1.23 ETH', tokenBalance)
+ assert.equal('N/A', fiatDisplayNumber)
+ })
+
+})
+
diff --git a/ui/app/account-and-transaction-details.js b/ui/app/account-and-transaction-details.js
new file mode 100644
index 000000000..03f2d9db5
--- /dev/null
+++ b/ui/app/account-and-transaction-details.js
@@ -0,0 +1,38 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+// Main Views
+const TxView = require('./components/tx-view')
+const WalletView = require('./components/wallet-view')
+
+module.exports = AccountAndTransactionDetails
+
+inherits(AccountAndTransactionDetails, Component)
+function AccountAndTransactionDetails () {
+ Component.call(this)
+}
+
+AccountAndTransactionDetails.prototype.render = function () {
+ return h('div', {
+ style: {
+ display: 'flex',
+ flex: '1 0 auto',
+ },
+ }, [
+ // wallet
+ h(WalletView, {
+ style: {
+ },
+ responsiveDisplayClassname: '.lap-visible',
+ }, [
+ ]),
+
+ // transaction
+ h(TxView, {
+ style: {
+ }
+ }, [
+ ]),
+ ])
+}
+
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
index f6041e856..2be5d5c3a 100644
--- a/ui/app/account-detail.js
+++ b/ui/app/account-detail.js
@@ -40,179 +40,11 @@ function AccountDetailScreen () {
Component.call(this)
}
-AccountDetailScreen.prototype.render = function () {
- var props = this.props
- var selected = props.address || Object.keys(props.accounts)[0]
- var checksumAddress = selected && ethUtil.toChecksumAddress(selected)
- var identity = props.identities[selected]
- var account = props.accounts[selected]
- const { network, conversionRate, currentCurrency } = props
-
- return (
-
- h('.account-detail-section.full-flex-height', [
-
- // identicon, label, balance, etc
- h('.account-data-subsection', {
- style: {
- margin: '0 20px',
- flex: '1 0 auto',
- },
- }, [
-
- // header - identicon + nav
- h('div', {
- style: {
- paddingTop: '20px',
- display: 'flex',
- justifyContent: 'flex-start',
- alignItems: 'flex-start',
- },
- }, [
-
- // large identicon and addresses
- h('.identicon-wrapper.select-none', [
- h(Identicon, {
- diameter: 62,
- address: selected,
- }),
- ]),
- h('flex-column', {
- style: {
- lineHeight: '10px',
- marginLeft: '15px',
- width: '100%',
- },
- }, [
- h(EditableLabel, {
- textValue: identity ? identity.name : '',
- state: {
- isEditingLabel: false,
- },
- saveText: (text) => {
- props.dispatch(actions.saveAccountLabel(selected, text))
- },
- }, [
-
- // What is shown when not editing + edit text:
- h('label.editing-label', [h('.edit-text', 'edit')]),
- h(
- 'div',
- {
- style: {
- display: 'flex',
- justifyContent: 'flex-start',
- alignItems: 'center',
- },
- },
- [
- h(
- 'div.font-medium.color-forest',
- {
- name: 'edit',
- style: {
- },
- },
- [
- h('h2', {
- style: {
- maxWidth: '180px',
- overflowX: 'hidden',
- textOverflow: 'ellipsis',
- padding: '5px 0px',
- },
- }, [
- identity && identity.name,
- ]),
- ]
- ),
- h(
- AccountDropdowns,
- {
- style: {
- marginRight: '8px',
- marginLeft: 'auto',
- cursor: 'pointer',
- },
- selected,
- network,
- identities: props.identities,
- enableAccountOptions: true,
- },
- ),
- ]
- ),
- ]),
- h('.flex-row', {
- style: {
- width: '15em',
- justifyContent: 'space-between',
- alignItems: 'baseline',
- },
- }, [
-
- // address
-
- h('div', {
- style: {
- overflow: 'hidden',
- textOverflow: 'ellipsis',
- paddingTop: '3px',
- width: '5em',
- fontSize: '13px',
- fontFamily: 'Montserrat Light',
- textRendering: 'geometricPrecision',
- marginBottom: '15px',
- color: '#AEAEAE',
- },
- }, checksumAddress),
- ]),
-
- // account ballence
-
- ]),
- ]),
- h('.flex-row', {
- style: {
- justifyContent: 'space-between',
- alignItems: 'flex-start',
- },
- }, [
-
- h(EthBalance, {
- value: account && account.balance,
- conversionRate,
- currentCurrency,
- style: {
- lineHeight: '7px',
- marginTop: '10px',
- },
- }),
-
- h('.flex-grow'),
-
- h('button', {
- onClick: () => props.dispatch(actions.buyEthView(selected)),
- style: { marginRight: '10px' },
- }, 'BUY'),
-
- h('button', {
- onClick: () => props.dispatch(actions.showSendPage()),
- style: {
- marginBottom: '20px',
- marginRight: '8px',
- },
- }, 'SEND'),
-
- ]),
- ]),
-
- // subview (tx history, pk export confirm, buy eth warning)
- this.subview(),
-
- ])
- )
-}
+// Note: This component is no longer used. Leaving the file for reference:
+// - structuring routing for add token
+// - state required for TxList
+// Delete file when those features are complete
+AccountDetailScreen.prototype.render = function () {}
AccountDetailScreen.prototype.subview = function () {
var subview
diff --git a/ui/app/actions.js b/ui/app/actions.js
index eafd04b4c..ae6d92733 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -5,6 +5,21 @@ var actions = {
GO_HOME: 'GO_HOME',
goHome: goHome,
+ // modal state
+ MODAL_OPEN: 'UI_MODAL_OPEN',
+ MODAL_CLOSE: 'UI_MODAL_CLOSE',
+ showModal: showModal,
+ hideModal: hideModal,
+ // sidebar state
+ SIDEBAR_OPEN: 'UI_SIDEBAR_OPEN',
+ SIDEBAR_CLOSE: 'UI_SIDEBAR_CLOSE',
+ showSidebar: showSidebar,
+ hideSidebar: hideSidebar,
+ // network dropdown open
+ NETWORK_DROPDOWN_OPEN: 'UI_NETWORK_DROPDOWN_OPEN',
+ NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE',
+ showNetworkDropdown: showNetworkDropdown,
+ hideNetworkDropdown: hideNetworkDropdown,
// menu state
getNetworkStatus: 'getNetworkStatus',
// transition state
@@ -763,6 +778,44 @@ function useEtherscanProvider () {
}
}
+function showNetworkDropdown () {
+ return {
+ type: actions.NETWORK_DROPDOWN_OPEN,
+ }
+}
+
+function hideNetworkDropdown () {
+ return {
+ type: actions.NETWORK_DROPDOWN_CLOSE,
+ }
+}
+
+
+function showModal () {
+ return {
+ type: actions.MODAL_OPEN,
+ }
+}
+
+function hideModal () {
+ return {
+ type: actions.MODAL_CLOSE,
+ }
+}
+
+function showSidebar () {
+ return {
+ type: actions.SIDEBAR_OPEN,
+ }
+}
+
+function hideSidebar () {
+ return {
+ type: actions.SIDEBAR_CLOSE,
+ }
+}
+
+
function showLoadingIndication (message) {
return {
type: actions.SHOW_LOADING,
diff --git a/ui/app/add-token.js b/ui/app/add-token.js
index 15ef7a852..5c6dea4a0 100644
--- a/ui/app/add-token.js
+++ b/ui/app/add-token.js
@@ -212,7 +212,6 @@ AddTokenScreen.prototype.attemptToAutoFillTokenParams = async function (address)
const [ symbol, decimals ] = results
if (symbol && decimals) {
- console.log('SETTING SYMBOL AND DECIMALS', { symbol, decimals })
this.setState({ symbol: symbol[0], decimals: decimals[0].toString() })
}
}
diff --git a/ui/app/app.js b/ui/app/app.js
index 1f3d5b0f8..c6777ca16 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -9,12 +9,16 @@ const NewKeyChainScreen = require('./new-keychain')
// unlock
const UnlockScreen = require('./unlock')
// accounts
-const AccountDetailScreen = require('./account-detail')
+const MainContainer = require('./main-container')
const SendTransactionScreen = require('./send')
const ConfirmTxScreen = require('./conf-tx')
// notice
const NoticeScreen = require('./components/notice')
const generateLostAccountsNotice = require('../lib/lost-accounts-notice')
+
+// slideout menu
+const WalletView = require('./components/wallet-view')
+
// other views
const ConfigScreen = require('./config')
const AddTokenScreen = require('./add-token')
@@ -22,17 +26,19 @@ const Import = require('./accounts/import')
const InfoScreen = require('./info')
const Loading = require('./components/loading')
const SandwichExpando = require('sandwich-expando')
-const Dropdown = require('./components/dropdown').Dropdown
-const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem
const NetworkIndicator = require('./components/network')
const BuyView = require('./components/buy-button-subview')
const QrView = require('./components/qr-code')
const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete')
const HDRestoreVaultScreen = require('./keychains/hd/restore-vault')
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
-const AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns
+const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
+const NetworkDropdown = require('./components/dropdowns/network-dropdown')
-module.exports = connect(mapStateToProps)(App)
+// Global Modals
+const BuyModal = require('./components/modals/index').BuyModal
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(App)
inherits(App, Component)
function App () { Component.call(this) }
@@ -47,6 +53,8 @@ function mapStateToProps (state) {
return {
// state from plugin
+ networkDropdownOpen: state.appState.networkDropdownOpen,
+ sidebarOpen: state.appState.sidebarOpen,
isLoading: state.appState.isLoading,
loadingMessage: state.appState.loadingMessage,
noActiveNotices: state.metamask.noActiveNotices,
@@ -72,9 +80,17 @@ function mapStateToProps (state) {
}
}
+function mapDispatchToProps (dispatch, ownProps) {
+ return {
+ hideSidebar: () => {dispatch(actions.hideSidebar())},
+ showNetworkDropdown: () => {dispatch(actions.showNetworkDropdown())},
+ hideNetworkDropdown: () => {dispatch(actions.hideNetworkDropdown())},
+ }
+}
+
App.prototype.render = function () {
var props = this.props
- const { isLoading, loadingMessage, transForward, network } = props
+ const { isLoading, loadingMessage, transForward, network, sidebarOpen } = props
const isLoadingNetwork = network === 'loading' && props.currentView.name !== 'config'
const loadMessage = loadingMessage || isLoadingNetwork ?
`Connecting to ${this.getNetworkName()}` : null
@@ -84,35 +100,93 @@ App.prototype.render = function () {
h('.flex-column.full-height', {
style: {
- // Windows was showing a vertical scroll bar:
- overflow: 'hidden',
+ overflowX: 'hidden',
position: 'relative',
alignItems: 'center',
},
}, [
+ // global modal
+ h(BuyModal, {}, []),
+
// app bar
this.renderAppBar(),
- this.renderNetworkDropdown(),
- this.renderDropdown(),
+
+ // sidebar
+ this.renderSidebar(),
+
+ // network dropdown
+ h(NetworkDropdown, {
+ provider: this.props.provider,
+ frequentRpcList: this.props.frequentRpcList,
+ }, []),
h(Loading, {
isLoading: isLoading || isLoadingNetwork,
loadingMessage: loadMessage,
}),
- // panel content
- h('.app-primary' + (transForward ? '.from-right' : '.from-left'), {
- style: {
- width: '100%',
- },
- }, [
- this.renderPrimary(),
- ]),
+ // content
+ this.renderPrimary(),
])
)
}
+App.prototype.renderGlobalModal = function() {
+ return h(Modal, {
+ ref: "modalRef",
+ }, [
+ h(BuyOptions, {}, []),
+ ])
+}
+
+App.prototype.renderSidebar = function() {
+
+ return h('div', {
+ }, [
+ h('style', `
+ .sidebar-enter {
+ transition: transform 300ms ease-in-out;
+ transform: translateX(-100%);
+ }
+ .sidebar-enter.sidebar-enter-active {
+ transition: transform 300ms ease-in-out;
+ transform: translateX(0%);
+ }
+ .sidebar-leave {
+ transition: transform 200ms ease-out;
+ transform: translateX(0%);
+ }
+ .sidebar-leave.sidebar-leave-active {
+ transition: transform 200ms ease-out;
+ transform: translateX(-100%);
+ }
+ `),
+
+ h(ReactCSSTransitionGroup, {
+ transitionName: 'sidebar',
+ transitionEnterTimeout: 300,
+ transitionLeaveTimeout: 200,
+ }, [
+ // A second instance of Walletview is used for non-mobile viewports
+ this.props.sidebarOpen ? h(WalletView, {
+ responsiveDisplayClassname: '.sidebar',
+ style: {},
+ }) : undefined,
+
+ ]),
+
+ // overlay
+ // TODO: add onClick for overlay to close sidebar
+ this.props.sidebarOpen ? h('div.sidebar-overlay', {
+ style: {},
+ onClick: () => {
+ this.props.hideSidebar()
+ },
+ }, []) : undefined,
+ ])
+}
+
App.prototype.renderAppBar = function () {
if (window.METAMASK_UI_TYPE === 'notification') {
return null
@@ -125,28 +199,16 @@ App.prototype.renderAppBar = function () {
return (
h('.full-width', {
- height: '38px',
+ style: {}
}, [
h('.app-header.flex-row.flex-space-between', {
- style: {
- alignItems: 'center',
- visibility: props.isUnlocked ? 'visible' : 'none',
- background: props.isUnlocked ? 'white' : 'none',
- height: '38px',
- position: 'relative',
- zIndex: 12,
- },
+ style: {},
}, [
- h('div.left-menu-section', {
- style: {
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- },
+ h('div.left-menu-wrapper', {
+ style: {},
}, [
-
// mini logo
h('img', {
height: 24,
@@ -154,245 +216,41 @@ App.prototype.renderAppBar = function () {
src: '/images/icon-128.png',
}),
+ // metamask name
+ h('h1', {
+ style: {
+ position: 'relative',
+ left: '9px',
+ },
+ }, 'MetaMask'),
+
+ ]),
+
+ h('div.network-component-wrapper', {
+ style: {},
+ }, [
+ // Network Indicator
h(NetworkIndicator, {
network: this.props.network,
provider: this.props.provider,
onClick: (event) => {
event.preventDefault()
event.stopPropagation()
- this.setState({ isNetworkMenuOpen: !isNetworkMenuOpen })
+ if (this.props.networkDropdownOpen === false) {
+ this.props.showNetworkDropdown()
+ } else {
+ this.props.hideNetworkDropdown()
+ }
},
}),
- ]),
-
- // metamask name
- props.isUnlocked && h('h1', {
- style: {
- position: 'relative',
- left: '9px',
- },
- }, 'MetaMask'),
- props.isUnlocked && h('div', {
- style: {
- display: 'flex',
- flexDirection: 'row',
- alignItems: 'center',
- },
- }, [
-
- props.isUnlocked && h(AccountDropdowns, {
- style: {},
- enableAccountsSelector: true,
- identities: this.props.identities,
- selected: this.props.currentView.context,
- network: this.props.network,
- }, []),
-
- // hamburger
- props.isUnlocked && h(SandwichExpando, {
- className: 'sandwich-expando',
- width: 16,
- barHeight: 2,
- padding: 0,
- isOpen: state.isMainMenuOpen,
- color: 'rgb(247,146,30)',
- onClick: () => {
- this.setState({
- isMainMenuOpen: !state.isMainMenuOpen,
- })
- },
- }),
]),
]),
+
])
)
}
-App.prototype.renderNetworkDropdown = function () {
- const props = this.props
- const { provider: { type: providerType, rpcTarget: activeNetwork } } = props
- const rpcList = props.frequentRpcList
- const state = this.state || {}
- const isOpen = state.isNetworkMenuOpen
-
- return h(Dropdown, {
- useCssTransition: true,
- isOpen,
- onClickOutside: (event) => {
- const { classList } = event.target
- const isNotToggleElement = [
- classList.contains('menu-icon'),
- classList.contains('network-name'),
- classList.contains('network-indicator'),
- ].filter(bool => bool).length === 0
- // classes from three constituent nodes of the toggle element
-
- if (isNotToggleElement) {
- this.setState({ isNetworkMenuOpen: false })
- }
- },
- zIndex: 11,
- style: {
- position: 'absolute',
- left: '2px',
- top: '36px',
- },
- innerStyle: {
- padding: '2px 16px 2px 0px',
- },
- }, [
-
- h(
- DropdownMenuItem,
- {
- key: 'main',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('mainnet')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('.menu-icon.diamond'),
- 'Main Ethereum Network',
- providerType === 'mainnet' ? h('.check', '✓') : null,
- ]
- ),
-
- h(
- DropdownMenuItem,
- {
- key: 'ropsten',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('ropsten')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('.menu-icon.red-dot'),
- 'Ropsten Test Network',
- providerType === 'ropsten' ? h('.check', '✓') : null,
- ]
- ),
-
- h(
- DropdownMenuItem,
- {
- key: 'kovan',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('kovan')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('.menu-icon.hollow-diamond'),
- 'Kovan Test Network',
- providerType === 'kovan' ? h('.check', '✓') : null,
- ]
- ),
-
- h(
- DropdownMenuItem,
- {
- key: 'rinkeby',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setProviderType('rinkeby')),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('.menu-icon.golden-square'),
- 'Rinkeby Test Network',
- providerType === 'rinkeby' ? h('.check', '✓') : null,
- ]
- ),
-
- h(
- DropdownMenuItem,
- {
- key: 'default',
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => props.dispatch(actions.setDefaultRpcTarget()),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('i.fa.fa-question-circle.fa-lg.menu-icon'),
- 'Localhost 8545',
- activeNetwork === 'http://localhost:8545' ? h('.check', '✓') : null,
- ]
- ),
-
- this.renderCustomOption(props.provider),
- this.renderCommonRpc(rpcList, props.provider),
-
- h(
- DropdownMenuItem,
- {
- closeMenu: () => this.setState({ isNetworkMenuOpen: !isOpen }),
- onClick: () => this.props.dispatch(actions.showConfigPage()),
- style: {
- fontSize: '18px',
- },
- },
- [
- h('i.fa.fa-question-circle.fa-lg.menu-icon'),
- 'Custom RPC',
- activeNetwork === 'custom' ? h('.check', '✓') : null,
- ]
- ),
-
- ])
-}
-
-App.prototype.renderDropdown = function () {
- const state = this.state || {}
- const isOpen = state.isMainMenuOpen
-
- return h(Dropdown, {
- useCssTransition: true,
- isOpen: isOpen,
- zIndex: 11,
- onClickOutside: (event) => {
- const classList = event.target.classList
- const parentClassList = event.target.parentElement.classList
-
- const isToggleElement = classList.contains('sandwich-expando') ||
- parentClassList.contains('sandwich-expando')
-
- if (isOpen && !isToggleElement) {
- this.setState({ isMainMenuOpen: false })
- }
- },
- style: {
- position: 'absolute',
- right: '2px',
- top: '38px',
- },
- innerStyle: {},
- }, [
- h(DropdownMenuItem, {
- closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- onClick: () => { this.props.dispatch(actions.showConfigPage()) },
- }, 'Settings'),
-
- h(DropdownMenuItem, {
- closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- onClick: () => { this.props.dispatch(actions.lockMetamask()) },
- }, 'Lock'),
-
- h(DropdownMenuItem, {
- closeMenu: () => this.setState({ isMainMenuOpen: !isOpen }),
- onClick: () => { this.props.dispatch(actions.showInfoPage()) },
- }, 'Info/Help'),
- ])
-}
-
App.prototype.renderBackButton = function (style, justArrow = false) {
var props = this.props
return (
@@ -456,28 +314,18 @@ App.prototype.renderPrimary = function () {
// show unlock screen
if (!props.isUnlocked) {
- switch (props.currentView.name) {
-
- case 'restoreVault':
- log.debug('rendering restore vault screen')
- return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'})
-
- case 'config':
- log.debug('rendering config screen from unlock screen.')
- return h(ConfigScreen, {key: 'config'})
-
- default:
- log.debug('rendering locked screen')
- return h(UnlockScreen, {key: 'locked'})
- }
+ return h(MainContainer, {
+ currentViewName: props.currentView.name,
+ isUnlocked: props.isUnlocked,
+ })
}
// show current view
switch (props.currentView.name) {
case 'accountDetail':
- log.debug('rendering account detail screen')
- return h(AccountDetailScreen, {key: 'account-detail'})
+ log.debug('rendering main container')
+ return h(MainContainer, {key: 'account-detail'})
case 'sendTransaction':
log.debug('rendering send tx screen')
@@ -545,7 +393,7 @@ App.prototype.renderPrimary = function () {
default:
log.debug('rendering default, account detail screen')
- return h(AccountDetailScreen, {key: 'account-detail'})
+ return h(MainContainer, {key: 'account-detail'})
}
}
@@ -561,40 +409,6 @@ App.prototype.toggleMetamaskActive = function () {
}
}
-App.prototype.renderCustomOption = function (provider) {
- const { rpcTarget, type } = provider
- const props = this.props
-
- if (type !== 'rpc') return null
-
- // Concatenate long URLs
- let label = rpcTarget
- if (rpcTarget.length > 31) {
- label = label.substr(0, 34) + '...'
- }
-
- switch (rpcTarget) {
-
- case 'http://localhost:8545':
- return null
-
- default:
- return h(
- DropdownMenuItem,
- {
- key: rpcTarget,
- onClick: () => props.dispatch(actions.setRpcTarget(rpcTarget)),
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- },
- [
- h('i.fa.fa-question-circle.fa-lg.menu-icon'),
- label,
- h('.check', '✓'),
- ]
- )
- }
-}
-
App.prototype.getNetworkName = function () {
const { provider } = this.props
const providerName = provider.type
@@ -615,28 +429,3 @@ App.prototype.getNetworkName = function () {
return name
}
-
-App.prototype.renderCommonRpc = function (rpcList, provider) {
- const props = this.props
- const rpcTarget = provider.rpcTarget
-
- return rpcList.map((rpc) => {
- if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) {
- return null
- } else {
- return h(
- DropdownMenuItem,
- {
- key: `common${rpc}`,
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- onClick: () => props.dispatch(actions.setRpcTarget(rpc)),
- },
- [
- h('i.fa.fa-question-circle.fa-lg.menu-icon'),
- rpc,
- rpcTarget === rpc ? h('.check', '✓') : null,
- ]
- )
- }
- })
-}
diff --git a/ui/app/components/balance-component.js b/ui/app/components/balance-component.js
new file mode 100644
index 000000000..48efc7b6a
--- /dev/null
+++ b/ui/app/components/balance-component.js
@@ -0,0 +1,95 @@
+const Component = require('react').Component
+const connect = require('react-redux').connect
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+
+const { formatBalance, generateBalanceObject } = require('../util')
+
+module.exports = connect(mapStateToProps)(BalanceComponent)
+
+function mapStateToProps (state) {
+ return {
+ conversionRate: state.metamask.conversionRate,
+ currentCurrency: state.metamask.currentCurrency,
+ }
+}
+
+inherits(BalanceComponent, Component)
+function BalanceComponent () {
+ Component.call(this)
+}
+
+BalanceComponent.prototype.render = function () {
+ const props = this.props
+ const { balanceValue } = props
+ const needsParse = 'needsParse' in props ? props.needsParse : true
+ const formattedBalance = balanceValue ? formatBalance(balanceValue, 6, needsParse) : '...'
+
+ return h('div.balance-container', {}, [
+
+ // TODO: balance icon needs to be passed in
+ h('img.balance-icon', {
+ src: '../images/eth_logo.svg',
+ style: {},
+ }),
+
+ this.renderBalance(formattedBalance),
+ ])
+}
+
+BalanceComponent.prototype.renderBalance = function (formattedBalance) {
+ const props = this.props
+ const { shorten } = props
+ const showFiat = 'showFiat' in props ? props.showFiat : true
+
+ if (formattedBalance === 'None' || formattedBalance === '...') {
+ return h('div.flex-column.balance-display', {}, [
+ h('div.token-amount', {
+ style: {},
+ }, formattedBalance),
+ ])
+ }
+
+ return h('div.flex-column.balance-display', {}, [
+ h('div.token-amount', {
+ style: {},
+ }, this.getTokenBalance(formattedBalance, shorten)),
+
+ showFiat ? this.renderFiatValue(formattedBalance) : null,
+ ])
+}
+
+BalanceComponent.prototype.renderFiatValue = function (formattedBalance) {
+
+ const { conversionRate, currentCurrency } = this.props
+
+ const fiatDisplayNumber = this.getFiatDisplayNumber(formattedBalance, conversionRate)
+
+ return this.renderFiatAmount(fiatDisplayNumber, currentCurrency)
+}
+
+BalanceComponent.prototype.renderFiatAmount = function (fiatDisplayNumber, fiatSuffix) {
+ if (fiatDisplayNumber === 'N/A') return null
+
+ return h('div.fiat-amount', {
+ style: {},
+ }, `${fiatDisplayNumber} ${fiatSuffix}`)
+}
+
+BalanceComponent.prototype.getTokenBalance = function (formattedBalance, shorten) {
+ const balanceObj = generateBalanceObject(formattedBalance, shorten ? 1 : 3)
+
+ const balanceValue = shorten ? balanceObj.shortBalance : balanceObj.balance
+ const label = balanceObj.label
+
+ return `${balanceValue} ${label}`
+}
+
+BalanceComponent.prototype.getFiatDisplayNumber = function (formattedBalance, conversionRate) {
+ if (formattedBalance === 'None') return formattedBalance
+ if (conversionRate === 0) return 'N/A'
+
+ const splitBalance = formattedBalance.split(' ')
+
+ return (Number(splitBalance[0]) * conversionRate).toFixed(2)
+}
diff --git a/ui/app/components/buy-options.js b/ui/app/components/buy-options.js
new file mode 100644
index 000000000..7d640c007
--- /dev/null
+++ b/ui/app/components/buy-options.js
@@ -0,0 +1,80 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const actions = require('../actions')
+
+function mapStateToProps (state) {
+ return {
+ network: state.metamask.network,
+ address: state.metamask.selectedAddress,
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ toCoinbase: (address) => {
+ dispatch(actions.buyEth({ network: '1', address, amount: 0 }))
+ },
+ hideModal: () => {
+ dispatch(actions.hideModal())
+ }
+ }
+}
+
+inherits(BuyOptions, Component)
+function BuyOptions () {
+ Component.call(this)
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(BuyOptions)
+
+// BuyOptions is currently meant to be rendered inside <Modal />
+// It is the only component in this codebase that does so
+// It utilizes modal styles
+BuyOptions.prototype.render = function () {
+ return h('div', {}, [
+ h('div.modal-content.transfers-subview', {
+ }, [
+ h('div.modal-content-title-wrapper.flex-column.flex-center', {
+ style: {},
+ }, [
+ h('div.modal-content-title', {
+ style: {},
+ }, 'Transfers'),
+ h('div', {}, 'How would you like to buy Ether?'),
+ ]),
+
+ h('div.modal-content-options.flex-column.flex-center', {}, [
+
+ h('div.modal-content-option', {
+ onClick: () => {
+ const { toCoinbase, address } = this.props
+ toCoinbase(address)
+ },
+ }, [
+ h('div.modal-content-option-title', {}, 'Coinbase'),
+ h('div.modal-content-option-subtitle', {}, 'Buy with Fiat'),
+ ]),
+
+ h('div.modal-content-option', {}, [
+ h('div.modal-content-option-title', {}, 'Shapeshift'),
+ h('div.modal-content-option-subtitle', {}, 'Trade any digital asset for any other'),
+ ]),
+
+ h('div.modal-content-option', {}, [
+ h('div.modal-content-option-title', {}, 'Direct Deposit'),
+ h('div.modal-content-option-subtitle', {}, 'Deposit from another account'),
+ ]),
+
+ ]),
+
+ h('button', {
+ style: {
+ background: 'white',
+ },
+ onClick: () => { this.props.hideModal() },
+ }, h('div.modal-content-footer#modal-content-footer-text',{}, 'Cancel')),
+ ])
+ ])
+}
diff --git a/ui/app/components/dropdowns/account-options-dropdown.js b/ui/app/components/dropdowns/account-options-dropdown.js
new file mode 100644
index 000000000..7d7188ec4
--- /dev/null
+++ b/ui/app/components/dropdowns/account-options-dropdown.js
@@ -0,0 +1,28 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const AccountDropdowns = require('./components/account-dropdowns')
+
+inherits(AccountOptionsDropdown, Component)
+function AccountOptionsDropdown () {
+ Component.call(this)
+}
+
+module.exports = AccountOptionsDropdown
+
+// TODO: specify default props and proptypes
+// TODO: hook up to state, connect to redux to clean up API
+AccountOptionsDropdown.prototype.render = function () {
+ const { selected, network, identities, style, dropdownWrapperStyle, menuItemStyles } = this.props
+
+ return h(AccountDropdowns, {
+ enableAccountOptions: true,
+ enableAccountsSelector: false,
+ selected: selectedAddress,
+ network,
+ identities,
+ style: !!style ? style : {},
+ dropdownWrapperStyle: !!dropdownWrapperStyle ? dropdownWrapperStyle : {},
+ menuItemStyles: !!menuItemStyles ? menuItemStyles : {},
+ }, [])
+}
diff --git a/ui/app/components/dropdowns/account-selection-dropdown.js b/ui/app/components/dropdowns/account-selection-dropdown.js
new file mode 100644
index 000000000..ccb73bde7
--- /dev/null
+++ b/ui/app/components/dropdowns/account-selection-dropdown.js
@@ -0,0 +1,28 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const AccountDropdowns = require('./components/account-dropdowns')
+
+inherits(AccountSelectionDropdown, Component)
+function AccountSelectionDropdown () {
+ Component.call(this)
+}
+
+module.exports = AccountSelectionDropdown
+
+// TODO: specify default props and proptypes
+// TODO: hook up to state, connect to redux to clean up API
+AccountSelectionDropdown.prototype.render = function () {
+ const { selected, network, identities, style, dropdownWrapperStyle, menuItemStyles } = this.props
+
+ return h(AccountDropdowns, {
+ enableAccountOptions: false,
+ enableAccountsSelector: true,
+ selected: selectedAddress,
+ network,
+ identities,
+ style: !!style ? style : {},
+ dropdownWrapperStyle: !!dropdownWrapperStyle ? dropdownWrapperStyle : {},
+ menuItemStyles: !!menuItemStyles ? menuItemStyles : {},
+ }, [])
+}
diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js
index 7c24e70bd..b59f9bbf4 100644
--- a/ui/app/components/account-dropdowns.js
+++ b/ui/app/components/dropdowns/components/account-dropdowns.js
@@ -1,12 +1,12 @@
const Component = require('react').Component
const PropTypes = require('react').PropTypes
const h = require('react-hyperscript')
-const actions = require('../actions')
-const genAccountLink = require('../../lib/account-link.js')
+const actions = require('../../../actions')
+const genAccountLink = require('../../../../lib/account-link.js')
const connect = require('react-redux').connect
const Dropdown = require('./dropdown').Dropdown
const DropdownMenuItem = require('./dropdown').DropdownMenuItem
-const Identicon = require('./identicon')
+const Identicon = require('../../identicon')
const ethUtil = require('ethereumjs-util')
const copyToClipboard = require('copy-to-clipboard')
@@ -17,12 +17,14 @@ class AccountDropdowns extends Component {
accountSelectorActive: false,
optionsMenuActive: false,
}
- this.accountSelectorToggleClassName = 'accounts-selector'
+ // Used for orangeaccount selector icon
+ // this.accountSelectorToggleClassName = 'accounts-selector'
+ this.accountSelectorToggleClassName = 'fa-angle-down'
this.optionsMenuToggleClassName = 'fa-ellipsis-h'
}
renderAccounts () {
- const { identities, selected } = this.props
+ const { identities, selected, menuItemStyles, dropdownWrapperStyle } = this.props
return Object.keys(identities).map((key, index) => {
const identity = identities[key]
@@ -35,10 +37,13 @@ class AccountDropdowns extends Component {
onClick: () => {
this.props.actions.showAccountDetail(identity.address)
},
- style: {
- marginTop: index === 0 ? '5px' : '',
- fontSize: '24px',
- },
+ style: Object.assign(
+ {
+ marginTop: index === 0 ? '5px' : '',
+ fontSize: '24px',
+ },
+ menuItemStyles,
+ ),
},
[
h(
@@ -68,16 +73,16 @@ class AccountDropdowns extends Component {
}
renderAccountSelector () {
- const { actions } = this.props
- const { accountSelectorActive } = this.state
+ const { actions, dropdownWrapperStyle, useCssTransition } = this.props
+ const { accountSelectorActive, menuItemStyles } = this.state
return h(
Dropdown,
{
- useCssTransition: true, // Hardcoded because account selector is temporarily in app-header
+ useCssTransition,
style: {
- marginLeft: '-238px',
- marginTop: '38px',
+ marginLeft: '-185px',
+ marginTop: '50px',
minWidth: '180px',
overflowY: 'auto',
maxHeight: '300px',
@@ -102,6 +107,10 @@ class AccountDropdowns extends Component {
{
closeMenu: () => {},
onClick: () => actions.addNewAccount(),
+ style: Object.assign(
+ {},
+ menuItemStyles,
+ ),
},
[
h(
@@ -121,6 +130,10 @@ class AccountDropdowns extends Component {
{
closeMenu: () => {},
onClick: () => actions.showImportPage(),
+ style: Object.assign(
+ {},
+ menuItemStyles,
+ ),
},
[
h(
@@ -146,16 +159,21 @@ class AccountDropdowns extends Component {
}
renderAccountOptions () {
- const { actions } = this.props
- const { optionsMenuActive } = this.state
+ const { actions, dropdownWrapperStyle, useCssTransition } = this.props
+ const { optionsMenuActive, menuItemStyles } = this.state
return h(
Dropdown,
{
- style: {
- marginLeft: '-215px',
- minWidth: '180px',
- },
+ useCssTransition,
+ style: Object.assign(
+ {
+ marginLeft: '-10px',
+ position: 'absolute',
+ width: '29vh', // affects both mobile and laptop views
+ },
+ dropdownWrapperStyle,
+ ),
isOpen: optionsMenuActive,
onClickOutside: () => {
const { classList } = event.target
@@ -175,6 +193,10 @@ class AccountDropdowns extends Component {
const url = genAccountLink(selected, network)
global.platform.openWindow({ url })
},
+ style: Object.assign(
+ {},
+ menuItemStyles,
+ ),
},
'View account on Etherscan',
),
@@ -187,6 +209,10 @@ class AccountDropdowns extends Component {
var identity = identities[selected]
actions.showQrView(selected, identity ? identity.name : '')
},
+ style: Object.assign(
+ {},
+ menuItemStyles,
+ ),
},
'Show QR Code',
),
@@ -199,6 +225,10 @@ class AccountDropdowns extends Component {
const checkSumAddress = selected && ethUtil.toChecksumAddress(selected)
copyToClipboard(checkSumAddress)
},
+ style: Object.assign(
+ {},
+ menuItemStyles,
+ ),
},
'Copy Address to clipboard',
),
@@ -209,6 +239,10 @@ class AccountDropdowns extends Component {
onClick: () => {
actions.requestAccountExport()
},
+ style: Object.assign(
+ {},
+ menuItemStyles,
+ ),
},
'Export Private Key',
),
@@ -217,7 +251,7 @@ class AccountDropdowns extends Component {
}
render () {
- const { style, enableAccountsSelector, enableAccountOptions } = this.props
+ const { style, enableAccountsSelector, enableAccountOptions, dropdownWrapperStyle } = this.props
const { optionsMenuActive, accountSelectorActive } = this.state
return h(
@@ -227,16 +261,16 @@ class AccountDropdowns extends Component {
},
[
enableAccountsSelector && h(
- // 'i.fa.fa-angle-down',
- 'div.cursor-pointer.color-orange.accounts-selector',
+ 'i.fa.fa-angle-down',
+ // 'div.cursor-pointer.color-orange.accounts-selector',
{
style: {
- // fontSize: '1.8em',
- background: 'url(images/switch_acc.svg) white center center no-repeat',
- height: '25px',
- width: '25px',
- transform: 'scale(0.75)',
- marginRight: '3px',
+ // fontSize: '135%',
+ // background: 'url(images/switch_acc.svg) white center center no-repeat',
+ // height: '25px',
+ // width: '25px',
+ // transform: 'scale(0.75)',
+ // marginRight: '3px',
},
onClick: (event) => {
event.stopPropagation()
@@ -252,8 +286,7 @@ class AccountDropdowns extends Component {
'i.fa.fa-ellipsis-h',
{
style: {
- marginRight: '0.5em',
- fontSize: '1.8em',
+ fontSize: '135%',
},
onClick: (event) => {
event.stopPropagation()
@@ -277,7 +310,7 @@ AccountDropdowns.defaultProps = {
AccountDropdowns.propTypes = {
identities: PropTypes.objectOf(PropTypes.object),
- selected: PropTypes.string,
+ selected: PropTypes.string, // TODO: refactor to be more explicit: selectedAddress
}
const mapDispatchToProps = (dispatch) => {
@@ -293,6 +326,5 @@ const mapDispatchToProps = (dispatch) => {
}
}
-module.exports = {
- AccountDropdowns: connect(null, mapDispatchToProps)(AccountDropdowns),
-}
+module.exports = connect(null, mapDispatchToProps)(AccountDropdowns)
+
diff --git a/ui/app/components/dropdown.js b/ui/app/components/dropdowns/components/dropdown.js
index 34c7149ee..1f35f0c70 100644
--- a/ui/app/components/dropdown.js
+++ b/ui/app/components/dropdowns/components/dropdown.js
@@ -1,7 +1,7 @@
const Component = require('react').Component
const PropTypes = require('react').PropTypes
const h = require('react-hyperscript')
-const MenuDroppo = require('./menu-droppo')
+const MenuDroppo = require('../../menu-droppo')
const extend = require('xtend')
const noop = () => {}
@@ -22,7 +22,7 @@ class Dropdown extends Component {
{
useCssTransition,
isOpen,
- zIndex: 11,
+ zIndex: 30,
onClickOutside,
style,
innerStyle: innerStyleDefaults,
@@ -67,7 +67,7 @@ class DropdownMenuItem extends Component {
},
style: Object.assign({
listStyle: 'none',
- padding: '8px 0px 8px 0px',
+ padding: '8px 0px',
fontSize: '18px',
fontStyle: 'normal',
fontFamily: 'Montserrat Regular',
@@ -75,6 +75,7 @@ class DropdownMenuItem extends Component {
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
+ color: 'white',
}, style),
},
children
diff --git a/ui/app/components/dropdowns/index.js b/ui/app/components/dropdowns/index.js
new file mode 100644
index 000000000..d21c795f5
--- /dev/null
+++ b/ui/app/components/dropdowns/index.js
@@ -0,0 +1,18 @@
+// Reusable Dropdown Components
+//TODO: Refactor into separate components
+const Dropdown = require('./components/dropdown').Dropdown
+const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem
+const AccountDropdowns = require('./components/account-dropdowns')
+
+// App-Specific Instances
+const AccountSelectionDropdown = require('./account-selection-dropdown')
+const AccountOptionsDropdown = require('./account-options-dropdown')
+const NetworkDropdown = require('./network-dropdown').default
+
+module.exports = {
+ AccountSelectionDropdown,
+ AccountOptionsDropdown,
+ NetworkDropdown,
+ Dropdown,
+ AccountDropdowns,
+} \ No newline at end of file
diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js
new file mode 100644
index 000000000..6228513c9
--- /dev/null
+++ b/ui/app/components/dropdowns/network-dropdown.js
@@ -0,0 +1,268 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const actions = require('../../actions')
+const Dropdown = require('./components/dropdown').Dropdown
+const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem
+
+function mapStateToProps (state) {
+ return {
+ provider: state.metamask.provider,
+ frequentRpcList: state.metamask.frequentRpcList || [],
+ networkDropdownOpen: state.appState.networkDropdownOpen,
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ hideModal: () => {
+ dispatch(actions.hideModal())
+ },
+ setProviderType: (type) => {
+ dispatch(actions.setProviderType(type))
+ },
+ setDefaultRpcTarget: () => {
+ dispatch(actions.setDefaultRpcTarget(type))
+ },
+ setRpcTarget: (target) => {
+ dispatch(actions.setRpcTarget(target))
+ },
+ showConfigPage: () => {
+ dispatch(actions.showConfigPage())
+ },
+ showNetworkDropdown: () => {dispatch(actions.showNetworkDropdown())},
+ hideNetworkDropdown: () => {dispatch(actions.hideNetworkDropdown())},
+ }
+}
+
+
+inherits(NetworkDropdown, Component)
+function NetworkDropdown () {
+ Component.call(this)
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(NetworkDropdown)
+
+// TODO: specify default props and proptypes
+NetworkDropdown.prototype.render = function () {
+ const props = this.props
+ const { provider: { type: providerType, rpcTarget: activeNetwork } } = props
+ const rpcList = props.frequentRpcList
+ const state = this.state || {}
+ const isOpen = this.props.networkDropdownOpen
+
+ return h(Dropdown, {
+ useCssTransition: true,
+ isOpen,
+ onClickOutside: (event) => {
+ const { classList } = event.target
+ const isNotToggleElement = [
+ classList.contains('menu-icon'),
+ classList.contains('network-name'),
+ classList.contains('network-indicator'),
+ ].filter(bool => bool).length === 0
+ // classes from three constituent nodes of the toggle element
+
+ if (isNotToggleElement) {
+ this.props.hideNetworkDropdown()
+ }
+ },
+ zIndex: 11,
+ style: {
+ position: 'absolute',
+ right: '2px',
+ top: '38px',
+ },
+ innerStyle: {
+ padding: '2px 16px 2px 0px',
+ },
+ }, [
+
+ h(
+ DropdownMenuItem,
+ {
+ key: 'main',
+ closeMenu: () => this.props.hideNetworkDropdown(),
+ onClick: () => props.setProviderType('mainnet'),
+ style: {
+ fontSize: '18px',
+ },
+ },
+ [
+ h('.menu-icon.diamond'),
+ 'Main Ethereum Network',
+ providerType === 'mainnet' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ h(
+ DropdownMenuItem,
+ {
+ key: 'ropsten',
+ closeMenu: () => this.props.hideNetworkDropdown(),
+ onClick: () => props.setProviderType('ropsten'),
+ style: {
+ fontSize: '18px',
+ },
+ },
+ [
+ h('.menu-icon.red-dot'),
+ 'Ropsten Test Network',
+ providerType === 'ropsten' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ h(
+ DropdownMenuItem,
+ {
+ key: 'kovan',
+ closeMenu: () => this.props.hideNetworkDropdown(),
+ onClick: () => props.setProviderType('kovan'),
+ style: {
+ fontSize: '18px',
+ },
+ },
+ [
+ h('.menu-icon.hollow-diamond'),
+ 'Kovan Test Network',
+ providerType === 'kovan' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ h(
+ DropdownMenuItem,
+ {
+ key: 'rinkeby',
+ closeMenu: () => this.props.hideNetworkDropdown(),
+ onClick: () => propssetProviderType('rinkeby'),
+ style: {
+ fontSize: '18px',
+ },
+ },
+ [
+ h('.menu-icon.golden-square'),
+ 'Rinkeby Test Network',
+ providerType === 'rinkeby' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ h(
+ DropdownMenuItem,
+ {
+ key: 'default',
+ closeMenu: () => this.props.hideNetworkDropdown(),
+ onClick: () => props.setDefaultRpcTarget(),
+ style: {
+ fontSize: '18px',
+ },
+ },
+ [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ 'Localhost 8545',
+ activeNetwork === 'http://localhost:8545' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ this.renderCustomOption(props.provider),
+ this.renderCommonRpc(rpcList, props.provider),
+
+ h(
+ DropdownMenuItem,
+ {
+ closeMenu: () => this.props.hideNetworkDropdown(),
+ onClick: () => this.props.showConfigPage(),
+ style: {
+ fontSize: '18px',
+ },
+ },
+ [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ 'Custom RPC',
+ activeNetwork === 'custom' ? h('.check', '✓') : null,
+ ]
+ ),
+
+ ])
+}
+
+
+NetworkDropdown.prototype.getNetworkName = function () {
+ const { provider } = this.props
+ const providerName = provider.type
+
+ let name
+
+ if (providerName === 'mainnet') {
+ name = 'Main Ethereum Network'
+ } else if (providerName === 'ropsten') {
+ name = 'Ropsten Test Network'
+ } else if (providerName === 'kovan') {
+ name = 'Kovan Test Network'
+ } else if (providerName === 'rinkeby') {
+ name = 'Rinkeby Test Network'
+ } else {
+ name = 'Unknown Private Network'
+ }
+
+ return name
+}
+
+NetworkDropdown.prototype.renderCommonRpc = function (rpcList, provider) {
+ const props = this.props
+ const rpcTarget = provider.rpcTarget
+
+ return rpcList.map((rpc) => {
+ if ((rpc === 'http://localhost:8545') || (rpc === rpcTarget)) {
+ return null
+ } else {
+ return h(
+ DropdownMenuItem,
+ {
+ key: `common${rpc}`,
+ closeMenu: () => this.props.hideNetworkDropdown(),
+ onClick: () => props.setRpcTarget(rpc),
+ },
+ [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ rpc,
+ rpcTarget === rpc ? h('.check', '✓') : null,
+ ]
+ )
+ }
+ })
+}
+
+NetworkDropdown.prototype.renderCustomOption = function (provider) {
+ const { rpcTarget, type } = provider
+ const props = this.props
+
+ if (type !== 'rpc') return null
+
+ // Concatenate long URLs
+ let label = rpcTarget
+ if (rpcTarget.length > 31) {
+ label = label.substr(0, 34) + '...'
+ }
+
+ switch (rpcTarget) {
+
+ case 'http://localhost:8545':
+ return null
+
+ default:
+ return h(
+ DropdownMenuItem,
+ {
+ key: rpcTarget,
+ onClick: () => props.setRpcTarget(rpcTarget),
+ closeMenu: () => this.props.hideNetworkDropdown(),
+ },
+ [
+ h('i.fa.fa-question-circle.fa-lg.menu-icon'),
+ label,
+ h('.check', '✓'),
+ ]
+ )
+ }
+}
diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js
index 3a33ebf74..93c07599d 100644
--- a/ui/app/components/ens-input.js
+++ b/ui/app/components/ens-input.js
@@ -44,6 +44,13 @@ EnsInput.prototype.render = function () {
return h('div', {
style: { width: '100%' },
}, [
+ h('span', {
+ style: {
+ textAlign: 'left',
+ }
+ }, [
+ 'To:'
+ ]),
h('input.large-input', opts),
// The address book functionality.
h('datalist#addresses',
diff --git a/ui/app/components/modals/buy-modal.js b/ui/app/components/modals/buy-modal.js
new file mode 100644
index 000000000..9a3e4dff9
--- /dev/null
+++ b/ui/app/components/modals/buy-modal.js
@@ -0,0 +1,23 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const BuyOptions = require('../buy-options')
+const Modal = require('./modal.js')
+
+inherits(BuyModal, Component)
+function BuyModal () {
+ Component.call(this)
+}
+
+module.exports = BuyModal
+
+BuyModal.prototype.render = function () {
+ return h(Modal, {
+ ref: "modalRef",
+ }, [
+ h(BuyOptions, {}, []),
+ ])
+
+}
+
+// TODO: specify default props and proptypes
diff --git a/ui/app/components/modals/index.js b/ui/app/components/modals/index.js
new file mode 100644
index 000000000..23b432b7c
--- /dev/null
+++ b/ui/app/components/modals/index.js
@@ -0,0 +1,9 @@
+const Modal = require('./modal')
+const BuyModal = require('./buy-modal')
+// const h = require('account-options')
+// const h = require('account-details')
+
+module.exports = {
+ Modal,
+ BuyModal,
+} \ No newline at end of file
diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js
new file mode 100644
index 000000000..006e009b3
--- /dev/null
+++ b/ui/app/components/modals/modal.js
@@ -0,0 +1,100 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const FadeModal = require('boron').FadeModal
+const actions = require('../../actions')
+const isMobileView = require('../../../lib/is-mobile-view')
+const isPopupOrNotification = require('../../../../app/scripts/lib/is-popup-or-notification')
+
+function mapStateToProps (state) {
+ return {
+ active: state.appState.modalOpen
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ hideModal: () => {
+ dispatch(actions.hideModal())
+ },
+ }
+}
+
+// Global Modal Component
+inherits(Modal, Component)
+function Modal () {
+ Component.call(this)
+}
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(Modal)
+
+const mobileModalStyles = {
+ width: '95%',
+ // Used to create matching t/l/r/b space in mobile view.
+ top: isPopupOrNotification() === 'popup' ? '48vh' : '36.5vh',
+ boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px',
+}
+
+const laptopModalStyles = {
+ width: '66%',
+ top: 'calc(30% + 10px)',
+ boxShadow: 'rgba(0, 0, 0, 0.15) 0px 2px 2px 2px',
+}
+
+const backdropStyles = {
+ backgroundColor: 'rgba(245, 245, 245, 0.85)',
+}
+
+Modal.prototype.render = function () {
+
+ return h(FadeModal,
+ {
+ className: 'modal',
+ keyboard: false,
+ onHide: () => {this.onHide()},
+ ref: (ref) => {
+ this.modalRef = ref
+ },
+ modalStyle: isMobileView() ? mobileModalStyles : laptopModalStyles,
+ backdropStyle: backdropStyles,
+ },
+ this.props.children,
+ )
+}
+
+Modal.prototype.componentWillReceiveProps = function(nextProps) {
+ if (nextProps.active) {
+ this.show()
+ } else if (this.props.active) {
+ this.hide()
+ }
+}
+
+Modal.prototype.onHide = function() {
+ if (this.props.onHideCallback) {
+ this.props.onHideCallback()
+ }
+ this.props.hideModal()
+}
+
+Modal.prototype.hide = function() {
+ this.modalRef.hide()
+}
+
+Modal.prototype.show = function() {
+ this.modalRef.show()
+}
+
+// TODO: specify default props and proptypes
+// Modal.defaultProps = {}
+
+// const elementType = require('react-prop-types/lib/elementType')
+// const PropTypes from 'prop-types'
+
+// Modal.propTypes = {
+// active: PropTypes.bool,
+// hideModal: PropTypes.func.isRequired,
+// component: elementType,
+// onHideCallback: PropTypes.func,
+// }
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index 698a0bbb9..ba1d0ea11 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -60,7 +60,7 @@ Network.prototype.render = function () {
}
return (
- h('#network_component.pointer', {
+ h('.network-component.pointer', {
title: hoverText,
onClick: (event) => this.props.onClick(event),
}, [
diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js
index 5324ccd64..1c47440f2 100644
--- a/ui/app/components/pending-tx.js
+++ b/ui/app/components/pending-tx.js
@@ -20,6 +20,34 @@ const GWEI_FACTOR = new BN(1e9)
const MIN_GAS_PRICE_BN = MIN_GAS_PRICE_GWEI_BN.mul(GWEI_FACTOR)
const MIN_GAS_LIMIT_BN = new BN(21000)
+
+// Faked, for Icon
+const Identicon = require('./identicon')
+const ARAGON = '960b236A07cf122663c4303350609A66A7B288C0'
+
+// Next: create separate react components
+// roughly 5 components:
+// heroIcon
+// numericDisplay (contains symbol + currency)
+// divider
+// contentBox
+// actionButtons
+const sectionDivider = h('div', {
+ style: {
+ height:'1px',
+ background:'#E7E7E7',
+ },
+})
+
+const contentDivider = h('div', {
+ style: {
+ marginLeft: '16px',
+ marginRight: '16px',
+ height:'1px',
+ background:'#E7E7E7',
+ },
+})
+
module.exports = PendingTx
inherits(PendingTx, Component)
function PendingTx () {
@@ -70,344 +98,342 @@ PendingTx.prototype.render = function () {
this.inputs = []
return (
-
- h('div', {
- key: txMeta.id,
+ h('div.flex-column.flex-grow', {
+ style: {
+ // overflow: 'scroll',
+ minWidth: '355px', // TODO: maxWidth TBD, use home.html
+ },
}, [
- h('form#pending-tx-form', {
- onSubmit: this.onSubmit.bind(this),
-
+ // Main Send token Card
+ h('div.send-screen.flex-column.flex-grow', {
+ style: {
+ marginLeft: '3.5%',
+ marginRight: '3.5%',
+ background: '#FFFFFF', // $background-white
+ boxShadow: '0 2px 4px 0 rgba(0,0,0,0.08)',
+ }
}, [
+ h('section.flex-center.flex-row', {
+ style: {
+ zIndex: 15, // $token-icon-z-index
+ marginTop: '-35px',
+ }
+ }, [
+ h(Identicon, {
+ address: ARAGON,
+ diameter: 76,
+ }),
+ ]),
- // tx info
- h('div', [
+ //
+ // Required Fields
+ //
- h('.flex-row.flex-center', {
- style: {
- maxWidth: '100%',
- },
- }, [
+ h('h3.flex-center', {
+ style: {
+ marginTop: '-18px',
+ fontSize: '16px',
+ },
+ }, [
+ 'Confirm Transaction',
+ ]),
- h(MiniAccountPanel, {
- imageSeed: address,
- picOrder: 'right',
- }, [
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
- },
- }, identity.name),
-
- h(Copyable, {
- value: ethUtil.toChecksumAddress(address),
- }, [
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Light, Montserrat, sans-serif',
- },
- }, addressSummary(address, 6, 4, false)),
- ]),
-
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Light, Montserrat, sans-serif',
- },
- }, [
- h(EthBalance, {
- value: balance,
- conversionRate,
- currentCurrency,
- inline: true,
- labelColor: '#F7861C',
- }),
- ]),
- ]),
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ fontSize: '12px',
+ },
+ }, [
+ 'You\'re sending to Recipient ...5924',
+ ]),
- forwardCarrat(),
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ fontSize: '36px',
+ marginTop: '8px',
+ },
+ }, [
+ '0.24',
+ ]),
- this.miniAccountPanelForRecipient(),
- ]),
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ fontSize: '12px',
+ marginTop: '4px',
+ },
+ }, [
+ 'ANT',
+ ]),
- h('style', `
- .table-box {
- margin: 7px 0px 0px 0px;
- width: 100%;
- }
- .table-box .row {
- margin: 0px;
- background: rgb(236,236,236);
- display: flex;
- justify-content: space-between;
- font-family: Montserrat Light, sans-serif;
- font-size: 13px;
- padding: 5px 25px;
- }
- .table-box .row .value {
- font-family: Montserrat Regular;
- }
- `),
+ // error message
+ props.error && h('span.error.flex-center', props.error),
- h('.table-box', [
+ sectionDivider,
- // Ether Value
- // Currently not customizable, but easily modified
- // in the way that gas and gasLimit currently are.
- h('.row', [
- h('.cell.label', 'Amount'),
- h(EthBalance, { value: txParams.value, currentCurrency, conversionRate }),
- ]),
+ h('section.flex-row.flex-center', {
+ }, [
+ h('div', {
+ style: {
+ width: '50%',
+ }
+ }, [
+ h('span', {
+ style: {
+ textAlign: 'left',
+ fontSize: '12px',
+ }
+ }, [
+ 'From'
+ ])
+ ]),
- // Gas Limit (customizable)
- h('.cell.row', [
- h('.cell.label', 'Gas Limit'),
- h('.cell.value', {
- }, [
- h(BNInput, {
- name: 'Gas Limit',
- value: gasBn,
- precision: 0,
- scale: 0,
- // The hard lower limit for gas.
- min: MIN_GAS_LIMIT_BN.toString(10),
- max: safeGasLimit,
- suffix: 'UNITS',
- style: {
- position: 'relative',
- top: '5px',
- },
- onChange: this.gasLimitChanged.bind(this),
-
- ref: (hexInput) => { this.inputs.push(hexInput) },
- }),
- ]),
- ]),
+ h('div', {
+ style: {
+ width: '50%',
+ }
+ },[
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '10px',
+ marginBottom: '-10px',
+ },
+ }, 'Aragon Token'),
- // Gas Price (customizable)
- h('.cell.row', [
- h('.cell.label', 'Gas Price'),
- h('.cell.value', {
- }, [
- h(BNInput, {
- name: 'Gas Price',
- value: gasPriceBn,
- precision: 9,
- scale: 9,
- suffix: 'GWEI',
- min: MIN_GAS_PRICE_GWEI_BN.toString(10),
- style: {
- position: 'relative',
- top: '5px',
- },
- onChange: this.gasPriceChanged.bind(this),
- ref: (hexInput) => { this.inputs.push(hexInput) },
- }),
- ]),
- ]),
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '8px',
+ },
+ }, 'Your Balance 2.34 ANT')
+ ])
+ ]),
- // Max Transaction Fee (calculated)
- h('.cell.row', [
- h('.cell.label', 'Max Transaction Fee'),
- h(EthBalance, { value: txFeeBn.toString(16), currentCurrency, conversionRate }),
- ]),
+ contentDivider,
- h('.cell.row', {
+ h('section.flex-row.flex-center', {
+ }, [
+ h('div', {
+ style: {
+ width: '50%',
+ }
+ }, [
+ h('span', {
style: {
- fontFamily: 'Montserrat Regular',
- background: 'white',
- padding: '10px 25px',
- },
+ textAlign: 'left',
+ fontSize: '12px',
+ }
}, [
- h('.cell.label', 'Max Total'),
- h('.cell.value', {
- style: {
- display: 'flex',
- alignItems: 'center',
- },
- }, [
- h(EthBalance, {
- value: maxCost.toString(16),
- currentCurrency,
- conversionRate,
- inline: true,
- labelColor: 'black',
- fontSize: '16px',
- }),
- ]),
- ]),
+ 'To'
+ ])
+ ]),
- // Data size row:
- h('.cell.row', {
+ h('div', {
+ style: {
+ width: '50%',
+ }
+ },[
+ h('div', {
style: {
- background: '#f7f7f7',
- paddingBottom: '0px',
+ textAlign: 'left',
+ fontSize: '10px',
+ marginBottom: '-10px',
},
- }, [
- h('.cell.label'),
- h('.cell.value', {
- style: {
- fontFamily: 'Montserrat Light',
- fontSize: '11px',
- },
- }, `Data included: ${dataLength} bytes`),
- ]),
- ]), // End of Table
+ }, 'Ethereum Address'),
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '8px',
+ },
+ }, '...5924')
+ ])
]),
- h('style', `
- .conf-buttons button {
- margin-left: 10px;
- text-transform: uppercase;
- }
- `),
+ contentDivider,
- txMeta.simulationFails ?
- h('.error', {
- style: {
- marginLeft: 50,
- fontSize: '0.9em',
- },
- }, 'Transaction Error. Exception thrown in contract code.')
- : null,
-
- !isValidAddress ?
- h('.error', {
+ h('section.flex-row.flex-center', {
+ }, [
+ h('div', {
style: {
- marginLeft: 50,
- fontSize: '0.9em',
- },
- }, 'Recipient address is invalid. Sending this transaction will result in a loss of ETH.')
- : null,
-
- insufficientBalance ?
- h('span.error', {
+ width: '50%',
+ }
+ }, [
+ h('span', {
+ style: {
+ textAlign: 'left',
+ fontSize: '12px',
+ }
+ }, [
+ 'Gas Fee'
+ ])
+ ]),
+
+ h('div', {
style: {
- marginLeft: 50,
- fontSize: '0.9em',
- },
- }, 'Insufficient balance for transaction')
- : null,
-
- // send + cancel
- h('.flex-row.flex-space-around.conf-buttons', {
+ width: '50%',
+ }
+ },[
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '10px',
+ marginBottom: '-10px',
+ },
+ }, '$0.04 USD'),
+
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '8px',
+ },
+ }, '0.001575 ETH')
+ ])
+ ]),
+
+ contentDivider,
+
+ h('section.flex-row.flex-center', {
style: {
- display: 'flex',
- justifyContent: 'flex-end',
- margin: '14px 25px',
- },
+ backgroundColor: '#F6F6F6', // $wild-sand
+ borderRadius: '8px',
+ marginLeft: '10px',
+ marginRight: '10px',
+ paddingLeft: '6px',
+ paddingRight: '6px',
+ marginBottom: '10px',
+ }
}, [
+ h('div', {
+ style: {
+ width: '50%',
+ }
+ }, [
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '12px',
+ marginBottom: '-10px',
+ }
+ }, [
+ 'Total Tokens'
+ ]),
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '8px',
+ }
+ }, [
+ 'Total Gas'
+ ])
- insufficientBalance ?
- h('button.btn-green', {
- onClick: props.buyEth,
- }, 'Buy Ether')
- : null,
-
- h('button', {
- onClick: (event) => {
- this.resetGasFields()
- event.preventDefault()
- },
- }, 'Reset'),
-
- // Accept Button
- h('input.confirm.btn-green', {
- type: 'submit',
- value: 'SUBMIT',
- style: { marginLeft: '10px' },
- disabled: insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting,
- }),
+ ]),
- h('button.cancel.btn-red', {
- onClick: props.cancelTransaction,
- }, 'Reject'),
- ]),
- ]),
- ])
- )
-}
+ h('div', {
+ style: {
+ width: '50%',
+ }
+ },[
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '10px',
+ marginBottom: '-10px',
+ },
+ }, '0.24 ANT (127.00 USD)'),
-PendingTx.prototype.miniAccountPanelForRecipient = function () {
- const props = this.props
- const txData = props.txData
- const txParams = txData.txParams || {}
- const isContractDeploy = !('to' in txParams)
-
- // If it's not a contract deploy, send to the account
- if (!isContractDeploy) {
- return h(MiniAccountPanel, {
- imageSeed: txParams.to,
- picOrder: 'left',
- }, [
+ h('div', {
+ style: {
+ textAlign: 'left',
+ fontSize: '8px',
+ },
+ }, '0.249 ETH')
+ ])
+ ]),
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
- },
- }, nameForAddress(txParams.to, props.identities)),
+ ]), // end of container
- h(Copyable, {
- value: ethUtil.toChecksumAddress(txParams.to),
+ h('form#pending-tx-form.flex-column.flex-center', {
+ onSubmit: this.onSubmit.bind(this),
}, [
- h('span.font-small', {
+ // Reset Button
+ // h('button', {
+ // onClick: (event) => {
+ // this.resetGasFields()
+ // event.preventDefault()
+ // },
+ // }, 'Reset'),
+
+ // Accept Button
+ h('input.confirm.btn-green', {
+ type: 'submit',
+ value: 'CONFIRM',
style: {
- fontFamily: 'Montserrat Light, Montserrat, sans-serif',
+ marginTop: '8px',
+ width: '8em',
+ color: '#FFFFFF',
+ borderRadius: '2px',
+ fontSize: '12px',
+ lineHeight: '20px',
+ textAlign: 'center',
+ borderStyle: 'none',
},
- }, addressSummary(txParams.to, 6, 4, false)),
- ]),
-
- ])
- } else {
- return h(MiniAccountPanel, {
- picOrder: 'left',
- }, [
+ disabled: insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting,
+ }),
- h('span.font-small', {
- style: {
- fontFamily: 'Montserrat Bold, Montserrat, sans-serif',
- },
- }, 'New Contract'),
-
- ])
- }
-}
-
-PendingTx.prototype.gasPriceChanged = function (newBN, valid) {
- log.info(`Gas price changed to: ${newBN.toString(10)}`)
- const txMeta = this.gatherTxMeta()
- txMeta.txParams.gasPrice = '0x' + newBN.toString('hex')
- this.setState({
- txData: clone(txMeta),
- valid,
- })
-}
-
-PendingTx.prototype.gasLimitChanged = function (newBN, valid) {
- log.info(`Gas limit changed to ${newBN.toString(10)}`)
- const txMeta = this.gatherTxMeta()
- txMeta.txParams.gas = '0x' + newBN.toString('hex')
- this.setState({
- txData: clone(txMeta),
- valid,
- })
+ // Cancel Button
+ h('button.cancel.btn-light', {
+ style: {
+ background: '#F7F7F7', // $alabaster
+ border: 'none',
+ opacity: 1,
+ width: '8em',
+ },
+ onClick: props.cancelTransaction,
+ }, 'CANCEL'),
+ ]),
+ ]) // end of minwidth wrapper
+ )
}
-PendingTx.prototype.resetGasFields = function () {
- log.debug(`pending-tx resetGasFields`)
-
- this.inputs.forEach((hexInput) => {
- if (hexInput) {
- hexInput.setValid()
- }
- })
-
- this.setState({
- txData: null,
- valid: true,
- })
-}
+// PendingTx.prototype.gasPriceChanged = function (newBN, valid) {
+// log.info(`Gas price changed to: ${newBN.toString(10)}`)
+// const txMeta = this.gatherTxMeta()
+// txMeta.txParams.gasPrice = '0x' + newBN.toString('hex')
+// this.setState({
+// txData: clone(txMeta),
+// valid,
+// })
+// }
+
+// PendingTx.prototype.gasLimitChanged = function (newBN, valid) {
+// log.info(`Gas limit changed to ${newBN.toString(10)}`)
+// const txMeta = this.gatherTxMeta()
+// txMeta.txParams.gas = '0x' + newBN.toString('hex')
+// this.setState({
+// txData: clone(txMeta),
+// valid,
+// })
+// }
+
+// PendingTx.prototype.resetGasFields = function () {
+// log.debug(`pending-tx resetGasFields`)
+
+// this.inputs.forEach((hexInput) => {
+// if (hexInput) {
+// hexInput.setValid()
+// }
+// })
+
+// this.setState({
+// txData: null,
+// valid: true,
+// })
+// }
PendingTx.prototype.onSubmit = function (event) {
event.preventDefault()
@@ -466,15 +492,3 @@ PendingTx.prototype.bnMultiplyByFraction = function (targetBN, numerator, denomi
const denomBN = new BN(denominator)
return targetBN.mul(numBN).div(denomBN)
}
-
-function forwardCarrat () {
- return (
- h('img', {
- src: 'images/forward-carrat.svg',
- style: {
- padding: '5px 6px 0px 10px',
- height: '37px',
- },
- })
- )
-}
diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js
new file mode 100644
index 000000000..74d46728c
--- /dev/null
+++ b/ui/app/components/tx-list.js
@@ -0,0 +1,166 @@
+const Component = require('react').Component
+const connect = require('react-redux').connect
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const selectors = require('../selectors')
+const Identicon = require('./identicon')
+
+const valuesFor = require('../util').valuesFor
+
+module.exports = connect(mapStateToProps)(TxList)
+
+function mapStateToProps (state) {
+ return {
+ txsToRender: selectors.transactionsSelector(state),
+ conversionRate: selectors.conversionRateSelector(state),
+ }
+}
+
+inherits(TxList, Component)
+function TxList () {
+ Component.call(this)
+}
+
+const contentDivider = h('div.tx-list-content-divider', {
+ style: {},
+})
+
+TxList.prototype.render = function () {
+
+ const { txsToRender, conversionRate } = this.props
+
+ console.log('transactions to render', txsToRender)
+
+ return h('div.flex-column.tx-list-container', {}, [
+
+ h('div.flex-row.tx-list-header-wrapper', {
+ style: {},
+ }, [
+
+ h('div.flex-row.tx-list-header', {
+ }, [
+
+ h('div', {
+ style: {}
+ }, 'TRANSACTIONS'),
+
+ ]),
+
+ ]),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ this.renderTransactionListItem(),
+
+ contentDivider,
+
+ ])
+}
+
+TxList.prototype.renderTransactionListItem = function () {
+ // fake data
+ const props = {
+ dateString: 'Jul 01, 2017',
+ address: '0x82df11beb942beeed58d466fcb0f0791365c7684',
+ transactionStatus: 'Confirmed',
+ transactionAmount: '+ 3 ETH'
+ }
+
+ const { address, transactionStatus, transactionAmount, dateString } = props
+
+ return h('div.flex-column.tx-list-item-wrapper', {
+ style: {}
+ }, [
+
+ h('div.tx-list-date-wrapper', {
+ style: {}
+ }, [
+ h('span.tx-list-date', {}, [
+ dateString,
+ ])
+ ]),
+
+ h('div.flex-row.tx-list-content-wrapper', {
+ style: {}
+ }, [
+
+ h('div.tx-list-identicon-wrapper', {
+ style: {}
+ }, [
+ h(Identicon, {
+ address,
+ diameter: 24,
+ })
+ ]),
+
+ h('div.tx-list-account-and-status-wrapper', {}, [
+ h('div.tx-list-account-wrapper', {
+ style: {}
+ }, [
+ h('span.tx-list-account', {}, [
+ '0x82df11be...7684', //address
+ ]),
+ ]),
+
+ h('div.tx-list-status-wrapper', {
+ style: {}
+ }, [
+ h('span.tx-list-status', {}, [
+ transactionStatus,
+ ]),
+ ]),
+ ]),
+
+ h('div.flex-column.tx-list-details-wrapper', {
+ style: {}
+ }, [
+
+ h('span.tx-list-value', {}, [
+ transactionAmount,
+ ]),
+
+ h('span.tx-list-fiat-value', {}, [
+ '+ $300 USD',
+ ]),
+
+ ]),
+ ])
+ ])
+}
+
diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js
new file mode 100644
index 000000000..0d1f3fc31
--- /dev/null
+++ b/ui/app/components/tx-view.js
@@ -0,0 +1,124 @@
+const Component = require('react').Component
+const connect = require('react-redux').connect
+const h = require('react-hyperscript')
+const ethUtil = require('ethereumjs-util')
+const inherits = require('util').inherits
+const actions = require('../actions')
+
+const WalletView = require('./wallet-view')
+const BalanceComponent = require('./balance-component')
+const TxList = require('./tx-list')
+const Identicon = require('./identicon')
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(TxView)
+
+function mapStateToProps (state) {
+ const sidebarOpen = state.appState.sidebarOpen
+
+ const identities = state.metamask.identities
+ const accounts = state.metamask.accounts
+ const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
+ const checksumAddress = selectedAddress && ethUtil.toChecksumAddress(selectedAddress)
+ const identity = identities[selectedAddress]
+ const account = accounts[selectedAddress]
+
+ return {
+ sidebarOpen,
+ selectedAddress,
+ checksumAddress,
+ identity,
+ account,
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ showSidebar: () => { dispatch(actions.showSidebar()) },
+ hideSidebar: () => { dispatch(actions.hideSidebar()) },
+ showModal: () => { dispatch(actions.showModal()) },
+ }
+}
+
+inherits(TxView, Component)
+function TxView () {
+ Component.call(this)
+}
+
+TxView.prototype.render = function () {
+
+ const { selectedAddress, identity, account } = this.props
+
+ return h('div.tx-view.flex-column', {
+ style: {},
+ }, [
+
+ h('div.flex-row.phone-visible', {
+ style: {
+ margin: '1em 0.9em',
+ alignItems: 'center',
+ },
+ onClick: () => {
+ this.props.sidebarOpen ? this.props.hideSidebar() : this.props.showSidebar()
+ },
+ }, [
+
+ h('div.fa.fa-bars', {
+ style: {
+ fontSize: '1.3em',
+ },
+ }, []),
+
+ h('.identicon-wrapper.select-none', {
+ style: {
+ marginLeft: '0.9em',
+ },
+ }, [
+ h(Identicon, {
+ diameter: 24,
+ address: selectedAddress,
+ }),
+ ]),
+
+ h('span.account-name', {
+ style: {},
+ }, [
+ identity.name,
+ ]),
+
+ ]),
+
+ h('div.hero-balance', {
+ style: {},
+ }, [
+
+ h(BalanceComponent, {
+ balanceValue: account && account.balance,
+ style: {},
+ }),
+
+ h('div.flex-row.flex-center.hero-balance-buttons', {
+ style: {},
+ }, [
+ h('button.btn-clear', {
+ style: {
+ textAlign: 'center',
+ },
+ onClick: () => {
+ this.props.showModal()
+ },
+ }, 'BUY'),
+
+ h('button.btn-clear', {
+ style: {
+ textAlign: 'center',
+ marginLeft: '1.4em',
+ },
+ }, 'SEND'),
+
+ ]),
+ ]),
+
+ h(TxList, {}),
+
+ ])
+}
diff --git a/ui/app/components/wallet-content-display.js b/ui/app/components/wallet-content-display.js
new file mode 100644
index 000000000..3baffad69
--- /dev/null
+++ b/ui/app/components/wallet-content-display.js
@@ -0,0 +1,56 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+
+module.exports = WalletContentDisplay
+
+inherits(WalletContentDisplay, Component)
+function WalletContentDisplay () {
+ Component.call(this)
+}
+
+WalletContentDisplay.prototype.render = function () {
+ const { title, amount, fiatValue, active, style } = this.props
+
+ // TODO: Separate component: wallet-content-account
+ return h('div.flex-column', {
+ style: {
+ marginLeft: '1.3em',
+ alignItems: 'flex-start',
+ ...style,
+ }
+ }, [
+
+ h('span', {
+ style: {
+ fontSize: '1.1em',
+ },
+ }, title),
+
+ h('span', {
+ style: {
+ fontSize: '1.8em',
+ margin: '0.4em 0em',
+ },
+ }, amount),
+
+ h('span', {
+ style: {
+ fontSize: '1.3em',
+ },
+ }, fiatValue),
+
+ active && h('div', {
+ style: {
+ position: 'absolute',
+ marginLeft: '-1.3em',
+ height: '6em',
+ width: '0.3em',
+ background: '#D8D8D8', // TODO: add to resuable colors
+ }
+ }, [
+ ])
+ ])
+
+}
+
diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js
new file mode 100644
index 000000000..6bde2d9f4
--- /dev/null
+++ b/ui/app/components/wallet-view.js
@@ -0,0 +1,172 @@
+const Component = require('react').Component
+const connect = require('react-redux').connect
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const Identicon = require('./identicon')
+const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns
+const Content = require('./wallet-content-display')
+const actions = require('../actions')
+const BalanceComponent = require('./balance-component')
+const selectors = require('../selectors')
+
+module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView)
+
+function mapStateToProps (state) {
+
+ return {
+ network: state.metamask.network,
+ sidebarOpen: state.appState.sidebarOpen,
+ identities: state.metamask.identities,
+ accounts: state.metamask.accounts,
+ selectedAddress: selectors.getSelectedAddress(state),
+ selectedIdentity: selectors.getSelectedIdentity(state),
+ selectedAccount: selectors.getSelectedAccount(state),
+ }
+}
+
+function mapDispatchToProps (dispatch) {
+ return {
+ showSendPage: () => {dispatch(actions.showSendPage())},
+ hideSidebar: () => {dispatch(actions.hideSidebar())},
+ }
+}
+
+inherits(WalletView, Component)
+function WalletView () {
+ Component.call(this)
+}
+
+const noop = () => {}
+
+WalletView.prototype.render = function () {
+ const { network, responsiveDisplayClassname, style, identities, selectedAddress, selectedAccount } = this.props
+
+ // temporary logs + fake extra wallets
+ console.log(selectedAccount)
+
+ const extraWallet = h('div.flex-column.wallet-balance-wrapper', {}, [
+ h('div.wallet-balance', {}, [
+ h(BalanceComponent, {
+ balanceValue: selectedAccount.balance,
+ style: {},
+ }),
+ ]),
+ ])
+
+ return h('div.wallet-view.flex-column' + (responsiveDisplayClassname || ''), {
+ style: {},
+ }, [
+
+ // TODO: Separate component: wallet account details
+ h('div.flex-column.wallet-view-account-details', {
+ style: {}
+ }, [
+
+ h('div.flex-row.account-options-menu', {
+ style: {
+ position: 'relative',
+ },
+ }, [
+
+ h(AccountDropdowns, {
+ selected: selectedAddress,
+ network,
+ identities,
+ useCssTransition: true,
+ enableAccountOptions: true,
+ dropdownWrapperStyle: {
+ padding: '1px 15px',
+ marginLeft: '-25px',
+ position: 'absolute',
+ width: '122%', //TODO, refactor all of this component out into media queries
+ },
+ menuItemStyles: {
+ padding: '0px 0px',
+ margin: '22px 0px',
+ }
+ }, []),
+
+ ]),
+
+ h('div.flex-column.flex-center', {
+ }, [
+ h('div', {
+ style: {
+ position: 'relative',
+ }
+ }, [
+ h(AccountDropdowns, {
+ style: {
+ position: 'absolute',
+ left: 'calc(50% + 28px + 5.5px)',
+ top: '14px',
+ },
+ useCssTransition: true,
+ selected: selectedAddress,
+ network,
+ identities,
+ enableAccountsSelector: true,
+ }, []),
+ ]),
+
+ h(Identicon, {
+ diameter: 54,
+ address: selectedAddress,
+ }),
+
+ h('span.account-name', {
+ style: {}
+ }, [
+ 'Account 1'
+ ]),
+
+ ]),
+ ]),
+
+ //'Wallet' - Title
+ // Not visible on mobile
+ h('div.flex-column.wallet-view-title-wrapper', {}, [
+ h('span.wallet-view-title', {}, [
+ 'Wallet',
+ ])
+ ]),
+
+ //Wallet Balances
+ h('div.flex-column.wallet-balance-wrapper.wallet-balance-wrapper-active', {}, [
+
+ h('div.wallet-balance', {}, [
+
+ h(BalanceComponent, {
+ balanceValue: selectedAccount.balance,
+ style: {},
+ }),
+
+ ]),
+
+ ]),
+
+ h('div.flex-column.wallet-balance-wrapper', {}, [
+
+ h('div.wallet-balance', {}, [
+
+ h(BalanceComponent, {
+ balanceValue: selectedAccount.balance,
+ style: {},
+ }),
+
+ ]),
+
+ ]),
+
+ extraWallet,
+ extraWallet,
+ extraWallet,
+ extraWallet,
+ extraWallet,
+ extraWallet,
+ extraWallet,
+ extraWallet,
+ extraWallet,
+ extraWallet,
+ ])
+}
diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js
index 34727ff78..4a8c616e2 100644
--- a/ui/app/conf-tx.js
+++ b/ui/app/conf-tx.js
@@ -52,66 +52,25 @@ ConfirmTxScreen.prototype.render = function () {
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
if (unconfTxList.length === 0) return h(Loading, { isLoading: true })
- return (
-
- h('.flex-column.flex-grow', [
-
- // subtitle and nav
- h('.section-title.flex-row.flex-center', [
- !isNotification ? h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
- onClick: this.goHome.bind(this),
- }) : null,
- h('h2.page-subtitle', 'Confirm Transaction'),
- isNotification ? h(NetworkIndicator, {
- network: network,
- provider: provider,
- }) : null,
- ]),
-
- h('h3', {
- style: {
- alignSelf: 'center',
- display: unconfTxList.length > 1 ? 'block' : 'none',
- },
- }, [
- h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
- style: {
- display: props.index === 0 ? 'none' : 'inline-block',
- },
- onClick: () => props.dispatch(actions.previousTx()),
- }),
- ` ${props.index + 1} of ${unconfTxList.length} `,
- h('i.fa.fa-arrow-right.fa-lg.cursor-pointer', {
- style: {
- display: props.index + 1 === unconfTxList.length ? 'none' : 'inline-block',
- },
- onClick: () => props.dispatch(actions.nextTx()),
- }),
- ]),
-
- warningIfExists(props.warning),
-
- currentTxView({
- // Properties
- txData: txData,
- key: txData.id,
- selectedAddress: props.selectedAddress,
- accounts: props.accounts,
- identities: props.identities,
- conversionRate,
- currentCurrency,
- blockGasLimit,
- // Actions
- buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress),
- sendTransaction: this.sendTransaction.bind(this),
- cancelTransaction: this.cancelTransaction.bind(this, txData),
- signMessage: this.signMessage.bind(this, txData),
- signPersonalMessage: this.signPersonalMessage.bind(this, txData),
- cancelMessage: this.cancelMessage.bind(this, txData),
- cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
- }),
- ])
- )
+ return currentTxView({
+ // Properties
+ txData: txData,
+ key: txData.id,
+ selectedAddress: props.selectedAddress,
+ accounts: props.accounts,
+ identities: props.identities,
+ conversionRate,
+ currentCurrency,
+ blockGasLimit,
+ // Actions
+ buyEth: this.buyEth.bind(this, txParams.from || props.selectedAddress),
+ sendTransaction: this.sendTransaction.bind(this),
+ cancelTransaction: this.cancelTransaction.bind(this, txData),
+ signMessage: this.signMessage.bind(this, txData),
+ signPersonalMessage: this.signPersonalMessage.bind(this, txData),
+ cancelMessage: this.cancelMessage.bind(this, txData),
+ cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
+ })
}
function currentTxView (opts) {
diff --git a/ui/app/css/debug.css b/ui/app/css/debug.css
deleted file mode 100644
index 3e125bcd4..000000000
--- a/ui/app/css/debug.css
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-debug / dev
-*/
-
-#app-content {
- border: 2px solid green;
-}
-
-#design-container {
- position: absolute;
- left: 360px;
- top: -42px;
- width: calc(100vw - 360px);
- height: 100vh;
- overflow: scroll;
-}
-
-#design-container img {
- width: 2000px;
- margin-right: 600px;
-} \ No newline at end of file
diff --git a/ui/app/css/fonts.css b/ui/app/css/fonts.css
deleted file mode 100644
index 3b9f581b9..000000000
--- a/ui/app/css/fonts.css
+++ /dev/null
@@ -1,36 +0,0 @@
-@import url(https://fonts.googleapis.com/css?family=Roboto:300,500);
-@import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css);
-
-@font-face {
- font-family: 'Montserrat Regular';
- src: url('/fonts/Montserrat/Montserrat-Regular.woff') format('woff');
- src: url('/fonts/Montserrat/Montserrat-Regular.ttf') format('truetype');
- font-weight: normal;
- font-style: normal;
- font-size: 'small';
-
-}
-
-@font-face {
- font-family: 'Montserrat Bold';
- src: url('/fonts/Montserrat/Montserrat-Bold.woff') format('woff');
- src: url('/fonts/Montserrat/Montserrat-Bold.ttf') format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-
-@font-face {
- font-family: 'Montserrat Light';
- src: url('/fonts/Montserrat/Montserrat-Light.woff') format('woff');
- src: url('/fonts/Montserrat/Montserrat-Light.ttf') format('truetype');
- font-weight: normal;
- font-style: normal;
-}
-
-@font-face {
- font-family: 'Montserrat UltraLight';
- src: url('/fonts/Montserrat/Montserrat-UltraLight.woff') format('woff');
- src: url('/fonts/Montserrat/Montserrat-UltraLight.ttf') format('truetype');
- font-weight: normal;
- font-style: normal;
-}
diff --git a/ui/app/css/index.scss b/ui/app/css/index.scss
new file mode 100644
index 000000000..01899ccad
--- /dev/null
+++ b/ui/app/css/index.scss
@@ -0,0 +1,13 @@
+/*
+ ITCSS
+
+ http://www.creativebloq.com/web-design/manage-large-css-projects-itcss-101517528
+ https://www.xfive.co/blog/itcss-scalable-maintainable-css-architecture/
+ */
+@import './itcss/settings/index.scss';
+@import './itcss/tools/index.scss';
+@import './itcss/generic/index.scss';
+@import './itcss/base/index.scss';
+@import './itcss/objects/index.scss';
+@import './itcss/components/index.scss';
+@import './itcss/trumps/index.scss';
diff --git a/ui/app/css/itcss/base/index.scss b/ui/app/css/itcss/base/index.scss
new file mode 100644
index 000000000..baa6ea037
--- /dev/null
+++ b/ui/app/css/itcss/base/index.scss
@@ -0,0 +1 @@
+// Base
diff --git a/ui/app/css/itcss/components/buttons.scss b/ui/app/css/itcss/components/buttons.scss
new file mode 100644
index 000000000..9916db488
--- /dev/null
+++ b/ui/app/css/itcss/components/buttons.scss
@@ -0,0 +1,83 @@
+/*
+ Buttons
+ */
+
+.btn-green {
+ background-color: #02c9b1; // TODO: reusable color in colors.css
+}
+
+button.btn-clear {
+ background: $white;
+ border: 1px solid;
+}
+
+// No longer used in flat design, remove when modal buttons done
+// div.wallet-btn {
+// border: 1px solid rgb(91, 93, 103);
+// border-radius: 2px;
+// height: 30px;
+// width: 75px;
+// font-size: 0.8em;
+// text-align: center;
+// line-height: 25px;
+// }
+
+// .btn-red {
+// background: rgba(254, 35, 17, 1);
+// box-shadow: 0px 3px 6px rgba(254, 35, 17, 0.36);
+// }
+
+// button[disabled], input[type="submit"][disabled] {
+// cursor: not-allowed;
+// background: rgba(197, 197, 197, 1);
+// box-shadow: 0px 3px 6px rgba(197, 197, 197, 0.36);
+// }
+
+// button.spaced {
+// margin: 2px;
+// }
+
+// button:not([disabled]):hover, input[type="submit"]:not([disabled]):hover {
+// transform: scale(1.1);
+// }
+// button:not([disabled]):active, input[type="submit"]:not([disabled]):active {
+// transform: scale(0.95);
+// }
+
+button.primary {
+ padding: 8px 12px;
+ background: #f7861c;
+ box-shadow: 0 3px 6px rgba(247, 134, 28, .36);
+ color: $white;
+ font-size: 1.1em;
+ font-family: 'Montserrat Regular';
+ text-transform: uppercase;
+}
+
+.btn-light {
+ padding: 8px 12px;
+ // background: #FFFFFF; // $bg-white
+ box-shadow: 0 3px 6px rgba(247, 134, 28, .36);
+ color: #585d67; // TODO: make reusable light button color
+ font-size: 1.1em;
+ font-family: 'Montserrat Regular';
+ text-transform: uppercase;
+ text-align: center;
+ line-height: 20px;
+ border-radius: 2px;
+ border: 1px solid #979797; // #TODO: make reusable light border color
+ opacity: .5;
+}
+
+// TODO: cleanup: not used anywhere
+button.btn-thin {
+ border: 1px solid;
+ border-color: #4d4d4d;
+ color: #4d4d4d;
+ background: rgb(255, 174, 41);
+ border-radius: 4px;
+ min-width: 200px;
+ margin: 12px 0;
+ padding: 6px;
+ font-size: 13px;
+}
diff --git a/ui/app/css/itcss/components/footer.scss b/ui/app/css/itcss/components/footer.scss
new file mode 100644
index 000000000..000a53eed
--- /dev/null
+++ b/ui/app/css/itcss/components/footer.scss
@@ -0,0 +1,4 @@
+.app-footer {
+ padding-bottom: 10px;
+ align-items: center;
+}
diff --git a/ui/app/css/itcss/components/header.scss b/ui/app/css/itcss/components/header.scss
new file mode 100644
index 000000000..9434d0386
--- /dev/null
+++ b/ui/app/css/itcss/components/header.scss
@@ -0,0 +1,52 @@
+.app-header {
+ align-items: center;
+ visibility: visible;
+ background: $gallery;
+ padding: 6px 8px;
+ height: 12vh;
+ max-height: 60px;
+ position: relative;
+ z-index: 12;
+
+ @media screen and (max-width: 575px) {
+ position: fixed;
+ height: 34px;
+ width: 100%;
+ box-shadow: 0 2px 2px 1px rgba(0, 0, 0, .08);
+ z-index: 30;
+ }
+}
+
+.app-header h1 {
+ font-family: 'Montserrat Regular';
+ text-transform: uppercase;
+ color: #22232c; // $shark
+}
+
+h2.page-subtitle {
+ font-family: 'Montserrat Regular';
+ text-transform: uppercase;
+ color: #aeaeae;
+ font-size: 1em;
+ margin: 12px;
+}
+
+.network-component-wrapper {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+
+ @media screen and (min-width: 576px) {
+ margin-bottom: 1.8em;
+ }
+}
+
+.left-menu-wrapper {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+
+ @media screen and (min-width: 576px) {
+ margin-bottom: 1.8em;
+ }
+}
diff --git a/ui/app/css/itcss/components/hero-balance.scss b/ui/app/css/itcss/components/hero-balance.scss
new file mode 100644
index 000000000..ad7f5952f
--- /dev/null
+++ b/ui/app/css/itcss/components/hero-balance.scss
@@ -0,0 +1,107 @@
+.hero-balance {
+
+ @media screen and (max-width: $break-small) {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: center;
+ margin: .3em .9em 0;
+ height: 80vh;
+ max-height: 225px;
+ }
+
+ @media screen and (min-width: $break-large) {
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+ margin: 2.8em .9em .8em;
+ }
+
+ .balance-container {
+ display: flex;
+ margin: 0;
+ justify-content: flex-start;
+ align-items: center;
+
+ @media screen and (max-width: $break-small) {
+ flex-direction: column;
+ }
+
+ @media screen and (min-width: $break-large) {
+ flex-direction: row;
+ flex-grow: 3;
+ }
+ }
+
+ .balance-display {
+
+ @media screen and (max-width: $break-small) {
+ text-align: center;
+
+ .token-amount {
+ font-size: 175%;
+ margin-top: 12.5%;
+ }
+
+ .fiat-amount {
+ font-size: 115%;
+ margin-top: 8.5%;
+ color: #a0a0a0;
+ }
+ }
+
+ @media screen and (min-width: $break-large) {
+ margin-left: 3%;
+ justify-content: flex-start;
+ align-items: flex-start;
+
+ .token-amount {
+ font-size: 135%;
+ }
+
+ .fiat-amount {
+ margin-top: .25%;
+ font-size: 105%;
+ }
+ }
+ }
+
+ .balance-icon {
+ border-radius: 25px;
+ width: 45px;
+ height: 45px;
+ border: 1px solid $alto;
+ }
+
+ .hero-balance-buttons {
+
+ @media screen and (max-width: $break-small) {
+ width: 100%;
+ height: 100px; // needed a round number to set the heights of the buttons inside
+ }
+
+ @media screen and (min-width: $break-large) {
+ flex-grow: 2;
+ }
+
+ button.btn-clear {
+ font-size: 75%;
+ background: $white;
+ border: 1px solid;
+
+ @media screen and (max-width: $break-small) {
+ width: 28%;
+ height: 55%;
+ }
+
+ @media screen and (min-width: $break-large) {
+ width: 5%;
+ flex-grow: 2;
+ height: 4.2vh;
+ min-height: 28px;
+ font-size: .7em;
+ }
+ }
+ }
+}
diff --git a/ui/app/css/itcss/components/index.scss b/ui/app/css/itcss/components/index.scss
new file mode 100644
index 000000000..291e09007
--- /dev/null
+++ b/ui/app/css/itcss/components/index.scss
@@ -0,0 +1,21 @@
+@import './buttons.scss';
+
+@import './header.scss';
+
+@import './footer.scss';
+
+@import './network.scss';
+
+@import './modal.scss';
+
+@import './newui-sections.scss';
+
+// Balances
+@import './hero-balance.scss';
+
+@import './wallet-balance.scss';
+
+// Tx List and Sections
+@import './transaction-list.scss';
+
+@import './sections.scss';
diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss
new file mode 100644
index 000000000..8bf7cd44f
--- /dev/null
+++ b/ui/app/css/itcss/components/modal.scss
@@ -0,0 +1,128 @@
+.modal-content {
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ font-family: 'DIN OT';
+}
+
+@media screen and (max-width: 575px) {
+ .modal-content-title-wrapper {
+ justify-content: space-around;
+ width: 100%;
+ height: 100px;
+ }
+
+ .modal-content-title {
+ font-size: 26px;
+ margin-top: 15px;
+ }
+
+ .modal-content-options {
+ flex-direction: column;
+ padding: 5% 33%;
+ }
+
+ .modal-content-footer {
+ text-transform: uppercase;
+ width: 100%;
+ height: 50px;
+ }
+
+ div.modal-content-option {
+ display: flex;
+ flex-direction: column;
+ width: 80vw;
+ height: 15vh;
+ margin: 10px;
+ text-align: center;
+ border-radius: 6px;
+ border: 1px solid $black;
+ padding: 0% 7%;
+ justify-content: space-around;
+
+ div.modal-content-option-title {
+ font-size: 20px;
+ }
+
+ div.modal-content-option-subtitle {
+ font-size: 16px;
+ }
+ }
+}
+
+@media screen and (min-width: 576px) {
+ .modal-content-title-wrapper {
+ justify-content: space-around;
+ width: 100%;
+ height: 110px;
+ }
+
+ .modal-content-title {
+ font-size: 26px;
+ margin-top: 15px;
+ }
+
+ .modal-content-footer {
+ text-transform: uppercase;
+ width: 100%;
+ height: 50px;
+ }
+
+ .modal-content-options {
+ flex-direction: row;
+ margin: 20px 0;
+ }
+
+ div.modal-content-option {
+ display: flex;
+ flex-direction: column;
+ width: 20vw;
+ height: 18vw;
+ text-align: center;
+ border-radius: 6px;
+ border: 1px solid $black;
+ margin: 0 .5vw;
+ justify-content: space-around;
+
+ div.modal-content-option-title {
+ font-size: 20px;
+
+ @media screen and (max-width: 679px) {
+ font-size: 14px;
+ }
+
+ @media screen and (min-width: 1281px) {
+ font-size: 26px;
+ }
+ }
+
+ div.modal-content-option-subtitle {
+ font-size: 16px;
+ padding: 0 10px;
+ height: 25%;
+
+ @media screen and (max-width: 679px) {
+ font-size: 10px;
+ padding: 0 10px;
+ margin-bottom: 5px;
+ line-height: 15px;
+ }
+
+ @media screen and (min-width: 680px) {
+ font-size: 14px;
+ padding: 0 4px;
+ margin-bottom: 2px;
+ }
+
+ @media screen and (min-width: 1281px) {
+ font-size: 20px;
+ padding: 0;
+ }
+ }
+
+ div.modal-content-footer {
+ margin-top: 8vh;
+ }
+ }
+}
diff --git a/ui/app/css/itcss/components/network.scss b/ui/app/css/itcss/components/network.scss
new file mode 100644
index 000000000..aea5063f0
--- /dev/null
+++ b/ui/app/css/itcss/components/network.scss
@@ -0,0 +1,11 @@
+.network-indicator {
+ display: flex;
+ align-items: center;
+ font-size: .6em;
+}
+
+.network-name {
+ width: 5.2em;
+ line-height: 9px;
+ text-rendering: geometricPrecision;
+}
diff --git a/ui/app/css/itcss/components/newui-sections.scss b/ui/app/css/itcss/components/newui-sections.scss
new file mode 100644
index 000000000..7daf72bf2
--- /dev/null
+++ b/ui/app/css/itcss/components/newui-sections.scss
@@ -0,0 +1,166 @@
+/*
+ NewUI Container Elements
+ */
+
+// Component Colors
+$tx-view-bg: $white;
+$wallet-view-bg: $wild-sand;
+
+// Main container
+.main-container {
+ position: absolute;
+ z-index: 18;
+ font-family: "DIN OT";
+ display: flex;
+ flex-wrap: wrap;
+ align-items: stretch;
+ overflow-y: scroll;
+}
+
+// tx view
+
+.tx-view {
+ flex: 63.5 0 66.5%;
+ background: $tx-view-bg;
+}
+
+// wallet view and sidebar
+
+.wallet-view {
+ display: flex;
+ flex-direction: column;
+ flex: 33.5 0 33.5%;
+ background: $wallet-view-bg;
+
+ @media screen and (min-width: 576px) {
+ overflow-y: scroll;
+ }
+
+ .wallet-view-account-details {
+ flex: 0 0 150px;
+ }
+}
+
+.wallet-view-title-wrapper {
+ flex: 0 0 25px;
+}
+
+.wallet-view-title {
+ margin-left: 15px;
+ font-size: 16px;
+
+ // No title on mobile
+ @media screen and (max-width: 575px) {
+ display: none;
+ }
+}
+
+.wallet-view.sidebar {
+ flex: 1 0 230px;
+ background: rgb(250, 250, 250);
+ z-index: 26;
+ position: fixed;
+ top: 35px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ opacity: 1;
+ visibility: visible;
+ will-change: transform;
+ overflow-y: auto;
+ box-shadow: rgba(0, 0, 0, .15) 2px 2px 4px;
+ width: 85%;
+ height: 100%;
+}
+
+.sidebar-overlay {
+ z-index: 25;
+ position: fixed;
+ top: 35px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ opacity: 1;
+ visibility: visible;
+ background-color: rgba(0, 0, 0, .3);
+}
+
+// main-container media queries
+
+@media screen and (min-width: 576px) {
+ .lap-visible {
+ display: flex;
+ }
+
+ .phone-visible {
+ display: none;
+ }
+
+ .main-container {
+ margin-top: 35px;
+ width: 85%;
+ height: 90vh;
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08);
+ }
+}
+
+@media screen and (min-width: 769px) {
+ .main-container {
+ margin-top: 35px;
+ width: 80%;
+ height: 82vh;
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08);
+ }
+}
+
+@media screen and (min-width: 1281px) {
+ .main-container {
+ margin-top: 35px;
+ width: 65%;
+ height: 82vh;
+ box-shadow: 0 0 7px 0 rgba(0, 0, 0, .08);
+ }
+}
+
+@media screen and (max-width: 575px) {
+ .lap-visible {
+ display: none;
+ }
+
+ .phone-visible {
+ display: flex;
+ }
+
+ .main-container {
+ margin-top: 35px;
+ width: 100%;
+ }
+
+ button.btn-clear {
+ width: 93px;
+ height: 50px;
+ font-size: .7em;
+ background: $white;
+ border: 1px solid;
+ }
+}
+
+// wallet view
+.account-name {
+
+ @media screen and (max-width: 575px) {
+ font-size: 102%;
+ margin-left: 3%;
+ }
+
+ @media screen and (max-width: 575px) {
+ text-align: center;
+ }
+}
+
+// account options dropdown
+.account-options-menu {
+ align-items: center;
+ justify-content: flex-start;
+ margin: 5% 7%;
+}
diff --git a/ui/app/css/index.css b/ui/app/css/itcss/components/sections.scss
index 49b432a1f..5f0a034d8 100644
--- a/ui/app/css/index.css
+++ b/ui/app/css/itcss/components/sections.scss
@@ -1,222 +1,26 @@
-/*
-faint orange (textfield shades) #FAF6F0
-light orange (button shades): #F5C26D
-dark orange (text): #F5A623
-borders/font/any gray: #4A4A4A
-*/
-
-/*
-application specific styles
-*/
-
-* {
- box-sizing: border-box;
-}
-
-html, body {
- font-family: 'Montserrat Regular', Arial;
- color: #4D4D4D;
- font-weight: 300;
- line-height: 1.4em;
- background: #F7F7F7;
- margin: 0;
- padding: 0;
-}
-
-html {
- min-height: 500px;
-}
-
-.app-root {
- overflow: hidden;
- position: relative
-}
-
-.app-primary {
- display: flex;
-}
+// Old scss, do not lint - clean up later
+/* stylelint-disable */
-input:focus, textarea:focus {
- outline: none;
-}
-
-.full-size {
- height: 100%;
- width: 100%;
-}
-
-.full-width {
- width: 100%;
-}
-
-.full-height {
- height: 100%;
-}
-
-.full-flex-height {
- display: flex;
- flex: 1 1 auto;
- flex-direction: column;
-}
-
-#app-content {
- overflow-x: hidden;
- min-width: 357px;
- height: 100%;
- display: flex;
- flex-direction: column;
-}
-
-button, input[type="submit"] {
- font-family: 'Montserrat Bold';
- outline: none;
- cursor: pointer;
- padding: 8px 12px;
- border: none;
- color: white;
- transform-origin: center center;
- transition: transform 50ms ease-in;
- /* default orange */
- background: rgba(247, 134, 28, 1);
- box-shadow: 0px 3px 6px rgba(247, 134, 28, 0.36);
-}
-
-.btn-green, input[type="submit"].btn-green {
- background: rgba(106, 195, 96, 1);
- box-shadow: 0px 3px 6px rgba(106, 195, 96, 0.36);
-}
-
-.btn-red {
- background: rgba(254, 35, 17, 1);
- box-shadow: 0px 3px 6px rgba(254, 35, 17, 0.36);
-}
-
-button[disabled], input[type="submit"][disabled] {
- cursor: not-allowed;
- background: rgba(197, 197, 197, 1);
- box-shadow: 0px 3px 6px rgba(197, 197, 197, 0.36);
-}
-
-button.spaced {
- margin: 2px;
-}
-
-button:not([disabled]):hover, input[type="submit"]:not([disabled]):hover {
- transform: scale(1.1);
-}
-button:not([disabled]):active, input[type="submit"]:not([disabled]):active {
- transform: scale(0.95);
-}
-
-a {
- text-decoration: none;
- color: inherit;
-}
-
-a:hover{
- color: #df6b0e;
-}
/*
-app
+App Sections
+ TODO: Move into separate files.
*/
-.active {
- color: #909090;
-}
-
-button.primary {
- padding: 8px 12px;
- background: #F7861C;
- box-shadow: 0px 3px 6px rgba(247, 134, 28, 0.36);
- color: white;
- font-size: 1.1em;
- font-family: 'Montserrat Regular';
- text-transform: uppercase;
-}
-
-button.btn-thin {
- border: 1px solid;
- border-color: #4D4D4D;
- color: #4D4D4D;
- background: rgb(255, 174, 41);
- border-radius: 4px;
- min-width: 200px;
- margin: 12px 0;
- padding: 6px;
- font-size: 13px;
-}
-
-.app-header {
- padding: 6px 8px;
-}
-
-.app-header h1 {
- font-family: 'Montserrat Regular';
- text-transform: uppercase;
- color: #AEAEAE;
-}
-
-h2.page-subtitle {
- font-family: 'Montserrat Regular';
- text-transform: uppercase;
- color: #AEAEAE;
- font-size: 1em;
- margin: 12px;
-}
-
-.app-footer {
- padding-bottom: 10px;
- align-items: center;
-}
-
-.identicon {
- height: 46px;
- width: 46px;
- background-size: cover;
- border-radius: 100%;
- border: 3px solid gray;
-}
-
+/* initialize */
textarea.twelve-word-phrase {
padding: 12px;
width: 300px;
height: 140px;
font-size: 16px;
- background: white;
+ background: $white;
resize: none;
}
-.network-indicator {
- display: flex;
- align-items: center;
- font-size: 0.6em;
-
-}
-
-.network-name {
- width: 5.2em;
- line-height: 9px;
- text-rendering: geometricPrecision;
-}
-
-.check {
- margin-left: 12px;
- color: #F7861C;
- flex: 1 0 auto;
- display: flex;
- justify-content: flex-end;
-}
-/*
-app sections
-*/
-
-/* initialize */
-
.initialize-screen hr {
width: 60px;
margin: 12px;
- border-color: #F7861C;
+ border-color: #f7861c;
border-style: solid;
}
@@ -235,11 +39,11 @@ app sections
/* unlock */
.error {
- color: #E20202;
+ color: #e20202;
}
.warning {
- color: #FFAE00;
+ color: #ffae00;
}
.lock {
@@ -249,9 +53,10 @@ app sections
.lock.locked {
transform: scale(1.5);
- opacity: 0.0;
+ opacity: 0;
transition: opacity 400ms ease-in, transform 400ms ease-in;
}
+
.lock.unlocked {
transform: scale(1);
opacity: 1;
@@ -262,15 +67,18 @@ app sections
transform: scaleX(1) translateX(0);
transition: transform 250ms ease-in;
}
+
.lock.unlocked .lock-top {
transform: scaleX(-1) translateX(-12px);
transition: transform 250ms ease-in;
}
+
.lock.unlocked:hover {
border-radius: 4px;
background: #e5e5e5;
border: 1px solid #b1b1b1;
}
+
.lock.unlocked:active {
background: #c3c3c3;
}
@@ -290,55 +98,46 @@ app sections
.unlock-screen input[type=password] {
width: 260px;
- /*height: 36px;
- margin-bottom: 24px;
- padding: 8px;*/
}
-.sizing-input{
+.sizing-input {
font-size: 14px;
height: 30px;
padding-left: 5px;
}
-.editable-label{
+
+.editable-label {
display: flex;
}
+
/* Webkit */
+
.unlock-screen input::-webkit-input-placeholder {
text-align: center;
font-size: 1.2em;
}
+
/* Firefox 18- */
+
.unlock-screen input:-moz-placeholder {
text-align: center;
font-size: 1.2em;
}
+
/* Firefox 19+ */
+
.unlock-screen input::-moz-placeholder {
text-align: center;
font-size: 1.2em;
}
+
/* IE */
+
.unlock-screen input:-ms-input-placeholder {
text-align: center;
font-size: 1.2em;
}
-input.large-input, textarea.large-input {
- /*margin-bottom: 24px;*/
- padding: 8px;
-}
-
-input.large-input {
- height: 36px;
-}
-
-.letter-spacey {
- letter-spacing: 0.1em;
-}
-
-
-
/* accounts */
.accounts-section {
@@ -346,7 +145,7 @@ input.large-input {
}
.accounts-section .horizontal-line {
- margin: 0px 18px;
+ margin: 0 18px;
}
.accounts-list-option {
@@ -363,7 +162,7 @@ input.large-input {
}
.unconftx-link .fa-arrow-right {
- margin: 0px -8px 0px 8px;
+ margin: 0 -8px 0px 8px;
}
/* identity panel */
@@ -390,7 +189,7 @@ input.large-input {
.identity-panel i {
margin-top: 32px;
margin-right: 6px;
- color: #B9B9B9;
+ color: #b9b9b9;
}
.identity-panel .arrow-right {
@@ -401,34 +200,33 @@ input.large-input {
}
.identity-copy.flex-column {
- flex: 0.25 0 auto;
+ flex: .25 0 auto;
justify-content: center;
}
/* accounts screen */
.identity-section {
-
}
.identity-section .identity-panel {
- background: #E9E9E9;
- border-bottom: 1px solid #B1B1B1;
+ background: #e9e9e9;
+ border-bottom: 1px solid #b1b1b1;
cursor: pointer;
}
.identity-section .identity-panel.selected {
- background: white;
- color: #F3C83E;
+ background: $white;
+ color: #f3c83e;
}
.identity-section .identity-panel.selected .identicon {
- border-color: orange;
+ border-color: $orange;
}
.identity-section .accounts-list-option:hover,
.identity-section .accounts-list-option.selected {
- background:white;
+ background: $white;
}
/* account detail screen */
@@ -444,15 +242,14 @@ input.large-input {
flex-grow: 10;
}
-.name-label{
-
+.name-label {
}
.unapproved-tx-icon {
height: 16px;
width: 16px;
background: rgb(47, 174, 244);
- border-color: #AEAEAE;
+ border-color: $silver-chalice;
border-radius: 13px;
}
@@ -460,6 +257,7 @@ input.large-input {
height: 100%;
visibility: hidden;
}
+
.editing-label {
display: flex;
justify-content: flex-start;
@@ -467,8 +265,9 @@ input.large-input {
margin-bottom: 2px;
font-size: 11px;
text-rendering: geometricPrecision;
- color: #F7861C;
+ color: #f7861c;
}
+
.name-label:hover .edit-text {
visibility: visible;
}
@@ -480,18 +279,14 @@ input.large-input {
margin: 12px;
margin-bottom: 24px;
border-radius: 4px;
- border: 2px solid #F3C83E;
- background: #FAF6F0;
+ border: 2px solid #f3c83e;
+ background: #faf6f0;
}
/* Send Screen */
-.send-screen {
-
-}
-
.send-screen section {
- margin: 8px 16px;
+ margin: 4px 16px;
}
.send-screen input {
@@ -502,25 +297,25 @@ input.large-input {
/* Ether Balance Widget */
.ether-balance-amount {
- color: #F7861C;
+ color: #f7861c;
}
.ether-balance-label {
- color: #ABA9AA;
+ color: #aba9aa;
}
/* Info screen */
-.info-gray{
+.info-gray {
font-family: 'Montserrat Regular';
text-transform: uppercase;
- color: #AEAEAE;
+ color: $silver-chalice;
}
-.icon-size{
+.icon-size {
width: 20px;
}
-.info{
+.info {
font-family: 'Montserrat Regular', Arial;
padding-bottom: 10px;
display: inline-block;
@@ -533,7 +328,6 @@ input.large-input {
align-items: center;
}
-
.custom-radio-selected {
width: 17px;
height: 17px;
@@ -542,7 +336,7 @@ input.large-input {
border-radius: 15px;
border-width: 5px;
background: rgba(247, 134, 28, 1);
- border-color: #F7F7F7;
+ border-color: #f7f7f7;
}
.custom-radio-inactive {
@@ -551,38 +345,26 @@ input.large-input {
border: solid;
border-width: 1px;
border-radius: 24px;
- border-color: #AEAEAE;
+ border-color: $silver-chalice;
}
.radio-titles {
color: rgba(247, 134, 28, 1);
}
-.radio-titles-subtext {
-
-}
-
-.selected-exchange {
-
-}
-
-.buy-radio {
-
-}
-
-.eth-warning{
+.eth-warning {
transition: opacity 400ms ease-in, transform 400ms ease-in;
}
-.buy-subview{
+.buy-subview {
transition: opacity 400ms ease-in, transform 400ms ease-in;
}
-.input-container:hover .edit-text{
+.input-container:hover .edit-text {
visibility: visible;
}
-.buy-inputs{
+.buy-inputs {
font-family: 'Montserrat Light';
font-size: 13px;
height: 20px;
@@ -590,33 +372,32 @@ input.large-input {
box-sizing: border-box;
border: solid;
border-color: transparent;
- border-width: 0.5px;
+ border-width: .5px;
border-radius: 2px;
-
}
-.input-container:hover .buy-inputs{
+
+.input-container:hover .buy-inputs {
box-sizing: inherit;
border: solid;
- border-color: #F7861C;
- border-width: 0.5px;
+ border-color: #f7861c;
+ border-width: .5px;
border-radius: 2px;
}
-.buy-inputs:focus{
+.buy-inputs:focus {
border: solid;
- border-color: #F7861C;
- border-width: 0.5px;
+ border-color: #f7861c;
+ border-width: .5px;
border-radius: 2px;
}
.activeForm {
- background: #F7F7F7;
+ background: #f7f7f7;
border: none;
border-radius: 8px 8px 0px 0px;
width: 50%;
text-align: center;
padding-bottom: 4px;
-
}
.inactiveForm {
@@ -635,12 +416,12 @@ input.large-input {
width: 118px;
height: 42px;
padding: 1px;
- color: #4D4D4D;
+ color: #4d4d4d;
}
-.marketinfo{
+.marketinfo {
font-family: 'Montserrat light';
- color: #AEAEAE;
+ color: $silver-chalice;
font-size: 15px;
line-height: 17px;
}
@@ -655,25 +436,25 @@ input.large-input {
overflow: scroll;
}
-.icon-control .fa-refresh{
+.icon-control .fa-refresh {
visibility: hidden;
}
-.icon-control:hover .fa-refresh{
+.icon-control:hover .fa-refresh {
visibility: visible;
}
-.icon-control:hover .fa-chevron-right{
+.icon-control:hover .fa-chevron-right {
visibility: hidden;
}
.inactive {
- color: #AEAEAE;
+ color: $silver-chalice;
}
-.inactive button{
- background: #AEAEAE;
- color: white;
+.inactive button {
+ background: $silver-chalice;
+ color: $white;
}
.ellip-address {
@@ -686,21 +467,23 @@ input.large-input {
}
.qr-header {
- font-size: 25px;
- margin-top: 40px;
+ font-size: 25px;
+ margin-top: 40px;
}
.qr-message {
font-size: 12px;
- color: #F7861C;
+ color: #f7861c;
}
div.message-container > div:first-child {
margin-top: 18px;
font-size: 15px;
- color: #4D4D4D;
+ color: #4d4d4d;
}
.pop-hover:hover {
- transform: scale(1.1);
+ transform: scale(1.1);
}
+
+/* stylelint-enable */
diff --git a/ui/app/css/itcss/components/transaction-list.scss b/ui/app/css/itcss/components/transaction-list.scss
new file mode 100644
index 000000000..a6e68df42
--- /dev/null
+++ b/ui/app/css/itcss/components/transaction-list.scss
@@ -0,0 +1,141 @@
+.tx-list-container {
+ height: 87.5%;
+
+ @media screen and (min-width: $break-large) {
+ overflow-y: scroll;
+ }
+}
+
+@media screen and (max-width: $break-small) {
+ .tx-list-header-wrapper {
+ margin-top: .2em;
+ margin-bottom: .6em;
+ // TODO: Resolve Layout Conflicst in Wallet View
+ // - This fixes txlist "transactions" title dispay
+ // margin-top: 0.2em;
+ // margin-bottom: 0.6em;
+ justify-content: center;
+ }
+
+ .tx-list-header {
+ align-self: center;
+ font-size: 12px;
+ color: $dusty-gray;
+ }
+}
+
+@media screen and (min-width: $break-large) {
+ .tx-list-header-wrapper {
+ flex: 0 0 55px;
+ }
+
+ .tx-list-header {
+ font-size: 16px;
+ margin: 1.8em 1.3em;
+ }
+}
+
+.tx-list-content-divider {
+ height: 1px;
+ background: rgb(231, 231, 231);
+ flex: 0 0 1px;
+
+ @media screen and (max-width: $break-small) {
+ margin: .1em 0;
+ }
+
+ @media screen and (min-width: $break-large) {
+ margin: .1em 1.3em;
+ }
+}
+
+.tx-list-item-wrapper {
+ flex: 0 0 70px;
+ align-items: stretch;
+ justify-content: flex-start;
+
+ @media screen and (max-width: $break-small) {
+ margin: 0 1.3em .95em;
+ }
+
+ @media screen and (min-width: $break-large) {
+ margin: 0 1.3em;
+ }
+}
+
+.tx-list-date-wrapper {
+ flex: 1 1 auto;
+
+ @media screen and (max-width: $break-small) {
+ margin-top: 6px;
+ margin-bottom: 20px;
+ }
+
+ @media screen and (min-width: $break-large) {
+ margin-top: 6px;
+ }
+}
+
+.tx-list-content-wrapper {
+ align-items: stretch;
+ margin-bottom: 8px;
+}
+
+.tx-list-date {
+ color: $dusty-gray;
+ font-size: 14px;
+}
+
+.tx-list-identicon-wrapper {
+ align-self: center;
+ flex: 1 1 auto;
+ margin-left: 3px;
+}
+
+.tx-list-account-and-status-wrapper {
+ display: flex;
+ flex: 8 8 auto;
+
+ @media screen and (max-width: $break-small) {
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: flex-start;
+ align-self: center;
+ }
+
+ @media screen and (min-width: $break-large) {
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+
+ .tx-list-account-wrapper {
+ flex: 2 2 auto;
+ }
+
+ .tx-list-status-wrapper {
+ flex: 6 6 auto;
+ }
+ }
+
+ .tx-list-account {
+ font-size: 16px;
+ }
+
+ .tx-list-status {
+ color: $dusty-gray;
+ font-size: 16px;
+ }
+}
+
+.tx-list-details-wrapper {
+ align-self: center;
+ flex: 2 2 auto;
+
+ .tx-list-value {
+ font-size: 16px;
+ }
+
+ .tx-list-fiat-value {
+ font-size: 12px;
+ }
+}
diff --git a/ui/app/css/itcss/components/wallet-balance.scss b/ui/app/css/itcss/components/wallet-balance.scss
new file mode 100644
index 000000000..36f0e1025
--- /dev/null
+++ b/ui/app/css/itcss/components/wallet-balance.scss
@@ -0,0 +1,66 @@
+$wallet-balance-bg: $gallery;
+$wallet-balance-breakpoint: 890px;
+$wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and (max-width: #{$wallet-balance-breakpoint})";
+
+.wallet-balance-wrapper {
+ flex: 0 0 80px;
+}
+
+.wallet-balance {
+ background: inherit;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+
+ .balance-container {
+ display: flex;
+ justify-content: flex-start;
+ align-items: center;
+ margin: 20px 24px;
+ flex-direction: row;
+ flex-grow: 3;
+
+ @media #{$wallet-balance-breakpoint-range} {
+ margin: 10% 4%;
+ }
+ }
+
+ .balance-display {
+ margin-left: 15px;
+ justify-content: flex-start;
+ align-items: flex-start;
+
+ .token-amount {
+ font-size: 135%;
+ }
+
+ .fiat-amount {
+ margin-top: .25%;
+ font-size: 105%;
+ }
+
+ @media #{$wallet-balance-breakpoint-range} {
+ margin-left: 4%;
+
+ .token-amount {
+ font-size: 105%;
+ }
+
+ .fiat-amount {
+ font-size: 95%;
+ }
+ }
+ }
+
+ .balance-icon {
+ border-radius: 25px;
+ width: 45px;
+ height: 45px;
+ border: 1px solid $alto;
+ }
+}
+
+.wallet-balance-wrapper-active {
+ background: $wallet-balance-bg;
+}
diff --git a/ui/app/css/itcss/generic/index.scss b/ui/app/css/itcss/generic/index.scss
new file mode 100644
index 000000000..a1ffa98a3
--- /dev/null
+++ b/ui/app/css/itcss/generic/index.scss
@@ -0,0 +1,68 @@
+/*
+ Generic
+ */
+
+@import './reset.scss';
+
+* {
+ box-sizing: border-box;
+}
+
+html,
+body {
+ font-family: 'Montserrat Regular', Arial;
+ color: #4d4d4d;
+ font-weight: 300;
+ line-height: 1.4em;
+ background: #f7f7f7;
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+
+html {
+ min-height: 500px;
+}
+
+.app-root {
+ overflow: hidden;
+ position: relative;
+}
+
+.app-primary {
+ display: flex;
+}
+
+input:focus,
+textarea:focus {
+ outline: none;
+}
+
+/* stylelint-disable */
+#app-content {
+ overflow-x: hidden;
+ min-width: 357px;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+}
+/* stylelint-enable */
+
+a {
+ text-decoration: none;
+ color: inherit;
+}
+
+a:hover {
+ color: #df6b0e;
+}
+
+input.large-input,
+textarea.large-input {
+ padding: 8px;
+}
+
+input.large-input {
+ height: 36px;
+}
diff --git a/ui/app/css/itcss/generic/reset.scss b/ui/app/css/itcss/generic/reset.scss
new file mode 100644
index 000000000..2c70ee70a
--- /dev/null
+++ b/ui/app/css/itcss/generic/reset.scss
@@ -0,0 +1,146 @@
+/* http://meyerweb.com/eric/tools/css/reset/
+ v2.0 | 20110126
+ License: none (public domain)
+*/
+
+html,
+body,
+div,
+span,
+applet,
+object,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+a,
+abbr,
+acronym,
+address,
+big,
+cite,
+code,
+del,
+dfn,
+em,
+img,
+ins,
+kbd,
+q,
+s,
+samp,
+small,
+strike,
+strong,
+sub,
+sup,
+tt,
+var,
+b,
+u,
+i,
+center,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+label,
+legend,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td,
+article,
+aside,
+canvas,
+details,
+embed,
+figure,
+figcaption,
+footer,
+header,
+hgroup,
+menu,
+nav,
+output,
+ruby,
+section,
+summary,
+time,
+mark,
+audio,
+video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ /* stylelint-disable */
+ font: inherit;
+ /* stylelint-enable */
+ vertical-align: baseline;
+}
+
+/* HTML5 display-role reset for older browsers */
+
+/* stylelint-disable */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+ display: block;
+}
+
+body {
+ line-height: 1;
+}
+
+ol,
+ul {
+ list-style: none;
+}
+
+blockquote,
+q {
+ quotes: none;
+}
+
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+ content: '';
+ content: none;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+button {
+ border-style: none;
+}
+
+/* stylelint-enable */
diff --git a/ui/app/css/itcss/objects/index.scss b/ui/app/css/itcss/objects/index.scss
new file mode 100644
index 000000000..220775682
--- /dev/null
+++ b/ui/app/css/itcss/objects/index.scss
@@ -0,0 +1 @@
+// Objects
diff --git a/ui/app/css/itcss/settings/index.scss b/ui/app/css/itcss/settings/index.scss
new file mode 100644
index 000000000..58a7ca7b7
--- /dev/null
+++ b/ui/app/css/itcss/settings/index.scss
@@ -0,0 +1,3 @@
+@import './variables.scss';
+
+@import './typography.scss';
diff --git a/ui/app/css/itcss/settings/typography.scss b/ui/app/css/itcss/settings/typography.scss
new file mode 100644
index 000000000..e18a1979d
--- /dev/null
+++ b/ui/app/css/itcss/settings/typography.scss
@@ -0,0 +1,43 @@
+@import url('https://fonts.googleapis.com/css?family=Roboto:300,500');
+
+@import url('https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css');
+
+@font-face {
+ font-family: 'Montserrat Regular';
+ src: url('/fonts/Montserrat/Montserrat-Regular.woff') format('woff');
+ src: url('/fonts/Montserrat/Montserrat-Regular.ttf') format('truetype');
+ font-weight: 400;
+ font-style: normal;
+ font-size: 'small';
+}
+
+@font-face {
+ font-family: 'Montserrat Bold';
+ src: url('/fonts/Montserrat/Montserrat-Bold.woff') format('woff');
+ src: url('/fonts/Montserrat/Montserrat-Bold.ttf') format('truetype');
+ font-weight: 400;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Montserrat Light';
+ src: url('/fonts/Montserrat/Montserrat-Light.woff') format('woff');
+ src: url('/fonts/Montserrat/Montserrat-Light.ttf') format('truetype');
+ font-weight: 400;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Montserrat UltraLight';
+ src: url('/fonts/Montserrat/Montserrat-UltraLight.woff') format('woff');
+ src: url('/fonts/Montserrat/Montserrat-UltraLight.ttf') format('truetype');
+ font-weight: 400;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'DIN OT';
+ src: url('/fonts/DIN_OT/DINOT-2.otf') format('opentype');
+ font-weight: 400;
+ font-style: normal;
+}
diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss
new file mode 100644
index 000000000..829c3d591
--- /dev/null
+++ b/ui/app/css/itcss/settings/variables.scss
@@ -0,0 +1,51 @@
+/*
+ Variables
+ */
+
+// Base Colors
+$white: #fff;
+$black: #000;
+$orange: #ffa500;
+$red: #f00;
+
+/*
+ Colors
+ */
+$white-linen: #faf6f0; // formerly 'faint orange (textfield shades)'
+$rajah: #f5c26d; // formerly 'light orange (button shades)'
+$buttercup: #f5a623; // formerly 'dark orange (text)'
+$tundora: #4a4a4a; // formerly 'borders/font/any gray'
+$gallery: #efefef;
+$alabaster: #f7f7f7;
+$shark: #22232c;
+$wild-sand: #f6f6f6;
+$white: #fff;
+$dusty-gray: #9b9b9b;
+$alto: #dedede;
+$alabaster: #fafafa;
+$silver-chalice: #aeaeae;
+
+/*
+ Z-Indicies
+ */
+
+// Planned
+$dropdown-z: 30;
+$container-z: 15;
+$header-z: 12;
+
+/*
+ Z Indicies - Current
+ app - 11
+ hex/bn as decimal input - 1 - remove?
+ dropdown - 11
+ loading - 10 - higher?
+ mascot - 0 - remove?
+ */
+
+/*
+ Responsive Breakpoints
+ */
+$break-small: 575px;
+$break-midpoint: 780px;
+$break-large: 576px;
diff --git a/ui/app/css/itcss/tools/index.scss b/ui/app/css/itcss/tools/index.scss
new file mode 100644
index 000000000..2236729e8
--- /dev/null
+++ b/ui/app/css/itcss/tools/index.scss
@@ -0,0 +1 @@
+@import './utilities.scss';
diff --git a/ui/app/css/lib.css b/ui/app/css/itcss/tools/utilities.scss
index 81647d1c1..b9c99219b 100644
--- a/ui/app/css/lib.css
+++ b/ui/app/css/itcss/tools/utilities.scss
@@ -1,19 +1,34 @@
+/*
+ Utility Classes
+ */
+
/* color */
.color-orange {
- color: #F7861C;
+ color: #f7861c; // TODO: move to settings/variables
}
.color-forest {
- color: #0A5448;
+ color: #0a5448; // TODO: move to settings/variables
}
/* lib */
+.full-size {
+ height: 100%;
+ width: 100%;
+}
+
.full-width {
width: 100%;
}
+.full-flex-height {
+ display: flex;
+ flex: 1 1 auto;
+ flex-direction: column;
+}
+
.full-height {
height: 100%;
}
@@ -118,16 +133,19 @@
.pointer {
cursor: pointer;
}
+
.cursor-pointer {
cursor: pointer;
transform-origin: center center;
transition: transform 50ms ease-in-out;
}
+
.cursor-pointer:hover {
transform: scale(1.1);
}
+
.cursor-pointer:active {
- transform: scale(0.95);
+ transform: scale(.95);
}
.cursor-disabled {
@@ -147,7 +165,7 @@
}
.bold {
- font-weight: bold;
+ font-weight: 700;
}
.text-transform-uppercase {
@@ -172,12 +190,12 @@ hr.horizontal-line {
}
.hover-white:hover {
- background: white;
+ background: $white;
}
.red-dot {
- background: #E91550;
- color: white;
+ background: #e91550;
+ color: $white;
border-radius: 10px;
}
@@ -192,14 +210,14 @@ hr.horizontal-line {
}
.golden-square {
- background: #EBB33F;
+ background: #ebb33f;
}
.pending-dot {
- background: red;
+ background: $red;
left: 14px;
top: 14px;
- color: white;
+ color: $white;
border-radius: 10px;
height: 20px;
min-width: 20px;
@@ -214,9 +232,9 @@ hr.horizontal-line {
.keyring-label {
z-index: 1;
font-size: 11px;
- background: rgba(255,0,0,0.8);
+ background: rgba(255, 0, 0, .8);
bottom: -47px;
- color: white;
+ color: $white;
border-radius: 10px;
height: 20px;
min-width: 20px;
@@ -243,16 +261,13 @@ hr.horizontal-line {
margin: 13px;
}
-i.fa.fa-question-circle.fa-lg.menu-icon {
- font-size: 18px;
-}
-
.ether-icon {
background: rgb(0, 163, 68);
border-radius: 20px;
}
+
.testnet-icon {
- background: #2465E1;
+ background: #2465e1;
}
.drop-menu-item {
@@ -273,33 +288,26 @@ i.fa.fa-question-circle.fa-lg.menu-icon {
.critical-error {
text-align: center;
margin-top: 20px;
- color: red;
+ color: $red;
}
/*
- Hacky breakpoint fix for account + tab sections
- Resolves issue from @frankiebee in
- https://github.com/MetaMask/metamask-extension/pull/1835
- Please remove this when integrating new designs
+ Misc
*/
-@media screen and (min-width: 575px) and (max-width: 800px) {
- .account-data-subsection {
- flex: 0 0 auto !important; // reset flex
- margin-left: 10px !important; // create additional horizontal space
- margin-right: 10px !important;
- width: 40%;
- }
-
- .tabSection {
- flex: 0 0 auto !important;
- margin-left: 10px !important;
- margin-right: 10px !important;
- min-width: 285px;
- width: 49%;
- }
-
- .name-label {
- width: 80%;
- }
+// TODO: move into component-level contextual 'active' state
+.letter-spacey {
+ letter-spacing: .1em;
+}
+
+.active {
+ color: #909090;
+}
+
+.check {
+ margin-left: 7px;
+ color: #f7861c;
+ flex: 1 0 auto;
+ display: flex;
+ justify-content: flex-end;
}
diff --git a/ui/app/css/transitions.css b/ui/app/css/itcss/trumps/index.scss
index 393a944f9..e09642aa8 100644
--- a/ui/app/css/transitions.css
+++ b/ui/app/css/itcss/trumps/index.scss
@@ -1,3 +1,9 @@
+/*
+ Trumps
+ */
+
+// Transitions
+
/* universal */
.app-primary .main-enter {
position: absolute;
@@ -8,7 +14,7 @@
.app-primary.from-right .main-enter-active,
.app-primary.from-left .main-enter-active {
overflow-x: hidden;
- transform: translateX(0px);
+ transform: translateX(0);
transition: transform 300ms ease-in;
}
@@ -17,18 +23,27 @@
transform: translateX(360px);
transition: transform 300ms ease-in;
}
+
.app-primary.from-right .main-leave-active {
transform: translateX(-360px);
transition: transform 300ms ease-in;
}
+.sidebar.from-left {
+ transform: translateX(-320px);
+ transition: transform 300ms ease-in;
+}
+
/* loader transitions */
-.loader-enter, .loader-leave-active {
- opacity: 0.0;
+.loader-enter,
+.loader-leave-active {
+ opacity: 0;
transition: opacity 150 ease-in;
}
-.loader-enter-active, .loader-leave {
- opacity: 1.0;
+
+.loader-enter-active,
+.loader-leave {
+ opacity: 1;
transition: opacity 150 ease-in;
}
@@ -36,7 +51,22 @@
.app-primary.from-right .main-enter:not(.main-enter-active) {
transform: translateX(360px);
}
+
.app-primary.from-left .main-enter:not(.main-enter-active) {
transform: translateX(-360px);
}
+i.fa.fa-question-circle.fa-lg.menu-icon {
+ font-size: 18px;
+}
+
+// This text is contained inside a div.
+// ID needed to override user agent stylesheet.
+// See components/modal.scss
+
+/* stylelint-disable */
+#modal-content-footer-text {
+ font-family: 'DIN OT';
+ font-size: 16px;
+}
+/* stylelint-enable */
diff --git a/ui/app/css/reset.css b/ui/app/css/reset.css
deleted file mode 100644
index 9ce89e8bc..000000000
--- a/ui/app/css/reset.css
+++ /dev/null
@@ -1,48 +0,0 @@
-/* http://meyerweb.com/eric/tools/css/reset/
- v2.0 | 20110126
- License: none (public domain)
-*/
-
-html, body, div, span, applet, object, iframe,
-h1, h2, h3, h4, h5, h6, p, blockquote, pre,
-a, abbr, acronym, address, big, cite, code,
-del, dfn, em, img, ins, kbd, q, s, samp,
-small, strike, strong, sub, sup, tt, var,
-b, u, i, center,
-dl, dt, dd, ol, ul, li,
-fieldset, form, label, legend,
-table, caption, tbody, tfoot, thead, tr, th, td,
-article, aside, canvas, details, embed,
-figure, figcaption, footer, header, hgroup,
-menu, nav, output, ruby, section, summary,
-time, mark, audio, video {
- margin: 0;
- padding: 0;
- border: 0;
- font-size: 100%;
- font: inherit;
- vertical-align: baseline;
-}
-/* HTML5 display-role reset for older browsers */
-article, aside, details, figcaption, figure,
-footer, header, hgroup, menu, nav, section {
- display: block;
-}
-body {
- line-height: 1;
-}
-ol, ul {
- list-style: none;
-}
-blockquote, q {
- quotes: none;
-}
-blockquote:before, blockquote:after,
-q:before, q:after {
- content: '';
- content: none;
-}
-table {
- border-collapse: collapse;
- border-spacing: 0;
-} \ No newline at end of file
diff --git a/ui/app/main-container.js b/ui/app/main-container.js
new file mode 100644
index 000000000..31583f3e5
--- /dev/null
+++ b/ui/app/main-container.js
@@ -0,0 +1,71 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const TxView = require('./components/tx-view')
+const WalletView = require('./components/wallet-view')
+const AccountAndTransactionDetails = require('./account-and-transaction-details')
+const HDRestoreVaultScreen = require('./keychains/hd/restore-vault')
+const ConfigScreen = require('./config')
+const UnlockScreen = require('./unlock')
+
+module.exports = MainContainer
+
+inherits(MainContainer, Component)
+function MainContainer () {
+ Component.call(this)
+}
+
+MainContainer.prototype.render = function () {
+ // 3. summarize:
+ // switch statement goes inside MainContainer,
+ // or a method in renderPrimary
+ // - pass resulting h() to MainContainer
+ // - error checking in separate func
+ // - router in separate func
+ let contents = {
+ component: AccountAndTransactionDetails,
+ key: 'account-detail',
+ style: {},
+ }
+
+ if (this.props.isUnlocked === false) {
+ switch (this.props.currentViewName) {
+ case 'restoreVault':
+ log.debug('rendering restore vault screen')
+ contents = {
+ component: HDRestoreVaultScreen,
+ key: 'HDRestoreVaultScreen',
+ }
+ case 'config':
+ log.debug('rendering config screen from unlock screen.')
+ contents = {
+ component: ConfigScreen,
+ key: 'config',
+ }
+ default:
+ log.debug('rendering locked screen')
+ contents = {
+ component: UnlockScreen,
+ style: {
+ boxShadow: 'none',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ background: '#F7F7F7',
+ // must force 100%, because lock screen is full-width
+ width: '100%',
+ },
+ key: 'locked',
+ }
+ }
+ }
+
+ return h('div.main-container', {
+ style: contents.style,
+ }, [
+ h(contents.component, {
+ key: contents.key,
+ }, [])
+ ])
+}
+
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index 3a98d53a9..3e74fb732 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -36,6 +36,9 @@ function reduceApp (state, action) {
var appState = extend({
shouldClose: false,
menuOpen: false,
+ modalOpen: false,
+ sidebarOpen: false,
+ networkDropdownOpen: false,
currentView: seedWords ? seedConfView : defaultView,
accountDetail: {
subview: 'transactions',
@@ -49,9 +52,40 @@ function reduceApp (state, action) {
}, state.appState)
switch (action.type) {
+ // dropdown methods
+ case actions.NETWORK_DROPDOWN_OPEN:
+ return extend(appState, {
+ networkDropdownOpen: true,
+ })
- // transition methods
+ case actions.NETWORK_DROPDOWN_CLOSE:
+ return extend(appState, {
+ networkDropdownOpen: false,
+ })
+
+ // sidebar methods
+ case actions.SIDEBAR_OPEN:
+ return extend(appState, {
+ sidebarOpen: true,
+ })
+
+ case actions.SIDEBAR_CLOSE:
+ return extend(appState, {
+ sidebarOpen: false,
+ })
+
+ // modal methods:
+ case actions.MODAL_OPEN:
+ return extend(appState, {
+ modalOpen: true,
+ })
+ case actions.MODAL_CLOSE:
+ return extend(appState, {
+ modalOpen: false,
+ })
+
+ // transition methods
case actions.TRANSITION_FORWARD:
return extend(appState, {
transForward: true,
diff --git a/ui/app/selectors.js b/ui/app/selectors.js
new file mode 100644
index 000000000..fd203dbb4
--- /dev/null
+++ b/ui/app/selectors.js
@@ -0,0 +1,45 @@
+const valuesFor = require('./util').valuesFor
+
+const selectors = {
+ getSelectedAddress,
+ getSelectedIdentity,
+ getSelectedAccount,
+ conversionRateSelector,
+ transactionsSelector,
+}
+
+module.exports = selectors
+
+function getSelectedAddress(state) {
+ const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
+
+ return selectedAddress
+}
+
+function getSelectedIdentity(state) {
+ const selectedAddress = getSelectedAddress(state)
+ const identities = state.metamask.identities
+
+ return identities[selectedAddress]
+}
+
+function getSelectedAccount(state) {
+ const accounts = state.metamask.accounts
+ const selectedAddress = getSelectedAddress(state)
+
+ return accounts[selectedAddress]
+}
+
+function conversionRateSelector(state) {
+ return state.metamask.conversionRate
+}
+
+function transactionsSelector(state) {
+ const { network } = state.metamask
+ const unapprovedMsgs = valuesFor(state.metamask.unapprovedMsgs)
+ const shapeShiftTxList = (network === '1') ? state.metamask.shapeShiftTxList : undefined
+ const transactions = state.metamask.selectedAddressTxList || []
+ const txsToRender = !shapeShiftTxList ? transactions.concat(unapprovedMsgs) : transactions.concat(unapprovedMsgs, shapeShiftTxList)
+
+ return txsToRender.sort((a, b) => b.time - a.time)
+} \ No newline at end of file
diff --git a/ui/app/send.js b/ui/app/send.js
index a21a219eb..ab527019f 100644
--- a/ui/app/send.js
+++ b/ui/app/send.js
@@ -11,6 +11,9 @@ const isHex = require('./util').isHex
const EthBalance = require('./components/eth-balance')
const EnsInput = require('./components/ens-input')
const ethUtil = require('ethereumjs-util')
+
+const ARAGON = '960b236A07cf122663c4303350609A66A7B288C0'
+
module.exports = connect(mapStateToProps)(SendTransactionScreen)
function mapStateToProps (state) {
@@ -56,172 +59,425 @@ SendTransactionScreen.prototype.render = function () {
return (
- h('.send-screen.flex-column.flex-grow', [
-
- //
- // Sender Profile
- //
+ h('div.flex-column.flex-grow', {
+ style: {
+ minWidth: '355px', // TODO: maxWidth TBD, use home.html
+ },
+ }, [
- h('.account-data-subsection.flex-row.flex-grow', {
+ // Main Send token Card
+ h('div.send-screen.flex-column.flex-grow', {
style: {
- margin: '0 20px',
- },
+ marginLeft: '3.5%',
+ marginRight: '3.5%',
+ background: '#FFFFFF', // $background-white
+ boxShadow: '0 2px 4px 0 rgba(0,0,0,0.08)',
+ }
}, [
+ h('section.flex-center.flex-row', {
+ style: {
+ zIndex: 15, // $token-icon-z-index
+ marginTop: '-35px',
+ }
+ }, [
+ h(Identicon, {
+ address: ARAGON,
+ diameter: 76,
+ }),
+ ]),
- // header - identicon + nav
- h('.flex-row.flex-space-between', {
+ h('h3.flex-center', {
style: {
- marginTop: '15px',
+ marginTop: '-18px',
+ fontSize: '16px',
},
}, [
- // back button
- h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
- onClick: this.back.bind(this),
+ 'Send Tokens',
+ ]),
+
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ fontSize: '12px',
+ },
+ }, [
+ 'Send Tokens to anyone with an Ethereum account',
+ ]),
+
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ marginTop: '2px',
+ fontSize: '12px',
+ },
+ }, [
+ 'Your Aragon Token Balance is:',
+ ]),
+
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ fontSize: '36px',
+ marginTop: '8px',
+ },
+ }, [
+ '2.34',
+ ]),
+
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ fontSize: '12px',
+ marginTop: '4px',
+ },
+ }, [
+ 'ANT',
+ ]),
+
+ // error message
+ props.error && h('span.error.flex-center', props.error),
+
+ // 'to' field
+ h('section.flex-row.flex-center', {
+ style: {
+ fontSize: '12px',
+ },
+ }, [
+ h(EnsInput, {
+ name: 'address',
+ placeholder: 'Recipient Address',
+ onChange: this.recipientDidChange.bind(this),
+ network,
+ identities,
+ addressBook,
}),
+ ]),
- // large identicon
- h('.identicon-wrapper.flex-column.flex-center.select-none', [
- h(Identicon, {
- diameter: 62,
- address: address,
- }),
+ // 'amount' and send button
+ h('section.flex-column.flex-center', [
+ h('div.flex-row.flex-center', {
+ style: {
+ fontSize: '12px',
+ width: '100%',
+ justifyContent: 'space-between',
+ }
+ },[
+ h('span', { style: {} }, ['Amount']),
+ h('span', { style: {} }, ['Token <> USD']),
]),
- // invisible place holder
- h('i.fa.fa-users.fa-lg.invisible', {
+ h('input.large-input', {
+ name: 'amount',
+ placeholder: '0',
+ type: 'number',
style: {
- marginTop: '28px',
+ marginRight: '6px',
+ fontSize: '12px',
+ },
+ dataset: {
+ persistentFormId: 'tx-amount',
},
}),
]),
- // account label
+ h('section.flex-column.flex-center', [
+ h('div.flex-row.flex-center', {
+ style: {
+ fontSize: '12px',
+ width: '100%',
+ justifyContent: 'space-between',
+ }
+ },[
+ h('span', { style: {} }, ['Gas Fee:']),
+ h('span', { style: { fontSize: '8px' } }, ['What\'s this?']),
+ ]),
+
+ h('input.large-input', {
+ name: 'Gas Fee',
+ placeholder: '0',
+ type: 'number',
+ style: {
+ fontSize: '12px',
+ marginRight: '6px',
+ },
+ // dataset: {
+ // persistentFormId: 'tx-amount',
+ // },
+ }),
+
+ ]),
- h('.flex-column', {
+ h('section.flex-column.flex-center', {
style: {
- marginTop: '10px',
- alignItems: 'flex-start',
+ marginBottom: '10px',
},
}, [
- h('h2.font-medium.color-forest.flex-center', {
+ h('div.flex-row.flex-center', {
style: {
- paddingTop: '8px',
- marginBottom: '8px',
- },
- }, identity && identity.name),
+ fontSize: '12px',
+ width: '100%',
+ justifyContent: 'flex-start',
+ }
+ },[
+ h('span', { style: {} }, ['Transaction Memo (optional)']),
+ ]),
- // address and getter actions
- h('.flex-row.flex-center', {
+ h('input.large-input', {
+ name: 'memo',
+ placeholder: '',
+ type: 'string',
style: {
- marginBottom: '8px',
+ marginRight: '6px',
},
- }, [
+ }),
+ ]),
+ ]),
- h('div', {
- style: {
- lineHeight: '16px',
- },
- }, addressSummary(address)),
+ // Buttons underneath card
+ h('section.flex-column.flex-center', [
- ]),
+ h('button.btn-light', {
+ onClick: this.onSubmit.bind(this),
+ style: {
+ marginTop: '8px',
+ width: '8em',
+ background: '#FFFFFF'
+ },
+ }, 'Next'),
- // balance
- h('.flex-row.flex-center', [
+ h('button.btn-light', {
+ onClick: this.back.bind(this),
+ style: {
+ background: '#F7F7F7', // $alabaster
+ border: 'none',
+ opacity: 1,
+ width: '8em',
+ },
+ }, 'Cancel'),
+ ]),
+ ])
- h(EthBalance, {
- value: account && account.balance,
- conversionRate,
- currentCurrency,
- }),
+ )
+}
- ]),
- ]),
- ]),
+// WIP - hyperscript for renderSendToken - hook up later
+SendTransactionScreen.prototype.renderSendToken = function () {
+ this.persistentFormParentId = 'send-tx-form'
+
+ const props = this.props
+ const {
+ address,
+ account,
+ identity,
+ network,
+ identities,
+ addressBook,
+ conversionRate,
+ currentCurrency,
+ } = props
+
+ return (
- //
- // Required Fields
- //
+ h('div.flex-column.flex-grow', {
+ style: {
+ minWidth: '355px', // TODO: maxWidth TBD, use home.html
+ },
+ }, [
- h('h3.flex-center.text-transform-uppercase', {
+ // Main Send token Card
+ h('div.send-screen.flex-column.flex-grow', {
style: {
- background: '#EBEBEB',
- color: '#AEAEAE',
- marginTop: '15px',
- marginBottom: '16px',
- },
+ marginLeft: '3.5%',
+ marginRight: '3.5%',
+ background: '#FFFFFF', // $background-white
+ boxShadow: '0 2px 4px 0 rgba(0,0,0,0.08)',
+ }
}, [
- 'Send Transaction',
- ]),
+ h('section.flex-center.flex-row', {
+ style: {
+ zIndex: 15, // $token-icon-z-index
+ marginTop: '-35px',
+ }
+ }, [
+ h(Identicon, {
+ address: ARAGON,
+ diameter: 76,
+ }),
+ ]),
- // error message
- props.error && h('span.error.flex-center', props.error),
-
- // 'to' field
- h('section.flex-row.flex-center', [
- h(EnsInput, {
- name: 'address',
- placeholder: 'Recipient Address',
- onChange: this.recipientDidChange.bind(this),
- network,
- identities,
- addressBook,
- }),
- ]),
+ h('h3.flex-center', {
+ style: {
+ marginTop: '-18px',
+ fontSize: '16px',
+ },
+ }, [
+ 'Send Tokens',
+ ]),
- // 'amount' and send button
- h('section.flex-row.flex-center', [
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ fontSize: '12px',
+ },
+ }, [
+ 'Send Tokens to anyone with an Ethereum account',
+ ]),
- h('input.large-input', {
- name: 'amount',
- placeholder: 'Amount',
- type: 'number',
+ h('h3.flex-center', {
style: {
- marginRight: '6px',
+ textAlign: 'center',
+ marginTop: '2px',
+ fontSize: '12px',
},
- dataset: {
- persistentFormId: 'tx-amount',
+ }, [
+ 'Your Aragon Token Balance is:',
+ ]),
+
+ h('h3.flex-center', {
+ style: {
+ textAlign: 'center',
+ fontSize: '36px',
+ marginTop: '8px',
},
- }),
+ }, [
+ '2.34',
+ ]),
- h('button.primary', {
- onClick: this.onSubmit.bind(this),
+ h('h3.flex-center', {
style: {
- textTransform: 'uppercase',
+ textAlign: 'center',
+ fontSize: '12px',
+ marginTop: '4px',
},
- }, 'Next'),
+ }, [
+ 'ANT',
+ ]),
- ]),
+ // error message
+ props.error && h('span.error.flex-center', props.error),
- //
- // Optional Fields
- //
- h('h3.flex-center.text-transform-uppercase', {
- style: {
- background: '#EBEBEB',
- color: '#AEAEAE',
- marginTop: '16px',
- marginBottom: '16px',
- },
- }, [
- 'Transaction Data (optional)',
+ // 'to' field
+ h('section.flex-row.flex-center', {
+ style: {
+ fontSize: '12px',
+ },
+ }, [
+ h(EnsInput, {
+ name: 'address',
+ placeholder: 'Recipient Address',
+ onChange: this.recipientDidChange.bind(this),
+ network,
+ identities,
+ addressBook,
+ }),
+ ]),
+
+ // 'amount' and send button
+ h('section.flex-column.flex-center', [
+ h('div.flex-row.flex-center', {
+ style: {
+ fontSize: '12px',
+ width: '100%',
+ justifyContent: 'space-between',
+ }
+ },[
+ h('span', { style: {} }, ['Amount']),
+ h('span', { style: {} }, ['Token <> USD']),
+ ]),
+
+ h('input.large-input', {
+ name: 'amount',
+ placeholder: '0',
+ type: 'number',
+ style: {
+ marginRight: '6px',
+ fontSize: '12px',
+ },
+ dataset: {
+ persistentFormId: 'tx-amount',
+ },
+ }),
+
+ ]),
+
+ h('section.flex-column.flex-center', [
+ h('div.flex-row.flex-center', {
+ style: {
+ fontSize: '12px',
+ width: '100%',
+ justifyContent: 'space-between',
+ }
+ },[
+ h('span', { style: {} }, ['Gas Fee:']),
+ h('span', { style: { fontSize: '8px' } }, ['What\'s this?']),
+ ]),
+
+ h('input.large-input', {
+ name: 'Gas Fee',
+ placeholder: '0',
+ type: 'number',
+ style: {
+ fontSize: '12px',
+ marginRight: '6px',
+ },
+ // dataset: {
+ // persistentFormId: 'tx-amount',
+ // },
+ }),
+
+ ]),
+
+ h('section.flex-column.flex-center', {
+ style: {
+ marginBottom: '10px',
+ },
+ }, [
+ h('div.flex-row.flex-center', {
+ style: {
+ fontSize: '12px',
+ width: '100%',
+ justifyContent: 'flex-start',
+ }
+ },[
+ h('span', { style: {} }, ['Transaction Memo (optional)']),
+ ]),
+
+ h('input.large-input', {
+ name: 'memo',
+ placeholder: '',
+ type: 'string',
+ style: {
+ marginRight: '6px',
+ },
+ }),
+ ]),
]),
- // 'data' field
+ // Buttons underneath card
h('section.flex-column.flex-center', [
- h('input.large-input', {
- name: 'txData',
- placeholder: '0x01234',
+
+ h('button.btn-light', {
+ onClick: this.onSubmit.bind(this),
style: {
- width: '100%',
- resize: 'none',
+ marginTop: '8px',
+ width: '8em',
+ background: '#FFFFFF'
},
- dataset: {
- persistentFormId: 'tx-data',
+ }, 'Next'),
+
+ h('button.btn-light', {
+ onClick: this.back.bind(this),
+ style: {
+ background: '#F7F7F7', // $alabaster
+ border: 'none',
+ opacity: 1,
+ width: '8em',
},
- }),
+ }, 'Cancel'),
]),
])
+
)
}
@@ -248,7 +504,11 @@ SendTransactionScreen.prototype.onSubmit = function () {
const nickname = state.nickname || ' '
const input = document.querySelector('input[name="amount"]').value
const value = util.normalizeEthStringToWei(input)
- const txData = document.querySelector('input[name="txData"]').value
+ // TODO: check with team on whether txData is removed completely.
+ const txData = false;
+ // Must replace with memo data.
+ // const txData = document.querySelector('input[name="txData"]').value
+
const balance = this.props.balance
let message
@@ -267,7 +527,7 @@ SendTransactionScreen.prototype.onSubmit = function () {
return this.props.dispatch(actions.displayWarning(message))
}
- if (!isHex(ethUtil.stripHexPrefix(txData)) && txData) {
+ if (txData && !isHex(ethUtil.stripHexPrefix(txData))) {
message = 'Transaction data must be hex string.'
return this.props.dispatch(actions.displayWarning(message))
}
diff --git a/ui/app/unlock.js b/ui/app/unlock.js
index 9bacd5124..1918e2e6a 100644
--- a/ui/app/unlock.js
+++ b/ui/app/unlock.js
@@ -50,7 +50,7 @@ UnlockScreen.prototype.render = function () {
id: 'password-box',
placeholder: 'enter password',
style: {
-
+ background: 'white',
},
onKeyPress: this.onKeyPress.bind(this),
onInput: this.inputChanged.bind(this),
diff --git a/ui/css.js b/ui/css.js
index 043363cd7..d8f954434 100644
--- a/ui/css.js
+++ b/ui/css.js
@@ -4,11 +4,7 @@ const path = require('path')
module.exports = bundleCss
var cssFiles = {
- 'fonts.css': fs.readFileSync(path.join(__dirname, '/app/css/fonts.css'), 'utf8'),
- 'reset.css': fs.readFileSync(path.join(__dirname, '/app/css/reset.css'), 'utf8'),
- 'lib.css': fs.readFileSync(path.join(__dirname, '/app/css/lib.css'), 'utf8'),
- 'index.css': fs.readFileSync(path.join(__dirname, '/app/css/index.css'), 'utf8'),
- 'transitions.css': fs.readFileSync(path.join(__dirname, '/app/css/transitions.css'), 'utf8'),
+ 'index.css': fs.readFileSync(path.join(__dirname, '/app/css/output/index.css'), 'utf8'),
'react-tooltip-component.css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-tooltip-component', 'dist', 'react-tooltip-component.css'), 'utf8'),
'react-css': fs.readFileSync(path.join(__dirname, '..', 'node_modules', 'react-select', 'dist', 'react-select.css'), 'utf8'),
}
diff --git a/ui/lib/is-mobile-view.js b/ui/lib/is-mobile-view.js
new file mode 100644
index 000000000..8a8591c1a
--- /dev/null
+++ b/ui/lib/is-mobile-view.js
@@ -0,0 +1,5 @@
+// Checks if viewport at invoke time fits mobile dimensions
+// isMobileView :: () => Bool
+const isMobileView = () => window.matchMedia("screen and (max-width: 575px)").matches
+
+module.exports = isMobileView \ No newline at end of file