refactor(nip34): Extract StatusIndicator component, improve UI layout

- Create reusable StatusIndicator component for issues/patches/PRs
- Move status icon next to status text in feed renderers (not title)
- Place status badge below title in detail renderers
- Fix dark theme destructive color contrast (0 90% 65%)
- Remove duplicate getStatusIcon/getStatusColorClass functions

https://claude.ai/code/session_01C6Lty4k9pKxdwnYUCcpzV2
This commit is contained in:
Claude
2026-01-23 12:16:56 +00:00
parent 34cab50040
commit b5337a3d93
8 changed files with 213 additions and 447 deletions

View File

@@ -0,0 +1,135 @@
import {
CircleDot,
CheckCircle2,
XCircle,
FileEdit,
Loader2,
} from "lucide-react";
import { getStatusType } from "@/lib/nip34-helpers";
/**
* Get the icon component for a status kind
*/
function getStatusIcon(kind: number) {
switch (kind) {
case 1630:
return CircleDot;
case 1631:
return CheckCircle2;
case 1632:
return XCircle;
case 1633:
return FileEdit;
default:
return CircleDot;
}
}
/**
* Get the color class for a status kind
* Uses theme semantic colors
*/
function getStatusColorClass(kind: number): string {
switch (kind) {
case 1630: // Open - neutral
return "text-foreground";
case 1631: // Resolved/Merged - positive
return "text-accent";
case 1632: // Closed - negative
return "text-destructive";
case 1633: // Draft - muted
return "text-muted-foreground";
default:
return "text-foreground";
}
}
/**
* Get the background/border classes for a status badge
* Uses theme semantic colors
*/
function getStatusBadgeClasses(kind: number): string {
switch (kind) {
case 1630: // Open - neutral
return "bg-muted/50 text-foreground border-border";
case 1631: // Resolved/Merged - positive
return "bg-accent/20 text-accent border-accent/30";
case 1632: // Closed - negative
return "bg-destructive/20 text-destructive border-destructive/30";
case 1633: // Draft - muted
return "bg-muted text-muted-foreground border-muted-foreground/30";
default:
return "bg-muted/50 text-foreground border-border";
}
}
export interface StatusIndicatorProps {
/** The status event kind (1630-1633) or undefined for default "open" */
statusKind?: number;
/** Whether status is loading */
loading?: boolean;
/** Event type for appropriate labeling (affects "resolved" vs "merged") */
eventType?: "issue" | "patch" | "pr";
/** Display variant */
variant?: "inline" | "badge";
/** Optional custom class */
className?: string;
}
/**
* Reusable status indicator for NIP-34 events (issues, patches, PRs)
* Displays status icon and text with appropriate styling
*/
export function StatusIndicator({
statusKind,
loading = false,
eventType = "issue",
variant = "inline",
className = "",
}: StatusIndicatorProps) {
if (loading) {
return (
<span
className={`inline-flex items-center gap-1.5 text-sm text-muted-foreground ${className}`}
>
<Loader2 className="size-3.5 animate-spin" />
<span>Loading...</span>
</span>
);
}
// Default to "open" if no status
const effectiveKind = statusKind ?? 1630;
// For patches/PRs, kind 1631 means "merged" not "resolved"
const statusText =
effectiveKind === 1631 && (eventType === "patch" || eventType === "pr")
? "merged"
: getStatusType(effectiveKind) || "open";
const StatusIcon = getStatusIcon(effectiveKind);
if (variant === "badge") {
const badgeClasses = getStatusBadgeClasses(effectiveKind);
return (
<span
className={`inline-flex items-center gap-1.5 px-2 py-1 text-xs font-medium border rounded-sm ${badgeClasses} ${className}`}
>
<StatusIcon className="size-3.5" />
<span className="capitalize">{statusText}</span>
</span>
);
}
// Inline variant (default)
const colorClass = getStatusColorClass(effectiveKind);
return (
<span className={`inline-flex items-center gap-1 text-xs ${className}`}>
<StatusIcon className={`size-3 ${colorClass}`} />
<span className={colorClass}>{statusText}</span>
</span>
);
}
// Re-export utilities for use in feed renderers that need just the icon/color
export { getStatusIcon, getStatusColorClass, getStatusBadgeClasses };

View File

