diff --git a/src/app/App.tsx b/src/app/App.tsx index 48ca831..e994607 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,7 +1,7 @@ import { CSSProperties, memo } from 'react'; import { Flexbox } from 'react-layout-kit'; +import ImagePreview from 'src/features/Preview'; -import ImagePreview from '@/features/ImagePreview'; import PromptInput from '@/features/Input'; import TaskList from '@/features/TaskList'; diff --git a/src/features/Preview/Actions.tsx b/src/features/Preview/Actions.tsx new file mode 100644 index 0000000..536eafe --- /dev/null +++ b/src/features/Preview/Actions.tsx @@ -0,0 +1,49 @@ +import { createStyles } from 'antd-style'; +import { memo, useMemo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import { midjourneySelectors, useStore } from '@/store'; + +import ImagineAction from './ImagineAction'; + +const useStyles = createStyles(({ css }) => ({ + container: css` + position: absolute; + top: 0; + left: 0; + + width: 100%; + height: 100%; + `, +})); + +const Actions = memo(() => { + const currentTask = useStore(midjourneySelectors.currentActiveTask); + const { styles } = useStyles(); + const content = useMemo(() => { + switch (currentTask?.action) { + case 'IMAGINE': { + return ; + } + case 'UPSCALE': { + break; + } + case 'VARIATION': { + break; + } + case 'REROLL': { + break; + } + case 'DESCRIBE': { + break; + } + case 'BLEND': { + break; + } + } + }, [currentTask?.action]); + + return {content}; +}); + +export default Actions; diff --git a/src/features/ImagePreview/index.tsx b/src/features/Preview/Image.tsx similarity index 53% rename from src/features/ImagePreview/index.tsx rename to src/features/Preview/Image.tsx index 079e9ef..8a682df 100644 --- a/src/features/ImagePreview/index.tsx +++ b/src/features/Preview/Image.tsx @@ -1,16 +1,19 @@ import { Image } from '@lobehub/ui'; import { useSize } from 'ahooks'; -import { Progress, Skeleton } from 'antd'; +import { Skeleton } from 'antd'; import { createStyles } from 'antd-style'; import { memo, useEffect, useRef, useState } from 'react'; import { Dimensions, getImageSize } from 'react-image-size'; -import { Center, Flexbox } from 'react-layout-kit'; +import { Center } from 'react-layout-kit'; import { midjourneySelectors, useStore } from '@/store'; +import Actions from './Actions'; + interface Size extends Dimensions { aspectRadio: number; } + const fetchImageSize = async (url: string): Promise => { try { const dim = await getImageSize(url); @@ -26,29 +29,27 @@ const getContainerSize = (content?: Dimensions, container?: Dimensions) => { let width = String(content?.width); let height = String(content?.height); - const spacing = 24; - const maxWidth = container.width - spacing; - const maxHeight = container.height - spacing; + const maxWidth = container.width; + const maxHeight = container.height; + let maxValue; if (content?.height >= content?.width && content?.height >= maxHeight) { + maxValue = maxHeight; height = maxHeight + 'px'; width = 'auto'; } else if (content?.width >= content?.height && content?.width >= maxWidth) { height = 'auto'; width = maxWidth + 'px'; + maxValue = maxWidth; } else { width = width + 'px'; height = height + 'px'; } - return { height, width }; + return { height, maxValue, width }; }; -const useStyles = createStyles(({ css, token, prefixCls }) => ({ - container: css` - overflow: hidden; - background: ${token.colorFillTertiary}; - border-radius: 24px; - `, + +const useStyles = createStyles(({ css, prefixCls }) => ({ image: css` border-radius: 24px; `, @@ -66,16 +67,14 @@ const useStyles = createStyles(({ css, token, prefixCls }) => ({ })); const ImagePreview = memo(() => { + const { styles, cx, theme } = useStyles(); + const [dim, setDims] = useState(); const containerRef = useRef(null); const size = useSize(containerRef); - const [progress, taskLoading] = useStore((s) => [ - midjourneySelectors.currentTaskProgress(s), - midjourneySelectors.isCurrentTaskRunning(s), - ]); + const imageContainerSize = getContainerSize(dim, size); - const { styles, cx, theme } = useStyles(); const currentTask = useStore(midjourneySelectors.currentActiveTask); useEffect(() => { @@ -88,47 +87,36 @@ const ImagePreview = memo(() => { }); }, [currentTask?.imageUrl]); - const imageContainerSize = getContainerSize(dim, size); - return ( - (taskLoading || currentTask?.imageUrl) && ( - - {currentTask?.imageUrl ? ( -
- -
- ) : ( -
- - Task is waiting to start... - -
- )} - {progress !== 100 && } -
- ) +
+ {currentTask?.imageUrl ? ( +
+ + +
+ ) : ( + + Task is waiting to start... + + )} +
); }); diff --git a/src/features/Preview/ImagineAction.tsx b/src/features/Preview/ImagineAction.tsx new file mode 100644 index 0000000..f978c06 --- /dev/null +++ b/src/features/Preview/ImagineAction.tsx @@ -0,0 +1,14 @@ +import { Button } from 'antd'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +const ImageAction = memo(() => { + return ( + + + + + ); +}); + +export default ImageAction; diff --git a/src/features/Preview/index.tsx b/src/features/Preview/index.tsx new file mode 100644 index 0000000..2582af0 --- /dev/null +++ b/src/features/Preview/index.tsx @@ -0,0 +1,43 @@ +import { Progress } from 'antd'; +import { createStyles } from 'antd-style'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import { midjourneySelectors, useStore } from '@/store'; + +import ImagePreview from './Image'; + +const useStyles = createStyles(({ css, token }) => ({ + container: css` + overflow: hidden; + background: ${token.colorFillTertiary}; + border-radius: 24px; + `, +})); + +const Preview = memo(() => { + const [progress, taskLoading] = useStore((s) => [ + midjourneySelectors.currentTaskProgress(s), + midjourneySelectors.isCurrentTaskRunning(s), + ]); + + const { styles } = useStyles(); + const currentTask = useStore(midjourneySelectors.currentActiveTask); + + return ( + (taskLoading || currentTask?.imageUrl) && ( + + + {progress !== 100 && } + + ) + ); +}); + +export default Preview; diff --git a/src/services/Midjourney.ts b/src/services/Midjourney.ts index 2fed682..c3fc1ec 100644 --- a/src/services/Midjourney.ts +++ b/src/services/Midjourney.ts @@ -12,9 +12,9 @@ interface DescribeResponse { } interface SimpleChangeDTO { - content: string; - notifyHook?: string; - state?: string; + index: number; + taskId: string; + type: 'UPSCALE' | 'VARIATION'; } interface SimpleChangeResponse { code: 1; @@ -87,12 +87,11 @@ class MidjourneyService { return data.result; } - async createSimpleChangeTask({ content, notifyHook, state }: SimpleChangeDTO) { - const data: SimpleChangeResponse = await this.post('/mj/submit/simple-change', { - content, - notifyHook, - state, - }); + async createSimpleChangeTask({ taskId, index, type }: SimpleChangeDTO) { + // e.g. 1320098173412546 U2 + const content = `${taskId} ${type[0]}${index}`; + + const data: SimpleChangeResponse = await this.post('/mj/submit/simple-change', { content }); return data.result; } diff --git a/src/store/_mockdata.ts b/src/store/_mockdata.ts index 90c4e5e..469d869 100644 --- a/src/store/_mockdata.ts +++ b/src/store/_mockdata.ts @@ -143,5 +143,61 @@ export const mockState: AppState = { status: 'SUCCESS', submitTime: 1705308810603, }, + { + action: 'IMAGINE', + description: '/imagine a bird', + failReason: null, + finishTime: 1705310324053, + id: '1705310285146113', + imageUrl: + 'https://cdn.discordapp.com/attachments/1174150905801736255/1196382952741945424/meng1011_a_bird_822d0ff9-e8da-4a35-b71f-78f59ad4ee1f.png?ex=65b76d73&is=65a4f873&hm=bb30ac4aa536d22fa28d06943127ba7a955047ae8138d48f3e86ccfaa4a24975&', + progress: '100%', + prompt: 'a bird', + promptEn: 'a bird', + properties: { + discordInstanceId: '1174150905801736255', + finalPrompt: 'a bird --v 6.0 --s 250', + flags: 0, + messageHash: '822d0ff9-e8da-4a35-b71f-78f59ad4ee1f', + messageId: '1196382953580810310', + nonce: '1467932102711394304', + notifyHook: null, + progressMessageId: '1196382794021097573', + }, + startTime: 1705310285146, + state: null, + status: 'SUCCESS', + submitTime: 1705310285146, + }, + { + action: 'IMAGINE', + description: + '/imagine Dragon sleeping on clouds, translucent glass, zbrush, ruby and gold style, anime aesthetics, furry art, red and white, elaborate, c4d rendering, super high detail, 3d --ar 9:16 --stylize 250 --v 6.0', + failReason: null, + finishTime: 1705310645445, + id: '1705310583960676', + imageUrl: + 'https://cdn.discordapp.com/attachments/1174150905801736255/1196384301101617262/meng1011_Dragon_sleeping_on_clouds_translucent_glass_zbrush_rub_4bed1f85-d7d9-4c68-b4d8-7652991e0b65.png?ex=65b76eb5&is=65a4f9b5&hm=198de4766243776970c66ba736a25a526110a051eadff6fcf46bbdeacda88d4d&', + progress: '100%', + prompt: + 'Dragon sleeping on clouds, translucent glass, zbrush, ruby and gold style, anime aesthetics, furry art, red and white, elaborate, c4d rendering, super high detail, 3d --ar 9:16 --stylize 250 --v 6.0', + promptEn: + 'Dragon sleeping on clouds, translucent glass, zbrush, ruby and gold style, anime aesthetics, furry art, red and white, elaborate, c4d rendering, super high detail, 3d --ar 9:16 --stylize 250 --v 6.0', + properties: { + discordInstanceId: '1174150905801736255', + finalPrompt: + 'Dragon sleeping on clouds, translucent glass, zbrush, ruby and gold style, anime aesthetics, furry art, red and white, elaborate, c4d rendering, super high detail, 3d --ar 9:16 --stylize 250 --v 6.0', + flags: 0, + messageHash: '4bed1f85-d7d9-4c68-b4d8-7652991e0b65', + messageId: '1196384301479116861', + nonce: '1467933356028149760', + notifyHook: null, + progressMessageId: '1196384047509815366', + }, + startTime: 1705310583961, + state: null, + status: 'SUCCESS', + submitTime: 1705310583960, + }, ], };