mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactoring: rework application files structure
This commit is contained in:
parent
5310e0c9ed
commit
fa6fef5fa5
|
@ -1,102 +0,0 @@
|
||||||
import { createBrowserRouter, Outlet, RouterProvider } from 'react-router-dom';
|
|
||||||
|
|
||||||
import ConceptToaster from '@/components/ConceptToaster';
|
|
||||||
import Footer from '@/components/Footer';
|
|
||||||
import Navigation from '@/components/Navigation';
|
|
||||||
import { NavigationState } from '@/context/NavigationContext';
|
|
||||||
import { useConceptTheme } from '@/context/ThemeContext';
|
|
||||||
import CreateRSFormPage from '@/pages/CreateRSFormPage';
|
|
||||||
import HomePage from '@/pages/HomePage';
|
|
||||||
import LibraryPage from '@/pages/LibraryPage';
|
|
||||||
import LoginPage from '@/pages/LoginPage';
|
|
||||||
import ManualsPage from '@/pages/ManualsPage';
|
|
||||||
import NotFoundPage from '@/pages/NotFoundPage';
|
|
||||||
import RegisterPage from '@/pages/RegisterPage';
|
|
||||||
import RestorePasswordPage from '@/pages/RestorePasswordPage';
|
|
||||||
import RSFormPage from '@/pages/RSFormPage';
|
|
||||||
import UserProfilePage from '@/pages/UserProfilePage';
|
|
||||||
import { globalIDs } from '@/utils/constants';
|
|
||||||
|
|
||||||
function Root() {
|
|
||||||
const { viewportHeight, mainHeight, showScroll } = useConceptTheme();
|
|
||||||
return (
|
|
||||||
<NavigationState>
|
|
||||||
<div className='min-w-[30rem] clr-app antialiased'>
|
|
||||||
<ConceptToaster
|
|
||||||
className='mt-[4rem] text-sm' // prettier: split lines
|
|
||||||
autoClose={3000}
|
|
||||||
draggable={false}
|
|
||||||
pauseOnFocusLoss={false}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Navigation />
|
|
||||||
|
|
||||||
<div
|
|
||||||
id={globalIDs.main_scroll}
|
|
||||||
className='overflow-y-auto overscroll-none min-w-fit'
|
|
||||||
style={{
|
|
||||||
maxHeight: viewportHeight,
|
|
||||||
overflowY: showScroll ? 'scroll' : 'auto'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<main className='flex flex-col items-center' style={{ minHeight: mainHeight }}>
|
|
||||||
<Outlet />
|
|
||||||
</main>
|
|
||||||
<Footer />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</NavigationState>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
|
||||||
{
|
|
||||||
path: '/',
|
|
||||||
element: <Root />,
|
|
||||||
errorElement: <NotFoundPage />,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
element: <HomePage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'login',
|
|
||||||
element: <LoginPage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'signup',
|
|
||||||
element: <RegisterPage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'restore-password',
|
|
||||||
element: <RestorePasswordPage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'profile',
|
|
||||||
element: <UserProfilePage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'manuals',
|
|
||||||
element: <ManualsPage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'library',
|
|
||||||
element: <LibraryPage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'library/create',
|
|
||||||
element: <CreateRSFormPage />
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'rsforms/:id',
|
|
||||||
element: <RSFormPage />
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
return <RouterProvider router={router} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
42
rsconcept/frontend/src/app/ApplicationLayout.tsx
Normal file
42
rsconcept/frontend/src/app/ApplicationLayout.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
|
|
||||||
|
import ConceptToaster from '@/app/ConceptToaster';
|
||||||
|
import Footer from '@/app/Footer';
|
||||||
|
import Navigation from '@/app/Navigation';
|
||||||
|
import { NavigationState } from '@/context/NavigationContext';
|
||||||
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
|
function ApplicationLayout() {
|
||||||
|
const { viewportHeight, mainHeight, showScroll } = useConceptTheme();
|
||||||
|
return (
|
||||||
|
<NavigationState>
|
||||||
|
<div className='min-w-[30rem] clr-app antialiased'>
|
||||||
|
<ConceptToaster
|
||||||
|
className='mt-[4rem] text-sm' // prettier: split lines
|
||||||
|
autoClose={3000}
|
||||||
|
draggable={false}
|
||||||
|
pauseOnFocusLoss={false}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Navigation />
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={globalIDs.main_scroll}
|
||||||
|
className='overflow-y-auto overscroll-none min-w-fit'
|
||||||
|
style={{
|
||||||
|
maxHeight: viewportHeight,
|
||||||
|
overflowY: showScroll ? 'scroll' : 'auto'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<main className='flex flex-col items-center' style={{ minHeight: mainHeight }}>
|
||||||
|
<Outlet />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</NavigationState>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ApplicationLayout;
|
|
@ -1,7 +1,7 @@
|
||||||
import { type FallbackProps } from 'react-error-boundary';
|
import { type FallbackProps } from 'react-error-boundary';
|
||||||
|
|
||||||
import Button from './Common/Button';
|
import Button from '../components/Common/Button';
|
||||||
import InfoError from './InfoError';
|
import InfoError from '../components/InfoError';
|
||||||
|
|
||||||
function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
|
function ErrorFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||||
return (
|
return (
|
|
@ -3,7 +3,7 @@ import clsx from 'clsx';
|
||||||
import { useConceptTheme } from '@/context/ThemeContext';
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
import { urls } from '@/utils/constants';
|
import { urls } from '@/utils/constants';
|
||||||
|
|
||||||
import TextURL from './Common/TextURL';
|
import TextURL from '../components/Common/TextURL';
|
||||||
|
|
||||||
function Footer() {
|
function Footer() {
|
||||||
const { noNavigation, noFooter } = useConceptTheme();
|
const { noNavigation, noFooter } = useConceptTheme();
|
|
@ -9,7 +9,7 @@ import { LibraryState } from '@/context/LibraryContext';
|
||||||
import { ThemeState } from '@/context/ThemeContext';
|
import { ThemeState } from '@/context/ThemeContext';
|
||||||
import { UsersState } from '@/context/UsersContext';
|
import { UsersState } from '@/context/UsersContext';
|
||||||
|
|
||||||
import ErrorFallback from './components/ErrorFallback';
|
import ErrorFallback from './ErrorFallback';
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.js', import.meta.url).toString();
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.js', import.meta.url).toString();
|
||||||
|
|
60
rsconcept/frontend/src/app/Router.tsx
Normal file
60
rsconcept/frontend/src/app/Router.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { createBrowserRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
import CreateRSFormPage from '@/pages/CreateRSFormPage';
|
||||||
|
import HomePage from '@/pages/HomePage';
|
||||||
|
import LibraryPage from '@/pages/LibraryPage';
|
||||||
|
import LoginPage from '@/pages/LoginPage';
|
||||||
|
import ManualsPage from '@/pages/ManualsPage';
|
||||||
|
import NotFoundPage from '@/pages/NotFoundPage';
|
||||||
|
import RegisterPage from '@/pages/RegisterPage';
|
||||||
|
import RestorePasswordPage from '@/pages/RestorePasswordPage';
|
||||||
|
import RSFormPage from '@/pages/RSFormPage';
|
||||||
|
import UserProfilePage from '@/pages/UserProfilePage';
|
||||||
|
|
||||||
|
import ApplicationLayout from './ApplicationLayout';
|
||||||
|
|
||||||
|
export const Router = createBrowserRouter([
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
element: <ApplicationLayout />,
|
||||||
|
errorElement: <NotFoundPage />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
element: <HomePage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'login',
|
||||||
|
element: <LoginPage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'signup',
|
||||||
|
element: <RegisterPage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'restore-password',
|
||||||
|
element: <RestorePasswordPage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'profile',
|
||||||
|
element: <UserProfilePage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'manuals',
|
||||||
|
element: <ManualsPage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'library',
|
||||||
|
element: <LibraryPage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'library/create',
|
||||||
|
element: <CreateRSFormPage />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'rsforms/:id',
|
||||||
|
element: <RSFormPage />
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
9
rsconcept/frontend/src/app/index.tsx
Normal file
9
rsconcept/frontend/src/app/index.tsx
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { RouterProvider } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { Router } from './Router';
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return <RouterProvider router={Router} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
|
@ -6,12 +6,21 @@ import { globalIDs } from '@/utils/constants';
|
||||||
import { CheckboxCheckedIcon, CheckboxNullIcon } from '../Icons';
|
import { CheckboxCheckedIcon, CheckboxNullIcon } from '../Icons';
|
||||||
import { CheckboxProps } from './Checkbox';
|
import { CheckboxProps } from './Checkbox';
|
||||||
|
|
||||||
export interface TristateProps extends Omit<CheckboxProps, 'value' | 'setValue'> {
|
export interface CheckboxTristateProps extends Omit<CheckboxProps, 'value' | 'setValue'> {
|
||||||
value: boolean | null;
|
value: boolean | null;
|
||||||
setValue?: (newValue: boolean | null) => void;
|
setValue?: (newValue: boolean | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Tristate({ id, disabled, label, title, className, value, setValue, ...restProps }: TristateProps) {
|
function CheckboxTristate({
|
||||||
|
id,
|
||||||
|
disabled,
|
||||||
|
label,
|
||||||
|
title,
|
||||||
|
className,
|
||||||
|
value,
|
||||||
|
setValue,
|
||||||
|
...restProps
|
||||||
|
}: CheckboxTristateProps) {
|
||||||
const cursor = useMemo(() => {
|
const cursor = useMemo(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return 'cursor-not-allowed';
|
return 'cursor-not-allowed';
|
||||||
|
@ -71,4 +80,4 @@ function Tristate({ id, disabled, label, title, className, value, setValue, ...r
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Tristate;
|
export default CheckboxTristate;
|
|
@ -4,11 +4,11 @@ import { ThreeDots } from 'react-loader-spinner';
|
||||||
|
|
||||||
import { useConceptTheme } from '@/context/ThemeContext';
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
|
|
||||||
interface ConceptLoaderProps {
|
interface LoaderProps {
|
||||||
size?: number;
|
size?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ConceptLoader({ size = 10 }: ConceptLoaderProps) {
|
export function Loader({ size = 10 }: LoaderProps) {
|
||||||
const { colors } = useConceptTheme();
|
const { colors } = useConceptTheme();
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-center'>
|
<div className='flex justify-center'>
|
|
@ -4,13 +4,13 @@ import { CProps } from '../props';
|
||||||
import Overlay from './Overlay';
|
import Overlay from './Overlay';
|
||||||
import TextInput from './TextInput';
|
import TextInput from './TextInput';
|
||||||
|
|
||||||
interface ConceptSearchProps extends CProps.Styling {
|
interface SearchBarProps extends CProps.Styling {
|
||||||
value: string;
|
value: string;
|
||||||
onChange?: (newValue: string) => void;
|
onChange?: (newValue: string) => void;
|
||||||
noBorder?: boolean;
|
noBorder?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConceptSearch({ value, onChange, noBorder, ...restProps }: ConceptSearchProps) {
|
function SearchBar({ value, onChange, noBorder, ...restProps }: SearchBarProps) {
|
||||||
return (
|
return (
|
||||||
<div {...restProps}>
|
<div {...restProps}>
|
||||||
<Overlay position='top-[-0.125rem] left-3 translate-y-1/2' className='pointer-events-none clr-text-controls'>
|
<Overlay position='top-[-0.125rem] left-3 translate-y-1/2' className='pointer-events-none clr-text-controls'>
|
||||||
|
@ -19,6 +19,7 @@ function ConceptSearch({ value, onChange, noBorder, ...restProps }: ConceptSearc
|
||||||
<TextInput
|
<TextInput
|
||||||
noOutline
|
noOutline
|
||||||
placeholder='Поиск'
|
placeholder='Поиск'
|
||||||
|
type='search'
|
||||||
className='w-full pl-10'
|
className='w-full pl-10'
|
||||||
noBorder={noBorder}
|
noBorder={noBorder}
|
||||||
value={value}
|
value={value}
|
||||||
|
@ -28,4 +29,4 @@ function ConceptSearch({ value, onChange, noBorder, ...restProps }: ConceptSearc
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ConceptSearch;
|
export default SearchBar;
|
|
@ -1,47 +0,0 @@
|
||||||
import clsx from 'clsx';
|
|
||||||
|
|
||||||
import { CProps } from '../props';
|
|
||||||
|
|
||||||
interface SwitchButtonProps<ValueType> extends CProps.Styling {
|
|
||||||
id?: string;
|
|
||||||
value: ValueType;
|
|
||||||
label?: string;
|
|
||||||
icon?: React.ReactNode;
|
|
||||||
title?: string;
|
|
||||||
|
|
||||||
isSelected?: boolean;
|
|
||||||
onSelect: (value: ValueType) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
function SwitchButton<ValueType>({
|
|
||||||
value,
|
|
||||||
icon,
|
|
||||||
label,
|
|
||||||
className,
|
|
||||||
isSelected,
|
|
||||||
onSelect,
|
|
||||||
...restProps
|
|
||||||
}: SwitchButtonProps<ValueType>) {
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
type='button'
|
|
||||||
tabIndex={-1}
|
|
||||||
onClick={() => onSelect(value)}
|
|
||||||
className={clsx(
|
|
||||||
'px-2 py-1',
|
|
||||||
'border rounded-none',
|
|
||||||
'font-controls',
|
|
||||||
'clr-btn-clear clr-hover',
|
|
||||||
'cursor-pointer',
|
|
||||||
isSelected && 'clr-selected',
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...restProps}
|
|
||||||
>
|
|
||||||
{icon ? icon : null}
|
|
||||||
{label}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SwitchButton;
|
|
|
@ -1,16 +1,16 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import type { TabProps } from 'react-tabs';
|
import type { TabProps as TabPropsImpl } from 'react-tabs';
|
||||||
import { Tab } from 'react-tabs';
|
import { Tab as TabImpl } from 'react-tabs';
|
||||||
|
|
||||||
import { globalIDs } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
interface ConceptTabProps extends Omit<TabProps, 'children'> {
|
interface TabLabelProps extends Omit<TabPropsImpl, 'children'> {
|
||||||
label?: string;
|
label?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConceptTab({ label, title, className, ...otherProps }: ConceptTabProps) {
|
function TabLabel({ label, title, className, ...otherProps }: TabLabelProps) {
|
||||||
return (
|
return (
|
||||||
<Tab
|
<TabImpl
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'min-w-[6rem]',
|
'min-w-[6rem]',
|
||||||
'px-2 py-1 flex justify-center',
|
'px-2 py-1 flex justify-center',
|
||||||
|
@ -24,10 +24,10 @@ function ConceptTab({ label, title, className, ...otherProps }: ConceptTabProps)
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</Tab>
|
</TabImpl>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConceptTab.tabsRole = 'Tab';
|
TabLabel.tabsRole = 'Tab';
|
||||||
|
|
||||||
export default ConceptTab;
|
export default TabLabel;
|
|
@ -3,16 +3,16 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { ITooltip, Tooltip } from 'react-tooltip';
|
import { ITooltip, Tooltip as TooltipImpl } from 'react-tooltip';
|
||||||
|
|
||||||
import { useConceptTheme } from '@/context/ThemeContext';
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
|
|
||||||
interface ConceptTooltipProps extends Omit<ITooltip, 'variant'> {
|
interface TooltipProps extends Omit<ITooltip, 'variant'> {
|
||||||
layer?: string;
|
layer?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConceptTooltip({
|
function Tooltip({
|
||||||
text,
|
text,
|
||||||
children,
|
children,
|
||||||
layer = 'z-tooltip',
|
layer = 'z-tooltip',
|
||||||
|
@ -20,13 +20,13 @@ function ConceptTooltip({
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
...restProps
|
...restProps
|
||||||
}: ConceptTooltipProps) {
|
}: TooltipProps) {
|
||||||
const { darkMode } = useConceptTheme();
|
const { darkMode } = useConceptTheme();
|
||||||
if (typeof window === 'undefined') {
|
if (typeof window === 'undefined') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<Tooltip
|
<TooltipImpl
|
||||||
delayShow={1000}
|
delayShow={1000}
|
||||||
delayHide={100}
|
delayHide={100}
|
||||||
opacity={0.97}
|
opacity={0.97}
|
||||||
|
@ -39,9 +39,9 @@ function ConceptTooltip({
|
||||||
>
|
>
|
||||||
{text ? text : null}
|
{text ? text : null}
|
||||||
{children as ReactNode}
|
{children as ReactNode}
|
||||||
</Tooltip>,
|
</TooltipImpl>,
|
||||||
document.body
|
document.body
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ConceptTooltip;
|
export default Tooltip;
|
|
@ -1,6 +1,6 @@
|
||||||
import { Table } from '@tanstack/react-table';
|
import { Table } from '@tanstack/react-table';
|
||||||
|
|
||||||
import Tristate from '@/components/Common/Tristate';
|
import CheckboxTristate from '@/components/Common/CheckboxTristate';
|
||||||
|
|
||||||
interface SelectAllProps<TData> {
|
interface SelectAllProps<TData> {
|
||||||
table: Table<TData>;
|
table: Table<TData>;
|
||||||
|
@ -8,7 +8,7 @@ interface SelectAllProps<TData> {
|
||||||
|
|
||||||
function SelectAll<TData>({ table }: SelectAllProps<TData>) {
|
function SelectAll<TData>({ table }: SelectAllProps<TData>) {
|
||||||
return (
|
return (
|
||||||
<Tristate
|
<CheckboxTristate
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
title='Выделить все'
|
title='Выделить все'
|
||||||
value={
|
value={
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import ConceptTooltip from '@/components/Common/ConceptTooltip';
|
import Tooltip from '@/components/Common/Tooltip';
|
||||||
import InfoConstituenta from '@/components/Shared/InfoConstituenta';
|
import InfoConstituenta from '@/components/Shared/InfoConstituenta';
|
||||||
import { IConstituenta } from '@/models/rsform';
|
import { IConstituenta } from '@/models/rsform';
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@ interface ConstituentaTooltipProps {
|
||||||
|
|
||||||
function ConstituentaTooltip({ data, anchor }: ConstituentaTooltipProps) {
|
function ConstituentaTooltip({ data, anchor }: ConstituentaTooltipProps) {
|
||||||
return (
|
return (
|
||||||
<ConceptTooltip clickable anchorSelect={anchor} className='max-w-[30rem]'>
|
<Tooltip clickable anchorSelect={anchor} className='max-w-[30rem]'>
|
||||||
<InfoConstituenta data={data} />
|
<InfoConstituenta data={data} />
|
||||||
</ConceptTooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,14 @@ function HelpAPI() {
|
||||||
<h1>Программный интерфейс Портала</h1>
|
<h1>Программный интерфейс Портала</h1>
|
||||||
<p>В качестве программного интерфейса сервера используется REST API, реализованный с помощью Django.</p>
|
<p>В качестве программного интерфейса сервера используется REST API, реализованный с помощью Django.</p>
|
||||||
<p>На данный момент API находится в разработке, поэтому поддержка внешних запросов не производится.</p>
|
<p>На данный момент API находится в разработке, поэтому поддержка внешних запросов не производится.</p>
|
||||||
<p>С описанием интерфейса можно ознакомиться <TextURL text='по ссылке' href={urls.restAPI}/>.</p>
|
<p>
|
||||||
<p><TextURL text='Принять участие в разработке' href={urls.git_repo}/></p>
|
С описанием интерфейса можно ознакомиться <TextURL text='по ссылке' href={urls.restAPI} />.
|
||||||
</div>);
|
</p>
|
||||||
|
<p>
|
||||||
|
<TextURL text='Принять участие в разработке' href={urls.git_repo} />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HelpAPI;
|
export default HelpAPI;
|
|
@ -1,7 +1,7 @@
|
||||||
import { BiInfoCircle } from 'react-icons/bi';
|
import { BiInfoCircle } from 'react-icons/bi';
|
||||||
|
|
||||||
import ConceptTooltip from '@/components/Common/ConceptTooltip';
|
|
||||||
import TextURL from '@/components/Common/TextURL';
|
import TextURL from '@/components/Common/TextURL';
|
||||||
|
import Tooltip from '@/components/Common/Tooltip';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
|
||||||
import { CProps } from '../props';
|
import { CProps } from '../props';
|
||||||
|
@ -16,14 +16,14 @@ function HelpButton({ topic, ...restProps }: HelpButtonProps) {
|
||||||
return (
|
return (
|
||||||
<div id={`help-${topic}`} className='p-1'>
|
<div id={`help-${topic}`} className='p-1'>
|
||||||
<BiInfoCircle size='1.25rem' className='clr-text-primary' />
|
<BiInfoCircle size='1.25rem' className='clr-text-primary' />
|
||||||
<ConceptTooltip clickable anchorSelect={`#help-${topic}`} layer='z-modal-tooltip' {...restProps}>
|
<Tooltip clickable anchorSelect={`#help-${topic}`} layer='z-modal-tooltip' {...restProps}>
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<div className='absolute right-0 text-sm top-[0.4rem]'>
|
<div className='absolute right-0 text-sm top-[0.4rem]'>
|
||||||
<TextURL text='Справка...' href={`/manuals?topic=${topic}`} />
|
<TextURL text='Справка...' href={`/manuals?topic=${topic}`} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<InfoTopic topic={topic} />
|
<InfoTopic topic={topic} />
|
||||||
</ConceptTooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import ConceptSearch from '@/components/Common/ConceptSearch';
|
import SearchBar from '@/components/Common/SearchBar';
|
||||||
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/DataTable';
|
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/DataTable';
|
||||||
import { useConceptTheme } from '@/context/ThemeContext';
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
import { CstMatchMode } from '@/models/miscellaneous';
|
import { CstMatchMode } from '@/models/miscellaneous';
|
||||||
|
@ -83,7 +83,7 @@ function ConstituentaPicker({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ConceptSearch value={filterText} onChange={newValue => setFilterText(newValue)} />
|
<SearchBar value={filterText} onChange={newValue => setFilterText(newValue)} />
|
||||||
<DataTable
|
<DataTable
|
||||||
dense
|
dense
|
||||||
noHeader
|
noHeader
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { createContext, useCallback, useContext, useLayoutEffect, useMemo, useState } from 'react';
|
import { createContext, useCallback, useContext, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import ConceptTooltip from '@/components/Common/ConceptTooltip';
|
import Tooltip from '@/components/Common/Tooltip';
|
||||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||||
import { animationDuration } from '@/utils/animations';
|
import { animationDuration } from '@/utils/animations';
|
||||||
import { darkT, IColorTheme, lightT } from '@/utils/color';
|
import { darkT, IColorTheme, lightT } from '@/utils/color';
|
||||||
|
@ -104,7 +104,7 @@ export const ThemeState = ({ children }: ThemeStateProps) => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<>
|
<>
|
||||||
<ConceptTooltip
|
<Tooltip
|
||||||
float
|
float
|
||||||
id={`${globalIDs.tooltip}`}
|
id={`${globalIDs.tooltip}`}
|
||||||
layer='z-topmost'
|
layer='z-topmost'
|
||||||
|
|
|
@ -4,9 +4,9 @@ import clsx from 'clsx';
|
||||||
import { useLayoutEffect, useState } from 'react';
|
import { useLayoutEffect, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
import ConceptTab from '@/components/Common/ConceptTab';
|
|
||||||
import Modal, { ModalProps } from '@/components/Common/Modal';
|
import Modal, { ModalProps } from '@/components/Common/Modal';
|
||||||
import Overlay from '@/components/Common/Overlay';
|
import Overlay from '@/components/Common/Overlay';
|
||||||
|
import TabLabel from '@/components/Common/TabLabel';
|
||||||
import HelpButton from '@/components/Help/HelpButton';
|
import HelpButton from '@/components/Help/HelpButton';
|
||||||
import usePartialUpdate from '@/hooks/usePartialUpdate';
|
import usePartialUpdate from '@/hooks/usePartialUpdate';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
@ -125,9 +125,9 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
onSelect={setActiveTab}
|
onSelect={setActiveTab}
|
||||||
>
|
>
|
||||||
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
||||||
<ConceptTab label='Шаблон' title='Выбор шаблона выражения' className='w-[8rem]' />
|
<TabLabel label='Шаблон' title='Выбор шаблона выражения' className='w-[8rem]' />
|
||||||
<ConceptTab label='Аргументы' title='Подстановка аргументов шаблона' className='w-[8rem]' />
|
<TabLabel label='Аргументы' title='Подстановка аргументов шаблона' className='w-[8rem]' />
|
||||||
<ConceptTab label='Конституента' title='Редактирование атрибутов конституенты' className='w-[8rem]' />
|
<TabLabel label='Конституента' title='Редактирование атрибутов конституенты' className='w-[8rem]' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<TabPanel style={{ display: activeTab === TabID.TEMPLATE ? '' : 'none' }}>
|
<TabPanel style={{ display: activeTab === TabID.TEMPLATE ? '' : 'none' }}>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import clsx from 'clsx';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
import ConceptTab from '@/components/Common/ConceptTab';
|
import TabLabel from '@/components/Common/TabLabel';
|
||||||
import Modal from '@/components/Common/Modal';
|
import Modal from '@/components/Common/Modal';
|
||||||
import Overlay from '@/components/Common/Overlay';
|
import Overlay from '@/components/Common/Overlay';
|
||||||
import HelpButton from '@/components/Help/HelpButton';
|
import HelpButton from '@/components/Help/HelpButton';
|
||||||
|
@ -64,12 +64,12 @@ function DlgEditReference({ hideWindow, items, initial, onSave }: DlgEditReferen
|
||||||
onSelect={setActiveTab}
|
onSelect={setActiveTab}
|
||||||
>
|
>
|
||||||
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
||||||
<ConceptTab
|
<TabLabel
|
||||||
title='Отсылка на термин в заданной словоформе'
|
title='Отсылка на термин в заданной словоформе'
|
||||||
label={labelReferenceType(ReferenceType.ENTITY)}
|
label={labelReferenceType(ReferenceType.ENTITY)}
|
||||||
className='w-[12rem]'
|
className='w-[12rem]'
|
||||||
/>
|
/>
|
||||||
<ConceptTab
|
<TabLabel
|
||||||
title='Установление синтаксической связи с отсылкой на термин'
|
title='Установление синтаксической связи с отсылкой на термин'
|
||||||
label={labelReferenceType(ReferenceType.SYNTACTIC)}
|
label={labelReferenceType(ReferenceType.SYNTACTIC)}
|
||||||
className='w-[12rem]'
|
className='w-[12rem]'
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
import { useCallback, useMemo, useState } from 'react';
|
import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import GraphUI, { GraphEdge, GraphNode } from '@/components/Common/GraphUI';
|
|
||||||
import Modal, { ModalProps } from '@/components/Common/Modal';
|
import Modal, { ModalProps } from '@/components/Common/Modal';
|
||||||
|
import GraphUI, { GraphEdge, GraphNode } from '@/components/GraphUI';
|
||||||
import { useConceptTheme } from '@/context/ThemeContext';
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
import { SyntaxTree } from '@/models/rslang';
|
import { SyntaxTree } from '@/models/rslang';
|
||||||
import { graphDarkT, graphLightT } from '@/utils/color';
|
import { graphDarkT, graphLightT } from '@/utils/color';
|
||||||
|
|
|
@ -2,8 +2,8 @@ import './index.css';
|
||||||
|
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import App from './App.tsx';
|
import App from './app';
|
||||||
import GlobalProviders from './GlobalProviders';
|
import GlobalProviders from './app/GlobalProviders';
|
||||||
|
|
||||||
createRoot(document.getElementById('root')!).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<GlobalProviders>
|
<GlobalProviders>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
import { ConceptLoader } from '@/components/Common/ConceptLoader';
|
import { Loader } from '@/components/Common/Loader';
|
||||||
import InfoError from '@/components/InfoError';
|
import InfoError from '@/components/InfoError';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useLibrary } from '@/context/LibraryContext';
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
|
@ -65,7 +65,7 @@ function LibraryPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{library.loading ? <ConceptLoader /> : null}
|
{library.loading ? <Loader /> : null}
|
||||||
{library.error ? <InfoError error={library.error} /> : null}
|
{library.error ? <InfoError error={library.error} /> : null}
|
||||||
{!library.loading && library.items ? (
|
{!library.loading && library.items ? (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import ConceptSearch from '@/components/Common/ConceptSearch';
|
import SearchBar from '@/components/Common/SearchBar';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { ILibraryFilter } from '@/models/miscellaneous';
|
import { ILibraryFilter } from '@/models/miscellaneous';
|
||||||
import { LibraryFilterStrategy } from '@/models/miscellaneous';
|
import { LibraryFilterStrategy } from '@/models/miscellaneous';
|
||||||
|
@ -67,7 +67,7 @@ function SearchPanel({ total, filtered, query, setQuery, strategy, setFilter }:
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={clsx('flex-grow', 'flex gap-1 justify-center items-center')}>
|
<div className={clsx('flex-grow', 'flex gap-1 justify-center items-center')}>
|
||||||
<ConceptSearch noBorder className='min-w-[10rem]' value={query} onChange={handleChangeQuery} />
|
<SearchBar noBorder className='min-w-[10rem]' value={query} onChange={handleChangeQuery} />
|
||||||
<PickerStrategy value={strategy} onChange={handleChangeStrategy} />
|
<PickerStrategy value={strategy} onChange={handleChangeStrategy} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { ConceptLoader } from '@/components/Common/ConceptLoader';
|
import { Loader } from '@/components/Common/Loader';
|
||||||
import { useConceptTheme } from '@/context/ThemeContext';
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
import { ExpressionStatus } from '@/models/rsform';
|
import { ExpressionStatus } from '@/models/rsform';
|
||||||
import { type IConstituenta } from '@/models/rsform';
|
import { type IConstituenta } from '@/models/rsform';
|
||||||
|
@ -52,7 +52,7 @@ function StatusBar({ isModified, processing, constituenta, parseData, onAnalyze
|
||||||
onClick={onAnalyze}
|
onClick={onAnalyze}
|
||||||
>
|
>
|
||||||
{processing ? (
|
{processing ? (
|
||||||
<ConceptLoader size={3} />
|
<Loader size={3} />
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<StatusIcon status={status} />
|
<StatusIcon status={status} />
|
||||||
|
|
|
@ -14,21 +14,26 @@ import RSFormStats from './RSFormStats';
|
||||||
import RSFormToolbar from './RSFormToolbar';
|
import RSFormToolbar from './RSFormToolbar';
|
||||||
|
|
||||||
interface EditorRSFormProps {
|
interface EditorRSFormProps {
|
||||||
isModified: boolean
|
isModified: boolean;
|
||||||
isMutable: boolean
|
isMutable: boolean;
|
||||||
|
|
||||||
setIsModified: Dispatch<SetStateAction<boolean>>
|
setIsModified: Dispatch<SetStateAction<boolean>>;
|
||||||
onDestroy: () => void
|
onDestroy: () => void;
|
||||||
onClaim: () => void
|
onClaim: () => void;
|
||||||
onShare: () => void
|
onShare: () => void;
|
||||||
onDownload: () => void
|
onDownload: () => void;
|
||||||
onToggleSubscribe: () => void
|
onToggleSubscribe: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function EditorRSForm({
|
function EditorRSForm({
|
||||||
isModified, isMutable,
|
isModified,
|
||||||
onDestroy, onClaim, onShare, setIsModified,
|
isMutable,
|
||||||
onDownload, onToggleSubscribe
|
onDestroy,
|
||||||
|
onClaim,
|
||||||
|
onShare,
|
||||||
|
setIsModified,
|
||||||
|
onDownload,
|
||||||
|
onToggleSubscribe
|
||||||
}: EditorRSFormProps) {
|
}: EditorRSFormProps) {
|
||||||
const { schema, isClaimable, isSubscribed, processing } = useRSForm();
|
const { schema, isClaimable, isSubscribed, processing } = useRSForm();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
@ -58,7 +63,6 @@ function EditorRSForm({
|
||||||
modified={isModified}
|
modified={isModified}
|
||||||
claimable={isClaimable}
|
claimable={isClaimable}
|
||||||
anonymous={!user}
|
anonymous={!user}
|
||||||
|
|
||||||
onSubmit={initiateSubmit}
|
onSubmit={initiateSubmit}
|
||||||
onShare={onShare}
|
onShare={onShare}
|
||||||
onDownload={onDownload}
|
onDownload={onDownload}
|
||||||
|
@ -66,12 +70,10 @@ function EditorRSForm({
|
||||||
onDestroy={onDestroy}
|
onDestroy={onDestroy}
|
||||||
onToggleSubscribe={onToggleSubscribe}
|
onToggleSubscribe={onToggleSubscribe}
|
||||||
/>
|
/>
|
||||||
<div tabIndex={-1}
|
<div tabIndex={-1} className='flex' onKeyDown={handleInput}>
|
||||||
className='flex'
|
|
||||||
onKeyDown={handleInput}
|
|
||||||
>
|
|
||||||
<FlexColumn className='px-4 pb-2'>
|
<FlexColumn className='px-4 pb-2'>
|
||||||
<FormRSForm disabled={!isMutable}
|
<FormRSForm
|
||||||
|
disabled={!isMutable}
|
||||||
id={globalIDs.library_item_editor}
|
id={globalIDs.library_item_editor}
|
||||||
isModified={isModified}
|
isModified={isModified}
|
||||||
setIsModified={setIsModified}
|
setIsModified={setIsModified}
|
||||||
|
@ -84,7 +86,8 @@ function EditorRSForm({
|
||||||
|
|
||||||
<RSFormStats stats={schema?.stats} />
|
<RSFormStats stats={schema?.stats} />
|
||||||
</div>
|
</div>
|
||||||
</>);
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EditorRSForm;
|
export default EditorRSForm;
|
|
@ -3,7 +3,7 @@ import LabeledValue from '@/components/Common/LabeledValue';
|
||||||
import { type IRSFormStats } from '@/models/rsform';
|
import { type IRSFormStats } from '@/models/rsform';
|
||||||
|
|
||||||
interface RSFormStatsProps {
|
interface RSFormStatsProps {
|
||||||
stats?: IRSFormStats
|
stats?: IRSFormStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSFormStats({ stats }: RSFormStatsProps) {
|
function RSFormStats({ stats }: RSFormStatsProps) {
|
||||||
|
@ -12,83 +12,45 @@ function RSFormStats({ stats }: RSFormStatsProps) {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-1 px-4 mt-8 w-[16rem]'>
|
<div className='flex flex-col gap-1 px-4 mt-8 w-[16rem]'>
|
||||||
<LabeledValue id='count_all'
|
<LabeledValue id='count_all' label='Всего конституент ' text={stats.count_all} />
|
||||||
label='Всего конституент '
|
<LabeledValue id='count_errors' label='Некорректных' text={stats.count_errors} />
|
||||||
text={stats.count_all}
|
{stats.count_property !== 0 ? (
|
||||||
/>
|
<LabeledValue id='count_property' label='Неразмерных' text={stats.count_property} />
|
||||||
<LabeledValue id='count_errors'
|
) : null}
|
||||||
label='Некорректных'
|
{stats.count_incalculable !== 0 ? (
|
||||||
text={stats.count_errors}
|
<LabeledValue id='count_incalculable' label='Невычислимых' text={stats.count_incalculable} />
|
||||||
/>
|
) : null}
|
||||||
{stats.count_property !== 0 ?
|
|
||||||
<LabeledValue id='count_property'
|
|
||||||
label='Неразмерных'
|
|
||||||
text={stats.count_property}
|
|
||||||
/> : null}
|
|
||||||
{stats.count_incalculable !== 0 ?
|
|
||||||
<LabeledValue id='count_incalculable'
|
|
||||||
label='Невычислимых'
|
|
||||||
text={stats.count_incalculable}
|
|
||||||
/> : null}
|
|
||||||
|
|
||||||
<Divider margins='my-2' />
|
<Divider margins='my-2' />
|
||||||
|
|
||||||
<LabeledValue id='count_text_term'
|
<LabeledValue id='count_text_term' label='Термины' text={stats.count_text_term} />
|
||||||
label='Термины'
|
<LabeledValue id='count_definition' label='Определения' text={stats.count_definition} />
|
||||||
text={stats.count_text_term}
|
<LabeledValue id='count_convention' label='Конвенции' text={stats.count_convention} />
|
||||||
/>
|
|
||||||
<LabeledValue id='count_definition'
|
|
||||||
label='Определения'
|
|
||||||
text={stats.count_definition}
|
|
||||||
/>
|
|
||||||
<LabeledValue id='count_convention'
|
|
||||||
label='Конвенции'
|
|
||||||
text={stats.count_convention}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Divider margins='my-2' />
|
<Divider margins='my-2' />
|
||||||
|
|
||||||
{stats.count_base !== 0 ?
|
{stats.count_base !== 0 ? (
|
||||||
<LabeledValue id='count_base'
|
<LabeledValue id='count_base' label='Базисные множества ' text={stats.count_base} />
|
||||||
label='Базисные множества '
|
) : null}
|
||||||
text={stats.count_base}
|
{stats.count_constant !== 0 ? (
|
||||||
/> : null}
|
<LabeledValue id='count_constant' label='Константные множества ' text={stats.count_constant} />
|
||||||
{ stats.count_constant !== 0 ?
|
) : null}
|
||||||
<LabeledValue id='count_constant'
|
{stats.count_structured !== 0 ? (
|
||||||
label='Константные множества '
|
<LabeledValue id='count_structured' label='Родовые структуры ' text={stats.count_structured} />
|
||||||
text={stats.count_constant}
|
) : null}
|
||||||
/> : null}
|
{stats.count_axiom !== 0 ? <LabeledValue id='count_axiom' label='Аксиомы ' text={stats.count_axiom} /> : null}
|
||||||
{stats.count_structured !== 0 ?
|
{stats.count_term !== 0 ? <LabeledValue id='count_term' label='Термы ' text={stats.count_term} /> : null}
|
||||||
<LabeledValue id='count_structured'
|
{stats.count_function !== 0 ? (
|
||||||
label='Родовые структуры '
|
<LabeledValue id='count_function' label='Терм-функции ' text={stats.count_function} />
|
||||||
text={stats.count_structured}
|
) : null}
|
||||||
/> : null}
|
{stats.count_predicate !== 0 ? (
|
||||||
{stats.count_axiom !== 0 ?
|
<LabeledValue id='count_predicate' label='Предикат-функции ' text={stats.count_predicate} />
|
||||||
<LabeledValue id='count_axiom'
|
) : null}
|
||||||
label='Аксиомы '
|
{stats.count_theorem !== 0 ? (
|
||||||
text={stats.count_axiom}
|
<LabeledValue id='count_theorem' label='Теоремы ' text={stats.count_theorem} />
|
||||||
/> : null}
|
) : null}
|
||||||
{stats.count_term !== 0 ?
|
</div>
|
||||||
<LabeledValue id='count_term'
|
);
|
||||||
label='Термы '
|
|
||||||
text={stats.count_term}
|
|
||||||
/> : null}
|
|
||||||
{stats.count_function !== 0 ?
|
|
||||||
<LabeledValue id='count_function'
|
|
||||||
label='Терм-функции '
|
|
||||||
text={stats.count_function}
|
|
||||||
/> : null}
|
|
||||||
{stats.count_predicate !== 0 ?
|
|
||||||
<LabeledValue id='count_predicate'
|
|
||||||
label='Предикат-функции '
|
|
||||||
text={stats.count_predicate}
|
|
||||||
/> : null}
|
|
||||||
{stats.count_theorem !== 0 ?
|
|
||||||
<LabeledValue id='count_theorem'
|
|
||||||
label='Теоремы '
|
|
||||||
text={stats.count_theorem}
|
|
||||||
/> : null}
|
|
||||||
</div>);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RSFormStats;
|
export default RSFormStats;
|
|
@ -11,28 +11,36 @@ import HelpButton from '@/components/Help/HelpButton';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
|
||||||
interface RSFormToolbarProps {
|
interface RSFormToolbarProps {
|
||||||
isMutable: boolean
|
isMutable: boolean;
|
||||||
isSubscribed: boolean
|
isSubscribed: boolean;
|
||||||
modified: boolean
|
modified: boolean;
|
||||||
claimable: boolean
|
claimable: boolean;
|
||||||
anonymous: boolean
|
anonymous: boolean;
|
||||||
processing: boolean
|
processing: boolean;
|
||||||
|
|
||||||
onSubmit: () => void
|
onSubmit: () => void;
|
||||||
onShare: () => void
|
onShare: () => void;
|
||||||
onDownload: () => void
|
onDownload: () => void;
|
||||||
onClaim: () => void
|
onClaim: () => void;
|
||||||
onDestroy: () => void
|
onDestroy: () => void;
|
||||||
onToggleSubscribe: () => void
|
onToggleSubscribe: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSFormToolbar({
|
function RSFormToolbar({
|
||||||
isMutable, modified, claimable, anonymous,
|
isMutable,
|
||||||
isSubscribed, onToggleSubscribe, processing,
|
modified,
|
||||||
onSubmit, onShare, onDownload,
|
claimable,
|
||||||
onClaim, onDestroy
|
anonymous,
|
||||||
|
isSubscribed,
|
||||||
|
onToggleSubscribe,
|
||||||
|
processing,
|
||||||
|
onSubmit,
|
||||||
|
onShare,
|
||||||
|
onDownload,
|
||||||
|
onClaim,
|
||||||
|
onDestroy
|
||||||
}: RSFormToolbarProps) {
|
}: RSFormToolbarProps) {
|
||||||
const canSave = useMemo(() => (modified && isMutable), [modified, isMutable]);
|
const canSave = useMemo(() => modified && isMutable, [modified, isMutable]);
|
||||||
return (
|
return (
|
||||||
<Overlay position='top-1 right-1/2 translate-x-1/2' className='flex'>
|
<Overlay position='top-1 right-1/2 translate-x-1/2' className='flex'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
|
@ -54,9 +62,12 @@ function RSFormToolbar({
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title={`Отслеживание ${isSubscribed ? 'включено' : 'выключено'}`}
|
title={`Отслеживание ${isSubscribed ? 'включено' : 'выключено'}`}
|
||||||
disabled={anonymous || processing}
|
disabled={anonymous || processing}
|
||||||
icon={isSubscribed
|
icon={
|
||||||
? <FiBell size='1.25rem' className='clr-text-primary' />
|
isSubscribed ? (
|
||||||
: <FiBellOff size='1.25rem' className='clr-text-controls' />
|
<FiBell size='1.25rem' className='clr-text-primary' />
|
||||||
|
) : (
|
||||||
|
<FiBellOff size='1.25rem' className='clr-text-controls' />
|
||||||
|
)
|
||||||
}
|
}
|
||||||
style={{ outlineColor: 'transparent' }}
|
style={{ outlineColor: 'transparent' }}
|
||||||
onClick={onToggleSubscribe}
|
onClick={onToggleSubscribe}
|
||||||
|
@ -74,7 +85,8 @@ function RSFormToolbar({
|
||||||
icon={<BiTrash size='1.25rem' className={isMutable ? 'clr-text-warning' : ''} />}
|
icon={<BiTrash size='1.25rem' className={isMutable ? 'clr-text-warning' : ''} />}
|
||||||
/>
|
/>
|
||||||
<HelpButton topic={HelpTopic.RSFORM} offset={4} />
|
<HelpButton topic={HelpTopic.RSFORM} offset={4} />
|
||||||
</Overlay>);
|
</Overlay>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RSFormToolbar;
|
export default RSFormToolbar;
|
|
@ -2,14 +2,7 @@
|
||||||
|
|
||||||
import { useCallback, useLayoutEffect, useMemo, useRef } from 'react';
|
import { useCallback, useLayoutEffect, useMemo, useRef } from 'react';
|
||||||
|
|
||||||
import GraphUI, {
|
import GraphUI, { GraphCanvasRef, GraphEdge, GraphNode, LayoutTypes, Sphere, useSelection } from '@/components/GraphUI';
|
||||||
GraphCanvasRef,
|
|
||||||
GraphEdge,
|
|
||||||
GraphNode,
|
|
||||||
LayoutTypes,
|
|
||||||
Sphere,
|
|
||||||
useSelection
|
|
||||||
} from '@/components/Common/GraphUI';
|
|
||||||
import { useConceptTheme } from '@/context/ThemeContext';
|
import { useConceptTheme } from '@/context/ThemeContext';
|
||||||
import { graphDarkT, graphLightT } from '@/utils/color';
|
import { graphDarkT, graphLightT } from '@/utils/color';
|
||||||
import { resources } from '@/utils/constants';
|
import { resources } from '@/utils/constants';
|
||||||
|
|
|
@ -8,8 +8,8 @@ import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { ConceptLoader } from '@/components/Common/ConceptLoader';
|
import { Loader } from '@/components/Common/Loader';
|
||||||
import ConceptTab from '@/components/Common/ConceptTab';
|
import TabLabel from '@/components/Common/TabLabel';
|
||||||
import TextURL from '@/components/Common/TextURL';
|
import TextURL from '@/components/Common/TextURL';
|
||||||
import InfoError, { ErrorData } from '@/components/InfoError';
|
import InfoError, { ErrorData } from '@/components/InfoError';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
import { useAccessMode } from '@/context/AccessModeContext';
|
||||||
|
@ -360,7 +360,7 @@ function RSTabs() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{loading ? <ConceptLoader /> : null}
|
{loading ? <Loader /> : null}
|
||||||
{error ? <ProcessError error={error} /> : null}
|
{error ? <ProcessError error={error} /> : null}
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{showUpload ? <DlgUploadRSForm hideWindow={() => setShowUpload(false)} /> : null}
|
{showUpload ? <DlgUploadRSForm hideWindow={() => setShowUpload(false)} /> : null}
|
||||||
|
@ -425,13 +425,13 @@ function RSTabs() {
|
||||||
showCloneDialog={promptClone}
|
showCloneDialog={promptClone}
|
||||||
showUploadDialog={() => setShowUpload(true)}
|
showUploadDialog={() => setShowUpload(true)}
|
||||||
/>
|
/>
|
||||||
<ConceptTab label='Карточка' title={`Название схемы: ${schema.title ?? ''}`} />
|
<TabLabel label='Карточка' title={`Название схемы: ${schema.title ?? ''}`} />
|
||||||
<ConceptTab
|
<TabLabel
|
||||||
label='Содержание'
|
label='Содержание'
|
||||||
title={`Конституент: ${schema.stats?.count_all ?? 0} | Ошибок: ${schema.stats?.count_errors ?? 0}`}
|
title={`Конституент: ${schema.stats?.count_all ?? 0} | Ошибок: ${schema.stats?.count_errors ?? 0}`}
|
||||||
/>
|
/>
|
||||||
<ConceptTab label='Редактор' />
|
<TabLabel label='Редактор' />
|
||||||
<ConceptTab label='Граф термов' />
|
<TabLabel label='Граф термов' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<TabPanel forceRender style={{ display: activeTab === RSTabID.CARD ? '' : 'none' }}>
|
<TabPanel forceRender style={{ display: activeTab === RSTabID.CARD ? '' : 'none' }}>
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
import { useCallback, useLayoutEffect } from 'react';
|
import { useCallback, useLayoutEffect } from 'react';
|
||||||
import { BiCog, BiFilterAlt } from 'react-icons/bi';
|
import { BiCog, BiFilterAlt } from 'react-icons/bi';
|
||||||
|
|
||||||
import ConceptSearch from '@/components/Common/ConceptSearch';
|
|
||||||
import Dropdown from '@/components/Common/Dropdown';
|
import Dropdown from '@/components/Common/Dropdown';
|
||||||
import DropdownButton from '@/components/Common/DropdownButton';
|
import DropdownButton from '@/components/Common/DropdownButton';
|
||||||
|
import SearchBar from '@/components/Common/SearchBar';
|
||||||
import SelectorButton from '@/components/Common/SelectorButton';
|
import SelectorButton from '@/components/Common/SelectorButton';
|
||||||
import useDropdown from '@/hooks/useDropdown';
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||||
|
@ -75,7 +75,7 @@ function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }:
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex border-b clr-input'>
|
<div className='flex border-b clr-input'>
|
||||||
<ConceptSearch noBorder className='min-w-[6rem] pr-2 flex-grow' value={filterText} onChange={setFilterText} />
|
<SearchBar noBorder className='min-w-[6rem] pr-2 flex-grow' value={filterText} onChange={setFilterText} />
|
||||||
|
|
||||||
<div ref={matchModeMenu.ref}>
|
<div ref={matchModeMenu.ref}>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
|
|
|
@ -7,12 +7,12 @@ import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import Button from '@/components/Common/Button';
|
import Button from '@/components/Common/Button';
|
||||||
import Checkbox from '@/components/Common/Checkbox';
|
import Checkbox from '@/components/Common/Checkbox';
|
||||||
import ConceptTooltip from '@/components/Common/ConceptTooltip';
|
|
||||||
import FlexColumn from '@/components/Common/FlexColumn';
|
import FlexColumn from '@/components/Common/FlexColumn';
|
||||||
import Overlay from '@/components/Common/Overlay';
|
import Overlay from '@/components/Common/Overlay';
|
||||||
import SubmitButton from '@/components/Common/SubmitButton';
|
import SubmitButton from '@/components/Common/SubmitButton';
|
||||||
import TextInput from '@/components/Common/TextInput';
|
import TextInput from '@/components/Common/TextInput';
|
||||||
import TextURL from '@/components/Common/TextURL';
|
import TextURL from '@/components/Common/TextURL';
|
||||||
|
import Tooltip from '@/components/Common/Tooltip';
|
||||||
import ExpectedAnonymous from '@/components/ExpectedAnonymous';
|
import ExpectedAnonymous from '@/components/ExpectedAnonymous';
|
||||||
import InfoError from '@/components/InfoError';
|
import InfoError from '@/components/InfoError';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
|
@ -75,10 +75,10 @@ function RegisterPage() {
|
||||||
<Overlay id={globalIDs.password_tooltip} position='top-[4.8rem] left-[3.4rem] absolute'>
|
<Overlay id={globalIDs.password_tooltip} position='top-[4.8rem] left-[3.4rem] absolute'>
|
||||||
<BiInfoCircle size='1.25rem' className='clr-text-primary' />
|
<BiInfoCircle size='1.25rem' className='clr-text-primary' />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
<ConceptTooltip anchorSelect={`#${globalIDs.password_tooltip}`} offset={6}>
|
<Tooltip anchorSelect={`#${globalIDs.password_tooltip}`} offset={6}>
|
||||||
<p>- используйте уникальный пароль</p>
|
<p>- используйте уникальный пароль</p>
|
||||||
<p>- портал функционирует в тестовом режиме</p>
|
<p>- портал функционирует в тестовом режиме</p>
|
||||||
</ConceptTooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { AnimatePresence } from 'framer-motion';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
import { FiBell, FiBellOff } from 'react-icons/fi';
|
import { FiBell, FiBellOff } from 'react-icons/fi';
|
||||||
|
|
||||||
import { ConceptLoader } from '@/components/Common/ConceptLoader';
|
import { Loader } from '@/components/Common/Loader';
|
||||||
import MiniButton from '@/components/Common/MiniButton';
|
import MiniButton from '@/components/Common/MiniButton';
|
||||||
import Overlay from '@/components/Common/Overlay';
|
import Overlay from '@/components/Common/Overlay';
|
||||||
import InfoError from '@/components/InfoError';
|
import InfoError from '@/components/InfoError';
|
||||||
|
@ -29,7 +29,7 @@ function UserTabs() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{loading ? <ConceptLoader /> : null}
|
{loading ? <Loader /> : null}
|
||||||
{error ? <InfoError error={error} /> : null}
|
{error ? <InfoError error={error} /> : null}
|
||||||
{user ? (
|
{user ? (
|
||||||
<div className='flex gap-6 py-2'>
|
<div className='flex gap-6 py-2'>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user