mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-31 23:58:50 +01:00
💡 style: switched to Ariakit's tooltip (#3748)
* inital Tooltip implementation and test * style(tooltip): L/R sidePanel and Nav * style(tooltip): unarchive button; refactor: `useArchiveHandler` and `ArchiveButton` * style(tooltip): Delete button * refactor: remove unused className prop in DeleteButton component * style(tooltip): finish final tooltip and fix bookmark edit and delete button * refactor(ui): remove TooltipTest and DropDownMenu component and unused imports * style: update mobile UI * fix: sidePanel icon not showing * feat(AttachFile): add tooltip * fix(NavToggle): remove button without this button, kb users don't have to manually press 2 times to change the focus Also, tooltips with buttons focus don't trigger * fix: right side panel issue with double button * fix: merge issues * fix: sharedLink table issue * chore: update ariakit and framer-motion version * a11y: kb toggle for sidebar * feat: tooltip for some buttons
This commit is contained in:
parent
e293ff63f9
commit
4ef5ae6f71
37 changed files with 747 additions and 967 deletions
|
|
@ -1,87 +0,0 @@
|
|||
import React from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import type { MouseEvent, FocusEvent, KeyboardEvent } from 'react';
|
||||
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '~/components/ui';
|
||||
import { useConversations, useLocalize, useNewConvo } from '~/hooks';
|
||||
import { useArchiveConversationMutation } from '~/data-provider';
|
||||
import { NotificationSeverity } from '~/common';
|
||||
import { useToastContext } from '~/Providers';
|
||||
|
||||
type ArchiveButtonProps = {
|
||||
children?: React.ReactNode;
|
||||
conversationId: string;
|
||||
retainView: () => void;
|
||||
shouldArchive: boolean;
|
||||
icon?: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function useArchiveHandler(
|
||||
conversationId: string,
|
||||
shouldArchive: boolean,
|
||||
retainView: () => void,
|
||||
) {
|
||||
const localize = useLocalize();
|
||||
const navigate = useNavigate();
|
||||
const { showToast } = useToastContext();
|
||||
const { newConversation } = useNewConvo();
|
||||
const { refreshConversations } = useConversations();
|
||||
const { conversationId: currentConvoId } = useParams();
|
||||
|
||||
const archiveConvoMutation = useArchiveConversationMutation(conversationId);
|
||||
|
||||
return async (e?: MouseEvent | FocusEvent | KeyboardEvent) => {
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
const label = shouldArchive ? 'archive' : 'unarchive';
|
||||
archiveConvoMutation.mutate(
|
||||
{ conversationId, isArchived: shouldArchive },
|
||||
{
|
||||
onSuccess: () => {
|
||||
if (currentConvoId === conversationId || currentConvoId === 'new') {
|
||||
newConversation();
|
||||
navigate('/c/new', { replace: true });
|
||||
}
|
||||
refreshConversations();
|
||||
retainView();
|
||||
},
|
||||
onError: () => {
|
||||
showToast({
|
||||
message: localize(`com_ui_${label}_error`),
|
||||
severity: NotificationSeverity.ERROR,
|
||||
showIcon: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export default function ArchiveButton({
|
||||
conversationId,
|
||||
retainView,
|
||||
shouldArchive,
|
||||
icon,
|
||||
className = '',
|
||||
}: ArchiveButtonProps) {
|
||||
const localize = useLocalize();
|
||||
const archiveHandler = useArchiveHandler(conversationId, shouldArchive, retainView);
|
||||
|
||||
return (
|
||||
<button type="button" className={className} onClick={archiveHandler}>
|
||||
<TooltipProvider delayDuration={250}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="h-5 w-5">{icon}</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={0}>
|
||||
{localize(`com_ui_${shouldArchive ? 'archive' : 'unarchive'}`)}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export { useArchiveHandler as archiveHandler };
|
||||
|
|
@ -2,11 +2,10 @@ import { useState, useId } from 'react';
|
|||
import * as Ariakit from '@ariakit/react';
|
||||
import { Ellipsis, Share2, Archive, Pen, Trash } from 'lucide-react';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import { useArchiveHandler } from './ArchiveButton';
|
||||
import { useLocalize, useArchiveHandler } from '~/hooks';
|
||||
import { DropdownPopup } from '~/components/ui';
|
||||
import DeleteButton from './DeleteButton';
|
||||
import ShareButton from './ShareButton';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
export default function ConvoOptions({
|
||||
|
|
|
|||
|
|
@ -4,15 +4,7 @@ import { useQueryClient } from '@tanstack/react-query';
|
|||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import type { TMessage } from 'librechat-data-provider';
|
||||
import { useDeleteConversationMutation } from '~/data-provider';
|
||||
import {
|
||||
OGDialog,
|
||||
OGDialogTrigger,
|
||||
Label,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from '~/components/ui';
|
||||
import { OGDialog, OGDialogTrigger, Label, TooltipAnchor } from '~/components/ui';
|
||||
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
|
||||
import { TrashIcon } from '~/components/svg';
|
||||
import { useLocalize, useNewConvo } from '~/hooks';
|
||||
|
|
@ -21,7 +13,6 @@ type DeleteButtonProps = {
|
|||
conversationId: string;
|
||||
retainView: () => void;
|
||||
title: string;
|
||||
className?: string;
|
||||
showDeleteDialog?: boolean;
|
||||
setShowDeleteDialog?: (value: boolean) => void;
|
||||
};
|
||||
|
|
@ -30,7 +21,6 @@ export default function DeleteButton({
|
|||
conversationId,
|
||||
retainView,
|
||||
title,
|
||||
className = '',
|
||||
showDeleteDialog,
|
||||
setShowDeleteDialog,
|
||||
}: DeleteButtonProps) {
|
||||
|
|
@ -92,20 +82,13 @@ export default function DeleteButton({
|
|||
|
||||
return (
|
||||
<OGDialog open={open} onOpenChange={setOpen}>
|
||||
<TooltipProvider delayDuration={250}>
|
||||
<Tooltip>
|
||||
<OGDialogTrigger asChild>
|
||||
<TooltipTrigger asChild>
|
||||
<button>
|
||||
<TrashIcon className="h-5 w-5" />
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
</OGDialogTrigger>
|
||||
<TooltipContent side="top" sideOffset={0} className={className}>
|
||||
{localize('com_ui_delete')}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
<TooltipAnchor description={localize('com_ui_delete')}>
|
||||
<OGDialogTrigger asChild>
|
||||
<button>
|
||||
<TrashIcon className="h-5 w-5" />
|
||||
</button>
|
||||
</OGDialogTrigger>
|
||||
</TooltipAnchor>
|
||||
{dialogContent}
|
||||
</OGDialog>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
export { default as ArchiveButton } from './ArchiveButton';
|
||||
export { default as DeleteButton } from './DeleteButton';
|
||||
export { default as ShareButton } from './ShareButton';
|
||||
export { default as SharedLinkButton } from './SharedLinkButton';
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
import { cloneElement, type FC } from 'react';
|
||||
import { DotsIcon } from '~/components/svg';
|
||||
import { Content, Portal, Root, Trigger } from '@radix-ui/react-popover';
|
||||
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '~/components/ui';
|
||||
import { useToggle } from './ToggleContext';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
type DropDownMenuProps = {
|
||||
children: React.ReactNode;
|
||||
icon?: React.ReactElement;
|
||||
tooltip?: string;
|
||||
className?: string;
|
||||
};
|
||||
const DropDownMenu: FC<DropDownMenuProps> = ({
|
||||
children,
|
||||
icon = <DotsIcon />,
|
||||
tooltip = 'More',
|
||||
className,
|
||||
}: DropDownMenuProps) => {
|
||||
const localize = useLocalize();
|
||||
const { isPopoverActive, setPopoverActive } = useToggle();
|
||||
|
||||
return (
|
||||
<Root open={isPopoverActive} onOpenChange={(open) => setPopoverActive(open)}>
|
||||
<Trigger asChild>
|
||||
<div
|
||||
className={cn(
|
||||
'pointer-cursor relative flex flex-col text-left focus:outline-none focus:ring-0 focus:ring-offset-0 sm:text-sm',
|
||||
'hover:text-gray-400 radix-state-open:text-gray-400 dark:hover:text-gray-400 dark:radix-state-open:text-gray-400',
|
||||
'z-50 flex h-[40px] min-w-4 flex-none items-center justify-center focus:ring-0 focus:ring-offset-0',
|
||||
)}
|
||||
id="edit-menu-button"
|
||||
data-testid="edit-menu-button"
|
||||
title={localize('com_ui_more_options')}
|
||||
>
|
||||
<TooltipProvider delayDuration={500}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button type="button" className={className}>
|
||||
{cloneElement(icon, {
|
||||
className:
|
||||
'h-[18px] w-[18px] flex-shrink-0 text-gray-500 hover:text-gray-400 dark:text-gray-300 dark:hover:text-gray-400',
|
||||
})}
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="top" sideOffset={0}>
|
||||
{tooltip}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
</Trigger>
|
||||
<Portal>
|
||||
<Content
|
||||
side="bottom"
|
||||
align="start"
|
||||
className={cn(
|
||||
'popover radix-side-bottom:animate-slideUpAndFade radix-side-left:animate-slideRightAndFade radix-side-right:animate-slideLeftAndFade radix-side-top:animate-slideDownAndFade overflow-hidden rounded-lg shadow-lg',
|
||||
'border border-gray-200 bg-white dark:border-gray-600 dark:bg-gray-700 dark:text-white',
|
||||
'flex min-w-[200px] max-w-xs flex-wrap',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</Content>
|
||||
</Portal>
|
||||
</Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropDownMenu;
|
||||
Loading…
Add table
Add a link
Reference in a new issue