refactor: integrate Grimoire member styling into UserName component

Simplifies the member system by removing the separate GrimoireUsername
component and handling everything directly in UserName.

Changes:
- UserName now checks isGrimoireMember and displays special styling
- Grimoire members show with yellow-orange gradient (from-yellow-400 to-orange-500)
- Member username displayed as "username@grimoire.rocks"
- Removed GrimoireUsername and GrimoireBadge components
- Updated nip05 to skip display for Grimoire members (UserName handles it)

This consolidates the logic and creates a cleaner, more maintainable
architecture where UserName is the single source of truth for all
username displays.
This commit is contained in:
Claude
2026-01-18 11:02:49 +00:00
parent 7fe97ad157
commit 07b0831966
3 changed files with 19 additions and 86 deletions

View File

@@ -1,72 +0,0 @@
import { getGrimoireMember } from "@/lib/grimoire-members";
import { BookOpen } from "lucide-react";
import { cn } from "@/lib/utils";
/**
* Grimoire Username Component
*
* Displays Grimoire member usernames with special styling and verification badge.
* If the pubkey belongs to a Grimoire member, shows their custom username
* with a Grimoire badge icon. Otherwise returns null.
*/
export function GrimoireUsername({
pubkey,
className,
showIcon = true,
}: {
pubkey: string;
className?: string;
showIcon?: boolean;
}) {
const member = getGrimoireMember(pubkey);
if (!member) {
return null;
}
return (
<span
className={cn(
"inline-flex items-center gap-1.5 text-accent font-medium",
className,
)}
title={`Grimoire member: ${member.nip05}`}
>
<span>{member.username}@grimoire.rocks</span>
{showIcon && (
<BookOpen
className="h-3.5 w-3.5 text-accent"
aria-label="Grimoire member"
/>
)}
</span>
);
}
/**
* Grimoire Badge Component
*
* Shows just the verification badge icon for Grimoire members.
* Useful for adding next to existing username displays.
*/
export function GrimoireBadge({
pubkey,
className,
}: {
pubkey: string;
className?: string;
}) {
const member = getGrimoireMember(pubkey);
if (!member) {
return null;
}
return (
<BookOpen
className={cn("h-3.5 w-3.5 text-accent", className)}
title={`Grimoire member: ${member.nip05}`}
aria-label="Grimoire member"
/>
);
}

View File

@@ -2,7 +2,7 @@ import { useProfile } from "@/hooks/useProfile";
import { getDisplayName } from "@/lib/nostr-utils";
import { cn } from "@/lib/utils";
import { useGrimoire } from "@/core/state";
import { GrimoireBadge } from "./GrimoireUsername";
import { getGrimoireUsername, isGrimoireMember } from "@/lib/grimoire-members";
interface UserNameProps {
pubkey: string;
@@ -15,12 +15,17 @@ interface UserNameProps {
* Shows placeholder derived from pubkey while loading or if no profile exists
* Clicking opens the user's profile
* Uses highlight color for the logged-in user (themeable amber)
* Shows Grimoire badge for Grimoire members
* Shows Grimoire members with yellow-orange gradient styling
*/
export function UserName({ pubkey, isMention, className }: UserNameProps) {
const { addWindow, state } = useGrimoire();
const profile = useProfile(pubkey);
const displayName = getDisplayName(pubkey, profile);
const isGrimoire = isGrimoireMember(pubkey);
const grimoireUsername = getGrimoireUsername(pubkey);
const displayName =
isGrimoire && grimoireUsername
? `${grimoireUsername}@grimoire.rocks`
: getDisplayName(pubkey, profile);
// Check if this is the logged-in user
const isActiveAccount = state.activeAccount?.pubkey === pubkey;
@@ -34,17 +39,18 @@ export function UserName({ pubkey, isMention, className }: UserNameProps) {
<span
dir="auto"
className={cn(
"inline-flex items-center gap-1.5 font-semibold cursor-crosshair hover:underline hover:decoration-dotted",
isActiveAccount ? "text-highlight" : "text-accent",
"font-semibold cursor-crosshair hover:underline hover:decoration-dotted",
isGrimoire
? "bg-gradient-to-r from-yellow-400 to-orange-500 bg-clip-text text-transparent"
: isActiveAccount
? "text-highlight"
: "text-accent",
className,
)}
onClick={handleClick}
>
<span>
{isMention ? "@" : null}
{displayName}
</span>
<GrimoireBadge pubkey={pubkey} />
{isMention ? "@" : null}
{displayName}
</span>
);
}

View File

@@ -1,6 +1,5 @@
import { useNip05 } from "@/hooks/useNip05";
import { ProfileContent } from "applesauce-core/helpers";
import { GrimoireUsername } from "./GrimoireUsername";
import { isGrimoireMember } from "@/lib/grimoire-members";
export function QueryNip05({
@@ -22,12 +21,12 @@ export default function Nip05({
pubkey: string;
profile: ProfileContent;
}) {
// Check if this is a Grimoire member first - they get special display
// Grimoire members don't show NIP-05 here (handled by UserName component)
if (isGrimoireMember(pubkey)) {
return <GrimoireUsername pubkey={pubkey} />;
return null;
}
// Otherwise show regular NIP-05 if available
// Show regular NIP-05 if available
if (!profile?.nip05) return null;
return <QueryNip05 pubkey={pubkey} nip05={profile.nip05} />;
}