F: Animation rework
This commit is contained in:
parent
ce8f2584db
commit
162dfa4bff
822
rsconcept/frontend/package-lock.json
generated
822
rsconcept/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
|
@ -20,7 +20,6 @@
|
|||
"@uiw/react-codemirror": "^4.23.6",
|
||||
"axios": "^1.7.8",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^11.13.1",
|
||||
"html-to-image": "^1.11.11",
|
||||
"js-file-download": "^0.4.12",
|
||||
"react": "^18.3.1",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import useWindowSize from '@/hooks/useWindowSize';
|
||||
|
||||
|
@ -10,7 +8,7 @@ function Logo() {
|
|||
return (
|
||||
<img
|
||||
alt=''
|
||||
className={clsx('max-h-[1.6rem] w-fit max-w-[11.4rem]')}
|
||||
className='max-h-[1.6rem] w-fit max-w-[11.4rem]'
|
||||
src={size.isSmall ? '/logo_sign.svg' : !darkMode ? '/logo_full.svg' : '/logo_full_dark.svg'}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -3,13 +3,22 @@ import clsx from 'clsx';
|
|||
import { CProps } from '@/components/props';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
interface NavigationButtonProps extends CProps.Titled {
|
||||
interface NavigationButtonProps extends CProps.Titled, CProps.Styling {
|
||||
text?: string;
|
||||
icon: React.ReactNode;
|
||||
onClick?: (event: CProps.EventMouse) => void;
|
||||
}
|
||||
|
||||
function NavigationButton({ icon, title, titleHtml, hideTitle, onClick, text }: NavigationButtonProps) {
|
||||
function NavigationButton({
|
||||
icon,
|
||||
title,
|
||||
className,
|
||||
style,
|
||||
titleHtml,
|
||||
hideTitle,
|
||||
onClick,
|
||||
text
|
||||
}: NavigationButtonProps) {
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
|
@ -29,8 +38,10 @@ function NavigationButton({ icon, title, titleHtml, hideTitle, onClick, text }:
|
|||
{
|
||||
'px-2': text,
|
||||
'px-4': !text
|
||||
}
|
||||
},
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
>
|
||||
{icon ? <span>{icon}</span> : null}
|
||||
{text ? <span className='hidden sm:inline'>{text}</span> : null}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { IconLogin, IconUser2 } from '@/components/Icons';
|
||||
import Loader from '@/components/ui/Loader';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||
|
@ -19,27 +18,21 @@ function UserMenu() {
|
|||
const navigateLogin = () => router.push(urls.login);
|
||||
return (
|
||||
<div ref={menu.ref} className='h-full w-[4rem] flex items-center justify-center'>
|
||||
{loading ? (
|
||||
<AnimateFade key='nav_user_badge_loader'>
|
||||
<Loader circular scale={1.5} />
|
||||
</AnimateFade>
|
||||
) : null}
|
||||
{loading ? <Loader circular scale={1.5} /> : null}
|
||||
{!user && !loading ? (
|
||||
<AnimateFade key='nav_user_badge_login' className='h-full'>
|
||||
<NavigationButton
|
||||
className='cc-fade-in'
|
||||
title='Перейти на страницу логина'
|
||||
icon={<IconLogin size='1.5rem' className='icon-primary' />}
|
||||
onClick={navigateLogin}
|
||||
/>
|
||||
</AnimateFade>
|
||||
) : null}
|
||||
{user ? (
|
||||
<AnimateFade key='nav_user_badge_profile' className='h-full'>
|
||||
<NavigationButton
|
||||
className='cc-fade-in'
|
||||
icon={<IconUser2 size='1.5rem' className={adminMode && user.is_staff ? 'icon-primary' : ''} />}
|
||||
onClick={menu.toggle}
|
||||
/>
|
||||
</AnimateFade>
|
||||
) : null}
|
||||
<UserDropdown isOpen={!!user && menu.isOpen} hideDropdown={() => menu.hide()} />
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,6 @@ import clsx from 'clsx';
|
|||
import { isResponseHtml } from '@/utils/utils';
|
||||
|
||||
import PrettyJson from '../ui/PrettyJSON';
|
||||
import AnimateFade from '../wrap/AnimateFade';
|
||||
|
||||
export type ErrorData = string | Error | AxiosError | undefined;
|
||||
|
||||
|
@ -59,8 +58,9 @@ function DescribeError({ error }: { error: ErrorData }) {
|
|||
|
||||
function InfoError({ error }: InfoErrorProps) {
|
||||
return (
|
||||
<AnimateFade
|
||||
<div
|
||||
className={clsx(
|
||||
'cc-fade-in',
|
||||
'min-w-[25rem]',
|
||||
'px-3 py-2 flex flex-col',
|
||||
'clr-text-red',
|
||||
|
@ -75,7 +75,7 @@ function InfoError({ error }: InfoErrorProps) {
|
|||
</div>
|
||||
|
||||
<DescribeError error={error} />
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
6
rsconcept/frontend/src/components/props.d.ts
vendored
6
rsconcept/frontend/src/components/props.d.ts
vendored
|
@ -1,6 +1,5 @@
|
|||
// =========== Module contains interfaces for common UI elements. ==========
|
||||
import { animated } from '@react-spring/web';
|
||||
import { HTMLMotionProps } from 'framer-motion';
|
||||
import React from 'react';
|
||||
|
||||
export namespace CProps {
|
||||
|
@ -90,11 +89,6 @@ export namespace CProps {
|
|||
*/
|
||||
export type Input = Titled & React.ComponentProps<'input'>;
|
||||
|
||||
/**
|
||||
* Represents `button` component with optional title and animation properties.
|
||||
*/
|
||||
export type AnimatedButton = Titled & Omit<HTMLMotionProps<'button'>, 'type'>;
|
||||
|
||||
/**
|
||||
* Represents `div` component with animation properties.
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
import { animateDropdown } from '@/styling/animations';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
|
@ -25,11 +24,12 @@ function Dropdown({
|
|||
stretchTop,
|
||||
className,
|
||||
children,
|
||||
style,
|
||||
...restProps
|
||||
}: React.PropsWithChildren<DropdownProps>) {
|
||||
return (
|
||||
<div className='relative'>
|
||||
<motion.div
|
||||
<div
|
||||
tabIndex={-1}
|
||||
className={clsx(
|
||||
'z-topmost',
|
||||
|
@ -45,13 +45,18 @@ function Dropdown({
|
|||
},
|
||||
className
|
||||
)}
|
||||
initial={false}
|
||||
animate={isOpen ? 'open' : 'closed'}
|
||||
variants={animateDropdown}
|
||||
style={{
|
||||
transitionProperty: 'clip-path, transform',
|
||||
transitionDuration: `${PARAMETER.dropdownDuration}ms`,
|
||||
transitionTimingFunction: 'ease-in-out',
|
||||
transform: isOpen ? 'translateY(0)' : 'translateY(-10%)',
|
||||
clipPath: isOpen ? 'inset(0% 0% 0% 0%)' : 'inset(10% 0% 90% 0%)',
|
||||
...style
|
||||
}}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
import { animateDropdownItem } from '@/styling/animations';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
import { CProps } from '../props';
|
||||
|
||||
interface DropdownButtonProps extends CProps.AnimatedButton {
|
||||
interface DropdownButtonProps extends CProps.Button {
|
||||
/** Icon to display first (not used if children are provided). */
|
||||
icon?: React.ReactNode;
|
||||
|
||||
|
@ -18,7 +16,7 @@ interface DropdownButtonProps extends CProps.AnimatedButton {
|
|||
}
|
||||
|
||||
/**
|
||||
* Animated `button` with optional text, icon, and click functionality.
|
||||
* `button` with optional text, icon, and click functionality styled for use in a {@link Dropdown}.
|
||||
* It supports optional children for custom content or the default text/icon display.
|
||||
*/
|
||||
function DropdownButton({
|
||||
|
@ -33,7 +31,7 @@ function DropdownButton({
|
|||
...restProps
|
||||
}: DropdownButtonProps) {
|
||||
return (
|
||||
<motion.button
|
||||
<button
|
||||
tabIndex={-1}
|
||||
type='button'
|
||||
onClick={onClick}
|
||||
|
@ -48,7 +46,6 @@ function DropdownButton({
|
|||
},
|
||||
className
|
||||
)}
|
||||
variants={animateDropdownItem}
|
||||
data-tooltip-id={!!title || !!titleHtml ? globals.tooltip : undefined}
|
||||
data-tooltip-html={titleHtml}
|
||||
data-tooltip-content={title}
|
||||
|
@ -58,7 +55,7 @@ function DropdownButton({
|
|||
{children ? children : null}
|
||||
{!children && icon ? icon : null}
|
||||
{!children && text ? <span>{text}</span> : null}
|
||||
</motion.button>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
import { animateDropdownItem } from '@/styling/animations';
|
||||
|
||||
import Checkbox, { CheckboxProps } from './Checkbox';
|
||||
|
||||
/** Animated {@link Checkbox} inside a {@link Dropdown} item. */
|
||||
function DropdownCheckbox({ setValue, disabled, ...restProps }: CheckboxProps) {
|
||||
return (
|
||||
<motion.div
|
||||
variants={animateDropdownItem}
|
||||
<div
|
||||
className={clsx(
|
||||
'px-3 py-1',
|
||||
'text-left overflow-ellipsis whitespace-nowrap',
|
||||
|
@ -18,7 +14,7 @@ function DropdownCheckbox({ setValue, disabled, ...restProps }: CheckboxProps) {
|
|||
)}
|
||||
>
|
||||
<Checkbox tabIndex={-1} disabled={disabled} setValue={setValue} {...restProps} />
|
||||
</motion.div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
import { animateDropdownItem } from '@/styling/animations';
|
||||
|
||||
import { DividerProps } from './Divider';
|
||||
|
||||
/**
|
||||
* {@link Divider} with animation inside {@link Dropdown}.
|
||||
*/
|
||||
function DropdownDivider({ vertical, margins = 'mx-2', className, ...restProps }: DividerProps) {
|
||||
return (
|
||||
<motion.div
|
||||
variants={animateDropdownItem}
|
||||
className={clsx(
|
||||
margins, //prettier: split-lines
|
||||
className,
|
||||
{
|
||||
'border-x': vertical,
|
||||
'border-y': !vertical
|
||||
}
|
||||
)}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default DropdownDivider;
|
|
@ -1,11 +1,9 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
|
||||
import useEscapeKey from '@/hooks/useEscapeKey';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import { animateModal } from '@/styling/animations';
|
||||
import { PARAMETER } from '@/utils/constants';
|
||||
import { prepareTooltip } from '@/utils/labels';
|
||||
|
||||
|
@ -100,17 +98,12 @@ function Modal({
|
|||
className={clsx('z-navigation', 'fixed top-0 left-0', 'w-full h-full', 'cc-modal-backdrop')}
|
||||
onClick={hideWindow}
|
||||
/>
|
||||
<motion.div
|
||||
<div
|
||||
className={clsx(
|
||||
'z-modal',
|
||||
'absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-1/2',
|
||||
'border rounded-xl',
|
||||
'clr-app'
|
||||
'cc-animate-modal',
|
||||
'z-modal absolute bottom-1/2 left-1/2 -translate-x-1/2 translate-y-1/2',
|
||||
'border rounded-xl clr-app'
|
||||
)}
|
||||
initial={{ ...animateModal.initial }}
|
||||
animate={{ ...animateModal.animate }}
|
||||
exit={{ ...animateModal.exit }}
|
||||
{...restProps}
|
||||
>
|
||||
<Overlay position='right-2 top-2'>
|
||||
<MiniButton
|
||||
|
@ -137,6 +130,7 @@ function Modal({
|
|||
},
|
||||
className
|
||||
)}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
@ -155,7 +149,7 @@ function Modal({
|
|||
) : null}
|
||||
<Button text={readonly ? 'Закрыть' : 'Отмена'} className='min-w-[7rem]' onClick={handleCancel} />
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,41 +1,25 @@
|
|||
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;
|
||||
|
||||
interface DataLoaderProps {
|
||||
isLoading?: boolean;
|
||||
error?: ErrorData;
|
||||
hasNoData?: boolean;
|
||||
}
|
||||
|
||||
function DataLoader({
|
||||
id,
|
||||
isLoading,
|
||||
hasNoData,
|
||||
error,
|
||||
className,
|
||||
children,
|
||||
...restProps
|
||||
}: React.PropsWithChildren<DataLoaderProps>) {
|
||||
return (
|
||||
<>
|
||||
{!isLoading && !error && !hasNoData ? (
|
||||
<AnimateFade id={id} key={`${id}-data`} className={className} {...restProps}>
|
||||
{children}
|
||||
</AnimateFade>
|
||||
) : null}
|
||||
{!isLoading && !error && hasNoData ? (
|
||||
<AnimateFade key={`${id}-no-data`} className='w-full text-center p-1' {...restProps}>
|
||||
Данные не загружены
|
||||
</AnimateFade>
|
||||
) : null}
|
||||
{isLoading ? <Loader key={`${id}-loader`} /> : null}
|
||||
{error ? <InfoError key={`${id}-error`} error={error} /> : null}
|
||||
</>
|
||||
);
|
||||
function DataLoader({ isLoading, hasNoData, error, children }: React.PropsWithChildren<DataLoaderProps>) {
|
||||
if (isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
if (error) {
|
||||
return <InfoError error={error} />;
|
||||
}
|
||||
|
||||
if (hasNoData) {
|
||||
return <div className='cc-fade-in w-full text-center p-1'>Данные не загружены</div>;
|
||||
} else {
|
||||
return <>{children}</>;
|
||||
}
|
||||
}
|
||||
|
||||
export default DataLoader;
|
||||
|
|
|
@ -13,7 +13,7 @@ function ExpectedAnonymous() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className='flex flex-col items-center gap-3 py-6'>
|
||||
<div className='cc-fade-in flex flex-col items-center gap-3 py-6'>
|
||||
<p className='font-semibold'>{`Вы вошли в систему как ${user?.username ?? ''}`}</p>
|
||||
<div className='flex gap-3'>
|
||||
<TextURL text='Новая схема' href='/library/create' />
|
||||
|
|
|
@ -4,25 +4,25 @@ import { useAuth } from '@/context/AuthContext';
|
|||
|
||||
import Loader from '../ui/Loader';
|
||||
import TextURL from '../ui/TextURL';
|
||||
import AnimateFade from './AnimateFade';
|
||||
|
||||
function RequireAuth({ children }: React.PropsWithChildren) {
|
||||
const { user, loading } = useAuth();
|
||||
|
||||
if (loading) {
|
||||
return <Loader key='auth-loader' />;
|
||||
}
|
||||
if (user) {
|
||||
return <>{children}</>;
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
{loading ? <Loader key='auth-loader' /> : null}
|
||||
{!loading && user ? <AnimateFade key='auth-data'>{children}</AnimateFade> : null}
|
||||
{!loading && !user ? (
|
||||
<AnimateFade key='auth-no-user' className='flex flex-col items-center gap-1 mt-2'>
|
||||
<div key='auth-no-user' className='flex flex-col items-center gap-1 mt-2'>
|
||||
<p className='mb-2'>Пожалуйста войдите в систему</p>
|
||||
<TextURL text='Войти в Портал' href='/login' />
|
||||
<TextURL text='Зарегистрироваться' href='/signup' />
|
||||
<TextURL text='Начальная страница' href='/' />
|
||||
</AnimateFade>
|
||||
) : null}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RequireAuth;
|
||||
|
|
|
@ -6,7 +6,6 @@ import { TabList, TabPanel, Tabs } from 'react-tabs';
|
|||
|
||||
import Modal, { ModalProps } from '@/components/ui/Modal';
|
||||
import TabLabel from '@/components/ui/TabLabel';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useLibrary } from '@/context/LibraryContext';
|
||||
import usePartialUpdate from '@/hooks/usePartialUpdate';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
|
@ -145,9 +144,9 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
|||
const editorPanel = useMemo(
|
||||
() => (
|
||||
<TabPanel>
|
||||
<AnimateFade className='cc-column'>
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<FormCreateCst state={constituenta} partialUpdate={updateConstituenta} schema={schema} />
|
||||
</AnimateFade>
|
||||
</div>
|
||||
</TabPanel>
|
||||
),
|
||||
[constituenta, updateConstituenta, schema]
|
||||
|
|
|
@ -10,7 +10,6 @@ import PickConstituenta from '@/components/select/PickConstituenta';
|
|||
import DataTable, { IConditionalStyle } from '@/components/ui/DataTable';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import NoData from '@/components/ui/NoData';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { IConstituenta, IRSForm } from '@/models/rsform';
|
||||
import { IArgumentValue } from '@/models/rslang';
|
||||
|
@ -147,7 +146,7 @@ function TabArguments({ state, schema, partialUpdate }: TabArgumentsProps) {
|
|||
);
|
||||
|
||||
return (
|
||||
<AnimateFade>
|
||||
<div className='cc-fade-in'>
|
||||
<DataTable
|
||||
dense
|
||||
noFooter
|
||||
|
@ -224,7 +223,7 @@ function TabArguments({ state, schema, partialUpdate }: TabArgumentsProps) {
|
|||
height='5.1rem'
|
||||
value={state.definition}
|
||||
/>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import RSInput from '@/components/RSInput';
|
|||
import PickConstituenta from '@/components/select/PickConstituenta';
|
||||
import SelectSingle from '@/components/ui/SelectSingle';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useLibrary } from '@/context/LibraryContext';
|
||||
import { CATEGORY_CST_TYPE, IConstituenta, IRSForm } from '@/models/rsform';
|
||||
import { applyFilterCategory } from '@/models/rsformAPI';
|
||||
|
@ -78,7 +77,7 @@ function TabTemplate({ state, partialUpdate, templateSchema }: TabTemplateProps)
|
|||
}, [state.filterCategory, templateSchema]);
|
||||
|
||||
return (
|
||||
<AnimateFade>
|
||||
<div className='cc-fade-in'>
|
||||
<div className='flex border-t border-x rounded-t-md clr-input'>
|
||||
<SelectSingle
|
||||
noBorder
|
||||
|
@ -138,7 +137,7 @@ function TabTemplate({ state, partialUpdate, templateSchema }: TabTemplateProps)
|
|||
height='5.1rem'
|
||||
value={state.prototype?.definition_formal}
|
||||
/>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import Label from '@/components/ui/Label';
|
|||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useLibrary } from '@/context/LibraryContext';
|
||||
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library';
|
||||
import { IOperationSchema } from '@/models/oss';
|
||||
|
@ -53,7 +52,7 @@ function TabInputOperation({
|
|||
}, [createSchema, onChangeAttachedID]);
|
||||
|
||||
return (
|
||||
<AnimateFade className='cc-column'>
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<TextInput
|
||||
id='operation_title'
|
||||
label='Полное название'
|
||||
|
@ -111,7 +110,7 @@ function TabInputOperation({
|
|||
baseFilter={baseFilter}
|
||||
/>
|
||||
) : null}
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import FlexColumn from '@/components/ui/FlexColumn';
|
|||
import Label from '@/components/ui/Label';
|
||||
import TextArea from '@/components/ui/TextArea';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { IOperationSchema, OperationID } from '@/models/oss';
|
||||
|
||||
import PickMultiOperation from '../../components/select/PickMultiOperation';
|
||||
|
@ -31,7 +30,7 @@ function TabSynthesisOperation({
|
|||
setInputs
|
||||
}: TabSynthesisOperationProps) {
|
||||
return (
|
||||
<AnimateFade className='cc-column'>
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<TextInput
|
||||
id='operation_title'
|
||||
label='Полное название'
|
||||
|
@ -61,7 +60,7 @@ function TabSynthesisOperation({
|
|||
<Label text={`Выбор аргументов: [ ${inputs.length} ]`} />
|
||||
<PickMultiOperation items={oss.items} selected={inputs} setSelected={setInputs} rows={6} />
|
||||
</FlexColumn>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import { useMemo } from 'react';
|
|||
import PickMultiOperation from '@/components/select/PickMultiOperation';
|
||||
import FlexColumn from '@/components/ui/FlexColumn';
|
||||
import Label from '@/components/ui/Label';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { IOperationSchema, OperationID } from '@/models/oss';
|
||||
|
||||
interface TabArgumentsProps {
|
||||
|
@ -22,12 +21,12 @@ function TabArguments({ oss, inputs, target, setInputs }: TabArgumentsProps) {
|
|||
[oss.items, potentialCycle]
|
||||
);
|
||||
return (
|
||||
<AnimateFade className='cc-column'>
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<FlexColumn>
|
||||
<Label text={`Выбор аргументов: [ ${inputs.length} ]`} />
|
||||
<PickMultiOperation items={filtered} selected={inputs} setSelected={setInputs} rows={8} />
|
||||
</FlexColumn>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import TextArea from '@/components/ui/TextArea';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
|
||||
interface TabOperationProps {
|
||||
alias: string;
|
||||
|
@ -13,7 +12,7 @@ interface TabOperationProps {
|
|||
|
||||
function TabOperation({ alias, onChangeAlias, title, onChangeTitle, comment, onChangeComment }: TabOperationProps) {
|
||||
return (
|
||||
<AnimateFade className='cc-column'>
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<TextInput
|
||||
id='operation_title'
|
||||
label='Полное название'
|
||||
|
@ -38,7 +37,7 @@ function TabOperation({ alias, onChangeAlias, title, onChangeTitle, comment, onC
|
|||
onChange={event => onChangeComment(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@ function TabSynthesis({
|
|||
}: TabSynthesisProps) {
|
||||
const { colors } = useConceptOptions();
|
||||
return (
|
||||
<DataLoader id='dlg-synthesis-tab' className='cc-column mt-3' isLoading={loading} error={error}>
|
||||
<DataLoader isLoading={loading} error={error}>
|
||||
<div className='cc-fade-in cc-column mt-3'>
|
||||
<PickSubstitutions
|
||||
schemas={schemas}
|
||||
prefixID={prefixes.dlg_cst_substitutes_list}
|
||||
|
@ -46,6 +47,7 @@ function TabSynthesis({
|
|||
rows={4}
|
||||
style={{ borderColor: isCorrect ? undefined : colors.fgRed }}
|
||||
/>
|
||||
</div>
|
||||
</DataLoader>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import PickConstituenta from '@/components/select/PickConstituenta';
|
|||
import SelectMultiGrammeme from '@/components/select/SelectMultiGrammeme';
|
||||
import Label from '@/components/ui/Label';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { ReferenceType } from '@/models/language';
|
||||
import { parseEntityReference, parseGrammemes } from '@/models/languageAPI';
|
||||
import { CstMatchMode } from '@/models/miscellaneous';
|
||||
|
@ -59,7 +58,7 @@ function TabEntityReference({ initial, schema, onChangeValid, onChangeReference
|
|||
}
|
||||
|
||||
return (
|
||||
<AnimateFade className='cc-column'>
|
||||
<div className='cc-fade-in cc-column'>
|
||||
<PickConstituenta
|
||||
id='dlg_reference_entity_picker'
|
||||
initialFilter={initial.text}
|
||||
|
@ -108,7 +107,7 @@ function TabEntityReference({ initial, schema, onChangeValid, onChangeReference
|
|||
onChangeValue={setSelectedGrams}
|
||||
/>
|
||||
</div>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import { useEffect, useLayoutEffect, useMemo, useState } from 'react';
|
||||
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { ReferenceType } from '@/models/language';
|
||||
import { parseSyntacticReference } from '@/models/languageAPI';
|
||||
|
||||
|
@ -44,7 +43,7 @@ function TabSyntacticReference({ initial, onChangeValid, onChangeReference }: Ta
|
|||
}, [nominal, offset, onChangeValid, onChangeReference]);
|
||||
|
||||
return (
|
||||
<AnimateFade className='flex flex-col gap-2'>
|
||||
<div className='cc-fade-in flex flex-col gap-2'>
|
||||
<TextInput
|
||||
id='dlg_reference_offset'
|
||||
type='number'
|
||||
|
@ -70,7 +69,7 @@ function TabSyntacticReference({ initial, onChangeValid, onChangeReference }: Ta
|
|||
value={nominal}
|
||||
onChange={event => setNominal(event.target.value)}
|
||||
/>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ interface TabConstituentsProps {
|
|||
|
||||
function TabConstituents({ schema, error, loading, selected, setSelected }: TabConstituentsProps) {
|
||||
return (
|
||||
<DataLoader id='dlg-constituents-tab' isLoading={loading} error={error} hasNoData={!schema}>
|
||||
<DataLoader isLoading={loading} error={error} hasNoData={!schema}>
|
||||
{schema ? (
|
||||
<PickMultiConstituenta
|
||||
schema={schema}
|
||||
|
|
|
@ -4,7 +4,6 @@ import { useMemo } from 'react';
|
|||
|
||||
import PickSchema from '@/components/select/PickSchema';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useLibrary } from '@/context/LibraryContext';
|
||||
import { LibraryItemID, LibraryItemType } from '@/models/library';
|
||||
import { IRSForm } from '@/models/rsform';
|
||||
|
@ -22,7 +21,7 @@ function TabSchema({ selected, receiver, setSelected }: TabSchemaProps) {
|
|||
const sortedItems = useMemo(() => sortItemsForInlineSynthesis(receiver, library.items), [receiver, library.items]);
|
||||
|
||||
return (
|
||||
<AnimateFade className='flex flex-col'>
|
||||
<div className='cc-fade-in flex flex-col'>
|
||||
<PickSchema
|
||||
id='dlg_schema_picker' // prettier: split lines
|
||||
items={sortedItems}
|
||||
|
@ -43,7 +42,7 @@ function TabSchema({ selected, receiver, setSelected }: TabSchemaProps) {
|
|||
dense
|
||||
/>
|
||||
</div>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ function TabSubstitutions({
|
|||
const schemas = useMemo(() => [...(source ? [source] : []), ...(receiver ? [receiver] : [])], [source, receiver]);
|
||||
|
||||
return (
|
||||
<DataLoader id='dlg-substitutions-tab' className='cc-column' isLoading={loading} error={error} hasNoData={!source}>
|
||||
<DataLoader isLoading={loading} error={error} hasNoData={!source}>
|
||||
<PickSubstitutions
|
||||
substitutions={substitutions}
|
||||
setSubstitutions={setSubstitutions}
|
||||
|
|
|
@ -118,7 +118,7 @@ function DlgRelocateConstituents({ oss, hideWindow, initialTarget, onSubmit }: D
|
|||
onSelectValue={handleSelectDestination}
|
||||
/>
|
||||
</div>
|
||||
<DataLoader id='dlg-relocate-constituents' isLoading={sourceData.loading} error={sourceData.error}>
|
||||
<DataLoader isLoading={sourceData.loading} error={sourceData.error}>
|
||||
{sourceData.schema ? (
|
||||
<PickMultiConstituenta
|
||||
noBorder
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import RequireAuth from '@/components/wrap/RequireAuth';
|
||||
|
||||
import FormCreateItem from './FormCreateItem';
|
||||
|
||||
function CreateItemPage() {
|
||||
return (
|
||||
<AnimateFade>
|
||||
<RequireAuth>
|
||||
<FormCreateItem />
|
||||
</RequireAuth>
|
||||
</AnimateFade>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -122,7 +122,10 @@ function FormCreateItem() {
|
|||
}, [itemType]);
|
||||
|
||||
return (
|
||||
<form className={clsx('cc-column', 'min-w-[30rem] max-w-[30rem] mx-auto', 'px-6 py-3')} onSubmit={handleSubmit}>
|
||||
<form
|
||||
className={clsx('cc-fade-in cc-column', 'min-w-[30rem] max-w-[30rem] mx-auto', 'px-6 py-3')}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<h1 className='select-none'>
|
||||
{itemType == LibraryItemType.RSFORM ? (
|
||||
<Overlay position='top-0 right-[0.5rem]'>
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import { useLayoutEffect, useMemo } from 'react';
|
||||
import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch';
|
||||
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { resources } from '@/utils/constants';
|
||||
|
||||
|
@ -18,13 +17,13 @@ function DatabaseSchemaPage() {
|
|||
}, [setNoFooter]);
|
||||
|
||||
return (
|
||||
<AnimateFade className='flex justify-center overflow-hidden' style={{ maxHeight: panelHeight }}>
|
||||
<div className='cc-fade-in flex justify-center overflow-hidden' style={{ maxHeight: panelHeight }}>
|
||||
<TransformWrapper>
|
||||
<TransformComponent>
|
||||
<img alt='Схема базы данных' src={resources.db_schema} className='w-fit h-fit' />
|
||||
</TransformComponent>
|
||||
</TransformWrapper>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -172,12 +172,7 @@ function LibraryPage() {
|
|||
);
|
||||
|
||||
return (
|
||||
<DataLoader
|
||||
id='library-page' // prettier: split lines
|
||||
isLoading={library.loading}
|
||||
error={library.loadingError}
|
||||
hasNoData={library.items.length === 0}
|
||||
>
|
||||
<DataLoader isLoading={library.loading} error={library.loadingError} hasNoData={library.items.length === 0}>
|
||||
{showRenameLocation ? (
|
||||
<DlgChangeLocation
|
||||
initial={options.location}
|
||||
|
@ -219,7 +214,7 @@ function LibraryPage() {
|
|||
toggleFolderMode={toggleFolderMode}
|
||||
/>
|
||||
|
||||
<div className='flex'>
|
||||
<div className='cc-fade-in flex'>
|
||||
{viewLocations}
|
||||
{viewLibrary}
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
'use client';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { LocationIcon, VisibilityIcon } from '@/components/DomainIcons';
|
||||
|
@ -25,7 +24,6 @@ import { useUsers } from '@/context/UsersContext';
|
|||
import useDropdown from '@/hooks/useDropdown';
|
||||
import { LocationHead } from '@/models/library';
|
||||
import { UserID } from '@/models/user';
|
||||
import { animateDropdownItem } from '@/styling/animations';
|
||||
import { prefixes } from '@/utils/constants';
|
||||
import { describeLocationHead, labelLocationHead } from '@/utils/labels';
|
||||
import { tripleToggleColor } from '@/utils/utils';
|
||||
|
@ -163,16 +161,14 @@ function ToolbarSearch({
|
|||
icon={<IconEditor size='1.25rem' className={tripleToggleColor(isEditor)} />}
|
||||
onClick={toggleEditor}
|
||||
/>
|
||||
<motion.div className='px-1 pb-1' variants={animateDropdownItem}>
|
||||
<SelectUser
|
||||
noBorder
|
||||
placeholder='Выберите владельца'
|
||||
className='min-w-[15rem] text-sm'
|
||||
className='min-w-[15rem] text-sm mx-1 mb-1'
|
||||
items={users}
|
||||
value={filterUser}
|
||||
onSelectValue={onChangeFilterUser}
|
||||
/>
|
||||
</motion.div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ import InfoError, { ErrorData } from '@/components/info/InfoError';
|
|||
import SubmitButton from '@/components/ui/SubmitButton';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import TextURL from '@/components/ui/TextURL';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import ExpectedAnonymous from '@/components/wrap/ExpectedAnonymous';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||
|
@ -52,8 +51,7 @@ function LoginPage() {
|
|||
return <ExpectedAnonymous />;
|
||||
}
|
||||
return (
|
||||
<AnimateFade>
|
||||
<form className={clsx('cc-column', 'w-[24rem] mx-auto', 'pt-12 pb-6 px-6')} onSubmit={handleSubmit}>
|
||||
<form className={clsx('cc-column cc-fade-in', 'w-[24rem] mx-auto', 'pt-12 pb-6 px-6')} onSubmit={handleSubmit}>
|
||||
<img alt='Концепт Портал' src={resources.logo} className='max-h-[2.5rem] min-w-[2.5rem] mb-3' />
|
||||
<TextInput
|
||||
id='username'
|
||||
|
@ -89,7 +87,6 @@ function LoginPage() {
|
|||
</div>
|
||||
{error ? <ProcessError error={error} /> : null}
|
||||
</form>
|
||||
</AnimateFade>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
'use client';
|
||||
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { HelpTopic } from '@/models/miscellaneous';
|
||||
import TopicPage from '@/pages/ManualsPage/TopicPage';
|
||||
|
@ -12,13 +11,13 @@ interface ViewTopicProps {
|
|||
function ViewTopic({ topic }: ViewTopicProps) {
|
||||
const { mainHeight } = useConceptOptions();
|
||||
return (
|
||||
<AnimateFade
|
||||
<div
|
||||
key={topic}
|
||||
className='py-2 px-6 mx-auto sm:mx-0 lg:px-12 overflow-y-auto'
|
||||
className='cc-fade-in py-2 px-6 mx-auto sm:mx-0 lg:px-12 overflow-y-auto'
|
||||
style={{ maxHeight: mainHeight }}
|
||||
>
|
||||
<TopicPage topic={topic} />
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import FlexColumn from '@/components/ui/FlexColumn';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useOSS } from '@/context/OssContext';
|
||||
import EditorLibraryItem from '@/pages/RSFormPage/EditorRSFormCard/EditorLibraryItem';
|
||||
import ToolbarRSFormCard from '@/pages/RSFormPage/EditorRSFormCard/ToolbarRSFormCard';
|
||||
|
@ -47,9 +46,14 @@ function EditorOssCard({ isModified, onDestroy, setIsModified }: EditorOssCardPr
|
|||
onDestroy={onDestroy}
|
||||
controller={controller}
|
||||
/>
|
||||
<AnimateFade
|
||||
<div
|
||||
onKeyDown={handleInput}
|
||||
className={clsx('md:w-fit md:max-w-fit max-w-[32rem]', 'mx-auto pt-[1.9rem]', 'flex flex-row flex-wrap px-6')}
|
||||
className={clsx(
|
||||
'cc-fade-in',
|
||||
'md:w-fit md:max-w-fit max-w-[32rem]',
|
||||
'mx-auto pt-[1.9rem]',
|
||||
'flex flex-row flex-wrap px-6'
|
||||
)}
|
||||
>
|
||||
<FlexColumn className='px-3'>
|
||||
<FormOSS id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} />
|
||||
|
@ -57,7 +61,7 @@ function EditorOssCard({ isModified, onDestroy, setIsModified }: EditorOssCardPr
|
|||
</FlexColumn>
|
||||
|
||||
{schema ? <OssStats stats={schema.stats} /> : null}
|
||||
</AnimateFade>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ import {
|
|||
|
||||
import { CProps } from '@/components/props';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { useOSS } from '@/context/OssContext';
|
||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||
|
@ -349,7 +348,7 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
);
|
||||
|
||||
return (
|
||||
<AnimateFade tabIndex={-1} onKeyDown={handleKeyDown}>
|
||||
<div tabIndex={-1} onKeyDown={handleKeyDown}>
|
||||
<Overlay position='top-[1.9rem] pt-1 right-1/2 translate-x-1/2' className='rounded-b-2xl cc-blur'>
|
||||
<ToolbarOssGraph
|
||||
isModified={isModified}
|
||||
|
@ -381,10 +380,10 @@ function OssFlow({ isModified, setIsModified }: OssFlowProps) {
|
|||
{...menuProps}
|
||||
/>
|
||||
) : null}
|
||||
<div className='relative w-[100vw]' style={{ height: mainHeight, fontFamily: 'Rubik' }}>
|
||||
<div className='cc-fade-in relative w-[100vw]' style={{ height: mainHeight, fontFamily: 'Rubik' }}>
|
||||
{graph}
|
||||
</div>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@ import {
|
|||
IconShare
|
||||
} from '@/components/Icons';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Divider from '@/components/ui/Divider';
|
||||
import Dropdown from '@/components/ui/Dropdown';
|
||||
import DropdownButton from '@/components/ui/DropdownButton';
|
||||
import DropdownDivider from '@/components/ui/DropdownDivider';
|
||||
import { useAccessMode } from '@/context/AccessModeContext';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||
|
@ -102,7 +102,7 @@ function MenuOssTabs({ onDestroy }: MenuOssTabsProps) {
|
|||
/>
|
||||
) : null}
|
||||
|
||||
<DropdownDivider margins='mx-3 my-1' />
|
||||
<Divider margins='mx-3 my-1' />
|
||||
|
||||
{user ? (
|
||||
<DropdownButton
|
||||
|
|
|
@ -12,7 +12,6 @@ import Loader from '@/components/ui/Loader';
|
|||
import Overlay from '@/components/ui/Overlay';
|
||||
import TabLabel from '@/components/ui/TabLabel';
|
||||
import TextURL from '@/components/ui/TextURL';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { useLibrary } from '@/context/LibraryContext';
|
||||
|
@ -151,10 +150,10 @@ function OssTabs() {
|
|||
</TabList>
|
||||
</Overlay>
|
||||
|
||||
<AnimateFade>
|
||||
<div className='overflow-x-hidden'>
|
||||
{cardPanel}
|
||||
{graphPanel}
|
||||
</AnimateFade>
|
||||
</div>
|
||||
</Tabs>
|
||||
) : null}
|
||||
</OssEditState>
|
||||
|
|
|
@ -65,12 +65,8 @@ function PasswordChangePage() {
|
|||
return <ProcessError error={error} />;
|
||||
}
|
||||
return (
|
||||
<DataLoader
|
||||
id='password-change-page' //
|
||||
isLoading={loading}
|
||||
hasNoData={!isTokenValid}
|
||||
>
|
||||
<form className={clsx('cc-column', 'w-[24rem] mx-auto', 'px-6 mt-3')} onSubmit={handleSubmit}>
|
||||
<DataLoader isLoading={loading} hasNoData={!isTokenValid}>
|
||||
<form className={clsx('cc-fade-in cc-column', 'w-[24rem] mx-auto', 'px-6 mt-3')} onSubmit={handleSubmit}>
|
||||
<TextInput
|
||||
id='new_password'
|
||||
type='password'
|
||||
|
|
|
@ -87,14 +87,16 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
|
|||
onReset={() => setToggleReset(prev => !prev)}
|
||||
onToggleList={() => setShowList(prev => !prev)}
|
||||
/>
|
||||
<div className='pt-[1.9rem] overflow-y-auto overflow-x-clip min-h-[20rem]' style={{ maxHeight: mainHeight }}>
|
||||
<div
|
||||
tabIndex={-1}
|
||||
className={clsx(
|
||||
'max-w-[95rem] mx-auto', // prettier: split lines
|
||||
'flex',
|
||||
'cc-fade-in',
|
||||
'min-h-[20rem] max-w-[95rem] mx-auto',
|
||||
'flex pt-[1.9rem]',
|
||||
'overflow-y-auto overflow-x-clip',
|
||||
{ 'flex-col md:items-center': isNarrow }
|
||||
)}
|
||||
style={{ maxHeight: mainHeight }}
|
||||
onKeyDown={handleInput}
|
||||
>
|
||||
<FormConstituenta
|
||||
|
@ -117,7 +119,6 @@ function EditorConstituenta({ activeCst, isModified, setIsModified, onOpenEdit }
|
|||
onOpenEdit={onOpenEdit}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -154,7 +154,7 @@ function FormConstituenta({
|
|||
}
|
||||
|
||||
return (
|
||||
<AnimateFade className='mx-0 md:mx-auto pt-[2rem] xs:pt-0'>
|
||||
<div className='mx-0 md:mx-auto pt-[2rem] xs:pt-0'>
|
||||
{showTypification && state ? (
|
||||
<DlgShowTypeGraph items={typeInfo ? [typeInfo] : []} hideWindow={() => setShowTypification(false)} />
|
||||
) : null}
|
||||
|
@ -293,7 +293,7 @@ function FormConstituenta({
|
|||
</>
|
||||
) : null}
|
||||
</form>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import FlexColumn from '@/components/ui/FlexColumn';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useRSForm } from '@/context/RSFormContext';
|
||||
import { globals } from '@/utils/constants';
|
||||
|
||||
|
@ -47,9 +46,13 @@ function EditorRSFormCard({ isModified, onDestroy, setIsModified }: EditorRSForm
|
|||
onDestroy={onDestroy}
|
||||
controller={controller}
|
||||
/>
|
||||
<AnimateFade
|
||||
<div
|
||||
onKeyDown={handleInput}
|
||||
className={clsx('md:w-fit md:max-w-fit max-w-[32rem] mx-auto', 'flex flex-row flex-wrap px-6 pt-[1.9rem]')}
|
||||
className={clsx(
|
||||
'cc-fade-in',
|
||||
'md:w-fit md:max-w-fit max-w-[32rem] mx-auto',
|
||||
'flex flex-row flex-wrap px-6 pt-[1.9rem]'
|
||||
)}
|
||||
>
|
||||
<FlexColumn className='flex-shrink'>
|
||||
<FormRSForm id={globals.library_item_editor} isModified={isModified} setIsModified={setIsModified} />
|
||||
|
@ -57,7 +60,7 @@ function EditorRSFormCard({ isModified, onDestroy, setIsModified }: EditorRSForm
|
|||
</FlexColumn>
|
||||
|
||||
{model.schema ? <RSFormStats stats={model.schema.stats} isArchive={model.isArchive} /> : null}
|
||||
</AnimateFade>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import { type RowSelectionState } from '@/components/ui/DataTable';
|
|||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import SearchBar from '@/components/ui/SearchBar';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { CstMatchMode } from '@/models/miscellaneous';
|
||||
import { ConstituentaID, CstType, IConstituenta } from '@/models/rsform';
|
||||
|
@ -142,7 +141,7 @@ function EditorRSList({ onOpenEdit }: EditorRSListProps) {
|
|||
return (
|
||||
<>
|
||||
{controller.isContentEditable ? <ToolbarRSList /> : null}
|
||||
<AnimateFade tabIndex={-1} onKeyDown={handleKeyDown} className='pt-[1.9rem]'>
|
||||
<div tabIndex={-1} onKeyDown={handleKeyDown} className='cc-fade-in pt-[1.9rem]'>
|
||||
{controller.isContentEditable ? (
|
||||
<div className='flex items-center border-b'>
|
||||
<div className='px-2'>
|
||||
|
@ -175,7 +174,7 @@ function EditorRSList({ onOpenEdit }: EditorRSListProps) {
|
|||
onEdit={onOpenEdit}
|
||||
onCreateNew={() => controller.createCst(undefined, false)}
|
||||
/>
|
||||
</AnimateFade>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import SelectedCounter from '@/components/info/SelectedCounter';
|
|||
import { CProps } from '@/components/props';
|
||||
import ToolbarGraphSelection from '@/components/select/ToolbarGraphSelection';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import DlgGraphParams from '@/dialogs/DlgGraphParams';
|
||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||
|
@ -383,7 +382,6 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
|||
/>
|
||||
) : null}
|
||||
|
||||
<AnimateFade tabIndex={-1} onKeyDown={handleKeyDown}>
|
||||
<Overlay position='cc-tab-tools' className='flex flex-col items-center rounded-b-2xl cc-blur'>
|
||||
<ToolbarTermGraph
|
||||
noText={filterParams.noText}
|
||||
|
@ -437,6 +435,7 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
|||
) : null}
|
||||
</Overlay>
|
||||
|
||||
<div className='cc-fade-in' tabIndex={-1} onKeyDown={handleKeyDown}>
|
||||
<SelectedCounter
|
||||
hideZero
|
||||
totalCount={controller.schema?.stats?.count_all ?? 0}
|
||||
|
@ -467,8 +466,9 @@ function TGFlow({ onOpenEdit }: TGFlowProps) {
|
|||
{viewHidden}
|
||||
</div>
|
||||
</Overlay>
|
||||
|
||||
{graph}
|
||||
</AnimateFade>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ import {
|
|||
IconUpload
|
||||
} from '@/components/Icons';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Divider from '@/components/ui/Divider';
|
||||
import Dropdown from '@/components/ui/Dropdown';
|
||||
import DropdownButton from '@/components/ui/DropdownButton';
|
||||
import DropdownDivider from '@/components/ui/DropdownDivider';
|
||||
import { useAccessMode } from '@/context/AccessModeContext';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useGlobalOss } from '@/context/GlobalOssContext';
|
||||
|
@ -191,7 +191,7 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
|
|||
/>
|
||||
) : null}
|
||||
|
||||
<DropdownDivider margins='mx-3 my-1' />
|
||||
<Divider margins='mx-3 my-1' />
|
||||
|
||||
{user ? (
|
||||
<DropdownButton
|
||||
|
@ -244,7 +244,7 @@ function MenuRSTabs({ onDestroy }: MenuRSTabsProps) {
|
|||
onClick={handleInlineSynthesis}
|
||||
/>
|
||||
|
||||
<DropdownDivider margins='mx-3 my-1' />
|
||||
<Divider margins='mx-3 my-1' />
|
||||
|
||||
<DropdownButton
|
||||
text='Упорядочить список'
|
||||
|
|
|
@ -13,7 +13,6 @@ import Loader from '@/components/ui/Loader';
|
|||
import Overlay from '@/components/ui/Overlay';
|
||||
import TabLabel from '@/components/ui/TabLabel';
|
||||
import TextURL from '@/components/ui/TextURL';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||
import { useGlobalOss } from '@/context/GlobalOssContext';
|
||||
import { useLibrary } from '@/context/LibraryContext';
|
||||
|
@ -270,12 +269,12 @@ function RSTabs() {
|
|||
</TabList>
|
||||
</Overlay>
|
||||
|
||||
<AnimateFade className='overflow-x-hidden'>
|
||||
<div className='overflow-x-hidden'>
|
||||
{cardPanel}
|
||||
{listPanel}
|
||||
{editorPanel}
|
||||
{graphPanel}
|
||||
</AnimateFade>
|
||||
</div>
|
||||
</Tabs>
|
||||
) : null}
|
||||
</RSEditState>
|
||||
|
|
|
@ -72,7 +72,7 @@ function FormSignup() {
|
|||
}
|
||||
}
|
||||
return (
|
||||
<form className={clsx('cc-column', 'mx-auto w-[36rem]', 'px-6 py-3')} onSubmit={handleSubmit}>
|
||||
<form className={clsx('cc-fade-in cc-column', 'mx-auto w-[36rem]', 'px-6 py-3')} onSubmit={handleSubmit}>
|
||||
<h1>
|
||||
<span>Новый пользователь</span>
|
||||
<Overlay id={globals.password_tooltip} position='top-[5.4rem] left-[3.5rem]'>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Loader from '@/components/ui/Loader';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import ExpectedAnonymous from '@/components/wrap/ExpectedAnonymous';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
|
||||
|
@ -12,17 +11,10 @@ function RegisterPage() {
|
|||
return <Loader />;
|
||||
}
|
||||
if (user) {
|
||||
return (
|
||||
<AnimateFade>
|
||||
<ExpectedAnonymous />
|
||||
</AnimateFade>
|
||||
);
|
||||
return <ExpectedAnonymous />;
|
||||
} else {
|
||||
return <FormSignup />;
|
||||
}
|
||||
return (
|
||||
<AnimateFade key='signup-no-user'>
|
||||
<FormSignup />
|
||||
</AnimateFade>
|
||||
);
|
||||
}
|
||||
|
||||
export default RegisterPage;
|
||||
|
|
|
@ -8,7 +8,6 @@ import InfoError, { ErrorData } from '@/components/info/InfoError';
|
|||
import SubmitButton from '@/components/ui/SubmitButton';
|
||||
import TextInput from '@/components/ui/TextInput';
|
||||
import TextURL from '@/components/ui/TextURL';
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { IRequestPasswordData } from '@/models/user';
|
||||
|
||||
|
@ -32,10 +31,17 @@ function RestorePasswordPage() {
|
|||
setError(undefined);
|
||||
}, [email, setError]);
|
||||
|
||||
if (isCompleted) {
|
||||
return (
|
||||
<AnimateFade>
|
||||
{!isCompleted ? (
|
||||
<form className={clsx('cc-column', 'w-[24rem] mx-auto', 'px-6 mt-3')} onSubmit={handleSubmit}>
|
||||
<div className='cc-fade-in flex flex-col items-center gap-1 mt-3'>
|
||||
<p>На указанную почту отправлены инструкции по восстановлению пароля.</p>
|
||||
<TextURL text='Войти в Портал' href='/login' />
|
||||
<TextURL text='Начальная страница' href='/' />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<form className={clsx('cc-fade-in cc-column', 'w-[24rem] mx-auto', 'px-6 mt-3')} onSubmit={handleSubmit}>
|
||||
<TextInput
|
||||
id='email'
|
||||
autoComplete='email'
|
||||
|
@ -54,16 +60,8 @@ function RestorePasswordPage() {
|
|||
/>
|
||||
{error ? <ProcessError error={error} /> : null}
|
||||
</form>
|
||||
) : null}
|
||||
{isCompleted ? (
|
||||
<div className='flex flex-col items-center gap-1 mt-3'>
|
||||
<p>На указанную почту отправлены инструкции по восстановлению пароля.</p>
|
||||
<TextURL text='Войти в Портал' href='/login' />
|
||||
<TextURL text='Начальная страница' href='/' />
|
||||
</div>
|
||||
) : null}
|
||||
</AnimateFade>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default RestorePasswordPage;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
'use client';
|
||||
|
||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||
import DataLoader from '@/components/wrap/DataLoader';
|
||||
import { useUserProfile } from '@/context/UserProfileContext';
|
||||
|
||||
|
@ -11,21 +10,14 @@ function UserContents() {
|
|||
const { user, error, loading } = useUserProfile();
|
||||
|
||||
return (
|
||||
<DataLoader
|
||||
id='profile-page' // prettier: split lines
|
||||
isLoading={loading}
|
||||
error={error}
|
||||
hasNoData={!user}
|
||||
>
|
||||
<AnimateFade className='flex gap-6 py-2 mx-auto w-fit'>
|
||||
<div className='w-fit'>
|
||||
<DataLoader isLoading={loading} error={error} hasNoData={!user}>
|
||||
<div className='cc-fade-in flex gap-6 py-2 mx-auto w-fit'>
|
||||
<h1 className='mb-4 select-none'>Учетные данные пользователя</h1>
|
||||
<div className='flex py-2'>
|
||||
<EditorProfile />
|
||||
<EditorPassword />
|
||||
</div>
|
||||
</div>
|
||||
</AnimateFade>
|
||||
</DataLoader>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* Module: animations parameters.
|
||||
*/
|
||||
|
||||
import { Variants } from 'framer-motion';
|
||||
|
||||
export const animateDropdown: Variants = {
|
||||
open: {
|
||||
clipPath: 'inset(0% 0% 0% 0%)',
|
||||
transition: {
|
||||
type: 'spring',
|
||||
bounce: 0,
|
||||
duration: 0.4,
|
||||
delayChildren: 0.2,
|
||||
staggerChildren: 0.05
|
||||
}
|
||||
},
|
||||
closed: {
|
||||
clipPath: 'inset(10% 0% 90% 0%)',
|
||||
transition: {
|
||||
type: 'spring',
|
||||
bounce: 0,
|
||||
duration: 0.3
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const animateDropdownItem: Variants = {
|
||||
open: {
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
type: 'spring',
|
||||
duration: 0.1,
|
||||
stiffness: 300,
|
||||
damping: 24
|
||||
}
|
||||
},
|
||||
closed: {
|
||||
opacity: 0,
|
||||
y: 10,
|
||||
transition: {
|
||||
duration: 0.1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const animateModal = {
|
||||
initial: {
|
||||
clipPath: 'inset(50% 50% 50% 50%)',
|
||||
opacity: 0
|
||||
},
|
||||
animate: {
|
||||
clipPath: 'inset(0% 0% 0% 0%)',
|
||||
opacity: 1,
|
||||
transition: {
|
||||
type: 'spring',
|
||||
bounce: 0,
|
||||
duration: 0.3
|
||||
}
|
||||
},
|
||||
exit: {
|
||||
opacity: 0,
|
||||
clipPath: 'inset(50% 50% 50% 50%)',
|
||||
transition: {
|
||||
type: 'spring',
|
||||
bounce: 0,
|
||||
duration: 0.2
|
||||
}
|
||||
}
|
||||
};
|
|
@ -16,7 +16,9 @@
|
|||
--text-max-width: 75ch;
|
||||
--scroll-padding: 3rem;
|
||||
|
||||
--duration-move: 400ms;
|
||||
--duration-move: 500ms;
|
||||
--duration-modal: 300ms;
|
||||
--duration-fade: 300ms;
|
||||
|
||||
/* Light Theme */
|
||||
--cl-bg-120: hsl(000, 000%, 100%);
|
||||
|
|
|
@ -214,11 +214,14 @@
|
|||
}
|
||||
|
||||
.cc-column {
|
||||
@apply flex flex-col gap-3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.cc-icons {
|
||||
@apply flex gap-1;
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.cc-fit-content {
|
||||
|
@ -254,4 +257,30 @@
|
|||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: var(--duration-move);
|
||||
}
|
||||
|
||||
.cc-fade-in {
|
||||
opacity: 1;
|
||||
|
||||
transition-property: opacity;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: var(--duration-fade);
|
||||
|
||||
@starting-style {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cc-animate-modal {
|
||||
clip-path: inset(0% 0% 0% 0%);
|
||||
opacity: 1;
|
||||
|
||||
transition-property: clip-path, opacity;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: var(--duration-modal);
|
||||
|
||||
@starting-style {
|
||||
clip-path: inset(50% 50% 50% 50%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ export const PARAMETER = {
|
|||
|
||||
fastAnimation: 200, // milliseconds - duration of fast animation
|
||||
fadeDuration: 300, // milliseconds - duration of fade animation
|
||||
dropdownDuration: 300, // milliseconds - duration of dropdown animation
|
||||
moveDuration: 500, // milliseconds - duration of move animation
|
||||
|
||||
graphHandleSize: 3, // pixels - size of graph connection handle
|
||||
|
|
Loading…
Reference in New Issue
Block a user