authorgravatar for zortosdev@proton.meZortos <zortosdev@proton.me> 2026-03-13 03:26:14+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-12 19:26:14-07:00
log36473f7de6f32bb2765e0ad2b08e2a0c2e737d63
tree0e6425d18689ab713e341213387763824261da1a
parenta14debc83e04ee4b28d9e3eb830f0cf74d489f93
signature Signed by PGP key B5690EEEBB952194

feat: replace worktree toggle with discoverable Select dropdown (#1001)

Co-authored-by: Julius Marminge <julius0216@outlook.com>

2 files changed, 52 insertions(+), 17 deletions(-)

apps/web/src/components/BranchToolbar.tsx+51-17
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1import type { ThreadId } from "@t3tools/contracts";1import type { ThreadId } from "@t3tools/contracts";
2import { FolderIcon, GitForkIcon } from "lucide-react";
2import { useCallback } from "react";3import { useCallback } from "react";
34
4import { newCommandId } from "../lib/utils";5import { newCommandId } from "../lib/utils";
...@@ -11,8 +12,14 @@ import {...@@ -11,8 +12,14 @@ import {
11 resolveEffectiveEnvMode,12 resolveEffectiveEnvMode,
12} from "./BranchToolbar.logic";13} from "./BranchToolbar.logic";
13import { BranchToolbarBranchSelector } from "./BranchToolbarBranchSelector";14import { BranchToolbarBranchSelector } from "./BranchToolbarBranchSelector";
15import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "./ui/select";
14import { Button } from "./ui/button";16import { Button } from "./ui/button";
1517
18const envModeItems = [
19 { value: "local", label: "Local" },
20 { value: "worktree", label: "New worktree" },
21] as const;
22
16interface BranchToolbarProps {23interface BranchToolbarProps {
17 threadId: ThreadId;24 threadId: ThreadId;
18 onEnvModeChange: (mode: EnvMode) => void;25 onEnvModeChange: (mode: EnvMode) => void;
...@@ -104,23 +111,50 @@ export default function BranchToolbar({...@@ -104,23 +111,50 @@ export default function BranchToolbar({
104111
105 return (112 return (
106 <div className="mx-auto flex w-full max-w-3xl items-center justify-between px-5 pb-3 pt-1">113 <div className="mx-auto flex w-full max-w-3xl items-center justify-between px-5 pb-3 pt-1">
107 <div className="flex items-center gap-2">114 {envLocked || activeWorktreePath ? (
108 {envLocked || activeWorktreePath ? (115 <span className="inline-flex items-center gap-1 border border-transparent px-[calc(--spacing(3)-1px)] text-sm font-medium text-muted-foreground/70 sm:text-xs">
109 <span className="border border-transparent px-[calc(--spacing(2)-1px)] text-sm font-medium text-muted-foreground/70 sm:text-xs">116 {activeWorktreePath ? (
110 {activeWorktreePath ? "Worktree" : "Local"}117 <>
111 </span>118 <GitForkIcon className="size-3" />
112 ) : (119 Worktree
113 <Button120 </>
114 type="button"121 ) : (
115 variant="ghost"122 <>
116 className="text-muted-foreground/70 hover:text-foreground/80"123 <FolderIcon className="size-3" />
117 size="xs"124 Local
118 onClick={() => onEnvModeChange(effectiveEnvMode === "local" ? "worktree" : "local")}125 </>
119 >126 )}
120 {effectiveEnvMode === "worktree" ? "New worktree" : "Local"}127 </span>
121 </Button>128 ) : (
122 )}129 <Select
123 </div>130 value={effectiveEnvMode}
131 onValueChange={(value) => onEnvModeChange(value as EnvMode)}
132 items={envModeItems}
133 >
134 <SelectTrigger variant="ghost" size="xs" className="font-medium">
135 {effectiveEnvMode === "worktree" ? (
136 <GitForkIcon className="size-3" />
137 ) : (
138 <FolderIcon className="size-3" />
139 )}
140 <SelectValue />
141 </SelectTrigger>
142 <SelectPopup>
143 <SelectItem value="local">
144 <span className="inline-flex items-center gap-1.5">
145 <FolderIcon className="size-3" />
146 Local
147 </span>
148 </SelectItem>
149 <SelectItem value="worktree">
150 <span className="inline-flex items-center gap-1.5">
151 <GitForkIcon className="size-3" />
152 New worktree
153 </span>
154 </SelectItem>
155 </SelectPopup>
156 </Select>
157 )}
124158
125 <BranchToolbarBranchSelector159 <BranchToolbarBranchSelector
126 activeProjectCwd={activeProject.cwd}160 activeProjectCwd={activeProject.cwd}
apps/web/src/components/ui/select.tsx+1
...@@ -29,6 +29,7 @@ const selectTriggerVariants = cva(...@@ -29,6 +29,7 @@ const selectTriggerVariants = cva(
29 default: "min-h-9 px-[calc(--spacing(3)-1px)] sm:min-h-8",29 default: "min-h-9 px-[calc(--spacing(3)-1px)] sm:min-h-8",
30 lg: "min-h-10 px-[calc(--spacing(3)-1px)] sm:min-h-9",30 lg: "min-h-10 px-[calc(--spacing(3)-1px)] sm:min-h-9",
31 sm: "min-h-8 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:min-h-7",31 sm: "min-h-8 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:min-h-7",
32 xs: "h-7 gap-1 rounded-md px-[calc(--spacing(2)-1px)] text-sm before:rounded-[calc(var(--radius-md)-1px)] sm:h-6 sm:text-xs [&_svg:not([class*='size-'])]:size-4 sm:[&_svg:not([class*='size-'])]:size-3.5",
32 },33 },
33 },34 },
34 },35 },