mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 09:20:15 +01:00
✨ feat: Add 'EnterToSend' Option & Update Br. Translation 🇧🇷 (#2413)
* chore: Add EnterToSend, Translation Portuguese Brazilian Update * Inverted selection and corrected translation * fix: removed Trailing spaces not allowed * feat: Refactor key event handler & updated translations * fix: removed return; & updated files translations * fix: duplicate switchs on General.tsx * fix: added again switch * refactor(useTextarea): limit refactoring of handleKeyDown * refactor: correct keyDown handler and add English localization --------- Co-authored-by: Raí Santos <140329135+itzraiss@users.noreply.github.com> Co-authored-by: Raí Santos <raimorningstarchristus@gmail.com>
This commit is contained in:
parent
f380f261a5
commit
d2d9ac0280
7 changed files with 966 additions and 896 deletions
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { useRecoilState } from 'recoil';
|
||||||
|
import { Switch } from '~/components/ui/Switch';
|
||||||
|
import useLocalize from '~/hooks/useLocalize';
|
||||||
|
import store from '~/store';
|
||||||
|
|
||||||
|
export default function SendMessageKeyEnter({
|
||||||
|
onCheckedChange,
|
||||||
|
}: {
|
||||||
|
onCheckedChange?: (value: boolean) => void;
|
||||||
|
}) {
|
||||||
|
const [enterToSend, setEnterToSend] = useRecoilState<boolean>(store.enterToSend);
|
||||||
|
const localize = useLocalize();
|
||||||
|
|
||||||
|
const handleCheckedChange = (value: boolean) => {
|
||||||
|
setEnterToSend(value);
|
||||||
|
if (onCheckedChange) {
|
||||||
|
onCheckedChange(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div> {localize('com_nav_enter_to_send')} </div>
|
||||||
|
<Switch
|
||||||
|
id="enterToSend"
|
||||||
|
checked={enterToSend}
|
||||||
|
onCheckedChange={handleCheckedChange}
|
||||||
|
className="ml-4 mt-2"
|
||||||
|
data-testid="enterToSend"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ import {
|
||||||
import type { TDangerButtonProps } from '~/common';
|
import type { TDangerButtonProps } from '~/common';
|
||||||
import HideSidePanelSwitch from './HideSidePanelSwitch';
|
import HideSidePanelSwitch from './HideSidePanelSwitch';
|
||||||
import AutoScrollSwitch from './AutoScrollSwitch';
|
import AutoScrollSwitch from './AutoScrollSwitch';
|
||||||
|
import SendMessageKeyEnter from './EnterToSend';
|
||||||
import ShowCodeSwitch from './ShowCodeSwitch';
|
import ShowCodeSwitch from './ShowCodeSwitch';
|
||||||
import { Dropdown } from '~/components/ui';
|
import { Dropdown } from '~/components/ui';
|
||||||
import DangerButton from '../DangerButton';
|
import DangerButton from '../DangerButton';
|
||||||
|
|
@ -186,6 +187,9 @@ function General() {
|
||||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
||||||
<AutoScrollSwitch />
|
<AutoScrollSwitch />
|
||||||
</div>
|
</div>
|
||||||
|
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
||||||
|
<SendMessageKeyEnter />
|
||||||
|
</div>
|
||||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-700">
|
||||||
<ShowCodeSwitch />
|
<ShowCodeSwitch />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
import React, { useEffect, useRef, useCallback } from 'react';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { EModelEndpoint } from 'librechat-data-provider';
|
import { EModelEndpoint } from 'librechat-data-provider';
|
||||||
|
import React, { useEffect, useRef, useCallback } from 'react';
|
||||||
import type { TEndpointOption } from 'librechat-data-provider';
|
import type { TEndpointOption } from 'librechat-data-provider';
|
||||||
import type { UseFormSetValue } from 'react-hook-form';
|
import type { UseFormSetValue } from 'react-hook-form';
|
||||||
import type { KeyboardEvent } from 'react';
|
import type { KeyboardEvent } from 'react';
|
||||||
|
|
@ -10,6 +11,7 @@ import useGetSender from '~/hooks/Conversations/useGetSender';
|
||||||
import useFileHandling from '~/hooks/Files/useFileHandling';
|
import useFileHandling from '~/hooks/Files/useFileHandling';
|
||||||
import { useChatContext } from '~/Providers/ChatContext';
|
import { useChatContext } from '~/Providers/ChatContext';
|
||||||
import useLocalize from '~/hooks/useLocalize';
|
import useLocalize from '~/hooks/useLocalize';
|
||||||
|
import store from '~/store';
|
||||||
|
|
||||||
type KeyEvent = KeyboardEvent<HTMLTextAreaElement>;
|
type KeyEvent = KeyboardEvent<HTMLTextAreaElement>;
|
||||||
|
|
||||||
|
|
@ -27,6 +29,7 @@ export default function useTextarea({
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const assistantMap = useAssistantsMapContext();
|
const assistantMap = useAssistantsMapContext();
|
||||||
|
const enterToSend = useRecoilValue(store.enterToSend);
|
||||||
const {
|
const {
|
||||||
conversation,
|
conversation,
|
||||||
isSubmitting,
|
isSubmitting,
|
||||||
|
|
@ -134,25 +137,34 @@ export default function useTextarea({
|
||||||
assistantMap,
|
assistantMap,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyEvent) => {
|
const handleKeyDown = useCallback(
|
||||||
if (e.key === 'Enter' && isSubmitting) {
|
(e: KeyEvent) => {
|
||||||
return;
|
if (e.key === 'Enter' && isSubmitting) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isNonShiftEnter = e.key === 'Enter' && !e.shiftKey;
|
const isNonShiftEnter = e.key === 'Enter' && !e.shiftKey;
|
||||||
|
|
||||||
if (isNonShiftEnter && filesLoading) {
|
if (isNonShiftEnter && filesLoading) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNonShiftEnter) {
|
if (isNonShiftEnter) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNonShiftEnter && !isComposing?.current) {
|
if (e.key === 'Enter' && !enterToSend && textAreaRef.current) {
|
||||||
submitButtonRef.current?.click();
|
insertTextAtCursor(textAreaRef.current, '\n');
|
||||||
}
|
forceResize(textAreaRef);
|
||||||
};
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNonShiftEnter && !isComposing?.current) {
|
||||||
|
submitButtonRef.current?.click();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[isSubmitting, filesLoading, enterToSend, textAreaRef, submitButtonRef],
|
||||||
|
);
|
||||||
|
|
||||||
const handleKeyUp = (e: KeyEvent) => {
|
const handleKeyUp = (e: KeyEvent) => {
|
||||||
const target = e.target as HTMLTextAreaElement;
|
const target = e.target as HTMLTextAreaElement;
|
||||||
|
|
|
||||||
|
|
@ -405,6 +405,7 @@ export default {
|
||||||
com_nav_theme_system: 'System',
|
com_nav_theme_system: 'System',
|
||||||
com_nav_theme_dark: 'Dark',
|
com_nav_theme_dark: 'Dark',
|
||||||
com_nav_theme_light: 'Light',
|
com_nav_theme_light: 'Light',
|
||||||
|
com_nav_enter_to_send: 'Press Enter to send messages',
|
||||||
com_nav_user_name_display: 'Display username in messages',
|
com_nav_user_name_display: 'Display username in messages',
|
||||||
com_nav_show_code: 'Always show code when using code interpreter',
|
com_nav_show_code: 'Always show code when using code interpreter',
|
||||||
com_nav_clear_all_chats: 'Clear all chats',
|
com_nav_clear_all_chats: 'Clear all chats',
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,25 @@ const UsernameDisplay = atom<boolean>({
|
||||||
] as const,
|
] as const,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const enterToSend = atom<boolean>({
|
||||||
|
key: 'enterToSend',
|
||||||
|
default: true,
|
||||||
|
effects: [
|
||||||
|
({ setSelf, onSet }) => {
|
||||||
|
const savedValue = localStorage.getItem('enterToSend');
|
||||||
|
if (savedValue != null) {
|
||||||
|
setSelf(savedValue === 'true');
|
||||||
|
}
|
||||||
|
|
||||||
|
onSet((newValue: unknown) => {
|
||||||
|
if (typeof newValue === 'boolean') {
|
||||||
|
localStorage.setItem('enterToSend', newValue.toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
] as const,
|
||||||
|
});
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
abortScroll,
|
abortScroll,
|
||||||
showFiles,
|
showFiles,
|
||||||
|
|
@ -166,6 +185,7 @@ export default {
|
||||||
showBingToneSetting,
|
showBingToneSetting,
|
||||||
showPopover,
|
showPopover,
|
||||||
autoScroll,
|
autoScroll,
|
||||||
|
enterToSend,
|
||||||
showCode,
|
showCode,
|
||||||
hideSidePanel,
|
hideSidePanel,
|
||||||
modularChat,
|
modularChat,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue