diff --git a/src/components/FloatingPromptInput.tsx b/src/components/FloatingPromptInput.tsx index eeedaf6..1681909 100644 --- a/src/components/FloatingPromptInput.tsx +++ b/src/components/FloatingPromptInput.tsx @@ -7,12 +7,14 @@ import { ChevronUp, Sparkles, Zap, - Square + Square, + Brain } from "lucide-react"; import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { Popover } from "@/components/ui/popover"; import { Textarea } from "@/components/ui/textarea"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { FilePicker } from "./FilePicker"; import { ImagePreview } from "./ImagePreview"; import { type FileEntry } from "@/lib/api"; @@ -53,6 +55,78 @@ export interface FloatingPromptInputRef { addImage: (imagePath: string) => void; } +/** + * Thinking mode type definition + */ +type ThinkingMode = "auto" | "think" | "think_hard" | "think_harder" | "ultrathink"; + +/** + * Thinking mode configuration + */ +type ThinkingModeConfig = { + id: ThinkingMode; + name: string; + description: string; + level: number; // 0-4 for visual indicator + phrase?: string; // The phrase to append +}; + +const THINKING_MODES: ThinkingModeConfig[] = [ + { + id: "auto", + name: "Auto", + description: "Let Claude decide", + level: 0 + }, + { + id: "think", + name: "Think", + description: "Basic reasoning", + level: 1, + phrase: "think" + }, + { + id: "think_hard", + name: "Think Hard", + description: "Deeper analysis", + level: 2, + phrase: "think hard" + }, + { + id: "think_harder", + name: "Think Harder", + description: "Extensive reasoning", + level: 3, + phrase: "think harder" + }, + { + id: "ultrathink", + name: "Ultrathink", + description: "Maximum computation", + level: 4, + phrase: "ultrathink" + } +]; + +/** + * ThinkingModeIndicator component - Shows visual indicator bars for thinking level + */ +const ThinkingModeIndicator: React.FC<{ level: number }> = ({ level }) => { + return ( +
+ {[1, 2, 3, 4].map((i) => ( +
+ ))} +
+ ); +}; + type Model = { id: "sonnet" | "opus"; name: string; @@ -100,8 +174,10 @@ const FloatingPromptInputInner = ( ) => { const [prompt, setPrompt] = useState(""); const [selectedModel, setSelectedModel] = useState<"sonnet" | "opus">(defaultModel); + const [selectedThinkingMode, setSelectedThinkingMode] = useState("auto"); const [isExpanded, setIsExpanded] = useState(false); const [modelPickerOpen, setModelPickerOpen] = useState(false); + const [thinkingModePickerOpen, setThinkingModePickerOpen] = useState(false); const [showFilePicker, setShowFilePicker] = useState(false); const [filePickerQuery, setFilePickerQuery] = useState(""); const [cursorPosition, setCursorPosition] = useState(0); @@ -260,7 +336,15 @@ const FloatingPromptInputInner = ( const handleSend = () => { if (prompt.trim() && !isLoading && !disabled) { - onSend(prompt.trim(), selectedModel); + let finalPrompt = prompt.trim(); + + // Append thinking phrase if not auto mode + const thinkingMode = THINKING_MODES.find(m => m.id === selectedThinkingMode); + if (thinkingMode && thinkingMode.phrase) { + finalPrompt = `${finalPrompt}\n\n${thinkingMode.phrase}.`; + } + + onSend(finalPrompt, selectedModel); setPrompt(""); setEmbeddedImages([]); } @@ -440,17 +524,81 @@ const FloatingPromptInputInner = ( />
-
- Model: - +
+
+ Model: + +
+ +
+ Thinking: + + + + + + +

{THINKING_MODES.find(m => m.id === selectedThinkingMode)?.name || "Auto"}

+

{THINKING_MODES.find(m => m.id === selectedThinkingMode)?.description}

+
+
+ + } + content={ +
+ {THINKING_MODES.map((mode) => ( + + ))} +
+ } + open={thinkingModePickerOpen} + onOpenChange={setThinkingModePickerOpen} + align="start" + side="top" + /> +
+ + +

{THINKING_MODES.find(m => m.id === selectedThinkingMode)?.name || "Auto"}

+

{THINKING_MODES.find(m => m.id === selectedThinkingMode)?.description}

+
+ + + } + content={ +
+ {THINKING_MODES.map((mode) => ( + + ))} +
+ } + open={thinkingModePickerOpen} + onOpenChange={setThinkingModePickerOpen} + align="start" + side="top" + /> + {/* Prompt Input */}