Skip to content

Commit ec6bf03

Browse files
committed
feat: enhance dashboard UI with new animations, improved loading states, and updated styling for better user experience
1 parent bc3deb3 commit ec6bf03

17 files changed

+292
-194
lines changed

components/dashboard/Dashboard.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -406,19 +406,29 @@ export function Dashboard() {
406406
// Loading state
407407
if (isLoading) {
408408
return (
409-
<div className="w-screen h-[100vh] flex items-center justify-center">
410-
<div className="text-2xl text-gray-600">Loading graph data...</div>
409+
<div className="w-screen h-[100vh] flex items-center justify-center bg-[#0a0a0a]">
410+
<div className="relative flex items-center justify-center">
411+
<div className="absolute w-24 h-24 rounded-full border border-emerald-500/20 animate-pulse-ring" />
412+
<div className="absolute w-16 h-16 rounded-full border border-emerald-500/30 animate-pulse-ring" style={{ animationDelay: "0.5s" }} />
413+
<div className="absolute w-8 h-8 rounded-full border border-emerald-500/40 animate-pulse-ring" style={{ animationDelay: "1s" }} />
414+
<div className="w-3 h-3 rounded-full bg-emerald-400 animate-pulse" />
415+
</div>
411416
</div>
412417
);
413418
}
414419

415420
// Error state
416421
if (error) {
417422
return (
418-
<div className="w-screen h-[100vh] flex items-center justify-center">
423+
<div className="w-screen h-[100vh] flex items-center justify-center bg-[#0a0a0a]">
419424
<div className="text-center">
420-
<div className="text-2xl text-red-600 mb-4">Error loading data</div>
421-
<div className="text-gray-600">
425+
<div className="w-16 h-16 mx-auto mb-4 rounded-full bg-red-500/10 flex items-center justify-center">
426+
<svg className="w-8 h-8 text-red-400" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
427+
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
428+
</svg>
429+
</div>
430+
<div className="text-xl text-red-400 mb-2">Error loading data</div>
431+
<div className="text-gray-500">
422432
{error.message || "Failed to load graph data"}
423433
</div>
424434
</div>
@@ -429,9 +439,15 @@ export function Dashboard() {
429439
// No data state
430440
if (!data) {
431441
return (
432-
<div className="w-screen h-[100vh] flex items-center justify-center">
442+
<div className="w-screen h-[100vh] flex items-center justify-center bg-[#0a0a0a]">
433443
<div className="text-center">
434-
<div className="text-2xl text-gray-600 mb-4">No data available</div>
444+
<div className="w-16 h-16 mx-auto mb-4 rounded-full bg-white/5 flex items-center justify-center">
445+
<svg className="w-8 h-8 text-gray-500" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
446+
<path strokeLinecap="round" strokeLinejoin="round" d="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125" />
447+
</svg>
448+
</div>
449+
<div className="text-xl text-gray-400 mb-2">No data available</div>
450+
<div className="text-gray-600">Check your connection and try again</div>
435451
</div>
436452
</div>
437453
);
@@ -441,7 +457,7 @@ export function Dashboard() {
441457
<div className="w-screen h-[100vh] overflow-hidden my-auto">
442458
{/* Top controls */}
443459
<div
444-
className={`justify-center items-center absolute gap-4 md:gap-0 right-0 flex z-20 transition-all ${
460+
className={`justify-center items-center absolute gap-2 right-3 flex z-20 transition-all ${
445461
showTimelineBar ? "top-2" : "bottom-0"
446462
}`}
447463
>

components/dashboard/FieldReportCard.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ export function FieldReportCard({ report, onDismiss }: FieldReportCardProps) {
2626
href={`https://sarafu.network/reports/${report.id}`}
2727
target="_blank"
2828
rel="noopener noreferrer"
29-
className="block w-72 max-w-[calc(100vw-2rem)] bg-white/95 backdrop-blur-sm rounded-lg shadow-xl border border-gray-200 overflow-hidden hover:shadow-2xl hover:scale-[1.02] transition-all cursor-pointer"
29+
className="block w-72 max-w-[calc(100vw-2rem)] bg-gray-900/85 backdrop-blur-xl rounded-lg shadow-xl border border-white/10 overflow-hidden hover:shadow-2xl hover:scale-[1.02] transition-all cursor-pointer"
3030
>
3131
{/* Image */}
3232
{report.image_url && !imgError && (
3333
<div className="relative h-32 w-full">
3434
{!imgLoaded && (
35-
<div className="absolute inset-0 bg-gray-200 animate-pulse" />
35+
<div className="absolute inset-0 bg-white/5 shimmer-bg animate-shimmer" />
3636
)}
3737
<img
3838
src={report.image_url}
@@ -58,17 +58,17 @@ export function FieldReportCard({ report, onDismiss }: FieldReportCardProps) {
5858
<div className="p-3 space-y-2">
5959
{/* Title with dismiss if no image */}
6060
<div className="flex items-start justify-between gap-2">
61-
<h3 className="text-sm font-semibold text-gray-800 line-clamp-2 flex-1">
61+
<h3 className="text-sm font-semibold text-gray-100 line-clamp-2 flex-1">
6262
{report.title}
6363
</h3>
6464
{!report.image_url && (
6565
<button
6666
onClick={handleDismiss}
67-
className="p-0.5 hover:bg-gray-100 rounded transition-colors"
67+
className="p-0.5 hover:bg-white/10 rounded transition-colors"
6868
>
6969
<CloseIcon
7070
onClick={onDismiss}
71-
className="w-4 h-4 text-gray-400 hover:text-gray-600 transition-colors flex-shrink-0"
71+
className="w-4 h-4 text-gray-400 hover:text-gray-200 transition-colors flex-shrink-0"
7272
/>
7373
</button>
7474
)}
@@ -80,13 +80,13 @@ export function FieldReportCard({ report, onDismiss }: FieldReportCardProps) {
8080
{report.tags.slice(0, 4).map((tag, index) => (
8181
<span
8282
key={index}
83-
className="px-2 py-0.5 bg-emerald-50 text-emerald-700 text-xs rounded-full"
83+
className="px-2 py-0.5 bg-emerald-500/15 text-emerald-400 text-xs rounded-full"
8484
>
8585
{tag}
8686
</span>
8787
))}
8888
{report.tags.length > 4 && (
89-
<span className="px-2 py-0.5 bg-gray-100 text-gray-500 text-xs rounded-full">
89+
<span className="px-2 py-0.5 bg-white/5 text-gray-400 text-xs rounded-full">
9090
+{report.tags.length - 4}
9191
</span>
9292
)}
@@ -95,7 +95,7 @@ export function FieldReportCard({ report, onDismiss }: FieldReportCardProps) {
9595
</div>
9696

9797
{/* Bottom accent bar */}
98-
<div className="h-1 bg-gradient-to-r from-emerald-500 to-green-600" />
98+
<div className="h-0.5 bg-gradient-to-r from-emerald-500/60 to-green-600/40" />
9999
</a>
100100
);
101101
}

components/dashboard/FieldReportsOverlay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function FieldReportsOverlay({
4747
}
4848

4949
return (
50-
<div className="absolute bottom-20 left-0 right-0 z-10 flex justify-center gap-3 px-4 overflow-x-auto pointer-events-none overflow-y-hidden">
50+
<div className="absolute bottom-24 left-0 right-0 z-10 flex justify-center gap-3 px-4 overflow-x-auto pointer-events-none overflow-y-hidden">
5151
<AnimatePresence mode="popLayout">
5252
{visibleReports.map((report) => (
5353
<motion.div

components/dashboard/InfoPanel.tsx

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ export function InfoPanel({
4747
if (!selectedInfo) return null;
4848

4949
return (
50-
<div className="absolute top-4 left-4 z-20 w-80 max-w-[calc(100vw-2rem)] bg-white/95 backdrop-blur-sm rounded-lg shadow-xl border border-gray-200 overflow-hidden">
50+
<div className="absolute top-4 left-4 z-20 w-80 max-w-[calc(100vw-2rem)] bg-gray-900/85 backdrop-blur-xl rounded-lg shadow-xl border border-white/10 overflow-hidden">
5151
{/* Header */}
52-
<div className="flex items-center justify-between px-4 py-3 bg-gradient-to-r from-emerald-500 to-green-600">
52+
<div className="flex items-center justify-between px-4 py-3 bg-gradient-to-r from-emerald-600/80 to-emerald-500/60">
5353
<h2 className="text-white font-semibold">
5454
{selectedInfo.type === "node" ? "Account" : "Transaction"}
5555
</h2>
@@ -96,19 +96,19 @@ function NodeInfoContent({
9696
<>
9797
{/* Node Address */}
9898
<div>
99-
<label className="text-xs text-gray-500 block mb-1">Address</label>
99+
<label className="text-xs text-gray-400 block mb-1">Address</label>
100100
<div className="flex items-center gap-2">
101-
<code className="flex-1 text-sm bg-gray-100 text-gray-500 px-2 py-1.5 rounded font-mono truncate">
101+
<code className="flex-1 text-sm bg-white/5 text-gray-300 px-2 py-1.5 rounded font-mono truncate">
102102
{data.id}
103103
</code>
104104
<button
105105
onClick={() => copyToClipboard(data.id, "address")}
106-
className="p-1.5 hover:bg-gray-100 rounded transition-colors"
106+
className="p-1.5 hover:bg-white/10 rounded transition-colors"
107107
title="Copy address"
108108
>
109109
<CopyIcon
110110
className={`w-4 h-4 ${
111-
copiedField === "address" ? "text-green-500" : "text-gray-500"
111+
copiedField === "address" ? "text-emerald-400" : "text-gray-400"
112112
}`}
113113
/>
114114
</button>
@@ -117,15 +117,15 @@ function NodeInfoContent({
117117

118118
{/* Transaction count */}
119119
<div>
120-
<label className="text-xs text-gray-500 block mb-1">
120+
<label className="text-xs text-gray-400 block mb-1">
121121
Total Transactions
122122
</label>
123-
<p className="text-sm font-medium text-gray-700">{data.value}</p>
123+
<p className="text-sm font-medium text-gray-200">{data.value}</p>
124124
</div>
125125

126126
{/* Vouchers used with details */}
127127
<div>
128-
<label className="text-xs text-gray-500 block mb-1">
128+
<label className="text-xs text-gray-400 block mb-1">
129129
Vouchers Used ({Object.keys(data.usedVouchers).length})
130130
</label>
131131
<div className="max-h-40 overflow-y-auto space-y-1.5">
@@ -138,18 +138,18 @@ function NodeInfoContent({
138138
return (
139139
<div
140140
key={contractAddress}
141-
className="flex items-center justify-between text-sm bg-gray-50 px-2 py-1.5 rounded"
141+
className="flex items-center justify-between text-sm bg-white/5 px-2 py-1.5 rounded"
142142
>
143-
<span className="text-gray-700 truncate flex-1">
143+
<span className="text-gray-200 truncate flex-1">
144144
{voucher
145145
? `${voucher.token_name} (${voucher.token_symbol})`
146146
: contractAddress.slice(0, 10) + "..."}
147147
</span>
148148
<div className="flex items-center gap-2 ml-2">
149-
<span className="text-xs font-medium text-emerald-600 whitespace-nowrap">
149+
<span className="text-xs font-medium text-emerald-400 whitespace-nowrap">
150150
{txCount} tx
151151
</span>
152-
<span className="text-xs text-gray-400 whitespace-nowrap">
152+
<span className="text-xs text-gray-500 whitespace-nowrap">
153153
{new Date(firstTxDate).toLocaleDateString()}
154154
</span>
155155
</div>
@@ -164,7 +164,7 @@ function NodeInfoContent({
164164
href={`https://celoscan.io/address/${data.id}`}
165165
target="_blank"
166166
rel="noopener noreferrer"
167-
className="flex items-center gap-2 w-full px-3 py-2 bg-emerald-50 hover:bg-emerald-100 text-emerald-700 rounded-md transition-colors text-sm font-medium"
167+
className="flex items-center gap-2 w-full px-3 py-2 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-400 rounded-md transition-colors text-sm font-medium"
168168
>
169169
<ExternalLinkIcon className="w-4 h-4" />
170170
View on Celoscan
@@ -173,7 +173,7 @@ function NodeInfoContent({
173173
href={`https://sarafu.network/users/${data.id}`}
174174
target="_blank"
175175
rel="noopener noreferrer"
176-
className="flex items-center gap-2 w-full px-3 py-2 bg-emerald-50 hover:bg-emerald-100 text-emerald-700 rounded-md transition-colors text-sm font-medium"
176+
className="flex items-center gap-2 w-full px-3 py-2 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-400 rounded-md transition-colors text-sm font-medium"
177177
>
178178
<ExternalLinkIcon className="w-4 h-4" />
179179
View on Sarafu Network
@@ -197,27 +197,27 @@ function LinkInfoContent({
197197
<>
198198
{/* Token info */}
199199
<div>
200-
<label className="text-xs text-gray-500 block mb-1">Token</label>
201-
<p className="text-sm font-medium text-gray-700">
200+
<label className="text-xs text-gray-400 block mb-1">Token</label>
201+
<p className="text-sm font-medium text-gray-200">
202202
{data.token_name} ({data.token_symbol})
203203
</p>
204204
</div>
205205

206206
{/* Contract address */}
207207
<div>
208-
<label className="text-xs text-gray-500 block mb-1">Contract</label>
208+
<label className="text-xs text-gray-400 block mb-1">Contract</label>
209209
<div className="flex items-center gap-2">
210-
<code className="flex-1 text-sm text-gray-500 px-2 py-1.5 rounded font-mono truncate">
210+
<code className="flex-1 text-sm text-gray-300 bg-white/5 px-2 py-1.5 rounded font-mono truncate">
211211
{data.contract_address}
212212
</code>
213213
<button
214214
onClick={() => copyToClipboard(data.contract_address, "contract")}
215-
className="p-1.5 hover:bg-gray-100 rounded transition-colors"
215+
className="p-1.5 hover:bg-white/10 rounded transition-colors"
216216
title="Copy contract"
217217
>
218218
<CopyIcon
219219
className={`w-4 h-4 ${
220-
copiedField === "contract" ? "text-green-500" : "text-gray-500"
220+
copiedField === "contract" ? "text-emerald-400" : "text-gray-400"
221221
}`}
222222
/>
223223
</button>
@@ -226,19 +226,19 @@ function LinkInfoContent({
226226

227227
{/* Source */}
228228
<div>
229-
<label className="text-xs text-gray-500 block mb-1">From</label>
229+
<label className="text-xs text-gray-400 block mb-1">From</label>
230230
<div className="flex items-center gap-2">
231-
<code className="flex-1 text-xs text-gray-500 px-2 py-1 rounded font-mono truncate">
231+
<code className="flex-1 text-xs text-gray-300 bg-white/5 px-2 py-1 rounded font-mono truncate">
232232
{data.source}
233233
</code>
234234
<button
235235
onClick={() => copyToClipboard(data.source, "source")}
236-
className="p-1 hover:bg-gray-100 rounded transition-colors"
236+
className="p-1 hover:bg-white/10 rounded transition-colors"
237237
title="Copy source"
238238
>
239239
<CopyIcon
240240
className={`w-3 h-3 ${
241-
copiedField === "source" ? "text-green-500" : "text-gray-500"
241+
copiedField === "source" ? "text-emerald-400" : "text-gray-400"
242242
}`}
243243
/>
244244
</button>
@@ -247,19 +247,19 @@ function LinkInfoContent({
247247

248248
{/* Target */}
249249
<div>
250-
<label className="text-xs text-gray-500 block mb-1">To</label>
250+
<label className="text-xs text-gray-400 block mb-1">To</label>
251251
<div className="flex items-center gap-2">
252-
<code className="flex-1 text-xs text-gray-500 px-2 py-1 rounded font-mono truncate">
252+
<code className="flex-1 text-xs text-gray-300 bg-white/5 px-2 py-1 rounded font-mono truncate">
253253
{data.target}
254254
</code>
255255
<button
256256
onClick={() => copyToClipboard(data.target, "target")}
257-
className="p-1 hover:bg-gray-100 rounded transition-colors"
257+
className="p-1 hover:bg-white/10 rounded transition-colors"
258258
title="Copy target"
259259
>
260260
<CopyIcon
261261
className={`w-3 h-3 ${
262-
copiedField === "target" ? "text-green-500" : "text-gray-500"
262+
copiedField === "target" ? "text-emerald-400" : "text-gray-400"
263263
}`}
264264
/>
265265
</button>
@@ -269,14 +269,14 @@ function LinkInfoContent({
269269
{/* Stats */}
270270
<div className="grid grid-cols-2 gap-3">
271271
<div>
272-
<label className="text-xs text-gray-500 block mb-1">
272+
<label className="text-xs text-gray-400 block mb-1">
273273
Transactions
274274
</label>
275-
<p className="text-sm font-medium text-gray-700">{data.txCount}</p>
275+
<p className="text-sm font-medium text-gray-200">{data.txCount}</p>
276276
</div>
277277
<div>
278-
<label className="text-xs text-gray-500 block mb-1">Total Value</label>
279-
<p className="text-sm font-medium text-gray-700">
278+
<label className="text-xs text-gray-400 block mb-1">Total Value</label>
279+
<p className="text-sm font-medium text-gray-200">
280280
{data.value.toLocaleString(undefined, {
281281
maximumFractionDigits: 2,
282282
})}
@@ -286,10 +286,10 @@ function LinkInfoContent({
286286

287287
{/* Date range */}
288288
<div>
289-
<label className="text-xs text-gray-500 block mb-1">
289+
<label className="text-xs text-gray-400 block mb-1">
290290
Activity Period
291291
</label>
292-
<p className="text-sm text-gray-700">
292+
<p className="text-sm text-gray-200">
293293
{new Date(data.dateFirst).toLocaleDateString()} -{" "}
294294
{new Date(data.date).toLocaleDateString()}
295295
</p>
@@ -300,7 +300,7 @@ function LinkInfoContent({
300300
href={`https://sarafu.network/vouchers/${data.contract_address}`}
301301
target="_blank"
302302
rel="noopener noreferrer"
303-
className="flex items-center gap-2 w-full px-3 py-2 bg-emerald-50 hover:bg-emerald-100 text-emerald-700 rounded-md transition-colors text-sm font-medium"
303+
className="flex items-center gap-2 w-full px-3 py-2 bg-emerald-500/10 hover:bg-emerald-500/20 text-emerald-400 rounded-md transition-colors text-sm font-medium"
304304
>
305305
<ExternalLinkIcon className="w-4 h-4" />
306306
View on Sarafu Network

components/dashboard/SettingsPanel.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,9 @@ export function SettingsPanel({
118118
lastUpdate,
119119
}: SettingsPanelProps) {
120120
return (
121-
<div className="w-full sm:w-[360px] z-20 absolute inset-0 sm:inset-auto sm:top-0 sm:right-0 bg-white sm:m-3 sm:rounded-lg shadow-xl overflow-hidden flex flex-col">
121+
<div className="w-full sm:w-[360px] z-20 absolute inset-0 sm:inset-auto sm:top-0 sm:right-0 bg-gray-900/85 backdrop-blur-xl border border-white/10 sm:m-3 sm:rounded-lg shadow-xl overflow-hidden flex flex-col">
122122
{/* Header */}
123-
<div className="flex items-center justify-between px-4 py-3 bg-gradient-to-r from-green-500 to-emerald-600">
123+
<div className="flex items-center justify-between px-4 py-3 bg-gradient-to-r from-emerald-600/80 to-emerald-500/60">
124124
<h1 className="text-white font-semibold text-lg">Settings</h1>
125125
<CloseIcon
126126
onClick={onClose}
@@ -196,8 +196,8 @@ export function SettingsPanel({
196196
</div>
197197

198198
{/* Footer */}
199-
<div className="px-4 py-3 bg-gray-50 border-t border-gray-100 mt-auto">
200-
<p className="text-xs text-gray-400 text-center">
199+
<div className="px-4 py-3 bg-white/[0.03] border-t border-white/5 mt-auto">
200+
<p className="text-xs text-gray-500 text-center">
201201
Last updated:{" "}
202202
{lastUpdate
203203
? new Date(lastUpdate).toLocaleString()

0 commit comments

Comments
 (0)