Skip to content

Commit de2be35

Browse files
neikoptienkane
andauthored
feat: new zap create widget (#2905)
* update: migrate to package * fix: install * fix: update build-package * fix: remove export * fix: hooks file * Clone zap widget (#2904) * First look Add FeeTierControl Chore Chore Add PriceControl * Try integrate api * Chore * Add calc tickSpacing * Update fee default null * Fix poolPrice * Fix inputPrice * Chore * Update responsive * Update * Fix tickSpacing * Fix useTokenPrices clear interval * Update Preview * Add config hooks * Update set default fee by poolCategory * Fix config hooks undefined * Chore * Update default chainId * Add config poolCategory * Update find exist pool * Fix check pool exist * Check pool exist add hoooks * Improve success tx modal * Check invalid token * Check FOT * Sort tokens and update fot message * Update create flow Chore * Try fix switch * Chore * Clone zap widget * Update pipeline * Revert liquidity-widgets * Continue * Refactor * Continue * Update i18n * Try to fix getZapRoute deps * Chore * Update message * Update pnpm lock * Add PriceSlider * Rename CreatePoolModal * Add warning * Add effect getZapRoute * Clone zap widget (#2904) * First look Add FeeTierControl Chore Chore Add PriceControl * Try integrate api * Chore * Add calc tickSpacing * Update fee default null * Fix poolPrice * Fix inputPrice * Chore * Update responsive * Update * Fix tickSpacing * Fix useTokenPrices clear interval * Update Preview * Add config hooks * Update set default fee by poolCategory * Fix config hooks undefined * Chore * Update default chainId * Add config poolCategory * Update find exist pool * Fix check pool exist * Check pool exist add hoooks * Improve success tx modal * Check invalid token * Check FOT * Sort tokens and update fot message * Update create flow Chore * Try fix switch * Chore * Clone zap widget * Update pipeline * Revert liquidity-widgets * Continue * Refactor * Continue * Update i18n * Try to fix getZapRoute deps * Chore * Update message * update: migrate to package * fix: install * fix: update build-package * fix: remove export * fix: hooks file * Update pnpm lock * Add PriceSlider * Rename CreatePoolModal * Add warning * Add effect getZapRoute * Update pnpm lock * fix(price-slider): calculate current tick from pool price * fix: auto-zoom threshold * fix: remove margin top * fix: remove stuff * Merge branch 'feat/price-slider' of github.com:KyberNetwork/kyberswap-interface into feat/new-zap-create-widget * fix: focus-fighting * Update protocol allowlist * fix: remove className * fix: remove className * fix: styles * fix: styles * fix: mt * fix: mt * Fix fromCreatePoolFlow default * rename to range slider * Update Ether protocols * Update notice and add arrow left * Add Estimated preview Chore * Update zap-in preview Chore Chore add * Check pool price at market rate * Update * Fix formatInputValue * Use prod api --------- Co-authored-by: Tien Nguyen <dinhtiennguyen.1202@gmail.com>
1 parent 94e4956 commit de2be35

File tree

107 files changed

+7441
-265
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

107 files changed

+7441
-265
lines changed

.github/workflows/widget-release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ on:
1212
required: true
1313
options:
1414
- packages/liquidity-widgets
15+
- packages/zap-create-widgets
1516
- packages/zap-migration-widgets
1617
- packages/zap-out-widgets
1718
- packages/pancake-liquidity-widgets
@@ -60,4 +61,3 @@ jobs:
6061
- name: Publish package to npm
6162
working-directory: ${{ github.event.inputs.package }}
6263
run: npm publish --access public
63-

apps/kyberswap-interface/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"@kyberswap/liquidity-chart": "workspace:*",
6363
"@kyberswap/liquidity-widgets": "workspace:*",
6464
"@kyberswap/oauth2": "1.0.2",
65+
"@kyberswap/zap-create-widgets": "workspace:*",
6566
"@kyberswap/zap-migration-widgets": "workspace:*",
6667
"@kyberswap/zap-out-widgets": "workspace:*",
6768
"@ledgerhq/hw-app-btc": "^10.9.1",
@@ -187,6 +188,7 @@
187188
"@babel/preset-react": "^7.18.6",
188189
"@babel/preset-typescript": "^7.21.4",
189190
"@cypress/grep": "^3.1.5",
191+
"@kyber/schema": "workspace:^",
190192
"@kyber/ui": "workspace:^",
191193
"@kyber/utils": "workspace:*",
192194
"@lingui/cli": "^4.6.0",

apps/kyberswap-interface/src/components/Button/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,11 @@ const disabledPrimary = css<{
7676
}>`
7777
background-color: ${({ theme, altDisabledStyle }) =>
7878
altDisabledStyle ? theme.primary : theme.buttonGray} !important;
79-
color: ${({ theme, altDisabledStyle }) => (altDisabledStyle ? 'white' : theme.border)};
79+
color: ${({ theme, altDisabledStyle }) => (altDisabledStyle ? theme.textReverse : theme.border)};
8080
box-shadow: none !important;
8181
border: 1px solid transparent;
8282
outline: none;
83-
opacity: ${({ altDisabledStyle }) => (altDisabledStyle ? '0.7' : '1')};
83+
opacity: ${({ altDisabledStyle }) => (altDisabledStyle ? '0.5' : '1')};
8484
`
8585
export const ButtonPrimary = styled(Base)`
8686
background-color: ${({ theme, backgroundColor }) => backgroundColor || theme.primary};
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import { rgba } from 'polished'
2+
import React, { useEffect, useState } from 'react'
3+
import styled, { css } from 'styled-components'
4+
5+
const optionCSS = css`
6+
height: 100%;
7+
padding: 0 8px;
8+
border-radius: 20px;
9+
border-color: transparent;
10+
11+
color: ${({ theme }) => theme.subText};
12+
text-align: center;
13+
14+
font-size: 12px;
15+
font-weight: 400;
16+
line-height: 16px;
17+
18+
outline: none;
19+
display: inline-flex;
20+
align-items: center;
21+
justify-content: center;
22+
23+
&:hover {
24+
background-color: ${({ theme }) => rgba(theme.background, 0.6)};
25+
}
26+
27+
&[data-active='true'] {
28+
background-color: ${({ theme }) => theme.background};
29+
color: ${({ theme }) => theme.text};
30+
border-color: ${({ theme }) => theme.primary};
31+
font-weight: 500;
32+
}
33+
34+
&[data-disabled='true'] {
35+
opacity: 0.5;
36+
cursor: not-allowed;
37+
}
38+
`
39+
40+
const CustomOption = styled.div`
41+
${optionCSS};
42+
flex: 1;
43+
column-gap: 4px;
44+
cursor: text;
45+
`
46+
47+
const CustomInput = styled.input`
48+
width: 54px;
49+
height: 100%;
50+
border: 0;
51+
padding: 4px 0px 4px 4px;
52+
background: transparent;
53+
color: inherit;
54+
outline: none;
55+
text-align: right;
56+
57+
&::-webkit-outer-spin-button,
58+
&::-webkit-inner-spin-button {
59+
-webkit-appearance: none;
60+
}
61+
62+
&::placeholder {
63+
color: inherit;
64+
opacity: 0.6;
65+
}
66+
`
67+
68+
const formatPercentValue = (value: number) => {
69+
if (!Number.isFinite(value)) return ''
70+
const fixed = Number(value.toFixed(4))
71+
const text = fixed.toString()
72+
return text.replace(/\.0+$/, '').replace(/(\.\d*[1-9])0+$/, '$1')
73+
}
74+
75+
type Props = {
76+
value: number | null
77+
onChange: (value: number) => void
78+
isCustom?: boolean
79+
disabled?: boolean
80+
}
81+
82+
const CustomFeeTierInput: React.FC<Props> = ({ value, onChange, isCustom, disabled }) => {
83+
const [text, setText] = useState('')
84+
85+
useEffect(() => {
86+
if (!isCustom || value === null) {
87+
setText('')
88+
return
89+
}
90+
setText(formatPercentValue(value))
91+
}, [isCustom, value])
92+
93+
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
94+
if (disabled) return
95+
const next = event.target.value
96+
97+
if (next === '') {
98+
setText(next)
99+
return
100+
}
101+
102+
const numberRegex = /^(\d{0,3})(\.\d{0,5})?$/
103+
if (!numberRegex.test(next)) return
104+
105+
const parsed = Number(next)
106+
if (Number.isNaN(parsed)) return
107+
108+
setText(next)
109+
onChange(parsed)
110+
}
111+
112+
return (
113+
<CustomOption data-active={isCustom} data-disabled={disabled}>
114+
<CustomInput
115+
type="text"
116+
value={text}
117+
onChange={handleChange}
118+
placeholder="Custom"
119+
inputMode="decimal"
120+
disabled={disabled}
121+
/>
122+
%
123+
</CustomOption>
124+
)
125+
}
126+
127+
export default CustomFeeTierInput
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { rgba } from 'polished'
2+
import React, { useEffect } from 'react'
3+
import styled, { css } from 'styled-components'
4+
5+
import CustomFeeTierInput from './CustomFeeTierInput'
6+
7+
const Container = styled.div`
8+
display: flex;
9+
align-items: stretch;
10+
border-radius: 20px;
11+
border: ${({ theme }) => `1px solid ${theme.border}`};
12+
width: 100%;
13+
height: 36px;
14+
`
15+
16+
const optionButtonCSS = css`
17+
height: 100%;
18+
padding: 0 12px;
19+
border-radius: 20px;
20+
border-color: transparent;
21+
22+
background-color: transparent;
23+
color: ${({ theme }) => theme.subText};
24+
text-align: center;
25+
26+
font-size: 12px;
27+
font-weight: 400;
28+
line-height: 16px;
29+
cursor: pointer;
30+
outline: none;
31+
32+
&:hover {
33+
background-color: ${({ theme }) => rgba(theme.background, 0.6)};
34+
}
35+
36+
&[data-active='true'] {
37+
background-color: ${({ theme }) => theme.background};
38+
color: ${({ theme }) => theme.text};
39+
font-weight: 500;
40+
}
41+
42+
&:disabled,
43+
&[data-disabled='true'] {
44+
opacity: 0.5;
45+
cursor: not-allowed;
46+
}
47+
`
48+
49+
const OptionButton = styled.button`
50+
${optionButtonCSS};
51+
flex: 1;
52+
`
53+
54+
const DEFAULT_FEE_OPTIONS = [0.1, 0.3, 0.5, 1]
55+
56+
type Props = {
57+
value: number | null
58+
onChange: (value: number) => void
59+
options?: number[]
60+
disabled?: boolean
61+
className?: string
62+
}
63+
64+
const FeeTierControl: React.FC<Props> = ({ value, onChange, options = DEFAULT_FEE_OPTIONS, disabled, className }) => {
65+
const [isCustom, setIsCustom] = React.useState(false)
66+
67+
useEffect(() => {
68+
setIsCustom(false)
69+
}, [options])
70+
71+
return (
72+
<Container className={className}>
73+
{options.map(option => (
74+
<OptionButton
75+
type="button"
76+
key={option}
77+
onClick={() => {
78+
onChange(option)
79+
setIsCustom(false)
80+
}}
81+
data-active={option === value && !isCustom}
82+
data-disabled={disabled}
83+
disabled={disabled}
84+
>
85+
{option}%
86+
</OptionButton>
87+
))}
88+
<CustomFeeTierInput
89+
value={value}
90+
onChange={value => {
91+
onChange(value)
92+
setIsCustom(true)
93+
}}
94+
isCustom={isCustom}
95+
/>
96+
</Container>
97+
)
98+
}
99+
100+
export default FeeTierControl

0 commit comments

Comments
 (0)