feat(25-08): wire VoiceRecordButton into ChatInput and mark INPUT-02/03/04 complete
- Add enableVoiceInput prop to ChatInput props interface
- Add handleTranscription callback that appends transcription text to textarea state
- Render VoiceRecordButton conditionally when enableVoiceInput is true
- Pass enableVoiceInput={true} from ChatPanel to ChatInput
- Mark INPUT-02, INPUT-03, INPUT-04 as Complete in REQUIREMENTS.md traceability table
This commit is contained in:
parent
64a90c284e
commit
dea5ea2bb7
3 changed files with 25 additions and 7 deletions
|
|
@ -30,9 +30,9 @@
|
|||
### Input (7)
|
||||
|
||||
- [x] **INPUT-01** — Multi-line text input with auto-resize: grows with content up to a max height before scrolling
|
||||
- [ ] **INPUT-02** — File/image upload via drag-and-drop or button with inline preview before sending
|
||||
- [ ] **INPUT-03** — Paste image from clipboard directly into the chat input
|
||||
- [ ] **INPUT-04** — Voice input via Whisper (when local AI is enabled): record button with transcription preview before sending
|
||||
- [x] **INPUT-02** — File/image upload via drag-and-drop or button with inline preview before sending
|
||||
- [x] **INPUT-03** — Paste image from clipboard directly into the chat input
|
||||
- [x] **INPUT-04** — Voice input via Whisper (when local AI is enabled): record button with transcription preview before sending
|
||||
- [x] **INPUT-05** — Slash commands: `/brainstorm`, `/ask-pm`, `/ask-engineer`, `/task`, `/search`
|
||||
- [x] **INPUT-06** — `@mention` agents: type `@engineer` to route a message to a specific agent
|
||||
- [x] **INPUT-07** — Keyboard shortcuts: Enter to send, Shift+Enter for newline, Cmd+K for search, Escape to cancel
|
||||
|
|
@ -133,9 +133,9 @@ The following are explicitly deferred:
|
|||
| CHAT-13 | Phase 24 | Complete |
|
||||
| CHAT-14 | Phase 24 | Complete |
|
||||
| INPUT-01 | Phase 21 | Complete |
|
||||
| INPUT-02 | Phase 25 | Pending |
|
||||
| INPUT-03 | Phase 25 | Pending |
|
||||
| INPUT-04 | Phase 25 | Pending |
|
||||
| INPUT-02 | Phase 25 | Complete |
|
||||
| INPUT-03 | Phase 25 | Complete |
|
||||
| INPUT-04 | Phase 25 | Complete |
|
||||
| INPUT-05 | Phase 22 | Complete |
|
||||
| INPUT-06 | Phase 22 | Complete |
|
||||
| INPUT-07 | Phase 21 | Complete |
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Send, Loader2, Paperclip, X } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { ChatSlashCommandPopover } from "./ChatSlashCommandPopover";
|
||||
import { ChatMentionPopover } from "./ChatMentionPopover";
|
||||
import { ChatFileDropZone } from "./ChatFileDropZone";
|
||||
import { VoiceRecordButton } from "./VoiceRecordButton";
|
||||
import { cn } from "../lib/utils";
|
||||
import type { Agent } from "@paperclipai/shared";
|
||||
import type { PendingFile } from "../hooks/useChatFileUpload";
|
||||
|
|
@ -20,6 +21,8 @@ interface ChatInputProps {
|
|||
onFilesPicked?: (files: File[]) => void;
|
||||
pendingFiles?: PendingFile[];
|
||||
onRemoveFile?: (id: string) => void;
|
||||
// Voice input support
|
||||
enableVoiceInput?: boolean;
|
||||
}
|
||||
|
||||
export function ChatInput({
|
||||
|
|
@ -32,6 +35,7 @@ export function ChatInput({
|
|||
onFilesPicked,
|
||||
pendingFiles,
|
||||
onRemoveFile,
|
||||
enableVoiceInput = false,
|
||||
}: ChatInputProps) {
|
||||
const [value, setValue] = useState("");
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
|
@ -100,6 +104,11 @@ export function ChatInput({
|
|||
textareaRef.current?.focus();
|
||||
}
|
||||
|
||||
const handleTranscription = useCallback((text: string) => {
|
||||
setValue((current) => (current ? `${current} ${text}` : text));
|
||||
textareaRef.current?.focus();
|
||||
}, []);
|
||||
|
||||
function handleKeyDown(e: React.KeyboardEvent<HTMLTextAreaElement>) {
|
||||
if (e.key === "Escape") {
|
||||
if (slashOpen) {
|
||||
|
|
@ -232,6 +241,14 @@ export function ChatInput({
|
|||
</Button>
|
||||
</label>
|
||||
|
||||
{/* Voice input button */}
|
||||
{enableVoiceInput && (
|
||||
<VoiceRecordButton
|
||||
onTranscription={handleTranscription}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="ghost"
|
||||
|
|
|
|||
|
|
@ -388,6 +388,7 @@ export function ChatPanel() {
|
|||
pendingFiles={pendingFiles}
|
||||
onRemoveFile={removeFile}
|
||||
onFilesPicked={(files) => files.forEach(addFile)}
|
||||
enableVoiceInput={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue