diff --git a/web/cashtab/extension/src/components/App.js b/web/cashtab/extension/src/components/App.js index 6c916a94b..de3215e66 100644 --- a/web/cashtab/extension/src/components/App.js +++ b/web/cashtab/extension/src/components/App.js @@ -1,325 +1,343 @@ import React, { useState } from 'react'; import 'antd/dist/antd.less'; import { Spin } from 'antd'; -import { CashLoadingIcon } from '@components/Common/CustomIcons'; +import { + CashLoadingIcon, + HomeIcon, + SendIcon, + ReceiveIcon, + SettingsIcon, +} from '@components/Common/CustomIcons'; import '../index.css'; import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; import { theme } from '@assets/styles/theme'; -import { - FolderOpenFilled, - CaretRightOutlined, - SettingFilled, - AppstoreAddOutlined, -} from '@ant-design/icons'; -import Wallet from '@components/Wallet/Wallet'; +import Home from '@components/Home/Home'; +import Receive from '@components/Receive/Receive'; import Tokens from '@components/Tokens/Tokens'; import Send from '@components/Send/Send'; import SendToken from '@components/Send/SendToken'; import Configure from '@components/Configure/Configure'; import NotFound from '@components/NotFound'; import CashTab from '@assets/cashtab_xec.png'; import './App.css'; import { WalletContext } from '@utils/context'; import { isValidStoredWallet } from '@utils/cashMethods'; -import WalletLabel from '@components/Common/WalletLabel.js'; import { Route, Redirect, Switch, useLocation, useHistory, } from 'react-router-dom'; // Extension-only import used for open in new tab link import PopOut from '@assets/popout.svg'; const GlobalStyle = createGlobalStyle` + *::placeholder { + color: ${props => props.theme.forms.placeholder} !important; + } + *::selection { + background: ${props => props.theme.eCashBlue} !important; + } + .ant-modal-content, .ant-modal-header, .ant-modal-title { + background-color: ${props => props.theme.modal.background} !important; + color: ${props => props.theme.modal.color} !important; + } + .ant-modal-content svg { + fill: ${props => props.theme.modal.color}; + } + .ant-modal-footer button { + background-color: ${props => + props.theme.modal.buttonBackground} !important; + color: ${props => props.theme.modal.color} !important; + border-color: ${props => props.theme.modal.border} !important; + :hover { + background-color: ${props => props.theme.eCashBlue} !important; + } + } .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button, .ant-modal > button, .ant-modal-confirm-btns > button, .ant-modal-footer > button, #cropControlsConfirm{ - border-radius: 8px; - background-color: ${props => props.theme.modals.buttons.background}; - color: ${props => props.theme.wallet.text.secondary}; - font-weight: bold; + border-radius: 3px; + border-radius: 3px; + background-color: ${props => + props.theme.modal.buttonBackground} !important; + color: ${props => props.theme.modal.color} !important; + border-color: ${props => props.theme.modal.border} !important; + :hover { + background-color: ${props => props.theme.eCashBlue} !important; + } + text-shadow: none !important; + text-shadow: none !important; } .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button:hover,.ant-modal-confirm-btns > button:hover, .ant-modal-footer > button:hover, #cropControlsConfirm:hover { - color: ${props => props.theme.primary}; - transition: color 0.3s; - background-color: ${props => props.theme.modals.buttons.background}; + color: ${props => props.theme.contrast}; + transition: all 0.3s; + background-color: ${props => props.theme.eCashBlue}; + border-color: ${props => props.theme.eCashBlue}; } - .selectedCurrencyOption { + .selectedCurrencyOption, .ant-select-dropdown { text-align: left; - color: ${props => props.theme.wallet.text.secondary} !important; - background-color: ${props => props.theme.contrast} !important; + color: ${props => props.theme.contrast} !important; + background-color: ${props => + props.theme.collapses.expandedBackground} !important; } .cashLoadingIcon { - color: ${props => props.theme.primary} !important; + color: ${props => props.theme.eCashBlue} !important; font-size: 48px !important; } .selectedCurrencyOption:hover { color: ${props => props.theme.contrast} !important; - background-color: ${props => props.theme.primary} !important; + background-color: ${props => props.theme.eCashBlue} !important; } #addrSwitch, #cropSwitch { .ant-switch-checked { background-color: white !important; } } #addrSwitch.ant-switch-checked, #cropSwitch.ant-switch-checked { background-image: ${props => props.theme.buttons.primary.backgroundImage} !important; } .ant-slider-rail { background-color: ${props => props.theme.forms.border} !important; } .ant-slider-track { - background-color: ${props => props.theme.primary} !important; + background-color: ${props => props.theme.eCashBlue} !important; + } + .ant-descriptions-bordered .ant-descriptions-row { + background: ${props => props.theme.contrast}; + } + .ant-modal-confirm-content, .ant-modal-confirm-title { + color: ${props => props.theme.contrast} !important; } `; const CustomApp = styled.div` text-align: center; font-family: 'Gilroy', sans-serif; - background-color: ${props => props.theme.app.background}; + font-family: 'Poppins', sans-serif; + background-color: ${props => props.theme.backgroundColor}; + background-size: 100px 171px; + background-image: ${props => props.theme.backgroundImage}; + background-attachment: fixed; `; const Footer = styled.div` z-index: 2; - background-color: ${props => props.theme.footer.background}; - border-radius: 20px; + height: 80px; + border-top: 1px solid rgba(255, 255, 255, 0.5); + background-color: ${props => props.theme.footerBackground}; position: fixed; bottom: 0; width: 500px; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 50px; @media (max-width: 768px) { width: 100%; + padding: 0 20px; } - border-top: 1px solid ${props => props.theme.wallet.borders.color}; `; export const NavButton = styled.button` :focus, :active { outline: none; } cursor: pointer; - padding: 24px 12px 12px 12px; - margin: 0 28px; - @media (max-width: 475px) { - margin: 0 20px; - } - @media (max-width: 420px) { - margin: 0 12px; - } - @media (max-width: 350px) { - margin: 0 8px; - } - background-color: ${props => props.theme.footer.background}; + padding: 0; + background: none; border: none; - font-size: 12px; - font-weight: bold; - .anticon { - display: block; - color: ${props => props.theme.footer.navIconInactive}; - font-size: 24px; - margin-bottom: 6px; + font-size: 10px; + svg { + fill: ${props => props.theme.contrast}; + width: 26px; + height: auto; } ${({ active, ...props }) => active && - ` - color: ${props.theme.primary}; - .anticon { - color: ${props.theme.primary}; - } + ` + color: ${props.theme.navActive}; + svg { + fill: ${props.theme.navActive}; + } `} `; export const WalletBody = styled.div` display: flex; align-items: center; justify-content: center; width: 100%; min-height: 100vh; - background-image: ${props => props.theme.app.sidebars}; - background-attachment: fixed; `; export const WalletCtn = styled.div` position: relative; width: 500px; - background-color: ${props => props.theme.footerBackground}; min-height: 100vh; - padding: 10px 30px 120px 30px; - background: ${props => props.theme.wallet.background}; - -webkit-box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; - -moz-box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; - box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; + padding: 0 0 100px; + background: ${props => props.theme.walletBackground}; + -webkit-box-shadow: 0px 0px 24px 1px ${props => props.theme.shadow}; + -moz-box-shadow: 0px 0px 24px 1px ${props => props.theme.shadow}; + box-shadow: 0px 0px 24px 1px ${props => props.theme.shadow}; @media (max-width: 768px) { width: 100%; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } `; export const HeaderCtn = styled.div` display: flex; align-items: center; - justify-content: center; - width: 100%; - padding: 20px 0 30px; - margin-bottom: 20px; justify-content: space-between; - border-bottom: 1px solid ${props => props.theme.wallet.borders.color}; - - a { - color: ${props => props.theme.wallet.text.secondary}; - - :hover { - color: ${props => props.theme.primary}; - } - } - - @media (max-width: 768px) { - a { - font-size: 12px; - } - padding: 10px 0 20px; - } + width: 100%; + padding: 15px; `; export const CashTabLogo = styled.img` width: 120px; @media (max-width: 768px) { width: 110px; } `; // Extension only styled components const OpenInTabBtn = styled.button` background: none; border: none; `; const ExtTabImg = styled.img` max-width: 20px; `; const App = () => { const ContextValue = React.useContext(WalletContext); const { wallet, loading } = ContextValue; const [loadingUtxosAfterSend, setLoadingUtxosAfterSend] = useState(false); // If wallet is unmigrated, do not show page until it has migrated // An invalid wallet will be validated/populated after the next API call, ETA 10s const validWallet = isValidStoredWallet(wallet); const location = useLocation(); const history = useHistory(); const selectedKey = location && location.pathname ? location.pathname.substr(1) : ''; // openInTab is an extension-only method const openInTab = () => { window.open(`index.html#/${selectedKey}`); }; return ( {/*Begin extension-only components*/} openInTab()} > {/*End extension-only components*/} {/*Note that the extension does not support biometric security*/} {/*Hence is not pulled in*/} - - + + + + ( )} /> {wallet ? ( ) : null} ); }; export default App; diff --git a/web/cashtab/public/cashtab_bg.png b/web/cashtab/public/cashtab_bg.png index 372c389b7..bed03771d 100644 Binary files a/web/cashtab/public/cashtab_bg.png and b/web/cashtab/public/cashtab_bg.png differ diff --git a/web/cashtab/public/cashtab_twitter.png b/web/cashtab/public/cashtab_twitter.png index df43505da..ee3268618 100644 Binary files a/web/cashtab/public/cashtab_twitter.png and b/web/cashtab/public/cashtab_twitter.png differ diff --git a/web/cashtab/src/assets/alert-circle.svg b/web/cashtab/src/assets/alert-circle.svg new file mode 100644 index 000000000..7c01d8f61 --- /dev/null +++ b/web/cashtab/src/assets/alert-circle.svg @@ -0,0 +1 @@ +Alert Circle \ No newline at end of file diff --git a/web/cashtab/src/assets/cashtab_xec.png b/web/cashtab/src/assets/cashtab_xec.png index 39c68e7a9..51bd8541e 100644 Binary files a/web/cashtab/src/assets/cashtab_xec.png and b/web/cashtab/src/assets/cashtab_xec.png differ diff --git a/web/cashtab/src/assets/cog.svg b/web/cashtab/src/assets/cog.svg new file mode 100644 index 000000000..10c3c4fda --- /dev/null +++ b/web/cashtab/src/assets/cog.svg @@ -0,0 +1 @@ +Cog \ No newline at end of file diff --git a/web/cashtab/src/assets/flask.svg b/web/cashtab/src/assets/flask.svg new file mode 100644 index 000000000..7f8593ab4 --- /dev/null +++ b/web/cashtab/src/assets/flask.svg @@ -0,0 +1 @@ +Flask \ No newline at end of file diff --git a/web/cashtab/src/assets/fonts/Poppins-Bold.ttf b/web/cashtab/src/assets/fonts/Poppins-Bold.ttf new file mode 100755 index 000000000..b94d47f3a Binary files /dev/null and b/web/cashtab/src/assets/fonts/Poppins-Bold.ttf differ diff --git a/web/cashtab/src/assets/fonts/Poppins-Regular.ttf b/web/cashtab/src/assets/fonts/Poppins-Regular.ttf new file mode 100755 index 000000000..be06e7fdc Binary files /dev/null and b/web/cashtab/src/assets/fonts/Poppins-Regular.ttf differ diff --git a/web/cashtab/src/assets/home.svg b/web/cashtab/src/assets/home.svg new file mode 100644 index 000000000..94cf77d4c --- /dev/null +++ b/web/cashtab/src/assets/home.svg @@ -0,0 +1,13 @@ + + + + + + + diff --git a/web/cashtab/src/assets/receive.svg b/web/cashtab/src/assets/receive.svg new file mode 100644 index 000000000..8b3aaeb92 --- /dev/null +++ b/web/cashtab/src/assets/receive.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/web/cashtab/src/assets/send.svg b/web/cashtab/src/assets/send.svg new file mode 100644 index 000000000..f7b9fb467 --- /dev/null +++ b/web/cashtab/src/assets/send.svg @@ -0,0 +1 @@ +Send \ No newline at end of file diff --git a/web/cashtab/src/assets/styles/theme.js b/web/cashtab/src/assets/styles/theme.js index fc96fc8b9..4a28eeb27 100644 --- a/web/cashtab/src/assets/styles/theme.js +++ b/web/cashtab/src/assets/styles/theme.js @@ -1,96 +1,71 @@ export const theme = { - primary: '#00ABE7', - brandSecondary: '#CD0BC3', + eCashBlue: '#00ABE7', + eCashPurple: '#ff21d0', + darkBlue: '#273498', contrast: '#fff', - app: { - sidebars: `url("/cashtab_bg.png")`, - background: '#fbfbfd', - }, - wallet: { - background: '#fff', - encryption: '#DC143C', - text: { - primary: '#273498', - secondary: '#273498', - }, - switch: { - activeCash: { - shadow: 'inset 8px 8px 16px #0074C2, inset -8px -8px 16px #273498', - }, - activeToken: { - background: '#CD0BC3', - shadow: 'inset 5px 5px 11px #FF21D0, inset -5px -5px 11px #CD0BC3', - }, - inactive: { - background: 'linear-gradient(145deg, #eeeeee, #c8c8c8)', - }, - }, - borders: { color: '#e2e2e2' }, - shadow: 'rgba(0, 0, 0, 1)', - }, - tokenListItem: { - background: '#ffffff', - color: '', - boxShadow: - 'rgb(136 172 243 / 25%) 0px 10px 30px,rgb(0 0 0 / 3%) 0px 1px 1px, rgb(0 51 167 / 10%) 0px 10px 20px', - border: '#e9eaed', - hoverBorder: '#231F20', - }, - footer: { - background: '#fff', - navIconInactive: '#949494', + backgroundImage: `url("/cashtab_bg.png")`, + backgroundColor: '#d5d5d7', + walletBackground: '#152b45', + walletInfoContainer: '#255173', + footerBackground: '#152b45', + navActive: '#00ABE7', + encryptionRed: '#DC143C', + genesisGreen: '#00e781', + receivedMessage: 'rgba(0,171,231,0.2)', + sentMessage: 'rgba(255, 255, 255, 0.1)', + lightWhite: 'rgba(255,255,255,0.4)', + dropdownText: '#000', + shadow: 'rgba(0, 0, 0, 0.4)', + switchButtonActiveText: '#fff', + advancedCollapse: { + background: '#255173', + color: '#fff', + icon: '#fff', + expandedBackground: 'rgba(0,0,0,0.2)', }, forms: { error: '#FF21D0', - border: '#e7edf3', - text: '#001137', - addonBackground: '#f4f4f4', - addonForeground: '#3e3f42', - selectionBackground: '#fff', - darkLabel: '#0074c2', - lightLabel: '#c0c0c0', - }, - icons: { outlined: '#273498' }, - modals: { - buttons: { background: '#fff' }, + border: '#17171f', + text: '#fff', + addonBackground: '#255173', + addonForeground: '#fff', + selectionBackground: '#255173', + placeholder: 'rgba(255,255,255,0.3)', + highlightBox: '#00ABE7', }, + icons: { outlined: '#fff' }, settings: { delete: '#CD0BC3', - background: '#eee', + background: 'rgba(0,0,0,0.4)', }, qr: { - copyBorderCash: '#00ABE7', - copyBorderToken: '#FF21D0', background: '#fff', - token: '#231F20', - shadow: 'rgb(136 172 243 / 25%) 0px 10px 30px, rgb(0 0 0 / 3%) 0px 1px 1px, rgb(0 51 167 / 10%) 0px 10px 20px', }, buttons: { primary: { backgroundImage: 'linear-gradient(270deg, #0074C2 0%, #273498 100%)', color: '#fff', hoverShadow: '0px 3px 10px -5px rgba(0, 0, 0, 0.75)', disabledOverlay: 'rgba(255, 255, 255, 0.5)', }, secondary: { - background: '#e9eaed', - color: '#444', + background: '#4b67e1', + color: '#fff', hoverShadow: '0px 3px 10px -5px rgba(0, 0, 0, 0.75)', disabledOverlay: 'rgba(255, 255, 255, 0.5)', }, }, collapses: { - background: '#fbfcfd', - expandedBackground: '#fff', - border: '#eaedf3', - color: '#3e3f42', + background: '#255173', + expandedBackground: '#26415a', + border: '#17171f', + color: '#fff', }, - generalSettings: { - item: { - icon: '#949494', - title: '#949494', - }, - background: '#fff', + modal: { + background: '#255173', + border: '#17171f', + color: '#fff', + buttonBackground: '#26415a', }, }; diff --git a/web/cashtab/src/components/App.css b/web/cashtab/src/components/App.css index 63140c657..fdc009cb0 100644 --- a/web/cashtab/src/components/App.css +++ b/web/cashtab/src/components/App.css @@ -1,51 +1,65 @@ @import '~antd/dist/antd.less'; @import '~@fortawesome/fontawesome-free/css/all.css'; @import url('https://fonts.googleapis.com/css?family=Khula&display=swap&.css'); +@font-face { + font-family: 'Poppins'; + src: local('Poppins'), + url(../assets/fonts/Poppins-Regular.ttf) format('truetype'); + font-weight: normal; +} + +@font-face { + font-family: 'Poppins'; + src: local('Poppins'), + url(../assets/fonts/Poppins-Bold.ttf) format('truetype'); + font-weight: 700; +} + /* Hide scrollbars but keep functionality*/ /* Hide scrollbar for Chrome, Safari and Opera */ body::-webkit-scrollbar { display: none; } /* Hide scrollbar for IE, Edge and Firefox */ body { -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ } /* Hide up and down arros on input type="number" */ /* Chrome, Safari, Edge, Opera */ input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } /* Hide up and down arros on input type="number" */ /* Firefox */ input[type='number'] { -moz-appearance: textfield; } html, body { max-width: 100%; overflow-x: hidden; } /* Hide scroll bars on antd modals*/ .ant-modal-wrap.ant-modal-centered::-webkit-scrollbar { display: none; } /* ITEMS BELOW TO BE MOVED TO STYLED COMPONENTS*/ /* useWallet.js, useBCH.js */ @media (max-width: 768px) { .ant-notification { width: 100%; top: 20px !important; max-width: unset; margin-right: 0; } } diff --git a/web/cashtab/src/components/App.js b/web/cashtab/src/components/App.js index 917167651..085b2cfdd 100644 --- a/web/cashtab/src/components/App.js +++ b/web/cashtab/src/components/App.js @@ -1,358 +1,363 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import 'antd/dist/antd.less'; -import { Modal, Spin } from 'antd'; -import { CashLoadingIcon } from '@components/Common/CustomIcons'; +import { Spin } from 'antd'; +import { + CashLoadingIcon, + HomeIcon, + SendIcon, + ReceiveIcon, + SettingsIcon, +} from '@components/Common/CustomIcons'; import '../index.css'; import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; import { theme } from '@assets/styles/theme'; -import { - FolderOpenFilled, - CaretRightOutlined, - SettingFilled, - AppstoreAddOutlined, -} from '@ant-design/icons'; -import Wallet from '@components/Wallet/Wallet'; +import Home from '@components/Home/Home'; +import Receive from '@components/Receive/Receive'; import Tokens from '@components/Tokens/Tokens'; import Send from '@components/Send/Send'; import SendToken from '@components/Send/SendToken'; import Configure from '@components/Configure/Configure'; import NotFound from '@components/NotFound'; import CashTab from '@assets/cashtab_xec.png'; import './App.css'; import { WalletContext } from '@utils/context'; import { isValidStoredWallet } from '@utils/cashMethods'; -import WalletLabel from '@components/Common/WalletLabel.js'; import { Route, Redirect, Switch, useLocation, useHistory, } from 'react-router-dom'; // Easter egg imports not used in extension/src/components/App.js import TabCash from '@assets/tabcash.png'; -import ABC from '@assets/logo_topright.png'; import { checkForTokenById } from '@utils/tokenMethods.js'; // Biometric security import not used in extension/src/components/App.js import ProtectableComponentWrapper from './Authentication/ProtectableComponentWrapper'; -const GlobalStyle = createGlobalStyle` +const GlobalStyle = createGlobalStyle` + *::placeholder { + color: ${props => props.theme.forms.placeholder} !important; + } + *::selection { + background: ${props => props.theme.eCashBlue} !important; + } + .ant-modal-content, .ant-modal-header, .ant-modal-title { + background-color: ${props => props.theme.modal.background} !important; + color: ${props => props.theme.modal.color} !important; + } + .ant-modal-content svg { + fill: ${props => props.theme.modal.color}; + } + .ant-modal-footer button { + background-color: ${props => + props.theme.modal.buttonBackground} !important; + color: ${props => props.theme.modal.color} !important; + border-color: ${props => props.theme.modal.border} !important; + :hover { + background-color: ${props => props.theme.eCashBlue} !important; + } + } .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button, .ant-modal > button, .ant-modal-confirm-btns > button, .ant-modal-footer > button, #cropControlsConfirm { - border-radius: 8px; - background-color: ${props => props.theme.modals.buttons.background}; - color: ${props => props.theme.wallet.text.secondary}; - font-weight: bold; + border-radius: 3px; + background-color: ${props => + props.theme.modal.buttonBackground} !important; + color: ${props => props.theme.modal.color} !important; + border-color: ${props => props.theme.modal.border} !important; + :hover { + background-color: ${props => props.theme.eCashBlue} !important; + } + text-shadow: none !important; } .ant-modal-wrap > div > div.ant-modal-content > div > div > div.ant-modal-confirm-btns > button:hover,.ant-modal-confirm-btns > button:hover, .ant-modal-footer > button:hover, #cropControlsConfirm:hover { - color: ${props => props.theme.primary}; - transition: color 0.3s; - background-color: ${props => props.theme.modals.buttons.background}; + color: ${props => props.theme.contrast}; + transition: all 0.3s; + background-color: ${props => props.theme.eCashBlue}; + border-color: ${props => props.theme.eCashBlue}; } - .selectedCurrencyOption { + .selectedCurrencyOption, .ant-select-dropdown { text-align: left; - color: ${props => props.theme.wallet.text.secondary} !important; - background-color: ${props => props.theme.contrast} !important; + color: ${props => props.theme.contrast} !important; + background-color: ${props => + props.theme.collapses.expandedBackground} !important; } .cashLoadingIcon { - color: ${props => props.theme.primary} !important; + color: ${props => props.theme.eCashBlue} !important; font-size: 48px !important; } .selectedCurrencyOption:hover { color: ${props => props.theme.contrast} !important; - background-color: ${props => props.theme.primary} !important; + background-color: ${props => props.theme.eCashBlue} !important; } #addrSwitch, #cropSwitch { .ant-switch-checked { background-color: white !important; } } #addrSwitch.ant-switch-checked, #cropSwitch.ant-switch-checked { background-image: ${props => props.theme.buttons.primary.backgroundImage} !important; } .ant-slider-rail { background-color: ${props => props.theme.forms.border} !important; } .ant-slider-track { - background-color: ${props => props.theme.primary} !important; + background-color: ${props => props.theme.eCashBlue} !important; + } + .ant-descriptions-bordered .ant-descriptions-row { + background: ${props => props.theme.contrast}; + } + .ant-modal-confirm-content, .ant-modal-confirm-title { + color: ${props => props.theme.contrast} !important; } `; const CustomApp = styled.div` text-align: center; - font-family: 'Gilroy', sans-serif; - background-color: ${props => props.theme.app.background}; + font-family: 'Poppins', sans-serif; + background-color: ${props => props.theme.backgroundColor}; + background-size: 100px 171px; + background-image: ${props => props.theme.backgroundImage}; + background-attachment: fixed; `; const Footer = styled.div` z-index: 2; - background-color: ${props => props.theme.footer.background}; - border-radius: 20px 20px 0 0; + height: 80px; + border-top: 1px solid rgba(255, 255, 255, 0.5); + background-color: ${props => props.theme.footerBackground}; position: fixed; bottom: 0; width: 500px; - box-shadow: rgb(136 172 243 / 25%) 0px 10px 30px, - rgb(0 0 0 / 3%) 0px 1px 1px, rgb(0 51 167 / 10%) 0px 10px 20px; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 50px; @media (max-width: 768px) { width: 100%; + padding: 0 20px; } `; export const NavButton = styled.button` :focus, :active { outline: none; } cursor: pointer; - padding: 24px 12px 12px 12px; - margin: 0 28px; - @media (max-width: 475px) { - margin: 0 20px; - } - @media (max-width: 420px) { - margin: 0 12px; - } - @media (max-width: 350px) { - margin: 0 8px; - } - background-color: ${props => props.theme.footer.background}; + padding: 0; + background: none; border: none; - font-size: 10.5px; - font-weight: bold; - .anticon { - display: block; - color: ${props => props.theme.footer.navIconInactive}; - font-size: 24px; - margin-bottom: 6px; + font-size: 10px; + svg { + fill: ${props => props.theme.contrast}; + width: 26px; + height: auto; } ${({ active, ...props }) => active && ` - color: ${props.theme.primary}; - .anticon { - color: ${props.theme.primary}; + color: ${props.theme.navActive}; + svg { + fill: ${props.theme.navActive}; } `} `; export const WalletBody = styled.div` display: flex; align-items: center; justify-content: center; width: 100%; min-height: 100vh; - background-image: ${props => props.theme.app.sidebars}; - background-attachment: fixed; `; export const WalletCtn = styled.div` position: relative; width: 500px; - background-color: ${props => props.theme.footerBackground}; min-height: 100vh; - padding: 10px 30px 120px 30px; - background: ${props => props.theme.wallet.background}; - -webkit-box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; - -moz-box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; - box-shadow: 0px 0px 24px 1px ${props => props.theme.wallet.shadow}; + padding: 0 0 100px; + background: ${props => props.theme.walletBackground}; + -webkit-box-shadow: 0px 0px 24px 1px ${props => props.theme.shadow}; + -moz-box-shadow: 0px 0px 24px 1px ${props => props.theme.shadow}; + box-shadow: 0px 0px 24px 1px ${props => props.theme.shadow}; @media (max-width: 768px) { width: 100%; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } `; export const HeaderCtn = styled.div` display: flex; align-items: center; justify-content: center; width: 100%; - padding: 20px 0 30px; - margin-bottom: 20px; - justify-content: space-between; - - a { - color: ${props => props.theme.wallet.text.secondary}; - - :hover { - color: ${props => props.theme.primary}; - } - } - - @media (max-width: 768px) { - a { - font-size: 12px; - } - padding: 10px 0 20px; - } + padding: 15px 0; `; export const CashTabLogo = styled.img` width: 120px; @media (max-width: 768px) { width: 110px; } `; // AbcLogo styled component not included in extension, replaced by open in new tab link export const AbcLogo = styled.img` width: 150px; @media (max-width: 768px) { width: 120px; } `; // Easter egg styled component not used in extension/src/components/App.js export const EasterEgg = styled.img` position: fixed; bottom: -195px; margin: 0; right: 10%; transition-property: bottom; transition-duration: 1.5s; transition-timing-function: ease-out; :hover { bottom: 0; } @media screen and (max-width: 1250px) { display: none; } `; const App = () => { const ContextValue = React.useContext(WalletContext); const { wallet, loading } = ContextValue; const [loadingUtxosAfterSend, setLoadingUtxosAfterSend] = useState(false); // If wallet is unmigrated, do not show page until it has migrated // An invalid wallet will be validated/populated after the next API call, ETA 10s const validWallet = isValidStoredWallet(wallet); const location = useLocation(); const history = useHistory(); const selectedKey = location && location.pathname ? location.pathname.substr(1) : ''; // Easter egg boolean not used in extension/src/components/App.js const hasTab = validWallet ? checkForTokenById( wallet.state.tokens, '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e', ) : false; return ( {/*Begin component not included in extension as desktop only*/} {hasTab && ( )} {/*End component not included in extension as desktop only*/} - {/*Begin component not included in extension as replaced by open in tab link*/} - - - - {/*Begin component not included in extension as replaced by open in tab link*/} - - + + + + ( )} /> {wallet ? ( ) : null} ); }; export default App; diff --git a/web/cashtab/src/components/Authentication/SignIn.js b/web/cashtab/src/components/Authentication/SignIn.js index a1c188e3f..b9f48bddb 100644 --- a/web/cashtab/src/components/Authentication/SignIn.js +++ b/web/cashtab/src/components/Authentication/SignIn.js @@ -1,155 +1,155 @@ import React, { useContext, useEffect, useState } from 'react'; import { Modal, Spin } from 'antd'; import styled from 'styled-components'; import { AuthenticationContext } from '@utils/context'; import { ThemedLockOutlined } from '@components/Common/CustomIcons'; import PrimaryButton from '@components/Common/PrimaryButton'; import { ReactComponent as FingerprintSVG } from '@assets/fingerprint-solid.svg'; const StyledSignIn = styled.div` h2 { - color: ${props => props.theme.wallet.text.primary}; + color: ${props => props.theme.contrast}; font-size: 25px; } p { - color: ${props => props.theme.wallet.text.secondary}; + color: ${props => props.theme.darkBlue}; } `; const UnlockButton = styled(PrimaryButton)` position: relative; width: auto; margin: 30px auto; padding: 20px 30px; svg { fill: ${props => props.theme.buttons.primary.color}; } @media (max-width: 768px) { font-size: 16px; padding: 15px 20px; } :disabled { cursor: not-allowed; box-shadow: none; ::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: ${props => props.theme.buttons.primary.disabledOverlay}; z-index: 10; } } `; const StyledFingerprintIcon = styled.div` width: 48px; height: 48px; margin: auto; `; const SignIn = () => { const authentication = useContext(AuthenticationContext); const [isVisible, setIsVisible] = useState(false); const [isLoading, setIsLoading] = useState(false); const handleDocVisibilityChange = () => { document.visibilityState === 'visible' ? setIsVisible(true) : setIsVisible(false); }; const handleSignIn = async () => { try { setIsLoading(true); await authentication.signIn(); } catch (err) { Modal.error({ title: 'Authentication Error', content: 'Cannot get Credential from your device', centered: true, }); } setIsLoading(false); }; const handleSignInAndSuppressError = async () => { try { setIsLoading(true); await authentication.signIn(); } catch (err) { // fail silently } setIsLoading(false); }; useEffect(() => { if (document.visibilityState === 'visible') { setIsVisible(true); } document.addEventListener( 'visibilitychange', handleDocVisibilityChange, ); return () => { document.removeEventListener( 'visibilitychange', handleDocVisibilityChange, ); }; }, []); useEffect(() => { // This will trigger the plaform authenticator as soon as the component becomes visible // (when switch back to this app), without any user gesture (such as clicking a button) // In platforms that require user gesture in order to invoke the platform authenticator, // this will fail. We want it to fail silently, and then show user a button to activate // the platform authenticator if (isVisible && authentication) { handleSignInAndSuppressError(); } }, [isVisible]); let signInBody; if (authentication) { signInBody = ( <>

