style(desktop): simplify thread panel chrome

Reduce thread panel visual noise so the nested reply column feels lighter and more focused while preserving the existing thread behavior.

Made-with: Cursor
This commit is contained in:
Thomas Petersen
2026-04-13 18:03:55 -04:00
parent 5c28fb783d
commit f9b541dcb5
4 changed files with 23 additions and 27 deletions

View File

@@ -6,6 +6,7 @@ import { useDrafts } from "@/features/messages/lib/useDrafts";
import { useMediaUpload } from "@/features/messages/lib/useMediaUpload";
import { useMentions } from "@/features/messages/lib/useMentions";
import { useTypingBroadcast } from "@/features/messages/useTypingBroadcast";
import { cn } from "@/shared/lib/cn";
import { Button } from "@/shared/ui/button";
import { Textarea } from "@/shared/ui/textarea";
import { ChannelAutocomplete } from "./ChannelAutocomplete";
@@ -40,6 +41,7 @@ type MessageComposerProps = {
body: string;
id: string;
} | null;
showTopBorder?: boolean;
typingParentEventId?: string | null;
typingRootEventId?: string | null;
};
@@ -58,6 +60,7 @@ export function MessageComposer({
onSend,
placeholder,
replyTarget = null,
showTopBorder = true,
typingParentEventId = null,
typingRootEventId = null,
}: MessageComposerProps) {
@@ -503,7 +506,12 @@ export function MessageComposer({
}, [media.handlePaperclip]);
return (
<footer className="border-t border-border/80 bg-background p-4">
<footer
className={cn(
"bg-background p-4",
showTopBorder ? "border-t border-border/80" : "",
)}
>
<div className="mx-auto flex w-full max-w-4xl flex-col gap-3">
<form
className="relative rounded-2xl border border-input bg-card px-3 py-4 shadow-sm sm:px-4"

View File

@@ -163,9 +163,6 @@ export const MessageRow = React.memo(
className={cn(
"group/message flex items-start gap-2.5 rounded-2xl px-2 py-1 transition-colors",
highlighted ? "bg-primary/10 ring-1 ring-primary/30" : "",
activeReplyTargetId === message.id
? "bg-muted/60 ring-1 ring-border"
: "",
)}
data-message-id={message.id}
data-testid="message-row"

View File

@@ -1,4 +1,4 @@
import { ArrowLeft, MessageSquareText, X } from "lucide-react";
import { ArrowLeft, X } from "lucide-react";
import type { MainTimelineEntry } from "@/features/messages/lib/threadPanel";
import type { TimelineMessage } from "@/features/messages/types";
@@ -94,7 +94,7 @@ export function MessageThreadPanel({
className="hidden h-full w-[380px] shrink-0 flex-col border-l border-border/80 bg-background lg:flex"
data-testid="message-thread-panel"
>
<div className="flex items-center gap-3 border-b border-border/80 px-4 py-3">
<div className="flex items-center gap-3 px-4 py-3">
{canGoBack ? (
<Button
aria-label="Back"
@@ -108,13 +108,7 @@ export function MessageThreadPanel({
</Button>
) : null}
<div className="min-w-0 flex-1">
<div className="flex items-center gap-2">
<MessageSquareText className="h-4 w-4 text-muted-foreground" />
<h2 className="text-sm font-semibold tracking-tight">Thread</h2>
</div>
<p className="mt-1 text-xs text-muted-foreground">
{totalReplyCount} {totalReplyCount === 1 ? "reply" : "replies"}
</p>
<h2 className="text-sm font-semibold tracking-tight">Thread</h2>
</div>
<Button
aria-label="Close thread"
@@ -128,15 +122,8 @@ export function MessageThreadPanel({
</Button>
</div>
<TypingIndicatorRow
channel={channel}
currentPubkey={currentPubkey}
profiles={profiles}
typingPubkeys={threadTypingPubkeys}
/>
<div className="min-h-0 flex-1 overflow-y-auto" data-testid="message-thread-body">
<div className="border-b border-border/60 px-3 py-3" data-testid="message-thread-head">
<div className="px-3 py-3" data-testid="message-thread-head">
<MessageRow
activeReplyTargetId={replyTargetId}
message={threadHead}
@@ -190,7 +177,13 @@ export function MessageThreadPanel({
</div>
</div>
<div className="border-t border-border/80 p-4">
<div className="p-4">
<TypingIndicatorRow
channel={channel}
currentPubkey={currentPubkey}
profiles={profiles}
typingPubkeys={threadTypingPubkeys}
/>
<MessageComposer
channelId={channelId}
channelName={channelName}
@@ -200,6 +193,7 @@ export function MessageThreadPanel({
onSend={onSend}
placeholder={`Reply in thread to ${threadHead.author}`}
replyTarget={composerReplyTarget}
showTopBorder={false}
typingParentEventId={threadHead.id}
typingRootEventId={threadHead.rootId}
/>

View File

@@ -1,5 +1,3 @@
import { MessageSquareText } from "lucide-react";
import type {
TimelineThreadSummary,
TimelineThreadSummaryParticipant,
@@ -40,7 +38,7 @@ export function MessageThreadSummaryRow({
}) {
return (
<button
className="ml-8 flex w-fit max-w-full items-center gap-3 rounded-xl px-3 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
className="ml-8 flex w-fit max-w-full items-center gap-2 rounded-xl px-3 py-2 text-left text-sm text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
data-thread-head-id={message.id}
data-testid="message-thread-summary"
onClick={() => onOpenThread(message)}
@@ -56,8 +54,7 @@ export function MessageThreadSummaryRow({
))}
</div>
<div className="min-w-0">
<div className="flex items-center gap-1.5 font-medium">
<MessageSquareText className="h-3.5 w-3.5" />
<div className="font-medium">
<span>
{summary.replyCount}{" "}
{summary.replyCount === 1 ? "reply" : "replies"}