{
    "name": "ai-modal-selector",
    "title": "Modal Selector",
    "description": "AI-focused model selector with preview, tooltips, and capability indicators built-in",
    "type": "registry:ui",
    "dependencies": ["gsap", "@gsap/react"],
    "registryDependencies": ["@paceui-gsap/swap", "button"],
    "files": [
        {
            "path": "components/gsap/ai-modal-selector.tsx",
            "type": "registry:ui",
            "target": "~/components/gsap/ai-modal-selector.tsx",
            "content": "\"use client\";\n\nimport { ComponentProps, ReactNode, useMemo, useState } from \"react\";\n\nimport {\n    BrainIcon,\n    CodeIcon,\n    EyeIcon,\n    FileSearch2Icon,\n    LanguagesIcon,\n    LayersIcon,\n    SpeechIcon,\n    VariableIcon,\n    VideoIcon,\n    Wand2Icon,\n    WrenchIcon,\n} from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport { Swap } from \"@/components/gsap/swap\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n    DropdownMenu,\n    DropdownMenuContent,\n    DropdownMenuItem,\n    DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"@/components/ui/tooltip\";\n\ntype ModalCapability =\n    | \"vision\"\n    | \"thinking\"\n    | \"code\"\n    | \"speech\"\n    | \"search\"\n    | \"tools\"\n    | \"multimodal\"\n    | \"video\"\n    | \"math\"\n    | \"multilingual\"\n    | \"creativity\";\n\nexport type ModalOption = {\n    value: string;\n    image: string;\n    name: string;\n    darkInvertImage?: boolean;\n    description: string;\n    capabilities: ModalCapability[];\n};\n\ntype ModalSelectorProps = ComponentProps<typeof Button> & {\n    showCapabilities?: boolean;\n    showDescription?: boolean;\n};\n\nconst modals: ModalOption[] = [\n    {\n        value: \"openai-gpt-4o\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/openai.svg\",\n        name: \"GPT-4o\",\n        darkInvertImage: true,\n        description: \"Omni model supporting seamless text, audio, and vision integration.\",\n        capabilities: [\"vision\", \"code\", \"speech\", \"tools\", \"multimodal\"],\n    },\n    {\n        value: \"google-gemini-2-0-pro\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/gemini-color.svg\",\n        name: \"Gemini 2.0 Pro\",\n        description: \"Next-generation performance with ultra-long context windows.\",\n        capabilities: [\"vision\", \"thinking\", \"speech\", \"tools\", \"video\"],\n    },\n    {\n        value: \"anthropic-claude-3-5-sonnet\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/claude-color.svg\",\n        name: \"Claude 3.5 Sonnet\",\n        description: \"Industry-leading intelligence with a focus on coding and nuance.\",\n        capabilities: [\"thinking\", \"code\", \"vision\", \"tools\"],\n    },\n    {\n        value: \"xai-grok-3\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/grok.svg\",\n        name: \"Grok-3\",\n        darkInvertImage: true,\n        description: \"Real-time information processing with enhanced logical reasoning.\",\n        capabilities: [\"thinking\", \"search\", \"code\"],\n    },\n    {\n        value: \"deepseek-v3\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/deepseek-color.svg\",\n        name: \"DeepSeek-V3\",\n        description: \"High-performance Mixture-of-Experts model for advanced logic.\",\n        capabilities: [\"thinking\", \"code\", \"math\"],\n    },\n    {\n        value: \"meta-llama-3-1-405b\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/meta-color.svg\",\n        name: \"Llama 3.1 (405B)\",\n        description: \"The premier open-source model for complex reasoning and scale.\",\n        capabilities: [\"thinking\", \"code\", \"tools\"],\n    },\n    {\n        value: \"mistral-large-latest\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/mistral-color.svg\",\n        name: \"Mistral Large\",\n        description: \"European powerhouse optimized for multilingual reasoning.\",\n        capabilities: [\"thinking\", \"code\", \"multilingual\"],\n    },\n    {\n        value: \"stability-sd3-ultra\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/stability-color.svg\",\n        name: \"Stable Diffusion 3 Ultra\",\n        description: \"State-of-the-art text-to-image with superior prompt adherence.\",\n        capabilities: [\"vision\", \"creativity\"],\n    },\n    {\n        value: \"midjourney-v6-1\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/midjourney.svg\",\n        name: \"Midjourney v6.1\",\n        darkInvertImage: true,\n        description: \"Highly aesthetic and photorealistic image generation.\",\n        capabilities: [\"vision\", \"creativity\"],\n    },\n    {\n        value: \"perplexity-sonar-pro\",\n        image: \"https://unpkg.com/@lobehub/icons-static-svg@latest/icons/perplexity-color.svg\",\n        name: \"Sonar Pro\",\n        description: \"Search-centric model designed for cited, real-time factual answers.\",\n        capabilities: [\"search\", \"thinking\"],\n    },\n];\n\nconst CapabilityBadge = ({ capability }: { capability: ModalCapability }) => {\n    const styles: Record<ModalCapability, { color: string; text: string; icon: ReactNode }> = {\n        thinking: {\n            color: \"bg-purple-500/10 hover:bg-purple-500/20 text-purple-500\",\n            text: \"Thinking\",\n            icon: <BrainIcon className=\"size-4.5\" />,\n        },\n        code: {\n            color: \"bg-cyan-500/10 hover:bg-cyan-500/20 text-cyan-500\",\n            text: \"Code\",\n            icon: <CodeIcon className=\"size-4.5\" />,\n        },\n        vision: {\n            color: \"bg-green-500/10 hover:bg-green-500/20 text-green-500\",\n            text: \"Vision\",\n            icon: <EyeIcon className=\"size-4.5\" />,\n        },\n        creativity: {\n            color: \"bg-orange-500/10 hover:bg-orange-500/20 text-orange-500\",\n            text: \"Creativity\",\n            icon: <Wand2Icon className=\"size-4.5\" />,\n        },\n        search: {\n            color: \"bg-teal-500/10 hover:bg-teal-500/20 text-teal-500\",\n            text: \"Search\",\n            icon: <FileSearch2Icon className=\"size-4.5\" />,\n        },\n        speech: {\n            color: \"bg-pink-500/10 hover:bg-pink-500/20 text-pink-500\",\n            text: \"Speech\",\n            icon: <SpeechIcon className=\"size-4.5\" />,\n        },\n        tools: {\n            color: \"bg-blue-500/10 hover:bg-blue-500/20 text-blue-500\",\n            text: \"Tools\",\n            icon: <WrenchIcon className=\"size-4.5\" />,\n        },\n        video: {\n            color: \"bg-rose-500/10 hover:bg-rose-500/20 text-rose-500\",\n            text: \"Video\",\n            icon: <VideoIcon className=\"size-4.5\" />,\n        },\n        multilingual: {\n            color: \"bg-amber-500/10 hover:bg-amber-500/20 text-amber-500\",\n            text: \"Global\",\n            icon: <LanguagesIcon className=\"size-4.5\" />,\n        },\n        multimodal: {\n            color: \"bg-indigo-500/10 hover:bg-indigo-500/20 text-indigo-500\",\n            text: \"Multimodal\",\n            icon: <LayersIcon className=\"size-4.5\" />,\n        },\n        math: {\n            color: \"bg-slate-500/10 hover:bg-slate-500/20 text-slate-500\",\n            text: \"Math\",\n            icon: <VariableIcon className=\"size-4.5\" />,\n        },\n    };\n\n    const defaultStyle = {\n        color: \"bg-purple-500/10 hover:bg-purple-500/20 text-purple-500\",\n        text: \"Thinking\",\n        icon: <BrainIcon className=\"size-4.5\" />,\n    };\n\n    const { color, text, icon } = styles[capability] ?? defaultStyle;\n\n    return (\n        <Tooltip>\n            <TooltipTrigger render={<div className={cn(\"rounded p-1\", color)}>{icon}</div>}></TooltipTrigger>\n            <TooltipContent>\n                <p>{text}</p>\n            </TooltipContent>\n        </Tooltip>\n    );\n};\n\nexport const AiModalSelector = ({\n    showDescription = true,\n    showCapabilities = true,\n    variant = \"outline\",\n    className,\n    ...props\n}: ModalSelectorProps) => {\n    const [selectedModal, setSelectedModal] = useState(modals[0].value);\n\n    const selectedModalItem = useMemo(() => {\n        return modals.find((item) => item.value === selectedModal) ?? modals[0];\n    }, [selectedModal]);\n\n    return (\n        <TooltipProvider>\n            <DropdownMenu>\n                <DropdownMenuTrigger\n                    render={\n                        <Button\n                            {...props}\n                            variant={variant}\n                            className={cn(\"cursor-pointer overflow-hidden shadow-none select-none\", className)}>\n                            <Swap state={selectedModalItem} effects={[\"blur\", \"slideDown\", \"opacity\"]}>\n                                {(state) => (\n                                    <div className=\"flex items-center gap-2.5\">\n                                        <img\n                                            src={state.image}\n                                            className={cn(\"min-w-4.5\", { \"dark:invert\": state.darkInvertImage })}\n                                            alt={`${state.name} logo`}\n                                        />\n                                        <p className=\"text-base overflow-ellipsis\">{state.name}</p>\n                                        {showCapabilities && (\n                                            <div className=\"flex items-center gap-1.5\">\n                                                {state.capabilities.map((capability) => (\n                                                    <CapabilityBadge capability={capability} key={capability} />\n                                                ))}\n                                            </div>\n                                        )}\n                                    </div>\n                                )}\n                            </Swap>\n                        </Button>\n                    }></DropdownMenuTrigger>\n                <DropdownMenuContent className=\"w-80 shadow-xs transition-all hover:shadow-md\" align=\"start\">\n                    <ScrollArea className=\"h-80\">\n                        <div className=\"space-y-0.5\">\n                            {modals.map((item) => (\n                                <DropdownMenuItem\n                                    key={item.value}\n                                    onClick={() => setSelectedModal(item.value)}\n                                    className={cn(\"group relative cursor-pointer gap-3\", {\n                                        \"bg-accent\": selectedModal === item.value,\n                                    })}>\n                                    <img\n                                        src={item.image}\n                                        alt={`${item.name} logo`}\n                                        className={cn(\"size-6\", {\n                                            \"dark:invert\": item.darkInvertImage,\n                                        })}\n                                    />\n                                    <div className=\"grow\">\n                                        <div className=\"flex items-center gap-2\">\n                                            <p className=\"grow text-base/none font-medium\">{item.name}</p>\n                                        </div>\n                                        {showDescription && (\n                                            <p className=\"text-muted-foreground mt-0.5 line-clamp-1\">\n                                                {item.description}\n                                            </p>\n                                        )}\n                                    </div>\n                                    {showCapabilities && (\n                                        <div className=\"absolute end-0 flex translate-x-5 scale-90 items-center gap-1.5 rounded bg-inherit px-2.5 py-1 opacity-0 transition-all duration-300 group-hover:translate-x-0 group-hover:scale-100 group-hover:opacity-100\">\n                                            {item.capabilities.map((capability) => (\n                                                <CapabilityBadge capability={capability} key={capability} />\n                                            ))}\n                                        </div>\n                                    )}\n                                </DropdownMenuItem>\n                            ))}\n                        </div>\n                    </ScrollArea>\n                </DropdownMenuContent>\n            </DropdownMenu>\n        </TooltipProvider>\n    );\n};\n"
        }
    ]
}
