diff --git a/src/components/chat-view/ChatView.tsx b/src/components/chat-view/ChatView.tsx index 8764bc5..1b09093 100644 --- a/src/components/chat-view/ChatView.tsx +++ b/src/components/chat-view/ChatView.tsx @@ -56,7 +56,6 @@ import { PromptGenerator, addLineNumbers } from '../../utils/prompt-generator' // Removed empty line above, added one below for group separation import { fetchUrlsContent, onEnt, webSearch } from '../../utils/web-search' -import { ModeSelect } from './chat-input/ModeSelect'; // Start of new group import PromptInputWithActions, { ChatUserInputRef } from './chat-input/PromptInputWithActions' import { editorStateToPlainText } from './chat-input/utils/editor-state-to-plain-text' import ChatHistoryView from './ChatHistoryView' @@ -986,7 +985,7 @@ const Chat = forwardRef((props, ref) => {
{/* header view */}
- + INFIO
) } diff --git a/src/components/chat-view/chat-input/ModeSelect.tsx b/src/components/chat-view/chat-input/ModeSelect.tsx index d14a788..dc17bb3 100644 --- a/src/components/chat-view/chat-input/ModeSelect.tsx +++ b/src/components/chat-view/chat-input/ModeSelect.tsx @@ -1,5 +1,5 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu' -import { ChevronDown, ChevronUp } from 'lucide-react' +import { ChevronDown, ChevronUp, MessageSquare, SquarePen, Search } from 'lucide-react' import { useEffect, useMemo, useState } from 'react' import { useSettings } from '../../../contexts/SettingsContext' @@ -21,39 +21,178 @@ export function ModeSelect() { setMode(settings.mode) }, [settings.mode]) - return ( - - -
- {isOpen ? : } -
-
- {allModes.find((m) => m.slug === mode)?.name} -
-
+ // 为默认模式定义快捷键提示 + const getShortcutText = (slug: string) => { + switch (slug) { + case 'write': + return 'Cmd+Shift+.' + case 'ask': + return 'Cmd+Shift+,' + case 'research': + return 'Cmd+Shift+/' + default: + return null + } + } - - -
    - {allModes.map((mode) => ( - { - setMode(mode.slug) - setSettings({ - ...settings, - mode: mode.slug, - }) - }} - asChild - > -
  • {mode.name}
  • -
    - ))} -
-
-
-
+ // 为默认模式定义图标 + const getModeIcon = (slug: string) => { + switch (slug) { + case 'ask': + return + case 'write': + return + case 'research': + return + default: + return null + } + } + + + return ( + <> + + + {getModeIcon(mode)} +
+ {allModes.find((m) => m.slug === mode)?.name} +
+
+ {isOpen ? : } +
+
+ + + +
    + {allModes.map((mode) => { + const shortcut = getShortcutText(mode.slug) + const icon = getModeIcon(mode.slug) + + return ( + { + setMode(mode.slug) + setSettings({ + ...settings, + mode: mode.slug, + }) + }} + asChild + > +
  • +
    + {icon && ( + {icon} + )} + {mode.name} +
    + {shortcut && ( + {shortcut} + )} +
  • +
    + ) + })} +
