| ... | @@ -32,6 +32,7 @@ import { type Thread } from "../types"; | ... | @@ -32,6 +32,7 @@ import { type Thread } from "../types"; |
| 32 | import { derivePendingApprovals } from "../session-logic"; | 32 | import { derivePendingApprovals } from "../session-logic"; |
| 33 | import { gitRemoveWorktreeMutationOptions, gitStatusQueryOptions } from "../lib/gitReactQuery"; | 33 | import { gitRemoveWorktreeMutationOptions, gitStatusQueryOptions } from "../lib/gitReactQuery"; |
| 34 | import { serverConfigQueryOptions } from "../lib/serverReactQuery"; | 34 | import { serverConfigQueryOptions } from "../lib/serverReactQuery"; |
| | 35 | import { useMediaQuery } from "../hooks/useMediaQuery"; |
| 35 | import { readNativeApi } from "../nativeApi"; | 36 | import { readNativeApi } from "../nativeApi"; |
| 36 | import { type DraftThreadEnvMode, useComposerDraftStore } from "../composerDraftStore"; | 37 | import { type DraftThreadEnvMode, useComposerDraftStore } from "../composerDraftStore"; |
| 37 | import { selectThreadTerminalState, useTerminalStateStore } from "../terminalStateStore"; | 38 | import { selectThreadTerminalState, useTerminalStateStore } from "../terminalStateStore"; |
| ... | @@ -49,6 +50,7 @@ import { | ... | @@ -49,6 +50,7 @@ import { |
| 49 | } from "./desktopUpdate.logic"; | 50 | } from "./desktopUpdate.logic"; |
| 50 | import { Alert, AlertAction, AlertDescription, AlertTitle } from "./ui/alert"; | 51 | import { Alert, AlertAction, AlertDescription, AlertTitle } from "./ui/alert"; |
| 51 | import { Button } from "./ui/button"; | 52 | import { Button } from "./ui/button"; |
| | 53 | import { shouldOpenProjectFolderPickerImmediately } from "./Sidebar.logic"; |
| 52 | import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./ui/collapsible"; | 54 | import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./ui/collapsible"; |
| 53 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; | 55 | import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; |
| 54 | import { | 56 | import { |
| ... | @@ -266,6 +268,7 @@ function ProjectFavicon({ cwd }: { cwd: string }) { | ... | @@ -266,6 +268,7 @@ function ProjectFavicon({ cwd }: { cwd: string }) { |
| 266 | } | 268 | } |
| 267 | | 269 | |
| 268 | export default function Sidebar() { | 270 | export default function Sidebar() { |
| | 271 | const isMobile = useMediaQuery("(max-width: 767px)"); |
| 269 | const projects = useStore((store) => store.projects); | 272 | const projects = useStore((store) => store.projects); |
| 270 | const threads = useStore((store) => store.threads); | 273 | const threads = useStore((store) => store.threads); |
| 271 | const markThreadUnread = useStore((store) => store.markThreadUnread); | 274 | const markThreadUnread = useStore((store) => store.markThreadUnread); |
| ... | @@ -312,6 +315,11 @@ export default function Sidebar() { | ... | @@ -312,6 +315,11 @@ export default function Sidebar() { |
| 312 | const renamingCommittedRef = useRef(false); | 315 | const renamingCommittedRef = useRef(false); |
| 313 | const renamingInputRef = useRef<HTMLInputElement | null>(null); | 316 | const renamingInputRef = useRef<HTMLInputElement | null>(null); |
| 314 | const [desktopUpdateState, setDesktopUpdateState] = useState<DesktopUpdateState | null>(null); | 317 | const [desktopUpdateState, setDesktopUpdateState] = useState<DesktopUpdateState | null>(null); |
| | 318 | const shouldBrowseForProjectImmediately = shouldOpenProjectFolderPickerImmediately({ |
| | 319 | isElectron, |
| | 320 | isMobile, |
| | 321 | }); |
| | 322 | const shouldShowProjectPathEntry = addingProject && !shouldBrowseForProjectImmediately; |
| 315 | const pendingApprovalByThreadId = useMemo(() => { | 323 | const pendingApprovalByThreadId = useMemo(() => { |
| 316 | const map = new Map<ThreadId, boolean>(); | 324 | const map = new Map<ThreadId, boolean>(); |
| 317 | for (const thread of threads) { | 325 | for (const thread of threads) { |
| ... | @@ -550,12 +558,21 @@ export default function Sidebar() { | ... | @@ -550,12 +558,21 @@ export default function Sidebar() { |
| 550 | } | 558 | } |
| 551 | if (pickedPath) { | 559 | if (pickedPath) { |
| 552 | await addProjectFromPath(pickedPath); | 560 | await addProjectFromPath(pickedPath); |
| 553 | } else { | 561 | } else if (!shouldBrowseForProjectImmediately) { |
| 554 | addProjectInputRef.current?.focus(); | 562 | addProjectInputRef.current?.focus(); |
| 555 | } | 563 | } |
| 556 | setIsPickingFolder(false); | 564 | setIsPickingFolder(false); |
| 557 | }; | 565 | }; |
| 558 | | 566 | |
| | 567 | const handleStartAddProject = () => { |
| | 568 | setAddProjectError(null); |
| | 569 | if (shouldBrowseForProjectImmediately) { |
| | 570 | void handlePickFolder(); |
| | 571 | return; |
| | 572 | } |
| | 573 | setAddingProject((prev) => !prev); |
| | 574 | }; |
| | 575 | |
| 559 | const cancelRename = useCallback(() => { | 576 | const cancelRename = useCallback(() => { |
| 560 | setRenamingThreadId(null); | 577 | setRenamingThreadId(null); |
| 561 | renamingInputRef.current = null; | 578 | renamingInputRef.current = null; |
| ... | @@ -1075,21 +1092,23 @@ export default function Sidebar() { | ... | @@ -1075,21 +1092,23 @@ export default function Sidebar() { |
| 1075 | <button | 1092 | <button |
| 1076 | type="button" | 1093 | type="button" |
| 1077 | aria-label="Add project" | 1094 | aria-label="Add project" |
| | 1095 | aria-pressed={shouldShowProjectPathEntry} |
| 1078 | className="inline-flex size-5 items-center justify-center rounded-md text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground" | 1096 | className="inline-flex size-5 items-center justify-center rounded-md text-muted-foreground/60 transition-colors hover:bg-accent hover:text-foreground" |
| 1079 | onClick={() => { | 1097 | onClick={handleStartAddProject} |
| 1080 | setAddingProject((prev) => !prev); | | |
| 1081 | setAddProjectError(null); | | |
| 1082 | }} | | |
| 1083 | /> | 1098 | /> |
| 1084 | } | 1099 | } |
| 1085 | > | 1100 | > |
| 1086 | <PlusIcon className="size-3.5" /> | 1101 | <PlusIcon |
| | 1102 | className={`size-3.5 transition-transform duration-150 ${ |
| | 1103 | shouldShowProjectPathEntry ? "rotate-45" : "rotate-0" |
| | 1104 | }`} |
| | 1105 | /> |
| 1087 | </TooltipTrigger> | 1106 | </TooltipTrigger> |
| 1088 | <TooltipPopup side="right">Add project</TooltipPopup> | 1107 | <TooltipPopup side="right">Add project</TooltipPopup> |
| 1089 | </Tooltip> | 1108 | </Tooltip> |
| 1090 | </div> | 1109 | </div> |
| 1091 | | 1110 | |
| 1092 | {addingProject && ( | 1111 | {shouldShowProjectPathEntry && ( |
| 1093 | <div className="mb-2 px-1"> | 1112 | <div className="mb-2 px-1"> |
| 1094 | {isElectron && ( | 1113 | {isElectron && ( |
| 1095 | <button | 1114 | <button |
| ... | @@ -1415,7 +1434,7 @@ export default function Sidebar() { | ... | @@ -1415,7 +1434,7 @@ export default function Sidebar() { |
| 1415 | })} | 1434 | })} |
| 1416 | </SidebarMenu> | 1435 | </SidebarMenu> |
| 1417 | | 1436 | |
| 1418 | {projects.length === 0 && !addingProject && ( | 1437 | {projects.length === 0 && !shouldShowProjectPathEntry && ( |
| 1419 | <div className="px-2 pt-4 text-center text-xs text-muted-foreground/60"> | 1438 | <div className="px-2 pt-4 text-center text-xs text-muted-foreground/60"> |
| 1420 | No projects yet | 1439 | No projects yet |
| 1421 | </div> | 1440 | </div> |