feat: add @ file mention support in chat input and unify directory attachment

Support typing "@" in the chat input to trigger a file list popup with
filtering, keyboard navigation, and file/directory attachment. Directories
from the sidebar file tree now attach as resource links instead of injecting
text into the input.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xintaofei
2026-04-02 22:43:27 +08:00
parent e87f930ec1
commit 9396127cd9
6 changed files with 379 additions and 158 deletions

View File

@@ -0,0 +1,62 @@
"use client"
import { useEffect, useRef } from "react"
import { File, Folder } from "lucide-react"
import { cn } from "@/lib/utils"
import type { FlatFileEntry } from "@/hooks/use-file-tree"
interface FileMentionMenuProps {
files: FlatFileEntry[]
selectedIndex: number
onSelect: (entry: FlatFileEntry) => void
}
export function FileMentionMenu({
files,
selectedIndex,
onSelect,
}: FileMentionMenuProps) {
const listRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const el = listRef.current?.children[selectedIndex] as
| HTMLElement
| undefined
el?.scrollIntoView({ block: "nearest" })
}, [selectedIndex])
if (files.length === 0) return null
return (
<div
ref={listRef}
className="absolute bottom-full left-0 right-0 z-50 mb-1 max-h-48 overflow-y-auto rounded-xl border border-border bg-popover p-1 shadow-lg"
>
{files.map((entry, i) => (
<button
key={entry.relativePath}
type="button"
className={cn(
"flex w-full items-center gap-2 rounded-lg px-3 py-1.5 text-left text-sm",
i === selectedIndex
? "bg-accent text-accent-foreground"
: "hover:bg-muted"
)}
onMouseDown={(e) => {
e.preventDefault()
onSelect(entry)
}}
>
{entry.kind === "dir" ? (
<Folder className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
) : (
<File className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
)}
<span className="truncate font-mono text-xs">
{entry.relativePath}
</span>
</button>
))}
</div>
)
}