feat: link repository names in repository state renderers

- Repository name in both feed and detail views now links to the repository (kind 30617)
- Uses same link styling as issues: cursor-crosshair, underline decoration-dotted
- Fetches repository event to display proper name instead of identifier
- Only "pushed <commit>" part opens the state event itself
- Repository link opens in new window using addWindow("open")
This commit is contained in:
Claude
2025-12-21 12:50:08 +00:00
parent 1519e30e5c
commit 2792cab04d
2 changed files with 91 additions and 19 deletions

View File

@@ -1,6 +1,8 @@
import { useMemo } from "react";
import { GitBranch, GitCommit, Tag, Copy, CopyCheck } from "lucide-react";
import { GitBranch, GitCommit, Tag, Copy, CopyCheck, FolderGit2 } from "lucide-react";
import { useCopy } from "@/hooks/useCopy";
import { useGrimoire } from "@/core/state";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import type { NostrEvent } from "@/types/nostr";
import {
getRepositoryIdentifier,
@@ -9,6 +11,7 @@ import {
getRepositoryStateHeadCommit,
getRepositoryStateBranches,
getRepositoryStateTags,
getRepositoryName,
} from "@/lib/nip34-helpers";
/**
@@ -16,6 +19,7 @@ import {
* Displays full repository state with all refs, branches, and tags
*/
export function RepositoryStateDetailRenderer({ event }: { event: NostrEvent }) {
const { addWindow } = useGrimoire();
const repoId = useMemo(() => getRepositoryIdentifier(event), [event]);
const headRef = useMemo(() => getRepositoryStateHead(event), [event]);
const branch = useMemo(() => parseHeadBranch(headRef), [event, headRef]);
@@ -23,14 +27,49 @@ export function RepositoryStateDetailRenderer({ event }: { event: NostrEvent })
const branches = useMemo(() => getRepositoryStateBranches(event), [event]);
const tags = useMemo(() => getRepositoryStateTags(event), [event]);
const displayName = repoId || "Repository";
// Create repository pointer (kind 30617)
const repoPointer = useMemo(
() =>
repoId
? {
kind: 30617,
pubkey: event.pubkey,
identifier: repoId,
}
: null,
[repoId, event.pubkey],
);
// Fetch the repository event to get its name
const repoEvent = useNostrEvent(repoPointer || undefined);
// Get repository display name
const displayName = repoEvent
? getRepositoryName(repoEvent) || repoId || "Repository"
: repoId || "Repository";
const handleRepoClick = () => {
if (repoPointer) {
addWindow("open", { pointer: repoPointer });
}
};
return (
<div className="flex flex-col gap-4 p-4 max-w-3xl mx-auto">
{/* Repository Header */}
<header className="flex flex-col gap-4 border-b border-border pb-4">
{/* Name */}
<h1 className="text-3xl font-bold">{displayName}</h1>
{/* Name with link to repository */}
{repoPointer ? (
<h1
onClick={handleRepoClick}
className="text-3xl font-bold cursor-crosshair underline decoration-dotted hover:text-primary inline-flex items-center gap-2"
>
<FolderGit2 className="size-8" />
{displayName}
</h1>
) : (
<h1 className="text-3xl font-bold">{displayName}</h1>
)}
{/* HEAD Info */}
{branch && commitHash && (

View File

@@ -3,12 +3,15 @@ import {
type BaseEventProps,
ClickableEventTitle,
} from "./BaseEventRenderer";
import { GitCommit } from "lucide-react";
import { GitCommit, FolderGit2 } from "lucide-react";
import { useGrimoire } from "@/core/state";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import {
getRepositoryIdentifier,
getRepositoryStateHeadCommit,
parseHeadBranch,
getRepositoryStateHead,
getRepositoryName,
} from "@/lib/nip34-helpers";
/**
@@ -16,34 +19,64 @@ import {
* Displays as a compact git push notification in feed view
*/
export function RepositoryStateRenderer({ event }: BaseEventProps) {
const { addWindow } = useGrimoire();
const repoId = getRepositoryIdentifier(event);
const headRef = getRepositoryStateHead(event);
const branch = parseHeadBranch(headRef);
const commitHash = getRepositoryStateHeadCommit(event);
// Format: "pushed <8 chars of HEAD commit> to <branch> in <repo>"
// Create repository pointer (kind 30617)
const repoPointer = repoId
? {
kind: 30617,
pubkey: event.pubkey,
identifier: repoId,
}
: null;
// Fetch the repository event to get its name
const repoEvent = useNostrEvent(repoPointer || undefined);
// Get repository display name
const repoName = repoEvent
? getRepositoryName(repoEvent) || repoId || "Repository"
: repoId || "repository";
const shortHash = commitHash?.substring(0, 8) || "unknown";
const branchName = branch || "unknown";
const repoName = repoId || "repository";
const handleRepoClick = () => {
if (repoPointer) {
addWindow("open", { pointer: repoPointer });
}
};
return (
<BaseEventContainer event={event}>
<div className="flex flex-col gap-2">
{/* Push notification */}
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 flex-wrap">
<GitCommit className="size-4 text-muted-foreground flex-shrink-0" />
<ClickableEventTitle
event={event}
className="text-sm font-medium text-foreground"
as="span"
>
pushed{" "}
<code className="px-1.5 py-0.5 rounded bg-muted text-xs font-mono">
{shortHash}
</code>{" "}
<div className="text-sm font-medium text-foreground">
<ClickableEventTitle event={event} className="" as="span">
pushed{" "}
<code className="px-1.5 py-0.5 rounded bg-muted text-xs font-mono">
{shortHash}
</code>
</ClickableEventTitle>{" "}
to <span className="font-semibold">{branchName}</span> in{" "}
<span className="font-semibold">{repoName}</span>
</ClickableEventTitle>
{repoPointer ? (
<span
onClick={handleRepoClick}
className="inline-flex items-center gap-1 cursor-crosshair underline decoration-dotted hover:text-primary"
>
<FolderGit2 className="size-3" />
<span className="font-semibold">{repoName}</span>
</span>
) : (
<span className="font-semibold">{repoName}</span>
)}
</div>
</div>
</div>
</BaseEventContainer>