diff --git a/rsconcept/frontend/src/components/AnimateFade.tsx b/rsconcept/frontend/src/components/AnimateFade.tsx
new file mode 100644
index 00000000..b2d59713
--- /dev/null
+++ b/rsconcept/frontend/src/components/AnimateFade.tsx
@@ -0,0 +1,25 @@
+import { motion } from 'framer-motion';
+
+import { animateFade } from '@/styling/animations';
+
+import { CProps } from './props';
+
+interface AnimateFadeProps extends CProps.AnimatedDiv {
+ noFadeIn?: boolean;
+ noFadeOut?: boolean;
+}
+
+function AnimateFade({ noFadeIn, noFadeOut, children, ...restProps }: AnimateFadeProps) {
+ return (
+
+ {children}
+
+ );
+}
+
+export default AnimateFade;
diff --git a/rsconcept/frontend/src/components/AnimateFadeIn.tsx b/rsconcept/frontend/src/components/AnimateFadeIn.tsx
deleted file mode 100644
index a8abc058..00000000
--- a/rsconcept/frontend/src/components/AnimateFadeIn.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { motion } from 'framer-motion';
-
-import { animateFadeIn } from '@/styling/animations';
-
-import { CProps } from './props';
-
-interface AnimateFadeInProps extends CProps.AnimatedDiv {}
-
-function AnimateFadeIn({ children, ...restProps }: AnimateFadeInProps) {
- return (
-
- {children}
-
- );
-}
-
-export default AnimateFadeIn;
diff --git a/rsconcept/frontend/src/components/DataLoader.tsx b/rsconcept/frontend/src/components/DataLoader.tsx
new file mode 100644
index 00000000..de8ae6c3
--- /dev/null
+++ b/rsconcept/frontend/src/components/DataLoader.tsx
@@ -0,0 +1,31 @@
+import { AnimatePresence } from 'framer-motion';
+
+import AnimateFade from './AnimateFade';
+import InfoError, { ErrorData } from './InfoError';
+import Loader from './ui/Loader';
+
+interface DataLoaderProps {
+ id: string;
+
+ isLoading: boolean;
+ error?: ErrorData;
+ hasNoData?: boolean;
+
+ children: React.ReactNode;
+}
+
+function DataLoader({ id, isLoading, hasNoData, error, children }: DataLoaderProps) {
+ return (
+
+ {isLoading ? : null}
+ {error ? : null}
+ {!isLoading && !error && !hasNoData ? (
+
+ {children}
+
+ ) : null}
+
+ );
+}
+
+export default DataLoader;
diff --git a/rsconcept/frontend/src/components/InfoError.tsx b/rsconcept/frontend/src/components/InfoError.tsx
index 28579623..a586c657 100644
--- a/rsconcept/frontend/src/components/InfoError.tsx
+++ b/rsconcept/frontend/src/components/InfoError.tsx
@@ -2,6 +2,7 @@ import axios, { type AxiosError } from 'axios';
import { isResponseHtml } from '@/utils/utils';
+import AnimateFade from './AnimateFade';
import PrettyJson from './ui/PrettyJSON';
export type ErrorData = string | Error | AxiosError | undefined;
@@ -49,9 +50,9 @@ function DescribeError({ error }: { error: ErrorData }) {
function InfoError({ error }: InfoErrorProps) {
return (
-
+
);
}
diff --git a/rsconcept/frontend/src/components/ui/Loader.tsx b/rsconcept/frontend/src/components/ui/Loader.tsx
index 875ce966..70f9041e 100644
--- a/rsconcept/frontend/src/components/ui/Loader.tsx
+++ b/rsconcept/frontend/src/components/ui/Loader.tsx
@@ -4,15 +4,19 @@ import { ThreeDots } from 'react-loader-spinner';
import { useConceptTheme } from '@/context/ThemeContext';
+import AnimateFade from '../AnimateFade';
+
interface LoaderProps {
size?: number;
}
-export function Loader({ size = 10 }: LoaderProps) {
+function Loader({ size = 10 }: LoaderProps) {
const { colors } = useConceptTheme();
return (
-
-
-
+
+
+
);
}
+
+export default Loader;
diff --git a/rsconcept/frontend/src/context/LibraryContext.tsx b/rsconcept/frontend/src/context/LibraryContext.tsx
index 92c96fbc..9c34a1c9 100644
--- a/rsconcept/frontend/src/context/LibraryContext.tsx
+++ b/rsconcept/frontend/src/context/LibraryContext.tsx
@@ -97,7 +97,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
setError(undefined);
getRSFormDetails(String(templateID), {
showError: true,
- setLoading: setLoading,
+ setLoading: setProcessing,
onError: setError,
onSuccess: data => {
const schema = loadRSFormData(data);
diff --git a/rsconcept/frontend/src/pages/CreateRSFormPage.tsx b/rsconcept/frontend/src/pages/CreateRSFormPage.tsx
index 3245f569..4b4135ee 100644
--- a/rsconcept/frontend/src/pages/CreateRSFormPage.tsx
+++ b/rsconcept/frontend/src/pages/CreateRSFormPage.tsx
@@ -5,7 +5,7 @@ import { useEffect, useRef, useState } from 'react';
import { BiDownload } from 'react-icons/bi';
import { toast } from 'react-toastify';
-import AnimateFadeIn from '@/components/AnimateFadeIn';
+import AnimateFade from '@/components/AnimateFade';
import InfoError from '@/components/InfoError';
import RequireAuth from '@/components/RequireAuth';
import Button from '@/components/ui/Button';
@@ -79,7 +79,7 @@ function CreateRSFormPage() {
}
return (
-
+
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/LibraryPage/LibraryPage.tsx b/rsconcept/frontend/src/pages/LibraryPage/LibraryPage.tsx
index 2bc09bb7..33fab920 100644
--- a/rsconcept/frontend/src/pages/LibraryPage/LibraryPage.tsx
+++ b/rsconcept/frontend/src/pages/LibraryPage/LibraryPage.tsx
@@ -2,9 +2,7 @@
import { useCallback, useLayoutEffect, useState } from 'react';
-import AnimateFadeIn from '@/components/AnimateFadeIn';
-import InfoError from '@/components/InfoError';
-import { Loader } from '@/components/ui/Loader';
+import DataLoader from '@/components/DataLoader';
import { useAuth } from '@/context/AuthContext';
import { useLibrary } from '@/context/LibraryContext';
import { useConceptNavigation } from '@/context/NavigationContext';
@@ -65,23 +63,25 @@ function LibraryPage() {
}, []);
return (
- <>
- {library.loading ? : null}
- {library.error ? : null}
- {!library.loading && library.items ? (
-
-
-
-
- ) : null}
- >
+
+
+
+
);
}
diff --git a/rsconcept/frontend/src/pages/LoginPage.tsx b/rsconcept/frontend/src/pages/LoginPage.tsx
index e3a44c76..0245a505 100644
--- a/rsconcept/frontend/src/pages/LoginPage.tsx
+++ b/rsconcept/frontend/src/pages/LoginPage.tsx
@@ -4,7 +4,7 @@ import axios from 'axios';
import clsx from 'clsx';
import { useEffect, useState } from 'react';
-import AnimateFadeIn from '@/components/AnimateFadeIn';
+import AnimateFade from '@/components/AnimateFade';
import ExpectedAnonymous from '@/components/ExpectedAnonymous';
import InfoError, { ErrorData } from '@/components/InfoError';
import SubmitButton from '@/components/ui/SubmitButton';
@@ -63,7 +63,7 @@ function LoginPage() {
return ;
}
return (
-
+
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/ManualsPage/ViewTopic.tsx b/rsconcept/frontend/src/pages/ManualsPage/ViewTopic.tsx
index 294bc429..dba070c3 100644
--- a/rsconcept/frontend/src/pages/ManualsPage/ViewTopic.tsx
+++ b/rsconcept/frontend/src/pages/ManualsPage/ViewTopic.tsx
@@ -1,4 +1,4 @@
-import AnimateFadeIn from '@/components/AnimateFadeIn';
+import AnimateFade from '@/components/AnimateFade';
import InfoTopic from '@/components/InfoTopic';
import { HelpTopic } from '@/models/miscellaneous';
@@ -8,9 +8,9 @@ interface ViewTopicProps {
function ViewTopic({ topic }: ViewTopicProps) {
return (
-
+
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/StatusBar.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/StatusBar.tsx
index 2fb90bc8..66cc7e2b 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/StatusBar.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSExpression/StatusBar.tsx
@@ -1,9 +1,10 @@
'use client';
import clsx from 'clsx';
+import { AnimatePresence } from 'framer-motion';
import { useMemo } from 'react';
-import { Loader } from '@/components/ui/Loader';
+import Loader from '@/components/ui/Loader';
import { useConceptTheme } from '@/context/ThemeContext';
import { ExpressionStatus } from '@/models/rsform';
import { type IConstituenta } from '@/models/rsform';
@@ -51,14 +52,15 @@ function StatusBar({ isModified, processing, constituenta, parseData, onAnalyze
data-tooltip-content='Проверить определение [Ctrl + Q]'
onClick={onAnalyze}
>
- {processing ? (
-
- ) : (
- <>
-
- {labelExpressionStatus(status)}
- >
- )}
+
+ {processing ? : null}
+ {!processing ? (
+ <>
+
+ {labelExpressionStatus(status)}
+ >
+ ) : null}
+
);
}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx b/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx
index df773cca..207d4fed 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx
@@ -8,9 +8,9 @@ import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
import { TabList, TabPanel, Tabs } from 'react-tabs';
import { toast } from 'react-toastify';
-import AnimateFadeIn from '@/components/AnimateFadeIn';
+import AnimateFade from '@/components/AnimateFade';
import InfoError, { ErrorData } from '@/components/InfoError';
-import { Loader } from '@/components/ui/Loader';
+import Loader from '@/components/ui/Loader';
import TabLabel from '@/components/ui/TabLabel';
import TextURL from '@/components/ui/TextURL';
import { useAccessMode } from '@/context/AccessModeContext';
@@ -45,19 +45,6 @@ export enum RSTabID {
TERM_GRAPH = 3
}
-function ProcessError({ error }: { error: ErrorData }): React.ReactElement {
- if (axios.isAxiosError(error) && error.response && error.response.status === 404) {
- return (
-
-
Схема с указанным идентификатором отсутствует на портале.
-
-
- );
- } else {
- return ;
- }
-}
-
function RSTabs() {
const router = useConceptNavigation();
const query = useQueryStrings();
@@ -361,8 +348,6 @@ function RSTabs() {
return (
<>
- {loading ? : null}
- {error ? : null}
{showUpload ? setShowUpload(false)} /> : null}
{showClone ? setShowClone(false)} /> : null}
@@ -406,6 +391,8 @@ function RSTabs() {
) : null}
+ {loading ? : null}
+ {error ? : null}
{schema && !loading ? (
-
+
-
+
) : null}
>
@@ -491,6 +478,19 @@ function RSTabs() {
export default RSTabs;
// ====== Internals =========
+function ProcessError({ error }: { error: ErrorData }): React.ReactElement {
+ if (axios.isAxiosError(error) && error.response && error.response.status === 404) {
+ return (
+
+
Схема с указанным идентификатором отсутствует на портале.
+
+
+ );
+ } else {
+ return ;
+ }
+}
+
function getNextActiveOnDelete(
activeID: number | undefined,
items: IConstituenta[],
diff --git a/rsconcept/frontend/src/pages/RegisterPage.tsx b/rsconcept/frontend/src/pages/RegisterPage.tsx
index fe2a2fa6..edde6c5f 100644
--- a/rsconcept/frontend/src/pages/RegisterPage.tsx
+++ b/rsconcept/frontend/src/pages/RegisterPage.tsx
@@ -5,7 +5,7 @@ import { useEffect, useState } from 'react';
import { BiInfoCircle } from 'react-icons/bi';
import { toast } from 'react-toastify';
-import AnimateFadeIn from '@/components/AnimateFadeIn';
+import AnimateFade from '@/components/AnimateFade';
import ExpectedAnonymous from '@/components/ExpectedAnonymous';
import InfoError from '@/components/InfoError';
import Button from '@/components/ui/Button';
@@ -68,7 +68,7 @@ function RegisterPage() {
return ;
}
return (
-
+
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/RestorePasswordPage.tsx b/rsconcept/frontend/src/pages/RestorePasswordPage.tsx
index e5da9dba..b8dac7c2 100644
--- a/rsconcept/frontend/src/pages/RestorePasswordPage.tsx
+++ b/rsconcept/frontend/src/pages/RestorePasswordPage.tsx
@@ -1,15 +1,15 @@
-import AnimateFadeIn from '@/components/AnimateFadeIn';
+import AnimateFade from '@/components/AnimateFade';
import TextURL from '@/components/ui/TextURL';
import { urls } from '@/utils/constants';
function RestorePasswordPage() {
return (
-
+
Автоматическое восстановление пароля не доступно.
Возможно восстановление пароля через обращение на
-
+
);
}
diff --git a/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx b/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx
index 895f7302..e1e249da 100644
--- a/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx
+++ b/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx
@@ -4,9 +4,8 @@ import { AnimatePresence } from 'framer-motion';
import { useMemo, useState } from 'react';
import { FiBell, FiBellOff } from 'react-icons/fi';
-import AnimateFadeIn from '@/components/AnimateFadeIn';
-import InfoError from '@/components/InfoError';
-import { Loader } from '@/components/ui/Loader';
+import AnimateFade from '@/components/AnimateFade';
+import DataLoader from '@/components/DataLoader';
import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay';
import { useAuth } from '@/context/AuthContext';
@@ -29,37 +28,38 @@ function UserTabs() {
}, [auth, items]);
return (
- <>
- {loading ? : null}
- {error ? : null}
- {user ? (
-
-
-
-
- ) : (
-
- )
- }
- onClick={() => setShowSubs(prev => !prev)}
- />
-
-
Учетные данные пользователя
-
-
-
-
+
+
+
+
+
+ ) : (
+
+ )
+ }
+ onClick={() => setShowSubs(prev => !prev)}
+ />
+
+
Учетные данные пользователя
+
+
+
-
- {subscriptions.length > 0 && showSubs ? : null}
-
-
- ) : null}
- >
+
+
+ {subscriptions.length > 0 && showSubs ? : null}
+
+
+
);
}
diff --git a/rsconcept/frontend/src/styling/animations.ts b/rsconcept/frontend/src/styling/animations.ts
index a9b8a3ff..b6dc0d3b 100644
--- a/rsconcept/frontend/src/styling/animations.ts
+++ b/rsconcept/frontend/src/styling/animations.ts
@@ -191,7 +191,7 @@ export const animateModal = {
}
};
-export const animateFadeIn = {
+export const animateFade = {
initial: {
opacity: 0
},
@@ -208,7 +208,7 @@ export const animateFadeIn = {
transition: {
type: 'tween',
ease: 'linear',
- duration: 2
+ duration: 0.3
}
}
};