diff --git a/README.md b/README.md index 62730b1..1944834 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,8 @@ Easy peasy highly scalable nodejs APIs!

- NodeJs - Rest API + NodeJs + Rest API

# Code easy @@ -47,10 +47,10 @@ If you need help with Code easy platform, feel free to open an issue with a desc ## Built with

- React Js + React Js Typescript - NodeJs - Firebase + NodeJs + Firebase

## License diff --git a/src/app/pages/editor/Editor.css b/src/app/pages/editor/Editor.css index bd24b0c..5bc0f50 100644 --- a/src/app/pages/editor/Editor.css +++ b/src/app/pages/editor/Editor.css @@ -1,7 +1,2 @@ .main-page { - background-color: var(--main-background); - height: var(--size-window-vh-fill); - width: var(--size-window-vw-fill); - flex-direction: column; - display: flex; } diff --git a/src/app/pages/editor/Editor.tsx b/src/app/pages/editor/Editor.tsx index 8b52ee9..2e3b156 100755 --- a/src/app/pages/editor/Editor.tsx +++ b/src/app/pages/editor/Editor.tsx @@ -10,17 +10,31 @@ export const Editor: React.FC = () => { -
+ + + + + + +
+
-
{/* 2px is in 2x
*/} +

+
+ + + + + + diff --git a/src/app/pages/editor/editor-tab/Playground.tsx b/src/app/pages/editor/editor-tab/Playground.tsx index c1028cf..89ccce6 100644 --- a/src/app/pages/editor/editor-tab/Playground.tsx +++ b/src/app/pages/editor/editor-tab/Playground.tsx @@ -1,41 +1,36 @@ import React, { memo } from 'react'; -import { TwoColumnsResizable, TwoRowsResizable, OutputPanel } from '../../../shared/components'; +import { TwoRowsResizable, OutputPanel, TwoColumnsResizable } from '../../../shared/components'; import { PropertiesEditorController } from './PropertiesEditor.Controller'; import { TreeManagerController } from './TreeManager.Controller'; import { FlowEditorController } from './FlowEditor.Controller'; export const Playground: React.FC = memo(() => { return ( - + } + bottom={ +
+ +
+ } + /> +
} - id={"TwoRowsResizableOutput"} - maxBottomHeight={"99%"} - useMinMaxHeight={true} - minBottomHeight={"1%"} - bottom={ -
- -
- } + id="EditorTabRightRows" + top={} + bottom={} /> - } - right={ -
- } - bottom={} - /> -
- } - /> +
+
); }); diff --git a/src/app/pages/home-page/HomePage.tsx b/src/app/pages/home-page/HomePage.tsx index cd70003..2ebcd33 100755 --- a/src/app/pages/home-page/HomePage.tsx +++ b/src/app/pages/home-page/HomePage.tsx @@ -46,7 +46,7 @@ export const HomePage = () => { }, []); return ( -
+
= ({ children, maxWidths = children.map(() => 'auto'), minWidth = 100 }) => { + const containerRef = useRef(null); + + const [sizes, setSizes] = useState(children.map(() => 0)); + const oldBodyClientWidth = useRef(0); + const extraWidthRef = useRef(0); + const oldPageX = useRef(0); + + // Initialize oldBodyClientWidth + useEffect(() => { + oldBodyClientWidth.current = document.body.clientWidth; + }, []); + + // Validate maxWidths + useEffect(() => { + if (maxWidths.length !== children.length) { + throw new Error("The number of items in maxWidths must be the same as children in the 'ResizableColumns' component"); + } + }, [children.length, maxWidths]); + + // Initialize childs sizes + useEffect(() => { + setSizes(oldSizes => { + /** The ResizableColumns main container client width */ + const containerClientWidth = containerRef.current?.clientWidth || 0; + + /** The sum of all old sizes */ + const sumOfAllOldSizes = oldSizes.reduce((size, curSize) => size > minWidth ? curSize + size : curSize, 0); + + /** The number of sizes that are less than minWidth */ + const numberOfSizesLessThanMinWidth = oldSizes.filter(size => size < minWidth).length; + + /** The value to sizes less than min width */ + const valueToSizesLessThanMinWidth = (containerClientWidth - sumOfAllOldSizes) / numberOfSizesLessThanMinWidth; + + // Change value to sizes less than minWidth + oldSizes = oldSizes.map(() => valueToSizesLessThanMinWidth); + + /* if (sumOfAllOldSizes < containerClientWidth) { + if (oldSizes.length > 0) { + oldSizes[0] += containerClientWidth - sumOfAllOldSizes; + } + } else if (sumOfAllOldSizes > containerClientWidth) { + console.log('entrou') + } */ + + return [...oldSizes]; + }); + }, [minWidth]); + + const handleWindowResize = useCallback(() => { + const clientWidth = containerRef.current?.clientWidth; + if (clientWidth) { + const diference = oldBodyClientWidth.current - document.body.clientWidth; + oldBodyClientWidth.current = document.body.clientWidth; + + setSizes(oldSizes => { + if (diference > 0) { + const splitedValue = diference / oldSizes.filter(oldValue => (oldValue > minWidth)).length; + return [ + ...oldSizes.map(oldValue => (oldValue > minWidth) ? oldValue -= splitedValue : oldValue), + ]; + } else { + const splitedValue = diference / oldSizes.length; + return [ + ...oldSizes.map(oldValue => oldValue -= splitedValue), + ]; + } + }); + } + }, [minWidth]); + + // Listen to window size changes + useEffect(() => { + window.addEventListener('resize', handleWindowResize); + return () => window.removeEventListener('resize', handleWindowResize); + }, [handleWindowResize]); + + const handleMouseMove = useCallback((e: any, index: number) => { + const movementX = e.pageX - oldPageX.current; + oldPageX.current = e.pageX; + + setSizes(oldSizes => { + if (extraWidthRef.current > 5 || extraWidthRef.current < -5) { + extraWidthRef.current += movementX; + return [...oldSizes]; + } else { + if ( + (oldSizes[index - 1] + movementX) > maxWidths[index] || + (oldSizes[index] - movementX) > maxWidths[index] || + (oldSizes[index - 1] + movementX) < minWidth || + (oldSizes[index] - movementX) < minWidth + ) { + extraWidthRef.current += movementX; + return oldSizes; + } + + oldSizes[index - 1] += movementX; + oldSizes[index] -= movementX; + + return [...oldSizes]; + } + }); + }, [maxWidths, minWidth]); + + const handleMouseUp = useCallback(() => { + extraWidthRef.current = 0; + window.onmouseup = null; + window.onmousemove = null; + window.document.body.style.cursor = 'unset'; + }, []); + + const handleMouseDown = useCallback((e: React.MouseEvent, index: number) => { + window.onmousemove = (e: any) => handleMouseMove(e, index); + window.document.body.style.cursor = 'e-resize'; + window.onmouseup = handleMouseUp; + oldPageX.current = e.pageX; + }, [handleMouseUp, handleMouseMove]); + + return ( +
+ {children.map((child, index) => ( +
minWidth ? sizes[index] : minWidth + }} + > + {index !== 0 && ( + <> +
handleMouseDown(e, index)} + style={{ + zIndex: 1, + cursor: 'e-resize', + width: 'var(--main-grapper-size)', + marginRight: 'calc(var(--main-grapper-size) - (2 * var(--main-grapper-size)))', + }} + /> +
handleMouseDown(e, index)} + /> + + )} + {child} +
+ ))} +
+ ); +} diff --git a/src/app/shared/components/resizable-columns/TwoColumnsResizable.tsx b/src/app/shared/components/resizable-columns/TwoColumnsResizable.tsx index ecc4b09..62e017c 100644 --- a/src/app/shared/components/resizable-columns/TwoColumnsResizable.tsx +++ b/src/app/shared/components/resizable-columns/TwoColumnsResizable.tsx @@ -1,55 +1,101 @@ -import React, { Component } from 'react'; +import React, { useCallback, useRef, useState } from 'react'; import { IdeConfigStorage } from '../../services'; -interface IRecipeProps { - id: string, - left: JSX.Element, - right: JSX.Element, - aligment: 'left' | 'center' | 'right', +interface TwoColumnsResizableProps { + minWidth?: number; + maxWidth?: number; + variant?: "left" | "right"; + children: [React.ReactElement, React.ReactElement]; } -export class TwoColumnsResizable extends Component { - private isRight = this.props.aligment === 'right'; +export const TwoColumnsResizable: React.FC = ({ variant = 'right', children: [leftChild, rightChild], minWidth, maxWidth }) => { + const oldPageX = useRef(0); - state = { colX: 300 } + const [[sizeLeft, sizeRight], setSizes] = useState([ + variant === 'left' ? IdeConfigStorage.getResizableColumns(String(leftChild.key)) : 0, + variant === 'right' ? IdeConfigStorage.getResizableColumns(String(rightChild.key)) : 0, + ]); - componentDidMount() { - this.setState({ colX: IdeConfigStorage.getColumnsResizableSize(this.props.id) }); - window.addEventListener("resize", () => this.setState({})); - } + const handleMouseMove = useCallback((e: any) => { + const movementX = e.pageX - oldPageX.current; + oldPageX.current = e.pageX; - componentWillUnmount() { - window.removeEventListener("resize", () => this.setState({})); - } + setSizes(oldSizes => { + if (variant === 'left') { + oldSizes[0] += movementX; + } else { + oldSizes[1] -= movementX; + } + return [...oldSizes]; + }); + }, [variant]); - mouseMove = (event: any) => { - this.setState({ colX: this.isRight ? (window.innerWidth - event.pageX + 6) : event.pageX }); - } - - mouseUp = () => { + const handleMouseUp = useCallback(() => { + oldPageX.current = 0; window.onmouseup = null; window.onmousemove = null; window.document.body.style.cursor = 'unset'; - IdeConfigStorage.setColumnsResizableSize(this.props.id, this.state.colX); - } + setSizes(oldSizes => { + if (variant === 'left') { + if (maxWidth && oldSizes[0] > maxWidth) { + oldSizes[0] = maxWidth; + } else if (minWidth && oldSizes[0] < minWidth) { + oldSizes[0] = minWidth; + } + } else { + if (maxWidth && oldSizes[1] > maxWidth) { + oldSizes[1] = maxWidth; + } else if (minWidth && oldSizes[1] < minWidth) { + oldSizes[1] = minWidth; + } + } + return [...oldSizes]; + }); + }, [variant, maxWidth, minWidth]); - mouseDown = () => { + const handleMouseDown = useCallback((e: React.MouseEvent) => { + window.onmousemove = (e: any) => handleMouseMove(e); window.document.body.style.cursor = 'e-resize'; - window.onmousemove = this.mouseMove; - window.onmouseup = this.mouseUp; - } - - render = () => ( -
-
{this.props.left}
-
-
-
-
- {this.props.right} -
+ window.onmouseup = handleMouseUp; + oldPageX.current = e.pageX; + }, [handleMouseUp, handleMouseMove]); + + return ( +
+
+ {leftChild} +
+
+
handleMouseDown(e)} + style={{ + zIndex: 1, + cursor: 'e-resize', + width: 'var(--main-grapper-size)', + marginRight: 'calc(var(--main-grapper-size) - (2 * var(--main-grapper-size)))', + }} + /> +
handleMouseDown(e)} + style={{ cursor: 'e-resize', zIndex: 1 }} + /> + {rightChild}
); - } diff --git a/src/app/shared/services/storage/IdeConfigStorage.ts b/src/app/shared/services/storage/IdeConfigStorage.ts index 480b662..86d676d 100644 --- a/src/app/shared/services/storage/IdeConfigStorage.ts +++ b/src/app/shared/services/storage/IdeConfigStorage.ts @@ -51,4 +51,22 @@ export class IdeConfigStorage { localStorage.setItem(id, size.toString()); return size; } + + + /** + * Get the saved state from a ColumnResizable at localstorage + * + * @returns `number` or `0` + */ + public static getResizableColumns(id: string): number { + let props = localStorage.getItem(id); + return parseInt(props || '0'); + } + + /** Save the state from a ColumnResizable in the localstorage */ + public static setResizableColumns(id: string, size: number): number { + localStorage.setItem(id, size.toString()); + return size; + } + }