From 51497d883ac4a21d28690a64abeba90e04190a27 Mon Sep 17 00:00:00 2001 From: spacebean Date: Wed, 15 Nov 2023 19:07:27 -0700 Subject: [PATCH 01/30] update Home Page to spec except animated contract info carousel --- .../dex-ui/src/assets/images/home-banner.svg | 5 + projects/dex-ui/src/breakpoints.ts | 35 +- projects/dex-ui/src/pages/Home.tsx | 364 ++++++++++++------ 3 files changed, 293 insertions(+), 111 deletions(-) create mode 100644 projects/dex-ui/src/assets/images/home-banner.svg diff --git a/projects/dex-ui/src/assets/images/home-banner.svg b/projects/dex-ui/src/assets/images/home-banner.svg new file mode 100644 index 0000000000..bd43ec9f77 --- /dev/null +++ b/projects/dex-ui/src/assets/images/home-banner.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/projects/dex-ui/src/breakpoints.ts b/projects/dex-ui/src/breakpoints.ts index e901f52c42..562fbdc4a8 100644 --- a/projects/dex-ui/src/breakpoints.ts +++ b/projects/dex-ui/src/breakpoints.ts @@ -1,3 +1,34 @@ export const size = { - mobile: '769px', -} \ No newline at end of file + mobile: "769px", + tablet: "1024px" +}; + +const mediaSizes = { + mobile: 769, + tablet: 1024, + desktop: 1200 +}; + +/// we add 1px to the mobile and tablet sizes so that the media queries don't overlap +export const mediaQuery = { + sm: { + // 769px & above + up: `@media (min-width: ${mediaSizes.mobile}px)`, + // 768px & below + only: `@media (max-width: ${mediaSizes.mobile - 1}px)` + }, + md: { + // 1024px & above + up: `@media (min-width: ${mediaSizes.mobile}px)`, + // between 769px & 1024px + only: `@media (min-width: ${mediaSizes.mobile}px) and (max-width: ${mediaSizes.tablet - 1}px)`, + // 1024px & below + down: `@media (max-width: ${mediaSizes.tablet}px)` + }, + lg: { + // 1200px & below + down: `@media (max-width: ${mediaSizes.tablet}px)`, + // 1200px & above + only: `@media (min-width: ${mediaSizes.desktop}px)` + } +}; diff --git a/projects/dex-ui/src/pages/Home.tsx b/projects/dex-ui/src/pages/Home.tsx index 0d3482ff32..75a49b9803 100644 --- a/projects/dex-ui/src/pages/Home.tsx +++ b/projects/dex-ui/src/pages/Home.tsx @@ -1,53 +1,77 @@ /* eslint-disable jsx-a11y/accessible-emoji */ import React from "react"; -import { size } from "src/breakpoints"; +import { mediaQuery } from "src/breakpoints"; import { Link } from "react-router-dom"; -import { RightArrowCircle } from "src/components/Icons"; import styled from "styled-components"; +import shapesIcons from "src/assets/images/home-banner.svg"; +import { BodyL, BodyXS, H2 } from "src/components/Typography"; + +const copy = { + build: "Use components written, audited and deployed by other developers for your custom liquidity pool.", + deploy: "Liquidity pools with unique pricing functions for more granular market making.", + fees: "Trade assets using liquidity pools that don’t impose trading fees." +}; export const Home = () => { return ( - - - - - 🔮 Multi-block MEV manipulation resistant oracle{" "} - - whitepaper - - - - - A Composable EVM-native DEX - - Customizable liquidity pools with shared components.   - - Read the whitepaper → - - - - - - - 🔮 - {" "} - Build using components - - - - ⚡️ - {" "} - Deploy flexible liquidity - - - - ❤️ - {" "} - Zero-fee swaps - - + + + + Multi-Flow Pump is here! +
+ Explore the multi-block MEV manipulation resistant Oracle framework, with easy + integration for everyone. +
+
+ Get Started → +
+
+ + + A Composable EVM-native DEX + + Customizable liquidity pools with shared components.  + + Read the whitepaper → + + + + + + + + 🔮 + +  Build using components + + {copy.build} + + + +
+ + ⚡️ + +  Deploy flexible liquidity +
+
+ {copy.deploy} +
+ + +
+ + ❤️ + +  Zero-fee swaps +
+
+ {copy.fees} +
+
+
); @@ -56,12 +80,17 @@ export const Home = () => { const Container = styled.div` height: calc(100% - 24px); padding: 12px; - @media (min-width: ${size.mobile}) { - padding: 0px; + + ${mediaQuery.sm.up} { + padding-top: 32px; + padding-left: 48px; + padding-right: 48px; + padding-bottom: 24px; height: 100%; width: 100%; justify-content: center; align-items: center; + box-sizing: border-box; } `; @@ -70,29 +99,84 @@ const Content = styled.div` flex-direction: column; justify-content: space-between; height: 100%; - @media (min-width: ${size.mobile}) { - gap: 48px; - justify-content: center; + ${mediaQuery.sm.up} { + justify-content: space-between; align-items: center; } `; -const MevBubble = styled.div` - display: none; - @media (min-width: ${size.mobile}) { - display: flex; - box-sizing: border-box; - flex-direction: row; - justify-content: center; +const MevBanner = styled.div` + background: #fff; + width: 100%; + border: 0.25px solid #9ca3af; + ${mediaQuery.sm.only} { + display: none; + } +`; + +const MevBannerBG = styled.div` + background: url(${shapesIcons}); + background-size: contain; + background-repeat: no-repeat; + background-position: right; + + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + height: auto; + padding: 24px; + width: 100%; + box-sizing: border-box; +`; + +const MevInfo = styled.div` + display: flex; + flex-direction: column; + gap: 8px; +`; + +const MevTitle = styled.div` + ${BodyL} +`; + +const GetStarted = styled.div` + display: flex; + justify-content: center; + align-items: center; + padding: 12px; + background: #000; + outline: 0.5px solid #000; + color: #fff; + font-weight: 600; + font-size: 16px; + line-height: 24px; + letter-spacing: 0.32px; + white-space: nowrap; + cursor: pointer; + + :hover { + outline: 2px solid #46b955; + } + + :focus { + outline: 2px solid #46b955; + } +`; + +const InfoContainer = styled.div` + display: flex; + flex-direction: column; + gap: 8px; + box-sizing: border-box; + height: 100%; + + ${mediaQuery.sm.up} { + padding-top: min(25%, 185px); + justify-content: flex-start align-items: center; - padding: 8px; - gap: 8px; - height: 40px; - line-height: 16px; - width: 522px; - background: #ffffff; - border: 0.25px solid #4b5563; - border-radius: 100px; + width: 100%; + gap: 72px; } `; @@ -100,9 +184,8 @@ const TitleSubtitleContainer = styled.div` display: flex; flex-direction: column; gap: 8px; - @media (min-width: ${size.mobile}) { - display: flex; - flex-direction: column; + ${mediaQuery.sm.up} { + align-items: center; gap: 48px; } `; @@ -111,10 +194,11 @@ const Title = styled.div` font-size: 32px; font-weight: 600; line-height: 40px; - @media (min-width: ${size.mobile}) { + ${mediaQuery.sm.up} { font-style: normal; font-size: 72px; line-height: 100%; + text-align: center; } `; @@ -128,7 +212,7 @@ const SubTitle = styled.div` line-height: 22px; color: #4b5563; gap: 8px; - @media (min-width: ${size.mobile}) { + ${mediaQuery.sm.up} { flex-direction: row; font-size: 20px; line-height: 24px; @@ -138,16 +222,6 @@ const SubTitle = styled.div` } `; -const OracleWP = styled.a` - color: #46b955; - text-decoration: none; - display: flex; - align-items: center; - :hover { - text-decoration: underline; - } -`; - const WhitepaperLink = styled.a` font-weight: 400; font-size: 14px; @@ -157,65 +231,137 @@ const WhitepaperLink = styled.a` text-decoration: none; display: flex; align-items: center; + white-space: nowrap; :hover { text-decoration: underline; } - @media (min-width: ${size.mobile}) { + ${mediaQuery.sm.up} { font-size: 20px; line-height: 24px; } `; -const Boxes = styled.div` - box-sizing: border-box; +const AccordionContainer = styled.div` + /// Desktop display: flex; - flex-direction: column; - gap: 12px; - justify-content: space-around; - position: fixed; - bottom: 12px; - width: calc(100vw - 24px); - @media (min-width: ${size.mobile}) { - flex-direction: row; + flex-direction: row; + justify-content: space-between; + align-items: center; + gap: 24px; + width: 100%; + + /// Tablet + ${mediaQuery.md.only} { + width: 100%; + flex-direction: column; + gap: 12px; + } + + /// Mobile + ${mediaQuery.sm.only} { + flex-direction: column; position: relative; bottom: 0px; - gap: 48px; - padding: 0 48px; - width: 100vw; + gap: 12px; + justify-content: space-around; + position: fixed; + bottom: 12px; + width: calc(100vw - 24px); } `; -const Box = styled(Link)` +const Emoji = styled.span` + margin-right: 4px; +`; + +const AccordionItem = styled(Link)` display: flex; + flex-direction: column; justify-content: center; align-items: center; - - background: #f9f8f6; + background-color: #f9f9f9; + color: #444; + cursor: pointer; + padding: 24px; border: 0.5px solid #4b5563; - flex-grow: 1; - - font-weight: 600; - font-size: 14px; - line-height: 22px; - padding: 12px; - + outline: 1.5px solid white; + text-align: left; + width: 33%; + transition: background-color 0.3s ease; + overflow: hidden; + max-height: 132px; // Initial max-height + box-sizing: border-box; text-decoration: none; - color: black; - :hover { + &:hover { + border: 1.5px solid #46b955; background-color: #f0fdf4; + outline: 0.5px solid transparent; } - @media (min-width: ${size.mobile}) { - padding: 0px; - font-size: 24px; - line-height: 32px; - height: 80px; + &:hover { + border: 1.5px solid #46b955; + background-color: #f0fdf4; + outline: 0.5px solid transparent; + max-height: 250px; // Adjust as needed for your content + } + + ${mediaQuery.md.up} { + padding: 24px; + height: 100%; + } + + ${mediaQuery.md.only} { + width: calc(100vw - 86px); + height: auto; + :last-child { + margin-bottom: 24px; + } + } + + ${mediaQuery.sm.only} { + width: calc(100vw - 24px); + max-height: 80px; + padding: 12px; } `; -const Emoji = styled.span` - margin-right: 4px; +const AccordionContent = styled.div` + overflow: hidden; + opacity: 0; // Initially hidden + transition: opacity 0.3s ease-out, max-height 0.3s ease-out; + max-height: 0; + width: 100%; // Ensure it takes full width + + ${AccordionItem}:hover & { + padding-top: 12px; + opacity: 1; + max-height: 200px; // Adjust as needed for your content + } + + ${mediaQuery.sm.only} { + display: none; + } +`; + +const AccordionTitle = styled.div` + text-align: center; + width: 100%; + + ${mediaQuery.md.up} { + ${H2} + font-weight: 600; + } + + ${mediaQuery.md.only} { + ${BodyL} + font-weight: 600; + } + + ${mediaQuery.sm.only} { + ${BodyXS} + font-weight: 600; + } `; From e83c73d2286b17013175323fd18daf999502dddb Mon Sep 17 00:00:00 2001 From: spacebean Date: Wed, 15 Nov 2023 21:04:51 -0700 Subject: [PATCH 02/30] Add ContractInfoMarquee to Home + tweak homepage --- .../components/Frame/ContractInfoMarquee.tsx | 121 ++++++++++++++ projects/dex-ui/src/pages/Home.tsx | 157 ++++++++++-------- 2 files changed, 207 insertions(+), 71 deletions(-) create mode 100644 projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx diff --git a/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx b/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx new file mode 100644 index 0000000000..ec95814777 --- /dev/null +++ b/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx @@ -0,0 +1,121 @@ +import React from "react"; + +import styled, { keyframes } from "styled-components"; + +const CarouselData: Record = { + ADDRESS: { + display: "0x1584B668643617D18321a0BEc6EF3786F4b8Eb7B", + to: "/" // TODO: link to etherscan + }, + DEPLOY: { + display: "17113653", + to: "/" // TODO: link to etherscan + }, + AUDIT: { + display: "HALBORN, CYFRIN", + to: "https://www.halborn.com/" // TODO: link to audit + }, + V1: { + display: "WHITEPAPER", + to: "/basin.pdf" + } +}; + +export const ContractInfoMarqueeHeight = 57; + +export const ContractInfoMarquee = () => { + const data = Object.entries(CarouselData); + + /// See TokenMarquee.tsx for more info on how this works + const speedPerItem = 20; + const repeatableWidth = 1192.34; + const numItems = 3; + const animationDuration = numItems * speedPerItem; + + return ( + //
+ + + <> + {Array(numItems + 1) + .fill(null) + .map((_, idx) => ( + + {data.map(([key, { display, to }], idx) => ( + + + {key.toUpperCase()}: + + {display} + + + / + + ))} + + ))} + + + + //
+ ); +}; + +const Scroller = styled.div<{ x: number; duration: number }>` + background: #fff; + padding: 16px 48px; + box-sizing: border-box; + border-top: 1px solid #000; + + animation-name: ${(props) => marquee(props.x)}; + animation-duration: ${(props) => props.duration}s; + animation-iteration-count: infinite; + animation-timing-function: linear; +`; + +const marquee = (x: number) => keyframes` + 0% { transform: translateX(0px); } + 100% { transform: translateX(-${x}px);} +`; + +const CarouselRow = styled.div` + display: flex; + flex-direction: row; + justify-content: flex-start; +`; + +const Container = styled.div` + display: flex; + flex-direction: row; + gap: 24px; + margin-right: 24px; +`; + +const RowContainer = styled.div` + display: flex; + flex-direction: row; + gap: 24px; +`; + +const InfoRow = styled.div` + display: flex; + flex-direction: row; + gap: 8px; + white-space: nowrap; +`; + +const InfoText = styled.div` + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 24px; +`; + +const TextLink = styled.a` + color: #46b955; + font-size: 16px; + font-weight: 600; + line-height: 24px; + letter-spacing: 0.32px; + text-decoration-line: underline; +`; diff --git a/projects/dex-ui/src/pages/Home.tsx b/projects/dex-ui/src/pages/Home.tsx index 75a49b9803..cb78e24021 100644 --- a/projects/dex-ui/src/pages/Home.tsx +++ b/projects/dex-ui/src/pages/Home.tsx @@ -4,7 +4,8 @@ import { mediaQuery } from "src/breakpoints"; import { Link } from "react-router-dom"; import styled from "styled-components"; import shapesIcons from "src/assets/images/home-banner.svg"; -import { BodyL, BodyXS, H2 } from "src/components/Typography"; +import { BodyL } from "src/components/Typography"; +import { ContractInfoMarquee } from "src/components/Frame/ContractInfoMarquee"; const copy = { build: "Use components written, audited and deployed by other developers for your custom liquidity pool.", @@ -14,78 +15,94 @@ const copy = { export const Home = () => { return ( - - - - - - Multi-Flow Pump is here! -
- Explore the multi-block MEV manipulation resistant Oracle framework, with easy - integration for everyone. -
-
- Get Started → -
-
- - - A Composable EVM-native DEX - - Customizable liquidity pools with shared components.  - - Read the whitepaper → - - - - - - - - 🔮 - -  Build using components - - {copy.build} - - - + <> + + + + + + Multi-Flow Pump is here!
- - ⚡️ - -  Deploy flexible liquidity + Explore the multi-block MEV manipulation resistant Oracle framework, with easy + integration for everyone.
-
- {copy.deploy} -
- - -
- - ❤️ + + Get Started → + + + + + A Composable EVM-native DEX + + Customizable liquidity pools with shared components.  + + Read the whitepaper → + + + + + + + + 🔮 -  Zero-fee swaps -
-
- {copy.fees} -
-
-
-
-
+  Build using components + + {copy.build} + + + +
+ + ⚡️ + +  Deploy flexible liquidity +
+
+ {copy.deploy} +
+ + +
+ + ❤️ + +  Zero-fee swaps +
+
+ {copy.fees} +
+ + + + + + + + ); }; +const MarqueeContainer = styled.div` + ${mediaQuery.sm.only} { + position: absolute; + left: 0; + bottom: 0; + } +`; + const Container = styled.div` height: calc(100% - 24px); - padding: 12px; + padding-top: 12px; + padding-left: 12px; + padding-right: 12px; + padding-bottom: 0px; ${mediaQuery.sm.up} { padding-top: 32px; padding-left: 48px; padding-right: 48px; - padding-bottom: 24px; + height: 100%; width: 100%; justify-content: center; @@ -99,6 +116,7 @@ const Content = styled.div` flex-direction: column; justify-content: space-between; height: 100%; + ${mediaQuery.sm.up} { justify-content: space-between; align-items: center; @@ -263,11 +281,10 @@ const AccordionContainer = styled.div` ${mediaQuery.sm.only} { flex-direction: column; position: relative; - bottom: 0px; + bottom: calc(57px + 12px); // 57px is the height of the contract info marquee gap: 12px; justify-content: space-around; position: fixed; - bottom: 12px; width: calc(100vw - 24px); } `; @@ -349,19 +366,17 @@ const AccordionContent = styled.div` const AccordionTitle = styled.div` text-align: center; width: 100%; - - ${mediaQuery.md.up} { - ${H2} - font-weight: 600; - } + font-weight: 600; + font-size: 24px; + line-height: 32px; ${mediaQuery.md.only} { - ${BodyL} - font-weight: 600; + font-size: 20px; + line-height: 24px; } ${mediaQuery.sm.only} { - ${BodyXS} - font-weight: 600; + font-size: 14px; + line-height: 22px; } `; From d4f9d9a1c41efa2bf257ddb9fb77a1746faab035 Mon Sep 17 00:00:00 2001 From: spacebean Date: Wed, 15 Nov 2023 21:18:36 -0700 Subject: [PATCH 03/30] fix Footer responsive --- .../dex-ui/src/components/Frame/Footer.tsx | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/projects/dex-ui/src/components/Frame/Footer.tsx b/projects/dex-ui/src/components/Frame/Footer.tsx index ad7f0942b8..75ebc37a4c 100644 --- a/projects/dex-ui/src/components/Frame/Footer.tsx +++ b/projects/dex-ui/src/components/Frame/Footer.tsx @@ -1,24 +1,24 @@ import React from "react"; import styled from "styled-components"; import { BeanstalkLogoBlack, Discord, Github, Twitter } from "../Icons"; -import { size } from "src/breakpoints"; +import { mediaQuery, size } from "src/breakpoints"; export const Footer = () => ( -
+ 📃 Protocol Documentation -
+ Visit the Docs →
-
+ 👾 Basin Bug Bounty Program -
+ Learn More →
@@ -54,7 +54,7 @@ const Container = styled.footer` const Box = styled.a` display: flex; - flex: 1; + flex: 2; border-left: 1px solid black; justify-content: center; align-items: center; @@ -67,6 +67,16 @@ const Box = styled.a` :first-child { border-left: none; } + + ${mediaQuery.md.only} { + flex-wrap: wrap; + gap: 8px; + flex-flow: column; + } +`; + +const InfoText = styled.div` + whitespace: nowrap; `; const SmallBox = styled.a` @@ -82,4 +92,5 @@ const SmallBox = styled.a` const StyledLink = styled.span` text-decoration: underline; + white-space: nowrap; `; From 5eea73b2bcb1a239eaf26c10a133b99a7b81c7bb Mon Sep 17 00:00:00 2001 From: spacebean Date: Wed, 15 Nov 2023 21:30:14 -0700 Subject: [PATCH 04/30] clean up home --- .../src/components/Frame/ContractInfoMarquee.tsx | 2 -- projects/dex-ui/src/pages/Home.tsx | 13 +++++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx b/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx index ec95814777..4e32660b7b 100644 --- a/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx +++ b/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx @@ -33,7 +33,6 @@ export const ContractInfoMarquee = () => { const animationDuration = numItems * speedPerItem; return ( - //
<> @@ -57,7 +56,6 @@ export const ContractInfoMarquee = () => { - //
); }; diff --git a/projects/dex-ui/src/pages/Home.tsx b/projects/dex-ui/src/pages/Home.tsx index cb78e24021..2cac6b88ec 100644 --- a/projects/dex-ui/src/pages/Home.tsx +++ b/projects/dex-ui/src/pages/Home.tsx @@ -84,8 +84,11 @@ export const Home = () => { }; const MarqueeContainer = styled.div` + position: fixed; + bottom: 72px; + ${mediaQuery.sm.only} { - position: absolute; + position: fixed; left: 0; bottom: 0; } @@ -308,16 +311,10 @@ const AccordionItem = styled(Link)` width: 33%; transition: background-color 0.3s ease; overflow: hidden; - max-height: 132px; // Initial max-height + max-height: 113px; // Initial max-height box-sizing: border-box; text-decoration: none; - &:hover { - border: 1.5px solid #46b955; - background-color: #f0fdf4; - outline: 0.5px solid transparent; - } - &:hover { border: 1.5px solid #46b955; background-color: #f0fdf4; From 8811365bfdaecf904b336bf962ba4b23031aaa9e Mon Sep 17 00:00:00 2001 From: spacebean Date: Thu, 16 Nov 2023 09:43:37 -0700 Subject: [PATCH 05/30] fix well row ui --- projects/dex-ui/src/pages/Wells.tsx | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/projects/dex-ui/src/pages/Wells.tsx b/projects/dex-ui/src/pages/Wells.tsx index 93ecf0c3e1..44d41e3399 100644 --- a/projects/dex-ui/src/pages/Wells.tsx +++ b/projects/dex-ui/src/pages/Wells.tsx @@ -81,6 +81,15 @@ const PositionBreakdown: React.FC<{ ); }; +/// format value with 2 decimals, if value is less than 1M, otherwise use short format +const formatMayDecimals = (tv: TokenValue | undefined) => { + if (!tv) return "-.--"; + if (tv.lt(1_000_000)) { + return formatNum(tv, { minDecimals: 2, maxDecimals: 2 }); + } + return tv.toHuman("short"); +}; + export const Wells = () => { const { data: wells, isLoading, error } = useWells(); const navigate = useNavigate(); @@ -236,7 +245,7 @@ export const Wells = () => { - {wellFunctionNames[index] ? wellFunctionNames[index] : "Price Function"} + {wellFunctionNames?.[index] ? wellFunctionNames[index] : "Price Function"} 0.00% @@ -246,12 +255,12 @@ export const Wells = () => { - {smallLogos[0]} - {well.reserves![0] ? well.reserves![0].toHuman("short") : "-.--"} + {{smallLogos[0]}} + {formatMayDecimals(well.reserves?.[0])} - {smallLogos[1]} - {well.reserves![1] ? well.reserves![1].toHuman("short") : "-.--"} + {{smallLogos[1]}} + {formatMayDecimals(well.reserves?.[1])} {well.reserves && well.reserves.length > 2 ? {`+ ${well.reserves.length - 2} MORE`} : null} @@ -389,10 +398,10 @@ const TokenLogos = styled.div` const TokenSymbols = styled.div` font-size: 20px; line-height: 24px; - margin-top: 8px; color: #1c1917; @media (max-width: ${size.mobile}) { font-size: 14px; + margin-top: 2px; } `; @@ -412,7 +421,8 @@ const Reserves = styled.div` display: flex; flex-direction: row; justify-content flex-end; - gap: 8px; + align-items: center; + gap: 4px; flex: 1; `; @@ -479,3 +489,7 @@ const BreakdownRow = styled.div` justify-content: space-between; gap: 4px; `; + +const TokenLogoWrapper = styled.div` + margin-bottom: 2px; +`; From 91a58f02fedae0d5967f4e66816db609cf2a8984 Mon Sep 17 00:00:00 2001 From: spacebean Date: Thu, 16 Nov 2023 09:56:08 -0700 Subject: [PATCH 06/30] Well page tweaks + WETH icon --- projects/dex-ui/src/assets/images/tokens/WETH.svg | 2 +- projects/dex-ui/src/components/PageComponents/Title.tsx | 3 +++ projects/dex-ui/src/pages/Well.tsx | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/projects/dex-ui/src/assets/images/tokens/WETH.svg b/projects/dex-ui/src/assets/images/tokens/WETH.svg index 854eb9194e..0a304a4438 100644 --- a/projects/dex-ui/src/assets/images/tokens/WETH.svg +++ b/projects/dex-ui/src/assets/images/tokens/WETH.svg @@ -1,5 +1,5 @@ - + diff --git a/projects/dex-ui/src/components/PageComponents/Title.tsx b/projects/dex-ui/src/components/PageComponents/Title.tsx index b157a97bc0..e5a5374ee5 100644 --- a/projects/dex-ui/src/components/PageComponents/Title.tsx +++ b/projects/dex-ui/src/components/PageComponents/Title.tsx @@ -66,4 +66,7 @@ const ParentText = styled(Link)` @media (max-width: ${size.mobile}) { ${BodyXS} } + :hover { + color: #000000; + } `; diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index 30cc6319ef..79b8ba93c0 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -128,7 +128,7 @@ export const Well = () => { return ( - +
From 80d5b36a1f0e9861283a5e2091331b2d40fe53c2 Mon Sep 17 00:00:00 2001 From: spacebean Date: Thu, 16 Nov 2023 09:56:36 -0700 Subject: [PATCH 07/30] update contract info marquee speed --- projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx b/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx index 4e32660b7b..6f01f445f8 100644 --- a/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx +++ b/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx @@ -27,7 +27,7 @@ export const ContractInfoMarquee = () => { const data = Object.entries(CarouselData); /// See TokenMarquee.tsx for more info on how this works - const speedPerItem = 20; + const speedPerItem = 25; const repeatableWidth = 1192.34; const numItems = 3; const animationDuration = numItems * speedPerItem; From 08f485cb63e0b73af9f3b8167c28508e5eecf4fb Mon Sep 17 00:00:00 2001 From: spacebean Date: Thu, 16 Nov 2023 11:58:28 -0700 Subject: [PATCH 08/30] create skeleton component --- projects/dex-ui/src/components/Skeleton.tsx | 66 +++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 projects/dex-ui/src/components/Skeleton.tsx diff --git a/projects/dex-ui/src/components/Skeleton.tsx b/projects/dex-ui/src/components/Skeleton.tsx new file mode 100644 index 0000000000..477e510125 --- /dev/null +++ b/projects/dex-ui/src/components/Skeleton.tsx @@ -0,0 +1,66 @@ +import React from "react"; + +import styled, { css, keyframes } from "styled-components"; + +export type SkeletonProps = { + height: number; + width: number; + // if true, rounded will be ignored + circle?: boolean; + // defaults to true + rounded?: boolean; + // defaults to pulse + shimmer?: boolean; +}; + +export const Skeleton: React.FC = (props) => { + if (props.shimmer) { + return ; + } + + return ; +}; + +const pulse = () => keyframes` + 0% { + opacity: 1; + } + 50% { + opacity: 0.5; + } + 100% { + opacity: 1; + } +`; + +const shimmer = () => keyframes` + 0% { + background-position: -800px 0; + } + 100% { + background-position: 800px 0; + } +`; + +const SkeletonBase = css` + display: inline-block; + ${(props) => ` + height: ${props.height ? `${props.height}px` : "100%"}; + width: ${props.width ? `${props.width}px` : "100%"}; + border-radius: ${props.circle ? "50%" : props.rounded === false ? `0px` : "4px"}; + `} +`; + +const SkeletonPulse = styled.div` + ${SkeletonBase} + background: linear-gradient(to right, #e5e7eb 8%, #F3F4F6 18%, #e5e7eb 33%); + background-size: 1200px 100%; + animation: ${pulse} 2s ease-in-out infinite; +`; + +const SkeletonShimmer = styled.div` + ${SkeletonBase} + background: linear-gradient(65deg, #f3f4f6 8%, #e5e7eb 18%, #f3f4f6 33%); + background-size: 1200px 100%; + animation: ${shimmer} 2s linear infinite; +`; From 689e00fa6b36e9d3180495a662ef5bc9008bfd36 Mon Sep 17 00:00:00 2001 From: spacebean Date: Thu, 16 Nov 2023 11:58:59 -0700 Subject: [PATCH 09/30] separate components + add loading skeletons --- .../Well/Table/MyWellPositionRow.tsx | 270 ++++++++++++ .../components/Well/Table/WellDetailRow.tsx | 212 ++++++++++ projects/dex-ui/src/pages/Wells.tsx | 391 +++--------------- 3 files changed, 536 insertions(+), 337 deletions(-) create mode 100644 projects/dex-ui/src/components/Well/Table/MyWellPositionRow.tsx create mode 100644 projects/dex-ui/src/components/Well/Table/WellDetailRow.tsx diff --git a/projects/dex-ui/src/components/Well/Table/MyWellPositionRow.tsx b/projects/dex-ui/src/components/Well/Table/MyWellPositionRow.tsx new file mode 100644 index 0000000000..d14933ac74 --- /dev/null +++ b/projects/dex-ui/src/components/Well/Table/MyWellPositionRow.tsx @@ -0,0 +1,270 @@ +import { TokenValue } from "@beanstalk/sdk"; +import React, { FC, ReactNode } from "react"; +import { Row, Td } from "src/components/Table"; +import { TokenLogo } from "src/components/TokenLogo"; +import styled from "styled-components"; +import { mediaQuery, size } from "src/breakpoints"; +import { displayTokenSymbol, formatNum, formatUSD } from "src/utils/format"; +import { useWellLPTokenPrice } from "src/wells/useWellLPTokenPrice"; +import { LPBalanceSummary } from "src/tokens/useLPPositionSummary"; +import { useBeanstalkSiloWhitelist } from "src/wells/useBeanstalkSiloWhitelist"; +import { Tooltip } from "src/components/Tooltip"; +import { Well } from "@beanstalk/sdk/Wells"; +import { Skeleton } from "src/components/Skeleton"; + +import { useNavigate } from "react-router-dom"; +import useIsMobile from "src/utils/ui/useIsMobile"; + +const PositionBreakdown: React.FC<{ + items: { external: TokenValue; silo: TokenValue; internal: TokenValue; total: TokenValue }; + isWhitelisted: boolean; + isLP: boolean; + totalDisplay: string; +}> = ({ items, isWhitelisted, totalDisplay, isLP = true }) => { + const formatFn = isLP ? formatNum : formatUSD; + const isMobile = useIsMobile(); + + const getTooltipProps = () => { + let base = { side: "right", offsetX: 3, offsetY: -100, arrowSize: 4, arrowOffset: 40 }; + + if (isMobile) { + if (isLP) { + base.offsetY = -162; + base.arrowOffset = 67; + } else { + base.side = "left"; + base.offsetX = -5; + base.offsetY = -96; + base.arrowOffset = 43; + } + } else if (!isMobile && !isLP) { + base.side = "left"; + base.offsetX = -10; + base.offsetY = -100; + } + + return base; + }; + + return isWhitelisted ? ( + + + {"Wallet Balance:"} +
{formatFn(items.external)} + + + {"Silo Deposits:"} + {formatFn(items.silo)} + + + {"Farm Balance:"} + {formatFn(items.internal)} + + + } + > + {totalDisplay} + + ) : ( + {totalDisplay} + ); +}; + +export const MyWellPositionRow: FC<{ + well: Well | undefined; + position: LPBalanceSummary | undefined; + prices: ReturnType["data"]; +}> = ({ well, position, prices }) => { + const navigate = useNavigate(); + const { getIsWhitelisted } = useBeanstalkSiloWhitelist(); + + const lpAddress = well?.lpToken?.address; + const lpToken = well?.lpToken; + + if (!well || !position || position.total.lte(0) || !lpAddress || !lpToken) { + return null; + } + + const tokens = well.tokens || []; + const logos: ReactNode[] = []; + const symbols: string[] = []; + const gotoWell = () => navigate(`/wells/${well.address}`); + + tokens.map((token: any) => { + logos.push(); + symbols.push(token.symbol); + }); + + const lpPrice = lpAddress && lpAddress in prices ? prices[lpAddress] : undefined; + const whitelisted = getIsWhitelisted(well); + + const positionsUSD = { + total: lpPrice?.mul(position.total) || TokenValue.ZERO, + external: lpPrice?.mul(position.external) || TokenValue.ZERO, + silo: lpPrice?.mul(position.silo) || TokenValue.ZERO, + internal: lpPrice?.mul(position.internal) || TokenValue.ZERO + }; + + return ( + + + + {logos} + {symbols.join("/")} + + + + + + + + + + + + + + + {logos} + {symbols.join("/")} + {/* {deployer} */} + + + + + + + + + + + + ); +}; + +export const MyWellPositionLoadingRow: FC<{}> = () => ( + + + + + + + + + + + + + + + + + + + + + + + +); + +const LoadingColumn = styled.div<{ align?: "right" | "left" }>` + display: flex; + flex-direction: column; + gap: 8px; + ${(props) => ` + align-items: ${props.align === "right" ? "flex-end" : "flex-start"}; + `} + + ${mediaQuery.sm.only} { + gap: 4px; + } +`; + +const TableRow = styled(Row)` + @media (max-width: ${size.mobile}) { + height: 66px; + } +`; + +const DesktopContainer = styled(Td)` + @media (max-width: ${size.mobile}) { + display: none; + } +`; + +const MobileContainer = styled(Td)` + padding: 8px 16px; + @media (min-width: ${size.mobile}) { + display: none; + } +`; + +const WellDetail = styled.div` + display: flex; + flex-direction: row; + gap: 8px; + @media (min-width: ${size.mobile}) { + flex-direction: column; + } +`; + +const TokenLogos = styled.div` + display: flex; + div:not(:first-child) { + margin-left: -8px; + } +`; +const TokenSymbols = styled.div` + font-size: 20px; + line-height: 24px; + color: #1c1917; + @media (max-width: ${size.mobile}) { + font-size: 14px; + margin-top: 2px; + } +`; + +const WellLPBalance = styled.div` + font-size: 20px; + line-height: 24px; + @media (max-width: ${size.mobile}) { + font-size: 14px; + font-weight: normal; + } +`; + +const BalanceContainer = styled.div<{ left?: boolean }>` + display: flex; + justify-content: ${(props) => (props.left ? "flex-start" : "flex-end")}; +`; + +const Breakdown = styled.div` + display: flex; + flex-direction: column; + width: 100%; + gap: 4px; + @media (max-width: ${size.mobile}) { + gap: 0px; + } +`; + +const BreakdownRow = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 4px; +`; diff --git a/projects/dex-ui/src/components/Well/Table/WellDetailRow.tsx b/projects/dex-ui/src/components/Well/Table/WellDetailRow.tsx new file mode 100644 index 0000000000..9f151385d3 --- /dev/null +++ b/projects/dex-ui/src/components/Well/Table/WellDetailRow.tsx @@ -0,0 +1,212 @@ +import { TokenValue } from "@beanstalk/sdk"; +import React, { FC, ReactNode } from "react"; +import { useNavigate } from "react-router-dom"; +import { Row, Td } from "src/components/Table"; +import { TokenLogo } from "src/components/TokenLogo"; +import styled from "styled-components"; +import { mediaQuery, size } from "src/breakpoints"; +import { formatNum } from "src/utils/format"; +import { Well } from "@beanstalk/sdk/Wells"; +import { Skeleton } from "src/components/Skeleton"; + +/// format value with 2 decimals, if value is less than 1M, otherwise use short format +const formatMayDecimals = (tv: TokenValue | undefined) => { + if (!tv) return "-.--"; + if (tv.lt(1_000_000)) { + return formatNum(tv, { minDecimals: 2, maxDecimals: 2 }); + } + return tv.toHuman("short"); +}; + +export const WellDetailRow: FC<{ + well: Well | undefined; + liquidity: TokenValue | undefined; + functionName: string | undefined; +}> = ({ well, liquidity, functionName }) => { + const navigate = useNavigate(); + + if (!well) return null; + + const tokens = well?.tokens || []; + const logos: ReactNode[] = []; + const smallLogos: ReactNode[] = []; + const symbols: string[] = []; + const gotoWell = () => navigate(`/wells/${well?.address}`); + + tokens.map((token: any) => { + logos.push(); + smallLogos.push(); + symbols.push(token.symbol); + }); + + return ( + + + + {logos} + {symbols.join("/")} + + + + {functionName || "Price Function"} + + + 0.00% + + + ${liquidity ? liquidity.toHuman("short") : "-.--"} + + + + {{smallLogos[0]}} + {formatMayDecimals(well.reserves?.[0])} + + + {{smallLogos[1]}} + {formatMayDecimals(well.reserves?.[1])} + + {well.reserves && well.reserves.length > 2 ? {`+ ${well.reserves.length - 2} MORE`} : null} + + + + {logos} + {symbols.join("/")} + + ${formatNum(liquidity, { minDecimals: 2 })} + + + ); +}; + +export const WellDetailLoadingRow: FC<{}> = () => { + return ( + {}}> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +const LoadingColumn = styled.div<{ align?: "right" | "left" }>` + display: flex; + flex-direction: column; + gap: 8px; + ${(props) => ` + align-items: ${props.align === "right" ? "flex-end" : "flex-start"}; + `} + + ${mediaQuery.sm.only} { + gap: 4px; + } +`; + +const TableRow = styled(Row)` + @media (max-width: ${size.mobile}) { + height: 66px; + } +`; + +const DesktopContainer = styled(Td)` + @media (max-width: ${size.mobile}) { + display: none; + } +`; + +const MobileContainer = styled(Td)` + padding: 8px 16px; + @media (min-width: ${size.mobile}) { + display: none; + } +`; + +const WellDetail = styled.div` + display: flex; + flex-direction: row; + gap: 8px; + @media (min-width: ${size.mobile}) { + flex-direction: column; + } +`; + +const TokenLogos = styled.div` + display: flex; + div:not(:first-child) { + margin-left: -8px; + } +`; +const TokenSymbols = styled.div` + font-size: 20px; + line-height: 24px; + color: #1c1917; + @media (max-width: ${size.mobile}) { + font-size: 14px; + margin-top: 2px; + } +`; + +const Amount = styled.div` + font-weight: 500; + font-size: 20px; + line-height: 24px; + color: #1c1917; + + @media (max-width: ${size.mobile}) { + font-size: 14px; + font-weight: normal; + } +`; + +const Reserves = styled.div` + display: flex; + flex-direction: row; + justify-content flex-end; + align-items: center; + gap: 4px; + flex: 1; +`; + +const MoreReserves = styled.div` + color: #9ca3af; +`; + +const TradingFee = styled.div` + font-size: 20px; + line-height: 24px; + color: #4b5563; + text-transform: uppercase; +`; + +const WellPricing = styled.div` + font-size: 20px; + line-height: 24px; + text-transform: capitalize; +`; + +const TokenLogoWrapper = styled.div` + margin-bottom: 2px; +`; diff --git a/projects/dex-ui/src/pages/Wells.tsx b/projects/dex-ui/src/pages/Wells.tsx index 44d41e3399..70006f2348 100644 --- a/projects/dex-ui/src/pages/Wells.tsx +++ b/projects/dex-ui/src/pages/Wells.tsx @@ -1,98 +1,25 @@ import { TokenValue } from "@beanstalk/sdk"; -import React, { FC, ReactNode, useMemo, useState } from "react"; -import { useNavigate } from "react-router-dom"; +import React, { useMemo, useState } from "react"; import { Item } from "src/components/Layout"; import { Page } from "src/components/Page"; import { Title } from "src/components/PageComponents/Title"; import { TabButton } from "src/components/TabButton"; import { Row, TBody, THead, Table, Td, Th } from "src/components/Table"; import { Row as TabRow } from "src/components/Layout"; -import { TokenLogo } from "src/components/TokenLogo"; import { getPrice } from "src/utils/price/usePrice"; import useSdk from "src/utils/sdk/useSdk"; import { useWells } from "src/wells/useWells"; import styled from "styled-components"; -import { size } from "src/breakpoints"; -import { Loading } from "../components/Loading"; -import { Error } from "../components/Error"; -import { displayTokenSymbol, formatNum, formatUSD } from "src/utils/format"; +import { mediaQuery, size } from "src/breakpoints"; +import { Error } from "src/components/Error"; import { useWellLPTokenPrice } from "src/wells/useWellLPTokenPrice"; -import { LPBalanceSummary, useLPPositionSummary } from "src/tokens/useLPPositionSummary"; -import { useBeanstalkSiloWhitelist } from "src/wells/useBeanstalkSiloWhitelist"; -import { Tooltip } from "src/components/Tooltip"; -import { Well } from "@beanstalk/sdk/Wells"; -import useIsMobile from "src/utils/ui/useIsMobile"; +import { useLPPositionSummary } from "src/tokens/useLPPositionSummary"; -const PositionBreakdown: React.FC<{ - items: { external: TokenValue; silo: TokenValue; internal: TokenValue; total: TokenValue }; - isWhitelisted: boolean; - isLP: boolean; - totalDisplay: string; -}> = ({ items, isWhitelisted, totalDisplay, isLP = true }) => { - const formatFn = isLP ? formatNum : formatUSD; - const isMobile = useIsMobile(); - - const getTooltipProps = () => { - let base = { side: "right", offsetX: 3, offsetY: -100, arrowSize: 4, arrowOffset: 40 }; - - if (isMobile) { - if (isLP) { - base.offsetY = -162; - base.arrowOffset = 67; - } else { - base.side = "left"; - base.offsetX = -5; - base.offsetY = -96; - base.arrowOffset = 43; - } - } else if (!isMobile && !isLP) { - base.side = "left"; - base.offsetX = -10; - base.offsetY = -100; - } - - return base; - }; - - return isWhitelisted ? ( - - - {"Wallet Balance:"} - {formatFn(items.external)} - - - {"Silo Deposits:"} - {formatFn(items.silo)} - - - {"Farm Balance:"} - {formatFn(items.internal)} - - - } - > - {totalDisplay} - - ) : ( - {totalDisplay} - ); -}; - -/// format value with 2 decimals, if value is less than 1M, otherwise use short format -const formatMayDecimals = (tv: TokenValue | undefined) => { - if (!tv) return "-.--"; - if (tv.lt(1_000_000)) { - return formatNum(tv, { minDecimals: 2, maxDecimals: 2 }); - } - return tv.toHuman("short"); -}; +import { WellDetailLoadingRow, WellDetailRow } from "src/components/Well/Table/WellDetailRow"; +import { MyWellPositionLoadingRow, MyWellPositionRow } from "src/components/Well/Table/MyWellPositionRow"; export const Wells = () => { const { data: wells, isLoading, error } = useWells(); - const navigate = useNavigate(); const sdk = useSdk(); const [wellLiquidity, setWellLiquidity] = useState<(TokenValue | undefined)[]>([]); @@ -103,9 +30,6 @@ export const Wells = () => { const { hasPositions, getPositionWithWell } = useLPPositionSummary(); - const { getIsWhitelisted } = useBeanstalkSiloWhitelist(); - const isMobile = useIsMobile(); - useMemo(() => { const run = async () => { if (!wells || !wells.length) return; @@ -134,147 +58,10 @@ export const Wells = () => { run(); }, [sdk, wells]); - if (isLoading) { - return ; - } - if (error) { return ; } - const MyLiquidityRow: FC<{ - well: Well | undefined; - position: LPBalanceSummary | undefined; - prices: ReturnType["data"]; - }> = ({ well, position, prices }) => { - const lpAddress = well?.lpToken?.address; - const lpToken = well?.lpToken; - - if (!well || !position || position.total.lte(0) || !lpAddress || !lpToken) { - return null; - } - - const tokens = well.tokens || []; - const logos: ReactNode[] = []; - const symbols: string[] = []; - const gotoWell = () => navigate(`/wells/${well.address}`); - - tokens.map((token: any) => { - logos.push(); - symbols.push(token.symbol); - }); - - const lpPrice = lpAddress && lpAddress in prices ? prices[lpAddress] : undefined; - const whitelisted = getIsWhitelisted(well); - - const positionsUSD = { - total: lpPrice?.mul(position.total) || TokenValue.ZERO, - external: lpPrice?.mul(position.external) || TokenValue.ZERO, - silo: lpPrice?.mul(position.silo) || TokenValue.ZERO, - internal: lpPrice?.mul(position.internal) || TokenValue.ZERO - }; - - return ( - - - - {logos} - {symbols.join("/")} - - - - - - - - - - - - - - - {logos} - {symbols.join("/")} - {/* {deployer} */} - - - - - - - - - - - - ); - }; - - const WellRow: FC<{ well: Well | undefined; index: number }> = ({ well, index }) => { - if (!well) return null; - - const tokens = well.tokens || []; - const logos: ReactNode[] = []; - const smallLogos: ReactNode[] = []; - const symbols: string[] = []; - const gotoWell = () => navigate(`/wells/${well.address}`); - - tokens.map((token: any) => { - logos.push(); - smallLogos.push(); - symbols.push(token.symbol); - }); - - return ( - - - - {logos} - {symbols.join("/")} - - - - {wellFunctionNames?.[index] ? wellFunctionNames[index] : "Price Function"} - - - 0.00% - - - ${wellLiquidity[index] ? wellLiquidity[index]!.toHuman("short") : "-.--"} - - - - {{smallLogos[0]}} - {formatMayDecimals(well.reserves?.[0])} - - - {{smallLogos[1]}} - {formatMayDecimals(well.reserves?.[1])} - - {well.reserves && well.reserves.length > 2 ? {`+ ${well.reserves.length - 2} MORE`} : null} - - - - {logos} - {symbols.join("/")} - - ${formatNum(wellLiquidity[index], { minDecimals: 2 })} - - - ); - }; - return ( @@ -314,22 +101,49 @@ export const Wells = () => { </THead> )} <TBody> - {hasPositions === false && tab === 1 ? ( + {isLoading ? ( <> - <NoLPRow colSpan={isMobile ? 2 : 3}> - <NoLPMessage>Liquidity Positions will appear here.</NoLPMessage> - </NoLPRow> + {Array(5) + .fill(null) + .map((_, idx) => + tab === 0 ? ( + <WellDetailLoadingRow key={`well-detail-loading-row-${idx}`} /> + ) : ( + <MyWellPositionLoadingRow key={`well-position-loading-row-${idx}`} /> + ) + )} </> ) : ( - wells?.map((well, index) => { - return tab === 0 ? ( + <> + {hasPositions === false && tab === 1 ? ( <> - <WellRow well={well} index={index} key={well.address} /> + <NoLPRow colSpan={3}> + <NoLPMessage>Liquidity Positions will appear here.</NoLPMessage> + </NoLPRow> + <NoLPRowMobile colSpan={2}> + <NoLPMessage>Liquidity Positions will appear here.</NoLPMessage> + </NoLPRowMobile> </> ) : ( - <MyLiquidityRow well={well} position={getPositionWithWell(well)} prices={lpTokenPrices} key={well.address} /> - ); - }) + wells?.map((well, index) => { + return tab === 0 ? ( + <WellDetailRow + well={well} + liquidity={wellLiquidity?.[index]} + functionName={wellFunctionNames?.[index]} + key={`well-detail-row-${well.address}-${index}`} + /> + ) : ( + <MyWellPositionRow + well={well} + position={getPositionWithWell(well)} + prices={lpTokenPrices} + key={`My-liquidity-row-${well.address}-${index}`} + /> + ); + }) + )} + </> )} </TBody> </Table> @@ -353,19 +167,6 @@ const StyledRow = styled(TabRow)` } `; -const DesktopContainer = styled(Td)` - @media (max-width: ${size.mobile}) { - display: none; - } -`; - -const MobileContainer = styled(Td)` - padding: 8px 16px; - @media (min-width: ${size.mobile}) { - display: none; - } -`; - const MobileHeader = styled(Th)` font-size: 14px; padding: 8px 16px; @@ -380,73 +181,24 @@ const DesktopHeader = styled(Th)` } `; -const WellDetail = styled.div` - display: flex; - flex-direction: row; - gap: 8px; - @media (min-width: ${size.mobile}) { - flex-direction: column; - } -`; - -const TokenLogos = styled.div` - display: flex; - div:not(:first-child) { - margin-left: -8px; - } -`; -const TokenSymbols = styled.div` - font-size: 20px; - line-height: 24px; - color: #1c1917; - @media (max-width: ${size.mobile}) { - font-size: 14px; - margin-top: 2px; - } -`; - -const Amount = styled.div` - font-weight: 500; - font-size: 20px; - line-height: 24px; - color: #1c1917; +const NoLPRow = styled.td` + background-color: #fff; + height: 120px; + border-bottom: 0.5px solid #9ca3af; - @media (max-width: ${size.mobile}) { - font-size: 14px; - font-weight: normal; + ${mediaQuery.sm.only} { + display: none; } `; -const Reserves = styled.div` - display: flex; - flex-direction: row; - justify-content flex-end; - align-items: center; - gap: 4px; - flex: 1; -`; - -const MoreReserves = styled.div` - color: #9ca3af; -`; - -const TradingFee = styled.div` - font-size: 20px; - line-height: 24px; - color: #4b5563; - text-transform: uppercase; -`; - -const WellPricing = styled.div` - font-size: 20px; - line-height: 24px; - text-transform: capitalize; -`; - -const NoLPRow = styled.td` +const NoLPRowMobile = styled.td` background-color: #fff; height: 120px; border-bottom: 0.5px solid #9ca3af; + + ${mediaQuery.sm.up} { + display: none; + } `; const NoLPMessage = styled.div` @@ -458,38 +210,3 @@ const NoLPMessage = styled.div` font-size: 14px; } `; - -const WellLPBalance = styled.div` - font-size: 20px; - line-height: 24px; - @media (max-width: ${size.mobile}) { - font-size: 14px; - font-weight: normal; - } -`; - -const BalanceContainer = styled.div<{ left?: boolean }>` - display: flex; - justify-content: ${(props) => (props.left ? "flex-start" : "flex-end")}; -`; - -const Breakdown = styled.div` - display: flex; - flex-direction: column; - width: 100%; - gap: 4px; - @media (max-width: ${size.mobile}) { - gap: 0px; - } -`; - -const BreakdownRow = styled.div` - display: flex; - flex-direction: row; - justify-content: space-between; - gap: 4px; -`; - -const TokenLogoWrapper = styled.div` - margin-bottom: 2px; -`; From b909104d2637e633e532edd8dd659630f3084a1c Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Thu, 16 Nov 2023 12:47:10 -0700 Subject: [PATCH 10/30] update loading state for swap --- projects/dex-ui/src/components/Skeleton.tsx | 2 +- .../src/components/Swap/SwapLoading.tsx | 104 ++++++++++++++++++ projects/dex-ui/src/pages/Swap.tsx | 13 ++- projects/dex-ui/src/tokens/TokenProvider.tsx | 7 +- 4 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 projects/dex-ui/src/components/Swap/SwapLoading.tsx diff --git a/projects/dex-ui/src/components/Skeleton.tsx b/projects/dex-ui/src/components/Skeleton.tsx index 477e510125..2363951f70 100644 --- a/projects/dex-ui/src/components/Skeleton.tsx +++ b/projects/dex-ui/src/components/Skeleton.tsx @@ -4,7 +4,7 @@ import styled, { css, keyframes } from "styled-components"; export type SkeletonProps = { height: number; - width: number; + width?: number; // if true, rounded will be ignored circle?: boolean; // defaults to true diff --git a/projects/dex-ui/src/components/Swap/SwapLoading.tsx b/projects/dex-ui/src/components/Swap/SwapLoading.tsx new file mode 100644 index 0000000000..281ce0dcdc --- /dev/null +++ b/projects/dex-ui/src/components/Swap/SwapLoading.tsx @@ -0,0 +1,104 @@ +import React from "react"; +import { size } from "src/breakpoints"; +import styled from "styled-components"; +import { Skeleton } from "../Skeleton"; +import { ArrowButton } from "./ArrowButton"; + +export const SwapLoading: React.FC<{}> = () => { + return ( + <Container> + <LoadingInput> + {"-"} + <SkeletonRow> + <Skeleton width={16} height={16} circle /> + <Skeleton width={48} height={24} rounded /> + </SkeletonRow> + </LoadingInput> + <ArrowContainer> + <ArrowButton onClick={() => {}} /> + </ArrowContainer> + <LoadingInput> + {"-"} + <SkeletonRow> + <Skeleton width={16} height={16} circle /> + <Skeleton width={48} height={24} rounded /> + </SkeletonRow> + </LoadingInput> + <OutputRow> + <Background> + <Skeleton width={90} height={24} /> + </Background> + <Background> + <Skeleton width={70} height={24} /> + </Background> + </OutputRow> + <Background> + <Skeleton height={48} rounded={false} /> + </Background> + </Container> + ); +}; + +const Background = styled.div` + display: flex; + background: white; +`; + +const OutputRow = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +`; + +const LoadingInput = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + box-sizing: border-box; + background: #fff; + border: 0.5px solid #d1d5db; + padding: 23.5px 8px; + outline: 0.5px solid black; + // outline-offset: -1px; +`; + +const SkeletonRow = styled.div` + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; +`; + +const Container = styled.div` + width: 384px; + display: flex; + flex-direction: column; + gap: 24px; + @media (max-width: ${size.mobile}) { + width: 100%; + gap: 16px; + } +`; + +const ArrowContainer = styled.div` + // border: 1px dashed orange; + display: flex; + flex-direction: row; + justify-content: center; +`; + +const SwapButtonContainer = styled.div` + // border: 1px dashed pink; + display: flex; + flex-direction: column; + justify-content: center; + @media (max-width: ${size.mobile}) { + position: fixed; + width: calc(100% - 24px); + margin-bottom: 0; + bottom: 12px; + } +`; + +export default SwapLoading; diff --git a/projects/dex-ui/src/pages/Swap.tsx b/projects/dex-ui/src/pages/Swap.tsx index 1d6ef27cc0..261489744e 100644 --- a/projects/dex-ui/src/pages/Swap.tsx +++ b/projects/dex-ui/src/pages/Swap.tsx @@ -1,13 +1,24 @@ import React from "react"; import { Page } from "src/components/Page"; import { Title } from "src/components/PageComponents/Title"; +import SwapLoading from "src/components/Swap/SwapLoading"; import { SwapRoot } from "src/components/Swap/SwapRoot"; +import { useWellTokens } from "src/tokens/useWellTokens"; + +/** + * Normally we would not check the loading state at this level, but + * if we don't it'll cause errors in the SwapRoot component & it's children. + * It's simpler to render a separate loading component here instead of handling it + * everywhere else. + */ export const Swap = () => { + const { isLoading } = useWellTokens(); + return ( <Page> <Title title="Swap" /> - <SwapRoot /> + {isLoading ? <SwapLoading /> : <SwapRoot />} </Page> ); }; diff --git a/projects/dex-ui/src/tokens/TokenProvider.tsx b/projects/dex-ui/src/tokens/TokenProvider.tsx index 181409b06c..ccf9091825 100644 --- a/projects/dex-ui/src/tokens/TokenProvider.tsx +++ b/projects/dex-ui/src/tokens/TokenProvider.tsx @@ -3,7 +3,6 @@ import React, { createContext, useContext } from "react"; import { useWellTokens } from "src/tokens/useWellTokens"; import { images } from "src/assets/images/tokens"; -import { Loading } from "src/components/Loading"; import { Error } from "src/components/Error"; const tokenMap: Record<string, Token> = {}; @@ -13,16 +12,16 @@ export const TokenProvider = ({ children }: { children: React.ReactNode }) => { const { data: tokens, isLoading, error } = useWellTokens(); if (isLoading) { - return <Loading /> + <></>; } if (error) { - return <Error message={error?.message} /> + return <Error message={error?.message} />; } const add = (token: Token) => (tokenMap[token.symbol] = token); - for (const token of tokens! || []) { + for (const token of tokens || []) { let logo = images[token.symbol] ?? images.DEFAULT; token.setMetadata({ logo }); add(token); From b04dd08220970570365466540107f3d90ab7fccf Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Fri, 17 Nov 2023 15:14:18 -0700 Subject: [PATCH 11/30] fix liquidity page responsive --- .../components/Liquidity/RemoveLiquidity.tsx | 2 +- projects/dex-ui/src/pages/Liquidity.tsx | 132 +++++++++--------- 2 files changed, 67 insertions(+), 67 deletions(-) diff --git a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx index 218ed2085a..1b35b77673 100644 --- a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx @@ -452,7 +452,7 @@ const LargeGapContainer = styled.div` flex-direction: column; gap: 24px; @media (max-width: ${size.mobile}) { - margin-bottom: 40px; + margin-bottom: 64px; } `; diff --git a/projects/dex-ui/src/pages/Liquidity.tsx b/projects/dex-ui/src/pages/Liquidity.tsx index 2e6cf729a2..73c03c2679 100644 --- a/projects/dex-ui/src/pages/Liquidity.tsx +++ b/projects/dex-ui/src/pages/Liquidity.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import { useNavigate, useParams } from "react-router-dom"; import { useWell } from "src/wells/useWell"; import styled from "styled-components"; @@ -16,7 +16,7 @@ import { Log } from "src/utils/logger"; import { BodyXS, TextNudge } from "src/components/Typography"; import { ImageButton } from "src/components/ImageButton"; import { ChevronDown } from "src/components/Icons"; -import { size } from "src/breakpoints"; +import { mediaQuery, size } from "src/breakpoints"; import { Loading } from "../components/Loading"; import { Error } from "../components/Error"; @@ -25,17 +25,9 @@ export const Liquidity = () => { const navigate = useNavigate(); const { well, loading, error } = useWell(wellAddress!); const [wellFunctionName, setWellFunctionName] = useState<string>("This Well's Function"); - const [isMobile, setIsMobile] = useState(window.matchMedia(`(max-width: ${size.mobile})`).matches); - const [tab, setTab] = useState(isMobile ? null : 0); + const [tab, setTab] = useState(0); - // Media query - useEffect(() => { - window.matchMedia(`(max-width: ${size.mobile})`).addEventListener("change", (event) => setIsMobile(event.matches)); - - return () => { - window.matchMedia(`(max-width: ${size.mobile})`).removeEventListener("change", (event) => setIsMobile(event.matches)); - }; - }, []); + const scrollRef = useRef<HTMLDivElement>(null); // Slippage-related const [showSlippageSettings, setShowSlippageSettings] = useState<boolean>(false); @@ -49,7 +41,6 @@ export const Liquidity = () => { Log.module("liquidity").debug(`Slippage changed: ${parseFloat(value)}`); setSlippage(parseFloat(value)); }; - // /Slippage-related const [open, setOpen] = useState(false); const toggle = useCallback(() => { @@ -79,48 +70,44 @@ export const Liquidity = () => { <Button secondary label="← Back To Well Details" - width={isMobile ? "100vw" : "100%"} - margin={isMobile ? "-12px -11px 0px -12px" : "0"} + width={"100%"} + margin={"0px"} onClick={() => navigate(`../wells/${wellAddress}`)} /> - {(tab === null && isMobile) || !isMobile ? ( - <> - <LiquidityBox well={well} /> - <LearnMoreContainer> - <LearnMoreLabel onClick={toggle}> - <LearnMoreLine /> - <LearnMoreText> - <TextNudge amount={2}>Learn more about this Well</TextNudge> - <ImageButton - component={ChevronDown} - size={10} - rotate={open ? "180" : "0"} - onClick={toggle} - padding="0px" - alt="Click to expand and learn how to earn yield" - color={"#46B955"} - /> - </LearnMoreText> - <LearnMoreLine /> - </LearnMoreLabel> - <LearnMoreButtons open={open}> - <LearnYield /> - <LearnWellFunction name={wellFunctionName} /> - <LearnPump /> - </LearnMoreButtons> - </LearnMoreContainer> - </> - ) : null} + <LiquidityBox well={well} /> + <LearnMoreContainer> + <LearnMoreLabel onClick={toggle}> + <LearnMoreLine /> + <LearnMoreText> + <TextNudge amount={2}>Learn more about this Well</TextNudge> + <ImageButton + component={ChevronDown} + size={10} + rotate={open ? "180" : "0"} + onClick={toggle} + padding="0px" + alt="Click to expand and learn how to earn yield" + color={"#46B955"} + /> + </LearnMoreText> + <LearnMoreLine /> + </LearnMoreLabel> + <LearnMoreButtons open={open}> + <LearnYield /> + <LearnWellFunction name={wellFunctionName} /> + <LearnPump /> + </LearnMoreButtons> + </LearnMoreContainer> </SideBar> - <CenterBar id="centerbar"> - <AddRemoveLiquidityRow gap={0} tabSelected={tab === 0 || tab === 1}> + <CenterBar id="centerbar" ref={scrollRef}> + <AddRemoveLiquidityRow gap={0} tabSelected={true}> <Item stretch> - <TabButton onClick={() => setTab(isMobile && tab === 0 ? null : 0)} active={tab === 0} stretch bold justify hover> + <TabButton onClick={() => setTab(0)} active={tab === 0} stretch bold justify hover> <span>Add Liquidity</span> </TabButton> </Item> <Item stretch> - <TabButton onClick={() => setTab(isMobile && tab === 1 ? null : 1)} active={tab === 1} stretch bold justify hover> + <TabButton onClick={() => setTab(1)} active={tab === 1} stretch bold justify hover> <span>Remove Liquidity</span> </TabButton> </Item> @@ -142,32 +129,38 @@ export const Liquidity = () => { /> )} </CenterBar> - <SideBar id="leftbar" /> </ContentWrapper> </Page> ); }; +const EmptyItem = styled.div` + display: none; +`; + const ContentWrapper = styled.div` - // outline: 1px solid red; display: flex; flex-direction: row; - justify-content: center; gap: 48px; - @media (max-width: ${size.mobile}) { + + ${mediaQuery.lg.down} { flex-direction: column; gap: 16px; } + + ${mediaQuery.lg.only} { + justify-content: flex-start; + } `; const SideBar = styled.div` - // outline: 1px solid green; display: flex; flex-direction: column; width: calc(16 * 24px); min-width: calc(16 * 24px); gap: 24px; - @media (max-width: ${size.mobile}) { + + ${mediaQuery.lg.down} { width: 100%; min-width: 100%; gap: 16px; @@ -175,13 +168,17 @@ const SideBar = styled.div` `; const CenterBar = styled.div` - // outline: 1px solid green; display: flex; flex-direction: column; - width: calc(17 * 24px); - min-width: calc(17 * 24px); gap: 24px; - @media (max-width: ${size.mobile}) { + width: 100%; + + ${mediaQuery.md.up} { + width: calc(17 * 24px); + min-width: calc(17 * 24px); + } + + ${mediaQuery.md.down} { width: 100%; min-width: 100%; gap: 16px; @@ -206,16 +203,18 @@ const LearnMoreContainer = styled.div` gap: 16px; order: 1; width: 100%; + @media (min-width: ${size.mobile}) { gap: 24px; order: 0; } `; const LearnMoreLabel = styled.div` - display: flex; - flex-direction: row; - @media (min-width: ${size.mobile}) { - display: none; + display: none; + + ${mediaQuery.lg.down} { + display: flex; + flex-direction: row; } `; @@ -240,11 +239,12 @@ const LearnMoreText = styled.div` `; const LearnMoreButtons = styled.div<{ open: boolean }>` - ${(props) => (props.open ? "display: flex" : "display: none")}; + display: flex; flex-direction: column; - gap: 16px; - @media (min-width: ${size.mobile}) { - display: flex; - gap: 24px; + gap: 24px; + + ${mediaQuery.lg.down} { + ${(props) => (props.open ? "display: flex" : "display: none")}; + gap: 16px; } `; From cada86a9b16b52c389586bd8cd98bfe4392da011 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Fri, 17 Nov 2023 15:14:37 -0700 Subject: [PATCH 12/30] clean up --- .../dex-ui/src/components/Well/Table/MyWellPositionRow.tsx | 2 +- projects/dex-ui/src/utils/ui/useIsMobile.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/projects/dex-ui/src/components/Well/Table/MyWellPositionRow.tsx b/projects/dex-ui/src/components/Well/Table/MyWellPositionRow.tsx index d14933ac74..778d005e57 100644 --- a/projects/dex-ui/src/components/Well/Table/MyWellPositionRow.tsx +++ b/projects/dex-ui/src/components/Well/Table/MyWellPositionRow.tsx @@ -13,7 +13,7 @@ import { Well } from "@beanstalk/sdk/Wells"; import { Skeleton } from "src/components/Skeleton"; import { useNavigate } from "react-router-dom"; -import useIsMobile from "src/utils/ui/useIsMobile"; +import { useIsMobile } from "src/utils/ui/useIsMobile"; const PositionBreakdown: React.FC<{ items: { external: TokenValue; silo: TokenValue; internal: TokenValue; total: TokenValue }; diff --git a/projects/dex-ui/src/utils/ui/useIsMobile.ts b/projects/dex-ui/src/utils/ui/useIsMobile.ts index f6b7b08daa..cfbc83d2f9 100644 --- a/projects/dex-ui/src/utils/ui/useIsMobile.ts +++ b/projects/dex-ui/src/utils/ui/useIsMobile.ts @@ -1,7 +1,7 @@ import { useEffect, useState } from "react"; import { size } from "src/breakpoints"; -const useIsMobile = () => { +export const useIsMobile = () => { const [isMobile, setIsMobile] = useState(window.matchMedia(`(max-width: ${size.mobile})`).matches); // Media query useEffect(() => { @@ -14,5 +14,3 @@ const useIsMobile = () => { return isMobile; }; - -export default useIsMobile; From bb5a8b8d1a89025a252e666dfc4f6918dd8fc9f2 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Sat, 18 Nov 2023 18:16:00 -0700 Subject: [PATCH 13/30] make well page responsive --- projects/dex-ui/src/breakpoints.ts | 2 +- projects/dex-ui/src/pages/Well.tsx | 101 +++++++++++++++++++---------- 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/projects/dex-ui/src/breakpoints.ts b/projects/dex-ui/src/breakpoints.ts index 562fbdc4a8..2c5c079b49 100644 --- a/projects/dex-ui/src/breakpoints.ts +++ b/projects/dex-ui/src/breakpoints.ts @@ -19,7 +19,7 @@ export const mediaQuery = { }, md: { // 1024px & above - up: `@media (min-width: ${mediaSizes.mobile}px)`, + up: `@media (min-width: ${mediaSizes.tablet}px)`, // between 769px & 1024px only: `@media (min-width: ${mediaSizes.mobile}px) and (max-width: ${mediaSizes.tablet - 1}px)`, // 1024px & below diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index 79b8ba93c0..2585499e85 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -22,7 +22,7 @@ import { OtherSection } from "src/components/Well/OtherSection"; import { WellHistory } from "src/components/Well/Activity/WellHistory"; import { ChevronDown } from "src/components/Icons"; import { ImageButton } from "src/components/ImageButton"; -import { size } from "src/breakpoints"; +import { mediaQuery } from "src/breakpoints"; import { Loading } from "src/components/Loading"; import { Error } from "../components/Error"; @@ -209,18 +209,22 @@ export const Well = () => { const leftColumnWidth = 940; const rightColumnWidth = 400; +const calcWellContentMaxWidth = `min(calc(100% - 48px - 400px), ${leftColumnWidth}px)`; + const ContentWrapper = styled.div` - // outline: 1px solid red; display: flex; flex-flow: column wrap; flex: auto; justify-content: flex-start; - align-content: center; + align-content: start; gap: 24px; - @media (min-width: ${size.mobile}) { + width: 100%; + + ${mediaQuery.lg.only} { height: 1400px; } - @media (max-width: ${size.mobile}) { + + ${mediaQuery.lg.down} { flex-flow: column nowrap; } `; @@ -236,7 +240,7 @@ const Header = styled.div` line-height: 32px; gap: 24px; - @media (max-width: ${size.mobile}) { + ${mediaQuery.lg.down} { font-size: 24px; gap: 8px; } @@ -250,8 +254,13 @@ const TokenLogos = styled.div` `; const HeaderContainer = styled(Row)` - width: ${leftColumnWidth}px; - @media (max-width: ${size.mobile}) { + ${mediaQuery.lg.only} { + display: flex; + max-width: ${calcWellContentMaxWidth}; + width: 100%; + } + + ${mediaQuery.lg.down} { display: flex; width: 100%; flex-direction: column; @@ -259,13 +268,19 @@ const HeaderContainer = styled(Row)` gap: 8px; order: 0; } + + ${mediaQuery.md.up} { + align-item: space-between; + } `; const ReservesContainer = styled.div` width: 100%; order: 3; - @media (min-width: ${size.mobile}) { - width: ${leftColumnWidth}px; + + ${mediaQuery.lg.only} { + max-width: ${calcWellContentMaxWidth}; + width: 100%; order: 0; } `; @@ -273,8 +288,10 @@ const ReservesContainer = styled.div` const ChartContainer = styled.div` width: 100%; order: 4; - @media (min-width: ${size.mobile}) { - width: ${leftColumnWidth}px; + + ${mediaQuery.lg.only} { + display: block; + max-width: ${calcWellContentMaxWidth}; order: 0; } `; @@ -282,8 +299,10 @@ const ChartContainer = styled.div` const ActivityOtherButtons = styled(Row)` width: 100%; order: 5; - @media (min-width: ${size.mobile}) { - width: ${leftColumnWidth}px; + + ${mediaQuery.lg.only} { + max-width: ${calcWellContentMaxWidth}; + width: 100%; order: 0; } `; @@ -295,7 +314,8 @@ const StickyDetector = styled.div` background-color: transparent; margin-bottom: -24px; order: 2; - @media (min-width: ${size.mobile}) { + + ${mediaQuery.lg.only} { display: none; } `; @@ -308,18 +328,25 @@ const LiquiditySwapButtons = styled(Row)<{ sticky?: boolean }>` top: 0px; z-index: 10; transition: all 0.3s ease-in-out; - @media (min-width: ${size.mobile}) { + + ${mediaQuery.lg.only} { + max-width: ${rightColumnWidth}px; + order: 0; margin-top: 48px; - width: ${rightColumnWidth}px; position: relative; margin-left: 0px; - order: 0; + } + + ${mediaQuery.md.only} { + max-width: calc(100vw - 96px); } `; const StyledItem = styled(Item)` - @media (min-width: ${size.mobile}) { - align-items: end; + align-items: flex-start; + + ${mediaQuery.md.up} { + align-items: flex-end; } `; const BottomContainer = styled.div` @@ -328,30 +355,35 @@ const BottomContainer = styled.div` gap: 24px; width: 100%; order: 6; - @media (min-width: ${size.mobile}) { - width: ${leftColumnWidth}px; + + ${mediaQuery.lg.only} { + max-width: ${calcWellContentMaxWidth}; + width: 100%; order: 0; } `; const FunctionName = styled.div` ${BodyL} - @media (max-width: ${size.mobile}) { + + ${mediaQuery.lg.down} { ${BodyS} } `; const Fee = styled.div` ${BodyS} color: #4B5563; - @media (max-width: ${size.mobile}) { + ${mediaQuery.lg.down} { ${BodyXS} } `; const LiquidityBoxContainer = styled.div` - width: ${rightColumnWidth}px; - @media (max-width: ${size.mobile}) { - display: none; + display: none; + + ${mediaQuery.lg.only} { + display: block; + max-width: ${rightColumnWidth}px; } `; @@ -361,16 +393,17 @@ const LearnMoreContainer = styled.div` gap: 16px; order: 1; width: 100%; - @media (min-width: ${size.mobile}) { - width: ${rightColumnWidth}px; - gap: 24px; + + ${mediaQuery.lg.only} { + max-width: ${rightColumnWidth}px; order: 0; + gap: 24px; } `; const LearnMoreLabel = styled.div` display: flex; flex-direction: row; - @media (min-width: ${size.mobile}) { + ${mediaQuery.lg.only} { display: none; } `; @@ -399,7 +432,8 @@ const LearnMoreButtons = styled.div<{ open: boolean }>` ${(props) => (props.open ? "display: flex" : "display: none")}; flex-direction: column; gap: 16px; - @media (min-width: ${size.mobile}) { + + ${mediaQuery.lg.only} { display: flex; gap: 24px; } @@ -407,7 +441,8 @@ const LearnMoreButtons = styled.div<{ open: boolean }>` const ColumnBreak = styled.div` display: none; - @media (min-width: ${size.mobile}) { + + ${mediaQuery.lg.only} { display: block; flex-basis: 100%; width: 0px; From 856479aa03c7a23befd8075836ed6aa0833f7647 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Sat, 18 Nov 2023 18:17:01 -0700 Subject: [PATCH 14/30] fix internal whitelist broken in prod + clean up --- projects/dex-ui/src/pages/Liquidity.tsx | 4 ---- projects/dex-ui/src/wells/useBeanstalkSiloWhitelist.ts | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/projects/dex-ui/src/pages/Liquidity.tsx b/projects/dex-ui/src/pages/Liquidity.tsx index 73c03c2679..77b905e0c1 100644 --- a/projects/dex-ui/src/pages/Liquidity.tsx +++ b/projects/dex-ui/src/pages/Liquidity.tsx @@ -134,10 +134,6 @@ export const Liquidity = () => { ); }; -const EmptyItem = styled.div` - display: none; -`; - const ContentWrapper = styled.div` display: flex; flex-direction: row; diff --git a/projects/dex-ui/src/wells/useBeanstalkSiloWhitelist.ts b/projects/dex-ui/src/wells/useBeanstalkSiloWhitelist.ts index a125c52579..817f9d99cd 100644 --- a/projects/dex-ui/src/wells/useBeanstalkSiloWhitelist.ts +++ b/projects/dex-ui/src/wells/useBeanstalkSiloWhitelist.ts @@ -3,7 +3,7 @@ import { Well } from "@beanstalk/sdk/Wells"; const WHITELIST_MAP = { /// BEANWETHCP2w (BEANETH LP) - "0xBEA0e11282e2bB5893bEcE110cF199501e872bAd": { + "0xbea0e11282e2bb5893bece110cf199501e872bad": { address: "0xBEA0e11282e2bB5893bEcE110cF199501e872bAd", lpTokenAddress: "0xbea0e11282e2bb5893bece110cf199501e872bad" } @@ -15,7 +15,7 @@ export const useBeanstalkSiloWhitelist = () => { const getIsWhitelisted = (well: Well | undefined) => { if (!well) return false; - const wellAddress = well.address; + const wellAddress = well.address.toLowerCase(); return wellAddress in WHITELIST_MAP; }; From 37fa5e682908cf382eb293a81200dc95a0b6e74a Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Sat, 18 Nov 2023 18:51:23 -0700 Subject: [PATCH 15/30] fix font sizes --- .../dex-ui/src/components/Liquidity/QuoteDetails.tsx | 4 ++-- .../dex-ui/src/components/PageComponents/Title.tsx | 6 +++--- projects/dex-ui/src/components/Swap/Button.tsx | 2 +- projects/dex-ui/src/components/TabButton.tsx | 2 +- projects/dex-ui/src/components/Well/LiquidityBox.tsx | 11 ++++++++--- projects/dex-ui/src/components/Well/Reserves.tsx | 8 ++++---- projects/dex-ui/src/pages/Swap.tsx | 2 +- projects/dex-ui/src/pages/Wells.tsx | 5 ++--- 8 files changed, 22 insertions(+), 18 deletions(-) diff --git a/projects/dex-ui/src/components/Liquidity/QuoteDetails.tsx b/projects/dex-ui/src/components/Liquidity/QuoteDetails.tsx index 7ad785ef8e..bbdf879b4c 100644 --- a/projects/dex-ui/src/components/Liquidity/QuoteDetails.tsx +++ b/projects/dex-ui/src/components/Liquidity/QuoteDetails.tsx @@ -8,7 +8,7 @@ import SlippagePanel from "./SlippagePanel"; import { ChevronDown, Info } from "../Icons"; import { ImageButton } from "../ImageButton"; import { Tooltip } from "../Tooltip"; -import { BodyXS } from "../Typography"; +import { BodyS } from "../Typography"; import { size } from "src/breakpoints"; import { displayTokenSymbol } from "src/utils/format"; @@ -343,6 +343,6 @@ const QuoteContainer = styled.div` display: flex; flex-direction: column; @media (max-width: ${size.mobile}) { - ${BodyXS} + ${BodyS} } `; diff --git a/projects/dex-ui/src/components/PageComponents/Title.tsx b/projects/dex-ui/src/components/PageComponents/Title.tsx index e5a5374ee5..e4cff5c663 100644 --- a/projects/dex-ui/src/components/PageComponents/Title.tsx +++ b/projects/dex-ui/src/components/PageComponents/Title.tsx @@ -1,7 +1,7 @@ import React from "react"; import { FC } from "src/types"; import styled from "styled-components"; -import { BodyL, BodyXS, H2 } from "../Typography"; +import { BodyL, BodyS, BodyXS, H2 } from "../Typography"; import { Link } from "react-router-dom"; import { size } from "src/breakpoints"; @@ -55,7 +55,7 @@ const TitleText = styled.div<TitleProps>` ${(props) => props.fontWeight && `font-weight: ${props.fontWeight}`}; text-transform: uppercase; @media (max-width: ${size.mobile}) { - ${({ largeOnMobile }) => (largeOnMobile ? `${H2}` : `${BodyXS}`)} + ${({ largeOnMobile }) => (largeOnMobile ? `${H2}` : `${BodyS}`)} } `; const ParentText = styled(Link)` @@ -64,7 +64,7 @@ const ParentText = styled(Link)` text-decoration: none; text-transform: uppercase; @media (max-width: ${size.mobile}) { - ${BodyXS} + ${BodyS} } :hover { color: #000000; diff --git a/projects/dex-ui/src/components/Swap/Button.tsx b/projects/dex-ui/src/components/Swap/Button.tsx index 5df82e4c85..7d5410bb0c 100644 --- a/projects/dex-ui/src/components/Swap/Button.tsx +++ b/projects/dex-ui/src/components/Swap/Button.tsx @@ -70,6 +70,6 @@ const StyledButton = styled.button<ButtonProps>` ${BodyXS} font-weight: 600; padding: 8px 8px; - height: 40px; + height: 48x; } `; diff --git a/projects/dex-ui/src/components/TabButton.tsx b/projects/dex-ui/src/components/TabButton.tsx index a2fcac7611..6e6d98e810 100644 --- a/projects/dex-ui/src/components/TabButton.tsx +++ b/projects/dex-ui/src/components/TabButton.tsx @@ -28,7 +28,7 @@ export const TabButton = styled.button<{ active?: boolean; stretch?: boolean; bo @media (max-width: ${size.mobile}) { ${BodyXS} - height: 40px; + height: 48px; font-weight: ${({ bold, active }) => (bold || active ? "600" : "normal")}; padding: 8px 8px; line-height: 18px; diff --git a/projects/dex-ui/src/components/Well/LiquidityBox.tsx b/projects/dex-ui/src/components/Well/LiquidityBox.tsx index 52ad1254f5..7d4d17d04b 100644 --- a/projects/dex-ui/src/components/Well/LiquidityBox.tsx +++ b/projects/dex-ui/src/components/Well/LiquidityBox.tsx @@ -4,8 +4,8 @@ import styled from "styled-components"; import { TokenValue } from "@beanstalk/sdk"; import { Well } from "@beanstalk/sdk/Wells"; -import { size } from "src/breakpoints"; -import { BodyCaps, BodyXS, LinksButtonText, TextNudge } from "src/components/Typography"; +import { mediaQuery, size } from "src/breakpoints"; +import { BodyCaps, BodyS, BodyXS, LinksButtonText, TextNudge } from "src/components/Typography"; import { InfoBox } from "src/components/InfoBox"; import { TokenLogo } from "src/components/TokenLogo"; import { Tooltip } from "src/components/Tooltip"; @@ -117,9 +117,14 @@ export const LiquidityBox: FC<Props> = (props) => { const BoxHeader = styled.div` ${BodyCaps} @media (max-width: ${size.mobile}) { - ${BodyXS} + ${BodyS} } `; + +const InfoText = styled.div` + ${BodyS} +`; + const BoxHeaderAmount = styled.div` display: flex; align-items: center; diff --git a/projects/dex-ui/src/components/Well/Reserves.tsx b/projects/dex-ui/src/components/Well/Reserves.tsx index 0ee1047043..794a3c82a6 100644 --- a/projects/dex-ui/src/components/Well/Reserves.tsx +++ b/projects/dex-ui/src/components/Well/Reserves.tsx @@ -1,6 +1,6 @@ import React from "react"; import styled from "styled-components"; -import { BodyL, BodyXS, TextNudge } from "../Typography"; +import { BodyL, BodyS, TextNudge } from "../Typography"; import { FC } from "src/types"; import { Token, TokenValue } from "@beanstalk/sdk"; import { TokenLogo } from "../TokenLogo"; @@ -38,7 +38,7 @@ const Symbol = styled.div` ${BodyL} color: #4B5563; @media (max-width: ${size.mobile}) { - ${BodyXS} + ${BodyS} } `; const Wrapper = styled.div` @@ -54,7 +54,7 @@ const Amount = styled.div` text-align: right; color: #000000; @media (max-width: ${size.mobile}) { - ${BodyXS} + ${BodyS} font-weight: 600; } `; @@ -65,6 +65,6 @@ const Percent = styled.div` text-align: right; color: #9ca3af; @media (max-width: ${size.mobile}) { - ${BodyXS} + ${BodyS} } `; diff --git a/projects/dex-ui/src/pages/Swap.tsx b/projects/dex-ui/src/pages/Swap.tsx index 261489744e..b4122477d6 100644 --- a/projects/dex-ui/src/pages/Swap.tsx +++ b/projects/dex-ui/src/pages/Swap.tsx @@ -17,7 +17,7 @@ export const Swap = () => { return ( <Page> - <Title title="Swap" /> + <Title title="Swap" fontWeight={"600"} largeOnMobile /> {isLoading ? <SwapLoading /> : <SwapRoot />} </Page> ); diff --git a/projects/dex-ui/src/pages/Wells.tsx b/projects/dex-ui/src/pages/Wells.tsx index 70006f2348..12007f21c4 100644 --- a/projects/dex-ui/src/pages/Wells.tsx +++ b/projects/dex-ui/src/pages/Wells.tsx @@ -161,9 +161,8 @@ const StyledRow = styled(TabRow)` @media (max-width: ${size.mobile}) { position: fixed; width: 100vw; - margin-left: -12px; - margin-bottom: -2px; - top: calc(100% - 40px); + top: calc(100% - 48px); + left: 0; } `; From 8dc92b44946b69e7387513c21ae5cd475d6952ec Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Sat, 18 Nov 2023 20:11:03 -0700 Subject: [PATCH 16/30] add loading skeletons to AddLiquidity + fix LiquidityBox + fix SwapLoading --- .../src/components/Liquidity/AddLiquidity.tsx | 36 ++++++- .../dex-ui/src/components/LoadingItem.tsx | 31 ++++++ .../dex-ui/src/components/LoadingTemplate.tsx | 94 ++++++++++++++++++ projects/dex-ui/src/components/Skeleton.tsx | 4 +- .../src/components/Swap/SwapLoading.tsx | 87 ++--------------- .../src/components/Well/LiquidityBox.tsx | 95 ++++++++++--------- projects/dex-ui/src/pages/Liquidity.tsx | 74 ++++++++++++--- projects/dex-ui/src/pages/Well.tsx | 2 +- .../dex-ui/src/wells/useWellWithParams.tsx | 7 ++ 9 files changed, 285 insertions(+), 145 deletions(-) create mode 100644 projects/dex-ui/src/components/LoadingItem.tsx create mode 100644 projects/dex-ui/src/components/LoadingTemplate.tsx create mode 100644 projects/dex-ui/src/wells/useWellWithParams.tsx diff --git a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx index 6f239877ce..5220b31226 100644 --- a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx @@ -16,14 +16,18 @@ import useSdk from "src/utils/sdk/useSdk"; import { useWellReserves } from "src/wells/useWellReserves"; import { Checkbox } from "../Checkbox"; import { size } from "src/breakpoints"; +import { LoadingTemplate } from "../LoadingTemplate"; -type AddLiquidityProps = { - well: Well; +type BaseAddLiquidityProps = { slippage: number; slippageSettingsClickHandler: () => void; handleSlippageValueChange: (value: string) => void; }; +type AddLiquidityProps = { + well: Well; +} & BaseAddLiquidityProps; + export type AddLiquidityQuote = { quote: { quote: TokenValue[]; @@ -31,7 +35,33 @@ export type AddLiquidityQuote = { estimate: TokenValue; }; -export const AddLiquidity = ({ well, slippage, slippageSettingsClickHandler, handleSlippageValueChange }: AddLiquidityProps) => { +export const AddLiquidityLoading = () => ( + <div> + <LargeGapContainer> + <LoadingTemplate.Flex gap={12}> + <LoadingTemplate.Input /> + <LoadingTemplate.Input /> + </LoadingTemplate.Flex> + <LoadingTemplate.Flex gap={8}> + <LoadingTemplate.OutputSingle size={20} width={285} /> + <LoadingTemplate.OutputSingle size={20} width={145} /> + </LoadingTemplate.Flex> + <ButtonWrapper> + <LoadingTemplate.Button /> + </ButtonWrapper> + </LargeGapContainer> + </div> +); + +export const AddLiquidity = (props: BaseAddLiquidityProps & { well: Well | undefined; loading: boolean }) => { + if (!props.well || props.loading) { + return <AddLiquidityLoading />; + } + + return <AddLiquidityContent {...props} well={props.well} />; +}; + +const AddLiquidityContent = ({ well, slippage, slippageSettingsClickHandler, handleSlippageValueChange }: AddLiquidityProps) => { const { address } = useAccount(); const [amounts, setAmounts] = useState<LiquidityAmounts>({}); const inputs = Object.values(amounts); diff --git a/projects/dex-ui/src/components/LoadingItem.tsx b/projects/dex-ui/src/components/LoadingItem.tsx new file mode 100644 index 0000000000..c02cc29280 --- /dev/null +++ b/projects/dex-ui/src/components/LoadingItem.tsx @@ -0,0 +1,31 @@ +import React, { FC } from "react"; +import { Skeleton, SkeletonProps } from "./Skeleton"; + +type BaseProps = { + loading?: boolean; + children: React.ReactNode; +}; + +type WithOnLoadingProps = BaseProps & { + onLoading: JSX.Element | null; + loadProps?: never; // Indicate that skeletonProps should not be provided +}; + +type WithoutOnLoadingProps = BaseProps & { + onLoading?: never; + loadProps: SkeletonProps; // Ensure SkeletonProps are provided +}; + +type Props = WithOnLoadingProps | WithoutOnLoadingProps; + +export const LoadingItem: FC<Props> = ({ loading, onLoading, children, loadProps }) => { + if (!loading) { + return <>{children}</>; + } + + if (onLoading !== undefined) { + return <>{onLoading}</>; + } + + return <Skeleton {...loadProps} />; +}; diff --git a/projects/dex-ui/src/components/LoadingTemplate.tsx b/projects/dex-ui/src/components/LoadingTemplate.tsx new file mode 100644 index 0000000000..5182bcdbc2 --- /dev/null +++ b/projects/dex-ui/src/components/LoadingTemplate.tsx @@ -0,0 +1,94 @@ +import React from "react"; +import styled from "styled-components"; +import { Skeleton } from "./Skeleton"; +import { ArrowButton } from "./Swap/ArrowButton"; + +export function LoadingTemplate() {} + +LoadingTemplate.Input = () => ( + <LoadingInputItem> + {"-"} + <SkeletonRow> + <Skeleton width={16} height={16} circle /> + <Skeleton width={48} height={24} /> + </SkeletonRow> + </LoadingInputItem> +); + +LoadingTemplate.Arrow = () => ( + <ArrowContainer> + <ArrowButton onClick={() => {}} /> + </ArrowContainer> +); + +LoadingTemplate.OutputDouble = ({ size }: { size?: number }) => ( + <OutputRow> + <Background> + <Skeleton width={90} height={size ? size : 24} /> + </Background> + <Background> + <Skeleton width={70} height={size ? size : 24} /> + </Background> + </OutputRow> +); + +LoadingTemplate.Button = () => ( + <Background> + <Skeleton height={48} /> + </Background> +); + +LoadingTemplate.OutputSingle = ({ size, width }: { size?: number; width?: number }) => ( + <Background width={width || 90}> + <Skeleton width={width || 90} height={size ? size : 24} /> + </Background> +); + +LoadingTemplate.Flex = styled.div<{ row?: boolean; gap?: number }>` + display: flex; + ${(props) => ` + flex-direction: ${props.row ? "row" : "column"}; + gap: ${props.gap || 0}px; + `} +`; + +const Background = styled.div<{ width?: number }>` + display: flex; + background: white; + ${(props) => ` + width: ${props.width ? `${props.width}px` : "100"}; + `} +`; + +const OutputRow = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +`; + +const LoadingInputItem = styled.div` + display: flex; + flex-direction: row; + justify-content: space-between; + box-sizing: border-box; + background: #fff; + border: 0.5px solid #d1d5db; + padding: 23.5px 8px; + outline: 0.5px solid black; + // outline-offset: -1px; +`; + +const SkeletonRow = styled.div` + display: flex; + flex-direction: row; + align-items: center; + gap: 8px; +`; + +const ArrowContainer = styled.div` + // border: 1px dashed orange; + display: flex; + flex-direction: row; + justify-content: center; +`; diff --git a/projects/dex-ui/src/components/Skeleton.tsx b/projects/dex-ui/src/components/Skeleton.tsx index 2363951f70..9563f6632c 100644 --- a/projects/dex-ui/src/components/Skeleton.tsx +++ b/projects/dex-ui/src/components/Skeleton.tsx @@ -7,7 +7,7 @@ export type SkeletonProps = { width?: number; // if true, rounded will be ignored circle?: boolean; - // defaults to true + // defaults to false rounded?: boolean; // defaults to pulse shimmer?: boolean; @@ -47,7 +47,7 @@ const SkeletonBase = css<SkeletonProps>` ${(props) => ` height: ${props.height ? `${props.height}px` : "100%"}; width: ${props.width ? `${props.width}px` : "100%"}; - border-radius: ${props.circle ? "50%" : props.rounded === false ? `0px` : "4px"}; + border-radius: ${props.circle ? "50%" : props.rounded === true ? `4px` : "0px"}; `} `; diff --git a/projects/dex-ui/src/components/Swap/SwapLoading.tsx b/projects/dex-ui/src/components/Swap/SwapLoading.tsx index 281ce0dcdc..f7207c92e7 100644 --- a/projects/dex-ui/src/components/Swap/SwapLoading.tsx +++ b/projects/dex-ui/src/components/Swap/SwapLoading.tsx @@ -1,75 +1,20 @@ import React from "react"; import { size } from "src/breakpoints"; import styled from "styled-components"; -import { Skeleton } from "../Skeleton"; -import { ArrowButton } from "./ArrowButton"; +import { LoadingTemplate } from "../LoadingTemplate"; export const SwapLoading: React.FC<{}> = () => { return ( <Container> - <LoadingInput> - {"-"} - <SkeletonRow> - <Skeleton width={16} height={16} circle /> - <Skeleton width={48} height={24} rounded /> - </SkeletonRow> - </LoadingInput> - <ArrowContainer> - <ArrowButton onClick={() => {}} /> - </ArrowContainer> - <LoadingInput> - {"-"} - <SkeletonRow> - <Skeleton width={16} height={16} circle /> - <Skeleton width={48} height={24} rounded /> - </SkeletonRow> - </LoadingInput> - <OutputRow> - <Background> - <Skeleton width={90} height={24} /> - </Background> - <Background> - <Skeleton width={70} height={24} /> - </Background> - </OutputRow> - <Background> - <Skeleton height={48} rounded={false} /> - </Background> + <LoadingTemplate.Input /> + <LoadingTemplate.Arrow /> + <LoadingTemplate.Input /> + <LoadingTemplate.OutputDouble /> + <LoadingTemplate.Button /> </Container> ); }; -const Background = styled.div` - display: flex; - background: white; -`; - -const OutputRow = styled.div` - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; -`; - -const LoadingInput = styled.div` - display: flex; - flex-direction: row; - justify-content: space-between; - box-sizing: border-box; - background: #fff; - border: 0.5px solid #d1d5db; - padding: 23.5px 8px; - outline: 0.5px solid black; - // outline-offset: -1px; -`; - -const SkeletonRow = styled.div` - display: flex; - flex-direction: row; - align-items: center; - gap: 8px; -`; - const Container = styled.div` width: 384px; display: flex; @@ -81,24 +26,4 @@ const Container = styled.div` } `; -const ArrowContainer = styled.div` - // border: 1px dashed orange; - display: flex; - flex-direction: row; - justify-content: center; -`; - -const SwapButtonContainer = styled.div` - // border: 1px dashed pink; - display: flex; - flex-direction: column; - justify-content: center; - @media (max-width: ${size.mobile}) { - position: fixed; - width: calc(100% - 24px); - margin-bottom: 0; - bottom: 12px; - } -`; - export default SwapLoading; diff --git a/projects/dex-ui/src/components/Well/LiquidityBox.tsx b/projects/dex-ui/src/components/Well/LiquidityBox.tsx index 7d4d17d04b..75b6f83936 100644 --- a/projects/dex-ui/src/components/Well/LiquidityBox.tsx +++ b/projects/dex-ui/src/components/Well/LiquidityBox.tsx @@ -2,10 +2,9 @@ import React, { useMemo } from "react"; import styled from "styled-components"; import { TokenValue } from "@beanstalk/sdk"; -import { Well } from "@beanstalk/sdk/Wells"; -import { mediaQuery, size } from "src/breakpoints"; -import { BodyCaps, BodyS, BodyXS, LinksButtonText, TextNudge } from "src/components/Typography"; +import { mediaQuery } from "src/breakpoints"; +import { BodyCaps, BodyS, LinksButtonText, TextNudge } from "src/components/Typography"; import { InfoBox } from "src/components/InfoBox"; import { TokenLogo } from "src/components/TokenLogo"; import { Tooltip } from "src/components/Tooltip"; @@ -15,9 +14,12 @@ import { formatUSD } from "src/utils/format"; import { useWellLPTokenPrice } from "src/wells/useWellLPTokenPrice"; import { useLPPositionSummary } from "src/tokens/useLPPositionSummary"; import { useBeanstalkSiloWhitelist } from "src/wells/useBeanstalkSiloWhitelist"; +import { LoadingItem } from "src/components/LoadingItem"; +import { Well } from "@beanstalk/sdk/Wells"; type Props = { well: Well | undefined; + loading: boolean; }; const tooltipProps = { @@ -31,8 +33,8 @@ const tooltipProps = { const displayTV = (value?: TokenValue) => (value?.gt(0) ? value.toHuman("short") : "-"); -export const LiquidityBox: FC<Props> = (props) => { - const well = useMemo(() => props.well, [props.well]); +export const LiquidityBox: FC<Props> = ({ well: _well, loading }) => { + const well = useMemo(() => _well, [_well]); const { getPositionWithWell } = useLPPositionSummary(); const { getIsWhitelisted } = useBeanstalkSiloWhitelist(); @@ -55,19 +57,27 @@ export const LiquidityBox: FC<Props> = (props) => { <InfoBox> <InfoBox.Header> <TextNudge amount={0} mobileAmount={2}> - <BoxHeader>My Liquidity</BoxHeader> + <BoxHeader> + <LoadingItem loading={loading} onLoading={null}> + {"My Liquidity"} + </LoadingItem> + </BoxHeader> </TextNudge> - <BoxHeaderAmount> - <TokenLogo token={well!.lpToken} size={16} mobileSize={16} isLP /> - <TextNudge amount={1.5}>{displayTV(position?.total)}</TextNudge> - </BoxHeaderAmount> + <LoadingItem loading={loading} onLoading={null}> + <BoxHeaderAmount> + <TokenLogo token={well?.lpToken} size={16} mobileSize={16} isLP /> + <TextNudge amount={1.5}>{displayTV(position?.total)}</TextNudge> + </BoxHeaderAmount> + </LoadingItem> </InfoBox.Header> <InfoBox.Body> <InfoBox.Row> - <InfoBox.Key>In my Wallet</InfoBox.Key> + <LoadingItem loading={loading} loadProps={{ height: 24, width: 100 }}> + <InfoBox.Key>In my Wallet</InfoBox.Key> + </LoadingItem> <InfoBox.Value>{displayTV(position?.external)}</InfoBox.Value> </InfoBox.Row> - {isWhitelisted ? ( + {!loading && isWhitelisted ? ( <> <InfoBox.Row> <InfoBox.Key>Deposited in the Silo</InfoBox.Key> @@ -82,32 +92,34 @@ export const LiquidityBox: FC<Props> = (props) => { </InfoBox.Body> <InfoBox.Footer> <USDWrapper> - {isWhitelisted ? ( - <Tooltip - {...tooltipProps} - content={ - <Breakdown> - <BreakdownRow> - {"Wallet: "} - <div>${externalUSD.toHuman("short")}</div> - </BreakdownRow> - - <BreakdownRow> - {"Silo Deposits: "} - <div>${siloUSD.toHuman("short")}</div> - </BreakdownRow> - <BreakdownRow> - {"Farm Balance: "} - <div>${internalUSD.toHuman("short")}</div> - </BreakdownRow> - </Breakdown> - } - > - USD TOTAL: {formatUSD(USDTotal)} - </Tooltip> - ) : ( - <>USD TOTAL: {formatUSD(USDTotal)}</> - )} + <LoadingItem loading={loading} loadProps={{ height: 24, width: 100 }}> + {isWhitelisted ? ( + <Tooltip + {...tooltipProps} + content={ + <Breakdown> + <BreakdownRow> + {"Wallet: "} + <div>${externalUSD.toHuman("short")}</div> + </BreakdownRow> + + <BreakdownRow> + {"Silo Deposits: "} + <div>${siloUSD.toHuman("short")}</div> + </BreakdownRow> + <BreakdownRow> + {"Farm Balance: "} + <div>${internalUSD.toHuman("short")}</div> + </BreakdownRow> + </Breakdown> + } + > + <>USD TOTAL: {formatUSD(USDTotal)}</> + </Tooltip> + ) : ( + <>USD TOTAL: {formatUSD(USDTotal)}</> + )} + </LoadingItem> </USDWrapper> </InfoBox.Footer> </InfoBox> @@ -116,15 +128,12 @@ export const LiquidityBox: FC<Props> = (props) => { const BoxHeader = styled.div` ${BodyCaps} - @media (max-width: ${size.mobile}) { + min-height: 24px; + ${mediaQuery.sm.only} { ${BodyS} } `; -const InfoText = styled.div` - ${BodyS} -`; - const BoxHeaderAmount = styled.div` display: flex; align-items: center; diff --git a/projects/dex-ui/src/pages/Liquidity.tsx b/projects/dex-ui/src/pages/Liquidity.tsx index 77b905e0c1..b63db9f671 100644 --- a/projects/dex-ui/src/pages/Liquidity.tsx +++ b/projects/dex-ui/src/pages/Liquidity.tsx @@ -19,11 +19,14 @@ import { ChevronDown } from "src/components/Icons"; import { mediaQuery, size } from "src/breakpoints"; import { Loading } from "../components/Loading"; import { Error } from "../components/Error"; +import { LoadingItem } from "src/components/LoadingItem"; export const Liquidity = () => { const { address: wellAddress } = useParams<"address">(); - const navigate = useNavigate(); const { well, loading, error } = useWell(wellAddress!); + + const navigate = useNavigate(); + const [wellFunctionName, setWellFunctionName] = useState<string>("This Well's Function"); const [tab, setTab] = useState(0); @@ -67,14 +70,16 @@ export const Liquidity = () => { <Page> <ContentWrapper> <SideBar id="sidebar"> - <Button - secondary - label="← Back To Well Details" - width={"100%"} - margin={"0px"} - onClick={() => navigate(`../wells/${wellAddress}`)} - /> - <LiquidityBox well={well} /> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <Button + secondary + label="← Back To Well Details" + width={"100%"} + margin={"0px"} + onClick={() => navigate(`../wells/${wellAddress}`)} + /> + </LoadingItem> + <LiquidityBox well={well} loading={loading} /> <LearnMoreContainer> <LearnMoreLabel onClick={toggle}> <LearnMoreLine /> @@ -93,28 +98,40 @@ export const Liquidity = () => { <LearnMoreLine /> </LearnMoreLabel> <LearnMoreButtons open={open}> - <LearnYield /> - <LearnWellFunction name={wellFunctionName} /> - <LearnPump /> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnYield /> + </LoadingItem> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnWellFunction name={wellFunctionName} /> + </LoadingItem> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnPump /> + </LoadingItem> </LearnMoreButtons> </LearnMoreContainer> </SideBar> + {/* <div style={{ display: "flex", flexDirection: "row", gap: "2px" }}> */} <CenterBar id="centerbar" ref={scrollRef}> <AddRemoveLiquidityRow gap={0} tabSelected={true}> <Item stretch> <TabButton onClick={() => setTab(0)} active={tab === 0} stretch bold justify hover> - <span>Add Liquidity</span> + <LoadingItem loading={loading} onLoading={<>{""}</>}> + <span>Add Liquidity</span> + </LoadingItem> </TabButton> </Item> <Item stretch> <TabButton onClick={() => setTab(1)} active={tab === 1} stretch bold justify hover> - <span>Remove Liquidity</span> + <LoadingItem loading={loading} onLoading={<>{""}</>}> + <span>Remove Liquidity</span> + </LoadingItem> </TabButton> </Item> </AddRemoveLiquidityRow> {tab === 0 && ( <AddLiquidity - well={well!} + well={well} + loading={loading} slippage={slippage} slippageSettingsClickHandler={slippageSettingsClickHandler} handleSlippageValueChange={handleSlippageValueChange} @@ -129,6 +146,26 @@ export const Liquidity = () => { /> )} </CenterBar> + {/* <CenterBar id="centerbar" ref={scrollRef}> + <AddRemoveLiquidityRow gap={0} tabSelected={true}> + <Item stretch> + <TabButton onClick={() => setTab(0)} active={tab === 0} stretch bold justify hover> + <LoadingItem loading={loading} onLoading={<>{""}</>}> + <span>Add Liquidity</span> + </LoadingItem> + </TabButton> + </Item> + <Item stretch> + <TabButton onClick={() => setTab(1)} active={tab === 1} stretch bold justify hover> + <LoadingItem loading={loading} onLoading={<>{""}</>}> + <span>Remove Liquidity</span> + </LoadingItem> + </TabButton> + </Item> + </AddRemoveLiquidityRow> + <AddLiquidityLoading /> + </CenterBar> */} + {/* </div> */} </ContentWrapper> </Page> ); @@ -244,3 +281,10 @@ const LearnMoreButtons = styled.div<{ open: boolean }>` gap: 16px; } `; + +const EmptyLearnItem = styled.div` + width: 100%; + height: 48px; + border: 0.5px solid #9ca3af; + background: #f9f8f6; +`; diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index 2585499e85..8d1970eef1 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -176,7 +176,7 @@ export const Well = () => { </Item> </LiquiditySwapButtons> <LiquidityBoxContainer> - <LiquidityBox well={well} /> + <LiquidityBox well={well} loading={loading} /> </LiquidityBoxContainer> <LearnMoreContainer> <LearnMoreLabel onClick={toggle}> diff --git a/projects/dex-ui/src/wells/useWellWithParams.tsx b/projects/dex-ui/src/wells/useWellWithParams.tsx new file mode 100644 index 0000000000..b0dd0f5fed --- /dev/null +++ b/projects/dex-ui/src/wells/useWellWithParams.tsx @@ -0,0 +1,7 @@ +import { useParams } from "react-router-dom"; +import { useWell } from "./useWell"; + +export const useWellWithParams = () => { + const { address: wellAddress } = useParams<"address">(); + return useWell(wellAddress || ""); +}; From 05fd678ad7a9c6d3123c6eae1c7740b658afcb6b Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Sat, 18 Nov 2023 20:14:36 -0700 Subject: [PATCH 17/30] clean up --- .../src/components/Liquidity/AddLiquidity.tsx | 52 +++++++++---------- .../src/components/Swap/SwapLoading.tsx | 29 ----------- projects/dex-ui/src/pages/Swap.tsx | 28 ++++++++-- 3 files changed, 50 insertions(+), 59 deletions(-) delete mode 100644 projects/dex-ui/src/components/Swap/SwapLoading.tsx diff --git a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx index 5220b31226..bb56b6d001 100644 --- a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx @@ -16,7 +16,7 @@ import useSdk from "src/utils/sdk/useSdk"; import { useWellReserves } from "src/wells/useWellReserves"; import { Checkbox } from "../Checkbox"; import { size } from "src/breakpoints"; -import { LoadingTemplate } from "../LoadingTemplate"; +import { LoadingTemplate } from "src/components/LoadingTemplate"; type BaseAddLiquidityProps = { slippage: number; @@ -35,32 +35,6 @@ export type AddLiquidityQuote = { estimate: TokenValue; }; -export const AddLiquidityLoading = () => ( - <div> - <LargeGapContainer> - <LoadingTemplate.Flex gap={12}> - <LoadingTemplate.Input /> - <LoadingTemplate.Input /> - </LoadingTemplate.Flex> - <LoadingTemplate.Flex gap={8}> - <LoadingTemplate.OutputSingle size={20} width={285} /> - <LoadingTemplate.OutputSingle size={20} width={145} /> - </LoadingTemplate.Flex> - <ButtonWrapper> - <LoadingTemplate.Button /> - </ButtonWrapper> - </LargeGapContainer> - </div> -); - -export const AddLiquidity = (props: BaseAddLiquidityProps & { well: Well | undefined; loading: boolean }) => { - if (!props.well || props.loading) { - return <AddLiquidityLoading />; - } - - return <AddLiquidityContent {...props} well={props.well} />; -}; - const AddLiquidityContent = ({ well, slippage, slippageSettingsClickHandler, handleSlippageValueChange }: AddLiquidityProps) => { const { address } = useAccount(); const [amounts, setAmounts] = useState<LiquidityAmounts>({}); @@ -443,6 +417,30 @@ const AddLiquidityContent = ({ well, slippage, slippageSettingsClickHandler, han ); }; +export const AddLiquidity = (props: BaseAddLiquidityProps & { well: Well | undefined; loading: boolean }) => { + if (!props.well || props.loading) { + return ( + <div> + <LargeGapContainer> + <LoadingTemplate.Flex gap={12}> + <LoadingTemplate.Input /> + <LoadingTemplate.Input /> + </LoadingTemplate.Flex> + <LoadingTemplate.Flex gap={8}> + <LoadingTemplate.OutputSingle size={20} width={285} /> + <LoadingTemplate.OutputSingle size={20} width={145} /> + </LoadingTemplate.Flex> + <ButtonWrapper> + <LoadingTemplate.Button /> + </ButtonWrapper> + </LargeGapContainer> + </div> + ); + } + + return <AddLiquidityContent {...props} well={props.well} />; +}; + const LargeGapContainer = styled.div` display: flex; flex-direction: column; diff --git a/projects/dex-ui/src/components/Swap/SwapLoading.tsx b/projects/dex-ui/src/components/Swap/SwapLoading.tsx deleted file mode 100644 index f7207c92e7..0000000000 --- a/projects/dex-ui/src/components/Swap/SwapLoading.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react"; -import { size } from "src/breakpoints"; -import styled from "styled-components"; -import { LoadingTemplate } from "../LoadingTemplate"; - -export const SwapLoading: React.FC<{}> = () => { - return ( - <Container> - <LoadingTemplate.Input /> - <LoadingTemplate.Arrow /> - <LoadingTemplate.Input /> - <LoadingTemplate.OutputDouble /> - <LoadingTemplate.Button /> - </Container> - ); -}; - -const Container = styled.div` - width: 384px; - display: flex; - flex-direction: column; - gap: 24px; - @media (max-width: ${size.mobile}) { - width: 100%; - gap: 16px; - } -`; - -export default SwapLoading; diff --git a/projects/dex-ui/src/pages/Swap.tsx b/projects/dex-ui/src/pages/Swap.tsx index b4122477d6..47f36a5a52 100644 --- a/projects/dex-ui/src/pages/Swap.tsx +++ b/projects/dex-ui/src/pages/Swap.tsx @@ -1,9 +1,11 @@ import React from "react"; +import { size } from "src/breakpoints"; +import { LoadingTemplate } from "src/components/LoadingTemplate"; import { Page } from "src/components/Page"; import { Title } from "src/components/PageComponents/Title"; -import SwapLoading from "src/components/Swap/SwapLoading"; import { SwapRoot } from "src/components/Swap/SwapRoot"; import { useWellTokens } from "src/tokens/useWellTokens"; +import styled from "styled-components"; /** * Normally we would not check the loading state at this level, but @@ -11,14 +13,34 @@ import { useWellTokens } from "src/tokens/useWellTokens"; * It's simpler to render a separate loading component here instead of handling it * everywhere else. */ - export const Swap = () => { const { isLoading } = useWellTokens(); return ( <Page> <Title title="Swap" fontWeight={"600"} largeOnMobile /> - {isLoading ? <SwapLoading /> : <SwapRoot />} + {isLoading ? ( + <Container> + <LoadingTemplate.Input /> + <LoadingTemplate.Arrow /> + <LoadingTemplate.Input /> + <LoadingTemplate.OutputDouble /> + <LoadingTemplate.Button /> + </Container> + ) : ( + <SwapRoot /> + )} </Page> ); }; + +const Container = styled.div` + width: 384px; + display: flex; + flex-direction: column; + gap: 24px; + @media (max-width: ${size.mobile}) { + width: 100%; + gap: 16px; + } +`; From 04dcec42b7e77bfa5f679ac4029c39cf218596a2 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Sat, 18 Nov 2023 20:32:58 -0700 Subject: [PATCH 18/30] add Remove Liquidity Loading state + clean up --- .../components/Liquidity/RemoveLiquidity.tsx | 45 +++++++++++++++++-- .../dex-ui/src/components/LoadingTemplate.tsx | 9 ++-- projects/dex-ui/src/pages/Liquidity.tsx | 14 +++--- projects/dex-ui/src/pages/Swap.tsx | 6 --- 4 files changed, 53 insertions(+), 21 deletions(-) diff --git a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx index 1b35b77673..bcabfc212e 100644 --- a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx @@ -21,15 +21,21 @@ import { useWellReserves } from "src/wells/useWellReserves"; import { Checkbox } from "../Checkbox"; import { size } from "src/breakpoints"; import { displayTokenSymbol } from "src/utils/format"; +import { LoadingTemplate } from "../LoadingTemplate"; +import { LoadingItem } from "../LoadingItem"; -type RemoveLiquidityProps = { - well: Well; +type BaseRemoveLiquidityProps = { + // well: Well; slippage: number; slippageSettingsClickHandler: () => void; handleSlippageValueChange: (value: string) => void; }; -export const RemoveLiquidity = ({ well, slippage, slippageSettingsClickHandler, handleSlippageValueChange }: RemoveLiquidityProps) => { +type RemoveLiquidityProps = { + well: Well; +} & BaseRemoveLiquidityProps; + +const RemoveLiquidityContent = ({ well, slippage, slippageSettingsClickHandler, handleSlippageValueChange }: RemoveLiquidityProps) => { const { address } = useAccount(); const [wellLpToken, setWellLpToken] = useState<Token | null>(null); @@ -443,6 +449,39 @@ export const RemoveLiquidity = ({ well, slippage, slippageSettingsClickHandler, ); }; +export const RemoveLiquidity = (props: BaseRemoveLiquidityProps & { well: Well | undefined; loading: boolean }) => { + if (!props.well || props.loading) { + return ( + <LargeGapContainer> + <TokenContainer> + <LoadingTemplate.Input /> + </TokenContainer> + <MediumGapContainer> + <OutputModeSelectorContainer> + <LoadingTemplate.OutputSingle width={100} size={20} mb={4} /> + <LoadingTemplate.Flex row gap={8}> + <LoadingTemplate.Button /> + <LoadingTemplate.Button /> + </LoadingTemplate.Flex> + </OutputModeSelectorContainer> + <TokenContainer> + <LoadingTemplate.Input /> + </TokenContainer> + <TokenContainer> + <LoadingTemplate.Input /> + </TokenContainer> + </MediumGapContainer> + <LoadingTemplate.OutputSingle width={185} /> + <ButtonWrapper> + <LoadingTemplate.Button /> + </ButtonWrapper> + </LargeGapContainer> + ); + } + + return <RemoveLiquidityContent {...props} well={props.well} />; +}; + type ReadOnlyRowProps = { selected?: boolean; }; diff --git a/projects/dex-ui/src/components/LoadingTemplate.tsx b/projects/dex-ui/src/components/LoadingTemplate.tsx index 5182bcdbc2..c2f69bad2d 100644 --- a/projects/dex-ui/src/components/LoadingTemplate.tsx +++ b/projects/dex-ui/src/components/LoadingTemplate.tsx @@ -38,8 +38,8 @@ LoadingTemplate.Button = () => ( </Background> ); -LoadingTemplate.OutputSingle = ({ size, width }: { size?: number; width?: number }) => ( - <Background width={width || 90}> +LoadingTemplate.OutputSingle = ({ size, width, mb }: { size?: number; width?: number; mb?: number }) => ( + <Background width={width || 90} mb={mb}> <Skeleton width={width || 90} height={size ? size : 24} /> </Background> ); @@ -52,11 +52,12 @@ LoadingTemplate.Flex = styled.div<{ row?: boolean; gap?: number }>` `} `; -const Background = styled.div<{ width?: number }>` +const Background = styled.div<{ width?: number; mb?: number }>` display: flex; background: white; ${(props) => ` - width: ${props.width ? `${props.width}px` : "100"}; + width: ${props.width ? `${props.width}px` : "100%"}; + margin-bottom: ${props.mb ? props.mb : 0}px; `} `; diff --git a/projects/dex-ui/src/pages/Liquidity.tsx b/projects/dex-ui/src/pages/Liquidity.tsx index b63db9f671..09143d2b9f 100644 --- a/projects/dex-ui/src/pages/Liquidity.tsx +++ b/projects/dex-ui/src/pages/Liquidity.tsx @@ -17,8 +17,7 @@ import { BodyXS, TextNudge } from "src/components/Typography"; import { ImageButton } from "src/components/ImageButton"; import { ChevronDown } from "src/components/Icons"; import { mediaQuery, size } from "src/breakpoints"; -import { Loading } from "../components/Loading"; -import { Error } from "../components/Error"; +import { Error } from "src/components/Error"; import { LoadingItem } from "src/components/LoadingItem"; export const Liquidity = () => { @@ -60,8 +59,6 @@ export const Liquidity = () => { run(); }, [well]); - if (loading) return <Loading spinnerOnly />; - if (error) { return <Error message={error?.message} errorOnly />; } @@ -139,7 +136,8 @@ export const Liquidity = () => { )} {tab === 1 && ( <RemoveLiquidity - well={well!} + well={well} + loading={loading} slippage={slippage} slippageSettingsClickHandler={slippageSettingsClickHandler} handleSlippageValueChange={handleSlippageValueChange} @@ -163,9 +161,9 @@ export const Liquidity = () => { </TabButton> </Item> </AddRemoveLiquidityRow> - <AddLiquidityLoading /> - </CenterBar> */} - {/* </div> */} + <RemoveLiquidityLoading /> + </CenterBar> + </div> */} </ContentWrapper> </Page> ); diff --git a/projects/dex-ui/src/pages/Swap.tsx b/projects/dex-ui/src/pages/Swap.tsx index 47f36a5a52..0bf5c49239 100644 --- a/projects/dex-ui/src/pages/Swap.tsx +++ b/projects/dex-ui/src/pages/Swap.tsx @@ -7,12 +7,6 @@ import { SwapRoot } from "src/components/Swap/SwapRoot"; import { useWellTokens } from "src/tokens/useWellTokens"; import styled from "styled-components"; -/** - * Normally we would not check the loading state at this level, but - * if we don't it'll cause errors in the SwapRoot component & it's children. - * It's simpler to render a separate loading component here instead of handling it - * everywhere else. - */ export const Swap = () => { const { isLoading } = useWellTokens(); From 9a05089a62345e7e401a2e7eb2ea89d8d78d9fad Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Mon, 20 Nov 2023 12:50:25 -0700 Subject: [PATCH 19/30] create & modify loading components --- .../dex-ui/src/components/LoadingItem.tsx | 2 +- .../dex-ui/src/components/LoadingTemplate.tsx | 115 ++++++++++++++++-- projects/dex-ui/src/components/Skeleton.tsx | 15 ++- 3 files changed, 117 insertions(+), 15 deletions(-) diff --git a/projects/dex-ui/src/components/LoadingItem.tsx b/projects/dex-ui/src/components/LoadingItem.tsx index c02cc29280..22f228c790 100644 --- a/projects/dex-ui/src/components/LoadingItem.tsx +++ b/projects/dex-ui/src/components/LoadingItem.tsx @@ -3,7 +3,7 @@ import { Skeleton, SkeletonProps } from "./Skeleton"; type BaseProps = { loading?: boolean; - children: React.ReactNode; + children: React.ReactNode | React.ReactNode[]; }; type WithOnLoadingProps = BaseProps & { diff --git a/projects/dex-ui/src/components/LoadingTemplate.tsx b/projects/dex-ui/src/components/LoadingTemplate.tsx index c2f69bad2d..cf063337f4 100644 --- a/projects/dex-ui/src/components/LoadingTemplate.tsx +++ b/projects/dex-ui/src/components/LoadingTemplate.tsx @@ -3,7 +3,28 @@ import styled from "styled-components"; import { Skeleton } from "./Skeleton"; import { ArrowButton } from "./Swap/ArrowButton"; -export function LoadingTemplate() {} +type MarginProps = { + left?: number; + right?: number; + bottom?: number; + top?: number; +}; + +type DimensionProps = { + height?: number; + width?: number; +}; + +const getMarginStyles = (props: { margin?: MarginProps }) => ` + margin-bottom: ${props.margin?.bottom ? props.margin.bottom : 0}px; + margin-top: ${props.margin?.top ? props.margin.top : 0}px; + margin-right: ${props.margin?.right ? props.margin.right : 0}px; + margin-left: ${props.margin?.left ? props.margin.left : 0}px; +`; + +export function LoadingTemplate(props: { children: React.ReactNode }) { + return <>{props.children}</>; +} LoadingTemplate.Input = () => ( <LoadingInputItem> @@ -21,43 +42,97 @@ LoadingTemplate.Arrow = () => ( </ArrowContainer> ); -LoadingTemplate.OutputDouble = ({ size }: { size?: number }) => ( +LoadingTemplate.OutputDouble = ({ size, height }: { size?: number; height?: number }) => ( <OutputRow> - <Background> + <Background width={90} height={height}> <Skeleton width={90} height={size ? size : 24} /> </Background> - <Background> + <Background width={70} height={height}> <Skeleton width={70} height={size ? size : 24} /> </Background> </OutputRow> ); +LoadingTemplate.LabelValue = ({ height, labelWidth, valueWidth }: { height?: number; labelWidth?: number; valueWidth?: number }) => ( + <OutputRow> + <Background width={labelWidth}> + <Skeleton width={labelWidth} height={height || 24} /> + </Background> + <Background width={valueWidth}> + <Skeleton width={valueWidth} height={height || 24} /> + </Background> + </OutputRow> +); + LoadingTemplate.Button = () => ( <Background> <Skeleton height={48} /> </Background> ); +LoadingTemplate.Item = ({ height, width, margin }: DimensionProps & { margin?: MarginProps }) => ( + <Background width={width || 90} margin={margin} height={height}> + <Skeleton width={width || 90} height={height || 24} /> + </Background> +); + LoadingTemplate.OutputSingle = ({ size, width, mb }: { size?: number; width?: number; mb?: number }) => ( - <Background width={width || 90} mb={mb}> - <Skeleton width={width || 90} height={size ? size : 24} /> + <Background width={width || 90} margin={{ bottom: mb }}> + <Skeleton width={width || 90} height={size || 24} /> </Background> ); -LoadingTemplate.Flex = styled.div<{ row?: boolean; gap?: number }>` +LoadingTemplate.Flex = (props: FlexProps & { children: React.ReactNode }) => <FlexBox {...props} />; + +LoadingTemplate.TokenLogo = ({ count = 1, size }: { count?: number; size: number }) => { + if (count === 0) return null; + + if (count === 1) { + return ( + <Background height={size} width={size} circle> + <Skeleton height={size} width={size} circle /> + </Background> + ); + } + + return ( + <FlexBox row> + {Array(count) + .fill(null) + .map((_, i) => ( + <Background height={size} width={size} circle key={`Token-Logo-skeleton-${i}`} margin={{ left: i === 0 ? 0 : -8 }}> + <Skeleton height={size} width={size} circle /> + </Background> + ))} + </FlexBox> + ); +}; + +type FlexProps = { + row?: boolean; + gap?: number; + alignItems?: string; + justifyContent?: string; +}; + +const FlexBox = styled.div<FlexProps>` display: flex; ${(props) => ` - flex-direction: ${props.row ? "row" : "column"}; - gap: ${props.gap || 0}px; - `} + flex-direction: ${props.row ? "row" : "column"}; + gap: ${props.gap || 0}px; + ${props.alignItems && `align-items: ${props.alignItems};`} + ${props.justifyContent && `justify-content: ${props.justifyContent};`} + `} `; -const Background = styled.div<{ width?: number; mb?: number }>` +const Background = styled.div<{ width?: number; height?: number; margin?: MarginProps; circle?: boolean; rounded?: boolean }>` display: flex; background: white; ${(props) => ` + height: ${props.height ? `${props.height}px` : "100%"}; width: ${props.width ? `${props.width}px` : "100%"}; - margin-bottom: ${props.mb ? props.mb : 0}px; + border-radius: ${props.circle ? "50%" : props.rounded === true ? "4px" : "0px"}; + ${getMarginStyles(props)} `} `; @@ -77,7 +152,6 @@ const LoadingInputItem = styled.div` border: 0.5px solid #d1d5db; padding: 23.5px 8px; outline: 0.5px solid black; - // outline-offset: -1px; `; const SkeletonRow = styled.div` @@ -93,3 +167,18 @@ const ArrowContainer = styled.div` flex-direction: row; justify-content: center; `; + +type Responsive<T> = + | { + sm?: T; + md?: T; + lg?: T; + } + | T; + +type FlexingProps = { + height: number; + width: number; + alignItems?: string; + justifyContent?: string; +}; diff --git a/projects/dex-ui/src/components/Skeleton.tsx b/projects/dex-ui/src/components/Skeleton.tsx index 9563f6632c..94812e2c8d 100644 --- a/projects/dex-ui/src/components/Skeleton.tsx +++ b/projects/dex-ui/src/components/Skeleton.tsx @@ -2,6 +2,13 @@ import React from "react"; import styled, { css, keyframes } from "styled-components"; +type MarginProps = { + bottom?: number; + top?: number; + left?: number; + right?: number; +}; + export type SkeletonProps = { height: number; width?: number; @@ -11,6 +18,8 @@ export type SkeletonProps = { rounded?: boolean; // defaults to pulse shimmer?: boolean; + // margin: + margin?: MarginProps; }; export const Skeleton: React.FC<SkeletonProps> = (props) => { @@ -47,7 +56,11 @@ const SkeletonBase = css<SkeletonProps>` ${(props) => ` height: ${props.height ? `${props.height}px` : "100%"}; width: ${props.width ? `${props.width}px` : "100%"}; - border-radius: ${props.circle ? "50%" : props.rounded === true ? `4px` : "0px"}; + border-radius: ${props.circle ? "50%" : props.rounded === true ? "4px" : "0px"}; + margin-top: ${props.margin?.top || 0}px; + margin-bottom: ${props.margin?.bottom || 0}px; + margin-right: ${props.margin?.right || 0}px; + margin-left: ${props.margin?.left || 0}px; `} `; From e36d5fc20a17a817f5779e690f6393503d225751 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Mon, 20 Nov 2023 12:51:59 -0700 Subject: [PATCH 20/30] clean up liquidity + swap components w/ loading --- .../src/components/Liquidity/AddLiquidity.tsx | 2 +- .../components/Liquidity/RemoveLiquidity.tsx | 4 +-- projects/dex-ui/src/pages/Liquidity.tsx | 32 +++---------------- projects/dex-ui/src/pages/Swap.tsx | 6 ++-- 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx index bb56b6d001..2f1e7de0b9 100644 --- a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx @@ -417,7 +417,7 @@ const AddLiquidityContent = ({ well, slippage, slippageSettingsClickHandler, han ); }; -export const AddLiquidity = (props: BaseAddLiquidityProps & { well: Well | undefined; loading: boolean }) => { +export const AddLiquidity: React.FC<BaseAddLiquidityProps & { well: Well | undefined; loading: boolean }> = (props) => { if (!props.well || props.loading) { return ( <div> diff --git a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx index bcabfc212e..fbe3502d0a 100644 --- a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx @@ -22,10 +22,8 @@ import { Checkbox } from "../Checkbox"; import { size } from "src/breakpoints"; import { displayTokenSymbol } from "src/utils/format"; import { LoadingTemplate } from "../LoadingTemplate"; -import { LoadingItem } from "../LoadingItem"; type BaseRemoveLiquidityProps = { - // well: Well; slippage: number; slippageSettingsClickHandler: () => void; handleSlippageValueChange: (value: string) => void; @@ -449,7 +447,7 @@ const RemoveLiquidityContent = ({ well, slippage, slippageSettingsClickHandler, ); }; -export const RemoveLiquidity = (props: BaseRemoveLiquidityProps & { well: Well | undefined; loading: boolean }) => { +export const RemoveLiquidity: React.FC<{ well: Well | undefined; loading: boolean } & BaseRemoveLiquidityProps> = (props) => { if (!props.well || props.loading) { return ( <LargeGapContainer> diff --git a/projects/dex-ui/src/pages/Liquidity.tsx b/projects/dex-ui/src/pages/Liquidity.tsx index 09143d2b9f..50f29b6a45 100644 --- a/projects/dex-ui/src/pages/Liquidity.tsx +++ b/projects/dex-ui/src/pages/Liquidity.tsx @@ -1,6 +1,5 @@ import React, { useCallback, useEffect, useRef, useState } from "react"; -import { useNavigate, useParams } from "react-router-dom"; -import { useWell } from "src/wells/useWell"; +import { useNavigate } from "react-router-dom"; import styled from "styled-components"; import { Page } from "src/components/Page"; import { LiquidityBox } from "src/components/Well/LiquidityBox"; @@ -19,11 +18,10 @@ import { ChevronDown } from "src/components/Icons"; import { mediaQuery, size } from "src/breakpoints"; import { Error } from "src/components/Error"; import { LoadingItem } from "src/components/LoadingItem"; +import { useWellWithParams } from "src/wells/useWellWithParams"; export const Liquidity = () => { - const { address: wellAddress } = useParams<"address">(); - const { well, loading, error } = useWell(wellAddress!); - + const { well, loading, error } = useWellWithParams(); const navigate = useNavigate(); const [wellFunctionName, setWellFunctionName] = useState<string>("This Well's Function"); @@ -73,7 +71,7 @@ export const Liquidity = () => { label="← Back To Well Details" width={"100%"} margin={"0px"} - onClick={() => navigate(`../wells/${wellAddress}`)} + onClick={() => navigate(`../wells/${well?.address || ""}`)} /> </LoadingItem> <LiquidityBox well={well} loading={loading} /> @@ -107,7 +105,7 @@ export const Liquidity = () => { </LearnMoreButtons> </LearnMoreContainer> </SideBar> - {/* <div style={{ display: "flex", flexDirection: "row", gap: "2px" }}> */} + <CenterBar id="centerbar" ref={scrollRef}> <AddRemoveLiquidityRow gap={0} tabSelected={true}> <Item stretch> @@ -144,26 +142,6 @@ export const Liquidity = () => { /> )} </CenterBar> - {/* <CenterBar id="centerbar" ref={scrollRef}> - <AddRemoveLiquidityRow gap={0} tabSelected={true}> - <Item stretch> - <TabButton onClick={() => setTab(0)} active={tab === 0} stretch bold justify hover> - <LoadingItem loading={loading} onLoading={<>{""}</>}> - <span>Add Liquidity</span> - </LoadingItem> - </TabButton> - </Item> - <Item stretch> - <TabButton onClick={() => setTab(1)} active={tab === 1} stretch bold justify hover> - <LoadingItem loading={loading} onLoading={<>{""}</>}> - <span>Remove Liquidity</span> - </LoadingItem> - </TabButton> - </Item> - </AddRemoveLiquidityRow> - <RemoveLiquidityLoading /> - </CenterBar> - </div> */} </ContentWrapper> </Page> ); diff --git a/projects/dex-ui/src/pages/Swap.tsx b/projects/dex-ui/src/pages/Swap.tsx index 0bf5c49239..4e29ab19a3 100644 --- a/projects/dex-ui/src/pages/Swap.tsx +++ b/projects/dex-ui/src/pages/Swap.tsx @@ -8,12 +8,14 @@ import { useWellTokens } from "src/tokens/useWellTokens"; import styled from "styled-components"; export const Swap = () => { - const { isLoading } = useWellTokens(); + const { isLoading, data } = useWellTokens(); + + const loading = !data || isLoading || !data.length; return ( <Page> <Title title="Swap" fontWeight={"600"} largeOnMobile /> - {isLoading ? ( + {loading ? ( <Container> <LoadingTemplate.Input /> <LoadingTemplate.Arrow /> From a1f56608920e435f48d8dbc072e241d917c878b6 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Mon, 20 Nov 2023 12:52:56 -0700 Subject: [PATCH 21/30] well page loading minus chart & table --- projects/dex-ui/src/pages/Well.tsx | 157 ++++++++++++++++++++++------- 1 file changed, 120 insertions(+), 37 deletions(-) diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index 8d1970eef1..a7b6a86abd 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -1,6 +1,5 @@ import React, { ReactNode, useCallback, useEffect, useRef, useState } from "react"; -import { useNavigate, useParams } from "react-router-dom"; -import { useWell } from "src/wells/useWell"; +import { useNavigate } from "react-router-dom"; import { getPrice } from "src/utils/price/usePrice"; import useSdk from "src/utils/sdk/useSdk"; import { TokenValue } from "@beanstalk/sdk"; @@ -25,12 +24,15 @@ import { ImageButton } from "src/components/ImageButton"; import { mediaQuery } from "src/breakpoints"; import { Loading } from "src/components/Loading"; import { Error } from "../components/Error"; +import { useWellWithParams } from "src/wells/useWellWithParams"; +import { LoadingItem } from "src/components/LoadingItem"; +import { LoadingTemplate } from "src/components/LoadingTemplate"; export const Well = () => { + const { well, loading: isLoading, error } = useWellWithParams(); + const sdk = useSdk(); const navigate = useNavigate(); - const { address: wellAddress } = useParams<"address">(); - const { well, loading, error } = useWell(wellAddress!); const [prices, setPrices] = useState<(TokenValue | null)[]>([]); const [wellFunctionName, setWellFunctionName] = useState<string | undefined>("-"); @@ -121,45 +123,62 @@ export const Well = () => { ); // Code above detects if the component with the Add/Remove Liq + Swap buttons is sticky - if (loading) return <Loading spinnerOnly />; + if (isLoading) return <Loading spinnerOnly />; if (error) return <Error message={error?.message} errorOnly />; + const loading = true; + return ( <Page> <ContentWrapper> <StyledTitle title={title} parent={{ title: "Liquidity", path: "/wells" }} fontWeight="550" center /> <HeaderContainer> - <Item> - <Header> - <TokenLogos>{logos}</TokenLogos> - <TextNudge amount={10} mobileAmount={-2}> - {title} - </TextNudge> - </Header> - </Item> - <StyledItem column stretch> - <FunctionName>{wellFunctionName}</FunctionName> - <Fee>0.00% Trading Fee</Fee> - </StyledItem> + <LoadingItem loading={loading} onLoading={<SkeletonHeader />}> + <Item> + <Header> + <TokenLogos>{logos}</TokenLogos> + <TextNudge amount={10} mobileAmount={-2}> + {title} + </TextNudge> + </Header> + </Item> + <StyledItem column stretch> + <FunctionName>{wellFunctionName}</FunctionName> + <Fee>0.00% Trading Fee</Fee> + </StyledItem> + </LoadingItem> </HeaderContainer> + {/* + * Reserves + */} <ReservesContainer> - <Reserves reserves={reserves} /> + <LoadingItem loading={loading} onLoading={<SkeletonReserves />}> + <Reserves reserves={reserves} /> + </LoadingItem> </ReservesContainer> + {/* + * Chart Section + */} <ChartContainer> <ChartSection well={well!} /> </ChartContainer> + {/* + * Chart Type Button Selectors + */} <ActivityOtherButtons gap={24} mobileGap={"0px"}> - <Item stretch> - <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} stretch justify bold hover> - Activity - </TabButton> - </Item> - <Item stretch> - <TabButton onClick={(e) => showTab(e, 1)} active={tab === 1} stretch justify bold hover> - Contract Addresses - </TabButton> - </Item> + <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> + <Item stretch> + <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} stretch justify bold hover> + Activity + </TabButton> + </Item> + <Item stretch> + <TabButton onClick={(e) => showTab(e, 1)} active={tab === 1} stretch justify bold hover> + Contract Addresses + </TabButton> + </Item> + </LoadingItem> </ActivityOtherButtons> <BottomContainer> {tab === 0 && <WellHistory well={well!} tokenPrices={prices} reservesUSD={totalUSD} />} @@ -167,13 +186,18 @@ export const Well = () => { </BottomContainer> <ColumnBreak /> <StickyDetector ref={containerRef} /> + {/* + * Liquidity Swap Button + */} <LiquiditySwapButtons gap={24} mobileGap={isSticky ? "0px" : "8px"} sticky={isSticky}> - <Item stretch> - <Button secondary label="Add/Rm Liquidity" onClick={goLiquidity} /> - </Item> - <Item stretch> - <Button label="Swap" onClick={goSwap} /> - </Item> + <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> + <Item stretch> + <Button secondary label="Add/Rm Liquidity" onClick={goLiquidity} /> + </Item> + <Item stretch> + <Button label="Swap" onClick={goSwap} /> + </Item> + </LoadingItem> </LiquiditySwapButtons> <LiquidityBoxContainer> <LiquidityBox well={well} loading={loading} /> @@ -196,9 +220,15 @@ export const Well = () => { <LearnMoreLine /> </LearnMoreLabel> <LearnMoreButtons open={open}> - <LearnYield /> - <LearnWellFunction name={wellFunctionName || "A Well Function"} /> - <LearnPump /> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnYield /> + </LoadingItem> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnWellFunction name={wellFunctionName || "A Well Function"} /> + </LoadingItem> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnPump /> + </LoadingItem> </LearnMoreButtons> </LearnMoreContainer> </ContentWrapper> @@ -448,3 +478,56 @@ const ColumnBreak = styled.div` width: 0px; } `; + +const EmptyLearnItem = styled.div` + width: 100%; + height: 48px; + border: 0.5px solid #9ca3af; + background: #f9f8f6; +`; + +const SkeletonHeader: React.FC<{}> = () => ( + <> + <Item> + <Header> + <LoadingTemplate.TokenLogo count={2} size={48} /> + <LoadingTemplate.Item width={150} height={32} margin={{ top: 8 }} /> + </Header> + </Item> + <StyledItem column stretch> + <LoadingTemplate.Item height={24} width={150} /> + <LoadingTemplate.Item height={20} width={100} margin={{ top: 4 }} /> + </StyledItem> + </> +); + +const SkeletonReserves: React.FC<{}> = () => { + return ( + <Row gap={24}> + {Array(2) + .fill(null) + .map((_, i) => ( + <LoadingTemplate key={`ReservesLoading-${i}`}> + <LoadingTemplate.Flex gap={4}> + <LoadingTemplate.Item width={75} height={20} /> + <LoadingTemplate.Flex gap={4} row alignItems="flex-end"> + <LoadingTemplate.Item width={100} height={24} /> + <LoadingTemplate.Item width={70} height={24} /> + </LoadingTemplate.Flex> + </LoadingTemplate.Flex> + </LoadingTemplate> + ))} + </Row> + ); +}; + +const SkeletonButtonsRow: React.FC<{}> = () => ( + <> + <Item stretch> + <LoadingTemplate.Button /> + </Item> + <Item stretch> + <LoadingTemplate.Button /> + </Item> + </> +); From 97852a943adb7e9e3cb940dadbeae242ba987a85 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Mon, 20 Nov 2023 13:56:00 -0700 Subject: [PATCH 22/30] add table loading state --- .../dex-ui/src/components/LoadingTemplate.tsx | 6 +- .../components/Well/Activity/WellHistory.tsx | 189 +++++++++++------- .../src/components/Well/OtherSection.tsx | 87 ++++++-- 3 files changed, 190 insertions(+), 92 deletions(-) diff --git a/projects/dex-ui/src/components/LoadingTemplate.tsx b/projects/dex-ui/src/components/LoadingTemplate.tsx index cf063337f4..86324e180f 100644 --- a/projects/dex-ui/src/components/LoadingTemplate.tsx +++ b/projects/dex-ui/src/components/LoadingTemplate.tsx @@ -22,8 +22,8 @@ const getMarginStyles = (props: { margin?: MarginProps }) => ` margin-left: ${props.margin?.left ? props.margin.left : 0}px; `; -export function LoadingTemplate(props: { children: React.ReactNode }) { - return <>{props.children}</>; +export function LoadingTemplate(props: FlexProps & { children: React.ReactNode }) { + return <FlexBox {...props} />; } LoadingTemplate.Input = () => ( @@ -113,6 +113,7 @@ type FlexProps = { gap?: number; alignItems?: string; justifyContent?: string; + width?: string | number; }; const FlexBox = styled.div<FlexProps>` @@ -122,6 +123,7 @@ const FlexBox = styled.div<FlexProps>` gap: ${props.gap || 0}px; ${props.alignItems && `align-items: ${props.alignItems};`} ${props.justifyContent && `justify-content: ${props.justifyContent};`} + ${props.width && `width: ${typeof props.width === "string" ? props.width : `${props.width}px`}`} `} `; diff --git a/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx b/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx index 05ee8ad726..4a93a41c36 100644 --- a/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx +++ b/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx @@ -9,15 +9,17 @@ import { TokenValue } from "@beanstalk/sdk"; import { TabButton } from "src/components/TabButton"; import { size } from "src/breakpoints"; import { useTokenSupply } from "src/tokens/useTokenSupply"; +import { LoadingTemplate } from "src/components/LoadingTemplate"; type WellHistoryProps = { well: Well; tokenPrices: (TokenValue | null)[]; reservesUSD: TokenValue; + loading?: boolean; }; -export const WellHistory = ({ well, tokenPrices, reservesUSD }: WellHistoryProps) => { - const { data: events, isLoading: loading } = useWellHistory(well); +export const WellHistory = ({ well, tokenPrices, reservesUSD, loading: _loading }: WellHistoryProps) => { + const { data: events, isLoading } = useWellHistory(well); const [filter, setFilter] = useState<EVENT_TYPE | null>(null); const eventsPerPage = 10; const totalEvents = events?.length || 0; @@ -36,89 +38,122 @@ export const WellHistory = ({ well, tokenPrices, reservesUSD }: WellHistoryProps (e, index): any => index >= newestEventOnPage && index <= oldestEventOnPage && renderEvent(e, well, tokenPrices, lpTokenPrice) ); + const loading = isLoading || _loading; + return ( <WellHistoryContainer> - {!loading && ( - <> - {/* <div> + {/* <div> <button onClick={() => setFilter(null)}>All</button> <button onClick={() => setFilter(EVENT_TYPE.SWAP)}>Swaps</button> <button onClick={() => setFilter(EVENT_TYPE.ADD_LIQUIDITY)}>Deposits</button> <button onClick={() => setFilter(EVENT_TYPE.REMOVE_LIQUIDITY)}>Withdraws</button> </div> */} - <Table width="100%"> - <THead> - <Row> - <Th>Action</Th> - <DesktopOnlyTh align={"right"}>Value</DesktopOnlyTh> - <DesktopOnlyTh align={"right"}>Description</DesktopOnlyTh> - <Th align={"right"}>Time</Th> - </Row> - </THead> - <TBody> - {eventRows.length ? ( - eventRows - ) : ( - <> - <NoEventsRow colSpan={4}> - <NoEventsData>No events to show</NoEventsData> - </NoEventsRow> - </> - )} - {isNonEmptyWell ? ( - <> - <MobilePageSelector> - <PageSelector colSpan={2}> - <SelectorContainer> - <StyledTabButton - active - pageLimit={currentPage === 1} - onClick={() => setCurrentPage(currentPage > 1 ? currentPage - 1 : 1)} - > - ← - </StyledTabButton> - {`Page ${currentPage} of ${totalPages}`} - <StyledTabButton - active - pageLimit={currentPage === totalPages} - onClick={() => setCurrentPage(currentPage < totalPages ? currentPage + 1 : totalPages)} - > - → - </StyledTabButton> - </SelectorContainer> - </PageSelector> - </MobilePageSelector> - <DesktopPageSelector> - <PageSelector colSpan={4}> - <SelectorContainer> - <StyledTabButton - active - pageLimit={currentPage === 1} - onClick={() => setCurrentPage(currentPage > 1 ? currentPage - 1 : 1)} - > - ← - </StyledTabButton> - {`Page ${currentPage} of ${totalPages}`} - <StyledTabButton - active - pageLimit={currentPage === totalPages} - onClick={() => setCurrentPage(currentPage < totalPages ? currentPage + 1 : totalPages)} - > - → - </StyledTabButton> - </SelectorContainer> - </PageSelector> - </DesktopPageSelector> - </> - ) : null} - </TBody> - </Table> - </> - )} + <Table width="100%"> + <THead> + <Row> + <Th>{loading ? "" : "Action"}</Th> + <DesktopOnlyTh align={"right"}>{loading ? "" : "Value"}</DesktopOnlyTh> + <DesktopOnlyTh align={"right"}>{loading ? "" : "Description"}</DesktopOnlyTh> + <Th align={"right"}>{loading ? "" : "Time"}</Th> + </Row> + </THead> + <TBody> + {loading ? ( + <> + {Array(10) + .fill(null) + .map((_, rowIdx) => ( + <LoadingRow key={`table-row-${rowIdx}`}> + <Td> + <LoadingTemplate.Flex> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate.Flex> + </Td> + <DesktopOnlyTd align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </DesktopOnlyTd> + <DesktopOnlyTd align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </DesktopOnlyTd> + <Td align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </Td> + </LoadingRow> + ))} + </> + ) : eventRows.length ? ( + eventRows + ) : ( + <> + <NoEventsRow colSpan={4}> + <NoEventsData>No events to show</NoEventsData> + </NoEventsRow> + </> + )} + {!loading && isNonEmptyWell ? ( + <> + <MobilePageSelector> + <PageSelector colSpan={2}> + <SelectorContainer> + <StyledTabButton + active + pageLimit={currentPage === 1} + onClick={() => setCurrentPage(currentPage > 1 ? currentPage - 1 : 1)} + > + ← + </StyledTabButton> + {`Page ${currentPage} of ${totalPages}`} + <StyledTabButton + active + pageLimit={currentPage === totalPages} + onClick={() => setCurrentPage(currentPage < totalPages ? currentPage + 1 : totalPages)} + > + → + </StyledTabButton> + </SelectorContainer> + </PageSelector> + </MobilePageSelector> + <DesktopPageSelector> + <PageSelector colSpan={4}> + <SelectorContainer> + <StyledTabButton + active + pageLimit={currentPage === 1} + onClick={() => setCurrentPage(currentPage > 1 ? currentPage - 1 : 1)} + > + ← + </StyledTabButton> + {`Page ${currentPage} of ${totalPages}`} + <StyledTabButton + active + pageLimit={currentPage === totalPages} + onClick={() => setCurrentPage(currentPage < totalPages ? currentPage + 1 : totalPages)} + > + → + </StyledTabButton> + </SelectorContainer> + </PageSelector> + </DesktopPageSelector> + </> + ) : null} + </TBody> + </Table> </WellHistoryContainer> ); }; +const DesktopOnlyTd = styled(Td)` + @media (max-width: ${size.mobile}) { + display: none; + } +`; + const WellHistoryContainer = styled.div` display: flex; `; @@ -179,3 +214,9 @@ const NoEventsData = styled.div` font-size: 14px; } `; + +const LoadingRow = styled(Row)` + :hover { + cursor: default; + } +`; diff --git a/projects/dex-ui/src/components/Well/OtherSection.tsx b/projects/dex-ui/src/components/Well/OtherSection.tsx index 85567ec2b2..0918d985ce 100644 --- a/projects/dex-ui/src/components/Well/OtherSection.tsx +++ b/projects/dex-ui/src/components/Well/OtherSection.tsx @@ -1,23 +1,23 @@ import React from "react"; import { FC } from "src/types"; -import { Row, TBody, THead, Table, Th, Td } from "./Table"; +import { Row, TBody, THead, Table, Td, Th } from "./Table"; import { Well } from "@beanstalk/sdk/Wells"; import styled from "styled-components"; import { size } from "src/breakpoints"; +import { displayTokenSymbol } from "src/utils/format"; +import { Token } from "@beanstalk/sdk"; +import { Skeleton } from "../Skeleton"; -type Props = { - well: Well; -}; - -export const OtherSection: FC<Props> = ({ well }) => { +type Props = { well: Well }; - const tableItems = [ - {name: "Multi Flow Pump", address: "0xBA510f10E3095B83a0F33aa9ad2544E22570a87C"}, - {name: "Constant Product 2", address: "0xBA510C20FD2c52E4cb0d23CFC3cCD092F9165a6E"}, - {name: "Well Implementation", address: "0xBA510e11eEb387fad877812108a3406CA3f43a4B"}, - {name: "Aquifer", address: "0xBA51AAAA95aeEFc1292515b36D86C51dC7877773"} - ]; +const tableItems = [ + { name: "Multi Flow Pump", address: "0xBA510f10E3095B83a0F33aa9ad2544E22570a87C" }, + { name: "Constant Product 2", address: "0xBA510C20FD2c52E4cb0d23CFC3cCD092F9165a6E" }, + { name: "Well Implementation", address: "0xBA510e11eEb387fad877812108a3406CA3f43a4B" }, + { name: "Aquifer", address: "0xBA51AAAA95aeEFc1292515b36D86C51dC7877773" } +]; +const OtherSectionContent: FC<Props> = ({ well }) => { return ( <div> <Table width="100%"> @@ -44,7 +44,7 @@ export const OtherSection: FC<Props> = ({ well }) => { </Row> <Row> <Td> - <Detail>Well LP Token - {well.lpToken?.symbol}</Detail> + <Detail>Well LP Token - {displayTokenSymbol(well.lpToken as Token)}</Detail> </Td> <DesktopTd> <Link href={`https://etherscan.io/address/${well.address}`}>{well.address}</Link> @@ -55,19 +55,27 @@ export const OtherSection: FC<Props> = ({ well }) => { </Link> </MobileTd> </Row> - {well.tokens!.map(function (token, index) { + {well.tokens?.map(function (token, index) { return ( <Row key={token.address}> <Td> <Detail>{`Token ${index + 1} - ${token.symbol}`}</Detail> </Td> <DesktopTd> - <Link href={token ? `https://etherscan.io/address/${token.address}` : `https://etherscan.io/`} target="_blank" rel="noopener noreferrer"> + <Link + href={token ? `https://etherscan.io/address/${token.address}` : `https://etherscan.io/`} + target="_blank" + rel="noopener noreferrer" + > {token.address || `-`} </Link> </DesktopTd> <MobileTd align={"right"}> - <Link href={token ? `https://etherscan.io/address/${token.address}` : `https://etherscan.io/`} target="_blank" rel="noopener noreferrer"> + <Link + href={token ? `https://etherscan.io/address/${token.address}` : `https://etherscan.io/`} + target="_blank" + rel="noopener noreferrer" + > {token.address.substr(0, 5) + "..." + token.address.substr(token.address.length - 5) || `-`} </Link> </MobileTd> @@ -97,6 +105,47 @@ export const OtherSection: FC<Props> = ({ well }) => { ); }; +const loadingItemProps = { + sm: { height: 24, width: 100 }, + lg: { height: 24, width: 200 } +}; + +export const OtherSection: FC<{ well: Well | undefined; loading?: boolean }> = ({ well, loading }) => { + if (!well || loading) { + return ( + <div> + <Table width="100%"> + <THead> + <Row> + <Th>{""}</Th> + <DesktopTh>{""}</DesktopTh> + <MobileTh align={"right"}>{""}</MobileTh> + </Row> + </THead> + <TBody> + {Array(8) + .fill(null) + .map((_, idx) => ( + <LoadingRow key={`token-info-row-${idx}`}> + <Td> + <Skeleton {...loadingItemProps.sm} /> + </Td> + <DesktopTd> + <Skeleton {...loadingItemProps.lg} /> + </DesktopTd> + <MobileTd align={"right"}> + <Skeleton {...loadingItemProps.sm} /> + </MobileTd> + </LoadingRow> + ))} + </TBody> + </Table> + </div> + ); + } + return <OtherSectionContent well={well} />; +}; + const Detail = styled.span` color: #4b5563; font-weight: 600; @@ -135,3 +184,9 @@ const MobileTh = styled(Th)` display: none; } `; + +const LoadingRow = styled(Row)` + :hover { + cursor: default; + } +`; From 81bebeba09795d9641fb4aa80aad824d0dcd98a3 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Mon, 20 Nov 2023 13:56:14 -0700 Subject: [PATCH 23/30] implement table loading state --- projects/dex-ui/src/pages/Well.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index a7b6a86abd..c80982002d 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -167,7 +167,7 @@ export const Well = () => { * Chart Type Button Selectors */} <ActivityOtherButtons gap={24} mobileGap={"0px"}> - <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> + <LoadingItem loading={false} onLoading={<SkeletonButtonsRow />}> <Item stretch> <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} stretch justify bold hover> Activity @@ -181,8 +181,8 @@ export const Well = () => { </LoadingItem> </ActivityOtherButtons> <BottomContainer> - {tab === 0 && <WellHistory well={well!} tokenPrices={prices} reservesUSD={totalUSD} />} - {tab === 1 && <OtherSection well={well!} />} + {tab === 0 && <WellHistory well={well!} tokenPrices={prices} reservesUSD={totalUSD} loading={loading} />} + {tab === 1 && <OtherSection well={well!} loading={loading} />} </BottomContainer> <ColumnBreak /> <StickyDetector ref={containerRef} /> @@ -199,9 +199,15 @@ export const Well = () => { </Item> </LoadingItem> </LiquiditySwapButtons> + {/* + * Liquidity Box + */} <LiquidityBoxContainer> <LiquidityBox well={well} loading={loading} /> </LiquidityBoxContainer> + {/* + * Learn More + */} <LearnMoreContainer> <LearnMoreLabel onClick={toggle}> <LearnMoreLine /> From 5df11cb6d326937b9b62e60e8f86e640ae1380e5 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Mon, 20 Nov 2023 14:04:26 -0700 Subject: [PATCH 24/30] refactor wellHistory --- .../components/Well/Activity/WellHistory.tsx | 104 +++++++++++------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx b/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx index 4a93a41c36..63a82129a5 100644 --- a/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx +++ b/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx @@ -11,15 +11,17 @@ import { size } from "src/breakpoints"; import { useTokenSupply } from "src/tokens/useTokenSupply"; import { LoadingTemplate } from "src/components/LoadingTemplate"; -type WellHistoryProps = { - well: Well; +type BaseWellHistoryProps = { tokenPrices: (TokenValue | null)[]; reservesUSD: TokenValue; - loading?: boolean; }; -export const WellHistory = ({ well, tokenPrices, reservesUSD, loading: _loading }: WellHistoryProps) => { - const { data: events, isLoading } = useWellHistory(well); +type WellHistoryProps = { + well: Well; +} & BaseWellHistoryProps; + +const WellHistoryContent = ({ well, tokenPrices, reservesUSD }: WellHistoryProps) => { + const { data: events, isLoading: loading } = useWellHistory(well); const [filter, setFilter] = useState<EVENT_TYPE | null>(null); const eventsPerPage = 10; const totalEvents = events?.length || 0; @@ -38,8 +40,6 @@ export const WellHistory = ({ well, tokenPrices, reservesUSD, loading: _loading (e, index): any => index >= newestEventOnPage && index <= oldestEventOnPage && renderEvent(e, well, tokenPrices, lpTokenPrice) ); - const loading = isLoading || _loading; - return ( <WellHistoryContainer> {/* <div> @@ -51,43 +51,14 @@ export const WellHistory = ({ well, tokenPrices, reservesUSD, loading: _loading <Table width="100%"> <THead> <Row> - <Th>{loading ? "" : "Action"}</Th> - <DesktopOnlyTh align={"right"}>{loading ? "" : "Value"}</DesktopOnlyTh> - <DesktopOnlyTh align={"right"}>{loading ? "" : "Description"}</DesktopOnlyTh> - <Th align={"right"}>{loading ? "" : "Time"}</Th> + <Th>Action</Th> + <DesktopOnlyTh align={"right"}>Value</DesktopOnlyTh> + <DesktopOnlyTh align={"right"}>Description</DesktopOnlyTh> + <Th align={"right"}>Time</Th> </Row> </THead> <TBody> - {loading ? ( - <> - {Array(10) - .fill(null) - .map((_, rowIdx) => ( - <LoadingRow key={`table-row-${rowIdx}`}> - <Td> - <LoadingTemplate.Flex> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate.Flex> - </Td> - <DesktopOnlyTd align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </DesktopOnlyTd> - <DesktopOnlyTd align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </DesktopOnlyTd> - <Td align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </Td> - </LoadingRow> - ))} - </> - ) : eventRows.length ? ( + {eventRows.length ? ( eventRows ) : ( <> @@ -148,6 +119,57 @@ export const WellHistory = ({ well, tokenPrices, reservesUSD, loading: _loading ); }; +export const WellHistory: React.FC<BaseWellHistoryProps & { well: Well | undefined; loading?: boolean }> = (props) => { + if (props.loading || !props.well) { + return ( + <WellHistoryContainer> + <Table width="100%"> + <THead> + <Row> + <Th>{""}</Th> + <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> + <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> + <Th align={"right"}>{""}</Th> + </Row> + </THead> + <TBody> + <> + {Array(10) + .fill(null) + .map((_, rowIdx) => ( + <LoadingRow key={`table-row-${rowIdx}`}> + <Td> + <LoadingTemplate.Flex> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate.Flex> + </Td> + <DesktopOnlyTd align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </DesktopOnlyTd> + <DesktopOnlyTd align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </DesktopOnlyTd> + <Td align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </Td> + </LoadingRow> + ))} + </> + </TBody> + </Table> + </WellHistoryContainer> + ); + } + + return <WellHistoryContent well={props.well} tokenPrices={props.tokenPrices} reservesUSD={props.reservesUSD} />; +}; + const DesktopOnlyTd = styled(Td)` @media (max-width: ${size.mobile}) { display: none; From 7fddc48b918be504fc7033aa8c5e288d63b68a06 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Mon, 20 Nov 2023 14:49:33 -0700 Subject: [PATCH 25/30] well page loading --- .../components/Well/Activity/WellHistory.tsx | 94 ++++----- .../components/Well/Chart/ChartSection.tsx | 186 ++++++++++++------ projects/dex-ui/src/pages/Well.tsx | 35 +++- 3 files changed, 203 insertions(+), 112 deletions(-) diff --git a/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx b/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx index 63a82129a5..6a853886f9 100644 --- a/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx +++ b/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx @@ -40,6 +40,10 @@ const WellHistoryContent = ({ well, tokenPrices, reservesUSD }: WellHistoryProps (e, index): any => index >= newestEventOnPage && index <= oldestEventOnPage && renderEvent(e, well, tokenPrices, lpTokenPrice) ); + if (loading) { + return <WellHistorySkeleton />; + } + return ( <WellHistoryContainer> {/* <div> @@ -119,52 +123,54 @@ const WellHistoryContent = ({ well, tokenPrices, reservesUSD }: WellHistoryProps ); }; +const WellHistorySkeleton = () => ( + <WellHistoryContainer> + <Table width="100%"> + <THead> + <Row> + <Th>{""}</Th> + <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> + <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> + <Th align={"right"}>{""}</Th> + </Row> + </THead> + <TBody> + <> + {Array(10) + .fill(null) + .map((_, rowIdx) => ( + <LoadingRow key={`table-row-${rowIdx}`}> + <Td> + <LoadingTemplate.Flex> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate.Flex> + </Td> + <DesktopOnlyTd align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </DesktopOnlyTd> + <DesktopOnlyTd align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </DesktopOnlyTd> + <Td align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </Td> + </LoadingRow> + ))} + </> + </TBody> + </Table> + </WellHistoryContainer> +); + export const WellHistory: React.FC<BaseWellHistoryProps & { well: Well | undefined; loading?: boolean }> = (props) => { if (props.loading || !props.well) { - return ( - <WellHistoryContainer> - <Table width="100%"> - <THead> - <Row> - <Th>{""}</Th> - <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> - <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> - <Th align={"right"}>{""}</Th> - </Row> - </THead> - <TBody> - <> - {Array(10) - .fill(null) - .map((_, rowIdx) => ( - <LoadingRow key={`table-row-${rowIdx}`}> - <Td> - <LoadingTemplate.Flex> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate.Flex> - </Td> - <DesktopOnlyTd align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </DesktopOnlyTd> - <DesktopOnlyTd align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </DesktopOnlyTd> - <Td align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </Td> - </LoadingRow> - ))} - </> - </TBody> - </Table> - </WellHistoryContainer> - ); + return <WellHistorySkeleton />; } return <WellHistoryContent well={props.well} tokenPrices={props.tokenPrices} reservesUSD={props.reservesUSD} />; diff --git a/projects/dex-ui/src/components/Well/Chart/ChartSection.tsx b/projects/dex-ui/src/components/Well/Chart/ChartSection.tsx index bb92eadd10..75c75aca9b 100644 --- a/projects/dex-ui/src/components/Well/Chart/ChartSection.tsx +++ b/projects/dex-ui/src/components/Well/Chart/ChartSection.tsx @@ -9,20 +9,21 @@ import { TabButton } from "src/components/TabButton"; import useWellChartData from "src/wells/useWellChartData"; import { ChartContainer } from "./ChartStyles"; import { BottomDrawer } from "src/components/BottomDrawer"; -import { size } from "src/breakpoints"; +import { mediaQuery, size } from "src/breakpoints"; +import { LoadingTemplate } from "src/components/LoadingTemplate"; function timeToLocal(originalTime: number) { const d = new Date(originalTime * 1000); return Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds()) / 1000; } -export const ChartSection: FC<{ well: Well }> = ({ well }) => { +const ChartSectionContent: FC<{ well: Well }> = ({ well }) => { const [tab, setTab] = useState(0); const [showDropdown, setShowDropdown] = useState(false); const [timePeriod, setTimePeriod] = useState("week"); const [dropdownButtonText, setDropdownButtonText] = useState("1 WEEK"); - const { data: chartData, refetch, error, isLoading } = useWellChartData(well, timePeriod); + const { data: chartData, refetch, error, isLoading: chartDataLoading } = useWellChartData(well, timePeriod); const [liquidityData, setLiquidityData] = useState<any[]>([]); const [volumeData, setVolumeData] = useState<any[]>([]); @@ -74,60 +75,63 @@ export const ChartSection: FC<{ well: Well }> = ({ well }) => { return ( <Container id="chart-section"> <DesktopRow> - <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} hover> - LIQUIDITY - </TabButton> - <TabButton onClick={(e) => showTab(e, 1)} active={tab === 1} hover> - VOLUME - </TabButton> - <FilterButton - onClick={() => { - setShowDropdown(!showDropdown); - }} - > - {dropdownButtonText} <ChevronDown width={6} /> - <Dropdown enabled={showDropdown}> - <DropdownItem - stretch - hover - onClick={() => { - setChartRange("day"); - }} - > - 1 DAY - </DropdownItem> - <DropdownItem - stretch - hover - onClick={() => { - setChartRange("week"); - }} - > - 1 WEEK - </DropdownItem> - <DropdownItem - stretch - hover - onClick={() => { - setChartRange("month"); - }} - > - 1 MONTH - </DropdownItem> - <DropdownItem - stretch - hover - onClick={() => { - setChartRange("all"); - }} - > - ALL - </DropdownItem> - </Dropdown> - </FilterButton> + <> + <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} hover> + LIQUIDITY + </TabButton> + <TabButton onClick={(e) => showTab(e, 1)} active={tab === 1} hover> + VOLUME + </TabButton> + <FilterButton + onClick={() => { + setShowDropdown(!showDropdown); + }} + > + {dropdownButtonText} <ChevronDown width={6} /> + <Dropdown enabled={showDropdown}> + <DropdownItem + stretch + hover + onClick={() => { + setChartRange("day"); + }} + > + 1 DAY + </DropdownItem> + <DropdownItem + stretch + hover + onClick={() => { + setChartRange("week"); + }} + > + 1 WEEK + </DropdownItem> + <DropdownItem + stretch + hover + onClick={() => { + setChartRange("month"); + }} + > + 1 MONTH + </DropdownItem> + <DropdownItem + stretch + hover + onClick={() => { + setChartRange("all"); + }} + > + ALL + </DropdownItem> + </Dropdown> + </FilterButton> + </> </DesktopRow> <MobileRow> <TabButton onClick={() => setChartTypeDrawerOpen(true)}>{tab === 0 ? "LIQUIDITY" : "VOLUME"}</TabButton> + <BottomDrawer showDrawer={isChartTypeDrawerOpen} headerText={"View Chart"} toggleDrawer={setChartTypeDrawerOpen}> <DrawerRow onClick={() => { @@ -144,9 +148,11 @@ export const ChartSection: FC<{ well: Well }> = ({ well }) => { VOLUME </DrawerRow> </BottomDrawer> + <FilterButton onClick={() => setChartRangeDrawerOpen(true)}> {dropdownButtonText} <ChevronDown width={6} /> </FilterButton> + <BottomDrawer showDrawer={isChartRangeDrawerOpen} headerText={"Time Period"} toggleDrawer={setChartRangeDrawerOpen}> <DrawerRow onClick={() => { @@ -178,15 +184,56 @@ export const ChartSection: FC<{ well: Well }> = ({ well }) => { </DrawerRow> </BottomDrawer> </MobileRow> - {error !== null && <ChartLoader>{`Error Loading Chart Data :(`}</ChartLoader>} - {isLoading && <ChartLoader>Loading Chart Data...</ChartLoader>} - {tab === 0 && !error && !isLoading && <Chart data={liquidityData} legend={"TOTAL LIQUIDITY"} />} - {tab === 1 && !error && !isLoading && <Chart data={volumeData} legend={"HOURLY VOLUME"} />} + {error !== null && <ChartError>{`Error Loading Chart Data :(`}</ChartError>} + {chartDataLoading && ( + <ChartLoader> + <LoadingTemplate gap={4}> + <LoadingTemplate.Item width={100} height={24} /> + <LoadingTemplate.Item width={150} height={24} /> + </LoadingTemplate> + </ChartLoader> + )} + {tab === 0 && !error && !chartDataLoading && <Chart data={liquidityData} legend={"TOTAL LIQUIDITY"} />} + {tab === 1 && !error && !chartDataLoading && <Chart data={volumeData} legend={"HOURLY VOLUME"} />} </Container> ); }; +export const ChartSection: FC<{ well: Well | undefined; loading?: boolean }> = ({ well, loading }) => { + if (!well || loading) { + return ( + <Container id="chart-section-loading"> + <DesktopRow> + <LoadingTabButton width={110.59}>{""}</LoadingTabButton> + <LoadingTabButton width={99.17} active> + {""} + </LoadingTabButton> + <LoadingFilterButton width={103.41}>{""}</LoadingFilterButton> + </DesktopRow> + <MobileRow> + <LoadingTabButton width={84.03}>{""}</LoadingTabButton> + <LoadingFilterButton width={103.41}>{""}</LoadingFilterButton> + </MobileRow> + <ChartLoader> + <LoadingTemplate gap={4}> + <LoadingTemplate.Item width={100} height={24} /> + <LoadingTemplate.Item width={150} height={24} /> + </LoadingTemplate> + </ChartLoader> + </Container> + ); + } + + return <ChartSectionContent well={well} />; +}; + const ChartLoader = styled(ChartContainer)` + padding: 24px; + justify-content: flex-start; + box-sizing: border-box; +`; + +const ChartError = styled(ChartContainer)` justify-content: center; align-items: center; `; @@ -260,3 +307,26 @@ const FilterButton = styled.div` height: 40px; } `; + +const LoadingTabButton = styled(TabButton)<{ width: number }>` + min-height: 48px; + min-width: ${(props) => props.width}px; + + :hover { + cursor: default; + } +`; + +const LoadingFilterButton = styled(FilterButton)<{ width: number }>` + min-height: 48px; + min-width: ${(props) => props.width}px; + + :hover { + cursor: default; + background: white; + } + + ${mediaQuery.sm.only} { + min-height: 40px; + } +`; diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index c80982002d..636d05b923 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -21,15 +21,14 @@ import { OtherSection } from "src/components/Well/OtherSection"; import { WellHistory } from "src/components/Well/Activity/WellHistory"; import { ChevronDown } from "src/components/Icons"; import { ImageButton } from "src/components/ImageButton"; -import { mediaQuery } from "src/breakpoints"; -import { Loading } from "src/components/Loading"; +import { mediaQuery, size } from "src/breakpoints"; import { Error } from "../components/Error"; import { useWellWithParams } from "src/wells/useWellWithParams"; import { LoadingItem } from "src/components/LoadingItem"; import { LoadingTemplate } from "src/components/LoadingTemplate"; export const Well = () => { - const { well, loading: isLoading, error } = useWellWithParams(); + const { well, loading, error } = useWellWithParams(); const sdk = useSdk(); const navigate = useNavigate(); @@ -123,16 +122,18 @@ export const Well = () => { ); // Code above detects if the component with the Add/Remove Liq + Swap buttons is sticky - if (isLoading) return <Loading spinnerOnly />; + // if (isLoading) return <Loading spinnerOnly />; if (error) return <Error message={error?.message} errorOnly />; - const loading = true; - return ( <Page> <ContentWrapper> <StyledTitle title={title} parent={{ title: "Liquidity", path: "/wells" }} fontWeight="550" center /> + + {/* + *Header + */} <HeaderContainer> <LoadingItem loading={loading} onLoading={<SkeletonHeader />}> <Item> @@ -149,6 +150,7 @@ export const Well = () => { </StyledItem> </LoadingItem> </HeaderContainer> + {/* * Reserves */} @@ -157,17 +159,19 @@ export const Well = () => { <Reserves reserves={reserves} /> </LoadingItem> </ReservesContainer> + {/* * Chart Section */} <ChartContainer> - <ChartSection well={well!} /> + <ChartSection well={well} loading={loading} /> </ChartContainer> + {/* * Chart Type Button Selectors */} <ActivityOtherButtons gap={24} mobileGap={"0px"}> - <LoadingItem loading={false} onLoading={<SkeletonButtonsRow />}> + <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> <Item stretch> <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} stretch justify bold hover> Activity @@ -180,12 +184,21 @@ export const Well = () => { </Item> </LoadingItem> </ActivityOtherButtons> + + {/* + * Well History & Contract Info Tables + */} <BottomContainer> - {tab === 0 && <WellHistory well={well!} tokenPrices={prices} reservesUSD={totalUSD} loading={loading} />} - {tab === 1 && <OtherSection well={well!} loading={loading} />} + {tab === 0 && <WellHistory well={well} tokenPrices={prices} reservesUSD={totalUSD} loading={loading} />} + {tab === 1 && <OtherSection well={well} loading={loading} />} </BottomContainer> + + {/* + * UI Helpers + */} <ColumnBreak /> <StickyDetector ref={containerRef} /> + {/* * Liquidity Swap Button */} @@ -199,12 +212,14 @@ export const Well = () => { </Item> </LoadingItem> </LiquiditySwapButtons> + {/* * Liquidity Box */} <LiquidityBoxContainer> <LiquidityBox well={well} loading={loading} /> </LiquidityBoxContainer> + {/* * Learn More */} From 35ac724ed7d935991d7b98aa6bfd6bad9e3030ef Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Mon, 20 Nov 2023 16:49:20 -0700 Subject: [PATCH 26/30] small updates + fixesxz --- projects/dex-ui/src/breakpoints.ts | 6 +- .../components/Well/Activity/WellHistory.tsx | 100 +++---- .../components/Well/Chart/ChartSection.tsx | 7 +- projects/dex-ui/src/pages/Well.tsx | 265 +++++++++--------- 4 files changed, 195 insertions(+), 183 deletions(-) diff --git a/projects/dex-ui/src/breakpoints.ts b/projects/dex-ui/src/breakpoints.ts index 2c5c079b49..d723f3efa9 100644 --- a/projects/dex-ui/src/breakpoints.ts +++ b/projects/dex-ui/src/breakpoints.ts @@ -27,8 +27,12 @@ export const mediaQuery = { }, lg: { // 1200px & below - down: `@media (max-width: ${mediaSizes.tablet}px)`, + down: `@media (max-width: ${mediaSizes.desktop}px)`, // 1200px & above only: `@media (min-width: ${mediaSizes.desktop}px)` + }, + between: { + // between 769px & 1200px + smAndLg: `@media (min-width: ${mediaSizes.mobile}px) and (max-width: ${mediaSizes.desktop - 1}px)` } }; diff --git a/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx b/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx index 6a853886f9..fcac9cd2d5 100644 --- a/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx +++ b/projects/dex-ui/src/components/Well/Activity/WellHistory.tsx @@ -20,7 +20,52 @@ type WellHistoryProps = { well: Well; } & BaseWellHistoryProps; -const WellHistoryContent = ({ well, tokenPrices, reservesUSD }: WellHistoryProps) => { +const WellHistorySkeleton: React.FC<{}> = () => ( + <WellHistoryContainer> + <Table width="100%"> + <THead> + <Row> + <Th>{""}</Th> + <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> + <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> + <Th align={"right"}>{""}</Th> + </Row> + </THead> + <TBody> + <> + {Array(10) + .fill(null) + .map((_, rowIdx) => ( + <LoadingRow key={`table-row-${rowIdx}`}> + <Td> + <LoadingTemplate.Flex> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate.Flex> + </Td> + <DesktopOnlyTd align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </DesktopOnlyTd> + <DesktopOnlyTd align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </DesktopOnlyTd> + <Td align={"right"}> + <LoadingTemplate alignItems="flex-end"> + <LoadingTemplate.Item width={75} /> + </LoadingTemplate> + </Td> + </LoadingRow> + ))} + </> + </TBody> + </Table> + </WellHistoryContainer> +); + +const WellHistoryContent: React.FC<WellHistoryProps> = ({ well, tokenPrices, reservesUSD }) => { const { data: events, isLoading: loading } = useWellHistory(well); const [filter, setFilter] = useState<EVENT_TYPE | null>(null); const eventsPerPage = 10; @@ -34,16 +79,16 @@ const WellHistoryContent = ({ well, tokenPrices, reservesUSD }: WellHistoryProps const isNonEmptyWell = lpTokenSupply.totalSupply && lpTokenSupply.totalSupply.gt(0); const lpTokenPrice = lpTokenSupply.totalSupply && isNonEmptyWell ? reservesUSD.div(lpTokenSupply.totalSupply) : TokenValue.ZERO; + if (loading) { + return <WellHistorySkeleton />; + } + const eventRows: JSX.Element[] = (events || []) .filter((e: WellEvent) => filter === null || e.type == filter) .map<ReactElement>( (e, index): any => index >= newestEventOnPage && index <= oldestEventOnPage && renderEvent(e, well, tokenPrices, lpTokenPrice) ); - if (loading) { - return <WellHistorySkeleton />; - } - return ( <WellHistoryContainer> {/* <div> @@ -123,51 +168,6 @@ const WellHistoryContent = ({ well, tokenPrices, reservesUSD }: WellHistoryProps ); }; -const WellHistorySkeleton = () => ( - <WellHistoryContainer> - <Table width="100%"> - <THead> - <Row> - <Th>{""}</Th> - <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> - <DesktopOnlyTh align={"right"}>{""}</DesktopOnlyTh> - <Th align={"right"}>{""}</Th> - </Row> - </THead> - <TBody> - <> - {Array(10) - .fill(null) - .map((_, rowIdx) => ( - <LoadingRow key={`table-row-${rowIdx}`}> - <Td> - <LoadingTemplate.Flex> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate.Flex> - </Td> - <DesktopOnlyTd align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </DesktopOnlyTd> - <DesktopOnlyTd align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </DesktopOnlyTd> - <Td align={"right"}> - <LoadingTemplate alignItems="flex-end"> - <LoadingTemplate.Item width={75} /> - </LoadingTemplate> - </Td> - </LoadingRow> - ))} - </> - </TBody> - </Table> - </WellHistoryContainer> -); - export const WellHistory: React.FC<BaseWellHistoryProps & { well: Well | undefined; loading?: boolean }> = (props) => { if (props.loading || !props.well) { return <WellHistorySkeleton />; diff --git a/projects/dex-ui/src/components/Well/Chart/ChartSection.tsx b/projects/dex-ui/src/components/Well/Chart/ChartSection.tsx index 75c75aca9b..4f5e9ddcf8 100644 --- a/projects/dex-ui/src/components/Well/Chart/ChartSection.tsx +++ b/projects/dex-ui/src/components/Well/Chart/ChartSection.tsx @@ -131,7 +131,6 @@ const ChartSectionContent: FC<{ well: Well }> = ({ well }) => { </DesktopRow> <MobileRow> <TabButton onClick={() => setChartTypeDrawerOpen(true)}>{tab === 0 ? "LIQUIDITY" : "VOLUME"}</TabButton> - <BottomDrawer showDrawer={isChartTypeDrawerOpen} headerText={"View Chart"} toggleDrawer={setChartTypeDrawerOpen}> <DrawerRow onClick={() => { @@ -148,11 +147,9 @@ const ChartSectionContent: FC<{ well: Well }> = ({ well }) => { VOLUME </DrawerRow> </BottomDrawer> - <FilterButton onClick={() => setChartRangeDrawerOpen(true)}> {dropdownButtonText} <ChevronDown width={6} /> </FilterButton> - <BottomDrawer showDrawer={isChartRangeDrawerOpen} headerText={"Time Period"} toggleDrawer={setChartRangeDrawerOpen}> <DrawerRow onClick={() => { @@ -204,10 +201,10 @@ export const ChartSection: FC<{ well: Well | undefined; loading?: boolean }> = ( return ( <Container id="chart-section-loading"> <DesktopRow> - <LoadingTabButton width={110.59}>{""}</LoadingTabButton> - <LoadingTabButton width={99.17} active> + <LoadingTabButton width={110.59} active> {""} </LoadingTabButton> + <LoadingTabButton width={99.17}>{""}</LoadingTabButton> <LoadingFilterButton width={103.41}>{""}</LoadingFilterButton> </DesktopRow> <MobileRow> diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index 636d05b923..aa8c697cfe 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -127,133 +127,135 @@ export const Well = () => { if (error) return <Error message={error?.message} errorOnly />; return ( - <Page> - <ContentWrapper> - <StyledTitle title={title} parent={{ title: "Liquidity", path: "/wells" }} fontWeight="550" center /> - - {/* - *Header - */} - <HeaderContainer> - <LoadingItem loading={loading} onLoading={<SkeletonHeader />}> - <Item> - <Header> - <TokenLogos>{logos}</TokenLogos> - <TextNudge amount={10} mobileAmount={-2}> - {title} - </TextNudge> - </Header> - </Item> - <StyledItem column stretch> - <FunctionName>{wellFunctionName}</FunctionName> - <Fee>0.00% Trading Fee</Fee> - </StyledItem> - </LoadingItem> - </HeaderContainer> - - {/* - * Reserves - */} - <ReservesContainer> - <LoadingItem loading={loading} onLoading={<SkeletonReserves />}> - <Reserves reserves={reserves} /> - </LoadingItem> - </ReservesContainer> - - {/* - * Chart Section - */} - <ChartContainer> - <ChartSection well={well} loading={loading} /> - </ChartContainer> - - {/* - * Chart Type Button Selectors - */} - <ActivityOtherButtons gap={24} mobileGap={"0px"}> - <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> - <Item stretch> - <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} stretch justify bold hover> - Activity - </TabButton> - </Item> - <Item stretch> - <TabButton onClick={(e) => showTab(e, 1)} active={tab === 1} stretch justify bold hover> - Contract Addresses - </TabButton> - </Item> - </LoadingItem> - </ActivityOtherButtons> - - {/* - * Well History & Contract Info Tables - */} - <BottomContainer> - {tab === 0 && <WellHistory well={well} tokenPrices={prices} reservesUSD={totalUSD} loading={loading} />} - {tab === 1 && <OtherSection well={well} loading={loading} />} - </BottomContainer> - - {/* - * UI Helpers - */} - <ColumnBreak /> - <StickyDetector ref={containerRef} /> - - {/* - * Liquidity Swap Button - */} - <LiquiditySwapButtons gap={24} mobileGap={isSticky ? "0px" : "8px"} sticky={isSticky}> - <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> - <Item stretch> - <Button secondary label="Add/Rm Liquidity" onClick={goLiquidity} /> - </Item> - <Item stretch> - <Button label="Swap" onClick={goSwap} /> - </Item> - </LoadingItem> - </LiquiditySwapButtons> - - {/* - * Liquidity Box - */} - <LiquidityBoxContainer> - <LiquidityBox well={well} loading={loading} /> - </LiquidityBoxContainer> - - {/* - * Learn More - */} - <LearnMoreContainer> - <LearnMoreLabel onClick={toggle}> - <LearnMoreLine /> - <LearnMoreText> - <TextNudge amount={2}>Learn more about this Well</TextNudge> - <ImageButton - component={ChevronDown} - size={10} - rotate={open ? "180" : "0"} - onClick={toggle} - padding="0px" - alt="Click to expand and learn how to earn yield" - color={"#46B955"} - /> - </LearnMoreText> - <LearnMoreLine /> - </LearnMoreLabel> - <LearnMoreButtons open={open}> - <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> - <LearnYield /> + <PageWrapper> + <Page> + <ContentWrapper> + <StyledTitle title={title} parent={{ title: "Liquidity", path: "/wells" }} fontWeight="550" center /> + + {/* + *Header + */} + <HeaderContainer> + <LoadingItem loading={loading} onLoading={<SkeletonHeader />}> + <Item> + <Header> + <TokenLogos>{logos}</TokenLogos> + <TextNudge amount={10} mobileAmount={-2}> + {title} + </TextNudge> + </Header> + </Item> + <StyledItem column stretch> + <FunctionName>{wellFunctionName}</FunctionName> + <Fee>0.00% Trading Fee</Fee> + </StyledItem> </LoadingItem> - <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> - <LearnWellFunction name={wellFunctionName || "A Well Function"} /> + </HeaderContainer> + + {/* + * Reserves + */} + <ReservesContainer> + <LoadingItem loading={loading} onLoading={<SkeletonReserves />}> + <Reserves reserves={reserves} /> </LoadingItem> - <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> - <LearnPump /> + </ReservesContainer> + + {/* + * Chart Section + */} + <ChartContainer> + <ChartSection well={well} loading={loading} /> + </ChartContainer> + + {/* + * Chart Type Button Selectors + */} + <ActivityOtherButtons gap={24} mobileGap={"0px"}> + <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> + <Item stretch> + <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} stretch justify bold hover> + Activity + </TabButton> + </Item> + <Item stretch> + <TabButton onClick={(e) => showTab(e, 1)} active={tab === 1} stretch justify bold hover> + Contract Addresses + </TabButton> + </Item> </LoadingItem> - </LearnMoreButtons> - </LearnMoreContainer> - </ContentWrapper> - </Page> + </ActivityOtherButtons> + + {/* + * Well History & Contract Info Tables + */} + <BottomContainer> + {tab === 0 && <WellHistory well={well} tokenPrices={prices} reservesUSD={totalUSD} loading={loading} />} + {tab === 1 && <OtherSection well={well} loading={loading} />} + </BottomContainer> + + {/* + * UI Helpers + */} + <ColumnBreak /> + <StickyDetector ref={containerRef} /> + + {/* + * Liquidity Swap Button + */} + <LiquiditySwapButtons gap={24} mobileGap={isSticky ? "0px" : "8px"} sticky={isSticky}> + <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> + <Item stretch> + <Button secondary label="Add/Rm Liquidity" onClick={goLiquidity} /> + </Item> + <Item stretch> + <Button label="Swap" onClick={goSwap} /> + </Item> + </LoadingItem> + </LiquiditySwapButtons> + + {/* + * Liquidity Box + */} + <LiquidityBoxContainer> + <LiquidityBox well={well} loading={loading} /> + </LiquidityBoxContainer> + + {/* + * Learn More + */} + <LearnMoreContainer> + <LearnMoreLabel onClick={toggle}> + <LearnMoreLine /> + <LearnMoreText> + <TextNudge amount={2}>Learn more about this Well</TextNudge> + <ImageButton + component={ChevronDown} + size={10} + rotate={open ? "180" : "0"} + onClick={toggle} + padding="0px" + alt="Click to expand and learn how to earn yield" + color={"#46B955"} + /> + </LearnMoreText> + <LearnMoreLine /> + </LearnMoreLabel> + <LearnMoreButtons open={open}> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnYield /> + </LoadingItem> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnWellFunction name={wellFunctionName || "A Well Function"} /> + </LoadingItem> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnPump /> + </LoadingItem> + </LearnMoreButtons> + </LearnMoreContainer> + </ContentWrapper> + </Page> + </PageWrapper> ); }; @@ -262,6 +264,15 @@ const rightColumnWidth = 400; const calcWellContentMaxWidth = `min(calc(100% - 48px - 400px), ${leftColumnWidth}px)`; +const PageWrapper = styled.div` + display: flex; + flex-direction: column; + + ${mediaQuery.between.smAndLg} { + align-items: center; + } +`; + const ContentWrapper = styled.div` display: flex; flex-flow: column wrap; @@ -275,8 +286,8 @@ const ContentWrapper = styled.div` height: 1400px; } - ${mediaQuery.lg.down} { - flex-flow: column nowrap; + ${mediaQuery.between.smAndLg} { + max-width: ${size.mobile}; } `; @@ -389,7 +400,7 @@ const LiquiditySwapButtons = styled(Row)<{ sticky?: boolean }>` } ${mediaQuery.md.only} { - max-width: calc(100vw - 96px); + max-width: calc(100vw - 48px); } `; From 5a058b837e99322c0dbd8aaedf55ea38306a78d6 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Tue, 21 Nov 2023 11:26:20 -0700 Subject: [PATCH 27/30] fix responsive on Loading Template + fix Well Page Responsive --- .../dex-ui/src/components/LoadingTemplate.tsx | 2 +- projects/dex-ui/src/pages/Well.tsx | 327 ++++++++++-------- 2 files changed, 175 insertions(+), 154 deletions(-) diff --git a/projects/dex-ui/src/components/LoadingTemplate.tsx b/projects/dex-ui/src/components/LoadingTemplate.tsx index 86324e180f..bb7dd414b4 100644 --- a/projects/dex-ui/src/components/LoadingTemplate.tsx +++ b/projects/dex-ui/src/components/LoadingTemplate.tsx @@ -84,7 +84,7 @@ LoadingTemplate.OutputSingle = ({ size, width, mb }: { size?: number; width?: nu LoadingTemplate.Flex = (props: FlexProps & { children: React.ReactNode }) => <FlexBox {...props} />; -LoadingTemplate.TokenLogo = ({ count = 1, size }: { count?: number; size: number }) => { +LoadingTemplate.TokenLogo = ({ count = 1, size, mobileSize }: { count?: number; size: number; mobileSize?: number }) => { if (count === 0) return null; if (count === 1) { diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index aa8c697cfe..1219a03e0b 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -28,7 +28,9 @@ import { LoadingItem } from "src/components/LoadingItem"; import { LoadingTemplate } from "src/components/LoadingTemplate"; export const Well = () => { - const { well, loading, error } = useWellWithParams(); + const { well, loading: _loading, error } = useWellWithParams(); + + const loading = true; const sdk = useSdk(); const navigate = useNavigate(); @@ -47,9 +49,9 @@ export const Well = () => { }, [open]); useEffect(() => { - const run = async () => { - if (!well?.tokens) return; + if (!well?.tokens) return; + const run = async () => { if (well.tokens) { const prices = await Promise.all(well.tokens.map((t) => getPrice(t, sdk))); setPrices(prices); @@ -122,140 +124,147 @@ export const Well = () => { ); // Code above detects if the component with the Add/Remove Liq + Swap buttons is sticky - // if (isLoading) return <Loading spinnerOnly />; - if (error) return <Error message={error?.message} errorOnly />; return ( - <PageWrapper> - <Page> - <ContentWrapper> - <StyledTitle title={title} parent={{ title: "Liquidity", path: "/wells" }} fontWeight="550" center /> - - {/* - *Header - */} - <HeaderContainer> - <LoadingItem loading={loading} onLoading={<SkeletonHeader />}> - <Item> - <Header> - <TokenLogos>{logos}</TokenLogos> - <TextNudge amount={10} mobileAmount={-2}> - {title} - </TextNudge> - </Header> - </Item> - <StyledItem column stretch> - <FunctionName>{wellFunctionName}</FunctionName> - <Fee>0.00% Trading Fee</Fee> - </StyledItem> - </LoadingItem> - </HeaderContainer> - - {/* - * Reserves - */} - <ReservesContainer> - <LoadingItem loading={loading} onLoading={<SkeletonReserves />}> - <Reserves reserves={reserves} /> + <Page> + <ContentWrapper> + <StyledTitle title={title} parent={{ title: "Liquidity", path: "/wells" }} fontWeight="550" center /> + + {/* + *Header + */} + <HeaderContainer> + <LoadingItem loading={loading} onLoading={<SkeletonHeader />}> + <Item> + <Header> + <TokenLogos>{logos}</TokenLogos> + <TextNudge amount={10} mobileAmount={-2}> + {title} + </TextNudge> + </Header> + </Item> + <StyledItem column stretch> + <FunctionName>{wellFunctionName}</FunctionName> + <Fee>0.00% Trading Fee</Fee> + </StyledItem> + </LoadingItem> + </HeaderContainer> + + {/* + * Reserves + */} + <ReservesContainer> + <LoadingItem loading={loading} onLoading={<SkeletonReserves />}> + <Reserves reserves={reserves} /> + </LoadingItem> + </ReservesContainer> + + {/* + * Chart Section + */} + <ChartSectionContainer> + <ChartSection well={well} loading={loading} /> + </ChartSectionContainer> + + {/* + * Chart Type Button Selectors + */} + <ActivityOtherButtons gap={24} mobileGap={"0px"}> + <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> + <Item stretch> + <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} stretch justify bold hover> + Activity + </TabButton> + </Item> + <Item stretch> + <TabButton onClick={(e) => showTab(e, 1)} active={tab === 1} stretch justify bold hover> + Contract Addresses + </TabButton> + </Item> + </LoadingItem> + </ActivityOtherButtons> + + {/* + * Well History & Contract Info Tables + */} + <BottomContainer> + {tab === 0 && <WellHistory well={well} tokenPrices={prices} reservesUSD={totalUSD} loading={loading} />} + {tab === 1 && <OtherSection well={well} loading={loading} />} + </BottomContainer> + + {/* + * UI Helpers + */} + <ColumnBreak /> + <StickyDetector ref={containerRef} /> + + {/* + * Liquidity Swap Buttons + * We render both Mobile & Desktop to prevent flex order switching animations from happening on page width changes + */} + <LiquiditySwapButtonsMobile sticky={isSticky}> + <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> + <Item stretch> + <Button secondary label="Add/Rm Liquidity" onClick={goLiquidity} /> + </Item> + <Item stretch> + <Button label="Swap" onClick={goSwap} /> + </Item> + </LoadingItem> + </LiquiditySwapButtonsMobile> + <LiquiditySwapButtonsDesktop gap={24}> + <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> + <Item stretch> + <Button secondary label="Add/Rm Liquidity" onClick={goLiquidity} /> + </Item> + <Item stretch> + <Button label="Swap" onClick={goSwap} /> + </Item> + </LoadingItem> + </LiquiditySwapButtonsDesktop> + + {/* + * Liquidity Box + */} + <LiquidityBoxContainer> + <LiquidityBox well={well} loading={loading} /> + </LiquidityBoxContainer> + + {/* + * Learn More + */} + <LearnMoreContainer> + <LearnMoreLabel onClick={toggle}> + <LearnMoreLine /> + <LearnMoreText> + <TextNudge amount={2}>Learn more about this Well</TextNudge> + <ImageButton + component={ChevronDown} + size={10} + rotate={open ? "180" : "0"} + onClick={toggle} + padding="0px" + alt="Click to expand and learn how to earn yield" + color={"#46B955"} + /> + </LearnMoreText> + <LearnMoreLine /> + </LearnMoreLabel> + <LearnMoreButtons open={open}> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnYield /> </LoadingItem> - </ReservesContainer> - - {/* - * Chart Section - */} - <ChartContainer> - <ChartSection well={well} loading={loading} /> - </ChartContainer> - - {/* - * Chart Type Button Selectors - */} - <ActivityOtherButtons gap={24} mobileGap={"0px"}> - <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> - <Item stretch> - <TabButton onClick={(e) => showTab(e, 0)} active={tab === 0} stretch justify bold hover> - Activity - </TabButton> - </Item> - <Item stretch> - <TabButton onClick={(e) => showTab(e, 1)} active={tab === 1} stretch justify bold hover> - Contract Addresses - </TabButton> - </Item> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnWellFunction name={wellFunctionName || "A Well Function"} /> </LoadingItem> - </ActivityOtherButtons> - - {/* - * Well History & Contract Info Tables - */} - <BottomContainer> - {tab === 0 && <WellHistory well={well} tokenPrices={prices} reservesUSD={totalUSD} loading={loading} />} - {tab === 1 && <OtherSection well={well} loading={loading} />} - </BottomContainer> - - {/* - * UI Helpers - */} - <ColumnBreak /> - <StickyDetector ref={containerRef} /> - - {/* - * Liquidity Swap Button - */} - <LiquiditySwapButtons gap={24} mobileGap={isSticky ? "0px" : "8px"} sticky={isSticky}> - <LoadingItem loading={loading} onLoading={<SkeletonButtonsRow />}> - <Item stretch> - <Button secondary label="Add/Rm Liquidity" onClick={goLiquidity} /> - </Item> - <Item stretch> - <Button label="Swap" onClick={goSwap} /> - </Item> + <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> + <LearnPump /> </LoadingItem> - </LiquiditySwapButtons> - - {/* - * Liquidity Box - */} - <LiquidityBoxContainer> - <LiquidityBox well={well} loading={loading} /> - </LiquidityBoxContainer> - - {/* - * Learn More - */} - <LearnMoreContainer> - <LearnMoreLabel onClick={toggle}> - <LearnMoreLine /> - <LearnMoreText> - <TextNudge amount={2}>Learn more about this Well</TextNudge> - <ImageButton - component={ChevronDown} - size={10} - rotate={open ? "180" : "0"} - onClick={toggle} - padding="0px" - alt="Click to expand and learn how to earn yield" - color={"#46B955"} - /> - </LearnMoreText> - <LearnMoreLine /> - </LearnMoreLabel> - <LearnMoreButtons open={open}> - <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> - <LearnYield /> - </LoadingItem> - <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> - <LearnWellFunction name={wellFunctionName || "A Well Function"} /> - </LoadingItem> - <LoadingItem loading={loading} onLoading={<EmptyLearnItem />}> - <LearnPump /> - </LoadingItem> - </LearnMoreButtons> - </LearnMoreContainer> - </ContentWrapper> - </Page> - </PageWrapper> + </LearnMoreButtons> + </LearnMoreContainer> + </ContentWrapper> + </Page> ); }; @@ -264,15 +273,6 @@ const rightColumnWidth = 400; const calcWellContentMaxWidth = `min(calc(100% - 48px - 400px), ${leftColumnWidth}px)`; -const PageWrapper = styled.div` - display: flex; - flex-direction: column; - - ${mediaQuery.between.smAndLg} { - align-items: center; - } -`; - const ContentWrapper = styled.div` display: flex; flex-flow: column wrap; @@ -288,6 +288,8 @@ const ContentWrapper = styled.div` ${mediaQuery.between.smAndLg} { max-width: ${size.mobile}; + flex: 2; + align-self: center; } `; @@ -347,7 +349,7 @@ const ReservesContainer = styled.div` } `; -const ChartContainer = styled.div` +const ChartSectionContainer = styled.div` width: 100%; order: 4; @@ -377,30 +379,48 @@ const StickyDetector = styled.div` margin-bottom: -24px; order: 2; - ${mediaQuery.lg.only} { + ${mediaQuery.sm.up} { display: none; } `; -const LiquiditySwapButtons = styled(Row)<{ sticky?: boolean }>` - width: ${(props) => (props.sticky ? "100vw" : "100%")}; - margin-left: ${(props) => (props.sticky ? "-12px" : "0px")}; +const LiquiditySwapButtonsMobile = styled(Row)<{ sticky?: boolean }>` + width: 100%; order: 2; - position: sticky; top: 0px; z-index: 10; transition: all 0.3s ease-in-out; + gap: 8px; + + ${mediaQuery.md.only} { + max-width: ${size.mobile}; + } + + ${mediaQuery.sm.only} { + position: sticky; + gap: ${(props) => (props.sticky ? "0px" : "8px")}; + margin-left: ${(props) => (props.sticky ? "-12px" : "0px")}; + width: ${(props) => (props.sticky ? "100vw" : "100%")}; + } ${mediaQuery.lg.only} { - max-width: ${rightColumnWidth}px; - order: 0; - margin-top: 48px; - position: relative; - margin-left: 0px; + display: none; } +`; - ${mediaQuery.md.only} { - max-width: calc(100vw - 48px); +const LiquiditySwapButtonsDesktop = styled(Row)` + max-width: ${rightColumnWidth}px; + width: 100%; + order: 0; + margin-top: 48px; + position: relative; + margin-left: 0px; + transition: all 0.3s ease-in-out; + top: 0px; + z-index: 10; + + ${mediaQuery.lg.down} { + display: none; } `; @@ -411,6 +431,7 @@ const StyledItem = styled(Item)` align-items: flex-end; } `; + const BottomContainer = styled.div` display: flex; flex-direction: column; From a25ca50c13863418901058351ff326c5f27584e1 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Tue, 21 Nov 2023 11:27:25 -0700 Subject: [PATCH 28/30] remove perma loading on Well page --- projects/dex-ui/src/pages/Well.tsx | 4 +--- projects/dex-ui/src/tokens/TokenProvider.tsx | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index 1219a03e0b..c4b06e62e2 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -28,9 +28,7 @@ import { LoadingItem } from "src/components/LoadingItem"; import { LoadingTemplate } from "src/components/LoadingTemplate"; export const Well = () => { - const { well, loading: _loading, error } = useWellWithParams(); - - const loading = true; + const { well, loading: loading, error } = useWellWithParams(); const sdk = useSdk(); const navigate = useNavigate(); diff --git a/projects/dex-ui/src/tokens/TokenProvider.tsx b/projects/dex-ui/src/tokens/TokenProvider.tsx index ccf9091825..ae71d6661b 100644 --- a/projects/dex-ui/src/tokens/TokenProvider.tsx +++ b/projects/dex-ui/src/tokens/TokenProvider.tsx @@ -9,11 +9,7 @@ const tokenMap: Record<string, Token> = {}; const TokenContext = createContext(tokenMap); export const TokenProvider = ({ children }: { children: React.ReactNode }) => { - const { data: tokens, isLoading, error } = useWellTokens(); - - if (isLoading) { - <></>; - } + const { data: tokens, error } = useWellTokens(); if (error) { return <Error message={error?.message} />; From 8a2d5bd7a20198190dea0de374b4c72d6d1fe366 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Tue, 21 Nov 2023 11:40:39 -0700 Subject: [PATCH 29/30] fix alignment on wells header + skeleton token logo size on mobile --- .../dex-ui/src/components/LoadingTemplate.tsx | 2 +- projects/dex-ui/src/pages/Well.tsx | 29 +++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/projects/dex-ui/src/components/LoadingTemplate.tsx b/projects/dex-ui/src/components/LoadingTemplate.tsx index bb7dd414b4..86324e180f 100644 --- a/projects/dex-ui/src/components/LoadingTemplate.tsx +++ b/projects/dex-ui/src/components/LoadingTemplate.tsx @@ -84,7 +84,7 @@ LoadingTemplate.OutputSingle = ({ size, width, mb }: { size?: number; width?: nu LoadingTemplate.Flex = (props: FlexProps & { children: React.ReactNode }) => <FlexBox {...props} />; -LoadingTemplate.TokenLogo = ({ count = 1, size, mobileSize }: { count?: number; size: number; mobileSize?: number }) => { +LoadingTemplate.TokenLogo = ({ count = 1, size }: { count?: number; size: number }) => { if (count === 0) return null; if (count === 1) { diff --git a/projects/dex-ui/src/pages/Well.tsx b/projects/dex-ui/src/pages/Well.tsx index c4b06e62e2..d257382c2c 100644 --- a/projects/dex-ui/src/pages/Well.tsx +++ b/projects/dex-ui/src/pages/Well.tsx @@ -22,7 +22,7 @@ import { WellHistory } from "src/components/Well/Activity/WellHistory"; import { ChevronDown } from "src/components/Icons"; import { ImageButton } from "src/components/ImageButton"; import { mediaQuery, size } from "src/breakpoints"; -import { Error } from "../components/Error"; +import { Error } from "src/components/Error"; import { useWellWithParams } from "src/wells/useWellWithParams"; import { LoadingItem } from "src/components/LoadingItem"; import { LoadingTemplate } from "src/components/LoadingTemplate"; @@ -425,7 +425,7 @@ const LiquiditySwapButtonsDesktop = styled(Row)` const StyledItem = styled(Item)` align-items: flex-start; - ${mediaQuery.md.up} { + ${mediaQuery.lg.only} { align-items: flex-end; } `; @@ -537,11 +537,34 @@ const EmptyLearnItem = styled.div` background: #f9f8f6; `; +const MobileOnlyTokenLogoContainer = styled.div` + display: none; + ${mediaQuery.sm.only} { + display: flex; + justify-content: center; + flex-direction: column; + margin-top: 6px; + } +`; + +const NonMobileTokenLogoContainer = styled.div` + display: block; + + ${mediaQuery.sm.only} { + display: none; + } +`; + const SkeletonHeader: React.FC<{}> = () => ( <> <Item> <Header> - <LoadingTemplate.TokenLogo count={2} size={48} /> + <MobileOnlyTokenLogoContainer> + <LoadingTemplate.TokenLogo count={2} size={24} /> + </MobileOnlyTokenLogoContainer> + <NonMobileTokenLogoContainer> + <LoadingTemplate.TokenLogo count={2} size={48} /> + </NonMobileTokenLogoContainer> <LoadingTemplate.Item width={150} height={32} margin={{ top: 8 }} /> </Header> </Item> From 13f40a1ebc20dcf0d1baa6d50daa45cae6f62ff8 Mon Sep 17 00:00:00 2001 From: spacebean <wndgud00@gmail.com> Date: Tue, 21 Nov 2023 13:14:34 -0700 Subject: [PATCH 30/30] housekeeping --- .../components/Frame/ContractInfoMarquee.tsx | 62 ++++++++++--------- .../src/components/Liquidity/AddLiquidity.tsx | 4 +- .../components/Liquidity/RemoveLiquidity.tsx | 4 +- .../dex-ui/src/components/LoadingTemplate.tsx | 27 +++----- projects/dex-ui/src/pages/Home.tsx | 31 +++++++--- projects/dex-ui/src/pages/Swap.tsx | 2 +- projects/dex-ui/src/pages/Wells.tsx | 2 +- 7 files changed, 73 insertions(+), 59 deletions(-) diff --git a/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx b/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx index 6f01f445f8..2f40b627b8 100644 --- a/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx +++ b/projects/dex-ui/src/components/Frame/ContractInfoMarquee.tsx @@ -2,51 +2,57 @@ import React from "react"; import styled, { keyframes } from "styled-components"; -const CarouselData: Record<string, { display: string; to: string }> = { - ADDRESS: { - display: "0x1584B668643617D18321a0BEc6EF3786F4b8Eb7B", - to: "/" // TODO: link to etherscan - }, - DEPLOY: { - display: "17113653", - to: "/" // TODO: link to etherscan - }, - AUDIT: { - display: "HALBORN, CYFRIN", - to: "https://www.halborn.com/" // TODO: link to audit - }, - V1: { - display: "WHITEPAPER", - to: "/basin.pdf" - } +type ContractMarqueeInfo = Record<string, { display: string; to?: string; url?: string }[]>; + +const CarouselData: ContractMarqueeInfo = { + ADDRESS: [ + { + display: "0x1584B668643617D18321a0BEc6EF3786F4b8Eb7B", + url: "https://etherscan.io/address/0xBA51AAAA95aeEFc1292515b36D86C51dC7877773" + } + ], + AUDIT: [ + { display: "HALBORN", url: "/halborn-basin-audit.pdf" }, + { display: "CYFRIN", url: "/cyfrin-basin-audit.pdf" }, + { display: "CODE4RENA", url: "https://code4rena.com/reports/2023-07-basin" } + ], + V1: [{ display: "WHITEPAPER", url: "/basin.pdf" }] }; -export const ContractInfoMarqueeHeight = 57; +const speedPerItem = 16; // approx same speed as TokenMarquee +const itemGap = 24; +const numItems = 4; +const singleItemWidth = 1107.44; export const ContractInfoMarquee = () => { const data = Object.entries(CarouselData); - /// See TokenMarquee.tsx for more info on how this works - const speedPerItem = 25; - const repeatableWidth = 1192.34; - const numItems = 3; + const totalItemWidth = numItems * singleItemWidth; + const totalGapWidth = numItems * itemGap; + + const totalWidth = totalItemWidth + totalGapWidth; + + const repeatableWidth = totalWidth / numItems; const animationDuration = numItems * speedPerItem; return ( <Scroller x={repeatableWidth} duration={animationDuration}> <CarouselRow style={{ justifyContent: "flex-start" }}> <> - {Array(numItems + 1) + {Array(numItems) .fill(null) .map((_, idx) => ( <Container key={`single-item-${idx}`}> - {data.map(([key, { display, to }], idx) => ( + {data.map(([key, data], idx) => ( <RowContainer key={`${key}-${idx}`}> <InfoRow> <InfoText>{key.toUpperCase()}:</InfoText> - <TextLink href={to} target="_blank" rel="noopener noreferrer"> - {display} - </TextLink> + {data.map(({ display, url }, i) => ( + <TextLink href={url} target="_blank" rel="noopener noreferrer" key={`${display}-${i}`}> + {display} + <span>{data.length > 1 && i + 1 < data.length ? <>{","}</> : ""}</span> + </TextLink> + ))} </InfoRow> <InfoText>/</InfoText> </RowContainer> @@ -80,13 +86,13 @@ const CarouselRow = styled.div` display: flex; flex-direction: row; justify-content: flex-start; + gap: 24px; `; const Container = styled.div` display: flex; flex-direction: row; gap: 24px; - margin-right: 24px; `; const RowContainer = styled.div` diff --git a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx index 2f1e7de0b9..2704723c1a 100644 --- a/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/AddLiquidity.tsx @@ -427,8 +427,8 @@ export const AddLiquidity: React.FC<BaseAddLiquidityProps & { well: Well | undef <LoadingTemplate.Input /> </LoadingTemplate.Flex> <LoadingTemplate.Flex gap={8}> - <LoadingTemplate.OutputSingle size={20} width={285} /> - <LoadingTemplate.OutputSingle size={20} width={145} /> + <LoadingTemplate.Item height={20} width={285} /> + <LoadingTemplate.Item height={20} width={145} /> </LoadingTemplate.Flex> <ButtonWrapper> <LoadingTemplate.Button /> diff --git a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx index fbe3502d0a..0271902a95 100644 --- a/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx +++ b/projects/dex-ui/src/components/Liquidity/RemoveLiquidity.tsx @@ -456,7 +456,7 @@ export const RemoveLiquidity: React.FC<{ well: Well | undefined; loading: boolea </TokenContainer> <MediumGapContainer> <OutputModeSelectorContainer> - <LoadingTemplate.OutputSingle width={100} size={20} mb={4} /> + <LoadingTemplate.Item width={100} height={20} margin={{ bottom: 4 }} /> <LoadingTemplate.Flex row gap={8}> <LoadingTemplate.Button /> <LoadingTemplate.Button /> @@ -469,7 +469,7 @@ export const RemoveLiquidity: React.FC<{ well: Well | undefined; loading: boolea <LoadingTemplate.Input /> </TokenContainer> </MediumGapContainer> - <LoadingTemplate.OutputSingle width={185} /> + <LoadingTemplate.Item width={185} /> <ButtonWrapper> <LoadingTemplate.Button /> </ButtonWrapper> diff --git a/projects/dex-ui/src/components/LoadingTemplate.tsx b/projects/dex-ui/src/components/LoadingTemplate.tsx index 86324e180f..fb99da29a3 100644 --- a/projects/dex-ui/src/components/LoadingTemplate.tsx +++ b/projects/dex-ui/src/components/LoadingTemplate.tsx @@ -42,18 +42,15 @@ LoadingTemplate.Arrow = () => ( </ArrowContainer> ); -LoadingTemplate.OutputDouble = ({ size, height }: { size?: number; height?: number }) => ( - <OutputRow> - <Background width={90} height={height}> - <Skeleton width={90} height={size ? size : 24} /> - </Background> - <Background width={70} height={height}> - <Skeleton width={70} height={size ? size : 24} /> - </Background> - </OutputRow> -); - -LoadingTemplate.LabelValue = ({ height, labelWidth, valueWidth }: { height?: number; labelWidth?: number; valueWidth?: number }) => ( +LoadingTemplate.LabelValue = ({ + height, + labelWidth = 90, + valueWidth = 70 +}: { + height?: number; + labelWidth?: number; + valueWidth?: number; +}) => ( <OutputRow> <Background width={labelWidth}> <Skeleton width={labelWidth} height={height || 24} /> @@ -76,12 +73,6 @@ LoadingTemplate.Item = ({ height, width, margin }: DimensionProps & { margin?: M </Background> ); -LoadingTemplate.OutputSingle = ({ size, width, mb }: { size?: number; width?: number; mb?: number }) => ( - <Background width={width || 90} margin={{ bottom: mb }}> - <Skeleton width={width || 90} height={size || 24} /> - </Background> -); - LoadingTemplate.Flex = (props: FlexProps & { children: React.ReactNode }) => <FlexBox {...props} />; LoadingTemplate.TokenLogo = ({ count = 1, size }: { count?: number; size: number }) => { diff --git a/projects/dex-ui/src/pages/Home.tsx b/projects/dex-ui/src/pages/Home.tsx index 2cac6b88ec..0ce89f0893 100644 --- a/projects/dex-ui/src/pages/Home.tsx +++ b/projects/dex-ui/src/pages/Home.tsx @@ -1,7 +1,7 @@ /* eslint-disable jsx-a11y/accessible-emoji */ import React from "react"; import { mediaQuery } from "src/breakpoints"; -import { Link } from "react-router-dom"; + import styled from "styled-components"; import shapesIcons from "src/assets/images/home-banner.svg"; import { BodyL } from "src/components/Typography"; @@ -13,6 +13,14 @@ const copy = { fees: "Trade assets using liquidity pools that don’t impose trading fees." }; +const links = { + multiFlowPump: "/multi-flow-pump.pdf", + whitepaper: "/basin.pdf", + docs: "https://docs.basin.exchange/", + wells: "/#/wells", + swap: "/#/swap" +}; + export const Home = () => { return ( <> @@ -27,7 +35,9 @@ export const Home = () => { integration for everyone. </div> </MevInfo> - <GetStarted>Get Started →</GetStarted> + <GetStartedContainer href={links.multiFlowPump} target="_blank" rel="noopener noreferrer"> + <GetStarted>Get Started →</GetStarted> + </GetStartedContainer> </MevBannerBG> </MevBanner> <InfoContainer> @@ -35,13 +45,13 @@ export const Home = () => { <Title>A Composable EVM-native DEX Customizable liquidity pools with shared components.  - + Read the whitepaper → - + 🔮 @@ -50,7 +60,7 @@ export const Home = () => { {copy.build} - +
@@ -61,7 +71,7 @@ export const Home = () => { {copy.deploy} - +
@@ -161,6 +171,12 @@ const MevTitle = styled.div` ${BodyL} `; +const GetStartedContainer = styled.a` + :focus { + text-decoration: none; + } +`; + const GetStarted = styled.div` display: flex; justify-content: center; @@ -253,6 +269,7 @@ const WhitepaperLink = styled.a` display: flex; align-items: center; white-space: nowrap; + margin-left: 4px; :hover { text-decoration: underline; @@ -296,7 +313,7 @@ const Emoji = styled.span` margin-right: 4px; `; -const AccordionItem = styled(Link)` +const AccordionItem = styled.a` display: flex; flex-direction: column; justify-content: center; diff --git a/projects/dex-ui/src/pages/Swap.tsx b/projects/dex-ui/src/pages/Swap.tsx index 4e29ab19a3..04a5ac5564 100644 --- a/projects/dex-ui/src/pages/Swap.tsx +++ b/projects/dex-ui/src/pages/Swap.tsx @@ -20,7 +20,7 @@ export const Swap = () => { - + ) : ( diff --git a/projects/dex-ui/src/pages/Wells.tsx b/projects/dex-ui/src/pages/Wells.tsx index 12007f21c4..80b848139b 100644 --- a/projects/dex-ui/src/pages/Wells.tsx +++ b/projects/dex-ui/src/pages/Wells.tsx @@ -4,7 +4,7 @@ import { Item } from "src/components/Layout"; import { Page } from "src/components/Page"; import { Title } from "src/components/PageComponents/Title"; import { TabButton } from "src/components/TabButton"; -import { Row, TBody, THead, Table, Td, Th } from "src/components/Table"; +import { Row, TBody, THead, Table, Th } from "src/components/Table"; import { Row as TabRow } from "src/components/Layout"; import { getPrice } from "src/utils/price/usePrice"; import useSdk from "src/utils/sdk/useSdk";