diff --git a/desktop/src/features/messages/lib/formatTimelineMessages.ts b/desktop/src/features/messages/lib/formatTimelineMessages.ts index a24da67f700..dc02f357cab 100644 --- a/desktop/src/features/messages/lib/formatTimelineMessages.ts +++ b/desktop/src/features/messages/lib/formatTimelineMessages.ts @@ -49,6 +49,16 @@ import { truncatePubkey } from "@/shared/lib/pubkey"; const HEX_RE = /^[0-9a-f]+$/i; +function pubkeyToAccentColor(pubkey: string): string { + let hash = 0; + for (let i = 0; i < pubkey.length; i++) { + hash = (hash << 5) - hash + pubkey.charCodeAt(i); + hash |= 0; + } + const hue = Math.abs(hash) % 360; + return `hsla(${hue}, 65%, 55%, 0.10)`; +} + export function isTimelineContentEvent(event: RelayEvent) { return ( event.kind === KIND_STREAM_MESSAGE || @@ -508,6 +518,7 @@ export function formatTimelineMessages( rootId: thread.rootId, depth: getDepth(event), accent: currentPubkey === authorPubkey, + accentColor: authorPubkey ? pubkeyToAccentColor(authorPubkey) : undefined, pending: event.pending, edited: edit !== undefined, kind: event.kind, diff --git a/desktop/src/features/messages/types.ts b/desktop/src/features/messages/types.ts index ec656f22366..7d38bb33aa8 100644 --- a/desktop/src/features/messages/types.ts +++ b/desktop/src/features/messages/types.ts @@ -43,6 +43,8 @@ export type TimelineMessage = { rootId?: string | null; depth: number; accent?: boolean; + /** Deterministic background tint derived from the sender's pubkey. */ + accentColor?: string; pending?: boolean; edited?: boolean; highlighted?: boolean; diff --git a/desktop/src/features/messages/ui/MessageRow.tsx b/desktop/src/features/messages/ui/MessageRow.tsx index 0f1ab3c981d..b33f9d2cb65 100644 --- a/desktop/src/features/messages/ui/MessageRow.tsx +++ b/desktop/src/features/messages/ui/MessageRow.tsx @@ -904,6 +904,13 @@ export const MessageRow = React.memo( data-testid="message-row" onAnimationEnd={handleEntranceAnimationEnd} > + {message.accentColor ? ( +
+ ) : null} {isThreadReplyLayout ? ( <> {avatarGutterNode} @@ -942,6 +949,7 @@ export const MessageRow = React.memo( prev.message.ownerLabel === next.message.ownerLabel && prev.message.avatarUrl === next.message.avatarUrl && prev.message.accent === next.message.accent && + prev.message.accentColor === next.message.accentColor && // The header timestamp and hover gutter both derive from createdAt (the // old `time` prop was the same value pre-formatted; this row reads neither). prev.message.createdAt === next.message.createdAt &&