diff --git a/src/apps/chat/components/composer/Composer.tsx b/src/apps/chat/components/composer/Composer.tsx index f09d3ed58..d0c0fc305 100644 --- a/src/apps/chat/components/composer/Composer.tsx +++ b/src/apps/chat/components/composer/Composer.tsx @@ -2,10 +2,9 @@ import * as React from 'react'; import { useShallow } from 'zustand/react/shallow'; import type { FileWithHandle } from 'browser-fs-access'; -import { Box, Button, ButtonGroup, Card, Dropdown, Grid, IconButton, Menu, MenuButton, MenuItem, Textarea, Tooltip, Typography } from '@mui/joy'; +import { Box, Button, ButtonGroup, Card, Dropdown, Grid, IconButton, Menu, MenuButton, MenuItem, Textarea, Typography } from '@mui/joy'; import { ColorPaletteProp, SxProps, VariantProp } from '@mui/joy/styles/types'; import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; -import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; import FormatPaintTwoToneIcon from '@mui/icons-material/FormatPaintTwoTone'; import PsychologyIcon from '@mui/icons-material/Psychology'; @@ -74,6 +73,7 @@ import { ButtonMicMemo } from './buttons/ButtonMic'; import { ButtonMultiChatMemo } from './buttons/ButtonMultiChat'; import { ButtonOptionsDraw } from './buttons/ButtonOptionsDraw'; import { ComposerTextAreaActions } from './textarea/ComposerTextAreaActions'; +import { ComposerTextAreaDrawActions } from './textarea/ComposerTextAreaDrawActions'; import { StatusBarMemo } from '../StatusBar'; import { TokenBadgeMemo } from './tokens/TokenBadge'; import { TokenProgressbarMemo } from './tokens/TokenProgressbar'; @@ -832,7 +832,7 @@ export function Composer(props: { variant='outlined' color={isDraw ? 'warning' : isReAct ? 'success' : undefined} autoFocus - minRows={isMobile ? 4 : agiAttachmentPrompts.hasData ? 3 : showChatInReferenceTo ? 4 : 5} + minRows={isMobile ? 4 : isDraw ? 4 : agiAttachmentPrompts.hasData ? 3 : showChatInReferenceTo ? 4 : 5} maxRows={isMobile ? 8 : 10} placeholder={textPlaceholder} value={composeText} @@ -841,8 +841,12 @@ export function Composer(props: { onPasteCapture={handleAttachCtrlV} // onFocusCapture={handleFocusModeOn} // onBlurCapture={handleFocusModeOff} - endDecorator={ - + : }*/} {/* [Draw] Imagine */} - {isDraw && !!composeText && - - - - } + {/* NOTE: disabled: as we have prompt enhancement in the TextArea (Draw Mode) already */} + {/*{isDraw && !!composeText && */} + {/* */} + {/* */} + {/* */} + {/*}*/} {/* Mode expander */} + {/* In-Reference-To bubbles */} {props.inReferenceTo?.map((item, index) => ( diff --git a/src/apps/chat/components/composer/textarea/ComposerTextAreaDrawActions.tsx b/src/apps/chat/components/composer/textarea/ComposerTextAreaDrawActions.tsx new file mode 100644 index 000000000..e0ed91a94 --- /dev/null +++ b/src/apps/chat/components/composer/textarea/ComposerTextAreaDrawActions.tsx @@ -0,0 +1,74 @@ +import * as React from 'react'; + +import { Box, Button } from '@mui/joy'; +import AutoFixHighIcon from '@mui/icons-material/AutoFixHigh'; + +import { composerTextAreaSx } from './ComposerTextAreaActions'; +import { imaginePromptFromTextOrThrow } from '~/modules/aifn/imagine/imaginePromptFromText'; + + +const _style = { + enhance: { + minWidth: 170, + mx: 0.625, + pr: 2, + border: '1px solid', + borderColor: 'warning.outlinedBorder', + boxShadow: '0px 4px 4px -4px rgb(var(--joy-palette-warning-darkChannel) / 20%)', + transition: 'background-color 0.14s', + justifyContent: 'space-between', + } as const, + gone: { + visibility: 'hidden', + } as const, +} as const; + +export function ComposerTextAreaDrawActions(props: { + composerText: string, + onReplaceText: (text: string) => void, +}) { + + // state + const [isSimpleEnhancing, setIsSimpleEnhancing] = React.useState(false); + + + // derived + const trimmedPrompt = props.composerText.trim(); + const userHasText = !!trimmedPrompt; + + + const { onReplaceText } = props; + + const handleSimpleEnhance = React.useCallback(async () => { + if (!trimmedPrompt || isSimpleEnhancing) return; + setIsSimpleEnhancing(true); + const improvedPrompt = await imaginePromptFromTextOrThrow(trimmedPrompt, 'DEV') + .catch(console.error); + if (improvedPrompt) + onReplaceText(improvedPrompt); + setIsSimpleEnhancing(false); + }, [isSimpleEnhancing, onReplaceText, trimmedPrompt]); + + + return ( + + + {/* Enhance button */} + + + + ); +}