mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-16 10:50:38 +09:00
Neutralize selected inbox accents
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
1871a602df
commit
50577b8c63
4 changed files with 258 additions and 71 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import { act } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import type { Issue } from "@paperclipai/shared";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { IssueRow } from "./IssueRow";
|
||||
|
||||
|
|
@ -14,6 +15,49 @@ vi.mock("@/lib/router", () => ({
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
function createIssue(overrides: Partial<Issue> = {}): Issue {
|
||||
return {
|
||||
id: "issue-1",
|
||||
identifier: "PAP-1",
|
||||
companyId: "company-1",
|
||||
projectId: null,
|
||||
projectWorkspaceId: null,
|
||||
goalId: null,
|
||||
parentId: null,
|
||||
title: "Inbox item",
|
||||
description: null,
|
||||
status: "todo",
|
||||
priority: "medium",
|
||||
assigneeAgentId: null,
|
||||
assigneeUserId: null,
|
||||
createdByAgentId: null,
|
||||
createdByUserId: null,
|
||||
issueNumber: 1,
|
||||
requestDepth: 0,
|
||||
billingCode: null,
|
||||
assigneeAdapterOverrides: null,
|
||||
executionWorkspaceId: null,
|
||||
executionWorkspacePreference: null,
|
||||
executionWorkspaceSettings: null,
|
||||
checkoutRunId: null,
|
||||
executionRunId: null,
|
||||
executionAgentNameKey: null,
|
||||
executionLockedAt: null,
|
||||
startedAt: null,
|
||||
completedAt: null,
|
||||
cancelledAt: null,
|
||||
hiddenAt: null,
|
||||
createdAt: new Date("2026-03-11T00:00:00.000Z"),
|
||||
updatedAt: new Date("2026-03-11T00:00:00.000Z"),
|
||||
labels: [],
|
||||
labelIds: [],
|
||||
myLastTouchAt: null,
|
||||
lastExternalCommentAt: null,
|
||||
isUnreadForMe: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe("IssueRow", () => {
|
||||
let container: HTMLDivElement;
|
||||
|
||||
|
|
@ -28,45 +72,7 @@ describe("IssueRow", () => {
|
|||
|
||||
it("suppresses accent hover styling when the row is selected", () => {
|
||||
const root = createRoot(container);
|
||||
const issue = {
|
||||
id: "issue-1",
|
||||
identifier: "PAP-1",
|
||||
companyId: "company-1",
|
||||
projectId: null,
|
||||
projectWorkspaceId: null,
|
||||
goalId: null,
|
||||
parentId: null,
|
||||
title: "Inbox item",
|
||||
description: null,
|
||||
status: "todo",
|
||||
priority: "medium",
|
||||
assigneeAgentId: null,
|
||||
assigneeUserId: null,
|
||||
createdByAgentId: null,
|
||||
createdByUserId: null,
|
||||
issueNumber: 1,
|
||||
requestDepth: 0,
|
||||
billingCode: null,
|
||||
assigneeAdapterOverrides: null,
|
||||
executionWorkspaceId: null,
|
||||
executionWorkspacePreference: null,
|
||||
executionWorkspaceSettings: null,
|
||||
checkoutRunId: null,
|
||||
executionRunId: null,
|
||||
executionAgentNameKey: null,
|
||||
executionLockedAt: null,
|
||||
startedAt: null,
|
||||
completedAt: null,
|
||||
cancelledAt: null,
|
||||
hiddenAt: null,
|
||||
createdAt: new Date("2026-03-11T00:00:00.000Z"),
|
||||
updatedAt: new Date("2026-03-11T00:00:00.000Z"),
|
||||
labels: [],
|
||||
labelIds: [],
|
||||
myLastTouchAt: null,
|
||||
lastExternalCommentAt: null,
|
||||
isUnreadForMe: false,
|
||||
} as const;
|
||||
const issue = createIssue();
|
||||
|
||||
act(() => {
|
||||
root.render(<IssueRow issue={issue} selected />);
|
||||
|
|
@ -81,4 +87,30 @@ describe("IssueRow", () => {
|
|||
root.unmount();
|
||||
});
|
||||
});
|
||||
|
||||
it("neutralizes selected status and unread dot accents", () => {
|
||||
const root = createRoot(container);
|
||||
|
||||
act(() => {
|
||||
root.render(<IssueRow issue={createIssue()} selected unreadState="visible" />);
|
||||
});
|
||||
|
||||
const markReadButton = container.querySelector('button[aria-label="Mark as read"]');
|
||||
const unreadDot = markReadButton?.querySelector("span");
|
||||
const statusIcon = container.querySelector('span[class*="border-muted-foreground"]');
|
||||
|
||||
expect(markReadButton).not.toBeNull();
|
||||
expect(markReadButton?.className).toContain("hover:bg-muted/80");
|
||||
expect(markReadButton?.className).not.toContain("hover:bg-blue-500/20");
|
||||
expect(unreadDot).not.toBeNull();
|
||||
expect(unreadDot?.className).toContain("bg-muted-foreground/70");
|
||||
expect(unreadDot?.className).not.toContain("bg-blue-600");
|
||||
expect(statusIcon).not.toBeNull();
|
||||
expect(statusIcon?.className).toContain("!border-muted-foreground");
|
||||
expect(statusIcon?.className).toContain("!text-muted-foreground");
|
||||
|
||||
act(() => {
|
||||
root.unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ export function IssueRow({
|
|||
const identifier = issue.identifier ?? issue.id.slice(0, 8);
|
||||
const showUnreadSlot = unreadState !== null;
|
||||
const showUnreadDot = unreadState === "visible" || unreadState === "fading";
|
||||
const selectedStatusClass = selected ? "!text-muted-foreground !border-muted-foreground" : undefined;
|
||||
|
||||
return (
|
||||
<Link
|
||||
|
|
@ -58,7 +59,7 @@ export function IssueRow({
|
|||
)}
|
||||
>
|
||||
<span className="shrink-0 pt-px sm:hidden">
|
||||
{mobileLeading ?? <StatusIcon status={issue.status} />}
|
||||
{mobileLeading ?? <StatusIcon status={issue.status} className={selectedStatusClass} />}
|
||||
</span>
|
||||
<span className="flex min-w-0 flex-1 flex-col gap-1 sm:contents">
|
||||
<span className="line-clamp-2 text-sm sm:order-2 sm:min-w-0 sm:flex-1 sm:truncate sm:line-clamp-none">
|
||||
|
|
@ -71,7 +72,7 @@ export function IssueRow({
|
|||
{desktopMetaLeading ?? (
|
||||
<>
|
||||
<span className="hidden shrink-0 sm:inline-flex">
|
||||
<StatusIcon status={issue.status} />
|
||||
<StatusIcon status={issue.status} className={selectedStatusClass} />
|
||||
</span>
|
||||
<span className="shrink-0 font-mono text-xs text-muted-foreground">
|
||||
{identifier}
|
||||
|
|
@ -113,12 +114,16 @@ export function IssueRow({
|
|||
onMarkRead?.();
|
||||
}
|
||||
}}
|
||||
className="inline-flex h-4 w-4 items-center justify-center rounded-full transition-colors hover:bg-blue-500/20"
|
||||
className={cn(
|
||||
"inline-flex h-4 w-4 items-center justify-center rounded-full transition-colors",
|
||||
selected ? "hover:bg-muted/80" : "hover:bg-blue-500/20",
|
||||
)}
|
||||
aria-label="Mark as read"
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"block h-2 w-2 rounded-full bg-blue-600 transition-opacity duration-300 dark:bg-blue-400",
|
||||
"block h-2 w-2 rounded-full transition-opacity duration-300",
|
||||
selected ? "bg-muted-foreground/70" : "bg-blue-600 dark:bg-blue-400",
|
||||
unreadState === "fading" ? "opacity-0" : "opacity-100",
|
||||
)}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue