update prompt input view style
This commit is contained in:
parent
d521184945
commit
c40c618311
@ -37,7 +37,7 @@ function BadgeBase({
|
||||
onDelete()
|
||||
}}
|
||||
>
|
||||
<X size={10} />
|
||||
<X size={16} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import * as DropdownMenu from '@radix-ui/react-dropdown-menu'
|
||||
import Fuse, { FuseResult } from 'fuse.js'
|
||||
import { ChevronDown, ChevronUp } from 'lucide-react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
|
||||
import { useSettings } from '../../../contexts/SettingsContext'
|
||||
import { ApiProvider } from '../../../types/llm/model'
|
||||
@ -138,6 +138,7 @@ export function ModelSelect() {
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [searchTerm, setSearchTerm] = useState("")
|
||||
const [selectedIndex, setSelectedIndex] = useState(0)
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const providers = GetAllProviders()
|
||||
|
||||
@ -189,138 +190,289 @@ export function ModelSelect() {
|
||||
}, [searchableItems, searchTerm, fuse])
|
||||
|
||||
return (
|
||||
<DropdownMenu.Root open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DropdownMenu.Trigger className="infio-chat-input-model-select">
|
||||
<div className="infio-chat-input-model-select__icon">
|
||||
{isOpen ? <ChevronUp size={12} /> : <ChevronDown size={12} />}
|
||||
</div>
|
||||
<div className="infio-chat-input-model-select__model-name">
|
||||
[{modelProvider}] {chatModelId}
|
||||
</div>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content className="infio-popover infio-llm-setting-combobox-dropdown">
|
||||
<div className="infio-llm-setting-search-container">
|
||||
<select
|
||||
className="infio-llm-setting-provider-switch"
|
||||
value={modelProvider}
|
||||
onChange={(e) => {
|
||||
const newProvider = e.target.value as ApiProvider
|
||||
setModelProvider(newProvider)
|
||||
setSearchTerm("")
|
||||
setSelectedIndex(0)
|
||||
}}
|
||||
>
|
||||
{providers.map((provider) => (
|
||||
<option
|
||||
key={provider}
|
||||
value={provider}
|
||||
className={`infio-llm-setting-provider-option ${provider === modelProvider ? 'is-active' : ''}`}
|
||||
>
|
||||
{provider}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{modelIds.length > 0 ? (
|
||||
<input
|
||||
type="text"
|
||||
className="infio-llm-setting-item-search"
|
||||
placeholder="search model..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value)
|
||||
setSelectedIndex(0)
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
switch (e.key) {
|
||||
case "ArrowDown":
|
||||
e.preventDefault()
|
||||
setSelectedIndex((prev) =>
|
||||
Math.min(prev + 1, filteredOptions.length - 1)
|
||||
)
|
||||
break
|
||||
case "ArrowUp":
|
||||
e.preventDefault()
|
||||
setSelectedIndex((prev) => Math.max(prev - 1, 0))
|
||||
break
|
||||
case "Enter": {
|
||||
e.preventDefault()
|
||||
const selectedOption = filteredOptions[selectedIndex]
|
||||
if (selectedOption) {
|
||||
setSettings({
|
||||
...settings,
|
||||
chatModelProvider: modelProvider,
|
||||
chatModelId: selectedOption.id,
|
||||
})
|
||||
setChatModelId(selectedOption.id)
|
||||
setSearchTerm("")
|
||||
setIsOpen(false)
|
||||
}
|
||||
break
|
||||
}
|
||||
case "Escape":
|
||||
e.preventDefault()
|
||||
setIsOpen(false)
|
||||
setSearchTerm("")
|
||||
break
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
type="text"
|
||||
className="infio-llm-setting-item-search"
|
||||
placeholder="input custom model name"
|
||||
value={searchTerm}
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value)
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault()
|
||||
setSettings({
|
||||
...settings,
|
||||
chatModelProvider: modelProvider,
|
||||
chatModelId: searchTerm,
|
||||
})
|
||||
setChatModelId(searchTerm)
|
||||
setIsOpen(false)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<>
|
||||
<DropdownMenu.Root open={isOpen} onOpenChange={setIsOpen}>
|
||||
<DropdownMenu.Trigger className="infio-chat-input-model-select">
|
||||
<div className="infio-chat-input-model-select__icon">
|
||||
{isOpen ? <ChevronUp size={12} /> : <ChevronDown size={12} />}
|
||||
</div>
|
||||
<ul>
|
||||
{isLoading ? (
|
||||
<li>Loading...</li>
|
||||
) : (
|
||||
filteredOptions.map((option, index) => (
|
||||
<DropdownMenu.Item
|
||||
key={option.id}
|
||||
onSelect={() => {
|
||||
setSettings({
|
||||
...settings,
|
||||
chatModelProvider: modelProvider,
|
||||
chatModelId: option.id,
|
||||
})
|
||||
setChatModelId(option.id)
|
||||
<div className="infio-chat-input-model-select__model-name">
|
||||
[{modelProvider}] {chatModelId}
|
||||
</div>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content className="infio-popover infio-llm-setting-combobox-dropdown">
|
||||
<div className="infio-llm-setting-search-container">
|
||||
<div className="infio-llm-setting-provider-container">
|
||||
<select
|
||||
className="infio-llm-setting-provider-switch"
|
||||
value={modelProvider}
|
||||
onChange={(e) => {
|
||||
const newProvider = e.target.value as ApiProvider
|
||||
setModelProvider(newProvider)
|
||||
setSearchTerm("")
|
||||
setIsOpen(false)
|
||||
setSelectedIndex(0)
|
||||
}}
|
||||
className={`infio-llm-setting-combobox-option ${index === selectedIndex ? 'is-selected' : ''}`}
|
||||
onMouseEnter={() => setSelectedIndex(index)}
|
||||
asChild
|
||||
>
|
||||
<li>
|
||||
<HighlightedText segments={option.html} />
|
||||
</li>
|
||||
</DropdownMenu.Item>
|
||||
))
|
||||
)}
|
||||
</ul>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
{providers.map((provider) => (
|
||||
<option
|
||||
key={provider}
|
||||
value={provider}
|
||||
className={`infio-llm-setting-provider-option ${provider === modelProvider ? 'is-active' : ''}`}
|
||||
>
|
||||
{provider}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
{modelIds.length > 0 ? (
|
||||
<div className="infio-search-input-container">
|
||||
<input
|
||||
type="text"
|
||||
className="infio-llm-setting-item-search"
|
||||
placeholder="search model..."
|
||||
ref={inputRef}
|
||||
value={searchTerm}
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value)
|
||||
setSelectedIndex(0)
|
||||
// 确保下一个渲染循环中仍然聚焦在输入框
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus()
|
||||
}, 0)
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
switch (e.key) {
|
||||
case "ArrowDown":
|
||||
e.preventDefault()
|
||||
setSelectedIndex((prev) =>
|
||||
Math.min(prev + 1, filteredOptions.length - 1)
|
||||
)
|
||||
break
|
||||
case "ArrowUp":
|
||||
e.preventDefault()
|
||||
setSelectedIndex((prev) => Math.max(prev - 1, 0))
|
||||
break
|
||||
case "Enter": {
|
||||
e.preventDefault()
|
||||
const selectedOption = filteredOptions[selectedIndex]
|
||||
if (selectedOption) {
|
||||
setSettings({
|
||||
...settings,
|
||||
chatModelProvider: modelProvider,
|
||||
chatModelId: selectedOption.id,
|
||||
})
|
||||
setChatModelId(selectedOption.id)
|
||||
setSearchTerm("")
|
||||
setIsOpen(false)
|
||||
}
|
||||
break
|
||||
}
|
||||
case "Escape":
|
||||
e.preventDefault()
|
||||
setIsOpen(false)
|
||||
setSearchTerm("")
|
||||
break
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<input
|
||||
type="text"
|
||||
className="infio-llm-setting-item-search"
|
||||
placeholder="input custom model name"
|
||||
ref={inputRef}
|
||||
value={searchTerm}
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value)
|
||||
// 确保下一个渲染循环中仍然聚焦在输入框
|
||||
setTimeout(() => {
|
||||
inputRef.current?.focus()
|
||||
}, 0)
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault()
|
||||
setSettings({
|
||||
...settings,
|
||||
chatModelProvider: modelProvider,
|
||||
chatModelId: searchTerm,
|
||||
})
|
||||
setChatModelId(searchTerm)
|
||||
setIsOpen(false)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<ul>
|
||||
{isLoading ? (
|
||||
<li>Loading...</li>
|
||||
) : (
|
||||
filteredOptions.map((option, index) => (
|
||||
<DropdownMenu.Item
|
||||
key={option.id}
|
||||
onSelect={() => {
|
||||
setSettings({
|
||||
...settings,
|
||||
chatModelProvider: modelProvider,
|
||||
chatModelId: option.id,
|
||||
})
|
||||
setChatModelId(option.id)
|
||||
setSearchTerm("")
|
||||
setIsOpen(false)
|
||||
}}
|
||||
className={`infio-llm-setting-combobox-option ${index === selectedIndex ? 'is-selected' : ''}`}
|
||||
onMouseEnter={() => setSelectedIndex(index)}
|
||||
asChild
|
||||
>
|
||||
<li
|
||||
className="infio-llm-setting-model-item"
|
||||
title={option.id}
|
||||
>
|
||||
<div className="infio-model-item-text-wrapper">
|
||||
<HighlightedText segments={option.html} />
|
||||
</div>
|
||||
</li>
|
||||
</DropdownMenu.Item>
|
||||
))
|
||||
)}
|
||||
</ul>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
<style>
|
||||
{`
|
||||
/* 模型项样式 */
|
||||
.infio-llm-setting-model-item {
|
||||
display: block;
|
||||
padding: 0;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.infio-llm-setting-combobox-option:hover {
|
||||
background-color: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.infio-llm-setting-combobox-option.is-selected {
|
||||
background-color: var(--background-modifier-active);
|
||||
border-left: 3px solid var(--interactive-accent);
|
||||
}
|
||||
|
||||
/* 文本溢出处理 */
|
||||
.infio-model-item-text-wrapper {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 280px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.infio-model-item-text-wrapper span {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
/* 高亮样式 - 使用紫色而不是主题色 */
|
||||
.infio-llm-setting-model-item-highlight {
|
||||
display: inline;
|
||||
color: #9370DB;
|
||||
font-weight: 700;
|
||||
background-color: rgba(147, 112, 219, 0.1);
|
||||
padding: 0 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* 搜索容器 */
|
||||
.infio-llm-setting-search-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
gap: 5px;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
/* 提供商选择器容器 */
|
||||
.infio-llm-setting-provider-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
width: 26%;
|
||||
}
|
||||
|
||||
/* 移除提供商选择箭头 */
|
||||
|
||||
/* 提供商选择器 */
|
||||
.infio-llm-setting-provider-switch {
|
||||
width: 100% !important;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding-right: 5px;
|
||||
text-align: left;
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
background-color: var(--background-modifier-form-field);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
font-weight: 500;
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.infio-llm-setting-provider-switch:hover {
|
||||
border-color: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
.infio-llm-setting-provider-switch:focus {
|
||||
border-color: var(--interactive-accent);
|
||||
box-shadow: 0 0 0 2px rgba(var(--interactive-accent-rgb), 0.2);
|
||||
}
|
||||
|
||||
/* 搜索框容器 */
|
||||
.infio-search-input-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1 1 auto;
|
||||
width: 74%;
|
||||
}
|
||||
|
||||
/* 移除搜索图标 */
|
||||
|
||||
/* 搜索输入框 */
|
||||
.infio-llm-setting-item-search {
|
||||
width: 100% !important;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0px !important;
|
||||
background-color: var(--background-modifier-form-field);
|
||||
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||
height: 28px;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.infio-llm-setting-item-search:hover {
|
||||
border-color: var(--interactive-accent-hover);
|
||||
}
|
||||
|
||||
.infio-llm-setting-item-search:focus {
|
||||
border-color: var(--interactive-accent);
|
||||
box-shadow: 0 0 0 2px rgba(var(--interactive-accent-rgb), 0.2);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* 下拉菜单容器 */
|
||||
.infio-llm-setting-combobox-dropdown {
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||
border-radius: 8px;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
|
||||
import clsx from 'clsx'
|
||||
import {
|
||||
$parseSerializedNode,
|
||||
COMMAND_PRIORITY_NORMAL, SerializedLexicalNode, TextNode
|
||||
} from 'lexical'
|
||||
import { Slash } from 'lucide-react'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
|
||||
@ -63,8 +63,11 @@ function CommandMenuItem({
|
||||
onMouseEnter={onMouseEnter}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="smtcmp-template-menu-item">
|
||||
<div className="text">{option.name}</div>
|
||||
<div className="infio-chat-template-menu-item">
|
||||
<div className="text">
|
||||
<Slash size={10} />{' '}
|
||||
<span>{option.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
@ -157,7 +160,7 @@ export default function CommandPlugin() {
|
||||
anchorElementRef.current && searchResults.length
|
||||
? createPortal(
|
||||
<div
|
||||
className="smtcmp-popover"
|
||||
className="infio-popover"
|
||||
style={{
|
||||
position: 'fixed',
|
||||
}}
|
||||
|
||||
13
styles.css
13
styles.css
@ -891,19 +891,6 @@ input[type='text'].infio-chat-list-dropdown-item-title-input {
|
||||
justify-content: space-between;
|
||||
gap: var(--size-4-1);
|
||||
width: 100%;
|
||||
|
||||
.infio-chat-template-menu-item-delete {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--size-4-1);
|
||||
margin: calc(var(--size-4-1) * -1);
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.infio-chat-message-actions {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user