Merged PR 203: Improve responsive design and refactor layout
This commit is contained in:
parent
50626218ba
commit
0d05f0959c
27 changed files with 968 additions and 485 deletions
|
@ -7,11 +7,9 @@ import { ISymbolModel } from '../../Interfaces/ISymbolModel';
|
|||
import { PropertyType } from '../../Enums/PropertyType';
|
||||
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
interface IElementsSidebarProps {
|
||||
interface IElementsProps {
|
||||
mainContainer: IContainerModel
|
||||
symbols: Map<string, ISymbolModel>
|
||||
isOpen: boolean
|
||||
isHistoryOpen: boolean
|
||||
selectedContainer: IContainerModel | undefined
|
||||
onPropertyChange: (
|
||||
key: string,
|
||||
|
@ -117,13 +115,8 @@ function HandleOnDrop(
|
|||
}
|
||||
}
|
||||
|
||||
export function ElementsSidebar(props: IElementsSidebarProps): JSX.Element {
|
||||
export function Elements(props: IElementsProps): JSX.Element {
|
||||
// Render
|
||||
let isOpenClasses = '-right-64';
|
||||
if (props.isOpen) {
|
||||
isOpenClasses = props.isHistoryOpen ? 'right-64' : 'right-0';
|
||||
}
|
||||
|
||||
const it = MakeRecursionDFSIterator(props.mainContainer, 0, [0, 0], true);
|
||||
const containers = [...it];
|
||||
function Row({
|
||||
|
@ -138,16 +131,19 @@ export function ElementsSidebar(props: IElementsSidebarProps): JSX.Element {
|
|||
const text = container.properties.displayedText === key
|
||||
? `${key}`
|
||||
: `${container.properties.displayedText}`;
|
||||
const selectedClass: string = props.selectedContainer !== undefined &&
|
||||
|
||||
const isSelected = props.selectedContainer !== undefined &&
|
||||
props.selectedContainer !== null &&
|
||||
props.selectedContainer.properties.id === container.properties.id
|
||||
? 'border-l-4 bg-slate-400/60 hover:bg-slate-400'
|
||||
: 'bg-slate-300/60 hover:bg-slate-300';
|
||||
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 (
|
||||
<button type="button"
|
||||
className={`w-full border-blue-500 elements-sidebar-row whitespace-pre
|
||||
text-left text-sm font-medium transition-all inline-flex ${container.properties.type} ${selectedClass}`}
|
||||
className={`transition-all w-full border-blue-500 hover:shadow-lg elements-sidebar-row whitespace-pre
|
||||
text-left text-sm font-medium inline-flex ${container.properties.type} ${selectedClass}`}
|
||||
id={key}
|
||||
key={key}
|
||||
style={style}
|
||||
|
@ -167,25 +163,21 @@ export function ElementsSidebar(props: IElementsSidebarProps): JSX.Element {
|
|||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fixed flex flex-col bg-slate-100 text-gray-800 transition-all h-full w-64 overflow-y-auto z-20 ${isOpenClasses}`}
|
||||
>
|
||||
<div className="bg-slate-100 font-bold sidebar-title">Elements</div>
|
||||
<div className="h-96 text-gray-800">
|
||||
<List
|
||||
className="List divide-y divide-black"
|
||||
itemCount={containers.length}
|
||||
itemSize={35}
|
||||
height={384}
|
||||
width={256}
|
||||
>
|
||||
{Row}
|
||||
</List>
|
||||
</div>
|
||||
<>
|
||||
<List
|
||||
className="List divide-y divide-black overflow-y-auto"
|
||||
itemCount={containers.length}
|
||||
itemSize={35}
|
||||
height={192}
|
||||
width={'100%'}
|
||||
>
|
||||
{Row}
|
||||
</List>
|
||||
<Properties
|
||||
properties={props.selectedContainer?.properties}
|
||||
symbols={props.symbols}
|
||||
onChange={props.onPropertyChange} />
|
||||
</div>
|
||||
onChange={props.onPropertyChange}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -1,261 +0,0 @@
|
|||
import { describe, expect, it, vi } from 'vitest';
|
||||
import * as React from 'react';
|
||||
import { fireEvent, render, screen } from '../../utils/test-utils';
|
||||
import { ElementsSidebar } from './ElementsSidebar';
|
||||
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
||||
import { PositionReference } from '../../Enums/PositionReference';
|
||||
import { FindContainerById } from '../../utils/itertools';
|
||||
import { DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default';
|
||||
import { Orientation } from '../../Enums/Orientation';
|
||||
|
||||
describe.concurrent('Elements sidebar', () => {
|
||||
it('With a MainContainer', () => {
|
||||
render(<ElementsSidebar
|
||||
symbols={new Map()}
|
||||
mainContainer={{
|
||||
children: [],
|
||||
parent: null,
|
||||
properties: DEFAULT_MAINCONTAINER_PROPS,
|
||||
userData: {}
|
||||
}}
|
||||
isOpen={true}
|
||||
isHistoryOpen={false}
|
||||
selectedContainer={undefined}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={() => {}}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect(screen.getByText(/Elements/i));
|
||||
expect(screen.queryByText('id')).toBeNull();
|
||||
expect(screen.getByText(/main/i));
|
||||
});
|
||||
|
||||
it('With a selected MainContainer', () => {
|
||||
const mainContainer: IContainerModel = {
|
||||
children: [],
|
||||
parent: null,
|
||||
properties: DEFAULT_MAINCONTAINER_PROPS,
|
||||
userData: {}
|
||||
};
|
||||
|
||||
const { container } = render(<ElementsSidebar
|
||||
symbols={new Map()}
|
||||
mainContainer={mainContainer}
|
||||
isOpen={true}
|
||||
isHistoryOpen={false}
|
||||
selectedContainer={mainContainer}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={() => {}}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect(screen.getByText(/Elements/i));
|
||||
expect(screen.getByText(/main/i));
|
||||
expect(screen.queryByText('id')).toBeDefined();
|
||||
expect(screen.queryByText('parentId')).toBeDefined();
|
||||
expect(screen.queryByText('x')).toBeDefined();
|
||||
expect(screen.queryByText('y')).toBeDefined();
|
||||
expect(screen.queryByText('width')).toBeDefined();
|
||||
expect(screen.queryByText('height')).toBeDefined();
|
||||
const propertyId = container.querySelector('#id');
|
||||
const propertyParentId = container.querySelector('#parentId');
|
||||
const propertyX = container.querySelector('#x');
|
||||
const propertyY = container.querySelector('#y');
|
||||
const propertyWidth = container.querySelector('#width');
|
||||
const propertyHeight = container.querySelector('#height');
|
||||
expect((propertyId as HTMLInputElement).value).toBe(mainContainer.properties.id.toString());
|
||||
expect(propertyParentId).toBeDefined();
|
||||
expect((propertyParentId as HTMLInputElement).value).toBe('');
|
||||
expect(propertyX).toBeDefined();
|
||||
expect((propertyX as HTMLInputElement).value).toBe(mainContainer.properties.x.toString());
|
||||
expect(propertyY).toBeDefined();
|
||||
expect((propertyY as HTMLInputElement).value).toBe(mainContainer.properties.y.toString());
|
||||
expect(propertyWidth).toBeDefined();
|
||||
expect((propertyWidth as HTMLInputElement).value).toBe(mainContainer.properties.width.toString());
|
||||
expect(propertyHeight).toBeDefined();
|
||||
expect((propertyHeight as HTMLInputElement).value).toBe(mainContainer.properties.height.toString());
|
||||
});
|
||||
|
||||
it('With multiple containers', () => {
|
||||
const children: IContainerModel[] = [];
|
||||
const mainContainer: IContainerModel = {
|
||||
children,
|
||||
parent: null,
|
||||
properties: DEFAULT_MAINCONTAINER_PROPS,
|
||||
userData: {}
|
||||
};
|
||||
|
||||
children.push(
|
||||
{
|
||||
children: [],
|
||||
parent: mainContainer,
|
||||
properties: {
|
||||
id: 'child-1',
|
||||
parentId: 'main',
|
||||
linkedSymbolId: '',
|
||||
displayedText: 'child-1',
|
||||
orientation: Orientation.Horizontal,
|
||||
x: 0,
|
||||
y: 0,
|
||||
minWidth: 1,
|
||||
minHeight: 1,
|
||||
width: 0,
|
||||
height: 0,
|
||||
margin: {},
|
||||
isFlex: false,
|
||||
maxWidth: Infinity,
|
||||
maxHeight: Infinity,
|
||||
type: 'type',
|
||||
isAnchor: false,
|
||||
warning: '',
|
||||
hideChildrenInTreeview: false,
|
||||
showChildrenDimensions: [],
|
||||
showSelfDimensions: [],
|
||||
showDimensionWithMarks: [],
|
||||
markPosition: [],
|
||||
positionReference: PositionReference.TopLeft
|
||||
},
|
||||
userData: {}
|
||||
}
|
||||
);
|
||||
|
||||
children.push(
|
||||
{
|
||||
children: [],
|
||||
parent: mainContainer,
|
||||
properties: {
|
||||
id: 'child-2',
|
||||
parentId: 'main',
|
||||
linkedSymbolId: '',
|
||||
displayedText: 'child-2',
|
||||
orientation: Orientation.Horizontal,
|
||||
x: 0,
|
||||
y: 0,
|
||||
margin: {},
|
||||
minWidth: 1,
|
||||
minHeight: 1,
|
||||
width: 0,
|
||||
height: 0,
|
||||
positionReference: PositionReference.TopLeft,
|
||||
isFlex: false,
|
||||
maxWidth: Infinity,
|
||||
maxHeight: Infinity,
|
||||
type: 'type',
|
||||
warning: '',
|
||||
hideChildrenInTreeview: false,
|
||||
showChildrenDimensions: [],
|
||||
showSelfDimensions: [],
|
||||
showDimensionWithMarks: [],
|
||||
markPosition: [],
|
||||
isAnchor: false
|
||||
},
|
||||
userData: {}
|
||||
}
|
||||
);
|
||||
|
||||
render(<ElementsSidebar
|
||||
symbols={new Map()}
|
||||
mainContainer={mainContainer}
|
||||
isOpen={true}
|
||||
isHistoryOpen={false}
|
||||
selectedContainer={mainContainer}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={() => {}}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect(screen.getByText(/Elements/i));
|
||||
expect(screen.queryByText('id')).toBeDefined();
|
||||
expect(screen.getByText(/main/i));
|
||||
expect(screen.getByText(/child-1/i));
|
||||
expect(screen.getByText(/child-2/i));
|
||||
});
|
||||
|
||||
it('With multiple containers, change selection', () => {
|
||||
const children: IContainerModel[] = [];
|
||||
const mainContainer: IContainerModel = {
|
||||
children,
|
||||
parent: null,
|
||||
properties: DEFAULT_MAINCONTAINER_PROPS,
|
||||
userData: {}
|
||||
};
|
||||
|
||||
const child1Model: IContainerModel = {
|
||||
children: [],
|
||||
parent: mainContainer,
|
||||
properties: {
|
||||
id: 'child-1',
|
||||
parentId: 'main',
|
||||
linkedSymbolId: '',
|
||||
displayedText: 'child-1',
|
||||
orientation: Orientation.Horizontal,
|
||||
x: 0,
|
||||
y: 0,
|
||||
minWidth: 1,
|
||||
minHeight: 1,
|
||||
width: 0,
|
||||
height: 0,
|
||||
warning: '',
|
||||
positionReference: PositionReference.TopLeft,
|
||||
margin: {},
|
||||
isFlex: false,
|
||||
maxWidth: Infinity,
|
||||
maxHeight: Infinity,
|
||||
type: 'type',
|
||||
hideChildrenInTreeview: false,
|
||||
showChildrenDimensions: [],
|
||||
showSelfDimensions: [],
|
||||
showDimensionWithMarks: [],
|
||||
markPosition: [],
|
||||
isAnchor: false
|
||||
},
|
||||
userData: {}
|
||||
};
|
||||
children.push(child1Model);
|
||||
|
||||
let selectedContainer: IContainerModel | undefined = mainContainer;
|
||||
const selectContainer = vi.fn((containerId: string) => {
|
||||
selectedContainer = FindContainerById(mainContainer, containerId);
|
||||
});
|
||||
|
||||
const { container, rerender } = render(<ElementsSidebar
|
||||
symbols={new Map()}
|
||||
mainContainer={mainContainer}
|
||||
isOpen={true}
|
||||
isHistoryOpen={false}
|
||||
selectedContainer={selectedContainer}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={selectContainer}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect(screen.getByText(/Elements/i));
|
||||
expect(screen.queryByText('id')).toBeDefined();
|
||||
expect(screen.getByText(/main/i));
|
||||
const child1 = screen.getByText(/child-1/i);
|
||||
expect(child1);
|
||||
const propertyId = container.querySelector('#id');
|
||||
const propertyParentId = container.querySelector('#parentId');
|
||||
expect((propertyId as HTMLInputElement).value).toBe(mainContainer.properties.id.toString());
|
||||
expect((propertyParentId as HTMLInputElement).value).toBe('');
|
||||
|
||||
fireEvent.click(child1);
|
||||
|
||||
rerender(<ElementsSidebar
|
||||
symbols={new Map()}
|
||||
mainContainer={mainContainer}
|
||||
isOpen={true}
|
||||
isHistoryOpen={false}
|
||||
selectedContainer={selectedContainer}
|
||||
onPropertyChange={() => {}}
|
||||
selectContainer={selectContainer}
|
||||
addContainer={() => {}}
|
||||
/>);
|
||||
|
||||
expect((propertyId as HTMLInputElement).value === 'main').toBeFalsy();
|
||||
expect((propertyParentId as HTMLInputElement).value === '').toBeFalsy();
|
||||
expect((propertyId as HTMLInputElement).value).toBe(child1Model.properties.id.toString());
|
||||
expect((propertyParentId as HTMLInputElement).value).toBe(child1Model.properties.parentId?.toString());
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue