From c427196fa8e1df12a74497e5c29e10bff613a27a Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Wed, 4 Dec 2024 17:33:45 +0000 Subject: [PATCH 01/15] feat: modify layout --- .../CurrencyInputPanel/CurrencyInputPanel.tsx | 34 +++++++-------- .../common/pure/CurrencyInputPanel/styled.tsx | 5 ++- .../containers/LimitOrdersWidget/index.tsx | 14 +++--- .../containers/LimitOrdersWidget/styled.tsx | 5 +-- .../containers/RateInput/index.tsx | 22 +++++++--- .../containers/RateInput/styled.ts | 22 +++++----- .../containers/TradeRateDetails/index.tsx | 19 ++++++-- .../pure/DeadlineSelector/deadlines.ts | 41 ++++++++++++------ .../pure/DeadlineSelector/index.tsx | 2 +- .../pure/DeadlineSelector/styled.tsx | 43 +++++-------------- .../pure/RateInput/HeadingText.tsx | 21 ++++++--- .../TradeWidget/TradeWidgetForm.tsx | 3 ++ .../trade/containers/TradeWidget/types.ts | 1 + 13 files changed, 135 insertions(+), 97 deletions(-) diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsx index 9020f7c004..da4ffec05b 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/CurrencyInputPanel.tsx @@ -163,6 +163,15 @@ export function CurrencyInputPanel(props: CurrencyInputPanelProps) { {topContent} +
+ {inputTooltip ? ( + + {numericalInput} + + ) : ( + numericalInput + )} +
-
- {inputTooltip ? ( - - {numericalInput} - - ) : ( - numericalInput - )} -
+
+ {amount && ( + + + + )} +
{balance && !disabled && ( - Balance: + {showSetMax && balance.greaterThan(0) && ( Max )} )}
-
- {amount && ( - - - - )} -
diff --git a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/styled.tsx b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/styled.tsx index 81d5492220..cd619d4475 100644 --- a/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/styled.tsx +++ b/apps/cowswap-frontend/src/common/pure/CurrencyInputPanel/styled.tsx @@ -81,6 +81,7 @@ export const NumericalInput = styled(Input)<{ $loading: boolean }>` font-size: 28px; font-weight: 500; color: inherit; + text-align: left; &::placeholder { opacity: 0.7; @@ -150,7 +151,9 @@ export const SetMaxBtn = styled.button` border-radius: 6px; padding: 3px 4px; text-transform: uppercase; - transition: background var(${UI.ANIMATION_DURATION}) ease-in-out, color var(${UI.ANIMATION_DURATION}) ease-in-out; + transition: + background var(${UI.ANIMATION_DURATION}) ease-in-out, + color var(${UI.ANIMATION_DURATION}) ease-in-out; &:hover { background: var(${UI.COLOR_PRIMARY}); diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx index a2420948e3..a43684da38 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx @@ -194,17 +194,19 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => {

))} - - - - ), + limitPriceInput: ( + + + + ), bottomContent(warnings) { return ( <> - + + @@ -220,7 +222,7 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { } const params = { - compactView: false, + compactView: true, recipient, showRecipient, isTradePriceUpdating: isRateLoading, diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx index c23762aa09..758c1eae48 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx @@ -20,9 +20,8 @@ export const FooterBox = styled.div` ` export const RateWrapper = styled.div` - display: grid; - grid-template-columns: auto 151px; - grid-template-rows: max-content; + display: flex; + width: 100%; max-width: 100%; gap: 6px; text-align: right; diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index e1d21cab06..9bbfffb9de 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -2,12 +2,12 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useCallback, useEffect, useMemo, useState } from 'react' import { formatInputAmount, getAddress, isFractionFalsy } from '@cowprotocol/common-utils' +import { TokenLogo } from '@cowprotocol/tokens' import { HelpTooltip, Loader, TokenSymbol } from '@cowprotocol/ui' import { useWalletInfo } from '@cowprotocol/wallet' import { RefreshCw } from 'react-feather' - import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOrdersDerivedState' import { useRateImpact } from 'modules/limitOrders/hooks/useRateImpact' import { useUpdateActiveRate } from 'modules/limitOrders/hooks/useUpdateActiveRate' @@ -84,7 +84,7 @@ export function RateInput() { isAlternativeOrderRate: false, }) }, - [isInverted, updateRate, updateLimitRateState] + [isInverted, updateRate, updateLimitRateState], ) // Handle toggle primary field @@ -146,9 +146,20 @@ export function RateInput() { - - Set to market - + {areBothCurrencies && ( + + Market:{' '} + + {isLoadingMarketRate ? ( + + ) : marketRate && !marketRate.equalTo(0) ? ( + formatInputAmount(isInverted ? marketRate.invert() : marketRate) + ) : ( + '' + )} + + + )} @@ -165,6 +176,7 @@ export function RateInput() { + diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index 08d19b62ea..a3f5befebb 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -29,29 +29,31 @@ export const Header = styled.div` font-weight: 500; width: 100%; color: inherit; + + > span > i { + font-style: normal; + color: var(${UI.COLOR_TEXT}); + } ` export const MarketPriceButton = styled.button` - background: var(${UI.COLOR_PAPER}); color: inherit; white-space: nowrap; border: none; font-weight: 500; cursor: pointer; - border-radius: 9px; - padding: 5px 8px; font-size: 11px; - transition: background var(${UI.ANIMATION_DURATION}) ease-in-out, color var(${UI.ANIMATION_DURATION}) ease-in-out; + background: transparent; + padding: 0; + color: var(${UI.COLOR_TEXT}); + transition: + background var(${UI.ANIMATION_DURATION}) ease-in-out, + color var(${UI.ANIMATION_DURATION}) ease-in-out; &:disabled { cursor: default; opacity: 0.6; } - - &:not(:disabled):hover { - background: var(${UI.COLOR_PRIMARY}); - color: var(${UI.COLOR_BUTTON_TEXT}); - } ` export const Body = styled.div` @@ -80,6 +82,7 @@ export const NumericalInput = styled(Input)<{ $loading: boolean }>` export const ActiveCurrency = styled.button` display: flex; + flex-flow: row wrap; align-items: center; justify-content: flex-end; border: none; @@ -87,7 +90,6 @@ export const ActiveCurrency = styled.button` padding: 0; margin: 0 0 0 auto; gap: 8px; - max-width: 130px; width: auto; color: inherit; cursor: pointer; diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/TradeRateDetails/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/TradeRateDetails/index.tsx index 1508275f31..db516ce54d 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/TradeRateDetails/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/TradeRateDetails/index.tsx @@ -2,6 +2,8 @@ import React, { useState, useCallback } from 'react' import { useInjectedWidgetParams } from 'modules/injectedWidget' import { TradeTotalCostsDetails, PartnerFeeRow } from 'modules/trade' +import { StyledRateInfo } from 'modules/trade/containers/TradeTotalCostsDetails/styled' +import { Box } from 'modules/trade/containers/TradeTotalCostsDetails/styled' import { useUsdAmount } from 'modules/usdAmount' import { useVolumeFee, useVolumeFeeTooltip } from 'modules/volumeFee' @@ -11,10 +13,11 @@ import { useLimitOrderPartnerFeeAmount } from '../../hooks/useLimitOrderPartnerF interface TradeRateDetailsProps { rateInfoParams?: RateInfoParams + alwaysExpanded?: boolean } -export function TradeRateDetails({ rateInfoParams }: TradeRateDetailsProps) { - const [isFeeDetailsOpen, setFeeDetailsOpen] = useState(false) +export function TradeRateDetails({ rateInfoParams, alwaysExpanded = false }: TradeRateDetailsProps) { + const [isFeeDetailsOpen, setFeeDetailsOpen] = useState(alwaysExpanded) const widgetParams = useInjectedWidgetParams() const volumeFee = useVolumeFee() const partnerFeeAmount = useLimitOrderPartnerFeeAmount() @@ -23,8 +26,9 @@ export function TradeRateDetails({ rateInfoParams }: TradeRateDetailsProps) { const partnerFeeBps = volumeFee?.bps const toggleAccordion = useCallback(() => { + if (alwaysExpanded) return setFeeDetailsOpen((prev) => !prev) - }, []) + }, [alwaysExpanded]) const partnerFeeRow = ( + + {partnerFeeRow} + + ) + } + return ( = { + [LimitOrderDeadlinePreset.FIVE_MINUTES]: ms`5m`, + [LimitOrderDeadlinePreset.THIRTY_MINUTES]: ms`30m`, + [LimitOrderDeadlinePreset.ONE_HOUR]: ms`1 hour`, + [LimitOrderDeadlinePreset.ONE_DAY]: ms`1d`, + [LimitOrderDeadlinePreset.THREE_DAYS]: ms`3d`, + [LimitOrderDeadlinePreset.ONE_MONTH]: ms`30d`, + [LimitOrderDeadlinePreset.SIX_MONTHS]: MAX_CUSTOM_DEADLINE, +} + +export const defaultLimitOrderDeadline: LimitOrderDeadline = { + title: LimitOrderDeadlinePreset.SIX_MONTHS, + value: DEADLINE_VALUES[LimitOrderDeadlinePreset.SIX_MONTHS], +} + +export const LIMIT_ORDERS_DEADLINES: LimitOrderDeadline[] = Object.entries(DEADLINE_VALUES).map(([title, value]) => ({ + title, + value, +})) /** * Get limit order deadlines and optionally adds diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx index 247d86c01f..32d1fdb777 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/index.tsx @@ -126,7 +126,7 @@ export function DeadlineSelector(props: DeadlineSelectorProps) { return ( - Expiry + Order expires in {isDeadlineDisabled ? ( diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/styled.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/styled.tsx index 8f07cfb6cc..73272e0ef7 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/styled.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/DeadlineSelector/styled.tsx @@ -5,52 +5,32 @@ import { transparentize } from 'color2k' import { X } from 'react-feather' import styled from 'styled-components/macro' -export const Wrapper = styled.div<{ inline?: boolean; minHeight?: string }>` - background: var(${UI.COLOR_PAPER_DARKER}); +export const Wrapper = styled.div` color: inherit; - border-radius: 16px; - padding: 10px 16px; - min-height: ${({ minHeight }) => minHeight || '80px'}; + padding: 0; justify-content: space-between; display: flex; flex-flow: row wrap; - - ${({ inline }) => - inline && - ` - justify-content: space-between; - - > span { - flex: 1; - } - - > button { - width: auto; - } - `} + width: 100%; + font-size: 13px; + font-weight: inherit; + min-height: 24px; ` export const Label = styled.span` display: flex; - align-items: center; - justify-content: space-between; - font-size: 13px; - font-weight: 500; - width: 100%; + font-size: inherit; + font-weight: inherit; color: inherit; - opacity: 0.7; - transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; - - &:hover { - opacity: 1; - } + align-self: center; + justify-self: center; ` export const Current = styled(MenuButton)<{ $custom?: boolean }>` color: inherit; font-size: ${({ $custom }) => ($custom ? '12px' : '100%')}; letter-spacing: ${({ $custom }) => ($custom ? '-0.3px' : '0')}; - font-weight: 500; + font-weight: inherit; display: flex; align-items: center; justify-content: space-between; @@ -61,7 +41,6 @@ export const Current = styled(MenuButton)<{ $custom?: boolean }>` padding: 0; white-space: nowrap; cursor: pointer; - width: 100%; text-overflow: ellipsis; overflow: hidden; diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx index 822e847b32..fda7a6087e 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx @@ -1,4 +1,5 @@ -import { UI } from '@cowprotocol/ui' +import { TokenLogo } from '@cowprotocol/tokens' +import { TokenSymbol, UI } from '@cowprotocol/ui' import { Currency } from '@uniswap/sdk-core' import styled from 'styled-components/macro' @@ -18,12 +19,14 @@ const Wrapper = styled.span` justify-content: flex-start; text-align: left; gap: 0 3px; - opacity: 0.7; transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; +` - &:hover { - opacity: 1; - } +const TokenWrapper = styled.div` + display: flex; + align-items: center; + gap: 4px; + font-weight: bold; ` export function HeadingText({ inputCurrency, currency, rateImpact }: Props) { @@ -33,8 +36,12 @@ export function HeadingText({ inputCurrency, currency, rateImpact }: Props) { return ( - {/* Price of */} - Limit price + When 1 + + + + + is worth {} ) diff --git a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/TradeWidgetForm.tsx b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/TradeWidgetForm.tsx index 6866a903ba..a2f3738b46 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/TradeWidgetForm.tsx +++ b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/TradeWidgetForm.tsx @@ -193,6 +193,7 @@ export function TradeWidgetForm(props: TradeWidgetProps) { /> {!isWrapOrUnwrap && middleContent} + + {slots.limitPriceInput} + {withRecipient && } {isWrapOrUnwrap ? ( diff --git a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/types.ts b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/types.ts index 0cf4606b84..f9fe79e55b 100644 --- a/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/types.ts +++ b/apps/cowswap-frontend/src/modules/trade/containers/TradeWidget/types.ts @@ -38,6 +38,7 @@ export interface TradeWidgetSlots { lockScreen?: ReactNode topContent?: ReactNode middleContent?: ReactNode + limitPriceInput?: ReactNode bottomContent?(warnings: ReactNode | null): ReactNode outerContent?: ReactNode updaters?: ReactNode From 886c4518fad975a3eb11768f43952ab01231a3e4 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:10:34 +0000 Subject: [PATCH 02/15] feat: add limit price usd price toggle --- .../containers/RateInput/index.tsx | 40 ++++++++++++++----- .../containers/RateInput/styled.ts | 34 +++++++++++----- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index 9bbfffb9de..4003faaebb 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -41,6 +41,7 @@ export function RateInput() { const updateLimitRateState = useSetAtom(updateLimitRateAtom) const executionPrice = useAtomValue(executionPriceAtom) const [isQuoteCurrencySet, setIsQuoteCurrencySet] = useState(false) + const [isUsdMode, setIsUsdMode] = useState(false) // Limit order state const { inputCurrency, outputCurrency, inputCurrencyAmount, outputCurrencyAmount } = useLimitOrdersDerivedState() @@ -87,10 +88,21 @@ export function RateInput() { [isInverted, updateRate, updateLimitRateState], ) + // Handle toggle USD mode + const handleToggleUsdMode = useCallback(() => { + setIsUsdMode(!isUsdMode) + }, [isUsdMode]) + // Handle toggle primary field const handleToggle = useCallback(() => { - updateLimitRateState({ isInverted: !isInverted, isTypedValue: false }) - }, [isInverted, updateLimitRateState]) + if (isUsdMode) { + // When in USD mode, just switch to token mode without toggling tokens + setIsUsdMode(false) + } else { + // When already in token mode, toggle between tokens + updateLimitRateState({ isInverted: !isInverted, isTypedValue: false }) + } + }, [isInverted, updateLimitRateState, isUsdMode]) const isDisabledMPrice = useMemo(() => { if (isLoadingMarketRate) return true @@ -174,15 +186,21 @@ export function RateInput() { /> )} - - - - - - - - - + + + + + + + + + + + + + $ + + diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index a3f5befebb..dd8edc787a 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -80,19 +80,33 @@ export const NumericalInput = styled(Input)<{ $loading: boolean }>` } ` -export const ActiveCurrency = styled.button` +export const ActiveCurrency = styled.button<{ $active?: boolean }>` display: flex; - flex-flow: row wrap; align-items: center; - justify-content: flex-end; - border: none; - background: none; - padding: 0; - margin: 0 0 0 auto; - gap: 8px; - width: auto; - color: inherit; + gap: 6px; + background: ${({ theme }) => theme.grey1}; + border: 1px solid ${({ theme, $active }) => ($active ? theme.blue : 'transparent')}; + border-radius: 6px; + padding: 5px 8px; cursor: pointer; + transition: border-color 0.2s ease-in-out; + + &:hover { + border-color: ${({ theme }) => theme.blue}; + } +` + +export const CurrencyToggleGroup = styled.div` + display: flex; + gap: 8px; + align-items: center; +` + +export const UsdButton = styled(ActiveCurrency)` + font-size: 16px; + font-weight: 600; + min-width: 40px; + justify-content: center; ` export const ActiveSymbol = styled.span` From 3c522cc9aeedbf347119a4d040290fc6c4e949fd Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:44:12 +0000 Subject: [PATCH 03/15] feat: add settings limit price position --- .../containers/LimitOrdersWidget/index.tsx | 23 +++- .../containers/RateInput/index.tsx | 14 ++- .../containers/RateInput/styled.ts | 76 +++++++++--- .../pure/RateInput/HeadingText.tsx | 4 +- .../limitOrders/pure/Settings/index.tsx | 111 +++++++++++++++++- .../state/limitOrdersSettingsAtom.ts | 14 ++- 6 files changed, 206 insertions(+), 36 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx index a43684da38..a3ba4e88c7 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx @@ -91,7 +91,7 @@ export function LimitOrdersWidget() { const inputCurrencyInfo: CurrencyInfo = { field: Field.INPUT, - label: isSell ? 'Sell amount' : 'You sell at most', + label: isSell ? 'Sell' : 'You sell at most', currency: inputCurrency, amount: inputCurrencyAmount, isIndependent: isSell, @@ -176,6 +176,12 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { handleUnlock={() => updateLimitOrdersState({ isUnlocked: true })} /> ), + topContent: + props.settingsState.limitPricePosition === 'top' ? ( + + + + ) : undefined, middleContent: ( <> {!isWrapOrUnwrap && @@ -194,16 +200,21 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => {

))} + {props.settingsState.limitPricePosition === 'between' && ( + + + + )} ), - limitPriceInput: ( - - - - ), bottomContent(warnings) { return ( <> + {props.settingsState.limitPricePosition === 'bottom' && ( + + + + )} diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index 4003faaebb..d602adf4c3 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -156,7 +156,16 @@ export function RateInput() { <> - + + + + } + /> {areBothCurrencies && ( @@ -192,9 +201,6 @@ export function RateInput() { - - - diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index dd8edc787a..6c526b99f8 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -9,9 +9,7 @@ export const Wrapper = styled.div` background: var(${UI.COLOR_PAPER_DARKER}); border-radius: 16px; padding: 10px 16px; - flex: 1 1 70%; - min-height: 80px; - justify-content: space-between; + max-width: 100%; display: flex; flex-flow: row wrap; color: inherit; @@ -70,7 +68,7 @@ export const NumericalInput = styled(Input)<{ $loading: boolean }>` align-items: center; background: none; border: none; - width: 100%; + width: max-content; text-align: left; color: inherit; @@ -80,31 +78,71 @@ export const NumericalInput = styled(Input)<{ $loading: boolean }>` } ` +export const CurrencyToggleGroup = styled.div` + display: flex; + align-items: center; + background: transparent; + overflow: hidden; +` + export const ActiveCurrency = styled.button<{ $active?: boolean }>` display: flex; align-items: center; gap: 6px; - background: ${({ theme }) => theme.grey1}; - border: 1px solid ${({ theme, $active }) => ($active ? theme.blue : 'transparent')}; - border-radius: 6px; - padding: 5px 8px; + font-size: 13px; + font-weight: var(${UI.FONT_WEIGHT_MEDIUM}); + border: none; cursor: pointer; - transition: border-color 0.2s ease-in-out; + position: relative; + background: ${({ $active }) => ($active ? 'var(' + UI.COLOR_PAPER + ')' : 'var(' + UI.COLOR_PAPER_DARKEST + ')')}; + color: ${({ $active }) => ($active ? 'var(' + UI.COLOR_TEXT + ')' : 'var(' + UI.COLOR_TEXT_OPACITY_70 + ')')}; + transition: all 0.2s ease-in-out; + + &:first-child { + padding-right: 16px; + + ${({ $active }) => + $active && + ` + &::after { + content: ''; + position: absolute; + right: 0; + top: 0; + bottom: 0; + width: 12px; + background: var(${UI.COLOR_PAPER_DARKER}); + transform: skew(-10deg); + } + `} + } - &:hover { - border-color: ${({ theme }) => theme.blue}; + &:last-child { + padding-left: 16px; + + ${({ $active }) => + $active && + ` + &::before { + content: ''; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 12px; + background: var(${UI.COLOR_PAPER_DARKER}); + transform: skew(-10deg); + } + `} } -` -export const CurrencyToggleGroup = styled.div` - display: flex; - gap: 8px; - align-items: center; + &:hover { + color: var(${UI.COLOR_TEXT}); + } ` export const UsdButton = styled(ActiveCurrency)` - font-size: 16px; - font-weight: 600; + font-weight: var(${UI.FONT_WEIGHT_BOLD}); min-width: 40px; justify-content: center; ` @@ -115,6 +153,8 @@ export const ActiveSymbol = styled.span` font-weight: 500; text-align: right; padding: 10px 0; + display: flex; + gap: 4px; ` export const ActiveIcon = styled.div` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx index fda7a6087e..d828f18e40 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx @@ -10,6 +10,7 @@ type Props = { currency: Currency | null inputCurrency: Currency | null rateImpact: number + toggleIcon?: React.ReactNode } const Wrapper = styled.span` @@ -29,13 +30,14 @@ const TokenWrapper = styled.div` font-weight: bold; ` -export function HeadingText({ inputCurrency, currency, rateImpact }: Props) { +export function HeadingText({ inputCurrency, currency, rateImpact, toggleIcon }: Props) { if (!currency) { return Select input and output } return ( + {toggleIcon} When 1 diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx index a12ec03174..f863b1d759 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx @@ -1,14 +1,104 @@ +import { useCallback, useState } from 'react' + +import { InfoTooltip } from '@cowprotocol/ui' + +import styled from 'styled-components/macro' + import { SettingsBox, SettingsContainer, SettingsTitle } from 'modules/trade/pure/Settings' import { LimitOrdersSettingsState } from '../../state/limitOrdersSettingsAtom' +const DropdownButton = styled.button` + background: var(--color-background-2); + color: inherit; + border: 1px solid var(--color-text); + border-radius: 6px; + padding: 8px 12px; + min-width: 140px; + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + justify-content: space-between; + position: relative; + + &:focus { + outline: none; + border-color: var(--color-text-hover); + } +` + +const DropdownList = styled.div<{ isOpen: boolean }>` + display: ${({ isOpen }) => (isOpen ? 'block' : 'none')}; + position: absolute; + top: 100%; + right: 0; + margin-top: 4px; + background: var(--color-background-2); + border: 1px solid var(--color-text); + border-radius: 6px; + padding: 4px; + min-width: 140px; + z-index: 100; +` + +const DropdownItem = styled.div` + padding: 8px 12px; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + + &:hover { + background: var(--color-background-3); + } +` + +const DropdownContainer = styled.div` + position: relative; +` + +const SettingsRow = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px; + gap: 15px; +` + +const SettingsLabel = styled.div` + display: flex; + align-items: center; + gap: 5px; +` + export interface SettingsProps { state: LimitOrdersSettingsState onStateChanged: (state: Partial) => void } +const POSITION_LABELS = { + top: 'Top', + between: 'Between currencies', + bottom: 'Bottom', +} + export function Settings({ state, onStateChanged }: SettingsProps) { - const { showRecipient, partialFillsEnabled } = state + const { showRecipient, partialFillsEnabled, limitPricePosition } = state + const [isOpen, setIsOpen] = useState(false) + + const handleSelect = useCallback( + (value: LimitOrdersSettingsState['limitPricePosition']) => (e: React.MouseEvent) => { + e.stopPropagation() + onStateChanged({ limitPricePosition: value }) + setIsOpen(false) + }, + [onStateChanged], + ) + + const toggleDropdown = (e: React.MouseEvent) => { + e.stopPropagation() + setIsOpen(!isOpen) + } return ( @@ -37,6 +127,25 @@ export function Settings({ state, onStateChanged }: SettingsProps) { value={partialFillsEnabled} toggle={() => onStateChanged({ partialFillsEnabled: !partialFillsEnabled })} /> + + Layout Settings + + + + Limit Price Position + + + + {POSITION_LABELS[limitPricePosition]} + + {Object.entries(POSITION_LABELS).map(([value, label]) => ( + + {label} + + ))} + + + ) } diff --git a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts index b4df5c2ef4..f902310e2c 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts @@ -17,6 +17,7 @@ export interface LimitOrdersSettingsState { readonly partialFillsEnabled: boolean readonly deadlineMilliseconds: Milliseconds readonly customDeadlineTimestamp: Timestamp | null + readonly limitPricePosition: 'top' | 'between' | 'bottom' } export const defaultLimitOrdersSettings: LimitOrdersSettingsState = { @@ -24,40 +25,41 @@ export const defaultLimitOrdersSettings: LimitOrdersSettingsState = { partialFillsEnabled: true, deadlineMilliseconds: defaultLimitOrderDeadline.value, customDeadlineTimestamp: null, + limitPricePosition: 'between', } // regular const regularLimitOrdersSettingsAtom = atomWithStorage( 'limit-orders-settings-atom:v2', defaultLimitOrdersSettings, - getJotaiIsolatedStorage() + getJotaiIsolatedStorage(), ) const regularUpdateLimitOrdersSettingsAtom = atom( null, - partialFillsOverrideSetterFactory(regularLimitOrdersSettingsAtom) + partialFillsOverrideSetterFactory(regularLimitOrdersSettingsAtom), ) // alternative const alternativeLimitOrdersSettingsAtom = atom(defaultLimitOrdersSettings) const alternativeUpdateLimitOrdersSettingsAtom = atom( null, - partialFillsOverrideSetterFactory(alternativeLimitOrdersSettingsAtom) + partialFillsOverrideSetterFactory(alternativeLimitOrdersSettingsAtom), ) // export export const limitOrdersSettingsAtom = alternativeOrderReadWriteAtomFactory( regularLimitOrdersSettingsAtom, - alternativeLimitOrdersSettingsAtom + alternativeLimitOrdersSettingsAtom, ) export const updateLimitOrdersSettingsAtom = atom( null, - alternativeOrderAtomSetterFactory(regularUpdateLimitOrdersSettingsAtom, alternativeUpdateLimitOrdersSettingsAtom) + alternativeOrderAtomSetterFactory(regularUpdateLimitOrdersSettingsAtom, alternativeUpdateLimitOrdersSettingsAtom), ) // utils function partialFillsOverrideSetterFactory( - atomToUpdate: typeof regularLimitOrdersSettingsAtom | typeof alternativeLimitOrdersSettingsAtom + atomToUpdate: typeof regularLimitOrdersSettingsAtom | typeof alternativeLimitOrdersSettingsAtom, ) { return (get: Getter, set: Setter, nextState: Partial) => { set(atomToUpdate, () => { From 51f9267e6f0a105d2ec7830a3608afb73a022ed3 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:34:53 +0000 Subject: [PATCH 04/15] feat: toggle usd input skew style --- .../containers/RateInput/styled.ts | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index 6c526b99f8..12b372e712 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -47,6 +47,11 @@ export const MarketPriceButton = styled.button` transition: background var(${UI.ANIMATION_DURATION}) ease-in-out, color var(${UI.ANIMATION_DURATION}) ease-in-out; + text-decoration: underline; + text-decoration-style: dashed; + text-decoration-thickness: 1px; + text-underline-offset: 2px; + text-decoration-color: var(${UI.COLOR_TEXT_OPACITY_70}); &:disabled { cursor: default; @@ -60,6 +65,7 @@ export const Body = styled.div` justify-content: space-between; width: 100%; gap: 8px; + padding: 12px 0 4px; color: inherit; ` @@ -86,20 +92,33 @@ export const CurrencyToggleGroup = styled.div` ` export const ActiveCurrency = styled.button<{ $active?: boolean }>` + --height: 25px; + --skew-width: 6px; + --skew-offset: -3px; + --skew-angle: -10deg; + --padding: 16px; + --gap: 6px; + --font-size: 13px; + --border-radius: 8px; + display: flex; align-items: center; - gap: 6px; - font-size: 13px; + gap: var(--gap); + font-size: var(--font-size); font-weight: var(${UI.FONT_WEIGHT_MEDIUM}); border: none; cursor: pointer; position: relative; + height: var(--height); + border-radius: var(--border-radius); + transition: all 0.2s ease-in-out; background: ${({ $active }) => ($active ? 'var(' + UI.COLOR_PAPER + ')' : 'var(' + UI.COLOR_PAPER_DARKEST + ')')}; color: ${({ $active }) => ($active ? 'var(' + UI.COLOR_TEXT + ')' : 'var(' + UI.COLOR_TEXT_OPACITY_70 + ')')}; - transition: all 0.2s ease-in-out; &:first-child { - padding-right: 16px; + padding-right: var(--padding); + border-top-right-radius: 0; + border-bottom-right-radius: 0; ${({ $active }) => $active && @@ -107,18 +126,21 @@ export const ActiveCurrency = styled.button<{ $active?: boolean }>` &::after { content: ''; position: absolute; - right: 0; + right: var(--skew-offset); top: 0; bottom: 0; - width: 12px; + width: var(--skew-width); background: var(${UI.COLOR_PAPER_DARKER}); - transform: skew(-10deg); + transform: skew(var(--skew-angle)); + z-index: 5; } `} } &:last-child { - padding-left: 16px; + padding-left: var(--padding); + border-top-left-radius: 0; + border-bottom-left-radius: 0; ${({ $active }) => $active && @@ -126,12 +148,13 @@ export const ActiveCurrency = styled.button<{ $active?: boolean }>` &::before { content: ''; position: absolute; - left: 0; + left: var(--skew-offset); top: 0; bottom: 0; - width: 12px; + width: var(--skew-width); background: var(${UI.COLOR_PAPER_DARKER}); - transform: skew(-10deg); + transform: skew(var(--skew-angle)); + z-index: 5; } `} } From 745d0ae2051c89ba5457871cb2a6a5daddcf681a Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:08:48 +0000 Subject: [PATCH 05/15] feat: toggle usd input skew style --- .../limitOrders/containers/RateInput/index.tsx | 2 +- .../limitOrders/containers/RateInput/styled.ts | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index d602adf4c3..572fb2de05 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -197,7 +197,7 @@ export function RateInput() { - + diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index 12b372e712..ab48efc6c3 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -1,4 +1,4 @@ -import { Loader, Media } from '@cowprotocol/ui' +import { Loader, Media, TokenSymbol } from '@cowprotocol/ui' import { UI } from '@cowprotocol/ui' import styled from 'styled-components/macro' @@ -170,7 +170,7 @@ export const UsdButton = styled(ActiveCurrency)` justify-content: center; ` -export const ActiveSymbol = styled.span` +export const ActiveSymbol = styled.span<{ $active?: boolean }>` color: inherit; font-size: 13px; font-weight: 500; @@ -178,6 +178,18 @@ export const ActiveSymbol = styled.span` padding: 10px 0; display: flex; gap: 4px; + + ${({ $active }) => + !$active && + ` + > div > img { + opacity: 0.5; + } + + > ${TokenSymbol} { + color: var(${UI.COLOR_TEXT_OPACITY_50}); + } + `} ` export const ActiveIcon = styled.div` From fcee6432f65ed88044ce40dae37c4d25b1942b39 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:43:08 +0000 Subject: [PATCH 06/15] feat: update limit order input layouti --- .../limitOrders/containers/LimitOrdersWidget/styled.tsx | 6 ------ .../src/modules/limitOrders/containers/RateInput/styled.ts | 6 +++++- .../modules/limitOrders/state/limitOrdersSettingsAtom.ts | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx index 758c1eae48..642a750647 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx @@ -2,8 +2,6 @@ import { Media } from '@cowprotocol/ui' import styled from 'styled-components/macro' -import { NumericalInput } from 'modules/limitOrders/containers/RateInput/styled' - export const TradeButtonBox = styled.div` margin: 10px 0 0; display: flex; @@ -31,8 +29,4 @@ export const RateWrapper = styled.div` display: flex; flex-flow: column wrap; } - - ${NumericalInput} { - font-size: 21px; - } ` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index ab48efc6c3..0e7e853b3d 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -9,6 +9,7 @@ export const Wrapper = styled.div` background: var(${UI.COLOR_PAPER_DARKER}); border-radius: 16px; padding: 10px 16px; + width: 100%; max-width: 100%; display: flex; flex-flow: row wrap; @@ -64,6 +65,7 @@ export const Body = styled.div` align-items: center; justify-content: space-between; width: 100%; + max-width: 100%; gap: 8px; padding: 12px 0 4px; color: inherit; @@ -74,9 +76,11 @@ export const NumericalInput = styled(Input)<{ $loading: boolean }>` align-items: center; background: none; border: none; - width: max-content; text-align: left; color: inherit; + font-size: 32px; + letter-spacing: -1.5px; + flex: 1 1 auto; &::placeholder { opacity: 0.7; diff --git a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts index f902310e2c..683a01ab15 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts @@ -25,7 +25,7 @@ export const defaultLimitOrdersSettings: LimitOrdersSettingsState = { partialFillsEnabled: true, deadlineMilliseconds: defaultLimitOrderDeadline.value, customDeadlineTimestamp: null, - limitPricePosition: 'between', + limitPricePosition: 'top', } // regular From feb5262aa0a2f743adc87b06b1d8442c8d025760 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:19:45 +0000 Subject: [PATCH 07/15] feat: style rate input and switch --- .../containers/RateInput/index.tsx | 12 +++--- .../containers/RateInput/styled.ts | 39 ++++++++++++++++--- .../pure/RateInput/HeadingText.tsx | 13 +++++-- libs/assets/src/images/icon-USD.svg | 1 + libs/assets/src/images/icon-switch-arrows.svg | 1 + 5 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 libs/assets/src/images/icon-USD.svg create mode 100644 libs/assets/src/images/icon-switch-arrows.svg diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index 572fb2de05..31462679e9 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -1,12 +1,14 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useCallback, useEffect, useMemo, useState } from 'react' +import SwitchArrowsIcon from '@cowprotocol/assets/images/icon-switch-arrows.svg' +import UsdIcon from '@cowprotocol/assets/images/icon-USD.svg' import { formatInputAmount, getAddress, isFractionFalsy } from '@cowprotocol/common-utils' import { TokenLogo } from '@cowprotocol/tokens' import { HelpTooltip, Loader, TokenSymbol } from '@cowprotocol/ui' import { useWalletInfo } from '@cowprotocol/wallet' -import { RefreshCw } from 'react-feather' +import SVG from 'react-inlinesvg' import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOrdersDerivedState' import { useRateImpact } from 'modules/limitOrders/hooks/useRateImpact' @@ -162,13 +164,13 @@ export function RateInput() { rateImpact={rateImpact} toggleIcon={ - + } /> {areBothCurrencies && ( - + Market:{' '} {isLoadingMarketRate ? ( @@ -179,7 +181,7 @@ export function RateInput() { '' )} - + )} @@ -204,7 +206,7 @@ export function RateInput() { - $ + diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index 0e7e853b3d..b7cc7db780 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -8,7 +8,7 @@ import Input from 'legacy/components/NumericalInput' export const Wrapper = styled.div` background: var(${UI.COLOR_PAPER_DARKER}); border-radius: 16px; - padding: 10px 16px; + padding: 16px; width: 100%; max-width: 100%; display: flex; @@ -35,13 +35,26 @@ export const Header = styled.div` } ` +export const MarketRateWrapper = styled.div` + display: flex; + align-items: center; + gap: 4px; + font-size: 12px; + font-weight: 400; + + > i { + font-style: normal; + color: var(${UI.COLOR_TEXT_OPACITY_70}); + } +` + export const MarketPriceButton = styled.button` color: inherit; white-space: nowrap; border: none; font-weight: 500; cursor: pointer; - font-size: 11px; + font-size: inherit; background: transparent; padding: 0; color: var(${UI.COLOR_TEXT}); @@ -56,7 +69,8 @@ export const MarketPriceButton = styled.button` &:disabled { cursor: default; - opacity: 0.6; + opacity: 0.7; + text-decoration: none; } ` @@ -100,7 +114,7 @@ export const ActiveCurrency = styled.button<{ $active?: boolean }>` --skew-width: 6px; --skew-offset: -3px; --skew-angle: -10deg; - --padding: 16px; + --padding: 10px; --gap: 6px; --font-size: 13px; --border-radius: 8px; @@ -118,6 +132,7 @@ export const ActiveCurrency = styled.button<{ $active?: boolean }>` transition: all 0.2s ease-in-out; background: ${({ $active }) => ($active ? 'var(' + UI.COLOR_PAPER + ')' : 'var(' + UI.COLOR_PAPER_DARKEST + ')')}; color: ${({ $active }) => ($active ? 'var(' + UI.COLOR_TEXT + ')' : 'var(' + UI.COLOR_TEXT_OPACITY_70 + ')')}; + padding: 0 10px; &:first-child { padding-right: var(--padding); @@ -172,6 +187,12 @@ export const UsdButton = styled(ActiveCurrency)` font-weight: var(${UI.FONT_WEIGHT_BOLD}); min-width: 40px; justify-content: center; + + > svg { + width: 7px; + height: 12px; + color: inherit; + } ` export const ActiveSymbol = styled.span<{ $active?: boolean }>` @@ -197,8 +218,7 @@ export const ActiveSymbol = styled.span<{ $active?: boolean }>` ` export const ActiveIcon = styled.div` - --size: 20px; - background-color: var(${UI.COLOR_PAPER}); + --size: 16px; color: inherit; width: var(--size); min-width: var(--size); @@ -208,6 +228,13 @@ export const ActiveIcon = styled.div` display: flex; align-items: center; justify-content: center; + cursor: pointer; + margin: 0; + transition: color var(${UI.ANIMATION_DURATION}) ease-in-out; + + &:hover { + color: var(${UI.COLOR_TEXT}); + } ` export const RateLoader = styled(Loader)` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx index d828f18e40..2ef0b0cbbd 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx @@ -16,18 +16,22 @@ type Props = { const Wrapper = styled.span` display: flex; flex-flow: row wrap; - align-items: flex-start; + align-items: center; justify-content: flex-start; text-align: left; gap: 0 3px; - transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; + font-size: 13px; + font-weight: 400; + margin: auto 0; + color: var(${UI.COLOR_TEXT_OPACITY_70}); ` const TokenWrapper = styled.div` display: flex; align-items: center; gap: 4px; - font-weight: bold; + font-weight: 600; + color: var(${UI.COLOR_TEXT}); ` export function HeadingText({ inputCurrency, currency, rateImpact, toggleIcon }: Props) { @@ -38,8 +42,9 @@ export function HeadingText({ inputCurrency, currency, rateImpact, toggleIcon }: return ( {toggleIcon} - When 1 + When + 1 diff --git a/libs/assets/src/images/icon-USD.svg b/libs/assets/src/images/icon-USD.svg new file mode 100644 index 0000000000..f25534c9af --- /dev/null +++ b/libs/assets/src/images/icon-USD.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/libs/assets/src/images/icon-switch-arrows.svg b/libs/assets/src/images/icon-switch-arrows.svg new file mode 100644 index 0000000000..98b6786c9b --- /dev/null +++ b/libs/assets/src/images/icon-switch-arrows.svg @@ -0,0 +1 @@ + \ No newline at end of file From 09a817b1bf0ee2ad0f984ad5561d99d7ce026ac2 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:44:57 +0000 Subject: [PATCH 08/15] feat: add estimated fill price --- .../containers/LimitOrdersWidget/styled.tsx | 5 +- .../containers/RateInput/index.tsx | 53 +++--------- .../containers/RateInput/styled.ts | 26 +++--- .../pure/EstimatedFillPrice/index.tsx | 82 +++++++++++++++++++ 4 files changed, 112 insertions(+), 54 deletions(-) create mode 100644 apps/cowswap-frontend/src/modules/limitOrders/pure/EstimatedFillPrice/index.tsx diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx index 642a750647..1c0c34d7df 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/styled.tsx @@ -1,4 +1,4 @@ -import { Media } from '@cowprotocol/ui' +import { Media, UI } from '@cowprotocol/ui' import styled from 'styled-components/macro' @@ -19,11 +19,14 @@ export const FooterBox = styled.div` export const RateWrapper = styled.div` display: flex; + flex-flow: column wrap; width: 100%; max-width: 100%; gap: 6px; text-align: right; color: inherit; + background: var(${UI.COLOR_PAPER_DARKER}); + border-radius: 16px; ${Media.upToSmall()} { display: flex; diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index 31462679e9..c1246a5aad 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -5,7 +5,7 @@ import SwitchArrowsIcon from '@cowprotocol/assets/images/icon-switch-arrows.svg' import UsdIcon from '@cowprotocol/assets/images/icon-USD.svg' import { formatInputAmount, getAddress, isFractionFalsy } from '@cowprotocol/common-utils' import { TokenLogo } from '@cowprotocol/tokens' -import { HelpTooltip, Loader, TokenSymbol } from '@cowprotocol/ui' +import { Loader, TokenSymbol } from '@cowprotocol/ui' import { useWalletInfo } from '@cowprotocol/wallet' import SVG from 'react-inlinesvg' @@ -13,13 +13,11 @@ import SVG from 'react-inlinesvg' import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOrdersDerivedState' import { useRateImpact } from 'modules/limitOrders/hooks/useRateImpact' import { useUpdateActiveRate } from 'modules/limitOrders/hooks/useUpdateActiveRate' -import { ExecutionPriceTooltip } from 'modules/limitOrders/pure/ExecutionPriceTooltip' import { HeadingText } from 'modules/limitOrders/pure/RateInput/HeadingText' import { executionPriceAtom } from 'modules/limitOrders/state/executionPriceAtom' import { limitRateAtom, updateLimitRateAtom } from 'modules/limitOrders/state/limitRateAtom' import { toFraction } from 'modules/limitOrders/utils/toFraction' -import { ordersTableFeatures } from 'common/constants/featureFlags' import { ExecutionPrice } from 'common/pure/ExecutionPrice' import { getQuoteCurrency, getQuoteCurrencyByStableCoin } from 'common/services/getQuoteCurrency' @@ -28,17 +26,8 @@ import * as styledEl from './styled' export function RateInput() { const { chainId } = useWalletInfo() // Rate state - const { - isInverted, - activeRate, - isLoading, - marketRate, - feeAmount, - isLoadingMarketRate, - typedValue, - isTypedValue, - initialRate, - } = useAtomValue(limitRateAtom) + const { isInverted, activeRate, isLoading, marketRate, isLoadingMarketRate, typedValue, isTypedValue, initialRate } = + useAtomValue(limitRateAtom) const updateRate = useUpdateActiveRate() const updateLimitRateState = useSetAtom(updateLimitRateAtom) const executionPrice = useAtomValue(executionPriceAtom) @@ -184,7 +173,6 @@ export function RateInput() { )} - {isLoading && areBothCurrencies ? ( @@ -212,31 +200,16 @@ export function RateInput() { - {ordersTableFeatures.DISPLAY_EST_EXECUTION_PRICE && ( - - - Order executes at{' '} - {isLoadingMarketRate ? ( - - ) : executionPrice ? ( - - } - /> - ) : null} - - {!isLoadingMarketRate && executionPrice && ( - - )} - - )} + + + {isLoadingMarketRate ? ( + + ) : executionPrice ? ( + + ) : null} + + Estimated fill price + ) } diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index b7cc7db780..ff11208e89 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -6,9 +6,7 @@ import styled from 'styled-components/macro' import Input from 'legacy/components/NumericalInput' export const Wrapper = styled.div` - background: var(${UI.COLOR_PAPER_DARKER}); - border-radius: 16px; - padding: 16px; + padding: 16px 16px 0; width: 100%; max-width: 100%; display: flex; @@ -245,27 +243,22 @@ export const EstimatedRate = styled.div` display: flex; width: 100%; justify-content: space-between; - min-height: 42px; + min-height: 36px; margin: 0; padding: 12px 10px 14px; - font-size: 13px; + font-size: 16px; border-radius: 0 0 16px 16px; - font-weight: 400; + font-weight: 500; + color: var(${UI.COLOR_TEXT}); background: var(${UI.COLOR_PAPER}); border: 2px solid var(${UI.COLOR_PAPER_DARKER}); - background: red; > b { display: flex; flex-flow: row nowrap; - font-weight: normal; + font-weight: inherit; text-align: left; - opacity: 0.7; transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; - - &:hover { - opacity: 1; - } } // TODO: Make the question helper icon transparent through a prop instead @@ -283,4 +276,11 @@ export const EstimatedRate = styled.div` color: inherit; opacity: 0.7; } + + > span { + font-size: 13px; + font-weight: 400; + color: var(${UI.COLOR_TEXT_OPACITY_70}); + text-align: right; + } ` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/EstimatedFillPrice/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/EstimatedFillPrice/index.tsx new file mode 100644 index 0000000000..5c9b4e47c9 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/EstimatedFillPrice/index.tsx @@ -0,0 +1,82 @@ +import { TokenAmount, HoverTooltip } from '@cowprotocol/ui' +import { UI } from '@cowprotocol/ui' +import { FractionLike, Nullish } from '@cowprotocol/ui' +import { Currency, Price, CurrencyAmount, Fraction } from '@uniswap/sdk-core' + +import styled from 'styled-components/macro' + +import { ExecutionPriceTooltip } from '../ExecutionPriceTooltip' + +const EstimatedFillPriceBox = styled.div` + display: flex; + justify-content: space-between; + padding: 10px; + border-radius: 0 0 16px 16px; + font-size: 14px; + font-weight: 600; + background: var(${UI.COLOR_PAPER}); + border: 1px solid var(${UI.COLOR_PAPER_DARKER}); +` + +const Label = styled.div` + display: flex; + align-items: center; + gap: 5px; + font-weight: 500; +` + +const Value = styled.div` + font-size: 16px; + display: flex; + align-items: center; + gap: 4px; +` + +const QuestionWrapper = styled.div` + display: flex; + align-items: center; +` + +export interface EstimatedFillPriceProps { + currency: Currency + estimatedFillPrice: Nullish + executionPrice: Price + isInverted: boolean + feeAmount: CurrencyAmount | null + marketRate: Fraction | null +} + +export function EstimatedFillPrice({ + currency, + estimatedFillPrice, + executionPrice, + isInverted, + feeAmount, + marketRate, +}: EstimatedFillPriceProps) { + return ( + + + + ≈ + + + ) +} From 369cf28002a6603a206757b772802806bac3f80c Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 16:50:09 +0000 Subject: [PATCH 09/15] feat: add estimated fill price --- .../src/modules/limitOrders/containers/RateInput/index.tsx | 7 +++++-- .../src/modules/limitOrders/containers/RateInput/styled.ts | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index c1246a5aad..2699e8e0a2 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -5,7 +5,7 @@ import SwitchArrowsIcon from '@cowprotocol/assets/images/icon-switch-arrows.svg' import UsdIcon from '@cowprotocol/assets/images/icon-USD.svg' import { formatInputAmount, getAddress, isFractionFalsy } from '@cowprotocol/common-utils' import { TokenLogo } from '@cowprotocol/tokens' -import { Loader, TokenSymbol } from '@cowprotocol/ui' +import { Loader, TokenSymbol, HelpTooltip } from '@cowprotocol/ui' import { useWalletInfo } from '@cowprotocol/wallet' import SVG from 'react-inlinesvg' @@ -208,7 +208,10 @@ export function RateInput() { ) : null} - Estimated fill price + + Estimated fill price + + ) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index ff11208e89..ab5e7a4820 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -278,6 +278,8 @@ export const EstimatedRate = styled.div` } > span { + display: flex; + align-items: center; font-size: 13px; font-weight: 400; color: var(${UI.COLOR_TEXT_OPACITY_70}); From d57f2d64ad6e71bed38b532f1ce71044b69fe2da Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:03:48 +0000 Subject: [PATCH 10/15] feat: add estimated fill price --- .../modules/limitOrders/containers/RateInput/index.tsx | 4 ++-- .../modules/limitOrders/containers/RateInput/styled.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index 2699e8e0a2..de5aa5559c 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -163,7 +163,7 @@ export function RateInput() { Market:{' '} {isLoadingMarketRate ? ( - + ) : marketRate && !marketRate.equalTo(0) ? ( formatInputAmount(isInverted ? marketRate.invert() : marketRate) ) : ( @@ -203,7 +203,7 @@ export function RateInput() { {isLoadingMarketRate ? ( - + ) : executionPrice ? ( ) : null} diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index ab5e7a4820..d05542f4a2 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -65,6 +65,10 @@ export const MarketPriceButton = styled.button` text-underline-offset: 2px; text-decoration-color: var(${UI.COLOR_TEXT_OPACITY_70}); + > svg { + margin: 0 0 -2px 7px; + } + &:disabled { cursor: default; opacity: 0.7; @@ -259,12 +263,13 @@ export const EstimatedRate = styled.div` font-weight: inherit; text-align: left; transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; + color: inherit; } - // TODO: Make the question helper icon transparent through a prop instead > b svg { opacity: 0.7; transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; + color: inherit; &:hover { opacity: 1; @@ -283,6 +288,5 @@ export const EstimatedRate = styled.div` font-size: 13px; font-weight: 400; color: var(${UI.COLOR_TEXT_OPACITY_70}); - text-align: right; } ` From f8c7c2a107b28c936ea024c11cd2d4542a1091ba Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:54:20 +0000 Subject: [PATCH 11/15] feat: style limit settings menu --- .../containers/RateInput/index.tsx | 6 +- .../containers/SettingsWidget/index.tsx | 23 +++---- .../limitOrders/pure/Settings/index.tsx | 65 +++++++++++++------ .../src/modules/trade/pure/Settings/styled.ts | 6 +- 4 files changed, 63 insertions(+), 37 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index de5aa5559c..cbb91cf43c 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -5,7 +5,7 @@ import SwitchArrowsIcon from '@cowprotocol/assets/images/icon-switch-arrows.svg' import UsdIcon from '@cowprotocol/assets/images/icon-USD.svg' import { formatInputAmount, getAddress, isFractionFalsy } from '@cowprotocol/common-utils' import { TokenLogo } from '@cowprotocol/tokens' -import { Loader, TokenSymbol, HelpTooltip } from '@cowprotocol/ui' +import { TokenSymbol, HelpTooltip } from '@cowprotocol/ui' import { useWalletInfo } from '@cowprotocol/wallet' import SVG from 'react-inlinesvg' @@ -206,7 +206,9 @@ export function RateInput() { ) : executionPrice ? ( - ) : null} + ) : ( + '-' + )} Estimated fill price diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx index 00267f9fb2..450aafe25c 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx @@ -1,5 +1,4 @@ import { useAtomValue, useSetAtom } from 'jotai' -import React from 'react' import { Menu, MenuItem } from '@reach/menu-button' @@ -13,17 +12,15 @@ export function SettingsWidget() { const updateSettingsState = useSetAtom(updateLimitOrdersSettingsAtom) return ( - <> - - - - - - void 0}> - - - - - + + + + + + void 0}> + + + + ) } diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx index f863b1d759..1582c4390e 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx @@ -1,6 +1,7 @@ import { useCallback, useState } from 'react' -import { InfoTooltip } from '@cowprotocol/ui' +import { UI } from '@cowprotocol/ui' +import { HelpTooltip } from '@cowprotocol/ui' import styled from 'styled-components/macro' @@ -9,11 +10,11 @@ import { SettingsBox, SettingsContainer, SettingsTitle } from 'modules/trade/pur import { LimitOrdersSettingsState } from '../../state/limitOrdersSettingsAtom' const DropdownButton = styled.button` - background: var(--color-background-2); + background: var(${UI.COLOR_PAPER_DARKER}); color: inherit; - border: 1px solid var(--color-text); - border-radius: 6px; - padding: 8px 12px; + border: 1px solid var(${UI.COLOR_BORDER}); + border-radius: 12px; + padding: 10px 34px 10px 12px; min-width: 140px; cursor: pointer; font-size: 14px; @@ -21,48 +22,74 @@ const DropdownButton = styled.button` align-items: center; justify-content: space-between; position: relative; + transition: all 0.2s ease-in-out; + + &::after { + content: '▼'; + position: absolute; + right: 12px; + top: 50%; + transform: translateY(-50%); + font-size: 10px; + transition: transform 0.2s ease-in-out; + color: var(${UI.COLOR_PRIMARY_OPACITY_50}); + } + + &:hover { + border-color: var(${UI.COLOR_PRIMARY_OPACITY_25}); + background: var(${UI.COLOR_PRIMARY_OPACITY_10}); + } &:focus { outline: none; - border-color: var(--color-text-hover); } ` const DropdownList = styled.div<{ isOpen: boolean }>` display: ${({ isOpen }) => (isOpen ? 'block' : 'none')}; position: absolute; - top: 100%; + top: calc(100% + 8px); right: 0; - margin-top: 4px; - background: var(--color-background-2); - border: 1px solid var(--color-text); - border-radius: 6px; - padding: 4px; + background: var(${UI.COLOR_PAPER}); + border: 1px solid var(${UI.COLOR_BORDER}); + border-radius: 12px; + padding: 6px; min-width: 140px; z-index: 100; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); ` const DropdownItem = styled.div` - padding: 8px 12px; - border-radius: 4px; + padding: 10px 12px; + border-radius: 8px; cursor: pointer; font-size: 14px; + transition: all 0.15s ease-in-out; + color: inherit; &:hover { - background: var(--color-background-3); + background: var(${UI.COLOR_PRIMARY_OPACITY_10}); + transform: translateX(2px); + } + + &:active { + transform: translateX(2px) scale(0.98); } ` const DropdownContainer = styled.div` position: relative; + user-select: none; ` const SettingsRow = styled.div` display: flex; justify-content: space-between; align-items: center; - padding: 16px; gap: 15px; + font-weight: 400; + color: inherit; + font-size: 14px; ` const SettingsLabel = styled.div` @@ -102,7 +129,7 @@ export function Settings({ state, onStateChanged }: SettingsProps) { return ( - Interface Settings + Limit Order Settings onStateChanged({ partialFillsEnabled: !partialFillsEnabled })} /> - Layout Settings - Limit Price Position - + {POSITION_LABELS[limitPricePosition]} diff --git a/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts b/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts index 8ae70bc993..9448db9d4a 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts +++ b/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts @@ -6,9 +6,11 @@ import styled from 'styled-components/macro' export const SettingsTitle = styled.h3` font-weight: 600; - font-size: 14px; + font-size: 18px; color: inherit; - margin: 0 0 12px 0; + margin: 0 auto 21px; + width: 100%; + text-align: center; ` export const SettingsContainer = styled.div` From 7364354786913c28403804cd05da7cef0e48e6b8 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Thu, 5 Dec 2024 19:02:42 +0000 Subject: [PATCH 12/15] feat: add USD settings button --- .../containers/RateInput/styled.ts | 4 +- .../containers/SettingsWidget/index.tsx | 32 ++++++++---- .../trade/pure/Settings/SettingsIcon.tsx | 18 ++----- .../src/modules/trade/pure/Settings/styled.ts | 50 ++++++++++++++++++- libs/assets/src/images/icon-USD.svg | 2 +- 5 files changed, 77 insertions(+), 29 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index d05542f4a2..86532fa202 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -191,8 +191,8 @@ export const UsdButton = styled(ActiveCurrency)` justify-content: center; > svg { - width: 7px; - height: 12px; + width: 10px; + height: 16px; color: inherit; } ` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx index 450aafe25c..5750c21f07 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/SettingsWidget/index.tsx @@ -1,8 +1,11 @@ import { useAtomValue, useSetAtom } from 'jotai' +import UsdIcon from '@cowprotocol/assets/images/icon-USD.svg' + import { Menu, MenuItem } from '@reach/menu-button' +import SVG from 'react-inlinesvg' -import { MenuContent, SettingsButton, SettingsIcon } from 'modules/trade/pure/Settings' +import { ButtonsContainer, MenuContent, SettingsButton, SettingsIcon, UsdButton } from 'modules/trade/pure/Settings' import { Settings } from '../../pure/Settings' import { limitOrdersSettingsAtom, updateLimitOrdersSettingsAtom } from '../../state/limitOrdersSettingsAtom' @@ -12,15 +15,22 @@ export function SettingsWidget() { const updateSettingsState = useSetAtom(updateLimitOrdersSettingsAtom) return ( - - - - - - void 0}> - - - - + + {/* TODO: add active state */} + + + + + + {/* TODO: add active state */} + + + + void 0}> + + + + + ) } diff --git a/apps/cowswap-frontend/src/modules/trade/pure/Settings/SettingsIcon.tsx b/apps/cowswap-frontend/src/modules/trade/pure/Settings/SettingsIcon.tsx index a3a5694823..9f145ac95c 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/Settings/SettingsIcon.tsx +++ b/apps/cowswap-frontend/src/modules/trade/pure/Settings/SettingsIcon.tsx @@ -1,23 +1,13 @@ import IMAGE_ICON_SETTINGS_ALT from '@cowprotocol/assets/images/icon-settings-alt.svg' -import { UI } from '@cowprotocol/ui' import SVG from 'react-inlinesvg' -import styled from 'styled-components/macro' -const StyledMenuIcon = styled.span` - height: var(${UI.ICON_SIZE_NORMAL}); - width: var(${UI.ICON_SIZE_NORMAL}); - opacity: 0.6; +import { SettingsButtonIcon } from './styled' - &:hover { - opacity: 1; - } -` - -export function SettingsIcon() { +export function SettingsIcon({ active }: { active?: boolean }) { return ( - + - + ) } diff --git a/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts b/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts index 9448db9d4a..0570b448da 100644 --- a/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts +++ b/apps/cowswap-frontend/src/modules/trade/pure/Settings/styled.ts @@ -2,7 +2,7 @@ import { UI } from '@cowprotocol/ui' import { MenuButton, MenuList } from '@reach/menu-button' import { transparentize } from 'color2k' -import styled from 'styled-components/macro' +import styled, { css } from 'styled-components/macro' export const SettingsTitle = styled.h3` font-weight: 600; @@ -58,8 +58,56 @@ export const SettingsButton = styled(MenuButton)` cursor: pointer; ` +const iconButtonStyles = css<{ active?: boolean; iconSize?: string }>` + --maxSize: 28px; + --iconSize: ${({ iconSize }) => iconSize || `var(${UI.ICON_SIZE_NORMAL})`}; + background: ${({ active }) => (active ? `var(${UI.COLOR_PAPER_DARKER})` : 'none')}; + border: none; + padding: 4px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + color: var(${UI.COLOR_TEXT}); + opacity: ${({ active }) => (active ? '1' : '0.6')}; + transition: all var(${UI.ANIMATION_DURATION}) ease-in-out; + border-radius: 8px; + max-width: var(--maxSize); + max-height: var(--maxSize); + width: var(--maxSize); + height: var(--maxSize); + + &:hover { + opacity: 1; + background: var(${UI.COLOR_PAPER_DARKER}); + } + + > svg { + width: var(--iconSize); + height: var(--iconSize); + color: inherit; + object-fit: contain; + } +` + +export const SettingsButtonIcon = styled.span<{ active?: boolean; iconSize?: string }>` + ${iconButtonStyles} + --iconSize: 18px; + margin: auto; +` + export const MenuContent = styled(MenuList)` position: relative; z-index: 2; color: var(${UI.COLOR_TEXT_PAPER}); ` + +export const ButtonsContainer = styled.div` + display: flex; + gap: 4px; +` + +export const UsdButton = styled.button<{ active?: boolean }>` + ${iconButtonStyles} + --iconSize: 20px; +` diff --git a/libs/assets/src/images/icon-USD.svg b/libs/assets/src/images/icon-USD.svg index f25534c9af..eaaacd1af3 100644 --- a/libs/assets/src/images/icon-USD.svg +++ b/libs/assets/src/images/icon-USD.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 8ac8c9920265efc51fcb2df5a5220ecfec55639e Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:14:13 +0000 Subject: [PATCH 13/15] feat: toggle token on click --- .../limitOrders/containers/RateInput/index.tsx | 3 ++- .../limitOrders/pure/RateInput/HeadingText.tsx | 15 +++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index cbb91cf43c..471a7814d8 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -152,10 +152,11 @@ export function RateInput() { currency={primaryCurrency} rateImpact={rateImpact} toggleIcon={ - + } + onToggle={handleToggle} /> {areBothCurrencies && ( diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx index 2ef0b0cbbd..4408477c28 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx @@ -11,9 +11,10 @@ type Props = { inputCurrency: Currency | null rateImpact: number toggleIcon?: React.ReactNode + onToggle?: () => void } -const Wrapper = styled.span` +const Wrapper = styled.span<{ clickable: boolean }>` display: flex; flex-flow: row wrap; align-items: center; @@ -24,6 +25,12 @@ const Wrapper = styled.span` font-weight: 400; margin: auto 0; color: var(${UI.COLOR_TEXT_OPACITY_70}); + cursor: ${({ clickable }) => (clickable ? 'pointer' : 'default')}; + transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; + + &:hover { + opacity: ${({ clickable }) => (clickable ? 0.7 : 1)}; + } ` const TokenWrapper = styled.div` @@ -34,13 +41,13 @@ const TokenWrapper = styled.div` color: var(${UI.COLOR_TEXT}); ` -export function HeadingText({ inputCurrency, currency, rateImpact, toggleIcon }: Props) { +export function HeadingText({ inputCurrency, currency, rateImpact, toggleIcon, onToggle }: Props) { if (!currency) { - return Select input and output + return Select input and output } return ( - + {toggleIcon} When From 6ea2c049a2cdbf681bcb06265925baff925a5147 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:41:14 +0000 Subject: [PATCH 14/15] feat: add lock and unlock for limit price --- .../containers/LimitOrdersWidget/index.tsx | 17 +++-- .../containers/RateInput/index.tsx | 31 +++++++-- .../containers/RateInput/styled.ts | 36 +++++++++- .../hooks/useUpdateCurrencyAmount.ts | 65 +++++++++++++++---- .../pure/RateInput/HeadingText.tsx | 46 ++++++++----- .../limitOrders/pure/Settings/index.tsx | 9 ++- .../state/limitOrdersSettingsAtom.ts | 2 + libs/assets/src/images/icon-locked.svg | 1 + libs/assets/src/images/icon-unlocked.svg | 1 + 9 files changed, 164 insertions(+), 44 deletions(-) create mode 100644 libs/assets/src/images/icon-locked.svg create mode 100644 libs/assets/src/images/icon-unlocked.svg diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx index a3ba4e88c7..5b6cf6ad4f 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/LimitOrdersWidget/index.tsx @@ -176,13 +176,7 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => { handleUnlock={() => updateLimitOrdersState({ isUnlocked: true })} /> ), - topContent: - props.settingsState.limitPricePosition === 'top' ? ( - - - - ) : undefined, - middleContent: ( + topContent: ( <> {!isWrapOrUnwrap && ClosableBanner(ZERO_BANNER_STORAGE_KEY, (onClose) => ( @@ -200,6 +194,15 @@ const LimitOrders = React.memo((props: LimitOrdersProps) => {

))} + {props.settingsState.limitPricePosition === 'top' && ( + + + + )} + + ), + middleContent: ( + <> {props.settingsState.limitPricePosition === 'between' && ( diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index 471a7814d8..393abd1278 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -1,11 +1,12 @@ import { useAtomValue, useSetAtom } from 'jotai' import { useCallback, useEffect, useMemo, useState } from 'react' -import SwitchArrowsIcon from '@cowprotocol/assets/images/icon-switch-arrows.svg' +import LockedIcon from '@cowprotocol/assets/images/icon-locked.svg' +import UnlockedIcon from '@cowprotocol/assets/images/icon-unlocked.svg' import UsdIcon from '@cowprotocol/assets/images/icon-USD.svg' import { formatInputAmount, getAddress, isFractionFalsy } from '@cowprotocol/common-utils' import { TokenLogo } from '@cowprotocol/tokens' -import { TokenSymbol, HelpTooltip } from '@cowprotocol/ui' +import { TokenSymbol, HoverTooltip, HelpTooltip } from '@cowprotocol/ui' import { useWalletInfo } from '@cowprotocol/wallet' import SVG from 'react-inlinesvg' @@ -15,6 +16,10 @@ import { useRateImpact } from 'modules/limitOrders/hooks/useRateImpact' import { useUpdateActiveRate } from 'modules/limitOrders/hooks/useUpdateActiveRate' import { HeadingText } from 'modules/limitOrders/pure/RateInput/HeadingText' import { executionPriceAtom } from 'modules/limitOrders/state/executionPriceAtom' +import { + limitOrdersSettingsAtom, + updateLimitOrdersSettingsAtom, +} from 'modules/limitOrders/state/limitOrdersSettingsAtom' import { limitRateAtom, updateLimitRateAtom } from 'modules/limitOrders/state/limitRateAtom' import { toFraction } from 'modules/limitOrders/utils/toFraction' @@ -33,6 +38,8 @@ export function RateInput() { const executionPrice = useAtomValue(executionPriceAtom) const [isQuoteCurrencySet, setIsQuoteCurrencySet] = useState(false) const [isUsdMode, setIsUsdMode] = useState(false) + const { limitPriceLocked } = useAtomValue(limitOrdersSettingsAtom) + const updateLimitOrdersSettings = useSetAtom(updateLimitOrdersSettingsAtom) // Limit order state const { inputCurrency, outputCurrency, inputCurrencyAmount, outputCurrencyAmount } = useLimitOrdersDerivedState() @@ -95,6 +102,15 @@ export function RateInput() { } }, [isInverted, updateLimitRateState, isUsdMode]) + // Handle toggle price lock + const handleTogglePriceLock = useCallback( + (event: React.MouseEvent) => { + event.stopPropagation() + updateLimitOrdersSettings({ limitPriceLocked: !limitPriceLocked }) + }, + [limitPriceLocked, updateLimitOrdersSettings], + ) + const isDisabledMPrice = useMemo(() => { if (isLoadingMarketRate) return true @@ -152,9 +168,14 @@ export function RateInput() { currency={primaryCurrency} rateImpact={rateImpact} toggleIcon={ - - - + + + + + } onToggle={handleToggle} /> diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index 86532fa202..a560b23964 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -220,7 +220,7 @@ export const ActiveSymbol = styled.span<{ $active?: boolean }>` ` export const ActiveIcon = styled.div` - --size: 16px; + --size: 19px; color: inherit; width: var(--size); min-width: var(--size); @@ -231,11 +231,17 @@ export const ActiveIcon = styled.div` align-items: center; justify-content: center; cursor: pointer; - margin: 0; - transition: color var(${UI.ANIMATION_DURATION}) ease-in-out; + margin: 0 2px 0 0; + transition: + color var(${UI.ANIMATION_DURATION}) ease-in-out, + background var(${UI.ANIMATION_DURATION}) ease-in-out; + background: transparent; + border: 1px solid var(${UI.COLOR_PAPER_DARKEST}); &:hover { color: var(${UI.COLOR_TEXT}); + background: var(${UI.COLOR_PAPER}); + border-color: var(${UI.COLOR_PAPER}); } ` @@ -290,3 +296,27 @@ export const EstimatedRate = styled.div` color: var(${UI.COLOR_TEXT_OPACITY_70}); } ` + +export const LockIcon = styled.span` + --size: 19px; + position: relative; + display: flex; + align-items: center; + justify-content: center; + gap: 4px; + color: inherit; + border-radius: var(--size); + width: var(--size); + min-width: var(--size); + height: var(--size); + border: 1px solid var(${UI.COLOR_PAPER_DARKEST}); + cursor: pointer; + transition: + border-color var(${UI.ANIMATION_DURATION}) ease-in-out, + background var(${UI.ANIMATION_DURATION}) ease-in-out; + + &:hover { + border-color: var(${UI.COLOR_PAPER}); + background: var(${UI.COLOR_PAPER}); + } +` diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useUpdateCurrencyAmount.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useUpdateCurrencyAmount.ts index 73b0318d59..9000bf0c01 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useUpdateCurrencyAmount.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useUpdateCurrencyAmount.ts @@ -1,8 +1,9 @@ +import { useAtomValue, useSetAtom } from 'jotai' import { useCallback } from 'react' import { FractionUtils, isSellOrder } from '@cowprotocol/common-utils' import { OrderKind } from '@cowprotocol/cow-sdk' -import { Currency, CurrencyAmount, Fraction } from '@uniswap/sdk-core' +import { Currency, CurrencyAmount, Fraction, Price } from '@uniswap/sdk-core' import { Writeable } from 'types' @@ -11,6 +12,8 @@ import { Field } from 'legacy/state/types' import { useLimitOrdersDerivedState } from 'modules/limitOrders/hooks/useLimitOrdersDerivedState' import { useUpdateLimitOrdersRawState } from 'modules/limitOrders/hooks/useLimitOrdersRawState' import { LimitOrdersRawState } from 'modules/limitOrders/state/limitOrdersRawStateAtom' +import { limitOrdersSettingsAtom } from 'modules/limitOrders/state/limitOrdersSettingsAtom' +import { updateLimitRateAtom } from 'modules/limitOrders/state/limitRateAtom' import { calculateAmountForRate } from 'utils/orderUtils/calculateAmountForRate' @@ -22,13 +25,53 @@ type CurrencyAmountProps = { export function useUpdateCurrencyAmount() { const updateLimitOrdersState = useUpdateLimitOrdersRawState() - const { inputCurrency, outputCurrency } = useLimitOrdersDerivedState() + const { inputCurrency, outputCurrency, inputCurrencyAmount: currentInputAmount } = useLimitOrdersDerivedState() + const { limitPriceLocked } = useAtomValue(limitOrdersSettingsAtom) + const updateLimitRateState = useSetAtom(updateLimitRateAtom) return useCallback( (params: CurrencyAmountProps) => { const { activeRate, amount, orderKind } = params const field = isSellOrder(orderKind) ? Field.INPUT : Field.OUTPUT + const isBuyAmountChange = field === Field.OUTPUT + if (isBuyAmountChange) { + // When changing BUY amount + if (limitPriceLocked) { + // If price is locked, only update the output amount + const update: Partial> = { + orderKind, + outputCurrencyAmount: FractionUtils.serializeFractionToJSON(amount), + } + updateLimitOrdersState(update) + } else { + // If price is unlocked, update the rate based on the new amounts + const update: Partial> = { + orderKind, + outputCurrencyAmount: FractionUtils.serializeFractionToJSON(amount), + } + updateLimitOrdersState(update) + + // Calculate and update the new rate + if (amount && currentInputAmount) { + const newRate = new Price( + currentInputAmount.currency, + amount.currency, + currentInputAmount.quotient, + amount.quotient, + ) + updateLimitRateState({ + activeRate: FractionUtils.fractionLikeToFraction(newRate), + isTypedValue: false, + isRateFromUrl: false, + isAlternativeOrderRate: false, + }) + } + } + return + } + + // Normal flow for SELL amount changes const calculatedAmount = calculateAmountForRate({ activeRate, amount, @@ -37,21 +80,21 @@ export function useUpdateCurrencyAmount() { outputCurrency, }) - const inputCurrencyAmount = FractionUtils.serializeFractionToJSON( - field === Field.INPUT ? amount : calculatedAmount - ) - const outputCurrencyAmount = FractionUtils.serializeFractionToJSON( - field === Field.OUTPUT ? amount : calculatedAmount - ) + const newInputAmount = (field as Field) === Field.INPUT ? amount : calculatedAmount + const newOutputAmount = (field as Field) === Field.OUTPUT ? amount : calculatedAmount const update: Partial> = { orderKind, - ...(inputCurrencyAmount ? { inputCurrencyAmount } : undefined), - ...(outputCurrencyAmount ? { outputCurrencyAmount } : undefined), + ...(newInputAmount + ? { inputCurrencyAmount: FractionUtils.serializeFractionToJSON(newInputAmount) } + : undefined), + ...(newOutputAmount + ? { outputCurrencyAmount: FractionUtils.serializeFractionToJSON(newOutputAmount) } + : undefined), } updateLimitOrdersState(update) }, - [inputCurrency, outputCurrency, updateLimitOrdersState] + [inputCurrency, outputCurrency, updateLimitOrdersState, limitPriceLocked, updateLimitRateState, currentInputAmount], ) } diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx index 4408477c28..88ed3dee08 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/RateInput/HeadingText.tsx @@ -14,7 +14,7 @@ type Props = { onToggle?: () => void } -const Wrapper = styled.span<{ clickable: boolean }>` +const Wrapper = styled.span` display: flex; flex-flow: row wrap; align-items: center; @@ -25,12 +25,6 @@ const Wrapper = styled.span<{ clickable: boolean }>` font-weight: 400; margin: auto 0; color: var(${UI.COLOR_TEXT_OPACITY_70}); - cursor: ${({ clickable }) => (clickable ? 'pointer' : 'default')}; - transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; - - &:hover { - opacity: ${({ clickable }) => (clickable ? 0.7 : 1)}; - } ` const TokenWrapper = styled.div` @@ -41,22 +35,40 @@ const TokenWrapper = styled.div` color: var(${UI.COLOR_TEXT}); ` +const TextWrapper = styled.span<{ clickable: boolean }>` + display: flex; + align-items: center; + gap: 4px; + cursor: ${({ clickable }) => (clickable ? 'pointer' : 'default')}; + transition: opacity var(${UI.ANIMATION_DURATION}) ease-in-out; + + &:hover { + text-decoration: underline; + text-decoration-style: dashed; + text-decoration-thickness: 1px; + text-underline-offset: 2px; + text-decoration-color: var(${UI.COLOR_TEXT_OPACITY_70}); + } +` + export function HeadingText({ inputCurrency, currency, rateImpact, toggleIcon, onToggle }: Props) { if (!currency) { - return Select input and output + return Select input and output } return ( - + {toggleIcon} - When - - 1 - - - - is worth - {} + + When + + 1 + + + + is worth + {} + ) } diff --git a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx index 1582c4390e..94f49afc4b 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/pure/Settings/index.tsx @@ -110,7 +110,7 @@ const POSITION_LABELS = { } export function Settings({ state, onStateChanged }: SettingsProps) { - const { showRecipient, partialFillsEnabled, limitPricePosition } = state + const { showRecipient, partialFillsEnabled, limitPricePosition, limitPriceLocked } = state const [isOpen, setIsOpen] = useState(false) const handleSelect = useCallback( @@ -155,6 +155,13 @@ export function Settings({ state, onStateChanged }: SettingsProps) { toggle={() => onStateChanged({ partialFillsEnabled: !partialFillsEnabled })} /> + onStateChanged({ limitPriceLocked: !limitPriceLocked })} + /> + Limit Price Position diff --git a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts index 683a01ab15..ee14f8fc04 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/state/limitOrdersSettingsAtom.ts @@ -18,6 +18,7 @@ export interface LimitOrdersSettingsState { readonly deadlineMilliseconds: Milliseconds readonly customDeadlineTimestamp: Timestamp | null readonly limitPricePosition: 'top' | 'between' | 'bottom' + readonly limitPriceLocked: boolean } export const defaultLimitOrdersSettings: LimitOrdersSettingsState = { @@ -26,6 +27,7 @@ export const defaultLimitOrdersSettings: LimitOrdersSettingsState = { deadlineMilliseconds: defaultLimitOrderDeadline.value, customDeadlineTimestamp: null, limitPricePosition: 'top', + limitPriceLocked: true, } // regular diff --git a/libs/assets/src/images/icon-locked.svg b/libs/assets/src/images/icon-locked.svg new file mode 100644 index 0000000000..debfee8ade --- /dev/null +++ b/libs/assets/src/images/icon-locked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/libs/assets/src/images/icon-unlocked.svg b/libs/assets/src/images/icon-unlocked.svg new file mode 100644 index 0000000000..7ccd1d2701 --- /dev/null +++ b/libs/assets/src/images/icon-unlocked.svg @@ -0,0 +1 @@ + \ No newline at end of file From b57aaca6dc4a8329d256d3818e62da52446eae40 Mon Sep 17 00:00:00 2001 From: fairlighteth <31534717+fairlighteth@users.noreply.github.com> Date: Fri, 6 Dec 2024 14:30:36 +0000 Subject: [PATCH 15/15] feat: rate input tooltip styling --- .../src/modules/limitOrders/containers/RateInput/index.tsx | 1 + .../src/modules/limitOrders/containers/RateInput/styled.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx index 393abd1278..58f3bb461f 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/index.tsx @@ -171,6 +171,7 @@ export function RateInput() { diff --git a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts index a560b23964..c56abdaaa8 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/containers/RateInput/styled.ts @@ -133,7 +133,7 @@ export const ActiveCurrency = styled.button<{ $active?: boolean }>` border-radius: var(--border-radius); transition: all 0.2s ease-in-out; background: ${({ $active }) => ($active ? 'var(' + UI.COLOR_PAPER + ')' : 'var(' + UI.COLOR_PAPER_DARKEST + ')')}; - color: ${({ $active }) => ($active ? 'var(' + UI.COLOR_TEXT + ')' : 'var(' + UI.COLOR_TEXT_OPACITY_70 + ')')}; + color: ${({ $active }) => ($active ? 'var(' + UI.COLOR_TEXT + ')' : 'var(' + UI.COLOR_TEXT_OPACITY_50 + ')')}; padding: 0 10px; &:first-child { @@ -209,6 +209,9 @@ export const ActiveSymbol = styled.span<{ $active?: boolean }>` ${({ $active }) => !$active && ` + > div { + background: transparent; + } > div > img { opacity: 0.5; }