diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 2a96f9e9f3..2c3caa427e 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -1,8 +1,11 @@ import { + ArrowLeftIcon, ChevronRightIcon, FolderIcon, GitPullRequestIcon, + PlusIcon, RocketIcon, + SettingsIcon, SquarePenIcon, TerminalIcon, } from "lucide-react"; @@ -17,7 +20,7 @@ import { type ResolvedKeybindingsConfig, } from "@t3tools/contracts"; import { useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/react-query"; -import { useNavigate, useParams } from "@tanstack/react-router"; +import { useLocation, useNavigate, useParams } from "@tanstack/react-router"; import { useAppSettings } from "../appSettings"; import { isElectron } from "../env"; import { APP_STAGE_LABEL } from "../branding"; @@ -278,6 +281,7 @@ export default function Sidebar() { (store) => store.clearProjectDraftThreadById, ); const navigate = useNavigate(); + const isOnSettings = useLocation({ select: (loc) => loc.pathname === "/settings" }); const { settings: appSettings } = useAppSettings(); const routeThreadId = useParams({ strict: false, @@ -293,6 +297,8 @@ export default function Sidebar() { const [newCwd, setNewCwd] = useState(""); const [isPickingFolder, setIsPickingFolder] = useState(false); const [isAddingProject, setIsAddingProject] = useState(false); + const [addProjectError, setAddProjectError] = useState(null); + const addProjectInputRef = useRef(null); const [renamingThreadId, setRenamingThreadId] = useState(null); const [renamingTitle, setRenamingTitle] = useState(""); const [expandedThreadListsByProject, setExpandedThreadListsByProject] = useState< @@ -486,6 +492,7 @@ export default function Sidebar() { const finishAddingProject = () => { setIsAddingProject(false); setNewCwd(""); + setAddProjectError(null); setAddingProject(false); }; @@ -512,12 +519,9 @@ export default function Sidebar() { await handleNewThread(projectId).catch(() => undefined); } catch (error) { setIsAddingProject(false); - toastManager.add({ - type: "error", - title: "Unable to add project", - description: - error instanceof Error ? error.message : "An error occurred while adding the project.", - }); + setAddProjectError( + error instanceof Error ? error.message : "An error occurred while adding the project.", + ); return; } finishAddingProject(); @@ -541,6 +545,8 @@ export default function Sidebar() { } if (pickedPath) { await addProjectFromPath(pickedPath); + } else { + addProjectInputRef.current?.focus(); } setIsPickingFolder(false); }; @@ -1025,6 +1031,95 @@ export default function Sidebar() { +
+ + Projects + + + { + setAddingProject((prev) => !prev); + setAddProjectError(null); + }} + /> + } + > + + + Add project + +
+ + {addingProject && ( +
+ {isElectron && ( + + )} +
+ { + setNewCwd(event.target.value); + setAddProjectError(null); + }} + onKeyDown={(event) => { + if (event.key === "Enter") handleAddProject(); + if (event.key === "Escape") { + setAddingProject(false); + setAddProjectError(null); + } + }} + autoFocus + /> + +
+ {addProjectError && ( +

+ {addProjectError} +

+ )} +
+ +
+
+ )} + {projects.map((project) => { const projectThreads = threads @@ -1288,68 +1383,37 @@ export default function Sidebar() { {projects.length === 0 && !addingProject && (
- No projects yet. -
- Add one to get started. + No projects yet
)}
- - {addingProject ? ( - <> -

- Add project -

- setNewCwd(event.target.value)} - onKeyDown={(event) => { - if (event.key === "Enter") handleAddProject(); - if (event.key === "Escape") setAddingProject(false); - }} - /> - {isElectron && ( - - )} -
- - -
- - ) : ( - - )} + + Settings + + )} + +
);