From 99f9bdb856a098a6fda89e0afef4e5954aca8815 Mon Sep 17 00:00:00 2001 From: IRBorisov <8611739+IRBorisov@users.noreply.github.com> Date: Mon, 1 Apr 2024 11:13:50 +0300 Subject: [PATCH] UI improvements --- .../src/components/info/InfoConstituenta.tsx | 6 +- .../src/components/info/InfoCstClass.tsx | 2 +- .../src/components/info/InfoCstStatus.tsx | 2 +- .../src/components/wrap/AnimateFade.tsx | 19 +- .../src/components/wrap/DataLoader.tsx | 18 +- rsconcept/frontend/src/models/rsformAPI.ts | 55 +++++- .../EditorConstituenta/FormConstituenta.tsx | 180 +++++++++++------- .../EditorRSExpression/RSEditControls.tsx | 2 +- rsconcept/frontend/src/pages/RegisterPage.tsx | 6 +- rsconcept/frontend/src/styling/animations.ts | 22 ++- rsconcept/frontend/src/utils/codemirror.ts | 5 +- rsconcept/frontend/src/utils/labels.ts | 2 + 12 files changed, 222 insertions(+), 97 deletions(-) diff --git a/rsconcept/frontend/src/components/info/InfoConstituenta.tsx b/rsconcept/frontend/src/components/info/InfoConstituenta.tsx index cbcd3183..51615be9 100644 --- a/rsconcept/frontend/src/components/info/InfoConstituenta.tsx +++ b/rsconcept/frontend/src/components/info/InfoConstituenta.tsx @@ -1,3 +1,5 @@ +import clsx from 'clsx'; + import { IConstituenta } from '@/models/rsform'; import { labelCstTypification } from '@/utils/labels'; @@ -7,9 +9,9 @@ interface InfoConstituentaProps extends CProps.Div { data: IConstituenta; } -function InfoConstituenta({ data, ...restProps }: InfoConstituentaProps) { +function InfoConstituenta({ data, className, ...restProps }: InfoConstituentaProps) { return ( -
+

Конституента {data.alias}

Типизация: diff --git a/rsconcept/frontend/src/components/info/InfoCstClass.tsx b/rsconcept/frontend/src/components/info/InfoCstClass.tsx index 94fce698..f1f5a686 100644 --- a/rsconcept/frontend/src/components/info/InfoCstClass.tsx +++ b/rsconcept/frontend/src/components/info/InfoCstClass.tsx @@ -14,7 +14,7 @@ function InfoCstClass({ header }: InfoCstClassProps) { const { colors } = useConceptTheme(); return ( -

+
{header ?

{header}

: null} {Object.values(CstClass).map((cstClass, index) => { return ( diff --git a/rsconcept/frontend/src/components/info/InfoCstStatus.tsx b/rsconcept/frontend/src/components/info/InfoCstStatus.tsx index 9fd9872a..dda547c6 100644 --- a/rsconcept/frontend/src/components/info/InfoCstStatus.tsx +++ b/rsconcept/frontend/src/components/info/InfoCstStatus.tsx @@ -14,7 +14,7 @@ function InfoCstStatus({ title }: InfoCstStatusProps) { const { colors } = useConceptTheme(); return ( -
+
{title ?

{title}

: null} {Object.values(ExpressionStatus) .filter(status => status !== ExpressionStatus.UNDEFINED) diff --git a/rsconcept/frontend/src/components/wrap/AnimateFade.tsx b/rsconcept/frontend/src/components/wrap/AnimateFade.tsx index 2861a456..f30b4dd9 100644 --- a/rsconcept/frontend/src/components/wrap/AnimateFade.tsx +++ b/rsconcept/frontend/src/components/wrap/AnimateFade.tsx @@ -7,14 +7,29 @@ import { CProps } from '../props'; interface AnimateFadeProps extends CProps.AnimatedDiv { noFadeIn?: boolean; noFadeOut?: boolean; + removeContent?: boolean; + hideContent?: boolean; } -function AnimateFade({ noFadeIn, noFadeOut, children, ...restProps }: AnimateFadeProps) { +function AnimateFade({ + style, + noFadeIn, + noFadeOut, + children, + removeContent, + hideContent, + ...restProps +}: AnimateFadeProps) { + if (removeContent) { + return null; + } return ( {children} diff --git a/rsconcept/frontend/src/components/wrap/DataLoader.tsx b/rsconcept/frontend/src/components/wrap/DataLoader.tsx index 0b01adbc..f48ceca6 100644 --- a/rsconcept/frontend/src/components/wrap/DataLoader.tsx +++ b/rsconcept/frontend/src/components/wrap/DataLoader.tsx @@ -1,9 +1,9 @@ import { AnimatePresence } from 'framer-motion'; -import AnimateFade from './AnimateFade'; import InfoError, { ErrorData } from '../info/InfoError'; import { CProps } from '../props'; import Loader from '../ui/Loader'; +import AnimateFade from './AnimateFade'; interface DataLoaderProps extends CProps.AnimatedDiv { id: string; @@ -20,16 +20,12 @@ function DataLoader({ id, isLoading, hasNoData, error, children, ...restProps }: {isLoading ? : null} {error ? : null} - {!isLoading && !error && !hasNoData ? ( - - {children} - - ) : null} - {!isLoading && !error && hasNoData ? ( - - Данные не загружены - - ) : null} + + {children} + + + Данные не загружены + ); } diff --git a/rsconcept/frontend/src/models/rsformAPI.ts b/rsconcept/frontend/src/models/rsformAPI.ts index ad3e4c8d..5bd14f20 100644 --- a/rsconcept/frontend/src/models/rsformAPI.ts +++ b/rsconcept/frontend/src/models/rsformAPI.ts @@ -239,7 +239,7 @@ export function applyFilterCategory(start: IConstituenta, schema: IRSFormData): /** * Prefix for alias indicating {@link CstType}. */ -export function getCstTypePrefix(type: CstType) { +export function getCstTypePrefix(type: CstType): string { // prettier-ignore switch (type) { case CstType.BASE: return 'X'; @@ -256,7 +256,7 @@ export function getCstTypePrefix(type: CstType) { /** * Guess {@link CstType} from user input hint. */ -export function guessCstType(hint: string, defaultType: CstType = CstType.TERM) { +export function guessCstType(hint: string, defaultType: CstType = CstType.TERM): CstType { if (hint.length !== 1) { return defaultType; } @@ -274,6 +274,57 @@ export function guessCstType(hint: string, defaultType: CstType = CstType.TERM) return defaultType; } +/** + * Evaluate if {@link CstType} is basic concept. + */ +export function isBasicConcept(type: CstType): boolean { + // prettier-ignore + switch (type) { + case CstType.BASE: return true; + case CstType.CONSTANT: return true; + case CstType.STRUCTURED: return true; + case CstType.AXIOM: return true; + case CstType.TERM: return false; + case CstType.FUNCTION: return false; + case CstType.PREDICATE: return false; + case CstType.THEOREM: return false; + } +} + +/** + * Evaluate if {@link CstType} is base set or constant set. + */ +export function isBaseSet(type: CstType): boolean { + // prettier-ignore + switch (type) { + case CstType.BASE: return true; + case CstType.CONSTANT: return true; + case CstType.STRUCTURED: return false; + case CstType.AXIOM: return false; + case CstType.TERM: return false; + case CstType.FUNCTION: return false; + case CstType.PREDICATE: return false; + case CstType.THEOREM: return false; + } +} + +/** + * Evaluate if {@link CstType} is function. + */ +export function isFunctional(type: CstType): boolean { + // prettier-ignore + switch (type) { + case CstType.BASE: return false; + case CstType.CONSTANT: return false; + case CstType.STRUCTURED: return false; + case CstType.AXIOM: return false; + case CstType.TERM: return false; + case CstType.FUNCTION: return true; + case CstType.PREDICATE: return true; + case CstType.THEOREM: return false; + } +} + /** * Validate new alias against {@link CstType} and {@link IRSForm}. */ diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx index d6ec1fff..4ee6fcfc 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx @@ -1,15 +1,18 @@ 'use client'; import clsx from 'clsx'; -import { useEffect, useLayoutEffect, useState } from 'react'; +import { AnimatePresence } from 'framer-motion'; +import { useEffect, useLayoutEffect, useMemo, useState } from 'react'; import { FiSave } from 'react-icons/fi'; import { toast } from 'react-toastify'; import RefsInput from '@/components/RefsInput'; import SubmitButton from '@/components/ui/SubmitButton'; import TextArea from '@/components/ui/TextArea'; +import AnimateFade from '@/components/wrap/AnimateFade'; import { useRSForm } from '@/context/RSFormContext'; -import { IConstituenta, ICstUpdateData } from '@/models/rsform'; +import { CstType, IConstituenta, ICstUpdateData } from '@/models/rsform'; +import { isBaseSet, isBasicConcept, isFunctional } from '@/models/rsformAPI'; import { labelCstTypification } from '@/utils/labels'; import EditorRSExpression from '../EditorRSExpression'; @@ -40,9 +43,11 @@ function FormConstituenta({ disabled, showList, id, + constituenta, + isModified, setIsModified, - constituenta, + toggleReset, onRename, onEditTerm, @@ -56,6 +61,14 @@ function FormConstituenta({ const [expression, setExpression] = useState(''); const [convention, setConvention] = useState(''); const [typification, setTypification] = useState('N/A'); + const [forceComment, setForceComment] = useState(false); + + const isBasic = useMemo(() => !!constituenta && isBasicConcept(constituenta.cst_type), [constituenta]); + const isElementary = useMemo(() => !!constituenta && isBaseSet(constituenta.cst_type), [constituenta]); + const showConvention = useMemo( + () => !constituenta || !!constituenta.convention || forceComment || isBasic, + [constituenta, forceComment, isBasic] + ); useEffect(() => { if (!constituenta) { @@ -90,6 +103,7 @@ function FormConstituenta({ setTextDefinition(constituenta.definition_raw || ''); setExpression(constituenta.definition_formal || ''); setTypification(constituenta ? labelCstTypification(constituenta) : 'N/A'); + setForceComment(false); } }, [constituenta, schema, toggleReset]); @@ -126,73 +140,101 @@ function FormConstituenta({ className={clsx('cc-column', 'mt-1 w-full md:w-[47.8rem] shrink-0', 'px-4 py-1')} onSubmit={handleSubmit} > - setTerm(newValue)} - /> -