"use client" import React, { useState, useEffect, forwardRef, useImperativeHandle } from "react" import { Input } from "@/components/ui/input" import { motion, AnimatePresence } from "framer-motion" import { Search, Send, BarChart2, Globe, Video, PlaneTakeoff, AudioLines } from "lucide-react" import useDebounce from "@/hooks/use-debounce" interface Action { id: string label: string icon: React.ReactNode description?: string short?: string end?: string } interface SearchResult { actions: Action[] } const allActions = [ { id: "1", label: "Book tickets", icon: , description: "Operator", short: "⌘K", end: "Agent", }, { id: "2", label: "Summarize", icon: , description: "gpt-4o", short: "⌘cmd+p", end: "Command", }, { id: "3", label: "Screen Studio", icon: , description: "gpt-4o", short: "", end: "Application", }, { id: "4", label: "Talk to Jarvis", icon: , description: "gpt-4o voice", short: "", end: "Active", }, { id: "5", label: "Translate", icon: , description: "gpt-4o", short: "", end: "Command", }, ] interface ActionSearchBarProps { actions?: Action[] autoFocus?: boolean isFloating?: boolean } const ActionSearchBar = forwardRef( ({ actions = allActions, autoFocus = false, isFloating = false }, ref) => { const [query, setQuery] = useState("") const [result, setResult] = useState(null) const [isFocused, setIsFocused] = useState(autoFocus) const [selectedAction, setSelectedAction] = useState(null) const debouncedQuery = useDebounce(query, 200) const inputRef = React.useRef(null) useImperativeHandle(ref, () => inputRef.current as HTMLInputElement) useEffect(() => { if (autoFocus && inputRef.current) { inputRef.current.focus() } }, [autoFocus]) useEffect(() => { if (!debouncedQuery) { setResult({ actions: allActions }) return } const normalizedQuery = debouncedQuery.toLowerCase().trim() const filteredActions = allActions.filter((action) => { const searchableText = action.label.toLowerCase() return searchableText.includes(normalizedQuery) }) setResult({ actions: filteredActions }) }, [debouncedQuery]) const handleInputChange = (e: React.ChangeEvent) => { setQuery(e.target.value) } const container = { hidden: { opacity: 0, height: 0 }, show: { opacity: 1, height: "auto", transition: { height: { duration: 0.4, }, staggerChildren: 0.1, }, }, exit: { opacity: 0, height: 0, transition: { height: { duration: 0.3, }, opacity: { duration: 0.2, }, }, }, } const item = { hidden: { opacity: 0, y: 20 }, show: { opacity: 1, y: 0, transition: { duration: 0.3, }, }, exit: { opacity: 0, y: -10, transition: { duration: 0.2, }, }, } return ( setIsFocused(true)} onBlur={() => !isFloating && setTimeout(() => setIsFocused(false), 200)} className="pl-3 pr-9 py-1.5 h-9 text-sm rounded-lg focus-visible:ring-offset-0" /> {query.length > 0 ? ( ) : ( )} {(isFocused || isFloating) && result && !selectedAction && ( {result.actions.map((action) => ( setSelectedAction(action)} > {action.icon} {action.label} {action.description} {action.short} {action.end} ))} Press ⌘K to open commands ESC to cancel )} ) }, ) ActionSearchBar.displayName = "ActionSearchBar" export default ActionSearchBar