Implement Category list

This commit is contained in:
Eric NGUYEN 2022-09-16 16:23:17 +02:00
parent 9f24d2d40a
commit 0476a294d6
7 changed files with 61 additions and 51 deletions

View file

@ -1,58 +1,38 @@
import { ChevronRightIcon } from '@heroicons/react/outline'; import { ChevronRightIcon } from '@heroicons/react/outline';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { ICategory } from '../../Interfaces/ICategory';
import { TruncateString } from '../../utils/stringtools'; import { TruncateString } from '../../utils/stringtools';
interface ICategoryProps { interface ICategoryProps {
children: JSX.Element | JSX.Element[] children: JSX.Element | JSX.Element[]
category: string category: ICategory
} }
export function Category(props: ICategoryProps): JSX.Element { export function Category(props: ICategoryProps): JSX.Element {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
if (isOpen) { const categoryType: string = props.category.Type;
return ( const categoryDisplayedText: string = props.category.DisplayedText ?? categoryType;
<div
className='overflow-hidden h-full transition-all text-center cursor-pointer'
key={props.category}
id={props.category}
title={props.category}
>
<div
className='flex flex-row group full'
onClick={() => setIsOpen(!isOpen)}
>
<span className={'transition-all flex-1 h-full justify-center sidebar-component-left rounded-b-none bg-slate-400/80 group-hover:bg-blue-600'}>
{TruncateString(props.category, 25)}
</span>
<span className={'flex-none h-full justify-center sidebar-component-right rounded-b-none'}>
<ChevronRightIcon className='transition-all w-5 rotate-90' />
</span>
</div>
<div className='transition-all grid gap-2 p-2 bg-slate-400/80 overflow-auto rounded-b-lg visible'>
{ props.children }
</div>
</div>
);
}
return ( return (
<div <div
className='overflow-visible h-16 group transition-all text-center cursor-pointer' className={` transition-all text-center ${isOpen ? 'overflow-hidden h-full' : 'overflow-visible h-16'}`}
key={props.category} key={categoryType}
id={props.category} id={categoryType}
title={props.category} title={categoryDisplayedText}
onClick={() => setIsOpen(!isOpen)}
> >
<div className='flex flex-row h-full'> <div
<span className='flex-1 h-full justify-center sidebar-component-left'> className='flex flex-row group cursor-pointer h-16'
{TruncateString(props.category, 25)} onClick={() => setIsOpen(!isOpen)}
>
<span className={`transition-all flex-1 h-full justify-center sidebar-component-left ${isOpen ? 'rounded-b-none bg-slate-400/80 group-hover:bg-blue-600' : ''}`}>
{TruncateString(categoryDisplayedText, 25)}
</span> </span>
<span className='flex-none h-full justify-center sidebar-component-right'> <span className={`flex-none h-full justify-center sidebar-component-right ${isOpen ? 'rounded-b-none' : ''}`}>
<ChevronRightIcon className='transition-all w-5' /> <ChevronRightIcon className={`transition-all w-5 ${isOpen ? 'rotate-90' : ''}`} />
</span> </span>
</div> </div>
<div className='transition-all overflow-hidden rounded-b-lg hidden'> <div className={`transition-all grid gap-2 p-2 rounded-b-lg ${isOpen ? 'visible overflow-auto bg-slate-400/80' : 'hidden overflow-hidden'}`}>
{ props.children } { props.children }
</div> </div>
</div> </div>

View file

@ -210,6 +210,7 @@ export function Editor(props: IEditorProps): JSX.Element {
historyCurrentStep={historyCurrentStep} historyCurrentStep={historyCurrentStep}
availableContainers={configuration.AvailableContainers} availableContainers={configuration.AvailableContainers}
availableSymbols={configuration.AvailableSymbols} availableSymbols={configuration.AvailableSymbols}
categories={configuration.Categories}
selectContainer={(container) => setNewHistory( selectContainer={(container) => setNewHistory(
SelectContainer( SelectContainer(
container, container,

View file

@ -1,10 +1,12 @@
import * as React from 'react'; import * as React from 'react';
import { IAvailableContainer } from '../../Interfaces/IAvailableContainer'; import { IAvailableContainer } from '../../Interfaces/IAvailableContainer';
import { ICategory } from '../../Interfaces/ICategory';
import { TruncateString } from '../../utils/stringtools'; import { TruncateString } from '../../utils/stringtools';
import { Category } from '../Category/Category'; import { Category } from '../Category/Category';
interface ISidebarProps { interface ISidebarProps {
componentOptions: IAvailableContainer[] componentOptions: IAvailableContainer[]
categories: ICategory[]
isOpen: boolean isOpen: boolean
buttonOnClick: (type: string) => void buttonOnClick: (type: string) => void
} }
@ -15,7 +17,12 @@ function HandleDragStart(event: React.DragEvent<HTMLButtonElement>): void {
export function Sidebar(props: ISidebarProps): JSX.Element { export function Sidebar(props: ISidebarProps): JSX.Element {
const rootElements: Array<JSX.Element | undefined> = []; const rootElements: Array<JSX.Element | undefined> = [];
const categories = new Map<string, JSX.Element[]>(); const categories = new Map<string, ICategory>();
const categoriesElements = new Map<string, JSX.Element[]>(props.categories.map(category => {
categories.set(category.Type, category);
return [category.Type, []];
}));
// build the components // build the components
props.componentOptions.forEach(componentOption => { props.componentOptions.forEach(componentOption => {
if (componentOption.IsHidden === true) { if (componentOption.IsHidden === true) {
@ -39,25 +46,27 @@ export function Sidebar(props: ISidebarProps): JSX.Element {
return; return;
} }
if (categories.get(componentOption.Category) === undefined) { const category = categoriesElements.get(componentOption.Category);
categories.set(componentOption.Category, []);
}
const category = categories.get(componentOption.Category);
if (category === undefined) { if (category === undefined) {
// should never go here console.error(`[Category] Category does not exists in configuration.Categories: ${componentOption.Category}`);
return; return;
} }
category.push(componentButton); category.push(componentButton);
}); });
// build the categories // build the categories
categories.forEach((options, category) => { categoriesElements.forEach((options, categoryName) => {
const category = categories.get(categoryName);
if (category === undefined) {
// should never go here
console.error(`[Category] Category does not exists in configuration.Categories: ${categoryName}`);
return;
}
rootElements.unshift( rootElements.unshift(
<Category <Category
key={category} key={categoryName}
category={category} category={category}
> >
{ options } { options }

View file

@ -13,6 +13,7 @@ import { Symbols } from '../Symbols/Symbols';
import { SymbolsSidebar } from '../SymbolsSidebar/SymbolsSidebar'; import { SymbolsSidebar } from '../SymbolsSidebar/SymbolsSidebar';
import { PropertyType } from '../../Enums/PropertyType'; import { PropertyType } from '../../Enums/PropertyType';
import { MessagesSidebar } from '../MessagesSidebar/MessagesSidebar'; import { MessagesSidebar } from '../MessagesSidebar/MessagesSidebar';
import { ICategory } from '../../Interfaces/ICategory';
interface IUIProps { interface IUIProps {
selectedContainer: IContainerModel | undefined selectedContainer: IContainerModel | undefined
@ -21,6 +22,7 @@ interface IUIProps {
historyCurrentStep: number historyCurrentStep: number
availableContainers: IAvailableContainer[] availableContainers: IAvailableContainer[]
availableSymbols: IAvailableSymbol[] availableSymbols: IAvailableSymbol[]
categories: ICategory[]
selectContainer: (containerId: string) => void selectContainer: (containerId: string) => void
deleteContainer: (containerId: string) => void deleteContainer: (containerId: string) => void
onPropertyChange: (key: string, value: string | number | boolean, type?: PropertyType) => void onPropertyChange: (key: string, value: string | number | boolean, type?: PropertyType) => void
@ -83,6 +85,7 @@ export function UI(props: IUIProps): JSX.Element {
<Sidebar <Sidebar
componentOptions={props.availableContainers} componentOptions={props.availableContainers}
categories={props.categories}
isOpen={isSidebarOpen} isOpen={isSidebarOpen}
buttonOnClick={props.addContainer} /> buttonOnClick={props.addContainer} />
<Symbols <Symbols

View file

@ -0,0 +1,5 @@
/* eslint-disable @typescript-eslint/naming-convention */
export interface ICategory {
Type: string
DisplayedText?: string
}

View file

@ -1,12 +1,14 @@
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
import { IAvailableContainer } from './IAvailableContainer'; import { IAvailableContainer } from './IAvailableContainer';
import { IAvailableSymbol } from './IAvailableSymbol'; import { IAvailableSymbol } from './IAvailableSymbol';
import { ICategory } from './ICategory';
import { IPattern } from './IPattern'; import { IPattern } from './IPattern';
/** Model of configuration for the application to configure it */ /** Model of configuration for the application to configure it */
export interface IConfiguration { export interface IConfiguration {
AvailableContainers: IAvailableContainer[] // TODO: Use a Map<string, IAvailableContainer> AvailableContainers: IAvailableContainer[] // TODO: Use a Map<string, IAvailableContainer>
AvailableSymbols: IAvailableSymbol[] // TODO: Use a Map<string, IAvailableContainer> AvailableSymbols: IAvailableSymbol[] // TODO: Use a Map<string, IAvailableContainer>
Categories: ICategory[]
Patterns: IPattern[] Patterns: IPattern[]
MainContainer: IAvailableContainer MainContainer: IAvailableContainer
} }

View file

@ -77,7 +77,7 @@ const GetSVGLayoutConfiguration = () => {
}, },
ShowSelfDimensions: true, ShowSelfDimensions: true,
IsDimensionBorrower: true, IsDimensionBorrower: true,
Category: "Category" Category: "Stuff"
}, },
{ {
Type: 'Trou', Type: 'Trou',
@ -96,11 +96,11 @@ const GetSVGLayoutConfiguration = () => {
stroke: 'green', stroke: 'green',
fill: 'white' fill: 'white'
}, },
Category: "Category" Category: "Stuff"
}, },
{ {
Type: 'Remplissage', Type: 'Remplissage',
Category: "Category2", Category: "Other stuff",
CustomSVG: ` CustomSVG: `
<rect width="{width}" height="{height}" style="{style}"></rect> <rect width="{width}" height="{height}" style="{style}"></rect>
<rect width="{width}" height="{height}" stroke="black" fill-opacity="0"></rect> <rect width="{width}" height="{height}" stroke="black" fill-opacity="0"></rect>
@ -204,6 +204,16 @@ const GetSVGLayoutConfiguration = () => {
XPositionReference: 0 XPositionReference: 0
} }
], ],
Categories: [
{
Type: "Stuff",
DisplayedText: "Stuff made here"
},
{
Type: "Other stuff",
DisplayedText: "Stuff not made here"
}
],
MainContainer: { MainContainer: {
Height: 200, Height: 200,
Width: 800 Width: 800