import { Box, Button, Divider, Flex, IconButton, Menu, MenuButton, MenuItem, MenuList, Text, useDisclosure, useOutsideClick, } from '@chakra-ui/react'; import { ChevronDown, Copy, RefreshCcw, Settings } from 'lucide-react'; import { observer } from 'mobx-react-lite'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useIsMobile as useIsMobileUserAgent } from '../../../hooks/_IsMobileHook'; import clientChatStore from '../../../stores/ClientChatStore'; import { useIsMobile } from '../../contexts/MobileContext'; import { formatConversationMarkdown } from '../lib/exportConversationAsMarkdown'; import FlyoutSubMenu from './FlyoutSubMenu'; export const MsM_commonButtonStyles = { bg: 'transparent', color: 'text.primary', borderRadius: 'full', padding: 2, border: 'none', _hover: { bg: 'rgba(255, 255, 255, 0.2)' }, _active: { bg: 'rgba(255, 255, 255, 0.3)' }, _focus: { boxShadow: 'none' }, }; const InputMenu: React.FC<{ isDisabled?: boolean }> = observer(({ isDisabled }) => { const isMobile = useIsMobile(); const isMobileUserAgent = useIsMobileUserAgent(); const { isOpen, onOpen, onClose, onToggle, getDisclosureProps, getButtonProps } = useDisclosure(); const [controlledOpen, setControlledOpen] = useState(false); const [supportedModels, setSupportedModels] = useState([]); useEffect(() => { setControlledOpen(isOpen); }, [isOpen]); useEffect(() => { fetch('/api/models') .then(response => response.json()) .then(models => { setSupportedModels(models); }) .catch(err => { console.error('Could not fetch models: ', err); }); }, []); const handleClose = useCallback(() => { onClose(); }, [isOpen]); const handleCopyConversation = useCallback(() => { navigator.clipboard .writeText(formatConversationMarkdown(clientChatStore.items)) .then(() => { window.alert('Conversation copied to clipboard. \n\nPaste it somewhere safe!'); onClose(); }) .catch(err => { console.error('Could not copy text to clipboard: ', err); window.alert('Failed to copy conversation. Please try again.'); }); }, [onClose]); async function selectModelFn({ name, value }) { clientChatStore.setModel(value); } function isSelectedModelFn({ name, value }) { return clientChatStore.model === value; } const menuRef = useRef(); const [menuState, setMenuState] = useState(); useOutsideClick({ enabled: !isMobile && isOpen, ref: menuRef, handler: () => { handleClose(); }, }); return ( {isMobile ? ( } isDisabled={isDisabled} aria-label="Settings" _hover={{ bg: 'rgba(255, 255, 255, 0.2)' }} _focus={{ boxShadow: 'none' }} {...MsM_commonButtonStyles} /> ) : ( } isDisabled={isDisabled} variant="ghost" display="flex" justifyContent="space-between" alignItems="center" minW="auto" {...MsM_commonButtonStyles} > {clientChatStore.model} )} ({ name: modelData.id.split('/').pop() || modelData.id, value: modelData.id, }))} onClose={onClose} parentIsOpen={isOpen} setMenuState={setMenuState} handleSelect={selectModelFn} isSelected={isSelectedModelFn} /> {/*Export conversation button*/} Export {/*New conversation button*/} { clientChatStore.setActiveConversation('conversation:new'); onClose(); }} _hover={{ bg: 'rgba(0, 0, 0, 0.05)' }} _focus={{ bg: 'rgba(0, 0, 0, 0.1)' }} > New ); }); export default InputMenu;