Merged PR 315: ErgonomieTreeView
Affichage fonctionnelle sous forme de toolbar vertical, comme dans les IDE Related work items: #7976
This commit is contained in:
parent
acb5ba2d82
commit
8a99ef4cfd
13 changed files with 240 additions and 133 deletions
|
@ -4,11 +4,11 @@ import { expect, describe, it, vi } from 'vitest';
|
|||
import { PositionReference } from '../../Enums/PositionReference';
|
||||
import { IContainerProperties } from '../../Interfaces/IContainerProperties';
|
||||
import { Orientation } from '../../Enums/Orientation';
|
||||
import { Properties } from './ContainerProperties';
|
||||
import { ContainerProperties } from './ContainerProperties';
|
||||
|
||||
describe.concurrent('Properties', () => {
|
||||
it('No properties', () => {
|
||||
render(<Properties
|
||||
render(<ContainerProperties
|
||||
properties={undefined}
|
||||
onChange={() => {}}
|
||||
symbols={new Map()}
|
||||
|
@ -67,7 +67,7 @@ describe.concurrent('Properties', () => {
|
|||
(prop as any)[key] = value;
|
||||
});
|
||||
|
||||
const { container, rerender } = render(<Properties
|
||||
const { container, rerender } = render(<ContainerProperties
|
||||
properties={prop}
|
||||
onChange={handleChange}
|
||||
symbols={new Map()}
|
||||
|
@ -108,7 +108,7 @@ describe.concurrent('Properties', () => {
|
|||
expect(prop.parentId).toBe('parentId');
|
||||
expect(prop.x).toBe(2);
|
||||
expect(prop.y).toBe(2);
|
||||
rerender(<Properties
|
||||
rerender(<ContainerProperties
|
||||
properties={Object.assign({}, prop)}
|
||||
onChange={handleChange}
|
||||
symbols={new Map()}
|
||||
|
|
|
@ -10,7 +10,7 @@ interface IPropertiesProps {
|
|||
onChange: (key: string, value: string | number | boolean | number[], type?: PropertyType) => void
|
||||
}
|
||||
|
||||
export function Properties(props: IPropertiesProps): JSX.Element {
|
||||
export function ContainerProperties(props: IPropertiesProps): JSX.Element {
|
||||
if (props.properties === undefined) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,30 @@ export function SelectContainer(
|
|||
return history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deselect a container
|
||||
* @returns New history
|
||||
*/
|
||||
export function DeselectContainer(
|
||||
containerId: string,
|
||||
fullHistory: IHistoryState[],
|
||||
historyCurrentStep: number
|
||||
): IHistoryState[] {
|
||||
const history = GetCurrentHistory(fullHistory, historyCurrentStep);
|
||||
const current = history[history.length - 1];
|
||||
|
||||
history.push({
|
||||
lastAction: `Deselect ${containerId}`,
|
||||
mainContainer: current.mainContainer,
|
||||
containers: structuredClone(current.containers),
|
||||
selectedContainerId: 'undefined',
|
||||
typeCounters: Object.assign({}, current.typeCounters),
|
||||
symbols: structuredClone(current.symbols),
|
||||
selectedSymbolId: current.selectedSymbolId
|
||||
});
|
||||
return history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a container
|
||||
* @param containerId containerId of the container to delete
|
||||
|
@ -115,7 +139,7 @@ export function DeleteContainer(
|
|||
* If the selected container is removed, select the sibling after,
|
||||
* If there is no sibling, select the parent,
|
||||
*
|
||||
* @param mainContainerClone Main container
|
||||
* @param containers
|
||||
* @param selectedContainerId Current selected container
|
||||
* @param parent Parent of the selected/deleted container
|
||||
* @param index Index of the selected/deleted container
|
||||
|
@ -127,11 +151,10 @@ function GetSelectedContainerOnDelete(
|
|||
parent: IContainerModel,
|
||||
index: number
|
||||
): string {
|
||||
const newSelectedContainerId = FindContainerById(containers, selectedContainerId)?.properties.id ??
|
||||
return FindContainerById(containers, selectedContainerId)?.properties.id ??
|
||||
parent.children.at(index) ??
|
||||
parent.children.at(index - 1) ??
|
||||
parent.properties.id;
|
||||
return newSelectedContainerId;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,6 +183,10 @@ function UnlinkContainerFromSymbols(
|
|||
* Handled the property change event in the properties form
|
||||
* @param key Property name
|
||||
* @param value New value of the property
|
||||
* @param type
|
||||
* @param selected
|
||||
* @param fullHistory
|
||||
* @param historyCurrentStep
|
||||
* @returns void
|
||||
*/
|
||||
export function OnPropertyChange(
|
||||
|
@ -201,6 +228,7 @@ export function OnPropertyChange(
|
|||
|
||||
/**
|
||||
* Sort the parent children by x
|
||||
* @param containers
|
||||
* @param parent The clone used for the sort
|
||||
* @returns void
|
||||
*/
|
||||
|
@ -265,6 +293,7 @@ export function SortChildren(
|
|||
|
||||
/**
|
||||
* Set the container with properties and behaviors (mutate)
|
||||
* @param containers
|
||||
* @param container Container to update
|
||||
* @param key Key of the property to update
|
||||
* @param value Value of the property to update
|
||||
|
@ -371,9 +400,8 @@ function AssignProperty(container: IContainerModel, key: string, value: string |
|
|||
/**
|
||||
* Link a symbol to a container
|
||||
* @param containerId Container id
|
||||
* @param oldSymbolId Old Symbol id
|
||||
* @param newSymbolId New Symbol id
|
||||
* @param symbols Current list of symbols
|
||||
* @param oldSymbol
|
||||
* @param newSymbol
|
||||
* @returns
|
||||
*/
|
||||
export function LinkSymbol(
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
import useSize from '@react-hook/size';
|
||||
import { FixedSizeList as List } from 'react-window';
|
||||
import { Properties } from '../ContainerProperties/ContainerProperties';
|
||||
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
|
||||
import { ContainerProperties } from '../ContainerProperties/ContainerProperties';
|
||||
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
||||
import { FindContainerById, MakeRecursionDFSIterator } from '../../utils/itertools';
|
||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
||||
import { PropertyType } from '../../Enums/PropertyType';
|
||||
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
|
||||
import { ToggleSideBar } from '../Sidebar/ToggleSideBar/ToggleSideBar';
|
||||
import { Text } from '../Text/Text';
|
||||
|
||||
interface IElementsListProps {
|
||||
interface IElementsSideBarProps {
|
||||
containers: Map<string, IContainerModel>
|
||||
mainContainer: IContainerModel
|
||||
symbols: Map<string, ISymbolModel>
|
||||
|
@ -20,6 +23,8 @@ interface IElementsListProps {
|
|||
) => void
|
||||
selectContainer: (containerId: string) => void
|
||||
addContainer: (index: number, type: string, parent: string) => void
|
||||
isExpanded: boolean
|
||||
onExpandChange: () => void
|
||||
}
|
||||
|
||||
function RemoveBorderClasses(target: HTMLButtonElement, exception: string = ''): void {
|
||||
|
@ -119,10 +124,11 @@ function HandleOnDrop(
|
|||
}
|
||||
}
|
||||
|
||||
export function ElementsList(props: IElementsListProps): JSX.Element {
|
||||
export function ElementsSideBar(props: IElementsSideBarProps): JSX.Element {
|
||||
// States
|
||||
const divRef = React.useRef<HTMLDivElement>(null);
|
||||
const [, height] = useSize(divRef);
|
||||
const [,height] = useSize(divRef);
|
||||
const [showProperties, setShowProperties] = useState(props.isExpanded);
|
||||
|
||||
// Render
|
||||
const it = MakeRecursionDFSIterator(props.mainContainer, props.containers, 0, [0, 0], true);
|
||||
|
@ -160,10 +166,21 @@ export function ElementsList(props: IElementsListProps): JSX.Element {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className='h-full flex flex-col'>
|
||||
<div ref={divRef} className='h-1/2'>
|
||||
<div className='flex flex-row h-full w-full' >
|
||||
{showProperties &&
|
||||
<div className='flex flex-1 flex-col w-64 border-r-2 border-slate-400'>
|
||||
<ContainerProperties
|
||||
properties={props.selectedContainer?.properties}
|
||||
symbols={props.symbols}
|
||||
onChange={props.onPropertyChange}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
<div className='flex w-64' ref={divRef}>
|
||||
<div className='w-6'>
|
||||
<ToggleSideBar title={Text({ textId: '@Properties' })} checked={showProperties} onChange={(newValue) => { setShowProperties(newValue); props.onExpandChange(); }} />
|
||||
</div>
|
||||
<List
|
||||
className="List divide-y divide-black overflow-y-auto"
|
||||
itemCount={containers.length}
|
||||
itemSize={35}
|
||||
height={height}
|
||||
|
@ -172,13 +189,6 @@ export function ElementsList(props: IElementsListProps): JSX.Element {
|
|||
{Row}
|
||||
</List>
|
||||
</div>
|
||||
<div className='grow overflow-auto'>
|
||||
<Properties
|
||||
properties={props.selectedContainer?.properties}
|
||||
symbols={props.symbols}
|
||||
onChange={props.onPropertyChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
4
src/Components/Sidebar/ToggleSideBar/ToggleSideBar.scss
Normal file
4
src/Components/Sidebar/ToggleSideBar/ToggleSideBar.scss
Normal file
|
@ -0,0 +1,4 @@
|
|||
.text-vertical{
|
||||
text-align: right;
|
||||
writing-mode: vertical-rl;
|
||||
}
|
23
src/Components/Sidebar/ToggleSideBar/ToggleSideBar.tsx
Normal file
23
src/Components/Sidebar/ToggleSideBar/ToggleSideBar.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
import * as React from 'react';
|
||||
import './ToggleSideBar.scss';
|
||||
|
||||
interface IToggleSidebarProps {
|
||||
title: string
|
||||
checked: boolean
|
||||
onChange: (newValue: boolean) => void
|
||||
}
|
||||
|
||||
export function ToggleSideBar({ title, checked, onChange }: IToggleSidebarProps): JSX.Element {
|
||||
return (
|
||||
<div className={`${(checked ? 'bg-slate-400 hover:bg-slate-500' : 'bg-slate-300 hover:bg-slate-400')}`}>
|
||||
<button
|
||||
className={'w-full py-2'}
|
||||
type='button'
|
||||
onClick={() => onChange(!checked)}
|
||||
>
|
||||
<p className='text-vertical'>{title}
|
||||
</p>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -14,7 +14,7 @@ export function SymbolProperties(props: ISymbolPropertiesProps): JSX.Element {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className='h-full p-3 bg-slate-200 overflow-y-auto'>
|
||||
<div className='h-full p-3 bg-slate-200 overflow-y-auto '>
|
||||
<SymbolForm
|
||||
symbol={props.symbol}
|
||||
symbols={props.symbols}
|
||||
|
|
|
@ -3,18 +3,24 @@ import useSize from '@react-hook/size';
|
|||
import { FixedSizeList as List } from 'react-window';
|
||||
import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
||||
import { SymbolProperties } from '../SymbolProperties/SymbolProperties';
|
||||
import { ToggleSideBar } from '../Sidebar/ToggleSideBar/ToggleSideBar';
|
||||
import { Text } from '../Text/Text';
|
||||
import { useState } from 'react';
|
||||
|
||||
interface ISymbolsSidebarProps {
|
||||
selectedSymbolId: string
|
||||
symbols: Map<string, ISymbolModel>
|
||||
onPropertyChange: (key: string, value: string | number | boolean) => void
|
||||
selectSymbol: (symbolId: string) => void
|
||||
isExpanded: boolean
|
||||
onExpandChange: (isExpanded: boolean) => void
|
||||
}
|
||||
|
||||
export function SymbolsSidebar(props: ISymbolsSidebarProps): JSX.Element {
|
||||
// States
|
||||
const divRef = React.useRef<HTMLDivElement>(null);
|
||||
const height = useSize(divRef)[1];
|
||||
const [showProperties, setShowProperties] = useState(props.isExpanded);
|
||||
// Render
|
||||
const symbols = [...props.symbols.values()];
|
||||
function Row({ index, style }: { index: number, style: React.CSSProperties }): JSX.Element {
|
||||
|
@ -39,12 +45,22 @@ export function SymbolsSidebar(props: ISymbolsSidebarProps): JSX.Element {
|
|||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
const selectedSymbol = props.symbols.get(props.selectedSymbolId);
|
||||
return (
|
||||
<div className='h-full'>
|
||||
<div ref={divRef} className='h-1/2 text-gray-800'>
|
||||
<div className='flex flex-row h-full w-full'>
|
||||
{showProperties && <div className='flex flex-1 flex-col w-64 border-r-2 border-slate-400'>
|
||||
{(selectedSymbol == null) && <h1 className={'p-4'}>{Text({ textId: '@NoSymbolSelected' })}</h1>}
|
||||
<SymbolProperties
|
||||
symbol={selectedSymbol}
|
||||
symbols={props.symbols}
|
||||
onChange={props.onPropertyChange}
|
||||
/>
|
||||
</div>}
|
||||
<div className={'flex w-64'} ref={divRef}>
|
||||
<div className='w-6'>
|
||||
<ToggleSideBar title={Text({ textId: '@Properties' })} checked={showProperties} onChange={(newValue) => { setShowProperties(newValue); props.onExpandChange(newValue); }} />
|
||||
</div>
|
||||
<List
|
||||
className='List divide-y divide-black'
|
||||
itemCount={symbols.length}
|
||||
itemSize={35}
|
||||
height={height}
|
||||
|
@ -53,13 +69,6 @@ export function SymbolsSidebar(props: ISymbolsSidebarProps): JSX.Element {
|
|||
{Row}
|
||||
</List>
|
||||
</div>
|
||||
<div>
|
||||
<SymbolProperties
|
||||
symbol={props.symbols.get(props.selectedSymbolId)}
|
||||
symbols={props.symbols}
|
||||
onChange={props.onPropertyChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
import * as React from 'react';
|
||||
import { ElementsList } from '../ElementsList/ElementsList';
|
||||
import { ElementsSideBar } from '../ElementsList/ElementsSideBar';
|
||||
import { History } from '../History/History';
|
||||
import { Bar } from '../Bar/Bar';
|
||||
import { Bar, BAR_WIDTH } from '../Bar/Bar';
|
||||
import { Symbols } from '../Symbols/Symbols';
|
||||
import { SymbolsSidebar } from '../SymbolsList/SymbolsList';
|
||||
import { SymbolsSidebar } from '../SymbolsList/SymbolsSidebar';
|
||||
import { PropertyType } from '../../Enums/PropertyType';
|
||||
import { Messages } from '../Messages/Messages';
|
||||
import { Sidebar } from '../Sidebar/Sidebar';
|
||||
|
@ -37,7 +37,9 @@ export interface IUIProps {
|
|||
export enum SidebarType {
|
||||
None,
|
||||
Components,
|
||||
ComponentsExpanded,
|
||||
Symbols,
|
||||
SymbolsExpanded,
|
||||
History,
|
||||
Messages,
|
||||
Settings
|
||||
|
@ -59,6 +61,7 @@ function UseSetOrToggleSidebar(
|
|||
|
||||
export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
||||
const [selectedSidebar, setSelectedSidebar] = React.useState<SidebarType>(SidebarType.Components);
|
||||
|
||||
const [messages, setMessages] = React.useState<IMessage[]>([]);
|
||||
const current = GetCurrentHistoryState(editorState.history, editorState.historyCurrentStep);
|
||||
const configuration = editorState.configuration;
|
||||
|
@ -78,7 +81,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
|||
);
|
||||
}
|
||||
|
||||
// Please use setOrToggleSidebar rather than setSelectedSidebar so we can close the sidebar
|
||||
// Please use setOrToggleSidebar rather than setSelectedSidebar, so we can close the sidebar
|
||||
const setOrToggleSidebar = UseSetOrToggleSidebar(selectedSidebar, setSelectedSidebar);
|
||||
|
||||
let leftSidebarTitle = '';
|
||||
|
@ -104,7 +107,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
|||
buttonOnClick={methods.addContainer}
|
||||
/>;
|
||||
rightSidebarTitle = Text({ textId: '@Elements' });
|
||||
rightChildren = <ElementsList
|
||||
rightChildren = <ElementsSideBar
|
||||
containers={current.containers}
|
||||
mainContainer={mainContainer}
|
||||
symbols={current.symbols}
|
||||
|
@ -112,9 +115,31 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
|||
onPropertyChange={methods.onPropertyChange}
|
||||
selectContainer={methods.selectContainer}
|
||||
addContainer={methods.addContainerAt}
|
||||
isExpanded ={false}
|
||||
onExpandChange={() => setOrToggleSidebar(SidebarType.ComponentsExpanded) }
|
||||
/>;
|
||||
break;
|
||||
case SidebarType.ComponentsExpanded:
|
||||
leftSidebarTitle = Text({ textId: '@Components' });
|
||||
leftChildren = <Components
|
||||
selectedContainer={selectedContainer}
|
||||
componentOptions={configuration.AvailableContainers}
|
||||
categories={configuration.Categories}
|
||||
buttonOnClick={methods.addContainer}
|
||||
/>;
|
||||
rightSidebarTitle = Text({ textId: '@Elements' });
|
||||
rightChildren = <ElementsSideBar
|
||||
containers={current.containers}
|
||||
mainContainer={mainContainer}
|
||||
symbols={current.symbols}
|
||||
selectedContainer={selectedContainer}
|
||||
onPropertyChange={methods.onPropertyChange}
|
||||
selectContainer={methods.selectContainer}
|
||||
addContainer={methods.addContainerAt}
|
||||
isExpanded ={true}
|
||||
onExpandChange={() => setOrToggleSidebar(SidebarType.Components) }
|
||||
/>;
|
||||
break;
|
||||
|
||||
case SidebarType.Symbols:
|
||||
leftSidebarTitle = Text({ textId: '@SymbolsLeft' });
|
||||
leftChildren = <Symbols
|
||||
|
@ -127,6 +152,24 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
|||
symbols={current.symbols}
|
||||
onPropertyChange={methods.onSymbolPropertyChange}
|
||||
selectSymbol={methods.selectSymbol}
|
||||
isExpanded ={false}
|
||||
onExpandChange={() => setOrToggleSidebar(SidebarType.SymbolsExpanded) }
|
||||
/>;
|
||||
break;
|
||||
case SidebarType.SymbolsExpanded:
|
||||
leftSidebarTitle = Text({ textId: '@SymbolsLeft' });
|
||||
leftChildren = <Symbols
|
||||
componentOptions={configuration.AvailableSymbols}
|
||||
buttonOnClick={methods.addSymbol}
|
||||
/>;
|
||||
rightSidebarTitle = Text({ textId: '@SymbolsRight' });
|
||||
rightChildren = <SymbolsSidebar
|
||||
selectedSymbolId={current.selectedSymbolId}
|
||||
symbols={current.symbols}
|
||||
onPropertyChange={methods.onSymbolPropertyChange}
|
||||
selectSymbol={methods.selectSymbol}
|
||||
isExpanded ={true}
|
||||
onExpandChange={() => setOrToggleSidebar(SidebarType.Symbols)}
|
||||
/>;
|
||||
break;
|
||||
|
||||
|
@ -159,6 +202,7 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
|||
|
||||
const isLeftSidebarOpen = selectedSidebar !== SidebarType.None;
|
||||
const isRightSidebarOpen = selectedSidebar === SidebarType.Components || selectedSidebar === SidebarType.Symbols;
|
||||
const isRightSidebarOpenExpanded = selectedSidebar === SidebarType.ComponentsExpanded || selectedSidebar === SidebarType.SymbolsExpanded;
|
||||
|
||||
const isLeftSidebarOpenClasses = new Set<string>([
|
||||
'left-sidebar',
|
||||
|
@ -170,14 +214,29 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
|||
|
||||
let isRightSidebarOpenClasses = 'right-0 -bottom-full md:-right-80 md:bottom-0';
|
||||
|
||||
let marginSidebar = BAR_WIDTH;
|
||||
const viewerMarginClasses = new Set<string>([
|
||||
'ml-16'
|
||||
]);
|
||||
|
||||
if (isLeftSidebarOpen) {
|
||||
isLeftSidebarOpenClasses.delete('-bottom-full');
|
||||
isLeftSidebarOpenClasses.delete('md:-left-64');
|
||||
isLeftSidebarOpenClasses.delete('md:bottom-0');
|
||||
marginSidebar += 256;
|
||||
viewerMarginClasses.add(' md:ml-80');
|
||||
}
|
||||
|
||||
if (isRightSidebarOpen) {
|
||||
if (isRightSidebarOpen || isRightSidebarOpenExpanded) {
|
||||
isRightSidebarOpenClasses = 'right-0';
|
||||
|
||||
if (isRightSidebarOpenExpanded) {
|
||||
viewerMarginClasses.add(' md:mr-[32rem]');
|
||||
marginSidebar += 512;
|
||||
} else {
|
||||
viewerMarginClasses.add(' md:mr-64');
|
||||
marginSidebar += 256;
|
||||
}
|
||||
} else {
|
||||
isLeftSidebarOpenClasses.delete('left-sidebar');
|
||||
isLeftSidebarOpenClasses.add('left-sidebar-single');
|
||||
|
@ -186,16 +245,24 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
|||
return (
|
||||
<>
|
||||
<Bar
|
||||
isComponentsOpen={selectedSidebar === SidebarType.Components}
|
||||
isSymbolsOpen={selectedSidebar === SidebarType.Symbols}
|
||||
isComponentsOpen={selectedSidebar === SidebarType.Components || selectedSidebar === SidebarType.ComponentsExpanded}
|
||||
isSymbolsOpen={selectedSidebar === SidebarType.Symbols || selectedSidebar === SidebarType.SymbolsExpanded}
|
||||
isHistoryOpen={selectedSidebar === SidebarType.History}
|
||||
isMessagesOpen={selectedSidebar === SidebarType.Messages}
|
||||
isSettingsOpen={selectedSidebar === SidebarType.Settings}
|
||||
toggleComponents={() => {
|
||||
if (selectedSidebar === SidebarType.ComponentsExpanded) {
|
||||
setOrToggleSidebar(SidebarType.ComponentsExpanded);
|
||||
} else {
|
||||
setOrToggleSidebar(SidebarType.Components);
|
||||
}
|
||||
} }
|
||||
toggleSymbols={() => {
|
||||
if (selectedSidebar === SidebarType.SymbolsExpanded) {
|
||||
setOrToggleSidebar(SidebarType.SymbolsExpanded);
|
||||
} else {
|
||||
setOrToggleSidebar(SidebarType.Symbols);
|
||||
}
|
||||
} }
|
||||
toggleTimeline={() => {
|
||||
setOrToggleSidebar(SidebarType.History);
|
||||
|
@ -214,11 +281,11 @@ export function UI({ editorState, ...methods }: IUIProps): JSX.Element {
|
|||
{ leftChildren }
|
||||
</Sidebar>
|
||||
<Viewer
|
||||
isLeftSidebarOpen={isLeftSidebarOpen}
|
||||
isRightSidebarOpen={isRightSidebarOpen}
|
||||
className={`${[...viewerMarginClasses.values()].join(' ')} w-full h-full`}
|
||||
current={current}
|
||||
selectedContainer={selectedContainer}
|
||||
selectContainer={methods.selectContainer}
|
||||
margin={marginSidebar}
|
||||
/>
|
||||
<Sidebar
|
||||
className={`right-sidebar ${isRightSidebarOpenClasses}`}
|
||||
|
|
|
@ -10,48 +10,38 @@ import { AddDimensions } from '../Canvas/DimensionLayer';
|
|||
import { RenderSelector } from '../Canvas/Selector';
|
||||
import { SVG } from '../SVG/SVG';
|
||||
import { RenderSymbol } from '../Canvas/Symbol';
|
||||
import { useState } from 'react';
|
||||
|
||||
interface IViewerProps {
|
||||
isLeftSidebarOpen: boolean
|
||||
isRightSidebarOpen: boolean
|
||||
className?: string
|
||||
current: IHistoryState
|
||||
selectedContainer: IContainerModel | undefined
|
||||
selectContainer: (containerId: string) => void
|
||||
margin: number
|
||||
}
|
||||
|
||||
interface IViewer {
|
||||
viewerWidth: number
|
||||
viewerHeight: number
|
||||
}
|
||||
|
||||
function OnResize(
|
||||
isLeftSidebarOpen: boolean,
|
||||
isRightSidebarOpen: boolean,
|
||||
setViewer: React.Dispatch<React.SetStateAction<IViewer>>
|
||||
): void {
|
||||
let marginSidebar = BAR_WIDTH;
|
||||
if (isLeftSidebarOpen) {
|
||||
marginSidebar += 256;
|
||||
}
|
||||
if (isRightSidebarOpen) {
|
||||
marginSidebar += 256;
|
||||
export function Viewer({
|
||||
className,
|
||||
current,
|
||||
selectedContainer,
|
||||
selectContainer,
|
||||
margin
|
||||
}: IViewerProps): JSX.Element {
|
||||
function computeWidth(margin: number): number {
|
||||
return window.innerWidth - (window.innerWidth < 768 ? BAR_WIDTH : margin);
|
||||
}
|
||||
|
||||
const margin = window.innerWidth < 768 ? BAR_WIDTH : marginSidebar;
|
||||
setViewer({
|
||||
viewerWidth: window.innerWidth - margin,
|
||||
viewerHeight: window.innerHeight
|
||||
});
|
||||
}
|
||||
const [windowSize, setWindowSize] = useState([
|
||||
computeWidth(margin),
|
||||
window.innerHeight
|
||||
]);
|
||||
|
||||
function UseSVGAutoResizerOnWindowResize(
|
||||
isLeftSidebarOpen: boolean,
|
||||
isRightSidebarOpen: boolean,
|
||||
setViewer: React.Dispatch<React.SetStateAction<IViewer>>
|
||||
): void {
|
||||
React.useEffect(() => {
|
||||
function SVGAutoResizer(): void {
|
||||
OnResize(isLeftSidebarOpen, isRightSidebarOpen, setViewer);
|
||||
setWindowSize([
|
||||
computeWidth(margin),
|
||||
window.innerHeight
|
||||
]);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', SVGAutoResizer);
|
||||
|
@ -60,41 +50,13 @@ function UseSVGAutoResizerOnWindowResize(
|
|||
window.removeEventListener('resize', SVGAutoResizer);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function UseSVGAutoResizerOnSidebar(
|
||||
isLeftSidebarOpen: boolean,
|
||||
isRightSidebarOpen: boolean,
|
||||
setViewer: React.Dispatch<React.SetStateAction<IViewer>>
|
||||
): void {
|
||||
React.useEffect(() => {
|
||||
OnResize(isLeftSidebarOpen, isRightSidebarOpen, setViewer);
|
||||
}, [isLeftSidebarOpen, isRightSidebarOpen, setViewer]);
|
||||
}
|
||||
|
||||
export function Viewer({
|
||||
isLeftSidebarOpen, isRightSidebarOpen,
|
||||
current,
|
||||
selectedContainer,
|
||||
selectContainer
|
||||
}: IViewerProps): JSX.Element {
|
||||
let marginClasses = 'ml-16';
|
||||
let marginSidebar = BAR_WIDTH;
|
||||
if (isLeftSidebarOpen) {
|
||||
marginClasses += ' md:ml-80';
|
||||
marginSidebar += 256;
|
||||
}
|
||||
|
||||
if (isRightSidebarOpen) {
|
||||
marginClasses += ' md:mr-64';
|
||||
marginSidebar += 256;
|
||||
}
|
||||
|
||||
const margin = window.innerWidth < 768 ? BAR_WIDTH : marginSidebar;
|
||||
const [viewer, setViewer] = React.useState<IViewer>({
|
||||
viewerWidth: window.innerWidth - margin,
|
||||
viewerHeight: window.innerHeight
|
||||
});
|
||||
setWindowSize([
|
||||
computeWidth(margin),
|
||||
window.innerHeight
|
||||
]);
|
||||
}, [margin]);
|
||||
|
||||
const mainContainer = FindContainerById(current.containers, current.mainContainer);
|
||||
|
||||
|
@ -102,9 +64,6 @@ export function Viewer({
|
|||
return <></>;
|
||||
}
|
||||
|
||||
UseSVGAutoResizerOnWindowResize(isLeftSidebarOpen, isRightSidebarOpen, setViewer);
|
||||
UseSVGAutoResizerOnSidebar(isLeftSidebarOpen, isRightSidebarOpen, setViewer);
|
||||
|
||||
if (USE_EXPERIMENTAL_CANVAS_API) {
|
||||
function Draw(ctx: CanvasRenderingContext2D, frameCount: number, scale: number, translatePos: IPoint): void {
|
||||
if (mainContainer === undefined) {
|
||||
|
@ -169,9 +128,9 @@ export function Viewer({
|
|||
|
||||
return (
|
||||
<SVG
|
||||
className={marginClasses}
|
||||
viewerWidth={viewer.viewerWidth}
|
||||
viewerHeight={viewer.viewerHeight}
|
||||
className={className}
|
||||
viewerWidth={windowSize[0]}
|
||||
viewerHeight={windowSize[1]}
|
||||
width={mainContainer.properties.width}
|
||||
height={mainContainer.properties.height}
|
||||
containers={current.containers}
|
||||
|
@ -179,6 +138,7 @@ export function Viewer({
|
|||
symbols={current.symbols}
|
||||
selectContainer={selectContainer}
|
||||
>
|
||||
|
||||
{mainContainer}
|
||||
</SVG>
|
||||
);
|
||||
|
@ -206,10 +166,11 @@ function RenderDimensions(
|
|||
currentTransform: [number, number]
|
||||
): void {
|
||||
ctx.save();
|
||||
const containerLeftDim = leftDim - (DIMENSION_MARGIN * (depth + 1)) / scale;
|
||||
const containerTopDim = topDim - (DIMENSION_MARGIN * (depth + 1)) / scale;
|
||||
const containerBottomDim = bottomDim + (DIMENSION_MARGIN * (depth + 1)) / scale;
|
||||
const containerRightDim = rightDim + (DIMENSION_MARGIN * (depth + 1)) / scale;
|
||||
const depthOffset = (DIMENSION_MARGIN * (depth + 1)) / scale;
|
||||
const containerLeftDim = leftDim - depthOffset;
|
||||
const containerTopDim = topDim - depthOffset;
|
||||
const containerBottomDim = bottomDim + depthOffset;
|
||||
const containerRightDim = rightDim + depthOffset;
|
||||
const dimMapped = [containerLeftDim, containerBottomDim, containerTopDim, containerRightDim];
|
||||
AddDimensions(ctx, containers, container, dimMapped, currentTransform, scale, depth);
|
||||
ctx.restore();
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
"@StartFromScratch": "Start from scratch",
|
||||
"@LoadConfigFile": "Load a configuration file",
|
||||
"@GoBack": "Go back",
|
||||
"@Properties" : "Properties",
|
||||
|
||||
"@Components": "Components",
|
||||
"@Elements": "Elements",
|
||||
"@Symbols": "Symbols",
|
||||
"@SymbolsLeft": "Symbols",
|
||||
"@SymbolsRight": "Symbols",
|
||||
"@NoSymbolSelected": "No symbol selected",
|
||||
"@Timeline": "Timeline",
|
||||
"@Messages": "Messages",
|
||||
"@Settings": "Settings",
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
"@StartFromScratch": "Partir de zéro",
|
||||
"@LoadConfigFile": "Charger un fichier de configuration",
|
||||
"@GoBack": "Revenir",
|
||||
"@Properties" : "Propriétés",
|
||||
|
||||
"@Components": "Composants",
|
||||
"@Elements": "Éléments",
|
||||
"@Symbols": "Symboles",
|
||||
"@SymbolsLeft": "Symboles",
|
||||
"@SymbolsRight": "Symboles",
|
||||
"@NoSymbolSelected": "Pas de symbol sélectionné",
|
||||
"@Timeline": "Chronologie",
|
||||
"@Messages": "Messages",
|
||||
"@Settings": "Paramètres",
|
||||
|
|
|
@ -21,10 +21,11 @@
|
|||
|
||||
.right-sidebar {
|
||||
@apply fixed shadow-lg z-20
|
||||
w-[calc(100%_-_4rem)] md:w-64
|
||||
h-1/2 md:h-full bottom-0 md:bottom-0
|
||||
}
|
||||
|
||||
|
||||
|
||||
.sidebar-title {
|
||||
@apply p-3 md:p-5 font-bold h-12 md:h-16
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue