Merged PR 235: Update master
This commit is contained in:
commit
69e80af773
51 changed files with 1183 additions and 495 deletions
|
@ -7,13 +7,26 @@ namespace SVGLDLibs.Models
|
||||||
{
|
{
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public ImageModel Image { get; set; }
|
public ImageModel Image { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public PositionReferenceEnumModel PositionReference { get; set; }
|
public double X { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public double Y { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public double Width { get; set; }
|
public double Width { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public double Height { get; set; }
|
public double Height { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public PositionReferenceEnumModel PositionReference { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public AvailableContainerModel AssociatedContainer { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,16 +5,19 @@ namespace SVGLDLibs.Models
|
||||||
[DataContract]
|
[DataContract]
|
||||||
public class CSSStyle
|
public class CSSStyle
|
||||||
{
|
{
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public double? strokeWidth;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public double? fillOpacity;
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string stroke;
|
public string stroke;
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public double? strokeOpacity;
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public double? strokeWidth;
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string fill;
|
public string fill;
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public double? fillOpacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,16 +8,22 @@ namespace SVGLDLibs.Models
|
||||||
{
|
{
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string id { get; set; }
|
public string id { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string type { get; set; }
|
public string type { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public AvailableSymbolModel config { get; set; }
|
public AvailableSymbolModel config { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public double x { get; set; }
|
public double x { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public double width { get; set; }
|
public double width { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public double height { get; set; }
|
public double height { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public List<string> linkedContainers { get; set; }
|
public List<string> linkedContainers { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ Liens :
|
||||||
- [Système de comportement](Pages/Behaviors.md)
|
- [Système de comportement](Pages/Behaviors.md)
|
||||||
- [Cycle de vie de l'application](Pages/Application.md)
|
- [Cycle de vie de l'application](Pages/Application.md)
|
||||||
- [Implémentation du menu contextuel](Pages/ContextMenu.md)
|
- [Implémentation du menu contextuel](Pages/ContextMenu.md)
|
||||||
- [Web workers](Pages/WebWorkers.md)
|
- [Implémentation du système de cote](Pages/SVGLD_Cotes.pdf)
|
||||||
|
- [Web workers](Pages/WebWorkers.md) (pdf)
|
||||||
|
- [Traductions](Pages/Translations.drawio) (nécessite diagrams.net)
|
||||||
- [Système de CI/CD](Pages/Behaviors.md)
|
- [Système de CI/CD](Pages/Behaviors.md)
|
||||||
- [Mise en place du SmartComponent sur Modeler](Pages/SmartComponent.md)
|
- [Mise en place du SmartComponent sur Modeler](Pages/SmartComponent.md)
|
||||||
|
|
BIN
docs/#Project/Pages/Translations.drawio
(Stored with Git LFS)
Normal file
BIN
docs/#Project/Pages/Translations.drawio
(Stored with Git LFS)
Normal file
Binary file not shown.
|
@ -5,6 +5,7 @@
|
||||||
type IHistoryState = SVGLD.IHistoryState;
|
type IHistoryState = SVGLD.IHistoryState;
|
||||||
type IEditorState = SVGLD.IEditorState;
|
type IEditorState = SVGLD.IEditorState;
|
||||||
type IConfiguration = SVGLD.IConfiguration;
|
type IConfiguration = SVGLD.IConfiguration;
|
||||||
|
type ILanguage = SVGLD.ILanguage;
|
||||||
|
|
||||||
export class SVGLayoutDesigner extends Components.ComponentBase {
|
export class SVGLayoutDesigner extends Components.ComponentBase {
|
||||||
|
|
||||||
|
@ -134,11 +135,15 @@
|
||||||
* ReviveEditorState -> SetEditor -> SetHistory
|
* ReviveEditorState -> SetEditor -> SetHistory
|
||||||
* @param editorState
|
* @param editorState
|
||||||
*/
|
*/
|
||||||
public LoadEditor(editorState: IEditorState) {
|
public LoadEditor(editorState: IEditorState) {
|
||||||
this.ReviveEditorState(editorState, (state) => {
|
this.ReviveEditorState(editorState, (state) => {
|
||||||
this.SetEditor(state, (currentState) => {
|
this.SetEditor(state, (currentState) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.app.Editor.SetHistory({ history: state.history, historyCurrentStep: state.historyCurrentStep });
|
this.app.App.SetAppState(2, () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.app.Editor.SetHistory({ history: state.history, historyCurrentStep: state.historyCurrentStep });
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
}, 200);
|
}, 200);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -161,14 +166,14 @@
|
||||||
/**
|
/**
|
||||||
* Hide the main menu to go to the application.
|
* Hide the main menu to go to the application.
|
||||||
* SetEditor must be called first or the application will crash.
|
* SetEditor must be called first or the application will crash.
|
||||||
* @param isLoaded
|
* @param appState
|
||||||
* @param callback
|
* @param callback
|
||||||
*/
|
*/
|
||||||
public SetLoaded(isLoaded: boolean, callback?: (state: IEditorState) => void) {
|
public SetAppState(appState: SVGLD.AppState, callback?: (state: IEditorState) => void) {
|
||||||
const eventType = 'setLoaded';
|
const eventType = 'setAppState';
|
||||||
this.app.AddEventListener(eventType, callback);
|
this.app.AddEventListener(eventType, callback);
|
||||||
const component = this.GetAppComponent();
|
const component = this.GetAppComponent();
|
||||||
component.dispatchEvent(new CustomEvent(eventType, { detail: isLoaded }))
|
component.dispatchEvent(new CustomEvent(eventType, { detail: appState }))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -210,6 +215,43 @@
|
||||||
const component = this.GetAppComponent();
|
const component = this.GetAppComponent();
|
||||||
component.dispatchEvent(new CustomEvent(eventType, { detail: configuration }));
|
component.dispatchEvent(new CustomEvent(eventType, { detail: configuration }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a language to the app
|
||||||
|
* @param option Displayed string of the language
|
||||||
|
* @param language Language containing an id and a dictionary
|
||||||
|
* @param callback Callback
|
||||||
|
*/
|
||||||
|
public AddLanguage(option: string, language: ILanguage, callback?: () => void) {
|
||||||
|
const eventType = 'addLanguage';
|
||||||
|
this.app.AddEventListener(eventType, callback);
|
||||||
|
const component = this.GetAppComponent();
|
||||||
|
component.dispatchEvent(new CustomEvent(eventType, { detail: { language, option } }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the language of the app (defaults: ['fr', 'en'])
|
||||||
|
* @param languageId Language identifier for the language to select
|
||||||
|
* @param callback Callback
|
||||||
|
*/
|
||||||
|
public SetLanguage(languageId: string, callback?: (success: boolean) => void) {
|
||||||
|
const eventType = 'setLanguage';
|
||||||
|
this.app.AddEventListener(eventType, callback);
|
||||||
|
const component = this.GetAppComponent();
|
||||||
|
component.dispatchEvent(new CustomEvent(eventType, { detail: languageId }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the language of the app (defaults: ['fr', 'en'])
|
||||||
|
* @param languageId Language identifier for the language to select
|
||||||
|
* @param callback Callback
|
||||||
|
*/
|
||||||
|
public GetLanguages(callback: (languages: Record<string, Record<string, string>>) => void) {
|
||||||
|
const eventType = 'getLanguages';
|
||||||
|
this.app.AddEventListener(eventType, callback);
|
||||||
|
const component = this.GetAppComponent();
|
||||||
|
component.dispatchEvent(new CustomEvent(eventType));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
27
public/svgld.d.ts
vendored
27
public/svgld.d.ts
vendored
|
@ -13,6 +13,12 @@ export enum AddMethod {
|
||||||
ReplaceParent = 3
|
ReplaceParent = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AppState {
|
||||||
|
MainMenu = 0,
|
||||||
|
Loading = 1,
|
||||||
|
Loaded = 2
|
||||||
|
}
|
||||||
|
|
||||||
export enum MessageType {
|
export enum MessageType {
|
||||||
Normal = 0,
|
Normal = 0,
|
||||||
Success = 1,
|
Success = 1,
|
||||||
|
@ -88,6 +94,7 @@ export interface IAPIConfiguration {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Model of available container used in application configuration */
|
/** Model of available container used in application configuration */
|
||||||
export interface IAvailableContainer {
|
export interface IAvailableContainer {
|
||||||
/** type */
|
/** type */
|
||||||
|
@ -212,7 +219,7 @@ export interface IAvailableContainer {
|
||||||
* (optional)
|
* (optional)
|
||||||
* User data that can be used for data storage or custom SVG
|
* User data that can be used for data storage or custom SVG
|
||||||
*/
|
*/
|
||||||
UserData?: object;
|
UserData?: IKeyValue[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -250,7 +257,6 @@ export interface IConfiguration {
|
||||||
|
|
||||||
export interface IContainerModel {
|
export interface IContainerModel {
|
||||||
children: string[];
|
children: string[];
|
||||||
parent: IContainerModel | null;
|
|
||||||
properties: IContainerProperties;
|
properties: IContainerProperties;
|
||||||
userData: Record<string, string | number>;
|
userData: Record<string, string | number>;
|
||||||
}
|
}
|
||||||
|
@ -260,10 +266,9 @@ export interface IContainerModel {
|
||||||
*/
|
*/
|
||||||
export class ContainerModel implements IContainerModel {
|
export class ContainerModel implements IContainerModel {
|
||||||
children: string[];
|
children: string[];
|
||||||
parent: IContainerModel | null;
|
|
||||||
properties: IContainerProperties;
|
properties: IContainerProperties;
|
||||||
userData: Record<string, string | number>;
|
userData: Record<string, string | number>;
|
||||||
constructor(parent: IContainerModel | null, properties: IContainerProperties, children?: string[], userData?: {});
|
constructor(properties: IContainerProperties, children?: string[], userData?: {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -271,6 +276,7 @@ export class ContainerModel implements IContainerModel {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties of a container
|
* Properties of a container
|
||||||
*/
|
*/
|
||||||
|
@ -363,7 +369,7 @@ export interface IContainerProperties {
|
||||||
* (optional)
|
* (optional)
|
||||||
* User data that can be used for data storage or custom SVG
|
* User data that can be used for data storage or custom SVG
|
||||||
*/
|
*/
|
||||||
userData?: object;
|
userData?: IKeyValue[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -428,6 +434,17 @@ export interface IInputGroup {
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IKeyValue {
|
||||||
|
Key: string;
|
||||||
|
Value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILanguage {
|
||||||
|
language: string;
|
||||||
|
dictionary: Record<string, string>;
|
||||||
|
languageChange?: (selected: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IMargin {
|
export interface IMargin {
|
||||||
left?: number;
|
left?: number;
|
||||||
bottom?: number;
|
bottom?: number;
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
|
import { AppState } from '../../../Enums/AppState';
|
||||||
import { IEditorState } from '../../../Interfaces/IEditorState';
|
import { IEditorState } from '../../../Interfaces/IEditorState';
|
||||||
import { Revive } from '../../../utils/saveload';
|
import { Revive } from '../../../utils/saveload';
|
||||||
|
|
||||||
export function LoadState(
|
export function LoadState(
|
||||||
editorState: IEditorState,
|
editorState: IEditorState,
|
||||||
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
||||||
setLoaded: Dispatch<SetStateAction<boolean>>
|
setAppState: Dispatch<SetStateAction<AppState>>
|
||||||
): void {
|
): void {
|
||||||
Revive(editorState);
|
Revive(editorState);
|
||||||
setEditorState(editorState);
|
setEditorState(editorState);
|
||||||
setLoaded(true);
|
setAppState(AppState.Loaded);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { Dispatch, SetStateAction, useEffect } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { IConfiguration } from '../../../Interfaces/IConfiguration';
|
import { IConfiguration } from '../../../Interfaces/IConfiguration';
|
||||||
import { FetchConfiguration } from '../../API/api';
|
import { FetchConfiguration } from '../../API/api';
|
||||||
import { IEditorState } from '../../../Interfaces/IEditorState';
|
import { IEditorState } from '../../../Interfaces/IEditorState';
|
||||||
import { LoadState } from './Load';
|
import { LoadState } from './Load';
|
||||||
import { DISABLE_API, GetDefaultEditorState } from '../../../utils/default';
|
import { DISABLE_API, GetDefaultEditorState } from '../../../utils/default';
|
||||||
|
import { AppState } from '../../../Enums/AppState';
|
||||||
|
|
||||||
export function NewEditor(
|
export function NewEditor(
|
||||||
editorState: IEditorState,
|
editorState: IEditorState,
|
||||||
|
@ -36,7 +37,7 @@ export function NewEditor(
|
||||||
export function LoadEditor(
|
export function LoadEditor(
|
||||||
files: FileList | null,
|
files: FileList | null,
|
||||||
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
||||||
setLoaded: Dispatch<SetStateAction<boolean>>
|
setAppState: Dispatch<SetStateAction<AppState>>
|
||||||
): void {
|
): void {
|
||||||
if (files === null) {
|
if (files === null) {
|
||||||
return;
|
return;
|
||||||
|
@ -47,7 +48,7 @@ export function LoadEditor(
|
||||||
const result = reader.result as string;
|
const result = reader.result as string;
|
||||||
const editorState: IEditorState = JSON.parse(result);
|
const editorState: IEditorState = JSON.parse(result);
|
||||||
|
|
||||||
LoadState(editorState, setEditorState, setLoaded);
|
LoadState(editorState, setEditorState, setAppState);
|
||||||
});
|
});
|
||||||
reader.readAsText(file);
|
reader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react';
|
import React, { Dispatch, SetStateAction, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { UseCustomEvents } from '../../Events/AppEvents';
|
import { UseCustomEvents } from '../../Events/AppEvents';
|
||||||
import { MainMenu } from '../MainMenu/MainMenu';
|
import { MainMenu } from '../MainMenu/MainMenu';
|
||||||
import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
|
import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
|
||||||
|
@ -6,7 +6,10 @@ import { Editor } from '../Editor/Editor';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { IEditorState } from '../../Interfaces/IEditorState';
|
||||||
import { LoadState } from './Actions/Load';
|
import { LoadState } from './Actions/Load';
|
||||||
import { LoadEditor, NewEditor } from './Actions/MenuActions';
|
import { LoadEditor, NewEditor } from './Actions/MenuActions';
|
||||||
import { DEFAULT_CONFIG, DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default';
|
import { DEFAULT_CONFIG, DEFAULT_MAINCONTAINER_PROPS, FAST_BOOT } from '../../utils/default';
|
||||||
|
import { AppState } from '../../Enums/AppState';
|
||||||
|
import { Loader } from '../Loader/Loader';
|
||||||
|
import { LanguageContext } from '../LanguageProvider/LanguageProvider';
|
||||||
|
|
||||||
// App will never have props
|
// App will never have props
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||||
|
@ -15,9 +18,9 @@ interface IAppProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
function UseHTTPGETStatePreloading(
|
function UseHTTPGETStatePreloading(
|
||||||
isLoaded: boolean,
|
appState: AppState,
|
||||||
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
setEditorState: Dispatch<SetStateAction<IEditorState>>,
|
||||||
setLoaded: Dispatch<SetStateAction<boolean>>
|
setAppState: Dispatch<SetStateAction<AppState>>
|
||||||
): void {
|
): void {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const queryString = window.location.search;
|
const queryString = window.location.search;
|
||||||
|
@ -28,22 +31,23 @@ function UseHTTPGETStatePreloading(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isLoaded) {
|
if (appState !== AppState.Loaded) {
|
||||||
fetch(state)
|
fetch(state)
|
||||||
.then(
|
.then(
|
||||||
async(response) => await response.json(),
|
async(response) => await response.json(),
|
||||||
(error) => { throw new Error(error); }
|
(error) => { throw new Error(error); }
|
||||||
)
|
)
|
||||||
.then((data: IEditorState) => {
|
.then((data: IEditorState) => {
|
||||||
LoadState(data, setEditorState, setLoaded);
|
LoadState(data, setEditorState, setAppState);
|
||||||
}, (error) => { throw new Error(error); });
|
}, (error) => { throw new Error(error); });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function App(props: IAppProps): JSX.Element {
|
export function App(props: IAppProps): JSX.Element {
|
||||||
const [isLoaded, setLoaded] = useState<boolean>(false);
|
const [appState, setAppState] = useState<AppState>(FAST_BOOT);
|
||||||
const appRef = useRef<HTMLDivElement>(null);
|
const appRef = useRef<HTMLDivElement>(null);
|
||||||
|
const languageContext = useContext(LanguageContext);
|
||||||
|
|
||||||
const defaultMainContainer = new ContainerModel(
|
const defaultMainContainer = new ContainerModel(
|
||||||
DEFAULT_MAINCONTAINER_PROPS
|
DEFAULT_MAINCONTAINER_PROPS
|
||||||
|
@ -68,49 +72,61 @@ export function App(props: IAppProps): JSX.Element {
|
||||||
UseCustomEvents(
|
UseCustomEvents(
|
||||||
props.root,
|
props.root,
|
||||||
appRef,
|
appRef,
|
||||||
|
languageContext,
|
||||||
setEditorState,
|
setEditorState,
|
||||||
setLoaded
|
setAppState
|
||||||
);
|
);
|
||||||
|
|
||||||
UseHTTPGETStatePreloading(isLoaded, setEditorState, setLoaded);
|
UseHTTPGETStatePreloading(appState, setEditorState, setAppState);
|
||||||
|
|
||||||
const enableLoaded = useCallback(() => {
|
switch (appState) {
|
||||||
setLoaded(true);
|
case AppState.Loaded:
|
||||||
}, []);
|
return (
|
||||||
|
<div
|
||||||
if (isLoaded) {
|
ref={appRef}
|
||||||
return (
|
className='App'
|
||||||
<div
|
>
|
||||||
ref={appRef}
|
<Editor
|
||||||
className='App'
|
root={props.root}
|
||||||
>
|
configuration={editorState.configuration}
|
||||||
<Editor
|
history={editorState.history}
|
||||||
root={props.root}
|
historyCurrentStep={editorState.historyCurrentStep}
|
||||||
configuration={editorState.configuration}
|
/>
|
||||||
history={editorState.history}
|
</div>
|
||||||
historyCurrentStep={editorState.historyCurrentStep}
|
);
|
||||||
/>
|
case AppState.Loading:
|
||||||
</div>
|
return (
|
||||||
);
|
<div
|
||||||
|
ref={appRef}
|
||||||
|
className='App mainmenu-bg'
|
||||||
|
>
|
||||||
|
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={appRef}
|
||||||
|
className='App mainmenu-bg'
|
||||||
|
>
|
||||||
|
<MainMenu
|
||||||
|
newEditor={() => {
|
||||||
|
setAppState(AppState.Loading);
|
||||||
|
NewEditor(
|
||||||
|
editorState,
|
||||||
|
(newEditor) => setEditorState(newEditor),
|
||||||
|
() => setAppState(AppState.Loaded)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
loadEditor={(files: FileList | null) => LoadEditor(
|
||||||
|
files,
|
||||||
|
setEditorState,
|
||||||
|
setAppState
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
ref={appRef}
|
|
||||||
className='App mainmenu-bg'
|
|
||||||
>
|
|
||||||
<MainMenu
|
|
||||||
newEditor={() => NewEditor(
|
|
||||||
editorState,
|
|
||||||
(newEditor) => setEditorState(newEditor),
|
|
||||||
enableLoaded
|
|
||||||
)}
|
|
||||||
loadEditor={(files: FileList | null) => LoadEditor(
|
|
||||||
files,
|
|
||||||
setEditorState,
|
|
||||||
setLoaded
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
Cog8ToothIcon as Cog8ToothIconS
|
Cog8ToothIcon as Cog8ToothIconS
|
||||||
} from '@heroicons/react/24/solid';
|
} from '@heroicons/react/24/solid';
|
||||||
import { BarIcon } from './BarIcon';
|
import { BarIcon } from './BarIcon';
|
||||||
|
import { Text } from '../Text/Text';
|
||||||
|
|
||||||
interface IBarProps {
|
interface IBarProps {
|
||||||
isComponentsOpen: boolean
|
isComponentsOpen: boolean
|
||||||
|
@ -35,7 +36,7 @@ export function Bar(props: IBarProps): JSX.Element {
|
||||||
<div className='bar'>
|
<div className='bar'>
|
||||||
<BarIcon
|
<BarIcon
|
||||||
isActive={props.isComponentsOpen}
|
isActive={props.isComponentsOpen}
|
||||||
title='Components'
|
title={Text({ textId: '@Components' })}
|
||||||
onClick={() => props.toggleComponents()}>
|
onClick={() => props.toggleComponents()}>
|
||||||
{
|
{
|
||||||
props.isComponentsOpen
|
props.isComponentsOpen
|
||||||
|
@ -45,7 +46,7 @@ export function Bar(props: IBarProps): JSX.Element {
|
||||||
</BarIcon>
|
</BarIcon>
|
||||||
<BarIcon
|
<BarIcon
|
||||||
isActive={props.isSymbolsOpen}
|
isActive={props.isSymbolsOpen}
|
||||||
title='Symbols'
|
title={Text({ textId: '@Symbols' })}
|
||||||
onClick={() => props.toggleSymbols()}>
|
onClick={() => props.toggleSymbols()}>
|
||||||
{
|
{
|
||||||
props.isSymbolsOpen
|
props.isSymbolsOpen
|
||||||
|
@ -55,7 +56,7 @@ export function Bar(props: IBarProps): JSX.Element {
|
||||||
</BarIcon>
|
</BarIcon>
|
||||||
<BarIcon
|
<BarIcon
|
||||||
isActive={props.isMessagesOpen}
|
isActive={props.isMessagesOpen}
|
||||||
title='Messages'
|
title={Text({ textId: '@Messages' })}
|
||||||
onClick={() => props.toggleMessages()}>
|
onClick={() => props.toggleMessages()}>
|
||||||
{
|
{
|
||||||
props.isMessagesOpen
|
props.isMessagesOpen
|
||||||
|
@ -66,7 +67,7 @@ export function Bar(props: IBarProps): JSX.Element {
|
||||||
<div className='grow'></div>
|
<div className='grow'></div>
|
||||||
<BarIcon
|
<BarIcon
|
||||||
isActive={props.isHistoryOpen}
|
isActive={props.isHistoryOpen}
|
||||||
title='Timeline'
|
title={Text({ textId: '@Timeline' })}
|
||||||
onClick={() => props.toggleTimeline()}>
|
onClick={() => props.toggleTimeline()}>
|
||||||
{
|
{
|
||||||
props.isHistoryOpen
|
props.isHistoryOpen
|
||||||
|
@ -76,7 +77,7 @@ export function Bar(props: IBarProps): JSX.Element {
|
||||||
</BarIcon>
|
</BarIcon>
|
||||||
<BarIcon
|
<BarIcon
|
||||||
isActive={props.isSettingsOpen}
|
isActive={props.isSettingsOpen}
|
||||||
title='Settings'
|
title={Text({ textId: '@Settings' })}
|
||||||
onClick={() => props.toggleSettings()}>
|
onClick={() => props.toggleSettings()}>
|
||||||
{
|
{
|
||||||
props.isSettingsOpen
|
props.isSettingsOpen
|
||||||
|
|
|
@ -79,18 +79,20 @@ function ActionByPosition(
|
||||||
dimMapped: number[],
|
dimMapped: number[],
|
||||||
positions: Position[],
|
positions: Position[],
|
||||||
horizontalAction: (ctx: CanvasRenderingContext2D, dim: number, ...params: any[]) => void,
|
horizontalAction: (ctx: CanvasRenderingContext2D, dim: number, ...params: any[]) => void,
|
||||||
verticalAction: (ctx: CanvasRenderingContext2D, dim: number, ...params: any[]) => void,
|
verticalAction: (ctx: CanvasRenderingContext2D, dim: number, isRight: boolean, ...params: any[]) => void,
|
||||||
params: any[]
|
params: any[]
|
||||||
): void {
|
): void {
|
||||||
positions.forEach((position: Position) => {
|
positions.forEach((position: Position) => {
|
||||||
const dim = dimMapped[position];
|
const dim = dimMapped[position];
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case Position.Left:
|
case Position.Left:
|
||||||
case Position.Right:
|
case Position.Right: {
|
||||||
verticalAction(ctx, dim, ...params);
|
const isRight = position === Position.Right;
|
||||||
|
verticalAction(ctx, dim, isRight, ...params);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Position.Down:
|
|
||||||
case Position.Up:
|
case Position.Up:
|
||||||
|
case Position.Down:
|
||||||
horizontalAction(ctx, dim, ...params);
|
horizontalAction(ctx, dim, ...params);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -140,10 +142,10 @@ function AddHorizontalChildrenDimension(
|
||||||
}
|
}
|
||||||
|
|
||||||
const textChildren = (xChildrenEnd - xChildrenStart)
|
const textChildren = (xChildrenEnd - xChildrenStart)
|
||||||
.toFixed(2)
|
.toFixed(0);
|
||||||
.toString();
|
|
||||||
|
|
||||||
const offset = currentTransform[0] + container.properties.x;
|
const offset = currentTransform[0] + container.properties.x;
|
||||||
|
|
||||||
RenderDimension(ctx, {
|
RenderDimension(ctx, {
|
||||||
id: childrenId,
|
id: childrenId,
|
||||||
xStart: xChildrenStart + offset,
|
xStart: xChildrenStart + offset,
|
||||||
|
@ -159,6 +161,7 @@ function AddHorizontalChildrenDimension(
|
||||||
function AddVerticalChildrenDimension(
|
function AddVerticalChildrenDimension(
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
xDim: number,
|
xDim: number,
|
||||||
|
isRight: boolean,
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
container: IContainerModel,
|
container: IContainerModel,
|
||||||
currentTransform: [number, number],
|
currentTransform: [number, number],
|
||||||
|
@ -174,7 +177,7 @@ function AddVerticalChildrenDimension(
|
||||||
}
|
}
|
||||||
|
|
||||||
let yChildrenStart = TransformY(lastChild.properties.y, lastChild.properties.height, lastChild.properties.positionReference);
|
let yChildrenStart = TransformY(lastChild.properties.y, lastChild.properties.height, lastChild.properties.positionReference);
|
||||||
let yChildrenEnd = TransformY(lastChild.properties.y, lastChild.properties.height, lastChild.properties.positionReference);
|
let yChildrenEnd = yChildrenStart;
|
||||||
|
|
||||||
// Find the min and max
|
// Find the min and max
|
||||||
for (let i = container.children.length - 2; i >= 0; i--) {
|
for (let i = container.children.length - 2; i >= 0; i--) {
|
||||||
|
@ -201,11 +204,14 @@ function AddVerticalChildrenDimension(
|
||||||
}
|
}
|
||||||
|
|
||||||
const textChildren = (yChildrenEnd - yChildrenStart)
|
const textChildren = (yChildrenEnd - yChildrenStart)
|
||||||
.toFixed(2)
|
.toFixed(0);
|
||||||
.toString();
|
|
||||||
|
|
||||||
const offset = currentTransform[0] + container.properties.x;
|
const offset = currentTransform[0] + container.properties.x;
|
||||||
|
|
||||||
|
if (!isRight) {
|
||||||
|
[yChildrenStart, yChildrenEnd] = [yChildrenEnd, yChildrenStart];
|
||||||
|
}
|
||||||
|
|
||||||
RenderDimension(ctx, {
|
RenderDimension(ctx, {
|
||||||
id: childrenId,
|
id: childrenId,
|
||||||
xStart: xDim,
|
xStart: xDim,
|
||||||
|
@ -257,6 +263,11 @@ function AddHorizontalBorrowerDimension(
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (const { cur, next } of Pairwise(marks)) {
|
for (const { cur, next } of Pairwise(marks)) {
|
||||||
const id = `dim-y${yDim.toFixed(0)}-borrow-${container.properties.id}-{${count}}`;
|
const id = `dim-y${yDim.toFixed(0)}-borrow-${container.properties.id}-{${count}}`;
|
||||||
|
const value = next - cur;
|
||||||
|
if (value === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RenderDimension(ctx, {
|
RenderDimension(ctx, {
|
||||||
id,
|
id,
|
||||||
xStart: cur,
|
xStart: cur,
|
||||||
|
@ -264,7 +275,7 @@ function AddHorizontalBorrowerDimension(
|
||||||
yStart: yDim,
|
yStart: yDim,
|
||||||
yEnd: yDim,
|
yEnd: yDim,
|
||||||
strokeWidth: MODULE_STROKE_WIDTH,
|
strokeWidth: MODULE_STROKE_WIDTH,
|
||||||
text: (next - cur).toFixed(0).toString(),
|
text: value.toFixed(0),
|
||||||
scale
|
scale
|
||||||
});
|
});
|
||||||
count++;
|
count++;
|
||||||
|
@ -274,6 +285,7 @@ function AddHorizontalBorrowerDimension(
|
||||||
function AddVerticalBorrowerDimension(
|
function AddVerticalBorrowerDimension(
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
xDim: number,
|
xDim: number,
|
||||||
|
isRight: boolean,
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
container: IContainerModel,
|
container: IContainerModel,
|
||||||
depth: number,
|
depth: number,
|
||||||
|
@ -307,9 +319,19 @@ function AddVerticalBorrowerDimension(
|
||||||
marks.push(restoredY);
|
marks.push(restoredY);
|
||||||
marks.push(restoredY + container.properties.height);
|
marks.push(restoredY + container.properties.height);
|
||||||
marks.sort((a, b) => a - b);
|
marks.sort((a, b) => a - b);
|
||||||
|
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (const { cur, next } of Pairwise(marks)) {
|
for (let { cur, next } of Pairwise(marks)) {
|
||||||
const id = `dim-x${xDim.toFixed(0)}-borrow-${container.properties.id}-{${count}}`;
|
const id = `dim-x${xDim.toFixed(0)}-borrow-${container.properties.id}-{${count}}`;
|
||||||
|
const value = next - cur;
|
||||||
|
if (value === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRight) {
|
||||||
|
[cur, next] = [next, cur];
|
||||||
|
}
|
||||||
|
|
||||||
RenderDimension(ctx, {
|
RenderDimension(ctx, {
|
||||||
id,
|
id,
|
||||||
xStart: xDim,
|
xStart: xDim,
|
||||||
|
@ -317,7 +339,7 @@ function AddVerticalBorrowerDimension(
|
||||||
yStart: cur,
|
yStart: cur,
|
||||||
yEnd: next,
|
yEnd: next,
|
||||||
strokeWidth: MODULE_STROKE_WIDTH,
|
strokeWidth: MODULE_STROKE_WIDTH,
|
||||||
text: (next - cur).toFixed(0).toString(),
|
text: value.toFixed(0),
|
||||||
scale
|
scale
|
||||||
});
|
});
|
||||||
count++;
|
count++;
|
||||||
|
@ -327,22 +349,28 @@ function AddVerticalBorrowerDimension(
|
||||||
function AddVerticalSelfDimension(
|
function AddVerticalSelfDimension(
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
xDim: number,
|
xDim: number,
|
||||||
|
isRight: boolean,
|
||||||
container: IContainerModel,
|
container: IContainerModel,
|
||||||
currentTransform: [number, number],
|
currentTransform: [number, number],
|
||||||
scale: number
|
scale: number
|
||||||
): void {
|
): void {
|
||||||
const height = container.properties.height;
|
const height = container.properties.height;
|
||||||
const idVert = `dim-x${xDim.toFixed(0)}-${container.properties.id}`;
|
const idVert = `dim-x${xDim.toFixed(0)}-${container.properties.id}`;
|
||||||
const yStart = container.properties.y + currentTransform[1];
|
let yStart = container.properties.y + currentTransform[1] + height;
|
||||||
const yEnd = yStart + height;
|
let yEnd = container.properties.y + currentTransform[1];
|
||||||
const textVert = height
|
const textVert = height
|
||||||
.toFixed(0)
|
.toFixed(0)
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
|
if (isRight) {
|
||||||
|
[yStart, yEnd] = [yEnd, yStart];
|
||||||
|
}
|
||||||
|
|
||||||
RenderDimension(ctx, {
|
RenderDimension(ctx, {
|
||||||
id: idVert,
|
id: idVert,
|
||||||
xStart: xDim,
|
xStart: xDim,
|
||||||
yStart,
|
|
||||||
xEnd: xDim,
|
xEnd: xDim,
|
||||||
|
yStart,
|
||||||
yEnd,
|
yEnd,
|
||||||
strokeWidth: MODULE_STROKE_WIDTH,
|
strokeWidth: MODULE_STROKE_WIDTH,
|
||||||
text: textVert,
|
text: textVert,
|
||||||
|
|
|
@ -33,7 +33,7 @@ export function RenderSelector(ctx: CanvasRenderingContext2D, frameCount: number
|
||||||
|
|
||||||
ctx.strokeStyle = '#3B82F6';
|
ctx.strokeStyle = '#3B82F6';
|
||||||
ctx.lineWidth = 4 / scale;
|
ctx.lineWidth = 4 / scale;
|
||||||
ctx.globalAlpha = 0.25 * (Math.sin(frameCount * 0.0125) ** 2);
|
ctx.globalAlpha = (Math.sin(frameCount * 0.0450) ** 2);
|
||||||
ctx.strokeRect(x, y, width, height);
|
ctx.strokeRect(x, y, width, height);
|
||||||
ctx.globalAlpha = 1;
|
ctx.globalAlpha = 1;
|
||||||
ctx.lineWidth = 1;
|
ctx.lineWidth = 1;
|
||||||
|
|
|
@ -63,9 +63,7 @@ export function CheckboxGroupButtons(props: ICheckboxGroupButtonsProps): JSX.Ele
|
||||||
<label className='text-xs font-medium text-gray-800'>
|
<label className='text-xs font-medium text-gray-800'>
|
||||||
{props.labelText}
|
{props.labelText}
|
||||||
</label>
|
</label>
|
||||||
<div id='XPositionReference'
|
<div className={`grid ${gridColsClass}`}>
|
||||||
className={`grid ${gridColsClass}`}
|
|
||||||
>
|
|
||||||
{inputGroups}
|
{inputGroups}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { ICategory } from '../../Interfaces/ICategory';
|
||||||
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
||||||
import { TruncateString } from '../../utils/stringtools';
|
import { TruncateString } from '../../utils/stringtools';
|
||||||
import { Category } from '../Category/Category';
|
import { Category } from '../Category/Category';
|
||||||
|
import { Text } from '../Text/Text';
|
||||||
|
|
||||||
interface IComponentsProps {
|
interface IComponentsProps {
|
||||||
selectedContainer: IContainerModel | undefined
|
selectedContainer: IContainerModel | undefined
|
||||||
|
@ -24,7 +25,7 @@ interface SidebarCategory {
|
||||||
|
|
||||||
export function Components(props: IComponentsProps): JSX.Element {
|
export function Components(props: IComponentsProps): JSX.Element {
|
||||||
const [hideDisabled, setHideDisabled] = React.useState<boolean>(false);
|
const [hideDisabled, setHideDisabled] = React.useState<boolean>(false);
|
||||||
const disabledTitle = hideDisabled ? 'Show disabled components' : 'Hide disabled components';
|
const disabledTitle = hideDisabled ? Text({ textId: '@ShowDisabledComponents' }) : Text({ textId: '@HideDisabledComponents' });
|
||||||
|
|
||||||
const rootElements: Array<JSX.Element | undefined> = [];
|
const rootElements: Array<JSX.Element | undefined> = [];
|
||||||
const categories = new Map<string, SidebarCategory>(props.categories.map(category => [
|
const categories = new Map<string, SidebarCategory>(props.categories.map(category => [
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { IContainerProperties } from '../../Interfaces/IContainerProperties';
|
||||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
||||||
import { SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, SHOW_SELF_DIMENSIONS } from '../../utils/default';
|
import { SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, SHOW_SELF_DIMENSIONS } from '../../utils/default';
|
||||||
import { ApplyWidthMargin, ApplyXMargin, RemoveWidthMargin, RemoveXMargin, RestoreX, RestoreY, TransformX, TransformY } from '../../utils/svg';
|
import { ApplyWidthMargin, ApplyXMargin, RemoveWidthMargin, RemoveXMargin, RestoreX, RestoreY, TransformX, TransformY } from '../../utils/svg';
|
||||||
|
import { Text } from '../Text/Text';
|
||||||
import { InputGroup } from '../InputGroup/InputGroup';
|
import { InputGroup } from '../InputGroup/InputGroup';
|
||||||
import { TextInputGroup } from '../InputGroup/TextInputGroup';
|
import { TextInputGroup } from '../InputGroup/TextInputGroup';
|
||||||
import { Select } from '../Select/Select';
|
import { Select } from '../Select/Select';
|
||||||
|
@ -20,31 +21,13 @@ interface IContainerFormProps {
|
||||||
onChange: (key: string, value: string | number | boolean | number[], type?: PropertyType) => void
|
onChange: (key: string, value: string | number | boolean | number[], type?: PropertyType) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetCSSInputs(properties: IContainerProperties,
|
|
||||||
onChange: (key: string, value: string | number | boolean, type: PropertyType) => void): JSX.Element[] {
|
|
||||||
const groupInput: JSX.Element[] = [];
|
|
||||||
for (const key in properties.style) {
|
|
||||||
groupInput.push(<TextInputGroup
|
|
||||||
key={key}
|
|
||||||
id={key}
|
|
||||||
labelText={key}
|
|
||||||
inputKey={key}
|
|
||||||
labelClassName='col-span-2'
|
|
||||||
inputClassName='col-span-3'
|
|
||||||
type='string'
|
|
||||||
value={(properties.style as any)[key]}
|
|
||||||
onChange={(value) => onChange(key, value, PropertyType.Style)} />);
|
|
||||||
}
|
|
||||||
return groupInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
const categoryHeight = 'h-11';
|
const categoryHeight = 'h-11';
|
||||||
return (
|
return (
|
||||||
<div className='grid grid-cols-1 gap-y-4 items-center'>
|
<div className='grid grid-cols-1 gap-y-4 items-center'>
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-displayedText`}
|
id={`${props.properties.id}-displayedText`}
|
||||||
labelText='Displayed text'
|
labelText={Text({ textId: '@ContainerDisplayedText' })}
|
||||||
inputKey='displayedText'
|
inputKey='displayedText'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -54,7 +37,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
<OrientationSelector
|
<OrientationSelector
|
||||||
id='orientation'
|
id='orientation'
|
||||||
name='Orientation'
|
name='Orientation'
|
||||||
labelText='Orientation'
|
labelText={Text({ textId: '@ContainerOrientation' })}
|
||||||
value={props.properties.orientation}
|
value={props.properties.orientation}
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
|
@ -62,14 +45,14 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
<Category
|
<Category
|
||||||
category={{
|
category={{
|
||||||
Type: 'Properties',
|
Type: 'Properties',
|
||||||
DisplayedText: 'Properties'
|
DisplayedText: Text({ textId: '@ContainerProperties' })
|
||||||
}}
|
}}
|
||||||
heightClass={`${categoryHeight}`}
|
heightClass={`${categoryHeight}`}
|
||||||
>
|
>
|
||||||
<div className='grid grid-cols-1 gap-y-6 items-center prop-category-body'>
|
<div className='grid grid-cols-1 gap-y-6 items-center prop-category-body'>
|
||||||
<div>
|
<div>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
labelText='Name'
|
labelText={Text({ textId: '@ContainerName' })}
|
||||||
inputKey='id'
|
inputKey='id'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -79,7 +62,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
labelText='Parent name'
|
labelText={Text({ textId: '@ContainerParentName' })}
|
||||||
inputKey='parentId'
|
inputKey='parentId'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -89,7 +72,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
labelText='Type'
|
labelText={Text({ textId: '@ContainerType' })}
|
||||||
inputKey='type'
|
inputKey='type'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -102,7 +85,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
|
|
||||||
<Category category={{
|
<Category category={{
|
||||||
Type: 'Position',
|
Type: 'Position',
|
||||||
DisplayedText: 'Position'
|
DisplayedText: Text({ textId: '@ContainerPosition' })
|
||||||
}}
|
}}
|
||||||
defaultIsOpen={true}
|
defaultIsOpen={true}
|
||||||
heightClass={`${categoryHeight}`}
|
heightClass={`${categoryHeight}`}
|
||||||
|
@ -110,7 +93,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
<div className='grid grid-cols-3 gap-y-2 items-center prop-category-body'>
|
<div className='grid grid-cols-3 gap-y-2 items-center prop-category-body'>
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-x`}
|
id={`${props.properties.id}-x`}
|
||||||
labelText='x'
|
labelText={Text({ textId: '@ContainerX' })}
|
||||||
inputKey='x'
|
inputKey='x'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName='col-span-2'
|
inputClassName='col-span-2'
|
||||||
|
@ -134,7 +117,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
)} />
|
)} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-y`}
|
id={`${props.properties.id}-y`}
|
||||||
labelText='y'
|
labelText={Text({ textId: '@ContainerY' })}
|
||||||
inputKey='y'
|
inputKey='y'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName='col-span-2'
|
inputClassName='col-span-2'
|
||||||
|
@ -158,16 +141,17 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
</Category>
|
</Category>
|
||||||
|
|
||||||
<Category category={{
|
<Category
|
||||||
Type: 'Size',
|
category={{
|
||||||
DisplayedText: 'Size'
|
Type: 'Size',
|
||||||
}}
|
DisplayedText: Text({ textId: '@ContainerSize' })
|
||||||
heightClass={`${categoryHeight}`}
|
}}
|
||||||
|
heightClass={`${categoryHeight}`}
|
||||||
>
|
>
|
||||||
<div className='grid grid-cols-5 gap-y-2 items-center prop-category-body'>
|
<div className='grid grid-cols-5 gap-y-2 items-center prop-category-body'>
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-minWidth`}
|
id={`${props.properties.id}-minWidth`}
|
||||||
labelText='Minimum Width'
|
labelText={Text({ textId: '@ContainerMinWidth' })}
|
||||||
inputKey='minWidth'
|
inputKey='minWidth'
|
||||||
labelClassName='col-span-2'
|
labelClassName='col-span-2'
|
||||||
inputClassName='col-span-3'
|
inputClassName='col-span-3'
|
||||||
|
@ -177,7 +161,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
onChange={(value) => props.onChange('minWidth', Number(value))} />
|
onChange={(value) => props.onChange('minWidth', Number(value))} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-width`}
|
id={`${props.properties.id}-width`}
|
||||||
labelText='Width'
|
labelText={Text({ textId: '@ContainerWidth' })}
|
||||||
inputKey='width'
|
inputKey='width'
|
||||||
labelClassName='col-span-2'
|
labelClassName='col-span-2'
|
||||||
inputClassName='col-span-3'
|
inputClassName='col-span-3'
|
||||||
|
@ -189,7 +173,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
isDisabled={props.properties.isFlex} />
|
isDisabled={props.properties.isFlex} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-maxWidth`}
|
id={`${props.properties.id}-maxWidth`}
|
||||||
labelText='Maximum Width'
|
labelText={Text({ textId: '@ContainerMaxWidth' })}
|
||||||
inputKey='maxWidth'
|
inputKey='maxWidth'
|
||||||
labelClassName='col-span-2'
|
labelClassName='col-span-2'
|
||||||
inputClassName='col-span-3'
|
inputClassName='col-span-3'
|
||||||
|
@ -200,7 +184,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
<div className='col-span-5 p-3'></div>
|
<div className='col-span-5 p-3'></div>
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-minHeight`}
|
id={`${props.properties.id}-minHeight`}
|
||||||
labelText='Minimum Height'
|
labelText={Text({ textId: '@ContainerMinHeight' })}
|
||||||
inputKey='minHeight'
|
inputKey='minHeight'
|
||||||
labelClassName='col-span-2'
|
labelClassName='col-span-2'
|
||||||
inputClassName='col-span-3'
|
inputClassName='col-span-3'
|
||||||
|
@ -210,7 +194,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
onChange={(value) => props.onChange('minHeight', Number(value))} />
|
onChange={(value) => props.onChange('minHeight', Number(value))} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-height`}
|
id={`${props.properties.id}-height`}
|
||||||
labelText='Height'
|
labelText={Text({ textId: '@ContainerHeight' })}
|
||||||
inputKey='height'
|
inputKey='height'
|
||||||
labelClassName='col-span-2'
|
labelClassName='col-span-2'
|
||||||
inputClassName='col-span-3'
|
inputClassName='col-span-3'
|
||||||
|
@ -223,7 +207,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
/>
|
/>
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-maxHeight`}
|
id={`${props.properties.id}-maxHeight`}
|
||||||
labelText='Maximum Height'
|
labelText={Text({ textId: '@ContainerMaxHeight' })}
|
||||||
inputKey='maxHeight'
|
inputKey='maxHeight'
|
||||||
labelClassName='col-span-2'
|
labelClassName='col-span-2'
|
||||||
inputClassName='col-span-3'
|
inputClassName='col-span-3'
|
||||||
|
@ -236,14 +220,14 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
|
|
||||||
<Category category={{
|
<Category category={{
|
||||||
Type: 'Margins',
|
Type: 'Margins',
|
||||||
DisplayedText: 'Margins'
|
DisplayedText: Text({ textId: '@ContainerMargins' })
|
||||||
}}
|
}}
|
||||||
heightClass={`${categoryHeight}`}
|
heightClass={`${categoryHeight}`}
|
||||||
>
|
>
|
||||||
<div className='grid grid-cols-2 items-center gap-y-2 prop-category-body'>
|
<div className='grid grid-cols-2 items-center gap-y-2 prop-category-body'>
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-ml`}
|
id={`${props.properties.id}-ml`}
|
||||||
labelText='Margin left'
|
labelText={Text({ textId: '@ContainerMarginLeft' })}
|
||||||
inputKey='left'
|
inputKey='left'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -253,7 +237,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
onChange={(value) => props.onChange('left', Number(value), PropertyType.Margin)} />
|
onChange={(value) => props.onChange('left', Number(value), PropertyType.Margin)} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-mb`}
|
id={`${props.properties.id}-mb`}
|
||||||
labelText='Margin bottom'
|
labelText={Text({ textId: '@ContainerMarginBottom' })}
|
||||||
inputKey='bottom'
|
inputKey='bottom'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -263,7 +247,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
onChange={(value) => props.onChange('bottom', Number(value), PropertyType.Margin)} />
|
onChange={(value) => props.onChange('bottom', Number(value), PropertyType.Margin)} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-mt`}
|
id={`${props.properties.id}-mt`}
|
||||||
labelText='Margin top'
|
labelText={Text({ textId: '@ContainerMarginTop' })}
|
||||||
inputKey='top'
|
inputKey='top'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -273,7 +257,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
onChange={(value) => props.onChange('top', Number(value), PropertyType.Margin)} />
|
onChange={(value) => props.onChange('top', Number(value), PropertyType.Margin)} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id={`${props.properties.id}-mr`}
|
id={`${props.properties.id}-mr`}
|
||||||
labelText='Margin right'
|
labelText={Text({ textId: '@ContainerMarginRight' })}
|
||||||
inputKey='right'
|
inputKey='right'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -286,13 +270,13 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
|
|
||||||
<Category category={{
|
<Category category={{
|
||||||
Type: 'Behaviors',
|
Type: 'Behaviors',
|
||||||
DisplayedText: 'Behaviors'
|
DisplayedText: Text({ textId: '@ContainerBehaviors' })
|
||||||
}}
|
}}
|
||||||
heightClass={`${categoryHeight}`}
|
heightClass={`${categoryHeight}`}
|
||||||
>
|
>
|
||||||
<div className='grid grid-cols-2 items-center gap-y-2 prop-category-body'>
|
<div className='grid grid-cols-2 items-center gap-y-2 prop-category-body'>
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
labelText='Flex'
|
labelText={Text({ textId: '@ContainerFlex' })}
|
||||||
inputKey='isFlex'
|
inputKey='isFlex'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName='ml-auto mr-auto block'
|
inputClassName='ml-auto mr-auto block'
|
||||||
|
@ -301,7 +285,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
onChange={(event) => props.onChange('isFlex', event.target.checked)}
|
onChange={(event) => props.onChange('isFlex', event.target.checked)}
|
||||||
/>
|
/>
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
labelText='Anchor'
|
labelText={Text({ textId: '@ContainerAnchor' })}
|
||||||
inputKey='isAnchor'
|
inputKey='isAnchor'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName='ml-auto mr-auto block'
|
inputClassName='ml-auto mr-auto block'
|
||||||
|
@ -313,7 +297,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
|
|
||||||
<Category category={{
|
<Category category={{
|
||||||
Type: 'Alignment',
|
Type: 'Alignment',
|
||||||
DisplayedText: 'Alignment'
|
DisplayedText: Text({ textId: '@ContainerAlignment' })
|
||||||
}}
|
}}
|
||||||
heightClass={`${categoryHeight}`}
|
heightClass={`${categoryHeight}`}
|
||||||
>
|
>
|
||||||
|
@ -321,14 +305,14 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
<PositionReferenceSelector
|
<PositionReferenceSelector
|
||||||
id='positionReference'
|
id='positionReference'
|
||||||
name='PositionReference'
|
name='PositionReference'
|
||||||
labelText='Alignment'
|
labelText={Text({ textId: '@ContainerAlignmentInput' })}
|
||||||
value={props.properties.positionReference}
|
value={props.properties.positionReference}
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
<div className='p-3'></div>
|
<div className='p-3'></div>
|
||||||
<Select
|
<Select
|
||||||
inputKey='linkedSymbolId'
|
inputKey='linkedSymbolId'
|
||||||
labelText='Align with symbol'
|
labelText={Text({ textId: '@ContainerAlignWithSymbol' })}
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
inputs={[...props.symbols.values()].map(symbol => ({
|
inputs={[...props.symbols.values()].map(symbol => ({
|
||||||
|
@ -343,7 +327,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
|
|
||||||
<Category category={{
|
<Category category={{
|
||||||
Type: 'Dimensions',
|
Type: 'Dimensions',
|
||||||
DisplayedText: 'Dimensions'
|
DisplayedText: Text({ textId: '@ContainerDimensions' })
|
||||||
}}
|
}}
|
||||||
heightClass={`${categoryHeight}`}
|
heightClass={`${categoryHeight}`}
|
||||||
>
|
>
|
||||||
|
@ -354,7 +338,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
<PositionCheckboxes
|
<PositionCheckboxes
|
||||||
id='showSelfDimensions'
|
id='showSelfDimensions'
|
||||||
name='ShowSelfDimensions'
|
name='ShowSelfDimensions'
|
||||||
labelText='Show dimension'
|
labelText={Text({ textId: '@ContainerShowDimension' })}
|
||||||
value={props.properties.showSelfDimensions}
|
value={props.properties.showSelfDimensions}
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
|
@ -366,7 +350,7 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
<PositionCheckboxes
|
<PositionCheckboxes
|
||||||
id='showChildrenDimensions'
|
id='showChildrenDimensions'
|
||||||
name='ShowChildrenDimensions'
|
name='ShowChildrenDimensions'
|
||||||
labelText='Show overall dimension of its children'
|
labelText={Text({ textId: '@ContainerShowChildrenDimension' })}
|
||||||
value={props.properties.showChildrenDimensions}
|
value={props.properties.showChildrenDimensions}
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
|
@ -374,40 +358,97 @@ export function ContainerForm(props: IContainerFormProps): JSX.Element {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
SHOW_BORROWER_DIMENSIONS &&
|
SHOW_BORROWER_DIMENSIONS &&
|
||||||
<>
|
<>
|
||||||
<div className='grid grid-cols-1 gap-2'>
|
<div className='grid grid-cols-1 gap-2'>
|
||||||
<OrientationCheckboxes
|
<OrientationCheckboxes
|
||||||
id='markPosition'
|
id='markPosition'
|
||||||
name='MarkPosition'
|
name='MarkPosition'
|
||||||
value={props.properties.markPosition}
|
value={props.properties.markPosition}
|
||||||
labelText='Mark the position'
|
labelText={Text({ textId: '@ContainerMarkPosition' })}
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='grid grid-cols-1 gap-2'>
|
<div className='grid grid-cols-1 gap-2'>
|
||||||
<PositionCheckboxes
|
<PositionCheckboxes
|
||||||
id='showDimensionWithMarks'
|
id='showDimensionWithMarks'
|
||||||
name='ShowDimensionWithMarks'
|
name='ShowDimensionWithMarks'
|
||||||
labelText='Show dimension with marked children'
|
labelText={Text({ textId: '@ContainerShowDimensionWithMarks' })}
|
||||||
value={props.properties.showDimensionWithMarks}
|
value={props.properties.showDimensionWithMarks}
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</Category>
|
</Category>
|
||||||
|
|
||||||
<Category category={{
|
{ props.properties.style !== undefined &&
|
||||||
Type: 'Style',
|
<Category category={{
|
||||||
DisplayedText: 'Style'
|
Type: 'Style',
|
||||||
}}
|
DisplayedText: Text({ textId: '@ContainerStyle' })
|
||||||
heightClass={`${categoryHeight}`}
|
}}
|
||||||
>
|
heightClass={`${categoryHeight}`}
|
||||||
<div className='grid grid-cols-5 gap-6 items-center prop-category-body'>
|
>
|
||||||
{GetCSSInputs(props.properties, props.onChange)}
|
<div className='grid grid-cols-5 gap-6 items-center prop-category-body'>
|
||||||
</div>
|
<TextInputGroup
|
||||||
</Category>
|
id={`${props.properties.id}-stroke`}
|
||||||
|
labelText={Text({ textId: '@StyleStroke' })}
|
||||||
|
inputKey='stroke'
|
||||||
|
labelClassName='col-span-2'
|
||||||
|
inputClassName='col-span-3'
|
||||||
|
type='string'
|
||||||
|
value={props.properties.style.stroke ?? 'black'}
|
||||||
|
onChange={(value) => props.onChange('stroke', value, PropertyType.Style)}
|
||||||
|
/>
|
||||||
|
<InputGroup
|
||||||
|
labelKey={`${props.properties.id}-strokeOpacity`}
|
||||||
|
labelText={Text({ textId: '@StyleStrokeOpacity' })}
|
||||||
|
inputKey='strokeOpacity'
|
||||||
|
labelClassName='col-span-2'
|
||||||
|
inputClassName='col-span-3'
|
||||||
|
type='range'
|
||||||
|
min={0}
|
||||||
|
max={1}
|
||||||
|
step={0.01}
|
||||||
|
value={(props.properties.style.strokeOpacity ?? 1).toString()}
|
||||||
|
onChange={(event) => props.onChange('strokeOpacity', Number(event.target.value), PropertyType.Style)}
|
||||||
|
/>
|
||||||
|
<TextInputGroup
|
||||||
|
id={`${props.properties.id}-strokeWidth`}
|
||||||
|
labelText={Text({ textId: '@StyleStrokeWidth' })}
|
||||||
|
inputKey='strokeWidth'
|
||||||
|
labelClassName='col-span-2'
|
||||||
|
inputClassName='col-span-3'
|
||||||
|
type='number'
|
||||||
|
value={(props.properties.style.strokeWidth ?? 1).toString()}
|
||||||
|
onChange={(value) => props.onChange('strokeWidth', Number(value), PropertyType.Style)}
|
||||||
|
/>
|
||||||
|
<TextInputGroup
|
||||||
|
id={`${props.properties.id}-fill`}
|
||||||
|
labelText={Text({ textId: '@StyleFill' })}
|
||||||
|
inputKey='fill'
|
||||||
|
labelClassName='col-span-2'
|
||||||
|
inputClassName='col-span-3'
|
||||||
|
type='string'
|
||||||
|
value={props.properties.style.fill ?? 'black'}
|
||||||
|
onChange={(value) => props.onChange('fill', value, PropertyType.Style)}
|
||||||
|
/>
|
||||||
|
<InputGroup
|
||||||
|
labelKey={`${props.properties.id}-fillOpacity`}
|
||||||
|
labelText={Text({ textId: '@StyleFillOpacity' })}
|
||||||
|
inputKey='fillOpacity'
|
||||||
|
labelClassName='col-span-2'
|
||||||
|
inputClassName='col-span-3'
|
||||||
|
type='range'
|
||||||
|
min={0}
|
||||||
|
max={1}
|
||||||
|
step={0.01}
|
||||||
|
value={(props.properties.style.fillOpacity ?? 1).toString()}
|
||||||
|
onChange={(event) => props.onChange('fillOpacity', Number(event.target.value), PropertyType.Style)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Category>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,14 @@
|
||||||
import { AddMethod } from '../../../Enums/AddMethod';
|
import { AddMethod } from '../../../Enums/AddMethod';
|
||||||
import { IAvailableContainer } from '../../../Interfaces/IAvailableContainer';
|
import { IAvailableContainer } from '../../../Interfaces/IAvailableContainer';
|
||||||
import { IConfiguration } from '../../../Interfaces/IConfiguration';
|
import { IConfiguration } from '../../../Interfaces/IConfiguration';
|
||||||
import { IContainerModel, ContainerModel } from '../../../Interfaces/IContainerModel';
|
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
import { IHistoryState } from '../../../Interfaces/IHistoryState';
|
import { IHistoryState } from '../../../Interfaces/IHistoryState';
|
||||||
import { IPattern, GetPattern, ContainerOrPattern } from '../../../Interfaces/IPattern';
|
import { IPattern, GetPattern, ContainerOrPattern } from '../../../Interfaces/IPattern';
|
||||||
import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
|
import { ISymbolModel } from '../../../Interfaces/ISymbolModel';
|
||||||
import { Orientation } from '../../../Enums/Orientation';
|
import { Orientation } from '../../../Enums/Orientation';
|
||||||
import { GetDefaultContainerProps } from '../../../utils/default';
|
import { GetDefaultContainerProps } from '../../../utils/default';
|
||||||
import { FindContainerById } from '../../../utils/itertools';
|
import { FindContainerById } from '../../../utils/itertools';
|
||||||
import { ApplyMargin } from '../../../utils/svg';
|
import { ApplyMargin, RestoreX, RestoreY } from '../../../utils/svg';
|
||||||
import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
|
import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
|
||||||
import { GetCurrentHistory, UpdateCounters } from '../Editor';
|
import { GetCurrentHistory, UpdateCounters } from '../Editor';
|
||||||
import { SortChildren } from './ContainerOperations';
|
import { SortChildren } from './ContainerOperations';
|
||||||
|
@ -59,7 +59,10 @@ export function AddContainers(
|
||||||
configuration: IConfiguration,
|
configuration: IConfiguration,
|
||||||
fullHistory: IHistoryState[],
|
fullHistory: IHistoryState[],
|
||||||
historyCurrentStep: number
|
historyCurrentStep: number
|
||||||
): IHistoryState[] {
|
): {
|
||||||
|
history: IHistoryState[]
|
||||||
|
newContainers: IContainerModel[]
|
||||||
|
} {
|
||||||
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
|
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
|
||||||
const current = history[history.length - 1];
|
const current = history[history.length - 1];
|
||||||
|
|
||||||
|
@ -77,18 +80,27 @@ export function AddContainers(
|
||||||
// Deep clone the counters
|
// Deep clone the counters
|
||||||
const newCounters = Object.assign({}, current.typeCounters);
|
const newCounters = Object.assign({}, current.typeCounters);
|
||||||
|
|
||||||
// containerIds is used for logging purpose (see setHistory below)
|
|
||||||
const containerIds: string[] = [];
|
|
||||||
|
|
||||||
// Iterate over the containers
|
// Iterate over the containers
|
||||||
|
const newContainers: IContainerModel[] = [];
|
||||||
availableContainers.forEach((availableContainer, typeIndex) => {
|
availableContainers.forEach((availableContainer, typeIndex) => {
|
||||||
// Get the preset properties from the API
|
// Get the preset properties from the API
|
||||||
AddNewContainerToParent(availableContainer, configuration, containers, parentClone, index, typeIndex, newCounters, current.symbols, containerIds);
|
const newContainer = AddNewContainerToParent(
|
||||||
|
availableContainer,
|
||||||
|
configuration,
|
||||||
|
containers,
|
||||||
|
parentClone,
|
||||||
|
index,
|
||||||
|
typeIndex,
|
||||||
|
newCounters,
|
||||||
|
current.symbols
|
||||||
|
);
|
||||||
|
newContainers.push(newContainer);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update the state
|
// Update the state
|
||||||
|
const containersIds = newContainers.map(container => container.properties.id);
|
||||||
history.push({
|
history.push({
|
||||||
lastAction: `Add [${containerIds.join(', ')}] in ${parentClone.properties.id}`,
|
lastAction: `Add [${containersIds.join(', ')}] in ${parentClone.properties.id}`,
|
||||||
mainContainer: current.mainContainer,
|
mainContainer: current.mainContainer,
|
||||||
selectedContainerId: parentClone.properties.id,
|
selectedContainerId: parentClone.properties.id,
|
||||||
containers,
|
containers,
|
||||||
|
@ -97,7 +109,10 @@ export function AddContainers(
|
||||||
selectedSymbolId: current.selectedSymbolId
|
selectedSymbolId: current.selectedSymbolId
|
||||||
});
|
});
|
||||||
|
|
||||||
return history;
|
return {
|
||||||
|
history,
|
||||||
|
newContainers
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function AddNewContainerToParent(
|
function AddNewContainerToParent(
|
||||||
|
@ -109,9 +124,8 @@ function AddNewContainerToParent(
|
||||||
typeIndex: number,
|
typeIndex: number,
|
||||||
newCounters: Record<string, number>,
|
newCounters: Record<string, number>,
|
||||||
symbols: Map<string, ISymbolModel>,
|
symbols: Map<string, ISymbolModel>,
|
||||||
containerIds: string[] = [],
|
|
||||||
initChilds: boolean = true
|
initChilds: boolean = true
|
||||||
): ContainerModel {
|
): IContainerModel {
|
||||||
const type = availableContainer.Type;
|
const type = availableContainer.Type;
|
||||||
|
|
||||||
const defaultConfig = configuration.AvailableContainers
|
const defaultConfig = configuration.AvailableContainers
|
||||||
|
@ -121,7 +135,7 @@ function AddNewContainerToParent(
|
||||||
throw new Error(`[AddContainer] Object type not found among default config. Found: ${type}`);
|
throw new Error(`[AddContainer] Object type not found among default config. Found: ${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const containerConfig = Object.assign(defaultConfig, availableContainer);
|
const containerConfig = Object.assign(structuredClone(defaultConfig), availableContainer);
|
||||||
|
|
||||||
// Default margin
|
// Default margin
|
||||||
const left: number = containerConfig.Margin?.left ?? 0;
|
const left: number = containerConfig.Margin?.left ?? 0;
|
||||||
|
@ -130,10 +144,10 @@ function AddNewContainerToParent(
|
||||||
const right: number = containerConfig.Margin?.right ?? 0;
|
const right: number = containerConfig.Margin?.right ?? 0;
|
||||||
|
|
||||||
// Default coordinates
|
// Default coordinates
|
||||||
let x = containerConfig.X ?? 0;
|
|
||||||
let y = containerConfig.Y ?? 0;
|
|
||||||
let width = containerConfig.Width ?? containerConfig.MaxWidth ?? containerConfig.MinWidth ?? parentClone.properties.width;
|
let width = containerConfig.Width ?? containerConfig.MaxWidth ?? containerConfig.MinWidth ?? parentClone.properties.width;
|
||||||
let height = containerConfig.Height ?? containerConfig.MaxHeight ?? containerConfig.MinHeight ?? parentClone.properties.height;
|
let height = containerConfig.Height ?? containerConfig.MaxHeight ?? containerConfig.MinHeight ?? parentClone.properties.height;
|
||||||
|
let x = RestoreX(containerConfig.X ?? 0, width, containerConfig.PositionReference);
|
||||||
|
let y = RestoreY(containerConfig.Y ?? 0, height, containerConfig.PositionReference);
|
||||||
|
|
||||||
({ x, y, width, height } = ApplyMargin(x, y, width, height, left, bottom, top, right));
|
({ x, y, width, height } = ApplyMargin(x, y, width, height, left, bottom, top, right));
|
||||||
|
|
||||||
|
@ -156,13 +170,11 @@ function AddNewContainerToParent(
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the container
|
// Create the container
|
||||||
const newContainer = new ContainerModel(
|
const newContainer: IContainerModel = {
|
||||||
defaultProperties,
|
properties: defaultProperties,
|
||||||
[],
|
children: [],
|
||||||
{
|
userData: {}
|
||||||
type
|
};
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Register the container in the hashmap
|
// Register the container in the hashmap
|
||||||
containers.set(newContainer.properties.id, newContainer);
|
containers.set(newContainer.properties.id, newContainer);
|
||||||
|
@ -207,9 +219,6 @@ function AddNewContainerToParent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the list of container id for logging purpose
|
|
||||||
containerIds.push(newContainer.properties.id);
|
|
||||||
|
|
||||||
return newContainer;
|
return newContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +243,7 @@ export function AddContainer(
|
||||||
historyCurrentStep: number
|
historyCurrentStep: number
|
||||||
): IHistoryState[] {
|
): IHistoryState[] {
|
||||||
// just call AddContainers with an array on a single element
|
// just call AddContainers with an array on a single element
|
||||||
return AddContainers(
|
const { history } = AddContainers(
|
||||||
index,
|
index,
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
[{ Type: type }],
|
[{ Type: type }],
|
||||||
|
@ -243,6 +252,7 @@ export function AddContainer(
|
||||||
fullHistory,
|
fullHistory,
|
||||||
historyCurrentStep
|
historyCurrentStep
|
||||||
);
|
);
|
||||||
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -254,7 +264,7 @@ export function AddContainer(
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function InitializeDefaultChild(
|
function InitializeDefaultChild(
|
||||||
newContainer: ContainerModel,
|
newContainer: IContainerModel,
|
||||||
configuration: IConfiguration,
|
configuration: IConfiguration,
|
||||||
containerConfig: IAvailableContainer,
|
containerConfig: IAvailableContainer,
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
|
@ -285,7 +295,7 @@ function InitializeDefaultChild(
|
||||||
}
|
}
|
||||||
|
|
||||||
function InitializeChildrenWithPattern(
|
function InitializeChildrenWithPattern(
|
||||||
newContainer: ContainerModel,
|
newContainer: IContainerModel,
|
||||||
configuration: IConfiguration,
|
configuration: IConfiguration,
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
containerConfig: IAvailableContainer,
|
containerConfig: IAvailableContainer,
|
||||||
|
@ -326,7 +336,7 @@ function InitializeChildrenWithPattern(
|
||||||
*/
|
*/
|
||||||
function BuildPatterns(
|
function BuildPatterns(
|
||||||
rootPattern: ContainerOrPattern,
|
rootPattern: ContainerOrPattern,
|
||||||
newContainer: ContainerModel,
|
newContainer: IContainerModel,
|
||||||
configuration: IConfiguration,
|
configuration: IConfiguration,
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
newCounters: Record<string, number>,
|
newCounters: Record<string, number>,
|
||||||
|
@ -432,7 +442,6 @@ function AddContainerInLevel(
|
||||||
0, 0,
|
0, 0,
|
||||||
newCounters,
|
newCounters,
|
||||||
symbols,
|
symbols,
|
||||||
undefined,
|
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { IHistoryState } from '../../../Interfaces/IHistoryState';
|
import { IHistoryState } from '../../../Interfaces/IHistoryState';
|
||||||
import { ContainerModel, IContainerModel } from '../../../Interfaces/IContainerModel';
|
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
import { FindContainerById, MakeDFSIterator } from '../../../utils/itertools';
|
import { FindContainerById, MakeDFSIterator } from '../../../utils/itertools';
|
||||||
import { GetCurrentHistory } from '../Editor';
|
import { GetCurrentHistory } from '../Editor';
|
||||||
import { ApplyBehaviors, ApplyBehaviorsOnSiblings, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
|
import { ApplyBehaviors, ApplyBehaviorsOnSiblings, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
|
||||||
|
@ -176,7 +176,7 @@ export function OnPropertyChange(
|
||||||
}
|
}
|
||||||
|
|
||||||
const containers = structuredClone(current.containers);
|
const containers = structuredClone(current.containers);
|
||||||
const container: ContainerModel | undefined = FindContainerById(containers, selected.properties.id);
|
const container: IContainerModel | undefined = FindContainerById(containers, selected.properties.id);
|
||||||
|
|
||||||
if (container === null || container === undefined) {
|
if (container === null || container === undefined) {
|
||||||
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
|
||||||
|
@ -270,7 +270,7 @@ export function SortChildren(
|
||||||
*/
|
*/
|
||||||
function SetContainer(
|
function SetContainer(
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
container: ContainerModel,
|
container: IContainerModel,
|
||||||
key: string, value: string | number | boolean | number[],
|
key: string, value: string | number | boolean | number[],
|
||||||
type: PropertyType,
|
type: PropertyType,
|
||||||
symbols: Map<string, ISymbolModel>
|
symbols: Map<string, ISymbolModel>
|
||||||
|
@ -282,11 +282,12 @@ function SetContainer(
|
||||||
AssignProperty(container, key, value, type);
|
AssignProperty(container, key, value, type);
|
||||||
|
|
||||||
// link the symbol if it exists
|
// link the symbol if it exists
|
||||||
|
const oldSymbol = symbols.get(oldSymbolId);
|
||||||
|
const newSymbol = symbols.get(container.properties.linkedSymbolId);
|
||||||
LinkSymbol(
|
LinkSymbol(
|
||||||
container.properties.id,
|
container.properties.id,
|
||||||
oldSymbolId,
|
oldSymbol,
|
||||||
container.properties.linkedSymbolId,
|
newSymbol
|
||||||
symbols
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Apply special behaviors: rigid, flex, symbol, anchor
|
// Apply special behaviors: rigid, flex, symbol, anchor
|
||||||
|
@ -309,7 +310,7 @@ function SetContainer(
|
||||||
* @param value Value of the property
|
* @param value Value of the property
|
||||||
* @param type Type of the property
|
* @param type Type of the property
|
||||||
*/
|
*/
|
||||||
function AssignProperty(container: ContainerModel, key: string, value: string | number | boolean | number[], type: PropertyType): void {
|
function AssignProperty(container: IContainerModel, key: string, value: string | number | boolean | number[], type: PropertyType): void {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PropertyType.Style:
|
case PropertyType.Style:
|
||||||
(container.properties.style as any)[key] = value;
|
(container.properties.style as any)[key] = value;
|
||||||
|
@ -357,15 +358,11 @@ function AssignProperty(container: ContainerModel, key: string, value: string |
|
||||||
* @param symbols Current list of symbols
|
* @param symbols Current list of symbols
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function LinkSymbol(
|
export function LinkSymbol(
|
||||||
containerId: string,
|
containerId: string,
|
||||||
oldSymbolId: string,
|
oldSymbol: ISymbolModel | undefined,
|
||||||
newSymbolId: string,
|
newSymbol: ISymbolModel | undefined
|
||||||
symbols: Map<string, ISymbolModel>
|
|
||||||
): void {
|
): void {
|
||||||
const oldSymbol = symbols.get(oldSymbolId);
|
|
||||||
const newSymbol = symbols.get(newSymbolId);
|
|
||||||
|
|
||||||
if (newSymbol === undefined) {
|
if (newSymbol === undefined) {
|
||||||
if (oldSymbol !== undefined) {
|
if (oldSymbol !== undefined) {
|
||||||
oldSymbol.linkedContainers.delete(containerId);
|
oldSymbol.linkedContainers.delete(containerId);
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { GetCurrentHistoryState } from '../Editor';
|
||||||
import { AddContainers } from './AddContainer';
|
import { AddContainers } from './AddContainer';
|
||||||
import { DeleteContainer } from './ContainerOperations';
|
import { DeleteContainer } from './ContainerOperations';
|
||||||
import { DeleteSymbol } from './SymbolOperations';
|
import { DeleteSymbol } from './SymbolOperations';
|
||||||
|
import { Text } from '../../Text/Text';
|
||||||
|
|
||||||
export function InitActions(
|
export function InitActions(
|
||||||
menuActions: Map<string, IMenuAction[]>,
|
menuActions: Map<string, IMenuAction[]>,
|
||||||
|
@ -28,8 +29,8 @@ export function InitActions(
|
||||||
'',
|
'',
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
text: 'Undo',
|
text: Text({ textId: '@Undo' }),
|
||||||
title: 'Undo last action',
|
title: Text({ textId: '@UndoTitle' }),
|
||||||
shortcut: '<kbd>Ctrl</kbd>+<kbd>Z</kbd>',
|
shortcut: '<kbd>Ctrl</kbd>+<kbd>Z</kbd>',
|
||||||
action: () => {
|
action: () => {
|
||||||
if (historyCurrentStep <= 0) {
|
if (historyCurrentStep <= 0) {
|
||||||
|
@ -39,8 +40,8 @@ export function InitActions(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: 'Redo',
|
text: Text({ textId: '@Redo' }),
|
||||||
title: 'Redo last action',
|
title: Text({ textId: '@RedoTitle' }),
|
||||||
shortcut: '<kbd>Ctrl</kbd>+<kbd>Y</kbd>',
|
shortcut: '<kbd>Ctrl</kbd>+<kbd>Y</kbd>',
|
||||||
action: () => {
|
action: () => {
|
||||||
if (historyCurrentStep >= history.length - 1) {
|
if (historyCurrentStep >= history.length - 1) {
|
||||||
|
@ -55,8 +56,8 @@ export function InitActions(
|
||||||
menuActions.set(
|
menuActions.set(
|
||||||
'elements-sidebar-row',
|
'elements-sidebar-row',
|
||||||
[{
|
[{
|
||||||
text: 'Delete',
|
text: Text({ textId: '@DeleteContainer' }),
|
||||||
title: 'Delete the container',
|
title: Text({ textId: '@DeleteContainerTitle' }),
|
||||||
shortcut: '<kbd>Suppr</kbd>',
|
shortcut: '<kbd>Suppr</kbd>',
|
||||||
action: (target: HTMLElement) => {
|
action: (target: HTMLElement) => {
|
||||||
const id = target.id;
|
const id = target.id;
|
||||||
|
@ -73,8 +74,8 @@ export function InitActions(
|
||||||
menuActions.set(
|
menuActions.set(
|
||||||
'symbols-sidebar-row',
|
'symbols-sidebar-row',
|
||||||
[{
|
[{
|
||||||
text: 'Delete',
|
text: Text({ textId: '@DeleteSymbol' }),
|
||||||
title: 'Delete the container',
|
title: Text({ textId: '@DeleteSymbolTitle' }),
|
||||||
shortcut: '<kbd>Suppr</kbd>',
|
shortcut: '<kbd>Suppr</kbd>',
|
||||||
action: (target: HTMLElement) => {
|
action: (target: HTMLElement) => {
|
||||||
const id = target.id;
|
const id = target.id;
|
||||||
|
@ -200,21 +201,23 @@ function HandleSetContainerList(
|
||||||
const addingBehavior = response.AddingBehavior ?? action.AddingBehavior;
|
const addingBehavior = response.AddingBehavior ?? action.AddingBehavior;
|
||||||
const current = GetCurrentHistoryState(history, historyCurrentStep);
|
const current = GetCurrentHistoryState(history, historyCurrentStep);
|
||||||
const containers = current.containers;
|
const containers = current.containers;
|
||||||
const parent = FindContainerById(containers, selectedContainer.properties.parentId);
|
|
||||||
switch (addingBehavior) {
|
switch (addingBehavior) {
|
||||||
case AddMethod.Append:
|
|
||||||
setNewHistory(
|
|
||||||
AddContainers(
|
|
||||||
selectedContainer.children.length,
|
|
||||||
response.Containers,
|
|
||||||
selectedContainer.properties.id,
|
|
||||||
configuration,
|
|
||||||
history,
|
|
||||||
historyCurrentStep
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
case AddMethod.Insert:
|
case AddMethod.Insert:
|
||||||
throw new Error('Not yet supported');
|
case AddMethod.Append: {
|
||||||
|
response.Containers.forEach(config => {
|
||||||
|
config.AddMethod = config.AddMethod ?? addingBehavior;
|
||||||
|
});
|
||||||
|
const { history: newHistory } = AddContainers(
|
||||||
|
selectedContainer.children.length,
|
||||||
|
response.Containers,
|
||||||
|
selectedContainer.properties.id,
|
||||||
|
configuration,
|
||||||
|
history,
|
||||||
|
historyCurrentStep);
|
||||||
|
|
||||||
|
setNewHistory(newHistory);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case AddMethod.Replace:
|
case AddMethod.Replace:
|
||||||
setNewHistory(
|
setNewHistory(
|
||||||
HandleReplace(
|
HandleReplace(
|
||||||
|
@ -227,7 +230,8 @@ function HandleSetContainerList(
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case AddMethod.ReplaceParent:
|
case AddMethod.ReplaceParent: {
|
||||||
|
const parent = FindContainerById(containers, selectedContainer.properties.parentId);
|
||||||
if (parent === undefined || parent === null) {
|
if (parent === undefined || parent === null) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
|
@ -247,6 +251,7 @@ function HandleSetContainerList(
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +276,50 @@ function HandleReplace(
|
||||||
historyCurrentStep
|
historyCurrentStep
|
||||||
);
|
);
|
||||||
|
|
||||||
const newHistoryBeforeDelete = AddContainers(
|
const { history: newHistoryBeforeDelete } = AddContainers(
|
||||||
|
index,
|
||||||
|
response.Containers,
|
||||||
|
selectedContainer.properties.parentId,
|
||||||
|
configuration,
|
||||||
|
newHistoryAfterDelete,
|
||||||
|
newHistoryAfterDelete.length - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove AddContainers from history
|
||||||
|
if (import.meta.env.PROD) {
|
||||||
|
newHistoryBeforeDelete.splice(newHistoryBeforeDelete.length - 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rename the last action by Replace
|
||||||
|
const types = response.Containers.map(container => container.Type);
|
||||||
|
newHistoryBeforeDelete[newHistoryBeforeDelete.length - 1].lastAction =
|
||||||
|
`Replace ${selectedContainer.properties.id} by [${types.join(', ')}]`;
|
||||||
|
|
||||||
|
return newHistoryBeforeDelete;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HandleInsert(
|
||||||
|
containers: Map<string, IContainerModel>,
|
||||||
|
selectedContainer: IContainerModel,
|
||||||
|
response: ISetContainerListResponse,
|
||||||
|
configuration: IConfiguration,
|
||||||
|
history: IHistoryState[],
|
||||||
|
historyCurrentStep: number
|
||||||
|
): IHistoryState[] {
|
||||||
|
const parent = FindContainerById(containers, selectedContainer.properties.id);
|
||||||
|
if (parent === undefined || parent === null) {
|
||||||
|
throw new Error('[InsertContainer] Cannot insert in a container that does not exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = parent.children.indexOf(selectedContainer.properties.id);
|
||||||
|
|
||||||
|
const newHistoryAfterDelete = DeleteContainer(
|
||||||
|
selectedContainer.properties.id,
|
||||||
|
history,
|
||||||
|
historyCurrentStep
|
||||||
|
);
|
||||||
|
|
||||||
|
const { history: newHistoryBeforeDelete } = AddContainers(
|
||||||
index,
|
index,
|
||||||
response.Containers,
|
response.Containers,
|
||||||
selectedContainer.properties.parentId,
|
selectedContainer.properties.parentId,
|
||||||
|
|
|
@ -6,7 +6,9 @@ import { GetDefaultSymbolModel } from '../../../utils/default';
|
||||||
import { FindContainerById } from '../../../utils/itertools';
|
import { FindContainerById } from '../../../utils/itertools';
|
||||||
import { RestoreX } from '../../../utils/svg';
|
import { RestoreX } from '../../../utils/svg';
|
||||||
import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
|
import { ApplyBehaviors, ApplyBehaviorsOnSiblingsChildren } from '../Behaviors/Behaviors';
|
||||||
import { GetCurrentHistory, UpdateCounters } from '../Editor';
|
import { GetCurrentHistory, GetCurrentHistoryState, UpdateCounters } from '../Editor';
|
||||||
|
import { AddContainers } from './AddContainer';
|
||||||
|
import { LinkSymbol } from './ContainerOperations';
|
||||||
|
|
||||||
export function AddSymbol(
|
export function AddSymbol(
|
||||||
name: string,
|
name: string,
|
||||||
|
@ -14,7 +16,7 @@ export function AddSymbol(
|
||||||
fullHistory: IHistoryState[],
|
fullHistory: IHistoryState[],
|
||||||
historyCurrentStep: number
|
historyCurrentStep: number
|
||||||
): IHistoryState[] {
|
): IHistoryState[] {
|
||||||
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
|
let history = GetCurrentHistory(fullHistory, historyCurrentStep);
|
||||||
const current = history[history.length - 1];
|
const current = history[history.length - 1];
|
||||||
|
|
||||||
const symbolConfig = configuration.AvailableSymbols
|
const symbolConfig = configuration.AvailableSymbols
|
||||||
|
@ -24,24 +26,48 @@ export function AddSymbol(
|
||||||
throw new Error('[AddSymbol] Symbol could not be found in the config');
|
throw new Error('[AddSymbol] Symbol could not be found in the config');
|
||||||
}
|
}
|
||||||
const type = `symbol-${name}`;
|
const type = `symbol-${name}`;
|
||||||
const newCounters = structuredClone(current.typeCounters);
|
const typeCounters = structuredClone(current.typeCounters);
|
||||||
UpdateCounters(newCounters, type);
|
UpdateCounters(typeCounters, type);
|
||||||
|
|
||||||
const newSymbols = structuredClone(current.symbols);
|
const newSymbols = structuredClone(current.symbols);
|
||||||
const newSymbol: ISymbolModel = GetDefaultSymbolModel(name, newCounters, type, symbolConfig);
|
const newSymbol: ISymbolModel = GetDefaultSymbolModel(name, typeCounters, type, symbolConfig);
|
||||||
|
const containers = structuredClone(current.containers);
|
||||||
newSymbol.x = RestoreX(newSymbol.x, newSymbol.width, newSymbol.config.PositionReference);
|
newSymbol.x = RestoreX(newSymbol.x, newSymbol.width, newSymbol.config.PositionReference);
|
||||||
|
|
||||||
newSymbols.set(newSymbol.id, newSymbol);
|
newSymbols.set(newSymbol.id, newSymbol);
|
||||||
|
|
||||||
history.push({
|
history.push({
|
||||||
lastAction: `Add ${name}`,
|
lastAction: `Add ${name}`,
|
||||||
mainContainer: structuredClone(current.mainContainer),
|
mainContainer: current.mainContainer,
|
||||||
containers: structuredClone(current.containers),
|
containers,
|
||||||
selectedContainerId: current.selectedContainerId,
|
selectedContainerId: current.selectedContainerId,
|
||||||
typeCounters: newCounters,
|
typeCounters,
|
||||||
symbols: newSymbols,
|
symbols: newSymbols,
|
||||||
selectedSymbolId: newSymbol.id
|
selectedSymbolId: newSymbol.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (symbolConfig.AssociatedContainer !== undefined) {
|
||||||
|
const {
|
||||||
|
history: newHistory,
|
||||||
|
newContainers
|
||||||
|
} = AddContainers(
|
||||||
|
0,
|
||||||
|
[symbolConfig.AssociatedContainer],
|
||||||
|
current.mainContainer,
|
||||||
|
configuration,
|
||||||
|
history,
|
||||||
|
historyCurrentStep + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
history = newHistory;
|
||||||
|
const newCurrent = GetCurrentHistoryState(newHistory, historyCurrentStep + 2);
|
||||||
|
const newerSymbol = newCurrent.symbols.get(newSymbol.id);
|
||||||
|
|
||||||
|
newContainers.forEach((newContainer) => {
|
||||||
|
LinkContainer(newerSymbol, newContainer, newSymbols);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +81,7 @@ export function SelectSymbol(
|
||||||
|
|
||||||
history.push({
|
history.push({
|
||||||
lastAction: `Select ${symbolId}`,
|
lastAction: `Select ${symbolId}`,
|
||||||
mainContainer: structuredClone(current.mainContainer),
|
mainContainer: current.mainContainer,
|
||||||
containers: structuredClone(current.containers),
|
containers: structuredClone(current.containers),
|
||||||
selectedContainerId: current.selectedContainerId,
|
selectedContainerId: current.selectedContainerId,
|
||||||
typeCounters: structuredClone(current.typeCounters),
|
typeCounters: structuredClone(current.typeCounters),
|
||||||
|
@ -166,3 +192,20 @@ export function OnPropertyChange(
|
||||||
});
|
});
|
||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link a container to a symbol.
|
||||||
|
* If symbol is undefined, unlink the previous symbol of the container
|
||||||
|
* @param symbol
|
||||||
|
* @param container
|
||||||
|
* @param symbols
|
||||||
|
*/
|
||||||
|
function LinkContainer(
|
||||||
|
symbol: ISymbolModel | undefined,
|
||||||
|
container: IContainerModel,
|
||||||
|
symbols: Map<string, ISymbolModel>
|
||||||
|
): void {
|
||||||
|
const oldSymbol = symbols.get(container.properties.linkedSymbolId);
|
||||||
|
LinkSymbol(container.properties.id, oldSymbol, symbol);
|
||||||
|
container.properties.linkedSymbolId = symbol !== undefined ? symbol.id : '';
|
||||||
|
}
|
||||||
|
|
|
@ -135,7 +135,6 @@ export function ElementsList(props: IElementsListProps): JSX.Element {
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const { container, depth } = containers[index];
|
const { container, depth } = containers[index];
|
||||||
const key = container.properties.id.toString();
|
const key = container.properties.id.toString();
|
||||||
const tabs = '|\t'.repeat(depth);
|
|
||||||
const text = container.properties.displayedText === key
|
const text = container.properties.displayedText === key
|
||||||
? `${key}`
|
? `${key}`
|
||||||
: `${container.properties.displayedText}`;
|
: `${container.properties.displayedText}`;
|
||||||
|
@ -144,29 +143,19 @@ export function ElementsList(props: IElementsListProps): JSX.Element {
|
||||||
props.selectedContainer !== null &&
|
props.selectedContainer !== null &&
|
||||||
props.selectedContainer.properties.id === container.properties.id;
|
props.selectedContainer.properties.id === container.properties.id;
|
||||||
|
|
||||||
const selectedClass: string = isSelected
|
|
||||||
? 'border-l-4 bg-blue-500 shadow-lg shadow-blue-500/60 hover:bg-blue-600 hover:shadow-blue-500 text-slate-50'
|
|
||||||
: 'bg-slate-300/60 hover:bg-slate-400 hover:shadow-slate-400';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button type="button"
|
ElementsListRow(
|
||||||
className={`transition-all w-full border-blue-500 hover:shadow-lg elements-sidebar-row whitespace-pre
|
key,
|
||||||
text-left text-sm font-medium inline-flex ${container.properties.type} ${selectedClass}`}
|
container,
|
||||||
id={key}
|
depth,
|
||||||
key={key}
|
isSelected,
|
||||||
style={style}
|
style,
|
||||||
title={container.properties.warning}
|
text,
|
||||||
onClick={() => props.selectContainer(container.properties.id)}
|
props.containers,
|
||||||
onDrop={(event) => HandleOnDrop(event, props.containers, props.mainContainer, props.addContainer)}
|
props.mainContainer,
|
||||||
onDragOver={(event) => HandleDragOver(event, props.mainContainer)}
|
props.addContainer,
|
||||||
onDragLeave={(event) => HandleDragLeave(event)}
|
props.selectContainer
|
||||||
>
|
)
|
||||||
{tabs}
|
|
||||||
{text}
|
|
||||||
{container.properties.warning.length > 0 &&
|
|
||||||
<ExclamationTriangleIcon className='w-8'/>
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,3 +182,51 @@ export function ElementsList(props: IElementsListProps): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ElementsListRow(
|
||||||
|
key: string,
|
||||||
|
container: IContainerModel,
|
||||||
|
depth: number,
|
||||||
|
isSelected: boolean,
|
||||||
|
style: React.CSSProperties,
|
||||||
|
text: string,
|
||||||
|
containers: Map<string, IContainerModel>,
|
||||||
|
mainContainer: IContainerModel,
|
||||||
|
addContainer: (index: number, type: string, parent: string) => void,
|
||||||
|
selectContainer: (containerId: string) => void
|
||||||
|
): JSX.Element {
|
||||||
|
const verticalBars: JSX.Element[] = [];
|
||||||
|
const verticalBarSelectedClass = isSelected
|
||||||
|
? 'border-l-blue-400 group-hover:border-l-blue-300'
|
||||||
|
: 'border-l-slate-400 group-hover:border-l-slate-300';
|
||||||
|
for (let i = 0; i < depth; i++) {
|
||||||
|
verticalBars.push(
|
||||||
|
<span
|
||||||
|
key={`${key}-${i}`}
|
||||||
|
className={`h-full border-l-2 pr-2 ${verticalBarSelectedClass}`}
|
||||||
|
></span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const buttonSelectedClass: string = isSelected
|
||||||
|
? 'bg-blue-500 shadow-lg shadow-blue-500/60 hover:bg-blue-600 hover:shadow-blue-500 text-slate-50'
|
||||||
|
: 'bg-slate-300/60 hover:bg-slate-400 hover:shadow-slate-400';
|
||||||
|
|
||||||
|
return <button type="button"
|
||||||
|
className={`transition-all border-blue-500 hover:shadow-lg elements-sidebar-row whitespace-pre
|
||||||
|
text-left text-sm font-medium flex items-center align-middle group ${container.properties.type} ${buttonSelectedClass}`}
|
||||||
|
id={key}
|
||||||
|
key={key}
|
||||||
|
style={style}
|
||||||
|
title={container.properties.warning}
|
||||||
|
onClick={() => selectContainer(container.properties.id)}
|
||||||
|
onDrop={(event) => HandleOnDrop(event, containers, mainContainer, addContainer)}
|
||||||
|
onDragOver={(event) => HandleDragOver(event, mainContainer)}
|
||||||
|
onDragLeave={(event) => HandleDragLeave(event)}
|
||||||
|
>
|
||||||
|
{verticalBars}
|
||||||
|
{text}
|
||||||
|
{container.properties.warning.length > 0 &&
|
||||||
|
<ExclamationTriangleIcon className='pl-2 w-7' />}
|
||||||
|
</button>;
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ interface IInputGroupProps {
|
||||||
defaultChecked?: boolean
|
defaultChecked?: boolean
|
||||||
min?: number
|
min?: number
|
||||||
max?: number
|
max?: number
|
||||||
|
step?: number
|
||||||
isDisabled?: boolean
|
isDisabled?: boolean
|
||||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||||
}
|
}
|
||||||
|
@ -39,6 +40,7 @@ export function InputGroup(props: IInputGroupProps): JSX.Element {
|
||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
min={props.min}
|
min={props.min}
|
||||||
max={props.max}
|
max={props.max}
|
||||||
|
step={props.step}
|
||||||
disabled={props.isDisabled} />
|
disabled={props.isDisabled} />
|
||||||
</>;
|
</>;
|
||||||
}
|
}
|
||||||
|
|
31
src/Components/LanguageProvider/LanguageProvider.tsx
Normal file
31
src/Components/LanguageProvider/LanguageProvider.tsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { createContext, useState } from 'react';
|
||||||
|
import { ILanguage } from '../../Interfaces/ILanguage';
|
||||||
|
import { languageOptions, translations } from '../../Translations/Translations';
|
||||||
|
import { DEFAULT_LANGUAGE } from '../../utils/default';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
export const LanguageContext = createContext<ILanguage>({
|
||||||
|
language: DEFAULT_LANGUAGE,
|
||||||
|
dictionary: translations.en
|
||||||
|
});
|
||||||
|
|
||||||
|
export function LanguageProvider({ children }: { children: React.ReactNode | React.ReactNode[] | undefined }): JSX.Element {
|
||||||
|
const [language, setLanguage] = useState(DEFAULT_LANGUAGE);
|
||||||
|
const provider = {
|
||||||
|
language,
|
||||||
|
dictionary: translations[language],
|
||||||
|
languageChange: (selected: string) => {
|
||||||
|
const newLanguage = languageOptions[selected] !== undefined ? selected : DEFAULT_LANGUAGE;
|
||||||
|
setLanguage(newLanguage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LanguageContext.Provider
|
||||||
|
value={provider}
|
||||||
|
>
|
||||||
|
{ children }
|
||||||
|
</LanguageContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,6 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { FAST_BOOT } from '../../utils/default';
|
import { Text } from '../Text/Text';
|
||||||
import { Loader } from '../Loader/Loader';
|
|
||||||
|
|
||||||
interface IMainMenuProps {
|
interface IMainMenuProps {
|
||||||
newEditor: () => void
|
newEditor: () => void
|
||||||
|
@ -10,21 +9,11 @@ interface IMainMenuProps {
|
||||||
enum WindowState {
|
enum WindowState {
|
||||||
Main,
|
Main,
|
||||||
Load,
|
Load,
|
||||||
Loading,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MainMenu(props: IMainMenuProps): JSX.Element {
|
export function MainMenu(props: IMainMenuProps): JSX.Element {
|
||||||
const [windowState, setWindowState] = React.useState(WindowState.Main);
|
const [windowState, setWindowState] = React.useState(WindowState.Main);
|
||||||
|
|
||||||
if (FAST_BOOT) {
|
|
||||||
props.newEditor();
|
|
||||||
return (
|
|
||||||
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (windowState) {
|
switch (windowState) {
|
||||||
case WindowState.Load:
|
case WindowState.Load:
|
||||||
return (
|
return (
|
||||||
|
@ -65,12 +54,6 @@ export function MainMenu(props: IMainMenuProps): JSX.Element {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
);
|
);
|
||||||
case WindowState.Loading:
|
|
||||||
return (
|
|
||||||
<div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2'>
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<div className='absolute bg-blue-50 p-12
|
<div className='absolute bg-blue-50 p-12
|
||||||
|
@ -80,10 +63,17 @@ export function MainMenu(props: IMainMenuProps): JSX.Element {
|
||||||
w-full sm:w-auto
|
w-full sm:w-auto
|
||||||
sm:top-1/2 sm:left-1/2 sm:-translate-x-1/2 sm:-translate-y-1/2'>
|
sm:top-1/2 sm:left-1/2 sm:-translate-x-1/2 sm:-translate-y-1/2'>
|
||||||
<button type="button" className='mainmenu-btn' onClick={() => {
|
<button type="button" className='mainmenu-btn' onClick={() => {
|
||||||
setWindowState(WindowState.Loading);
|
|
||||||
props.newEditor();
|
props.newEditor();
|
||||||
}}>Start from scratch</button>
|
}}>
|
||||||
<button type="button" className='mainmenu-btn' onClick={() => setWindowState(WindowState.Load)}>Load a configuration file</button>
|
{Text({ textId: '@StartFromScratch' })}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className='mainmenu-btn'
|
||||||
|
onClick={() => setWindowState(WindowState.Load)}
|
||||||
|
>
|
||||||
|
{Text({ textId: '@LoadConfigFile' })}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { IMessage } from '../../Interfaces/IMessage';
|
||||||
import { DISABLE_API } from '../../utils/default';
|
import { DISABLE_API } from '../../utils/default';
|
||||||
import { GetCircularReplacer } from '../../utils/saveload';
|
import { GetCircularReplacer } from '../../utils/saveload';
|
||||||
import { TITLE_BAR_HEIGHT } from '../Sidebar/Sidebar';
|
import { TITLE_BAR_HEIGHT } from '../Sidebar/Sidebar';
|
||||||
|
import { Text } from '../Text/Text';
|
||||||
|
|
||||||
interface IMessagesProps {
|
interface IMessagesProps {
|
||||||
historyState: IHistoryState
|
historyState: IHistoryState
|
||||||
|
@ -49,8 +50,8 @@ export function Messages(props: IMessagesProps): JSX.Element {
|
||||||
<button
|
<button
|
||||||
onClick={() => { props.clearMessage(); }}
|
onClick={() => { props.clearMessage(); }}
|
||||||
className='h-full hover:bg-slate-400 rounded-lg p-1'
|
className='h-full hover:bg-slate-400 rounded-lg p-1'
|
||||||
aria-label='Clear all messages'
|
aria-label={Text({ textId: '@ClearAllMessages' })}
|
||||||
title='Clear all messages'
|
title={Text({ textId: '@ClearAllMessages' })}
|
||||||
>
|
>
|
||||||
<TrashIcon className='heroicon'></TrashIcon>
|
<TrashIcon className='heroicon'></TrashIcon>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ContainerModel, IContainerModel } from '../../../Interfaces/IContainerModel';
|
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
import { DIMENSION_MARGIN } from '../../../utils/default';
|
import { DIMENSION_MARGIN } from '../../../utils/default';
|
||||||
import { GetAbsolutePosition, MakeBFSIterator } from '../../../utils/itertools';
|
import { GetAbsolutePosition, MakeBFSIterator } from '../../../utils/itertools';
|
||||||
import { TransformX } from '../../../utils/svg';
|
import { TransformX } from '../../../utils/svg';
|
||||||
|
@ -7,13 +7,13 @@ import { Dimension } from './Dimension';
|
||||||
|
|
||||||
interface IDimensionLayerProps {
|
interface IDimensionLayerProps {
|
||||||
containers: Map<string, IContainerModel>
|
containers: Map<string, IContainerModel>
|
||||||
roots: ContainerModel | ContainerModel[] | null
|
roots: IContainerModel | IContainerModel[] | null
|
||||||
scale?: number
|
scale?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetDimensionsNodes(
|
function GetDimensionsNodes(
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
root: ContainerModel,
|
root: IContainerModel,
|
||||||
scale: number
|
scale: number
|
||||||
): React.ReactNode[] {
|
): React.ReactNode[] {
|
||||||
const it = MakeBFSIterator(root, containers);
|
const it = MakeBFSIterator(root, containers);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { Orientation } from '../../../Enums/Orientation';
|
import { Orientation } from '../../../Enums/Orientation';
|
||||||
import { Position } from '../../../Enums/Position';
|
import { Position } from '../../../Enums/Position';
|
||||||
import { ContainerModel, IContainerModel } from '../../../Interfaces/IContainerModel';
|
import { IContainerModel } from '../../../Interfaces/IContainerModel';
|
||||||
import { DIMENSION_MARGIN, SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, SHOW_SELF_DIMENSIONS } from '../../../utils/default';
|
import { DIMENSION_MARGIN, SHOW_BORROWER_DIMENSIONS, SHOW_CHILDREN_DIMENSIONS, SHOW_SELF_DIMENSIONS } from '../../../utils/default';
|
||||||
import { FindContainerById, MakeRecursionDFSIterator, Pairwise } from '../../../utils/itertools';
|
import { FindContainerById, MakeRecursionDFSIterator, Pairwise } from '../../../utils/itertools';
|
||||||
import { TransformX, TransformY } from '../../../utils/svg';
|
import { TransformX, TransformY } from '../../../utils/svg';
|
||||||
|
@ -9,7 +9,7 @@ import { Dimension } from './Dimension';
|
||||||
|
|
||||||
interface IDimensionLayerProps {
|
interface IDimensionLayerProps {
|
||||||
containers: Map<string, IContainerModel>
|
containers: Map<string, IContainerModel>
|
||||||
root: ContainerModel
|
root: IContainerModel
|
||||||
scale: number
|
scale: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,16 +29,18 @@ function ActionByPosition(
|
||||||
dimMapped: number[],
|
dimMapped: number[],
|
||||||
positions: Position[],
|
positions: Position[],
|
||||||
horizontalAction: (dim: number, ...params: any[]) => void,
|
horizontalAction: (dim: number, ...params: any[]) => void,
|
||||||
verticalAction: (dim: number, ...params: any[]) => void,
|
verticalAction: (dim: number, isRight: boolean, ...params: any[]) => void,
|
||||||
params: any[]
|
params: any[]
|
||||||
): void {
|
): void {
|
||||||
positions.forEach((position: Position) => {
|
positions.forEach((position: Position) => {
|
||||||
const dim = dimMapped[position];
|
const dim = dimMapped[position];
|
||||||
switch (position) {
|
switch (position) {
|
||||||
case Position.Left:
|
case Position.Left:
|
||||||
case Position.Right:
|
case Position.Right: {
|
||||||
verticalAction(dim, ...params);
|
const isRight = position === Position.Right;
|
||||||
|
verticalAction(dim, isRight, ...params);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Position.Down:
|
case Position.Down:
|
||||||
case Position.Up:
|
case Position.Up:
|
||||||
horizontalAction(dim, ...params);
|
horizontalAction(dim, ...params);
|
||||||
|
@ -179,7 +181,7 @@ function AddHorizontalChildrenDimension(
|
||||||
}
|
}
|
||||||
|
|
||||||
const textChildren = (xChildrenEnd - xChildrenStart)
|
const textChildren = (xChildrenEnd - xChildrenStart)
|
||||||
.toFixed(2)
|
.toFixed(0)
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
const offset = currentTransform[0] + container.properties.x;
|
const offset = currentTransform[0] + container.properties.x;
|
||||||
|
@ -197,6 +199,7 @@ function AddHorizontalChildrenDimension(
|
||||||
|
|
||||||
function AddVerticalChildrenDimension(
|
function AddVerticalChildrenDimension(
|
||||||
xDim: number,
|
xDim: number,
|
||||||
|
isRight: boolean,
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
container: IContainerModel,
|
container: IContainerModel,
|
||||||
currentTransform: [number, number],
|
currentTransform: [number, number],
|
||||||
|
@ -240,10 +243,15 @@ function AddVerticalChildrenDimension(
|
||||||
}
|
}
|
||||||
|
|
||||||
const textChildren = (yChildrenEnd - yChildrenStart)
|
const textChildren = (yChildrenEnd - yChildrenStart)
|
||||||
.toFixed(2)
|
.toFixed(0)
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
const offset = currentTransform[0] + container.properties.x;
|
const offset = currentTransform[0] + container.properties.x;
|
||||||
|
|
||||||
|
if (!isRight) {
|
||||||
|
[yChildrenStart, yChildrenEnd] = [yChildrenEnd, yChildrenStart];
|
||||||
|
}
|
||||||
|
|
||||||
dimensions.push(<Dimension
|
dimensions.push(<Dimension
|
||||||
key={childrenId}
|
key={childrenId}
|
||||||
id={childrenId}
|
id={childrenId}
|
||||||
|
@ -296,6 +304,11 @@ function AddHorizontalBorrowerDimension(
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (const { cur, next } of Pairwise(marks)) {
|
for (const { cur, next } of Pairwise(marks)) {
|
||||||
const id = `dim-y${yDim.toFixed(0)}-borrow-${container.properties.id}-{${count}}`;
|
const id = `dim-y${yDim.toFixed(0)}-borrow-${container.properties.id}-{${count}}`;
|
||||||
|
const value = next - cur;
|
||||||
|
if (value === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dimensions.push(<Dimension
|
dimensions.push(<Dimension
|
||||||
key={id}
|
key={id}
|
||||||
id={id}
|
id={id}
|
||||||
|
@ -304,7 +317,7 @@ function AddHorizontalBorrowerDimension(
|
||||||
yStart={yDim}
|
yStart={yDim}
|
||||||
yEnd={yDim}
|
yEnd={yDim}
|
||||||
strokeWidth={MODULE_STROKE_WIDTH}
|
strokeWidth={MODULE_STROKE_WIDTH}
|
||||||
text={(next - cur).toFixed(0).toString()}
|
text={value.toFixed(0)}
|
||||||
scale={scale} />);
|
scale={scale} />);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -312,6 +325,7 @@ function AddHorizontalBorrowerDimension(
|
||||||
|
|
||||||
function AddVerticalBorrowerDimension(
|
function AddVerticalBorrowerDimension(
|
||||||
xDim: number,
|
xDim: number,
|
||||||
|
isRight: boolean,
|
||||||
containers: Map<string, IContainerModel>,
|
containers: Map<string, IContainerModel>,
|
||||||
container: IContainerModel,
|
container: IContainerModel,
|
||||||
depth: number,
|
depth: number,
|
||||||
|
@ -346,9 +360,19 @@ function AddVerticalBorrowerDimension(
|
||||||
marks.push(restoredY);
|
marks.push(restoredY);
|
||||||
marks.push(restoredY + container.properties.height);
|
marks.push(restoredY + container.properties.height);
|
||||||
marks.sort((a, b) => a - b);
|
marks.sort((a, b) => a - b);
|
||||||
|
|
||||||
let count = 0;
|
let count = 0;
|
||||||
for (const { cur, next } of Pairwise(marks)) {
|
for (let { cur, next } of Pairwise(marks)) {
|
||||||
const id = `dim-x${xDim.toFixed(0)}-borrow-${container.properties.id}-{${count}}`;
|
const id = `dim-x${xDim.toFixed(0)}-borrow-${container.properties.id}-{${count}}`;
|
||||||
|
const value = next - cur;
|
||||||
|
if (value === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRight) {
|
||||||
|
[cur, next] = [next, cur];
|
||||||
|
}
|
||||||
|
|
||||||
dimensions.push(<Dimension
|
dimensions.push(<Dimension
|
||||||
key={id}
|
key={id}
|
||||||
id={id}
|
id={id}
|
||||||
|
@ -357,7 +381,7 @@ function AddVerticalBorrowerDimension(
|
||||||
yStart={cur}
|
yStart={cur}
|
||||||
yEnd={next}
|
yEnd={next}
|
||||||
strokeWidth={MODULE_STROKE_WIDTH}
|
strokeWidth={MODULE_STROKE_WIDTH}
|
||||||
text={(next - cur).toFixed(0).toString()}
|
text={value.toFixed(0)}
|
||||||
scale={scale} />);
|
scale={scale} />);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -365,6 +389,7 @@ function AddVerticalBorrowerDimension(
|
||||||
|
|
||||||
function AddVerticalSelfDimension(
|
function AddVerticalSelfDimension(
|
||||||
xDim: number,
|
xDim: number,
|
||||||
|
isRight: boolean,
|
||||||
container: IContainerModel,
|
container: IContainerModel,
|
||||||
currentTransform: [number, number],
|
currentTransform: [number, number],
|
||||||
dimensions: React.ReactNode[],
|
dimensions: React.ReactNode[],
|
||||||
|
@ -372,11 +397,16 @@ function AddVerticalSelfDimension(
|
||||||
): void {
|
): void {
|
||||||
const height = container.properties.height;
|
const height = container.properties.height;
|
||||||
const idVert = `dim-x${xDim.toFixed(0)}-${container.properties.id}`;
|
const idVert = `dim-x${xDim.toFixed(0)}-${container.properties.id}`;
|
||||||
const yStart = container.properties.y + currentTransform[1];
|
let yStart = container.properties.y + currentTransform[1] + height;
|
||||||
const yEnd = yStart + height;
|
let yEnd = container.properties.y + currentTransform[1];
|
||||||
const textVert = height
|
const textVert = height
|
||||||
.toFixed(0)
|
.toFixed(0)
|
||||||
.toString();
|
.toString();
|
||||||
|
|
||||||
|
if (isRight) {
|
||||||
|
[yStart, yEnd] = [yEnd, yStart];
|
||||||
|
}
|
||||||
|
|
||||||
dimensions.push(
|
dimensions.push(
|
||||||
<Dimension
|
<Dimension
|
||||||
key={idVert}
|
key={idVert}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ReactSVGPanZoom, Tool, TOOL_PAN, Value } from 'react-svg-pan-zoom';
|
import { ReactSVGPanZoom, Tool, TOOL_PAN, Value } from 'react-svg-pan-zoom';
|
||||||
import { Container } from './Elements/Container';
|
import { Container } from './Elements/Container';
|
||||||
import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
|
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
||||||
import { Selector } from './Elements/Selector/Selector';
|
import { Selector } from './Elements/Selector/Selector';
|
||||||
import { DepthDimensionLayer } from './Elements/DepthDimensionLayer';
|
import { DepthDimensionLayer } from './Elements/DepthDimensionLayer';
|
||||||
import { MAX_FRAMERATE, SHOW_DIMENSIONS_PER_DEPTH } from '../../utils/default';
|
import { MAX_FRAMERATE, SHOW_DIMENSIONS_PER_DEPTH } from '../../utils/default';
|
||||||
|
@ -16,8 +16,8 @@ interface ISVGProps {
|
||||||
width: number
|
width: number
|
||||||
height: number
|
height: number
|
||||||
containers: Map<string, IContainerModel>
|
containers: Map<string, IContainerModel>
|
||||||
children: ContainerModel
|
children: IContainerModel
|
||||||
selected?: ContainerModel
|
selected?: IContainerModel
|
||||||
symbols: Map<string, ISymbolModel>
|
symbols: Map<string, ISymbolModel>
|
||||||
selectContainer: (containerId: string) => void
|
selectContainer: (containerId: string) => void
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { ArrowUpOnSquareIcon, CameraIcon } from '@heroicons/react/24/outline';
|
import { ArrowUpOnSquareIcon, CameraIcon } from '@heroicons/react/24/outline';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Text } from '../Text/Text';
|
||||||
|
|
||||||
interface ISettingsProps {
|
interface ISettingsProps {
|
||||||
saveEditorAsJSON: () => void
|
saveEditorAsJSON: () => void
|
||||||
|
@ -12,19 +13,19 @@ export function Settings(props: ISettingsProps): JSX.Element {
|
||||||
m-2 md:text-xs font-bold'>
|
m-2 md:text-xs font-bold'>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
className={'w-full transition-all flex sidebar-component'}
|
className={'w-full transition-all flex sidebar-component'}
|
||||||
title='Export as JSON'
|
title={Text({ textId: '@ExportAsJSON' })}
|
||||||
onClick={props.saveEditorAsJSON}
|
onClick={props.saveEditorAsJSON}
|
||||||
>
|
>
|
||||||
<ArrowUpOnSquareIcon className="heroicon w-16 h-7" />
|
<ArrowUpOnSquareIcon className="heroicon w-16 h-7" />
|
||||||
Export as JSON
|
{Text({ textId: '@ExportAsJSON' })}
|
||||||
</button>
|
</button>
|
||||||
<button type="button"
|
<button type="button"
|
||||||
className={'w-full transition-all flex sidebar-component'}
|
className={'w-full transition-all flex sidebar-component'}
|
||||||
title='Export as SVG'
|
title={Text({ textId: '@ExportAsSVG' })}
|
||||||
onClick={props.saveEditorAsSVG}
|
onClick={props.saveEditorAsSVG}
|
||||||
>
|
>
|
||||||
<CameraIcon className="heroicon w-16 h-7" />
|
<CameraIcon className="heroicon w-16 h-7" />
|
||||||
Export as SVG
|
{Text({ textId: '@ExportAsSVG' })}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { RestoreX, TransformX } from '../../utils/svg';
|
||||||
import { InputGroup } from '../InputGroup/InputGroup';
|
import { InputGroup } from '../InputGroup/InputGroup';
|
||||||
import { TextInputGroup } from '../InputGroup/TextInputGroup';
|
import { TextInputGroup } from '../InputGroup/TextInputGroup';
|
||||||
import { PositionReferenceSelector } from '../RadioGroupButtons/PositionReferenceSelector';
|
import { PositionReferenceSelector } from '../RadioGroupButtons/PositionReferenceSelector';
|
||||||
|
import { Text } from '../Text/Text';
|
||||||
|
|
||||||
interface ISymbolFormProps {
|
interface ISymbolFormProps {
|
||||||
symbol: ISymbolModel
|
symbol: ISymbolModel
|
||||||
|
@ -15,7 +16,7 @@ export function SymbolForm(props: ISymbolFormProps): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className='grid grid-cols-2 gap-y-4'>
|
<div className='grid grid-cols-2 gap-y-4'>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
labelText='Name'
|
labelText={Text({ textId: '@SymbolName' })}
|
||||||
inputKey='id'
|
inputKey='id'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -24,7 +25,7 @@ export function SymbolForm(props: ISymbolFormProps): JSX.Element {
|
||||||
isDisabled={true} />
|
isDisabled={true} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id='x'
|
id='x'
|
||||||
labelText='x'
|
labelText={Text({ textId: '@SymbolX' })}
|
||||||
inputKey='x'
|
inputKey='x'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -33,7 +34,7 @@ export function SymbolForm(props: ISymbolFormProps): JSX.Element {
|
||||||
onChange={(value) => props.onChange('x', RestoreX(Number(value), props.symbol.width, props.symbol.config.PositionReference))} />
|
onChange={(value) => props.onChange('x', RestoreX(Number(value), props.symbol.width, props.symbol.config.PositionReference))} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id='height'
|
id='height'
|
||||||
labelText='Height'
|
labelText={Text({ textId: '@SymbolHeight' })}
|
||||||
inputKey='height'
|
inputKey='height'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
@ -43,7 +44,7 @@ export function SymbolForm(props: ISymbolFormProps): JSX.Element {
|
||||||
onChange={(value) => props.onChange('height', Number(value))} />
|
onChange={(value) => props.onChange('height', Number(value))} />
|
||||||
<TextInputGroup
|
<TextInputGroup
|
||||||
id='width'
|
id='width'
|
||||||
labelText='Width'
|
labelText={Text({ textId: '@SymbolWidth' })}
|
||||||
inputKey='width'
|
inputKey='width'
|
||||||
labelClassName=''
|
labelClassName=''
|
||||||
inputClassName=''
|
inputClassName=''
|
||||||
|
|
|
@ -16,7 +16,7 @@ export function Symbols(props: ISymbolsProps): JSX.Element {
|
||||||
if (componentOption.Image.Url !== undefined || componentOption.Image.Base64Image !== undefined) {
|
if (componentOption.Image.Url !== undefined || componentOption.Image.Base64Image !== undefined) {
|
||||||
const url = componentOption.Image.Base64Image ?? componentOption.Image.Url;
|
const url = componentOption.Image.Base64Image ?? componentOption.Image.Url;
|
||||||
return (<button type="button"
|
return (<button type="button"
|
||||||
className='justify-center sidebar-component-card hover:h-full'
|
className='flex justify-start items-center sidebar-component-card hover:h-full'
|
||||||
key={componentOption.Name}
|
key={componentOption.Name}
|
||||||
id={componentOption.Name}
|
id={componentOption.Name}
|
||||||
title={componentOption.Name}
|
title={componentOption.Name}
|
||||||
|
@ -30,8 +30,8 @@ export function Symbols(props: ISymbolsProps): JSX.Element {
|
||||||
src={url}
|
src={url}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className='ml-5'>
|
||||||
{TruncateString(componentOption.Name, 5)}
|
{TruncateString(componentOption.Name, 20)}
|
||||||
</div>
|
</div>
|
||||||
</button>);
|
</button>);
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ export function Symbols(props: ISymbolsProps): JSX.Element {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='h-full overflow-y-auto'>
|
<div className='h-full overflow-y-auto'>
|
||||||
<div className='grid grid-cols-1 md:grid-cols-3 gap-2
|
<div className='grid grid-cols-1 md:grid-cols-1 gap-2
|
||||||
overflow-auto m-2 md:text-xs font-bold'>
|
overflow-auto m-2 md:text-xs font-bold'>
|
||||||
{listElements}
|
{listElements}
|
||||||
</div>
|
</div>
|
||||||
|
|
11
src/Components/Text/Text.tsx
Normal file
11
src/Components/Text/Text.tsx
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { LanguageContext } from '../LanguageProvider/LanguageProvider';
|
||||||
|
|
||||||
|
interface TextProps {
|
||||||
|
textId: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Text({ textId }: TextProps): string {
|
||||||
|
const languageContext = useContext(LanguageContext);
|
||||||
|
return languageContext.dictionary[textId] ?? textId;
|
||||||
|
};
|
|
@ -16,6 +16,7 @@ import { UseWorker, UseAsync } from './UseWorker';
|
||||||
import { FindContainerById } from '../../utils/itertools';
|
import { FindContainerById } from '../../utils/itertools';
|
||||||
import { IEditorState } from '../../Interfaces/IEditorState';
|
import { IEditorState } from '../../Interfaces/IEditorState';
|
||||||
import { GetCurrentHistoryState } from '../Editor/Editor';
|
import { GetCurrentHistoryState } from '../Editor/Editor';
|
||||||
|
import { Text } from '../Text/Text';
|
||||||
|
|
||||||
export interface IUIProps {
|
export interface IUIProps {
|
||||||
editorState: IEditorState
|
editorState: IEditorState
|
||||||
|
@ -95,14 +96,14 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
||||||
|
|
||||||
switch (selectedSidebar) {
|
switch (selectedSidebar) {
|
||||||
case SidebarType.Components:
|
case SidebarType.Components:
|
||||||
leftSidebarTitle = 'Components';
|
leftSidebarTitle = Text({ textId: '@Components' });
|
||||||
leftChildren = <Components
|
leftChildren = <Components
|
||||||
selectedContainer={selectedContainer}
|
selectedContainer={selectedContainer}
|
||||||
componentOptions={configuration.AvailableContainers}
|
componentOptions={configuration.AvailableContainers}
|
||||||
categories={configuration.Categories}
|
categories={configuration.Categories}
|
||||||
buttonOnClick={methods.addContainer}
|
buttonOnClick={methods.addContainer}
|
||||||
/>;
|
/>;
|
||||||
rightSidebarTitle = 'Elements';
|
rightSidebarTitle = Text({ textId: '@Elements' });
|
||||||
rightChildren = <ElementsList
|
rightChildren = <ElementsList
|
||||||
containers={current.containers}
|
containers={current.containers}
|
||||||
mainContainer={mainContainer}
|
mainContainer={mainContainer}
|
||||||
|
@ -115,12 +116,12 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SidebarType.Symbols:
|
case SidebarType.Symbols:
|
||||||
leftSidebarTitle = 'Symbols';
|
leftSidebarTitle = Text({ textId: '@SymbolsLeft' });
|
||||||
leftChildren = <Symbols
|
leftChildren = <Symbols
|
||||||
componentOptions={configuration.AvailableSymbols}
|
componentOptions={configuration.AvailableSymbols}
|
||||||
buttonOnClick={methods.addSymbol}
|
buttonOnClick={methods.addSymbol}
|
||||||
/>;
|
/>;
|
||||||
rightSidebarTitle = 'Symbols';
|
rightSidebarTitle = Text({ textId: '@SymbolsRight' });
|
||||||
rightChildren = <SymbolsSidebar
|
rightChildren = <SymbolsSidebar
|
||||||
selectedSymbolId={current.selectedSymbolId}
|
selectedSymbolId={current.selectedSymbolId}
|
||||||
symbols={current.symbols}
|
symbols={current.symbols}
|
||||||
|
@ -130,7 +131,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SidebarType.History:
|
case SidebarType.History:
|
||||||
leftSidebarTitle = 'Timeline';
|
leftSidebarTitle = Text({ textId: '@Timeline' });
|
||||||
leftChildren = <History
|
leftChildren = <History
|
||||||
history={editorState.history}
|
history={editorState.history}
|
||||||
historyCurrentStep={editorState.historyCurrentStep}
|
historyCurrentStep={editorState.historyCurrentStep}
|
||||||
|
@ -139,7 +140,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SidebarType.Messages:
|
case SidebarType.Messages:
|
||||||
leftSidebarTitle = 'Messages';
|
leftSidebarTitle = Text({ textId: '@Messages' });
|
||||||
leftChildren = <Messages
|
leftChildren = <Messages
|
||||||
historyState={current}
|
historyState={current}
|
||||||
messages={messages}
|
messages={messages}
|
||||||
|
@ -148,7 +149,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SidebarType.Settings:
|
case SidebarType.Settings:
|
||||||
leftSidebarTitle = 'Settings';
|
leftSidebarTitle = Text({ textId: '@Settings' });
|
||||||
leftChildren = <Settings
|
leftChildren = <Settings
|
||||||
saveEditorAsJSON={methods.saveEditorAsJSON}
|
saveEditorAsJSON={methods.saveEditorAsJSON}
|
||||||
saveEditorAsSVG={methods.saveEditorAsSVG}
|
saveEditorAsSVG={methods.saveEditorAsSVG}
|
||||||
|
|
|
@ -16,7 +16,7 @@ export function UseWorker(
|
||||||
// use webworker for the stringify to avoid freezing
|
// use webworker for the stringify to avoid freezing
|
||||||
myWorker.postMessage({
|
myWorker.postMessage({
|
||||||
state,
|
state,
|
||||||
url: import.meta.env.VITE_API_GET_FEEDBACK_URL
|
url: configurationUrl ?? import.meta.env.VITE_API_GET_FEEDBACK_URL
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -39,7 +39,8 @@ export function UseAsync(
|
||||||
ApplicationState: state
|
ApplicationState: state
|
||||||
};
|
};
|
||||||
const dataParsed = JSON.stringify(request, GetCircularReplacer());
|
const dataParsed = JSON.stringify(request, GetCircularReplacer());
|
||||||
fetch(import.meta.env.VITE_API_GET_FEEDBACK_URL, {
|
const url = configurationUrl ?? import.meta.env.VITE_API_GET_FEEDBACK_URL;
|
||||||
|
fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: new Headers({
|
headers: new Headers({
|
||||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
@ -47,9 +48,9 @@ export function UseAsync(
|
||||||
}),
|
}),
|
||||||
body: dataParsed
|
body: dataParsed
|
||||||
})
|
})
|
||||||
.then(async (response) => await response.json()
|
.then(async(response) => await response.json()
|
||||||
)
|
)
|
||||||
.then(async (json: IGetFeedbackResponse) => {
|
.then(async(json: IGetFeedbackResponse) => {
|
||||||
setMessages(json.messages);
|
setMessages(json.messages);
|
||||||
});
|
});
|
||||||
}, [state]);
|
}, [state]);
|
||||||
|
|
5
src/Enums/AppState.ts
Normal file
5
src/Enums/AppState.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export enum AppState {
|
||||||
|
MainMenu,
|
||||||
|
Loading,
|
||||||
|
Loaded
|
||||||
|
}
|
|
@ -1,44 +1,55 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import { AppState } from '../Enums/AppState';
|
||||||
import { IConfiguration } from '../Interfaces/IConfiguration';
|
import { IConfiguration } from '../Interfaces/IConfiguration';
|
||||||
import { IEditorState } from '../Interfaces/IEditorState';
|
import { IEditorState } from '../Interfaces/IEditorState';
|
||||||
import { IHistoryState } from '../Interfaces/IHistoryState';
|
import { IHistoryState } from '../Interfaces/IHistoryState';
|
||||||
|
import { ILanguage } from '../Interfaces/ILanguage';
|
||||||
|
import { languageOptions, translations } from '../Translations/Translations';
|
||||||
import { GetDefaultEditorState as GetDefaultEditorStateAction } from '../utils/default';
|
import { GetDefaultEditorState as GetDefaultEditorStateAction } from '../utils/default';
|
||||||
import { Revive, ReviveHistory as ReviveHistoryAction } from '../utils/saveload';
|
import { Revive, ReviveHistory as ReviveHistoryAction } from '../utils/saveload';
|
||||||
|
|
||||||
|
interface IAppEventParams {
|
||||||
|
root: Element | Document
|
||||||
|
languageContext: ILanguage
|
||||||
|
setEditor: (newState: IEditorState) => void
|
||||||
|
setAppState: (appState: AppState) => void
|
||||||
|
eventInitDict?: CustomEventInit
|
||||||
|
}
|
||||||
|
|
||||||
export interface IAppEvent {
|
export interface IAppEvent {
|
||||||
name: string
|
name: string
|
||||||
func: (
|
func: (params: IAppEventParams) => void
|
||||||
root: Element | Document,
|
|
||||||
setEditor: (newState: IEditorState) => void,
|
|
||||||
setLoaded: (loaded: boolean) => void,
|
|
||||||
eventInitDict?: CustomEventInit
|
|
||||||
) => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const events: IAppEvent[] = [
|
export const events: IAppEvent[] = [
|
||||||
{ name: 'setEditor', func: SetEditor },
|
{ name: 'setEditor', func: SetEditor },
|
||||||
{ name: 'setLoaded', func: SetLoaded },
|
{ name: 'setAppState', func: SetAppState },
|
||||||
{ name: 'reviveEditorState', func: ReviveEditorState },
|
{ name: 'reviveEditorState', func: ReviveEditorState },
|
||||||
{ name: 'reviveHistory', func: ReviveHistory },
|
{ name: 'reviveHistory', func: ReviveHistory },
|
||||||
{ name: 'getDefaultEditorState', func: GetDefaultEditorState }
|
{ name: 'getDefaultEditorState', func: GetDefaultEditorState },
|
||||||
|
{ name: 'addLanguage', func: AddLanguage },
|
||||||
|
{ name: 'setLanguage', func: SetLanguage },
|
||||||
|
{ name: 'getLanguages', func: GetLanguages }
|
||||||
];
|
];
|
||||||
|
|
||||||
export function UseCustomEvents(
|
export function UseCustomEvents(
|
||||||
root: Element | Document,
|
root: Element | Document,
|
||||||
appRef: React.RefObject<HTMLDivElement>,
|
appRef: React.RefObject<HTMLDivElement>,
|
||||||
|
languageContext: ILanguage,
|
||||||
setEditor: (newState: IEditorState) => void,
|
setEditor: (newState: IEditorState) => void,
|
||||||
setLoaded: (loaded: boolean) => void
|
setAppState: (appState: AppState) => void
|
||||||
): void {
|
): void {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const funcs = new Map<string, () => void>();
|
const funcs = new Map<string, () => void>();
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
function Func(eventInitDict?: CustomEventInit): void {
|
function Func(eventInitDict?: CustomEventInit): void {
|
||||||
return event.func(
|
return event.func({
|
||||||
root,
|
root,
|
||||||
|
languageContext,
|
||||||
setEditor,
|
setEditor,
|
||||||
setLoaded,
|
setAppState,
|
||||||
eventInitDict
|
eventInitDict
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
appRef.current?.addEventListener(event.name, Func);
|
appRef.current?.addEventListener(event.name, Func);
|
||||||
funcs.set(event.name, Func);
|
funcs.set(event.name, Func);
|
||||||
|
@ -55,57 +66,87 @@ export function UseCustomEvents(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function SetEditor(
|
function SetEditor({
|
||||||
root: Element | Document,
|
root,
|
||||||
setEditor: (newState: IEditorState) => void,
|
setEditor,
|
||||||
setLoaded: (loaded: boolean) => void,
|
setAppState,
|
||||||
eventInitDict?: CustomEventInit
|
eventInitDict
|
||||||
): void {
|
}: IAppEventParams): void {
|
||||||
const editor: IEditorState = eventInitDict?.detail;
|
const editor: IEditorState = eventInitDict?.detail;
|
||||||
setEditor(editor);
|
setEditor(editor);
|
||||||
|
setAppState(AppState.Loading);
|
||||||
const customEvent = new CustomEvent<IEditorState>('setEditor', { detail: editor });
|
const customEvent = new CustomEvent<IEditorState>('setEditor', { detail: editor });
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SetLoaded(
|
function SetAppState({
|
||||||
root: Element | Document,
|
setAppState,
|
||||||
setEditor: (newState: IEditorState) => void,
|
eventInitDict
|
||||||
setLoaded: (loaded: boolean) => void,
|
}: IAppEventParams): void {
|
||||||
eventInitDict?: CustomEventInit
|
const appState: AppState = eventInitDict?.detail;
|
||||||
): void {
|
setAppState(appState);
|
||||||
const isLoaded: boolean = eventInitDict?.detail;
|
|
||||||
setLoaded(isLoaded);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ReviveEditorState(
|
function ReviveEditorState({
|
||||||
root: Element | Document,
|
root,
|
||||||
setEditor: (newState: IEditorState) => void,
|
eventInitDict
|
||||||
setLoaded: (loaded: boolean) => void,
|
}: IAppEventParams): void {
|
||||||
eventInitDict?: CustomEventInit): void {
|
|
||||||
const anEditorState: IEditorState = eventInitDict?.detail;
|
const anEditorState: IEditorState = eventInitDict?.detail;
|
||||||
Revive(anEditorState);
|
Revive(anEditorState);
|
||||||
const customEvent = new CustomEvent<IEditorState>('reviveEditorState', { detail: anEditorState });
|
const customEvent = new CustomEvent<IEditorState>('reviveEditorState', { detail: anEditorState });
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ReviveHistory(
|
function ReviveHistory({
|
||||||
root: Element | Document,
|
root,
|
||||||
setEditor: (newState: IEditorState) => void,
|
eventInitDict
|
||||||
setLoaded: (loaded: boolean) => void,
|
}: IAppEventParams): void {
|
||||||
eventInitDict?: CustomEventInit): void {
|
|
||||||
const history: IHistoryState[] = eventInitDict?.detail;
|
const history: IHistoryState[] = eventInitDict?.detail;
|
||||||
ReviveHistoryAction(history);
|
ReviveHistoryAction(history);
|
||||||
const customEvent = new CustomEvent<IHistoryState[]>('reviveHistory', { detail: history });
|
const customEvent = new CustomEvent<IHistoryState[]>('reviveHistory', { detail: history });
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetDefaultEditorState(
|
function GetDefaultEditorState({
|
||||||
root: Element | Document,
|
root,
|
||||||
setEditor: (newState: IEditorState) => void,
|
eventInitDict
|
||||||
setLoaded: (loaded: boolean) => void,
|
}: IAppEventParams): void {
|
||||||
eventInitDict?: CustomEventInit): void {
|
|
||||||
const configuration: IConfiguration = eventInitDict?.detail;
|
const configuration: IConfiguration = eventInitDict?.detail;
|
||||||
const editorState = GetDefaultEditorStateAction(configuration);
|
const editorState = GetDefaultEditorStateAction(configuration);
|
||||||
const customEvent = new CustomEvent<IEditorState>('getDefaultEditorState', { detail: editorState });
|
const customEvent = new CustomEvent<IEditorState>('getDefaultEditorState', { detail: editorState });
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function AddLanguage({
|
||||||
|
root,
|
||||||
|
eventInitDict
|
||||||
|
}: IAppEventParams): void {
|
||||||
|
const language: ILanguage = eventInitDict?.detail.language;
|
||||||
|
const option: string = eventInitDict?.detail.option;
|
||||||
|
languageOptions[language.language] = option;
|
||||||
|
translations[language.language] = language.dictionary;
|
||||||
|
const customEvent = new CustomEvent('addLanguage');
|
||||||
|
root.dispatchEvent(customEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetLanguage({
|
||||||
|
root,
|
||||||
|
languageContext,
|
||||||
|
eventInitDict
|
||||||
|
}: IAppEventParams): void {
|
||||||
|
const language: string = eventInitDict?.detail;
|
||||||
|
let success = false;
|
||||||
|
if (languageContext.languageChange !== undefined) {
|
||||||
|
languageContext.languageChange(language);
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
const customEvent = new CustomEvent<boolean>('setLanguage', { detail: success });
|
||||||
|
root.dispatchEvent(customEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetLanguages({
|
||||||
|
root
|
||||||
|
}: IAppEventParams): void {
|
||||||
|
const customEvent = new CustomEvent<Record<string, Record<string, string>>>('getLanguages', { detail: translations });
|
||||||
|
root.dispatchEvent(customEvent);
|
||||||
|
}
|
||||||
|
|
|
@ -9,14 +9,15 @@ import { IHistoryState } from '../Interfaces/IHistoryState';
|
||||||
import { FindContainerById } from '../utils/itertools';
|
import { FindContainerById } from '../utils/itertools';
|
||||||
import { GetCircularReplacer } from '../utils/saveload';
|
import { GetCircularReplacer } from '../utils/saveload';
|
||||||
|
|
||||||
|
interface IEditorEventParams {
|
||||||
|
root: Element | Document
|
||||||
|
editorState: IEditorState
|
||||||
|
setNewHistory: (newHistory: IHistoryState[], historyCurrentStep?: number) => void
|
||||||
|
eventInitDict?: CustomEventInit
|
||||||
|
}
|
||||||
export interface IEditorEvent {
|
export interface IEditorEvent {
|
||||||
name: string
|
name: string
|
||||||
func: (
|
func: (params: IEditorEventParams) => void
|
||||||
root: Element | Document,
|
|
||||||
editorState: IEditorState,
|
|
||||||
setNewHistory: (newHistory: IHistoryState[], historyCurrentStep?: number) => void,
|
|
||||||
eventInitDict?: CustomEventInit
|
|
||||||
) => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const events: IEditorEvent[] = [
|
export const events: IEditorEvent[] = [
|
||||||
|
@ -54,12 +55,12 @@ export function UseCustomEvents(
|
||||||
const funcs = new Map<string, () => void>();
|
const funcs = new Map<string, () => void>();
|
||||||
for (const event of events) {
|
for (const event of events) {
|
||||||
function Func(eventInitDict?: CustomEventInit): void {
|
function Func(eventInitDict?: CustomEventInit): void {
|
||||||
return event.func(
|
return event.func({
|
||||||
root,
|
root,
|
||||||
editorState,
|
editorState,
|
||||||
setNewHistory,
|
setNewHistory,
|
||||||
eventInitDict
|
eventInitDict
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
editorRef.current?.addEventListener(event.name, Func);
|
editorRef.current?.addEventListener(event.name, Func);
|
||||||
funcs.set(event.name, Func);
|
funcs.set(event.name, Func);
|
||||||
|
@ -93,24 +94,30 @@ export function UseEditorListener(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetEditorState(root: Element | Document,
|
function GetEditorState({
|
||||||
editorState: IEditorState): void {
|
root,
|
||||||
|
editorState
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const customEvent = new CustomEvent<IEditorState>('getEditorState', { detail: structuredClone(editorState) });
|
const customEvent = new CustomEvent<IEditorState>('getEditorState', { detail: structuredClone(editorState) });
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetEditorStateAsString(root: Element | Document,
|
function GetEditorStateAsString({
|
||||||
editorState: IEditorState): void {
|
root,
|
||||||
|
editorState
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const spaces = import.meta.env.DEV ? 4 : 0;
|
const spaces = import.meta.env.DEV ? 4 : 0;
|
||||||
const data = JSON.stringify(editorState, GetCircularReplacer(), spaces);
|
const data = JSON.stringify(editorState, GetCircularReplacer(), spaces);
|
||||||
const customEvent = new CustomEvent<string>('getEditorStateAsString', { detail: data });
|
const customEvent = new CustomEvent<string>('getEditorStateAsString', { detail: data });
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SetHistory(root: Element | Document,
|
function SetHistory({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[], historyCurrentStep?: number) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const history: IHistoryState[] = eventInitDict?.detail.history;
|
const history: IHistoryState[] = eventInitDict?.detail.history;
|
||||||
const historyCurrentStep: number | undefined = eventInitDict?.detail.historyCurrentStep;
|
const historyCurrentStep: number | undefined = eventInitDict?.detail.historyCurrentStep;
|
||||||
setNewHistory(history, historyCurrentStep);
|
setNewHistory(history, historyCurrentStep);
|
||||||
|
@ -118,18 +125,22 @@ function SetHistory(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetCurrentHistoryState(root: Element | Document,
|
function GetCurrentHistoryState({
|
||||||
editorState: IEditorState): void {
|
root,
|
||||||
|
editorState
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const customEvent = new CustomEvent<IHistoryState>(
|
const customEvent = new CustomEvent<IHistoryState>(
|
||||||
'getCurrentHistoryState',
|
'getCurrentHistoryState',
|
||||||
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) });
|
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) });
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AppendNewState(root: Element | Document,
|
function AppendNewState({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const state: IHistoryState = eventInitDict?.detail.state;
|
const state: IHistoryState = eventInitDict?.detail.state;
|
||||||
const history = GetCurrentHistory(editorState.history, editorState.historyCurrentStep);
|
const history = GetCurrentHistory(editorState.history, editorState.historyCurrentStep);
|
||||||
|
|
||||||
|
@ -142,10 +153,12 @@ function AppendNewState(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AddContainer(root: Element | Document,
|
function AddContainer({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
index,
|
index,
|
||||||
type,
|
type,
|
||||||
|
@ -169,10 +182,12 @@ function AddContainer(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AddContainerToSelectedContainer(root: Element | Document,
|
function AddContainerToSelectedContainer({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
index,
|
index,
|
||||||
type
|
type
|
||||||
|
@ -197,10 +212,12 @@ function AddContainerToSelectedContainer(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AppendContainer(root: Element | Document,
|
function AppendContainer({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
type,
|
type,
|
||||||
parentId
|
parentId
|
||||||
|
@ -227,10 +244,12 @@ function AppendContainer(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AppendContainerToSelectedContainer(root: Element | Document,
|
function AppendContainerToSelectedContainer({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
type
|
type
|
||||||
} = eventInitDict?.detail;
|
} = eventInitDict?.detail;
|
||||||
|
@ -256,10 +275,12 @@ function AppendContainerToSelectedContainer(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectContainer(root: Element | Document,
|
function SelectContainer({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
containerId
|
containerId
|
||||||
} = eventInitDict?.detail;
|
} = eventInitDict?.detail;
|
||||||
|
@ -279,10 +300,12 @@ function SelectContainer(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DeleteContainer(root: Element | Document,
|
function DeleteContainer({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
containerId
|
containerId
|
||||||
} = eventInitDict?.detail;
|
} = eventInitDict?.detail;
|
||||||
|
@ -302,10 +325,12 @@ function DeleteContainer(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function AddSymbol(root: Element | Document,
|
function AddSymbol({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
name
|
name
|
||||||
} = eventInitDict?.detail;
|
} = eventInitDict?.detail;
|
||||||
|
@ -326,10 +351,12 @@ function AddSymbol(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectSymbol(root: Element | Document,
|
function SelectSymbol({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
symbolId
|
symbolId
|
||||||
} = eventInitDict?.detail;
|
} = eventInitDict?.detail;
|
||||||
|
@ -349,10 +376,12 @@ function SelectSymbol(root: Element | Document,
|
||||||
root.dispatchEvent(customEvent);
|
root.dispatchEvent(customEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DeleteSymbol(root: Element | Document,
|
function DeleteSymbol({
|
||||||
editorState: IEditorState,
|
root,
|
||||||
setNewHistory: (newHistory: IHistoryState[]) => void,
|
editorState,
|
||||||
eventInitDict?: CustomEventInit): void {
|
setNewHistory,
|
||||||
|
eventInitDict
|
||||||
|
}: IEditorEventParams): void {
|
||||||
const {
|
const {
|
||||||
symbolId
|
symbolId
|
||||||
} = eventInitDict?.detail;
|
} = eventInitDict?.detail;
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import React from 'react';
|
|
||||||
import { AddMethod } from '../Enums/AddMethod';
|
import { AddMethod } from '../Enums/AddMethod';
|
||||||
import { PositionReference } from '../Enums/PositionReference';
|
import { PositionReference } from '../Enums/PositionReference';
|
||||||
import { IAction } from './IAction';
|
import { IAction } from './IAction';
|
||||||
|
@ -7,6 +6,7 @@ import { IMargin } from './IMargin';
|
||||||
import { Orientation } from '../Enums/Orientation';
|
import { Orientation } from '../Enums/Orientation';
|
||||||
import { Position } from '../Enums/Position';
|
import { Position } from '../Enums/Position';
|
||||||
import { IKeyValue } from './IKeyValue';
|
import { IKeyValue } from './IKeyValue';
|
||||||
|
import { IStyle } from './IStyle';
|
||||||
|
|
||||||
/** Model of available container used in application configuration */
|
/** Model of available container used in application configuration */
|
||||||
export interface IAvailableContainer {
|
export interface IAvailableContainer {
|
||||||
|
@ -151,7 +151,7 @@ export interface IAvailableContainer {
|
||||||
* (optional)
|
* (optional)
|
||||||
* Style of the <rect>
|
* Style of the <rect>
|
||||||
*/
|
*/
|
||||||
Style?: React.CSSProperties
|
Style?: IStyle
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of possible actions shown on right-click
|
* List of possible actions shown on right-click
|
||||||
|
|
|
@ -1,13 +1,25 @@
|
||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
import { PositionReference } from '../Enums/PositionReference';
|
import { PositionReference } from '../Enums/PositionReference';
|
||||||
|
import { IAvailableContainer } from './IAvailableContainer';
|
||||||
import { IImage } from './IImage';
|
import { IImage } from './IImage';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model of available symbol to configure the application */
|
* Model of available symbol to configure the application */
|
||||||
export interface IAvailableSymbol {
|
export interface IAvailableSymbol {
|
||||||
Name: string
|
Name: string
|
||||||
|
|
||||||
Image: IImage
|
Image: IImage
|
||||||
|
|
||||||
|
X?: number
|
||||||
|
|
||||||
|
Y?: number
|
||||||
|
|
||||||
Width?: number
|
Width?: number
|
||||||
|
|
||||||
Height?: number
|
Height?: number
|
||||||
|
|
||||||
PositionReference?: PositionReference
|
PositionReference?: PositionReference
|
||||||
|
|
||||||
|
/** An existing or new available container */
|
||||||
|
AssociatedContainer?: IAvailableContainer
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { PositionReference } from '../Enums/PositionReference';
|
import { PositionReference } from '../Enums/PositionReference';
|
||||||
import { IMargin } from './IMargin';
|
import { IMargin } from './IMargin';
|
||||||
import { Orientation } from '../Enums/Orientation';
|
import { Orientation } from '../Enums/Orientation';
|
||||||
import { Position } from '../Enums/Position';
|
import { Position } from '../Enums/Position';
|
||||||
import { IKeyValue } from './IKeyValue';
|
import { IKeyValue } from './IKeyValue';
|
||||||
|
import { IStyle } from './IStyle';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties of a container
|
* Properties of a container
|
||||||
|
@ -27,6 +27,7 @@ export interface IContainerProperties {
|
||||||
/** orientation */
|
/** orientation */
|
||||||
orientation: Orientation
|
orientation: Orientation
|
||||||
|
|
||||||
|
// TODO: Refactor x, y in IPoint interface
|
||||||
/** horizontal offset */
|
/** horizontal offset */
|
||||||
x: number
|
x: number
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ export interface IContainerProperties {
|
||||||
/** margin */
|
/** margin */
|
||||||
margin: IMargin
|
margin: IMargin
|
||||||
|
|
||||||
|
// TODO: Refactor width, height, minWidth... in ISize interface
|
||||||
/** width */
|
/** width */
|
||||||
width: number
|
width: number
|
||||||
|
|
||||||
|
@ -62,6 +64,7 @@ export interface IContainerProperties {
|
||||||
*/
|
*/
|
||||||
maxHeight: number
|
maxHeight: number
|
||||||
|
|
||||||
|
// TODO: Refactor isAnchor, isFlex in IBehaviors interface
|
||||||
/** true if anchor, false otherwise */
|
/** true if anchor, false otherwise */
|
||||||
isAnchor: boolean
|
isAnchor: boolean
|
||||||
|
|
||||||
|
@ -71,9 +74,11 @@ export interface IContainerProperties {
|
||||||
/** Horizontal alignment, also determines the visual location of x {Left = 0, Center, Right } */
|
/** Horizontal alignment, also determines the visual location of x {Left = 0, Center, Right } */
|
||||||
positionReference: PositionReference
|
positionReference: PositionReference
|
||||||
|
|
||||||
|
// TODO: Refactor hideChildrenInTreeview in IUserInterface interface
|
||||||
/** Hide the children in the treeview */
|
/** Hide the children in the treeview */
|
||||||
hideChildrenInTreeview: boolean
|
hideChildrenInTreeview: boolean
|
||||||
|
|
||||||
|
// TODO: Refactor showSelf., showChildren., markPosition, showDimensionWithMarks in IDimensionOptions interface
|
||||||
/** if true, show the dimension of the container */
|
/** if true, show the dimension of the container */
|
||||||
showSelfDimensions: Position[]
|
showSelfDimensions: Position[]
|
||||||
|
|
||||||
|
@ -117,7 +122,7 @@ export interface IContainerProperties {
|
||||||
* (optional)
|
* (optional)
|
||||||
* Style of the <rect>
|
* Style of the <rect>
|
||||||
*/
|
*/
|
||||||
style?: React.CSSProperties
|
style?: IStyle
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (optional)
|
* (optional)
|
||||||
|
|
5
src/Interfaces/ILanguage.ts
Normal file
5
src/Interfaces/ILanguage.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export interface ILanguage {
|
||||||
|
language: string
|
||||||
|
dictionary: Record<string, string>
|
||||||
|
languageChange?: (selected: string) => void
|
||||||
|
}
|
11
src/Interfaces/IStyle.ts
Normal file
11
src/Interfaces/IStyle.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
export interface IStyle {
|
||||||
|
stroke?: string
|
||||||
|
|
||||||
|
strokeOpacity?: number
|
||||||
|
|
||||||
|
strokeWidth?: number
|
||||||
|
|
||||||
|
fill?: string
|
||||||
|
|
||||||
|
fillOpacity?: number
|
||||||
|
}
|
|
@ -13,6 +13,8 @@ export interface ISymbolModel {
|
||||||
/** Horizontal offset */
|
/** Horizontal offset */
|
||||||
x: number
|
x: number
|
||||||
|
|
||||||
|
// TODO: Implement Y and verticality
|
||||||
|
|
||||||
/** Width */
|
/** Width */
|
||||||
width: number
|
width: number
|
||||||
|
|
||||||
|
|
14
src/Translations/Translations.ts
Normal file
14
src/Translations/Translations.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import en from './translation.en.json';
|
||||||
|
import fr from './translation.fr.json';
|
||||||
|
|
||||||
|
export const translations: Record<string, Record<string, string>> = {
|
||||||
|
en,
|
||||||
|
fr
|
||||||
|
};
|
||||||
|
|
||||||
|
// Use languageOptions to restrict existing dictionary
|
||||||
|
// and create a select input
|
||||||
|
export const languageOptions: Record<string, string> = {
|
||||||
|
en: 'English',
|
||||||
|
fr: 'French'
|
||||||
|
};
|
75
src/Translations/translation.en.json
Normal file
75
src/Translations/translation.en.json
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
"@StartFromScratch": "Start from scratch",
|
||||||
|
"@LoadConfigFile": "Load a configuration file",
|
||||||
|
"@GoBack": "Go back",
|
||||||
|
|
||||||
|
"@Components": "Components",
|
||||||
|
"@Elements": "Elements",
|
||||||
|
"@Symbols": "Symbols",
|
||||||
|
"@SymbolsLeft": "Symbols",
|
||||||
|
"@SymbolsRight": "Symbols",
|
||||||
|
"@Timeline": "Timeline",
|
||||||
|
"@Messages": "Messages",
|
||||||
|
"@Settings": "Settings",
|
||||||
|
|
||||||
|
"@Undo": "Undo",
|
||||||
|
"@UndoTitle": "Undo last action",
|
||||||
|
"@Redo": "Redo",
|
||||||
|
"@RedoTitle": "Redo last action",
|
||||||
|
"@DeleteContainer": "Delete",
|
||||||
|
"@DeleteContainerTitle": "Delete the container",
|
||||||
|
"@DeleteSymbol": "Delete",
|
||||||
|
"@DeleteSymbolTitle": "Delete the container",
|
||||||
|
|
||||||
|
"@ExportAsJSON": "Export as JSON",
|
||||||
|
"@ExportAsSVG": "Export as SVG",
|
||||||
|
|
||||||
|
"@HideDisabledComponents": "Hide disabled components",
|
||||||
|
"@ShowDisabledComponents": "Show disabled components",
|
||||||
|
|
||||||
|
"@ClearAllMessages": "Clear all messages",
|
||||||
|
|
||||||
|
"@ContainerDisplayedText": "Displayed text",
|
||||||
|
"@ContainerOrientation": "Orientation",
|
||||||
|
"@ContainerProperties": "Properties",
|
||||||
|
"@ContainerName": "Name",
|
||||||
|
"@ContainerParentName": "Parent name",
|
||||||
|
"@ContainerType": "Type",
|
||||||
|
"@ContainerPosition": "Position",
|
||||||
|
"@ContainerX": "x",
|
||||||
|
"@ContainerY": "y",
|
||||||
|
"@ContainerSize": "Size",
|
||||||
|
"@ContainerMinWidth": "Minimum Width",
|
||||||
|
"@ContainerWidth": "Width",
|
||||||
|
"@ContainerMaxWidth": "Maximum Width",
|
||||||
|
"@ContainerMinHeight": "Minimum Height",
|
||||||
|
"@ContainerHeight": "Height",
|
||||||
|
"@ContainerMaxHeight": "Maximum Height",
|
||||||
|
"@ContainerMargins": "Margins",
|
||||||
|
"@ContainerMarginLeft": "Margin Left",
|
||||||
|
"@ContainerMarginBottom": "Margin Bottom",
|
||||||
|
"@ContainerMarginTop": "Margin Top",
|
||||||
|
"@ContainerMarginRight": "Margin Right",
|
||||||
|
"@ContainerBehaviors": "Behaviors",
|
||||||
|
"@ContainerFlex": "Flex",
|
||||||
|
"@ContainerAnchor": "Lock position and size",
|
||||||
|
"@ContainerAlignment": "Alignment",
|
||||||
|
"@ContainerAlignmentInput": "Alignment",
|
||||||
|
"@ContainerAlignWithSymbol": "Align to symbol",
|
||||||
|
"@ContainerDimensions": "Dimensions",
|
||||||
|
"@ContainerShowDimension": "Show Dimension",
|
||||||
|
"@ContainerShowChildrenDimension": "Show surrounding dimension of children",
|
||||||
|
"@ContainerMarkPosition": "Mark the position for the parents",
|
||||||
|
"@ContainerShowDimensionWithMarks": "Show dimension with marked children",
|
||||||
|
"@ContainerStyle": "Style",
|
||||||
|
"@StyleStroke": "Stroke",
|
||||||
|
"@StyleStrokeOpacity": "Stroke Opacity",
|
||||||
|
"@StyleStrokeWidth": "Stroke Width",
|
||||||
|
"@StyleFill": "Fill",
|
||||||
|
"@StyleFillOpacity": "Fill Opacity",
|
||||||
|
|
||||||
|
"@SymbolName": "Name",
|
||||||
|
"@SymbolX": "x",
|
||||||
|
"@SymbolHeight": "Height",
|
||||||
|
"@SymbolWidth": "Width"
|
||||||
|
}
|
75
src/Translations/translation.fr.json
Normal file
75
src/Translations/translation.fr.json
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{
|
||||||
|
"@StartFromScratch": "Partir de zéro",
|
||||||
|
"@LoadConfigFile": "Charger un fichier de configuration",
|
||||||
|
"@GoBack": "Revenir",
|
||||||
|
|
||||||
|
"@Components": "Composants",
|
||||||
|
"@Elements": "Éléments",
|
||||||
|
"@Symbols": "Symboles",
|
||||||
|
"@SymbolsLeft": "Symboles",
|
||||||
|
"@SymbolsRight": "Symboles",
|
||||||
|
"@Timeline": "Chronologie",
|
||||||
|
"@Messages": "Messages",
|
||||||
|
"@Settings": "Paramètres",
|
||||||
|
|
||||||
|
"@Undo": "Annuler",
|
||||||
|
"@UndoTitle": "Annuler la dernière action",
|
||||||
|
"@Redo": "Refaire",
|
||||||
|
"@RedoTitle": "Refaire la dernière action",
|
||||||
|
"@DeleteContainer": "Supprimer",
|
||||||
|
"@DeleteContainerTitle": "Supprimer le conteneur",
|
||||||
|
"@DeleteSymbol": "Supprimer",
|
||||||
|
"@DeleteSymbolTitle": "Supprimer le symbole",
|
||||||
|
|
||||||
|
"@ExportAsJSON": "Exporter en JSON",
|
||||||
|
"@ExportAsSVG": "Exporter en SVG",
|
||||||
|
|
||||||
|
"@HideDisabledComponents": "Cacher les composants désactivés",
|
||||||
|
"@ShowDisabledComponents": "Montrer les composants activés",
|
||||||
|
|
||||||
|
"@ClearAllMessages": "Effacer tous les messages",
|
||||||
|
|
||||||
|
"@ContainerDisplayedText": "Texte affiché",
|
||||||
|
"@ContainerOrientation": "Orientation",
|
||||||
|
"@ContainerProperties": "Propriétés",
|
||||||
|
"@ContainerName": "Nom",
|
||||||
|
"@ContainerParentName": "Nom du parent",
|
||||||
|
"@ContainerType": "Type",
|
||||||
|
"@ContainerPosition": "Position",
|
||||||
|
"@ContainerX": "x",
|
||||||
|
"@ContainerY": "y",
|
||||||
|
"@ContainerSize": "Taille",
|
||||||
|
"@ContainerMinWidth": "Largeur minimale",
|
||||||
|
"@ContainerWidth": "Largeur",
|
||||||
|
"@ContainerMaxWidth": "Largeur maximale",
|
||||||
|
"@ContainerMinHeight": "Hauteur minimale",
|
||||||
|
"@ContainerHeight": "Hauteur",
|
||||||
|
"@ContainerMaxHeight": "Hauteur maximale",
|
||||||
|
"@ContainerMargins": "Marges",
|
||||||
|
"@ContainerMarginLeft": "Marge gauche",
|
||||||
|
"@ContainerMarginBottom": "Marge inférieure",
|
||||||
|
"@ContainerMarginTop": "Marge supérieure",
|
||||||
|
"@ContainerMarginRight": "Marge droite",
|
||||||
|
"@ContainerBehaviors": "Comportements",
|
||||||
|
"@ContainerFlex": "Flexible",
|
||||||
|
"@ContainerAnchor": "Verrouiller la position et la taille",
|
||||||
|
"@ContainerAlignment": "Alignement",
|
||||||
|
"@ContainerAlignmentInput": "Alignement",
|
||||||
|
"@ContainerAlignWithSymbol": "Aligner au symbole",
|
||||||
|
"@ContainerDimensions": "Cotations",
|
||||||
|
"@ContainerShowDimension": "Afficher les cotations",
|
||||||
|
"@ContainerShowChildrenDimension": "Afficher les cotations englobante des enfants",
|
||||||
|
"@ContainerMarkPosition": "Marquer la position pour les parents",
|
||||||
|
"@ContainerShowDimensionWithMarks": "Afficher les cotations avec les enfants marqués",
|
||||||
|
"@ContainerStyle": "Style",
|
||||||
|
"@StyleStroke": "Tracé",
|
||||||
|
"@StyleStrokeOpacity": "Opacité du tracé",
|
||||||
|
"@StyleStrokeWidth": "Epaisseur du tracé",
|
||||||
|
"@StyleFill": "Remplissage",
|
||||||
|
"@StyleFillOpacity": "Opacité du remplissage",
|
||||||
|
|
||||||
|
"@SymbolName": "Nom",
|
||||||
|
"@SymbolX": "x",
|
||||||
|
"@SymbolHeight": "Hauteur",
|
||||||
|
"@SymbolWidth": "Largeur"
|
||||||
|
}
|
27
src/dts/svgld.d.ts
vendored
27
src/dts/svgld.d.ts
vendored
|
@ -13,6 +13,12 @@ export enum AddMethod {
|
||||||
ReplaceParent = 3
|
ReplaceParent = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AppState {
|
||||||
|
MainMenu = 0,
|
||||||
|
Loading = 1,
|
||||||
|
Loaded = 2
|
||||||
|
}
|
||||||
|
|
||||||
export enum MessageType {
|
export enum MessageType {
|
||||||
Normal = 0,
|
Normal = 0,
|
||||||
Success = 1,
|
Success = 1,
|
||||||
|
@ -88,6 +94,7 @@ export interface IAPIConfiguration {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Model of available container used in application configuration */
|
/** Model of available container used in application configuration */
|
||||||
export interface IAvailableContainer {
|
export interface IAvailableContainer {
|
||||||
/** type */
|
/** type */
|
||||||
|
@ -212,7 +219,7 @@ export interface IAvailableContainer {
|
||||||
* (optional)
|
* (optional)
|
||||||
* User data that can be used for data storage or custom SVG
|
* User data that can be used for data storage or custom SVG
|
||||||
*/
|
*/
|
||||||
UserData?: object;
|
UserData?: IKeyValue[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -250,7 +257,6 @@ export interface IConfiguration {
|
||||||
|
|
||||||
export interface IContainerModel {
|
export interface IContainerModel {
|
||||||
children: string[];
|
children: string[];
|
||||||
parent: IContainerModel | null;
|
|
||||||
properties: IContainerProperties;
|
properties: IContainerProperties;
|
||||||
userData: Record<string, string | number>;
|
userData: Record<string, string | number>;
|
||||||
}
|
}
|
||||||
|
@ -260,10 +266,9 @@ export interface IContainerModel {
|
||||||
*/
|
*/
|
||||||
export class ContainerModel implements IContainerModel {
|
export class ContainerModel implements IContainerModel {
|
||||||
children: string[];
|
children: string[];
|
||||||
parent: IContainerModel | null;
|
|
||||||
properties: IContainerProperties;
|
properties: IContainerProperties;
|
||||||
userData: Record<string, string | number>;
|
userData: Record<string, string | number>;
|
||||||
constructor(parent: IContainerModel | null, properties: IContainerProperties, children?: string[], userData?: {});
|
constructor(properties: IContainerProperties, children?: string[], userData?: {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -271,6 +276,7 @@ export class ContainerModel implements IContainerModel {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Properties of a container
|
* Properties of a container
|
||||||
*/
|
*/
|
||||||
|
@ -363,7 +369,7 @@ export interface IContainerProperties {
|
||||||
* (optional)
|
* (optional)
|
||||||
* User data that can be used for data storage or custom SVG
|
* User data that can be used for data storage or custom SVG
|
||||||
*/
|
*/
|
||||||
userData?: object;
|
userData?: IKeyValue[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -428,6 +434,17 @@ export interface IInputGroup {
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IKeyValue {
|
||||||
|
Key: string;
|
||||||
|
Value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILanguage {
|
||||||
|
language: string;
|
||||||
|
dictionary: Record<string, string>;
|
||||||
|
languageChange?: (selected: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IMargin {
|
export interface IMargin {
|
||||||
left?: number;
|
left?: number;
|
||||||
bottom?: number;
|
bottom?: number;
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.elements-sidebar-row {
|
.elements-sidebar-row {
|
||||||
@apply pl-6 pr-6 pt-2 pb-2 w-full
|
@apply pl-6 pr-6 w-full
|
||||||
}
|
}
|
||||||
.symbols-sidebar-row {
|
.symbols-sidebar-row {
|
||||||
@apply elements-sidebar-row
|
@apply elements-sidebar-row
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import { App } from './Components/App/App';
|
import { App } from './Components/App/App';
|
||||||
|
import { LanguageProvider } from './Components/LanguageProvider/LanguageProvider';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
|
|
||||||
function RenderRoot(root: Element | Document): void {
|
function RenderRoot(root: Element | Document): void {
|
||||||
ReactDOM.createRoot(root.querySelector('#root') as HTMLDivElement).render(
|
ReactDOM.createRoot(root.querySelector('#root') as HTMLDivElement).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App root={root}/>
|
<LanguageProvider>
|
||||||
|
<App root={root}/>
|
||||||
|
</LanguageProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,14 @@ import { Position } from '../Enums/Position';
|
||||||
|
|
||||||
/// EDITOR DEFAULTS ///
|
/// EDITOR DEFAULTS ///
|
||||||
|
|
||||||
/** Enable fast boot and disable main menu (default = false) */
|
/** Enable fast boot and disable main menu (0 = disabled, 1 = loading, 2 = loaded) */
|
||||||
export const FAST_BOOT = true;
|
export const FAST_BOOT = import.meta.env.PROD ? 2 : 0;
|
||||||
|
|
||||||
/** Disable any call to the API (default = false) */
|
/** Disable any call to the API (default = false) */
|
||||||
export const DISABLE_API = false;
|
export const DISABLE_API = false;
|
||||||
|
|
||||||
|
export const DEFAULT_LANGUAGE = 'fr';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace the SVG viewer by a canvas
|
* Replace the SVG viewer by a canvas
|
||||||
* Better compatibility with Gecko and WebKit engines like Firefox and Safari.
|
* Better compatibility with Gecko and WebKit engines like Firefox and Safari.
|
||||||
|
|
|
@ -22,6 +22,9 @@ const requestListener = async (request, response) => {
|
||||||
case 'FillHoleWithChassis':
|
case 'FillHoleWithChassis':
|
||||||
json = FillHoleWithChassis(bodyParsed);
|
json = FillHoleWithChassis(bodyParsed);
|
||||||
break;
|
break;
|
||||||
|
case 'Insert':
|
||||||
|
json = Insert(bodyParsed);
|
||||||
|
break;
|
||||||
case 'SplitRemplissage':
|
case 'SplitRemplissage':
|
||||||
json = SplitRemplissage(bodyParsed);
|
json = SplitRemplissage(bodyParsed);
|
||||||
break;
|
break;
|
||||||
|
@ -118,6 +121,19 @@ const GetSVGLayoutConfiguration = () => {
|
||||||
},
|
},
|
||||||
Category: "Stuff",
|
Category: "Stuff",
|
||||||
Actions: [
|
Actions: [
|
||||||
|
{
|
||||||
|
Id: "Insert",
|
||||||
|
Action: "Insert",
|
||||||
|
Label: "Insert containers",
|
||||||
|
Description: "Insert containers",
|
||||||
|
CustomLogo: {
|
||||||
|
Base64Image: null,
|
||||||
|
Name: 'Image1',
|
||||||
|
Svg: null,
|
||||||
|
Url: ""
|
||||||
|
},
|
||||||
|
AddingBehavior: 1
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Id: "SplitRemplissage",
|
Id: "SplitRemplissage",
|
||||||
Action: "SplitRemplissage",
|
Action: "SplitRemplissage",
|
||||||
|
@ -131,32 +147,6 @@ const GetSVGLayoutConfiguration = () => {
|
||||||
},
|
},
|
||||||
AddingBehavior: 2
|
AddingBehavior: 2
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Id: "SplitRemplissageParent",
|
|
||||||
Action: "SplitRemplissageParent",
|
|
||||||
Label: "Diviser le remplissage en insérant un montant",
|
|
||||||
Description: "Diviser le remplissage en insérant un montant",
|
|
||||||
CustomLogo: {
|
|
||||||
Base64Image: null,
|
|
||||||
Name: 'Image1',
|
|
||||||
Svg: null,
|
|
||||||
Url: ""
|
|
||||||
},
|
|
||||||
AddingBehavior: 3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Id: "SplitRemplissageParent",
|
|
||||||
Action: "SplitRemplissageParent",
|
|
||||||
Label: "Diviser le remplissage en insérant un montant",
|
|
||||||
Description: "Diviser le remplissage en insérant un montant",
|
|
||||||
CustomLogo: {
|
|
||||||
Base64Image: null,
|
|
||||||
Name: 'Image1',
|
|
||||||
Svg: null,
|
|
||||||
Url: ""
|
|
||||||
},
|
|
||||||
AddingBehavior: 3
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
Id: "SplitRemplissageParent",
|
Id: "SplitRemplissageParent",
|
||||||
Action: "SplitRemplissageParent",
|
Action: "SplitRemplissageParent",
|
||||||
|
@ -293,7 +283,10 @@ const GetSVGLayoutConfiguration = () => {
|
||||||
Url: 'https://www.manutan.fr/img/S/GRP/ST/AIG3930272.jpg'
|
Url: 'https://www.manutan.fr/img/S/GRP/ST/AIG3930272.jpg'
|
||||||
},
|
},
|
||||||
Name: 'Poteau structure',
|
Name: 'Poteau structure',
|
||||||
PositionReference: 1
|
PositionReference: 1,
|
||||||
|
AssociatedContainer: {
|
||||||
|
Type: 'Montant'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Width: 32,
|
Width: 32,
|
||||||
|
@ -369,13 +362,15 @@ const FillHoleWithChassis = (request) => {
|
||||||
const SplitRemplissage = (request) => {
|
const SplitRemplissage = (request) => {
|
||||||
const lstModels = [
|
const lstModels = [
|
||||||
{
|
{
|
||||||
Type: 'Remplissage'
|
Type: 'Remplissage',
|
||||||
|
IsFlex: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: 'Montant'
|
Type: 'Montant'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Type: 'Remplissage'
|
Type: 'Remplissage',
|
||||||
|
IsFlex: true
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -385,3 +380,24 @@ const SplitRemplissage = (request) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const Insert = (request) => {
|
||||||
|
const lstModels = [
|
||||||
|
{
|
||||||
|
Type: 'Remplissage',
|
||||||
|
IsFlex: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: 'Montant',
|
||||||
|
X: 5,
|
||||||
|
IsAnchor: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: 'Remplissage',
|
||||||
|
IsFlex: true
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return {
|
||||||
|
Containers: lstModels
|
||||||
|
};
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue