diff --git a/desktop/src/features/messages/ui/MessageTimeline.tsx b/desktop/src/features/messages/ui/MessageTimeline.tsx
index 73e96dfa7..6e549bc8c 100644
--- a/desktop/src/features/messages/ui/MessageTimeline.tsx
+++ b/desktop/src/features/messages/ui/MessageTimeline.tsx
@@ -1,5 +1,5 @@
import * as React from "react";
-import { ArrowDown, ArrowUp, Hash } from "lucide-react";
+import { Hash } from "lucide-react";
import {
selectTimelineBodySurface,
@@ -11,9 +11,9 @@ import type { UserProfileLookup } from "@/features/profile/lib/identity";
import type { ChannelType } from "@/shared/api/types";
import { cn } from "@/shared/lib/cn";
import { channelChrome } from "@/shared/layout/chromeLayout";
-import { Button } from "@/shared/ui/button";
import { Spinner } from "@/shared/ui/spinner";
import { TooltipProvider } from "@/shared/ui/tooltip";
+import { UnreadPill, unreadCountLabel } from "@/shared/ui/UnreadPill";
import { UserAvatar } from "@/shared/ui/UserAvatar";
import { TimelineSkeleton, useTimelineSkeletonRows } from "./TimelineSkeleton";
import { TimelineMessageList } from "./TimelineMessageList";
@@ -313,17 +313,12 @@ const MessageTimelineBase = React.forwardRef<
channelChrome.top,
)}
>
-
+ testId="message-unread-pill"
+ />
) : null}
-
+ testId="message-scroll-to-latest"
+ />
) : null}
diff --git a/desktop/src/features/sidebar/ui/AppSidebar.tsx b/desktop/src/features/sidebar/ui/AppSidebar.tsx
index 9262d27e3..358937cff 100644
--- a/desktop/src/features/sidebar/ui/AppSidebar.tsx
+++ b/desktop/src/features/sidebar/ui/AppSidebar.tsx
@@ -1,8 +1,6 @@
// biome-ignore format: keep compact to stay within file size limit
import {
Activity,
- ArrowDown,
- ArrowUp,
Bot,
FolderGit2,
Home,
@@ -556,7 +554,6 @@ export function AppSidebar({
{unreadAboveCount > 0 ? (
}
onClick={scrollToNextAbove}
position="top"
testId="sidebar-more-unread-above"
@@ -768,7 +765,6 @@ export function AppSidebar({
}
onClick={scrollToNextBelow}
position="bottom"
testId="sidebar-more-unread-below"
diff --git a/desktop/src/features/sidebar/ui/MoreUnreadButton.tsx b/desktop/src/features/sidebar/ui/MoreUnreadButton.tsx
index e0b2d027b..403883482 100644
--- a/desktop/src/features/sidebar/ui/MoreUnreadButton.tsx
+++ b/desktop/src/features/sidebar/ui/MoreUnreadButton.tsx
@@ -1,21 +1,14 @@
-import type * as React from "react";
-
-import { Button } from "@/shared/ui/button";
-
-const MORE_UNREAD_BUTTON_CLASS =
- "h-7 min-h-7 gap-1.5 rounded-full border-0 bg-primary px-2.5 text-2xs font-medium text-primary-foreground shadow-md hover:bg-primary/90 [&_svg]:size-4";
+import { UnreadPill, unreadCountLabel } from "@/shared/ui/UnreadPill";
export function MoreUnreadButton({
bottomClassName = "bottom-0",
count,
- icon,
onClick,
position,
testId,
}: {
bottomClassName?: string;
count: number;
- icon: React.ReactNode;
onClick: () => void;
position: "top" | "bottom";
testId: string;
@@ -24,17 +17,12 @@ export function MoreUnreadButton({
-
+ testId={testId}
+ />
);
}
diff --git a/desktop/src/shared/ui/UnreadPill.tsx b/desktop/src/shared/ui/UnreadPill.tsx
new file mode 100644
index 000000000..50f481c0b
--- /dev/null
+++ b/desktop/src/shared/ui/UnreadPill.tsx
@@ -0,0 +1,37 @@
+import { ArrowDown, ArrowUp } from "lucide-react";
+
+import { Button } from "@/shared/ui/button";
+
+const UNREAD_PILL_CLASS =
+ "pointer-events-auto h-7 min-h-7 gap-1.5 rounded-full border-primary/40 bg-primary/10 px-2.5 text-2xs font-medium text-primary shadow-xs backdrop-blur-sm hover:bg-primary/20 [&_svg]:size-4";
+
+export function unreadCountLabel(count: number) {
+ return `${count} new message${count === 1 ? "" : "s"}`;
+}
+
+export function UnreadPill({
+ direction,
+ label,
+ onClick,
+ testId,
+}: {
+ direction: "up" | "down";
+ label: string;
+ onClick: () => void;
+ testId: string;
+}) {
+ const Arrow = direction === "up" ? ArrowUp : ArrowDown;
+ return (
+
+ );
+}