mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-21 10:50:14 +01:00
🅰️ feat: Dynamic Font Size (#3568)
* wip: general setup * added: translations for font-size * fix: prompts related linter errors and add theming * wip: font size selector * refactor: Update FontSizeSelector options display property * refactor: adjust Intersection Observer threshold and debounce rate * feat: Update selectedPrompt type in PromptForm to be optional * feat: dynamic font size * refactor: Update message font size in navigation bar * refactor: Update code analyze block styling * refactor: ProgressText dynamic font size * refactor: move FontSizeSelector component to Chat from General settings * fix: HoverButtons styling for better visibility * refactor: Update HoverButtons styling for better visibility --------- Co-authored-by: kraken <solodarken@gmail.com>
This commit is contained in:
parent
b390ba781f
commit
2bb0842650
44 changed files with 340 additions and 132 deletions
|
|
@ -5,11 +5,12 @@ import { Controller, useFormContext, useFormState } from 'react-hook-form';
|
|||
import AlwaysMakeProd from '~/components/Prompts/Groups/AlwaysMakeProd';
|
||||
import { SaveIcon, CrossIcon } from '~/components/svg';
|
||||
import { TextareaAutosize } from '~/components/ui';
|
||||
import { PromptsEditorMode } from '~/common';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
const { PromptsEditorMode, promptsEditorMode } = store;
|
||||
const { promptsEditorMode } = store;
|
||||
|
||||
type Props = {
|
||||
name: string;
|
||||
|
|
@ -22,17 +23,18 @@ const PromptEditor: React.FC<Props> = ({ name, isEditing, setIsEditing }) => {
|
|||
const { control } = useFormContext();
|
||||
const editorMode = useRecoilValue(promptsEditorMode);
|
||||
const { dirtyFields } = useFormState({ control: control });
|
||||
const { prompt } = dirtyFields as { prompt?: string };
|
||||
|
||||
const EditorIcon = useMemo(() => {
|
||||
if (isEditing && !dirtyFields.prompt) {
|
||||
if (isEditing && prompt?.length == null) {
|
||||
return CrossIcon;
|
||||
}
|
||||
return isEditing ? SaveIcon : EditIcon;
|
||||
}, [isEditing, dirtyFields.prompt]);
|
||||
}, [isEditing, prompt]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2 className="flex items-center justify-between rounded-t-lg border border-gray-300 py-2 pl-4 text-base font-semibold dark:border-gray-600 dark:text-gray-200">
|
||||
<h2 className="flex items-center justify-between rounded-t-lg border border-border-medium py-2 pl-4 text-base font-semibold text-text-primary">
|
||||
{localize('com_ui_prompt_text')}
|
||||
<div className="flex flex-row gap-6">
|
||||
{editorMode === PromptsEditorMode.ADVANCED && (
|
||||
|
|
@ -49,14 +51,21 @@ const PromptEditor: React.FC<Props> = ({ name, isEditing, setIsEditing }) => {
|
|||
</div>
|
||||
</h2>
|
||||
<div
|
||||
role="button"
|
||||
className={cn(
|
||||
'group relative min-h-32 rounded-b-lg border border-gray-300 p-4 transition-all duration-150 hover:opacity-90 dark:border-gray-600',
|
||||
'min-h-[8rem] w-full rounded-b-lg border border-border-medium p-4 transition-all duration-150',
|
||||
{ 'cursor-pointer hover:bg-gray-100/50 dark:hover:bg-gray-100/10': !isEditing },
|
||||
)}
|
||||
onClick={() => !isEditing && setIsEditing(true)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
!isEditing && setIsEditing(true);
|
||||
}
|
||||
}}
|
||||
tabIndex={0}
|
||||
>
|
||||
{!isEditing && (
|
||||
<EditIcon className="icon-xl absolute inset-0 m-auto hidden opacity-25 group-hover:block dark:text-gray-200" />
|
||||
<EditIcon className="icon-xl absolute inset-0 m-auto hidden text-text-primary opacity-25 group-hover:block" />
|
||||
)}
|
||||
<Controller
|
||||
name={name}
|
||||
|
|
@ -65,12 +74,20 @@ const PromptEditor: React.FC<Props> = ({ name, isEditing, setIsEditing }) => {
|
|||
isEditing ? (
|
||||
<TextareaAutosize
|
||||
{...field}
|
||||
className="w-full rounded border border-gray-300 bg-transparent px-2 py-1 focus:outline-none dark:border-gray-600 dark:text-gray-200"
|
||||
className="w-full rounded border border-border-medium bg-transparent px-2 py-1 text-text-primary focus:outline-none"
|
||||
minRows={3}
|
||||
onBlur={() => setIsEditing(false)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
setIsEditing(false);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<pre className="block break-words px-2 py-1 dark:text-gray-200">{field.value}</pre>
|
||||
<pre className="block h-full w-full whitespace-pre-wrap break-words px-2 py-1 text-left text-text-primary">
|
||||
{field.value}
|
||||
</pre>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue