Skip to content

Commit f3f090d

Browse files
committed
Update charts
1 parent 1a89e4b commit f3f090d

File tree

21 files changed

+1122
-1352
lines changed

21 files changed

+1122
-1352
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { type ReactNode } from 'react'
2+
import styled, { css } from 'styled-components'
3+
4+
export type SegmentedControlOption<T extends string = string> = {
5+
label: ReactNode
6+
value: T
7+
disabled?: boolean
8+
}
9+
10+
type SegmentedControlProps<T extends string> = {
11+
onChange?: (value: T) => void
12+
options?: readonly SegmentedControlOption<T>[]
13+
size?: 'sm' | 'md'
14+
value?: T
15+
}
16+
17+
const sizeStyles = {
18+
sm: css`
19+
padding: 8px;
20+
`,
21+
md: css`
22+
padding: 8px 12px;
23+
`,
24+
}
25+
26+
const Container = styled.div<{ $optionCount: number }>`
27+
display: grid;
28+
position: relative;
29+
grid-template-columns: repeat(${({ $optionCount }) => $optionCount}, minmax(0, 1fr));
30+
align-items: center;
31+
border: 1px solid ${({ theme }) => theme.border};
32+
border-radius: 999px;
33+
background: ${({ theme }) => theme.background};
34+
`
35+
36+
const ActivePill = styled.div<{ $activeIndex: number; $optionCount: number }>`
37+
position: absolute;
38+
top: 1px;
39+
bottom: 1px;
40+
left: 1px;
41+
width: calc((100% - 2px) / ${({ $optionCount }) => $optionCount});
42+
border-radius: 999px;
43+
background: ${({ theme }) => theme.tabActive};
44+
transform: translateX(calc(100% * ${({ $activeIndex }) => $activeIndex}));
45+
transition: transform 200ms ease, background 200ms ease;
46+
pointer-events: none;
47+
`
48+
49+
const OptionButton = styled.button<{ $active: boolean; $size: 'sm' | 'md' }>`
50+
position: relative;
51+
z-index: 1;
52+
min-width: 48px;
53+
border: 0;
54+
border-radius: 999px;
55+
background: transparent;
56+
color: ${({ theme, $active }) => ($active ? theme.text : theme.subText)};
57+
font-size: 14px;
58+
font-weight: 500;
59+
cursor: pointer;
60+
transition: color 200ms ease, background 200ms ease;
61+
62+
${({ $size }) => sizeStyles[$size]}
63+
64+
:hover:not(:disabled) {
65+
background: ${({ theme, $active }) => ($active ? 'transparent' : theme.buttonGray)};
66+
}
67+
68+
:disabled {
69+
cursor: not-allowed;
70+
opacity: 0.5;
71+
}
72+
`
73+
74+
const SegmentedControl = <T extends string>({
75+
onChange,
76+
options = [],
77+
size = 'sm',
78+
value,
79+
}: SegmentedControlProps<T>) => {
80+
if (!options.length) return null
81+
82+
const activeIndex = options.findIndex(option => option.value === value)
83+
84+
return (
85+
<Container $optionCount={options.length} role="tablist">
86+
<ActivePill $activeIndex={Math.max(activeIndex, 0)} $optionCount={options.length} />
87+
{options.map(option => (
88+
<OptionButton
89+
$active={option.value === value}
90+
$size={size}
91+
aria-selected={option.value === value}
92+
disabled={option.disabled || !onChange}
93+
key={option.value}
94+
onClick={() => !option.disabled && onChange?.(option.value)}
95+
role="tab"
96+
type="button"
97+
>
98+
{option.label}
99+
</OptionButton>
100+
))}
101+
</Container>
102+
)
103+
}
104+
105+
export default SegmentedControl

apps/kyberswap-interface/src/pages/Earns/PoolDetail/AddLiquidity/components/AddLiquidityWidget.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'
44
import { Text } from 'rebass'
55
import styled from 'styled-components'
66

7-
import { ButtonErrorStyle, ButtonOutlined, ButtonPrimary } from 'components/Button'
7+
import { ButtonErrorStyle, ButtonPrimary } from 'components/Button'
88
import { HStack, Stack } from 'components/Stack'
99
import { useActiveWeb3React } from 'hooks'
1010
import AddLiquiditySettings from 'pages/Earns/PoolDetail/AddLiquidity/components/AddLiquiditySettings'
@@ -44,10 +44,9 @@ type AddLiquidityWidgetProps = {
4444
preview?: AddLiquidityWidgetPreview
4545
feedback: ReturnType<typeof useFeedback>['widget']
4646
onTrackEvent?: (eventName: string, data?: Record<string, any>) => void
47-
onCancel?: () => void
4847
}
4948