@@ -1,12 +1,5 @@
import { useMemo } from "react";
import {
Tag,
CircleDot,
CheckCircle2,
XCircle,
FileEdit,
Loader2,
} from "lucide-react";
import { Tag } from "lucide-react";
import { UserName } from "../UserName";
import { MarkdownContent } from "../MarkdownContent";
import type { NostrEvent } from "@/types/nostr";
@@ -23,48 +16,12 @@ import { parseReplaceableAddress } from "applesauce-core/helpers/pointers";
import { getOutboxes } from "applesauce-core/helpers";
import { Label } from "@/components/ui/label";
import { RepositoryLink } from "../RepositoryLink";
import { StatusIndicator } from "../StatusIndicator";
import { useTimeline } from "@/hooks/useTimeline";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import { formatTimestamp } from "@/hooks/useLocale";
import { AGGREGATOR_RELAYS } from "@/services/loaders";
/**
* Get the icon for a status kind
*/
function getStatusIcon(kind: number) {
switch (kind) {
case 1630:
return CircleDot;
case 1631:
return CheckCircle2;
case 1632:
return XCircle;
case 1633:
return FileEdit;
default:
return CircleDot;
}
}
/**
* Get the color classes for a status badge
* Uses theme semantic colors
*/
function getStatusBadgeClasses(kind: number): string {
switch (kind) {
case 1630: // Open - neutral
return "bg-muted/50 text-foreground border-border";
case 1631: // Resolved/Merged - positive
return "bg-accent/20 text-accent border-accent/30";
case 1632: // Closed - negative
return "bg-destructive/20 text-destructive border-destructive/30";
case 1633: // Draft - muted
return "bg-muted text-muted-foreground border-muted-foreground/30";
default:
return "bg-muted/50 text-foreground border-border";
}
}
/**
* Detail renderer for Kind 1621 - Issue (NIP-34)
* Full view with repository context and markdown description
@@ -153,38 +110,20 @@ export function IssueDetailRenderer({ event }: { event: NostrEvent }) {
// Format created date using locale utility
const createdDate = formatTimestamp(event.created_at, "long");
// Get status display info
const statusType = currentStatus ? getStatusType(currentStatus.kind) : null;
const StatusIcon = currentStatus
? getStatusIcon(currentStatus.kind)
: CircleDot;
const statusBadgeClasses = currentStatus
? getStatusBadgeClasses(currentStatus.kind)
: "bg-muted/50 text-foreground border-border";
return (
<div className="flex flex-col gap-4 p-4 max-w-3xl mx-auto">
{/* Issue Header */}
<header className="flex flex-col gap-4 pb-4 border-b border-border">
{/* Status Badge */}
<div className="flex items-center gap-3">
{statusLoading ? (
<span className="inline-flex items-center gap-2 px-3 py-1.5 text-sm text-muted-foreground">
<Loader2 className="size-4 animate-spin" />
<span>Loading status...</span>
</span>
) : (
<span
className={`inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium border ${statusBadgeClasses}`}
>
<StatusIcon className="size-4" />
<span className="capitalize">{statusType || "open"}</span>
</span>
)}
</div>
<header className="flex flex-col gap-3 pb-4 border-b border-border">
{/* Title */}
<h1 className="text-3xl font-bold">{title || "Untitled Issue"}</h1>
<h1 className="text-2xl font-bold">{title || "Untitled Issue"}</h1>
{/* Status Badge (below title) */}
<StatusIndicator
statusKind={currentStatus?.kind}
loading={statusLoading}
eventType="issue"
variant="badge"
/>
{/* Repository Link */}
{repoAddress && (

View File

@@ -1,5 +1,4 @@
import { useMemo } from "react";
import { CircleDot, CheckCircle2, XCircle, FileEdit } from "lucide-react";
import {
BaseEventContainer,
type BaseEventProps,
@@ -10,7 +9,6 @@ import {
getIssueLabels,
getIssueRepositoryAddress,
getRepositoryRelays,
getStatusType,
getValidStatusAuthors,
findCurrentStatus,
} from "@/lib/nip34-helpers";
@@ -18,47 +16,11 @@ import { parseReplaceableAddress } from "applesauce-core/helpers/pointers";
import { getOutboxes } from "applesauce-core/helpers";
import { Label } from "@/components/ui/label";
import { RepositoryLink } from "../RepositoryLink";
import { StatusIndicator } from "../StatusIndicator";
import { useTimeline } from "@/hooks/useTimeline";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import { AGGREGATOR_RELAYS } from "@/services/loaders";
/**
* Get the icon for a status kind
*/
function getStatusIcon(kind: number) {
switch (kind) {
case 1630:
return CircleDot;
case 1631:
return CheckCircle2;
case 1632:
return XCircle;
case 1633:
return FileEdit;
default:
return CircleDot;
}
}
/**
* Get the color class for a status kind
* Uses theme semantic colors
*/
function getStatusColorClass(kind: number): string {
switch (kind) {
case 1630: // Open - neutral
return "text-foreground";
case 1631: // Resolved/Merged - positive
return "text-accent";
case 1632: // Closed - negative
return "text-destructive";
case 1633: // Draft - muted
return "text-muted-foreground";
default:
return "text-foreground";
}
}
/**
* Renderer for Kind 1621 - Issue
* Displays as a compact issue card in feed view with status
@@ -143,52 +105,31 @@ export function IssueRenderer({ event }: BaseEventProps) {
[statusEvents, validAuthors],
);
// Status display
const statusType = currentStatus ? getStatusType(currentStatus.kind) : "open";
const StatusIcon = currentStatus
? getStatusIcon(currentStatus.kind)
: CircleDot;
const statusColorClass = currentStatus
? getStatusColorClass(currentStatus.kind)
: "text-foreground";
return (
<BaseEventContainer event={event}>
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-1">
{/* Status and Title */}
<div className="flex items-center gap-2">
<StatusIcon
className={`size-4 flex-shrink-0 ${statusColorClass}`}
/>
<ClickableEventTitle
event={event}
className="font-semibold text-foreground"
>
{title || "Untitled Issue"}
</ClickableEventTitle>
</div>
{/* Title */}
<ClickableEventTitle
event={event}
className="font-semibold text-foreground"
>
{title || "Untitled Issue"}
</ClickableEventTitle>
{/* Status label (compact) */}
<div className="flex items-center gap-2 text-xs">
<span className={statusColorClass}>{statusType}</span>
{repoAddress && (
<>
<span className="text-muted-foreground">in</span>
<RepositoryLink repoAddress={repoAddress} />
</>
)}
</div>
{/* Status and Repository */}
<div className="flex items-center gap-2 text-xs">
<StatusIndicator statusKind={currentStatus?.kind} eventType="issue" />
{repoAddress && (
<>
<span className="text-muted-foreground">in</span>
<RepositoryLink repoAddress={repoAddress} />
</>
)}
</div>
{/* Labels */}
{labels.length > 0 && (
<div
className="flex
flex-wrap
line-clamp-2
items-center gap-1 overflow-x-scroll my-1"
>
<div className="flex flex-wrap line-clamp-2 items-center gap-1 overflow-x-scroll my-1">
{labels.map((label, idx) => (
<Label key={idx}>{label}</Label>
))}

View File

@@ -1,15 +1,5 @@
import { useMemo } from "react";
import {
GitCommit,
User,
Copy,
CopyCheck,
CircleDot,
CheckCircle2,
XCircle,
FileEdit,
Loader2,
} from "lucide-react";
import { GitCommit, User, Copy, CopyCheck } from "lucide-react";
import { UserName } from "../UserName";
import { CodeCopyButton } from "@/components/CodeCopyButton";
import { useCopy } from "@/hooks/useCopy";
@@ -32,47 +22,11 @@ import {
import { parseReplaceableAddress } from "applesauce-core/helpers/pointers";
import { getOutboxes } from "applesauce-core/helpers";
import { RepositoryLink } from "../RepositoryLink";
import { StatusIndicator } from "../StatusIndicator";
import { useTimeline } from "@/hooks/useTimeline";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import { AGGREGATOR_RELAYS } from "@/services/loaders";
/**
* Get the icon for a status kind
*/
function getStatusIcon(kind: number) {
switch (kind) {
case 1630:
return CircleDot;
case 1631:
return CheckCircle2;
case 1632:
return XCircle;
case 1633:
return FileEdit;
default:
return CircleDot;
}
}
/**
* Get the color classes for a status badge
* Uses theme semantic colors
*/
function getStatusBadgeClasses(kind: number): string {
switch (kind) {
case 1630: // Open - neutral
return "bg-muted/50 text-foreground border-border";
case 1631: // Merged - positive
return "bg-accent/20 text-accent border-accent/30";
case 1632: // Closed - negative
return "bg-destructive/20 text-destructive border-destructive/30";
case 1633: // Draft - muted
return "bg-muted text-muted-foreground border-muted-foreground/30";
default:
return "bg-muted/50 text-foreground border-border";
}
}
/**
* Detail renderer for Kind 1617 - Patch
* Displays full patch metadata and content with status
@@ -158,55 +112,33 @@ export function PatchDetailRenderer({ event }: { event: NostrEvent }) {
// Format created date using locale utility
const createdDate = formatTimestamp(event.created_at, "long");
// Status display - for patches, 1631 means "merged"
const statusType = currentStatus
? currentStatus.kind === 1631
? "merged"
: getStatusType(currentStatus.kind)
: "open";
const StatusIcon = currentStatus
? getStatusIcon(currentStatus.kind)
: CircleDot;
const statusBadgeClasses = currentStatus
? getStatusBadgeClasses(currentStatus.kind)
: "bg-muted/50 text-foreground border-border";
return (
<div className="flex flex-col gap-4 p-4 max-w-3xl mx-auto">
{/* Patch Header */}
<header className="flex flex-col gap-4 pb-4 border-b border-border">
{/* Status Badge */}
<div className="flex items-center gap-3">
{statusLoading ? (
<span className="inline-flex items-center gap-2 px-3 py-1.5 text-sm text-muted-foreground">
<Loader2 className="size-4 animate-spin" />
<span>Loading status...</span>
</span>
) : (
<span
className={`inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium border ${statusBadgeClasses}`}
>
<StatusIcon className="size-4" />
<span className="capitalize">{statusType}</span>
</span>
)}
<header className="flex flex-col gap-3 pb-4 border-b border-border">
{/* Title */}
<h1 className="text-2xl font-bold">{subject || "Untitled Patch"}</h1>
{/* Root badges */}
{/* Status and Root badges (below title) */}
<div className="flex items-center gap-2 flex-wrap">
<StatusIndicator
statusKind={currentStatus?.kind}
loading={statusLoading}
eventType="patch"
variant="badge"
/>
{isRoot && (
<span className="px-3 py-1 bg-accent/20 text-accent text-sm border border-accent/30">
<span className="px-2 py-1 bg-accent/20 text-accent text-xs border border-accent/30 rounded-sm">
Root Patch
</span>
)}
{isRootRevision && (
<span className="px-3 py-1 bg-primary/20 text-primary text-sm border border-primary/30">
<span className="px-2 py-1 bg-primary/20 text-primary text-xs border border-primary/30 rounded-sm">
Root Revision
</span>
)}
</div>
{/* Title */}
<h1 className="text-3xl font-bold">{subject || "Untitled Patch"}</h1>
{/* Repository Link */}
{repoAddress && (
<div className="flex items-center gap-2 text-sm">

View File

@@ -1,5 +1,4 @@
import { useMemo } from "react";
import { CircleDot, CheckCircle2, XCircle, FileEdit } from "lucide-react";
import {
BaseEventContainer,
type BaseEventProps,
@@ -10,54 +9,17 @@ import {
getPatchCommitId,
getPatchRepositoryAddress,
getRepositoryRelays,
getStatusType,
getValidStatusAuthors,
findCurrentStatus,
} from "@/lib/nip34-helpers";
import { parseReplaceableAddress } from "applesauce-core/helpers/pointers";
import { getOutboxes } from "applesauce-core/helpers";
import { RepositoryLink } from "../RepositoryLink";
import { StatusIndicator } from "../StatusIndicator";
import { useTimeline } from "@/hooks/useTimeline";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import { AGGREGATOR_RELAYS } from "@/services/loaders";
/**
* Get the icon for a status kind
*/
function getStatusIcon(kind: number) {
switch (kind) {
case 1630:
return CircleDot;
case 1631:
return CheckCircle2;
case 1632:
return XCircle;
case 1633:
return FileEdit;
default:
return CircleDot;
}
}
/**
* Get the color class for a status kind
* Uses theme semantic colors
*/
function getStatusColorClass(kind: number): string {
switch (kind) {
case 1630: // Open - neutral
return "text-foreground";
case 1631: // Merged - positive
return "text-accent";
case 1632: // Closed - negative
return "text-destructive";
case 1633: // Draft - muted
return "text-muted-foreground";
default:
return "text-foreground";
}
}
/**
* Renderer for Kind 1617 - Patch
* Displays as a compact patch card in feed view with status
@@ -145,36 +107,20 @@ export function PatchRenderer({ event }: BaseEventProps) {
[statusEvents, validAuthors],
);
// Status display - for patches, 1631 means "merged" not "resolved"
const statusType = currentStatus
? currentStatus.kind === 1631
? "merged"
: getStatusType(currentStatus.kind)
: "open";
const StatusIcon = currentStatus
? getStatusIcon(currentStatus.kind)
: CircleDot;
const statusColorClass = currentStatus
? getStatusColorClass(currentStatus.kind)
: "text-foreground";
return (
<BaseEventContainer event={event}>
<div className="flex flex-col gap-2">
{/* Status and Subject */}
<div className="flex items-center gap-2">
<StatusIcon className={`size-4 flex-shrink-0 ${statusColorClass}`} />
<ClickableEventTitle
event={event}
className="font-semibold text-foreground"
>
{subject || "Untitled Patch"}
</ClickableEventTitle>
</div>
{/* Subject/Title */}
<ClickableEventTitle
event={event}
className="font-semibold text-foreground"
>
{subject || "Untitled Patch"}
</ClickableEventTitle>
{/* Metadata */}
{/* Status and Metadata */}
<div className="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs">
<span className={statusColorClass}>{statusType}</span>
<StatusIndicator statusKind={currentStatus?.kind} eventType="patch" />
{repoAddress && (
<>
<span className="text-muted-foreground">in</span>

View File

@@ -1,15 +1,5 @@
import { useMemo } from "react";
import {
GitBranch,
Tag,
Copy,
CopyCheck,
CircleDot,
CheckCircle2,
XCircle,
FileEdit,
Loader2,
} from "lucide-react";
import { GitBranch, Tag, Copy, CopyCheck } from "lucide-react";
import { UserName } from "../UserName";
import { MarkdownContent } from "../MarkdownContent";
import { useCopy } from "@/hooks/useCopy";
@@ -32,47 +22,11 @@ import { parseReplaceableAddress } from "applesauce-core/helpers/pointers";
import { getOutboxes } from "applesauce-core/helpers";
import { Label } from "@/components/ui/label";
import { RepositoryLink } from "../RepositoryLink";
import { StatusIndicator } from "../StatusIndicator";
import { useTimeline } from "@/hooks/useTimeline";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import { AGGREGATOR_RELAYS } from "@/services/loaders";
/**
* Get the icon for a status kind
*/
function getStatusIcon(kind: number) {
switch (kind) {
case 1630:
return CircleDot;
case 1631:
return CheckCircle2;
case 1632:
return XCircle;
case 1633:
return FileEdit;
default:
return CircleDot;
}
}
/**
* Get the color classes for a status badge
* Uses theme semantic colors
*/
function getStatusBadgeClasses(kind: number): string {
switch (kind) {
case 1630: // Open - neutral
return "bg-muted/50 text-foreground border-border";
case 1631: // Merged - positive
return "bg-accent/20 text-accent border-accent/30";
case 1632: // Closed - negative
return "bg-destructive/20 text-destructive border-destructive/30";
case 1633: // Draft - muted
return "bg-muted text-muted-foreground border-muted-foreground/30";
default:
return "bg-muted/50 text-foreground border-border";
}
}
/**
* Detail renderer for Kind 1618 - Pull Request
* Displays full PR content with markdown rendering and status
@@ -158,45 +112,23 @@ export function PullRequestDetailRenderer({ event }: { event: NostrEvent }) {
// Format created date using locale utility
const createdDate = formatTimestamp(event.created_at, "long");
// Status display - for PRs, 1631 means "merged"
const statusType = currentStatus
? currentStatus.kind === 1631
? "merged"
: getStatusType(currentStatus.kind)
: "open";
const StatusIcon = currentStatus
? getStatusIcon(currentStatus.kind)
: CircleDot;
const statusBadgeClasses = currentStatus
? getStatusBadgeClasses(currentStatus.kind)
: "bg-muted/50 text-foreground border-border";
return (
<div className="flex flex-col gap-4 p-4 max-w-3xl mx-auto">
{/* PR Header */}
<header className="flex flex-col gap-4 pb-4 border-b border-border">
{/* Status Badge */}
<div className="flex items-center gap-3">
{statusLoading ? (
<span className="inline-flex items-center gap-2 px-3 py-1.5 text-sm text-muted-foreground">
<Loader2 className="size-4 animate-spin" />
<span>Loading status...</span>
</span>
) : (
<span
className={`inline-flex items-center gap-2 px-3 py-1.5 text-sm font-medium border ${statusBadgeClasses}`}
>
<StatusIcon className="size-4" />
<span className="capitalize">{statusType}</span>
</span>
)}
</div>
<header className="flex flex-col gap-3 pb-4 border-b border-border">
{/* Title */}
<h1 className="text-3xl font-bold">
<h1 className="text-2xl font-bold">
{subject || "Untitled Pull Request"}
</h1>
{/* Status Badge (below title) */}
<StatusIndicator
statusKind={currentStatus?.kind}
loading={statusLoading}
eventType="pr"
variant="badge"
/>
{/* Repository Link */}
{repoAddress && (
<div className="flex items-center gap-2 text-sm">

View File

@@ -1,11 +1,5 @@
import { useMemo } from "react";
import {
CircleDot,
CheckCircle2,
XCircle,
FileEdit,
GitBranch,
} from "lucide-react";
import { GitBranch } from "lucide-react";
import {
BaseEventContainer,
type BaseEventProps,
@@ -17,7 +11,6 @@ import {
getPullRequestBranchName,
getPullRequestRepositoryAddress,
getRepositoryRelays,
getStatusType,
getValidStatusAuthors,
findCurrentStatus,
} from "@/lib/nip34-helpers";
@@ -25,47 +18,11 @@ import { parseReplaceableAddress } from "applesauce-core/helpers/pointers";
import { getOutboxes } from "applesauce-core/helpers";
import { Label } from "@/components/ui/label";
import { RepositoryLink } from "../RepositoryLink";
import { StatusIndicator } from "../StatusIndicator";
import { useTimeline } from "@/hooks/useTimeline";
import { useNostrEvent } from "@/hooks/useNostrEvent";
import { AGGREGATOR_RELAYS } from "@/services/loaders";
/**
* Get the icon for a status kind
*/
function getStatusIcon(kind: number) {
switch (kind) {
case 1630:
return CircleDot;
case 1631:
return CheckCircle2;
case 1632:
return XCircle;
case 1633:
return FileEdit;
default:
return CircleDot;
}
}
/**
* Get the color class for a status kind
* Uses theme semantic colors
*/
function getStatusColorClass(kind: number): string {
switch (kind) {
case 1630: // Open - neutral
return "text-foreground";
case 1631: // Merged - positive
return "text-accent";
case 1632: // Closed - negative
return "text-destructive";
case 1633: // Draft - muted
return "text-muted-foreground";
default:
return "text-foreground";
}
}
/**
* Renderer for Kind 1618 - Pull Request
* Displays as a compact PR card in feed view with status
@@ -151,37 +108,21 @@ export function PullRequestRenderer({ event }: BaseEventProps) {
[statusEvents, validAuthors],
);
// Status display - for PRs, 1631 means "merged" not "resolved"
const statusType = currentStatus
? currentStatus.kind === 1631
? "merged"
: getStatusType(currentStatus.kind)
: "open";
const StatusIcon = currentStatus
? getStatusIcon(currentStatus.kind)
: CircleDot;
const statusColorClass = currentStatus
? getStatusColorClass(currentStatus.kind)
: "text-foreground";
return (
<BaseEventContainer event={event}>
<div className="flex flex-col gap-2">
{/* Status and PR Title */}
<div className="flex items-center gap-2">
<StatusIcon className={`size-4 flex-shrink-0 ${statusColorClass}`} />
<ClickableEventTitle
event={event}
className="font-semibold text-foreground"
>
{subject || "Untitled Pull Request"}
</ClickableEventTitle>
</div>
{/* PR Title */}
<ClickableEventTitle
event={event}
className="font-semibold text-foreground"
>
{subject || "Untitled Pull Request"}
</ClickableEventTitle>
<div className="flex flex-col gap-1">
{/* Status and Repository */}
<div className="flex items-center gap-2 text-xs">
<span className={statusColorClass}>{statusType}</span>
<StatusIndicator statusKind={currentStatus?.kind} eventType="pr" />
{repoAddress && (
<>
<span className="text-muted-foreground">in</span>

View File

@@ -115,7 +115,7 @@
--muted-foreground: 215 20.2% 70%;
--accent: 270 100% 70%;
--accent-foreground: 222.2 84% 4.9%;
--destructive: 0 72% 50%;
--destructive: 0 90% 65%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;