Skip to content
This repository was archived by the owner on Dec 23, 2025. It is now read-only.

Commit 10a013e

Browse files
committed
feat: add indicator
1 parent 7796f8d commit 10a013e

8 files changed

Lines changed: 151 additions & 23 deletions

File tree

.env.development

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
NEXT_PUBLIC_APP_URL=http://localhost:3000
2+
NEXT_PUBLIC_REFRESH_INTERVAL=10000

.env.production

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
NEXT_PUBLIC_APP_URL=${VERCEL_URL}
1+
NEXT_PUBLIC_APP_URL=https://${VERCEL_URL}
2+
NEXT_PUBLIC_REFRESH_INTERVAL=60000

package-lock.json

Lines changed: 66 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"@radix-ui/react-progress": "^1.0.3",
1213
"@radix-ui/react-slot": "^1.0.2",
1314
"@tanstack/react-table": "^8.13.2",
1415
"class-variance-authority": "^0.7.0",

src/app/_components/realtime-crypto-wrapper.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { FC, useEffect, useState } from 'react'
77
import { CryptoBubbles } from './crypto-bubbles'
88
import { CryptoDataTable } from './crypto-table/crypto-table'
99
import { columns } from './crypto-table/columns'
10+
import { Progress } from '@/components/ui/progress'
1011

1112
export type RealtimeCryptoWrapperProps = {
1213
initialCryptos: CryptoData[]
@@ -18,9 +19,11 @@ export const RealtimeCryptoWrapper: FC<RealtimeCryptoWrapperProps> = ({
1819
top,
1920
}) => {
2021
const [cryptos, setCryptos] = useState<CryptoData[]>(initialCryptos)
22+
const [lastUpdatedAt, setLastUpdatedAt] = useState(Date.now())
2123

2224
useEffect(() => {
2325
const interval = setInterval(async () => {
26+
setLastUpdatedAt(Date.now())
2427
getCryptoData(top).then(setCryptos)
2528
}, REFRESH_INTERVAL)
2629

@@ -29,6 +32,10 @@ export const RealtimeCryptoWrapper: FC<RealtimeCryptoWrapperProps> = ({
2932

3033
return (
3134
<>
35+
<UpdateProgress
36+
lastUpdatedAt={lastUpdatedAt}
37+
updateInterval={REFRESH_INTERVAL}
38+
/>
3239
<CryptoBubbles
3340
cryptos={cryptos}
3441
className="h-[calc(100dvh-56px)] bg-slate-900"
@@ -39,3 +46,26 @@ export const RealtimeCryptoWrapper: FC<RealtimeCryptoWrapperProps> = ({
3946
</>
4047
)
4148
}
49+
50+
const UpdateProgress: FC<{ lastUpdatedAt: number; updateInterval: number }> = ({
51+
lastUpdatedAt,
52+
updateInterval,
53+
}) => {
54+
const [progress, setProgress] = useState(0)
55+
56+
useEffect(() => {
57+
const interval = setInterval(() => {
58+
const elapsed = Date.now() - lastUpdatedAt
59+
setProgress((elapsed / updateInterval) * 100)
60+
}, 200)
61+
62+
return () => clearInterval(interval)
63+
}, [lastUpdatedAt, updateInterval])
64+
65+
return (
66+
<Progress
67+
value={progress}
68+
className="h-1 rounded-none [&>.indicator]:duration-200"
69+
/>
70+
)
71+
}

src/app/globals.css

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,76 @@
11
@tailwind base;
22
@tailwind components;
33
@tailwind utilities;
4-
4+
55
@layer base {
66
:root {
77
--background: 0 0% 100%;
88
--foreground: 0 0% 3.9%;
99

1010
--card: 0 0% 100%;
1111
--card-foreground: 0 0% 3.9%;
12-
12+
1313
--popover: 0 0% 100%;
1414
--popover-foreground: 0 0% 3.9%;
15-
16-
--primary: 0 0% 9%;
15+
16+
--primary: 259 90% 45%;
1717
--primary-foreground: 0 0% 98%;
18-
18+
1919
--secondary: 0 0% 96.1%;
2020
--secondary-foreground: 0 0% 9%;
21-
21+
2222
--muted: 0 0% 96.1%;
2323
--muted-foreground: 0 0% 45.1%;
24-
24+
2525
--accent: 0 0% 96.1%;
2626
--accent-foreground: 0 0% 9%;
27-
27+
2828
--destructive: 0 84.2% 60.2%;
2929
--destructive-foreground: 0 0% 98%;
3030

3131
--border: 0 0% 89.8%;
3232
--input: 0 0% 89.8%;
3333
--ring: 0 0% 3.9%;
34-
34+
3535
--radius: 0.5rem;
3636
}
37-
37+
3838
.dark {
3939
--background: 0 0% 3.9%;
4040
--foreground: 0 0% 98%;
41-
41+
4242
--card: 0 0% 3.9%;
4343
--card-foreground: 0 0% 98%;
44-
44+
4545
--popover: 0 0% 3.9%;
4646
--popover-foreground: 0 0% 98%;
47-
47+
4848
--primary: 0 0% 98%;
4949
--primary-foreground: 0 0% 9%;
50-
50+
5151
--secondary: 0 0% 14.9%;
5252
--secondary-foreground: 0 0% 98%;
53-
53+
5454
--muted: 0 0% 14.9%;
5555
--muted-foreground: 0 0% 63.9%;
56-
56+
5757
--accent: 0 0% 14.9%;
5858
--accent-foreground: 0 0% 98%;
59-
59+
6060
--destructive: 0 62.8% 30.6%;
6161
--destructive-foreground: 0 0% 98%;
62-
62+
6363
--border: 0 0% 14.9%;
6464
--input: 0 0% 14.9%;
6565
--ring: 0 0% 83.1%;
6666
}
6767
}
68-
68+
6969
@layer base {
7070
* {
7171
@apply border-border;
7272
}
7373
body {
7474
@apply bg-background text-foreground;
7575
}
76-
}
76+
}

src/components/ui/progress.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use client'
2+
3+
import * as React from 'react'
4+
import * as ProgressPrimitive from '@radix-ui/react-progress'
5+
6+
import { cn } from '@/lib/utils'
7+
8+
const Progress = React.forwardRef<
9+
React.ElementRef<typeof ProgressPrimitive.Root>,
10+
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
11+
>(({ className, value, ...props }, ref) => (
12+
<ProgressPrimitive.Root
13+
ref={ref}
14+
className={cn(
15+
'relative h-4 w-full overflow-hidden rounded-full bg-secondary',
16+
className,
17+
)}
18+
{...props}
19+
>
20+
<ProgressPrimitive.Indicator
21+
className="indicator h-full w-full flex-1 bg-primary transition-all"
22+
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
23+
/>
24+
</ProgressPrimitive.Root>
25+
))
26+
Progress.displayName = ProgressPrimitive.Root.displayName
27+
28+
export { Progress }

src/lib/constants.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
export const REFRESH_INTERVAL = 10000
1+
export const REFRESH_INTERVAL = +(
2+
process.env.NEXT_PUBLIC_REFRESH_INTERVAL || 10000
3+
)
24
export const CRYPTO_DATA_URL = 'https://d2vk6ctfmdeng6.cloudfront.net/1.json'

0 commit comments

Comments
 (0)