50-
const AddLiquidityWidget = ({ context, state, preview, feedback, onTrackEvent, onCancel }: AddLiquidityWidgetProps) => {
49+
const AddLiquidityWidget = ({ context, state, preview, feedback, onTrackEvent }: AddLiquidityWidgetProps) => {
5150
const { chainId: poolChainId, poolAddress, poolType, pool } = context
5251
const { account } = useActiveWeb3React()
5352
const toggleWalletModal = useWalletModalToggle()
@@ -194,7 +193,6 @@ const AddLiquidityWidget = ({ context, state, preview, feedback, onTrackEvent, o
194193
/>
195194

196195
<HStack gap={16}>
197-
<ButtonOutlined onClick={onCancel}>Cancel</ButtonOutlined>
198196
<PrimaryActionButton
199197
altDisabledStyle
200198
onClick={() => void actions.handlePrimaryAction()}

apps/kyberswap-interface/src/pages/Earns/PoolDetail/AddLiquidity/index.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { type ApprovalAdditionalInfo } from '@kyber/hooks'
22
import { PoolType, Pool as ZapPool, ZapRouteDetail } from '@kyber/schema'
33
import { translateFriendlyErrorMessage, translateZapMessage } from '@kyber/ui'
44
import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'
5-
import { useNavigate } from 'react-router-dom'
65
import { BuildZapInData, prepareBuildZapInRouteRequest, useBuildZapInRouteMutation } from 'services/zap'
76

87
import { HStack, Stack } from 'components/Stack'
@@ -90,7 +89,6 @@ const AddLiquidityBody = ({
9089
state,
9190
tracking,
9291
}: AddLiquidityBodyProps) => {
93-
const navigate = useNavigate()
9492
const { buildRouteLoading } = useAddLiquidityRuntimeContext()
9593

9694
return (
@@ -111,7 +109,6 @@ const AddLiquidityBody = ({
111109
}}
112110
feedback={feedback.widget}
113111
onTrackEvent={onTrackEvent}
114-
onCancel={() => navigate(-1)}
115112
/>
116113

117114
{feedback.page.warnings.length || previewError ? (
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { useState } from 'react'
2+
import { Text } from 'rebass'
3+
import { type PoolAnalyticsWindow } from 'services/zapEarn'
4+
import styled from 'styled-components'
5+
6+
import { Stack } from 'components/Stack'
7+
import useTheme from 'hooks/useTheme'
8+
import LiquidityFlowsChart from 'pages/Earns/PoolDetail/components/LiquidityFlowsChart'
9+
import PoolPriceChart from 'pages/Earns/PoolDetail/components/PoolPriceChart'
10+
import { usePoolDetailContext } from 'pages/Earns/PoolDetail/context'
11+
12+
import { formatAnalyticsNumber, formatAnalyticsUsd } from './utils'
13+
14+
const MetricsStrip = styled.div`
15+
display: grid;
16+
grid-template-columns: repeat(3, minmax(0, 1fr));
17+
gap: 16px;
18+
padding: 16px;
19+
border-radius: 16px;
20+
background: ${({ theme }) => theme.buttonGray};
21+
22+
${({ theme }) => theme.mediaWidth.upToMedium`
23+
grid-template-columns: repeat(2, minmax(0, 1fr));
24+
`}
25+
26+
${({ theme }) => theme.mediaWidth.upToSmall`
27+
grid-template-columns: repeat(2, minmax(0, 1fr));
28+
gap: 12px;
29+
padding: 16px;
30+
`}
31+
`
32+
33+
const AnalyticsTab = () => {
34+
const theme = useTheme()
35+
const { pool } = usePoolDetailContext()
36+
37+
const [priceWindow, setPriceWindow] = useState<PoolAnalyticsWindow>('7d')
38+
const [liquidityFlowsWindow, setLiquidityFlowsWindow] = useState<PoolAnalyticsWindow>('7d')
39+
const [currentTvl, setCurrentTvl] = useState<number | undefined>()
40+
41+
const handleLiquidityFlowsWindowChange = (value: PoolAnalyticsWindow) => {
42+
setCurrentTvl(undefined)
43+
setLiquidityFlowsWindow(value)
44+
}
45+
46+
let totalTvl = pool.tvl ?? pool.poolStats?.tvl
47+
48+
if (totalTvl === undefined && pool.reserveUsd !== undefined) {
49+
const parsedReserveUsd = Number(pool.reserveUsd)
50+
51+
totalTvl = Number.isNaN(parsedReserveUsd) ? undefined : parsedReserveUsd
52+
}
53+
54+
const metrics = [
55+
{ label: 'TVL', value: formatAnalyticsUsd(totalTvl) },
56+
{ label: 'Current TVL', value: formatAnalyticsUsd(currentTvl ?? totalTvl) },
57+
{ label: 'Liquidity Provider', value: formatAnalyticsNumber(pool.liquidity) },
58+
]
59+
60+
return (
61+
<Stack gap={20}>
62+
<MetricsStrip>
63+
{metrics.map(metric => (
64+
<Stack gap={4} key={metric.label} minWidth={0}>
65+
<Text color={theme.subText} fontSize={14}>
66+
{metric.label}
67+
</Text>
68+
<Text color={theme.text} fontWeight={500}>
69+
{metric.value}
70+
</Text>
71+
</Stack>
72+
))}
73+
</MetricsStrip>
74+
75+
<PoolPriceChart onSelectWindow={setPriceWindow} window={priceWindow} />
76+
77+
<LiquidityFlowsChart
78+
onCurrentTvlChange={setCurrentTvl}
79+
onSelectWindow={handleLiquidityFlowsWindowChange}
80+
window={liquidityFlowsWindow}
81+
/>
82+
</Stack>
83+
)
84+
}
85+
86+
export default AnalyticsTab

apps/kyberswap-interface/src/pages/Earns/PoolDetail/tabs/EarningsTab.tsx renamed to apps/kyberswap-interface/src/pages/Earns/PoolDetail/Information/EarningsTab.tsx

File renamed without changes.

0 commit comments

Comments
 (0)