: 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)}
- />
-
);
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/RSEditControls.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/RSEditControls.tsx
index 6e6ba949..bded37bc 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/RSEditControls.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/RSEditControls.tsx
@@ -49,7 +49,7 @@ const MAIN_THIRD_ROW: TokenID[] = [
TokenID.LOGIC_EQUIVALENT,
TokenID.SET_SYMMETRIC_MINUS,
TokenID.PUNCTUATION_ASSIGN,
- TokenID.EQUAL,
+ TokenID.MULTIPLY,
TokenID.GREATER_OR_EQ,
TokenID.LESSER_OR_EQ
];
diff --git a/rsconcept/frontend/src/pages/RegisterPage.tsx b/rsconcept/frontend/src/pages/RegisterPage.tsx
index 26d960f8..d15607e9 100644
--- a/rsconcept/frontend/src/pages/RegisterPage.tsx
+++ b/rsconcept/frontend/src/pages/RegisterPage.tsx
@@ -65,7 +65,11 @@ function RegisterPage() {
}
if (user) {
- return
;
+ return (
+
+
+
+ );
}
return (
diff --git a/rsconcept/frontend/src/styling/animations.ts b/rsconcept/frontend/src/styling/animations.ts
index 83a8f867..dc85a695 100644
--- a/rsconcept/frontend/src/styling/animations.ts
+++ b/rsconcept/frontend/src/styling/animations.ts
@@ -216,12 +216,22 @@ export const animateFade = {
initial: {
opacity: 0
},
- animate: {
- opacity: 1,
- transition: {
- type: 'tween',
- ease: 'linear',
- duration: 0.3
+ variants: {
+ active: {
+ opacity: 1,
+ transition: {
+ type: 'tween',
+ ease: 'linear',
+ duration: 0.3
+ }
+ },
+ hidden: {
+ opacity: 0,
+ transition: {
+ type: 'tween',
+ ease: 'linear',
+ duration: 0.3
+ }
}
},
exit: {
diff --git a/rsconcept/frontend/src/utils/codemirror.ts b/rsconcept/frontend/src/utils/codemirror.ts
index a5ca510b..643cee2e 100644
--- a/rsconcept/frontend/src/utils/codemirror.ts
+++ b/rsconcept/frontend/src/utils/codemirror.ts
@@ -129,10 +129,11 @@ export function domTooltipConstituenta(cst?: IConstituenta) {
dom.className = clsx(
'z-modal-tooltip',
'max-h-[25rem] max-w-[25rem] min-w-[10rem]',
+ 'dense',
'p-2',
'border shadow-md',
'overflow-y-auto',
- 'text-sm'
+ 'text-sm font-main'
);
if (cst) {
@@ -179,6 +180,7 @@ export function domTooltipEntityReference(ref: IEntityReference, cst: IConstitue
dom.className = clsx(
'z-tooltip',
'max-h-[25rem] max-w-[25rem] min-w-[10rem]',
+ 'dense',
'p-2 flex flex-col',
'border shadow-md',
'overflow-y-auto',
@@ -225,6 +227,7 @@ export function domTooltipSyntacticReference(ref: ISyntacticReference, masterRef
dom.className = clsx(
'z-tooltip',
'max-h-[25rem] max-w-[25rem] min-w-[10rem]',
+ 'dense',
'p-2 flex flex-col',
'border shadow-md',
'overflow-y-auto',
diff --git a/rsconcept/frontend/src/utils/labels.ts b/rsconcept/frontend/src/utils/labels.ts
index e8d3214e..e53038fa 100644
--- a/rsconcept/frontend/src/utils/labels.ts
+++ b/rsconcept/frontend/src/utils/labels.ts
@@ -96,6 +96,7 @@ export function labelToken(id: TokenID): string {
case TokenID.LOGIC_EQUIVALENT: return '⇔';
case TokenID.LIT_EMPTYSET: return '∅';
case TokenID.LIT_WHOLE_NUMBERS: return 'Z';
+ case TokenID.MULTIPLY: return '*';
case TokenID.EQUAL: return '=';
case TokenID.NOTEQUAL: return '≠';
case TokenID.GREATER_OR_EQ: return '≥';
@@ -163,6 +164,7 @@ export function describeToken(id: TokenID): string {
case TokenID.LIT_EMPTYSET: return prepareTooltip('Пустое множество', 'Alt + X');
case TokenID.LIT_WHOLE_NUMBERS: return prepareTooltip('Целые числа', 'Alt + Z');
case TokenID.EQUAL: return prepareTooltip('Равенство');
+ case TokenID.MULTIPLY: return prepareTooltip('Умножение чисел', 'Alt + 8');
case TokenID.NOTEQUAL: return prepareTooltip('Неравенство', 'Alt + Shift + `');
case TokenID.GREATER_OR_EQ: return prepareTooltip('Больше или равно', 'Alt + Shift + 7');
case TokenID.LESSER_OR_EQ: return prepareTooltip('Меньше или равно', 'Alt + Shift + 8');