diff --git a/package.json b/package.json index 79e1d70..5c5b0a8 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "@types/lodash": "^4.14.170", "@types/react": "^17.0.13", "@types/react-dom": "^17.0.8", + "@types/react-is": "^17.0.2", "@types/react-transition-group": "^4.4.1", "@types/styled-components": "^5.1.11", "autoprefixer": "^10.2.6", diff --git a/src/AsanyEditor.tsx b/src/AsanyEditor.tsx index e101b19..3f6928b 100644 --- a/src/AsanyEditor.tsx +++ b/src/AsanyEditor.tsx @@ -43,22 +43,23 @@ function NotFound() { } function useComponent( - RootContainer: React.ComponentType, - children?: React.ReactNode + _RootContainer: React.ComponentType, + _children?: React.ReactNode ): React.ComponentType { const project = useSelector((state) => state.project); const ReactComponent = useRef>(NotFound); - const [, forceRender] = useReducer((s) => s + 1, 0); + // const [, forceRender] = useReducer((s) => s + 1, 0); if (!project || !project.type) { console.warn('project is null !'); } // const data = project.data as IComponentData; - const Component: any = () => <>; + // const Component: any = () => <>; // const Component = useReactComponent(data ? data.id : 'notFound', { // linkElement: LinkRender, // }); - console.log(Component, forceRender, RootContainer, children); + // TODO: 需要修补 + // console.log(Component, forceRender, RootContainer, children); // useEffect(() => { // if (project.type !== 'component') { // ReactComponent.current = () => <>{children}; diff --git a/src/components/aside/Aside.tsx b/src/components/aside/Aside.tsx index b3efbf4..f2d564a 100644 --- a/src/components/aside/Aside.tsx +++ b/src/components/aside/Aside.tsx @@ -1,5 +1,5 @@ // import { CloseOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons'; -// import { Tabs } from 'antd'; +import { Tabs } from 'antd'; import classnames from 'classnames'; import React, { CSSProperties, @@ -91,9 +91,9 @@ function Aside(props: AsideProps, ref: React.ForwardedRef) { state.current.panels = []; }, [tabs.map((item) => item.id || item.title)]); - // const handleChange = (activeKey: string) => { - // setActiveKey(activeKey); - // }; + const handleChange = (activeKey: string) => { + setActiveKey(activeKey); + }; const handleCloseNextAside = async () => { if (state.current.nextIndex == -1) { @@ -149,28 +149,26 @@ function Aside(props: AsideProps, ref: React.ForwardedRef) { })} > {!!tabs.length ? ( -
- {' '} - {/** - + {/* */} } > {tabs.map((item) => ( - + {item.content} ))} - */} - sdfsdfsdfsdf -
) : ( <>
diff --git a/src/components/resizer/Resizer.tsx b/src/components/resizer/Resizer.tsx index 7fd2eaa..b866563 100644 --- a/src/components/resizer/Resizer.tsx +++ b/src/components/resizer/Resizer.tsx @@ -8,6 +8,8 @@ import React, { import classnames from 'classnames'; +import './style/index.less'; + type ResizeFunc = (e: React.MouseEvent) => void; export type ResizerProps = { diff --git a/src/components/scena/Screen.tsx b/src/components/scena/Screen.tsx index f998dec..8ce0637 100644 --- a/src/components/scena/Screen.tsx +++ b/src/components/scena/Screen.tsx @@ -128,23 +128,25 @@ function Screen({ children }: ScreenProps) { height: `${zoom * 100}%`, }} > -
- {root?.title} - -
+ {root?.title} + +
+ )}
; + } + return React.createElement(icon); +} + function Toolbar() { const tools = useTools((state) => state.ui.scena.toolbar.tools); const focus = useSelector( @@ -32,12 +42,13 @@ function Toolbar() { - + {iconRender(item.icon)} {item.name && ( {item.name} )} @@ -58,12 +69,13 @@ function Toolbar() { - + {iconRender(item.icon)} {item.name && ( {item.name} )} diff --git a/src/components/scena/index.tsx b/src/components/scena/index.tsx index ee3b470..31076e3 100644 --- a/src/components/scena/index.tsx +++ b/src/components/scena/index.tsx @@ -2,6 +2,9 @@ import classnames from 'classnames'; import React, { useCallback, useEffect, useReducer, useRef } from 'react'; import { useDispatch, useEditor, useSelector } from '../../hooks'; + +import { isElement, isValidElementType } from 'react-is'; + import { ActionType, UIActionType, @@ -12,6 +15,7 @@ import Ruler, { RulerGuides } from '../Ruler'; import SelectoMananger from './SelectoMananger'; import Toolbar from './Toolbar'; import ScreenViewport from './viewport/ScreenViewport'; +import { WorkspaceProps } from '../../typings'; export interface ScenaStatus { dragStatus: boolean; @@ -33,6 +37,18 @@ interface ScenaState { isOpenConfig: boolean; } +function Workspace(props: WorkspaceProps) { + const workspace = useSelector((state) => state.ui.scena.workspace); + if (isElement(workspace)) { + return React.cloneElement(workspace, props); + } + if (isValidElementType(workspace)) { + const { children, ...otherProps } = props; + return React.createElement(workspace, otherProps, children); + } + return props.children as any; +} + function Scena(props: ScenaProps) { const ref = useRef(null); const dispatch = useDispatch(); @@ -169,7 +185,7 @@ function Scena(props: ScenaProps) { onZoom={handleZoom} > - {props.children} + {props.children} {selecto && } diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx index 6bb91c6..0258864 100644 --- a/src/components/sidebar/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -17,6 +17,9 @@ function SiderBar(props: SiderBarProps) { const dispatch = useDispatch(); const visible = useSelector((state) => state.ui.sidebar.visible); const [collapsed, setCollapsed] = useState(true); + const scenaToolbarVisible = useSelector( + (state) => state.ui.scena.toolbar.visible + ); const Content = useSelector((state) => state.ui.sidebar.content); @@ -31,6 +34,7 @@ function SiderBar(props: SiderBarProps) { className={classnames('sketch-sidebar', 'asany-editor-sidebar', { collapsed: collapsed, 'sidebar-out': !visible, + falling: scenaToolbarVisible, })} > diff --git a/src/components/sidebar/Toolbar.tsx b/src/components/sidebar/Toolbar.tsx index 2abc6b6..cf53645 100644 --- a/src/components/sidebar/Toolbar.tsx +++ b/src/components/sidebar/Toolbar.tsx @@ -7,6 +7,13 @@ import { useSelector } from '../../hooks'; import useTools from '../../hooks/useTools'; import { AsanyTool } from '../../typings'; +function iconRender(icon: any) { + if (typeof icon === 'string') { + return ; + } + return React.createElement(icon); +} + function Toolbar() { const toolboardKey = useSelector((state) => state.ui.sidebar.toolboardKey); @@ -36,13 +43,18 @@ function Toolbar() { .map((item, index: number) => (
  • - + {iconRender(item.icon)}
  • ))} @@ -55,12 +67,17 @@ function Toolbar() { .map((item) => (
  • - + {iconRender(item.icon)}
  • ))} diff --git a/src/components/sidebar/Toolboard.tsx b/src/components/sidebar/Toolboard.tsx index bb0f257..68f8f0b 100644 --- a/src/components/sidebar/Toolboard.tsx +++ b/src/components/sidebar/Toolboard.tsx @@ -260,13 +260,15 @@ function Toolboard(props: ToolboardProps, ref: React.ForwardedRef) { } }, [minWidth, state.current.offset]); + console.log('children', children); + return ( diff --git a/src/components/toolbar/Toolbar.tsx b/src/components/toolbar/Toolbar.tsx index 7c7cb63..207e47d 100644 --- a/src/components/toolbar/Toolbar.tsx +++ b/src/components/toolbar/Toolbar.tsx @@ -1,18 +1,25 @@ -// import { EyeOutlined, LeftOutlined } from '@ant-design/icons'; import classnames from 'classnames'; import { isEqual } from 'lodash'; import React, { useCallback } from 'react'; import { AsanyTool } from '../..'; import Icon from '../../icon'; -import { useAsanyStore, useSelector } from '../../hooks'; +import { useSelector } from '../../hooks'; import useTools from '../../hooks/useTools'; -import EnvironmentPicker from './EnvironmentPicker'; -import { ActionType } from '../../reducers/actions'; interface HeaderProps { onBack?: () => void; } +function iconRender(icon: any) { + if (!icon) { + return null; + } + if (typeof icon === 'string') { + return ; + } + return React.createElement(icon); +} + function render(item: AsanyTool, focus: any) { const disabled = item.isDisabled!(focus[item.id]); return item.render ? ( @@ -20,21 +27,19 @@ function render(item: AsanyTool, focus: any) { ) : (
    - - {item.name} + {iconRender(item.icon)} + {item.name && {item.name}} ); } function Header(props: HeaderProps) { const { onBack } = props; - const store = useAsanyStore(); - const dispatch = store.dispatch; - const viewed = useSelector((state) => state.mode === 'VIEW'); const name = useSelector((state) => state.project && state.project.name); const tools = useTools((state) => state.ui.toolbar.tools); @@ -49,37 +54,28 @@ function Header(props: HeaderProps) { ); const handClickBack = useCallback(() => onBack && onBack(), []); - const handlePreview = () => { - dispatch({ - type: ActionType.ChangeMode, - payload: viewed ? 'CONFIG' : 'VIEW', - }); - }; return (
    - {/* */} + {name}
    -
    - {tools - .filter( - (item) => - item.position === 'left' && item.isVisibled!(focus[item.id]) - ) - .map(render, focus)} -
    + {tools + .filter( + (item) => + item.position === 'left' && item.isVisibled!(focus[item.id]) + ) + .map(render, focus)}
    - - {/* */} - - {viewed ? '退出预览' : '预览'} - - - + {tools + .filter( + (item) => + item.position === 'right' && item.isVisibled!(focus[item.id]) + ) + .map(render, focus)}
    ); diff --git a/src/icons.tsx b/src/icons.tsx index ec53d58..aa3be45 100644 --- a/src/icons.tsx +++ b/src/icons.tsx @@ -873,3 +873,37 @@ Icon.register('Arrow', function Arrow({ onClick, className }: IconProps) { ); }); +Icon.register('SelectFilled', function SelectFilled() { + return ( + + + + + + ); +}); +Icon.register( + 'ToolbarBack', + function ToolbarBack({ onClick, className }: IconProps) { + return ( + + + + ); + } +); diff --git a/src/index.tsx b/src/index.tsx index cd63712..55e0d0c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,4 +6,5 @@ export { default as useBlock } from './hooks/useBlock'; export { default as Aside } from './components/aside/Aside'; export * from './components/aside/Aside'; export * from './typings'; +export * from './reducers/actions'; export * from './hooks'; diff --git a/src/reducers/plugin.reducer.ts b/src/reducers/plugin.reducer.ts index 011b84a..086316f 100644 --- a/src/reducers/plugin.reducer.ts +++ b/src/reducers/plugin.reducer.ts @@ -8,6 +8,7 @@ export default function reducer( action: AsanyAction ): IPluginState { if (GlobalAsanyAction.Init === action.type) { + console.log('GlobalAsanyAction', '--->', action); return { ...state, ...defaultState }; } return state; diff --git a/src/reducers/ui.reducer/scena.reducer/index.ts b/src/reducers/ui.reducer/scena.reducer/index.ts index 88c8722..eb35285 100644 --- a/src/reducers/ui.reducer/scena.reducer/index.ts +++ b/src/reducers/ui.reducer/scena.reducer/index.ts @@ -42,12 +42,14 @@ export function reducer( action: AsanyAction ): UIScenaGlobalState { if (action.type == UIScenaGlobalActionType.SetScena) { + const { workspace, toolbar } = action.payload; return { ...state, ...action.payload, + workspace, toolbar: { ...(state as any).toolbar, - ...action.payload.toolbar, + ...toolbar, }, }; } diff --git a/src/reducers/ui.reducer/sidebar.reducer.ts b/src/reducers/ui.reducer/sidebar.reducer.ts index 8e63890..5cfed9c 100644 --- a/src/reducers/ui.reducer/sidebar.reducer.ts +++ b/src/reducers/ui.reducer/sidebar.reducer.ts @@ -4,7 +4,7 @@ import { GlobalAsanyAction, UISidebarActionType } from '../actions'; const defaultState: IUISidebarState = { tools: [], width: 250, - visible: true, + visible: false, library: undefined, activeKeys: [], minWidth: 170, diff --git a/src/style/asany-editor.less b/src/style/asany-editor.less index 4eeeed2..cf10c7a 100644 --- a/src/style/asany-editor.less +++ b/src/style/asany-editor.less @@ -1,3 +1,17 @@ +body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td, hr, button, article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { + margin: 0; + padding: 0; +} +button, input { + overflow: visible; +} +input, button, select, optgroup, textarea { + margin: 0; + color: inherit; + font-size: inherit; + font-family: inherit; + line-height: inherit; +} .asany-editor { &-scena { &.mini-toolbar { @@ -41,7 +55,7 @@ min-width: 32px; height: 32px; margin-right: 4px; - padding: 8px; + padding: 0 8px; color: var(--text-color-subtle-contrast); font-size: 18px; diff --git a/src/style/aside.less b/src/style/aside.less index ee0ee58..78ca40d 100644 --- a/src/style/aside.less +++ b/src/style/aside.less @@ -1,5 +1,5 @@ .settings-menu-container { - position: fixed; + position: absolute; top: 60px; right: 0; bottom: 0; diff --git a/src/style/sketch.less b/src/style/sketch.less index c6ace72..962d8be 100644 --- a/src/style/sketch.less +++ b/src/style/sketch.less @@ -105,7 +105,7 @@ height: 100%; margin-right: 7px; color: rgb(141, 158, 167); - font-size: 16px; + font-size: 12px; cursor: pointer; transition: all 0.1s linear 0s; } @@ -128,10 +128,9 @@ flex-direction: column; align-items: center; justify-content: center; - width: 44px; + min-width: 44px; height: 100%; color: rgb(91, 107, 115); - border-top: 2px solid transparent; &.disabled { position: relative; color: rgb(200, 205, 208) !important; @@ -162,10 +161,10 @@ height: 16px; } .toolbar-icon-tip { - margin-top: 8px; + // margin-top: 8px; color: rgb(65, 80, 88); font-size: 12px; - line-height: 1; + // line-height: 1; white-space: nowrap; } } @@ -235,7 +234,6 @@ display: flex; align-items: center; justify-content: center; - height: 51px; min-height: 51px; border: 1px solid transparent; border-right: 0; @@ -283,7 +281,8 @@ z-index: 10; flex: 1; flex-direction: column; - height: calc(100vh - 50px); + height: 100%; + display: flex; background: var(--background-panels); box-shadow: 1px 0 2px 0 rgba(100, 100, 100, 0.2); transition: transform 0.4s cubic-bezier(0.1, 0.7, 0.1, 1); @@ -397,6 +396,13 @@ } } } + + &.falling { + .sidebar-resizer { + top: 90px; + height: calc(100vh - 91px); + } + } } .sketch-body { @@ -639,17 +645,30 @@ flex: 1; } + .zoom-out { + z-index: 2; + } + .zoom-in { + z-index: 2; + left: -2px; + } + .editable-zoom { + position: relative; + z-index: 1; + left: -1px; + background: var(--general-background); + border-top: 1px solid var(--gray-darkest); + border-bottom: 1px solid var(--gray-darkest); input { flex-basis: 20px; - max-width: 35px; - min-height: 20px; + max-width: 39px; + min-height: 18px; padding: 0; + border: 0; font-weight: 600; font-size: 12px; text-align: center; - background: var(--general-background); - border: 1px solid var(--gray-darkest); border-right: 0; border-left: 0; border-radius: 0; diff --git a/src/typings.ts b/src/typings.ts index 71e5710..f47c3f8 100644 --- a/src/typings.ts +++ b/src/typings.ts @@ -1,4 +1,4 @@ -import { ComponentType } from 'react'; +import { ComponentType, CSSProperties, ReactElement } from 'react'; import { OnDragEnd, OnResize, @@ -162,7 +162,7 @@ export interface AsanyTool { /** * 工具名称 */ - name?: string; + name?: string | React.ReactElement; /** * 是否可见 */ @@ -200,6 +200,14 @@ export interface AsanyTool { * 自定义渲染逻辑 */ render?: (item: AsanyToolData) => React.ReactElement; + /** + * 样式 + */ + className?: string; + /** + * 样式 + */ + style?: CSSProperties; } export type AsanyToolData = { @@ -342,6 +350,7 @@ export interface UIScenaGlobalState { snaps: GuidelinesDataSet; // 屏幕设置 screen: DeviceScreen; + workspace?: ComponentType | ReactElement; // 点击事件 onClick?: (editor: IAsanyEditor, block?: IUseBlockState) => void; } @@ -401,6 +410,10 @@ export interface ScenaHelper { unmask(delay?: number): Promise; } +export interface WorkspaceProps { + children: React.ReactNode | React.ReactNode[]; +} + export interface SidebarHelper { state: IUISidebarState; /** diff --git a/yarn.lock b/yarn.lock index bcb55d5..38c41b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3086,6 +3086,13 @@ dependencies: "@types/react" "*" +"@types/react-is@^17.0.2": + version "17.0.2" + resolved "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.2.tgz#abc4d910bff5b0bc6b3e1bec57575f6b63fd4e05" + integrity sha512-2+L0ilcAEG8udkDnvx8B0upwXFBbNnVwOsSCTxW3SDOkmar9NyEeLG0ZLa3uOEw9zyYf/fQapcnfXAVmDKlyHw== + dependencies: + "@types/react" "*" + "@types/react-syntax-highlighter@11.0.4": version "11.0.4" resolved "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz#d86d17697db62f98046874f62fdb3e53a0bbc4cd"