Skip to content

Commit

Permalink
💄 style: Update base experience
Browse files Browse the repository at this point in the history
  • Loading branch information
canisminor1990 committed Jan 19, 2024
1 parent d353c13 commit 1a57100
Show file tree
Hide file tree
Showing 22 changed files with 337 additions and 301 deletions.
13 changes: 13 additions & 0 deletions next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
const isProd = process.env.NODE_ENV === 'production';

/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
transpilePackages: ['@lobehub/ui'],
images: {
remotePatterns: [
{
hostname: 'registry.npmmirror.com',
pathname: '/@lobehub/**',
port: '',
protocol: 'https',
},
],
unoptimized: !isProd,
},
async headers() {
return [
{
Expand Down
4 changes: 2 additions & 2 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ interface AppProps {
}
export const App = memo<AppProps>(({ style }) => {
return (
<Flexbox gap={8} style={style}>
<Flexbox gap={12} style={{ maxHeight: '100dvh', overflow: 'hidden', ...style }}>
<PromptInput />
<TaskList />
<ImagePreview />
<TaskList />
</Flexbox>
);
});
8 changes: 4 additions & 4 deletions src/app/iframe/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ import { Flexbox } from 'react-layout-kit';
import PromptInput from '@/features/Input';
import ImagePreview from '@/features/Preview';
import TaskList from '@/features/TaskList';
import { useMidjourneyStore } from '@/store/midjourney';
import { useStore } from '@/store';

import './global.css';

const InLobeChatPage = memo(() => {
const [useInitApp] = useMidjourneyStore((s) => [s.useInitApp]);
const [useInitApp] = useStore((s) => [s.useInitApp]);

useInitApp();

return (
<Flexbox gap={12} padding={'0 4px 8px'} style={{ height: '100vh' }}>
<Flexbox gap={12} style={{ height: '100dvh' }}>
<PromptInput />
<TaskList />
<ImagePreview />
<TaskList />
</Flexbox>
);
});
Expand Down
24 changes: 15 additions & 9 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,41 @@
'use client';

import { Logo } from '@lobehub/ui';
import { useTheme } from 'antd-style';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import Settings from '@/features/Settings';
import { useMidjourneyStore } from '@/store/midjourney';
import { useStore } from '@/store';

import { App } from './App';

const Page = memo(() => {
const [useInitApp] = useMidjourneyStore((s) => [s.useInitApp]);
const [useInitApp] = useStore((s) => [s.useInitApp]);

useInitApp();

const theme = useTheme();

return (
<Flexbox
align={'center'}
padding={16}
style={{ background: theme.colorBgLayout, height: '100vh' }}
>
<Flexbox gap={16} padding={16} style={{ background: theme.colorBgLayout, height: '100vh' }}>
<Flexbox align={'center'} horizontal justify={'space-between'}>
<Logo
extra={'Midjourney Webui'}
onClick={() => {
window.open('https://github.com/lobehub/chat-plugin-midjourney', '_blank');
}}
style={{ cursor: 'pointer' }}
type={'combine'}
/>
<Settings />
</Flexbox>
<App
style={{
height: '100%',
maxWidth: 1152,
width: '100%',
}}
/>
<Settings />
</Flexbox>
);
});
Expand Down
42 changes: 27 additions & 15 deletions src/features/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,46 @@
import { TextArea } from '@lobehub/ui';
import { Button, Flex } from 'antd';
import { ActionIcon, TextArea } from '@lobehub/ui';
import { Flex } from 'antd';
import { createStyles } from 'antd-style';
import { SendHorizontal } from 'lucide-react';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { useMidjourneyStore } from '@/store/midjourney';
import { useStore } from '@/store';

const useStyles = createStyles(({ css, token }) => ({
container: css`
padding: 4px;
background: ${token.colorFillTertiary};
border: 1px solid ${token.colorBorderSecondary};
border-radius: ${token.borderRadiusLG}px;
`,
prompt: css`
padding: 6px;
font-family: ${token.fontFamilyCode};
`,
}));

const PromptInput = memo(() => {
const [prompts, updatePrompts, createImagineTask] = useMidjourneyStore((s) => [
const { styles } = useStyles();
const [prompts, updatePrompts, createImagineTask] = useStore((s) => [
s.prompts,
s.updatePrompts,
s.createImagineTask,
]);

return (
<Flex gap={8}>
<Flex align={'flex-end'} className={styles.container} gap={8}>
<TextArea
autoSize={{ maxRows: 3, minRows: 1 }}
className={styles.prompt}
onChange={(e) => {
updatePrompts(e.target.value);
}}
placeholder={'请输入提示词'}
size={'large'}
style={{ maxHeight: 160, minHeight: 80 }}
type={'block'}
placeholder={'Midjourney Prompt...'}
resize={false}
type={'pure'}
value={prompts}
/>
<Flexbox direction={'vertical-reverse'} gap={8}>
<Button onClick={() => createImagineTask()} style={{ height: '100%' }} type={'primary'}>
生成
</Button>
</Flexbox>
<ActionIcon active icon={SendHorizontal} onClick={() => createImagineTask()} />
</Flex>
);
});
Expand Down
4 changes: 2 additions & 2 deletions src/features/Preview/Actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createStyles } from 'antd-style';
import { memo, useMemo } from 'react';
import { Flexbox } from 'react-layout-kit';

import { midjourneySelectors, useMidjourneyStore } from '@/store/midjourney';
import { midjourneySelectors, useStore } from '@/store';

import ImagineAction from './ImagineAction';

Expand All @@ -24,7 +24,7 @@ const useStyles = createStyles(({ css }) => ({
}));

const Actions = memo<{ setMask: (mask: boolean) => void }>(({ setMask }) => {
const currentTask = useMidjourneyStore(midjourneySelectors.currentActiveTask);
const currentTask = useStore(midjourneySelectors.currentActiveTask);
const { styles } = useStyles();
const content = useMemo(() => {
switch (currentTask?.action) {
Expand Down
105 changes: 22 additions & 83 deletions src/features/Preview/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,31 @@
import { Image } from '@lobehub/ui';
import { useSize } from 'ahooks';
import { Skeleton } from 'antd';
import { createStyles } from 'antd-style';
import { memo, useEffect, useRef, useState } from 'react';
import { Dimensions, getImageSize } from 'react-image-size';
import { memo, useState } from 'react';
import { Center } from 'react-layout-kit';

import { midjourneySelectors, useMidjourneyStore } from '@/store/midjourney';
import { midjourneySelectors, useStore } from '@/store';

import Actions from './Actions';

interface Size extends Dimensions {
aspectRadio: number;
}

const fetchImageSize = async (url: string): Promise<Size | undefined> => {
try {
const dim = await getImageSize(url);
return { ...dim, aspectRadio: dim.width / dim.height };
} catch (error) {
console.log(error);
return;
}
};

const getContainerSize = (content?: Dimensions, container?: Dimensions) => {
if (!content || !container) return {};
let width = String(content?.width);
let height = String(content?.height);

const maxWidth = container.width;
const maxHeight = container.height;
let maxValue: number = 0;

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';
}
maxValue = maxValue - 16;

return { height, maxValue, width };
};

const useStyles = createStyles(({ css, prefixCls }, inLobeChat: boolean) => {
const useStyles = createStyles(({ css, prefixCls, token }) => {
return {
empty: css`
width: var(--max);
height: var(--max);
background: ${token.colorTextTertiary};
border-radius: ${token.borderRadiusLG}px;
`,
image: css`
border-radius: ${inLobeChat ? 8 : 24}px;
border-radius: ${token.borderRadiusLG}px;
`,
imageWrapper: css`
margin-block: 0;
border-radius: ${inLobeChat ? 8 : 24}px;
border-radius: ${token.borderRadiusLG}px;
img {
width: var(--max);
height: var(--max);
}
`,
imagine: css`
.${prefixCls}-image-mask:hover {
Expand All @@ -68,33 +36,16 @@ const useStyles = createStyles(({ css, prefixCls }, inLobeChat: boolean) => {
});

const ImagePreview = memo(() => {
const inLobeChat = useMidjourneyStore((s) => s.inLobeChat);

const { styles, cx, theme } = useStyles(inLobeChat);
const { styles, cx } = useStyles();

const [modal, setMask] = useState<boolean>(false);
const [dim, setDims] = useState<Size>();
const containerRef = useRef(null);
const size = useSize(containerRef);

const imageContainerSize = getContainerSize(dim, size);

const currentTask = useMidjourneyStore(midjourneySelectors.currentActiveTask);

useEffect(() => {
const url = currentTask?.imageUrl;
if (!url) return;

fetchImageSize(url).then((size) => {
if (!size) return;
setDims(size);
});
}, [currentTask?.imageUrl]);
const currentTask = useStore(midjourneySelectors.currentActiveTask);

return (
<Center flex={1} height={'100%'} ref={containerRef} width={'100%'}>
<Center flex={1} height={`var(--max)`} width={`var(--max)`}>
{currentTask?.imageUrl ? (
<div style={{ position: 'relative' }}>
<div style={{ height: `var(--max)`, maxWidth: `var(--max)`, position: 'relative' }}>
<Image
className={styles.image}
preview={{ onVisibleChange: setMask, visible: modal }}
Expand All @@ -103,23 +54,11 @@ const ImagePreview = memo(() => {
styles.imageWrapper,
currentTask.action === 'IMAGINE' && styles.imagine,
)}
{...imageContainerSize}
/>
<Actions setMask={setMask} />
{currentTask.action !== 'UPSCALE' && <Actions setMask={setMask} />}
</div>
) : (
<Skeleton.Node
active
style={{
borderRadius: inLobeChat ? 8 : 24,
color: theme.colorTextTertiary,

height: imageContainerSize.maxValue || inLobeChat ? 400 : 600,
width: imageContainerSize.maxValue || inLobeChat ? 400 : 600,
}}
>
Task is waiting to start...
</Skeleton.Node>
<div className={styles.empty} />
)}
</Center>
);
Expand Down
Loading

0 comments on commit 1a57100

Please sign in to comment.