mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-12 08:27:27 +02:00
refactor: extract TopContributor into shared component
- Create shared TopContributor component in src/components/nostr/TopContributor.tsx - Support two variants: "default" (larger, shows "sats" suffix) and "compact" (smaller, no suffix) - Update user menu to use shared component with default variant - Update welcome screen to use shared component with compact variant - Remove duplicate code and consolidate formatting logic - Maintain consistent visual design across both usages
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
import { Terminal, Trophy } from "lucide-react";
|
||||
import { Terminal } from "lucide-react";
|
||||
import { Button } from "./ui/button";
|
||||
import { Kbd, KbdGroup } from "./ui/kbd";
|
||||
import { Progress } from "./ui/progress";
|
||||
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";
|
||||
import { TopContributor } from "./nostr/TopContributor";
|
||||
|
||||
interface GrimoireWelcomeProps {
|
||||
onLaunchCommand: () => void;
|
||||
@@ -30,36 +29,6 @@ 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 (
|
||||
<div className="flex items-center gap-1.5 mt-1.5 pt-1.5 border-t border-border/30">
|
||||
<Trophy className="size-3 text-yellow-500" />
|
||||
<span className="text-[10px] text-muted-foreground flex-1 truncate">
|
||||
{displayName}
|
||||
</span>
|
||||
<span className="text-[10px] font-medium">{formatNumber(amount)}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function GrimoireWelcome({
|
||||
onLaunchCommand,
|
||||
onExecuteCommand,
|
||||
@@ -187,6 +156,7 @@ export function GrimoireWelcome({
|
||||
<TopContributor
|
||||
pubkey={topContributor.pubkey}
|
||||
amount={topContributor.totalSats}
|
||||
variant="compact"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
48
src/components/nostr/TopContributor.tsx
Normal file
48
src/components/nostr/TopContributor.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Trophy } from "lucide-react";
|
||||
import { useProfile } from "@/hooks/useProfile";
|
||||
import { getDisplayName } from "@/lib/nostr-utils";
|
||||
|
||||
interface TopContributorProps {
|
||||
pubkey: string;
|
||||
amount: number;
|
||||
variant?: "default" | "compact";
|
||||
}
|
||||
|
||||
export function TopContributor({
|
||||
pubkey,
|
||||
amount,
|
||||
variant = "default",
|
||||
}: TopContributorProps) {
|
||||
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();
|
||||
}
|
||||
|
||||
const isCompact = variant === "compact";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center gap-1.5 mt-${isCompact ? "1.5" : "2"} pt-${isCompact ? "1.5" : "2"} border-t border-border/${isCompact ? "30" : "50"}`}
|
||||
>
|
||||
<Trophy
|
||||
className={`${isCompact ? "size-3" : "size-3.5"} text-yellow-500`}
|
||||
/>
|
||||
<span
|
||||
className={`${isCompact ? "text-[10px]" : "text-xs"} text-muted-foreground flex-1 truncate`}
|
||||
>
|
||||
{displayName}
|
||||
</span>
|
||||
<span className={`${isCompact ? "text-[10px]" : "text-xs"} font-medium`}>
|
||||
{formatNumber(amount)}
|
||||
{!isCompact && " sats"}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
Eye,
|
||||
EyeOff,
|
||||
Zap,
|
||||
Trophy,
|
||||
} from "lucide-react";
|
||||
import accounts from "@/services/accounts";
|
||||
import { useProfile } from "@/hooks/useProfile";
|
||||
@@ -40,6 +39,7 @@ import {
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import Nip05 from "./nip05";
|
||||
import { RelayLink } from "./RelayLink";
|
||||
import { TopContributor } from "./TopContributor";
|
||||
import SettingsDialog from "@/components/SettingsDialog";
|
||||
import LoginDialog from "./LoginDialog";
|
||||
import ConnectWalletDialog from "@/components/ConnectWalletDialog";
|
||||
@@ -83,36 +83,6 @@ function UserLabel({ pubkey }: { pubkey: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
function TopContributor({
|
||||
pubkey,
|
||||
amount,
|
||||
}: {
|
||||
pubkey: string;
|
||||
amount: number;
|
||||
}) {
|
||||
const profile = useProfile(pubkey);
|
||||
const displayName = getDisplayName(pubkey, profile);
|
||||
|
||||
function formatSats(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 (
|
||||
<div className="flex items-center gap-2 mt-2 pt-2 border-t border-border/50">
|
||||
<Trophy className="size-3.5 text-yellow-500" />
|
||||
<span className="text-xs text-muted-foreground flex-1 truncate">
|
||||
{displayName}
|
||||
</span>
|
||||
<span className="text-xs font-medium">{formatSats(amount)} sats</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function UserMenu() {
|
||||
const account = use$(accounts.active$);
|
||||
const { state, addWindow, disconnectNWC, toggleWalletBalancesBlur } =
|
||||
|
||||
Reference in New Issue
Block a user