Skip to content

Commit 9a0b3cf

Browse files
committed
Update loading skeleton
1 parent 03dfc94 commit 9a0b3cf

File tree

6 files changed

+203
-35
lines changed

6 files changed

+203
-35
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ const AprHistoryChart = ({ chainId, poolAddress }: AprHistoryChartProps) => {
142142
const gridColor = rgba(theme.text, 0.06)
143143

144144
const {
145-
currentData: aprHistoryData,
145+
data: aprHistoryData,
146146
isError,
147-
isFetching,
147+
isLoading,
148148
} = usePoolAprHistoryQuery({
149149
chainId,
150150
address: poolAddress,
@@ -223,7 +223,8 @@ const AprHistoryChart = ({ chainId, poolAddress }: AprHistoryChartProps) => {
223223
height={chartHeight}
224224
isEmpty={!chartData.length}
225225
isError={isError}
226-
isLoading={isFetching && !aprHistoryData}
226+
isLoading={isLoading}
227+
skeletonType="line"
227228
>
228229
<PoolChartWrapper $height={chartHeight}>
229230
<ResponsiveContainer width="100%" height="100%">

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ const LiquidityFlowsChart = ({ chainId, poolAddress }: LiquidityFlowsChartProps)
142142
const removeLiquidityColor = rgba(theme.red, 0.5)
143143

144144
const {
145-
currentData: liquidityFlowData,
145+
data: liquidityFlowData,
146146
isError,
147-
isFetching,
147+
isLoading,
148148
} = usePoolLiquidityFlowsQuery({
149149
chainId,
150150
address: poolAddress,
@@ -182,7 +182,7 @@ const LiquidityFlowsChart = ({ chainId, poolAddress }: LiquidityFlowsChartProps)
182182
height={chartHeight}
183183
isEmpty={!chartData.length}
184184
isError={isError}
185-
isLoading={isFetching && !liquidityFlowData}
185+
isLoading={isLoading}
186186
>
187187
<Stack gap={12}>
188188
<PoolChartWrapper $height={chartHeight}>

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

Lines changed: 168 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
import { rgba } from 'polished'
12
import { type ReactNode } from 'react'
2-
import { Text } from 'rebass'
3-
import styled from 'styled-components'
3+
import { Box, Text } from 'rebass'
4+
import styled, { keyframes } from 'styled-components'
45

56
import Skeleton from 'components/Skeleton'
67
import { HStack, Stack } from 'components/Stack'
@@ -13,8 +14,35 @@ export const PoolChartWrapper = styled.div<{ $height?: number }>`
1314
height: ${({ $height }) => $height ?? DEFAULT_CHART_HEIGHT}px;
1415
`
1516

17+
const shimmer = keyframes`
18+
0% { transform: translateX(-100%); }
19+
100% { transform: translateX(100%); }
20+
`
21+
22+
const SkeletonBar = styled.div<{ $height: number }>`
23+
position: relative;
24+
flex: 1 1 0;
25+
min-width: 4px;
26+
max-width: 12px;
27+
height: ${({ $height }) => $height}%;
28+
border-top-left-radius: 4px;
29+
border-top-right-radius: 4px;
30+
background: ${({ theme }) => rgba(theme.text, 0.04)};
31+
overflow: hidden;
32+
`
33+
34+
const SkeletonBarShimmer = styled.div`
35+
position: absolute;
36+
inset: 0;
37+
background: ${({ theme }) =>
38+
`linear-gradient(90deg, ${rgba(theme.text, 0)} 0%, ${rgba(theme.text, 0.04)} 50%, ${rgba(theme.text, 0)} 100%)`};
39+
opacity: 0.7;
40+
animation: ${shimmer} 1.8s linear infinite;
41+
`
42+
1643
type PoolChartSkeletonProps = {
1744
height?: number
45+
type?: 'line' | 'bar' | 'candle'
1846
}
1947

2048
type PoolChartMessageProps = {
@@ -31,6 +59,7 @@ type PoolChartStateProps = {
3159
isEmpty?: boolean
3260
isError?: boolean
3361
isLoading?: boolean
62+
skeletonType?: PoolChartSkeletonProps['type']
3463
}
3564

3665
const PoolChartStateLayout = ({
@@ -61,18 +90,149 @@ const PoolChartStateLayout = ({
6190
)
6291
}
6392

64-
export const PoolChartSkeleton = ({ height = DEFAULT_CHART_HEIGHT }: PoolChartSkeletonProps) => {
93+
const LineChartSkeleton = ({ height }: { height: number }) => {
94+
const theme = useTheme()
95+
96+
return (
97+
<Box height={`${Math.max(height - 64, 0)}px`} width="100%">
98+
<svg height="100%" preserveAspectRatio="none" viewBox="0 0 600 240" width="100%">
99+
<defs>
100+
<linearGradient id="pool-chart-line-skeleton-gradient" x1="0%" x2="100%" y1="0%" y2="0%">
101+
<stop offset="0%" stopColor={rgba(theme.text, 0.04)} />
102+
<stop offset="50%" stopColor={rgba(theme.text, 0.14)}>
103+
<animate attributeName="offset" dur="1.8s" repeatCount="indefinite" values="-0.5; 0.5; 1.5" />
104+
</stop>
105+
<stop offset="100%" stopColor={rgba(theme.text, 0.04)} />
106+
</linearGradient>
107+
</defs>
108+
109+
<path
110+
d="M24 182 C78 168, 110 116, 152 126 S246 196, 302 148 S390 68, 444 88 S526 164, 576 134"
111+
fill="none"
112+
stroke="url(#pool-chart-line-skeleton-gradient)"
113+
strokeLinecap="round"
114+
strokeLinejoin="round"
115+
strokeWidth="4"
116+
/>
117+
</svg>
118+
</Box>
119+
)
120+
}
121+
122+
const BarChartSkeleton = ({ height }: { height: number }) => {
123+
const barHeights = [15, 20, 5, 10, 15, 30, 10, 15, 60, 70, 85, 90, 100, 70, 80, 40, 55, 60, 15, 20, 25, 15, 10, 5]
124+
125+
return (
126+
<Box height={`${Math.max(height - 64, 0)}px`} width="100%">
127+
<HStack align="flex-end" gap={8} height="100%" justify="center" p="8px" width="100%">
128+
{barHeights.map((barHeight, index) => (
129+
<SkeletonBar $height={barHeight * 0.8} key={index}>
130+
<SkeletonBarShimmer />
131+
</SkeletonBar>
132+
))}
133+
</HStack>
134+
</Box>
135+
)
136+
}
137+
138+
const CandleChartSkeleton = ({ height }: { height: number }) => {
139+
const theme = useTheme()
140+
const candles = [
141+
{ bodyHeight: 34, bodyY: 142, wickTop: 88, wickBottom: 202, x: 38 },
142+
{ bodyHeight: 52, bodyY: 116, wickTop: 74, wickBottom: 198, x: 96 },
143+
{ bodyHeight: 38, bodyY: 136, wickTop: 102, wickBottom: 206, x: 154 },
144+
{ bodyHeight: 58, bodyY: 102, wickTop: 66, wickBottom: 194, x: 212 },
145+
{ bodyHeight: 42, bodyY: 128, wickTop: 92, wickBottom: 210, x: 270 },
146+
{ bodyHeight: 66, bodyY: 84, wickTop: 48, wickBottom: 186, x: 328 },
147+
{ bodyHeight: 44, bodyY: 122, wickTop: 80, wickBottom: 202, x: 386 },
148+
{ bodyHeight: 56, bodyY: 104, wickTop: 64, wickBottom: 192, x: 444 },
149+
{ bodyHeight: 36, bodyY: 140, wickTop: 106, wickBottom: 212, x: 502 },
150+
{ bodyHeight: 48, bodyY: 118, wickTop: 78, wickBottom: 200, x: 560 },
151+
]
152+
153+
return (
154+
<Box height={`${Math.max(height - 64, 0)}px`} width="100%">
155+
<svg height="100%" preserveAspectRatio="none" viewBox="0 0 600 240" width="100%">
156+
<defs>
157+
<linearGradient id="pool-chart-candle-skeleton-shimmer" x1="0%" x2="100%" y1="0%" y2="0%">
158+
<stop offset="0%" stopColor={rgba(theme.text, 0)} />
159+
<stop offset="50%" stopColor={rgba(theme.text, 0.12)} />
160+
<stop offset="100%" stopColor={rgba(theme.text, 0)} />
161+
</linearGradient>
162+
<mask id="pool-chart-candle-skeleton-mask">
163+
{candles.map(candle => (
164+
<g key={candle.x}>
165+
<line
166+
stroke="white"
167+
strokeLinecap="round"
168+
strokeWidth="2"
169+
x1={candle.x}
170+
x2={candle.x}
171+
y1={candle.wickTop}
172+
y2={candle.wickBottom}
173+
/>
174+
<rect height={candle.bodyHeight} rx="4" width="24" x={candle.x - 12} y={candle.bodyY} fill="white" />
175+
</g>
176+
))}
177+
</mask>
178+
</defs>
179+
180+
{candles.map(candle => (
181+
<g key={candle.x}>
182+
<line
183+
stroke={rgba(theme.text, 0.05)}
184+
strokeLinecap="round"
185+
strokeWidth="2"
186+
x1={candle.x}
187+
x2={candle.x}
188+
y1={candle.wickTop}
189+
y2={candle.wickBottom}
190+
/>
191+
<rect
192+
fill={rgba(theme.text, 0.05)}
193+
height={candle.bodyHeight}
194+
rx="4"
195+
width="24"
196+
x={candle.x - 12}
197+
y={candle.bodyY}
198+
/>
199+
</g>
200+
))}
201+
<rect
202+
fill="url(#pool-chart-candle-skeleton-shimmer)"
203+
height="240"
204+
mask="url(#pool-chart-candle-skeleton-mask)"
205+
width="240"
206+
x="-240"
207+
y="0"
208+
>
209+
<animateTransform
210+
attributeName="transform"
211+
dur="2.4s"
212+
repeatCount="indefinite"
213+
type="translate"
214+
values="-240 0; 600 0"
215+
/>
216+
</rect>
217+
</svg>
218+
</Box>
219+
)
220+
}
221+
222+
export const PoolChartSkeleton = ({ height = DEFAULT_CHART_HEIGHT, type = 'line' }: PoolChartSkeletonProps) => {
65223
return (
66224
<PoolChartStateLayout gap={12} height={height}>
67-
<Skeleton height={height} width="100%" />
225+
{type === 'line' ? <LineChartSkeleton height={height} /> : null}
226+
{type === 'bar' ? <BarChartSkeleton height={height} /> : null}
227+
{type === 'candle' ? <CandleChartSkeleton height={height} /> : null}
68228
</PoolChartStateLayout>
69229
)
70230
}
71231

72232
const LiquidityFlowChartSkeleton = ({ height = DEFAULT_CHART_HEIGHT }: PoolChartSkeletonProps) => {
73233
return (
74234
<Stack gap={12}>
75-
<PoolChartSkeleton height={height} />
235+
<PoolChartSkeleton height={height} type="bar" />
76236
<HStack gap={16} justify="center" wrap="wrap">
77237
{Array.from({ length: 3 }).map((_, index) => (
78238
<HStack align="center" gap={16} key={index}>
@@ -90,7 +250,7 @@ const EarningChartSkeleton = ({ height = DEFAULT_CHART_HEIGHT }: PoolChartSkelet
90250

91251
return (
92252
<Stack gap={16}>
93-
<PoolChartSkeleton height={height} />
253+
<PoolChartSkeleton height={height} type="bar" />
94254
<Stack
95255
align="center"
96256
direction={isCompact ? 'column' : 'row'}
@@ -131,6 +291,7 @@ const PoolChartState = ({
131291
isEmpty,
132292
isError,
133293
isLoading,
294+
skeletonType,
134295
}: PoolChartStateProps) => {
135296
if (isLoading) {
136297
if (exclusiveType === 'liquidity-flow') {
@@ -141,7 +302,7 @@ const PoolChartState = ({
141302
return <EarningChartSkeleton height={height} />
142303
}
143304

144-
return <PoolChartSkeleton height={height} />
305+
return <PoolChartSkeleton height={height} type={skeletonType} />
145306
}
146307

147308
if (isError && errorMessage) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const PoolInformationSkeleton = () => {
4646
<PositionSkeleton width={320} height={18} />
4747
</Stack>
4848

49-
<PoolChartSkeleton />
49+
<PoolChartSkeleton type="line" />
5050
</Stack>
5151
</Stack>
5252
)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,9 @@ const PoolEarningChart = ({ chainId, onWindowChange, poolAddress, window }: Pool
195195
}
196196

197197
const {
198-
currentData: earningsData,
198+
data: earningsData,
199199
isError,
200-
isFetching,
200+
isLoading,
201201
} = usePoolEarningsQuery({
202202
chainId,
203203
address: poolAddress,
@@ -254,7 +254,7 @@ const PoolEarningChart = ({ chainId, onWindowChange, poolAddress, window }: Pool
254254
height={chartHeight}
255255
isEmpty={!hasChartData}
256256
isError={isError}
257-
isLoading={isFetching && !earningsData}
257+
isLoading={isLoading}
258258
>
259259
<Stack gap={16}>
260260
<PoolChartWrapper $height={chartHeight}>

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

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import styled from 'styled-components'
99

1010
import { ReactComponent as RevertPriceIcon } from 'assets/svg/earn/ic_revert_price.svg'
1111
import SegmentedControl from 'components/SegmentedControl'
12+
import Skeleton from 'components/Skeleton'
1213
import { HStack, Stack } from 'components/Stack'
1314
import TokenLogo from 'components/TokenLogo'
1415
import useTheme from 'hooks/useTheme'
@@ -178,9 +179,9 @@ const PoolPriceChart = ({ chainId, poolAddress }: PoolPriceChartProps) => {
178179
const volumeDownColor = rgba(theme.red, 0.6)
179180

180181
const {
181-
currentData: priceData,
182+
data: priceData,
182183
isError,
183-
isFetching,
184+
isLoading,
184185
} = usePoolPriceQuery({
185186
chainId,
186187
address: poolAddress,
@@ -401,22 +402,26 @@ const PoolPriceChart = ({ chainId, poolAddress }: PoolPriceChartProps) => {
401402
</RevertIconWrapper>
402403
</HeaderTitle>
403404

404-
<HStack align="baseline" gap={10} wrap="wrap">
405-
<Text color={theme.text} fontSize={24} fontWeight={500}>
406-
{formatPrice(lastCandle?.close)}
407-
</Text>
408-
409-
{priceChange !== undefined ? (
410-
<HStack align="center" gap={6}>
411-
<Text color={priceChangeColor} fontSize={16} fontWeight={500}>
412-
{formatSignedPercent(priceChange)}
413-
</Text>
414-
<Text color={priceChangeColor} fontSize={12}>
415-
{priceChange >= 0 ? '▲' : '▼'}
405+
{lastCandle && priceChange !== undefined ? (
406+
<HStack align="baseline" gap={10} wrap="wrap">
407+
<>
408+
<Text color={theme.text} fontSize={24} fontWeight={500}>
409+
{formatPrice(lastCandle.close)}
416410
</Text>
417-
</HStack>
418-
) : null}
419-
</HStack>
411+
412+
<HStack align="center" gap={6}>
413+
<Text color={priceChangeColor} fontSize={16} fontWeight={500}>
414+
{formatSignedPercent(priceChange)}
415+
</Text>
416+
<Text color={priceChangeColor} fontSize={12}>
417+
{priceChange >= 0 ? '▲' : '▼'}
418+
</Text>
419+
</HStack>
420+
</>
421+
</HStack>
422+
) : (
423+
<Skeleton height={28.5} width={240} />
424+
)}
420425
</Stack>
421426

422427
<SegmentedControl onChange={setWindow} options={CHART_WINDOW_OPTIONS} value={window} />
@@ -428,7 +433,8 @@ const PoolPriceChart = ({ chainId, poolAddress }: PoolPriceChartProps) => {
428433
height={chartHeight}
429434
isEmpty={!chartData.length}
430435
isError={isError}
431-
isLoading={isFetching && !priceData}
436+
isLoading={isLoading}
437+
skeletonType="candle"
432438
>
433439
<ChartFrame $height={chartHeight}>
434440
{tooltip ? <PriceChartTooltip tooltip={tooltip} window={window} /> : null}

0 commit comments

Comments
 (0)