Implémenter l'orientation verticale Modifier l'effet de append Implementer RigidBody Implementer Flex et simplex Implémenter Push Implémenter Swap Implement MinMaxHeight without behaviors Fix Margin for Height Implement PositionReference Fix dimension vertical position inside children Add orientation change in form Implement sortChildren Implement Anchor Fix warning message on overlapping Fix minimap when root container is vertical #7287 #7288 #7289 #7290 #7291 #7292 #7294 #7295 #7296 #7297 #7298 #7299 #7300 #7301 #7302
122 lines
3.9 KiB
TypeScript
122 lines
3.9 KiB
TypeScript
import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline';
|
|
import * as React from 'react';
|
|
import { IAvailableContainer } from '../../Interfaces/IAvailableContainer';
|
|
import { ICategory } from '../../Interfaces/ICategory';
|
|
import { IContainerModel } from '../../Interfaces/IContainerModel';
|
|
import { TruncateString } from '../../utils/stringtools';
|
|
import { Category } from '../Category/Category';
|
|
|
|
interface ISidebarProps {
|
|
selectedContainer: IContainerModel | undefined
|
|
componentOptions: IAvailableContainer[]
|
|
categories: ICategory[]
|
|
isOpen: boolean
|
|
buttonOnClick: (type: string) => void
|
|
}
|
|
|
|
function HandleDragStart(event: React.DragEvent<HTMLButtonElement>): void {
|
|
event.dataTransfer.setData('type', (event.target as HTMLButtonElement).id);
|
|
}
|
|
|
|
interface SidebarCategory {
|
|
category: ICategory
|
|
children: JSX.Element[]
|
|
}
|
|
|
|
export function Sidebar(props: ISidebarProps): JSX.Element {
|
|
const [hideDisabled, setHideDisabled] = React.useState<boolean>(false);
|
|
|
|
const rootElements: Array<JSX.Element | undefined> = [];
|
|
const categories = new Map<string, SidebarCategory>(props.categories.map(category => [
|
|
category.Type,
|
|
{
|
|
category,
|
|
children: []
|
|
}
|
|
]));
|
|
|
|
// build the categories (sorted with categories first)
|
|
categories.forEach((categoryWrapper, categoryName) => {
|
|
rootElements.push(
|
|
<Category
|
|
key={categoryName}
|
|
category={categoryWrapper.category}
|
|
>
|
|
{ categoryWrapper.children }
|
|
</Category>);
|
|
});
|
|
|
|
const selectedContainer = props.selectedContainer;
|
|
const config = props.componentOptions.find(option => option.Type === selectedContainer?.properties.type);
|
|
// build the components
|
|
props.componentOptions.forEach(componentOption => {
|
|
if (componentOption.IsHidden === true) {
|
|
return;
|
|
}
|
|
|
|
let disabled = false;
|
|
if (config?.Whitelist !== undefined) {
|
|
disabled = config.Whitelist?.find(type => type === componentOption.Type) === undefined;
|
|
} else if (config?.Blacklist !== undefined) {
|
|
disabled = config.Blacklist?.find(type => type === componentOption.Type) !== undefined ?? false;
|
|
}
|
|
|
|
if (disabled && hideDisabled) {
|
|
return;
|
|
}
|
|
|
|
const componentButton = (<button
|
|
key={componentOption.Type}
|
|
type="button"
|
|
className='w-full justify-center h-16 transition-all sidebar-component'
|
|
id={componentOption.Type}
|
|
title={componentOption.Type}
|
|
onClick={() => props.buttonOnClick(componentOption.Type)}
|
|
draggable={true}
|
|
onDragStart={(event) => HandleDragStart(event)}
|
|
disabled={disabled}
|
|
>
|
|
{TruncateString(componentOption.DisplayedText ?? componentOption.Type, 25)}
|
|
</button>);
|
|
|
|
if (componentOption.Category === null || componentOption.Category === undefined) {
|
|
rootElements.push(componentButton);
|
|
return;
|
|
}
|
|
|
|
const category = categories.get(componentOption.Category);
|
|
if (category === undefined) {
|
|
console.error(`[Category] Category does not exists in configuration.Categories: ${componentOption.Category}`);
|
|
return;
|
|
}
|
|
|
|
category.children.push(componentButton);
|
|
});
|
|
|
|
const isOpenClasses = props.isOpen ? 'left-16' : '-left-64';
|
|
return (
|
|
<div className={`fixed z-10 bg-slate-200
|
|
text-gray-700 transition-all h-full w-64
|
|
overflow-y-auto ${isOpenClasses}`}>
|
|
<div className='bg-slate-100 sidebar-title flex place-content-between'>
|
|
Components
|
|
<button
|
|
onClick={() => { setHideDisabled(!hideDisabled); }}
|
|
className='h-6'
|
|
aria-label='Hide disabled component'
|
|
title='Hide disabled component'
|
|
>
|
|
{
|
|
hideDisabled
|
|
? <EyeSlashIcon className='heroicon' />
|
|
: <EyeIcon className='heroicon' />
|
|
}
|
|
</button>
|
|
</div>
|
|
<div className='transition-all grid grid-cols-1 md:grid-cols-1 gap-2
|
|
m-2 md:text-xs font-bold'>
|
|
{rootElements}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|