1import { describe, expect, it } from "vite-plus/test";
2import {
3 resolveThreadDetailsCardDensity,
4 resolveThreadDetailsCardLayout,
5} from "./threadDetailsCardLayout";
6
7const lane = { padding: 48, minChatWidth: 640 };
8const resolve = (width: number, height: number, previewY: number | null = null) =>
9 resolveThreadDetailsCardLayout({
10 container: { width, height },
11 lane,
12 frame: previewY === null ? null : { x: width - 332, y: previewY, width: 320, height: 240 },
13 });
14
15describe("workspace card", () => {
16 it("pins to the top right at a fixed width", () => {
17 expect(resolve(1600, 900)).toEqual({
18 x: 1308,
19 right: 12,
20 y: 12,
21 width: 280,
22 height: 876,
23 });
24 expect(resolve(1344, 900)).toMatchObject({ x: 1052, width: 280 });
25 });
26 it("starts below the open find bar, keeping the bottom inset", () => {
27 expect(
28 resolveThreadDetailsCardLayout({
29 container: { width: 1600, height: 900 },
30 lane,
31 frame: null,
32 topInset: 48,
33 }),
34 ).toEqual({ x: 1308, right: 12, y: 60, width: 280, height: 828 });
35 });
36 it("hides when a readable chat lane cannot fit beside it", () => {
37 expect(resolve(1012, 900)).toMatchObject({ x: 720 });
38 expect(resolve(1011, 900)).toBeNull();
39 });
40 it("keeps the card at the top right while the preview is freely dragged vertically", () => {
41 for (const y of [12, 170, 250, 400, 648]) {
42 expect(resolve(1600, 900, y)).toEqual({ x: 1308, right: 12, y: 12, width: 280, height: 876 });
43 }
44 });
45 it("keeps full height while a preview stays clear of the card", () => {
46 expect(resolve(1344, 900, 600)).toMatchObject({ width: 280, height: 876 });
47 expect(
48 resolveThreadDetailsCardLayout({
49 container: { width: 1600, height: 900 },
50 lane,
51 frame: { x: 12, y: 100, width: 320, height: 240 },
52 })?.height,
53 ).toBe(876);
54 });
55});
56
57describe("card content fitting", () => {
58 const place = (previewY: number, previewHeight = 365, overlapsDetailsCard = false) =>
59 resolveThreadDetailsCardLayout({
60 container: { width: 1584, height: 988 },
61 lane,
62 frame: { x: 1260, y: previewY, width: 240, height: previewHeight },
63 overlapsDetailsCard,
64 });
65 it("does not fold in response to a drag while the full card can be kept clear", () => {
66 for (const y of [12, 170, 225, 240, 340, 380, 611]) {
67 const placement = place(y)!;
68 expect(placement).toMatchObject({ x: 1292, y: 12, height: 964 });
69 expect(resolveThreadDetailsCardDensity(placement.height, { full: 327, compact: 182 })).toBe(
70 "full",
71 );
72 }
73 });
74 it("folds only after the preview cannot fit around the full card", () => {
75 const content = { full: 327, compact: 182 };
76 expect(resolveThreadDetailsCardDensity(place(351, 625, true)!.height, content)).toBe("full");
77 expect(resolveThreadDetailsCardDensity(place(350, 626, true)!.height, content)).toBe("compact");
78 expect(resolveThreadDetailsCardDensity(place(12)!.height, content)).toBe("full");
79 });
80 it("hides only when the available height cannot hold readable controls", () => {
81 expect(place(184, 792, true)).toMatchObject({ y: 12, height: 160 });
82 expect(place(183, 793, true)).toBeNull();
83 });
84 it("keeps all content as a freely moved preview approaches without colliding", () => {
85 const content = { full: 162, compact: 126 };
86 for (const y of [650, 450, 350, 250]) {
87 expect(resolveThreadDetailsCardDensity(resolve(1600, 900, y)!.height, content)).toBe("full");
88 }
89 });
90 it("folds only detail that cannot fit and restores it when space returns", () => {
91 const content = { full: 570, compact: 180 };
92 expect(resolveThreadDetailsCardDensity(600, content)).toBe("full");
93 expect(resolveThreadDetailsCardDensity(400, content)).toBe("compact");
94 expect(resolveThreadDetailsCardDensity(170, content)).toBe("essential");
95 expect(resolveThreadDetailsCardDensity(570, content)).toBe("full");
96 });
97 it("measures unseen content before deciding to fold it", () => {
98 expect(resolveThreadDetailsCardDensity(300, { full: 0, compact: 0 })).toBe("full");
99 expect(resolveThreadDetailsCardDensity(300, { full: 570, compact: 0 })).toBe("compact");
100 });
101});