diff --git a/AGENTS.md b/AGENTS.md index c94ba3881e..358d579e53 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -112,6 +112,7 @@ Additional rules: - No `unsafe` code - Do not introduce new `unwrap()` or `expect()` in production paths — use `?` and proper error types - New public API must have doc comments +- **DCO Sign-off**: Always sign off your commits (e.g. `git commit -s`) to comply with the Developer Certificate of Origin (DCO) check. --- diff --git a/desktop/src/features/channels/ui/ChannelScreenHeader.tsx b/desktop/src/features/channels/ui/ChannelScreenHeader.tsx index a3a8a20231..3bd505aed2 100644 --- a/desktop/src/features/channels/ui/ChannelScreenHeader.tsx +++ b/desktop/src/features/channels/ui/ChannelScreenHeader.tsx @@ -4,6 +4,7 @@ import type * as React from "react"; import { ChatHeader } from "@/features/chat/ui/ChatHeader"; import type { EphemeralChannelDisplay } from "@/features/channels/lib/ephemeralChannel"; import type { ActiveDmHeaderParticipant } from "@/features/channels/useActiveChannelHeader"; +import { UserProfilePopover } from "@/features/profile/ui/UserProfilePopover"; import { getChannelDescription } from "@/features/channels/lib/channelDescription"; import { getDmParticipantPreview } from "@/features/channels/lib/dmParticipantDisplay"; import { ChannelHeaderStatusBadge } from "@/features/channels/ui/ChannelHeaderStatusBadge"; @@ -113,6 +114,30 @@ export function ChannelScreenHeader({ + ) : activeDmHeaderParticipants.length === 1 ? ( + + + ) : ( ); } @@ -170,12 +201,23 @@ function DmHeaderParticipantStack({ }), }} > - + + + ))} {hiddenCount > 0 ? ( diff --git a/desktop/src/features/chat/ui/ChatHeader.tsx b/desktop/src/features/chat/ui/ChatHeader.tsx index 9ced506751..5f1299a6c5 100644 --- a/desktop/src/features/chat/ui/ChatHeader.tsx +++ b/desktop/src/features/chat/ui/ChatHeader.tsx @@ -15,6 +15,7 @@ import { toast } from "sonner"; import type { ChannelType, ChannelVisibility } from "@/shared/api/types"; import { UpdateIndicator } from "@/features/settings/UpdateIndicator"; +import { UserProfilePopover } from "@/features/profile/ui/UserProfilePopover"; import { cn } from "@/shared/lib/cn"; import { channelChrome } from "@/shared/layout/chromeLayout"; import { Button } from "@/shared/ui/button"; @@ -35,6 +36,7 @@ type ChatHeaderProps = { statusBadge?: React.ReactNode; /** Render the chrome wrapper without an individual backdrop when a parent supplies shared blur. */ transparentChrome?: boolean; + dmUserPubkey?: string; }; const HEADER_ICON_CLASS = "h-4 w-4 text-muted-foreground"; @@ -97,6 +99,7 @@ export function ChatHeader({ overlaysContent = false, statusBadge, transparentChrome = false, + dmUserPubkey, }: ChatHeaderProps) { const trimmedDescription = description?.trim() ?? ""; @@ -133,27 +136,51 @@ export function ChatHeader({ /> )} -

- {title} -

- + {dmUserPubkey ? ( + + + + ) : ( +

+ {title} +

+ )} + {channelType !== "dm" && ( + + )} {statusBadge ? (
{statusBadge} diff --git a/desktop/src/features/profile/ui/UserProfilePopover.tsx b/desktop/src/features/profile/ui/UserProfilePopover.tsx index 9161bac302..fa567e7796 100644 --- a/desktop/src/features/profile/ui/UserProfilePopover.tsx +++ b/desktop/src/features/profile/ui/UserProfilePopover.tsx @@ -63,6 +63,7 @@ type UserProfilePopoverProps = { role?: string; /** Value used to generate the BotIdenticon glyph (typically the author name). */ botIdenticonValue?: string; + hideMessageAction?: boolean; }; const HOVER_OPEN_DELAY_MS = 500; @@ -175,6 +176,7 @@ export function UserProfilePopover({ enableProfilePanel = true, role, botIdenticonValue, + hideMessageAction = false, }: UserProfilePopoverProps) { const [open, setOpen] = React.useState(false); const [pendingAction, setPendingAction] = React.useState< @@ -260,6 +262,7 @@ export function UserProfilePopover({ const isCurrentUserOwner = ownsAuthorAgent(profile, currentPubkey); const viewerIsOwner = isCurrentUserOwner || isOwner === true; const showMessageAction = + !hideMessageAction && showProfileActions && !isAgentClassificationPending && (!isBotProfile || viewerIsOwner);