mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
feat(desktop): unify unread pills into one shared UnreadPill component (#1111)
Signed-off-by: Wes <wesbillman@users.noreply.github.com> Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
@@ -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,
|
||||
)}
|
||||
>
|
||||
<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
|
||||
@@ -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>
|
||||
|
||||
@@ -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 ? (
|
||||
<MoreUnreadButton
|
||||
count={unreadAboveCount}
|
||||
icon={<ArrowUp />}
|
||||
onClick={scrollToNextAbove}
|
||||
position="top"
|
||||
testId="sidebar-more-unread-above"
|
||||
@@ -768,7 +765,6 @@ export function AppSidebar({
|
||||
<MoreUnreadButton
|
||||
bottomClassName={unreadBelowBottomClass}
|
||||
count={unreadBelowCount}
|
||||
icon={<ArrowDown />}
|
||||
onClick={scrollToNextBelow}
|
||||
position="bottom"
|
||||
testId="sidebar-more-unread-below"
|
||||
|
||||
@@ -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({
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user