@chainloyalty/react 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,6 +28,7 @@ import {
28
28
  TrendingUp,
29
29
  ExternalLink,
30
30
  } from 'lucide-react';
31
+ import { getThemeColors } from './theme';
31
32
 
32
33
  // ============================================================================
33
34
  // Types & Interfaces
@@ -142,6 +143,7 @@ const getRankIcon = (rank: number): React.ReactNode => {
142
143
  interface LeaderboardRowProps {
143
144
  entry: LeaderboardEntry;
144
145
  accentColor: string;
146
+ theme: ReturnType<typeof getThemeColors>;
145
147
  isCurrentUser?: boolean;
146
148
  onCopyAddress?: (address: string) => void;
147
149
  }
@@ -149,6 +151,7 @@ interface LeaderboardRowProps {
149
151
  const LeaderboardRow: React.FC<LeaderboardRowProps> = ({
150
152
  entry,
151
153
  accentColor,
154
+ theme,
152
155
  isCurrentUser = false,
153
156
  onCopyAddress,
154
157
  }) => {
@@ -168,9 +171,11 @@ const LeaderboardRow: React.FC<LeaderboardRowProps> = ({
168
171
 
169
172
  return (
170
173
  <tr
171
- className={`border-b border-gray-700 transition-all hover:bg-gray-700/30 ${
172
- isCurrentUser ? 'bg-gray-700/20' : ''
173
- }`}
174
+ className="border-b transition-all hover:opacity-80"
175
+ style={{
176
+ borderColor: theme.border,
177
+ backgroundColor: isCurrentUser ? 'rgba(0,0,0,0.1)' : 'transparent'
178
+ }}
174
179
  >
175
180
  {/* Rank */}
176
181
  <td className="px-4 py-3 text-sm">
@@ -190,12 +195,13 @@ const LeaderboardRow: React.FC<LeaderboardRowProps> = ({
190
195
  {/* Wallet Address */}
191
196
  <td className="px-4 py-3 text-sm">
192
197
  <div className="flex items-center gap-2 group">
193
- <span className="text-white font-mono">
198
+ <span className="font-mono" style={{ color: theme.foreground }}>
194
199
  {shortenAddress(entry.walletAddress)}
195
200
  </span>
196
201
  <button
197
202
  onClick={handleCopy}
198
- className="p-1.5 rounded-md text-gray-500 group-hover:text-gray-300 hover:bg-gray-700/50 transition-all opacity-0 group-hover:opacity-100"
203
+ className="p-1.5 rounded-md transition-all opacity-0 group-hover:opacity-100"
204
+ style={{ color: theme.mutedForeground }}
199
205
  title={entry.walletAddress}
200
206
  >
201
207
  {copied ? (
@@ -205,7 +211,7 @@ const LeaderboardRow: React.FC<LeaderboardRowProps> = ({
205
211
  )}
206
212
  </button>
207
213
  {entry.displayName && (
208
- <span className="hidden sm:inline text-xs text-gray-400">({entry.displayName})</span>
214
+ <span className="hidden sm:inline text-xs" style={{ color: theme.mutedForeground }}>({entry.displayName})</span>
209
215
  )}
210
216
  </div>
211
217
  </td>
@@ -216,7 +222,7 @@ const LeaderboardRow: React.FC<LeaderboardRowProps> = ({
216
222
  <p className="font-bold" style={{ color: accentColor }}>
217
223
  {entry.points.toLocaleString()}
218
224
  </p>
219
- <p className="text-xs text-gray-400 hidden sm:block">points</p>
225
+ <p className="text-xs hidden sm:block" style={{ color: theme.mutedForeground }}>points</p>
220
226
  </div>
221
227
  </td>
222
228
 
@@ -225,12 +231,13 @@ const LeaderboardRow: React.FC<LeaderboardRowProps> = ({
225
231
  <div
226
232
  className="inline-flex items-center gap-1 px-2 py-1 rounded-lg"
227
233
  style={{
228
- backgroundColor: 'rgba(47, 129, 247, 0.1)',
229
- borderColor: accentColor,
234
+ backgroundColor: theme.muted,
235
+ borderColor: theme.border,
236
+ border: '1px solid',
230
237
  }}
231
238
  >
232
239
  <Award className="w-4 h-4" style={{ color: accentColor }} />
233
- <span className="font-semibold text-white">{entry.badgesCount}</span>
240
+ <span className="font-semibold" style={{ color: theme.foreground }}>{entry.badgesCount}</span>
234
241
  </div>
235
242
  </td>
236
243
  </tr>
@@ -254,9 +261,12 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
254
261
  const [error, setError] = useState<string | null>(null);
255
262
  const [currentPage, setCurrentPage] = useState(1);
256
263
 
257
- const backgroundColor = customColors.background || '#0D1117';
258
- const accentColor = customColors.accent1 || '#2F81F7';
259
- const accentColor2 = customColors.accent2 || '#3FB950';
264
+ // Get theme colors from host app's CSS variables
265
+ const theme = getThemeColors();
266
+
267
+ // Override with customColors if provided (backward compatibility)
268
+ const accentColor = customColors.accent1 || theme.accent;
269
+ const accentColor2 = customColors.accent2 || theme.primary;
260
270
 
261
271
  // Fetch data when timeframe changes
262
272
  useEffect(() => {
@@ -294,20 +304,21 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
294
304
 
295
305
  return (
296
306
  <div
297
- className="rounded-lg border border-gray-700 overflow-hidden"
298
- style={{ backgroundColor }}
307
+ className="rounded-lg border overflow-hidden"
308
+ style={{ backgroundColor: theme.card, borderColor: theme.border }}
299
309
  >
300
310
  {/* Header */}
301
- <div className="p-6 border-b border-gray-700">
311
+ <div className="p-6" style={{ borderBottom: `1px solid ${theme.border}` }}>
302
312
  <div className="flex items-center justify-between mb-4">
303
313
  <div className="flex items-center gap-3">
304
314
  <Trophy className="w-6 h-6" style={{ color: accentColor2 }} />
305
- <h2 className="text-2xl font-bold text-white">Leaderboard</h2>
315
+ <h2 className="text-2xl font-bold" style={{ color: theme.foreground }}>Leaderboard</h2>
306
316
  </div>
307
317
  <button
308
318
  onClick={handleRefresh}
309
319
  disabled={loading}
310
- className="p-2 rounded-lg text-gray-400 hover:text-white hover:bg-gray-700 transition-all disabled:opacity-50"
320
+ className="p-2 rounded-lg transition-all disabled:opacity-50"
321
+ style={{ color: theme.mutedForeground }}
311
322
  title="Refresh leaderboard"
312
323
  >
313
324
  <RefreshCw className={`w-5 h-5 ${loading ? 'animate-spin' : ''}`} />
@@ -317,11 +328,11 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
317
328
  {/* Stats */}
318
329
  <div className="grid grid-cols-2 md:grid-cols-3 gap-3 mb-4">
319
330
  <div
320
- className="p-3 rounded-lg border border-gray-700"
321
- style={{ backgroundColor: 'rgba(31, 41, 55, 0.5)' }}
331
+ className="p-3 rounded-lg border"
332
+ style={{ backgroundColor: theme.muted, borderColor: theme.border }}
322
333
  >
323
- <p className="text-xs text-gray-400">Total Users</p>
324
- <p className="text-2xl font-bold text-white">{data.length.toLocaleString()}</p>
334
+ <p className="text-xs" style={{ color: theme.mutedForeground }}>Total Users</p>
335
+ <p className="text-2xl font-bold" style={{ color: theme.foreground }}>{data.length.toLocaleString()}</p>
325
336
  </div>
326
337
 
327
338
  {currentUserRank && (
@@ -330,10 +341,10 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
330
341
  className="p-3 rounded-lg border"
331
342
  style={{
332
343
  borderColor: accentColor,
333
- backgroundColor: 'rgba(47, 129, 247, 0.1)',
344
+ backgroundColor: theme.card,
334
345
  }}
335
346
  >
336
- <p className="text-xs text-gray-400">Your Rank</p>
347
+ <p className="text-xs" style={{ color: theme.mutedForeground }}>Your Rank</p>
337
348
  <p className="text-2xl font-bold" style={{ color: accentColor }}>
338
349
  #{currentUserRank.rank}
339
350
  </p>
@@ -343,10 +354,10 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
343
354
  className="p-3 rounded-lg border"
344
355
  style={{
345
356
  borderColor: accentColor2,
346
- backgroundColor: 'rgba(63, 185, 80, 0.1)',
357
+ backgroundColor: theme.card,
347
358
  }}
348
359
  >
349
- <p className="text-xs text-gray-400">Your Points</p>
360
+ <p className="text-xs" style={{ color: theme.mutedForeground }}>Your Points</p>
350
361
  <p className="text-2xl font-bold" style={{ color: accentColor2 }}>
351
362
  {currentUserRank.points.toLocaleString()}
352
363
  </p>
@@ -358,7 +369,7 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
358
369
  {/* Filters */}
359
370
  {!hideTimeframeFilter && (
360
371
  <div className="flex items-center gap-2">
361
- <Calendar className="w-4 h-4 text-gray-400" />
372
+ <Calendar className="w-4 h-4" style={{ color: theme.mutedForeground }} />
362
373
  <div className="flex gap-2">
363
374
  {(['alltime', 'month'] as const).map((tf) => (
364
375
  <button
@@ -366,8 +377,8 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
366
377
  onClick={() => setTimeframe(tf)}
367
378
  className={`px-3 py-1.5 rounded-lg text-sm font-medium transition-all ${
368
379
  timeframe === tf
369
- ? 'text-white'
370
- : 'text-gray-400 hover:text-white hover:bg-gray-700/50'
380
+ ? ''
381
+ : ''
371
382
  }`}
372
383
  style={
373
384
  timeframe === tf
@@ -375,7 +386,7 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
375
386
  backgroundColor: accentColor,
376
387
  color: 'white',
377
388
  }
378
- : {}
389
+ : { color: theme.mutedForeground }
379
390
  }
380
391
  >
381
392
  {tf === 'alltime' ? 'All Time' : 'This Month'}
@@ -387,12 +398,12 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
387
398
  </div>
388
399
 
389
400
  {/* Content */}
390
- <div style={{ backgroundColor: 'rgba(31, 41, 55, 0.2)' }}>
401
+ <div style={{ backgroundColor: theme.background }}>
391
402
  {/* Loading State */}
392
403
  {loading && !data.length && (
393
404
  <div className="p-6 space-y-3">
394
405
  {[...Array(5)].map((_, i) => (
395
- <div key={i} className="h-12 bg-gray-700 rounded-lg animate-pulse" />
406
+ <div key={i} className="h-12 rounded-lg animate-pulse" style={{ backgroundColor: theme.muted }} />
396
407
  ))}
397
408
  </div>
398
409
  )}
@@ -400,10 +411,10 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
400
411
  {/* Error State */}
401
412
  {error && !data.length && (
402
413
  <div className="p-6 text-center">
403
- <p className="text-red-400 mb-4">{error}</p>
414
+ <p className="mb-4" style={{ color: '#ef4444' }}>{error}</p>
404
415
  <button
405
416
  onClick={handleRefresh}
406
- className="px-4 py-2 rounded-lg text-white text-sm transition-all"
417
+ className="px-4 py-2 rounded-lg text-sm transition-all text-white"
407
418
  style={{ backgroundColor: accentColor }}
408
419
  >
409
420
  Try Again
@@ -414,9 +425,9 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
414
425
  {/* Empty State */}
415
426
  {!loading && !error && data.length === 0 && (
416
427
  <div className="p-12 text-center">
417
- <TrendingUp className="w-12 h-12 mx-auto mb-4 text-gray-500" />
418
- <h3 className="text-lg font-semibold text-white mb-2">No Leaderboard Data</h3>
419
- <p className="text-gray-400">The leaderboard will be populated as users start earning points.</p>
428
+ <TrendingUp className="w-12 h-12 mx-auto mb-4" style={{ color: theme.mutedForeground }} />
429
+ <h3 className="text-lg font-semibold mb-2" style={{ color: theme.foreground }}>No Leaderboard Data</h3>
430
+ <p style={{ color: theme.mutedForeground }}>The leaderboard will be populated as users start earning points.</p>
420
431
  </div>
421
432
  )}
422
433
 
@@ -425,17 +436,17 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
425
436
  <div className="overflow-x-auto">
426
437
  <table className="w-full">
427
438
  <thead>
428
- <tr className="border-b border-gray-700 bg-gray-800/50">
429
- <th className="px-4 py-3 text-left text-xs font-semibold text-gray-400 uppercase">
439
+ <tr className="border-b" style={{ borderColor: theme.border, backgroundColor: theme.muted }}>
440
+ <th className="px-4 py-3 text-left text-xs font-semibold uppercase" style={{ color: theme.mutedForeground }}>
430
441
  Rank
431
442
  </th>
432
- <th className="px-4 py-3 text-left text-xs font-semibold text-gray-400 uppercase">
443
+ <th className="px-4 py-3 text-left text-xs font-semibold uppercase" style={{ color: theme.mutedForeground }}>
433
444
  Wallet
434
445
  </th>
435
- <th className="px-4 py-3 text-right text-xs font-semibold text-gray-400 uppercase">
446
+ <th className="px-4 py-3 text-right text-xs font-semibold uppercase" style={{ color: theme.mutedForeground }}>
436
447
  Points
437
448
  </th>
438
- <th className="px-4 py-3 text-center text-xs font-semibold text-gray-400 uppercase">
449
+ <th className="px-4 py-3 text-center text-xs font-semibold uppercase" style={{ color: theme.mutedForeground }}>
439
450
  Badges
440
451
  </th>
441
452
  </tr>
@@ -446,6 +457,7 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
446
457
  key={entry.rank}
447
458
  entry={entry}
448
459
  accentColor={accentColor}
460
+ theme={theme}
449
461
  isCurrentUser={
450
462
  walletAddress
451
463
  ? entry.walletAddress.toLowerCase() === walletAddress.toLowerCase()
@@ -465,15 +477,16 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
465
477
 
466
478
  {/* Pagination */}
467
479
  {!compactMode && data.length > itemsPerPage && (
468
- <div className="px-6 py-4 border-t border-gray-700 flex items-center justify-between">
469
- <div className="text-sm text-gray-400">
480
+ <div className="px-6 py-4 border-t flex items-center justify-between" style={{ borderColor: theme.border }}>
481
+ <div className="text-sm" style={{ color: theme.mutedForeground }}>
470
482
  Showing {startIndex + 1} to {Math.min(endIndex, data.length)} of {data.length}
471
483
  </div>
472
484
  <div className="flex gap-2">
473
485
  <button
474
486
  onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
475
487
  disabled={currentPage === 1}
476
- className="px-3 py-1.5 rounded-lg text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-700 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
488
+ className="px-3 py-1.5 rounded-lg text-sm font-medium transition-all disabled:opacity-50 disabled:cursor-not-allowed"
489
+ style={{ color: theme.mutedForeground }}
477
490
  >
478
491
  ← Previous
479
492
  </button>
@@ -484,18 +497,14 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
484
497
  <button
485
498
  key={pageNum}
486
499
  onClick={() => setCurrentPage(pageNum)}
487
- className={`px-3 py-1.5 rounded-lg text-sm font-medium transition-all ${
488
- currentPage === pageNum
489
- ? 'text-white'
490
- : 'text-gray-400 hover:text-white hover:bg-gray-700'
491
- }`}
500
+ className="px-3 py-1.5 rounded-lg text-sm font-medium transition-all"
492
501
  style={
493
502
  currentPage === pageNum
494
503
  ? {
495
504
  backgroundColor: accentColor,
496
505
  color: 'white',
497
506
  }
498
- : {}
507
+ : { color: theme.mutedForeground }
499
508
  }
500
509
  >
501
510
  {pageNum}
@@ -506,7 +515,8 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
506
515
  <button
507
516
  onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
508
517
  disabled={currentPage === totalPages}
509
- className="px-3 py-1.5 rounded-lg text-sm font-medium text-gray-400 hover:text-white hover:bg-gray-700 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
518
+ className="px-3 py-1.5 rounded-lg text-sm font-medium transition-all disabled:opacity-50 disabled:cursor-not-allowed"
519
+ style={{ color: theme.mutedForeground }}
510
520
  >
511
521
  Next →
512
522
  </button>
@@ -515,7 +525,7 @@ export const Leaderboard: React.FC<LeaderboardProps> = ({
515
525
  )}
516
526
 
517
527
  {/* Footer */}
518
- <div className="px-6 py-3 border-t border-gray-700 flex items-center justify-end text-xs text-gray-500">
528
+ <div className="px-6 py-3 border-t flex items-center justify-end text-xs" style={{ borderColor: theme.border, color: theme.mutedForeground }}>
519
529
  <span className="flex items-center gap-1">
520
530
  <ExternalLink className="w-3 h-3" />
521
531
  @chainloyalty/react
@@ -30,6 +30,7 @@ import {
30
30
  RefreshCw,
31
31
  Lock,
32
32
  } from 'lucide-react';
33
+ import { getThemeColors } from './theme';
33
34
 
34
35
  // ============================================================================
35
36
  // Types & Interfaces
@@ -244,34 +245,40 @@ const getRarityColor = (rarity: string): string => {
244
245
  interface RewardHistoryProps {
245
246
  items: RewardHistoryItem[];
246
247
  accentColor: string;
248
+ theme: ReturnType<typeof getThemeColors>;
247
249
  }
248
250
 
249
- const RewardHistory: React.FC<RewardHistoryProps> = ({ items, accentColor }) => {
251
+ const RewardHistory: React.FC<RewardHistoryProps> = ({ items, accentColor, theme }) => {
250
252
  return (
251
253
  <div className="space-y-3">
252
254
  {items.map((item) => (
253
255
  <div
254
256
  key={item.id}
255
- className="flex items-start justify-between p-3 rounded-lg border border-gray-700 hover:border-gray-600 transition-colors"
256
- style={{ borderLeftColor: accentColor, borderLeftWidth: '3px' }}
257
+ className="flex items-start justify-between p-3 rounded-lg border transition-colors hover:opacity-80"
258
+ style={{
259
+ borderColor: theme.border,
260
+ borderLeftColor: accentColor,
261
+ borderLeftWidth: '3px',
262
+ backgroundColor: 'transparent',
263
+ }}
257
264
  >
258
265
  <div className="flex-1">
259
266
  <div className="flex items-center gap-2">
260
- <span className="text-sm font-semibold text-white">{item.title}</span>
261
- <span className="text-xs px-2 py-0.5 rounded-full bg-gray-700 text-gray-300">
267
+ <span className="text-sm font-semibold" style={{ color: theme.foreground }}>{item.title}</span>
268
+ <span className="text-xs px-2 py-0.5 rounded-full" style={{ backgroundColor: theme.muted, color: theme.mutedForeground }}>
262
269
  {item.type}
263
270
  </span>
264
271
  </div>
265
272
  {item.description && (
266
- <p className="text-xs text-gray-400 mt-1">{item.description}</p>
273
+ <p className="text-xs mt-1" style={{ color: theme.mutedForeground }}>{item.description}</p>
267
274
  )}
268
- <p className="text-xs text-gray-500 mt-1">{formatDate(item.timestamp)}</p>
275
+ <p className="text-xs mt-1" style={{ color: theme.mutedForeground }}>{formatDate(item.timestamp)}</p>
269
276
  </div>
270
277
  <div className="ml-4 text-right">
271
278
  <p className="text-lg font-bold" style={{ color: accentColor }}>
272
279
  +{item.points}
273
280
  </p>
274
- <p className="text-xs text-gray-400">points</p>
281
+ <p className="text-xs" style={{ color: theme.mutedForeground }}>points</p>
275
282
  </div>
276
283
  </div>
277
284
  ))}
@@ -285,10 +292,11 @@ const RewardHistory: React.FC<RewardHistoryProps> = ({ items, accentColor }) =>
285
292
 
286
293
  interface BadgeGridProps {
287
294
  badges: Badge[];
295
+ theme: ReturnType<typeof getThemeColors>;
288
296
  compactMode?: boolean;
289
297
  }
290
298
 
291
- const BadgeGrid: React.FC<BadgeGridProps> = ({ badges, compactMode = false }) => {
299
+ const BadgeGrid: React.FC<BadgeGridProps> = ({ badges, theme, compactMode = false }) => {
292
300
  const displayBadges = compactMode ? badges.slice(0, 4) : badges;
293
301
 
294
302
  return (
@@ -301,18 +309,19 @@ const BadgeGrid: React.FC<BadgeGridProps> = ({ badges, compactMode = false }) =>
301
309
  className="group relative p-3 rounded-lg border transition-all hover:scale-105 cursor-pointer"
302
310
  style={{
303
311
  borderColor: getRarityColor(badge.rarity),
304
- backgroundColor: 'rgba(31, 41, 55, 0.5)',
312
+ backgroundColor: theme.card,
313
+ opacity: 0.9,
305
314
  }}
306
315
  title={`${badge.name} - ${badge.description}`}
307
316
  >
308
317
  <div className="text-3xl mb-1 text-center">{badge.icon}</div>
309
- <p className="text-xs font-semibold text-white text-center truncate">{badge.name}</p>
310
- <p className="text-xs text-gray-400 text-center mt-0.5">
318
+ <p className="text-xs font-semibold text-center truncate" style={{ color: theme.foreground }}>{badge.name}</p>
319
+ <p className="text-xs text-center mt-0.5" style={{ color: theme.mutedForeground }}>
311
320
  {new Date(badge.earnedAt).toLocaleDateString()}
312
321
  </p>
313
322
 
314
323
  {/* Tooltip on hover */}
315
- <div className="hidden group-hover:block absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 p-2 bg-gray-900 border border-gray-700 rounded-lg text-xs text-gray-300 w-32 text-center whitespace-normal z-10">
324
+ <div className="hidden group-hover:block absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 p-2 border rounded-lg text-xs w-32 text-center whitespace-normal z-10" style={{ backgroundColor: theme.muted, borderColor: theme.border, color: theme.mutedForeground }}>
316
325
  {badge.description}
317
326
  </div>
318
327
  </div>
@@ -328,9 +337,10 @@ const BadgeGrid: React.FC<BadgeGridProps> = ({ badges, compactMode = false }) =>
328
337
  interface TierCardProps {
329
338
  tier: TierInfo;
330
339
  accentColor: string;
340
+ theme: ReturnType<typeof getThemeColors>;
331
341
  }
332
342
 
333
- const TierCard: React.FC<TierCardProps> = ({ tier, accentColor }) => {
343
+ const TierCard: React.FC<TierCardProps> = ({ tier, accentColor, theme }) => {
334
344
  const progressPercent = (tier.currentProgress / tier.nextMilestone) * 100;
335
345
 
336
346
  return (
@@ -338,24 +348,24 @@ const TierCard: React.FC<TierCardProps> = ({ tier, accentColor }) => {
338
348
  className="p-4 rounded-lg border"
339
349
  style={{
340
350
  borderColor: accentColor,
341
- backgroundColor: 'rgba(31, 41, 55, 0.3)',
351
+ backgroundColor: theme.card,
342
352
  }}
343
353
  >
344
354
  <div className="flex items-start justify-between mb-3">
345
355
  <div className="flex items-center gap-2">
346
356
  <span className="text-3xl">{tier.icon}</span>
347
357
  <div>
348
- <p className="text-sm font-semibold text-white">{tier.name}</p>
349
- <p className="text-xs text-gray-400">Level {tier.level}</p>
358
+ <p className="text-sm font-semibold" style={{ color: theme.foreground }}>{tier.name}</p>
359
+ <p className="text-xs" style={{ color: theme.mutedForeground }}>Level {tier.level}</p>
350
360
  </div>
351
361
  </div>
352
362
  </div>
353
363
  <div className="space-y-2">
354
- <div className="flex justify-between text-xs text-gray-400">
364
+ <div className="flex justify-between text-xs" style={{ color: theme.mutedForeground }}>
355
365
  <span>{tier.currentProgress.toLocaleString()} points</span>
356
366
  <span>{tier.nextMilestone.toLocaleString()} goal</span>
357
367
  </div>
358
- <div className="w-full bg-gray-700 rounded-full h-2 overflow-hidden">
368
+ <div className="w-full rounded-full h-2 overflow-hidden" style={{ backgroundColor: theme.muted }}>
359
369
  <div
360
370
  className="h-full rounded-full transition-all duration-500"
361
371
  style={{
@@ -387,9 +397,13 @@ export const RewardsDashboard: React.FC<RewardsDashboardProps> = ({
387
397
  const [error, setError] = useState<string | null>(null);
388
398
  const [copied, setCopied] = useState(false);
389
399
 
390
- const backgroundColor = customColors.background || '#0D1117';
391
- const accentColor = customColors.accent1 || '#2F81F7';
392
- const accentColor2 = customColors.accent2 || '#3FB950';
400
+ // Get theme colors from host app's CSS variables
401
+ const theme = getThemeColors();
402
+
403
+ // Override with customColors if provided (backward compatibility)
404
+ const accentColor = customColors.accent1 || theme.accent;
405
+ const accentColor2 = customColors.accent2 || theme.primary;
406
+ const backgroundColor = customColors.background || theme.card;
393
407
 
394
408
  // Fetch data when wallet changes
395
409
  useEffect(() => {
@@ -433,21 +447,22 @@ export const RewardsDashboard: React.FC<RewardsDashboardProps> = ({
433
447
  if (!walletAddress) {
434
448
  return (
435
449
  <div
436
- className="p-6 rounded-lg border border-gray-700 max-w-2xl"
437
- style={{ backgroundColor }}
450
+ className="p-6 rounded-lg border max-w-2xl"
451
+ style={{ backgroundColor: theme.card, borderColor: theme.border }}
438
452
  >
439
453
  <div className="text-center">
440
- <Lock className="w-12 h-12 mx-auto mb-4 text-gray-500" />
441
- <h2 className="text-xl font-bold text-white mb-2">Connect Your Wallet</h2>
442
- <p className="text-gray-400 mb-6">
454
+ <Lock className="w-12 h-12 mx-auto mb-4" style={{ color: theme.mutedForeground }} />
455
+ <h2 className="text-xl font-bold mb-2" style={{ color: theme.foreground }}>Connect Your Wallet</h2>
456
+ <p className="mb-6" style={{ color: theme.mutedForeground }}>
443
457
  Connect your wallet to view your rewards, badges, and track your achievements.
444
458
  </p>
445
459
  {onConnectWallet && (
446
460
  <button
447
461
  onClick={onConnectWallet}
448
- className="inline-flex items-center gap-2 px-6 py-2 rounded-lg font-semibold text-white transition-all hover:opacity-90"
462
+ className="inline-flex items-center gap-2 px-6 py-2 rounded-lg font-semibold transition-all hover:opacity-90"
449
463
  style={{
450
464
  backgroundColor: accentColor,
465
+ color: '#fff',
451
466
  }}
452
467
  >
453
468
  <Wallet className="w-5 h-5" />
@@ -463,13 +478,13 @@ export const RewardsDashboard: React.FC<RewardsDashboardProps> = ({
463
478
  if (loading && !data) {
464
479
  return (
465
480
  <div
466
- className="p-6 rounded-lg border border-gray-700 max-w-2xl"
467
- style={{ backgroundColor }}
481
+ className="p-6 rounded-lg border max-w-2xl"
482
+ style={{ backgroundColor: theme.card, borderColor: theme.border }}
468
483
  >
469
484
  <div className="space-y-4">
470
- <div className="h-20 bg-gray-700 rounded-lg animate-pulse" />
471
- <div className="h-40 bg-gray-700 rounded-lg animate-pulse" />
472
- <div className="h-32 bg-gray-700 rounded-lg animate-pulse" />
485
+ <div className="h-20 rounded-lg animate-pulse" style={{ backgroundColor: theme.muted }} />
486
+ <div className="h-40 rounded-lg animate-pulse" style={{ backgroundColor: theme.muted }} />
487
+ <div className="h-32 rounded-lg animate-pulse" style={{ backgroundColor: theme.muted }} />
473
488
  </div>
474
489
  </div>
475
490
  );
@@ -479,10 +494,10 @@ export const RewardsDashboard: React.FC<RewardsDashboardProps> = ({
479
494
  if (error && !data) {
480
495
  return (
481
496
  <div
482
- className="p-6 rounded-lg border border-red-700 max-w-2xl"
483
- style={{ backgroundColor }}
497
+ className="p-6 rounded-lg border max-w-2xl"
498
+ style={{ backgroundColor: theme.card, borderColor: '#dc2626' }}
484
499
  >
485
- <p className="text-red-400">Failed to load rewards: {error}</p>
500
+ <p style={{ color: '#ef4444' }}>Failed to load rewards: {error}</p>
486
501
  <button
487
502
  onClick={handleRefresh}
488
503
  className="mt-4 px-4 py-2 rounded-lg text-white text-sm transition-all"
@@ -504,28 +519,30 @@ export const RewardsDashboard: React.FC<RewardsDashboardProps> = ({
504
519
  {/* Header */}
505
520
  <div className="p-6 border-b border-gray-700">
506
521
  <div className="flex items-center justify-between mb-4">
507
- <h2 className="text-2xl font-bold text-white">Rewards Dashboard</h2>
522
+ <h2 className="text-2xl font-bold" style={{ color: theme.foreground }}>Rewards Dashboard</h2>
508
523
  <button
509
524
  onClick={handleRefresh}
510
525
  disabled={loading}
511
- className="p-2 rounded-lg text-gray-400 hover:text-white hover:bg-gray-700 transition-all disabled:opacity-50"
526
+ className="p-2 rounded-lg transition-all disabled:opacity-50"
527
+ style={{ color: theme.mutedForeground }}
512
528
  >
513
529
  <RefreshCw className={`w-5 h-5 ${loading ? 'animate-spin' : ''}`} />
514
530
  </button>
515
531
  </div>
516
532
 
517
533
  {/* Wallet Display */}
518
- <div className="flex items-center justify-between p-3 rounded-lg bg-gray-800/50 border border-gray-700">
534
+ <div className="flex items-center justify-between p-3 rounded-lg border" style={{ backgroundColor: theme.muted, borderColor: theme.border }}>
519
535
  <div className="flex items-center gap-2">
520
536
  <Wallet className="w-5 h-5" style={{ color: accentColor }} />
521
537
  <div>
522
- <p className="text-xs text-gray-400">Connected Wallet</p>
523
- <p className="text-sm font-mono font-semibold text-white">{shortenAddress(walletAddress)}</p>
538
+ <p className="text-xs" style={{ color: theme.mutedForeground }}>Connected Wallet</p>
539
+ <p className="text-sm font-mono font-semibold" style={{ color: theme.foreground }}>{shortenAddress(walletAddress)}</p>
524
540
  </div>
525
541
  </div>
526
542
  <button
527
543
  onClick={handleCopyAddress}
528
- className="p-2 rounded-lg text-gray-400 hover:text-white hover:bg-gray-700 transition-all"
544
+ className="p-2 rounded-lg transition-all"
545
+ style={{ color: theme.mutedForeground }}
529
546
  title={walletAddress}
530
547
  >
531
548
  {copied ? <CheckCircle className="w-5 h-5" style={{ color: accentColor2 }} /> : <Copy className="w-5 h-5" />}
@@ -534,28 +551,28 @@ export const RewardsDashboard: React.FC<RewardsDashboardProps> = ({
534
551
  </div>
535
552
 
536
553
  {/* Main Content */}
537
- <div className={`p-6 space-y-6 ${compactMode ? 'max-w-3xl' : ''}`} style={{backgroundColor: 'rgba(31, 41, 55, 0.2)'}}>
554
+ <div className={`p-6 space-y-6 ${compactMode ? 'max-w-3xl' : ''}`} style={{backgroundColor: theme.background}}>
538
555
  {/* Points Display */}
539
556
  <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
540
557
  <div
541
558
  className="p-6 rounded-lg border text-center"
542
559
  style={{
543
560
  borderColor: accentColor,
544
- backgroundColor: 'rgba(47, 129, 247, 0.1)',
561
+ backgroundColor: theme.card,
545
562
  }}
546
563
  >
547
- <p className="text-sm text-gray-400 mb-2">Total Points</p>
564
+ <p className="text-sm mb-2" style={{ color: theme.mutedForeground }}>Total Points</p>
548
565
  <p className="text-4xl font-bold" style={{ color: accentColor }}>
549
566
  {data.totalPoints.toLocaleString()}
550
567
  </p>
551
- <div className="flex items-center justify-center gap-1 mt-2 text-xs text-gray-400">
568
+ <div className="flex items-center justify-center gap-1 mt-2 text-xs" style={{ color: theme.mutedForeground }}>
552
569
  <TrendingUp className="w-4 h-4" />
553
570
  <span>Keep earning rewards</span>
554
571
  </div>
555
572
  </div>
556
573
 
557
574
  {!hideTier && (
558
- <TierCard tier={data.tier} accentColor={accentColor2} />
575
+ <TierCard tier={data.tier} accentColor={accentColor2} theme={theme} />
559
576
  )}
560
577
  </div>
561
578
 
@@ -564,11 +581,11 @@ export const RewardsDashboard: React.FC<RewardsDashboardProps> = ({
564
581
  <div>
565
582
  <div className="flex items-center gap-2 mb-4">
566
583
  <Award className="w-5 h-5" style={{ color: accentColor }} />
567
- <h3 className="text-lg font-semibold text-white">
584
+ <h3 className="text-lg font-semibold" style={{ color: theme.foreground }}>
568
585
  Badges ({data.badges.length})
569
586
  </h3>
570
587
  </div>
571
- <BadgeGrid badges={data.badges} compactMode={compactMode} />
588
+ <BadgeGrid badges={data.badges} theme={theme} compactMode={compactMode} />
572
589
  </div>
573
590
  )}
574
591
 
@@ -577,18 +594,19 @@ export const RewardsDashboard: React.FC<RewardsDashboardProps> = ({
577
594
  <div>
578
595
  <div className="flex items-center gap-2 mb-4">
579
596
  <Zap className="w-5 h-5" style={{ color: accentColor2 }} />
580
- <h3 className="text-lg font-semibold text-white">Recent Rewards</h3>
597
+ <h3 className="text-lg font-semibold" style={{ color: theme.foreground }}>Recent Rewards</h3>
581
598
  </div>
582
599
  <RewardHistory
583
600
  items={compactMode ? data.rewardHistory.slice(0, 3) : data.rewardHistory}
584
601
  accentColor={accentColor}
602
+ theme={theme}
585
603
  />
586
604
  </div>
587
605
  )}
588
606
  </div>
589
607
 
590
608
  {/* Footer */}
591
- <div className="px-6 py-3 border-t border-gray-700 flex items-center justify-between text-xs text-gray-500">
609
+ <div className="px-6 py-3 border-t flex items-center justify-between text-xs" style={{ borderColor: theme.border, color: theme.mutedForeground }}>
592
610
  <span>Last updated: {formatDate(data.lastUpdated)}</span>
593
611
  <span className="flex items-center gap-1">
594
612
  <ExternalLink className="w-3 h-3" />