🚀 feat: enhance UI components and refactor settings (#6625)

* 🚀 feat: Add Save Badges State functionality to chat settings

* 🚀 feat: Remove individual chat setting components and introduce a reusable ToggleSwitch component

* 🚀 feat: Replace Switches with reusable ToggleSwitch component in General settings; style: improved HoverCard

* 🚀 feat: Refactor ChatForm and Footer components for improved layout and state management

* 🚀 feat: Add deprecation warning for GPT Plugins endpoint

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Marco Beretta 2025-04-01 09:15:41 +02:00 committed by GitHub
parent 14ff66b2c3
commit a5154e1349
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 227 additions and 350 deletions

View file

@ -56,7 +56,6 @@ export default function Footer({ className }: { className?: string }) {
<React.Fragment key={`main-content-part-${index}`}>
<ReactMarkdown
components={{
a: ({ node: _n, href, children, ...otherProps }) => {
return (
<a
@ -87,7 +86,7 @@ export default function Footer({ className }: { className?: string }) {
<div
className={
className ??
'relative hidden items-center justify-center gap-2 px-2 py-2 text-center text-xs text-text-primary sm:flex md:px-[60px]'
'absolute bottom-0 left-0 right-0 hidden items-center justify-center gap-2 px-2 py-2 text-center text-xs text-text-primary sm:flex md:px-[60px]'
}
role="contentinfo"
>

View file

@ -43,12 +43,13 @@ const ChatForm = memo(({ index = 0 }: { index?: number }) => {
const [isTextAreaFocused, setIsTextAreaFocused] = useState(false);
const [backupBadges, setBackupBadges] = useState<Pick<BadgeItem, 'id'>[]>([]);
const isSearching = useRecoilValue(store.isSearching);
const SpeechToText = useRecoilValue(store.speechToText);
const TextToSpeech = useRecoilValue(store.textToSpeech);
const chatDirection = useRecoilValue(store.chatDirection);
const automaticPlayback = useRecoilValue(store.automaticPlayback);
const maximizeChatSpace = useRecoilValue(store.maximizeChatSpace);
const chatDirection = useRecoilValue(store.chatDirection);
const isSearching = useRecoilValue(store.isSearching);
const centerFormOnLanding = useRecoilValue(store.centerFormOnLanding);
const [badges, setBadges] = useRecoilState(store.chatBadges);
const [isEditingBadges, setIsEditingBadges] = useRecoilState(store.isEditingBadges);
@ -190,8 +191,9 @@ const ChatForm = memo(({ index = 0 }: { index?: number }) => {
<form
onSubmit={methods.handleSubmit(submitMessage)}
className={cn(
'mx-auto flex flex-row gap-3 transition-all duration-200 sm:mb-2 sm:px-2',
'mx-auto flex flex-row gap-3 transition-all duration-200 sm:px-2',
maximizeChatSpace ? 'w-full max-w-full' : 'md:max-w-3xl xl:max-w-4xl',
centerFormOnLanding ? 'sm:mb-28' : 'sm:mb-10',
)}
>
<div className="relative flex h-full flex-1 items-stretch md:flex-col">
@ -217,7 +219,7 @@ const ChatForm = memo(({ index = 0 }: { index?: number }) => {
<div
onClick={handleContainerClick}
className={cn(
'relative flex w-full flex-grow flex-col overflow-hidden rounded-t-3xl border border-border-light bg-surface-chat pb-4 text-text-primary transition-all duration-200 sm:rounded-3xl sm:pb-0',
'relative flex w-full flex-grow flex-col overflow-hidden rounded-t-3xl border border-border-medium bg-surface-chat pb-4 text-text-primary transition-all duration-200 sm:rounded-3xl sm:pb-0',
isTextAreaFocused ? 'shadow-lg' : 'shadow-md',
)}
>

View file

@ -1,11 +1,11 @@
import { useMemo } from 'react';
import { SettingsIcon } from 'lucide-react';
import { Spinner } from '~/components';
import { EModelEndpoint, isAgentsEndpoint, isAssistantsEndpoint } from 'librechat-data-provider';
import type { Endpoint } from '~/common';
import { CustomMenu as Menu, CustomMenuItem as MenuItem } from '../CustomMenu';
import { useModelSelectorContext } from '../ModelSelectorContext';
import { renderEndpointModels } from './EndpointModelItem';
import { TooltipAnchor, Spinner } from '~/components';
import { filterModels } from '../utils';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
@ -84,6 +84,18 @@ export function EndpointItem({ endpoint }: EndpointItemProps) {
>
{endpoint.label}
</span>
{/* TODO: remove this after deprecation */}
{endpoint.value === 'gptPlugins' && (
<TooltipAnchor
description={localize('com_endpoint_deprecated_info')}
aria-label={localize('com_endpoint_deprecated_info_a11y')}
render={
<span className="ml-2 rounded bg-amber-600/70 px-2 py-0.5 text-xs font-semibold text-white">
{localize('com_endpoint_deprecated')}
</span>
}
/>
)}
</div>
);