mirror of
https://github.com/trezor/trezor-wallet
synced 2024-12-29 10:28:08 +00:00
Merge pull request #9 from satoshilabs/styled-components-refactor
Styled components refactor - removed less completely
This commit is contained in:
commit
089aa0e829
5
.babelrc
5
.babelrc
@ -16,7 +16,10 @@
|
||||
"regenerator": true
|
||||
}],
|
||||
["module-resolver", {
|
||||
"root": ["./src"]
|
||||
"root": ["./src"],
|
||||
"alias": {
|
||||
"public": ["./public"]
|
||||
}
|
||||
}],
|
||||
"babel-plugin-styled-components"
|
||||
],
|
||||
|
@ -1,4 +1,5 @@
|
||||
solidity
|
||||
public
|
||||
coverage
|
||||
images
|
||||
node_modules
|
||||
node_modules
|
||||
src/flowtype/npm
|
@ -9,6 +9,7 @@
|
||||
"jest": true
|
||||
},
|
||||
"rules": {
|
||||
"no-plusplus": 0,
|
||||
"class-methods-use-this": 0,
|
||||
"react/require-default-props": 0,
|
||||
"react/forbid-prop-types": 0,
|
||||
|
91
README.md
91
README.md
@ -1,7 +1,90 @@
|
||||
# TREZOR Ethereum Wallet
|
||||
# TREZOR Wallet
|
||||
|
||||
To install dependencies run `npm install` or `yarn`
|
||||
|
||||
To start locally run `npm run dev` or `yarn run dev`
|
||||
|
||||
To build the project run `npm run build` or `yarn run build`
|
||||
|
||||
======================================
|
||||
|
||||
## Project structure
|
||||
The project is divided into two parts - data that are used when compiling the project and data that aren't.
|
||||
|
||||
All data that are used during compilation are stored inside the `src/` folder.
|
||||
|
||||
### `src/` folder
|
||||
At the root of the `src/` folder are all files or folders that are shared.
|
||||
|
||||
- `src/index.js` - root of the application
|
||||
- `src/views/` - contains all React `components` and `views`
|
||||
- `src/store/` - todo
|
||||
- `src/actions/` - todo
|
||||
- `src/reducers/` - todo
|
||||
- todo other folders/files?
|
||||
|
||||
|
||||
## Component
|
||||
Component is what you'd intuitively think it is. It's a regular React component (doesn't matter whether statefull or stateless).
|
||||
|
||||
### **Global components**
|
||||
All global components are are stored in `src/views/components/` folder.
|
||||
Global components are such components that are shared across multiple different components or views.
|
||||
- For example there's a `Button` component that is used in both `ConnectDevice` and `AccountSend`. `ConnectDevice` and `AccountSend` are both placed accross different views so the `Button` component they're both using must be stored in the global `components` folder.
|
||||
|
||||
### **Naming & structure convention**
|
||||
Each component has it's own folder. Name of the folder is same as is the name of the component (camel case and first letter is capitalized, e.g.: *MyComponent*).
|
||||
|
||||
If you want to create multiple components of the same type you should put them into a common folder with a lowercase name like this `views/componets/type/MyComponent`.
|
||||
|
||||
- For example there are different types of modals like `confirm` or `device`.
|
||||
Because the `confirm` and `device` modals are subtypes of modal the folder structure looks like this
|
||||
```
|
||||
modals/confirm/Address
|
||||
modals/confirm/SignTx
|
||||
modals/device/Duplicate
|
||||
```
|
||||
Where `Address`, `SignTx` and `Duplicate` are the actual modal components.
|
||||
|
||||
Inside each component's folder is `index.js` file containing the actual component's code with following export at the end of the file `export default ComponentName;`
|
||||
|
||||
There's only one render function per component's index file. If you need more renders you should probably create new component.
|
||||
|
||||
Each component may contain other components in its own `components/` folder. Component's components may contain another components etc.
|
||||
|
||||
|
||||
## View
|
||||
The difference between `view` and `component` is rather semantical then technical.
|
||||
|
||||
From the React's standpoint a view is just another component. So when is component a regular component and when is it a view?
|
||||
View components basically copy router structure and are composed either from view's own components or global components.
|
||||
|
||||
### **Naming & structure convention**
|
||||
Both naming and structure conventions are similar to components conventions.
|
||||
Each view has its own folder in `views/` folder. Name of this folder is same as is the view's name (camel case and first letter is capitalized, e.g.: *MyView*).
|
||||
Inside the view's folder is always an `index.js` file containing view's code itself.
|
||||
|
||||
View may contain own components inside view's folder - in the `components/` folder. One of the differences between a component and a view is that view can hav another views. Of course those views may have their own components and views, etc.
|
||||
|
||||
```
|
||||
views/
|
||||
MyView/
|
||||
components/
|
||||
views/
|
||||
index.js
|
||||
MyAnotherView/
|
||||
components/
|
||||
index.js
|
||||
```
|
||||
|
||||
- For example there's a `Landing` component that is displayed if no device is detected. This view contains its own components in a `Landing/components/` folder. These components are then used exclusively in `Landing/index.js` and together compose different versions of the `Landing` view.
|
||||
|
||||
<!-- If you aren't sure whether you should create component or view follow this discussion
|
||||
- If the route has following structure `/nameA/nameB/...` then `nameA` is probably a view and `nameB` is its subview
|
||||
- If the route has following structure `/nameA/:parameter/nameB/...` then `nameA` is a view
|
||||
- If the are some elements -->
|
||||
|
||||
|
||||
|
||||
npm install / yarn
|
||||
|
||||
npm run dev / yarn run dev
|
||||
|
||||
npm run build / yarn run build
|
31
package.json
31
package.json
@ -3,28 +3,28 @@
|
||||
"version": "1.0.0",
|
||||
"author": "TREZOR <info@trezor.io>",
|
||||
"description": "",
|
||||
"bugs": {
|
||||
"url": "https://github.com/szymonlesisz/trezor-connect-react-boilerplate/issues"
|
||||
},
|
||||
"bin": {
|
||||
"flow": "./node_modules/flow-bin"
|
||||
},
|
||||
"license": "LGPL-3.0+",
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --config ./webpack/config.dev.babel.js --mode development",
|
||||
"dev:local": "webpack-dev-server --config ./webpack/config.dev.local.babel.js --mode development",
|
||||
"build": "rm -rf build && webpack --config ./webpack/config.prod.babel.js --progress",
|
||||
"dev": "npx webpack-dev-server --config ./webpack/dev.babel.js",
|
||||
"dev:local": "npx webpack-dev-server --config ./webpack/local.babel.js",
|
||||
"build:clean": "rm -rf build",
|
||||
"build:production": "npx webpack --config ./webpack/production.babel.js --progress --bail",
|
||||
"build": "run-s build:*",
|
||||
"flow": "flow check src",
|
||||
"lint": "run-s lint:*",
|
||||
"lint:js": "eslint ./src ./webpack",
|
||||
"lint:css": "stylelint './src/**/*.js'",
|
||||
"lint:js": "npx eslint ./src ./webpack",
|
||||
"lint:css": "npx stylelint './src/**/*.js'",
|
||||
"test": "run-s test:*",
|
||||
"test:unit": "jest",
|
||||
"test-unit:watch": "jest -o --watch"
|
||||
"test:unit": "npx jest",
|
||||
"test-unit:watch": "npx jest -o --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel": "^6.23.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"bignumber.js": "2.4.0",
|
||||
"color-hash": "^1.0.3",
|
||||
"copy-webpack-plugin": "^4.5.2",
|
||||
"date-fns": "^1.29.0",
|
||||
@ -33,14 +33,12 @@
|
||||
"ethereumjs-util": "^5.1.4",
|
||||
"hdkey": "^0.8.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"mini-css-extract-plugin": "^0.4.1",
|
||||
"npm-run-all": "^4.1.3",
|
||||
"prop-types": "^15.6.2",
|
||||
"raf": "^3.4.0",
|
||||
"raven-js": "^3.22.3",
|
||||
"rc-tooltip": "^3.7.0",
|
||||
"react": "^16.2.0",
|
||||
"react-css-transition": "^0.7.4",
|
||||
"react": "^16.4.2",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-hot-loader": "^4.3.4",
|
||||
"react-qr-svg": "^2.1.0",
|
||||
@ -56,10 +54,12 @@
|
||||
"redux-raven-middleware": "^1.2.0",
|
||||
"redux-thunk": "^2.2.0",
|
||||
"styled-components": "^3.3.3",
|
||||
"styled-media-query": "^2.0.2",
|
||||
"styled-normalize": "^8.0.0",
|
||||
"trezor-connect": "5.0.30",
|
||||
"web3": "^0.19.0",
|
||||
"webpack": "^4.16.3",
|
||||
"webpack-bundle-analyzer": "^2.13.1",
|
||||
"whatwg-fetch": "^2.0.4",
|
||||
"yarn-run-all": "^3.1.1"
|
||||
},
|
||||
@ -80,6 +80,7 @@
|
||||
"eslint": "^4",
|
||||
"eslint-config-airbnb": "^17.0.0",
|
||||
"eslint-import-resolver-babel-module": "^4.0.0",
|
||||
"eslint-loader": "^2.1.0",
|
||||
"eslint-plugin-flowtype": "^2.50.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-jest": "^21.18.0",
|
||||
@ -90,10 +91,12 @@
|
||||
"jest": "^23.4.2",
|
||||
"less": "^3.0.1",
|
||||
"less-loader": "4.1.0",
|
||||
"stylelint": "^9.4.0",
|
||||
"stylelint": "^8.0.0",
|
||||
"stylelint-config-standard": "^18.2.0",
|
||||
"stylelint-config-styled-components": "^0.1.1",
|
||||
"stylelint-custom-processor-loader": "^0.5.0",
|
||||
"stylelint-processor-styled-components": "^1.3.2",
|
||||
"stylelint-webpack-plugin": "^0.10.5",
|
||||
"webpack-cli": "^2.1.3",
|
||||
"webpack-dev-server": "^3.1.4",
|
||||
"yargs": "11.0.0"
|
||||
|
@ -4,12 +4,6 @@ import * as ACCOUNT from 'actions/constants/account';
|
||||
import type { Action, TrezorDevice } from 'flowtype';
|
||||
import type { State } from 'reducers/AccountsReducer';
|
||||
|
||||
export type AccountAction =
|
||||
AccountFromStorageAction
|
||||
| AccountCreateAction
|
||||
| AccountSetBalanceAction
|
||||
| AccountSetNonceAction;
|
||||
|
||||
export type AccountFromStorageAction = {
|
||||
type: typeof ACCOUNT.FROM_STORAGE,
|
||||
payload: State
|
||||
@ -40,6 +34,12 @@ export type AccountSetNonceAction = {
|
||||
nonce: number
|
||||
}
|
||||
|
||||
export type AccountAction =
|
||||
AccountFromStorageAction
|
||||
| AccountCreateAction
|
||||
| AccountSetBalanceAction
|
||||
| AccountSetNonceAction;
|
||||
|
||||
export const setBalance = (address: string, network: string, deviceState: string, balance: string): Action => ({
|
||||
type: ACCOUNT.SET_BALANCE,
|
||||
address,
|
||||
@ -54,4 +54,4 @@ export const setNonce = (address: string, network: string, deviceState: string,
|
||||
network,
|
||||
deviceState,
|
||||
nonce,
|
||||
});
|
||||
});
|
||||
|
@ -1,11 +1,9 @@
|
||||
/* @flow */
|
||||
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import HDKey from 'hdkey';
|
||||
import EthereumjsUtil from 'ethereumjs-util';
|
||||
import * as DISCOVERY from 'actions/constants/discovery';
|
||||
import * as ACCOUNT from 'actions/constants/account';
|
||||
import * as TOKEN from 'actions/constants/token';
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import type {
|
||||
ThunkAction, AsyncAction, Action, GetState, Dispatch, TrezorDevice,
|
||||
@ -13,18 +11,9 @@ import type {
|
||||
import type { Discovery, State } from 'reducers/DiscoveryReducer';
|
||||
import * as AccountsActions from './AccountsActions';
|
||||
|
||||
import { getNonceAsync, getBalanceAsync, getTokenBalanceAsync } from './Web3Actions';
|
||||
import { setBalance as setTokenBalance } from './TokenActions';
|
||||
import { getNonceAsync, getBalanceAsync } from './Web3Actions';
|
||||
|
||||
|
||||
export type DiscoveryAction = {
|
||||
type: typeof DISCOVERY.FROM_STORAGE,
|
||||
payload: State
|
||||
} | DiscoveryStartAction
|
||||
| DiscoveryWaitingAction
|
||||
| DiscoveryStopAction
|
||||
| DiscoveryCompleteAction;
|
||||
|
||||
export type DiscoveryStartAction = {
|
||||
type: typeof DISCOVERY.START,
|
||||
device: TrezorDevice,
|
||||
@ -51,144 +40,29 @@ export type DiscoveryCompleteAction = {
|
||||
network: string
|
||||
}
|
||||
|
||||
export const start = (device: TrezorDevice, network: string, ignoreCompleted?: boolean): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const selected = getState().wallet.selectedDevice;
|
||||
if (!selected) {
|
||||
// TODO: throw error
|
||||
console.error('Start discovery: no selected device', device);
|
||||
return;
|
||||
} if (selected.path !== device.path) {
|
||||
console.error('Start discovery: requested device is not selected', device, selected);
|
||||
return;
|
||||
} if (!selected.state) {
|
||||
console.warn("Start discovery: Selected device wasn't authenticated yet...");
|
||||
return;
|
||||
} if (selected.connected && !selected.available) {
|
||||
console.warn('Start discovery: Selected device is unavailable...');
|
||||
return;
|
||||
}
|
||||
|
||||
const web3 = getState().web3.find(w3 => w3.network === network);
|
||||
if (!web3) {
|
||||
console.error('Start discovery: Web3 does not exist', network);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!web3.web3.currentProvider.isConnected()) {
|
||||
console.error('Start discovery: Web3 is not connected', network);
|
||||
dispatch({
|
||||
type: DISCOVERY.WAITING_FOR_BACKEND,
|
||||
device,
|
||||
network,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const discovery: State = getState().discovery;
|
||||
const discoveryProcess: ?Discovery = discovery.find(d => d.deviceState === device.state && d.network === network);
|
||||
export type DiscoveryAction = {
|
||||
type: typeof DISCOVERY.FROM_STORAGE,
|
||||
payload: State
|
||||
} | DiscoveryStartAction
|
||||
| DiscoveryWaitingAction
|
||||
| DiscoveryStopAction
|
||||
| DiscoveryCompleteAction;
|
||||
|
||||
|
||||
if (!selected.connected && (!discoveryProcess || !discoveryProcess.completed)) {
|
||||
dispatch({
|
||||
type: DISCOVERY.WAITING_FOR_DEVICE,
|
||||
device,
|
||||
network,
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Because start() is calling begin() and begin() is calling start() one of them must be declared first
|
||||
// otherwise eslint will start complaining
|
||||
let begin;
|
||||
|
||||
if (!discoveryProcess) {
|
||||
dispatch(begin(device, network));
|
||||
} else if (discoveryProcess.completed && !ignoreCompleted) {
|
||||
dispatch({
|
||||
type: DISCOVERY.COMPLETE,
|
||||
device,
|
||||
network,
|
||||
});
|
||||
} else if (discoveryProcess.interrupted || discoveryProcess.waitingForDevice) {
|
||||
// discovery cycle was interrupted
|
||||
// start from beginning
|
||||
dispatch(begin(device, network));
|
||||
} else {
|
||||
dispatch(discoverAccount(device, discoveryProcess));
|
||||
}
|
||||
};
|
||||
|
||||
const begin = (device: TrezorDevice, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const { config } = getState().localStorage;
|
||||
const coinToDiscover = config.coins.find(c => c.network === network);
|
||||
if (!coinToDiscover) return;
|
||||
|
||||
dispatch({
|
||||
type: DISCOVERY.WAITING_FOR_DEVICE,
|
||||
device,
|
||||
network,
|
||||
});
|
||||
|
||||
// get xpub from TREZOR
|
||||
const response = await TrezorConnect.getPublicKey({
|
||||
device: {
|
||||
path: device.path,
|
||||
instance: device.instance,
|
||||
state: device.state,
|
||||
},
|
||||
path: coinToDiscover.bip44,
|
||||
keepSession: true, // acquire and hold session
|
||||
useEmptyPassphrase: !device.instance,
|
||||
});
|
||||
|
||||
// handle TREZOR response error
|
||||
if (!response.success) {
|
||||
// TODO: check message
|
||||
console.warn('DISCOVERY ERROR', response);
|
||||
dispatch({
|
||||
type: NOTIFICATION.ADD,
|
||||
payload: {
|
||||
type: 'error',
|
||||
title: 'Discovery error',
|
||||
message: response.payload.error,
|
||||
cancelable: true,
|
||||
actions: [
|
||||
{
|
||||
label: 'Try again',
|
||||
callback: () => {
|
||||
dispatch(start(device, network));
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// check for interruption
|
||||
const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === device.state && d.network === network);
|
||||
if (discoveryProcess && discoveryProcess.interrupted) return;
|
||||
|
||||
const basePath: Array<number> = response.payload.path;
|
||||
|
||||
// send data to reducer
|
||||
dispatch({
|
||||
type: DISCOVERY.START,
|
||||
network: coinToDiscover.network,
|
||||
device,
|
||||
publicKey: response.payload.publicKey,
|
||||
chainCode: response.payload.chainCode,
|
||||
basePath,
|
||||
});
|
||||
|
||||
dispatch(start(device, network));
|
||||
};
|
||||
|
||||
const discoverAccount = (device: TrezorDevice, discoveryProcess: Discovery): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const completed: boolean = discoveryProcess.completed;
|
||||
const { completed } = discoveryProcess;
|
||||
discoveryProcess.completed = false;
|
||||
|
||||
const derivedKey = discoveryProcess.hdKey.derive(`m/${discoveryProcess.accountIndex}`);
|
||||
const path = discoveryProcess.basePath.concat(discoveryProcess.accountIndex);
|
||||
const publicAddress: string = EthereumjsUtil.publicToAddress(derivedKey.publicKey, true).toString('hex');
|
||||
const ethAddress: string = EthereumjsUtil.toChecksumAddress(publicAddress);
|
||||
const network = discoveryProcess.network;
|
||||
const { network } = discoveryProcess;
|
||||
|
||||
// TODO: check if address was created before
|
||||
|
||||
@ -312,6 +186,135 @@ const discoverAccount = (device: TrezorDevice, discoveryProcess: Discovery): Asy
|
||||
}
|
||||
};
|
||||
|
||||
export const start = (device: TrezorDevice, network: string, ignoreCompleted?: boolean): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const selected = getState().wallet.selectedDevice;
|
||||
if (!selected) {
|
||||
// TODO: throw error
|
||||
console.error('Start discovery: no selected device', device);
|
||||
return;
|
||||
} if (selected.path !== device.path) {
|
||||
console.error('Start discovery: requested device is not selected', device, selected);
|
||||
return;
|
||||
} if (!selected.state) {
|
||||
console.warn("Start discovery: Selected device wasn't authenticated yet...");
|
||||
return;
|
||||
} if (selected.connected && !selected.available) {
|
||||
console.warn('Start discovery: Selected device is unavailable...');
|
||||
return;
|
||||
}
|
||||
|
||||
const web3 = getState().web3.find(w3 => w3.network === network);
|
||||
if (!web3) {
|
||||
console.error('Start discovery: Web3 does not exist', network);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!web3.web3.currentProvider.isConnected()) {
|
||||
console.error('Start discovery: Web3 is not connected', network);
|
||||
dispatch({
|
||||
type: DISCOVERY.WAITING_FOR_BACKEND,
|
||||
device,
|
||||
network,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const { discovery }: { discovery: State } = getState();
|
||||
const discoveryProcess: ?Discovery = discovery.find(d => d.deviceState === device.state && d.network === network);
|
||||
|
||||
|
||||
if (!selected.connected && (!discoveryProcess || !discoveryProcess.completed)) {
|
||||
dispatch({
|
||||
type: DISCOVERY.WAITING_FOR_DEVICE,
|
||||
device,
|
||||
network,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!discoveryProcess) {
|
||||
dispatch(begin(device, network));
|
||||
} else if (discoveryProcess.completed && !ignoreCompleted) {
|
||||
dispatch({
|
||||
type: DISCOVERY.COMPLETE,
|
||||
device,
|
||||
network,
|
||||
});
|
||||
} else if (discoveryProcess.interrupted || discoveryProcess.waitingForDevice) {
|
||||
// discovery cycle was interrupted
|
||||
// start from beginning
|
||||
dispatch(begin(device, network));
|
||||
} else {
|
||||
dispatch(discoverAccount(device, discoveryProcess));
|
||||
}
|
||||
};
|
||||
|
||||
begin = (device: TrezorDevice, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const { config } = getState().localStorage;
|
||||
const coinToDiscover = config.coins.find(c => c.network === network);
|
||||
if (!coinToDiscover) return;
|
||||
|
||||
dispatch({
|
||||
type: DISCOVERY.WAITING_FOR_DEVICE,
|
||||
device,
|
||||
network,
|
||||
});
|
||||
|
||||
// get xpub from TREZOR
|
||||
const response = await TrezorConnect.getPublicKey({
|
||||
device: {
|
||||
path: device.path,
|
||||
instance: device.instance,
|
||||
state: device.state,
|
||||
},
|
||||
path: coinToDiscover.bip44,
|
||||
keepSession: true, // acquire and hold session
|
||||
useEmptyPassphrase: !device.instance,
|
||||
});
|
||||
|
||||
// handle TREZOR response error
|
||||
if (!response.success) {
|
||||
// TODO: check message
|
||||
console.warn('DISCOVERY ERROR', response);
|
||||
dispatch({
|
||||
type: NOTIFICATION.ADD,
|
||||
payload: {
|
||||
type: 'error',
|
||||
title: 'Discovery error',
|
||||
message: response.payload.error,
|
||||
cancelable: true,
|
||||
actions: [
|
||||
{
|
||||
label: 'Try again',
|
||||
callback: () => {
|
||||
dispatch(start(device, network));
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// check for interruption
|
||||
const discoveryProcess: ?Discovery = getState().discovery.find(d => d.deviceState === device.state && d.network === network);
|
||||
if (discoveryProcess && discoveryProcess.interrupted) return;
|
||||
|
||||
const basePath: Array<number> = response.payload.path;
|
||||
|
||||
// send data to reducer
|
||||
dispatch({
|
||||
type: DISCOVERY.START,
|
||||
network: coinToDiscover.network,
|
||||
device,
|
||||
publicKey: response.payload.publicKey,
|
||||
chainCode: response.payload.chainCode,
|
||||
basePath,
|
||||
});
|
||||
|
||||
dispatch(start(device, network));
|
||||
};
|
||||
|
||||
export const restore = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const selected = getState().wallet.selectedDevice;
|
||||
|
||||
|
@ -7,15 +7,15 @@ import * as TOKEN from 'actions/constants/token';
|
||||
import * as DISCOVERY from 'actions/constants/discovery';
|
||||
import * as STORAGE from 'actions/constants/localStorage';
|
||||
import * as PENDING from 'actions/constants/pendingTx';
|
||||
import { JSONRequest, httpRequest } from 'utils/networkUtils';
|
||||
import { httpRequest } from 'utils/networkUtils';
|
||||
|
||||
import type {
|
||||
ThunkAction, AsyncAction, GetState, Dispatch, TrezorDevice,
|
||||
ThunkAction, AsyncAction, /* GetState, */ Dispatch,
|
||||
} from 'flowtype';
|
||||
import type { Config, Coin, TokensCollection } from 'reducers/LocalStorageReducer';
|
||||
|
||||
import AppConfigJSON from 'data/appConfig.json';
|
||||
import Erc20AbiJSON from 'data/ERC20Abi.json';
|
||||
import Erc20AbiJSON from 'public/data/ERC20Abi.json';
|
||||
import AppConfigJSON from 'public/data/appConfig.json';
|
||||
|
||||
export type StorageAction = {
|
||||
type: typeof STORAGE.READY,
|
||||
@ -30,59 +30,66 @@ export type StorageAction = {
|
||||
error: string,
|
||||
};
|
||||
|
||||
export const loadData = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
// check if local storage is available
|
||||
// let available: boolean = true;
|
||||
// if (typeof window.localStorage === 'undefined') {
|
||||
// available = false;
|
||||
// } else {
|
||||
// try {
|
||||
// window.localStorage.setItem('ethereum_wallet', true);
|
||||
// } catch (error) {
|
||||
// available = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
dispatch(loadTokensFromJSON());
|
||||
export const get = (key: string): ?string => {
|
||||
try {
|
||||
return window.localStorage.getItem(key);
|
||||
} catch (error) {
|
||||
// available = false;
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// const parseConfig = (json: JSON): Config => {
|
||||
export function update(event: StorageEvent): AsyncAction {
|
||||
return async (dispatch: Dispatch/* , getState: GetState */): Promise<void> => {
|
||||
if (!event.newValue) return;
|
||||
|
||||
// if (json['coins']) {
|
||||
if (event.key === 'devices') {
|
||||
// check if device was added/ removed
|
||||
// const newDevices: Array<TrezorDevice> = JSON.parse(event.newValue);
|
||||
// const myDevices: Array<TrezorDevice> = getState().connect.devices.filter(d => d.features);
|
||||
|
||||
// }
|
||||
// if (newDevices.length !== myDevices.length) {
|
||||
// const diff = myDevices.filter(d => newDevices.indexOf(d) < 0)
|
||||
// console.warn("DEV LIST CHANGED!", newDevices.length, myDevices.length, diff)
|
||||
// // check if difference is caused by local device which is not saved
|
||||
// // or device which was saved in other tab
|
||||
// }
|
||||
|
||||
// for (let key in json) {
|
||||
// if (key === 'coins') {
|
||||
// const diff = oldDevices.filter(d => newDevices.indexOf())
|
||||
}
|
||||
|
||||
// }
|
||||
// }
|
||||
if (event.key === 'accounts') {
|
||||
dispatch({
|
||||
type: ACCOUNT.FROM_STORAGE,
|
||||
payload: JSON.parse(event.newValue),
|
||||
});
|
||||
}
|
||||
|
||||
// const coins: Array<Object> = json.coins || [];
|
||||
if (event.key === 'tokens') {
|
||||
dispatch({
|
||||
type: TOKEN.FROM_STORAGE,
|
||||
payload: JSON.parse(event.newValue),
|
||||
});
|
||||
}
|
||||
|
||||
// if ("coins" in json){
|
||||
// json.coins
|
||||
// }
|
||||
// if (!json.hasOwnProperty("fiatValueTickers")) throw new Error(`Property "fiatValueTickers" is missing in appConfig.json`);
|
||||
// if (json.config && json.hasOwnProperty('coins') && Array.isArray(json.coins)) {
|
||||
// json.coins.map(c => {
|
||||
// return {
|
||||
if (event.key === 'pending') {
|
||||
dispatch({
|
||||
type: PENDING.FROM_STORAGE,
|
||||
payload: JSON.parse(event.newValue),
|
||||
});
|
||||
}
|
||||
|
||||
// }
|
||||
// })
|
||||
// } else {
|
||||
// throw new Error(`Property "coins" is missing in appConfig.json`);
|
||||
// }
|
||||
|
||||
|
||||
// return {
|
||||
// coins: [],
|
||||
// fiatValueTickers: []
|
||||
// }
|
||||
// }
|
||||
if (event.key === 'discovery') {
|
||||
dispatch({
|
||||
type: DISCOVERY.FROM_STORAGE,
|
||||
payload: JSON.parse(event.newValue),
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function loadTokensFromJSON(): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
return async (dispatch: Dispatch): Promise<void> => {
|
||||
if (typeof window.localStorage === 'undefined') return;
|
||||
|
||||
try {
|
||||
@ -157,57 +164,58 @@ export function loadTokensFromJSON(): AsyncAction {
|
||||
};
|
||||
}
|
||||
|
||||
export function update(event: StorageEvent): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
if (!event.newValue) return;
|
||||
export const loadData = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||
// check if local storage is available
|
||||
// let available: boolean = true;
|
||||
// if (typeof window.localStorage === 'undefined') {
|
||||
// available = false;
|
||||
// } else {
|
||||
// try {
|
||||
// window.localStorage.setItem('ethereum_wallet', true);
|
||||
// } catch (error) {
|
||||
// available = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
if (event.key === 'devices') {
|
||||
// check if device was added/ removed
|
||||
// const newDevices: Array<TrezorDevice> = JSON.parse(event.newValue);
|
||||
// const myDevices: Array<TrezorDevice> = getState().connect.devices.filter(d => d.features);
|
||||
dispatch(loadTokensFromJSON());
|
||||
};
|
||||
|
||||
// if (newDevices.length !== myDevices.length) {
|
||||
// const diff = myDevices.filter(d => newDevices.indexOf(d) < 0)
|
||||
// console.warn("DEV LIST CHANGED!", newDevices.length, myDevices.length, diff)
|
||||
// // check if difference is caused by local device which is not saved
|
||||
// // or device which was saved in other tab
|
||||
// }
|
||||
// const parseConfig = (json: JSON): Config => {
|
||||
|
||||
// const diff = oldDevices.filter(d => newDevices.indexOf())
|
||||
}
|
||||
// if (json['coins']) {
|
||||
|
||||
if (event.key === 'accounts') {
|
||||
dispatch({
|
||||
type: ACCOUNT.FROM_STORAGE,
|
||||
payload: JSON.parse(event.newValue),
|
||||
});
|
||||
}
|
||||
// }
|
||||
|
||||
if (event.key === 'tokens') {
|
||||
dispatch({
|
||||
type: TOKEN.FROM_STORAGE,
|
||||
payload: JSON.parse(event.newValue),
|
||||
});
|
||||
}
|
||||
// for (let key in json) {
|
||||
// if (key === 'coins') {
|
||||
|
||||
if (event.key === 'pending') {
|
||||
dispatch({
|
||||
type: PENDING.FROM_STORAGE,
|
||||
payload: JSON.parse(event.newValue),
|
||||
});
|
||||
}
|
||||
// }
|
||||
// }
|
||||
|
||||
if (event.key === 'discovery') {
|
||||
dispatch({
|
||||
type: DISCOVERY.FROM_STORAGE,
|
||||
payload: JSON.parse(event.newValue),
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
// const coins: Array<Object> = json.coins || [];
|
||||
|
||||
// if ("coins" in json){
|
||||
// json.coins
|
||||
// }
|
||||
// if (!json.hasOwnProperty("fiatValueTickers")) throw new Error(`Property "fiatValueTickers" is missing in appConfig.json`);
|
||||
// if (json.config && json.hasOwnProperty('coins') && Array.isArray(json.coins)) {
|
||||
// json.coins.map(c => {
|
||||
// return {
|
||||
|
||||
// }
|
||||
// })
|
||||
// } else {
|
||||
// throw new Error(`Property "coins" is missing in appConfig.json`);
|
||||
// }
|
||||
|
||||
|
||||
export const save = (key: string, value: string): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
// return {
|
||||
// coins: [],
|
||||
// fiatValueTickers: []
|
||||
// }
|
||||
// }
|
||||
|
||||
export const save = (key: string, value: string): ThunkAction => (): void => {
|
||||
if (typeof window.localStorage !== 'undefined') {
|
||||
try {
|
||||
window.localStorage.setItem(key, value);
|
||||
@ -216,13 +224,4 @@ export const save = (key: string, value: string): ThunkAction => (dispatch: Disp
|
||||
console.error(`Local Storage ERROR: ${error}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const get = (key: string): ?string => {
|
||||
try {
|
||||
return window.localStorage.getItem(key);
|
||||
} catch (error) {
|
||||
// available = false;
|
||||
return null;
|
||||
}
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
import TrezorConnect, { UI, UI_EVENT } from 'trezor-connect';
|
||||
import TrezorConnect, { UI } from 'trezor-connect';
|
||||
import type { Device } from 'trezor-connect';
|
||||
import * as MODAL from 'actions/constants/modal';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
@ -24,14 +24,14 @@ export const onPinSubmit = (value: string): Action => {
|
||||
};
|
||||
};
|
||||
|
||||
export const onPassphraseSubmit = (passphrase: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const resp = await TrezorConnect.uiResponse({
|
||||
type: UI.RECEIVE_PASSPHRASE,
|
||||
payload: {
|
||||
value: passphrase,
|
||||
save: true,
|
||||
},
|
||||
});
|
||||
export const onPassphraseSubmit = (/* passphrase: string */): AsyncAction => async (dispatch: Dispatch): Promise<void> => {
|
||||
// const resp = await TrezorConnect.uiResponse({
|
||||
// type: UI.RECEIVE_PASSPHRASE,
|
||||
// payload: {
|
||||
// value: passphrase,
|
||||
// save: true,
|
||||
// },
|
||||
// });
|
||||
|
||||
dispatch({
|
||||
type: MODAL.CLOSE,
|
||||
@ -64,7 +64,7 @@ export const onCancel = (): Action => ({
|
||||
type: MODAL.CLOSE,
|
||||
});
|
||||
|
||||
export const onDuplicateDevice = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const onDuplicateDevice = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch): void => {
|
||||
dispatch(onCancel());
|
||||
|
||||
dispatch({
|
||||
|
@ -28,7 +28,7 @@ export type ReceiveAction = {
|
||||
type: typeof RECEIVE.SHOW_UNVERIFIED_ADDRESS
|
||||
}
|
||||
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||
const state: State = {
|
||||
...initialState,
|
||||
};
|
||||
|
@ -9,19 +9,13 @@ import * as PENDING from 'actions/constants/pendingTx';
|
||||
|
||||
import * as stateUtils from 'reducers/utils';
|
||||
|
||||
import { initialState } from 'reducers/SelectedAccountReducer';
|
||||
|
||||
import type {
|
||||
Coin,
|
||||
TrezorDevice,
|
||||
AsyncAction,
|
||||
ThunkAction,
|
||||
Action,
|
||||
GetState,
|
||||
Dispatch,
|
||||
State,
|
||||
} from 'flowtype';
|
||||
import * as SessionStorageActions from './SessionStorageActions';
|
||||
import * as SendFormActions from './SendFormActions';
|
||||
|
||||
|
||||
@ -32,13 +26,14 @@ export type SelectedAccountAction = {
|
||||
payload: $ElementType<State, 'selectedAccount'>
|
||||
};
|
||||
|
||||
export const dispose = (): Action => ({
|
||||
type: ACCOUNT.DISPOSE,
|
||||
});
|
||||
|
||||
export const updateSelectedValues = (prevState: State, action: Action): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const locationChange: boolean = action.type === LOCATION_CHANGE;
|
||||
const state: State = getState();
|
||||
const location = state.router.location;
|
||||
const prevLocation = prevState.router.location;
|
||||
|
||||
const needUpdate: boolean = false;
|
||||
const { location } = state.router;
|
||||
|
||||
// reset form to default
|
||||
if (action.type === SEND.TX_COMPLETE) {
|
||||
@ -126,7 +121,3 @@ export const updateSelectedValues = (prevState: State, action: Action): AsyncAct
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const dispose = (): Action => ({
|
||||
type: ACCOUNT.DISPOSE,
|
||||
});
|
@ -5,37 +5,29 @@ import EthereumjsUtil from 'ethereumjs-util';
|
||||
import EthereumjsUnits from 'ethereumjs-units';
|
||||
import EthereumjsTx from 'ethereumjs-tx';
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import { push } from 'react-router-redux';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import { strip } from 'utils/ethUtils';
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
|
||||
import { initialState } from 'reducers/SendFormReducer';
|
||||
import { findAccount } from 'reducers/AccountsReducer';
|
||||
import { findToken } from 'reducers/TokensReducer';
|
||||
import { findDevice } from 'reducers/utils';
|
||||
import * as stateUtils from 'reducers/utils';
|
||||
import { findDevice, getPendingAmount, getPendingNonce } from 'reducers/utils';
|
||||
|
||||
import type {
|
||||
PendingTx,
|
||||
Dispatch,
|
||||
GetState,
|
||||
Action,
|
||||
ThunkAction,
|
||||
AsyncAction,
|
||||
RouterLocationState,
|
||||
TrezorDevice,
|
||||
} from 'flowtype';
|
||||
import type { State as AccountState } from 'reducers/SelectedAccountReducer';
|
||||
import type { Web3Instance } from 'reducers/Web3Reducer';
|
||||
import type { Config, Coin } from 'reducers/LocalStorageReducer';
|
||||
import type { Coin } from 'reducers/LocalStorageReducer';
|
||||
import type { Token } from 'reducers/TokensReducer';
|
||||
import type { State, FeeLevel } from 'reducers/SendFormReducer';
|
||||
import type { Account } from 'reducers/AccountsReducer';
|
||||
import type { Props } from 'views/Wallet/views/AccountSend/Container';
|
||||
import * as SessionStorageActions from './SessionStorageActions';
|
||||
import { estimateGas, getGasPrice, pushTx } from './Web3Actions';
|
||||
import { estimateGas, pushTx } from './Web3Actions';
|
||||
|
||||
export type SendTxAction = {
|
||||
type: typeof SEND.TX_COMPLETE,
|
||||
@ -155,7 +147,6 @@ export const calculate = (prevProps: Props, props: Props) => {
|
||||
} = props.selectedAccount;
|
||||
if (!account) return;
|
||||
|
||||
const prevState = prevProps.sendForm;
|
||||
const state = props.sendForm;
|
||||
const isToken: boolean = state.currency !== state.networkSymbol;
|
||||
|
||||
@ -169,7 +160,7 @@ export const calculate = (prevProps: Props, props: Props) => {
|
||||
|
||||
|
||||
if (state.setMax) {
|
||||
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, state.currency, isToken);
|
||||
const pendingAmount: BigNumber = getPendingAmount(pending, state.currency, isToken);
|
||||
|
||||
if (isToken) {
|
||||
const token: ?Token = findToken(tokens, account.address, state.currency, account.deviceState);
|
||||
@ -277,7 +268,7 @@ export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState):
|
||||
});
|
||||
};
|
||||
|
||||
export const toggleAdvanced = (address: string): Action => ({
|
||||
export const toggleAdvanced = (/* address: string */): Action => ({
|
||||
type: SEND.TOGGLE_ADVANCED,
|
||||
});
|
||||
|
||||
@ -286,7 +277,6 @@ const addressValidation = (): ThunkAction => (dispatch: Dispatch, getState: GetS
|
||||
const {
|
||||
account,
|
||||
network,
|
||||
tokens,
|
||||
} = getState().selectedAccount;
|
||||
if (!account || !network) return;
|
||||
|
||||
@ -310,7 +300,7 @@ const addressValidation = (): ThunkAction => (dispatch: Dispatch, getState: GetS
|
||||
} else {
|
||||
const otherNetworkAccount = savedAccounts[0];
|
||||
const device: ?TrezorDevice = findDevice(getState().devices, otherNetworkAccount.deviceID, otherNetworkAccount.deviceState);
|
||||
const coins = getState().localStorage.config.coins;
|
||||
const { coins } = getState().localStorage.config;
|
||||
const otherNetwork: ?Coin = coins.find(c => c.network === otherNetworkAccount.network);
|
||||
if (device && otherNetwork) {
|
||||
warnings.address = `Looks like it's ${device.instanceLabel} Account #${(otherNetworkAccount.index + 1)} address of ${otherNetwork.name} network`;
|
||||
@ -351,7 +341,7 @@ export const validation = (props: Props): void => {
|
||||
if (state.untouched) return;
|
||||
// valid address
|
||||
if (state.touched.address) {
|
||||
if (state.address.length < 1) {
|
||||
/* if (state.address.length < 1) {
|
||||
errors.address = 'Address is not set';
|
||||
} else if (!EthereumjsUtil.isValidAddress(state.address)) {
|
||||
errors.address = 'Address is not valid';
|
||||
@ -363,6 +353,20 @@ export const validation = (props: Props): void => {
|
||||
} else if (state.infos.address) {
|
||||
infos.address = state.infos.address;
|
||||
}
|
||||
} */
|
||||
|
||||
/* eslint (no-lonely-if) */
|
||||
if (state.address.length < 1) {
|
||||
errors.address = 'Address is not set';
|
||||
} else if (!EthereumjsUtil.isValidAddress(state.address)) {
|
||||
errors.address = 'Address is not valid';
|
||||
} else if (state.warnings.address) {
|
||||
// address warning or info are set in addressValidation ThunkAction
|
||||
// do not override this
|
||||
warnings.address = state.warnings.address;
|
||||
if (state.infos.address) {
|
||||
infos.address = state.infos.address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,7 +380,7 @@ export const validation = (props: Props): void => {
|
||||
errors.amount = 'Amount is not a number';
|
||||
} else {
|
||||
let decimalRegExp: RegExp;
|
||||
const pendingAmount: BigNumber = stateUtils.getPendingAmount(pending, state.currency, state.currency !== state.networkSymbol);
|
||||
const pendingAmount: BigNumber = getPendingAmount(pending, state.currency, state.currency !== state.networkSymbol);
|
||||
|
||||
if (state.currency !== state.networkSymbol) {
|
||||
const token = findToken(tokens, account.address, state.currency, account.deviceState);
|
||||
@ -612,7 +616,7 @@ export const updateFeeLevels = (): ThunkAction => (dispatch: Dispatch, getState:
|
||||
// update only gasPrice
|
||||
currentState.selectedFeeLevel.gasPrice = currentState.recommendedGasPrice;
|
||||
// leave gas limit as it was
|
||||
gasLimit = currentState.gasLimit;
|
||||
({ gasLimit } = currentState);
|
||||
}
|
||||
|
||||
const feeLevels: Array<FeeLevel> = getFeeLevels(network.symbol, currentState.recommendedGasPrice, gasLimit, currentState.selectedFeeLevel);
|
||||
@ -659,9 +663,8 @@ export const onGasPriceChange = (gasPrice: string): ThunkAction => (dispatch: Di
|
||||
});
|
||||
};
|
||||
|
||||
export const onGasLimitChange = (gasLimit: string, updateFeeLevels: boolean = false): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const onGasLimitChange = (gasLimit: string/* , shouldUpdateFeeLevels: boolean = false */): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const currentState: State = getState().sendForm;
|
||||
const isToken: boolean = currentState.currency !== currentState.networkSymbol;
|
||||
|
||||
const touched = { ...currentState.touched };
|
||||
touched.gasLimit = true;
|
||||
@ -704,34 +707,6 @@ export const onNonceChange = (nonce: string): AsyncAction => async (dispatch: Di
|
||||
});
|
||||
};
|
||||
|
||||
export const onDataChange = (data: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const currentState: State = getState().sendForm;
|
||||
const touched = { ...currentState.touched };
|
||||
touched.data = true;
|
||||
|
||||
const state: State = {
|
||||
...currentState,
|
||||
calculatingGasLimit: true,
|
||||
untouched: false,
|
||||
touched,
|
||||
data,
|
||||
};
|
||||
|
||||
if (currentState.selectedFeeLevel.value !== 'Custom') {
|
||||
const customLevel = currentState.feeLevels.find(f => f.value === 'Custom');
|
||||
if (!customLevel) return;
|
||||
state.selectedFeeLevel = customLevel;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: SEND.DATA_CHANGE,
|
||||
state,
|
||||
});
|
||||
|
||||
dispatch(estimateGasPrice());
|
||||
};
|
||||
|
||||
|
||||
const estimateGasPrice = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const {
|
||||
web3,
|
||||
@ -771,6 +746,33 @@ const estimateGasPrice = (): AsyncAction => async (dispatch: Dispatch, getState:
|
||||
}
|
||||
};
|
||||
|
||||
export const onDataChange = (data: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const currentState: State = getState().sendForm;
|
||||
const touched = { ...currentState.touched };
|
||||
touched.data = true;
|
||||
|
||||
const state: State = {
|
||||
...currentState,
|
||||
calculatingGasLimit: true,
|
||||
untouched: false,
|
||||
touched,
|
||||
data,
|
||||
};
|
||||
|
||||
if (currentState.selectedFeeLevel.value !== 'Custom') {
|
||||
const customLevel = currentState.feeLevels.find(f => f.value === 'Custom');
|
||||
if (!customLevel) return;
|
||||
state.selectedFeeLevel = customLevel;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: SEND.DATA_CHANGE,
|
||||
state,
|
||||
});
|
||||
|
||||
dispatch(estimateGasPrice());
|
||||
};
|
||||
|
||||
export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const {
|
||||
account,
|
||||
@ -806,7 +808,7 @@ export const onSend = (): AsyncAction => async (dispatch: Dispatch, getState: Ge
|
||||
txAddress = token.address;
|
||||
}
|
||||
|
||||
const pendingNonce: number = stateUtils.getPendingNonce(pending);
|
||||
const pendingNonce: number = getPendingNonce(pending);
|
||||
const nonce = pendingNonce > 0 && pendingNonce >= account.nonce ? pendingNonce : account.nonce;
|
||||
|
||||
console.warn('NONCE', nonce, account.nonce, pendingNonce);
|
||||
|
@ -1,17 +1,11 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import EthereumjsUtil from 'ethereumjs-util';
|
||||
import * as SUMMARY from 'actions/constants/summary';
|
||||
import * as TOKEN from 'actions/constants/token';
|
||||
import { resolveAfter } from 'utils/promiseUtils';
|
||||
import { initialState } from 'reducers/SummaryReducer';
|
||||
|
||||
import type {
|
||||
ThunkAction, AsyncAction, Action, GetState, Dispatch,
|
||||
ThunkAction, Action, Dispatch,
|
||||
} from 'flowtype';
|
||||
import type { State } from 'reducers/SummaryReducer';
|
||||
import type { Token } from 'reducers/TokensReducer';
|
||||
|
||||
export type SummaryAction = {
|
||||
type: typeof SUMMARY.INIT,
|
||||
@ -22,7 +16,7 @@ export type SummaryAction = {
|
||||
type: typeof SUMMARY.DETAILS_TOGGLE
|
||||
}
|
||||
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||
const state: State = {
|
||||
...initialState,
|
||||
};
|
||||
|
@ -25,10 +25,6 @@ export type TokenAction = {
|
||||
payload: State
|
||||
}
|
||||
|
||||
type SelectOptions = {
|
||||
options?: Array<NetworkToken>
|
||||
}
|
||||
|
||||
|
||||
// action from component <reactSelect>
|
||||
export const load = (input: string, network: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<any> => {
|
||||
@ -57,6 +53,20 @@ export const load = (input: string, network: string): AsyncAction => async (disp
|
||||
//await resolveAfter(3000);
|
||||
};
|
||||
|
||||
export const setBalance = (tokenAddress: string, ethAddress: string, balance: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const newState: Array<Token> = [...getState().tokens];
|
||||
const token: ?Token = newState.find(t => t.address === tokenAddress && t.ethAddress === ethAddress);
|
||||
if (token) {
|
||||
token.loaded = true;
|
||||
token.balance = balance;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: TOKEN.SET_BALANCE,
|
||||
payload: newState,
|
||||
});
|
||||
};
|
||||
|
||||
export const add = (token: NetworkToken, account: Account): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.find(w3 => w3.network === account.network);
|
||||
if (!web3instance) return;
|
||||
@ -82,20 +92,6 @@ export const add = (token: NetworkToken, account: Account): AsyncAction => async
|
||||
dispatch(setBalance(token.address, account.address, tokenBalance));
|
||||
};
|
||||
|
||||
export const setBalance = (tokenAddress: string, ethAddress: string, balance: string): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const newState: Array<Token> = [...getState().tokens];
|
||||
const token: ?Token = newState.find(t => t.address === tokenAddress && t.ethAddress === ethAddress);
|
||||
if (token) {
|
||||
token.loaded = true;
|
||||
token.balance = balance;
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: TOKEN.SET_BALANCE,
|
||||
payload: newState,
|
||||
});
|
||||
};
|
||||
|
||||
export const remove = (token: Token): Action => ({
|
||||
type: TOKEN.REMOVE,
|
||||
token,
|
||||
|
@ -1,10 +1,7 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import TrezorConnect, {
|
||||
UI, DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT,
|
||||
DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT,
|
||||
} from 'trezor-connect';
|
||||
import * as TOKEN from 'actions/constants/token';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
@ -82,6 +79,13 @@ export type TrezorConnectAction = {
|
||||
};
|
||||
|
||||
|
||||
const sortDevices = (devices: Array<TrezorDevice>): Array<TrezorDevice> => devices.sort((a, b) => {
|
||||
if (!a.ts || !b.ts) {
|
||||
return -1;
|
||||
}
|
||||
return a.ts > b.ts ? -1 : 1;
|
||||
});
|
||||
|
||||
export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
// set listeners
|
||||
TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => {
|
||||
@ -112,7 +116,7 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS
|
||||
});
|
||||
|
||||
// $FlowIssue LOCAL not declared
|
||||
window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/';
|
||||
// window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/';
|
||||
// window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://connect.trezor.io/5/';
|
||||
//window.__TREZOR_CONNECT_SRC = 'https://sisyfos.trezor.io/connect/';
|
||||
// window.__TREZOR_CONNECT_SRC = 'https://localhost:8088/';
|
||||
@ -133,71 +137,6 @@ export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetS
|
||||
}
|
||||
};
|
||||
|
||||
// called after backend was initialized
|
||||
// set listeners for connect/disconnect
|
||||
export const postInit = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const handleDeviceConnect = (device: Device) => {
|
||||
dispatch(initConnectedDevice(device));
|
||||
};
|
||||
|
||||
TrezorConnect.off(DEVICE.CONNECT, handleDeviceConnect);
|
||||
TrezorConnect.off(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||
|
||||
TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect);
|
||||
TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||
|
||||
const { devices } = getState();
|
||||
|
||||
const { initialPathname, initialParams } = getState().wallet;
|
||||
|
||||
if (initialPathname) {
|
||||
dispatch({
|
||||
type: WALLET.SET_INITIAL_URL,
|
||||
// pathname: null,
|
||||
// params: null
|
||||
});
|
||||
}
|
||||
|
||||
if (devices.length > 0) {
|
||||
const unacquired: ?TrezorDevice = devices.find(d => d.features);
|
||||
if (unacquired) {
|
||||
dispatch(onSelectDevice(unacquired));
|
||||
} else {
|
||||
const latest: Array<TrezorDevice> = sortDevices(devices);
|
||||
const firstConnected: ?TrezorDevice = latest.find(d => d.connected);
|
||||
dispatch(onSelectDevice(firstConnected || latest[0]));
|
||||
|
||||
// TODO
|
||||
if (initialParams) {
|
||||
if (!initialParams.hasOwnProperty('network') && initialPathname !== getState().router.location.pathname) {
|
||||
// dispatch( push(initialPathname) );
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sortDevices = (devices: Array<TrezorDevice>): Array<TrezorDevice> => devices.sort((a, b) => {
|
||||
if (!a.ts || !b.ts) {
|
||||
return -1;
|
||||
}
|
||||
return a.ts > b.ts ? -1 : 1;
|
||||
});
|
||||
|
||||
export const initConnectedDevice = (device: TrezorDevice | Device): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const selected = getState().wallet.selectedDevice;
|
||||
// if (!selected || (selected && selected.state)) {
|
||||
dispatch(onSelectDevice(device));
|
||||
// }
|
||||
// if (device.unacquired && selected && selected.path !== device.path && !selected.connected) {
|
||||
// dispatch( onSelectDevice(device) );
|
||||
// } else if (!selected) {
|
||||
// dispatch( onSelectDevice(device) );
|
||||
// }
|
||||
};
|
||||
|
||||
// selection from Aside dropdown button
|
||||
// after device_connect event
|
||||
// or after acquiring device
|
||||
@ -242,6 +181,62 @@ export const onSelectDevice = (device: TrezorDevice | Device): ThunkAction => (d
|
||||
}
|
||||
};
|
||||
|
||||
export const initConnectedDevice = (device: TrezorDevice | Device): ThunkAction => (dispatch: Dispatch/* , getState: GetState */): void => {
|
||||
// const selected = getState().wallet.selectedDevice;
|
||||
// if (!selected || (selected && selected.state)) {
|
||||
dispatch(onSelectDevice(device));
|
||||
// }
|
||||
// if (device.unacquired && selected && selected.path !== device.path && !selected.connected) {
|
||||
// dispatch( onSelectDevice(device) );
|
||||
// } else if (!selected) {
|
||||
// dispatch( onSelectDevice(device) );
|
||||
// }
|
||||
};
|
||||
|
||||
// called after backend was initialized
|
||||
// set listeners for connect/disconnect
|
||||
export const postInit = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const handleDeviceConnect = (device: Device) => {
|
||||
dispatch(initConnectedDevice(device));
|
||||
};
|
||||
|
||||
TrezorConnect.off(DEVICE.CONNECT, handleDeviceConnect);
|
||||
TrezorConnect.off(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||
|
||||
TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect);
|
||||
TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
|
||||
|
||||
const { devices } = getState();
|
||||
|
||||
const { initialPathname, initialParams } = getState().wallet;
|
||||
|
||||
if (initialPathname) {
|
||||
dispatch({
|
||||
type: WALLET.SET_INITIAL_URL,
|
||||
// pathname: null,
|
||||
// params: null
|
||||
});
|
||||
}
|
||||
|
||||
if (devices.length > 0) {
|
||||
const unacquired: ?TrezorDevice = devices.find(d => d.features);
|
||||
if (unacquired) {
|
||||
dispatch(onSelectDevice(unacquired));
|
||||
} else {
|
||||
const latest: Array<TrezorDevice> = sortDevices(devices);
|
||||
const firstConnected: ?TrezorDevice = latest.find(d => d.connected);
|
||||
dispatch(onSelectDevice(firstConnected || latest[0]));
|
||||
|
||||
// TODO
|
||||
if (initialParams) {
|
||||
if (!initialParams.hasOwnProperty('network') && initialPathname !== getState().router.location.pathname) {
|
||||
// dispatch( push(initialPathname) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const switchToFirstAvailableDevice = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const { devices } = getState();
|
||||
if (devices.length > 0) {
|
||||
@ -388,7 +383,7 @@ export function acquire(): AsyncAction {
|
||||
};
|
||||
}
|
||||
|
||||
export const gotoDeviceSettings = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const gotoDeviceSettings = (device: TrezorDevice): ThunkAction => (dispatch: Dispatch): void => {
|
||||
if (device.features) {
|
||||
const devUrl: string = `${device.features.device_id}${device.instance ? `:${device.instance}` : ''}`;
|
||||
dispatch(push(`/device/${devUrl}/settings`));
|
||||
|
@ -3,16 +3,10 @@
|
||||
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as stateUtils from 'reducers/utils';
|
||||
|
||||
import type
|
||||
{
|
||||
Account,
|
||||
Coin,
|
||||
Discovery,
|
||||
Token,
|
||||
Web3Instance,
|
||||
Device,
|
||||
TrezorDevice,
|
||||
RouterLocationState,
|
||||
@ -47,8 +41,8 @@ export type WalletAction = {
|
||||
devices: Array<TrezorDevice>
|
||||
}
|
||||
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
const updateOnlineStatus = (event) => {
|
||||
export const init = (): ThunkAction => (dispatch: Dispatch): void => {
|
||||
const updateOnlineStatus = () => {
|
||||
dispatch({
|
||||
type: WALLET.ONLINE_STATUS,
|
||||
online: navigator.onLine,
|
||||
@ -72,7 +66,7 @@ export const toggleDeviceDropdown = (opened: boolean): WalletAction => ({
|
||||
// all saved instances will be removed immediately inside DevicesReducer
|
||||
// This method will clear leftovers associated with removed instances from reducers.
|
||||
// (DiscoveryReducer, AccountReducer, TokensReducer)
|
||||
export const clearUnavailableDevicesData = (prevState: State, device: Device): ThunkAction => (dispatch: Dispatch, getState: GetState): void => {
|
||||
export const clearUnavailableDevicesData = (prevState: State, device: Device): ThunkAction => (dispatch: Dispatch): void => {
|
||||
if (!device.features) return;
|
||||
|
||||
const affectedDevices = prevState.devices.filter(d => d.features && device.features
|
||||
|
@ -1,23 +1,19 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import Web3 from 'web3';
|
||||
import HDKey from 'hdkey';
|
||||
|
||||
import EthereumjsUtil from 'ethereumjs-util';
|
||||
import EthereumjsTx from 'ethereumjs-tx';
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import type { ContractFactory, EstimateGasOptions } from 'web3';
|
||||
import type {
|
||||
ContractFactory,
|
||||
EstimateGasOptions,
|
||||
TransactionStatus,
|
||||
TransactionReceipt,
|
||||
} from 'web3';
|
||||
import type BigNumber from 'bignumber.js';
|
||||
import type { TransactionStatus, TransactionReceipt } from 'web3';
|
||||
import { strip } from 'utils/ethUtils';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
import * as PENDING from 'actions/constants/pendingTx';
|
||||
|
||||
import type {
|
||||
Dispatch,
|
||||
GetState,
|
||||
Action,
|
||||
AsyncAction,
|
||||
} from 'flowtype';
|
||||
|
||||
@ -29,15 +25,6 @@ import type { NetworkToken } from 'reducers/LocalStorageReducer';
|
||||
import * as TokenActions from './TokenActions';
|
||||
import * as AccountsActions from './AccountsActions';
|
||||
|
||||
export type Web3Action = {
|
||||
type: typeof WEB3.READY,
|
||||
} | {
|
||||
type: typeof WEB3.CREATE,
|
||||
instance: Web3Instance
|
||||
}
|
||||
| Web3UpdateBlockAction
|
||||
| Web3UpdateGasPriceAction;
|
||||
|
||||
export type Web3UpdateBlockAction = {
|
||||
type: typeof WEB3.BLOCK_UPDATED,
|
||||
network: string,
|
||||
@ -50,6 +37,14 @@ export type Web3UpdateGasPriceAction = {
|
||||
gasPrice: string
|
||||
};
|
||||
|
||||
export type Web3Action = {
|
||||
type: typeof WEB3.READY,
|
||||
} | {
|
||||
type: typeof WEB3.CREATE,
|
||||
instance: Web3Instance
|
||||
}
|
||||
| Web3UpdateBlockAction
|
||||
| Web3UpdateGasPriceAction;
|
||||
|
||||
export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
@ -64,7 +59,7 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||
return;
|
||||
}
|
||||
|
||||
const network = coin.network;
|
||||
const { network } = coin;
|
||||
const urls = coin.backends[0].urls;
|
||||
|
||||
let web3host: string = urls[0];
|
||||
@ -150,7 +145,7 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||
|
||||
//const shh = instance.shh.newIdentity();
|
||||
|
||||
const latestBlockFilter = web3.eth.filter('latest');
|
||||
// const latestBlockFilter = web3.eth.filter('latest');
|
||||
|
||||
const onBlockMined = async (error: ?Error, blockHash: ?string) => {
|
||||
if (error) {
|
||||
@ -186,16 +181,12 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
|
||||
}
|
||||
|
||||
const tokens = getState().tokens.filter(t => t.network === network);
|
||||
for (const token of tokens) {
|
||||
dispatch(getTokenBalance(token));
|
||||
}
|
||||
tokens.forEach(token => dispatch(getTokenBalance(token)));
|
||||
|
||||
dispatch(getGasPrice(network));
|
||||
|
||||
const pending = getState().pending.filter(p => p.network === network);
|
||||
for (const tx of pending) {
|
||||
dispatch(getTransactionReceipt(tx));
|
||||
}
|
||||
pending.forEach(pendingTx => dispatch(getTransactionReceipt(pendingTx)));
|
||||
};
|
||||
|
||||
// latestBlockFilter.watch(onBlockMined);
|
||||
@ -220,7 +211,7 @@ export function getGasPrice(network: string): AsyncAction {
|
||||
const index: number = getState().web3.findIndex(w3 => w3.network === network);
|
||||
|
||||
const web3instance = getState().web3[index];
|
||||
const web3 = web3instance.web3;
|
||||
const { web3 } = web3instance;
|
||||
web3.eth.getGasPrice((error, gasPrice) => {
|
||||
if (!error) {
|
||||
if (web3instance.gasPrice && web3instance.gasPrice.toString() !== gasPrice.toString()) {
|
||||
@ -238,7 +229,7 @@ export function getGasPrice(network: string): AsyncAction {
|
||||
export function getBalance(account: Account): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0];
|
||||
const web3: Web3 = web3instance.web3;
|
||||
const { web3 } = web3instance;
|
||||
|
||||
web3.eth.getBalance(account.address, (error: Error, balance: BigNumber) => {
|
||||
if (!error) {
|
||||
@ -261,7 +252,6 @@ export function getBalance(account: Account): AsyncAction {
|
||||
export function getTokenBalance(token: Token): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.filter(w3 => w3.network === token.network)[0];
|
||||
const web3 = web3instance.web3;
|
||||
const contract = web3instance.erc20.at(token.address);
|
||||
|
||||
contract.balanceOf(token.ethAddress, (error: Error, balance: BigNumber) => {
|
||||
@ -282,7 +272,7 @@ export function getTokenBalance(token: Token): AsyncAction {
|
||||
export function getNonce(account: Account): AsyncAction {
|
||||
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.filter(w3 => w3.network === account.network)[0];
|
||||
const web3 = web3instance.web3;
|
||||
const { web3 } = web3instance;
|
||||
|
||||
web3.eth.getTransactionCount(account.address, (error: Error, result: number) => {
|
||||
if (!error) {
|
||||
@ -296,7 +286,7 @@ export function getNonce(account: Account): AsyncAction {
|
||||
|
||||
export const getTransactionReceipt = (tx: PendingTx): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
|
||||
const web3instance = getState().web3.filter(w3 => w3.network === tx.network)[0];
|
||||
const web3 = web3instance.web3;
|
||||
const { web3 } = web3instance;
|
||||
|
||||
web3.eth.getTransaction(tx.id, (error: Error, status: TransactionStatus) => {
|
||||
if (!error && !status) {
|
||||
@ -367,8 +357,8 @@ export const getNonceAsync = (web3: Web3, address: string): Promise<number> => n
|
||||
});
|
||||
|
||||
|
||||
export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise<?NetworkToken> => new Promise((resolve, reject) => {
|
||||
const contract = erc20.at(address, (error, res) => {
|
||||
export const getTokenInfoAsync = (erc20: ContractFactory, address: string): Promise<?NetworkToken> => new Promise((resolve) => {
|
||||
const contract = erc20.at(address, (error/* , res */) => {
|
||||
// console.warn("callback", error, res)
|
||||
});
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
import Icon from 'components/Icon';
|
||||
import colors from 'config/colors';
|
||||
import { TRANSITION } from 'config/variables';
|
||||
|
||||
@ -82,7 +81,7 @@ const Wrapper = styled.button`
|
||||
left: 18px;
|
||||
}
|
||||
|
||||
&:after {
|
||||
&:after {
|
||||
width: 2px;
|
||||
height: 12px;
|
||||
left: 23px;
|
||||
@ -107,66 +106,47 @@ const Wrapper = styled.button`
|
||||
`}
|
||||
`;
|
||||
|
||||
const IconWrapper = styled.span`
|
||||
${props => ((props.hasChildren && !props.isRight) ? 'margin: 0 8px 0 -4px;' : '')};
|
||||
${props => ((props.hasChildren && props.isRight) ? 'margin: 0 -4px 0 8px;' : '')};
|
||||
`;
|
||||
|
||||
const Button = ({
|
||||
children,
|
||||
className,
|
||||
icon,
|
||||
onClick = () => { },
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
onFocus,
|
||||
isDisabled = false,
|
||||
isWhite = false,
|
||||
isWebUsb = false,
|
||||
isTransparent = false,
|
||||
hasIconRight = false,
|
||||
}) => (
|
||||
<Wrapper
|
||||
className={className}
|
||||
icon={icon}
|
||||
onClick={onClick}
|
||||
isDisabled={isDisabled}
|
||||
isWhite={isWhite}
|
||||
isWebUsb={isWebUsb}
|
||||
isTransparent={isTransparent}
|
||||
>
|
||||
{hasIconRight && children}
|
||||
{icon && (
|
||||
<IconWrapper
|
||||
hasChildren={!!children}
|
||||
isRight={hasIconRight}
|
||||
>
|
||||
<Icon
|
||||
icon={icon.type}
|
||||
color={icon.color}
|
||||
size={icon.size}
|
||||
isActive={icon.isActive}
|
||||
canAnimate={icon.canAnimate}
|
||||
/>
|
||||
</IconWrapper>
|
||||
)}
|
||||
{!hasIconRight && children}
|
||||
</Wrapper>
|
||||
);
|
||||
}) => {
|
||||
const newClassName = isWebUsb ? `${className} trezor-webusb-button` : className;
|
||||
return (
|
||||
<Wrapper
|
||||
className={newClassName}
|
||||
onClick={onClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onFocus={onFocus}
|
||||
isDisabled={isDisabled}
|
||||
isWhite={isWhite}
|
||||
isWebUsb={isWebUsb}
|
||||
isTransparent={isTransparent}
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
Button.propTypes = {
|
||||
children: PropTypes.element.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
className: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
||||
onMouseEnter: PropTypes.func,
|
||||
onMouseLeave: PropTypes.func,
|
||||
onFocus: PropTypes.func,
|
||||
isDisabled: PropTypes.bool,
|
||||
isWhite: PropTypes.bool,
|
||||
isWebUsb: PropTypes.bool,
|
||||
isTransparent: PropTypes.bool,
|
||||
icon: PropTypes.shape({
|
||||
type: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
color: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
isActive: PropTypes.bool,
|
||||
canAnimate: PropTypes.bool,
|
||||
}),
|
||||
hasIconRight: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default Button;
|
@ -31,7 +31,7 @@ const Footer = ({ toggle }) => (
|
||||
<Wrapper>
|
||||
<Copy>© {getYear(new Date())}</Copy>
|
||||
<StyledLink href="http://satoshilabs.com" target="_blank" rel="noreferrer noopener" isGreen>SatoshiLabs</StyledLink>
|
||||
<StyledLink href="tos.pdf" target="_blank" rel="noreferrer noopener" isGreen>Terms</StyledLink>
|
||||
<StyledLink href="/assets/tos.pdf" target="_blank" rel="noreferrer noopener" isGreen>Terms</StyledLink>
|
||||
<StyledLink onClick={toggle} isGreen>Show Log</StyledLink>
|
||||
</Wrapper>
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import colors from 'config/colors';
|
||||
import styled, { keyframes } from 'styled-components';
|
||||
|
||||
// TODO: make animation of icons better
|
||||
@ -23,16 +24,25 @@ const rotate180down = keyframes`
|
||||
|
||||
const SvgWrapper = styled.svg`
|
||||
animation: ${props => (props.canAnimate ? (props.isActive ? rotate180up : rotate180down) : null)} 0.2s linear 1 forwards;
|
||||
|
||||
:hover {
|
||||
path {
|
||||
fill: ${props => props.hoverColor || colors.TEXT_SECONDARY}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Path = styled.path``;
|
||||
const Path = styled.path`
|
||||
fill: ${props => props.color};
|
||||
`;
|
||||
|
||||
const Icon = ({
|
||||
icon,
|
||||
size = 32,
|
||||
color = 'black',
|
||||
color = colors.TEXT_SECONDARY,
|
||||
isActive,
|
||||
canAnimate,
|
||||
hoverColor,
|
||||
className,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
@ -42,6 +52,7 @@ const Icon = ({
|
||||
<SvgWrapper
|
||||
className={className}
|
||||
canAnimate={canAnimate}
|
||||
hoverColor={hoverColor}
|
||||
isActive={isActive}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
@ -59,7 +70,7 @@ const Icon = ({
|
||||
<Path
|
||||
key={path}
|
||||
isActive={isActive}
|
||||
style={{ fill: color }}
|
||||
color={color}
|
||||
d={path}
|
||||
/>
|
||||
))}
|
||||
@ -68,6 +79,7 @@ const Icon = ({
|
||||
|
||||
Icon.propTypes = {
|
||||
className: PropTypes.string,
|
||||
hoverColor: PropTypes.string,
|
||||
canAnimate: PropTypes.bool,
|
||||
icon: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
size: PropTypes.number,
|
||||
|
@ -84,7 +84,7 @@ const NotificationButton = ({
|
||||
);
|
||||
|
||||
NotificationButton.propTypes = {
|
||||
children: PropTypes.element.isRequired,
|
||||
children: PropTypes.node.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
className: PropTypes.string,
|
||||
onClick: PropTypes.func,
|
@ -3,14 +3,13 @@ import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import styled, { css } from 'styled-components';
|
||||
import colors from 'config/colors';
|
||||
import NotificationButton from 'components/buttons/NotificationButton';
|
||||
import Icon from 'components/Icon';
|
||||
import icons from 'config/icons';
|
||||
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
||||
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import * as NotificationActions from 'actions/NotificationActions';
|
||||
import Loader from 'components/Loader';
|
||||
import NotificationButton from './components/NotificationButton';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
position: relative;
|
||||
@ -45,7 +44,6 @@ const Wrapper = styled.div`
|
||||
const Body = styled.div`
|
||||
display: flex;
|
||||
margin-right: 40px;
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
const Title = styled.div`
|
||||
@ -53,8 +51,6 @@ const Title = styled.div`
|
||||
font-weight: ${FONT_WEIGHT.BIGGER};
|
||||
`;
|
||||
|
||||
const ActionContent = styled.div``;
|
||||
|
||||
const CloseClick = styled.div`
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@ -81,7 +77,17 @@ const Texts = styled.div`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const AdditionalContent = styled.div``;
|
||||
const AdditionalContent = styled.div`
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: flex-end;
|
||||
`;
|
||||
|
||||
const ActionContent = styled.div`
|
||||
justify-content: right;
|
||||
align-items: flex-end;
|
||||
`;
|
||||
|
||||
export const Notification = (props: NProps): React$Element<string> => {
|
||||
const close: Function = typeof props.close === 'function' ? props.close : () => {}; // TODO: add default close action
|
||||
@ -109,12 +115,12 @@ export const Notification = (props: NProps): React$Element<string> => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper type={props.className}>
|
||||
<Wrapper type={props.type}>
|
||||
{props.loading && <Loader size={50} /> }
|
||||
{props.cancelable && (
|
||||
<CloseClick onClick={() => close()}>
|
||||
<Icon
|
||||
color={getIconColor(props.className)}
|
||||
color={getIconColor(props.type)}
|
||||
icon={icons.CLOSE}
|
||||
size={20}
|
||||
/>
|
||||
@ -123,8 +129,8 @@ export const Notification = (props: NProps): React$Element<string> => {
|
||||
<Body>
|
||||
<MessageContent>
|
||||
<StyledIcon
|
||||
color={getIconColor(props.className)}
|
||||
icon={icons[props.className.toUpperCase()]}
|
||||
color={getIconColor(props.type)}
|
||||
icon={icons[props.type.toUpperCase()]}
|
||||
/>
|
||||
<Texts>
|
||||
<Title>{ props.title }</Title>
|
||||
@ -142,7 +148,7 @@ export const Notification = (props: NProps): React$Element<string> => {
|
||||
{props.actions.map(action => (
|
||||
<NotificationButton
|
||||
key={action.label}
|
||||
type={props.className}
|
||||
type={props.type}
|
||||
text={action.label}
|
||||
onClick={() => { close(); action.callback(); }}
|
||||
>{action.label}
|
||||
@ -157,10 +163,10 @@ export const Notification = (props: NProps): React$Element<string> => {
|
||||
|
||||
export const NotificationGroup = (props) => {
|
||||
const { notifications, close } = props;
|
||||
return notifications.map((n, i) => (
|
||||
return notifications.map(n => (
|
||||
<Notification
|
||||
key={i}
|
||||
className={n.type}
|
||||
key={n.title}
|
||||
type={n.type}
|
||||
title={n.title}
|
||||
message={n.message}
|
||||
cancelable={n.cancelable}
|
||||
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
||||
import ReactSelect from 'react-select';
|
||||
import ReactAsyncSelect from 'react-select/lib/Async';
|
||||
import colors from 'config/colors';
|
||||
import { FONT_FAMILY } from 'config/variables';
|
||||
|
||||
const styles = isSearchable => ({
|
||||
singleValue: base => ({
|
||||
@ -12,6 +13,7 @@ const styles = isSearchable => ({
|
||||
}),
|
||||
control: (base, { isDisabled }) => ({
|
||||
...base,
|
||||
fontFamily: FONT_FAMILY.MONOSPACE,
|
||||
minHeight: 'initial',
|
||||
height: '100%',
|
||||
borderRadius: '2px',
|
||||
@ -43,6 +45,7 @@ const styles = isSearchable => ({
|
||||
menuList: base => ({
|
||||
...base,
|
||||
padding: 0,
|
||||
fontFamily: FONT_FAMILY.MONOSPACE,
|
||||
boxShadow: 'none',
|
||||
background: colors.WHITE,
|
||||
borderLeft: `1px solid ${colors.DIVIDER}`,
|
||||
|
@ -2,23 +2,29 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import colors from 'config/colors';
|
||||
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
||||
import { FONT_SIZE, FONT_WEIGHT, FONT_FAMILY } from 'config/variables';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
`;
|
||||
|
||||
const disabledColor = colors.TEXT_PRIMARY;
|
||||
|
||||
const TextArea = styled.textarea`
|
||||
width: 100%;
|
||||
padding: 5px 10px;
|
||||
padding: 6px 12px;
|
||||
box-sizing: border-box;
|
||||
min-height: 25px;
|
||||
border: ${props => (props.isError ? `1px solid ${colors.ERROR_PRIMARY}` : `1px solid ${colors.TEXT_PRIMARY}`)};
|
||||
border: ${props => (props.isError ? `1px solid ${colors.ERROR_PRIMARY}` : `1px solid ${colors.DIVIDER}`)};
|
||||
border-radius: 2px;
|
||||
resize: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
font-family: ${FONT_FAMILY.MONOSPACE};
|
||||
color: ${colors.TEXT_PRIMARY};
|
||||
background: ${colors.WHITE};
|
||||
font-weight: ${FONT_WEIGHT.BASE};
|
||||
font-size: ${FONT_SIZE.BASE};
|
||||
white-space: pre-wrap; /* css-3 */
|
||||
@ -73,34 +79,38 @@ const TextArea = styled.textarea`
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
&:hover:not(:disabled),
|
||||
&:focus:not(:disabled) {
|
||||
border: 1px solid ${colors.TEXT_SECONDARY};
|
||||
}
|
||||
const TopLabel = styled.span`
|
||||
padding-bottom: 4px;
|
||||
color: ${colors.TEXT_SECONDARY};
|
||||
`;
|
||||
|
||||
const Textarea = ({
|
||||
className,
|
||||
placeholder = '',
|
||||
value = '',
|
||||
value,
|
||||
customStyle = {},
|
||||
onFocus,
|
||||
onBlur,
|
||||
disabled,
|
||||
isDisabled,
|
||||
onChange,
|
||||
isError,
|
||||
topLabel,
|
||||
}) => (
|
||||
<Wrapper>
|
||||
{topLabel && (
|
||||
<TopLabel>{topLabel}</TopLabel>
|
||||
)}
|
||||
<TextArea
|
||||
className={className}
|
||||
disabled={disabled}
|
||||
disabled={isDisabled}
|
||||
style={customStyle}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
value={value}
|
||||
placeholder={placeholder}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
onChange={onChange}
|
||||
isError={isError}
|
||||
/>
|
||||
</Wrapper>
|
||||
@ -115,7 +125,8 @@ Textarea.propTypes = {
|
||||
customStyle: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
isDisabled: PropTypes.bool,
|
||||
topLabel: PropTypes.node,
|
||||
};
|
||||
|
||||
export default Textarea;
|
||||
|
213
src/components/Tooltip/index.js
Normal file
213
src/components/Tooltip/index.js
Normal file
@ -0,0 +1,213 @@
|
||||
import React, { Component } from 'react';
|
||||
import RcTooltip from 'rc-tooltip';
|
||||
import colors from 'config/colors';
|
||||
import styled from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FONT_SIZE } from 'config/variables';
|
||||
|
||||
const TooltipContent = styled.div`
|
||||
width: ${props => (props.isAside ? '260px' : '320px')};
|
||||
font-size: ${FONT_SIZE.SMALLEST};
|
||||
`;
|
||||
|
||||
const Wrapper = styled.div`
|
||||
.rc-tooltip {
|
||||
position: absolute;
|
||||
z-index: 1070;
|
||||
display: block;
|
||||
background: red;
|
||||
visibility: visible;
|
||||
border: 1px solid ${colors.DIVIDER};
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.rc-tooltip-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rc-tooltip-inner {
|
||||
padding: 8px 10px;
|
||||
color: ${colors.TEXT_SECONDARY};
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
background-color: ${colors.WHITE};
|
||||
border-radius: 3px;
|
||||
min-height: 34px;
|
||||
border: 1px solid ${colors.WHITE};
|
||||
}
|
||||
|
||||
.rc-tooltip-arrow,
|
||||
.rc-tooltip-arrow-inner {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-top .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-topLeft .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-topRight .rc-tooltip-arrow {
|
||||
bottom: -6px;
|
||||
margin-left: -6px;
|
||||
border-width: 6px 6px 0;
|
||||
border-top-color: ${colors.DIVIDER};
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-top .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-topLeft .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-topRight .rc-tooltip-arrow-inner {
|
||||
bottom: 2px;
|
||||
margin-left: -6px;
|
||||
border-width: 6px 6px 0;
|
||||
border-top-color: ${colors.WHITE};
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-top .rc-tooltip-arrow {
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-topLeft .rc-tooltip-arrow {
|
||||
left: 15%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-topRight .rc-tooltip-arrow {
|
||||
right: 15%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-right .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-rightTop .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-rightBottom .rc-tooltip-arrow {
|
||||
left: -5px;
|
||||
margin-top: -6px;
|
||||
border-width: 6px 6px 6px 0;
|
||||
border-right-color: ${colors.DIVIDER};
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-right .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-rightTop .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-rightBottom .rc-tooltip-arrow-inner {
|
||||
left: 1px;
|
||||
margin-top: -6px;
|
||||
border-width: 6px 6px 6px 0;
|
||||
border-right-color: ${colors.WHITE};
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-right .rc-tooltip-arrow {
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-rightTop .rc-tooltip-arrow {
|
||||
top: 15%;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-rightBottom .rc-tooltip-arrow {
|
||||
bottom: 15%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-left .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-leftTop .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-leftBottom .rc-tooltip-arrow {
|
||||
right: -5px;
|
||||
margin-top: -6px;
|
||||
border-width: 6px 0 6px 6px;
|
||||
border-left-color: ${colors.DIVIDER};
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-left .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-leftTop .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-leftBottom .rc-tooltip-arrow-inner {
|
||||
right: 1px;
|
||||
margin-top: -6px;
|
||||
border-width: 6px 0 6px 6px;
|
||||
border-left-color: ${colors.WHITE};
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-left .rc-tooltip-arrow {
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-leftTop .rc-tooltip-arrow {
|
||||
top: 15%;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-leftBottom .rc-tooltip-arrow {
|
||||
bottom: 15%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-bottom .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-bottomLeft .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-bottomRight .rc-tooltip-arrow {
|
||||
top: -5px;
|
||||
margin-left: -6px;
|
||||
border-width: 0 6px 6px;
|
||||
border-bottom-color: ${colors.DIVIDER};
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-bottom .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-bottomLeft .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-bottomRight .rc-tooltip-arrow-inner {
|
||||
top: 1px;
|
||||
margin-left: -6px;
|
||||
border-width: 0 6px 6px;
|
||||
border-bottom-color: ${colors.WHITE};
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-bottom .rc-tooltip-arrow {
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-bottomLeft .rc-tooltip-arrow {
|
||||
left: 15%;
|
||||
}
|
||||
|
||||
.rc-tooltip-placement-bottomRight .rc-tooltip-arrow {
|
||||
right: 15%;
|
||||
}
|
||||
`;
|
||||
|
||||
class Tooltip extends Component {
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
placement,
|
||||
content,
|
||||
children,
|
||||
} = this.props;
|
||||
return (
|
||||
<Wrapper
|
||||
className={className}
|
||||
innerRef={(node) => { this.tooltipContainerRef = node; }}
|
||||
>
|
||||
<RcTooltip
|
||||
getTooltipContainer={() => this.tooltipContainerRef}
|
||||
arrowContent={<div className="rc-tooltip-arrow-inner" />}
|
||||
placement={placement}
|
||||
overlay={<TooltipContent>{content}</TooltipContent>}
|
||||
>
|
||||
{children}
|
||||
</RcTooltip>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Tooltip.propTypes = {
|
||||
className: PropTypes.string,
|
||||
placement: PropTypes.string,
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.element,
|
||||
PropTypes.string,
|
||||
]),
|
||||
content: PropTypes.oneOfType([
|
||||
PropTypes.element,
|
||||
PropTypes.string,
|
||||
]),
|
||||
};
|
||||
|
||||
export default Tooltip;
|
@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FONT_SIZE } from 'config/variables';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
width: ${props => (props.isAside ? '260px' : '320px')};
|
||||
font-size: ${FONT_SIZE.SMALLEST};
|
||||
`;
|
||||
|
||||
const TooltipContent = ({
|
||||
children, isAside = false,
|
||||
}) => (
|
||||
<Wrapper
|
||||
isAside={isAside}
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
);
|
||||
|
||||
TooltipContent.propTypes = {
|
||||
children: PropTypes.node,
|
||||
isAside: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default TooltipContent;
|
@ -4,7 +4,12 @@ import styled, { css } from 'styled-components';
|
||||
import colors from 'config/colors';
|
||||
import ICONS from 'config/icons';
|
||||
import Icon from 'components/Icon';
|
||||
import { FONT_SIZE, FONT_WEIGHT, TRANSITION } from 'config/variables';
|
||||
import {
|
||||
FONT_SIZE,
|
||||
FONT_WEIGHT,
|
||||
TRANSITION,
|
||||
FONT_FAMILY,
|
||||
} from 'config/variables';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
width: 100%;
|
||||
@ -23,7 +28,7 @@ const InputIconWrapper = styled.div`
|
||||
display: inline-block;
|
||||
`;
|
||||
|
||||
const InputLabel = styled.span`
|
||||
const TopLabel = styled.span`
|
||||
padding-bottom: 4px;
|
||||
color: ${colors.TEXT_SECONDARY};
|
||||
`;
|
||||
@ -33,8 +38,9 @@ const StyledInput = styled.input`
|
||||
padding: 6px 12px;
|
||||
|
||||
line-height: 1.42857143;
|
||||
font-family: ${FONT_FAMILY.MONOSPACE};
|
||||
font-size: ${FONT_SIZE.SMALL};
|
||||
font-weight: ${FONT_WEIGHT.SMALLEST};
|
||||
font-weight: ${FONT_WEIGHT.BASE};
|
||||
color: ${colors.TEXT_PRIMARY};
|
||||
|
||||
border-radius: 2px;
|
||||
@ -96,8 +102,8 @@ class Input extends Component {
|
||||
<Wrapper
|
||||
className={this.props.className}
|
||||
>
|
||||
{this.props.inputLabel && (
|
||||
<InputLabel>{this.props.inputLabel}</InputLabel>
|
||||
{this.props.topLabel && (
|
||||
<TopLabel>{this.props.topLabel}</TopLabel>
|
||||
)}
|
||||
<InputWrapper>
|
||||
<InputIconWrapper>
|
||||
@ -147,7 +153,7 @@ Input.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
state: PropTypes.string,
|
||||
bottomText: PropTypes.string,
|
||||
inputLabel: PropTypes.string,
|
||||
topLabel: PropTypes.node,
|
||||
sideAddons: PropTypes.arrayOf(PropTypes.node),
|
||||
isDisabled: PropTypes.bool,
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled, { css } from 'styled-components';
|
||||
import styled from 'styled-components';
|
||||
import colors from 'config/colors';
|
||||
import Icon from 'components/Icon';
|
||||
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
||||
|
@ -6,11 +6,10 @@ import styled from 'styled-components';
|
||||
import Icon from 'components/Icon';
|
||||
import colors from 'config/colors';
|
||||
import icons from 'config/icons';
|
||||
import Button from 'components/buttons/Button';
|
||||
import Button from 'components/Button';
|
||||
import Link from 'components/Link';
|
||||
import { findAccount } from 'reducers/AccountsReducer';
|
||||
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
const StyledLink = styled(Link)`
|
||||
position: absolute;
|
||||
@ -38,15 +37,6 @@ const StyledButton = styled(Button)`
|
||||
`;
|
||||
|
||||
class ConfirmUnverifiedAddress extends Component<Props> {
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
this.verifyAddress();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
this.keyboardHandler = this.keyboardHandler.bind(this);
|
||||
window.addEventListener('keydown', this.keyboardHandler, false);
|
||||
@ -56,6 +46,15 @@ class ConfirmUnverifiedAddress extends Component<Props> {
|
||||
window.removeEventListener('keydown', this.keyboardHandler, false);
|
||||
}
|
||||
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
this.verifyAddress();
|
||||
}
|
||||
}
|
||||
|
||||
verifyAddress() {
|
||||
if (!this.props.modal.opened) return;
|
||||
const {
|
||||
|
@ -3,7 +3,7 @@ import React, { Component } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { H3 } from 'components/Heading';
|
||||
import P from 'components/Paragraph';
|
||||
import Button from 'components/buttons/Button';
|
||||
import Button from 'components/Button';
|
||||
import Input from 'components/inputs/Input';
|
||||
import { getDuplicateInstanceNumber } from 'reducers/utils';
|
||||
import { FONT_SIZE } from 'config/variables';
|
||||
@ -63,12 +63,12 @@ const ErrorMessage = styled.div`
|
||||
`;
|
||||
|
||||
export default class DuplicateDevice extends Component<Props, State> {
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
state: State;
|
||||
|
||||
input: ?HTMLInputElement;
|
||||
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@ -85,13 +85,6 @@ export default class DuplicateDevice extends Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13 && !this.state.isUsed) {
|
||||
event.preventDefault();
|
||||
this.submit();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
// one time autofocus
|
||||
if (this.input) this.input.focus();
|
||||
@ -115,6 +108,13 @@ export default class DuplicateDevice extends Component<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13 && !this.state.isUsed) {
|
||||
event.preventDefault();
|
||||
this.submit();
|
||||
}
|
||||
}
|
||||
|
||||
submit() {
|
||||
if (!this.props.modal.opened) return;
|
||||
const extended: Object = { instanceName: this.state.instanceName, instance: this.state.instance };
|
||||
@ -125,7 +125,7 @@ export default class DuplicateDevice extends Component<Props, State> {
|
||||
if (!this.props.modal.opened) return null;
|
||||
|
||||
const { device } = this.props.modal;
|
||||
const { onCancel, onDuplicateDevice } = this.props.modalActions;
|
||||
const { onCancel } = this.props.modalActions;
|
||||
const {
|
||||
defaultName,
|
||||
instanceName,
|
||||
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { H3 } from 'components/Heading';
|
||||
import P from 'components/Paragraph';
|
||||
import Button from 'components/buttons/Button';
|
||||
import Button from 'components/Button';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
width: 360px;
|
||||
|
@ -4,9 +4,9 @@ import styled from 'styled-components';
|
||||
import { H3 } from 'components/Heading';
|
||||
import P from 'components/Paragraph';
|
||||
import Loader from 'components/Loader';
|
||||
import Button from 'components/buttons/Button';
|
||||
import Button from 'components/Button';
|
||||
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
type State = {
|
||||
countdown: number;
|
||||
@ -77,9 +77,9 @@ export default class RememberDevice extends Component<Props, State> {
|
||||
this.props.modalActions.onForgetDevice(this.props.modal.device);
|
||||
}
|
||||
} else {
|
||||
this.setState({
|
||||
countdown: this.state.countdown - 1,
|
||||
});
|
||||
this.setState(previousState => ({
|
||||
countdown: previousState.countdown - 1,
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
@ -108,16 +108,16 @@ export default class RememberDevice extends Component<Props, State> {
|
||||
render() {
|
||||
if (!this.props.modal.opened) return null;
|
||||
const { device, instances } = this.props.modal;
|
||||
const { onForgetDevice, onRememberDevice } = this.props.modalActions;
|
||||
const { onRememberDevice } = this.props.modalActions;
|
||||
|
||||
let label = device.label;
|
||||
let { label } = device;
|
||||
const devicePlural: string = instances && instances.length > 1 ? 'devices or to remember them' : 'device or to remember it';
|
||||
if (instances && instances.length > 0) {
|
||||
label = instances.map((instance, index) => {
|
||||
let comma: string = '';
|
||||
if (index > 0) comma = ', ';
|
||||
return (
|
||||
<span key={index}>{ comma }{ instance.instanceLabel }</span>
|
||||
<span key={instance.instanceLabel}>{ comma }{ instance.instanceLabel }</span>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ import { CSSTransition } from 'react-transition-group';
|
||||
|
||||
import { UI } from 'trezor-connect';
|
||||
|
||||
import { default as ModalActions } from 'actions/ModalActions';
|
||||
import { default as ReceiveActions } from 'actions/ReceiveActions';
|
||||
import ModalActions from 'actions/ModalActions';
|
||||
import ReceiveActions from 'actions/ReceiveActions';
|
||||
|
||||
import * as RECEIVE from 'actions/constants/receive';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
@ -51,8 +51,6 @@ type DispatchProps = {
|
||||
|
||||
export type Props = StateProps & DispatchProps;
|
||||
|
||||
const duration = 300;
|
||||
|
||||
const Fade = ({ children, ...props }) => (
|
||||
<CSSTransition
|
||||
{...props}
|
||||
@ -75,7 +73,7 @@ const ModalContainer = styled.div`
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
overflow: auto;
|
||||
padding: 20px;
|
||||
padding: 20px;
|
||||
`;
|
||||
|
||||
const ModalWindow = styled.div`
|
||||
@ -125,7 +123,8 @@ class Modal extends Component<Props> {
|
||||
component = (<DuplicateDevice {...this.props} />);
|
||||
break;
|
||||
|
||||
default: null;
|
||||
default:
|
||||
component = null;
|
||||
}
|
||||
|
||||
let ch = null;
|
||||
@ -145,7 +144,7 @@ class Modal extends Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State, own: OwnProps): StateProps => ({
|
||||
const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: State): StateProps => ({
|
||||
modal: state.modal,
|
||||
accounts: state.accounts,
|
||||
devices: state.devices,
|
||||
|
@ -4,14 +4,13 @@ import raf from 'raf';
|
||||
import colors from 'config/colors';
|
||||
import P from 'components/Paragraph';
|
||||
import { FONT_SIZE } from 'config/variables';
|
||||
import { H2 } from 'components/Heading';
|
||||
import Link from 'components/Link';
|
||||
import Checkbox from 'components/Checkbox';
|
||||
import Button from 'components/buttons/Button';
|
||||
import Button from 'components/Button';
|
||||
import Input from 'components/inputs/Input';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding: 24px 48px;
|
||||
@ -55,14 +54,6 @@ type State = {
|
||||
}
|
||||
|
||||
export default class PinModal extends Component<Props, State> {
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
state: State;
|
||||
|
||||
passphraseInput: ?HTMLInputElement;
|
||||
|
||||
passphraseRevisionInput: ?HTMLInputElement;
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@ -91,6 +82,15 @@ export default class PinModal extends Component<Props, State> {
|
||||
};
|
||||
}
|
||||
|
||||
keyboardHandler: (event: KeyboardEvent) => void;
|
||||
|
||||
state: State;
|
||||
|
||||
passphraseInput: ?HTMLInputElement;
|
||||
|
||||
passphraseRevisionInput: ?HTMLInputElement;
|
||||
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
@ -108,6 +108,7 @@ export default class PinModal extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
componentDidMount(): void {
|
||||
// one time autofocus
|
||||
if (this.passphraseInput) this.passphraseInput.focus();
|
||||
@ -124,15 +125,6 @@ export default class PinModal extends Component<Props, State> {
|
||||
// };
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
window.removeEventListener('keydown', this.keyboardHandler, false);
|
||||
// this.passphraseInput.type = 'text';
|
||||
// this.passphraseInput.style.display = 'none';
|
||||
// this.passphraseRevisionInput.type = 'text';
|
||||
// this.passphraseRevisionInput.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
// we don't want to keep password inside "value" attribute,
|
||||
// so we need to replace it thru javascript
|
||||
componentDidUpdate() {
|
||||
@ -164,21 +156,30 @@ export default class PinModal extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
window.removeEventListener('keydown', this.keyboardHandler, false);
|
||||
// this.passphraseInput.type = 'text';
|
||||
// this.passphraseInput.style.display = 'none';
|
||||
// this.passphraseRevisionInput.type = 'text';
|
||||
// this.passphraseRevisionInput.style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
onPassphraseChange = (input: string, value: string): void => {
|
||||
// https://codepen.io/MiDri/pen/PGqvrO
|
||||
// or
|
||||
// https://github.com/zakangelle/react-password-mask/blob/master/src/index.js
|
||||
if (input === 'passphrase') {
|
||||
this.setState({
|
||||
match: this.state.singleInput || this.state.passphraseRevision === value,
|
||||
this.setState(previousState => ({
|
||||
match: previousState.singleInput || previousState.passphraseRevision === value,
|
||||
passphrase: value,
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
this.setState({
|
||||
match: this.state.passphrase === value,
|
||||
this.setState(previousState => ({
|
||||
match: previousState.passphrase === value,
|
||||
passphraseRevision: value,
|
||||
passphraseRevisionTouched: true,
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,7 +308,7 @@ export default class PinModal extends Component<Props, State> {
|
||||
onBlur={() => this.onPassphraseBlur('revision')}
|
||||
tabIndex="2"
|
||||
/>
|
||||
{!match && passphraseRevisionTouched && <PassphraseError className="error">Passphrases do not match</PassphraseError> }
|
||||
{!match && passphraseRevisionTouched && <PassphraseError>Passphrases do not match</PassphraseError> }
|
||||
</Row>
|
||||
) }
|
||||
<Row>
|
||||
|
@ -3,7 +3,7 @@ import styled from 'styled-components';
|
||||
import { H3 } from 'components/Heading';
|
||||
import P from 'components/Paragraph';
|
||||
|
||||
import type { Props } from './index';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
padding: 24px 48px;
|
||||
|
@ -3,12 +3,11 @@ import P from 'components/Paragraph';
|
||||
import { H2 } from 'components/Heading';
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'components/Link';
|
||||
import colors from 'config/colors';
|
||||
import styled from 'styled-components';
|
||||
import PinInput from 'components/inputs/PinInput';
|
||||
import PinButton from 'components/buttons/PinButton';
|
||||
import Button from 'components/buttons/Button';
|
||||
import type { Props } from './index';
|
||||
import Button from 'components/Button';
|
||||
import PinButton from './components/PinButton';
|
||||
import type { Props } from '../../index';
|
||||
|
||||
type State = {
|
||||
pin: string;
|
||||
@ -53,7 +52,7 @@ class Pin extends Component<Props, State> {
|
||||
}
|
||||
|
||||
onPinAdd = (input: number): void => {
|
||||
let pin: string = this.state.pin;
|
||||
let { pin } = this.state;
|
||||
if (pin.length < 9) {
|
||||
pin += input;
|
||||
this.setState({
|
||||
@ -63,9 +62,9 @@ class Pin extends Component<Props, State> {
|
||||
}
|
||||
|
||||
onPinBackspace = (): void => {
|
||||
this.setState({
|
||||
pin: this.state.pin.substring(0, this.state.pin.length - 1),
|
||||
});
|
||||
this.setState(previousState => ({
|
||||
pin: previousState.pin.substring(0, previousState.pin.length - 1),
|
||||
}));
|
||||
}
|
||||
|
||||
keyboardHandler(event: KeyboardEvent): void {
|
||||
|
@ -1,4 +1,14 @@
|
||||
export default {
|
||||
TOP: [
|
||||
'M677.44 613.76c-3.255 1.423-7.047 2.252-11.033 2.252-0.284 0-0.566-0.004-0.848-0.013l0.041 0.001c-8.323-0.531-15.657-4.371-20.77-10.206l-0.030-0.034-93.44-109.44c-0.378-0.735-1.131-1.229-1.999-1.229-1.237 0-2.24 1.003-2.24 2.24 0 0.209 0.029 0.412 0.083 0.605l-0.004-0.016v233.28c0.102 0.987 0.16 2.132 0.16 3.291 0 18.733-15.187 33.92-33.92 33.92s-33.92-15.187-33.92-33.92c0-1.159 0.058-2.304 0.172-3.433l-0.012 0.142v-236.16c0.050-0.177 0.079-0.379 0.079-0.589 0-1.237-1.003-2.24-2.24-2.24-0.868 0-1.621 0.494-1.993 1.216l-0.006 0.013-88.32 104.32c-5.204 6.343-13.042 10.358-21.819 10.358-7.711 0-14.699-3.099-19.784-8.121l0.003 0.003c-6.16-5.845-9.993-14.090-9.993-23.231 0-8.17 3.062-15.625 8.101-21.28l-0.028 0.032 146.56-173.44c5.311-6.15 13.061-10.069 21.731-10.24h0.029c8.727 0.036 16.523 3.991 21.724 10.196l0.036 0.044 152 178.56c5.441 6.124 8.764 14.234 8.764 23.121 0 12.698-6.785 23.81-16.927 29.911l-0.157 0.088z',
|
||||
'M329.28 292.8c-0.024-0.488-0.038-1.060-0.038-1.635 0-18.891 14.881-34.306 33.561-35.163l0.077-0.003h292.48c18.795 1.81 33.372 17.523 33.372 36.64s-14.577 34.83-33.222 36.628l-0.15 0.012h-292.48c-18.751-0.866-33.625-16.278-33.625-35.165 0-0.463 0.009-0.923 0.027-1.381l-0.002 0.066z',
|
||||
],
|
||||
EYE_CROSSED: [
|
||||
'M768 456.64c-20.16-34.88-44.48-63.68-71.68-86.72l-64.64 64.64c0.64 4.16 0.96 8.64 0.96 12.8 0 60.16-51.84 108.8-115.84 108.8-2.24 0-4.16 0-6.4-0.32l-33.92 33.92c12.16 1.6 24 2.24 36.16 2.24 98.88 0 197.44-45.12 255.36-135.36zM348.8 646.080c-8.96 8.96-23.68 8.96-32.64 0l-3.52-3.52c-8.96-8.96-8.96-23.68 0-32.64l53.76-53.76c-43.52-22.4-81.6-56.32-110.4-100.8 83.84-130.56 226.88-177.6 348.48-137.28l57.6-57.6c9.28-9.28 23.68-9.28 32.96 0l3.2 3.2c8.96 8.96 8.96 23.68 0 32.64l-349.44 349.76zM516.8 338.56c-64-0.32-115.84 48.64-115.84 108.48-0.32 21.12 6.080 40.64 17.28 57.28l42.56-42.56c-1.92-5.76-2.56-12.16-1.92-18.88 2.88-30.080 30.72-52.16 62.72-49.92 2.24 0.32 4.8 0.64 7.040 0.96l42.56-42.56c-16.32-8.32-34.56-12.8-54.4-12.8z',
|
||||
],
|
||||
EYE: [
|
||||
'M512.64 592c-99.2 0-198.4-45.76-256.64-136.64 128.64-200 394.56-203.84 512 1.28-57.92 90.24-156.48 135.36-255.36 135.36zM516.8 338.56c-64-0.32-115.84 48.64-115.84 108.48-0.32 60.16 51.52 109.12 115.84 109.12 64 0 115.84-48.64 115.84-108.8 0.32-60.16-51.52-108.8-115.84-108.8zM574.72 451.84c2.56-30.080-21.12-56.32-53.12-58.88-32-2.24-59.84 19.84-62.72 49.92-2.56 30.080 21.44 56.32 53.12 58.56 32 2.56 59.84-19.84 62.72-49.6z',
|
||||
],
|
||||
CHECKED: [
|
||||
'M692.8 313.92l-1.92-1.92c-6.246-7.057-15.326-11.484-25.44-11.484s-19.194 4.427-25.409 11.448l-0.031 0.036-196.48 224-3.84 1.6-3.84-1.92-48.64-57.28c-7.010-7.905-17.193-12.862-28.533-12.862-21.031 0-38.080 17.049-38.080 38.080 0 7.495 2.165 14.485 5.905 20.377l-0.092-0.155 100.8 148.16c5.391 8.036 14.386 13.292 24.618 13.44h8.662c17.251-0.146 32.385-9.075 41.163-22.529l0.117-0.191 195.2-296.32c4.473-6.632 7.141-14.803 7.141-23.597 0-11.162-4.297-21.32-11.326-28.911l0.025 0.028z',
|
||||
],
|
||||
|
@ -14,6 +14,12 @@ export const FONT_WEIGHT = {
|
||||
BIGGER: '600',
|
||||
};
|
||||
|
||||
export const FONT_FAMILY = {
|
||||
DEFAULT: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif',
|
||||
MONOSPACE: '"Roboto Mono", Menlo, Monaco, Consolas, "Courier New", monospace',
|
||||
MONOSPACE_NUMBERS: '"Roboto Zero", "Roboto Mono", Menlo, Monaco, Consolas, "Courier New", monospace',
|
||||
};
|
||||
|
||||
export const ICON_SIZE = {
|
||||
BASE: '20px',
|
||||
};
|
||||
|
@ -7,11 +7,10 @@ import type {
|
||||
Middleware as ReduxMiddleware,
|
||||
ThunkAction as ReduxThunkAction,
|
||||
AsyncAction as ReduxAsyncAction,
|
||||
ThunkDispatch as ReduxThunkDispatch,
|
||||
PlainDispatch as ReduxPlainDispatch,
|
||||
} from 'redux';
|
||||
|
||||
import type { Reducers, ReducersState } from 'reducers';
|
||||
import type { ReducersState } from 'reducers';
|
||||
|
||||
// Actions
|
||||
import type { SelectedAccountAction } from 'actions/SelectedAccountActions';
|
||||
|
Binary file not shown.
@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Generated by IcoMoon</metadata>
|
||||
<defs>
|
||||
<font id="icomoon" horiz-adv-x="1024">
|
||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||
<missing-glyph horiz-adv-x="1024" />
|
||||
<glyph unicode=" " horiz-adv-x="512" d="" />
|
||||
<glyph unicode="" glyph-name="icon-unlocked" d="M381.088 483.648v89.696c0 72.16 53.696 130.656 119.904 130.656h35.104c66.208 0 119.904-58.496 119.904-130.656v-7.616h-69.312c-4.416 36.704-33.248 65.056-68.128 65.056-37.952 0-68.736-33.536-68.736-74.88v-72.288h221.184c18.208 0 32.992-15.552 32.992-34.72v-222.24c0-19.104-14.784-34.656-32.992-34.656h-318.016c-18.208 0-32.992 15.552-32.992 34.72v222.24c0 19.168 14.784 34.72 32.992 34.72h28.096z" />
|
||||
<glyph unicode="" glyph-name="icon-locked" d="M671.008 483.648h-14.976v89.632c0 72.256-53.76 130.72-120.064 130.72h-35.136c-66.304 0-119.744-58.464-119.744-130.72v-89.632h-28.096c-18.336 0-32.992-15.424-32.992-34.688v-222.272c0-18.944 14.656-34.688 32.992-34.688h318.016c18.336 0 32.992 15.744 32.992 34.688v222.272c0 19.264-14.656 34.688-32.992 34.688zM449.824 555.936c0 41.44 30.56 74.848 68.736 74.848 34.816 0 63.552-33.728 68.128-70.336v-76.768h-136.864v72.256z" />
|
||||
<glyph unicode="" glyph-name="icon-eject" d="M276 192h471.968c11.072 0 20.032 9.76 20.032 21.824v75.968c0 12.064-8.96 21.824-20 21.824h-472c-11.040 0-20-9.76-20-21.824v-75.968c0-12.064 8.96-21.824 20-21.824zM503.552 699.808l-231.232-288.128c-6.368-7.904-1.184-20.32 8.448-20.32h462.496c9.664 0 14.816 12.384 8.448 20.32l-231.232 288.128c-4.512 5.6-12.448 5.6-16.928 0z" />
|
||||
<glyph unicode="" glyph-name="icon-refresh" d="M347.392 486.688c17.28 82.24 90.4 142.336 173.92 142.336 31.648 0 61.92-8.704 88.576-24.416 6.656-3.936 12.8-8.672 18.944-13.504l-68.832-68.736 192-33.056-32 198.272-38.4-42.016c-5.92 5.024-12.064 9.728-18.336 14.144-40.928 28.672-89.92 44.288-141.92 44.288-121.664 0-225.12-89.312-245.984-210.368l-3.36-20.896h72.672l2.72 13.952zM676.608 409.312c-17.28-82.24-90.4-142.336-173.92-142.336-31.648 0-61.92 8.704-88.576 24.416-6.624 3.936-12.8 8.672-18.944 13.504l68.832 68.736-192 33.056 32-198.272 38.4 42.016c5.92-5.024 12.032-9.696 18.336-14.144 40.928-28.672 89.92-44.288 141.952-44.288 121.664 0 225.12 89.312 245.984 210.368l3.328 20.864h-72.672l-2.72-13.92z" />
|
||||
<glyph unicode="" glyph-name="icon-info" d="M693.024 629.056c-99.968 99.936-262.080 99.936-362.048 0s-99.968-262.112 0-362.080c99.968-100 262.144-99.936 362.048 0 99.968 99.904 99.968 262.176 0 362.080zM507.904 659.808c27.008 0 48.992-21.984 48.992-49.088 0-27.296-21.984-49.472-48.992-49.472-27.264 0-49.536 22.176-49.536 49.472 0 27.552 21.728 49.088 49.536 49.088zM586.656 299.2c0-10.304-4.96-15.328-15.264-15.328h-126.464c-10.304 0-15.328 5.024-15.328 15.328v32.256c0 10.304 5.024 15.264 15.328 15.264h23.36v136.064h-23.872c-10.304 0-15.264 5.024-15.264 15.328v32.224c0 10.304 4.96 15.264 15.264 15.264h88.288c10.304 0 15.264-4.96 15.264-15.264v-183.648h23.424c10.304 0 15.264-4.96 15.264-15.264v-32.224z" />
|
||||
<glyph unicode="" glyph-name="icon-chat" d="M580.992 704h-137.984c-103.296 0-187.008-85.952-187.008-192 0-96.608 69.536-176.32 160-189.792v-130.208l128 128h36.992c103.296 0 187.008 85.952 187.008 192s-83.712 192-187.008 192z" />
|
||||
<glyph unicode="" glyph-name="icon-skip" d="M512 704c-141.376 0-256-114.656-256-256 0-141.408 114.624-256 256-256s256 114.592 256 256c0 141.344-114.624 256-256 256zM529.056 328.544v68.256c-102.4 34.144-136.544 0-170.656-68.256 0 170.656 102.4 204.8 170.656 204.8v68.256l136.544-136.544-136.544-136.512z" />
|
||||
<glyph unicode="" glyph-name="icon-cog" d="M739.552 497.856h-71.328c-4.256 13.664-10.208 26.56-17.472 38.56l47.264 47.424c11.2 11.008 11.2 29.056 0 40.192l-20.064 20.032c-11.136 11.104-29.152 11.040-40.192 0l-48.128-48.032c-12.992 7.392-27.072 13.152-42.080 16.992v62.496c0 15.68-12.672 28.48-28.448 28.48h-28.448c-15.68 0-28.416-12.8-28.416-28.48v-62.464c-16.352-4.128-31.68-10.656-45.728-19.2l-40.288 40.224c-11.072 11.040-29.184 11.104-40.288 0l-20.096-20.096c-11.104-11.072-10.976-29.152 0.064-40.288l40.992-40.992c-8.672-15.136-15.168-31.648-18.88-49.152h-53.504c-15.776 0-28.544-12.736-28.544-28.48v-28.416c0-15.68 12.768-28.416 28.544-28.416h57.152c5.184-17.152 12.992-32.928 23.008-47.328l-38.656-38.656c-11.136-11.136-11.136-29.216-0.064-40.288l20.064-20.096c11.2-11.040 29.248-11.040 40.32 0.032l43.232 43.2c14.528-7.232 30.336-12.48 46.944-15.2v-59.488c0-15.68 12.736-28.448 28.448-28.48h28.448c15.68 0.032 28.448 12.8 28.448 28.48v66.816c14.336 5.088 27.904 11.872 40.224 20.544l45.76-45.888c11.104-11.072 29.12-11.072 40.224 0l20.096 20.128c11.168 11.072 11.168 29.056-0.096 40.288l-50.144 50.24c6.144 12.512 10.944 25.792 13.92 39.904h67.776c15.744 0 28.448 12.672 28.48 28.448v28.448c-0.096 15.68-12.8 28.512-28.544 28.512zM504.928 376.928c-39.264 0-71.072 31.776-71.072 71.104 0 39.264 31.808 71.040 71.072 71.040 39.296 0 71.136-31.776 71.136-71.040 0-39.328-31.84-71.104-71.136-71.104z" />
|
||||
<glyph unicode="" glyph-name="icon-warning" d="M795.616 224.992l-264.896 465.44c-10.272 18.080-27.168 18.080-37.504 0l-264.864-465.44c-10.272-18.176-1.696-32.992 19.040-32.992h529.184c20.8 0 29.376 14.816 19.040 32.992zM549.76 286.88c0-10.464-8.48-18.976-18.912-18.976h-37.792c-10.336 0-18.912 8.512-18.912 18.976v37.952c0 10.464 8.576 18.976 18.912 18.976h37.792c10.4 0 18.912-8.544 18.912-18.976v-37.952zM549.76 400.736c0-10.464-8.48-18.976-18.912-18.976h-37.792c-10.336 0-18.912 8.512-18.912 18.976v113.856c0 10.464 8.576 18.976 18.912 18.976h37.792c10.4 0 18.912-8.544 18.912-18.976v-113.856z" />
|
||||
<glyph unicode="" glyph-name="icon-arrow-down" d="M757.216 539.072l-219.616-237.44c-8.128-8.576-19.296-13.632-31.040-13.632-11.744 0.288-23.2 5.056-31.040 13.664l-208.768 227.040c-15.36 16.928-14.176 43.040 3.008 58.176 16.864 15.424 43.392 13.952 59.040-2.656l177.76-193.504 188.608 203.904c7.52 8 18.080 12.768 29.216 13.344 11.456 0.608 21.696-3.264 30.112-10.688 16.896-15.456 18.080-41.568 2.72-58.208z" />
|
||||
<glyph unicode="" glyph-name="icon-close" d="M754.816 270.080c17.6-17.6 17.6-46.72 0-64.64-8.96-8.64-20.48-13.44-32.64-13.44s-23.68 4.8-32.32 13.44l-177.888 177.92-177.888-177.92c-16.32-16.96-47.040-17.6-64.64 0-17.92 17.92-17.92 47.040 0 64.64l178.208 177.92-178.208 177.92c-17.92 17.92-17.92 46.72 0 64.64 17.28 17.28 47.36 17.28 64.64 0l177.888-177.92 177.888 177.92c17.92 17.92 47.040 17.92 64.96 0 17.6-17.92 17.6-46.72 0-64.64l-178.24-177.92 178.24-177.92z" />
|
||||
<glyph unicode="" glyph-name="icon-arrow-up" d="M757.216 356.928l-219.616 237.44c-8.128 8.576-19.296 13.632-31.040 13.632-11.744-0.288-23.2-5.056-31.040-13.664l-208.768-227.040c-15.36-16.928-14.176-43.040 3.008-58.176 16.864-15.424 43.392-13.952 59.040 2.656l177.76 193.504 188.608-203.904c7.52-8 18.080-12.768 29.216-13.344 11.456-0.608 21.696 3.264 30.112 10.688 16.896 15.456 18.080 41.568 2.72 58.208z" />
|
||||
<glyph unicode="" glyph-name="icon-arrow-right2" d="M420.928 202.784l237.44 219.616c8.576 8.128 13.632 19.296 13.632 31.040-0.288 11.744-5.056 23.2-13.664 31.040l-227.040 208.768c-16.928 15.36-43.040 14.176-58.176-3.008-15.424-16.864-13.952-43.392 2.656-59.040l193.504-177.76-203.904-188.608c-8-7.52-12.768-18.080-13.344-29.216-0.608-11.456 3.264-21.696 10.688-30.112 15.456-16.896 41.568-18.080 58.208-2.72z" />
|
||||
<glyph unicode="" glyph-name="icon-plus" d="M768 448c0-22.080-17.92-40-40-40h-176v-176c0-22.080-17.92-40-40-40s-40 17.92-40 40v176h-176c-22.080 0-40 17.92-40 40s17.92 40 40 40h176v176c0 22.080 17.92 40 40 40s40-17.92 40-40v-176h176c22.080 0 40-17.92 40-40z" />
|
||||
<glyph unicode="" glyph-name="icon-arrow-right" d="M420.928 202.784l237.44 219.616c8.576 8.128 13.632 19.296 13.632 31.040-0.288 11.744-5.056 23.2-13.664 31.040l-227.040 208.768c-16.928 15.36-43.040 14.176-58.176-3.008-15.424-16.864-13.952-43.392 2.656-59.040l193.504-177.76-203.904-188.608c-8-7.52-12.768-18.080-13.344-29.216-0.608-11.456 3.264-21.696 10.688-30.112 15.456-16.896 41.568-18.080 58.208-2.72z" />
|
||||
<glyph unicode="" glyph-name="icon-help" d="M693.024 629.056c-99.968 99.936-262.080 99.936-362.048 0s-99.968-262.112 0-362.080c99.968-100 262.144-99.936 362.048 0 99.968 99.904 99.968 262.176 0 362.080zM501.216 242.048c-27.808 0-50.496 22.464-50.496 50.048 0 28.32 22.176 50.528 50.496 50.528 27.616 0 50.048-22.656 50.048-50.528 0.032-27.168-22.88-50.048-50.048-50.048zM536.416 417.536v-27.744c0-13.504-5.28-18.784-18.784-18.784h-36.224c-13.504 0-18.72 5.28-18.72 18.784v61.984c0 15.68 16.064 20.352 30.208 24.48 3.456 1.056 7.040 2.080 10.496 3.264 18.336 6.592 29.696 14.816 29.696 35.296 0 6.656 0 26.816-32.832 26.816-20.224 0-38.624-7.776-49.6-12.416-6.208-2.624-9.28-3.904-12.384-3.904-6.336 0-12.32 5.088-13.248 10.304l-12.608 32.96c-1.824 3.776-1.824 6.784-1.824 9.216 0 24.288 75.552 37.664 100.608 37.664 63.104 0 105.504-40.672 105.504-101.152 0.032-65.44-49.12-85.952-80.288-96.768z" />
|
||||
<glyph unicode="" glyph-name="icon-dashboard" d="M768 672v-160c0-17.6-14.4-32-32-32h-160c-17.6 0-32 14.4-32 32v160c0 17.6 14.4 32 32 32h160c17.6 0 32-14.4 32-32zM480 384v-160c0-17.6-14.4-32-32-32h-160c-17.6 0-32 14.4-32 32v160c0 17.6 14.4 32 32 32h160c17.6 0 32-14.4 32-32zM480 672v-160c0-17.6-14.4-32-32-32h-160c-17.6 0-32 14.4-32 32v160c0 17.6 14.4 32 32 32h160c17.6 0 32-14.4 32-32zM768 384v-160c0-17.6-14.4-32-32-32h-160c-17.6 0-32 14.4-32 32v160c0 17.6 14.4 32 32 32h160c17.6 0 32-14.4 32-32z" />
|
||||
<glyph unicode="" glyph-name="icon-eye-crossed" d="M768 456.64c-20.16-34.88-44.48-63.68-71.68-86.72l-64.64 64.64c0.64 4.16 0.96 8.64 0.96 12.8 0 60.16-51.84 108.8-115.84 108.8-2.24 0-4.16 0-6.4-0.32l-33.92 33.92c12.16 1.6 24 2.24 36.16 2.24 98.88 0 197.44-45.12 255.36-135.36zM348.8 646.080c-8.96 8.96-23.68 8.96-32.64 0l-3.52-3.52c-8.96-8.96-8.96-23.68 0-32.64l53.76-53.76c-43.52-22.4-81.6-56.32-110.4-100.8 83.84-130.56 226.88-177.6 348.48-137.28l57.6-57.6c9.28-9.28 23.68-9.28 32.96 0l3.2 3.2c8.96 8.96 8.96 23.68 0 32.64l-349.44 349.76zM516.8 338.56c-64-0.32-115.84 48.64-115.84 108.48-0.32 21.12 6.080 40.64 17.28 57.28l42.56-42.56c-1.92-5.76-2.56-12.16-1.92-18.88 2.88-30.080 30.72-52.16 62.72-49.92 2.24 0.32 4.8 0.64 7.040 0.96l42.56-42.56c-16.32-8.32-34.56-12.8-54.4-12.8z" />
|
||||
<glyph unicode="" glyph-name="icon-T1" d="M603.2 694.4h-6.4c-25.494 5.341-54.79 8.398-84.8 8.398s-59.305-3.058-87.592-8.879l2.792 0.48h-6.72c-30.053-5.643-52.489-31.68-52.489-62.956 0-0.367 0.003-0.733 0.009-1.099l-0.001 0.055v-234.88c0.075-40.921 11.238-79.22 30.643-112.071l-0.563 1.031 35.2-60.48c11.655-19.297 32.515-32.001 56.342-32.001 0.105 0 0.209 0 0.314 0.001h44.144c0.359-0.007 0.783-0.011 1.208-0.011 23.569 0 44.162 12.74 55.269 31.709l0.164 0.302 36.16 64c18.232 31.447 29.027 69.173 29.12 109.413v232.987c0.005 0.293 0.008 0.639 0.008 0.986 0 31.391-22.599 57.503-52.416 62.954l-0.392 0.059zM629.76 396.8c-0.193-35.364-9.792-68.446-26.418-96.923l0.498 0.923-35.84-64c-6.868-11.865-19.463-19.742-33.906-19.84h-44.174c-0.073 0-0.159-0.001-0.246-0.001-14.427 0-27.041 7.762-33.894 19.338l-0.1 0.183-34.88 59.84c-16.656 28.155-26.515 62.042-26.56 98.227v235.853c0.133 19.025 13.742 34.833 31.751 38.359l0.249 0.041h6.72c24.050 5.126 51.682 8.062 80 8.062s55.949-2.936 82.608-8.519l-2.608 0.457h6.72c18.258-3.568 31.867-19.375 32-38.386v-0.014zM422.4 606.080h179.2c3.535 0 6.4-2.865 6.4-6.4v-99.2c0-3.535-2.865-6.4-6.4-6.4h-179.2c-3.535 0-6.4 2.865-6.4 6.4v99.2c0 3.535 2.865 6.4 6.4 6.4z" />
|
||||
<glyph unicode="" glyph-name="icon-T1-buttons" d="M603.2 694.4h-6.4c-25.494 5.341-54.79 8.398-84.8 8.398s-59.305-3.058-87.592-8.879l2.792 0.48h-6.72c-30.053-5.643-52.489-31.68-52.489-62.956 0-0.367 0.003-0.733 0.009-1.099l-0.001 0.055v-234.88c0.075-40.921 11.238-79.22 30.643-112.071l-0.563 1.031 35.2-60.48c11.655-19.297 32.515-32.001 56.342-32.001 0.105 0 0.209 0 0.314 0.001h44.144c0.359-0.007 0.783-0.011 1.208-0.011 23.569 0 44.162 12.74 55.269 31.709l0.164 0.302 36.16 64c18.152 31.468 28.933 69.175 29.12 109.385v233.015c0.005 0.293 0.008 0.639 0.008 0.986 0 31.391-22.599 57.503-52.416 62.954l-0.392 0.059zM629.76 396.8c-0.193-35.364-9.792-68.446-26.418-96.923l0.498 0.923-35.84-64c-6.868-11.865-19.463-19.742-33.906-19.84h-44.174c-14.469 0.112-27.111 7.827-34.139 19.343l-34.981 61.297c-16.687 28.041-26.553 61.827-26.56 97.918v234.882c0 19.072 13.676 34.95 31.757 38.362l0.243 0.038h6.72c24.050 5.126 51.682 8.062 80 8.062s55.949-2.936 82.608-8.519l-2.608 0.457h6.72c18.324-3.45 32-19.328 32-38.4v0zM422.4 606.080h179.2c3.535 0 6.4-2.865 6.4-6.4v-99.2c0-3.535-2.865-6.4-6.4-6.4h-179.2c-3.535 0-6.4 2.865-6.4 6.4v99.2c0 3.535 2.865 6.4 6.4 6.4zM531.2 469.76h70.4c3.535 0 6.4-2.865 6.4-6.4v-28.8c0-3.535-2.865-6.4-6.4-6.4h-70.4c-3.535 0-6.4 2.865-6.4 6.4v28.8c0 3.535 2.865 6.4 6.4 6.4zM422.4 468.8h70.4c3.535 0 6.4-2.865 6.4-6.4v-28.8c0-3.535-2.865-6.4-6.4-6.4h-70.4c-3.535 0-6.4 2.865-6.4 6.4v28.8c0 3.535 2.865 6.4 6.4 6.4z" />
|
||||
<glyph unicode="" glyph-name="icon-T1-connect" d="M526.72 345.92h-29.44c-16.229 0.18-30.307 9.217-37.647 22.496l-0.113 0.224-23.36 41.92c-12.685 22.404-20.16 49.203-20.16 77.748 0 0.004 0 0.008 0 0.012v-0.001 164.16c-0.002 0.138-0.002 0.301-0.002 0.463 0 21.403 14.903 39.326 34.898 43.957l0.304 0.059h4.48c16.978 3.729 36.479 5.865 56.48 5.865s39.502-2.136 58.289-6.193l-1.809 0.327h4.48c20.14-4.81 34.883-22.655 34.883-43.943 0-0.189-0.001-0.377-0.003-0.565v0.029-163.52c0-0.064 0-0.139 0-0.214 0-28.079-7.233-54.468-19.937-77.407l0.417 0.821-24-43.84c-7.529-13.375-21.591-22.288-37.744-22.4h-0.016zM512 685.76c-0.097 0-0.212 0-0.327 0-18.693 0-36.923-1.981-54.492-5.745l1.699 0.305h-4.48c-12.188-2.865-21.122-13.645-21.122-26.512 0-0.129 0.001-0.258 0.003-0.387v0.020-164.48c0-0.094 0-0.204 0-0.315 0-25.018 6.525-48.512 17.966-68.873l-0.365 0.708 23.36-41.92c4.497-8.071 12.981-13.44 22.718-13.44 0.001 0 0.002 0 0.002 0h29.44c9.799 0.067 18.299 5.56 22.652 13.623l0.068 0.137 24 43.84c10.854 19.495 17.254 42.757 17.28 67.512v162.248c0.002 0.109 0.002 0.238 0.002 0.368 0 12.867-8.935 23.648-20.938 26.476l-0.184 0.037h-4.48c-15.736 3.739-33.906 6.053-52.557 6.396l-0.243 0.004zM452.48 635.52h119.040c2.474 0 4.48-2.006 4.48-4.48v-69.44c0-2.474-2.006-4.48-4.48-4.48h-119.040c-2.474 0-4.48 2.006-4.48 4.48v69.44c0 2.474 2.006 4.48 4.48 4.48zM540.48 303.68v-52.16h-18.24v-59.52h-19.84v59.52h-18.88v52.16h56.96z" />
|
||||
<glyph unicode="" d="M551.36 178.24h-78.4c-0.225-0.006-0.489-0.010-0.754-0.010-10.242 0-19.207 5.468-24.135 13.643l-0.071 0.127-64 96c-29.426 43.619-46.99 97.353-47.040 155.187v233.613c0.36 22.875 18.988 41.281 41.915 41.281 0.114 0 0.228 0 0.342-0.001h263.342c0.097 0.001 0.211 0.001 0.325 0.001 22.927 0 41.555-18.406 41.915-41.248v-239.394c-0.289-59.994-19.423-115.463-51.779-160.855l0.579 0.855-60.48-86.080c-4.695-7.399-12.575-12.414-21.664-13.114l-0.096-0.006zM380.48 690.24c-0.1 0.003-0.217 0.004-0.334 0.004-7.552 0-13.716-5.946-14.064-13.413l-0.001-0.031v-233.92c0-0.010 0-0.023 0-0.036 0-52.093 15.777-100.502 42.813-140.708l-0.573 0.904 64-96h79.040l60.16 86.080c28.821 40.408 46.080 90.794 46.080 145.211 0 0.024 0 0.049 0 0.073v-0.004 238.4c-0.35 7.498-6.513 13.444-14.066 13.444-0.118 0-0.235-0.001-0.352-0.004h0.017z" />
|
||||
<glyph unicode="" d="M407.040 624.32h209.92c4.595 0 8.32-3.725 8.32-8.32v-201.92c0-4.595-3.725-8.32-8.32-8.32h-209.92c-4.595 0-8.32 3.725-8.32 8.32v201.92c0 4.595 3.725 8.32 8.32 8.32z" />
|
||||
<glyph unicode="" d="M539.52 352h-54.72c-6.578 0.052-12.387 3.298-15.96 8.261l-0.040 0.059-45.12 64c-20.029 28.726-32.002 64.366-32.002 102.802 0 0.309 0.001 0.617 0.002 0.925v-0.047 157.76c0.349 15.459 12.963 27.856 28.473 27.856 0.34 0 0.679-0.006 1.016-0.018l-0.049 0.001h184.32c0.288 0.010 0.627 0.016 0.967 0.016 15.51 0 28.124-12.398 28.473-27.824l0.001-0.032v-160c-0.074-40.641-13.522-78.128-36.176-108.308l0.336 0.468-42.24-57.28c-3.622-5.258-9.609-8.66-16.39-8.66-0.313 0-0.624 0.007-0.934 0.022l0.044-0.002zM419.84 694.4c-0.205 0.016-0.444 0.025-0.686 0.025-4.973 0-9.062-3.781-9.551-8.624l-0.003-0.040v-155.84c0.066-34.769 11.081-66.953 29.778-93.302l-0.338 0.502 45.12-64h56l42.24 57.28c19.839 26.468 31.828 59.817 32 95.96v160.040c-0.492 4.884-4.582 8.665-9.554 8.665-0.241 0-0.481-0.009-0.717-0.026l0.032 0.002z" />
|
||||
<glyph unicode="" d="M438.4 650.88h146.88c3.181 0 5.76-2.579 5.76-5.76v-134.4c0-3.181-2.579-5.76-5.76-5.76h-146.88c-3.181 0-5.76 2.579-5.76 5.76v134.4c0 3.181 2.579 5.76 5.76 5.76z" />
|
||||
<glyph unicode="" d="M541.12 300.48v-50.56h-18.56v-57.92h-20.48v57.92h-18.88v50.56h57.92z" />
|
||||
<glyph unicode="" glyph-name="icon-arrow-left" d="M603.072 202.784l-237.44 219.616c-8.576 8.128-13.632 19.296-13.632 31.040 0.288 11.744 5.056 23.2 13.664 31.040l227.040 208.768c16.928 15.36 43.040 14.176 58.176-3.008 15.424-16.864 13.952-43.392-2.656-59.040l-193.504-177.76 203.904-188.608c8-7.52 12.768-18.080 13.344-29.216 0.608-11.456-3.264-21.696-10.688-30.112-15.456-16.896-41.568-18.080-58.208-2.72z" />
|
||||
<glyph unicode="" glyph-name="icon-top" d="M677.44 346.24c-3.255-1.423-7.047-2.252-11.033-2.252-0.284 0-0.566 0.004-0.848 0.013l0.041-0.001c-8.323 0.531-15.657 4.371-20.77 10.206l-0.030 0.034-93.44 109.44c-0.378 0.735-1.131 1.229-1.999 1.229-1.237 0-2.24-1.003-2.24-2.24 0-0.209 0.029-0.412 0.083-0.605l-0.004 0.016v-233.28c0.102-0.987 0.16-2.132 0.16-3.291 0-18.733-15.187-33.92-33.92-33.92s-33.92 15.187-33.92 33.92c0 1.159 0.058 2.304 0.172 3.433l-0.012-0.142v236.16c0.050 0.177 0.079 0.379 0.079 0.589 0 1.237-1.003 2.24-2.24 2.24-0.868 0-1.621-0.494-1.993-1.216l-0.006-0.013-88.32-104.32c-5.204-6.343-13.042-10.358-21.819-10.358-7.711 0-14.699 3.099-19.784 8.121l0.003-0.003c-6.16 5.845-9.993 14.090-9.993 23.231 0 8.17 3.062 15.625 8.101 21.28l-0.028-0.032 146.56 173.44c5.311 6.15 13.061 10.069 21.731 10.24h0.029c8.727-0.036 16.523-3.991 21.724-10.196l0.036-0.044 152-178.56c5.441-6.124 8.764-14.234 8.764-23.121 0-12.698-6.785-23.81-16.927-29.911l-0.157-0.088zM329.28 667.2c-0.024 0.488-0.038 1.060-0.038 1.635 0 18.891 14.881 34.306 33.561 35.163l0.077 0.003h292.48c18.795-1.81 33.372-17.523 33.372-36.64s-14.577-34.83-33.222-36.628l-0.15-0.012h-292.48c-18.751 0.866-33.625 16.278-33.625 35.165 0 0.463 0.009 0.923 0.027 1.381l-0.002-0.066z" />
|
||||
<glyph unicode="" glyph-name="icon-check" d="M692.8 646.080l-1.92 1.92c-6.246 7.057-15.326 11.484-25.44 11.484s-19.194-4.427-25.409-11.448l-0.031-0.036-196.48-224-3.84-1.6-3.84 1.92-48.64 57.28c-7.010 7.905-17.193 12.862-28.533 12.862-21.031 0-38.080-17.049-38.080-38.080 0-7.495 2.165-14.485 5.905-20.377l-0.092 0.155 100.8-148.16c5.391-8.036 14.386-13.292 24.618-13.44h8.662c17.251 0.146 32.385 9.075 41.163 22.529l0.117 0.191 195.2 296.32c4.473 6.632 7.141 14.803 7.141 23.597 0 11.162-4.297 21.32-11.326 28.911l0.025-0.028z" />
|
||||
<glyph unicode="" glyph-name="icon-error" d="M693.12 629.12c-46.317 46.267-110.276 74.88-180.919 74.88-141.385 0-256-114.615-256-256s114.615-256 256-256c70.642 0 134.602 28.613 180.921 74.882l-0.002-0.002c46.387 46.337 75.081 110.377 75.081 181.12s-28.694 134.783-75.079 181.118l-0.002 0.002zM494.080 615.68h53.12c16 0 18.24-9.28 18.24-14.72v-10.24l-10.88-194.56c0-14.4-8-17.28-18.88-17.28h-28.16c-10.56 0-17.28 2.88-18.88 17.92l-10.88 193.92v10.56c-1.28 4.8 2.24 14.080 16.32 14.080zM521.28 242.24c-0.095-0.001-0.207-0.001-0.319-0.001-27.747 0-50.24 22.493-50.24 50.24s22.493 50.24 50.24 50.24c27.747 0 50.24-22.493 50.24-50.24 0-0.112 0-0.224-0.001-0.336v0.017c0 0 0-0.001 0-0.001 0-27.634-22.311-50.057-49.903-50.239h-0.017z" />
|
||||
<glyph unicode="" glyph-name="icon-eye" d="M512.64 592c-99.2 0-198.4-45.76-256.64-136.64 128.64-200 394.56-203.84 512 1.28-57.92 90.24-156.48 135.36-255.36 135.36zM516.8 338.56c-64-0.32-115.84 48.64-115.84 108.48-0.32 60.16 51.52 109.12 115.84 109.12 64 0 115.84-48.64 115.84-108.8 0.32-60.16-51.52-108.8-115.84-108.8zM574.72 451.84c2.56-30.080-21.12-56.32-53.12-58.88-32-2.24-59.84 19.84-62.72 49.92-2.56 30.080 21.44 56.32 53.12 58.56 32 2.56 59.84-19.84 62.72-49.6z" />
|
||||
<glyph unicode="" glyph-name="icon-back" d="M656.224 557.696l-66.848-66.176-66.848 66.176-50.144-49.6 66.912-66.176-66.912-66.176 50.176-49.632 66.848 66.176 66.848-66.176 50.112 49.632-66.816 66.176 66.816 66.176-50.144 49.6zM337.824 704h540.928c27.2 0 49.248-21.824 49.248-48.768v-414.464c0-26.944-22.048-48.768-49.248-48.768h-540.608c-13.856 0-27.072 5.792-36.416 15.936l-192.896 209.664c-17.248 18.752-17.088 47.488 0.352 66.048l192.576 204.8c9.344 9.92 22.4 15.552 36.064 15.552z" />
|
||||
</font></defs></svg>
|
Before Width: | Height: | Size: 20 KiB |
Binary file not shown.
Binary file not shown.
@ -5,12 +5,10 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Ethereum Wallet | TREZOR</title>
|
||||
<meta name="title" content="TrezorConnect" />
|
||||
<meta name="description" content="TrezorConnect" />
|
||||
<meta name="keywords" content="TrezorConnect" />
|
||||
<meta name="author" content="" />
|
||||
<link rel="icon" type="image/png" href="favicon.png">
|
||||
<!--[if IE]><link rel="shortcut icon" href="favicon.ico"/><![endif]-->
|
||||
<meta name="title" content="Trezor Wallet" />
|
||||
<meta name="description" content="Trezor Wallet" />
|
||||
<meta name="keywords" content="trezor wallet" />
|
||||
<meta name="author" content="satoshilabs s.r.o." />
|
||||
<meta name="viewport" content="width=1024, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
|
@ -3,9 +3,8 @@ import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import baseStyles from 'support/BaseStyles';
|
||||
import { onBeforeUnload } from 'actions/WalletActions';
|
||||
import 'styles/index.less';
|
||||
import App from 'views/index';
|
||||
import store from 'support/store';
|
||||
import store from 'store';
|
||||
|
||||
const root: ?HTMLElement = document.getElementById('root');
|
||||
if (root) {
|
||||
|
@ -22,7 +22,7 @@ const mergeDevices = (current: TrezorDevice, upcoming: Device | TrezorDevice): T
|
||||
// }
|
||||
// }
|
||||
|
||||
let instanceLabel = current.instanceLabel;
|
||||
let { instanceLabel } = current;
|
||||
if (upcoming.label !== current.label) {
|
||||
instanceLabel = upcoming.label;
|
||||
if (typeof current.instance === 'number') {
|
||||
|
@ -62,9 +62,10 @@ const closeNotification = (state: State, payload: any): State => {
|
||||
|
||||
export default function notification(state: State = initialState, action: Action): State {
|
||||
switch (action.type) {
|
||||
case DEVICE.DISCONNECT:
|
||||
const path: string = action.device.path; // Flow warning
|
||||
case DEVICE.DISCONNECT: {
|
||||
const { path } = action.device; // Flow warning
|
||||
return state.filter(entry => entry.devicePath !== path);
|
||||
}
|
||||
|
||||
case NOTIFICATION.ADD:
|
||||
return addNotification(state, action.payload);
|
||||
|
@ -1,9 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import * as PENDING from 'actions/constants/pendingTx';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
|
||||
import type { Action } from 'flowtype';
|
||||
import type { SendTxAction } from 'actions/SendFormActions';
|
||||
|
@ -2,11 +2,9 @@
|
||||
|
||||
|
||||
import EthereumjsUnits from 'ethereumjs-units';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
import * as ACCOUNT from 'actions/constants/account';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
|
||||
import { getFeeLevels } from 'actions/SendFormActions';
|
||||
|
||||
@ -15,6 +13,12 @@ import type {
|
||||
Web3UpdateGasPriceAction,
|
||||
} from 'actions/Web3Actions';
|
||||
|
||||
export type FeeLevel = {
|
||||
label: string;
|
||||
gasPrice: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type State = {
|
||||
+networkName: string;
|
||||
+networkSymbol: string;
|
||||
@ -45,12 +49,6 @@ export type State = {
|
||||
sending: boolean;
|
||||
}
|
||||
|
||||
export type FeeLevel = {
|
||||
label: string;
|
||||
gasPrice: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
|
||||
export const initialState: State = {
|
||||
networkName: '',
|
||||
|
@ -1,9 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { TRANSPORT, DEVICE, UI } from 'trezor-connect';
|
||||
import { TRANSPORT, UI } from 'trezor-connect';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
|
||||
import type { Action } from 'flowtype';
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
import Web3 from 'web3';
|
||||
|
||||
import type { ContractFactory } from 'web3';
|
||||
import * as STORAGE from 'actions/constants/localStorage';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
|
||||
import type { Action } from 'flowtype';
|
||||
|
@ -1,20 +1,8 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import * as LogActions from 'actions/LogActions';
|
||||
import * as STORAGE from 'actions/constants/localStorage';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
import BigNumber from 'bignumber.js';
|
||||
|
||||
import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
Device,
|
||||
TrezorDevice,
|
||||
Account,
|
||||
@ -29,7 +17,7 @@ export const getSelectedDevice = (state: State): ?TrezorDevice => {
|
||||
const locationState = state.router.location.state;
|
||||
if (!locationState.device) return undefined;
|
||||
|
||||
const instance: ?number = locationState.deviceInstance ? parseInt(locationState.deviceInstance) : undefined;
|
||||
const instance: ?number = locationState.deviceInstance ? parseInt(locationState.deviceInstance, 10) : undefined;
|
||||
return state.devices.find((d) => {
|
||||
if (!d.features && d.path === locationState.device) {
|
||||
return true;
|
||||
@ -65,7 +53,7 @@ export const getDuplicateInstanceNumber = (devices: Array<TrezorDevice>, device:
|
||||
}
|
||||
return !b.instance || a.instance > b.instance ? 1 : -1;
|
||||
});
|
||||
|
||||
|
||||
// calculate new instance number
|
||||
const instance: number = affectedDevices.reduce((inst, dev) => (dev.instance ? dev.instance + 1 : inst + 1), 0);
|
||||
return instance;
|
||||
@ -76,14 +64,14 @@ export const getSelectedAccount = (state: State): ?Account => {
|
||||
const locationState = state.router.location.state;
|
||||
if (!device || !locationState.network || !locationState.account) return null;
|
||||
|
||||
const index: number = parseInt(locationState.account);
|
||||
const index: number = parseInt(locationState.account, 10);
|
||||
|
||||
return state.accounts.find(a => a.deviceState === device.state && a.index === index && a.network === locationState.network);
|
||||
};
|
||||
|
||||
export const getSelectedNetwork = (state: State): ?Coin => {
|
||||
const device = state.wallet.selectedDevice;
|
||||
const coins = state.localStorage.config.coins;
|
||||
const { coins } = state.localStorage.config;
|
||||
const locationState = state.router.location.state;
|
||||
if (!device || !locationState.network) return null;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* @flow */
|
||||
|
||||
import { JSONRequest, httpRequest } from 'utils/networkUtils';
|
||||
import { httpRequest } from 'utils/networkUtils';
|
||||
import { resolveAfter } from 'utils/promiseUtils';
|
||||
import { READY } from 'actions/constants/localStorage';
|
||||
|
||||
@ -8,7 +8,6 @@ import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
|
@ -1,18 +1,13 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { DEVICE } from 'trezor-connect';
|
||||
import { LOCATION_CHANGE } from 'react-router-redux';
|
||||
import * as LocalStorageActions from 'actions/LocalStorageActions';
|
||||
import * as WalletActions from 'actions/WalletActions';
|
||||
// import * as WalletActions from 'actions/WalletActions';
|
||||
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as MODAL from 'actions/constants/modal';
|
||||
import * as TOKEN from 'actions/constants/token';
|
||||
import * as ACCOUNT from 'actions/constants/account';
|
||||
import * as DISCOVERY from 'actions/constants/discovery';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
import * as PENDING from 'actions/constants/pendingTx';
|
||||
import { findAccountTokens } from 'reducers/TokensReducer';
|
||||
|
||||
@ -20,14 +15,12 @@ import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
TrezorDevice,
|
||||
} from 'flowtype';
|
||||
|
||||
import type { TrezorDevice } from 'flowtype';
|
||||
import type { Account } from 'reducers/AccountsReducer';
|
||||
import type { Token } from 'reducers/TokensReducer';
|
||||
import type { PendingTx } from 'reducers/PendingTxReducer';
|
||||
|
@ -1,29 +1,23 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import * as LogActions from 'actions/LogActions';
|
||||
import * as STORAGE from 'actions/constants/localStorage';
|
||||
import * as SEND from 'actions/constants/send';
|
||||
import { OPEN, CLOSE, ADD } from 'actions/constants/log';
|
||||
// import * as STORAGE from 'actions/constants/localStorage';
|
||||
// import * as SEND from 'actions/constants/send';
|
||||
// import { OPEN, CLOSE, ADD } from 'actions/constants/log';
|
||||
import { TRANSPORT, DEVICE } from 'trezor-connect';
|
||||
|
||||
import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
} from 'flowtype';
|
||||
|
||||
const exclude: Array<string> = [
|
||||
ADD, OPEN, CLOSE,
|
||||
STORAGE.READY,
|
||||
SEND.TX_COMPLETE,
|
||||
'web3__create',
|
||||
];
|
||||
// const exclude: Array<string> = [
|
||||
// ADD, OPEN, CLOSE,
|
||||
// STORAGE.READY,
|
||||
// SEND.TX_COMPLETE,
|
||||
// 'web3__create',
|
||||
// ];
|
||||
|
||||
const include: Array<string> = [
|
||||
TRANSPORT.START,
|
||||
|
@ -1,8 +1,5 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { DEVICE } from 'trezor-connect';
|
||||
import { LOCATION_CHANGE, push, replace } from 'react-router-redux';
|
||||
import { LOCATION_CHANGE/* , replace */ } from 'react-router-redux';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as WALLET from 'actions/constants/wallet';
|
||||
import * as NotificationActions from 'actions/NotificationActions';
|
||||
@ -11,12 +8,7 @@ import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
ThunkAction,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
RouterLocationState,
|
||||
TrezorDevice,
|
||||
} from 'flowtype';
|
||||
@ -51,7 +43,7 @@ const validation = (api: MiddlewareAPI, params: RouterLocationState): boolean =>
|
||||
|
||||
let device: ?TrezorDevice;
|
||||
if (params.hasOwnProperty('deviceInstance')) {
|
||||
device = devices.find(d => d.features && d.features.device_id === params.device && d.instance === parseInt(params.deviceInstance));
|
||||
device = devices.find(d => d.features && d.features.device_id === params.device && d.instance === parseInt(params.deviceInstance, 10));
|
||||
} else {
|
||||
device = devices.find(d => d.path === params.device || (d.features && d.features.device_id === params.device));
|
||||
}
|
||||
@ -61,25 +53,20 @@ const validation = (api: MiddlewareAPI, params: RouterLocationState): boolean =>
|
||||
|
||||
if (params.hasOwnProperty('network')) {
|
||||
const { config } = api.getState().localStorage;
|
||||
const coin = config.coins.find(coin => coin.network === params.network);
|
||||
const coin = config.coins.find(c => c.network === params.network);
|
||||
if (!coin) return false;
|
||||
if (!params.account) return false;
|
||||
}
|
||||
|
||||
if (params.account) {
|
||||
// if (params.account) {
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
let __unloading: boolean = false;
|
||||
|
||||
const LandingURLS: Array<string> = [
|
||||
'/',
|
||||
'/bridge',
|
||||
];
|
||||
|
||||
const RouterService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
|
||||
if (action.type === WALLET.ON_BEFORE_UNLOAD) {
|
||||
__unloading = true;
|
||||
|
@ -1,10 +1,8 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { push } from 'react-router-redux';
|
||||
|
||||
import TrezorConnect, {
|
||||
TRANSPORT, DEVICE_EVENT, UI_EVENT, UI, DEVICE,
|
||||
import {
|
||||
TRANSPORT, DEVICE,
|
||||
} from 'trezor-connect';
|
||||
import * as TrezorConnectActions from 'actions/TrezorConnectActions';
|
||||
import * as DiscoveryActions from 'actions/DiscoveryActions';
|
||||
@ -13,25 +11,19 @@ import { init as initWeb3 } from 'actions/Web3Actions';
|
||||
import * as WEB3 from 'actions/constants/web3';
|
||||
import * as STORAGE from 'actions/constants/localStorage';
|
||||
import * as CONNECT from 'actions/constants/TrezorConnect';
|
||||
import * as NOTIFICATION from 'actions/constants/notification';
|
||||
import * as MODAL from 'actions/constants/modal';
|
||||
|
||||
import type {
|
||||
Middleware,
|
||||
MiddlewareAPI,
|
||||
MiddlewareDispatch,
|
||||
State,
|
||||
Dispatch,
|
||||
Action,
|
||||
AsyncAction,
|
||||
GetState,
|
||||
RouterLocationState,
|
||||
} from 'flowtype';
|
||||
|
||||
const TrezorConnectService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispatch) => (action: Action): Action => {
|
||||
const prevState: $ElementType<State, 'connect'> = api.getState().connect;
|
||||
// const prevState: $ElementType<State, 'connect'> = api.getState().connect;
|
||||
const prevModalState: $ElementType<State, 'modal'> = api.getState().modal;
|
||||
const prevRouterState: $ElementType<State, 'router'> = api.getState().router;
|
||||
// const prevRouterState: $ElementType<State, 'router'> = api.getState().router;
|
||||
|
||||
next(action);
|
||||
|
||||
|
@ -1,20 +1,18 @@
|
||||
/* @flow */
|
||||
|
||||
|
||||
import { createStore, applyMiddleware, compose } from 'redux';
|
||||
import { routerMiddleware, push } from 'react-router-redux';
|
||||
import { routerMiddleware } from 'react-router-redux';
|
||||
import thunk from 'redux-thunk';
|
||||
// import createHistory from 'history/createBrowserHistory';
|
||||
// import { useRouterHistory } from 'react-router';
|
||||
import createHistory from 'history/createHashHistory';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import reducers from 'reducers';
|
||||
import services from 'services';
|
||||
|
||||
import Raven from 'raven-js';
|
||||
import RavenMiddleware from 'redux-raven-middleware';
|
||||
|
||||
import type { Action, GetState, Store } from 'flowtype';
|
||||
// import type { Action, GetState, Store } from 'flowtype';
|
||||
|
||||
export const history: History = createHistory({ queryKey: false });
|
||||
|
||||
@ -32,12 +30,12 @@ const middleware = [
|
||||
|
||||
let composedEnhancers: any;
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const excludeLogger = (getState: GetState, action: Action): boolean => {
|
||||
//'@@router/LOCATION_CHANGE'
|
||||
const excluded: Array<string> = ['LOG_TO_EXCLUDE', 'log__add'];
|
||||
const pass: Array<string> = excluded.filter(act => action.type === act);
|
||||
return pass.length === 0;
|
||||
};
|
||||
// const excludeLogger = (getState: GetState, action: Action): boolean => {
|
||||
// //'@@router/LOCATION_CHANGE'
|
||||
// const excluded: Array<string> = ['LOG_TO_EXCLUDE', 'log__add'];
|
||||
// const pass: Array<string> = excluded.filter(act => action.type === act);
|
||||
// return pass.length === 0;
|
||||
// };
|
||||
|
||||
composedEnhancers = compose(
|
||||
applyMiddleware(...middleware, ...services),
|
@ -1,28 +0,0 @@
|
||||
@color_white: #ffffff;
|
||||
|
||||
@color_header: #212121;
|
||||
@color_body: #E3E3E3;
|
||||
@color_main: #FBFBFB;
|
||||
@color_landing: #F9F9F9;
|
||||
|
||||
@color_text_primary: #494949;
|
||||
@color_text_secondary: #757575;
|
||||
|
||||
@color_gray_light: #F2F2F2; // hover menu
|
||||
@color_divider: #E3E3E3; //#EBEBEB;
|
||||
|
||||
@color_green_primary: #01B757;
|
||||
@color_green_secondary: #00AB51;
|
||||
@color_green_tertiary: #009546;
|
||||
|
||||
@color_info_primary: #1E7FF0;
|
||||
@color_info_secondary: #E1EFFF;
|
||||
|
||||
@color_warning_primary: #EB8A00;
|
||||
@color_warning_secondary: #FFEFD9;
|
||||
|
||||
@color_success_primary: #01B757;
|
||||
@color_success_secondary: #DFFFEE;
|
||||
|
||||
@color_error_primary: #ED1212;
|
||||
@color_error_secondary: #FFE9E9;
|
@ -1,58 +0,0 @@
|
||||
article {
|
||||
|
||||
nav {
|
||||
.account-tabs {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0px 28px; // 20px padding arround links
|
||||
max-width: 600px;
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: @color_text_secondary;
|
||||
margin: 0px 4px;
|
||||
padding: 20px;
|
||||
.hover();
|
||||
|
||||
&.active,
|
||||
&:hover {
|
||||
color: @color_text_primary;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.indicator {
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
width: 100px;
|
||||
height: 2px;
|
||||
background: @color_green_primary;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: @color_white;
|
||||
|
||||
p {
|
||||
padding: 0px 48px;
|
||||
color: @color_text_secondary;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,174 +0,0 @@
|
||||
// custom Roboto with Zero without the thing inside, so it's more readable as number
|
||||
// since 0 doesn't look too similar to 8
|
||||
@font-face {
|
||||
font-family: 'Roboto Zero';
|
||||
src: url('../fonts/roboto/RobotoZero.eot') format('embedded-opentype'),
|
||||
url('../fonts/roboto/RobotoZero.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/roboto/RobotoZero.woff') format('woff'),
|
||||
url('../fonts/roboto/RobotoZero.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
src: url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.eot') format('embedded-opentype'), /* IE9 Compat Modes */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.svg#RobotoMono') format('svg'); /* Legacy iOS */
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'icomoon';
|
||||
src: url('../fonts/icomoon.eot') format('embedded-opentype'),
|
||||
url('../fonts/icomoon.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/icomoon.woff') format('woff'),
|
||||
url('../fonts/icomoon.ttf') format('truetype'),
|
||||
url('../fonts/icomoon.svg#icomoon') format('svg');
|
||||
}
|
||||
|
||||
@font-default: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif;
|
||||
@font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif;
|
||||
@font-family-monospace: "Roboto Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
@font-family-monospace-numbers: "Roboto Zero", "Roboto Mono", Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
|
||||
// ::selection,
|
||||
// ::-moz-selection {
|
||||
// background: @color_info_secondary;
|
||||
// }
|
||||
|
||||
.icomoon-base() {
|
||||
display: inline-block;
|
||||
font-family: 'icomoon';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
font-size: 24px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.004);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.icomoon-eject {
|
||||
.icomoon-base();
|
||||
content: "\e902";
|
||||
}
|
||||
|
||||
.icomoon-refresh {
|
||||
.icomoon-base();
|
||||
content: "\e903";
|
||||
}
|
||||
|
||||
.icomoon-info {
|
||||
.icomoon-base();
|
||||
content: "\e904";
|
||||
}
|
||||
|
||||
.icomoon-chat {
|
||||
.icomoon-base();
|
||||
content: "\e905";
|
||||
}
|
||||
|
||||
.icomoon-redirect {
|
||||
.icomoon-base();
|
||||
content: "\e906";
|
||||
}
|
||||
|
||||
.icomoon-settings {
|
||||
.icomoon-base();
|
||||
content: "\e907";
|
||||
}
|
||||
|
||||
.icomoon-warning {
|
||||
.icomoon-base();
|
||||
content: "\e908";
|
||||
}
|
||||
|
||||
.icomoon-arrow-down {
|
||||
.icomoon-base();
|
||||
content: "\e909";
|
||||
}
|
||||
|
||||
.icomoon-close {
|
||||
.icomoon-base();
|
||||
content: "\e90a";
|
||||
}
|
||||
|
||||
.icomoon-arrow-up {
|
||||
.icomoon-base();
|
||||
content: "\e90b";
|
||||
}
|
||||
|
||||
.icomoon-arrow-right2 {
|
||||
.icomoon-base();
|
||||
content: "\e90c";
|
||||
}
|
||||
|
||||
.icomoon-plus {
|
||||
.icomoon-base();
|
||||
content: "\e90d";
|
||||
}
|
||||
|
||||
.icomoon-arrow-right {
|
||||
.icomoon-base();
|
||||
content: "\e90e";
|
||||
}
|
||||
|
||||
.icomoon-help {
|
||||
.icomoon-base();
|
||||
content: "\e90f";
|
||||
}
|
||||
|
||||
|
||||
.icomoon-eye-error {
|
||||
.icomoon-base();
|
||||
content: "\e911";
|
||||
}
|
||||
|
||||
.icomoon-T1 {
|
||||
.icomoon-base();
|
||||
content: "\e912";
|
||||
}
|
||||
|
||||
|
||||
|
||||
.icomoon-arrow-left {
|
||||
.icomoon-base();
|
||||
content: "\e91a";
|
||||
}
|
||||
|
||||
|
||||
.icomoon-setmax {
|
||||
.icomoon-base();
|
||||
content: "\e91b";
|
||||
}
|
||||
|
||||
.icomoon-checked {
|
||||
.icomoon-base();
|
||||
content: "\e91c";
|
||||
}
|
||||
|
||||
.icomoon-error {
|
||||
.icomoon-base();
|
||||
content: "\e91d";
|
||||
}
|
||||
|
||||
.icomoon-eye {
|
||||
.icomoon-base();
|
||||
content: "\e91e";
|
||||
}
|
||||
|
||||
.icomoon-back {
|
||||
.icomoon-base();
|
||||
content: "\e91f";
|
||||
}
|
||||
|
||||
.icomoon-download {
|
||||
.icomoon-base();
|
||||
content: "\e91b";
|
||||
transform: rotate(180deg)
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
@import './fonts.less';
|
||||
@import './colors.less';
|
||||
@import './mixins.less';
|
||||
@import './content.less';
|
||||
|
||||
@import './reactSelect.less';
|
||||
@import './rcTooltip.less';
|
||||
|
||||
@import './send.less';
|
||||
@import './receive.less';
|
||||
@import './summary.less';
|
||||
|
||||
@import './inputs.less';
|
@ -1,300 +0,0 @@
|
||||
input, textarea {
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.42857143;
|
||||
font-family: @font-family-monospace;
|
||||
color: @color_text_primary;
|
||||
background-color: @color_white;
|
||||
border: 1px solid @color_divider;
|
||||
border-radius: 2px;
|
||||
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
|
||||
padding: 6px 12px;
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 1px 2px 0 rgba(169, 169, 169, 0.25);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background: @color_gray_light;
|
||||
color: @color_text_secondary;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
|
||||
&.valid {
|
||||
border-color: @color_success_primary;
|
||||
&:focus {
|
||||
box-shadow: 0 1px 4px 0 rgba(1, 183, 87, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
&.warning {
|
||||
border-color: @color_warning_primary;
|
||||
&:focus {
|
||||
box-shadow: 0 1px 4px 0 rgba(235, 138, 0, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
&.not-valid {
|
||||
border-color: @color_error_primary;
|
||||
&:focus {
|
||||
box-shadow: 0 1px 4px 0 rgba(255, 111, 109, 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.button,
|
||||
button {
|
||||
padding: 12px 24px;
|
||||
border-radius: 3px;
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
cursor: pointer;
|
||||
background: @color_green_primary;
|
||||
color: @color_white;
|
||||
border: 0px;
|
||||
|
||||
.hover();
|
||||
|
||||
&:hover {
|
||||
background: @color_green_secondary;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: @color_green_tertiary;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
pointer-events: none;
|
||||
color: @color_text_secondary;
|
||||
background: @color_gray_light;
|
||||
}
|
||||
|
||||
&.blue {
|
||||
background: transparent;
|
||||
border: 1px solid @color_info_primary;
|
||||
color: @color_info_primary;
|
||||
padding: 12px 58px;
|
||||
|
||||
&:hover {
|
||||
color: @color_white;
|
||||
background: @color_info_primary;
|
||||
}
|
||||
}
|
||||
|
||||
&.white {
|
||||
background: @color_white;
|
||||
color: @color_text_secondary;
|
||||
border: 1px solid @color_divider;
|
||||
&:hover {
|
||||
//color: @color_text_primary;
|
||||
//border-color: @color_text_primary;
|
||||
background: @color_divider;
|
||||
}
|
||||
&:active {
|
||||
color: @color_text_primary;
|
||||
background: @color_divider;
|
||||
}
|
||||
}
|
||||
|
||||
&.transparent {
|
||||
background: transparent;
|
||||
border: 0px;
|
||||
color: @color_text_secondary;
|
||||
.hover();
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
color: @color_text_primary;
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a copy of webusb.less from trezor-connect
|
||||
.trezor-webusb-button {
|
||||
position: relative;
|
||||
padding: 12px 24px 12px 40px;
|
||||
background: transparent;
|
||||
color: @color_green_primary;
|
||||
border: 1px solid @color_green_primary;
|
||||
.hover();
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background: @color_green_primary;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
.hover();
|
||||
}
|
||||
|
||||
&:before {
|
||||
width: 12px;
|
||||
height: 2px;
|
||||
left: 18px;
|
||||
}
|
||||
|
||||
&:after {
|
||||
width: 2px;
|
||||
height: 12px;
|
||||
left: 23px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: @color_green_primary;
|
||||
color: @color_white;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
background: @color_white;
|
||||
}
|
||||
}
|
||||
|
||||
iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.custom-checkbox {
|
||||
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
color: @color_text_secondary;
|
||||
|
||||
input {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
|
||||
&:checked + .indicator:after {
|
||||
background-color: @color_green_primary;
|
||||
border-color: @color_green_primary;
|
||||
}
|
||||
&:disabled + .indicator:after {
|
||||
background-color: @color_text_secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.indicator {
|
||||
position: relative;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin-right: 12px;
|
||||
|
||||
&:after {
|
||||
.icomoon-checked;
|
||||
.hover();
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
color: @color_white;
|
||||
background-color: @color_white;
|
||||
border: 1px solid @color_divider;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: @color_text_secondary;
|
||||
}
|
||||
}
|
||||
|
||||
&.radio {
|
||||
.indicator {
|
||||
&:after {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
input:checked + .indicator:after {
|
||||
content: '';
|
||||
background: white;
|
||||
border: 4px solid @color_green_primary;
|
||||
}
|
||||
}
|
||||
|
||||
&.align-left {
|
||||
padding-left: 20px;
|
||||
padding-right: 10px;
|
||||
.indicator {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 2px;
|
||||
margin: 0;
|
||||
&:after {
|
||||
top: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.green,
|
||||
a.green:visited {
|
||||
position: relative;
|
||||
color: @color_green_primary;
|
||||
.hover();
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
border-top: 1px solid @color_green_primary;
|
||||
line-height: 1px;
|
||||
left: 0px;
|
||||
bottom: -1px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @color_green_secondary;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: @color_green_tertiary;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
&:after {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.gray,
|
||||
a.gray:visited {
|
||||
position: relative;
|
||||
color: @color_text_secondary;
|
||||
.hover();
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
border-top: 1px solid @color_text_secondary;
|
||||
line-height: 1px;
|
||||
left: 0px;
|
||||
bottom: -1px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
color: @color_text_primary;
|
||||
&:after {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
.antialised() {
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.no-outlines() {
|
||||
outline: none !important;
|
||||
border-color: inherit !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.hover() {
|
||||
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out, border-color 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.placeholder(@rules) {
|
||||
&::-webkit-input-placeholder {
|
||||
@rules();
|
||||
}
|
||||
&:-moz-placeholder {
|
||||
@rules();
|
||||
}
|
||||
&::-moz-placeholder {
|
||||
@rules();
|
||||
}
|
||||
&:-ms-input-placeholder {
|
||||
@rules();
|
||||
}
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
.tooltip-wrapper {
|
||||
width: 320px;
|
||||
font-size: 10px;
|
||||
span {
|
||||
color: @color_green_primary;
|
||||
}
|
||||
}
|
||||
|
||||
.aside-tooltip-wrapper {
|
||||
width: 260px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.rc-tooltip {
|
||||
position: absolute;
|
||||
z-index: 1070;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
border: 1px solid @color_divider;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.rc-tooltip-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rc-tooltip-inner {
|
||||
padding: 8px 10px;
|
||||
color: @color_text_secondary;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
background-color: @color_white;
|
||||
border-radius: 3px;
|
||||
min-height: 34px;
|
||||
border: 1px solid @color_white;
|
||||
}
|
||||
.rc-tooltip-arrow,
|
||||
.rc-tooltip-arrow-inner {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-color: transparent;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
|
||||
.rc-tooltip-placement-top .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-topLeft .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-topRight .rc-tooltip-arrow {
|
||||
bottom: -6px;
|
||||
margin-left: -6px;
|
||||
border-width: 6px 6px 0;
|
||||
border-top-color: @color_divider;
|
||||
}
|
||||
.rc-tooltip-placement-top .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-topLeft .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-topRight .rc-tooltip-arrow-inner {
|
||||
//bottom: 1px;
|
||||
bottom: 2px;
|
||||
margin-left: -6px;
|
||||
border-width: 6px 6px 0;
|
||||
border-top-color: @color_white;
|
||||
}
|
||||
.rc-tooltip-placement-top .rc-tooltip-arrow {
|
||||
left: 50%;
|
||||
}
|
||||
.rc-tooltip-placement-topLeft .rc-tooltip-arrow {
|
||||
left: 15%;
|
||||
}
|
||||
.rc-tooltip-placement-topRight .rc-tooltip-arrow {
|
||||
right: 15%;
|
||||
}
|
||||
.rc-tooltip-placement-right .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-rightTop .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-rightBottom .rc-tooltip-arrow {
|
||||
left: -5px;
|
||||
margin-top: -6px;
|
||||
border-width: 6px 6px 6px 0;
|
||||
border-right-color: @color_divider;
|
||||
}
|
||||
.rc-tooltip-placement-right .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-rightTop .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-rightBottom .rc-tooltip-arrow-inner {
|
||||
left: 1px;
|
||||
margin-top: -6px;
|
||||
border-width: 6px 6px 6px 0;
|
||||
border-right-color: @color_white;
|
||||
}
|
||||
.rc-tooltip-placement-right .rc-tooltip-arrow {
|
||||
top: 50%;
|
||||
}
|
||||
.rc-tooltip-placement-rightTop .rc-tooltip-arrow {
|
||||
top: 15%;
|
||||
margin-top: 0;
|
||||
}
|
||||
.rc-tooltip-placement-rightBottom .rc-tooltip-arrow {
|
||||
bottom: 15%;
|
||||
}
|
||||
.rc-tooltip-placement-left .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-leftTop .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-leftBottom .rc-tooltip-arrow {
|
||||
right: -5px;
|
||||
margin-top: -6px;
|
||||
border-width: 6px 0 6px 6px;
|
||||
border-left-color: @color_divider;
|
||||
}
|
||||
.rc-tooltip-placement-left .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-leftTop .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-leftBottom .rc-tooltip-arrow-inner {
|
||||
right: 1px;
|
||||
margin-top: -6px;
|
||||
border-width: 6px 0 6px 6px;
|
||||
border-left-color: @color_white;
|
||||
}
|
||||
.rc-tooltip-placement-left .rc-tooltip-arrow {
|
||||
top: 50%;
|
||||
}
|
||||
.rc-tooltip-placement-leftTop .rc-tooltip-arrow {
|
||||
top: 15%;
|
||||
margin-top: 0;
|
||||
}
|
||||
.rc-tooltip-placement-leftBottom .rc-tooltip-arrow {
|
||||
bottom: 15%;
|
||||
}
|
||||
.rc-tooltip-placement-bottom .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-bottomLeft .rc-tooltip-arrow,
|
||||
.rc-tooltip-placement-bottomRight .rc-tooltip-arrow {
|
||||
top: -5px;
|
||||
margin-left: -6px;
|
||||
border-width: 0 6px 6px;
|
||||
border-bottom-color: @color_divider;
|
||||
}
|
||||
.rc-tooltip-placement-bottom .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-bottomLeft .rc-tooltip-arrow-inner,
|
||||
.rc-tooltip-placement-bottomRight .rc-tooltip-arrow-inner {
|
||||
top: 1px;
|
||||
margin-left: -6px;
|
||||
border-width: 0 6px 6px;
|
||||
border-bottom-color: @color_white;
|
||||
}
|
||||
.rc-tooltip-placement-bottom .rc-tooltip-arrow {
|
||||
left: 50%;
|
||||
}
|
||||
.rc-tooltip-placement-bottomLeft .rc-tooltip-arrow {
|
||||
left: 15%;
|
||||
}
|
||||
.rc-tooltip-placement-bottomRight .rc-tooltip-arrow {
|
||||
right: 15%;
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
// https://github.com/JedWatson/react-select/blob/master/less/select.less
|
||||
|
||||
// @import '~react-select/less/select.less';
|
||||
|
||||
// // override predefined colors
|
||||
// @select-primary-color: @color_white;
|
||||
// @select-input-hover-box-shadow: none;
|
||||
// @select-input-box-shadow-focus: transparent;
|
||||
// @select-input-border-radius: 0px;
|
||||
// @select-item-border-radius: 0px;
|
||||
// @select-input-border-color: transparent;
|
||||
// @select-input-border-focus: @color_divider;
|
||||
// // @select-input-bg: transparent;
|
||||
// // @select-input-bg-focus: transparent;
|
||||
|
||||
// .Select-focus-state(@color) {
|
||||
// // do nothing
|
||||
// background: transparent;
|
||||
// box-shadow: none;
|
||||
// }
|
||||
|
||||
// .Select-focus-state-classic() {
|
||||
// background: transparent;
|
||||
// box-shadow: none;
|
||||
// }
|
||||
|
||||
// .Select-arrow-zone {
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// bottom: 0;
|
||||
// margin: auto 0;
|
||||
// padding-right: 0px !important;
|
||||
// width: 24px;
|
||||
// height: 24px;
|
||||
// right: 8px;
|
||||
|
||||
// .Select-arrow {
|
||||
// top: 0px;
|
||||
// border: 0px;
|
||||
// width: 24px;
|
||||
|
||||
// &:after {
|
||||
// .icomoon-arrow-down;
|
||||
// transition: transform 0.3s, color 0.3s;
|
||||
// color: @color_text_secondary;
|
||||
// transform-origin: 50% 50%;
|
||||
// font-size: 24px;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .Select {
|
||||
|
||||
// .Select-control {
|
||||
// cursor: pointer;
|
||||
|
||||
// .Select-input {
|
||||
// background: transparent;
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// // display: none !important; // uncomment for disable auto closing
|
||||
// }
|
||||
|
||||
// &:hover {
|
||||
// .Select-arrow:after {
|
||||
// color: @color_text_primary;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// .Select-noresults {
|
||||
// color: @color_text_secondary;
|
||||
// font-family: @font-default;
|
||||
// }
|
||||
|
||||
// .Select-placeholder {
|
||||
// color: @color_text_secondary;
|
||||
// font-family: @font-default;
|
||||
// }
|
||||
|
||||
// .Select-value-label {
|
||||
// color: @color_text_primary;
|
||||
// }
|
||||
|
||||
// .Select-menu-outer {
|
||||
// border-radius: 0px;
|
||||
// border: 1px solid @color_divider;
|
||||
// box-shadow: none;
|
||||
// }
|
||||
|
||||
// &.is-open {
|
||||
// .Select-arrow {
|
||||
// top: 0px !important;
|
||||
// border: 0px;
|
||||
// &:after {
|
||||
// transform: rotate(180deg);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
@ -1,126 +0,0 @@
|
||||
.receive {
|
||||
|
||||
.address {
|
||||
position: relative;
|
||||
padding: 0px 48px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.verify {
|
||||
position: absolute;
|
||||
background: @color_white;
|
||||
border: 2px solid @color_green_primary;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
margin: 0px 48px;
|
||||
z-index: 10001; // bigger than modal container
|
||||
}
|
||||
|
||||
.value {
|
||||
// same as input (inputs.less)
|
||||
font-size: 14px;
|
||||
font-weight: 300;
|
||||
line-height: 1.42857143;
|
||||
font-family: @font-family-monospace;
|
||||
color: @color_text_primary;
|
||||
border: 1px solid @color_divider;
|
||||
border-radius: 3px;
|
||||
padding: 6px 12px;
|
||||
padding-right: 38px; // eye icon
|
||||
position: relative;
|
||||
flex: 1;
|
||||
user-select: all; /* Chrome and Opera */
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 6px 24px;
|
||||
|
||||
&.white {
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
background: transparent;
|
||||
right: 48px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
white-space: nowrap;
|
||||
&:before {
|
||||
.icomoon-eye;
|
||||
font-size: 32px;
|
||||
line-height: 14px;
|
||||
// padding-top: 2px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.hidden {
|
||||
.value {
|
||||
padding-right: 6px; // no eye icon
|
||||
user-select: none;
|
||||
border-radius: 3px 0px 0px 3px;
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: linear-gradient(to right,
|
||||
rgba(255,255,255, 0) 0%,
|
||||
rgba(255,255,255, 1) 220px
|
||||
);
|
||||
pointer-events: none; /* so the text is still selectable */
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0px 3px 3px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&.unverified {
|
||||
button span:before {
|
||||
.icomoon-eye-error;
|
||||
color: @color_error_primary;
|
||||
font-size: 32px;
|
||||
line-height: 14px;
|
||||
padding-top: 0px;
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&.verifying {
|
||||
.value {
|
||||
background: @color_white;
|
||||
z-index: 10001; // bigger than modal container
|
||||
border-color: @color_green_primary;
|
||||
border-width: 2px;
|
||||
transform: translate(-1px, -1px);
|
||||
}
|
||||
|
||||
.confirm {
|
||||
display: block;
|
||||
position: relative;
|
||||
background: @color_white;
|
||||
z-index: 10001;
|
||||
width: 100%;
|
||||
padding: 6px 12px;
|
||||
transform: translate(-1px, -1px);
|
||||
margin: 0px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.qr {
|
||||
margin: 24px 48px;
|
||||
}
|
||||
}
|
@ -1,367 +0,0 @@
|
||||
.send-form {
|
||||
|
||||
.Select {
|
||||
width: 98px;
|
||||
height: 34px;
|
||||
font-family: @font-family-monospace;
|
||||
|
||||
&.fee {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.Select-control {
|
||||
height: 34px;
|
||||
border: 1px solid @color_divider;
|
||||
border-radius: 0px 2px 2px 0px;
|
||||
}
|
||||
|
||||
.Select-option {
|
||||
.hover();
|
||||
&.is-focused {
|
||||
background: @color_gray_light;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
background: @color_divider;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
.Select-control {
|
||||
cursor: default;
|
||||
}
|
||||
.Select-arrow {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.fee-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.fee-value {
|
||||
flex: 1;
|
||||
color: @color_text_primary;
|
||||
}
|
||||
|
||||
.fee-label {
|
||||
color: @color_text_secondary;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
padding-right: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.row {
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 0px 48px;
|
||||
padding-bottom: 24px;
|
||||
|
||||
.error,
|
||||
.warning:not(input),
|
||||
.info {
|
||||
position: absolute;
|
||||
left: 48px;
|
||||
bottom: 6px;
|
||||
font-size: 12px;
|
||||
color: @color_error_primary;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: @color_error_primary;
|
||||
}
|
||||
.warning:not(input) {
|
||||
color: @color_warning_primary;
|
||||
}
|
||||
.info {
|
||||
color: @color_green_primary;
|
||||
}
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 54px;
|
||||
margin: auto 0;
|
||||
height: 26px;
|
||||
color: @color_green_primary;
|
||||
}
|
||||
|
||||
.address-input {
|
||||
input.valid + .input-icon:before {
|
||||
.icomoon-checked;
|
||||
}
|
||||
input.not-valid + .input-icon:before {
|
||||
.icomoon-error;
|
||||
color: @color_error_primary;
|
||||
}
|
||||
input.warning + .input-icon:before {
|
||||
.icomoon-warning;
|
||||
color: @color_warning_primary;
|
||||
}
|
||||
}
|
||||
|
||||
.amount-input {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
border-radius: 2px 0px 0px 2px;
|
||||
}
|
||||
|
||||
.set-max {
|
||||
position: relative;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
font-size: 12px;
|
||||
font-weight: 300; // different
|
||||
color: @color_text_secondary;
|
||||
border: 1px solid @color_divider;
|
||||
border-right: 0px;
|
||||
border-left: 0px;
|
||||
background: @color_white;
|
||||
padding: 0px 10px 0px 32px;
|
||||
cursor: pointer;
|
||||
.hover();
|
||||
|
||||
&:before {
|
||||
.icomoon-setmax;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
font-size: 24px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: @color_gray_light;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: @color_divider;
|
||||
}
|
||||
|
||||
&.enabled {
|
||||
color: @color_white;
|
||||
background: @color_green_primary;
|
||||
border-color: @color_green_primary;
|
||||
&:before {
|
||||
.icomoon-checked;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: @color_green_secondary;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: @color_green_tertiary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.advanced {
|
||||
font-weight: 500;
|
||||
line-height: 40px; // button height
|
||||
color: @color_text_secondary;
|
||||
.hover();
|
||||
&:hover,
|
||||
&:active {
|
||||
color: @color_text_primary;
|
||||
}
|
||||
&:after {
|
||||
.icomoon-arrow-down;
|
||||
transition: transform 0.3s;
|
||||
transform-origin: 50% 50%;
|
||||
font-size: 24px;
|
||||
position: relative;
|
||||
top: 6px;
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.advanced-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0px 48px;
|
||||
|
||||
padding-bottom: 24px;
|
||||
button {
|
||||
min-width: 50%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
&.opened {
|
||||
flex-direction: column;
|
||||
padding: 0px;
|
||||
button {
|
||||
position: relative;
|
||||
// left: 50%;
|
||||
// width: 50%;
|
||||
float: right; // TODO: better
|
||||
}
|
||||
.advanced {
|
||||
display: inline-block;
|
||||
margin: 0px 48px 12px 48px;
|
||||
&:after {
|
||||
transform: rotate(180deg);
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.what-is-it {
|
||||
&:before {
|
||||
.icomoon-help;
|
||||
.hover();
|
||||
transform-origin: 50% 50%;
|
||||
font-size: 24px;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
&:hover {
|
||||
&:before {
|
||||
color: @color_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @media screen and (max-width: 900px) {
|
||||
// :not(.opened) {
|
||||
// border: 1px solid red;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
.gas-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-top: 1px solid @color_divider;
|
||||
padding-top: 24px;
|
||||
|
||||
.column {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
padding-right: 20px;
|
||||
|
||||
&.nonce {
|
||||
width: 100px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.error,
|
||||
.warning,
|
||||
.info {
|
||||
left: 0;
|
||||
bottom: -17px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.update-fee-levels {
|
||||
position: relative;
|
||||
font-size: 12px;
|
||||
color: @color_warning_primary;
|
||||
padding-left: 24px;
|
||||
margin-left: 8px;
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: @color_green_primary;
|
||||
margin-left: 4px;
|
||||
}
|
||||
&:before {
|
||||
.icomoon-warning;
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: @color_text_secondary;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
|
||||
.pending-transactions {
|
||||
|
||||
border-top: 1px solid @color_divider;
|
||||
|
||||
.tx {
|
||||
border-bottom: 1px solid @color_divider;
|
||||
padding: 14px 48px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
//border: 8px solid white;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
line-height: 30px;
|
||||
text-transform: uppercase;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
padding: 6px;
|
||||
p {
|
||||
line-height: 24px;
|
||||
padding: 0px;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
|
||||
a, a:visited {
|
||||
color: @color_text_secondary;
|
||||
.hover();
|
||||
|
||||
&:hover, &:active {
|
||||
color: @color_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.balance {
|
||||
color: @color_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
.summary {
|
||||
|
||||
.summary-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
&:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
height: 22px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: auto 20px;
|
||||
}
|
||||
|
||||
&.ethereum:before {
|
||||
background-image: url('../images/eth-logo.png');
|
||||
}
|
||||
&.ethereum-classic:before {
|
||||
background-image: url('../images/etc-logo.png');
|
||||
}
|
||||
&.ropsten:before {
|
||||
background-image: url('../images/ropsten-logo.png');
|
||||
}
|
||||
&.rinkeby:before {
|
||||
background-image: url('../images/rinkeby-logo.png');
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 12px;
|
||||
margin-left: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.token-select {
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
font-family: @font-family-monospace;
|
||||
|
||||
.Select-control {
|
||||
height: 34px;
|
||||
border: 1px solid @color_divider;
|
||||
}
|
||||
|
||||
.Select-input {
|
||||
|
||||
}
|
||||
|
||||
.Select-arrow-zone {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.identicon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
top: -4px;
|
||||
margin-right: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
.summary-details {
|
||||
position: relative;
|
||||
padding: 0px 48px;
|
||||
border-bottom: 1px solid @color_divider;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
padding-bottom: 32px;
|
||||
|
||||
.column {
|
||||
margin-right: 48px;
|
||||
|
||||
.label, .value {
|
||||
color: @color_text_secondary;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.fiat-value {
|
||||
font-weight: 500;
|
||||
font-size: 18px;
|
||||
margin: 7px 0px 7px 0px;
|
||||
color: @color_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toggle {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -20px;
|
||||
bottom: -20px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
//line-height: 30px;
|
||||
background: @color_white;
|
||||
color: @color_text_secondary;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.04);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: @color_divider;
|
||||
color: @color_text_primary;
|
||||
}
|
||||
|
||||
&:before {
|
||||
.icomoon-arrow-down;
|
||||
transition: transform 0.3s;
|
||||
transform-origin: 50% 50%;
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&.opened {
|
||||
.toggle:before {
|
||||
transform: rotate(180deg);
|
||||
top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.what-is-it {
|
||||
&:before {
|
||||
.icomoon-help;
|
||||
.hover();
|
||||
transform-origin: 50% 50%;
|
||||
font-size: 24px;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
cursor: pointer;
|
||||
color: @color_text_secondary;
|
||||
}
|
||||
&:hover {
|
||||
&:before {
|
||||
color: @color_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filter {
|
||||
//background: @color_main;
|
||||
padding: 0px 48px 32px 48px;
|
||||
// text-align: right;
|
||||
|
||||
input {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.token-select {
|
||||
.Select-control {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.Select-option {
|
||||
.hover();
|
||||
&.is-focused {
|
||||
background: @color_gray_light;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
background: @color_divider;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.token {
|
||||
border-top: 1px solid @color_divider;
|
||||
padding: 14px 48px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
.icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
//border: 8px solid white;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
line-height: 30px;
|
||||
text-transform: uppercase;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
padding: 6px;
|
||||
p {
|
||||
line-height: 24px;
|
||||
padding: 0px;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
flex: 1;
|
||||
color: @color_text_secondary;
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
padding: 0px;
|
||||
padding-top: 3px;
|
||||
&:after {
|
||||
.icomoon-close;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
&:last-child {
|
||||
// border-bottom: 1px solid @color_divider;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,243 +0,0 @@
|
||||
nav {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 1170px;
|
||||
height: 64px;
|
||||
margin: 0 auto;
|
||||
margin-top: 32px;
|
||||
z-index: 1;
|
||||
background: @color_white;
|
||||
border-radius: 4px 4px 0px 0px;
|
||||
border-bottom: 1px solid @color_divider;
|
||||
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.04);
|
||||
|
||||
@media screen and (max-width: 1170px) {
|
||||
border-radius: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
// .layout-wrapper {
|
||||
// height: 100%;
|
||||
// background: @color_white;
|
||||
// border-radius: 4px 4px 0px 0px;
|
||||
// border-bottom: 1px solid rgba(218, 218, 218, 0.5);
|
||||
// box-shadow: 0 3px 8px rgba(0, 0, 0, 0.04);
|
||||
// }
|
||||
|
||||
// override styles for react-select
|
||||
.device-select {
|
||||
width: 320px;
|
||||
height: 64px;
|
||||
// display: inline-block;
|
||||
// vertical-align: middle;
|
||||
box-shadow: none;
|
||||
|
||||
&.is-focused:not(.is-open) > .Select-control {
|
||||
border-color: @color_divider;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.Select-control {
|
||||
height: 63px;
|
||||
border: 0px;
|
||||
border-radius: 4px 0px 0px 0px;
|
||||
border-right: 1px solid @color_divider;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease-in-out;
|
||||
|
||||
.Select-input {
|
||||
background: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
//display: none !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
// border: 0px;
|
||||
border-right: 1px solid @color_divider;
|
||||
box-shadow: none;
|
||||
|
||||
.Select-arrow {
|
||||
&:after {
|
||||
color: @color_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Select-arrow-zone {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto 0;
|
||||
padding: 0px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
right: 24px;
|
||||
|
||||
.Select-arrow {
|
||||
top: 0px;
|
||||
border: 0px;
|
||||
width: 24px;
|
||||
|
||||
&:after {
|
||||
.icomoon-arrow-down;
|
||||
transition: transform 0.3s;
|
||||
color: @color_text_secondary;
|
||||
transform-origin: 50% 50%;
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.Select-option {
|
||||
&:hover {
|
||||
background: red;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
background: yellow;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-open {
|
||||
.Select-control {
|
||||
border-color: @color_divider;
|
||||
}
|
||||
|
||||
.Select-arrow {
|
||||
top: 0px !important;
|
||||
border: 0px;
|
||||
|
||||
|
||||
&:after {
|
||||
// .icomoon-arrow-up;
|
||||
transform: rotate(180deg);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
|
||||
.Select-control {
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.Select-arrow {
|
||||
visibility: hidden;
|
||||
&:after {
|
||||
content: ''
|
||||
}
|
||||
}
|
||||
|
||||
.device {
|
||||
.device-menu {
|
||||
padding-right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Select-menu-outer {
|
||||
border-radius: 0px;
|
||||
border: 1px solid @color_divider;
|
||||
box-shadow: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.device {
|
||||
height: 63px;
|
||||
width: 319px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 80px;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 13px;
|
||||
height: 25px;
|
||||
z-index: 2;
|
||||
left: 33px;
|
||||
top: 17px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 13px 25px;
|
||||
background-image: url('../images/icontrezor.png');
|
||||
}
|
||||
|
||||
.label-container {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
span {
|
||||
display: block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
&.label {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
color: @color_text_primary;
|
||||
}
|
||||
|
||||
&.status {
|
||||
font-size: 12px;
|
||||
color: @color_text_secondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.device-menu {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-right: 48px;
|
||||
padding-left: 4px;
|
||||
|
||||
div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.forget,
|
||||
.settings,
|
||||
.acquire {
|
||||
cursor: pointer;
|
||||
|
||||
&:before {
|
||||
.icomoon-refresh;
|
||||
color: @color_text_secondary;
|
||||
position: relative;
|
||||
font-size: 24px;
|
||||
.hover();
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:before {
|
||||
color: @color_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.forget {
|
||||
&:before {
|
||||
.icomoon-eject;
|
||||
}
|
||||
}
|
||||
|
||||
.settings {
|
||||
&:before {
|
||||
.icomoon-settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
import { injectGlobal } from 'styled-components';
|
||||
|
||||
import normalize from 'styled-normalize';
|
||||
|
||||
const baseStyles = () => injectGlobal`
|
||||
@ -40,23 +39,28 @@ const baseStyles = () => injectGlobal`
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
custom Roboto with Zero without the thing inside, so it's more readable as number
|
||||
since 0 doesn't look too similar to 8
|
||||
*/
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto Zero';
|
||||
src: url('../fonts/roboto/RobotoZero.eot') format('embedded-opentype'),
|
||||
url('../fonts/roboto/RobotoZero.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/roboto/RobotoZero.woff') format('woff'),
|
||||
url('../fonts/roboto/RobotoZero.ttf') format('truetype');
|
||||
src: url('./fonts/roboto/RobotoZero.eot') format('embedded-opentype'),
|
||||
url('./fonts/roboto/RobotoZero.eot?#iefix') format('embedded-opentype'),
|
||||
url('./fonts/roboto/RobotoZero.woff') format('woff'),
|
||||
url('./fonts/roboto/RobotoZero.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
font-style: normal;
|
||||
src: url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.eot') format('embedded-opentype'), /* IE9 Compat Modes */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('../fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.svg#RobotoMono') format('svg'); /* Legacy iOS */
|
||||
src: url('./fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.eot') format('embedded-opentype'), /* IE9 Compat Modes */
|
||||
url('./fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('./fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||
url('./fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('./fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||
url('./fonts/roboto/roboto-mono-v4-greek_cyrillic-ext_greek-ext_latin_cyrillic_vietnamese_latin-ext-regular.svg#RobotoMono') format('svg'); /* Legacy iOS */
|
||||
}
|
||||
|
||||
`;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import RedBox from 'redbox-react';
|
||||
|
||||
class ErrorBoundary extends Component {
|
||||
@ -7,7 +8,7 @@ class ErrorBoundary extends Component {
|
||||
this.state = { hasError: false, error: false };
|
||||
}
|
||||
|
||||
componentDidCatch(error, info) {
|
||||
componentDidCatch(error) {
|
||||
this.setState({ hasError: true, error });
|
||||
}
|
||||
|
||||
@ -19,4 +20,8 @@ class ErrorBoundary extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
ErrorBoundary.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
export default ErrorBoundary;
|
7
src/support/PropTypes.js
Normal file
7
src/support/PropTypes.js
Normal file
@ -0,0 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export const DEVICE_PROP_TYPES = PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
text: PropTypes.string.isRequired,
|
||||
author: authorPropType.isRequired,
|
||||
});
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
@ -4,9 +4,9 @@ import BigNumber from 'bignumber.js';
|
||||
|
||||
export const decimalToHex = (dec: number): string => new BigNumber(dec).toString(16);
|
||||
|
||||
export const hexToDecimal = (hex: number): string => {
|
||||
const sanitized: ?string = sanitizeHex(hex);
|
||||
return !sanitized ? 'null' : new BigNumber(sanitized).toString();
|
||||
export const padLeftEven = (hex: string): string => {
|
||||
hex = hex.length % 2 != 0 ? `0${hex}` : hex;
|
||||
return hex;
|
||||
};
|
||||
|
||||
export const sanitizeHex = (hex: number | string): ?string => {
|
||||
@ -16,9 +16,9 @@ export const sanitizeHex = (hex: number | string): ?string => {
|
||||
return `0x${padLeftEven(hex)}`;
|
||||
};
|
||||
|
||||
export const padLeftEven = (hex: string): string => {
|
||||
hex = hex.length % 2 != 0 ? `0${hex}` : hex;
|
||||
return hex;
|
||||
export const hexToDecimal = (hex: number): string => {
|
||||
const sanitized: ?string = sanitizeHex(hex);
|
||||
return !sanitized ? 'null' : new BigNumber(sanitized).toString();
|
||||
};
|
||||
|
||||
export const strip = (str: string): string => {
|
||||
|
@ -21,14 +21,14 @@ export const formatTime = (n: number): string => {
|
||||
|
||||
if (!n) return 'No time estimate';
|
||||
let res = '';
|
||||
if (hours != 0) {
|
||||
if (hours !== 0) {
|
||||
res += `${hours} hour`;
|
||||
if (hours > 1) {
|
||||
res += 's';
|
||||
}
|
||||
res += ' ';
|
||||
}
|
||||
if (minutes != 0) {
|
||||
if (minutes !== 0) {
|
||||
res += `${minutes} minutes`;
|
||||
}
|
||||
return res;
|
||||
|
@ -1,7 +1,4 @@
|
||||
/* @flow */
|
||||
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import type { MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||
@ -39,7 +36,7 @@ const mapStateToProps: MapStateToProps<State, OwnProps, StateProps> = (state: St
|
||||
devices: state.devices,
|
||||
});
|
||||
|
||||
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (dispatch: Dispatch): DispatchProps => ({
|
||||
const mapDispatchToProps: MapDispatchToProps<Dispatch, OwnProps, DispatchProps> = (/* dispatch: Dispatch */): DispatchProps => ({
|
||||
|
||||
});
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import styled, { css } from 'styled-components';
|
||||
import Link from 'components/Link';
|
||||
import Button from 'components/buttons/Button';
|
||||
import Button from 'components/Button';
|
||||
import P from 'components/Paragraph';
|
||||
import { H2 } from 'components/Heading';
|
||||
|
||||
|
@ -4,7 +4,7 @@ import React, { Component } from 'react';
|
||||
import styled, { keyframes } from 'styled-components';
|
||||
import TrezorConnect from 'trezor-connect';
|
||||
import P from 'components/Paragraph';
|
||||
import Button from 'components/buttons/Button';
|
||||
import Button from 'components/Button';
|
||||
import { PULSATE } from 'config/animations';
|
||||
import colors from 'config/colors';
|
||||
import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
||||
@ -89,10 +89,8 @@ class ConnectDevice extends Component<Props> {
|
||||
{this.props.showWebUsb && (
|
||||
<React.Fragment>
|
||||
<P>and</P>
|
||||
<Button
|
||||
className="trezor-webusb-button"
|
||||
isWebUsb
|
||||
>Check for devices
|
||||
<Button isWebUsb>
|
||||
Check for devices
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
@ -7,23 +7,24 @@ import { FONT_SIZE, FONT_WEIGHT } from 'config/variables';
|
||||
import installers from 'constants/bridge';
|
||||
import { Select } from 'components/Select';
|
||||
import Link from 'components/Link';
|
||||
import Button from 'components/buttons/Button';
|
||||
import Button from 'components/Button';
|
||||
import Loader from 'components/Loader';
|
||||
import P from 'components/Paragraph';
|
||||
import Icon from 'components/Icon';
|
||||
import ICONS from 'config/icons';
|
||||
|
||||
type State = {
|
||||
version: string;
|
||||
target: ?InstallTarget;
|
||||
url: string;
|
||||
}
|
||||
|
||||
type InstallTarget = {
|
||||
id: string;
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
type State = {
|
||||
version: string;
|
||||
target: ?InstallTarget;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// import type { Props } from './index';
|
||||
|
||||
type Props = {
|
||||
@ -73,6 +74,13 @@ const DownloadBridgeWrapper = styled.div`
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const DownloadBridgeButton = styled(Button)`
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export default class InstallBridge extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
@ -121,14 +129,14 @@ export default class InstallBridge extends Component<Props, State> {
|
||||
options={installers}
|
||||
/>
|
||||
<Link href={url}>
|
||||
<Button
|
||||
icon={{
|
||||
type: ICONS.DOWNLOAD,
|
||||
color: colors.WHITE,
|
||||
size: 30,
|
||||
}}
|
||||
>Download for {label}
|
||||
</Button>
|
||||
<DownloadBridgeButton>
|
||||
<Icon
|
||||
icon={ICONS.DOWNLOAD}
|
||||
color={colors.WHITE}
|
||||
size={30}
|
||||
/>
|
||||
Download for {label}
|
||||
</DownloadBridgeButton>
|
||||
</Link>
|
||||
</DownloadBridgeWrapper>
|
||||
<P>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user