diff --git a/src/App.tsx b/src/App.tsx index 5f20f93..705e40d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,9 +2,9 @@ import * as React from 'react'; import './App.scss'; import { MainMenu } from './Components/MainMenu/MainMenu'; import { ContainerModel, IContainerModel } from './Interfaces/ContainerModel'; -import { findContainerById, MakeIterator } from './utils/itertools'; import Editor, { IEditorState } from './Editor'; import { Configuration } from './Interfaces/Configuration'; +import { Revive } from './utils/saveload'; export interface IHistoryState { MainContainer: IContainerModel | null @@ -182,38 +182,3 @@ export async function fetchConfiguration(): Promise { xhr.send(); }); } - -/** - * Revive the Editor state - * by setting the containers references to their parent - * @param editorState Editor state - */ -function Revive(editorState: IEditorState): void { - const history = editorState.history; - for (const state of history) { - if (state.MainContainer === null || state.MainContainer === undefined) { - continue; - } - - const it = MakeIterator(state.MainContainer); - for (const container of it) { - const parentId = container.properties.parentId; - if (parentId === null) { - container.parent = null; - continue; - } - const parent = findContainerById(state.MainContainer, parentId); - if (parent === undefined) { - continue; - } - container.parent = parent; - } - - const selected = findContainerById(state.MainContainer, state.SelectedContainerId); - if (selected === undefined) { - state.SelectedContainer = null; - continue; - } - state.SelectedContainer = selected; - } -} diff --git a/src/Components/UI/UI.tsx b/src/Components/UI/UI.tsx new file mode 100644 index 0000000..6476af5 --- /dev/null +++ b/src/Components/UI/UI.tsx @@ -0,0 +1,139 @@ +import * as React from 'react'; +import { ElementsSidebar } from '../ElementsSidebar/ElementsSidebar'; +import Sidebar from '../Sidebar/Sidebar'; +import { History } from '../History/History'; +import { AvailableContainer } from '../../Interfaces/AvailableContainer'; +import { ContainerModel } from '../../Interfaces/ContainerModel'; +import { IHistoryState } from '../../App'; +import { PhotographIcon, UploadIcon } from '@heroicons/react/outline'; +import FloatingButton from '../FloatingButton/FloatingButton'; + +interface IUIProps { + current: IHistoryState + history: IHistoryState[] + historyCurrentStep: number + AvailableContainers: AvailableContainer[] + SelectContainer: (container: ContainerModel) => void + OnPropertyChange: (key: string, value: string) => void + AddContainer: (type: string) => void + SaveEditorAsJSON: () => void + SaveEditorAsSVG: () => void + LoadState: (move: number) => void +} + +interface IUIState { + isSidebarOpen: boolean + isElementsSidebarOpen: boolean + isHistoryOpen: boolean +} + +export class UI extends React.PureComponent { + constructor(props: IUIProps) { + super(props); + this.state = { + isSidebarOpen: true, + isElementsSidebarOpen: false, + isHistoryOpen: false + }; + } + + /** + * Toggle the components sidebar + */ + public ToggleSidebar(): void { + this.setState({ + isSidebarOpen: !this.state.isSidebarOpen + }); + } + + /** + * Toggle the elements + */ + public ToggleElementsSidebar(): void { + this.setState({ + isElementsSidebarOpen: !this.state.isElementsSidebarOpen + }); + } + + /** + * Toggle the elements + */ + public ToggleHistory(): void { + this.setState({ + isHistoryOpen: !this.state.isHistoryOpen + }); + } + + public render(): JSX.Element { + let buttonRightOffsetClasses = 'right-12'; + if (this.state.isElementsSidebarOpen || this.state.isHistoryOpen) { + buttonRightOffsetClasses = 'right-72'; + } + if (this.state.isHistoryOpen && this.state.isElementsSidebarOpen) { + buttonRightOffsetClasses = 'right-[544px]'; + } + + return ( + <> + this.ToggleSidebar()} + buttonOnClick={(type: string) => this.props.AddContainer(type)} + /> + + + this.ToggleElementsSidebar()} + onPropertyChange={this.props.OnPropertyChange} + selectContainer={this.props.SelectContainer} + /> + + + this.ToggleHistory()} + jumpTo={this.props.LoadState} + /> + + + + + + + + ); + } +} diff --git a/src/Editor.tsx b/src/Editor.tsx index 29b78f2..8cb75f2 100644 --- a/src/Editor.tsx +++ b/src/Editor.tsx @@ -1,15 +1,12 @@ import React from 'react'; -import { UploadIcon, PhotographIcon } from '@heroicons/react/outline'; import './Editor.scss'; -import Sidebar from './Components/Sidebar/Sidebar'; -import { ElementsSidebar } from './Components/ElementsSidebar/ElementsSidebar'; import { Configuration } from './Interfaces/Configuration'; import { SVG } from './Components/SVG/SVG'; -import { History } from './Components/History/History'; import { ContainerModel, IContainerModel } from './Interfaces/ContainerModel'; import { findContainerById, MakeIterator } from './utils/itertools'; import { IHistoryState } from './App'; -import FloatingButton from './Components/FloatingButton/FloatingButton'; +import { getCircularReplacer } from './utils/saveload'; +import { UI } from './Components/UI/UI'; interface IEditorProps { configuration: Configuration @@ -18,9 +15,6 @@ interface IEditorProps { } export interface IEditorState { - isSidebarOpen: boolean - isElementsSidebarOpen: boolean - isHistoryOpen: boolean history: IHistoryState[] historyCurrentStep: number // do not use it, use props.configuration @@ -34,9 +28,6 @@ class Editor extends React.Component { constructor(props: IEditorProps) { super(props); this.state = { - isSidebarOpen: true, - isElementsSidebarOpen: false, - isHistoryOpen: false, configuration: Object.assign({}, props.configuration), history: [...props.history], historyCurrentStep: props.historyCurrentStep @@ -46,33 +37,6 @@ class Editor extends React.Component { public getCurrentHistory = (): IHistoryState[] => this.state.history.slice(0, this.state.historyCurrentStep + 1); public getCurrentHistoryState = (): IHistoryState => this.state.history[this.state.historyCurrentStep]; - /** - * Toggle the components sidebar - */ - public ToggleSidebar(): void { - this.setState({ - isSidebarOpen: !this.state.isSidebarOpen - }); - } - - /** - * Toggle the elements - */ - public ToggleElementsSidebar(): void { - this.setState({ - isElementsSidebarOpen: !this.state.isElementsSidebarOpen - }); - } - - /** - * Toggle the elements - */ - public ToggleHistory(): void { - this.setState({ - isHistoryOpen: !this.state.isHistoryOpen - }); - } - /** * Select a container * @param container Selected container @@ -251,7 +215,7 @@ class Editor extends React.Component { }); } - public jumpTo(move: number): void { + public LoadState(move: number): void { this.setState({ historyCurrentStep: move }); @@ -290,57 +254,20 @@ class Editor extends React.Component { */ render(): JSX.Element { const current = this.getCurrentHistoryState(); - let buttonRightOffsetClasses = 'right-12'; - if (this.state.isElementsSidebarOpen || this.state.isHistoryOpen) { - buttonRightOffsetClasses = 'right-72'; - } - if (this.state.isHistoryOpen && this.state.isElementsSidebarOpen) { - buttonRightOffsetClasses = 'right-[544px]'; - } return (
- this.ToggleSidebar()} - buttonOnClick={(type: string) => this.AddContainer(type)} - /> - - - this.ToggleElementsSidebar()} - onPropertyChange={(key: string, value: string) => this.OnPropertyChange(key, value)} - selectContainer={(container: ContainerModel) => this.SelectContainer(container)} - /> - - - this.ToggleHistory()} - jumpTo={(move) => { this.jumpTo(move); }} + AvailableContainers={this.state.configuration.AvailableContainers} + SelectContainer={(container) => this.SelectContainer(container)} + OnPropertyChange={(key, value) => this.OnPropertyChange(key, value)} + AddContainer={(type) => this.AddContainer(type)} + SaveEditorAsJSON={() => this.SaveEditorAsJSON()} + SaveEditorAsSVG={() => this.SaveEditorAsSVG()} + LoadState={(move) => this.LoadState(move)} /> - - { > { current.MainContainer } - - - - -
); } } -const getCircularReplacer = (): (key: any, value: object | null) => object | null | undefined => { - const seen = new WeakSet(); - return (key: any, value: object | null) => { - if (key === 'parent') { - return; - } - - if (typeof value === 'object' && value !== null) { - if (seen.has(value)) { - return; - } - seen.add(value); - } - return value; - }; -}; - export default Editor; diff --git a/src/utils/saveload.ts b/src/utils/saveload.ts new file mode 100644 index 0000000..8993ad4 --- /dev/null +++ b/src/utils/saveload.ts @@ -0,0 +1,54 @@ +import { findContainerById, MakeIterator } from './itertools'; +import { IEditorState } from '../Editor'; + +/** + * Revive the Editor state + * by setting the containers references to their parent + * @param editorState Editor state + */ +export function Revive(editorState: IEditorState): void { + const history = editorState.history; + for (const state of history) { + if (state.MainContainer === null || state.MainContainer === undefined) { + continue; + } + + const it = MakeIterator(state.MainContainer); + for (const container of it) { + const parentId = container.properties.parentId; + if (parentId === null) { + container.parent = null; + continue; + } + const parent = findContainerById(state.MainContainer, parentId); + if (parent === undefined) { + continue; + } + container.parent = parent; + } + + const selected = findContainerById(state.MainContainer, state.SelectedContainerId); + if (selected === undefined) { + state.SelectedContainer = null; + continue; + } + state.SelectedContainer = selected; + } +} + +export const getCircularReplacer = (): (key: any, value: object | null) => object | null | undefined => { + const seen = new WeakSet(); + return (key: any, value: object | null) => { + if (key === 'parent') { + return; + } + + if (typeof value === 'object' && value !== null) { + if (seen.has(value)) { + return; + } + seen.add(value); + } + return value; + }; +};