This wallet can be unlocked with your{' '} fingerprint / device pin

Unlock
{isLoading ? : ''}
); } else { signInBody =

Authentication is not supported

; } return (

Wallet Unlock

{signInBody}
); }; export default SignIn; diff --git a/web/cashtab/src/components/Authentication/SignUp.js b/web/cashtab/src/components/Authentication/SignUp.js index 31b67c8db..dbe1d6b99 100644 --- a/web/cashtab/src/components/Authentication/SignUp.js +++ b/web/cashtab/src/components/Authentication/SignUp.js @@ -1,74 +1,76 @@ import React, { useContext } from 'react'; import { Modal } from 'antd'; import styled from 'styled-components'; import { AuthenticationContext } from '@utils/context'; import { ThemedLockOutlined } from '@components/Common/CustomIcons'; import PrimaryButton, { SecondaryButton, } from '@components/Common/PrimaryButton'; const StyledSignUp = styled.div` + padding: 0px 30px; + margin-top: 20px; h2 { - color: ${props => props.theme.wallet.text.primary}; + color: ${props => props.theme.contrast}; font-size: 25px; } p { - color: ${props => props.theme.wallet.text.secondary}; + color: ${props => props.theme.contrast}; } `; const SignUp = () => { const authentication = useContext(AuthenticationContext); const handleSignUp = async () => { try { await authentication.signUp(); } catch (err) { Modal.error({ title: 'Registration Error', content: 'Cannot create Credential on your device', centered: true, }); } }; let signUpBody; if (authentication) { signUpBody = (

Enable wallet lock to protect your funds.

You will need to unlock with your{' '} fingerprint / device pin in order to access the wallet.

This lock can also be enabled / disabled under
Settings / General Settings / App Lock

Enable Lock authentication.turnOffAuthentication()} > Skip
); } else { signUpBody =

Authentication is not supported

; } return (

Wallet Lock

{signUpBody}
); }; export default SignUp; diff --git a/web/cashtab/src/components/Common/Alerts.js b/web/cashtab/src/components/Common/Alerts.js deleted file mode 100644 index 81790d5de..000000000 --- a/web/cashtab/src/components/Common/Alerts.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { Alert } from 'antd'; - -const TokenIconAlert = () => { - return ( - <> -
- -
- - ); -}; - -export default TokenIconAlert; diff --git a/web/cashtab/src/components/Common/Atoms.js b/web/cashtab/src/components/Common/Atoms.js index afa1ec70c..84258f309 100644 --- a/web/cashtab/src/components/Common/Atoms.js +++ b/web/cashtab/src/components/Common/Atoms.js @@ -1,63 +1,84 @@ import styled from 'styled-components'; export const LoadingCtn = styled.div` width: 100%; display: flex; align-items: center; justify-content: center; height: 400px; flex-direction: column; svg { width: 50px; height: 50px; - fill: ${props => props.theme.primary}; + fill: ${props => props.theme.eCashBlue}; } `; -export const BalanceHeaderWrap = styled.div` - color: ${props => props.theme.wallet.text.primary}; - width: 100%; - font-size: 30px; - font-weight: bold; +export const SidePaddingCtn = styled.div` + padding: 0px 30px; @media (max-width: 768px) { - font-size: 23px; + padding: 0px 15px; } `; +export const FormLabel = styled.label` + font-size: 16px; + margin-bottom: 5px; + text-align: left; + width: 100%; + display: inline-block; + color: ${props => props.theme.contrast}; +`; + +export const WalletInfoCtn = styled.div` + background: ${props => props.theme.walletInfoContainer}; + width: 100%; + padding: 40px 20px; +`; + export const BalanceHeaderFiatWrap = styled.div` - color: ${props => props.theme.wallet.text.secondary}; + color: ${props => props.theme.contrast}; width: 100%; - font-size: 18px; - margin-bottom: 20px; - font-weight: bold; + font-size: 16px; @media (max-width: 768px) { font-size: 16px; } `; +export const BalanceHeaderWrap = styled.div` + color: ${props => props.theme.contrast}; + width: 100%; + font-size: 28px; + margin-bottom: 0px; + font-weight: bold; + line-height: 1.4em; + @media (max-width: 768px) { + font-size: 24px; + } +`; + export const ZeroBalanceHeader = styled.div` - color: ${props => props.theme.wallet.text.primary}; + color: ${props => props.theme.contrast}; width: 100%; font-size: 14px; margin-bottom: 5px; `; export const TokenParamLabel = styled.span` font-weight: bold; `; export const AlertMsg = styled.p` color: ${props => props.theme.forms.error} !important; `; export const ConvertAmount = styled.div` - color: ${props => props.theme.wallet.text.secondary}; + color: ${props => props.theme.contrast}; width: 100%; font-size: 14px; margin-bottom: 10px; - font-weight: bold; @media (max-width: 768px) { font-size: 12px; } `; diff --git a/web/cashtab/src/components/Common/BalanceHeaderFiat.js b/web/cashtab/src/components/Common/BalanceHeaderFiat.js index 9fa83c4b8..dec4d14a1 100644 --- a/web/cashtab/src/components/Common/BalanceHeaderFiat.js +++ b/web/cashtab/src/components/Common/BalanceHeaderFiat.js @@ -1,28 +1,28 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { BalanceHeaderFiatWrap } from '@components/Common/Atoms'; import { currency } from '@components/Common/Ticker.js'; const BalanceHeaderFiat = ({ balance, settings, fiatPrice }) => { return ( {settings - ? `${currency.fiatCurrencies[settings.fiatCurrency].symbol} ` - : '$ '} + ? `${currency.fiatCurrencies[settings.fiatCurrency].symbol}` + : '$'} {parseFloat((balance * fiatPrice).toFixed(2)).toLocaleString()}{' '} {settings ? `${currency.fiatCurrencies[ settings.fiatCurrency ].slug.toUpperCase()} ` : 'USD'} ); }; BalanceHeaderFiat.propTypes = { balance: PropTypes.number, settings: PropTypes.object, fiatPrice: PropTypes.number, }; export default BalanceHeaderFiat; diff --git a/web/cashtab/src/components/Common/CustomIcons.js b/web/cashtab/src/components/Common/CustomIcons.js index 59ae456c3..c487f449f 100644 --- a/web/cashtab/src/components/Common/CustomIcons.js +++ b/web/cashtab/src/components/Common/CustomIcons.js @@ -1,74 +1,89 @@ import * as React from 'react'; import styled from 'styled-components'; import { CopyOutlined, DollarOutlined, LoadingOutlined, WalletOutlined, QrcodeOutlined, SettingOutlined, LockOutlined, } from '@ant-design/icons'; import { Image } from 'antd'; import { currency } from '@components/Common/Ticker'; +import { ReactComponent as Send } from '@assets/send.svg'; +import { ReactComponent as Receive } from '@assets/receive.svg'; +import { ReactComponent as Genesis } from '@assets/flask.svg'; +import { ReactComponent as Unparsed } from '@assets/alert-circle.svg'; +import { ReactComponent as Home } from '@assets/home.svg'; +import { ReactComponent as Settings } from '@assets/cog.svg'; export const CashLoadingIcon = ; export const CashReceivedNotificationIcon = () => ( ); export const TokenReceivedNotificationIcon = () => ( ); export const MessageSignedNotificationIcon = () => ( ); export const ThemedCopyOutlined = styled(CopyOutlined)` color: ${props => props.theme.icons.outlined} !important; `; export const ThemedDollarOutlined = styled(DollarOutlined)` color: ${props => props.theme.icons.outlined} !important; `; export const ThemedWalletOutlined = styled(WalletOutlined)` color: ${props => props.theme.icons.outlined} !important; `; export const ThemedQrcodeOutlined = styled(QrcodeOutlined)` - color: ${props => props.theme.icons.outlined} !important; + color: ${props => props.theme.walletBackground} !important; `; export const ThemedSettingOutlined = styled(SettingOutlined)` color: ${props => props.theme.icons.outlined} !important; `; export const ThemedLockOutlined = styled(LockOutlined)` color: ${props => props.theme.icons.outlined} !important; `; export const LoadingBlock = styled.div` width: 100%; display: flex; align-items: center; justify-content: center; padding: 24px; flex-direction: column; svg { width: 50px; height: 50px; - fill: ${props => props.theme.primary}; + fill: ${props => props.theme.eCashBlue}; } `; export const CashLoader = () => ( ); + +export const ReceiveIcon = () => ; +export const GenesisIcon = () => ; +export const UnparsedIcon = () => ; +export const HomeIcon = () => ; +export const SettingsIcon = () => ; +export const SendIcon = styled(Send)` + transform: rotate(-35deg); +`; diff --git a/web/cashtab/src/components/Common/EnhancedInputs.js b/web/cashtab/src/components/Common/EnhancedInputs.js index 66c027e3d..ed8a23389 100644 --- a/web/cashtab/src/components/Common/EnhancedInputs.js +++ b/web/cashtab/src/components/Common/EnhancedInputs.js @@ -1,363 +1,375 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { Form, Input, Select } from 'antd'; const { TextArea } = Input; import { ThemedDollarOutlined, ThemedWalletOutlined, } from '@components/Common/CustomIcons'; import styled, { css } from 'styled-components'; import ScanQRCode from './ScanQRCode'; import useBCH from '@hooks/useBCH'; import { currency } from '@components/Common/Ticker.js'; export const AntdFormCss = css` .ant-input-group-addon { background-color: ${props => props.theme.forms.addonBackground} !important; border: 1px solid ${props => props.theme.forms.border}; color: ${props => props.theme.forms.addonForeground} !important; } input.ant-input, .ant-select-selection { background-color: ${props => props.theme.forms.selectionBackground} !important; box-shadow: none !important; border-radius: 4px; font-weight: bold; color: ${props => props.theme.forms.text}; opacity: 1; - height: 50px; + height: 45px; } textarea.ant-input, .ant-select-selection { background-color: ${props => props.theme.forms.selectionBackground} !important; box-shadow: none !important; border-radius: 4px; font-weight: bold; color: ${props => props.theme.forms.text}; opacity: 1; height: 50px; min-height: 100px; } .ant-input-affix-wrapper { background-color: ${props => props.theme.forms.selectionBackground}; - border: 1px solid ${props => props.theme.wallet.borders.color} !important; + border: 1px solid ${props => props.theme.forms.border} !important; + } + .ant-input-wrapper .anticon-qrcode { + color: ${props => props.theme.forms.addonForeground} !important; + } + input.ant-input::placeholder, + .ant-select-selection::placeholder { + color: ${props => props.theme.forms.placeholder} !important; } .ant-select-selector { - height: 60px !important; - border: 1px solid ${props => props.theme.wallet.borders.color} !important; + height: 55px !important; + border: 1px solid ${props => props.theme.forms.border} !important; background-color: ${props => props.theme.forms.selectionBackground}!important; } .ant-form-item-has-error > div > div.ant-form-item-control-input > div > span > span > span.ant-input-affix-wrapper { background-color: ${props => props.theme.forms.selectionBackground}; border-color: ${props => props.theme.forms.error} !important; } + .ant-input:hover { + border-color: ${props => props.theme.forms.highlightBox}; + } + .ant-form-item-has-error .ant-input, .ant-form-item-has-error .ant-input-affix-wrapper, .ant-form-item-has-error .ant-input:hover, .ant-form-item-has-error .ant-input-affix-wrapper:hover { background-color: ${props => props.theme.forms.selectionBackground}; border-color: ${props => props.theme.forms.error} !important; } .ant-form-item-has-error .ant-select:not(.ant-select-disabled):not(.ant-select-customize-input) .ant-select-selector { background-color: ${props => props.theme.forms.selectionBackground}; border-color: ${props => props.theme.forms.error} !important; } .ant-select-single .ant-select-selector .ant-select-selection-item, .ant-select-single .ant-select-selector .ant-select-selection-placeholder { - line-height: 60px; + line-height: 55px; text-align: left; color: ${props => props.theme.forms.text}; font-weight: bold; } .ant-form-item-has-error .ant-input-group-addon { color: ${props => props.theme.forms.error} !important; border-color: ${props => props.theme.forms.error} !important; } .ant-form-item-explain.ant-form-item-explain-error { color: ${props => props.theme.forms.error} !important; } `; export const AntdFormWrapper = styled.div` ${AntdFormCss} `; export const InputAddonText = styled.span` width: 100%; height: 100%; display: block; ${props => props.disabled ? ` cursor: not-allowed; ` : `cursor: pointer;`} `; export const InputNumberAddonText = styled.span` background-color: ${props => props.theme.forms.addonBackground} !important; border: 1px solid ${props => props.theme.forms.border}; color: ${props => props.theme.forms.addonForeground} !important; height: 50px; line-height: 47px; * { color: ${props => props.theme.forms.addonForeground} !important; } ${props => props.disabled ? ` cursor: not-allowed; ` : `cursor: pointer;`} `; export const SendBchInput = ({ onMax, inputProps, selectProps, activeFiatCode, ...otherProps }) => { const { Option } = Select; const currencies = [ { value: currency.ticker, label: currency.ticker, }, { value: activeFiatCode ? activeFiatCode : 'USD', label: activeFiatCode ? activeFiatCode : 'USD', }, ]; const currencyOptions = currencies.map(currency => { return ( ); }); const CurrencySelect = ( ); return ( ) : ( ) } {...inputProps} /> {CurrencySelect} max ); }; SendBchInput.propTypes = { onMax: PropTypes.func, inputProps: PropTypes.object, selectProps: PropTypes.object, activeFiatCode: PropTypes.string, }; export const DestinationAmount = ({ onMax, inputProps, ...otherProps }) => { return ( } addonAfter={ max } {...inputProps} /> ); }; DestinationAmount.propTypes = { onMax: PropTypes.func, inputProps: PropTypes.object, }; // loadWithCameraOpen prop: if true, load page with camera scanning open export const DestinationAddressSingle = ({ onScan, loadWithCameraOpen, inputProps, ...otherProps }) => { return ( } autoComplete="off" addonAfter={ } {...inputProps} /> ); }; DestinationAddressSingle.propTypes = { onScan: PropTypes.func, loadWithCameraOpen: PropTypes.bool, inputProps: PropTypes.object, }; export const DestinationAddressMulti = ({ inputProps, ...otherProps }) => { return (