mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-06-04 09:41:13 +02:00
fix: use RelayLink for relay URLs, remove redundant kindTag, add relay hints
Provider list renderers now use RelayLink instead of raw relay URL strings — shows favicon, insecure ws:// warning, opens relay detail on click. Remove kindTag display from provider cards — it's an internal protocol detail redundant in the UI context. Pass relay hints from provider entries to UserName so profiles can be fetched from the relay the provider actually publishes to. Add UserName relayHints prop (forwarded to useProfile). Add RelayLink and UserName to Shared Components section in CLAUDE.md so they're consistently used across the codebase. https://claude.ai/code/session_01XjwLaShFSVPR5gNA7iUjuB
This commit is contained in:
@@ -340,6 +340,9 @@ This allows `applyTheme()` to switch themes at runtime.
|
||||
- Example: `formatTimestamp(event.created_at, "long")` instead of manual `toLocaleDateString()`
|
||||
- **File Organization**: By domain (`nostr/`, `ui/`, `services/`, `hooks/`, `lib/`)
|
||||
- **State Logic**: All UI state mutations go through `src/core/logic.ts` pure functions
|
||||
- **Shared Components**:
|
||||
- **`RelayLink`** (`src/components/nostr/RelayLink.tsx`): Always use this when displaying relay URLs. It shows the relay favicon, handles insecure `ws://` warnings, and opens the relay detail window on click. Never render raw relay URL strings — use `<RelayLink url={relayUrl} />` instead.
|
||||
- **`UserName`** (`src/components/nostr/UserName.tsx`): Always use this for displaying user pubkeys. Accepts optional `relayHints` prop for fetching profiles from specific relays.
|
||||
|
||||
## Important Patterns
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ interface UserNameProps {
|
||||
pubkey: string;
|
||||
isMention?: boolean;
|
||||
className?: string;
|
||||
relayHints?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,9 +26,14 @@ interface UserNameProps {
|
||||
* - Premium supporters (2.1k+ sats/month): Flame badge in their username color
|
||||
* - Regular supporters: Yellow flame badge (no username color change)
|
||||
*/
|
||||
export function UserName({ pubkey, isMention, className }: UserNameProps) {
|
||||
export function UserName({
|
||||
pubkey,
|
||||
isMention,
|
||||
className,
|
||||
relayHints,
|
||||
}: UserNameProps) {
|
||||
const { addWindow, state } = useGrimoire();
|
||||
const profile = useProfile(pubkey);
|
||||
const profile = useProfile(pubkey, relayHints);
|
||||
const isGrimoire = isGrimoireMember(pubkey);
|
||||
const { isSupporter, isPremiumSupporter } = useIsSupporter(pubkey);
|
||||
const displayName = getDisplayName(pubkey, profile);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { NostrEvent } from "@/types/nostr";
|
||||
import { UserName } from "../UserName";
|
||||
import { RelayLink } from "../RelayLink";
|
||||
import {
|
||||
getTrustedProviders,
|
||||
hasEncryptedProviders,
|
||||
formatKindTag,
|
||||
} from "@/lib/nip85-helpers";
|
||||
import { Shield, Lock, Radio } from "lucide-react";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Shield, Lock } from "lucide-react";
|
||||
|
||||
/**
|
||||
* Trusted Provider List Detail Renderer (Kind 10040)
|
||||
@@ -50,28 +49,18 @@ export function TrustedProviderListDetailRenderer({
|
||||
<div className="flex flex-col gap-2">
|
||||
{providers.map((p, i) => (
|
||||
<div
|
||||
key={`${p.kindTag}-${i}`}
|
||||
className="flex flex-col gap-1.5 p-3 rounded-md border border-border/50 bg-muted/30"
|
||||
key={`${p.servicePubkey}-${i}`}
|
||||
className="flex flex-col gap-2 p-3 rounded-md border border-border/50 bg-muted/30"
|
||||
>
|
||||
{/* Metric badge */}
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="w-fit h-5 px-1.5 text-xs font-mono"
|
||||
>
|
||||
{formatKindTag(p.kindTag)}
|
||||
</Badge>
|
||||
|
||||
{/* Provider */}
|
||||
<div className="flex items-center gap-1.5 text-sm">
|
||||
<span className="text-muted-foreground text-xs">Provider:</span>
|
||||
<UserName pubkey={p.servicePubkey} className="text-sm" />
|
||||
</div>
|
||||
{/* Provider name */}
|
||||
<UserName
|
||||
pubkey={p.servicePubkey}
|
||||
relayHints={[p.relay]}
|
||||
className="text-sm font-medium"
|
||||
/>
|
||||
|
||||
{/* Relay */}
|
||||
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
|
||||
<Radio className="size-3 shrink-0" />
|
||||
<span className="font-mono break-all">{p.relay}</span>
|
||||
</div>
|
||||
<RelayLink url={p.relay} showInboxOutbox={false} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from "./BaseEventRenderer";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { UserName } from "../UserName";
|
||||
import { RelayLink } from "../RelayLink";
|
||||
import {
|
||||
getTrustedProviders,
|
||||
hasEncryptedProviders,
|
||||
@@ -33,7 +34,7 @@ export function TrustedProviderListRenderer({ event }: BaseEventProps) {
|
||||
{/* Compact summary */}
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<Badge variant="outline" className="h-5 px-1.5 text-muted-foreground">
|
||||
{providers.length} mapping{providers.length !== 1 ? "s" : ""}
|
||||
{providers.length} provider{providers.length !== 1 ? "s" : ""}
|
||||
</Badge>
|
||||
{hasEncrypted && (
|
||||
<Badge
|
||||
@@ -46,21 +47,25 @@ export function TrustedProviderListRenderer({ event }: BaseEventProps) {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Provider preview: show unique service keys */}
|
||||
{/* Provider preview */}
|
||||
{previewProviders.length > 0 && (
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<div className="flex flex-col gap-1">
|
||||
{previewProviders.map((p, i) => (
|
||||
<div
|
||||
key={`${p.kindTag}-${i}`}
|
||||
key={`${p.servicePubkey}-${i}`}
|
||||
className="flex items-center gap-1.5 text-xs text-muted-foreground"
|
||||
>
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="h-4 px-1 text-[10px] font-mono shrink-0"
|
||||
>
|
||||
{p.kindTag}
|
||||
</Badge>
|
||||
<UserName pubkey={p.servicePubkey} className="text-xs" />
|
||||
<UserName
|
||||
pubkey={p.servicePubkey}
|
||||
relayHints={[p.relay]}
|
||||
className="text-xs"
|
||||
/>
|
||||
<span className="text-muted-foreground/50">on</span>
|
||||
<RelayLink
|
||||
url={p.relay}
|
||||
showInboxOutbox={false}
|
||||
className="inline-flex"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{providers.length > 3 && (
|
||||
|
||||
Reference in New Issue
Block a user