mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-15 06:58:51 +01:00
🪟 fix+feat: General UI Enhancements (#2619)
* feat: Minor design changes to mimic OpenAI's latest login page * fix: Optimize ThemeSelector for mobile * fix: Use a svg for the logo for transperency in dark mode * feat: Update styles for Registration * feat: Update error colors for login & registration * fix: remove medium font * wip: Dropdown menu * feat: Update dropdown to match ChatGPT * feat: Improve rounding and padding * feat: Add UI Updates to RequestPasswordReset, PasswordRest and increase width for theme dropdown * fix: Modify the My Files modal's width to not touch the screen * feat: fix scrolling for dropdown, and make border width lighter * feat: Match popup menu design to OpenAI (p1/2) * fix+feat: fix dark mode, add user email, add lighter borders * fix: Add border color on focus of chat input. * feat: Move Export Conversation to a seperate button (testing) * fix: Properly center Login, Registration, Reset Password Flow * fix: Border colors on dark mode for settings modal * feat: Improve wording for settings menu * fix: Optimize settings modal for mobile and fix height for modal * feat: Optimize for desktop * fix: make TooltipTrigger asChild of button, improve settings mobile responsiveness * feat: Handle dropdowns properly TODO: Make height dynamic, fix dark mode colors * fix: input styles fix: make endpoint icon smaller * feat: Update UI to Match ChatGPT Style - Updated the dropdown styles to match the aesthetic of ChatGPT. - Decreased spacing within the conversation area for cleanliness. - Replaced the current archive icon with the ChatGPT's icon. * fix: fix colors for EditMenuButton & ArchiveButton for dark mode and light mode * fix: ui fixes * fix: Fix Conversation UI Bugs * fix: transparency of HoverToggle to make buttons not visible * fix: dark mode HoverToggle & compress menu item spacing * fix: responsiveness of export icon * fix: first mentionitem is set to always be highlighted * fix: improve hover state to text instead of bg * feat: Update icons to ChatGPT Style * fix: dark mode hover for PanelFileCell * fix: change navlinks z-index to 100 * fix: hover states for DataTable * feat: Move ExportButton to seperate component * chore: remove unused imports
This commit is contained in:
parent
d73ea8e1f2
commit
8f20fb28e5
43 changed files with 716 additions and 469 deletions
71
client/src/components/Chat/ExportButton.tsx
Normal file
71
client/src/components/Chat/ExportButton.tsx
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import React from 'react';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import type { TConversation } from 'librechat-data-provider';
|
||||
import { Download } from 'lucide-react';
|
||||
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '~/components/ui';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { ExportModal } from '../Nav';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import store from '~/store';
|
||||
|
||||
function ExportButton() {
|
||||
const localize = useLocalize();
|
||||
const location = useLocation();
|
||||
|
||||
const [showExports, setShowExports] = useState(false);
|
||||
|
||||
const activeConvo = useRecoilValue(store.conversationByIndex(0));
|
||||
const globalConvo = useRecoilValue(store.conversation) ?? ({} as TConversation);
|
||||
|
||||
let conversation: TConversation | null | undefined;
|
||||
if (location.state?.from?.pathname.includes('/chat')) {
|
||||
conversation = globalConvo;
|
||||
} else {
|
||||
conversation = activeConvo;
|
||||
}
|
||||
|
||||
const clickHandler = () => {
|
||||
if (exportable) {
|
||||
setShowExports(true);
|
||||
}
|
||||
};
|
||||
|
||||
const exportable =
|
||||
conversation &&
|
||||
conversation.conversationId &&
|
||||
conversation.conversationId !== 'new' &&
|
||||
conversation.conversationId !== 'search';
|
||||
|
||||
return (
|
||||
<>
|
||||
{exportable && (
|
||||
<div className="flex gap-1 gap-2 pr-1">
|
||||
<TooltipProvider delayDuration={50}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<button
|
||||
className="btn btn-neutral btn-small relative flex h-9 w-9 items-center justify-center whitespace-nowrap rounded-lg"
|
||||
onClick={clickHandler}
|
||||
>
|
||||
<div className="flex w-full items-center justify-center gap-2">
|
||||
<Download size={16} />
|
||||
</div>
|
||||
</button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right" sideOffset={5}>
|
||||
{localize('com_nav_export_conversation')}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
</div>
|
||||
)}
|
||||
{showExports && (
|
||||
<ExportModal open={showExports} onOpenChange={setShowExports} conversation={conversation} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ExportButton;
|
||||
|
|
@ -5,6 +5,7 @@ import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
|||
import type { ContextType } from '~/common';
|
||||
import { EndpointsMenu, ModelSpecsMenu, PresetsMenu, HeaderNewChat } from './Menus';
|
||||
import HeaderOptions from './Input/HeaderOptions';
|
||||
import ExportButton from './ExportButton';
|
||||
|
||||
const defaultInterface = getConfigDefaults().interface;
|
||||
|
||||
|
|
@ -19,12 +20,15 @@ export default function Header() {
|
|||
|
||||
return (
|
||||
<div className="sticky top-0 z-10 flex h-14 w-full items-center justify-between bg-white p-2 font-semibold dark:bg-gray-800 dark:text-white">
|
||||
<div className="hide-scrollbar flex items-center gap-2 overflow-x-auto">
|
||||
{!navVisible && <HeaderNewChat />}
|
||||
{interfaceConfig.endpointsMenu && <EndpointsMenu />}
|
||||
{modelSpecs?.length > 0 && <ModelSpecsMenu modelSpecs={modelSpecs} />}
|
||||
{<HeaderOptions interfaceConfig={interfaceConfig} />}
|
||||
{interfaceConfig.presets && <PresetsMenu />}
|
||||
<div className="hide-scrollbar flex w-full items-center justify-between gap-2 overflow-x-auto">
|
||||
<div className="flex items-center gap-2">
|
||||
{!navVisible && <HeaderNewChat />}
|
||||
{interfaceConfig.endpointsMenu && <EndpointsMenu />}
|
||||
{modelSpecs?.length > 0 && <ModelSpecsMenu modelSpecs={modelSpecs} />}
|
||||
{<HeaderOptions interfaceConfig={interfaceConfig} />}
|
||||
{interfaceConfig.presets && <PresetsMenu />}
|
||||
</div>
|
||||
<ExportButton />
|
||||
</div>
|
||||
{/* Empty div for spacing */}
|
||||
<div />
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ const ChatForm = ({ index = 0 }) => {
|
|||
{showMentionPopover && (
|
||||
<Mention setShowMentionPopover={setShowMentionPopover} textAreaRef={textAreaRef} />
|
||||
)}
|
||||
<div className="[&:has(textarea:focus)]:border-token-border-xheavy border-token-border-medium bg-token-main-surface-primary relative flex w-full flex-grow flex-col overflow-hidden rounded-2xl border dark:border-gray-600 dark:text-white [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)] dark:[&:has(textarea:focus)]:border-gray-500">
|
||||
<div className="bg-token-main-surface-primary relative flex w-full flex-grow flex-col overflow-hidden rounded-2xl border dark:border-gray-600 dark:text-white [&:has(textarea:focus)]:border-gray-300 [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)] dark:[&:has(textarea:focus)]:border-gray-500">
|
||||
<FileRow
|
||||
files={files}
|
||||
setFiles={setFiles}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ export default function Files({ open, onOpenChange }) {
|
|||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className={cn('overflow-x-auto shadow-2xl dark:bg-gray-700 dark:text-white')}>
|
||||
<DialogContent
|
||||
className={cn('w-11/12 overflow-x-auto shadow-2xl dark:bg-gray-700 dark:text-white')}
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-lg font-medium leading-6 text-gray-900 dark:text-gray-200">
|
||||
{localize('com_nav_my_files')}
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ export default function DataTable<TData, TValue>({ columns, data }: DataTablePro
|
|||
)}
|
||||
</div>
|
||||
<Button
|
||||
className="dark:border-gray-500"
|
||||
className="dark:border-gray-500 dark:hover:bg-gray-600"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.previousPage()}
|
||||
|
|
@ -229,7 +229,7 @@ export default function DataTable<TData, TValue>({ columns, data }: DataTablePro
|
|||
{localize('com_ui_prev')}
|
||||
</Button>
|
||||
<Button
|
||||
className="dark:border-gray-500"
|
||||
className="dark:border-gray-500 dark:hover:bg-gray-600"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => table.nextPage()}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ export default function MentionItem({
|
|||
<div
|
||||
className={cn(
|
||||
'hover:bg-token-main-surface-secondary text-token-text-primary bg-token-main-surface-secondary group flex h-10 items-center gap-2 rounded-lg px-2 text-sm font-medium dark:hover:bg-gray-600',
|
||||
index === 0 ? 'dark:bg-gray-600' : '',
|
||||
isActive ? 'dark:bg-gray-600' : '',
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export default function OptionsPopover({
|
|||
{presetsDisabled ? null : (
|
||||
<Button
|
||||
type="button"
|
||||
className="h-auto w-[150px] justify-start rounded-md border-2 border-gray-300/50 bg-transparent px-2 py-1 text-xs font-medium font-normal text-black hover:bg-gray-100 hover:text-black focus:ring-1 focus:ring-green-500/90 dark:border-gray-500/50 dark:bg-transparent dark:text-white dark:hover:bg-gray-600 dark:focus:ring-green-500"
|
||||
className="h-auto w-[150px] justify-start rounded-md border border-gray-300/50 bg-transparent px-2 py-1 text-xs font-medium font-normal text-black hover:bg-gray-100 hover:text-black focus:ring-1 focus:ring-green-500/90 dark:border-gray-500/50 dark:bg-transparent dark:text-white dark:hover:bg-gray-600 dark:focus:ring-green-500"
|
||||
onClick={saveAsPreset}
|
||||
>
|
||||
<Save className="mr-1 w-[14px]" />
|
||||
|
|
|
|||
|
|
@ -44,12 +44,7 @@ export default function Landing({ Header }: { Header?: ReactNode }) {
|
|||
<div className="relative h-full">
|
||||
<div className="absolute left-0 right-0">{Header && Header}</div>
|
||||
<div className="flex h-full flex-col items-center justify-center">
|
||||
<div
|
||||
className={cn(
|
||||
'relative h-[72px] w-[72px]',
|
||||
assistantName && avatar ? 'mb-0' : 'mb-3',
|
||||
)}
|
||||
>
|
||||
<div className={cn('relative h-12 w-12', assistantName && avatar ? 'mb-0' : 'mb-3')}>
|
||||
<ConvoIcon
|
||||
conversation={conversation}
|
||||
assistantMap={assistantMap}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ const MenuItem: FC<MenuItemProps> = ({
|
|||
'invisible flex gap-x-1 group-hover:visible',
|
||||
selected ? 'visible' : '',
|
||||
expiryTime
|
||||
? 'w-full rounded-lg p-2 hover:bg-gray-200 dark:hover:bg-gray-600'
|
||||
? 'w-full rounded-lg p-2 hover:text-gray-400 dark:hover:text-gray-400'
|
||||
: '',
|
||||
)}
|
||||
onClick={(e) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue