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 4eedaab63846..b454517bcda7 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 } 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, + ComboboxSearchInput, + 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,51 @@ 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} + + )} + + + ); } 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,