+
+
+
+ + ) } diff --git a/src/components/chat-view/chat-input/ModelSelect.tsx b/src/components/chat-view/chat-input/ModelSelect.tsx index 98331dc..53da8f7 100644 --- a/src/components/chat-view/chat-input/ModelSelect.tsx +++ b/src/components/chat-view/chat-input/ModelSelect.tsx @@ -1,6 +1,6 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu' import Fuse, { FuseResult } from 'fuse.js' -import { ChevronDown, ChevronUp, Star, StarOff } from 'lucide-react' +import { Brain, ChevronDown, ChevronUp, Star } from 'lucide-react' import { useEffect, useMemo, useRef, useState } from 'react' import { useSettings } from '../../../contexts/SettingsContext' @@ -8,6 +8,34 @@ import { t } from '../../../lang/helpers' import { ApiProvider } from '../../../types/llm/model' import { GetAllProviders, GetProviderModelIds } from "../../../utils/api" +// 优化模型名称显示的函数 +const getOptimizedModelName = (modelId: string): string => { + if (!modelId) return modelId; + + // 移除常见的前缀 + let optimized = modelId + .replace(/^(anthropic\/|openai\/|google\/|meta\/|microsoft\/|huggingface\/|mistral\/|cohere\/|ai21\/|together\/|perplexity\/|groq\/|deepseek\/|qwen\/|alibaba\/|baichuan\/|chatglm\/|yi\/|moonshot\/|zhipu\/|minimax\/|sensetime\/|iflytek\/|tencent\/|baidu\/|bytedance\/|netease\/|360\/|xunfei\/|spark\/|ernie\/|wenxin\/|tongyi\/|claude\/|gpt-|llama-|gemini-|palm-|bard-|codex-|davinci-|curie-|babbage-|ada-)/i, '') + // 移除版本号和日期 + .replace(/(-v?\d+(\.\d+)*(-\w+)?|:\d+(\.\d+)*|@\d+(\.\d+)*|-\d{4}-\d{2}-\d{2}|-\d{8}|-latest|-preview|-beta|-alpha|-rc\d*|-instruct|-chat|-base|-turbo|-16k|-32k|-128k)$/i, '') + // 移除多余的连字符和下划线 + .replace(/[-_]+/g, '-') + .replace(/^-+|-+$/g, ''); + + // 如果优化后的名称太短或为空,返回原始名称的简化版本 + if (optimized.length < 3) { + // 尝试提取主要部分 + const parts = modelId.split(/[\/\-_:@]/); + optimized = parts.find(part => part.length >= 3) || modelId; + } + + // 限制长度,如果太长则截断并添加省略号 + if (optimized.length > 25) { + optimized = optimized.substring(0, 22) + '...'; + } + + return optimized; +}; + type TextSegment = { text: string; isHighlighted: boolean; @@ -187,12 +215,12 @@ export function ModelSelect() { const fuse = useMemo(() => { return new Fuse(searchableItems, { keys: ["html"], - threshold: 0.6, + threshold: 1, shouldSort: true, isCaseSensitive: false, ignoreLocation: false, includeMatches: true, - minMatchCharLength: 1, + minMatchCharLength: 2, }) }, [searchableItems]) @@ -243,12 +271,18 @@ export function ModelSelect() { <> + {/*
+ +
*/} +
+ {getOptimizedModelName(chatModelId)} +
{isOpen ? : }
-
- {chatModelId} -
@@ -283,7 +317,7 @@ export function ModelSelect() { >
{collectedModel.provider} - {collectedModel.modelId} + {getOptimizedModelName(collectedModel.modelId)}
- + {searchTerm ? ( + + ) : ( + {getOptimizedModelName(option.id)} + )}
void } @@ -68,6 +68,7 @@ const PromptInputWithActions = forwardRef( ref, ) => { const app = useApp() + const { settings, setSettings } = useSettings() const editorRef = useRef(null) const contentEditableRef = useRef(null) @@ -83,6 +84,50 @@ const PromptInputWithActions = forwardRef( } }, [addedBlockKey]) + // 添加快捷键监听器 + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + // 检查是否按下了 Cmd + Shift 键 (macOS) + if (event.ctrlKey && event.shiftKey) { + // 使用 event.key 直接匹配,不使用 toLowerCase() + switch (event.key) { + case '.': + case '>': // Shift + . 在某些键盘布局下可能是 > + event.preventDefault() + setSettings({ + ...settings, + mode: 'write', + }) + break + case ',': + case '<': // Shift + , 在某些键盘布局下可能是 < + event.preventDefault() + setSettings({ + ...settings, + mode: 'ask', + }) + break + case '/': + case '?': // Shift + / 在某些键盘布局下可能是 ? + event.preventDefault() + setSettings({ + ...settings, + mode: 'research', + }) + break + } + } + } + + // 添加事件监听器到 document + document.addEventListener('keydown', handleKeyDown) + + // 清理函数 + return () => { + document.removeEventListener('keydown', handleKeyDown) + } + }, [settings, setSettings]) + useImperativeHandle(ref, () => ({ focus: () => { contentEditableRef.current?.focus() @@ -278,10 +323,11 @@ const PromptInputWithActions = forwardRef(
+ -
+ handleSubmit()} />
diff --git a/src/components/chat-view/chat-input/SubmitButton.tsx b/src/components/chat-view/chat-input/SubmitButton.tsx index 6d321d5..f5dea1e 100644 --- a/src/components/chat-view/chat-input/SubmitButton.tsx +++ b/src/components/chat-view/chat-input/SubmitButton.tsx @@ -1,14 +1,53 @@ -import { CornerDownLeftIcon } from 'lucide-react' +import { ArrowUpIcon } from 'lucide-react' -import { t } from '../../../lang/helpers' +// import { t } from '../../../lang/helpers' export function SubmitButton({ onClick }: { onClick: () => void }) { - return ( - - ) + return ( + <> + + + + + ) } diff --git a/styles.css b/styles.css index 3f851e5..67afa8e 100644 --- a/styles.css +++ b/styles.css @@ -331,7 +331,7 @@ button:not(.clickable-icon).infio-chat-list-dropdown { .infio-chat-user-input-controls__buttons { flex-shrink: 0; display: flex; - gap: var(--size-4-2); + gap: var(--size-4-3); align-items: center; } } @@ -1894,19 +1894,32 @@ select.infio-ai-block-model-select::-ms-expand { button.infio-chat-input-model-select { background-color: transparent; box-shadow: none; - border: 0; - padding: 0; + border: 1; + padding: var(--size-2-1) var(--size-2-2); font-size: var(--font-smallest); font-weight: var(--font-medium); color: var(--text-muted); + display: flex; justify-content: flex-start; align-items: center; cursor: pointer; height: var(--size-4-4); max-width: 100%; + gap: var(--size-2-2); + border-radius: var(--radius-s); + transition: all 0.15s ease-in-out; &:hover { color: var(--text-normal); + background-color: var(--background-modifier-hover); + } + + .infio-chat-input-model-select__mode-icon { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-accent); } .infio-chat-input-model-select__model-name { @@ -1914,6 +1927,7 @@ button.infio-chat-input-model-select { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + flex-grow: 1; } .infio-chat-input-model-select__icon { @@ -1921,6 +1935,7 @@ button.infio-chat-input-model-select { display: flex; align-items: center; justify-content: center; + margin-left: auto; } } @@ -2418,4 +2433,3 @@ button.infio-chat-input-model-select { max-width: 80vw; max-height: 80vh; } -