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 (
- <>
-
- >
+
)
}
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 (
-
+
+ {/* TODO: add active state */}
+
+
+
+
+
)
}
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;
}