diff --git a/web/cashtab/src/components/App.js b/web/cashtab/src/components/App.js index 8ce0214db..618f90dd8 100644 --- a/web/cashtab/src/components/App.js +++ b/web/cashtab/src/components/App.js @@ -1,530 +1,530 @@ import React, { useState } from 'react'; import 'antd/dist/antd.less'; import PropTypes from 'prop-types'; import { Spin } from 'antd'; import { CashLoadingIcon, HomeIcon, SendIcon, ReceiveIcon, SettingsIcon, AirdropIcon, ThemedSignAndVerifyMsg, } from 'components/Common/CustomIcons'; import '../index.css'; import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; import { theme } from 'assets/styles/theme'; 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 Airdrop from 'components/Airdrop/Airdrop'; import Configure from 'components/Configure/Configure'; import SignVerifyMsg from 'components/SignVerifyMsg/SignVerifyMsg'; 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 { 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 { checkForTokenById } from 'utils/tokenMethods.js'; // Biometric security import not used in extension/src/components/App.js import ProtectableComponentWrapper from './Authentication/ProtectableComponentWrapper'; import ServiceWorkerWrapper from './Common/ServiceWorkerWrapper'; 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: 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.contrast}; transition: all 0.3s; background-color: ${props => props.theme.eCashBlue}; border-color: ${props => props.theme.eCashBlue}; } .selectedCurrencyOption, .ant-select-dropdown { text-align: left; color: ${props => props.theme.contrast} !important; background-color: ${props => props.theme.collapses.expandedBackground} !important; } .cashLoadingIcon { color: ${props => props.theme.eCashBlue} !important; font-size: 48px !important; } .selectedCurrencyOption:hover { color: ${props => props.theme.contrast} !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.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; } .ant-form-item-explain { div { color: ${props => props.theme.forms.text}; } } .ant-input-prefix { color: ${props => props.theme.eCashBlue}; } .ant-spin-nested-loading>div>.ant-spin .ant-spin-dot { top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important; margin: auto !important; } .ant-spin-nested-loading>div>.ant-spin { position: fixed !important; } `; const CustomApp = styled.div` text-align: center; 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; 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; } `; const NavWrapper = styled.div` cursor: pointer; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 1.3rem; margin-bottom: 5px; `; const NavIcon = styled.span` position: relative; background-color: ${props => props.clicked ? 'transparent' : props.theme.buttons.primary.color}; width: 2rem; height: 2px; display: inline-block; transition: transform 300ms, top 300ms, background-color 300ms; &::before, &::after { content: ''; background-color: ${props => props.theme.buttons.primary.color}; width: 2rem; height: 2px; display: inline-block; position: absolute; left: 0; transition: transform 300ms, top 300ms, background-color 300ms; } &::before { top: ${props => (props.clicked ? '0' : '-0.8rem')}; transform: ${props => (props.clicked ? 'rotate(135deg)' : 'rotate(0)')}; } &::after { top: ${props => (props.clicked ? '0' : '0.8rem')}; transform: ${props => props.clicked ? 'rotate(-135deg)' : 'rotate(0)'}; } `; const NavMenu = styled.div` position: fixed; float: right; margin-right: 1px; bottom: 5rem; display: flex; width: 8.23rem; flex-direction: column; border: ${props => (props.open ? '1px solid' : '0px solid')}; border-color: ${props => props.open ? props.theme.contrast : 'transparent'}; justify-content: center; align-items: center; @media (max-width: 768px) { right: 0; margin-right: 0; } overflow: hidden; transition: ${props => props.open ? 'max-height 1000ms ease-in-out , border-color 800ms ease-in-out, border-width 800ms ease-in-out' : 'max-height 300ms cubic-bezier(0, 1, 0, 1), border-color 600ms ease-in-out, border-width 800ms ease-in-out'}; max-height: ${props => (props.open ? '100rem' : '0')}; `; const NavItem = styled.button` display: flex; justify-content: right; align-items: center; width: 100%; white-space: nowrap; height: 3rem; background-color: ${props => props.theme.walletBackground}; border: none; color: ${props => props.theme.contrast}; gap: 6px; cursor: pointer; &:hover { color: ${props => props.theme.navActive}; svg { fill: ${props => props.theme.navActive}; } } svg { fill: ${props => props.theme.contrast}; max-width: 26px; height: auto; flex: 1; } p { flex: 2; - margin-top: 5px; + margin: 0; } `; export const NavButton = styled.button` :focus, :active { outline: none; } cursor: pointer; padding: 0; background: none; border: none; font-size: 10px; svg { fill: ${props => props.theme.contrast}; width: 26px; height: auto; } ${({ active, ...props }) => active && ` 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; `; export const WalletCtn = styled.div` position: relative; width: 500px; min-height: 100vh; 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: 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); const [navMenuClicked, setNavMenuClicked] = useState(false); const handleNavMenuClick = () => setNavMenuClicked(!navMenuClicked); // 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*/} ( )} /> {wallet ? ( ) : null} ); }; App.propTypes = { match: PropTypes.string, }; export default App;