mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
AppChat: Draw: support N images
This commit is contained in:
@@ -68,6 +68,7 @@ import { ButtonAttachScreenCaptureMemo } from './buttons/ButtonAttachScreenCaptu
|
||||
import { ButtonAttachWebMemo } from './buttons/ButtonAttachWeb';
|
||||
import { ButtonBeamMemo } from './buttons/ButtonBeam';
|
||||
import { ButtonCallMemo } from './buttons/ButtonCall';
|
||||
import { ButtonGroupDrawRepeat } from './buttons/ButtonGroupDrawRepeat';
|
||||
import { ButtonMicContinuationMemo } from './buttons/ButtonMicContinuation';
|
||||
import { ButtonMicMemo } from './buttons/ButtonMic';
|
||||
import { ButtonMultiChatMemo } from './buttons/ButtonMultiChat';
|
||||
@@ -115,6 +116,7 @@ export function Composer(props: {
|
||||
|
||||
// state
|
||||
const [composeText, debouncedText, setComposeText] = useDebouncer('', 300, 1200, true);
|
||||
const [drawRepeat, setDrawRepeat] = React.useState(1);
|
||||
const [micContinuation, setMicContinuation] = React.useState(false);
|
||||
const [speechInterimResult, setSpeechInterimResult] = React.useState<SpeechResult | null>(null);
|
||||
const [sendStarted, setSendStarted] = React.useState(false);
|
||||
@@ -210,6 +212,8 @@ export function Composer(props: {
|
||||
const noConversation = !targetConversationId;
|
||||
const showChatAttachments = chatExecuteModeCanAttach(chatExecuteMode);
|
||||
|
||||
const composerTextSuffix = chatExecuteMode === 'generate-image' && isDesktop && drawRepeat > 1 ? ` x${drawRepeat}` : '';
|
||||
|
||||
const micIsRunning = !!speechInterimResult;
|
||||
// more mic way below, as we use complex hooks
|
||||
|
||||
@@ -298,7 +302,7 @@ export function Composer(props: {
|
||||
// prepare the fragments: content (if any) and attachments (if allowed, and any)
|
||||
const fragments: (DMessageContentFragment | DMessageAttachmentFragment)[] = [];
|
||||
if (composerText)
|
||||
fragments.push(createTextContentFragment(composerText));
|
||||
fragments.push(createTextContentFragment(composerText + composerTextSuffix));
|
||||
|
||||
const canAttach = chatExecuteModeCanAttach(_chatExecuteMode);
|
||||
if (canAttach) {
|
||||
@@ -319,7 +323,7 @@ export function Composer(props: {
|
||||
if (enqueued)
|
||||
_handleClearText();
|
||||
return enqueued;
|
||||
}, [attachmentsTakeAllFragments, confirmProceedIfAttachmentsNotSupported, _handleClearText, inReferenceTo, onAction, targetConversationId]);
|
||||
}, [attachmentsTakeAllFragments, composerTextSuffix, confirmProceedIfAttachmentsNotSupported, _handleClearText, inReferenceTo, onAction, targetConversationId]);
|
||||
|
||||
const handleSendAction = React.useCallback(async (chatExecuteMode: ChatExecuteMode, composerText: string): Promise<boolean> => {
|
||||
setSendStarted(true);
|
||||
@@ -1060,6 +1064,9 @@ export function Composer(props: {
|
||||
|
||||
</Box>
|
||||
|
||||
{/* [desktop] Draw mode N buttons */}
|
||||
{isDesktop && isDraw && <ButtonGroupDrawRepeat drawRepeat={drawRepeat} setDrawRepeat={setDrawRepeat} />}
|
||||
|
||||
{/* [desktop] Multicast switch (under the Chat button) */}
|
||||
{isDesktop && props.isMulticast !== null && <ButtonMultiChatMemo multiChat={props.isMulticast} onSetMultiChat={props.setIsMulticast} />}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Box, FormControl, IconButton } from '@mui/joy';
|
||||
|
||||
|
||||
const _styles = {
|
||||
control: {
|
||||
gap: 1,
|
||||
mt: 1,
|
||||
} as const,
|
||||
|
||||
buttonGroup: {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-evenly',
|
||||
} as const,
|
||||
|
||||
button: {
|
||||
borderRadius: 'sm',
|
||||
// boxShadow: drawRepeat === n ? '0px 2px 8px 0px rgb(var(--joy-palette-warning-mainChannel) / 40%)' : 'none',
|
||||
// fontWeight: drawRepeat === n ? 'xl' : 400, /* reset, from 600 */
|
||||
transition: 'transform 0.14s, box-shadow 0.14s',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-1px)',
|
||||
// backgroundColor: drawRepeat === n ? 'background.popup' : 'background.surface',
|
||||
// boxShadow: '0 0 8px 1px rgb(var(--joy-palette-warning-mainChannel) / 40%)',
|
||||
} as const,
|
||||
} as const,
|
||||
|
||||
text: {
|
||||
mx: 'auto',
|
||||
fontSize: 'xs',
|
||||
opacity: '0.5',
|
||||
} as const,
|
||||
} as const;
|
||||
|
||||
|
||||
export function ButtonGroupDrawRepeat(props: {
|
||||
drawRepeat: number,
|
||||
setDrawRepeat: (n: number) => void,
|
||||
}) {
|
||||
|
||||
const { drawRepeat, setDrawRepeat } = props;
|
||||
|
||||
return (
|
||||
<FormControl sx={_styles.control}>
|
||||
<Box sx={_styles.buttonGroup}>
|
||||
{[1, 2, 4, 5, 10].map((n) => (
|
||||
<IconButton
|
||||
key={n}
|
||||
size='sm'
|
||||
color='warning'
|
||||
variant={drawRepeat === n ? 'solid' : 'soft'}
|
||||
onClick={() => setDrawRepeat(n)}
|
||||
sx={_styles.button}
|
||||
>
|
||||
{n}
|
||||
</IconButton>
|
||||
))}
|
||||
</Box>
|
||||
<Box sx={_styles.text}>
|
||||
{drawRepeat > 1
|
||||
? `Create ${drawRepeat} Images`
|
||||
: 'Number of Images'}
|
||||
</Box>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user