diff --git a/apps/web/src/components/BranchToolbar.tsx b/apps/web/src/components/BranchToolbar.tsx index 95c7351b09..f2ba1d3db3 100644 --- a/apps/web/src/components/BranchToolbar.tsx +++ b/apps/web/src/components/BranchToolbar.tsx @@ -186,29 +186,58 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({ if (isLocked) { return ( - - {triggerContent} - + + } + className="inline-flex h-7 min-w-0 max-w-[48%] flex-initial items-center justify-start gap-1 rounded-md border border-transparent px-[calc(--spacing(2)-1px)] font-normal text-muted-foreground/70 text-xs sm:h-6" + data-composer-context-control + aria-label={ + showEnvironmentIndicator + ? `Run on ${autoEnvironmentLabel ?? activeEnvironment?.label ?? "Run on"}; Workspace ${workspaceLabel}` + : `Workspace ${workspaceLabel}` + } + > + {triggerContent} + + + {showEnvironmentIndicator + ? `${autoEnvironmentLabel ?? activeEnvironment?.label ?? "Run on"} · ${workspaceLabel}` + : workspaceLabel} + + ); } return ( - } - className="min-w-0 max-w-[48%] flex-initial justify-start font-normal text-muted-foreground/70 text-xs! hover:text-foreground/80" - data-composer-context-control - data-composer-shortcut={[ - showEnvironmentPicker && !envLocked ? "composer.host" : "", - !envModeLocked ? "composer.workspace" : "", - ].join(" ")} - > - {triggerContent} - - + + } + className="min-w-0 max-w-[48%] flex-initial justify-start font-normal text-muted-foreground/70 text-xs! hover:text-foreground/80" + data-composer-context-control + aria-label={ + showEnvironmentIndicator + ? `Run on ${autoEnvironmentLabel ?? activeEnvironment?.label ?? "Run on"}; Workspace ${workspaceLabel}` + : `Workspace ${workspaceLabel}` + } + data-composer-shortcut={[ + showEnvironmentPicker && !envLocked ? "composer.host" : "", + !envModeLocked ? "composer.workspace" : "", + ].join(" ")} + /> + } + > + {triggerContent} + + + + {showEnvironmentIndicator + ? `${autoEnvironmentLabel ?? activeEnvironment?.label ?? "Run on"} · ${workspaceLabel}` + : workspaceLabel} + + {showEnvironmentPicker && availableEnvironments && onEnvironmentChange ? ( <> diff --git a/apps/web/src/components/BranchToolbarContextTooltips.test.tsx b/apps/web/src/components/BranchToolbarContextTooltips.test.tsx new file mode 100644 index 0000000000..2d1505288c --- /dev/null +++ b/apps/web/src/components/BranchToolbarContextTooltips.test.tsx @@ -0,0 +1,39 @@ +import { EnvironmentId, ProjectId } from "@t3tools/contracts"; +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, it } from "vite-plus/test"; + +import { BranchToolbarEnvironmentSelector } from "./BranchToolbarEnvironmentSelector"; +import { BranchToolbarEnvModeSelector } from "./BranchToolbarEnvModeSelector"; + +describe("locked composer context labels", () => { + it("keeps clipped environment and workspace labels keyboard reachable", () => { + const environment = renderToStaticMarkup( + , + ); + const workspace = renderToStaticMarkup( + {}} + />, + ); + + expect(environment).toContain('tabindex="0"'); + expect(environment).toContain('aria-label="Run on Remote build host"'); + expect(workspace).toContain('tabindex="0"'); + expect(workspace).toContain('aria-label="Workspace'); + }); +}); diff --git a/apps/web/src/components/BranchToolbarEnvModeSelector.tsx b/apps/web/src/components/BranchToolbarEnvModeSelector.tsx index a350931fbf..b39089d705 100644 --- a/apps/web/src/components/BranchToolbarEnvModeSelector.tsx +++ b/apps/web/src/components/BranchToolbarEnvModeSelector.tsx @@ -17,6 +17,7 @@ import { SelectTrigger, SelectValue, } from "./ui/select"; +import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; const PREVIOUS_WORKTREE_SELECT_VALUE = "previous-worktree"; @@ -51,27 +52,36 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe if (envLocked) { return ( - - {activeWorktreePath ? ( - - ) : ( - - )} - + + } + className="inline-flex h-7 min-w-0 items-center gap-1 border border-transparent px-[calc(--spacing(2)-1px)] font-normal text-muted-foreground/70 text-xs sm:h-6" + data-composer-context-control > + {activeWorktreePath ? ( + + ) : ( + + )} - {resolveLockedWorkspaceLabel(activeWorktreePath)} + + {resolveLockedWorkspaceLabel(activeWorktreePath)} + - - + + {resolveLockedWorkspaceLabel(activeWorktreePath)} + ); } @@ -88,33 +98,49 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe }} items={envModeItems} > - - {effectiveEnvMode === "worktree" ? ( - - ) : activeWorktreePath ? ( - - ) : ( - - )} - + + } > + {effectiveEnvMode === "worktree" ? ( + + ) : activeWorktreePath ? ( + + ) : ( + + )} - + + + - - + + + {effectiveEnvMode === "worktree" + ? resolveEnvModeLabel("worktree") + : resolveCurrentWorkspaceLabel(activeWorktreePath)} + + Workspace diff --git a/apps/web/src/components/BranchToolbarEnvironmentSelector.tsx b/apps/web/src/components/BranchToolbarEnvironmentSelector.tsx index e18948310b..de4e4da9cc 100644 --- a/apps/web/src/components/BranchToolbarEnvironmentSelector.tsx +++ b/apps/web/src/components/BranchToolbarEnvironmentSelector.tsx @@ -14,6 +14,7 @@ import { SelectTrigger, SelectValue, } from "./ui/select"; +import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; interface BranchToolbarEnvironmentSelectorProps { autoEnvironmentLabel?: string | undefined; @@ -58,26 +59,32 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir // only thing in the strip. if (envLocked || onEnvironmentChange === undefined) { return ( - - - + + } + className="inline-flex h-7 min-w-0 max-w-full items-center gap-1 border border-transparent px-[calc(--spacing(2)-1px)] font-normal text-muted-foreground/70 text-xs sm:h-6" + data-composer-context-control > + - {activeEnvironment?.label ?? "Run on"} + + {activeEnvironment?.label ?? "Run on"} + - - + + {activeEnvironment?.label ?? "Run on"} + ); } @@ -90,34 +97,42 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir } items={environmentItems} > - - {autoEnvironmentLabel ? ( - + + {autoEnvironmentLabel ?? activeEnvironment?.label ?? "Run on"} + Run on