+
0 ? "text-[10px]" : "text-xs"
+ )}
+ >
{gitDescribe ?? "(dev)"}
diff --git a/src/browser/stories/App.titlebar.stories.tsx b/src/browser/stories/App.titlebar.stories.tsx
index 253378a632..2bb922f62d 100644
--- a/src/browser/stories/App.titlebar.stories.tsx
+++ b/src/browser/stories/App.titlebar.stories.tsx
@@ -1,109 +1,55 @@
/**
- * Workspace titlebar / header stories
+ * Title bar stories - demonstrates title bar layout variants
*/
+import React from "react";
import { appMeta, AppWithMocks, type AppStory } from "./meta.js";
-import {
- NOW,
- createWorkspace,
- groupWorkspacesByProject,
- type GitStatusFixture,
-} from "./mockFactory";
-import { createGitStatusExecutor, expandProjects, selectWorkspace } from "./storyHelpers";
-import { GIT_STATUS_INDICATOR_MODE_KEY } from "@/common/constants/storage";
-import { within, userEvent, waitFor } from "@storybook/test";
-
import { createMockORPCClient } from "@/browser/stories/mocks/orpc";
export default {
...appMeta,
- title: "App/Titlebar",
+ title: "App/TitleBar",
};
/**
- * Git status tooltip in workspace header - verifies alignment is near the indicator.
- * The header uses tooltipPosition="bottom" which requires align="start" to stay anchored.
+ * macOS desktop mode with traffic lights inset.
+ * Logo is stacked above version to fit in constrained space.
*/
-export const GitStatusTooltip: AppStory = {
+export const MacOSDesktop: AppStory = {
+ decorators: [
+ (Story) => {
+ // Save and restore window.api to prevent leaking to other stories
+ const originalApiRef = React.useRef(window.api);
+ window.api = {
+ platform: "darwin",
+ versions: {
+ node: "20.0.0",
+ chrome: "120.0.0",
+ electron: "28.0.0",
+ },
+ // This function's presence triggers isDesktopMode() → true
+ getIsRosetta: () => Promise.resolve(false),
+ };
+
+ // Cleanup on unmount
+ React.useEffect(() => {
+ const savedApi = originalApiRef.current;
+ return () => {
+ window.api = savedApi;
+ };
+ }, []);
+
+ return
;
+ },
+ ],
render: () => (
{
- window.localStorage.setItem(GIT_STATUS_INDICATOR_MODE_KEY, JSON.stringify("line-delta"));
-
- const workspaces = [
- createWorkspace({
- id: "ws-active",
- name: "feature/tooltip-test",
- projectName: "my-app",
- createdAt: new Date(NOW - 3600000).toISOString(),
- }),
- ];
-
- const gitStatus = new Map([
- [
- "ws-active",
- {
- ahead: 3,
- behind: 2,
- dirty: 5,
- outgoingAdditions: 150,
- outgoingDeletions: 30,
- headCommit: "WIP: Testing tooltip alignment",
- },
- ],
- ]);
-
- // Select workspace so header is visible
- selectWorkspace(workspaces[0]);
- expandProjects(["/home/user/projects/my-app"]);
-
- return createMockORPCClient({
- projects: groupWorkspacesByProject(workspaces),
- workspaces,
- executeBash: createGitStatusExecutor(gitStatus),
- });
- }}
+ setup={() =>
+ createMockORPCClient({
+ projects: new Map(),
+ workspaces: [],
+ })
+ }
/>
),
- play: async ({ canvasElement }: { canvasElement: HTMLElement }) => {
- const canvas = within(canvasElement);
-
- // Wait for the workspace header to render with git status
- await waitFor(
- () => {
- canvas.getByTestId("workspace-header");
- },
- { timeout: 5000 }
- );
-
- // Wait for git status to appear in the header specifically
- const header = canvas.getByTestId("workspace-header");
- await waitFor(
- () => {
- within(header).getByText("+150");
- },
- { timeout: 5000 }
- );
-
- // Hover over the git status indicator in the header (not the sidebar)
- const plusIndicator = within(header).getByText("+150");
- await userEvent.hover(plusIndicator);
-
- // Wait for tooltip to appear with correct alignment (portaled with data-state="open")
- // The key fix: data-align="start" anchors tooltip near the indicator (not "center")
- await waitFor(
- () => {
- const tooltip = document.body.querySelector(
- '.bg-modal-bg[data-state="open"][data-align="start"]'
- );
- if (!tooltip) throw new Error("git status tooltip not visible with align=start");
- // Verify tooltip has expected structure
- within(tooltip).getByText("Divergence:");
- },
- { timeout: 5000 }
- );
-
- // Double-RAF to ensure layout is stable after async rendering
- await new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
- },
};