|
1 | 1 | /** |
2 | | - * Workspace titlebar / header stories |
| 2 | + * Title bar stories - demonstrates title bar layout variants |
3 | 3 | */ |
4 | 4 |
|
| 5 | +import React from "react"; |
5 | 6 | import { appMeta, AppWithMocks, type AppStory } from "./meta.js"; |
6 | | -import { |
7 | | - NOW, |
8 | | - createWorkspace, |
9 | | - groupWorkspacesByProject, |
10 | | - type GitStatusFixture, |
11 | | -} from "./mockFactory"; |
12 | | -import { createGitStatusExecutor, expandProjects, selectWorkspace } from "./storyHelpers"; |
13 | | -import { GIT_STATUS_INDICATOR_MODE_KEY } from "@/common/constants/storage"; |
14 | | -import { within, userEvent, waitFor } from "@storybook/test"; |
15 | | - |
16 | 7 | import { createMockORPCClient } from "@/browser/stories/mocks/orpc"; |
17 | 8 |
|
18 | 9 | export default { |
19 | 10 | ...appMeta, |
20 | | - title: "App/Titlebar", |
| 11 | + title: "App/TitleBar", |
21 | 12 | }; |
22 | 13 |
|
23 | 14 | /** |
24 | | - * Git status tooltip in workspace header - verifies alignment is near the indicator. |
25 | | - * The header uses tooltipPosition="bottom" which requires align="start" to stay anchored. |
| 15 | + * macOS desktop mode with traffic lights inset. |
| 16 | + * Logo is stacked above version to fit in constrained space. |
26 | 17 | */ |
27 | | -export const GitStatusTooltip: AppStory = { |
| 18 | +export const MacOSDesktop: AppStory = { |
| 19 | + decorators: [ |
| 20 | + (Story) => { |
| 21 | + // Save and restore window.api to prevent leaking to other stories |
| 22 | + const originalApiRef = React.useRef(window.api); |
| 23 | + window.api = { |
| 24 | + platform: "darwin", |
| 25 | + versions: { |
| 26 | + node: "20.0.0", |
| 27 | + chrome: "120.0.0", |
| 28 | + electron: "28.0.0", |
| 29 | + }, |
| 30 | + // This function's presence triggers isDesktopMode() → true |
| 31 | + getIsRosetta: () => Promise.resolve(false), |
| 32 | + }; |
| 33 | + |
| 34 | + // Cleanup on unmount |
| 35 | + React.useEffect(() => { |
| 36 | + const savedApi = originalApiRef.current; |
| 37 | + return () => { |
| 38 | + window.api = savedApi; |
| 39 | + }; |
| 40 | + }, []); |
| 41 | + |
| 42 | + return <Story />; |
| 43 | + }, |
| 44 | + ], |
28 | 45 | render: () => ( |
29 | 46 | <AppWithMocks |
30 | | - setup={() => { |
31 | | - window.localStorage.setItem(GIT_STATUS_INDICATOR_MODE_KEY, JSON.stringify("line-delta")); |
32 | | - |
33 | | - const workspaces = [ |
34 | | - createWorkspace({ |
35 | | - id: "ws-active", |
36 | | - name: "feature/tooltip-test", |
37 | | - projectName: "my-app", |
38 | | - createdAt: new Date(NOW - 3600000).toISOString(), |
39 | | - }), |
40 | | - ]; |
41 | | - |
42 | | - const gitStatus = new Map<string, GitStatusFixture>([ |
43 | | - [ |
44 | | - "ws-active", |
45 | | - { |
46 | | - ahead: 3, |
47 | | - behind: 2, |
48 | | - dirty: 5, |
49 | | - outgoingAdditions: 150, |
50 | | - outgoingDeletions: 30, |
51 | | - headCommit: "WIP: Testing tooltip alignment", |
52 | | - }, |
53 | | - ], |
54 | | - ]); |
55 | | - |
56 | | - // Select workspace so header is visible |
57 | | - selectWorkspace(workspaces[0]); |
58 | | - expandProjects(["/home/user/projects/my-app"]); |
59 | | - |
60 | | - return createMockORPCClient({ |
61 | | - projects: groupWorkspacesByProject(workspaces), |
62 | | - workspaces, |
63 | | - executeBash: createGitStatusExecutor(gitStatus), |
64 | | - }); |
65 | | - }} |
| 47 | + setup={() => |
| 48 | + createMockORPCClient({ |
| 49 | + projects: new Map(), |
| 50 | + workspaces: [], |
| 51 | + }) |
| 52 | + } |
66 | 53 | /> |
67 | 54 | ), |
68 | | - play: async ({ canvasElement }: { canvasElement: HTMLElement }) => { |
69 | | - const canvas = within(canvasElement); |
70 | | - |
71 | | - // Wait for the workspace header to render with git status |
72 | | - await waitFor( |
73 | | - () => { |
74 | | - canvas.getByTestId("workspace-header"); |
75 | | - }, |
76 | | - { timeout: 5000 } |
77 | | - ); |
78 | | - |
79 | | - // Wait for git status to appear in the header specifically |
80 | | - const header = canvas.getByTestId("workspace-header"); |
81 | | - await waitFor( |
82 | | - () => { |
83 | | - within(header).getByText("+150"); |
84 | | - }, |
85 | | - { timeout: 5000 } |
86 | | - ); |
87 | | - |
88 | | - // Hover over the git status indicator in the header (not the sidebar) |
89 | | - const plusIndicator = within(header).getByText("+150"); |
90 | | - await userEvent.hover(plusIndicator); |
91 | | - |
92 | | - // Wait for tooltip to appear with correct alignment (portaled with data-state="open") |
93 | | - // The key fix: data-align="start" anchors tooltip near the indicator (not "center") |
94 | | - await waitFor( |
95 | | - () => { |
96 | | - const tooltip = document.body.querySelector<HTMLElement>( |
97 | | - '.bg-modal-bg[data-state="open"][data-align="start"]' |
98 | | - ); |
99 | | - if (!tooltip) throw new Error("git status tooltip not visible with align=start"); |
100 | | - // Verify tooltip has expected structure |
101 | | - within(tooltip).getByText("Divergence:"); |
102 | | - }, |
103 | | - { timeout: 5000 } |
104 | | - ); |
105 | | - |
106 | | - // Double-RAF to ensure layout is stable after async rendering |
107 | | - await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))); |
108 | | - }, |
109 | 55 | }; |
0 commit comments