@@ -13,6 +13,25 @@ import { CODE_BLOCK_BG_COLOR } from "@/components/common/CodeBlock"
1313import ThinkingBudgetSlider from "./ThinkingBudgetSlider"
1414import FeaturedModelCard from "./FeaturedModelCard"
1515
16+ // Star icon for favorites
17+ const StarIcon = ( { isFavorite, onClick } : { isFavorite : boolean ; onClick : ( e : React . MouseEvent ) => void } ) => {
18+ return (
19+ < div
20+ onClick = { onClick }
21+ style = { {
22+ cursor : "pointer" ,
23+ color : isFavorite ? "var(--vscode-terminal-ansiBlue)" : "var(--vscode-descriptionForeground)" ,
24+ marginLeft : "8px" ,
25+ fontSize : "16px" ,
26+ display : "flex" ,
27+ alignItems : "center" ,
28+ justifyContent : "center" ,
29+ } } >
30+ { isFavorite ? "★" : "☆" }
31+ </ div >
32+ )
33+ }
34+
1635export interface OpenRouterModelPickerProps {
1736 isPopup ?: boolean
1837}
@@ -110,9 +129,18 @@ const OpenRouterModelPicker: React.FC<OpenRouterModelPickerProps> = ({ isPopup }
110129 const results : { id : string ; html : string } [ ] = searchTerm
111130 ? highlight ( fuse . search ( searchTerm ) , "model-item-highlight" )
112131 : searchableItems
113- // results.sort((a, b) => a.id.localeCompare(b.id)) NOTE: sorting like this causes ids in objects to be reordered and mismatched
114- return results
115- } , [ searchableItems , searchTerm , fuse ] )
132+
133+ // Sort favorited models to the top
134+ const favoritedModelIds = apiConfiguration ?. favoritedModelIds || [ ]
135+ return results . sort ( ( a , b ) => {
136+ const aIsFavorite = favoritedModelIds . includes ( a . id )
137+ const bIsFavorite = favoritedModelIds . includes ( b . id )
138+
139+ if ( aIsFavorite && ! bIsFavorite ) return - 1
140+ if ( ! aIsFavorite && bIsFavorite ) return 1
141+ return a . id . localeCompare ( b . id )
142+ } )
143+ } , [ searchableItems , searchTerm , fuse , apiConfiguration ?. favoritedModelIds ] )
116144
117145 const handleKeyDown = ( event : KeyboardEvent < HTMLInputElement > ) => {
118146 if ( ! isDropdownVisible ) return
@@ -241,21 +269,34 @@ const OpenRouterModelPicker: React.FC<OpenRouterModelPickerProps> = ({ isPopup }
241269 </ VSCodeTextField >
242270 { isDropdownVisible && (
243271 < DropdownList ref = { dropdownListRef } >
244- { modelSearchResults . map ( ( item , index ) => (
245- < DropdownItem
246- key = { item . id }
247- ref = { ( el ) => ( itemRefs . current [ index ] = el ) }
248- isSelected = { index === selectedIndex }
249- onMouseEnter = { ( ) => setSelectedIndex ( index ) }
250- onClick = { ( ) => {
251- handleModelChange ( item . id )
252- setIsDropdownVisible ( false )
253- } }
254- dangerouslySetInnerHTML = { {
255- __html : item . html ,
256- } }
257- />
258- ) ) }
272+ { modelSearchResults . map ( ( item , index ) => {
273+ const isFavorite = ( apiConfiguration ?. favoritedModelIds || [ ] ) . includes ( item . id )
274+ return (
275+ < DropdownItem
276+ key = { item . id }
277+ ref = { ( el ) => ( itemRefs . current [ index ] = el ) }
278+ isSelected = { index === selectedIndex }
279+ onMouseEnter = { ( ) => setSelectedIndex ( index ) }
280+ onClick = { ( ) => {
281+ handleModelChange ( item . id )
282+ setIsDropdownVisible ( false )
283+ } } >
284+ < div style = { { display : "flex" , justifyContent : "space-between" , alignItems : "center" } } >
285+ < span dangerouslySetInnerHTML = { { __html : item . html } } />
286+ < StarIcon
287+ isFavorite = { isFavorite }
288+ onClick = { ( e ) => {
289+ e . stopPropagation ( )
290+ vscode . postMessage ( {
291+ type : "toggleFavoriteModel" ,
292+ modelId : item . id ,
293+ } )
294+ } }
295+ />
296+ </ div >
297+ </ DropdownItem >
298+ )
299+ } ) }
259300 </ DropdownList >
260301 ) }
261302 </ DropdownWrapper >
0 commit comments