From cd34b8245475fda07df419a833c4798d9759a434 Mon Sep 17 00:00:00 2001 From: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:19:32 +0800 Subject: [PATCH] =?UTF-8?q?fix(issues):=20UI=20polish=20batch=20=E2=80=94?= =?UTF-8?q?=20comment=20input,=20card=20gap,=20board=20title,=20activity?= =?UTF-8?q?=20coalescing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CommentInput: remove border-t divider, position submit button inside editor area (bottom-right) for cleaner look - CommentCard: add !gap-0 to override Card's default gap-4 - CommentInput/ReplyInput: strip trailing empty lines from markdown before submit to prevent extra blank lines in rendered comments - BoardCard: use normal text color for title instead of muted+hover - Timeline: coalesce same actor + same action within 2 min window, keeping only the final result (e.g. 5 status changes → 1) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../features/issues/components/board-card.tsx | 2 +- .../issues/components/comment-card.tsx | 2 +- .../issues/components/comment-input.tsx | 8 ++-- .../issues/components/issue-detail.tsx | 42 +++++++++++++++++-- .../issues/components/reply-input.tsx | 2 +- 5 files changed, 45 insertions(+), 11 deletions(-) diff --git a/apps/web/features/issues/components/board-card.tsx b/apps/web/features/issues/components/board-card.tsx index d418b103..a6eed5e0 100644 --- a/apps/web/features/issues/components/board-card.tsx +++ b/apps/web/features/issues/components/board-card.tsx @@ -91,7 +91,7 @@ export function BoardCardContent({ {/* Title */}

{issue.title}

diff --git a/apps/web/features/issues/components/comment-card.tsx b/apps/web/features/issues/components/comment-card.tsx index a8ea065a..5db099fb 100644 --- a/apps/web/features/issues/components/comment-card.tsx +++ b/apps/web/features/issues/components/comment-card.tsx @@ -168,7 +168,7 @@ function CommentCard({ collectReplies(entry.id); return ( - + {/* Parent comment */}
{ - const content = editorRef.current?.getMarkdown()?.trim(); + const content = editorRef.current?.getMarkdown()?.replace(/(\n\s*)+$/, "").trim(); if (!content || submitting) return; setSubmitting(true); try { @@ -28,8 +28,8 @@ function CommentInput({ onSubmit }: CommentInputProps) { }; return ( -
-
+
+
-
+
+ )}
); } @@ -856,9 +869,30 @@ export function IssueDetail({ issueId, onDelete, defaultSidebarOpen = true, layo } } + // Coalesce: same actor + same action within 2 min → keep last only + const COALESCE_MS = 2 * 60 * 1000; + const coalesced: TimelineEntry[] = []; + for (const entry of topLevel) { + if (entry.type === "activity") { + const prev = coalesced[coalesced.length - 1]; + if ( + prev?.type === "activity" && + prev.action === entry.action && + prev.actor_type === entry.actor_type && + prev.actor_id === entry.actor_id && + Math.abs(new Date(entry.created_at).getTime() - new Date(prev.created_at).getTime()) <= COALESCE_MS + ) { + // Replace previous with this one (keep the later result) + coalesced[coalesced.length - 1] = entry; + continue; + } + } + coalesced.push(entry); + } + // Group consecutive activities together so the connector line works const groups: { type: "activities" | "comment"; entries: TimelineEntry[] }[] = []; - for (const entry of topLevel) { + for (const entry of coalesced) { if (entry.type === "activity") { const last = groups[groups.length - 1]; if (last?.type === "activities") { diff --git a/apps/web/features/issues/components/reply-input.tsx b/apps/web/features/issues/components/reply-input.tsx index dc355509..b95662c4 100644 --- a/apps/web/features/issues/components/reply-input.tsx +++ b/apps/web/features/issues/components/reply-input.tsx @@ -34,7 +34,7 @@ function ReplyInput({ const [submitting, setSubmitting] = useState(false); const handleSubmit = async () => { - const content = editorRef.current?.getMarkdown()?.trim(); + const content = editorRef.current?.getMarkdown()?.replace(/(\n\s*)+$/, "").trim(); if (!content || submitting) return; setSubmitting(true); try {