mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-21 01:36:13 +01:00
🔄 feat: chat direction (LTR-RTL) (#3260)
* feat: chat direction * fix: FileRow * feat: smooth trigger transition
This commit is contained in:
parent
d5782ac66c
commit
237a0de8b6
31 changed files with 145 additions and 111 deletions
32
client/src/components/Nav/SettingsTabs/Chat/Chat.tsx
Normal file
32
client/src/components/Nav/SettingsTabs/Chat/Chat.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { memo } from 'react';
|
||||
import * as Tabs from '@radix-ui/react-tabs';
|
||||
import { SettingsTabValues } from 'librechat-data-provider';
|
||||
import SendMessageKeyEnter from './EnterToSend';
|
||||
import ShowCodeSwitch from './ShowCodeSwitch';
|
||||
import { ForkSettings } from './ForkSettings';
|
||||
import ChatDirection from './ChatDirection';
|
||||
import SaveDraft from './SaveDraft';
|
||||
|
||||
function Chat() {
|
||||
return (
|
||||
<Tabs.Content value={SettingsTabValues.CHAT} role="tabpanel" className="md: w-full">
|
||||
<div className="flex flex-col gap-3 text-sm text-black dark:text-gray-50">
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
|
||||
<SendMessageKeyEnter />
|
||||
</div>
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
|
||||
<ChatDirection />
|
||||
</div>
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
|
||||
<ShowCodeSwitch />
|
||||
</div>
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
|
||||
<SaveDraft />
|
||||
</div>
|
||||
<ForkSettings />
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(Chat);
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import store from '~/store';
|
||||
|
||||
const ChatDirection = () => {
|
||||
const [direction, setDirection] = useRecoilState(store.chatDirection);
|
||||
const localize = useLocalize();
|
||||
|
||||
const toggleChatDirection = () => {
|
||||
setDirection((prev) => (prev === 'LTR' ? 'RTL' : 'LTR'));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<span>{localize('com_nav_chat_direction')}</span>
|
||||
</div>
|
||||
<label
|
||||
onClick={toggleChatDirection}
|
||||
data-testid="chatDirection"
|
||||
className="btn btn-neutral relative"
|
||||
style={{ userSelect: 'none' }}
|
||||
>
|
||||
{direction.toLowerCase()}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatDirection;
|
||||
37
client/src/components/Nav/SettingsTabs/Chat/EnterToSend.tsx
Normal file
37
client/src/components/Nav/SettingsTabs/Chat/EnterToSend.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { useRecoilState } from 'recoil';
|
||||
import HoverCardSettings from '../HoverCardSettings';
|
||||
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 className="flex items-center space-x-2">
|
||||
<div>{localize('com_nav_enter_to_send')}</div>
|
||||
<HoverCardSettings side="bottom" text="com_nav_info_enter_to_send" />
|
||||
</div>
|
||||
<Switch
|
||||
id="enterToSend"
|
||||
checked={enterToSend}
|
||||
onCheckedChange={handleCheckedChange}
|
||||
className="ml-4 mt-2"
|
||||
data-testid="enterToSend"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
67
client/src/components/Nav/SettingsTabs/Chat/ForkSettings.tsx
Normal file
67
client/src/components/Nav/SettingsTabs/Chat/ForkSettings.tsx
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { useRecoilState } from 'recoil';
|
||||
import HoverCardSettings from '../HoverCardSettings';
|
||||
import { ForkOptions } from 'librechat-data-provider';
|
||||
import { Dropdown, Switch } from '~/components/ui';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import store from '~/store';
|
||||
|
||||
export const ForkSettings = () => {
|
||||
const localize = useLocalize();
|
||||
const [forkSetting, setForkSetting] = useRecoilState(store.forkSetting);
|
||||
const [splitAtTarget, setSplitAtTarget] = useRecoilState(store.splitAtTarget);
|
||||
const [remember, setRemember] = useRecoilState<boolean>(store.rememberForkOption);
|
||||
|
||||
const forkOptions = [
|
||||
{ value: ForkOptions.DIRECT_PATH, display: localize('com_ui_fork_visible') },
|
||||
{ value: ForkOptions.INCLUDE_BRANCHES, display: localize('com_ui_fork_branches') },
|
||||
{ value: ForkOptions.TARGET_LEVEL, display: localize('com_ui_fork_all_target') },
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div>{localize('com_ui_fork_change_default')}</div>
|
||||
<HoverCardSettings side="bottom" text="com_nav_info_fork_change_default" />
|
||||
</div>
|
||||
<Dropdown
|
||||
value={forkSetting}
|
||||
onChange={setForkSetting}
|
||||
options={forkOptions}
|
||||
sizeClasses="w-[200px]"
|
||||
anchor="bottom start"
|
||||
testId="fork-setting-dropdown"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
|
||||
<div className="flex items-center justify-between">
|
||||
<div> {localize('com_ui_fork_default')} </div>
|
||||
<Switch
|
||||
id="rememberForkOption"
|
||||
checked={remember}
|
||||
onCheckedChange={setRemember}
|
||||
className="ml-4 mt-2"
|
||||
data-testid="rememberForkOption"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="border-b pb-3 last-of-type:border-b-0 dark:border-gray-600">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div>{localize('com_ui_fork_split_target_setting')}</div>
|
||||
<HoverCardSettings side="bottom" text="com_nav_info_fork_split_target_setting" />
|
||||
</div>
|
||||
<Switch
|
||||
id="splitAtTarget"
|
||||
checked={splitAtTarget}
|
||||
onCheckedChange={setSplitAtTarget}
|
||||
className="ml-4 mt-2"
|
||||
data-testid="splitAtTarget"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
37
client/src/components/Nav/SettingsTabs/Chat/SaveDraft.tsx
Normal file
37
client/src/components/Nav/SettingsTabs/Chat/SaveDraft.tsx
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { useRecoilState } from 'recoil';
|
||||
import HoverCardSettings from '../HoverCardSettings';
|
||||
import { Switch } from '~/components/ui';
|
||||
import useLocalize from '~/hooks/useLocalize';
|
||||
import store from '~/store';
|
||||
|
||||
export default function SaveDraft({
|
||||
onCheckedChange,
|
||||
}: {
|
||||
onCheckedChange?: (value: boolean) => void;
|
||||
}) {
|
||||
const [saveDrafts, setSaveDrafts] = useRecoilState<boolean>(store.saveDrafts);
|
||||
const localize = useLocalize();
|
||||
|
||||
const handleCheckedChange = (value: boolean) => {
|
||||
setSaveDrafts(value);
|
||||
if (onCheckedChange) {
|
||||
onCheckedChange(value);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<div>{localize('com_nav_save_drafts')}</div>
|
||||
<HoverCardSettings side="bottom" text="com_nav_info_save_draft" />
|
||||
</div>
|
||||
<Switch
|
||||
id="saveDrafts"
|
||||
checked={saveDrafts}
|
||||
onCheckedChange={handleCheckedChange}
|
||||
className="ml-4 mt-2"
|
||||
data-testid="saveDrafts"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
import { useRecoilState } from 'recoil';
|
||||
import HoverCardSettings from '../HoverCardSettings';
|
||||
import { Switch } from '~/components/ui';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import store from '~/store';
|
||||
|
||||
export default function ShowCodeSwitch({
|
||||
onCheckedChange,
|
||||
}: {
|
||||
onCheckedChange?: (value: boolean) => void;
|
||||
}) {
|
||||
const [showCode, setShowCode] = useRecoilState<boolean>(store.showCode);
|
||||
const localize = useLocalize();
|
||||
|
||||
const handleCheckedChange = (value: boolean) => {
|
||||
setShowCode(value);
|
||||
if (onCheckedChange) {
|
||||
onCheckedChange(value);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<div> {localize('com_nav_show_code')} </div>
|
||||
<Switch
|
||||
id="showCode"
|
||||
checked={showCode}
|
||||
onCheckedChange={handleCheckedChange}
|
||||
className="ml-4 mt-2"
|
||||
data-testid="showCode"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue