Skip to content

Commit fef62c4

Browse files
committed
fix(workstation): keep left-pane close icon stable
Keep the workstation X unchanged on hover when the chat panel is docked on the right. Preserve the directional hover affordance for the mirrored layout and cover both positions with a focused regression test.\n\nVerification: pnpm exec vitest run src/modules/WorkStation/AppShell/useWorkstationTrailingSlot.test.ts; pnpm exec eslint src/modules/WorkStation/AppShell/useWorkstationTrailingSlot.tsx src/modules/WorkStation/AppShell/useWorkstationTrailingSlot.test.ts; pnpm run typecheck Pre-commit hook ran. Total eslint: 0, total circular: 0
1 parent 5c2a64d commit fef62c4

2 files changed

Lines changed: 70 additions & 37 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { createElement } from "react";
2+
import { renderToStaticMarkup } from "react-dom/server";
3+
import { describe, expect, it } from "vitest";
4+
5+
import { WorkstationMaximizeChatIcon } from "./useWorkstationTrailingSlot";
6+
7+
describe("WorkstationMaximizeChatIcon", () => {
8+
it("keeps the X unchanged when the workstation is left of the chat panel", () => {
9+
const markup = renderToStaticMarkup(
10+
createElement(WorkstationMaximizeChatIcon, {
11+
chatPanelPosition: "right",
12+
})
13+
);
14+
15+
expect(markup).toContain('data-icon="x"');
16+
expect(markup).not.toContain("group-hover");
17+
expect(markup).not.toContain('data-icon="panel-left-close"');
18+
});
19+
20+
it("preserves the directional hover affordance when the chat panel is left", () => {
21+
const markup = renderToStaticMarkup(
22+
createElement(WorkstationMaximizeChatIcon, {
23+
chatPanelPosition: "left",
24+
})
25+
);
26+
27+
expect(markup).toContain('data-icon="panel-right"');
28+
expect(markup).toContain('data-icon="panel-right-close"');
29+
expect(markup).toContain("group-hover:opacity-100");
30+
});
31+
});

src/modules/WorkStation/AppShell/useWorkstationTrailingSlot.tsx

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
BubbleChatIcon,
2020
Cancel01Icon,
2121
HugeiconsIcon,
22-
PanelLeftCloseIcon,
2322
PanelRightCloseIcon,
2423
PanelRightIcon,
2524
} from "@src/icons";
@@ -33,6 +32,7 @@ import {
3332
toggleChatPanelMaximizedAtom,
3433
} from "@src/store/ui/chatPanelAtom";
3534
import { chatPanelPositionAtom } from "@src/store/ui/workStationAtom";
35+
import type { ChatPanelPosition } from "@src/store/ui/workStationLayout/chatPositionAtoms";
3636
import { workstationProjectTabBarAtom } from "@src/store/workstation";
3737
import type { WorkstationTabHost } from "@src/store/workstation/tabHost";
3838

@@ -48,6 +48,42 @@ export interface UseWorkstationTrailingSlotReturn {
4848
handleToggleChatPanel: () => void;
4949
}
5050

51+
export function WorkstationMaximizeChatIcon({
52+
chatPanelPosition,
53+
}: {
54+
chatPanelPosition: ChatPanelPosition;
55+
}): ReactNode {
56+
if (chatPanelPosition === "right") {
57+
return (
58+
<HugeiconsIcon
59+
icon={Cancel01Icon}
60+
data-icon="x"
61+
size={HEADER_ICON_SIZE.md}
62+
strokeWidth={1.75}
63+
/>
64+
);
65+
}
66+
67+
return (
68+
<span className="relative flex h-4 w-4 items-center justify-center">
69+
<HugeiconsIcon
70+
icon={PanelRightIcon}
71+
data-icon="panel-right"
72+
size={HEADER_ICON_SIZE.md}
73+
strokeWidth={2}
74+
className="absolute transition-opacity duration-150 group-hover:opacity-0"
75+
/>
76+
<HugeiconsIcon
77+
icon={PanelRightCloseIcon}
78+
data-icon="panel-right-close"
79+
size={HEADER_ICON_SIZE.md}
80+
strokeWidth={2}
81+
className="absolute opacity-0 transition-opacity duration-150 group-hover:opacity-100"
82+
/>
83+
</span>
84+
);
85+
}
86+
5187
export function useWorkstationTrailingSlot({
5288
host,
5389
visible,
@@ -123,43 +159,9 @@ export function useWorkstationTrailingSlot({
123159
title={hideWorkstationLabel}
124160
shortcutId="maximize_chat"
125161
onClick={handleToggleChatPanelMaximized}
126-
className="group"
162+
className={chatPanelPosition === "left" ? "group" : undefined}
127163
>
128-
{chatPanelPosition === "left" ? (
129-
<span className="relative flex h-4 w-4 items-center justify-center">
130-
<HugeiconsIcon
131-
icon={PanelRightIcon}
132-
data-icon="panel-right"
133-
size={HEADER_ICON_SIZE.md}
134-
strokeWidth={2}
135-
className="absolute transition-opacity duration-150 group-hover:opacity-0"
136-
/>
137-
<HugeiconsIcon
138-
icon={PanelRightCloseIcon}
139-
data-icon="panel-right-close"
140-
size={HEADER_ICON_SIZE.md}
141-
strokeWidth={2}
142-
className="absolute opacity-0 transition-opacity duration-150 group-hover:opacity-100"
143-
/>
144-
</span>
145-
) : (
146-
<span className="relative flex h-4 w-4 items-center justify-center">
147-
<HugeiconsIcon
148-
icon={Cancel01Icon}
149-
data-icon="x"
150-
size={HEADER_ICON_SIZE.md}
151-
strokeWidth={1.75}
152-
className="absolute transition-opacity duration-150 group-hover:opacity-0"
153-
/>
154-
<HugeiconsIcon
155-
icon={PanelLeftCloseIcon}
156-
data-icon="panel-left-close"
157-
size={HEADER_ICON_SIZE.md}
158-
strokeWidth={2}
159-
className="absolute opacity-0 transition-opacity duration-150 group-hover:opacity-100"
160-
/>
161-
</span>
162-
)}
164+
<WorkstationMaximizeChatIcon chatPanelPosition={chatPanelPosition} />
163165
</TabBarTrailingIconButton>
164166
) : null;
165167

0 commit comments

Comments
 (0)