feat: model selection add search input

This commit is contained in:
Hk-Gosuto 2024-10-23 11:04:55 +08:00
parent e3600f5acb
commit 6593e05fcb
3 changed files with 120 additions and 1 deletions

View File

@ -96,6 +96,7 @@ import {
List,
ListItem,
Modal,
SearchSelector,
Selector,
showConfirm,
showPrompt,
@ -678,7 +679,7 @@ export function ChatActions(props: {
/>
{showModelSelector && (
<Selector
<SearchSelector
defaultSelectedValue={`${currentModel}@${currentProviderName}`}
items={models.map((m) => ({
title: `${m.displayName}${

View File

@ -311,4 +311,21 @@
}
}
}
&-search {
border-bottom: 1px solid var(--gray-200);
}
&-search-input {
width: 100% !important;
max-width: 100% !important;
padding: 8px 12px;
border: none;
outline: none;
font-size: 14px;
}
&-search-input:focus {
background-color: var(--gray-50);
}
}

View File

@ -465,7 +465,108 @@ export function showImageModal(
),
});
}
export function SearchSelector<T>(props: {
items: Array<{
title: string;
subTitle?: string;
value: T;
disable?: boolean;
}>;
defaultSelectedValue?: T[] | T;
onSelection?: (selection: T[]) => void;
onClose?: () => void;
multiple?: boolean;
}) {
const [selectedValues, setSelectedValues] = useState<T[]>(
Array.isArray(props.defaultSelectedValue)
? props.defaultSelectedValue
: props.defaultSelectedValue !== undefined
? [props.defaultSelectedValue]
: [],
);
// 添加搜索状态
const [searchQuery, setSearchQuery] = useState("");
const handleSelection = (e: MouseEvent, value: T) => {
if (props.multiple) {
e.stopPropagation();
const newSelectedValues = selectedValues.includes(value)
? selectedValues.filter((v) => v !== value)
: [...selectedValues, value];
setSelectedValues(newSelectedValues);
props.onSelection?.(newSelectedValues);
} else {
setSelectedValues([value]);
props.onSelection?.([value]);
props.onClose?.();
}
};
// 过滤列表项
const filteredItems = props.items.filter(
(item) =>
item.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
(item.subTitle &&
item.subTitle.toLowerCase().includes(searchQuery.toLowerCase())),
);
return (
<div className={styles["selector"]} onClick={() => props.onClose?.()}>
<div
className={styles["selector-content"]}
onClick={(e) => e.stopPropagation()}
>
<List>
{/* 搜索框 */}
<div className={styles["selector-search"]}>
<input
type="text"
className={styles["selector-search-input"]}
placeholder="search model"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
onClick={(e) => e.stopPropagation()}
/>
</div>
{filteredItems.map((item, i) => {
const selected = selectedValues.includes(item.value);
return (
<ListItem
className={`${styles["selector-item"]} ${
item.disable && styles["selector-item-disabled"]
}`}
key={i}
title={item.title}
subTitle={item.subTitle}
onClick={(e) => {
if (item.disable) {
e.stopPropagation();
} else {
handleSelection(e, item.value);
}
}}
>
{selected ? (
<div
style={{
height: 10,
width: 10,
backgroundColor: "var(--primary)",
borderRadius: 10,
}}
></div>
) : (
<></>
)}
</ListItem>
);
})}
</List>
</div>
</div>
);
}
export function Selector<T>(props: {
items: Array<{
title: string;