| 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} |
| /> |
| </> |
| ); |
| } |
|
|