mirror of
https://github.com/block/buzz.git
synced 2026-11-05 00:41:28 +00:00
Polish message row hover states (#880)
This commit is contained in:
@@ -6,7 +6,7 @@ export function DayDivider({ label }: { label: string }) {
|
|||||||
data-testid="message-timeline-day-divider"
|
data-testid="message-timeline-day-divider"
|
||||||
data-day-label={label}
|
data-day-label={label}
|
||||||
>
|
>
|
||||||
<p className="shrink-0 rounded-full bg-background/90 px-2 py-0.5 text-[10px] font-medium tracking-[0.02em] text-muted-foreground/65 backdrop-blur-sm">
|
<p className="shrink-0 rounded-lg border border-border/70 bg-background/95 px-2 py-1 text-[10px] font-medium tracking-[0.02em] text-muted-foreground/70 shadow-xs backdrop-blur-sm">
|
||||||
{label}
|
{label}
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const MessageRow = React.memo(
|
|||||||
function MessageRow({
|
function MessageRow({
|
||||||
channelId = null,
|
channelId = null,
|
||||||
highlighted = false,
|
highlighted = false,
|
||||||
|
hoverBackground = true,
|
||||||
isFollowingThread,
|
isFollowingThread,
|
||||||
layoutVariant = "default",
|
layoutVariant = "default",
|
||||||
message,
|
message,
|
||||||
@@ -45,6 +46,7 @@ export const MessageRow = React.memo(
|
|||||||
}: {
|
}: {
|
||||||
channelId?: string | null;
|
channelId?: string | null;
|
||||||
highlighted?: boolean;
|
highlighted?: boolean;
|
||||||
|
hoverBackground?: boolean;
|
||||||
isFollowingThread?: boolean;
|
isFollowingThread?: boolean;
|
||||||
layoutVariant?: "default" | "thread-reply";
|
layoutVariant?: "default" | "thread-reply";
|
||||||
message: TimelineMessage;
|
message: TimelineMessage;
|
||||||
@@ -314,7 +316,8 @@ export const MessageRow = React.memo(
|
|||||||
|
|
||||||
<article
|
<article
|
||||||
className={cn(
|
className={cn(
|
||||||
"group/message relative rounded-2xl px-2 py-1 transition-colors",
|
"group/message relative rounded-2xl px-3 py-2 transition-colors",
|
||||||
|
hoverBackground && "hover:bg-muted/50 focus-within:bg-muted/50",
|
||||||
"flex items-start gap-2.5",
|
"flex items-start gap-2.5",
|
||||||
highlighted
|
highlighted
|
||||||
? "-mx-4 rounded-none px-6 before:absolute before:-inset-y-1.5 before:inset-x-0 before:animate-[route-target-highlight-fade_2s_ease-out_forwards] before:bg-primary/10 before:content-[''] motion-reduce:before:animate-none sm:-mx-6 sm:px-8"
|
? "-mx-4 rounded-none px-6 before:absolute before:-inset-y-1.5 before:inset-x-0 before:animate-[route-target-highlight-fade_2s_ease-out_forwards] before:bg-primary/10 before:content-[''] motion-reduce:before:animate-none sm:-mx-6 sm:px-8"
|
||||||
@@ -448,6 +451,7 @@ export const MessageRow = React.memo(
|
|||||||
prev.message.role === next.message.role &&
|
prev.message.role === next.message.role &&
|
||||||
prev.message.personaDisplayName === next.message.personaDisplayName &&
|
prev.message.personaDisplayName === next.message.personaDisplayName &&
|
||||||
prev.highlighted === next.highlighted &&
|
prev.highlighted === next.highlighted &&
|
||||||
|
prev.hoverBackground === next.hoverBackground &&
|
||||||
prev.isFollowingThread === next.isFollowingThread &&
|
prev.isFollowingThread === next.isFollowingThread &&
|
||||||
prev.layoutVariant === next.layoutVariant &&
|
prev.layoutVariant === next.layoutVariant &&
|
||||||
prev.profiles === next.profiles &&
|
prev.profiles === next.profiles &&
|
||||||
|
|||||||
@@ -309,11 +309,16 @@ export function MessageThreadPanel({
|
|||||||
{threadReplies.map((entry) => {
|
{threadReplies.map((entry) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-1"
|
className={cn(
|
||||||
|
"flex flex-col gap-1",
|
||||||
|
entry.summary &&
|
||||||
|
"group/message -mx-1 rounded-2xl px-1 py-1 transition-colors hover:bg-muted/50 focus-within:bg-muted/50",
|
||||||
|
)}
|
||||||
key={entry.message.id}
|
key={entry.message.id}
|
||||||
>
|
>
|
||||||
<MessageRow
|
<MessageRow
|
||||||
channelId={channelId}
|
channelId={channelId}
|
||||||
|
hoverBackground={!entry.summary}
|
||||||
layoutVariant="thread-reply"
|
layoutVariant="thread-reply"
|
||||||
message={entry.message}
|
message={entry.message}
|
||||||
onDelete={
|
onDelete={
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ export const SystemMessageRow = React.memo(function SystemMessageRow({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="group/message relative rounded-2xl px-2 py-1 transition-colors"
|
className="group/message relative rounded-2xl px-3 py-2 transition-colors hover:bg-muted/50 focus-within:bg-muted/50"
|
||||||
data-testid="system-message-row"
|
data-testid="system-message-row"
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-2.5">
|
<div className="flex items-start gap-2.5">
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export const TimelineMessageList = React.memo(function TimelineMessageList({
|
|||||||
<div
|
<div
|
||||||
key={message.id}
|
key={message.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex flex-col gap-0",
|
"group/message relative -mx-1 flex flex-col gap-0 rounded-2xl px-1 py-1 transition-colors hover:bg-muted/50 focus-within:bg-muted/50",
|
||||||
isHighlighted &&
|
isHighlighted &&
|
||||||
"-mx-4 px-4 before:absolute before:-inset-y-1.5 before:inset-x-0 before:animate-[route-target-highlight-fade_2s_ease-out_forwards] before:bg-primary/10 before:content-[''] motion-reduce:before:animate-none sm:-mx-6 sm:px-6",
|
"-mx-4 px-4 before:absolute before:-inset-y-1.5 before:inset-x-0 before:animate-[route-target-highlight-fade_2s_ease-out_forwards] before:bg-primary/10 before:content-[''] motion-reduce:before:animate-none sm:-mx-6 sm:px-6",
|
||||||
)}
|
)}
|
||||||
@@ -116,6 +116,7 @@ export const TimelineMessageList = React.memo(function TimelineMessageList({
|
|||||||
<MessageRow
|
<MessageRow
|
||||||
channelId={channelId}
|
channelId={channelId}
|
||||||
highlighted={false}
|
highlighted={false}
|
||||||
|
hoverBackground={false}
|
||||||
isFollowingThread={
|
isFollowingThread={
|
||||||
isFollowingThreadById
|
isFollowingThreadById
|
||||||
? isFollowingThreadById(message.id)
|
? isFollowingThreadById(message.id)
|
||||||
|
|||||||
@@ -403,6 +403,7 @@ test("opens a single-level thread panel with inline expansion", async ({
|
|||||||
const siblingReply = `Sibling threaded reply ${timestamp}`;
|
const siblingReply = `Sibling threaded reply ${timestamp}`;
|
||||||
const nestedReply = `Nested threaded reply ${timestamp}`;
|
const nestedReply = `Nested threaded reply ${timestamp}`;
|
||||||
const nestedReplyFromBob = `Nested reply from Bob ${timestamp}`;
|
const nestedReplyFromBob = `Nested reply from Bob ${timestamp}`;
|
||||||
|
const nestedReplyVisibleTopMaxPx = 260;
|
||||||
const fillerReplies = Array.from(
|
const fillerReplies = Array.from(
|
||||||
{ length: 14 },
|
{ length: 14 },
|
||||||
(_, index) => `Thread filler reply ${index} ${timestamp}`,
|
(_, index) => `Thread filler reply ${index} ${timestamp}`,
|
||||||
@@ -524,7 +525,7 @@ test("opens a single-level thread panel with inline expansion", async ({
|
|||||||
return rowRect.top - bodyRect.top;
|
return rowRect.top - bodyRect.top;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.toBeLessThanOrEqual(240);
|
.toBeLessThanOrEqual(nestedReplyVisibleTopMaxPx);
|
||||||
|
|
||||||
const firstReplyId = await firstReplyRow.getAttribute("data-message-id");
|
const firstReplyId = await firstReplyRow.getAttribute("data-message-id");
|
||||||
if (!firstReplyId) {
|
if (!firstReplyId) {
|
||||||
@@ -578,7 +579,7 @@ test("opens a single-level thread panel with inline expansion", async ({
|
|||||||
return rowRect.top - bodyRect.top;
|
return rowRect.top - bodyRect.top;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.toBeLessThanOrEqual(240);
|
.toBeLessThanOrEqual(nestedReplyVisibleTopMaxPx);
|
||||||
|
|
||||||
await firstReplySummaryRow.click();
|
await firstReplySummaryRow.click();
|
||||||
await expect(
|
await expect(
|
||||||
|
|||||||
Reference in New Issue
Block a user