diff --git a/packages/frontend/PAGES.ts b/packages/frontend/PAGES.ts
new file mode 100644
index 0000000..52828d6
--- /dev/null
+++ b/packages/frontend/PAGES.ts
@@ -0,0 +1,12 @@
+export const pages = [
+ { label: "Dashboard", id: "dashboard", path: "/" },
+ { label: "Automate", id: "automate", path: "/automate" },
+ { label: "Swap Tokens", id: "swap-tokens", path: "/swap-tokens" },
+ {
+ label: "Import Positions",
+ id: "import-positions",
+ path: "/import-positions",
+ },
+ { label: "Exit Positions", id: "exit-positions", path: "/exit-positions" },
+ { label: "Info", id: "info", path: "/info" },
+];
diff --git a/packages/frontend/features/layout/Appbar.tsx b/packages/frontend/features/layout/Appbar.tsx
new file mode 100644
index 0000000..44be9d6
--- /dev/null
+++ b/packages/frontend/features/layout/Appbar.tsx
@@ -0,0 +1,120 @@
+import Router from "next/router";
+import styled from "styled-components";
+import { useState } from "react";
+import { pages } from "../../PAGES";
+
+const Container = styled.div`
+ color: white;
+ background: var(--bg);
+ height: 72px;
+ box-shadow: 0 6px 6px 0px rgba(0, 0, 0, 0.3);
+ z-index: 1;
+ position: relative;
+`;
+
+const LogoText = styled.div`
+ color: var(--highlight);
+ text-shadow: 0px 0px 12px rgba(254, 146, 31, 0.4);
+
+ font-family: IBM Plex Sans, Roboto, Sans-Serif;
+ font-size: 32px;
+ font-weight: 200;
+ text-transform: uppercase;
+ letter-spacing: 4px;
+
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(calc(-50% + 4px), -50%);
+`;
+
+const MenuButton = styled.div`
+ color: #aaa;
+ font-size: 24px;
+ padding: 12px;
+ position: absolute;
+ right: 0;
+ top: 50%;
+ transform: translate(-12px, -50%);
+ cursor: pointer;
+`;
+
+const Menu = styled.div`
+ width: 90%;
+ height: 100vh;
+ background: var(--dark-bg);
+ position: fixed;
+ z-index: 1;
+ left: ${(p) => (p.isOpen ? `0` : `-100%`)};
+ transition: left 200ms ease-in-out;
+
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+`;
+
+const Overlay = styled.div`
+ pointer-events: ${(p) => (p.show ? `unset` : `none`)};
+ width: 100vw;
+ height: 100vh;
+ background: rgba(0, 0, 0, 0.5);
+ position: fixed;
+ z-index: 1;
+ opacity: ${(p) => (p.show ? `1` : `0`)};
+ transition: opacity 200ms ease-in-out;
+`;
+
+const CloseButton = styled.div`
+ color: white;
+ font-size: 24px;
+ padding: 12px 16px;
+ position: absolute;
+ right: 12px;
+ top: 12px;
+ cursor: pointer;
+`;
+
+const MenuItem = styled.div`
+ font-family: IBM Plex Sans;
+ text-transform: uppercase;
+ font-weight: 200;
+ letter-spacing: 4px;
+ color: ${(p) => (p.active ? `var(--highlight)` : `#999`)};
+ text-align: center;
+ margin-bottom: 3rem;
+ font-size: 18px;
+ cursor: pointer;
+`;
+
+const Appbar = ({ activePage }) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const openMenu = () => setIsOpen(true);
+ const closeMenu = () => setIsOpen(false);
+ return (
+ <>
+
+ Dedge
+ ☰
+
+
+
+ >
+ );
+};
+
+export default Appbar;
diff --git a/packages/frontend/features/layout/AppbarLayout.tsx b/packages/frontend/features/layout/AppbarLayout.tsx
new file mode 100644
index 0000000..4b8dd4d
--- /dev/null
+++ b/packages/frontend/features/layout/AppbarLayout.tsx
@@ -0,0 +1,28 @@
+import styled from "styled-components";
+import Appbar from "./Appbar";
+import StatusBar from "../status-bar/StatusBar";
+
+const Container = styled.div`
+ width: 100%;
+ height: 100vh;
+ background: var(--dark-bg);
+ display: flex;
+ flex-direction: column;
+`;
+
+const Content = styled.div`
+ overflow: auto;
+ flex: 1;
+`;
+
+const AppbarLayout = ({ children, activePage }) => {
+ return (
+
+
+
+ {children}
+
+ );
+};
+
+export default AppbarLayout;
diff --git a/packages/frontend/features/layout/Layout.tsx b/packages/frontend/features/layout/Layout.tsx
new file mode 100644
index 0000000..804420e
--- /dev/null
+++ b/packages/frontend/features/layout/Layout.tsx
@@ -0,0 +1,14 @@
+import React from "react";
+import useScreenSize from "./useScreenSize";
+import AppbarLayout from "./AppbarLayout";
+import SidebarLayout from "./SidebarLayout";
+
+const Layout = ({ children, activePage }) => {
+ const { isMobile } = useScreenSize();
+ if (isMobile) {
+ return {children};
+ }
+ return {children};
+};
+
+export default Layout;
diff --git a/packages/frontend/features/layout/Sidebar.tsx b/packages/frontend/features/layout/Sidebar.tsx
new file mode 100644
index 0000000..2c89ee5
--- /dev/null
+++ b/packages/frontend/features/layout/Sidebar.tsx
@@ -0,0 +1,61 @@
+import Router from "next/router";
+import styled from "styled-components";
+import useScreenSize from "./useScreenSize";
+import { pages } from "../../PAGES";
+
+const Container = styled.div`
+ background: var(--bg);
+ width: ${(p) => p.width};
+ height: 100%;
+
+ text-align: right;
+ padding: 24px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+`;
+
+const LogoText = styled.div`
+ font-family: IBM Plex Sans, sans-serif;
+ font-size: 24px;
+ font-weight: 300;
+ color: var(--highlight);
+ text-transform: uppercase;
+ letter-spacing: 4px;
+ margin-right: -6px;
+ text-shadow: 0px 0px 12px rgba(254, 146, 31, 0.4);
+
+ margin-top: 1rem;
+ margin-bottom: 2rem;
+`;
+
+const NavItem = styled.div`
+ cursor: pointer;
+ color: ${(p) => (p.active ? `white` : `#666`)};
+ margin-bottom: 2rem;
+
+ &:hover {
+ color: var(--highlight);
+ }
+`;
+
+const Sidebar = ({ activePage }) => {
+ const { isTablet } = useScreenSize();
+ return (
+
+ Dedge
+
+ {pages.map((page) => (
+ Router.push(page.path)}
+ >
+ {page.label}
+
+ ))}
+
+ );
+};
+
+export default Sidebar;
diff --git a/packages/frontend/features/layout/SidebarLayout.tsx b/packages/frontend/features/layout/SidebarLayout.tsx
new file mode 100644
index 0000000..d42143c
--- /dev/null
+++ b/packages/frontend/features/layout/SidebarLayout.tsx
@@ -0,0 +1,37 @@
+import styled from "styled-components";
+import Sidebar from "./Sidebar";
+import StatusBar from "../status-bar/StatusBar";
+
+const Container = styled.div`
+ width: 100%;
+ height: 100vh;
+ background: var(--dark-bg);
+ display: flex;
+`;
+
+const Main = styled.div`
+ height: 100%;
+ flex: 1;
+ overflow: auto;
+ display: flex;
+ flex-direction: column;
+`;
+
+const Content = styled.div`
+ flex: 1;
+ overflow: auto;
+`;
+
+const SidebarLayout = ({ children, activePage }) => {
+ return (
+
+
+
+
+ {children}
+
+
+ );
+};
+
+export default SidebarLayout;
diff --git a/packages/frontend/features/layout/useScreenSize.ts b/packages/frontend/features/layout/useScreenSize.ts
new file mode 100644
index 0000000..c14db80
--- /dev/null
+++ b/packages/frontend/features/layout/useScreenSize.ts
@@ -0,0 +1,11 @@
+import { useMedia } from "use-media";
+
+const useScreenSize = () => {
+ const isDesktop = useMedia({ minWidth: "1200px" });
+ const isTablet = useMedia({ minWidth: "600px" }) && !isDesktop;
+ const isMobile = !isDesktop && !isTablet;
+
+ return { isDesktop, isTablet, isMobile };
+};
+
+export default useScreenSize;
diff --git a/packages/frontend/features/status-bar/MobileStatusBar.tsx b/packages/frontend/features/status-bar/MobileStatusBar.tsx
new file mode 100644
index 0000000..bc0cb15
--- /dev/null
+++ b/packages/frontend/features/status-bar/MobileStatusBar.tsx
@@ -0,0 +1,98 @@
+import styled from "styled-components";
+import { useState } from "react";
+
+const Container = styled.div`
+ width: 100%;
+ height: 72px;
+ background: black;
+ position: relative;
+`;
+
+const Content = styled.div`
+ background black;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ height: ${(p) => (p.isOpen ? `216px` : `72px`)};
+ overflow: hidden;
+ transition: height 200ms ease-in-out;
+ position: relative;
+`;
+
+const StatusItem = styled.div`
+ height: 72px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+`;
+const Value = styled.div`
+ color: white;
+`;
+const Label = styled.div`
+ color: var(--highlight);
+ font-size: 12px;
+`;
+
+const TriangleIndicator = styled.div`
+ position: absolute;
+ bottom: 4px;
+ left: 50%;
+ color: rgba(255, 255, 255, 0.15);
+ font-size: 24px;
+ transform: ${(p) =>
+ p.invert ? "rotate(-180deg) translateX(50%)" : "translateX(-50%)"};
+`;
+
+const Status = ({ label, value, percent = false }) => {
+ const valueStr = percent
+ ? `${parseFloat(value).toFixed(2)}%`
+ : `$${parseFloat(value).toFixed(2)}`;
+ return (
+
+ {valueStr}
+
+
+ );
+};
+
+const LastUpdate = ({ lastUpdated }) => {
+ const valueStr = "23 seconds ago";
+ return (
+
+ {valueStr}
+
+
+ );
+};
+
+const MobileStatusBar = ({ statusData }) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const toggleOpen = () => setIsOpen(!isOpen);
+
+ const {
+ supplyBalance,
+ borrowBalance,
+ borrowPercent,
+ liquidationPrice,
+ ethPrice,
+ lastUpdated,
+ } = statusData;
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ ▾
+
+
+ );
+};
+
+export default MobileStatusBar;
diff --git a/packages/frontend/features/status-bar/StatusBar.tsx b/packages/frontend/features/status-bar/StatusBar.tsx
new file mode 100644
index 0000000..d289076
--- /dev/null
+++ b/packages/frontend/features/status-bar/StatusBar.tsx
@@ -0,0 +1,23 @@
+import useScreenSize from "../layout/useScreenSize";
+import MobileStatusBar from "./MobileStatusBar";
+import WideStatusBar from "./WideStatusBar";
+
+const StatusBar = () => {
+ const { isMobile, isTablet } = useScreenSize();
+
+ const statusData = {
+ supplyBalance: 14242.13,
+ borrowBalance: 5242.12,
+ borrowPercent: 0.52, // 52%
+ liquidationPrice: 123.32,
+ ethPrice: 152.08,
+ lastUpdated: new Date(1586928677168),
+ };
+
+ if (isMobile || isTablet) {
+ return ;
+ }
+ return ;
+};
+
+export default StatusBar;
diff --git a/packages/frontend/features/status-bar/WideStatusBar.tsx b/packages/frontend/features/status-bar/WideStatusBar.tsx
new file mode 100644
index 0000000..cfd75b1
--- /dev/null
+++ b/packages/frontend/features/status-bar/WideStatusBar.tsx
@@ -0,0 +1,85 @@
+import styled from "styled-components";
+
+const Container = styled.div`
+ width: 100%;
+ height: 120px;
+ background: black;
+ position: relative;
+`;
+
+const Content = styled.div`
+ width: 100%;
+ max-width: 1200px;
+ height: 100%;
+ margin: auto;
+ padding: 12px;
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+`;
+
+const StatusItem = styled.div`
+ height: 72px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ text-align: center;
+ flex: 1;
+`;
+const Value = styled.div`
+ color: white;
+ font-size: 24px;
+`;
+const Label = styled.div`
+ color: var(--highlight);
+ font-size: 12px;
+`;
+
+const Status = ({ label, value, percent = false }) => {
+ const valueStr = percent
+ ? `${parseFloat(value).toFixed(2)}%`
+ : `$${parseFloat(value).toFixed(2)}`;
+ return (
+
+ {valueStr}
+
+
+ );
+};
+
+const LastUpdate = ({ lastUpdated }) => {
+ const valueStr = "23 seconds ago";
+ return (
+
+ {valueStr}
+
+
+ );
+};
+
+const WideStatusBar = ({ statusData }) => {
+ const {
+ supplyBalance,
+ borrowBalance,
+ borrowPercent,
+ liquidationPrice,
+ ethPrice,
+ lastUpdated,
+ } = statusData;
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default WideStatusBar;
diff --git a/packages/frontend/package-lock.json b/packages/frontend/package-lock.json
index c20be90..f364706 100644
--- a/packages/frontend/package-lock.json
+++ b/packages/frontend/package-lock.json
@@ -8582,6 +8582,11 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
+ "use-media": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/use-media/-/use-media-1.4.0.tgz",
+ "integrity": "sha512-XsgyUAf3nhzZmEfhc5MqLHwyaPjs78bgytpVJ/xDl0TF4Bptf3vEpBNBBT/EIKOmsOc8UbuECq3mrP3mt1QANA=="
+ },
"use-subscription": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.1.1.tgz",
diff --git a/packages/frontend/package.json b/packages/frontend/package.json
index fe55b98..a5e1750 100644
--- a/packages/frontend/package.json
+++ b/packages/frontend/package.json
@@ -22,7 +22,8 @@
"react-dom": "^16.13.1",
"rimble-ui": "^0.13.1",
"styled-components": "^5.0.1",
- "unstated-next": "^1.1.0"
+ "unstated-next": "^1.1.0",
+ "use-media": "^1.4.0"
},
"devDependencies": {
"@types/node": "^13.9.2",
diff --git a/packages/frontend/pages/_app.tsx b/packages/frontend/pages/_app.tsx
index 421c470..4cea569 100644
--- a/packages/frontend/pages/_app.tsx
+++ b/packages/frontend/pages/_app.tsx
@@ -1,6 +1,7 @@
import { AppProps } from "next/app";
import { BaseStyles, theme, ToastMessage } from "rimble-ui";
import { ThemeProvider, withTheme } from "styled-components";
+import { useRouter } from "next/router";
import Connection from "../containers/Connection";
import Contracts from "../containers/Contracts";
@@ -10,6 +11,9 @@ import CoinsContainer from "../containers/Coins";
import VaultsContainer from "../containers/Vaults";
import Head from "next/head";
+import "../theme.css";
+import Layout from "../features/layout/Layout";
+
const customTheme = {
...theme,
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
@@ -30,6 +34,8 @@ const WithProviders = ({ children }) => (
);
function MyApp({ Component, pageProps }: AppProps) {
+ const router = useRouter();
+ console.log(router.pathname);
return (
@@ -65,6 +71,15 @@ function MyApp({ Component, pageProps }: AppProps) {
/>
+
+
+
-
+
+
+
diff --git a/packages/frontend/pages/automate.tsx b/packages/frontend/pages/automate.tsx
new file mode 100644
index 0000000..aa9d7aa
--- /dev/null
+++ b/packages/frontend/pages/automate.tsx
@@ -0,0 +1,14 @@
+const Automate = () => {
+ return (
+ <>
+ I am the Automation Page!!!
+ I am the Automation Page!!!
+ I am the Automation Page!!!
+ I am the Automation Page!!!
+ I am the Automation Page!!!
+ I am the Automation Page!!!
+ >
+ );
+};
+
+export default Automate;
diff --git a/packages/frontend/pages/exit-positions.tsx b/packages/frontend/pages/exit-positions.tsx
new file mode 100644
index 0000000..a119323
--- /dev/null
+++ b/packages/frontend/pages/exit-positions.tsx
@@ -0,0 +1,13 @@
+const ExitPositions = () => {
+ return (
+ <>
+ I am the exit positions page!!!
+ I am the exit positions page!!!
+ I am the exit positions page!!!
+ I am the exit positions page!!!
+ I am the exit positions page!!!
+ >
+ );
+};
+
+export default ExitPositions;
diff --git a/packages/frontend/pages/import-positions.tsx b/packages/frontend/pages/import-positions.tsx
new file mode 100644
index 0000000..60e5986
--- /dev/null
+++ b/packages/frontend/pages/import-positions.tsx
@@ -0,0 +1,14 @@
+const ImportPositions = () => {
+ return (
+ <>
+ I am the import positions page!!!
+ I am the import positions page!!!
+ I am the import positions page!!!
+ I am the import positions page!!!
+ I am the import positions page!!!
+ I am the import positions page!!!
+ >
+ );
+};
+
+export default ImportPositions;
diff --git a/packages/frontend/pages/index.tsx b/packages/frontend/pages/index.tsx
index 2de12fc..917cb45 100644
--- a/packages/frontend/pages/index.tsx
+++ b/packages/frontend/pages/index.tsx
@@ -1,61 +1,13 @@
-// import Connection from "../containers/Connection";
-// import DACProxy from "../containers/DACProxy";
-
-import Head from "next/head";
-
-import Layout from "../features/common/Layout";
-import Topbar from "../features/topbar/Topbar";
-import Content from "../features/common/Content";
-
-import Dashboard from "../features/dashboard/Dashboard";
-
-const Home = () => {
- // const { signer, error, connect } = Connection.useContainer();
- // const { proxyAddress } = DACProxy.useContainer();
-
- // // no connection yet or have not looked up proxyAddress yet
- // if (!signer || proxyAddress === null) {
- // return (
- //
- //
- //
- //
- //
- // );
- // }
-
- // // user does not have a proxyAddress with us
- // if (
- // proxyAddress === "0x0000000000000000000000000000000000000000"
- // ) {
- // return (
- //
- //
- //
- //
- //
- //
- // );
- // }
-
- // user has a proxyAddress, they are good to go
- return (
- <>
-
- Dedge.exchange
-
-
-
-
-
-
-
-
-
-
-
- >
- );
+const Dashboard = () => {
+ return <>
+ I am the Dashboard!!!
+ I am the Dashboard!!!
+ I am the Dashboard!!!
+ I am the Dashboard!!!
+ I am the Dashboard!!!
+ I am the Dashboard!!!
+ I am the Dashboard!!!
+ >
};
-export default Home;
+export default Dashboard;
diff --git a/packages/frontend/pages/info.tsx b/packages/frontend/pages/info.tsx
new file mode 100644
index 0000000..4edfa8d
--- /dev/null
+++ b/packages/frontend/pages/info.tsx
@@ -0,0 +1,15 @@
+const Info = () => {
+ return (
+ <>
+ I am the info page!!!
+ I am the info page!!!
+ I am the info page!!!
+ I am the info page!!!
+ I am the info page!!!
+ I am the info page!!!
+ I am the info page!!!
+ >
+ );
+};
+
+export default Info;
diff --git a/packages/frontend/pages/swap-tokens.tsx b/packages/frontend/pages/swap-tokens.tsx
new file mode 100644
index 0000000..66987c2
--- /dev/null
+++ b/packages/frontend/pages/swap-tokens.tsx
@@ -0,0 +1,12 @@
+const SwapTokens = () => {
+ return <>
+ I am the Swap Tokens page!!!
+ I am the Swap Tokens page!!!
+ I am the Swap Tokens page!!!
+ I am the Swap Tokens page!!!
+ I am the Swap Tokens page!!!
+ I am the Swap Tokens page!!!
+ >
+};
+
+export default SwapTokens;
diff --git a/packages/frontend/theme.css b/packages/frontend/theme.css
new file mode 100644
index 0000000..8f4de6d
--- /dev/null
+++ b/packages/frontend/theme.css
@@ -0,0 +1,9 @@
+:root {
+ --bg: #1c232a;
+ --dark-bg: #141A1F;
+ --highlight: #fe921f;
+}
+
+html {
+ background: var(--dark-bg);
+}