mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-05-25 07:00:23 +09:00
feat: model selection add search input
This commit is contained in:
parent
e3600f5acb
commit
6593e05fcb
@ -96,6 +96,7 @@ import {
|
|||||||
List,
|
List,
|
||||||
ListItem,
|
ListItem,
|
||||||
Modal,
|
Modal,
|
||||||
|
SearchSelector,
|
||||||
Selector,
|
Selector,
|
||||||
showConfirm,
|
showConfirm,
|
||||||
showPrompt,
|
showPrompt,
|
||||||
@ -678,7 +679,7 @@ export function ChatActions(props: {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{showModelSelector && (
|
{showModelSelector && (
|
||||||
<Selector
|
<SearchSelector
|
||||||
defaultSelectedValue={`${currentModel}@${currentProviderName}`}
|
defaultSelectedValue={`${currentModel}@${currentProviderName}`}
|
||||||
items={models.map((m) => ({
|
items={models.map((m) => ({
|
||||||
title: `${m.displayName}${
|
title: `${m.displayName}${
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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: {
|
export function Selector<T>(props: {
|
||||||
items: Array<{
|
items: Array<{
|
||||||
title: string;
|
title: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user