feat(侧边栏): 集成消息搜索入口

- 添加搜索入口按钮显示快捷键提示
- 支持全局快捷键 ⌘K / Ctrl+K 打开搜索
- 集成 SearchModal 搜索弹框组件
This commit is contained in:
gaoziman 2025-12-24 22:50:45 +08:00
parent 236b368537
commit 57e8631e10

View File

@ -2,14 +2,15 @@
import Link from 'next/link'; import Link from 'next/link';
import { usePathname, useRouter } from 'next/navigation'; import { usePathname, useRouter } from 'next/navigation';
import { Plus, PanelLeft, Trash2, MoreHorizontal, Loader2, Pencil, Check, X, Bot, Bookmark } from 'lucide-react'; import { Plus, PanelLeft, Trash2, MoreHorizontal, Loader2, Pencil, Check, X, Bot, Bookmark, Search } from 'lucide-react';
import { UserMenu } from '@/components/ui/UserMenu'; import { UserMenu } from '@/components/ui/UserMenu';
import { NewChatModal } from '@/components/features/NewChatModal'; import { NewChatModal } from '@/components/features/NewChatModal';
import { SearchModal } from '@/components/features/SearchModal';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { useConversations } from '@/hooks/useConversations'; import { useConversations } from '@/hooks/useConversations';
import { useAuth } from '@/providers/AuthProvider'; import { useAuth } from '@/providers/AuthProvider';
import type { Conversation } from '@/drizzle/schema'; import type { Conversation } from '@/drizzle/schema';
import { useState, useRef, useEffect } from 'react'; import { useState, useRef, useEffect, useCallback } from 'react';
interface SidebarProps { interface SidebarProps {
isOpen?: boolean; isOpen?: boolean;
@ -26,6 +27,7 @@ export function Sidebar({ isOpen = true }: SidebarProps) {
const [editingTitle, setEditingTitle] = useState(''); const [editingTitle, setEditingTitle] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const [showNewChatModal, setShowNewChatModal] = useState(false); const [showNewChatModal, setShowNewChatModal] = useState(false);
const [showSearchModal, setShowSearchModal] = useState(false);
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const menuRef = useRef<HTMLDivElement>(null); const menuRef = useRef<HTMLDivElement>(null);
@ -52,6 +54,22 @@ export function Sidebar({ isOpen = true }: SidebarProps) {
}; };
}, [menuOpen]); }, [menuOpen]);
// 全局键盘快捷键⌘K / Ctrl+K 打开搜索
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
// ⌘K (Mac) 或 Ctrl+K (Windows/Linux)
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
setShowSearchModal(true);
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, []);
// 创建新对话 - 显示选择助手弹框 // 创建新对话 - 显示选择助手弹框
const handleNewChat = () => { const handleNewChat = () => {
setShowNewChatModal(true); setShowNewChatModal(true);
@ -142,6 +160,21 @@ export function Sidebar({ isOpen = true }: SidebarProps) {
</button> </button>
</div> </div>
{/* 搜索入口按钮 */}
<div className="px-3 pb-3">
<button
onClick={() => setShowSearchModal(true)}
className="w-full flex items-center gap-2.5 px-3 py-2.5 bg-[var(--color-bg-tertiary)] border border-[var(--color-border-light)] rounded text-[var(--color-text-tertiary)] text-sm hover:bg-[var(--color-bg-hover)] hover:border-[var(--color-border)] hover:text-[var(--color-text-secondary)] transition-all"
>
<Search size={16} className="flex-shrink-0" />
<span className="flex-1 text-left">...</span>
<span className="flex items-center gap-0.5 text-[11px]">
<kbd className="inline-flex items-center justify-center px-1.5 py-0.5 bg-[var(--color-bg-primary)] border border-[var(--color-border)] rounded text-[10px] shadow-sm"></kbd>
<kbd className="inline-flex items-center justify-center px-1.5 py-0.5 bg-[var(--color-bg-primary)] border border-[var(--color-border)] rounded text-[10px] shadow-sm">K</kbd>
</span>
</button>
</div>
{/* 助手库入口 */} {/* 助手库入口 */}
<div className="px-4 pb-2"> <div className="px-4 pb-2">
<Link <Link
@ -319,6 +352,12 @@ export function Sidebar({ isOpen = true }: SidebarProps) {
isOpen={showNewChatModal} isOpen={showNewChatModal}
onClose={() => setShowNewChatModal(false)} onClose={() => setShowNewChatModal(false)}
/> />
{/* 搜索弹框 */}
<SearchModal
isOpen={showSearchModal}
onClose={() => setShowSearchModal(false)}
/>
</> </>
); );
} }