Improve dynamic sizes in ConstituentaEdit

This commit is contained in:
IRBorisov 2023-08-13 13:18:50 +03:00
parent 27f515f5d3
commit e9eed37aee
5 changed files with 129 additions and 101 deletions

View File

@ -1,9 +1,18 @@
import { ThreeDots } from 'react-loader-spinner'; import { ThreeDots } from 'react-loader-spinner';
export function Loader() { interface LoaderProps {
size?: number
}
export function Loader({size=10}: LoaderProps) {
return ( return (
<div className='flex justify-center w-full h-full'> <div className='flex justify-center w-full h-full'>
<ThreeDots color='rgb(96 165 250)' height='100' width='100' radius='10' /> <ThreeDots
color='rgb(96 165 250)'
height={size*10}
width={size*10}
radius={size}
/>
</div> </div>
); );
} }

View File

@ -13,6 +13,9 @@ import { getCstTypeLabel, getCstTypificationLabel, mapStatusInfo } from '../../u
import EditorRSExpression from './EditorRSExpression'; import EditorRSExpression from './EditorRSExpression';
import ViewSideConstituents from './elements/ViewSideConstituents'; import ViewSideConstituents from './elements/ViewSideConstituents';
// Max height of content for left enditor pane
const UNFOLDED_HEIGHT = '59.1rem';
interface EditorConstituentaProps { interface EditorConstituentaProps {
activeID?: number activeID?: number
onOpenEdit: (cstID: number) => void onOpenEdit: (cstID: number) => void
@ -109,8 +112,8 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onOpenEdit, onDe
} }
return ( return (
<div className='flex items-stretch w-full gap-2 mb-2'> <div className='flex items-stretch w-full gap-2 mb-2 justify-stretch'>
<form onSubmit={handleSubmit} className='flex-grow min-w-[50rem] max-w-min max-h-fit px-4 py-2 border'> <form onSubmit={handleSubmit} className='min-w-[50rem] max-w-min px-4 py-2 border'>
<div className='flex items-start justify-between'> <div className='flex items-start justify-between'>
<button type='submit' <button type='submit'
title='Сохранить изменения' title='Сохранить изменения'
@ -238,11 +241,14 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onOpenEdit, onDe
/> />
</div> </div>
</form> </form>
<ViewSideConstituents <div className='self-stretch border w-full pb-1'>
expression={expression} <ViewSideConstituents
activeID={activeID} expression={expression}
onOpenEdit={onOpenEdit} baseHeight={UNFOLDED_HEIGHT}
/> activeID={activeID}
onOpenEdit={onOpenEdit}
/>
</div>
</div> </div>
); );
} }

View File

