mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactoring: attribute names + introducing namespace
This commit is contained in:
parent
6965e83e19
commit
db1d5077c7
|
@ -1,9 +1,9 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { IColorsProps, IControlProps } from './commonInterfaces';
|
import { CProps } from '../props';
|
||||||
|
|
||||||
interface ButtonProps
|
interface ButtonProps
|
||||||
extends IControlProps, IColorsProps, Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'title'| 'type'> {
|
extends CProps.Control, CProps.Colors, CProps.Button {
|
||||||
text?: string
|
text?: string
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ extends IControlProps, IColorsProps, Omit<React.ButtonHTMLAttributes<HTMLButtonE
|
||||||
}
|
}
|
||||||
|
|
||||||
function Button({
|
function Button({
|
||||||
text, icon, tooltip, loading,
|
text, icon, loading,
|
||||||
dense, disabled, noBorder, noOutline,
|
dense, disabled, noBorder, noOutline,
|
||||||
colors = 'clr-btn-default',
|
colors = 'clr-btn-default',
|
||||||
className,
|
className,
|
||||||
|
@ -21,7 +21,6 @@ function Button({
|
||||||
return (
|
return (
|
||||||
<button type='button'
|
<button type='button'
|
||||||
disabled={disabled ?? loading}
|
disabled={disabled ?? loading}
|
||||||
title={tooltip}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'inline-flex gap-2 items-center justify-center',
|
'inline-flex gap-2 items-center justify-center',
|
||||||
'select-none disabled:cursor-not-allowed',
|
'select-none disabled:cursor-not-allowed',
|
||||||
|
@ -34,8 +33,8 @@ function Button({
|
||||||
'outline-none': noOutline,
|
'outline-none': noOutline,
|
||||||
'clr-outline': !noOutline,
|
'clr-outline': !noOutline,
|
||||||
},
|
},
|
||||||
colors,
|
className,
|
||||||
className
|
colors
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
|
|
|
@ -2,20 +2,20 @@ import clsx from 'clsx';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { CheckboxCheckedIcon } from '../Icons';
|
import { CheckboxCheckedIcon } from '../Icons';
|
||||||
|
import { CProps } from '../props';
|
||||||
import Label from './Label';
|
import Label from './Label';
|
||||||
|
|
||||||
export interface CheckboxProps
|
export interface CheckboxProps
|
||||||
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'title' | 'value' | 'onClick' > {
|
extends Omit<CProps.Button, 'value' | 'onClick'> {
|
||||||
label?: string
|
label?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
tooltip?: string
|
|
||||||
|
|
||||||
value: boolean
|
value: boolean
|
||||||
setValue?: (newValue: boolean) => void
|
setValue?: (newValue: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function Checkbox({
|
function Checkbox({
|
||||||
id, disabled, tooltip, label,
|
id, disabled, label,
|
||||||
className, value, setValue, ...restProps
|
className, value, setValue, ...restProps
|
||||||
}: CheckboxProps) {
|
}: CheckboxProps) {
|
||||||
const cursor = useMemo(
|
const cursor = useMemo(
|
||||||
|
@ -46,7 +46,6 @@ function Checkbox({
|
||||||
cursor,
|
cursor,
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
title={tooltip}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import { BiSearchAlt2 } from 'react-icons/bi';
|
import { BiSearchAlt2 } from 'react-icons/bi';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
import Overlay from './Overlay';
|
import Overlay from './Overlay';
|
||||||
import TextInput from './TextInput';
|
import TextInput from './TextInput';
|
||||||
|
|
||||||
interface ConceptSearchProps {
|
interface ConceptSearchProps
|
||||||
|
extends CProps.Styling {
|
||||||
value: string
|
value: string
|
||||||
onChange?: (newValue: string) => void
|
onChange?: (newValue: string) => void
|
||||||
noBorder?: boolean
|
noBorder?: boolean
|
||||||
dimensions?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConceptSearch({ value, onChange, noBorder, dimensions }: ConceptSearchProps) {
|
function ConceptSearch({ value, onChange, noBorder, ...restProps }: ConceptSearchProps) {
|
||||||
return (
|
return (
|
||||||
<div className={dimensions}>
|
<div {...restProps}>
|
||||||
<Overlay
|
<Overlay
|
||||||
position='top-[-0.125rem] left-3 translate-y-1/2'
|
position='top-[-0.125rem] left-3 translate-y-1/2'
|
||||||
className='pointer-events-none clr-text-controls'
|
className='pointer-events-none clr-text-controls'
|
||||||
|
|
|
@ -3,13 +3,11 @@ import type { TabProps } from 'react-tabs';
|
||||||
import { Tab } from 'react-tabs';
|
import { Tab } from 'react-tabs';
|
||||||
|
|
||||||
interface ConceptTabProps
|
interface ConceptTabProps
|
||||||
extends Omit<TabProps, 'title' | 'children'> {
|
extends Omit<TabProps, 'children'> {
|
||||||
className?: string
|
|
||||||
tooltip?: string
|
|
||||||
label?: string
|
label?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConceptTab({ label, tooltip, className, ...otherProps }: ConceptTabProps) {
|
function ConceptTab({ label, className, ...otherProps }: ConceptTabProps) {
|
||||||
return (
|
return (
|
||||||
<Tab
|
<Tab
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -20,7 +18,6 @@ function ConceptTab({ label, tooltip, className, ...otherProps }: ConceptTabProp
|
||||||
'select-none hover:cursor-pointer',
|
'select-none hover:cursor-pointer',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
title={tooltip}
|
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
|
|
|
@ -12,9 +12,9 @@ extends Omit<ITooltip, 'variant'> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConceptTooltip({
|
function ConceptTooltip({
|
||||||
className,
|
|
||||||
layer='z-tooltip',
|
layer='z-tooltip',
|
||||||
place='bottom',
|
place='bottom',
|
||||||
|
className,
|
||||||
style,
|
style,
|
||||||
...restProps
|
...restProps
|
||||||
}: ConceptTooltipProps) {
|
}: ConceptTooltipProps) {
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
import Overlay from './Overlay';
|
import Overlay from './Overlay';
|
||||||
|
|
||||||
interface DropdownProps {
|
interface DropdownProps
|
||||||
|
extends CProps.Styling {
|
||||||
stretchLeft?: boolean
|
stretchLeft?: boolean
|
||||||
dimensions?: string
|
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
function Dropdown({
|
function Dropdown({
|
||||||
dimensions = 'w-fit',
|
className,
|
||||||
stretchLeft,
|
stretchLeft,
|
||||||
children
|
children,
|
||||||
|
...restProps
|
||||||
}: DropdownProps) {
|
}: DropdownProps) {
|
||||||
return (
|
return (
|
||||||
<Overlay
|
<Overlay
|
||||||
|
@ -26,8 +28,9 @@ function Dropdown({
|
||||||
'right-0': stretchLeft,
|
'right-0': stretchLeft,
|
||||||
'left-0': !stretchLeft
|
'left-0': !stretchLeft
|
||||||
},
|
},
|
||||||
dimensions
|
className
|
||||||
)}
|
)}
|
||||||
|
{...restProps}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Overlay>);
|
</Overlay>);
|
||||||
|
|
|
@ -1,27 +1,22 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
interface DropdownButtonProps {
|
import { CProps } from '../props';
|
||||||
|
|
||||||
|
interface DropdownButtonProps
|
||||||
|
extends CProps.Button {
|
||||||
text?: string
|
text?: string
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
|
|
||||||
className?: string
|
|
||||||
tooltip?: string | undefined
|
|
||||||
onClick?: () => void
|
|
||||||
disabled?: boolean
|
|
||||||
|
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownButton({
|
function DropdownButton({
|
||||||
text, icon, children,
|
text, icon, className, onClick,
|
||||||
tooltip, className,
|
children,
|
||||||
disabled,
|
...restProps
|
||||||
onClick
|
|
||||||
}: DropdownButtonProps) {
|
}: DropdownButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button type='button'
|
<button type='button'
|
||||||
disabled={disabled}
|
|
||||||
title={tooltip}
|
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'px-3 py-1 inline-flex items-center gap-2',
|
'px-3 py-1 inline-flex items-center gap-2',
|
||||||
|
@ -34,6 +29,7 @@ function DropdownButton({
|
||||||
},
|
},
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
{...restProps}
|
||||||
>
|
>
|
||||||
{children ? children : null}
|
{children ? children : null}
|
||||||
{!children && icon ? icon : null}
|
{!children && icon ? icon : null}
|
||||||
|
|
|
@ -5,15 +5,15 @@ import Checkbox from './Checkbox';
|
||||||
interface DropdownCheckboxProps {
|
interface DropdownCheckboxProps {
|
||||||
value: boolean
|
value: boolean
|
||||||
label?: string
|
label?: string
|
||||||
tooltip?: string
|
title?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
setValue?: (newValue: boolean) => void
|
setValue?: (newValue: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownCheckbox({ tooltip, setValue, disabled, ...restProps }: DropdownCheckboxProps) {
|
function DropdownCheckbox({ title, setValue, disabled, ...restProps }: DropdownCheckboxProps) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
title={tooltip}
|
title={title}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'px-3 py-1',
|
'px-3 py-1',
|
||||||
'text-left overflow-ellipsis whitespace-nowrap',
|
'text-left overflow-ellipsis whitespace-nowrap',
|
||||||
|
|
|
@ -4,22 +4,22 @@ import clsx from 'clsx';
|
||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { BiUpload } from 'react-icons/bi';
|
import { BiUpload } from 'react-icons/bi';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import Label from './Label';
|
import Label from './Label';
|
||||||
|
|
||||||
interface FileInputProps
|
interface FileInputProps
|
||||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title' | 'style' | 'accept' | 'type'> {
|
extends Omit<CProps.Input, 'accept' | 'type'> {
|
||||||
label: string
|
label: string
|
||||||
tooltip?: string
|
|
||||||
dimensions?: string
|
|
||||||
|
|
||||||
acceptType?: string
|
acceptType?: string
|
||||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function FileInput({
|
function FileInput({
|
||||||
label, acceptType, tooltip,
|
label, acceptType, title,
|
||||||
dimensions = 'w-fit', onChange,
|
className, style,
|
||||||
|
onChange,
|
||||||
...restProps
|
...restProps
|
||||||
}: FileInputProps) {
|
}: FileInputProps) {
|
||||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
@ -31,9 +31,9 @@ function FileInput({
|
||||||
|
|
||||||
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
if (event.target.files && event.target.files.length > 0) {
|
if (event.target.files && event.target.files.length > 0) {
|
||||||
setFileName(event.target.files[0].name)
|
setFileName(event.target.files[0].name);
|
||||||
} else {
|
} else {
|
||||||
setFileName('')
|
setFileName('');
|
||||||
}
|
}
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
onChange(event);
|
onChange(event);
|
||||||
|
@ -41,11 +41,14 @@ function FileInput({
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(
|
<div
|
||||||
'py-2',
|
className={clsx(
|
||||||
'flex flex-col gap-2 items-start',
|
'py-2',
|
||||||
dimensions
|
'flex flex-col gap-2 items-center',
|
||||||
)}>
|
className
|
||||||
|
)}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
<input type='file'
|
<input type='file'
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
style={{ display: 'none' }}
|
style={{ display: 'none' }}
|
||||||
|
@ -57,7 +60,7 @@ function FileInput({
|
||||||
text={label}
|
text={label}
|
||||||
icon={<BiUpload size='1.5rem' />}
|
icon={<BiUpload size='1.5rem' />}
|
||||||
onClick={handleUploadClick}
|
onClick={handleUploadClick}
|
||||||
tooltip={tooltip}
|
title={title}
|
||||||
/>
|
/>
|
||||||
<Label text={fileName} />
|
<Label text={fileName} />
|
||||||
</div>);
|
</div>);
|
||||||
|
|
26
rsconcept/frontend/src/components/Common/FlexColumn.tsx
Normal file
26
rsconcept/frontend/src/components/Common/FlexColumn.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { classnames } from '@/utils/constants';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
|
|
||||||
|
export interface FlexColumnProps
|
||||||
|
extends CProps.Div {}
|
||||||
|
|
||||||
|
function FlexColumn({
|
||||||
|
className, children,
|
||||||
|
...restProps
|
||||||
|
}: FlexColumnProps) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
classnames.flex_col,
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FlexColumn;
|
|
@ -1,13 +1,13 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { LabelHTMLAttributes } from 'react';
|
|
||||||
|
import { CProps } from '../props';
|
||||||
|
|
||||||
interface LabelProps
|
interface LabelProps
|
||||||
extends Omit<React.DetailedHTMLProps<LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, 'children' | 'title'> {
|
extends CProps.Label {
|
||||||
text?: string
|
text?: string
|
||||||
tooltip?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Label({ text, tooltip, className, ...restProps }: LabelProps) {
|
function Label({ text, className, ...restProps }: LabelProps) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ function Label({ text, tooltip, className, ...restProps }: LabelProps) {
|
||||||
'text-sm font-semibold whitespace-nowrap',
|
'text-sm font-semibold whitespace-nowrap',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
title={tooltip}
|
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
|
|
|
@ -2,15 +2,15 @@ interface LabeledValueProps {
|
||||||
id?: string
|
id?: string
|
||||||
label: string
|
label: string
|
||||||
text: string | number
|
text: string | number
|
||||||
tooltip?: string
|
title?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function LabeledValue({ id, label, text, tooltip }: LabeledValueProps) {
|
function LabeledValue({ id, label, text, title }: LabeledValueProps) {
|
||||||
return (
|
return (
|
||||||
<div className='flex justify-between gap-3'>
|
<div className='flex justify-between gap-3'>
|
||||||
<label
|
<label
|
||||||
className='font-semibold'
|
className='font-semibold'
|
||||||
title={tooltip}
|
title={title}
|
||||||
htmlFor={id}
|
htmlFor={id}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
|
|
||||||
interface MiniButtonProps
|
interface MiniButtonProps
|
||||||
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'title' | 'children' > {
|
extends CProps.Button {
|
||||||
icon: React.ReactNode
|
icon: React.ReactNode
|
||||||
tooltip?: string
|
|
||||||
noHover?: boolean
|
noHover?: boolean
|
||||||
dimensions?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function MiniButton({
|
function MiniButton({
|
||||||
icon, tooltip, noHover, tabIndex,
|
icon, noHover, tabIndex,
|
||||||
dimensions='w-fit h-fit',
|
className,
|
||||||
...restProps
|
...restProps
|
||||||
}: MiniButtonProps) {
|
}: MiniButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button type='button'
|
<button type='button'
|
||||||
title={tooltip}
|
|
||||||
tabIndex={tabIndex ?? -1}
|
tabIndex={tabIndex ?? -1}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'px-1 py-1',
|
'px-1 py-1',
|
||||||
|
@ -26,7 +25,7 @@ function MiniButton({
|
||||||
'outline-none': noHover,
|
'outline-none': noHover,
|
||||||
'clr-hover': !noHover
|
'clr-hover': !noHover
|
||||||
},
|
},
|
||||||
dimensions
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
|
|
|
@ -6,29 +6,34 @@ import { BiX } from 'react-icons/bi';
|
||||||
|
|
||||||
import useEscapeKey from '@/hooks/useEscapeKey';
|
import useEscapeKey from '@/hooks/useEscapeKey';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import MiniButton from './MiniButton';
|
import MiniButton from './MiniButton';
|
||||||
import Overlay from './Overlay';
|
import Overlay from './Overlay';
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps
|
||||||
title?: string
|
extends CProps.Styling {
|
||||||
|
header?: string
|
||||||
submitText?: string
|
submitText?: string
|
||||||
submitInvalidTooltip?: string
|
submitInvalidTooltip?: string
|
||||||
|
|
||||||
readonly?: boolean
|
readonly?: boolean
|
||||||
canSubmit?: boolean
|
canSubmit?: boolean
|
||||||
|
|
||||||
hideWindow: () => void
|
hideWindow: () => void
|
||||||
onSubmit?: () => void
|
onSubmit?: () => void
|
||||||
onCancel?: () => void
|
onCancel?: () => void
|
||||||
|
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
className?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Modal({
|
function Modal({
|
||||||
title, hideWindow, onSubmit,
|
header, hideWindow, onSubmit,
|
||||||
readonly, onCancel, canSubmit,
|
readonly, onCancel, canSubmit,
|
||||||
submitInvalidTooltip, className,
|
submitInvalidTooltip, className,
|
||||||
children,
|
children,
|
||||||
submitText = 'Продолжить'
|
submitText = 'Продолжить',
|
||||||
|
...restProps
|
||||||
}: ModalProps) {
|
}: ModalProps) {
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
useEscapeKey(hideWindow);
|
useEscapeKey(hideWindow);
|
||||||
|
@ -58,16 +63,17 @@ function Modal({
|
||||||
'border shadow-md',
|
'border shadow-md',
|
||||||
'clr-app'
|
'clr-app'
|
||||||
)}
|
)}
|
||||||
|
{...restProps}
|
||||||
>
|
>
|
||||||
<Overlay position='right-[0.3rem] top-2'>
|
<Overlay position='right-[0.3rem] top-2'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Закрыть диалоговое окно [ESC]'
|
title='Закрыть диалоговое окно [ESC]'
|
||||||
icon={<BiX size='1.25rem'/>}
|
icon={<BiX size='1.25rem'/>}
|
||||||
onClick={handleCancel}
|
onClick={handleCancel}
|
||||||
/>
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
{title ? <h1 className='px-12 py-2 select-none'>{title}</h1> : null}
|
{header ? <h1 className='px-12 py-2 select-none'>{header}</h1> : null}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -89,7 +95,7 @@ function Modal({
|
||||||
{!readonly ?
|
{!readonly ?
|
||||||
<Button autoFocus
|
<Button autoFocus
|
||||||
text={submitText}
|
text={submitText}
|
||||||
tooltip={!canSubmit ? submitInvalidTooltip: ''}
|
title={!canSubmit ? submitInvalidTooltip: ''}
|
||||||
className='min-w-[8rem] min-h-[2.6rem]'
|
className='min-w-[8rem] min-h-[2.6rem]'
|
||||||
colors='clr-btn-primary'
|
colors='clr-btn-primary'
|
||||||
disabled={!canSubmit}
|
disabled={!canSubmit}
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
interface OverlayProps {
|
import clsx from 'clsx'
|
||||||
|
|
||||||
|
import { CProps } from '../props'
|
||||||
|
|
||||||
|
interface OverlayProps extends CProps.Styling {
|
||||||
id?: string
|
id?: string
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
position?: string
|
position?: string
|
||||||
className?: string
|
|
||||||
layer?: string
|
layer?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function Overlay({
|
function Overlay({
|
||||||
id, children, className,
|
children, className,
|
||||||
position='top-0 right-0',
|
position='top-0 right-0',
|
||||||
layer='z-pop'
|
layer='z-pop',
|
||||||
|
...restProps
|
||||||
}: OverlayProps) {
|
}: OverlayProps) {
|
||||||
return (
|
return (
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<div id={id} className={`absolute ${className} ${position} ${layer}`}>
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'absolute',
|
||||||
|
className,
|
||||||
|
position,
|
||||||
|
layer
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</div>);
|
||||||
|
|
|
@ -6,9 +6,7 @@ interface PageControlsProps {
|
||||||
setPageNumber: React.Dispatch<React.SetStateAction<number>>
|
setPageNumber: React.Dispatch<React.SetStateAction<number>>
|
||||||
}
|
}
|
||||||
|
|
||||||
function PageControls({
|
function PageControls({ pageNumber, pageCount, setPageNumber }: PageControlsProps) {
|
||||||
pageNumber, pageCount, setPageNumber
|
|
||||||
}: PageControlsProps) {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button type='button'
|
<button type='button'
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
|
|
||||||
interface SelectorButtonProps
|
interface SelectorButtonProps
|
||||||
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children' | 'title' | 'type'> {
|
extends CProps.Button {
|
||||||
text?: string
|
text?: string
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
tooltip?: string
|
|
||||||
dimensions?: string
|
|
||||||
borderClass?: string
|
|
||||||
colors?: string
|
colors?: string
|
||||||
transparent?: boolean
|
transparent?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectorButton({
|
function SelectorButton({
|
||||||
text, icon, tooltip,
|
text, icon,
|
||||||
colors = 'clr-btn-default',
|
colors = 'clr-btn-default',
|
||||||
dimensions = 'w-fit h-fit',
|
className,
|
||||||
transparent,
|
transparent,
|
||||||
...restProps
|
...restProps
|
||||||
}: SelectorButtonProps) {
|
}: SelectorButtonProps) {
|
||||||
|
@ -29,10 +29,9 @@ function SelectorButton({
|
||||||
'clr-hover': transparent,
|
'clr-hover': transparent,
|
||||||
'border': !transparent,
|
'border': !transparent,
|
||||||
},
|
},
|
||||||
!transparent && colors,
|
className,
|
||||||
dimensions
|
!transparent && colors
|
||||||
)}
|
)}
|
||||||
title={tooltip}
|
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
{icon ? icon : null}
|
{icon ? icon : null}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
|
|
||||||
interface SubmitButtonProps
|
interface SubmitButtonProps
|
||||||
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'title'> {
|
extends CProps.Button {
|
||||||
text?: string
|
text?: string
|
||||||
tooltip?: string
|
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
function SubmitButton({
|
function SubmitButton({
|
||||||
text = 'ОК',
|
text = 'ОК',
|
||||||
icon, disabled, tooltip, loading,
|
icon, disabled, loading,
|
||||||
className,
|
className,
|
||||||
...restProps
|
...restProps
|
||||||
}: SubmitButtonProps) {
|
}: SubmitButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button type='submit'
|
<button type='submit'
|
||||||
title={tooltip}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'px-3 py-2 inline-flex items-center gap-2 align-middle justify-center',
|
'px-3 py-2 inline-flex items-center gap-2 align-middle justify-center',
|
||||||
'border',
|
'border',
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
interface SwitchButtonProps<ValueType> {
|
import { CProps } from '../props';
|
||||||
|
|
||||||
|
interface SwitchButtonProps<ValueType>
|
||||||
|
extends CProps.Styling {
|
||||||
id?: string
|
id?: string
|
||||||
value: ValueType
|
value: ValueType
|
||||||
label?: string
|
label?: string
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
tooltip?: string
|
title?: string
|
||||||
dimensions?: string
|
|
||||||
|
|
||||||
isSelected?: boolean
|
isSelected?: boolean
|
||||||
onSelect: (value: ValueType) => void
|
onSelect: (value: ValueType) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function SwitchButton<ValueType>({
|
function SwitchButton<ValueType>({
|
||||||
value, icon, label, tooltip,
|
value, icon, label, className,
|
||||||
dimensions='w-fit h-fit',
|
|
||||||
isSelected, onSelect, ...restProps
|
isSelected, onSelect, ...restProps
|
||||||
}: SwitchButtonProps<ValueType>) {
|
}: SwitchButtonProps<ValueType>) {
|
||||||
return (
|
return (
|
||||||
<button type='button' tabIndex={-1}
|
<button type='button' tabIndex={-1}
|
||||||
title={tooltip}
|
|
||||||
onClick={() => onSelect(value)}
|
onClick={() => onSelect(value)}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'px-2 py-1',
|
'px-2 py-1',
|
||||||
|
@ -28,7 +28,7 @@ function SwitchButton<ValueType>({
|
||||||
'clr-btn-clear clr-hover',
|
'clr-btn-clear clr-hover',
|
||||||
'cursor-pointer',
|
'cursor-pointer',
|
||||||
isSelected && 'clr-selected',
|
isSelected && 'clr-selected',
|
||||||
dimensions
|
className
|
||||||
)}
|
)}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { TextareaHTMLAttributes } from 'react';
|
|
||||||
|
|
||||||
import { IColorsProps, IEditorProps } from './commonInterfaces';
|
import { CProps } from '../props';
|
||||||
import Label from './Label';
|
import Label from './Label';
|
||||||
|
|
||||||
export interface TextAreaProps
|
export interface TextAreaProps
|
||||||
extends IEditorProps, IColorsProps, Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'title'> {
|
extends CProps.Editor, CProps.Colors, CProps.TextArea {
|
||||||
dense?: boolean
|
dense?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextArea({
|
function TextArea({
|
||||||
id, label, required, tooltip, rows,
|
id, label, required, rows,
|
||||||
dense, noBorder, noOutline,
|
dense, noBorder, noOutline,
|
||||||
className,
|
className,
|
||||||
colors = 'clr-input',
|
colors = 'clr-input',
|
||||||
|
@ -26,7 +25,6 @@ function TextArea({
|
||||||
)}>
|
)}>
|
||||||
<Label text={label} htmlFor={id} />
|
<Label text={label} htmlFor={id} />
|
||||||
<textarea id={id}
|
<textarea id={id}
|
||||||
title={tooltip}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'px-3 py-2',
|
'px-3 py-2',
|
||||||
'leading-tight',
|
'leading-tight',
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
import { IColorsProps, IEditorProps } from './commonInterfaces';
|
import { CProps } from '../props';
|
||||||
import Label from './Label';
|
import Label from './Label';
|
||||||
|
|
||||||
interface TextInputProps
|
interface TextInputProps
|
||||||
extends IEditorProps, IColorsProps, Omit<React.InputHTMLAttributes<HTMLInputElement>, 'title'> {
|
extends CProps.Editor, CProps.Colors, CProps.Input {
|
||||||
dense?: boolean
|
dense?: boolean
|
||||||
allowEnter?: boolean
|
allowEnter?: boolean
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ function preventEnterCapture(event: React.KeyboardEvent<HTMLInputElement>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextInput({
|
function TextInput({
|
||||||
id, label, dense, tooltip, noBorder, noOutline, allowEnter, disabled,
|
id, label, dense, noBorder, noOutline, allowEnter, disabled,
|
||||||
className,
|
className,
|
||||||
colors = 'clr-input',
|
colors = 'clr-input',
|
||||||
onKeyDown,
|
onKeyDown,
|
||||||
|
@ -32,7 +32,6 @@ function TextInput({
|
||||||
)}>
|
)}>
|
||||||
<Label text={label} htmlFor={id} />
|
<Label text={label} htmlFor={id} />
|
||||||
<input id={id}
|
<input id={id}
|
||||||
title={tooltip}
|
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'py-2',
|
'py-2',
|
||||||
'leading-tight truncate hover:text-clip',
|
'leading-tight truncate hover:text-clip',
|
||||||
|
|
|
@ -3,31 +3,29 @@ import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
interface TextURLProps {
|
interface TextURLProps {
|
||||||
text: string
|
text: string
|
||||||
tooltip?: string
|
title?: string
|
||||||
href?: string
|
href?: string
|
||||||
color?: string
|
color?: string
|
||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextURL({ text, href, tooltip, color='clr-text-url', onClick }: TextURLProps) {
|
function TextURL({ text, href, title, color='clr-text-url', onClick }: TextURLProps) {
|
||||||
const design = `cursor-pointer hover:underline ${color}`;
|
const design = `cursor-pointer hover:underline ${color}`;
|
||||||
if (href) {
|
if (href) {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link tabIndex={-1}
|
||||||
className={design}
|
className={design}
|
||||||
title={tooltip}
|
title={title}
|
||||||
to={href}
|
to={href}
|
||||||
tabIndex={-1}
|
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
} else if (onClick) {
|
} else if (onClick) {
|
||||||
return (
|
return (
|
||||||
<span
|
<span tabIndex={-1}
|
||||||
className={design}
|
className={design}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
tabIndex={-1}
|
|
||||||
>
|
>
|
||||||
{text}
|
{text}
|
||||||
</span>);
|
</span>);
|
||||||
|
|
|
@ -13,7 +13,7 @@ extends Omit<CheckboxProps, 'value' | 'setValue'> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Tristate({
|
function Tristate({
|
||||||
id, disabled, tooltip, label,
|
id, disabled, label,
|
||||||
className,
|
className,
|
||||||
value, setValue,
|
value, setValue,
|
||||||
...restProps
|
...restProps
|
||||||
|
@ -51,7 +51,6 @@ function Tristate({
|
||||||
cursor,
|
cursor,
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
title={tooltip}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
// =========== Module contains interfaces for common UI elements. ==========
|
|
||||||
export interface IControlProps {
|
|
||||||
tooltip?: string
|
|
||||||
disabled?: boolean
|
|
||||||
noBorder?: boolean
|
|
||||||
noOutline?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IStylingProps {
|
|
||||||
style?: React.CSSProperties
|
|
||||||
className?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IEditorProps extends IControlProps {
|
|
||||||
label?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IColorsProps {
|
|
||||||
colors?: string
|
|
||||||
}
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
import { IStylingProps } from '../Common/commonInterfaces';
|
import { CProps } from '../props';
|
||||||
import DefaultNoData from './DefaultNoData';
|
import DefaultNoData from './DefaultNoData';
|
||||||
import PaginationTools from './PaginationTools';
|
import PaginationTools from './PaginationTools';
|
||||||
import TableBody from './TableBody';
|
import TableBody from './TableBody';
|
||||||
|
@ -25,7 +25,7 @@ export interface IConditionalStyle<TData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DataTableProps<TData extends RowData>
|
export interface DataTableProps<TData extends RowData>
|
||||||
extends IStylingProps, Pick<TableOptions<TData>,
|
extends CProps.Styling, Pick<TableOptions<TData>,
|
||||||
'data' | 'columns' |
|
'data' | 'columns' |
|
||||||
'onRowSelectionChange' | 'onColumnVisibilityChange'
|
'onRowSelectionChange' | 'onColumnVisibilityChange'
|
||||||
> {
|
> {
|
||||||
|
|
|
@ -9,7 +9,7 @@ interface SelectAllProps<TData> {
|
||||||
function SelectAll<TData>({ table }: SelectAllProps<TData>) {
|
function SelectAll<TData>({ table }: SelectAllProps<TData>) {
|
||||||
return (
|
return (
|
||||||
<Tristate tabIndex={-1}
|
<Tristate tabIndex={-1}
|
||||||
tooltip='Выделить все'
|
title='Выделить все'
|
||||||
value={
|
value={
|
||||||
(!table.getIsAllPageRowsSelected() && table.getIsSomePageRowsSelected())
|
(!table.getIsAllPageRowsSelected() && table.getIsSomePageRowsSelected())
|
||||||
? null
|
? null
|
||||||
|
|
|
@ -11,7 +11,7 @@ function ConstituentaTooltip({ data, anchor }: ConstituentaTooltipProps) {
|
||||||
return (
|
return (
|
||||||
<ConceptTooltip clickable
|
<ConceptTooltip clickable
|
||||||
anchorSelect={anchor}
|
anchorSelect={anchor}
|
||||||
className='max-w-[25rem] min-w-[25rem]'
|
className='w-[25rem]'
|
||||||
>
|
>
|
||||||
<InfoConstituenta data={data} />
|
<InfoConstituenta data={data} />
|
||||||
</ConceptTooltip>);
|
</ConceptTooltip>);
|
||||||
|
|
|
@ -4,15 +4,16 @@ import ConceptTooltip from '@/components/Common/ConceptTooltip';
|
||||||
import TextURL from '@/components/Common/TextURL';
|
import TextURL from '@/components/Common/TextURL';
|
||||||
import { HelpTopic } from '@/models/miscelanious';
|
import { HelpTopic } from '@/models/miscelanious';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
import InfoTopic from './InfoTopic';
|
import InfoTopic from './InfoTopic';
|
||||||
|
|
||||||
interface HelpButtonProps {
|
interface HelpButtonProps
|
||||||
|
extends CProps.Styling {
|
||||||
topic: HelpTopic
|
topic: HelpTopic
|
||||||
offset?: number
|
offset?: number
|
||||||
dimensions?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function HelpButton({ topic, offset, dimensions }: HelpButtonProps) {
|
function HelpButton({ topic, ...restProps }: HelpButtonProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
|
@ -24,8 +25,7 @@ function HelpButton({ topic, offset, dimensions }: HelpButtonProps) {
|
||||||
<ConceptTooltip clickable
|
<ConceptTooltip clickable
|
||||||
anchorSelect={`#help-${topic}`}
|
anchorSelect={`#help-${topic}`}
|
||||||
layer='z-modal-tooltip'
|
layer='z-modal-tooltip'
|
||||||
className={dimensions}
|
{...restProps}
|
||||||
offset={offset}
|
|
||||||
>
|
>
|
||||||
<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]'>
|
||||||
|
|
|
@ -25,15 +25,15 @@ function UserDropdown({ hideDropdown }: UserDropdownProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown dimensions='w-36' stretchLeft>
|
<Dropdown className='w-36' stretchLeft>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={user?.username}
|
text={user?.username}
|
||||||
tooltip='Профиль пользователя'
|
title='Профиль пользователя'
|
||||||
onClick={navigateProfile}
|
onClick={navigateProfile}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={darkMode ? 'Светлая тема' : 'Темная тема'}
|
text={darkMode ? 'Светлая тема' : 'Темная тема'}
|
||||||
tooltip='Переключение темы оформления'
|
title='Переключение темы оформления'
|
||||||
onClick={toggleDarkMode}
|
onClick={toggleDarkMode}
|
||||||
/>
|
/>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
|
|
|
@ -47,10 +47,10 @@ const editorSetup: BasicSetupOptions = {
|
||||||
|
|
||||||
interface RSInputProps
|
interface RSInputProps
|
||||||
extends Pick<ReactCodeMirrorProps,
|
extends Pick<ReactCodeMirrorProps,
|
||||||
'id' | 'height' | 'minHeight' | 'maxHeight' | 'value' | 'className' | 'onFocus' | 'onBlur' | 'placeholder'
|
'id' | 'height' | 'minHeight' | 'maxHeight' | 'value' |
|
||||||
|
'onFocus' | 'onBlur' | 'placeholder' | 'style' | 'className'
|
||||||
> {
|
> {
|
||||||
label?: string
|
label?: string
|
||||||
dimensions?: string
|
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
noTooltip?: boolean
|
noTooltip?: boolean
|
||||||
innerref?: RefObject<ReactCodeMirrorRef> | undefined
|
innerref?: RefObject<ReactCodeMirrorRef> | undefined
|
||||||
|
@ -61,7 +61,7 @@ extends Pick<ReactCodeMirrorProps,
|
||||||
function RSInput({
|
function RSInput({
|
||||||
id, label, innerref, onChange, onAnalyze,
|
id, label, innerref, onChange, onAnalyze,
|
||||||
disabled, noTooltip,
|
disabled, noTooltip,
|
||||||
dimensions = 'w-full',
|
className, style,
|
||||||
...restProps
|
...restProps
|
||||||
}: RSInputProps) {
|
}: RSInputProps) {
|
||||||
const { darkMode, colors } = useConceptTheme();
|
const { darkMode, colors } = useConceptTheme();
|
||||||
|
@ -129,11 +129,14 @@ function RSInput({
|
||||||
}, [thisRef, onAnalyze]);
|
}, [thisRef, onAnalyze]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(
|
<div
|
||||||
'flex flex-col gap-2',
|
className={clsx(
|
||||||
dimensions,
|
'flex flex-col gap-2',
|
||||||
cursor
|
className,
|
||||||
)}>
|
cursor
|
||||||
|
)}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
<Label text={label} htmlFor={id}/>
|
<Label text={label} htmlFor={id}/>
|
||||||
<CodeMirror id={id}
|
<CodeMirror id={id}
|
||||||
ref={thisRef}
|
ref={thisRef}
|
||||||
|
|
|
@ -9,14 +9,12 @@ interface SelectGrammemeProps extends
|
||||||
Omit<SelectMultiProps<IGrammemeOption>, 'value' | 'onChange'> {
|
Omit<SelectMultiProps<IGrammemeOption>, 'value' | 'onChange'> {
|
||||||
value: IGrammemeOption[]
|
value: IGrammemeOption[]
|
||||||
setValue: React.Dispatch<React.SetStateAction<IGrammemeOption[]>>
|
setValue: React.Dispatch<React.SetStateAction<IGrammemeOption[]>>
|
||||||
dimensions?: string
|
|
||||||
className?: string
|
className?: string
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectGrammeme({
|
function SelectGrammeme({
|
||||||
value, setValue,
|
value, setValue,
|
||||||
dimensions, className, placeholder,
|
|
||||||
...restProps
|
...restProps
|
||||||
}: SelectGrammemeProps) {
|
}: SelectGrammemeProps) {
|
||||||
const [options, setOptions] = useState<IGrammemeOption[]>([]);
|
const [options, setOptions] = useState<IGrammemeOption[]>([]);
|
||||||
|
@ -33,9 +31,7 @@ function SelectGrammeme({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SelectMulti
|
<SelectMulti
|
||||||
className={`${dimensions} ${className}`}
|
|
||||||
options={options}
|
options={options}
|
||||||
placeholder={placeholder}
|
|
||||||
value={value}
|
value={value}
|
||||||
onChange={newValue => setValue([...newValue].sort(compareGrammemeOptions))}
|
onChange={newValue => setValue([...newValue].sort(compareGrammemeOptions))}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
|
36
rsconcept/frontend/src/components/props.d.ts
vendored
Normal file
36
rsconcept/frontend/src/components/props.d.ts
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// =========== Module contains interfaces for common UI elements. ==========
|
||||||
|
export namespace CProps {
|
||||||
|
|
||||||
|
export type Control = {
|
||||||
|
title?: string
|
||||||
|
disabled?: boolean
|
||||||
|
noBorder?: boolean
|
||||||
|
noOutline?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Styling = {
|
||||||
|
style?: React.CSSProperties
|
||||||
|
className?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Editor = Control & {
|
||||||
|
label?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Colors = {
|
||||||
|
colors?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Div = React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
|
export type Button = Omit<
|
||||||
|
React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>,
|
||||||
|
'children' | 'type'
|
||||||
|
>;
|
||||||
|
export type Label = Omit<
|
||||||
|
React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>,
|
||||||
|
'children'
|
||||||
|
>;
|
||||||
|
export type TextArea = React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>;
|
||||||
|
export type Input = React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@ import { useLibrary } from '@/context/LibraryContext';
|
||||||
import { useConceptNavigation } from '@/context/NagivationContext';
|
import { useConceptNavigation } from '@/context/NagivationContext';
|
||||||
import { ILibraryItem } from '@/models/library';
|
import { ILibraryItem } from '@/models/library';
|
||||||
import { IRSFormCreateData } from '@/models/rsform';
|
import { IRSFormCreateData } from '@/models/rsform';
|
||||||
|
import { classnames } from '@/utils/constants';
|
||||||
import { cloneTitle } from '@/utils/misc';
|
import { cloneTitle } from '@/utils/misc';
|
||||||
|
|
||||||
interface DlgCloneLibraryItemProps
|
interface DlgCloneLibraryItemProps
|
||||||
|
@ -57,12 +59,12 @@ function DlgCloneLibraryItem({ hideWindow, base }: DlgCloneLibraryItemProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title='Создание копии концептуальной схемы'
|
header='Создание копии концептуальной схемы'
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={canSubmit}
|
canSubmit={canSubmit}
|
||||||
submitText='Создать'
|
submitText='Создать'
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className='flex flex-col gap-3 px-6 py-2'
|
className={clsx('px-6 py-2', classnames.flex_col)}
|
||||||
>
|
>
|
||||||
<TextInput
|
<TextInput
|
||||||
label='Полное название'
|
label='Полное название'
|
||||||
|
|
|
@ -132,7 +132,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
<div className='max-h-[1.2rem]'>
|
<div className='max-h-[1.2rem]'>
|
||||||
{props.row.original.value ?
|
{props.row.original.value ?
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Очистить значение'
|
title='Очистить значение'
|
||||||
icon={<BiX size='0.75rem' className='clr-text-warning'/>}
|
icon={<BiX size='0.75rem' className='clr-text-warning'/>}
|
||||||
noHover
|
noHover
|
||||||
onClick={() => handleClearArgument(props.row.original)}
|
onClick={() => handleClearArgument(props.row.original)}
|
||||||
|
@ -148,7 +148,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
}], [selectedArgument, colors]);
|
}], [selectedArgument, colors]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-3'>
|
<>
|
||||||
<DataTable dense noFooter
|
<DataTable dense noFooter
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'max-h-[5.8rem] min-h-[5.8rem]',
|
'max-h-[5.8rem] min-h-[5.8rem]',
|
||||||
|
@ -173,8 +173,8 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={clsx(
|
<div className={clsx(
|
||||||
'py-1 flex gap-2 justify-center items-center',
|
'my-4',
|
||||||
'w-full',
|
'flex gap-2 justify-center items-center',
|
||||||
'select-none'
|
'select-none'
|
||||||
)}>
|
)}>
|
||||||
<span title='Выберите аргумент из списка сверху и значение из списка снизу'
|
<span title='Выберите аргумент из списка сверху и значение из списка снизу'
|
||||||
|
@ -184,25 +184,25 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
</span>
|
</span>
|
||||||
<span>=</span>
|
<span>=</span>
|
||||||
<RSInput noTooltip
|
<RSInput noTooltip
|
||||||
dimensions='max-w-[12rem] w-full'
|
className='w-[12rem]'
|
||||||
value={argumentValue}
|
value={argumentValue}
|
||||||
onChange={newValue => setArgumentValue(newValue)}
|
onChange={newValue => setArgumentValue(newValue)}
|
||||||
/>
|
/>
|
||||||
<div className='flex'>
|
<div className='flex'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Подставить значение аргумента'
|
title='Подставить значение аргумента'
|
||||||
icon={<BiCheck size='1.25rem' className={!!argumentValue && !!selectedArgument ? 'clr-text-success' : ''} />}
|
icon={<BiCheck size='1.25rem' className={!!argumentValue && !!selectedArgument ? 'clr-text-success' : ''} />}
|
||||||
disabled={!argumentValue || !selectedArgument}
|
disabled={!argumentValue || !selectedArgument}
|
||||||
onClick={() => handleAssignArgument(selectedArgument!, argumentValue)}
|
onClick={() => handleAssignArgument(selectedArgument!, argumentValue)}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Откатить значение'
|
title='Откатить значение'
|
||||||
disabled={!isModified}
|
disabled={!isModified}
|
||||||
onClick={handleReset}
|
onClick={handleReset}
|
||||||
icon={<BiRefresh size='1.25rem' className={isModified ? 'clr-text-primary' : ''} />}
|
icon={<BiRefresh size='1.25rem' className={isModified ? 'clr-text-primary' : ''} />}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Очистить значение аргумента'
|
title='Очистить значение аргумента'
|
||||||
disabled={!selectedClearable}
|
disabled={!selectedClearable}
|
||||||
icon={<BiX size='1.25rem' className={selectedClearable ? 'clr-text-warning': ''}/>}
|
icon={<BiX size='1.25rem' className={selectedClearable ? 'clr-text-warning': ''}/>}
|
||||||
onClick={() => selectedArgument ? handleClearArgument(selectedArgument) : undefined}
|
onClick={() => selectedArgument ? handleClearArgument(selectedArgument) : undefined}
|
||||||
|
@ -220,12 +220,12 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
|
|
||||||
<RSInput id='result'
|
<RSInput id='result'
|
||||||
placeholder='Итоговое определение'
|
placeholder='Итоговое определение'
|
||||||
|
className='mt-[1.2rem]'
|
||||||
height='5.1rem'
|
height='5.1rem'
|
||||||
dimensions='w-full mt-[0.45rem]'
|
|
||||||
value={state.definition}
|
value={state.definition}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ArgumentsTab;
|
export default ArgumentsTab;
|
|
@ -17,7 +17,7 @@ interface ConstituentaTabProps {
|
||||||
|
|
||||||
function ConstituentaTab({state, partialUpdate}: ConstituentaTabProps) {
|
function ConstituentaTab({state, partialUpdate}: ConstituentaTabProps) {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-3'>
|
<>
|
||||||
<div className='flex self-center gap-3 pr-2'>
|
<div className='flex self-center gap-3 pr-2'>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
className='min-w-[14rem]'
|
className='min-w-[14rem]'
|
||||||
|
@ -62,7 +62,7 @@ function ConstituentaTab({state, partialUpdate}: ConstituentaTabProps) {
|
||||||
value={state.convention}
|
value={state.convention}
|
||||||
onChange={event => partialUpdate({ convention: event.target.value })}
|
onChange={event => partialUpdate({ convention: event.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ConstituentaTab;
|
export default ConstituentaTab;
|
|
@ -12,6 +12,7 @@ import usePartialUpdate from '@/hooks/usePartialUpdate';
|
||||||
import { HelpTopic } from '@/models/miscelanious';
|
import { HelpTopic } from '@/models/miscelanious';
|
||||||
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
|
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
|
||||||
import { inferTemplatedType, substituteTemplateArgs } from '@/models/rslangAPI';
|
import { inferTemplatedType, substituteTemplateArgs } from '@/models/rslangAPI';
|
||||||
|
import { classnames } from '@/utils/constants';
|
||||||
import { createAliasFor, validateCstAlias } from '@/utils/misc';
|
import { createAliasFor, validateCstAlias } from '@/utils/misc';
|
||||||
|
|
||||||
import ArgumentsTab, { IArgumentsState } from './ArgumentsTab';
|
import ArgumentsTab, { IArgumentsState } from './ArgumentsTab';
|
||||||
|
@ -113,15 +114,15 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title='Создание конституенты из шаблона'
|
header='Создание конституенты из шаблона'
|
||||||
|
submitText='Создать'
|
||||||
|
className='w-[43rem] h-[36rem] px-6'
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={validated}
|
canSubmit={validated}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
submitText='Создать'
|
|
||||||
className='max-w-[43rem] min-w-[43rem] min-h-[36rem] px-6'
|
|
||||||
>
|
>
|
||||||
<Overlay position='top-0 right-[6rem]'>
|
<Overlay position='top-0 right-[6rem]'>
|
||||||
<HelpButton topic={HelpTopic.RSTEMPLATES} dimensions='max-w-[35rem]' />
|
<HelpButton topic={HelpTopic.RSTEMPLATES} className='max-w-[35rem]' />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
<Tabs forceRenderTabPanel
|
<Tabs forceRenderTabPanel
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='clr-selected'
|
||||||
|
@ -136,17 +137,17 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
)}>
|
)}>
|
||||||
<ConceptTab
|
<ConceptTab
|
||||||
label='Шаблон'
|
label='Шаблон'
|
||||||
tooltip='Выбор шаблона выражения'
|
title='Выбор шаблона выражения'
|
||||||
className='w-[8rem]'
|
className='w-[8rem]'
|
||||||
/>
|
/>
|
||||||
<ConceptTab
|
<ConceptTab
|
||||||
label='Аргументы'
|
label='Аргументы'
|
||||||
tooltip='Подстановка аргументов шаблона'
|
title='Подстановка аргументов шаблона'
|
||||||
className='w-[8rem]'
|
className='w-[8rem]'
|
||||||
/>
|
/>
|
||||||
<ConceptTab
|
<ConceptTab
|
||||||
label='Конституента'
|
label='Конституента'
|
||||||
tooltip='Редактирование атрибутов конституенты'
|
title='Редактирование атрибутов конституенты'
|
||||||
className='w-[8rem]'
|
className='w-[8rem]'
|
||||||
/>
|
/>
|
||||||
</TabList>
|
</TabList>
|
||||||
|
@ -166,7 +167,7 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel style={{ display: activeTab === TabID.CONSTITUENTA ? '': 'none' }}>
|
<TabPanel className={classnames.flex_col} style={{ display: activeTab === TabID.CONSTITUENTA ? '': 'none' }}>
|
||||||
<ConstituentaTab
|
<ConstituentaTab
|
||||||
state={constituenta}
|
state={constituenta}
|
||||||
partialUpdate={updateConstituenta}
|
partialUpdate={updateConstituenta}
|
||||||
|
|
|
@ -87,50 +87,46 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
||||||
}, [state.filterCategory, selectedSchema]);
|
}, [state.filterCategory, selectedSchema]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-3'>
|
<>
|
||||||
<div>
|
<div className='flex justify-stretch'>
|
||||||
<div className='flex justify-stretch'>
|
<SelectSingle
|
||||||
<SelectSingle
|
placeholder='Выберите категорию'
|
||||||
placeholder='Выберите категорию'
|
className='flex-grow border-none'
|
||||||
className='flex-grow border-none'
|
options={categorySelector}
|
||||||
options={categorySelector}
|
value={state.filterCategory && selectedSchema ? {
|
||||||
value={state.filterCategory && selectedSchema ? {
|
value: state.filterCategory.id,
|
||||||
value: state.filterCategory.id,
|
label: state.filterCategory.term_raw
|
||||||
label: state.filterCategory.term_raw
|
} : null}
|
||||||
} : null}
|
onChange={data => partialUpdate({filterCategory: selectedSchema?.items.find(cst => cst.id === data?.value) })}
|
||||||
onChange={data => partialUpdate({filterCategory: selectedSchema?.items.find(cst => cst.id === data?.value) })}
|
isClearable
|
||||||
isClearable
|
/>
|
||||||
/>
|
<SelectSingle
|
||||||
<SelectSingle
|
placeholder='Выберите источник'
|
||||||
placeholder='Выберите источник'
|
className='min-w-[12rem]'
|
||||||
className='min-w-[12rem]'
|
options={templateSelector}
|
||||||
options={templateSelector}
|
value={state.templateID ? { value: state.templateID, label: templates.find(item => item.id == state.templateID)!.title }: null}
|
||||||
value={state.templateID ? { value: state.templateID, label: templates.find(item => item.id == state.templateID)!.title }: null}
|
onChange={data => partialUpdate({templateID: (data ? data.value : undefined)})}
|
||||||
onChange={data => partialUpdate({templateID: (data ? data.value : undefined)})}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<ConstituentaPicker
|
|
||||||
value={state.prototype}
|
|
||||||
data={filteredData}
|
|
||||||
onSelectValue={cst => partialUpdate( { prototype: cst } )}
|
|
||||||
prefixID={prefixes.cst_template_ist}
|
|
||||||
rows={9}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<TextArea id='term'
|
<ConstituentaPicker
|
||||||
rows={2}
|
value={state.prototype}
|
||||||
disabled
|
data={filteredData}
|
||||||
placeholder='Шаблон конституенты не выбран'
|
onSelectValue={cst => partialUpdate( { prototype: cst } )}
|
||||||
value={prototypeInfo}
|
prefixID={prefixes.cst_template_ist}
|
||||||
spellCheck
|
rows={9}
|
||||||
/>
|
/>
|
||||||
<RSInput id='expression'
|
<TextArea disabled spellCheck
|
||||||
height='5.1rem'
|
placeholder='Шаблон конституенты не выбран'
|
||||||
|
className='my-3'
|
||||||
|
rows={2}
|
||||||
|
value={prototypeInfo}
|
||||||
|
/>
|
||||||
|
<RSInput disabled
|
||||||
placeholder='Выберите шаблон из списка'
|
placeholder='Выберите шаблон из списка'
|
||||||
disabled
|
height='5.1rem'
|
||||||
value={state.prototype?.definition_formal}
|
value={state.prototype?.definition_formal}
|
||||||
/>
|
/>
|
||||||
</div>);
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default TemplateTab;
|
export default TemplateTab;
|
|
@ -10,6 +10,7 @@ import TextInput from '@/components/Common/TextInput';
|
||||||
import RSInput from '@/components/RSInput';
|
import RSInput from '@/components/RSInput';
|
||||||
import usePartialUpdate from '@/hooks/usePartialUpdate';
|
import usePartialUpdate from '@/hooks/usePartialUpdate';
|
||||||
import { CstType,ICstCreateData, IRSForm } from '@/models/rsform';
|
import { CstType,ICstCreateData, IRSForm } from '@/models/rsform';
|
||||||
|
import { classnames } from '@/utils/constants';
|
||||||
import { labelCstType } from '@/utils/labels';
|
import { labelCstType } from '@/utils/labels';
|
||||||
import { createAliasFor, validateCstAlias } from '@/utils/misc';
|
import { createAliasFor, validateCstAlias } from '@/utils/misc';
|
||||||
import { SelectorCstType } from '@/utils/selectors';
|
import { SelectorCstType } from '@/utils/selectors';
|
||||||
|
@ -50,14 +51,15 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title='Создание конституенты'
|
header='Создание конституенты'
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={validated}
|
canSubmit={validated}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
submitText='Создать'
|
submitText='Создать'
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-[35rem]',
|
'w-[35rem]',
|
||||||
'py-2 px-6 flex flex-col gap-3'
|
'py-2 px-6',
|
||||||
|
classnames.flex_col
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className='flex self-center gap-6'>
|
<div className='flex self-center gap-6'>
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import Checkbox from '@/components/Common/Checkbox';
|
import Checkbox from '@/components/Common/Checkbox';
|
||||||
import Modal, { ModalProps } from '@/components/Common/Modal';
|
import Modal, { ModalProps } from '@/components/Common/Modal';
|
||||||
import { IRSForm } from '@/models/rsform';
|
import { IRSForm } from '@/models/rsform';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { classnames, prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
import ConstituentsList from './ConstituentsList';
|
import ConstituentsList from './ConstituentsList';
|
||||||
|
|
||||||
|
@ -31,11 +32,15 @@ function DlgDeleteCst({ hideWindow, selected, schema, onDelete }: DlgDeleteCstPr
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal canSubmit
|
<Modal canSubmit
|
||||||
title='Удаление конституент'
|
header='Удаление конституент'
|
||||||
submitText={expandOut ? 'Удалить с зависимыми' : 'Удалить'}
|
submitText={expandOut ? 'Удалить с зависимыми' : 'Удалить'}
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className='max-w-[60vw] min-w-[30rem] px-6 flex flex-col gap-3'
|
className={clsx(
|
||||||
|
'max-w-[60vw] min-w-[30rem]',
|
||||||
|
'px-6',
|
||||||
|
classnames.flex_col
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ConstituentsList
|
<ConstituentsList
|
||||||
title='Выбраны к удалению'
|
title='Выбраны к удалению'
|
||||||
|
|
|
@ -46,15 +46,15 @@ function DlgEditReference({ hideWindow, items, initial, onSave }: DlgEditReferen
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title='Редактирование ссылки'
|
header='Редактирование ссылки'
|
||||||
submitText='Сохранить ссылку'
|
submitText='Сохранить ссылку'
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={isValid}
|
canSubmit={isValid}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className='min-w-[40rem] max-w-[40rem] px-6 min-h-[34rem]'
|
className='w-[40rem] px-6 min-h-[34rem]'
|
||||||
>
|
>
|
||||||
<Overlay position='top-0 right-[4rem]'>
|
<Overlay position='top-0 right-[4rem]'>
|
||||||
<HelpButton topic={HelpTopic.TERM_CONTROL} dimensions='max-w-[35rem]' offset={14} />
|
<HelpButton topic={HelpTopic.TERM_CONTROL} className='max-w-[35rem]' offset={14} />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
<Tabs
|
<Tabs
|
||||||
|
@ -69,12 +69,12 @@ function DlgEditReference({ hideWindow, items, initial, onSave }: DlgEditReferen
|
||||||
'border divide-x rounded-none'
|
'border divide-x rounded-none'
|
||||||
)}>
|
)}>
|
||||||
<ConceptTab
|
<ConceptTab
|
||||||
tooltip='Отсылка на термин в заданной словоформе'
|
title='Отсылка на термин в заданной словоформе'
|
||||||
label={labelReferenceType(ReferenceType.ENTITY)}
|
label={labelReferenceType(ReferenceType.ENTITY)}
|
||||||
className='w-[12rem]'
|
className='w-[12rem]'
|
||||||
/>
|
/>
|
||||||
<ConceptTab
|
<ConceptTab
|
||||||
tooltip='Установление синтаксической связи с отсылкой на термин'
|
title='Установление синтаксической связи с отсылкой на термин'
|
||||||
label={labelReferenceType(ReferenceType.SYNTACTIC)}
|
label={labelReferenceType(ReferenceType.SYNTACTIC)}
|
||||||
className='w-[12rem]'
|
className='w-[12rem]'
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
import { useEffect, useLayoutEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import FlexColumn from '@/components/Common/FlexColumn';
|
||||||
import Label from '@/components/Common/Label';
|
import Label from '@/components/Common/Label';
|
||||||
import TextInput from '@/components/Common/TextInput';
|
import TextInput from '@/components/Common/TextInput';
|
||||||
import ConstituentaPicker from '@/components/Shared/ConstituentaPicker';
|
import ConstituentaPicker from '@/components/Shared/ConstituentaPicker';
|
||||||
|
@ -61,7 +62,7 @@ function EntityTab({ initial, items, setIsValid, setReference }: EntityTabProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-3'>
|
<FlexColumn>
|
||||||
<ConstituentaPicker
|
<ConstituentaPicker
|
||||||
value={selectedCst}
|
value={selectedCst}
|
||||||
data={items}
|
data={items}
|
||||||
|
@ -77,7 +78,7 @@ function EntityTab({ initial, items, setIsValid, setReference }: EntityTabProps)
|
||||||
<TextInput dense
|
<TextInput dense
|
||||||
label='Конституента'
|
label='Конституента'
|
||||||
placeholder='Имя'
|
placeholder='Имя'
|
||||||
className='max-w-[11rem] min-w-[11rem]'
|
className='w-[11rem]'
|
||||||
value={alias}
|
value={alias}
|
||||||
onChange={event => setAlias(event.target.value)}
|
onChange={event => setAlias(event.target.value)}
|
||||||
/>
|
/>
|
||||||
|
@ -85,7 +86,7 @@ function EntityTab({ initial, items, setIsValid, setReference }: EntityTabProps)
|
||||||
label='Термин'
|
label='Термин'
|
||||||
className='flex-grow text-sm'
|
className='flex-grow text-sm'
|
||||||
value={term}
|
value={term}
|
||||||
tooltip={term}
|
title={term}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ function EntityTab({ initial, items, setIsValid, setReference }: EntityTabProps)
|
||||||
setValue={setSelectedGrams}
|
setValue={setSelectedGrams}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>);
|
</FlexColumn>);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EntityTab;
|
export default EntityTab;
|
|
@ -123,14 +123,14 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal canSubmit
|
<Modal canSubmit
|
||||||
title='Редактирование словоформ'
|
header='Редактирование словоформ'
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
submitText='Сохранить'
|
submitText='Сохранить'
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className='flex flex-col min-w-[40rem] max-w-[40rem] px-6'
|
className='flex flex-col w-[40rem] px-6'
|
||||||
>
|
>
|
||||||
<Overlay position='top-[-0.2rem] left-[7.5rem]'>
|
<Overlay position='top-[-0.2rem] left-[7.5rem]'>
|
||||||
<HelpButton topic={HelpTopic.TERM_CONTROL} dimensions='max-w-[38rem]' offset={3} />
|
<HelpButton topic={HelpTopic.TERM_CONTROL} className='max-w-[38rem]' offset={3} />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
<TextArea disabled spellCheck
|
<TextArea disabled spellCheck
|
||||||
|
@ -154,7 +154,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
/>
|
/>
|
||||||
<div className='flex flex-col self-center gap-1'>
|
<div className='flex flex-col self-center gap-1'>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Определить граммемы'
|
title='Определить граммемы'
|
||||||
icon={<BiRightArrow
|
icon={<BiRightArrow
|
||||||
size='1.25rem'
|
size='1.25rem'
|
||||||
className={inputText ? 'clr-text-primary' : ''}
|
className={inputText ? 'clr-text-primary' : ''}
|
||||||
|
@ -163,7 +163,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
onClick={handleParse}
|
onClick={handleParse}
|
||||||
/>
|
/>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Генерировать словоформу'
|
title='Генерировать словоформу'
|
||||||
icon={<BiLeftArrow size='1.25rem' className={inputGrams.length !== 0 ? 'clr-text-primary' : ''} />}
|
icon={<BiLeftArrow size='1.25rem' className={inputGrams.length !== 0 ? 'clr-text-primary' : ''} />}
|
||||||
disabled={textProcessor.loading || inputGrams.length == 0}
|
disabled={textProcessor.loading || inputGrams.length == 0}
|
||||||
onClick={handleInflect}
|
onClick={handleInflect}
|
||||||
|
@ -171,7 +171,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
</div>
|
</div>
|
||||||
<SelectGrammeme
|
<SelectGrammeme
|
||||||
placeholder='Выберите граммемы'
|
placeholder='Выберите граммемы'
|
||||||
dimensions='min-w-[15rem] max-w-[15rem]'
|
className='w-[15rem]'
|
||||||
value={inputGrams}
|
value={inputGrams}
|
||||||
setValue={setInputGrams}
|
setValue={setInputGrams}
|
||||||
/>
|
/>
|
||||||
|
@ -179,7 +179,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
|
|
||||||
<Overlay position='top-2 left-0'>
|
<Overlay position='top-2 left-0'>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Внести словоформу'
|
title='Внести словоформу'
|
||||||
icon={<BiCheck
|
icon={<BiCheck
|
||||||
size='1.25rem'
|
size='1.25rem'
|
||||||
className={inputText && inputGrams.length !== 0 ? 'clr-text-success' : ''}
|
className={inputText && inputGrams.length !== 0 ? 'clr-text-success' : ''}
|
||||||
|
@ -188,7 +188,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
onClick={handleAddForm}
|
onClick={handleAddForm}
|
||||||
/>
|
/>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Генерировать стандартные словоформы'
|
title='Генерировать стандартные словоформы'
|
||||||
icon={<BiChevronsDown size='1.25rem' className={inputText ? 'clr-text-primary' : ''}
|
icon={<BiChevronsDown size='1.25rem' className={inputText ? 'clr-text-primary' : ''}
|
||||||
/>}
|
/>}
|
||||||
disabled={textProcessor.loading || !inputText}
|
disabled={textProcessor.loading || !inputText}
|
||||||
|
@ -203,7 +203,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
)}>
|
)}>
|
||||||
<span>Заданные вручную словоформы [{forms.length}]</span>
|
<span>Заданные вручную словоформы [{forms.length}]</span>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Сбросить все словоформы'
|
title='Сбросить все словоформы'
|
||||||
icon={<BiX size='1rem' className={forms.length !== 0 ? 'clr-text-warning' : ''} />}
|
icon={<BiX size='1rem' className={forms.length !== 0 ? 'clr-text-warning' : ''} />}
|
||||||
disabled={textProcessor.loading || forms.length === 0}
|
disabled={textProcessor.loading || forms.length === 0}
|
||||||
onClick={handleResetAll}
|
onClick={handleResetAll}
|
||||||
|
|
|
@ -62,7 +62,7 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
|
||||||
maxSize: 50,
|
maxSize: 50,
|
||||||
cell: props =>
|
cell: props =>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Удалить словоформу'
|
title='Удалить словоформу'
|
||||||
icon={<BiX size='1rem' className='clr-text-warning'/>}
|
icon={<BiX size='1rem' className='clr-text-warning'/>}
|
||||||
onClick={() => handleDeleteRow(props.row.index)}
|
onClick={() => handleDeleteRow(props.row.index)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -24,7 +24,7 @@ function DlgGraphParams({ hideWindow, initial, onConfirm } : DlgGraphParamsProps
|
||||||
return (
|
return (
|
||||||
<Modal canSubmit
|
<Modal canSubmit
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
title='Настройки графа термов'
|
header='Настройки графа термов'
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
submitText='Применить'
|
submitText='Применить'
|
||||||
className='flex gap-12 px-6 py-2'
|
className='flex gap-12 px-6 py-2'
|
||||||
|
@ -33,25 +33,25 @@ function DlgGraphParams({ hideWindow, initial, onConfirm } : DlgGraphParamsProps
|
||||||
<h1 className='mb-2'>Преобразования</h1>
|
<h1 className='mb-2'>Преобразования</h1>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Скрыть текст'
|
label='Скрыть текст'
|
||||||
tooltip='Не отображать термины'
|
title='Не отображать термины'
|
||||||
value={params.noText}
|
value={params.noText}
|
||||||
setValue={value => updateParams({noText: value})}
|
setValue={value => updateParams({noText: value})}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Скрыть несвязанные'
|
label='Скрыть несвязанные'
|
||||||
tooltip='Неиспользуемые конституенты'
|
title='Неиспользуемые конституенты'
|
||||||
value={params.noHermits}
|
value={params.noHermits}
|
||||||
setValue={value => updateParams({ noHermits: value})}
|
setValue={value => updateParams({ noHermits: value})}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Скрыть шаблоны'
|
label='Скрыть шаблоны'
|
||||||
tooltip='Терм-функции и предикат-функции с параметризованными аргументами'
|
title='Терм-функции и предикат-функции с параметризованными аргументами'
|
||||||
value={params.noTemplates}
|
value={params.noTemplates}
|
||||||
setValue={value => updateParams({ noTemplates: value})}
|
setValue={value => updateParams({ noTemplates: value})}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Транзитивная редукция'
|
label='Транзитивная редукция'
|
||||||
tooltip='Удалить связи, образующие транзитивные пути в графе'
|
title='Удалить связи, образующие транзитивные пути в графе'
|
||||||
value={params.noTransitive}
|
value={params.noTransitive}
|
||||||
setValue={value => updateParams({ noTransitive: value})}
|
setValue={value => updateParams({ noTransitive: value})}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -44,7 +44,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title='Переименование конституенты'
|
header='Переименование конституенты'
|
||||||
submitText='Переименовать'
|
submitText='Переименовать'
|
||||||
submitInvalidTooltip={'Введите незанятое имя, соответствующее типу'}
|
submitInvalidTooltip={'Введите незанятое имя, соответствующее типу'}
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
|
|
|
@ -41,7 +41,7 @@ function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title='Импорт схемы из Экстеора'
|
header='Импорт схемы из Экстеора'
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={!!file}
|
canSubmit={!!file}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
|
@ -50,7 +50,6 @@ function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) {
|
||||||
>
|
>
|
||||||
<FileInput
|
<FileInput
|
||||||
label='Выбрать файл'
|
label='Выбрать файл'
|
||||||
dimensions='w-full flex items-center'
|
|
||||||
acceptType={EXTEOR_TRS_FILE}
|
acceptType={EXTEOR_TRS_FILE}
|
||||||
onChange={handleFile}
|
onChange={handleFile}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { useLibrary } from '@/context/LibraryContext';
|
||||||
import { useConceptNavigation } from '@/context/NagivationContext';
|
import { useConceptNavigation } from '@/context/NagivationContext';
|
||||||
import { LibraryItemType } from '@/models/library';
|
import { LibraryItemType } from '@/models/library';
|
||||||
import { IRSFormCreateData } from '@/models/rsform';
|
import { IRSFormCreateData } from '@/models/rsform';
|
||||||
import { EXTEOR_TRS_FILE, limits, patterns } from '@/utils/constants';
|
import { classnames, EXTEOR_TRS_FILE, limits, patterns } from '@/utils/constants';
|
||||||
|
|
||||||
function CreateRSFormPage() {
|
function CreateRSFormPage() {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
|
@ -81,8 +81,8 @@ function CreateRSFormPage() {
|
||||||
<RequireAuth>
|
<RequireAuth>
|
||||||
<form
|
<form
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-full max-w-lg',
|
'px-6 py-3',
|
||||||
'px-6 py-3 flex flex-col gap-3'
|
classnames.flex_col
|
||||||
)}
|
)}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
|
@ -94,7 +94,7 @@ function CreateRSFormPage() {
|
||||||
onChange={handleFileChange}
|
onChange={handleFileChange}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Загрузить из Экстеор'
|
title='Загрузить из Экстеор'
|
||||||
icon={<BiDownload size='1.25rem' className='clr-text-primary'/>}
|
icon={<BiDownload size='1.25rem' className='clr-text-primary'/>}
|
||||||
onClick={() => inputRef.current?.click()}
|
onClick={() => inputRef.current?.click()}
|
||||||
/>
|
/>
|
||||||
|
@ -112,7 +112,7 @@ function CreateRSFormPage() {
|
||||||
placeholder={file && 'Загрузить из файла'}
|
placeholder={file && 'Загрузить из файла'}
|
||||||
className='w-[14rem]'
|
className='w-[14rem]'
|
||||||
pattern={patterns.alias}
|
pattern={patterns.alias}
|
||||||
tooltip={`не более ${limits.alias_len} символов`}
|
title={`не более ${limits.alias_len} символов`}
|
||||||
value={alias}
|
value={alias}
|
||||||
onChange={event => setAlias(event.target.value)}
|
onChange={event => setAlias(event.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -42,8 +42,8 @@ function PickerStrategy({ value, onChange }: PickerStrategyProps) {
|
||||||
return (
|
return (
|
||||||
<div ref={strategyMenu.ref} className='h-full text-right'>
|
<div ref={strategyMenu.ref} className='h-full text-right'>
|
||||||
<SelectorButton transparent tabIndex={-1}
|
<SelectorButton transparent tabIndex={-1}
|
||||||
tooltip='Список фильтров'
|
title='Список фильтров'
|
||||||
dimensions='w-fit h-full'
|
className='h-full'
|
||||||
icon={<BiFilterAlt size='1.25rem' />}
|
icon={<BiFilterAlt size='1.25rem' />}
|
||||||
text={labelLibraryFilter(value)}
|
text={labelLibraryFilter(value)}
|
||||||
onClick={strategyMenu.toggle}
|
onClick={strategyMenu.toggle}
|
||||||
|
@ -59,7 +59,7 @@ function PickerStrategy({ value, onChange }: PickerStrategyProps) {
|
||||||
value={value === strategy}
|
value={value === strategy}
|
||||||
setValue={() => handleChange(strategy)}
|
setValue={() => handleChange(strategy)}
|
||||||
label={labelLibraryFilter(strategy)}
|
label={labelLibraryFilter(strategy)}
|
||||||
tooltip={describeLibraryFilter(strategy)}
|
title={describeLibraryFilter(strategy)}
|
||||||
disabled={isStrategyDisabled(strategy)}
|
disabled={isStrategyDisabled(strategy)}
|
||||||
/>);
|
/>);
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -65,7 +65,7 @@ function SearchPanel({ total, filtered, query, setQuery, strategy, setFilter }:
|
||||||
'flex gap-1 justify-center items-center'
|
'flex gap-1 justify-center items-center'
|
||||||
)}>
|
)}>
|
||||||
<ConceptSearch noBorder
|
<ConceptSearch noBorder
|
||||||
dimensions='min-w-[10rem]'
|
className='min-w-[10rem]'
|
||||||
value={query}
|
value={query}
|
||||||
onChange={handleChangeQuery}
|
onChange={handleChangeQuery}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -101,7 +101,7 @@ function ViewLibrary({ items, resetQuery: cleanQuery }: ViewLibraryProps) {
|
||||||
)}>
|
)}>
|
||||||
<HelpButton
|
<HelpButton
|
||||||
topic={HelpTopic.LIBRARY}
|
topic={HelpTopic.LIBRARY}
|
||||||
dimensions='max-w-[35rem]'
|
className='max-w-[35rem]'
|
||||||
offset={0}
|
offset={0}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NagivationContext';
|
import { useConceptNavigation } from '@/context/NagivationContext';
|
||||||
import useQueryStrings from '@/hooks/useQueryStrings';
|
import useQueryStrings from '@/hooks/useQueryStrings';
|
||||||
import { IUserLoginData } from '@/models/library';
|
import { IUserLoginData } from '@/models/library';
|
||||||
import { resources } from '@/utils/constants';
|
import { classnames, resources } from '@/utils/constants';
|
||||||
|
|
||||||
|
|
||||||
function ProcessError({error}: { error: ErrorData }): React.ReactElement {
|
function ProcessError({error}: { error: ErrorData }): React.ReactElement {
|
||||||
|
@ -68,7 +68,8 @@ function LoginPage() {
|
||||||
<form
|
<form
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-[24rem]',
|
'w-[24rem]',
|
||||||
'pt-12 pb-6 px-6 flex flex-col gap-3'
|
'pt-12 pb-6 px-6',
|
||||||
|
classnames.flex_col
|
||||||
)}
|
)}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
|
|
|
@ -13,8 +13,7 @@ function TopicsList({ activeTopic, onChangeTopic }: TopicsListProps) {
|
||||||
return (
|
return (
|
||||||
<div className={clsx(
|
<div className={clsx(
|
||||||
'sticky top-0 left-0',
|
'sticky top-0 left-0',
|
||||||
'min-w-[13rem] h-fit',
|
'min-w-[13rem]',
|
||||||
'flex flex-col',
|
|
||||||
'border-x',
|
'border-x',
|
||||||
'clr-controls',
|
'clr-controls',
|
||||||
'small-caps',
|
'small-caps',
|
||||||
|
|
|
@ -30,31 +30,31 @@ function ConstituentaToolbar({
|
||||||
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
|
||||||
tooltip='Сохранить изменения [Ctrl + S]'
|
title='Сохранить изменения [Ctrl + S]'
|
||||||
disabled={!canSave}
|
disabled={!canSave}
|
||||||
icon={<FiSave size='1.25rem' className={canSave ? 'clr-text-primary' : ''}/>}
|
icon={<FiSave size='1.25rem' className={canSave ? 'clr-text-primary' : ''}/>}
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Сбросить несохраненные изменения'
|
title='Сбросить несохраненные изменения'
|
||||||
disabled={!canSave}
|
disabled={!canSave}
|
||||||
onClick={onReset}
|
onClick={onReset}
|
||||||
icon={<BiReset size='1.25rem' className={canSave ? 'clr-text-primary' : ''} />}
|
icon={<BiReset size='1.25rem' className={canSave ? 'clr-text-primary' : ''} />}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Создать конституенту после данной'
|
title='Создать конституенту после данной'
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={onCreate}
|
onClick={onCreate}
|
||||||
icon={<BiPlusCircle size={'1.25rem'} className={isMutable ? 'clr-text-success' : ''} />}
|
icon={<BiPlusCircle size={'1.25rem'} className={isMutable ? 'clr-text-success' : ''} />}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Клонировать конституенту [Alt + V]'
|
title='Клонировать конституенту [Alt + V]'
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={onClone}
|
onClick={onClone}
|
||||||
icon={<BiDuplicate size='1.25rem' className={isMutable ? 'clr-text-success' : ''} />}
|
icon={<BiDuplicate size='1.25rem' className={isMutable ? 'clr-text-success' : ''} />}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Удалить редактируемую конституенту'
|
title='Удалить редактируемую конституенту'
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={onDelete}
|
onClick={onDelete}
|
||||||
icon={<BiTrash size='1.25rem' className={isMutable ? 'clr-text-warning' : ''} />}
|
icon={<BiTrash size='1.25rem' className={isMutable ? 'clr-text-warning' : ''} />}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import TextArea from '@/components/Common/TextArea';
|
||||||
import RefsInput from '@/components/RefsInput';
|
import RefsInput from '@/components/RefsInput';
|
||||||
import { useRSForm } from '@/context/RSFormContext';
|
import { useRSForm } from '@/context/RSFormContext';
|
||||||
import { IConstituenta, ICstRenameData, ICstUpdateData } from '@/models/rsform';
|
import { IConstituenta, ICstRenameData, ICstUpdateData } from '@/models/rsform';
|
||||||
|
import { classnames } from '@/utils/constants';
|
||||||
import { labelCstTypification } from '@/utils/labels';
|
import { labelCstTypification } from '@/utils/labels';
|
||||||
|
|
||||||
import EditorRSExpression from '../EditorRSExpression';
|
import EditorRSExpression from '../EditorRSExpression';
|
||||||
|
@ -111,18 +112,18 @@ function FormConstituenta({
|
||||||
className='flex select-none'
|
className='flex select-none'
|
||||||
>
|
>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip={`Редактировать словоформы термина: ${constituenta?.term_forms.length ?? 0}`}
|
title={`Редактировать словоформы термина: ${constituenta?.term_forms.length ?? 0}`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
noHover
|
noHover
|
||||||
onClick={onEditTerm}
|
onClick={onEditTerm}
|
||||||
icon={<LiaEdit size='1rem' className={!disabled ? 'clr-text-primary' : ''} />}
|
icon={<LiaEdit size='1rem' className={!disabled ? 'clr-text-primary' : ''} />}
|
||||||
/>
|
/>
|
||||||
<div className='pt-1 pl-[1.375rem] text-sm font-semibold whitespace-nowrap w-fit'>
|
<div className='pt-1 pl-[1.375rem] text-sm font-semibold whitespace-nowrap'>
|
||||||
<span>Имя </span>
|
<span>Имя </span>
|
||||||
<span className='ml-1'>{constituenta?.alias ?? ''}</span>
|
<span className='ml-1'>{constituenta?.alias ?? ''}</span>
|
||||||
</div>
|
</div>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Переименовать конституенту'
|
title='Переименовать конституенту'
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={handleRename}
|
onClick={handleRename}
|
||||||
icon={<LiaEdit size='1rem' className={!disabled ? 'clr-text-primary' : ''} />}
|
icon={<LiaEdit size='1rem' className={!disabled ? 'clr-text-primary' : ''} />}
|
||||||
|
@ -131,7 +132,8 @@ function FormConstituenta({
|
||||||
<form id={id}
|
<form id={id}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'mt-1 min-w-[47.8rem] max-w-[47.8rem]',
|
'mt-1 min-w-[47.8rem] max-w-[47.8rem]',
|
||||||
'px-4 py-1 flex flex-col gap-3'
|
'px-4 py-1',
|
||||||
|
classnames.flex_col
|
||||||
)}
|
)}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
|
|
|
@ -138,12 +138,12 @@ function EditorRSExpression({
|
||||||
<div>
|
<div>
|
||||||
<Overlay position='top-0 right-0 flex'>
|
<Overlay position='top-0 right-0 flex'>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Включение специальной клавиатуры'
|
title='Включение специальной клавиатуры'
|
||||||
onClick={() => setShowControls(prev => !prev)}
|
onClick={() => setShowControls(prev => !prev)}
|
||||||
icon={<FaRegKeyboard size='1.25rem' className={showControls ? 'clr-text-primary': ''} />}
|
icon={<FaRegKeyboard size='1.25rem' className={showControls ? 'clr-text-primary': ''} />}
|
||||||
/>
|
/>
|
||||||
<MiniButton noHover
|
<MiniButton noHover
|
||||||
tooltip='Дерево разбора выражения'
|
title='Дерево разбора выражения'
|
||||||
onClick={handleShowAST}
|
onClick={handleShowAST}
|
||||||
icon={<RiNodeTree size='1.25rem' className='clr-text-primary' />}
|
icon={<RiNodeTree size='1.25rem' className='clr-text-primary' />}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -52,30 +52,30 @@ const MAIN_THIRD_ROW: TokenID[] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
const SECONDARY_FIRST_ROW = [
|
const SECONDARY_FIRST_ROW = [
|
||||||
{text: 'μ', tooltip: 'q'},
|
{text: 'μ', title: 'q'},
|
||||||
{text: 'ω', tooltip: 'w'},
|
{text: 'ω', title: 'w'},
|
||||||
{text: 'ε', tooltip: 'e'},
|
{text: 'ε', title: 'e'},
|
||||||
{text: 'ρ', tooltip: 'r'},
|
{text: 'ρ', title: 'r'},
|
||||||
{text: 'τ', tooltip: 't'},
|
{text: 'τ', title: 't'},
|
||||||
{text: 'π', tooltip: 'y'}
|
{text: 'π', title: 'y'}
|
||||||
];
|
];
|
||||||
|
|
||||||
const SECONDARY_SECOND_ROW = [
|
const SECONDARY_SECOND_ROW = [
|
||||||
{text: 'α', tooltip: 'a'},
|
{text: 'α', title: 'a'},
|
||||||
{text: 'σ', tooltip: 's'},
|
{text: 'σ', title: 's'},
|
||||||
{text: 'δ', tooltip: 'd'},
|
{text: 'δ', title: 'd'},
|
||||||
{text: 'φ', tooltip: 'f'},
|
{text: 'φ', title: 'f'},
|
||||||
{text: 'γ', tooltip: 'g'},
|
{text: 'γ', title: 'g'},
|
||||||
{text: 'λ', tooltip: 'h'}
|
{text: 'λ', title: 'h'}
|
||||||
];
|
];
|
||||||
|
|
||||||
const SECONDARY_THIRD_ROW = [
|
const SECONDARY_THIRD_ROW = [
|
||||||
{text: 'ζ', tooltip: 'z'},
|
{text: 'ζ', title: 'z'},
|
||||||
{text: 'ξ', tooltip: 'x'},
|
{text: 'ξ', title: 'x'},
|
||||||
{text: 'ψ', tooltip: 'c'},
|
{text: 'ψ', title: 'c'},
|
||||||
{text: 'θ', tooltip: 'v'},
|
{text: 'θ', title: 'v'},
|
||||||
{text: 'β', tooltip: 'b'},
|
{text: 'β', title: 'b'},
|
||||||
{text: 'η', tooltip: 'n'}
|
{text: 'η', title: 'n'}
|
||||||
];
|
];
|
||||||
|
|
||||||
interface RSEditorControlsProps {
|
interface RSEditorControlsProps {
|
||||||
|
@ -92,9 +92,9 @@ function RSEditorControls({ onEdit, disabled }: RSEditorControlsProps) {
|
||||||
token={token} onInsert={onEdit} disabled={disabled}
|
token={token} onInsert={onEdit} disabled={disabled}
|
||||||
/>)}
|
/>)}
|
||||||
{SECONDARY_FIRST_ROW.map(
|
{SECONDARY_FIRST_ROW.map(
|
||||||
({text, tooltip}) =>
|
({text, title}) =>
|
||||||
<RSLocalButton key={`${prefixes.rsedit_btn}${tooltip}`}
|
<RSLocalButton key={`${prefixes.rsedit_btn}${title}`}
|
||||||
text={text} tooltip={tooltip} onInsert={onEdit} disabled={disabled}
|
text={text} title={title} onInsert={onEdit} disabled={disabled}
|
||||||
/>)}
|
/>)}
|
||||||
|
|
||||||
{MAIN_SECOND_ROW.map(
|
{MAIN_SECOND_ROW.map(
|
||||||
|
@ -103,9 +103,9 @@ function RSEditorControls({ onEdit, disabled }: RSEditorControlsProps) {
|
||||||
token={token} onInsert={onEdit} disabled={disabled}
|
token={token} onInsert={onEdit} disabled={disabled}
|
||||||
/>)}
|
/>)}
|
||||||
{SECONDARY_SECOND_ROW.map(
|
{SECONDARY_SECOND_ROW.map(
|
||||||
({text, tooltip}) =>
|
({text, title}) =>
|
||||||
<RSLocalButton key={`${prefixes.rsedit_btn}${tooltip}`}
|
<RSLocalButton key={`${prefixes.rsedit_btn}${title}`}
|
||||||
text={text} tooltip={tooltip} onInsert={onEdit} disabled={disabled}
|
text={text} title={title} onInsert={onEdit} disabled={disabled}
|
||||||
/>)}
|
/>)}
|
||||||
|
|
||||||
{MAIN_THIRD_ROW.map(
|
{MAIN_THIRD_ROW.map(
|
||||||
|
@ -114,9 +114,9 @@ function RSEditorControls({ onEdit, disabled }: RSEditorControlsProps) {
|
||||||
token={token} onInsert={onEdit} disabled={disabled}
|
token={token} onInsert={onEdit} disabled={disabled}
|
||||||
/>)}
|
/>)}
|
||||||
{SECONDARY_THIRD_ROW.map(
|
{SECONDARY_THIRD_ROW.map(
|
||||||
({text, tooltip}) =>
|
({text, title}) =>
|
||||||
<RSLocalButton key={`${prefixes.rsedit_btn}${tooltip}`}
|
<RSLocalButton key={`${prefixes.rsedit_btn}${title}`}
|
||||||
text={text} tooltip={tooltip} onInsert={onEdit} disabled={disabled}
|
text={text} title={title} onInsert={onEdit} disabled={disabled}
|
||||||
/>)}
|
/>)}
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { TokenID } from '@/models/rslang';
|
||||||
|
|
||||||
interface RSLocalButtonProps {
|
interface RSLocalButtonProps {
|
||||||
text: string
|
text: string
|
||||||
tooltip: string
|
title: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
onInsert: (token: TokenID, key?: string) => void
|
onInsert: (token: TokenID, key?: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSLocalButton({ text, tooltip, disabled, onInsert }: RSLocalButtonProps) {
|
function RSLocalButton({ text, title, disabled, onInsert }: RSLocalButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button type='button' tabIndex={-1}
|
<button type='button' tabIndex={-1}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
title={tooltip}
|
title={title}
|
||||||
className='w-[2rem] h-6 cursor-pointer disabled:cursor-default rounded-none clr-hover clr-btn-clear'
|
className='w-[2rem] h-6 cursor-pointer disabled:cursor-default rounded-none clr-hover clr-btn-clear'
|
||||||
onClick={() => onInsert(TokenID.ID_LOCAL, text)}
|
onClick={() => onInsert(TokenID.ID_LOCAL, text)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
|
|
||||||
import Divider from '@/components/Common/Divider';
|
import Divider from '@/components/Common/Divider';
|
||||||
|
import FlexColumn from '@/components/Common/FlexColumn';
|
||||||
import InfoLibraryItem from '@/components/Shared/InfoLibraryItem';
|
import InfoLibraryItem from '@/components/Shared/InfoLibraryItem';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useRSForm } from '@/context/RSFormContext';
|
import { useRSForm } from '@/context/RSFormContext';
|
||||||
|
@ -69,7 +70,7 @@ function EditorRSForm({
|
||||||
className='flex'
|
className='flex'
|
||||||
onKeyDown={handleInput}
|
onKeyDown={handleInput}
|
||||||
>
|
>
|
||||||
<div className='flex flex-col gap-3 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}
|
||||||
|
@ -79,7 +80,7 @@ function EditorRSForm({
|
||||||
<Divider margins='my-2' />
|
<Divider margins='my-2' />
|
||||||
|
|
||||||
<InfoLibraryItem item={schema} />
|
<InfoLibraryItem item={schema} />
|
||||||
</div>
|
</FlexColumn>
|
||||||
|
|
||||||
<RSFormStats stats={schema?.stats}/>
|
<RSFormStats stats={schema?.stats}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
import { Dispatch, SetStateAction, useEffect, useLayoutEffect, useState } from 'react';
|
import { Dispatch, SetStateAction, useEffect, useLayoutEffect, useState } from 'react';
|
||||||
import { FiSave } from 'react-icons/fi';
|
import { FiSave } from 'react-icons/fi';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
@ -12,7 +13,7 @@ import { useAuth } from '@/context/AuthContext';
|
||||||
import { useRSForm } from '@/context/RSFormContext';
|
import { useRSForm } from '@/context/RSFormContext';
|
||||||
import { LibraryItemType } from '@/models/library';
|
import { LibraryItemType } from '@/models/library';
|
||||||
import { IRSFormCreateData } from '@/models/rsform';
|
import { IRSFormCreateData } from '@/models/rsform';
|
||||||
import { limits, patterns } from '@/utils/constants';
|
import { classnames, limits, patterns } from '@/utils/constants';
|
||||||
|
|
||||||
interface FormRSFormProps {
|
interface FormRSFormProps {
|
||||||
id?: string
|
id?: string
|
||||||
|
@ -79,7 +80,11 @@ function FormRSForm({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id={id}
|
<form id={id}
|
||||||
className='flex flex-col gap-3 mt-1 py-1 min-w-[22rem] w-[30rem]'
|
className={clsx(
|
||||||
|
'mt-1 min-w-[22rem] w-[30rem]',
|
||||||
|
'py-1',
|
||||||
|
classnames.flex_col
|
||||||
|
)}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<TextInput required
|
<TextInput required
|
||||||
|
@ -92,7 +97,7 @@ function FormRSForm({
|
||||||
label='Сокращение'
|
label='Сокращение'
|
||||||
className='w-[14rem]'
|
className='w-[14rem]'
|
||||||
pattern={patterns.alias}
|
pattern={patterns.alias}
|
||||||
tooltip={`не более ${limits.alias_len} символов`}
|
title={`не более ${limits.alias_len} символов`}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={alias}
|
value={alias}
|
||||||
onChange={event => setAlias(event.target.value)}
|
onChange={event => setAlias(event.target.value)}
|
||||||
|
@ -106,14 +111,14 @@ function FormRSForm({
|
||||||
<div className='flex justify-between whitespace-nowrap'>
|
<div className='flex justify-between whitespace-nowrap'>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Общедоступная схема'
|
label='Общедоступная схема'
|
||||||
tooltip='Общедоступные схемы видны всем пользователям и могут быть изменены'
|
title='Общедоступные схемы видны всем пользователям и могут быть изменены'
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={common}
|
value={common}
|
||||||
setValue={value => setCommon(value)}
|
setValue={value => setCommon(value)}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Неизменная схема'
|
label='Неизменная схема'
|
||||||
tooltip='Только администраторы могут присваивать схемам неизменный статус'
|
title='Только администраторы могут присваивать схемам неизменный статус'
|
||||||
disabled={disabled || !user?.is_staff}
|
disabled={disabled || !user?.is_staff}
|
||||||
value={canonical}
|
value={canonical}
|
||||||
setValue={value => setCanonical(value)}
|
setValue={value => setCanonical(value)}
|
||||||
|
|
|
@ -11,7 +11,7 @@ function RSFormStats({ stats }: RSFormStatsProps) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-1 px-4 mt-8 min-w-[16rem] max-w-[16rem]'>
|
<div className='flex flex-col gap-1 px-4 mt-8 w-[16rem]'>
|
||||||
<LabeledValue id='count_all'
|
<LabeledValue id='count_all'
|
||||||
label='Всего конституент '
|
label='Всего конституент '
|
||||||
text={stats.count_all}
|
text={stats.count_all}
|
||||||
|
|
|
@ -36,40 +36,39 @@ function RSFormToolbar({
|
||||||
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
|
||||||
tooltip='Сохранить изменения [Ctrl + S]'
|
title='Сохранить изменения [Ctrl + S]'
|
||||||
disabled={!canSave}
|
disabled={!canSave}
|
||||||
icon={<FiSave size='1.25rem' className={canSave ? 'clr-text-primary' : ''}/>}
|
icon={<FiSave size='1.25rem' className={canSave ? 'clr-text-primary' : ''}/>}
|
||||||
onClick={onSubmit}
|
onClick={onSubmit}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Поделиться схемой'
|
title='Поделиться схемой'
|
||||||
icon={<BiShareAlt size='1.25rem' className='clr-text-primary'/>}
|
icon={<BiShareAlt size='1.25rem' className='clr-text-primary'/>}
|
||||||
onClick={onShare}
|
onClick={onShare}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Скачать TRS файл'
|
title='Скачать TRS файл'
|
||||||
icon={<BiDownload size='1.25rem' className='clr-text-primary'/>}
|
icon={<BiDownload size='1.25rem' className='clr-text-primary'/>}
|
||||||
onClick={onDownload}
|
onClick={onDownload}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip={'отслеживание: ' + (isSubscribed ? '[включено]' : '[выключено]')}
|
title={'отслеживание: ' + (isSubscribed ? '[включено]' : '[выключено]')}
|
||||||
disabled={anonymous || processing}
|
disabled={anonymous || processing}
|
||||||
icon={isSubscribed
|
icon={isSubscribed
|
||||||
? <FiBell size='1.25rem' className='clr-text-primary' />
|
? <FiBell size='1.25rem' className='clr-text-primary' />
|
||||||
: <FiBellOff size='1.25rem' className='clr-text-controls' />
|
: <FiBellOff size='1.25rem' className='clr-text-controls' />
|
||||||
}
|
}
|
||||||
dimensions='h-full w-fit'
|
|
||||||
style={{outlineColor: 'transparent'}}
|
style={{outlineColor: 'transparent'}}
|
||||||
onClick={onToggleSubscribe}
|
onClick={onToggleSubscribe}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip={claimable ? 'Стать владельцем' : 'Невозможно стать владельцем' }
|
title={claimable ? 'Стать владельцем' : 'Невозможно стать владельцем' }
|
||||||
icon={<LuCrown size='1.25rem' className={!claimable ? '' : 'clr-text-success'}/>}
|
icon={<LuCrown size='1.25rem' className={!claimable ? '' : 'clr-text-success'}/>}
|
||||||
disabled={!claimable || anonymous || processing}
|
disabled={!claimable || anonymous || processing}
|
||||||
onClick={onClaim}
|
onClick={onClaim}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Удалить схему'
|
title='Удалить схему'
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={onDestroy}
|
onClick={onDestroy}
|
||||||
icon={<BiTrash size='1.25rem' className={isMutable ? 'clr-text-warning' : ''} />}
|
icon={<BiTrash size='1.25rem' className={isMutable ? 'clr-text-warning' : ''} />}
|
||||||
|
|
|
@ -40,25 +40,25 @@ function RSListToolbar({
|
||||||
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
|
||||||
tooltip='Переместить вверх [Alt + вверх]'
|
title='Переместить вверх [Alt + вверх]'
|
||||||
icon={<BiUpvote size='1.25rem' className={isMutable && !nothingSelected ? 'clr-text-primary': ''}/>}
|
icon={<BiUpvote size='1.25rem' className={isMutable && !nothingSelected ? 'clr-text-primary': ''}/>}
|
||||||
disabled={!isMutable || nothingSelected}
|
disabled={!isMutable || nothingSelected}
|
||||||
onClick={onMoveUp}
|
onClick={onMoveUp}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Переместить вниз [Alt + вниз]'
|
title='Переместить вниз [Alt + вниз]'
|
||||||
icon={<BiDownvote size='1.25rem' className={isMutable && !nothingSelected ? 'clr-text-primary': ''}/>}
|
icon={<BiDownvote size='1.25rem' className={isMutable && !nothingSelected ? 'clr-text-primary': ''}/>}
|
||||||
disabled={!isMutable || nothingSelected}
|
disabled={!isMutable || nothingSelected}
|
||||||
onClick={onMoveDown}
|
onClick={onMoveDown}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Клонировать конституенту [Alt + V]'
|
title='Клонировать конституенту [Alt + V]'
|
||||||
icon={<BiDuplicate size='1.25rem' className={isMutable && selectedCount === 1 ? 'clr-text-success': ''} />}
|
icon={<BiDuplicate size='1.25rem' className={isMutable && selectedCount === 1 ? 'clr-text-success': ''} />}
|
||||||
disabled={!isMutable || selectedCount !== 1}
|
disabled={!isMutable || selectedCount !== 1}
|
||||||
onClick={onClone}
|
onClick={onClone}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Добавить новую конституенту... [Alt + `]'
|
title='Добавить новую конституенту... [Alt + `]'
|
||||||
icon={<BiPlusCircle size='1.25rem' className={isMutable ? 'clr-text-success': ''} />}
|
icon={<BiPlusCircle size='1.25rem' className={isMutable ? 'clr-text-success': ''} />}
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={() => onCreate()}
|
onClick={() => onCreate()}
|
||||||
|
@ -66,7 +66,7 @@ function RSListToolbar({
|
||||||
<div ref={insertMenu.ref} className='flex justify-center'>
|
<div ref={insertMenu.ref} className='flex justify-center'>
|
||||||
<div>
|
<div>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Добавить пустую конституенту'
|
title='Добавить пустую конституенту'
|
||||||
icon={<BiDownArrowCircle size='1.25rem' className={isMutable ? 'clr-text-success': ''} />}
|
icon={<BiDownArrowCircle size='1.25rem' className={isMutable ? 'clr-text-success': ''} />}
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={insertMenu.toggle}
|
onClick={insertMenu.toggle}
|
||||||
|
@ -79,14 +79,14 @@ function RSListToolbar({
|
||||||
key={`${prefixes.csttype_list}${typeStr}`}
|
key={`${prefixes.csttype_list}${typeStr}`}
|
||||||
text={`${getCstTypePrefix(typeStr as CstType)}1 — ${labelCstType(typeStr as CstType)}`}
|
text={`${getCstTypePrefix(typeStr as CstType)}1 — ${labelCstType(typeStr as CstType)}`}
|
||||||
onClick={() => onCreate(typeStr as CstType)}
|
onClick={() => onCreate(typeStr as CstType)}
|
||||||
tooltip={getCstTypeShortcut(typeStr as CstType)}
|
title={getCstTypeShortcut(typeStr as CstType)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Dropdown> : null}
|
</Dropdown> : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Удалить выбранные [Delete]'
|
title='Удалить выбранные [Delete]'
|
||||||
icon={<BiTrash size='1.25rem' className={isMutable && !nothingSelected ? 'clr-text-warning' : ''} />}
|
icon={<BiTrash size='1.25rem' className={isMutable && !nothingSelected ? 'clr-text-warning' : ''} />}
|
||||||
disabled={!isMutable || nothingSelected}
|
disabled={!isMutable || nothingSelected}
|
||||||
onClick={onDelete}
|
onClick={onDelete}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import useLocalStorage from '@/hooks/useLocalStorage';
|
||||||
import { GraphColoringScheme, GraphFilterParams } from '@/models/miscelanious';
|
import { GraphColoringScheme, GraphFilterParams } from '@/models/miscelanious';
|
||||||
import { CstType, ICstCreateData } from '@/models/rsform';
|
import { CstType, ICstCreateData } from '@/models/rsform';
|
||||||
import { colorbgGraphNode } from '@/utils/color';
|
import { colorbgGraphNode } from '@/utils/color';
|
||||||
import { TIMEOUT_GRAPH_REFRESH } from '@/utils/constants';
|
import { classnames, TIMEOUT_GRAPH_REFRESH } from '@/utils/constants';
|
||||||
|
|
||||||
import GraphSidebar from './GraphSidebar';
|
import GraphSidebar from './GraphSidebar';
|
||||||
import GraphToolbar from './GraphToolbar';
|
import GraphToolbar from './GraphToolbar';
|
||||||
|
@ -235,7 +235,7 @@ function EditorTermGraph({ isMutable, onOpenEdit, onCreateCst, onDeleteCst }: Ed
|
||||||
layer='z-tooltip'
|
layer='z-tooltip'
|
||||||
position='top-[1.6rem] left-[2.6rem]'
|
position='top-[1.6rem] left-[2.6rem]'
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-[25rem] h-fit min-h-[11rem]',
|
'w-[25rem]',
|
||||||
'px-3',
|
'px-3',
|
||||||
'overflow-y-auto',
|
'overflow-y-auto',
|
||||||
'border shadow-md',
|
'border shadow-md',
|
||||||
|
@ -243,6 +243,7 @@ function EditorTermGraph({ isMutable, onOpenEdit, onCreateCst, onDeleteCst }: Ed
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<InfoConstituenta
|
<InfoConstituenta
|
||||||
|
className='pt-1 pb-2'
|
||||||
data={hoverCst}
|
data={hoverCst}
|
||||||
/>
|
/>
|
||||||
</Overlay> : null}
|
</Overlay> : null}
|
||||||
|
@ -250,8 +251,8 @@ function EditorTermGraph({ isMutable, onOpenEdit, onCreateCst, onDeleteCst }: Ed
|
||||||
<Overlay
|
<Overlay
|
||||||
position='top-0 left-0'
|
position='top-0 left-0'
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'max-w-[13.5rem] min-w-[13.5rem]',
|
'w-[13.5rem]',
|
||||||
'flex flex-col gap-3'
|
classnames.flex_col
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<GraphSidebar
|
<GraphSidebar
|
||||||
|
|
|
@ -34,12 +34,12 @@ function GraphToolbar({
|
||||||
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
|
||||||
tooltip='Настройки фильтрации узлов и связей'
|
title='Настройки фильтрации узлов и связей'
|
||||||
icon={<BiFilterAlt size='1.25rem' className='clr-text-primary' />}
|
icon={<BiFilterAlt size='1.25rem' className='clr-text-primary' />}
|
||||||
onClick={showParamsDialog}
|
onClick={showParamsDialog}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip={!noText ? 'Скрыть текст' : 'Отобразить текст'}
|
title={!noText ? 'Скрыть текст' : 'Отобразить текст'}
|
||||||
icon={
|
icon={
|
||||||
!noText
|
!noText
|
||||||
? <BiFontFamily size='1.25rem' className='clr-text-success' />
|
? <BiFontFamily size='1.25rem' className='clr-text-success' />
|
||||||
|
@ -49,28 +49,28 @@ function GraphToolbar({
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
icon={<BiCollapse size='1.25rem' className='clr-text-primary' />}
|
icon={<BiCollapse size='1.25rem' className='clr-text-primary' />}
|
||||||
tooltip='Восстановить камеру'
|
title='Восстановить камеру'
|
||||||
onClick={onResetViewpoint}
|
onClick={onResetViewpoint}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
icon={<BiPlanet size='1.25rem' className={!is3D ? '' : orbit ? 'clr-text-success' : 'clr-text-primary'} />}
|
icon={<BiPlanet size='1.25rem' className={!is3D ? '' : orbit ? 'clr-text-success' : 'clr-text-primary'} />}
|
||||||
tooltip='Анимация вращения'
|
title='Анимация вращения'
|
||||||
disabled={!is3D}
|
disabled={!is3D}
|
||||||
onClick={toggleOrbit}
|
onClick={toggleOrbit}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Новая конституента'
|
title='Новая конституента'
|
||||||
icon={<BiPlusCircle size='1.25rem' className={isMutable ? 'clr-text-success' : ''} />}
|
icon={<BiPlusCircle size='1.25rem' className={isMutable ? 'clr-text-success' : ''} />}
|
||||||
disabled={!isMutable}
|
disabled={!isMutable}
|
||||||
onClick={onCreate}
|
onClick={onCreate}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Удалить выбранные'
|
title='Удалить выбранные'
|
||||||
icon={<BiTrash size='1.25rem' className={isMutable && !nothingSelected ? 'clr-text-warning' : ''} />}
|
icon={<BiTrash size='1.25rem' className={isMutable && !nothingSelected ? 'clr-text-warning' : ''} />}
|
||||||
disabled={!isMutable || nothingSelected}
|
disabled={!isMutable || nothingSelected}
|
||||||
onClick={onDelete}
|
onClick={onDelete}
|
||||||
/>
|
/>
|
||||||
<HelpButton topic={HelpTopic.GRAPH_TERM} dimensions='max-w-[calc(100vw-20rem)]' offset={4} />
|
<HelpButton topic={HelpTopic.GRAPH_TERM} className='max-w-[calc(100vw-20rem)]' offset={4} />
|
||||||
</Overlay>);
|
</Overlay>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ function ViewHidden({
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col text-sm ml-2 border clr-app max-w-[12.5rem] min-w-[12.5rem]'>
|
<div className='flex flex-col text-sm ml-2 border clr-app w-[12.5rem]'>
|
||||||
<p className='mt-2 text-center'><b>Скрытые конституенты</b></p>
|
<p className='mt-2 text-center'><b>Скрытые конституенты</b></p>
|
||||||
<div className='flex flex-wrap justify-center gap-2 py-2 overflow-y-auto' style={{ maxHeight: dismissedHeight }}>
|
<div className='flex flex-wrap justify-center gap-2 py-2 overflow-y-auto' style={{ maxHeight: dismissedHeight }}>
|
||||||
{items.map(
|
{items.map(
|
||||||
|
|
|
@ -415,11 +415,11 @@ function RSTabs() {
|
||||||
/>
|
/>
|
||||||
<ConceptTab
|
<ConceptTab
|
||||||
label='Карточка'
|
label='Карточка'
|
||||||
tooltip={`Название схемы: ${schema.title ?? ''}`}
|
title={`Название схемы: ${schema.title ?? ''}`}
|
||||||
/>
|
/>
|
||||||
<ConceptTab
|
<ConceptTab
|
||||||
label='Содержание'
|
label='Содержание'
|
||||||
tooltip={[
|
title={[
|
||||||
`Всего конституент: ${schema.stats?.count_all ?? 0}`,
|
`Всего конституент: ${schema.stats?.count_all ?? 0}`,
|
||||||
`Количество ошибок: ${schema.stats?.count_errors ?? 0}`
|
`Количество ошибок: ${schema.stats?.count_errors ?? 0}`
|
||||||
].join('\n')}
|
].join('\n')}
|
||||||
|
|
|
@ -98,7 +98,7 @@ function RSTabsMenu({
|
||||||
<div className='flex'>
|
<div className='flex'>
|
||||||
<div ref={schemaMenu.ref}>
|
<div ref={schemaMenu.ref}>
|
||||||
<Button noBorder dense tabIndex={-1}
|
<Button noBorder dense tabIndex={-1}
|
||||||
tooltip='Меню'
|
title='Меню'
|
||||||
icon={<BiMenu size='1.25rem' className='clr-text-controls' />}
|
icon={<BiMenu size='1.25rem' className='clr-text-controls' />}
|
||||||
className='h-full pl-2'
|
className='h-full pl-2'
|
||||||
style={{outlineColor: 'transparent'}}
|
style={{outlineColor: 'transparent'}}
|
||||||
|
@ -108,7 +108,7 @@ function RSTabsMenu({
|
||||||
<Dropdown>
|
<Dropdown>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={isOwned ? 'Вы — владелец' : 'Стать владельцем'}
|
text={isOwned ? 'Вы — владелец' : 'Стать владельцем'}
|
||||||
tooltip={!user || !isClaimable ? 'Взять во владение можно общую изменяемую схему' : ''}
|
title={!user || !isClaimable ? 'Взять во владение можно общую изменяемую схему' : ''}
|
||||||
icon={<LuCrown size='1rem' className={isOwned ? 'clr-text-success' : 'clr-text-controls'} />}
|
icon={<LuCrown size='1rem' className={isOwned ? 'clr-text-success' : 'clr-text-controls'} />}
|
||||||
onClick={(!isOwned && user && isClaimable) ? handleClaimOwner : undefined}
|
onClick={(!isOwned && user && isClaimable) ? handleClaimOwner : undefined}
|
||||||
/>
|
/>
|
||||||
|
@ -147,7 +147,7 @@ function RSTabsMenu({
|
||||||
|
|
||||||
<div ref={editMenu.ref}>
|
<div ref={editMenu.ref}>
|
||||||
<Button dense noBorder tabIndex={-1}
|
<Button dense noBorder tabIndex={-1}
|
||||||
tooltip={'Редактирование'}
|
title={'Редактирование'}
|
||||||
className='h-full'
|
className='h-full'
|
||||||
style={{outlineColor: 'transparent'}}
|
style={{outlineColor: 'transparent'}}
|
||||||
icon={<FiEdit size='1.25rem' className={isMutable ? 'clr-text-success' : 'clr-text-warning'}/>}
|
icon={<FiEdit size='1.25rem' className={isMutable ? 'clr-text-success' : 'clr-text-warning'}/>}
|
||||||
|
@ -157,13 +157,13 @@ function RSTabsMenu({
|
||||||
<Dropdown>
|
<Dropdown>
|
||||||
<DropdownButton disabled={!isMutable}
|
<DropdownButton disabled={!isMutable}
|
||||||
text='Сброс имён'
|
text='Сброс имён'
|
||||||
tooltip='Присвоить порядковые имена и обновить выражения'
|
title='Присвоить порядковые имена и обновить выражения'
|
||||||
icon={<BiAnalyse size='1rem' className={isMutable ? 'clr-text-primary': ''} />}
|
icon={<BiAnalyse size='1rem' className={isMutable ? 'clr-text-primary': ''} />}
|
||||||
onClick={handleReindex}
|
onClick={handleReindex}
|
||||||
/>
|
/>
|
||||||
<DropdownButton disabled={!isMutable}
|
<DropdownButton disabled={!isMutable}
|
||||||
text='Банк выражений'
|
text='Банк выражений'
|
||||||
tooltip='Создать конституенту из шаблона'
|
title='Создать конституенту из шаблона'
|
||||||
icon={<BiDiamond size='1rem' className={isMutable ? 'clr-text-success': ''} />}
|
icon={<BiDiamond size='1rem' className={isMutable ? 'clr-text-success': ''} />}
|
||||||
onClick={handleTemplates}
|
onClick={handleTemplates}
|
||||||
/>
|
/>
|
||||||
|
@ -172,7 +172,7 @@ function RSTabsMenu({
|
||||||
|
|
||||||
<div ref={accessMenu.ref}>
|
<div ref={accessMenu.ref}>
|
||||||
<Button dense noBorder tabIndex={-1}
|
<Button dense noBorder tabIndex={-1}
|
||||||
tooltip={`режим ${labelAccessMode(mode)}`}
|
title={`режим ${labelAccessMode(mode)}`}
|
||||||
className='h-full pr-2'
|
className='h-full pr-2'
|
||||||
style={{outlineColor: 'transparent'}}
|
style={{outlineColor: 'transparent'}}
|
||||||
icon={
|
icon={
|
||||||
|
@ -186,19 +186,19 @@ function RSTabsMenu({
|
||||||
<Dropdown>
|
<Dropdown>
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
text={labelAccessMode(UserAccessMode.READER)}
|
text={labelAccessMode(UserAccessMode.READER)}
|
||||||
tooltip={describeAccessMode(UserAccessMode.READER)}
|
title={describeAccessMode(UserAccessMode.READER)}
|
||||||
icon={<LuGlasses size='1rem' className='clr-text-primary' />}
|
icon={<LuGlasses size='1rem' className='clr-text-primary' />}
|
||||||
onClick={() => handleChangeMode(UserAccessMode.READER)}
|
onClick={() => handleChangeMode(UserAccessMode.READER)}
|
||||||
/>
|
/>
|
||||||
<DropdownButton disabled={!isOwned}
|
<DropdownButton disabled={!isOwned}
|
||||||
text={labelAccessMode(UserAccessMode.OWNER)}
|
text={labelAccessMode(UserAccessMode.OWNER)}
|
||||||
tooltip={describeAccessMode(UserAccessMode.OWNER)}
|
title={describeAccessMode(UserAccessMode.OWNER)}
|
||||||
icon={<LuCrown size='1rem' className={isOwned ? 'clr-text-primary': ''} />}
|
icon={<LuCrown size='1rem' className={isOwned ? 'clr-text-primary': ''} />}
|
||||||
onClick={() => handleChangeMode(UserAccessMode.OWNER)}
|
onClick={() => handleChangeMode(UserAccessMode.OWNER)}
|
||||||
/>
|
/>
|
||||||
<DropdownButton disabled={!user?.is_staff}
|
<DropdownButton disabled={!user?.is_staff}
|
||||||
text={labelAccessMode(UserAccessMode.ADMIN)}
|
text={labelAccessMode(UserAccessMode.ADMIN)}
|
||||||
tooltip={describeAccessMode(UserAccessMode.ADMIN)}
|
title={describeAccessMode(UserAccessMode.ADMIN)}
|
||||||
icon={<BiMeteor size='1rem' className={user?.is_staff ? 'clr-text-primary': ''} />}
|
icon={<BiMeteor size='1rem' className={user?.is_staff ? 'clr-text-primary': ''} />}
|
||||||
onClick={() => handleChangeMode(UserAccessMode.ADMIN)}
|
onClick={() => handleChangeMode(UserAccessMode.ADMIN)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -77,15 +77,15 @@ function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }:
|
||||||
return (
|
return (
|
||||||
<div className='flex items-stretch border-b clr-input'>
|
<div className='flex items-stretch border-b clr-input'>
|
||||||
<ConceptSearch noBorder
|
<ConceptSearch noBorder
|
||||||
dimensions='min-w-[6rem] pr-2 w-full'
|
className='min-w-[6rem] pr-2 flex-grow'
|
||||||
value={filterText}
|
value={filterText}
|
||||||
onChange={setFilterText}
|
onChange={setFilterText}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div ref={matchModeMenu.ref}>
|
<div ref={matchModeMenu.ref}>
|
||||||
<SelectorButton transparent tabIndex={-1}
|
<SelectorButton transparent tabIndex={-1}
|
||||||
tooltip='Настройка атрибутов для фильтрации'
|
title='Настройка атрибутов для фильтрации'
|
||||||
dimensions='w-fit h-full'
|
className='h-full'
|
||||||
icon={<BiFilterAlt size='1.25rem' />}
|
icon={<BiFilterAlt size='1.25rem' />}
|
||||||
text={labelCstMathchMode(filterMatch)}
|
text={labelCstMathchMode(filterMatch)}
|
||||||
onClick={matchModeMenu.toggle}
|
onClick={matchModeMenu.toggle}
|
||||||
|
@ -108,8 +108,8 @@ function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }:
|
||||||
|
|
||||||
<div ref={sourceMenu.ref}>
|
<div ref={sourceMenu.ref}>
|
||||||
<SelectorButton transparent tabIndex={-1}
|
<SelectorButton transparent tabIndex={-1}
|
||||||
tooltip='Настройка фильтрации по графу термов'
|
title='Настройка фильтрации по графу термов'
|
||||||
dimensions='w-fit h-full pr-2'
|
className='h-full pr-2'
|
||||||
icon={<BiCog size='1.25rem' />}
|
icon={<BiCog size='1.25rem' />}
|
||||||
text={labelCstSource(filterSource)}
|
text={labelCstSource(filterSource)}
|
||||||
onClick={sourceMenu.toggle}
|
onClick={sourceMenu.toggle}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { BiInfoCircle } from 'react-icons/bi';
|
import { BiInfoCircle } from 'react-icons/bi';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
@ -7,6 +8,7 @@ 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 ConceptTooltip from '@/components/Common/ConceptTooltip';
|
||||||
|
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';
|
||||||
|
@ -16,7 +18,7 @@ import InfoError from '@/components/InfoError';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NagivationContext';
|
import { useConceptNavigation } from '@/context/NagivationContext';
|
||||||
import { type IUserSignupData } from '@/models/library';
|
import { type IUserSignupData } from '@/models/library';
|
||||||
import { globalIDs, patterns } from '@/utils/constants';
|
import { classnames, globalIDs, patterns } from '@/utils/constants';
|
||||||
|
|
||||||
function RegisterPage() {
|
function RegisterPage() {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
|
@ -66,12 +68,12 @@ function RegisterPage() {
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
className='flex flex-col gap-3 px-6 py-3 h-fit'
|
className={clsx('px-6 py-3', classnames.flex_col)}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<h1>Новый пользователь</h1>
|
<h1>Новый пользователь</h1>
|
||||||
<div className='flex gap-12'>
|
<div className='flex gap-12'>
|
||||||
<div className='flex flex-col gap-3'>
|
<FlexColumn>
|
||||||
<div className='absolute'>
|
<div className='absolute'>
|
||||||
<Overlay
|
<Overlay
|
||||||
id={globalIDs.password_tooltip}
|
id={globalIDs.password_tooltip}
|
||||||
|
@ -91,7 +93,7 @@ function RegisterPage() {
|
||||||
<TextInput id='username' required
|
<TextInput id='username' required
|
||||||
label='Имя пользователя (логин)'
|
label='Имя пользователя (логин)'
|
||||||
pattern={patterns.login}
|
pattern={patterns.login}
|
||||||
tooltip='Минимум 3 знака. Латинские буквы и цифры. Не может начинаться с цифры'
|
title='Минимум 3 знака. Латинские буквы и цифры. Не может начинаться с цифры'
|
||||||
value={username}
|
value={username}
|
||||||
className='w-[15rem]'
|
className='w-[15rem]'
|
||||||
onChange={event => setUsername(event.target.value)}
|
onChange={event => setUsername(event.target.value)}
|
||||||
|
@ -108,12 +110,12 @@ function RegisterPage() {
|
||||||
value={password2}
|
value={password2}
|
||||||
onChange={event => setPassword2(event.target.value)}
|
onChange={event => setPassword2(event.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</FlexColumn>
|
||||||
|
|
||||||
<div className='flex flex-col gap-3 w-[15rem]'>
|
<FlexColumn className='w-[15rem]'>
|
||||||
<TextInput id='email' required
|
<TextInput id='email' required
|
||||||
label='Электронная почта (email)'
|
label='Электронная почта (email)'
|
||||||
tooltip='электронная почта в корректном формате, например: i.petrov@mycompany.ru.com'
|
title='электронная почта в корректном формате, например: i.petrov@mycompany.ru.com'
|
||||||
value={email}
|
value={email}
|
||||||
onChange={event => setEmail(event.target.value)}
|
onChange={event => setEmail(event.target.value)}
|
||||||
/>
|
/>
|
||||||
|
@ -127,7 +129,7 @@ function RegisterPage() {
|
||||||
value={lastName}
|
value={lastName}
|
||||||
onChange={event => setLastName(event.target.value)}
|
onChange={event => setLastName(event.target.value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</FlexColumn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex gap-1 text-sm'>
|
<div className='flex gap-1 text-sm'>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import FlexColumn from '@/components/Common/FlexColumn';
|
||||||
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 InfoError, { ErrorData } from '@/components/InfoError';
|
import InfoError, { ErrorData } from '@/components/InfoError';
|
||||||
|
@ -78,7 +79,7 @@ function EditorPassword() {
|
||||||
)}
|
)}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<div className='flex flex-col gap-3'>
|
<FlexColumn>
|
||||||
<TextInput id='old_password' type='password' allowEnter
|
<TextInput id='old_password' type='password' allowEnter
|
||||||
label='Старый пароль'
|
label='Старый пароль'
|
||||||
value={oldPassword}
|
value={oldPassword}
|
||||||
|
@ -101,7 +102,7 @@ function EditorPassword() {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{error ? <ProcessError error={error} /> : null}
|
{error ? <ProcessError error={error} /> : null}
|
||||||
</div>
|
</FlexColumn>
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
text='Сменить пароль'
|
text='Сменить пароль'
|
||||||
className='self-center'
|
className='self-center'
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
import { useLayoutEffect, useMemo, useState } from 'react';
|
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
@ -8,6 +9,7 @@ import TextInput from '@/components/Common/TextInput';
|
||||||
import { useBlockNavigation } from '@/context/NagivationContext';
|
import { useBlockNavigation } from '@/context/NagivationContext';
|
||||||
import { useUserProfile } from '@/context/UserProfileContext';
|
import { useUserProfile } from '@/context/UserProfileContext';
|
||||||
import { IUserUpdateData } from '@/models/library';
|
import { IUserUpdateData } from '@/models/library';
|
||||||
|
import { classnames } from '@/utils/constants';
|
||||||
|
|
||||||
function EditorProfile() {
|
function EditorProfile() {
|
||||||
const { updateUser, user, processing } = useUserProfile();
|
const { updateUser, user, processing } = useUserProfile();
|
||||||
|
@ -53,11 +55,15 @@ function EditorProfile() {
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className='px-6 py-2 flex flex-col gap-3 min-w-[18rem]'
|
className={clsx(
|
||||||
|
'min-w-[18rem]',
|
||||||
|
'px-6 py-2',
|
||||||
|
classnames.flex_col
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<TextInput id='username' disabled
|
<TextInput id='username' disabled
|
||||||
label='Логин'
|
label='Логин'
|
||||||
tooltip='Логин изменить нельзя'
|
title='Логин изменить нельзя'
|
||||||
value={username}
|
value={username}
|
||||||
/>
|
/>
|
||||||
<TextInput id='first_name' allowEnter
|
<TextInput id='first_name' allowEnter
|
||||||
|
|
|
@ -36,7 +36,7 @@ function UserTabs() {
|
||||||
<div>
|
<div>
|
||||||
<Overlay position='top-0 right-0'>
|
<Overlay position='top-0 right-0'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Показать/Скрыть список отслеживаний'
|
title='Показать/Скрыть список отслеживаний'
|
||||||
icon={showSubs
|
icon={showSubs
|
||||||
? <FiBell size='1.25rem' className='clr-text-primary' />
|
? <FiBell size='1.25rem' className='clr-text-primary' />
|
||||||
: <FiBellOff size='1.25rem' className='clr-text-primary' />
|
: <FiBellOff size='1.25rem' className='clr-text-primary' />
|
||||||
|
|
|
@ -137,7 +137,7 @@ export function domTooltipConstituenta(cst: IConstituenta) {
|
||||||
const dom = document.createElement('div');
|
const dom = document.createElement('div');
|
||||||
dom.className = clsx(
|
dom.className = clsx(
|
||||||
'z-tooltip',
|
'z-tooltip',
|
||||||
'max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit',
|
'max-h-[25rem] max-w-[25rem] min-w-[10rem]',
|
||||||
'p-2',
|
'p-2',
|
||||||
'border shadow-md',
|
'border shadow-md',
|
||||||
'overflow-y-auto',
|
'overflow-y-auto',
|
||||||
|
@ -181,7 +181,7 @@ export function domTooltipEntityReference(ref: IEntityReference, cst: IConstitue
|
||||||
const dom = document.createElement('div');
|
const dom = document.createElement('div');
|
||||||
dom.className = clsx(
|
dom.className = clsx(
|
||||||
'z-tooltip',
|
'z-tooltip',
|
||||||
'max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit',
|
'max-h-[25rem] max-w-[25rem] min-w-[10rem]',
|
||||||
'p-2 flex flex-col',
|
'p-2 flex flex-col',
|
||||||
'border shadow-md',
|
'border shadow-md',
|
||||||
'overflow-y-auto',
|
'overflow-y-auto',
|
||||||
|
@ -229,7 +229,7 @@ export function domTooltipSyntacticReference(ref: ISyntacticReference, masterRef
|
||||||
const dom = document.createElement('div');
|
const dom = document.createElement('div');
|
||||||
dom.className = clsx(
|
dom.className = clsx(
|
||||||
'z-tooltip',
|
'z-tooltip',
|
||||||
'max-h-[25rem] max-w-[25rem] min-w-[10rem] w-fit',
|
'max-h-[25rem] max-w-[25rem] min-w-[10rem]',
|
||||||
'p-2 flex flex-col',
|
'p-2 flex flex-col',
|
||||||
'border shadow-md',
|
'border shadow-md',
|
||||||
'overflow-y-auto',
|
'overflow-y-auto',
|
||||||
|
|
|
@ -55,6 +55,14 @@ export const youtube = {
|
||||||
intro: '0Ty9mu9sOJo'
|
intro: '0Ty9mu9sOJo'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classname combinations.
|
||||||
|
* Note: using clsx in conjunction with tailwindCss is preferred to creating custom CSS
|
||||||
|
*/
|
||||||
|
export const classnames = {
|
||||||
|
flex_col: 'flex flex-col gap-3'
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constant URLs.
|
* Constant URLs.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue
Block a user