From 6fe7001b405ad9bc85f83905a9f44d4e98c03527 Mon Sep 17 00:00:00 2001 From: canisminor1990 Date: Tue, 4 Apr 2023 00:28:54 +0800 Subject: [PATCH] :sparkles: feat: base done --- package.json | 1 + .../ConfigProvider/AppContainer.tsx | 25 ++-- .../ConfigProvider/ConfigProvider.tsx | 53 +++++++ .../ConfigProvider/index.tsx | 0 src/components/Containers/FlowContainer.tsx | 7 +- .../Containers/ImageViewContainer.tsx | 18 --- src/components/Containers/index.tsx | 1 - src/components/ControlPanelComponent.tsx | 106 -------------- .../GalleryComponent.tsx | 42 ++++++ .../ControlPanelComponent/Label.tsx | 14 ++ .../NodePickerComponent.tsx | 26 ++-- .../ControlPanelComponent/QueueComponent.tsx | 43 ++++++ .../WorkflowPageComponent.tsx | 24 ++++ .../ControlPanelComponent/index.tsx | 85 ++++++++++++ .../EditorComponent/ActionIcon/ActionIcon.tsx | 38 ++--- .../EditorComponent/CollapseTitle/index.tsx | 50 +++---- .../EditorComponent/CollapseTitle/style.ts | 16 ++- .../ConfigProvider/ConfigProvider.tsx | 60 -------- .../DraggablePanel/DraggablePanel.tsx | 64 ++++----- .../DraggablePanel/FixMode.tsx | 130 +++++++++--------- src/components/EditorComponent/Input.tsx | 35 +++-- .../EditorComponent/InputNumber.tsx | 25 ++-- src/components/EditorComponent/Segmented.tsx | 38 ++--- src/components/EditorComponent/Select.tsx | 26 ++-- src/components/EditorComponent/Tabs.tsx | 57 ++++---- src/components/EditorComponent/Tree.tsx | 16 +-- src/components/EditorComponent/TreeSelect.tsx | 14 +- src/components/EditorComponent/index.ts | 17 ++- .../EditorComponent/override/button.ts | 4 +- src/components/GalleryComponent.tsx | 74 ---------- src/components/Header.tsx | 30 ++++ src/components/ImageViewComponent.tsx | 21 --- .../{ => NodeComponent}/InputComponent.tsx | 5 +- src/components/QueueComponent.tsx | 53 ------- src/components/WorkflowPageComponent.tsx | 26 ---- src/components/index.ts | 14 +- src/components/theme/index.ts | 15 +- src/components/theme/themes/darkAlgorithm.ts | 11 +- src/layouts/GlobalStyle.ts | 22 +++ src/{pages => layouts}/WsController.tsx | 0 src/layouts/index.tsx | 37 +++-- src/pages/App.tsx | 19 +-- src/utils/index.ts | 1 + 43 files changed, 666 insertions(+), 697 deletions(-) rename src/components/{EditorComponent => }/ConfigProvider/AppContainer.tsx (70%) create mode 100644 src/components/ConfigProvider/ConfigProvider.tsx rename src/components/{EditorComponent => }/ConfigProvider/index.tsx (100%) delete mode 100644 src/components/Containers/ImageViewContainer.tsx delete mode 100644 src/components/ControlPanelComponent.tsx create mode 100644 src/components/ControlPanelComponent/GalleryComponent.tsx create mode 100644 src/components/ControlPanelComponent/Label.tsx rename src/components/{ => ControlPanelComponent}/NodePickerComponent.tsx (51%) create mode 100644 src/components/ControlPanelComponent/QueueComponent.tsx create mode 100644 src/components/ControlPanelComponent/WorkflowPageComponent.tsx create mode 100644 src/components/ControlPanelComponent/index.tsx delete mode 100644 src/components/EditorComponent/ConfigProvider/ConfigProvider.tsx delete mode 100644 src/components/GalleryComponent.tsx create mode 100644 src/components/Header.tsx delete mode 100644 src/components/ImageViewComponent.tsx rename src/components/{ => NodeComponent}/InputComponent.tsx (94%) delete mode 100644 src/components/QueueComponent.tsx delete mode 100644 src/components/WorkflowPageComponent.tsx rename src/{pages => layouts}/WsController.tsx (100%) diff --git a/package.json b/package.json index beebda0..6e37489 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "husky": "^8", "lint-staged": "^13.2.0", "lodash-es": "^4.17.21", + "polished": "^4.2.2", "prettier": "^2", "prettier-plugin-organize-imports": "^3", "prettier-plugin-packagejson": "^2", diff --git a/src/components/EditorComponent/ConfigProvider/AppContainer.tsx b/src/components/ConfigProvider/AppContainer.tsx similarity index 70% rename from src/components/EditorComponent/ConfigProvider/AppContainer.tsx rename to src/components/ConfigProvider/AppContainer.tsx index 29c5135..1bb4a7f 100644 --- a/src/components/EditorComponent/ConfigProvider/AppContainer.tsx +++ b/src/components/ConfigProvider/AppContainer.tsx @@ -1,8 +1,7 @@ -import { ThemeConfig } from 'antd/es/config-provider/context'; -import type { FC, PropsWithChildren } from 'react'; -import { GetAntdThemeConfig, STUDIO_UI_PREFIX } from '@/components/theme'; +import { GetAntdThemeConfig, STUDIO_UI_PREFIX } from '@/components/theme' +import { ThemeConfig } from 'antd/es/config-provider/context' +import type { FC, PropsWithChildren } from 'react' -import { OverrideAntdGlobalStyles } from '../override'; import { createStudioAntdTheme, getStudioStylish, @@ -10,7 +9,8 @@ import { ThemeAppearance, ThemeMode, ThemeProvider, -} from '@/components/theme'; +} from '@/components/theme' +import { OverrideAntdGlobalStyles } from '../EditorComponent/override' /** * @title 应用容器属性 @@ -19,27 +19,22 @@ export interface AppContainerProps { /** * @title 主题外观 */ - appearance?: ThemeAppearance; + appearance?: ThemeAppearance /** * @title 主题模式 * @enum ['light', 'dark'] * @enumNames ['亮色', '暗色'] * @default 'light' */ - themeMode?: ThemeMode; + themeMode?: ThemeMode /** * @title 主题配置 * @description 可以传入一个对象或者函数来生成主题配置 */ - theme?: ThemeConfig | GetAntdThemeConfig; + theme?: ThemeConfig | GetAntdThemeConfig } -export const AppContainer: FC> = ({ - children, - theme, - appearance, - themeMode, -}) => ( +export const AppContainer: FC> = ({ children, theme, appearance, themeMode }) => ( > = ({ {children} -); +) diff --git a/src/components/ConfigProvider/ConfigProvider.tsx b/src/components/ConfigProvider/ConfigProvider.tsx new file mode 100644 index 0000000..a304d7f --- /dev/null +++ b/src/components/ConfigProvider/ConfigProvider.tsx @@ -0,0 +1,53 @@ +import { createStudioAntdTheme } from '@/components/theme' +import { useStore } from '@/layouts/useStore' +import { AntdToken, ThemeAppearance, ThemeProvider, setupStyled, useAntdToken, useThemeMode } from 'antd-style' +import type { OverrideToken } from 'antd/es/theme/interface' +import type { FC, ReactNode } from 'react' +import { ThemeContext } from 'styled-components' + +export const useStudioAntdTheme = (appearance: ThemeAppearance) => { + const token = useAntdToken() + const themeConfig = createStudioAntdTheme(appearance) + + const controlToken: Partial = { + colorBgContainer: token?.colorFillQuaternary, + colorBorder: 'transparent', + controlHeightSM: 24, + controlOutline: 'transparent', + } + + themeConfig.components = { + Input: controlToken, + InputNumber: controlToken, + Select: controlToken, + Tree: { + colorBgContainer: undefined, + controlHeightSM: 24, + }, + TreeSelect: controlToken, + } + + return themeConfig +} + +export interface ConfigProviderProps { + componentToken?: OverrideToken + children: ReactNode +} + +export const ConfigProvider: FC = ({ children, componentToken }) => { + setupStyled({ ThemeContext }) + const themeMode = useStore() + const { appearance } = useThemeMode() + const studioTheme = useStudioAntdTheme(appearance) + + if (componentToken) { + studioTheme.components = { ...studioTheme.components, ...componentToken } + } + + return ( + + {children} + + ) +} diff --git a/src/components/EditorComponent/ConfigProvider/index.tsx b/src/components/ConfigProvider/index.tsx similarity index 100% rename from src/components/EditorComponent/ConfigProvider/index.tsx rename to src/components/ConfigProvider/index.tsx diff --git a/src/components/Containers/FlowContainer.tsx b/src/components/Containers/FlowContainer.tsx index 151dc23..9ad01d2 100644 --- a/src/components/Containers/FlowContainer.tsx +++ b/src/components/Containers/FlowContainer.tsx @@ -1,7 +1,7 @@ -import { ImageViewContainer, NODE_IDENTIFIER, NodeContainer } from '@/components' +import { NODE_IDENTIFIER, NodeContainer } from '@/components' import { useAppStore } from '@/store' import React from 'react' -import ReactFlow, { Background, BackgroundVariant, Controls, Panel } from 'reactflow' +import ReactFlow, { Background, BackgroundVariant, Controls } from 'reactflow' import 'reactflow/dist/style.css' import { shallow } from 'zustand/shallow' @@ -37,9 +37,6 @@ const FlowContainer: React.FC = () => { > - - - ) } diff --git a/src/components/Containers/ImageViewContainer.tsx b/src/components/Containers/ImageViewContainer.tsx deleted file mode 100644 index 317165d..0000000 --- a/src/components/Containers/ImageViewContainer.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { ImageViewComponent } from '@/components' -import { useAppStore } from '@/store' -import React from 'react' -import { shallow } from 'zustand/shallow' - -const ImageViewContainer: React.FC = () => { - const { image, onPreviewImageNavigate } = useAppStore( - (st) => ({ - image: st.previewedImageIndex !== undefined ? st.gallery[st.previewedImageIndex]?.image : undefined, - onHideImagePreview: st.onHideImagePreview, - onPreviewImageNavigate: st.onPreviewImageNavigate, - }), - shallow - ) - return -} - -export default React.memo(ImageViewContainer) diff --git a/src/components/Containers/index.tsx b/src/components/Containers/index.tsx index cdce433..7dce109 100644 --- a/src/components/Containers/index.tsx +++ b/src/components/Containers/index.tsx @@ -1,7 +1,6 @@ export { default as ControlPanelContainer } from './ControlPanelContainer' export { default as FlowContainer } from './FlowContainer' export { default as GalleryContainer } from './GalleryContainer' -export { default as ImageViewContainer } from './ImageViewContainer' export { default as InputContainer } from './InputContainer' export { default as NodeContainer } from './NodeContainer' export { default as NodePickerContainer } from './NodePickerContainer' diff --git a/src/components/ControlPanelComponent.tsx b/src/components/ControlPanelComponent.tsx deleted file mode 100644 index f968403..0000000 --- a/src/components/ControlPanelComponent.tsx +++ /dev/null @@ -1,106 +0,0 @@ -import { GalleryContainer, NodePickerContainer, QueueContainer, WorkflowPageContainer } from '@/components' -import { ExitFullScreenIcon } from '@radix-ui/react-icons' -import { Button } from 'antd' -import React, { useState } from 'react' - -type Tab = 'Queue' | 'Gallery' | 'Nodes' | 'Workflow' - -interface PanelState { - activeTab: Tab - minimized: boolean -} - -interface ControlPanelComponentProps { - promptError?: string - onSubmit: () => Promise -} - -const TABS: Tab[] = ['Queue', 'Gallery', 'Nodes', 'Workflow'] - -const ControlPanelComponent: React.FC = ({ onSubmit, promptError }) => { - const [{ activeTab, minimized }, setState] = useState({ - activeTab: 'Queue', - minimized: false, - }) - - return ( - <> - {promptError !== undefined ? ( -
- {promptError} -
- ) : ( - <> - )} -
- setState({ minimized: false, activeTab: tab })}> - - setState((st) => ({ ...st, minimized: !st.minimized }))} - /> - - {minimized ? ( - <> - ) : ( -
- {minimized ? ( - <> - ) : activeTab === 'Queue' ? ( - - ) : activeTab === 'Gallery' ? ( - - ) : activeTab === 'Nodes' ? ( - - ) : ( - - )} -
- )} -
- - ) -} - -export default React.memo(ControlPanelComponent) - -interface PanelTabsProps { - tabs: T[] - active: T - onTabChange: (tab: T) => void - children: JSX.Element[] -} - -const PanelTabs: React.FC> = ({ tabs, active, onTabChange, children }) => { - return ( -
- {tabs.map((t) => ( - onTabChange(t)} /> - ))} - {children} -
- ) -} - -interface PanelTabProps { - label: string - isActive: boolean - onClick: () => void -} - -const PanelTab: React.FC = ({ label, isActive, onClick }) => { - const bgClasses = isActive ? ['bg-stone-600'] : ['bg-stone-800', 'hover:bg-stone-700'] - const defaultClasses = ['p-2', 'mx-0.5', 'cursor-pointer'] - return ( -
- {label} -
- ) -} diff --git a/src/components/ControlPanelComponent/GalleryComponent.tsx b/src/components/ControlPanelComponent/GalleryComponent.tsx new file mode 100644 index 0000000..423be04 --- /dev/null +++ b/src/components/ControlPanelComponent/GalleryComponent.tsx @@ -0,0 +1,42 @@ +import { getBackendUrl } from '@/config' +import { type GalleryItem } from '@/types' +import { Empty, Image } from 'antd' +import queryString from 'query-string' +import React from 'react' +import styled from 'styled-components' + +const ImgList = styled.div` + display: flex; + flex-wrap: wrap; +` + +interface Props { + gallery: GalleryItem[] +} + +const GalleryComponent: React.FC = ({ gallery }) => { + return gallery.length === 0 ? ( + + ) : ( + + + {gallery + .map(({ image }) => ( + + )) + .reverse()} + + + ) +} + +export default React.memo(GalleryComponent) diff --git a/src/components/ControlPanelComponent/Label.tsx b/src/components/ControlPanelComponent/Label.tsx new file mode 100644 index 0000000..6fd65c2 --- /dev/null +++ b/src/components/ControlPanelComponent/Label.tsx @@ -0,0 +1,14 @@ +import React from 'react' + +interface LabelProps { + label: string + value: string +} +const Label: React.FC = ({ label, value }) => { + return ( +
+ {label}: {value} +
+ ) +} +export default React.memo(Label) diff --git a/src/components/NodePickerComponent.tsx b/src/components/ControlPanelComponent/NodePickerComponent.tsx similarity index 51% rename from src/components/NodePickerComponent.tsx rename to src/components/ControlPanelComponent/NodePickerComponent.tsx index cc3e6ca..81e80c8 100644 --- a/src/components/NodePickerComponent.tsx +++ b/src/components/ControlPanelComponent/NodePickerComponent.tsx @@ -1,5 +1,7 @@ +import { CollapseTitle } from '@/components' import type { NodeItem, Widget, WidgetKey } from '@/types' -import { PlusIcon } from '@radix-ui/react-icons' +import { Button, Space } from 'antd' +import { startCase } from 'lodash-es' import React from 'react' interface NodePickerComponentProps { @@ -18,23 +20,17 @@ const NodePickerComponent: React.FC = ({ widgets, onAd } return ( -
+
{Object.entries(byCategory).map(([cat, items]) => ( -
-

{cat}

-
+ + {items.map((i) => ( -
onAddNode({ widget: i })} - > - - {i.name} -
+ ))} -
-
+ + ))}
) diff --git a/src/components/ControlPanelComponent/QueueComponent.tsx b/src/components/ControlPanelComponent/QueueComponent.tsx new file mode 100644 index 0000000..baa3e1b --- /dev/null +++ b/src/components/ControlPanelComponent/QueueComponent.tsx @@ -0,0 +1,43 @@ +import { type QueueItem } from '@/types' +import { TrashIcon } from '@radix-ui/react-icons' +import { Card } from 'antd' +import React from 'react' +import styled from 'styled-components' +import Label from './Label' + +const CardList = styled.div` + display: flex; + flex-direction: column; +` + +interface QueueComponentProps { + queue: QueueItem[] + onDeleteFromQueue: (id: number) => Promise +} + +const QueueComponent: React.FC = ({ queue, onDeleteFromQueue }) => { + return queue.length === 0 ? null : ( + + {queue.map((it, i) => ( + { + void onDeleteFromQueue(it.id) + }} + /> + } + > + + ))} + + ) +} + +export default React.memo(QueueComponent) diff --git a/src/components/ControlPanelComponent/WorkflowPageComponent.tsx b/src/components/ControlPanelComponent/WorkflowPageComponent.tsx new file mode 100644 index 0000000..3fb6524 --- /dev/null +++ b/src/components/ControlPanelComponent/WorkflowPageComponent.tsx @@ -0,0 +1,24 @@ +import { readWorkflowFromFile, type PersistedGraph } from '@/persistence' +import { Button, Input } from 'antd' +import React from 'react' + +interface WorkflowPageComponentProps { + onLoadWorkflow: (persisted: PersistedGraph) => void + onSaveWorkflow: () => void +} + +const WorkflowPageComponent: React.FC = ({ onLoadWorkflow, onSaveWorkflow }) => { + return ( +
+
Load workflow
+ readWorkflowFromFile(ev, onLoadWorkflow)} /> +
+
Save workflow
+ +
+ ) +} + +export default React.memo(WorkflowPageComponent) diff --git a/src/components/ControlPanelComponent/index.tsx b/src/components/ControlPanelComponent/index.tsx new file mode 100644 index 0000000..fda1795 --- /dev/null +++ b/src/components/ControlPanelComponent/index.tsx @@ -0,0 +1,85 @@ +import { GalleryContainer, NodePickerContainer, QueueContainer, Tabs, WorkflowPageContainer } from '@/components' +import { Button, message } from 'antd' +import React, { useEffect, useState } from 'react' +import styled from 'styled-components' + +const SideBar = styled.div` + display: flex; + flex-direction: column; + height: 100%; +` + +const Footer = styled.div` + flex: none; + padding: 12px 0; +` + +interface ControlPanelComponentProps { + promptError?: string + onSubmit: () => Promise +} + +const ControlPanelComponent: React.FC = ({ onSubmit, promptError }) => { + const [messageApi, contextHolder] = message.useMessage() + const [count, setCount] = useState(0) + + useEffect(() => { + if (promptError !== undefined) + messageApi.open({ + type: 'error', + content: promptError, + duration: 4, + }) + }, [promptError, count]) + + return ( + <> + {contextHolder} + + +
+ +
+
+ + +
+ + ), + }, + { + label: 'Nodes', + key: 'Nodes', + children: , + }, + { + label: 'Gallery', + key: 'Gallery', + children: , + }, + ]} + /> +
+ + ) +} + +export default React.memo(ControlPanelComponent) diff --git a/src/components/EditorComponent/ActionIcon/ActionIcon.tsx b/src/components/EditorComponent/ActionIcon/ActionIcon.tsx index 2f36c57..0e92b45 100644 --- a/src/components/EditorComponent/ActionIcon/ActionIcon.tsx +++ b/src/components/EditorComponent/ActionIcon/ActionIcon.tsx @@ -1,9 +1,9 @@ -import type { ButtonProps, TooltipProps } from 'antd'; -import { Button, Tooltip } from 'antd'; -import type { CSSProperties, FC } from 'react'; -import { ConfigProvider } from '../ConfigProvider'; -import { cx, getPrefixCls, useToken } from '@/components/theme'; -import { useStyles } from './style'; +import { cx, getPrefixCls, useToken } from '@/components/theme' +import type { ButtonProps, TooltipProps } from 'antd' +import { Button, Tooltip } from 'antd' +import type { CSSProperties, FC } from 'react' +import { ConfigProvider } from '../../ConfigProvider' +import { useStyles } from './style' /** * @title 动作图标属性 @@ -13,27 +13,27 @@ export interface ActionIconProps extends Omit { /** * @title 鼠标类型 */ - cursor?: CSSProperties['cursor']; + cursor?: CSSProperties['cursor'] /** * @title 动作提示 */ - title?: TooltipProps['title']; + title?: TooltipProps['title'] /** * @title 提示位置 */ - placement?: TooltipProps['placement']; + placement?: TooltipProps['placement'] /** * @title 图标 */ - icon: ButtonProps['icon']; + icon: ButtonProps['icon'] /** * @title 点击回调 */ - onClick?: ButtonProps['onClick']; + onClick?: ButtonProps['onClick'] /** * @title 图标尺寸 */ - size?: 'default' | 'large' | number; + size?: 'default' | 'large' | number } const ActionIcon: FC = ({ @@ -47,10 +47,10 @@ const ActionIcon: FC = ({ prefixCls: customPrefixCls, ...restProps }) => { - const prefixCls = getPrefixCls('actionicon', customPrefixCls); - const { styles } = useStyles({ size, prefixCls }); + const prefixCls = getPrefixCls('actionicon', customPrefixCls) + const { styles } = useStyles({ size, prefixCls }) - const token = useToken(); + const token = useToken() const Icon = (