diff --git a/background/backgroundComponents/externalMessageListener/index.ts b/background/backgroundComponents/externalMessageListener/index.ts index 09afc1269..846eafc8f 100644 --- a/background/backgroundComponents/externalMessageListener/index.ts +++ b/background/backgroundComponents/externalMessageListener/index.ts @@ -2,6 +2,7 @@ import StellarSdk from "stellar-sdk"; import { ExternalRequest as Request } from "api/types"; import { EXTERNAL_SERVICE_TYPES } from "statics"; +import { removeQueryParam } from "helpers"; import { Sender, SendResponseInterface } from "../types"; import { responseQueue, uiData, transactionQueue } from "../messageListener"; @@ -21,7 +22,7 @@ export const externalMessageListener = ( const { tab } = sender; const tabUrl = tab?.url ? tab.url : ""; - if (whitelist.includes(tabUrl)) { + if (whitelist.includes(removeQueryParam(tabUrl))) { if (uiData.publicKey) { // okay, the requester checks out and we have public key, send it sendResponse({ publicKey: uiData.publicKey }); @@ -31,7 +32,6 @@ export const externalMessageListener = ( // otherwise, we need to confirm either url or password. Maybe both const encodeOrigin = btoa(JSON.stringify(tab)); - window.open( chrome.runtime.getURL(`/index.html#/grant-access?${encodeOrigin}`), "Lyra: Connect", diff --git a/background/backgroundComponents/messageListener.ts b/background/backgroundComponents/messageListener.ts index 3b830024b..aca7b6e17 100644 --- a/background/backgroundComponents/messageListener.ts +++ b/background/backgroundComponents/messageListener.ts @@ -4,6 +4,7 @@ import StellarSdk from "stellar-sdk"; import { fromMnemonic, generateMnemonic } from "stellar-hd-wallet"; import { SERVICE_TYPES, APPLICATION_STATE, SERVER_URL } from "statics"; import { Response as Request } from "api/types"; +import { removeQueryParam } from "helpers"; import { externalMessageListener } from "./externalMessageListener"; import { Sender, SendResponseInterface } from "./types"; @@ -183,18 +184,20 @@ const initMessageListener = () => { const grantAccess = () => { const { url = "" } = request; + const sanitizedUrl = removeQueryParam(url); // TODO: right now we're just grabbing the last thing in the queue, but this should be smarter. // Maybe we need to search through responses to find a matching reponse :thinking_face const response = responseQueue.pop(); const whitelistStr = localStorage.getItem(WHITELIST_ID) || ""; const whitelist = whitelistStr.split(","); - whitelist.push(url); + whitelist.push(sanitizedUrl); localStorage.setItem(WHITELIST_ID, whitelist.join()); if (typeof response === "function") { response(url); + sendResponse({}); } else { sendResponse({ error: "Access was denied" }); } @@ -240,6 +243,7 @@ const initMessageListener = () => { const transactionResponse = responseQueue.pop(); if (typeof transactionResponse === "function") { transactionResponse(response); + sendResponse({}); } } }; diff --git a/package.json b/package.json index 4f8c36d80..a098ebf9c 100755 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "buffer": "^5.6.0", "eslint-loader": "^4.0.2", "fetch": "^1.1.0", + "file-loader": "^6.0.0", "lodash": "^4.17.15", "react": "^16.12.0", "react-copy-to-clipboard": "^5.0.2", diff --git a/public/index.html b/public/index.html index 6a9456ad0..5708f512b 100644 --- a/public/index.html +++ b/public/index.html @@ -8,6 +8,9 @@ name="description" content="Web site created using create-react-app" /> + React App diff --git a/src/App.tsx b/src/App.tsx index 3b0c0b7d9..d0878f6f8 100755 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,22 +5,27 @@ import { combineReducers } from "redux"; import { Provider } from "react-redux"; import styled, { createGlobalStyle } from "styled-components"; +import { COLOR_PALETTE } from "styles"; import { reducer as auth } from "ducks/authServices"; -import Menu from "components/Menu"; import Router from "./Router"; const GlobalStyle = createGlobalStyle` +html, body, #root { + height: 100%; +} body { + background: ${COLOR_PALETTE.background}; overscroll-behavior: none; - font-family: sans-serif; - width: 357px; - height: 600px; + font-family: 'Muli', sans-serif; margin: 0; } `; const Wrapper = styled.div` - text-align: center; + display: flex; + flex-flow: column; + height: 100%; + text-align: left; `; const store = configureStore({ @@ -36,7 +41,6 @@ export function App() { - diff --git a/src/assets/copy.png b/src/assets/copy.png new file mode 100644 index 000000000..ff37218b4 Binary files /dev/null and b/src/assets/copy.png differ diff --git a/src/assets/download.png b/src/assets/download.png new file mode 100644 index 000000000..addc3465e Binary files /dev/null and b/src/assets/download.png differ diff --git a/src/assets/spy.png b/src/assets/spy.png new file mode 100644 index 000000000..be4621cd2 Binary files /dev/null and b/src/assets/spy.png differ diff --git a/src/components/Layout/Fullscreen.tsx b/src/components/Layout/Fullscreen.tsx new file mode 100644 index 000000000..82611efb7 --- /dev/null +++ b/src/components/Layout/Fullscreen.tsx @@ -0,0 +1,52 @@ +import React from "react"; +import styled from "styled-components"; +import Header from "./Header"; + +const H1 = styled.h1` + font-weight: 200; + font-size: 2.5rem; + line-height: 3.4rem; + margin: 1rem 0; +`; + +const Screen = styled.div` + align-content: center; + align-items: center; + display: flex; + justify-content: center; + padding: 100px 170px; +`; + +const HalfScreen = styled.div` + padding: 0 30px; + width: 355px; + + :nth-child(1) { + margin-top: -20px; + } +`; + +const Fullscreen = ({ + header, + icon: [src, alt], + children, +}: { + header: string; + icon: [string, string]; + children: JSX.Element; +}) => { + return ( + <> +
+ + + {alt} +

{header}

+
+ {children} +
+ + ); +}; + +export default Fullscreen; diff --git a/src/components/Layout/Header/index.tsx b/src/components/Layout/Header/index.tsx new file mode 100644 index 000000000..cd92191cd --- /dev/null +++ b/src/components/Layout/Header/index.tsx @@ -0,0 +1,39 @@ +import React from "react"; +import styled from "styled-components"; +import { COLOR_PALETTE } from "styles"; + +const HeaderEl = styled.header` + background: ${COLOR_PALETTE.primaryGradient}; + box-sizing: border-box; + font-family: "Muli"; + display: flex; + height: 6.2rem; + justify-content: space-between; + padding: 26px 54px; + text-align: left; +`; + +const HeaderH1 = styled.h1` + color: #fff; + font-size: 2rem; + font-weight: 200; + line-height: 41px; + margin: 0; +`; + +const NetworkEl = styled.h3` + opacity: 0.5; + color: #fff; + font-size: 1rem; + font-weight: 800; + line-height: 21px; +`; + +const Header = () => ( + + Lyra + Test net + +); + +export default Header; diff --git a/src/components/form/index.tsx b/src/components/form/index.tsx index 7a864ed45..850b85a3c 100644 --- a/src/components/form/index.tsx +++ b/src/components/form/index.tsx @@ -1,5 +1,7 @@ import React from "react"; import styled from "styled-components"; +import { COLOR_PALETTE } from "styles"; +import { Button } from "styles/Basics"; const ErrorEl = styled.p` color: red; @@ -13,3 +15,15 @@ interface ErrorMessageProps { export const ErrorMessage = ({ authError }: ErrorMessageProps) => ( <>{authError ? {authError} : null} ); + +export const FormButton = styled(Button)` + background: ${COLOR_PALETTE.primaryGradient}; + border-radius: 1.5rem; + color: #fff; + display: block; + font-size: 1.1rem; + font-weight: 600; + line-height: 1.3rem; + margin: 2rem auto; + padding: 1.6rem 6rem; +`; diff --git a/src/components/mnemonicPhrase/DisplayMnemonicPhrase.tsx b/src/components/mnemonicPhrase/DisplayMnemonicPhrase.tsx index 31c98a74d..071c89d17 100644 --- a/src/components/mnemonicPhrase/DisplayMnemonicPhrase.tsx +++ b/src/components/mnemonicPhrase/DisplayMnemonicPhrase.tsx @@ -1,5 +1,35 @@ import React, { useState, useEffect } from "react"; import CopyToClipboard from "react-copy-to-clipboard"; +import styled from "styled-components"; +import { COLOR_PALETTE } from "styles"; +import Download from "assets/download.png"; +import Copy from "assets/copy.png"; +import { FormButton } from "components/form"; +import ActionButton from "./basics/ActionButton"; + +const Warning = styled.strong` + color: ${COLOR_PALETTE.primary}; +`; + +const MnemonicDisplay = styled.div` + background: ${COLOR_PALETTE.primaryGradient}; + border-radius: 30px; + color: #fff; + font-size: 1.125 rem; + line-height: 1.8rem; + margin: 3.5rem 0 1rem; + padding: 27px 37px; + text-align: center; +`; + +const DisplayButtons = styled.div` + margin-right: 1rem; + text-align: right; + + img { + margin-left: 0.5rem; + } +`; const DisplayMnemonicPhrase = ({ mnemonicPhrase, @@ -29,20 +59,34 @@ const DisplayMnemonicPhrase = ({ return ( <> -

Secret backup Phrase

-

{mnemonicPhrase}

- setCopied(true)}> - - - - {copied ? Copied! : null} - + ); }; diff --git a/src/components/mnemonicPhrase/basics/ActionButton.tsx b/src/components/mnemonicPhrase/basics/ActionButton.tsx new file mode 100644 index 000000000..ebaa443f1 --- /dev/null +++ b/src/components/mnemonicPhrase/basics/ActionButton.tsx @@ -0,0 +1,12 @@ +import styled from "styled-components"; +import { Button } from "styles/Basics"; + +const ActionButton = styled(Button)` + color: #748098; + font-size: 0.875rem; + font-weight: 500; + line-height: 1.7rem; + opacity: 0.6; +`; + +export default ActionButton; diff --git a/src/helpers/index.ts b/src/helpers/index.ts index dc16c80ca..1a7b39846 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1 +1,2 @@ export const newTabHref = (path = "") => `index.html#${path}`; +export const removeQueryParam = (url = "") => url.replace(/\?(.*)/, ""); diff --git a/src/styles/Basics/index.tsx b/src/styles/Basics/index.tsx new file mode 100644 index 000000000..dcd80096b --- /dev/null +++ b/src/styles/Basics/index.tsx @@ -0,0 +1,12 @@ +import styled from "styled-components"; + +export const Button = styled.button` + background: none; + border: none; + cursor: pointer; + -webkit-appearance: none; + + :focus { + outline: none; + } +`; diff --git a/src/styles/index.tsx b/src/styles/index.tsx new file mode 100644 index 000000000..c9c5a51ec --- /dev/null +++ b/src/styles/index.tsx @@ -0,0 +1,6 @@ +export const COLOR_PALETTE = { + background: "#F0F2F6", + text: "#060E1A", + primary: "#391EDA", + primaryGradient: "linear-gradient(90deg, #391EDA 100%, #5339ED 0%)", +}; diff --git a/src/views/MnemonicPhrase/index.tsx b/src/views/MnemonicPhrase/index.tsx index 7aa53bb10..4494aca05 100644 --- a/src/views/MnemonicPhrase/index.tsx +++ b/src/views/MnemonicPhrase/index.tsx @@ -2,6 +2,9 @@ import React, { useState } from "react"; import ConfirmMnemonicPhrase from "components/mnemonicPhrase/ConfirmMnemonicPhrase"; import useMnemonicPhrase from "hooks/useMnemonicPhrase"; import DisplayMnemonicPhrase from "components/mnemonicPhrase/DisplayMnemonicPhrase"; +import Fullscreen from "components/Layout/Fullscreen"; + +import spy from "assets/spy.png"; const MnemonicPhrase = () => { const [readyToConfirm, setReadyToConfirm] = useState(false); @@ -9,7 +12,7 @@ const MnemonicPhrase = () => { const mnemonicPhrase = useMnemonicPhrase(); return ( - <> + {readyToConfirm ? ( { setReadyToConfirm={setReadyToConfirm} /> )} - + ); }; diff --git a/src/views/RecoverAccount/index.tsx b/src/views/RecoverAccount/index.tsx index b191fd0e1..e63461e83 100644 --- a/src/views/RecoverAccount/index.tsx +++ b/src/views/RecoverAccount/index.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useRef, useState, useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; import { Link } from "react-router-dom"; -import { history } from "App"; import { authErrorSelector, publicKeySelector, @@ -44,7 +43,7 @@ const RecoverAccount = () => { useEffect(() => { if (publicKey) { - history.push("/account"); + window.close(); } }, [publicKey]); diff --git a/webpack.common.js b/webpack.common.js index 5d3f9b1d3..6dc0dd533 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -44,6 +44,14 @@ const commonConfig = { use: ["ts-loader", "eslint-loader"], exclude: /node-modules/, }, + { + test: /\.png$/, + use: [ + { + loader: "file-loader", + }, + ], + }, { test: /\.svg$/, use: [ diff --git a/yarn.lock b/yarn.lock index 2d2417b12..a54d9c265 100755 --- a/yarn.lock +++ b/yarn.lock @@ -4888,7 +4888,7 @@ file-loader@4.3.0: loader-utils "^1.2.3" schema-utils "^2.5.0" -file-loader@~6.0.0: +file-loader@^6.0.0, file-loader@~6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.0.0.tgz#97bbfaab7a2460c07bcbd72d3a6922407f67649f" integrity sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==