diff --git a/webview-ui/src/components/settings/OpenRouterModelPicker.tsx b/webview-ui/src/components/settings/OpenRouterModelPicker.tsx index c94d953..1302598 100644 --- a/webview-ui/src/components/settings/OpenRouterModelPicker.tsx +++ b/webview-ui/src/components/settings/OpenRouterModelPicker.tsx @@ -1,25 +1,26 @@ -import { VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react" -import React, { useMemo } from "react" -import { useMount } from "react-use" +import React, { useMemo, useState, useRef, useEffect, memo } from "react" +import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react" +import styled from "styled-components" import { useExtensionState } from "../../context/ExtensionStateContext" +import { useMount } from "react-use" import { vscode } from "../../utils/vscode" import { ModelInfoView, normalizeApiConfiguration } from "./ApiOptions" -import { memo, useEffect } from "react" import { useRemark } from "react-remark" -import styled from "styled-components" -interface OpenRouterModelPickerProps {} - -const OpenRouterModelPicker: React.FC = () => { +const OpenRouterModelPicker: React.FC = () => { const { apiConfiguration, setApiConfiguration, openRouterModels } = useExtensionState() + const [searchTerm, setSearchTerm] = useState("") + const [isDropdownVisible, setIsDropdownVisible] = useState(false) + const dropdownRef = useRef(null) - const handleModelChange = (event: any) => { - const newModelId = event.target.value + const handleModelChange = (newModelId: string) => { setApiConfiguration({ ...apiConfiguration, openRouterModelId: newModelId, openRouterModelInfo: openRouterModels[newModelId], }) + setSearchTerm(newModelId) + setIsDropdownVisible(false) } const { selectedModelId, selectedModelInfo } = useMemo(() => { @@ -30,36 +31,52 @@ const OpenRouterModelPicker: React.FC = () => { vscode.postMessage({ type: "refreshOpenRouterModels" }) }) - const modelIds = useMemo(() => { - return Object.keys(openRouterModels).sort((a, b) => a.localeCompare(b)) - }, [openRouterModels]) + const filteredModelIds = useMemo(() => { + return Object.keys(openRouterModels) + .filter((modelId) => modelId.toLowerCase().includes(searchTerm.toLowerCase())) + .sort((a, b) => a.localeCompare(b)) + }, [openRouterModels, searchTerm]) + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + setIsDropdownVisible(false) + } + } + + document.addEventListener("mousedown", handleClickOutside) + return () => { + document.removeEventListener("mousedown", handleClickOutside) + } + }, []) return ( <> -
-
+ { + setSearchTerm((e.target as HTMLInputElement).value) + setIsDropdownVisible(true) + }} + onFocus={() => setIsDropdownVisible(true)} + style={{ width: "100%", zIndex: 1001 }} + /> + {isDropdownVisible && ( + + {filteredModelIds.map((modelId) => ( + handleModelChange(modelId)}> + {modelId} + + ))} + + )} + @@ -68,6 +85,37 @@ const OpenRouterModelPicker: React.FC = () => { export default OpenRouterModelPicker +// Dropdown + +const DropdownWrapper = styled.div` + position: relative; + width: 100%; +` + +const DropdownList = styled.div` + position: absolute; + top: calc(100% - 3px); + left: 0; + width: calc(100% - 2px); + max-height: 200px; + overflow-y: auto; + background-color: var(--vscode-dropdown-background); + border: 1px solid var(--vscode-list-activeSelectionBackground); + z-index: 1000; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +` + +const DropdownItem = styled.div` + padding: 5px 10px; + cursor: pointer; + &:hover { + background-color: var(--vscode-list-activeSelectionBackground); + } +` + +// Markdown + const StyledMarkdown = styled.div` font-family: var(--vscode-font-family), system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;