| author | |
| committer | |
| log | dda44ed33280106aa46612fd9e1f1475bb5a0712 |
| tree | ceff4a641e602cb98ad089f103b716cb08f9857b |
| parent | 01e64193d9d2abfae8f7b3d20f66824e38397bd6 |
| signature | Signed by PGP key B5690EEEBB952194 |
3 files changed, 132 insertions(+), 90 deletions(-)
apps/web/src/components/BranchToolbar.tsx+24-10| ... | @@ -53,6 +53,7 @@ import { | ... | @@ -53,6 +53,7 @@ import { |
| 53 | MenuTrigger, | 53 | MenuTrigger, |
| 54 | } from "./ui/menu"; | 54 | } from "./ui/menu"; |
| 55 | import { Separator } from "./ui/separator"; | 55 | import { Separator } from "./ui/separator"; |
| 56 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; | ||
| 56 | import { ComposerSurface } from "./chat/ComposerSurface"; | 57 | import { ComposerSurface } from "./chat/ComposerSurface"; |
| 57 | import { useComposerMenuProps } from "./chat/composerEventScope"; | 58 | import { useComposerMenuProps } from "./chat/composerEventScope"; |
| 58 | import { measureRestingComposerControls } from "./chat/restingComposerControlsMeasurement"; | 59 | import { measureRestingComposerControls } from "./chat/restingComposerControlsMeasurement"; |
| ... | @@ -137,22 +138,35 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({ | ... | @@ -137,22 +138,35 @@ const MobileRunContextSelector = memo(function MobileRunContextSelector({ |
| 137 | ? resolveEnvModeLabel("worktree") | 138 | ? resolveEnvModeLabel("worktree") |
| 138 | : resolveCurrentWorkspaceLabel(activeWorktreePath); | 139 | : resolveCurrentWorkspaceLabel(activeWorktreePath); |
| 139 | const isLocked = envLocked || envModeLocked; | 140 | const isLocked = envLocked || envModeLocked; |
| 141 | const workspaceIcon = ( | ||
| 142 | <Tooltip> | ||
| 143 | <TooltipTrigger render={<span className="inline-flex shrink-0" />}> | ||
| 144 | <WorkspaceIcon className={cn("size-3 shrink-0", showEnvironmentIndicator && "mx-0!")} /> | ||
| 145 | </TooltipTrigger> | ||
| 146 | <TooltipPopup>{workspaceLabel}</TooltipPopup> | ||
| 147 | </Tooltip> | ||
| 148 | ); | ||
| 140 | const icon = showEnvironmentIndicator ? ( | 149 | const icon = showEnvironmentIndicator ? ( |
| 141 | // Button's base styles apply `-mx-0.5` to descendant SVGs, which eats 4px | 150 | // Button's base styles apply `-mx-0.5` to descendant SVGs, which eats 4px |
| 142 | // out of whatever gap we set. mx-0! cancels that so gap-0.5 reads as 2px. | 151 | // out of whatever gap we set. mx-0! cancels that so gap-0.5 reads as 2px. |
| 143 | <span className="inline-flex shrink-0 items-center gap-0.5"> | 152 | <span className="inline-flex shrink-0 items-center gap-0.5"> |
| 144 | {autoEnvironmentLabel ? ( | 153 | <Tooltip> |
| 145 | <ScaleIcon className="size-3 shrink-0 mx-0!" aria-hidden="true" /> | 154 | <TooltipTrigger render={<span className="inline-flex shrink-0" />}> |
| 146 | ) : ( | 155 | {autoEnvironmentLabel ? ( |
| 147 | <EnvironmentMachineIcon | 156 | <ScaleIcon className="size-3 shrink-0 mx-0!" aria-hidden="true" /> |
| 148 | kind={activeEnvironment?.machine ?? "server"} | 157 | ) : ( |
| 149 | className="size-3 shrink-0 mx-0!" | 158 | <EnvironmentMachineIcon |
| 150 | /> | 159 | kind={activeEnvironment?.machine ?? "server"} |
| 151 | )} | 160 | className="size-3 shrink-0 mx-0!" |
| 152 | <WorkspaceIcon className="size-3 shrink-0 mx-0!" /> | 161 | /> |
| 162 | )} | ||
| 163 | </TooltipTrigger> | ||
| 164 | <TooltipPopup>{autoEnvironmentLabel ?? activeEnvironment?.label ?? "Run on"}</TooltipPopup> | ||
| 165 | </Tooltip> | ||
| 166 | {workspaceIcon} | ||
| 153 | </span> | 167 | </span> |
| 154 | ) : ( | 168 | ) : ( |
| 155 | <WorkspaceIcon className="size-3 shrink-0" /> | 169 | workspaceIcon |
| 156 | ); | 170 | ); |
| 157 | const triggerContent = ( | 171 | const triggerContent = ( |
| 158 | <> | 172 | <> |
apps/web/src/components/BranchToolbarEnvModeSelector.tsx+56-40| ... | @@ -17,6 +17,7 @@ import { | ... | @@ -17,6 +17,7 @@ import { |
| 17 | SelectTrigger, | 17 | SelectTrigger, |
| 18 | SelectValue, | 18 | SelectValue, |
| 19 | } from "./ui/select"; | 19 | } from "./ui/select"; |
| 20 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; | ||
| 20 | 21 | ||
| 21 | const PREVIOUS_WORKTREE_SELECT_VALUE = "previous-worktree"; | 22 | const PREVIOUS_WORKTREE_SELECT_VALUE = "previous-worktree"; |
| 22 | 23 | ||
| ... | @@ -52,27 +53,31 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe | ... | @@ -52,27 +53,31 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe |
| 52 | 53 | ||
| 53 | if (envLocked) { | 54 | if (envLocked) { |
| 54 | return ( | 55 | return ( |
| 55 | <span | 56 | <Tooltip> |
| 56 | 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" | 57 | <TooltipTrigger |
| 57 | data-composer-context-control | 58 | render={<span />} |
| 58 | > | 59 | 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" |
| 59 | {activeWorktreePath ? ( | 60 | data-composer-context-control |
| 60 | <FolderGitIcon className="size-3 shrink-0" /> | ||
| 61 | ) : ( | ||
| 62 | <FolderIcon className="size-3 shrink-0" /> | ||
| 63 | )} | ||
| 64 | <span | ||
| 65 | data-composer-label | ||
| 66 | className="min-w-0 max-w-[240px] group-data-[compact]/composer-context:max-w-0" | ||
| 67 | > | 61 | > |
| 62 | {activeWorktreePath ? ( | ||
| 63 | <FolderGitIcon className="size-3 shrink-0" /> | ||
| 64 | ) : ( | ||
| 65 | <FolderIcon className="size-3 shrink-0" /> | ||
| 66 | )} | ||
| 68 | <span | 67 | <span |
| 69 | data-composer-label-motion | 68 | data-composer-label |
| 70 | className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none" | 69 | className="min-w-0 max-w-[240px] group-data-[compact]/composer-context:max-w-0" |
| 71 | > | 70 | > |
| 72 | {resolveLockedWorkspaceLabel(activeWorktreePath)} | 71 | <span |
| 72 | data-composer-label-motion | ||
| 73 | className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none" | ||
| 74 | > | ||
| 75 | {resolveLockedWorkspaceLabel(activeWorktreePath)} | ||
| 76 | </span> | ||
| 73 | </span> | 77 | </span> |
| 74 | </span> | 78 | </TooltipTrigger> |
| 75 | </span> | 79 | <TooltipPopup>{resolveLockedWorkspaceLabel(activeWorktreePath)}</TooltipPopup> |
| 80 | </Tooltip> | ||
| 76 | ); | 81 | ); |
| 77 | } | 82 | } |
| 78 | 83 | ||
| ... | @@ -89,33 +94,44 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe | ... | @@ -89,33 +94,44 @@ export const BranchToolbarEnvModeSelector = memo(function BranchToolbarEnvModeSe |
| 89 | }} | 94 | }} |
| 90 | items={envModeItems} | 95 | items={envModeItems} |
| 91 | > | 96 | > |
| 92 | <SelectTrigger | 97 | <Tooltip> |
| 93 | variant="ghost" | 98 | <TooltipTrigger |
| 94 | size="xs" | 99 | render={ |
| 95 | className="min-w-0 shrink font-normal text-xs!" | 100 | <SelectTrigger |
| 96 | aria-label="Workspace" | 101 | variant="ghost" |
| 97 | data-composer-shortcut="composer.workspace" | 102 | size="xs" |
| 98 | data-composer-context-control | 103 | className="min-w-0 shrink font-normal text-xs!" |
| 99 | > | 104 | aria-label="Workspace" |
| 100 | {effectiveEnvMode === "worktree" ? ( | 105 | data-composer-shortcut="composer.workspace" |
| 101 | <FolderGit2Icon className="size-3" /> | 106 | data-composer-context-control |
| 102 | ) : activeWorktreePath ? ( | 107 | /> |
| 103 | <FolderGitIcon className="size-3" /> | 108 | } |
| 104 | ) : ( | ||
| 105 | <FolderIcon className="size-3" /> | ||
| 106 | )} | ||
| 107 | <span | ||
| 108 | data-composer-label | ||
| 109 | className="min-w-0 max-w-[240px] group-data-[compact]/composer-context:max-w-0" | ||
| 110 | > | 109 | > |
| 110 | {effectiveEnvMode === "worktree" ? ( | ||
| 111 | <FolderGit2Icon className="size-3" /> | ||
| 112 | ) : activeWorktreePath ? ( | ||
| 113 | <FolderGitIcon className="size-3" /> | ||
| 114 | ) : ( | ||
| 115 | <FolderIcon className="size-3" /> | ||
| 116 | )} | ||
| 111 | <span | 117 | <span |
| 112 | data-composer-label-motion | 118 | data-composer-label |
| 113 | className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none" | 119 | className="min-w-0 max-w-[240px] group-data-[compact]/composer-context:max-w-0" |
| 114 | > | 120 | > |
| 115 | <SelectValue /> | 121 | <span |
| 122 | data-composer-label-motion | ||
| 123 | className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none" | ||
| 124 | > | ||
| 125 | <SelectValue /> | ||
| 126 | </span> | ||
| 116 | </span> | 127 | </span> |
| 117 | </span> | 128 | </TooltipTrigger> |
| 118 | </SelectTrigger> | 129 | <TooltipPopup> |
| 130 | {effectiveEnvMode === "worktree" | ||
| 131 | ? resolveEnvModeLabel("worktree") | ||
| 132 | : resolveCurrentWorkspaceLabel(activeWorktreePath)} | ||
| 133 | </TooltipPopup> | ||
| 134 | </Tooltip> | ||
| 119 | <SelectPopup alignItemWithTrigger={false} {...composerFloatingLayerProps}> | 135 | <SelectPopup alignItemWithTrigger={false} {...composerFloatingLayerProps}> |
| 120 | <SelectGroup> | 136 | <SelectGroup> |
| 121 | <SelectGroupLabel>Workspace</SelectGroupLabel> | 137 | <SelectGroupLabel>Workspace</SelectGroupLabel> |
apps/web/src/components/BranchToolbarEnvironmentSelector.tsx+52-40| ... | @@ -14,6 +14,7 @@ import { | ... | @@ -14,6 +14,7 @@ import { |
| 14 | SelectTrigger, | 14 | SelectTrigger, |
| 15 | SelectValue, | 15 | SelectValue, |
| 16 | } from "./ui/select"; | 16 | } from "./ui/select"; |
| 17 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; | ||
| 17 | 18 | ||
| 18 | interface BranchToolbarEnvironmentSelectorProps { | 19 | interface BranchToolbarEnvironmentSelectorProps { |
| 19 | autoEnvironmentLabel?: string | undefined; | 20 | autoEnvironmentLabel?: string | undefined; |
| ... | @@ -59,26 +60,30 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir | ... | @@ -59,26 +60,30 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir |
| 59 | // only thing in the strip. | 60 | // only thing in the strip. |
| 60 | if (envLocked || onEnvironmentChange === undefined) { | 61 | if (envLocked || onEnvironmentChange === undefined) { |
| 61 | return ( | 62 | return ( |
| 62 | <span | 63 | <Tooltip> |
| 63 | 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" | 64 | <TooltipTrigger |
| 64 | data-composer-context-control | 65 | render={<span />} |
| 65 | > | 66 | 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" |
| 66 | <EnvironmentMachineIcon | 67 | data-composer-context-control |
| 67 | kind={activeEnvironment?.machine ?? "server"} | ||
| 68 | className="size-3 shrink-0" | ||
| 69 | /> | ||
| 70 | <span | ||
| 71 | data-composer-label | ||
| 72 | className="min-w-0 max-w-[240px] group-data-[compact]/composer-context:max-w-0" | ||
| 73 | > | 68 | > |
| 69 | <EnvironmentMachineIcon | ||
| 70 | kind={activeEnvironment?.machine ?? "server"} | ||
| 71 | className="size-3 shrink-0" | ||
| 72 | /> | ||
| 74 | <span | 73 | <span |
| 75 | data-composer-label-motion | 74 | data-composer-label |
| 76 | className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none" | 75 | className="min-w-0 max-w-[240px] group-data-[compact]/composer-context:max-w-0" |
| 77 | > | 76 | > |
| 78 | {activeEnvironment?.label ?? "Run on"} | 77 | <span |
| 78 | data-composer-label-motion | ||
| 79 | className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none" | ||
| 80 | > | ||
| 81 | {activeEnvironment?.label ?? "Run on"} | ||
| 82 | </span> | ||
| 79 | </span> | 83 | </span> |
| 80 | </span> | 84 | </TooltipTrigger> |
| 81 | </span> | 85 | <TooltipPopup>{activeEnvironment?.label ?? "Run on"}</TooltipPopup> |
| 86 | </Tooltip> | ||
| 82 | ); | 87 | ); |
| 83 | } | 88 | } |
| 84 | 89 | ||
| ... | @@ -91,34 +96,41 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir | ... | @@ -91,34 +96,41 @@ export const BranchToolbarEnvironmentSelector = memo(function BranchToolbarEnvir |
| 91 | } | 96 | } |
| 92 | items={environmentItems} | 97 | items={environmentItems} |
| 93 | > | 98 | > |
| 94 | <SelectTrigger | 99 | <Tooltip> |
| 95 | variant="ghost" | 100 | <TooltipTrigger |
| 96 | size="xs" | 101 | render={ |
| 97 | className="min-w-0 max-w-full font-normal text-xs!" | 102 | <SelectTrigger |
| 98 | aria-label="Run on" | 103 | variant="ghost" |
| 99 | data-composer-shortcut="composer.host" | 104 | size="xs" |
| 100 | data-composer-context-control | 105 | className="min-w-0 max-w-full font-normal text-xs!" |
| 101 | > | 106 | aria-label="Run on" |
| 102 | {autoEnvironmentLabel ? ( | 107 | data-composer-shortcut="composer.host" |
| 103 | <ScaleIcon className="size-3 shrink-0" aria-hidden="true" /> | 108 | data-composer-context-control |
| 104 | ) : ( | 109 | /> |
| 105 | <EnvironmentMachineIcon | 110 | } |
| 106 | kind={activeEnvironment?.machine ?? "server"} | ||
| 107 | className="size-3 shrink-0" | ||
| 108 | /> | ||
| 109 | )} | ||
| 110 | <span | ||
| 111 | data-composer-label | ||
| 112 | className="min-w-0 max-w-[240px] group-data-[compact]/composer-context:max-w-0" | ||
| 113 | > | 111 | > |
| 112 | {autoEnvironmentLabel ? ( | ||
| 113 | <ScaleIcon className="size-3 shrink-0" aria-hidden="true" /> | ||
| 114 | ) : ( | ||
| 115 | <EnvironmentMachineIcon | ||
| 116 | kind={activeEnvironment?.machine ?? "server"} | ||
| 117 | className="size-3 shrink-0" | ||
| 118 | /> | ||
| 119 | )} | ||
| 114 | <span | 120 | <span |
| 115 | data-composer-label-motion | 121 | data-composer-label |
| 116 | className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none" | 122 | className="min-w-0 max-w-[240px] group-data-[compact]/composer-context:max-w-0" |
| 117 | > | 123 | > |
| 118 | <SelectValue /> | 124 | <span |
| 125 | data-composer-label-motion | ||
| 126 | className="block w-full min-w-0 max-w-[240px] truncate transition-opacity duration-180 ease-[cubic-bezier(0.32,0.72,0,1)] group-data-[compact]/composer-context:opacity-0 motion-reduce:transition-none" | ||
| 127 | > | ||
| 128 | <SelectValue /> | ||
| 129 | </span> | ||
| 119 | </span> | 130 | </span> |
| 120 | </span> | 131 | </TooltipTrigger> |
| 121 | </SelectTrigger> | 132 | <TooltipPopup>{autoEnvironmentLabel ?? activeEnvironment?.label ?? "Run on"}</TooltipPopup> |
| 133 | </Tooltip> | ||
| 122 | <SelectPopup alignItemWithTrigger={false} {...composerFloatingLayerProps}> | 134 | <SelectPopup alignItemWithTrigger={false} {...composerFloatingLayerProps}> |
| 123 | <SelectGroup> | 135 | <SelectGroup> |
| 124 | <SelectGroupLabel>Run on</SelectGroupLabel> | 136 | <SelectGroupLabel>Run on</SelectGroupLabel> |