"use client" import { useEffect, useRef, useState } from "react" import { AnimatePresence, motion } from "motion/react" import { cn } from "@lib/utils" import { Button } from "@ui/components/button" import { dmSansClassName } from "@/lib/fonts" import { CheckIcon, ChevronDownIcon } from "lucide-react" import { models, type ModelId, modelNames } from "@/lib/models" import { analytics } from "@/lib/analytics" interface ChatModelSelectorProps { selectedModel?: ModelId onModelChange?: (model: ModelId) => void /** Compact pill matching inline send control. */ minimal?: boolean dropdownDirection?: "up" | "down" } export default function ChatModelSelector({ selectedModel: selectedModelProp, onModelChange, minimal = false, dropdownDirection = "up", }: ChatModelSelectorProps = {}) { const [internalModel, setInternalModel] = useState("claude-sonnet-5") const [isOpen, setIsOpen] = useState(false) const containerRef = useRef(null) useEffect(() => { if (!isOpen) return const handleClickOutside = (e: MouseEvent) => { if ( containerRef.current && !containerRef.current.contains(e.target as Node) ) { setIsOpen(false) } } document.addEventListener("mousedown", handleClickOutside) return () => document.removeEventListener("mousedown", handleClickOutside) }, [isOpen]) const selectedModel = selectedModelProp ?? internalModel const currentModelData = modelNames[selectedModel] const selectedModelLabel = `${currentModelData.name} ${currentModelData.version}` const selectedItemClass = "bg-white/[0.06] text-white" const handleModelSelect = (modelId: ModelId) => { if (onModelChange) { onModelChange(modelId) } else { setInternalModel(modelId) } analytics.modelChanged({ model: modelId }) setIsOpen(false) } const trigger = minimal ? ( ) : ( ) return (
{trigger} {isOpen && (
{models.map((model) => { const modelData = modelNames[model.id] const isSelected = selectedModel === model.id return ( ) })}
)}
) }