From fb2b08639701b44b63d8a9e8f14cd00701ddbb15 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Mon, 7 Sep 2026 20:16:29 +0000 Subject: [PATCH 1/3] fix(web): make settings project scopes searchable and scrollable --- .../components/settings/ProjectsSettings.tsx | 89 +++++++++++++------ 1 file changed, 61 insertions(+), 28 deletions(-) diff --git a/apps/web/src/components/settings/ProjectsSettings.tsx b/apps/web/src/components/settings/ProjectsSettings.tsx index 4eedaab63846..c8ed352935bc 100644 --- a/apps/web/src/components/settings/ProjectsSettings.tsx +++ b/apps/web/src/components/settings/ProjectsSettings.tsx @@ -1,12 +1,22 @@ import { resolveEnvironmentMachineKind } from "@t3tools/contracts"; -import { FolderIcon } from "lucide-react"; -import type { ReactNode } from "react"; +import { ChevronDownIcon, FolderIcon, SearchIcon } from "lucide-react"; +import { type ReactNode, useState } from "react"; import { EnvironmentMachineIcon } from "../EnvironmentMachineIcon"; import { ProjectFavicon } from "../ProjectFavicon"; import { WorkspacePageContainer } from "../WorkspacePageContainer"; import { useEnvironments } from "../../state/environments"; import { Toggle, ToggleGroup } from "../ui/toggle-group"; -import { Select, SelectItem, SelectPopup, SelectTrigger, SelectValue } from "../ui/select"; +import { + Combobox, + ComboboxEmpty, + ComboboxInput, + ComboboxItem, + ComboboxList, + ComboboxPopup, + ComboboxTrigger, +} from "../ui/combobox"; +import { selectTriggerVariants } from "../ui/select"; +import { cn } from "../../lib/utils"; import { ProjectSettingsPanel, useSettingsProjectGroups } from "./ProjectSettingsPanel"; import { ProjectDefaultsSettings } from "./ProjectDefaultsSettings"; @@ -21,44 +31,67 @@ function ScopePicker({ options: ReadonlyArray<{ value: string; label: string; icon?: ReactNode }>; onChange: (value: string | null) => void; }) { + const [query, setQuery] = useState(""); const selected = options.find((option) => option.value === value); const allIcon = label === "project" ? : null; + const items = [{ value: "all", label: `All ${label}s`, icon: allIcon }, ...options]; return ( - + + + + +
+
+ + +
+
+ No matching {label}s. + + {(item: (typeof items)[number]) => ( + + {item.icon} + {item.label} + + )} + +
+ ); } From d57af40a2ac50fa7e69c3cb1d585db671112d6d9 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Mon, 7 Sep 2026 20:25:05 +0000 Subject: [PATCH 2/3] fix(web): use shared combobox input styling --- .../components/settings/ProjectsSettings.tsx | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/apps/web/src/components/settings/ProjectsSettings.tsx b/apps/web/src/components/settings/ProjectsSettings.tsx index c8ed352935bc..a9573152021c 100644 --- a/apps/web/src/components/settings/ProjectsSettings.tsx +++ b/apps/web/src/components/settings/ProjectsSettings.tsx @@ -60,22 +60,14 @@ function ScopePicker({ -
-
- - -
+
+ } + showTrigger={false} + size="sm" + />
No matching {label}s. From c5499a50820abf1e0cb313badf49dfb09dc6cb51 Mon Sep 17 00:00:00 2001 From: maria-rcks Date: Mon, 7 Sep 2026 21:18:30 +0000 Subject: [PATCH 3/3] fix(web): share the sidebar project search styling --- apps/web/src/components/Sidebar.tsx | 72 ++++++++----------- .../components/settings/ProjectsSettings.tsx | 14 +--- apps/web/src/components/ui/combobox.tsx | 24 ++++++- 3 files changed, 55 insertions(+), 55 deletions(-) diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 5182ee4d783e..954e10b38eb5 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -208,7 +208,7 @@ import { Input } from "./ui/input"; import { Combobox, ComboboxEmpty, - ComboboxInput, + ComboboxSearchInput, ComboboxItem, ComboboxList, ComboboxPopup, @@ -4395,48 +4395,34 @@ export default function Sidebar() { align="start" className="w-(--anchor-width) min-w-0 overflow-hidden" > -
-
-
-
+ { + if ( + event.defaultPrevented || + event.nativeEvent.isComposing || + event.ctrlKey || + event.altKey || + event.metaKey || + (event.key !== "ContextMenu" && !(event.shiftKey && event.key === "F10")) + ) { + return; + } + // Combobox items use virtual focus: keyboard events + // stay on this input, not on the highlighted option. + const scopeKey = highlightedProjectScopeKeyRef.current; + const project = scopeKey ? projectGroupByScopeKey.get(scopeKey) : null; + if (project) handleProjectSettings(event, project); + }} + onChange={(event) => + dispatchProjectScopeMenu({ + type: "query-changed", + query: event.target.value, + }) + } + /> No matching projects. {(item: (typeof projectScopeItems)[number]) => { diff --git a/apps/web/src/components/settings/ProjectsSettings.tsx b/apps/web/src/components/settings/ProjectsSettings.tsx index a9573152021c..b454517bcda7 100644 --- a/apps/web/src/components/settings/ProjectsSettings.tsx +++ b/apps/web/src/components/settings/ProjectsSettings.tsx @@ -1,5 +1,5 @@ import { resolveEnvironmentMachineKind } from "@t3tools/contracts"; -import { ChevronDownIcon, FolderIcon, SearchIcon } from "lucide-react"; +import { ChevronDownIcon, FolderIcon } from "lucide-react"; import { type ReactNode, useState } from "react"; import { EnvironmentMachineIcon } from "../EnvironmentMachineIcon"; import { ProjectFavicon } from "../ProjectFavicon"; @@ -9,7 +9,7 @@ import { Toggle, ToggleGroup } from "../ui/toggle-group"; import { Combobox, ComboboxEmpty, - ComboboxInput, + ComboboxSearchInput, ComboboxItem, ComboboxList, ComboboxPopup, @@ -60,15 +60,7 @@ function ScopePicker({ -
- } - showTrigger={false} - size="sm" - /> -
+ No matching {label}s. {(item: (typeof items)[number]) => ( diff --git a/apps/web/src/components/ui/combobox.tsx b/apps/web/src/components/ui/combobox.tsx index d9f09690331d..59bf4d637704 100644 --- a/apps/web/src/components/ui/combobox.tsx +++ b/apps/web/src/components/ui/combobox.tsx @@ -1,7 +1,7 @@ "use client"; import { Combobox as ComboboxPrimitive } from "@base-ui/react/combobox"; -import { ChevronsUpDownIcon, XIcon } from "lucide-react"; +import { ChevronsUpDownIcon, SearchIcon, XIcon } from "lucide-react"; import * as React from "react"; import { cn } from "~/lib/utils"; @@ -130,6 +130,27 @@ function ComboboxInput({ ); } +function ComboboxSearchInput(props: React.ComponentProps) { + return ( +
+
+
+
+ ); +} + function ComboboxTrigger({ className, children, ...props }: ComboboxPrimitive.Trigger.Props) { return ( @@ -393,6 +414,7 @@ export { Combobox, ComboboxChipsInput, ComboboxInput, + ComboboxSearchInput, ComboboxTrigger, ComboboxPopup, ComboboxItem,