| | import { useState, useId, useRef } from 'react'; |
| | import { useRecoilValue } from 'recoil'; |
| | import * as Ariakit from '@ariakit/react'; |
| | import { Upload, Share2 } from 'lucide-react'; |
| | import { DropdownPopup, TooltipAnchor, useMediaQuery } from '@librechat/client'; |
| | import type * as t from '~/common'; |
| | import ExportModal from '~/components/Nav/ExportConversation/ExportModal'; |
| | import { ShareButton } from '~/components/Conversations/ConvoOptions'; |
| | import { useLocalize } from '~/hooks'; |
| | import store from '~/store'; |
| |
|
| | export default function ExportAndShareMenu({ |
| | isSharedButtonEnabled, |
| | }: { |
| | isSharedButtonEnabled: boolean; |
| | }) { |
| | const localize = useLocalize(); |
| | const [showExports, setShowExports] = useState(false); |
| | const [isPopoverActive, setIsPopoverActive] = useState(false); |
| | const [showShareDialog, setShowShareDialog] = useState(false); |
| |
|
| | const menuId = useId(); |
| | const shareButtonRef = useRef<HTMLButtonElement>(null); |
| | const exportButtonRef = useRef<HTMLButtonElement>(null); |
| | const isSmallScreen = useMediaQuery('(max-width: 768px)'); |
| | const conversation = useRecoilValue(store.conversationByIndex(0)); |
| |
|
| | const exportable = |
| | conversation && |
| | conversation.conversationId != null && |
| | conversation.conversationId !== 'new' && |
| | conversation.conversationId !== 'search'; |
| |
|
| | if (exportable === false) { |
| | return null; |
| | } |
| |
|
| | const shareHandler = () => { |
| | setShowShareDialog(true); |
| | }; |
| |
|
| | const exportHandler = () => { |
| | setShowExports(true); |
| | }; |
| |
|
| | const dropdownItems: t.MenuItemProps[] = [ |
| | { |
| | label: localize('com_ui_share'), |
| | onClick: shareHandler, |
| | icon: <Share2 className="icon-md mr-2 text-text-secondary" />, |
| | show: isSharedButtonEnabled, |
| | |
| | hideOnClick: false, |
| | ref: shareButtonRef, |
| | render: (props) => <button {...props} />, |
| | }, |
| | { |
| | label: localize('com_endpoint_export'), |
| | onClick: exportHandler, |
| | icon: <Upload className="icon-md mr-2 text-text-secondary" />, |
| | |
| | hideOnClick: false, |
| | ref: exportButtonRef, |
| | render: (props) => <button {...props} />, |
| | }, |
| | ]; |
| |
|
| | return ( |
| | <> |
| | <DropdownPopup |
| | portal={true} |
| | menuId={menuId} |
| | focusLoop={true} |
| | unmountOnHide={true} |
| | isOpen={isPopoverActive} |
| | setIsOpen={setIsPopoverActive} |
| | trigger={ |
| | <TooltipAnchor |
| | description={localize('com_endpoint_export_share')} |
| | render={ |
| | <Ariakit.MenuButton |
| | id="export-menu-button" |
| | aria-label="Export options" |
| | className="inline-flex size-10 flex-shrink-0 items-center justify-center rounded-xl border border-border-light bg-transparent text-text-primary transition-all ease-in-out hover:bg-surface-tertiary disabled:pointer-events-none disabled:opacity-50 radix-state-open:bg-surface-tertiary" |
| | > |
| | <Share2 |
| | className="icon-md text-text-secondary" |
| | aria-hidden="true" |
| | focusable="false" |
| | /> |
| | </Ariakit.MenuButton> |
| | } |
| | /> |
| | } |
| | items={dropdownItems} |
| | className={isSmallScreen ? '' : 'absolute right-0 top-0 mt-2'} |
| | /> |
| | <ExportModal |
| | open={showExports} |
| | onOpenChange={setShowExports} |
| | conversation={conversation} |
| | triggerRef={exportButtonRef} |
| | aria-label={localize('com_ui_export_convo_modal')} |
| | /> |
| | <ShareButton |
| | triggerRef={shareButtonRef} |
| | conversationId={conversation.conversationId ?? ''} |
| | open={showShareDialog} |
| | onOpenChange={setShowShareDialog} |
| | /> |
| | </> |
| | ); |
| | } |
| |
|