From 7a7160bdacb9ca15b3409d625d0a6ddd26f33646 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Jan 2026 09:30:27 +0000 Subject: [PATCH] feat: add top contributor to welcome screen - Add TopContributor component to GrimoireWelcome with smaller size (text-[10px]) - Display below progress bar in "zap grimoire.rocks" command example - Remove "sats" suffix for cleaner display (shows just number with k/M abbreviation) - Use trophy icon (size-3) with yellow accent color - Fetch top contributor reactively using useLiveQuery for real-time updates - Only show when there is at least one contributor for the month --- src/components/GrimoireWelcome.tsx | 48 ++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/components/GrimoireWelcome.tsx b/src/components/GrimoireWelcome.tsx index 6791e47..abb0493 100644 --- a/src/components/GrimoireWelcome.tsx +++ b/src/components/GrimoireWelcome.tsx @@ -1,10 +1,12 @@ -import { Terminal } from "lucide-react"; +import { Terminal, Trophy } from "lucide-react"; import { Button } from "./ui/button"; import { Kbd, KbdGroup } from "./ui/kbd"; import { Progress } from "./ui/progress"; -import { MONTHLY_GOAL_SATS } from "@/services/supporters"; +import supportersService, { MONTHLY_GOAL_SATS } from "@/services/supporters"; import { useLiveQuery } from "dexie-react-hooks"; import db from "@/services/db"; +import { useProfile } from "@/hooks/useProfile"; +import { getDisplayName } from "@/lib/nostr-utils"; interface GrimoireWelcomeProps { onLaunchCommand: () => void; @@ -28,6 +30,36 @@ const EXAMPLE_COMMANDS = [ { command: "req -k 1 -l 20", description: "Query recent notes" }, ]; +function TopContributor({ + pubkey, + amount, +}: { + pubkey: string; + amount: number; +}) { + const profile = useProfile(pubkey); + const displayName = getDisplayName(pubkey, profile); + + function formatNumber(sats: number): string { + if (sats >= 1_000_000) { + return `${(sats / 1_000_000).toFixed(1)}M`; + } else if (sats >= 1_000) { + return `${Math.floor(sats / 1_000)}k`; + } + return sats.toString(); + } + + return ( +
+ + + {displayName} + + {formatNumber(amount)} +
+ ); +} + export function GrimoireWelcome({ onLaunchCommand, onExecuteCommand, @@ -46,6 +78,12 @@ export function GrimoireWelcome({ return total; }, []) ?? 0; + // Get top monthly contributor reactively + const topContributor = useLiveQuery( + async () => supportersService.getTopMonthlyContributor(), + [], + ); + // Calculate progress const goalProgress = (monthlyDonations / MONTHLY_GOAL_SATS) * 100; @@ -145,6 +183,12 @@ export function GrimoireWelcome({ + {topContributor && ( + + )} )}