From c40c6183112c01b5b9ef1f8c5b104dea73403421 Mon Sep 17 00:00:00 2001 From: duanfuxiang Date: Tue, 22 Apr 2025 22:10:22 +0800 Subject: [PATCH] update prompt input view style --- .../chat-view/chat-input/MentionableBadge.tsx | 2 +- .../chat-view/chat-input/ModelSelect.tsx | 412 ++++++++++++------ .../plugins/command/CommandPlugin.tsx | 11 +- styles.css | 13 - 4 files changed, 290 insertions(+), 148 deletions(-) diff --git a/src/components/chat-view/chat-input/MentionableBadge.tsx b/src/components/chat-view/chat-input/MentionableBadge.tsx index 9530dd1..e064fd9 100644 --- a/src/components/chat-view/chat-input/MentionableBadge.tsx +++ b/src/components/chat-view/chat-input/MentionableBadge.tsx @@ -37,7 +37,7 @@ function BadgeBase({ onDelete() }} > - + ) diff --git a/src/components/chat-view/chat-input/ModelSelect.tsx b/src/components/chat-view/chat-input/ModelSelect.tsx index 9449b6b..21d197a 100644 --- a/src/components/chat-view/chat-input/ModelSelect.tsx +++ b/src/components/chat-view/chat-input/ModelSelect.tsx @@ -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(null) const providers = GetAllProviders() @@ -189,138 +190,289 @@ export function ModelSelect() { }, [searchableItems, searchTerm, fuse]) return ( - - -
- {isOpen ? : } -
-
- [{modelProvider}] {chatModelId} -
-
- - - -
- - {modelIds.length > 0 ? ( - { - 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 - } - }} - /> - ) : ( - { - setSearchTerm(e.target.value) - }} - onKeyDown={(e) => { - if (e.key === "Enter") { - e.preventDefault() - setSettings({ - ...settings, - chatModelProvider: modelProvider, - chatModelId: searchTerm, - }) - setChatModelId(searchTerm) - setIsOpen(false) - } - }} - /> - )} + <> + + +
+ {isOpen ? : }
-
    - {isLoading ? ( -
  • Loading...
  • - ) : ( - filteredOptions.map((option, index) => ( - { - setSettings({ - ...settings, - chatModelProvider: modelProvider, - chatModelId: option.id, - }) - setChatModelId(option.id) +
    + [{modelProvider}] {chatModelId} +
    + + + + +
    +
    + +
    + {modelIds.length > 0 ? ( +
    + { + 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 + } + }} + /> +
    + ) : ( + { + 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) + } + }} + /> + )} +
    +
      + {isLoading ? ( +
    • Loading...
    • + ) : ( + filteredOptions.map((option, index) => ( + { + 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 + > +
    • +
      + +
      +
    • +
      + )) + )} +
    +
    +
    + + + ) } diff --git a/src/components/chat-view/chat-input/plugins/command/CommandPlugin.tsx b/src/components/chat-view/chat-input/plugins/command/CommandPlugin.tsx index bbf60c4..ceb7695 100644 --- a/src/components/chat-view/chat-input/plugins/command/CommandPlugin.tsx +++ b/src/components/chat-view/chat-input/plugins/command/CommandPlugin.tsx @@ -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} > -
    -
    {option.name}
    +
    +
    + {' '} + {option.name} +
    ) @@ -157,7 +160,7 @@ export default function CommandPlugin() { anchorElementRef.current && searchResults.length ? createPortal(