diff --git a/src/app/components/LeaderboardList.js b/src/app/components/LeaderboardList.js index 524ac50..3837749 100644 --- a/src/app/components/LeaderboardList.js +++ b/src/app/components/LeaderboardList.js @@ -6,37 +6,24 @@ import { Skeleton } from '@/components/ui/skeleton'; import { formatDistance, calculateScore, bandsForBbox } from '../../lib/game'; import { getRegion, isRegion } from '../../lib/regions'; -// Keyed by the round score the distance would earn, so the tint tracks the -// scoring ladder instead of re-typing its thresholds. -const DISTANCE_COLORS = { - 5: 'text-green-700 dark:text-green-300', - 4: 'text-blue-700 dark:text-blue-300', - 3: 'text-yellow-700 dark:text-yellow-300', - 2: 'text-orange-700 dark:text-orange-300', -}; - // Graded against the BOARD's own regional ladder, mirroring how the boards -// are credited: 2km is red on a district board and green on the country one. +// are credited: 2km is amber on a district board and green on the country +// one. Three semantic states, not a rainbow -- good, close, far -- because +// finer steps carried no meaning a reader could recover. function getDistanceColor(distance, bands) { - return DISTANCE_COLORS[calculateScore(distance, bands)] ?? 'text-red-700 dark:text-red-300'; -} - -function getScoreColor(score) { - if (score >= 50) return 'text-purple-700 dark:text-purple-300'; - if (score >= 25) return 'text-green-700 dark:text-green-300'; - if (score >= 15) return 'text-blue-700 dark:text-blue-300'; - if (score >= 10) return 'text-yellow-700 dark:text-yellow-300'; - if (score >= 5) return 'text-orange-700 dark:text-orange-300'; - return 'text-red-700 dark:text-red-300'; + const score = calculateScore(distance, bands); + if (score >= 4) return 'text-success'; + if (score >= 2) return 'text-warning'; + return 'text-danger'; } // Medal tint for the podium. The rank number stays visible alongside it, so the // placing never depends on reading the colour or an emoji glyph. function getMedalClass(rank) { switch (rank) { - case 1: return 'text-amber-500'; - case 2: return 'text-slate-400'; - case 3: return 'text-orange-700 dark:text-orange-400'; + case 1: return 'text-rank-gold'; + case 2: return 'text-rank-silver'; + case 3: return 'text-rank-bronze'; default: return ''; } } @@ -84,7 +71,7 @@ export default function LeaderboardList({ data, loading, currentUsername, type, key={key} className={`flex items-center justify-between p-3 rounded-lg transition-all ${ isUser - ? 'bg-amber-100/70 dark:bg-amber-950/40 border-2 border-amber-500 shadow-md' + ? 'bg-brand-subtle/70 border-2 border-brand shadow-md' : entry.rank <= 3 ? 'bg-brand-subtle/40 border border-brand/20' : 'bg-muted/50 hover:bg-muted' @@ -98,10 +85,10 @@ export default function LeaderboardList({ data, loading, currentUsername, type, #{entry.rank}
-
+
{entry.username} {isUser && ( - YOU + YOU )}
{isDistance && entry.timestamp && ( @@ -111,8 +98,11 @@ export default function LeaderboardList({ data, loading, currentUsername, type, )}
+ {/* Score totals carry no tint: unlike a distance, a running total + has no ladder to grade against, and the old size-keyed rainbow + encoded nothing a reader could recover. */} {isDistance ? formatDistance(entry.distance) : entry.score} diff --git a/src/app/components/ThemeToggle.js b/src/app/components/ThemeToggle.js index e5f2f01..f225b9c 100644 --- a/src/app/components/ThemeToggle.js +++ b/src/app/components/ThemeToggle.js @@ -1,6 +1,7 @@ "use client"; import { useEffect, useState } from 'react'; +import { Monitor, Moon, Sun } from 'lucide-react'; import { THEMES, DEFAULT_THEME, @@ -10,6 +11,14 @@ import { watchSystemTheme, } from '../../lib/theme'; +// Lucide, matching the rest of the chrome's icon language (Trophy, Wrench, +// ArrowLeft ...); emoji ignored currentColor and read noisier than the rest. +const THEME_ICONS = { + light: Sun, + dark: Moon, + system: Monitor, +}; + export default function ThemeToggle({ className = '' }) { const [theme, setTheme] = useState(DEFAULT_THEME); // The stored choice only exists on the client, so the first paint has to @@ -46,6 +55,7 @@ export default function ThemeToggle({ className = '' }) { > {THEMES.map((option) => { const selected = mounted && theme === option.value; + const Icon = THEME_ICONS[option.value]; return ( ); })} diff --git a/src/app/debug/layout.js b/src/app/debug/layout.js index d388b1a..aa72786 100644 --- a/src/app/debug/layout.js +++ b/src/app/debug/layout.js @@ -11,7 +11,7 @@ import DebugNav from './DebugNav'; // manages its own panes. export default function DebugLayout({ children }) { return ( -
+