@ -247,9 +247,9 @@ function EditorRSExpression({
</div> </div>
{isActive && !disabled && EditButtons} {isActive && !disabled && EditButtons}
</div> </div>
{ (loading || parseData) && { (isActive || loading || parseData) &&
<div className='w-full overflow-y-auto border mt-2 max-h-[14rem] min-h-[7rem]'> <div className='w-full overflow-y-auto border mt-2 max-h-[14rem] min-h-[4.2rem]'>
{ loading && <Loader />} { loading && <Loader size={6} />}
{ !loading && parseData && { !loading && parseData &&
<ParsingResult <ParsingResult
data={parseData} data={parseData}

View File

@ -33,9 +33,8 @@ function ParsingResult({ data, onShowAST, onShowError }: ParsingResultProps) {
title='отобразить дерево разбора' title='отобразить дерево разбора'
onClick={handleShowAST} onClick={handleShowAST}
> >
Дерево разбора: Дерево разбора
</button> </button>
<span> {data.astText}</span>
</p>} </p>}
</div> </div>
) )

View File

@ -11,14 +11,18 @@ import ConstituentaTooltip from './ConstituentaTooltip';
import DependencyModePicker from './DependencyModePicker'; import DependencyModePicker from './DependencyModePicker';
import MatchModePicker from './MatchModePicker'; import MatchModePicker from './MatchModePicker';
// Height that should be left to accomodate navigation panel + bottom margin
const LOCAL_NAVIGATION_H = '2.6rem';
interface ViewSideConstituentsProps { interface ViewSideConstituentsProps {
expression: string expression: string
baseHeight: string
activeID?: number activeID?: number
onOpenEdit: (cstID: number) => void onOpenEdit: (cstID: number) => void
} }
function ViewSideConstituents({ expression, activeID, onOpenEdit }: ViewSideConstituentsProps) { function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }: ViewSideConstituentsProps) {
const { darkMode } = useConceptTheme(); const { darkMode, noNavigation } = useConceptTheme();
const { schema } = useRSForm(); const { schema } = useRSForm();
const [filterMatch, setFilterMatch] = useLocalStorage('side-filter-match', CstMatchMode.ALL); const [filterMatch, setFilterMatch] = useLocalStorage('side-filter-match', CstMatchMode.ALL);
@ -27,7 +31,8 @@ function ViewSideConstituents({ expression, activeID, onOpenEdit }: ViewSideCons
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []); const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
useEffect(() => { useEffect(
() => {
if (!schema?.items) { if (!schema?.items) {
setFilteredData([]); setFilteredData([]);
return; return;
@ -67,8 +72,8 @@ function ViewSideConstituents({ expression, activeID, onOpenEdit }: ViewSideCons
} }
}, [onOpenEdit]); }, [onOpenEdit]);
const conditionalRowStyles = useMemo(() => const conditionalRowStyles = useMemo(
[ () => [
{ {
when: (cst: IConstituenta) => cst.id === activeID, when: (cst: IConstituenta) => cst.id === activeID,
style: { style: {
@ -77,92 +82,101 @@ function ViewSideConstituents({ expression, activeID, onOpenEdit }: ViewSideCons
} }
], [activeID, darkMode]); ], [activeID, darkMode]);
const columns = useMemo(() => const columns = useMemo(
[ () => [
{ {
id: 'id', id: 'id',
selector: (cst: IConstituenta) => cst.id, selector: (cst: IConstituenta) => cst.id,
omit: true omit: true
},
{
name: 'ID',
id: 'alias',
cell: (cst: IConstituenta) => {
const info = mapStatusInfo.get(cst.status)!;
return (<>
<div
id={`${prefixes.cst_list}${cst.alias}`}
className={`w-full rounded-md text-center ${info.color}`}
>
{cst.alias}
</div>
<ConstituentaTooltip data={cst} anchor={`#${prefixes.cst_list}${cst.alias}`} />
</>);
}, },
{ width: '65px',
name: 'ID', maxWidth: '65px',
id: 'alias', conditionalCellStyles: [
cell: (cst: IConstituenta) => { {
const info = mapStatusInfo.get(cst.status)!; when: (cst: IConstituenta) => cst.id <= 0,
return (<> classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
<div }
id={`${prefixes.cst_list}${cst.alias}`} ]
className={`w-full rounded-md text-center ${info.color}`} },
> {
{cst.alias} name: 'Описание',
</div> id: 'description',
<ConstituentaTooltip data={cst} anchor={`#${prefixes.cst_list}${cst.alias}`} /> selector: (cst: IConstituenta) => getCstDescription(cst),
</>); minWidth: '350px',
}, wrap: true,
width: '65px', conditionalCellStyles: [
maxWidth: '65px', {
conditionalCellStyles: [ when: (cst: IConstituenta) => cst.id <= 0,
{ classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
when: (cst: IConstituenta) => cst.id <= 0, }
classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]'] ]
} },
] {
}, name: 'Выражение',
{ id: 'expression',
name: 'Описание', selector: (cst: IConstituenta) => cst.definition?.formal ?? '',
id: 'description', minWidth: '200px',
selector: (cst: IConstituenta) => getCstDescription(cst), hide: 1600,
minWidth: '350px', grow: 2,
wrap: true, wrap: true,
conditionalCellStyles: [ conditionalCellStyles: [
{ {
when: (cst: IConstituenta) => cst.id <= 0, when: (cst: IConstituenta) => cst.id <= 0,
classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]'] classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
} }
] ]
}, }
{ ], []);
name: 'Выражение',
id: 'expression',
selector: (cst: IConstituenta) => cst.definition?.formal ?? '',
minWidth: '200px',
hide: 1600,
grow: 2,
wrap: true,
conditionalCellStyles: [
{
when: (cst: IConstituenta) => cst.id <= 0,
classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
}
]
}
], []
);
return ( const maxHeight = useMemo(
<div className='max-h-[calc(100vh-10.3rem)] min-h-[40rem] overflow-y-scroll border flex-grow w-full'> () => {
<div className='sticky top-0 left-0 right-0 z-10 flex items-center justify-between w-full gap-1 px-2 py-1 bg-white border-b rounded clr-bg-pop clr-border'> const siblingHeight = `${baseHeight} - ${LOCAL_NAVIGATION_H}`
<div className='flex items-center justify-between w-full'> return (noNavigation ?
<MatchModePicker value={filterMatch} onChange={setFilterMatch}/> `calc(min(100vh - 5.2rem, ${siblingHeight}))`
<input type='text' : `calc(min(100vh - 8.7rem, ${siblingHeight}))`);
className='w-full px-2 bg-white outline-none hover:text-clip clr-bg-pop clr-border' }, [noNavigation, baseHeight]);
placeholder='наберите текст фильтра'
value={filterText} return (<>
onChange={event => { setFilterText(event.target.value); }} <div className='px-2 py-1 sticky top-0 left-0 right-0 z-10 gap-1 flex items-center justify-between w-full bg-white border-b rounded clr-bg-pop clr-border'>
/> <MatchModePicker
<DependencyModePicker value={filterSource} onChange={setFilterSource}/> value={filterMatch}
</div> onChange={setFilterMatch}
</div> />
<input type='text'
className='w-full px-2 bg-white outline-none hover:text-clip clr-bg-pop clr-border'
placeholder='наберите текст фильтра'
value={filterText}
onChange={event => setFilterText(event.target.value)}
/>
<DependencyModePicker value={filterSource} onChange={setFilterSource}/>
</div>
<div className='overflow-y-auto' style={{maxHeight : `${maxHeight}`}}>
<ConceptDataTable <ConceptDataTable
data={filteredData} data={filteredData}
columns={columns} columns={columns}
conditionalRowStyles={conditionalRowStyles}
keyField='id' keyField='id'
noContextMenu conditionalRowStyles={conditionalRowStyles}
noDataComponent={<span className='flex flex-col justify-center p-2 text-center'> noDataComponent={
<p>Список конституент пуст</p> <span className='flex flex-col justify-center p-2 text-center min-h-[5rem]'>
<p>Измените параметры фильтра</p> <p>Список конституент пуст</p>
</span>} <p>Измените параметры фильтра</p>
</span>
}
striped striped
highlightOnHover highlightOnHover
@ -173,7 +187,7 @@ function ViewSideConstituents({ expression, activeID, onOpenEdit }: ViewSideCons
dense dense
/> />
</div> </div>
); </>);
} }
export default ViewSideConstituents; export default ViewSideConstituents;