mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-31 23:58:50 +01:00
💡 feat: Improve Reasoning Content UI, copy-to-clipboard, and error handling (#10278)
* ✨ feat: Refactor error handling and improve loading states in MessageContent component * ✨ feat: Enhance Thinking and ContentParts components with improved hover functionality and clipboard support * fix: Adjust padding in Thinking and ContentParts components for consistent layout * ✨ feat: Add response label and improve message editing UI with contextual indicators * ✨ feat: Add isEditing prop to Feedback and Fork components for improved editing state handling * refactor: Remove isEditing prop from Feedback and Fork components for cleaner state management * refactor: Migrate state management from Recoil to Jotai for font size and show thinking features * refactor: Separate ToggleSwitch into RecoilToggle and JotaiToggle components for improved clarity and state management * refactor: Remove unnecessary comments in ToggleSwitch and MessageContent components for cleaner code * chore: reorder import statements in Thinking.tsx * chore: reorder import statement in EditTextPart.tsx * chore: reorder import statement * chore: Reorganize imports in ToggleSwitch.tsx --------- Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
ea45d0b9c6
commit
c0f1cfcaba
13 changed files with 528 additions and 186 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import { memo } from 'react';
|
||||
import { showThinkingAtom } from '~/store/showThinking';
|
||||
import FontSizeSelector from './FontSizeSelector';
|
||||
import { ForkSettings } from './ForkSettings';
|
||||
import ChatDirection from './ChatDirection';
|
||||
|
|
@ -28,7 +29,7 @@ const toggleSwitchConfigs = [
|
|||
key: 'centerFormOnLanding',
|
||||
},
|
||||
{
|
||||
stateAtom: store.showThinking,
|
||||
stateAtom: showThinkingAtom,
|
||||
localizationKey: 'com_nav_show_thinking',
|
||||
switchId: 'showThinking',
|
||||
hoverCardText: undefined,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { useRecoilState } from 'recoil';
|
||||
import { useAtom } from 'jotai';
|
||||
import { Switch, InfoHoverCard, ESide } from '@librechat/client';
|
||||
import { showThinkingAtom } from '~/store/showThinking';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import store from '~/store';
|
||||
|
||||
export default function SaveDraft({
|
||||
onCheckedChange,
|
||||
}: {
|
||||
onCheckedChange?: (value: boolean) => void;
|
||||
}) {
|
||||
const [showThinking, setSaveDrafts] = useRecoilState<boolean>(store.showThinking);
|
||||
const [showThinking, setShowThinking] = useAtom(showThinkingAtom);
|
||||
const localize = useLocalize();
|
||||
|
||||
const handleCheckedChange = (value: boolean) => {
|
||||
setSaveDrafts(value);
|
||||
setShowThinking(value);
|
||||
if (onCheckedChange) {
|
||||
onCheckedChange(value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { WritableAtom, useAtom } from 'jotai';
|
||||
import { RecoilState, useRecoilState } from 'recoil';
|
||||
import { Switch, InfoHoverCard, ESide } from '@librechat/client';
|
||||
import { useLocalize } from '~/hooks';
|
||||
|
|
@ -6,7 +7,7 @@ type LocalizeFn = ReturnType<typeof useLocalize>;
|
|||
type LocalizeKey = Parameters<LocalizeFn>[0];
|
||||
|
||||
interface ToggleSwitchProps {
|
||||
stateAtom: RecoilState<boolean>;
|
||||
stateAtom: RecoilState<boolean> | WritableAtom<boolean, [boolean], void>;
|
||||
localizationKey: LocalizeKey;
|
||||
hoverCardText?: LocalizeKey;
|
||||
switchId: string;
|
||||
|
|
@ -16,13 +17,18 @@ interface ToggleSwitchProps {
|
|||
strongLabel?: boolean;
|
||||
}
|
||||
|
||||
const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
|
||||
function isRecoilState<T>(atom: unknown): atom is RecoilState<T> {
|
||||
return atom != null && typeof atom === 'object' && 'key' in atom;
|
||||
}
|
||||
|
||||
const RecoilToggle: React.FC<
|
||||
Omit<ToggleSwitchProps, 'stateAtom'> & { stateAtom: RecoilState<boolean> }
|
||||
> = ({
|
||||
stateAtom,
|
||||
localizationKey,
|
||||
hoverCardText,
|
||||
switchId,
|
||||
onCheckedChange,
|
||||
showSwitch = true,
|
||||
disabled = false,
|
||||
strongLabel = false,
|
||||
}) => {
|
||||
|
|
@ -36,9 +42,47 @@ const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
|
|||
|
||||
const labelId = `${switchId}-label`;
|
||||
|
||||
if (!showSwitch) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div id={labelId}>
|
||||
{strongLabel ? <strong>{localize(localizationKey)}</strong> : localize(localizationKey)}
|
||||
</div>
|
||||
{hoverCardText && <InfoHoverCard side={ESide.Bottom} text={localize(hoverCardText)} />}
|
||||
</div>
|
||||
<Switch
|
||||
id={switchId}
|
||||
checked={switchState}
|
||||
onCheckedChange={handleCheckedChange}
|
||||
disabled={disabled}
|
||||
className="ml-4"
|
||||
data-testid={switchId}
|
||||
aria-labelledby={labelId}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const JotaiToggle: React.FC<
|
||||
Omit<ToggleSwitchProps, 'stateAtom'> & { stateAtom: WritableAtom<boolean, [boolean], void> }
|
||||
> = ({
|
||||
stateAtom,
|
||||
localizationKey,
|
||||
hoverCardText,
|
||||
switchId,
|
||||
onCheckedChange,
|
||||
disabled = false,
|
||||
strongLabel = false,
|
||||
}) => {
|
||||
const [switchState, setSwitchState] = useAtom(stateAtom);
|
||||
const localize = useLocalize();
|
||||
|
||||
const handleCheckedChange = (value: boolean) => {
|
||||
setSwitchState(value);
|
||||
onCheckedChange?.(value);
|
||||
};
|
||||
|
||||
const labelId = `${switchId}-label`;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
|
|
@ -52,13 +96,29 @@ const ToggleSwitch: React.FC<ToggleSwitchProps> = ({
|
|||
id={switchId}
|
||||
checked={switchState}
|
||||
onCheckedChange={handleCheckedChange}
|
||||
disabled={disabled}
|
||||
className="ml-4"
|
||||
data-testid={switchId}
|
||||
aria-labelledby={labelId}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ToggleSwitch: React.FC<ToggleSwitchProps> = (props) => {
|
||||
const { stateAtom, showSwitch = true } = props;
|
||||
|
||||
if (!showSwitch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isRecoil = isRecoilState(stateAtom);
|
||||
|
||||
if (isRecoil) {
|
||||
return <RecoilToggle {...props} stateAtom={stateAtom as RecoilState<boolean>} />;
|
||||
}
|
||||
|
||||
return <JotaiToggle {...props} stateAtom={stateAtom as WritableAtom<boolean, [boolean], void>} />;
|
||||
};
|
||||
|
||||
export default ToggleSwitch;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue