Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 16 additions & 24 deletions desktop/src/features/messages/ui/MessageTimeline.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react";
import { ArrowDown, ArrowUp, Hash } from "lucide-react";
import { Hash } from "lucide-react";

import {
selectTimelineBodySurface,
Expand All @@ -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";
Expand Down Expand Up @@ -313,17 +313,12 @@ const MessageTimelineBase = React.forwardRef<
channelChrome.top,
)}
>
<Button
className="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"
data-testid="message-unread-pill"
<UnreadPill
direction="up"
label={unreadCountLabel(unreadCount)}
onClick={handleJumpToOldestUnread}
size="sm"
type="button"
variant="outline"
>
<ArrowUp aria-hidden />
{`${unreadCount} new message${unreadCount === 1 ? "" : "s"}`}
</Button>
testId="message-unread-pill"
/>
</div>
) : null}
<div
Expand Down Expand Up @@ -537,21 +532,18 @@ const MessageTimelineBase = React.forwardRef<
hasComposerOverlay ? "bottom-36" : "bottom-4",
)}
>
<Button
className="pointer-events-auto h-7 min-h-7 gap-1.5 rounded-full border-border/50 bg-background/85 px-2.5 text-2xs font-medium text-muted-foreground shadow-xs backdrop-blur-sm hover:bg-muted/70 hover:text-foreground [&_svg]:size-4"
data-testid="message-scroll-to-latest"
<UnreadPill
direction="down"
label={
newMessageCount > 0
? unreadCountLabel(newMessageCount)
: "Jump to latest"
}
onClick={() => {
scrollToBottom("smooth");
}}
size="sm"
type="button"
variant="outline"
>
<ArrowDown aria-hidden />
{newMessageCount > 0
? `${newMessageCount} new message${newMessageCount === 1 ? "" : "s"}`
: "Jump to latest"}
</Button>
testId="message-scroll-to-latest"
/>
</div>
) : null}
</div>
Expand Down
4 changes: 0 additions & 4 deletions desktop/src/features/sidebar/ui/AppSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// biome-ignore format: keep compact to stay within file size limit
import {
Activity,
ArrowDown,
ArrowUp,
Bot,
FolderGit2,
Home,
Expand Down Expand Up @@ -556,7 +554,6 @@ export function AppSidebar({
{unreadAboveCount > 0 ? (
<MoreUnreadButton
count={unreadAboveCount}
icon={<ArrowUp />}
onClick={scrollToNextAbove}
position="top"
testId="sidebar-more-unread-above"
Expand Down Expand Up @@ -768,7 +765,6 @@ export function AppSidebar({
<MoreUnreadButton
bottomClassName={unreadBelowBottomClass}
count={unreadBelowCount}
icon={<ArrowDown />}
onClick={scrollToNextBelow}
position="bottom"
testId="sidebar-more-unread-below"
Expand Down
24 changes: 6 additions & 18 deletions desktop/src/features/sidebar/ui/MoreUnreadButton.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -24,17 +17,12 @@ export function MoreUnreadButton({
<div
className={`pointer-events-none absolute inset-x-0 z-10 flex justify-center py-1 ${position === "top" ? "top-0" : bottomClassName}`}
>
<Button
className={`pointer-events-auto ${MORE_UNREAD_BUTTON_CLASS}`}
data-testid={testId}
<UnreadPill
direction={position === "top" ? "up" : "down"}
label={unreadCountLabel(count)}
onClick={onClick}
size="sm"
type="button"
variant="ghost"
>
{icon}
{count} more unread
</Button>
testId={testId}
/>
</div>
);
}
37 changes: 37 additions & 0 deletions desktop/src/shared/ui/UnreadPill.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<Button
className={UNREAD_PILL_CLASS}
data-testid={testId}
onClick={onClick}
size="sm"
type="button"
variant="outline"
>
<Arrow aria-hidden />
{label}
</Button>
);
}