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:
Danny Avila 2024-04-14 19:06:20 -04:00 committed by GitHub
parent f380f261a5
commit d2d9ac0280
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 966 additions and 896 deletions

View file

@ -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>
);
}

View file

@ -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>

View file

@ -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;

View file

@ -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',

View file

@ -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,