Refactor UI elements positioning and minor UI fixes

This commit is contained in:
IRBorisov 2023-09-15 23:29:52 +03:00
parent 1dd007a3e6
commit 88a7181695
36 changed files with 348 additions and 355 deletions

View File

@ -5,7 +5,7 @@ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'child
tooltip?: string tooltip?: string
dense?: boolean dense?: boolean
loading?: boolean loading?: boolean
widthClass?: string dimensions?: string
borderClass?: string borderClass?: string
colorClass?: string colorClass?: string
} }
@ -15,7 +15,7 @@ function Button({
dense, disabled, dense, disabled,
borderClass = 'border rounded', borderClass = 'border rounded',
colorClass = 'clr-btn-default', colorClass = 'clr-btn-default',
widthClass = 'w-fit h-fit', dimensions = 'w-fit h-fit',
loading, onClick, loading, onClick,
...props ...props
}: ButtonProps) { }: ButtonProps) {
@ -27,10 +27,10 @@ function Button({
disabled={disabled ?? loading} disabled={disabled ?? loading}
onClick={onClick} onClick={onClick}
title={tooltip} title={tooltip}
className={`inline-flex items-center gap-2 align-middle justify-center select-none ${padding} ${colorClass} ${widthClass} ${borderClass} ${cursor}`} className={`inline-flex items-center gap-2 align-middle justify-center select-none ${padding} ${colorClass} ${dimensions} ${borderClass} ${cursor}`}
{...props} {...props}
> >
{icon && <span>{icon}</span>} {icon && icon}
{text && <span className={'font-semibold'}>{text}</span>} {text && <span className={'font-semibold'}>{text}</span>}
</button> </button>
); );

View File

@ -1,16 +0,0 @@
interface CardProps {
title?: string
widthClass?: string
children: React.ReactNode
}
function Card({ title, widthClass = 'min-w-fit', children }: CardProps) {
return (
<div className={`border shadow-md py-2 clr-app px-6 ${widthClass}`}>
{ title && <h1 className='mb-2 text-xl font-bold whitespace-nowrap'>{title}</h1> }
{children}
</div>
);
}
export default Card;

View File

@ -9,7 +9,7 @@ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'child
label?: string label?: string
required?: boolean required?: boolean
disabled?: boolean disabled?: boolean
widthClass?: string dimensions?: string
tooltip?: string tooltip?: string
value: boolean value: boolean
@ -18,7 +18,7 @@ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'child
function Checkbox({ function Checkbox({
id, required, disabled, tooltip, label, id, required, disabled, tooltip, label,
widthClass = 'w-fit', value, setValue, ...props dimensions = 'w-fit', value, setValue, ...props
}: CheckboxProps) { }: CheckboxProps) {
const cursor = useMemo( const cursor = useMemo(
() => { () => {
@ -46,7 +46,7 @@ function Checkbox({
return ( return (
<button <button
id={id} id={id}
className={`flex items-center [&:not(:first-child)]:mt-3 clr-outline focus:outline-dotted focus:outline-1 ${widthClass}`} className={`flex items-center clr-outline focus:outline-dotted focus:outline-1 ${dimensions}`}
title={tooltip} title={tooltip}
disabled={disabled} disabled={disabled}
onClick={handleClick} onClick={handleClick}

View File

@ -1,13 +1,13 @@
interface DropdownProps { interface DropdownProps {
children: React.ReactNode children: React.ReactNode
stretchLeft?: boolean stretchLeft?: boolean
widthClass?: string dimensions?: string
} }
function Dropdown({ children, widthClass = 'w-fit', stretchLeft }: DropdownProps) { function Dropdown({ children, dimensions = 'w-fit', stretchLeft }: DropdownProps) {
return ( return (
<div className='relative text-sm'> <div className='relative text-sm'>
<div className={`absolute ${stretchLeft ? 'right-0' : 'left-0'} mt-2 py-1 z-tooltip flex flex-col items-stretch justify-start origin-top-right border divide-y divide-inherit rounded-md shadow-lg clr-input ${widthClass}`}> <div className={`absolute ${stretchLeft ? 'right-0' : 'left-0'} mt-2 py-1 z-tooltip flex flex-col items-stretch justify-start origin-top-right border divide-y divide-inherit rounded-md shadow-lg clr-input ${dimensions}`}>
{children} {children}
</div> </div>
</div> </div>

View File

@ -16,7 +16,7 @@ function DropdownCheckbox({ tooltip, setValue, disabled, ...props }: DropdownChe
className={`px-4 py-1 text-left overflow-ellipsis ${behavior} w-full whitespace-nowrap`} className={`px-4 py-1 text-left overflow-ellipsis ${behavior} w-full whitespace-nowrap`}
> >
<Checkbox <Checkbox
widthClass='w-full' dimensions='w-full'
disabled={disabled} disabled={disabled}
setValue={setValue} setValue={setValue}
{...props} {...props}

View File

@ -9,13 +9,13 @@ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title'
label: string label: string
tooltip?: string tooltip?: string
acceptType?: string acceptType?: string
widthClass?: string dimensions?: string
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
} }
function FileInput({ function FileInput({
label, acceptType, tooltip, label, acceptType, tooltip,
widthClass = 'w-fit', onChange, dimensions = 'w-fit', onChange,
...props ...props
}: FileInputProps) { }: FileInputProps) {
const inputRef = useRef<HTMLInputElement | null>(null); const inputRef = useRef<HTMLInputElement | null>(null);
@ -37,7 +37,7 @@ function FileInput({
}; };
return ( return (
<div className={`flex flex-col gap-2 py-2 mt-3 items-start ${widthClass}`}> <div className={`flex flex-col gap-2 py-2 items-start ${dimensions}`}>
<input type='file' <input type='file'
ref={inputRef} ref={inputRef}
style={{ display: 'none' }} style={{ display: 'none' }}

View File

@ -1,21 +1,19 @@
import Card from './Card';
interface FormProps { interface FormProps {
title: string title: string
widthClass?: string dimensions?: string
onSubmit: (event: React.FormEvent<HTMLFormElement>) => void onSubmit: (event: React.FormEvent<HTMLFormElement>) => void
children: React.ReactNode children: React.ReactNode
} }
function Form({ title, onSubmit, widthClass = 'max-w-xs', children }: FormProps) { function Form({ title, onSubmit, dimensions = 'max-w-xs', children }: FormProps) {
return ( return (
<div className='flex flex-col items-center w-full'> <form
<Card title={title} widthClass={widthClass}> className={`border shadow-md py-2 clr-app px-6 flex flex-col gap-3 ${dimensions}`}
<form onSubmit={onSubmit}> onSubmit={onSubmit}
>
{ title && <h1 className='text-xl font-bold whitespace-nowrap'>{title}</h1> }
{children} {children}
</form> </form>
</Card>
</div>
); );
} }

View File

@ -1,20 +1,23 @@
interface MiniButtonProps interface MiniButtonProps
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'title' > { extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'title' |'children' > {
icon?: React.ReactNode icon: React.ReactNode
tooltip?: string tooltip?: string
noHover?: boolean noHover?: boolean
dimensions?: string
} }
function MiniButton({ icon, tooltip, children, noHover, tabIndex, ...props }: MiniButtonProps) { function MiniButton({
icon, tooltip, noHover, tabIndex, dimensions,
...props
}: MiniButtonProps) {
return ( return (
<button type='button' <button type='button'
title={tooltip} title={tooltip}
tabIndex={tabIndex ?? -1} tabIndex={tabIndex ?? -1}
className={`px-1 py-1 font-bold rounded-full cursor-pointer whitespace-nowrap disabled:cursor-not-allowed clr-btn-clear ${noHover ? 'outline-none' : 'clr-hover'}`} className={`px-1 py-1 w-fit h-fit rounded-full cursor-pointer disabled:cursor-not-allowed clr-btn-clear ${noHover ? 'outline-none' : 'clr-hover'} ${dimensions}`}
{...props} {...props}
> >
{icon && <span>{icon}</span>} {icon}
{children}
</button> </button>
); );
} }

View File

@ -51,7 +51,7 @@ function Modal({
<Button <Button
text={submitText} text={submitText}
tooltip={!canSubmit ? submitInvalidTooltip: ''} tooltip={!canSubmit ? submitInvalidTooltip: ''}
widthClass='min-w-[6rem] min-h-[2.6rem] w-fit h-fit' dimensions='min-w-[6rem] min-h-[2.6rem] w-fit h-fit'
colorClass='clr-btn-primary' colorClass='clr-btn-primary'
disabled={!canSubmit} disabled={!canSubmit}
onClick={handleSubmit} onClick={handleSubmit}
@ -59,7 +59,7 @@ function Modal({
/>} />}
<Button <Button
text={readonly ? 'Закрыть' : 'Отмена'} text={readonly ? 'Закрыть' : 'Отмена'}
widthClass='min-w-[6rem] min-h-[2.6rem] w-fit h-fit' dimensions='min-w-[6rem] min-h-[2.6rem] w-fit h-fit'
onClick={handleCancel} onClick={handleCancel}
/> />
</div> </div>

View File

@ -4,17 +4,17 @@ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'child
tooltip?: string tooltip?: string
loading?: boolean loading?: boolean
icon?: React.ReactNode icon?: React.ReactNode
widthClass?: string dimensions?: string
} }
function SubmitButton({ function SubmitButton({
text = 'ОК', icon, disabled, tooltip, loading, text = 'ОК', icon, disabled, tooltip, loading,
widthClass = 'w-fit h-fit' dimensions = 'w-fit h-fit'
}: SubmitButtonProps) { }: SubmitButtonProps) {
return ( return (
<button type='submit' <button type='submit'
title={tooltip} title={tooltip}
className={`px-4 py-2 inline-flex items-center gap-2 align-middle justify-center font-semibold select-none disabled:cursor-not-allowed border rounded clr-btn-primary ${widthClass} ${loading ? ' cursor-progress' : ''}`} className={`px-4 py-2 inline-flex items-center gap-2 align-middle justify-center font-semibold select-none disabled:cursor-not-allowed border rounded clr-btn-primary ${dimensions} ${loading ? ' cursor-progress' : ''}`}
disabled={disabled ?? loading} disabled={disabled ?? loading}
> >
{icon && <span>{icon}</span>} {icon && <span>{icon}</span>}

View File

@ -6,27 +6,27 @@ export interface TextAreaProps
extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'className' | 'title'> { extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'className' | 'title'> {
label: string label: string
tooltip?: string tooltip?: string
widthClass?: string dimensions?: string
colorClass?: string colorClass?: string
} }
function TextArea({ function TextArea({
id, label, required, tooltip, id, label, required, tooltip,
widthClass = 'w-full', dimensions = 'w-full',
colorClass = 'clr-input', colorClass = 'clr-input',
rows = 4, rows = 4,
...props ...props
}: TextAreaProps) { }: TextAreaProps) {
return ( return (
<div className='flex flex-col items-start [&:not(:first-child)]:mt-3'> <div className='flex flex-col items-start gap-2'>
<Label {label && <Label
text={label} text={label}
required={!props.disabled && required} required={!props.disabled && required}
htmlFor={id} htmlFor={id}
/> />}
<textarea id={id} <textarea id={id}
title={tooltip} title={tooltip}
className={`px-3 py-2 mt-2 leading-tight border shadow clr-outline ${colorClass} ${widthClass}`} className={`px-3 py-2 leading-tight border shadow clr-outline ${colorClass} ${dimensions}`}
rows={rows} rows={rows}
required={required} required={required}
{...props} {...props}

View File

@ -5,19 +5,19 @@ extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title'>
id?: string id?: string
label?: string label?: string
tooltip?: string tooltip?: string
widthClass?: string dimensions?: string
colorClass?: string colorClass?: string
singleRow?: boolean singleRow?: boolean
} }
function TextInput({ function TextInput({
id, required, label, singleRow, tooltip, id, required, label, singleRow, tooltip,
widthClass = 'w-full', dimensions = 'w-full',
colorClass = 'clr-input', colorClass = 'clr-input',
...props ...props
}: TextInputProps) { }: TextInputProps) {
return ( return (
<div className={`flex [&:not(:first-child)]:mt-3 ${singleRow ? 'items-center gap-4 ' + widthClass : 'flex-col items-start'}`}> <div className={`flex ${singleRow ? 'items-center gap-4 ' + dimensions : 'flex-col items-start gap-2'}`}>
{label && <Label {label && <Label
text={label} text={label}
required={!props.disabled && required} required={!props.disabled && required}
@ -25,7 +25,7 @@ function TextInput({
/>} />}
<input id={id} <input id={id}
title={tooltip} title={tooltip}
className={`px-3 py-2 leading-tight border shadow truncate hover:text-clip clr-outline ${colorClass} ${singleRow ? '' : 'mt-2 ' + widthClass}`} className={`px-3 py-2 leading-tight border shadow truncate hover:text-clip clr-outline ${colorClass} ${singleRow ? '' : dimensions}`}
required={required} required={required}
{...props} {...props}
/> />

View File

@ -13,7 +13,7 @@ extends Omit<CheckboxProps, 'value' | 'setValue'> {
function Tristate({ function Tristate({
id, required, disabled, tooltip, label, id, required, disabled, tooltip, label,
widthClass = 'w-fit', value, setValue, ...props dimensions = 'w-fit', value, setValue, ...props
}: TristateProps) { }: TristateProps) {
const cursor = useMemo( const cursor = useMemo(
() => { () => {
@ -47,7 +47,7 @@ function Tristate({
return ( return (
<button <button
id={id} id={id}
className={`flex items-center [&:not(:first-child)]:mt-3 clr-outline focus:outline-dotted focus:outline-1 ${widthClass}`} className={`flex items-center clr-outline focus:outline-dotted focus:outline-1 ${dimensions}`}
title={tooltip} title={tooltip}
disabled={disabled} disabled={disabled}
onClick={handleClick} onClick={handleClick}

View File

@ -5,7 +5,7 @@ function HelpConstituenta() {
return ( return (
<div className=''> <div className=''>
<h1>Подсказки</h1> <h1>Подсказки</h1>
<p><b className='text-warning'>Изменения сохраняются ПОСЛЕ нажатия на кнопку снизу или слева вверху</b></p> <p><b className='text-warning'>Изменения сохраняются ПОСЛЕ нажатия на кнопку снизу или справа вверху</b></p>
<p><b>Клик на формальное выражение</b> - обратите внимание на кнопки снизу.<br/>Для каждой есть горячая клавиша в подсказке</p> <p><b>Клик на формальное выражение</b> - обратите внимание на кнопки снизу.<br/>Для каждой есть горячая клавиша в подсказке</p>
<p><b>Список конституент справа</b> - обратите внимание на настройки фильтрации</p> <p><b>Список конституент справа</b> - обратите внимание на настройки фильтрации</p>
<p>- слева от ввода текста настраивается набор атрибутов конституенты</p> <p>- слева от ввода текста настраивается набор атрибутов конституенты</p>

View File

@ -31,7 +31,7 @@ function UserDropdown({ hideDropdown }: UserDropdownProps) {
}; };
return ( return (
<Dropdown widthClass='w-36' stretchLeft> <Dropdown dimensions='w-36' stretchLeft>
<DropdownButton <DropdownButton
tooltip='Профиль пользователя' tooltip='Профиль пользователя'
onClick={navigateProfile} onClick={navigateProfile}

View File

@ -78,9 +78,10 @@ function CreateRSFormPage() {
return ( return (
<RequireAuth> <RequireAuth>
<div className='flex justify-center w-full'>
<Form title='Создание концептуальной схемы' <Form title='Создание концептуальной схемы'
onSubmit={handleSubmit} onSubmit={handleSubmit}
widthClass='max-w-lg w-full mt-4' dimensions='max-w-lg w-full mt-4'
> >
<div className='relative w-full'> <div className='relative w-full'>
<div className='absolute top-[-2.4rem] right-[-1rem] flex'> <div className='absolute top-[-2.4rem] right-[-1rem] flex'>
@ -98,6 +99,7 @@ function CreateRSFormPage() {
/> />
</div> </div>
</div> </div>
<div className='flex flex-col gap-3'>
{ fileName && <Label text={`Загружен файл: ${fileName}`} />} { fileName && <Label text={`Загружен файл: ${fileName}`} />}
<TextInput id='title' label='Полное название' type='text' <TextInput id='title' label='Полное название' type='text'
required={!file} required={!file}
@ -121,22 +123,23 @@ function CreateRSFormPage() {
value={common} value={common}
setValue={value => setCommon(value ?? false)} setValue={value => setCommon(value ?? false)}
/> />
<div className='flex items-center justify-center gap-4 py-2 mt-4'> <div className='flex items-center justify-center gap-4 py-2'>
<SubmitButton <SubmitButton
text='Создать схему' text='Создать схему'
loading={processing} loading={processing}
widthClass='min-w-[10rem]' dimensions='min-w-[10rem]'
/> />
<Button <Button
text='Отмена' text='Отмена'
onClick={() => handleCancel()} onClick={() => handleCancel()}
widthClass='min-w-[10rem]' dimensions='min-w-[10rem]'
/> />
</div> </div>
{ error && <BackendError error={error} />} { error && <BackendError error={error} />}
</div>
</Form> </Form>
</RequireAuth> </div>
); </RequireAuth>);
} }
export default CreateRSFormPage; export default CreateRSFormPage;

View File

@ -30,7 +30,7 @@ function PickerStrategy({ value, onChange }: PickerStrategyProps) {
dense dense
tooltip='Фильтры' tooltip='Фильтры'
colorClass='clr-input clr-hover text-btn' colorClass='clr-input clr-hover text-btn'
widthClass='h-full py-1 px-2 border-none' dimensions='h-full py-1 px-2 border-none'
onClick={pickerMenu.toggle} onClick={pickerMenu.toggle}
/> />
{ pickerMenu.isActive && { pickerMenu.isActive &&

View File

@ -15,7 +15,7 @@ import { IUserLoginData } from '../models/library';
function ProcessError({error}: {error: ErrorInfo}): React.ReactElement { function ProcessError({error}: {error: ErrorInfo}): React.ReactElement {
if (axios.isAxiosError(error) && error.response && error.response.status === 400) { if (axios.isAxiosError(error) && error.response && error.response.status === 400) {
return ( return (
<div className='mt-2 text-sm select-text text-warning'> <div className='text-sm select-text text-warning'>
На Портале отсутствует такое сочетание имени пользователя и пароля На Портале отсутствует такое сочетание имени пользователя и пароля
</div> </div>
); );
@ -80,7 +80,7 @@ function LoginPage() {
<Form <Form
title='Вход в Портал' title='Вход в Портал'
onSubmit={handleSubmit} onSubmit={handleSubmit}
widthClass='w-[24rem]' dimensions='w-[24rem]'
> >
<TextInput id='username' <TextInput id='username'
label='Имя пользователя' label='Имя пользователя'
@ -98,14 +98,14 @@ function LoginPage() {
onChange={event => setPassword(event.target.value)} onChange={event => setPassword(event.target.value)}
/> />
<div className='flex justify-center w-full gap-2 py-2 mt-4'> <div className='flex justify-center w-full gap-2 py-2'>
<SubmitButton <SubmitButton
text='Вход' text='Вход'
widthClass='w-[12rem]' dimensions='w-[12rem]'
loading={loading} loading={loading}
/> />
</div> </div>
<div className='flex flex-col mt-2 text-sm'> <div className='flex flex-col text-sm'>
<TextURL text='Восстановить пароль...' href='/restore-password' /> <TextURL text='Восстановить пароль...' href='/restore-password' />
<TextURL text='Нет аккаунта? Зарегистрируйтесь...' href='/signup' /> <TextURL text='Нет аккаунта? Зарегистрируйтесь...' href='/signup' />
</div> </div>

View File

@ -61,6 +61,7 @@ function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
submitText='Создать' submitText='Создать'
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<div className='flex flex-col gap-3'>
<TextInput id='title' label='Полное название' type='text' <TextInput id='title' label='Полное название' type='text'
required required
value={title} value={title}
@ -69,7 +70,7 @@ function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
<TextInput id='alias' label='Сокращение' type='text' <TextInput id='alias' label='Сокращение' type='text'
required required
value={alias} value={alias}
widthClass='max-w-sm' dimensions='max-w-sm'
onChange={event => setAlias(event.target.value)} onChange={event => setAlias(event.target.value)}
/> />
<TextArea id='comment' label='Комментарий' <TextArea id='comment' label='Комментарий'
@ -80,6 +81,7 @@ function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
value={common} value={common}
setValue={value => setCommon(value)} setValue={value => setCommon(value)}
/> />
</div>
</Modal> </Modal>
); );
} }

View File

@ -56,7 +56,7 @@ function DlgCreateCst({ hideWindow, initial, onCreate }: DlgCreateCstProps) {
canSubmit={validated} canSubmit={validated}
onSubmit={handleSubmit} onSubmit={handleSubmit}
> >
<div className='h-fit w-[35rem] px-2 mb-2 flex flex-col justify-stretch'> <div className='h-fit w-[35rem] px-2 mb-2 flex flex-col justify-stretch gap-3'>
<div className='flex justify-center w-full'> <div className='flex justify-center w-full'>
<SelectSingle <SelectSingle
className='my-2 min-w-[15rem] self-center' className='my-2 min-w-[15rem] self-center'
@ -73,14 +73,12 @@ function DlgCreateCst({ hideWindow, initial, onCreate }: DlgCreateCstProps) {
spellCheck spellCheck
onChange={event => setTerm(event.target.value)} onChange={event => setTerm(event.target.value)}
/> />
<div className='mt-3'>
<RSInput id='expression' label='Формальное выражение' <RSInput id='expression' label='Формальное выражение'
editable editable
height='5.5rem' height='5.5rem'
value={expression} value={expression}
onChange={value => setExpression(value)} onChange={value => setExpression(value)}
/> />
</div>
<TextArea id='definition' label='Текстовое определение' <TextArea id='definition' label='Текстовое определение'
placeholder='Лингвистическая интерпретация формального выражения' placeholder='Лингвистическая интерпретация формального выражения'
rows={2} rows={2}

View File

@ -36,14 +36,14 @@ function DlgDeleteCst({ hideWindow, selected, onDelete }: DlgDeleteCstProps) {
> >
<div className='max-w-[60vw] min-w-[20rem]'> <div className='max-w-[60vw] min-w-[20rem]'>
<p>Выбраны к удалению: <b>{selected.length}</b></p> <p>Выбраны к удалению: <b>{selected.length}</b></p>
<div className='px-3 border h-[9rem] overflow-y-auto whitespace-nowrap'> <div className='px-3 border h-[9rem] mt-1 overflow-y-auto whitespace-nowrap'>
{selected.map(id => { {selected.map(id => {
const cst = schema!.items.find(cst => cst.id === id); const cst = schema!.items.find(cst => cst.id === id);
return (cst && <p>{getCstLabel(cst)}</p>); return (cst && <p>{getCstLabel(cst)}</p>);
})} })}
</div> </div>
<p className='mt-4'>Зависимые конституенты: <b>{expansion.length}</b></p> <p className='mt-4'>Зависимые конституенты: <b>{expansion.length}</b></p>
<div className='px-3 border h-[9rem] overflow-y-auto whitespace-nowrap'> <div className='mt-1 mb-3 px-3 border h-[9rem] overflow-y-auto whitespace-nowrap'>
{expansion.map(id => { {expansion.map(id => {
const cst = schema!.items.find(cst => cst.id === id); const cst = schema!.items.find(cst => cst.id === id);
return (cst && <p>{getCstLabel(cst)}</p>); return (cst && <p>{getCstLabel(cst)}</p>);

View File

@ -75,7 +75,7 @@ function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps
submitText='Применить' submitText='Применить'
> >
<div className='flex gap-2'> <div className='flex gap-2'>
<div className='flex flex-col'> <div className='flex flex-col gap-1'>
<h1>Преобразования</h1> <h1>Преобразования</h1>
<Checkbox <Checkbox
label='Скрыть текст' label='Скрыть текст'
@ -102,7 +102,7 @@ function DlgGraphOptions({ hideWindow, initial, onConfirm }:DlgGraphOptionsProps
setValue={ value => setNoTransitive(value) } setValue={ value => setNoTransitive(value) }
/> />
</div> </div>
<div className='flex flex-col'> <div className='flex flex-col gap-1'>
<h1>Типы конституент</h1> <h1>Типы конституент</h1>
<Checkbox <Checkbox
label={getCstTypeLabel(CstType.BASE)} label={getCstTypeLabel(CstType.BASE)}

View File

@ -5,8 +5,8 @@ import SelectSingle from '../../components/Common/SelectSingle';
import TextInput from '../../components/Common/TextInput'; import TextInput from '../../components/Common/TextInput';
import { useRSForm } from '../../context/RSFormContext'; import { useRSForm } from '../../context/RSFormContext';
import { CstType, ICstRenameData } from '../../models/rsform'; import { CstType, ICstRenameData } from '../../models/rsform';
import { createAliasFor, getCstTypeLabel, getCstTypePrefix } from '../../utils/staticUI';
import { SelectorCstType } from '../../utils/selectors'; import { SelectorCstType } from '../../utils/selectors';
import { createAliasFor, getCstTypeLabel, getCstTypePrefix } from '../../utils/staticUI';
interface DlgRenameCstProps interface DlgRenameCstProps
extends Pick<ModalProps, 'hideWindow'> { extends Pick<ModalProps, 'hideWindow'> {
@ -78,7 +78,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
<div> <div>
<TextInput id='alias' label='Имя' <TextInput id='alias' label='Имя'
singleRow singleRow
widthClass='w-[7rem]' dimensions='w-[7rem]'
value={alias} value={alias}
onChange={event => setAlias(event.target.value)} onChange={event => setAlias(event.target.value)}
/> />

View File

@ -45,7 +45,7 @@ function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) {
onSubmit={handleSubmit} onSubmit={handleSubmit}
submitText='Загрузить' submitText='Загрузить'
> >
<div className='flex flex-col items-center'> <div className='flex flex-col items-start min-w-[20rem] max-w-[20rem]'>
<FileInput <FileInput
label='Выбрать файл' label='Выбрать файл'
acceptType={EXTEOR_TRS_FILE} acceptType={EXTEOR_TRS_FILE}
@ -55,7 +55,7 @@ function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) {
label='Загружать название и комментарий' label='Загружать название и комментарий'
value={loadMetadata} value={loadMetadata}
setValue={value => setLoadMetadata(value)} setValue={value => setLoadMetadata(value)}
widthClass='w-fit pb-2' dimensions='w-fit pb-2'
/> />
</div> </div>
</Modal> </Modal>

View File

@ -136,41 +136,19 @@ function EditorConstituenta({
} }
return ( return (
<div className='flex items-stretch w-full gap-2 mb-2 justify-stretch'> <div className='flex w-full gap-2 mb-2 justify-stretch'>
<form onSubmit={handleSubmit} className='min-w-[50rem] max-w-min px-4 py-2 border-y border-r'> <form onSubmit={handleSubmit} className='min-w-[50rem] max-w-min px-4 py-2 border-y border-r'>
<div className='relative'> <div className='relative w-full'>
<div className='absolute top-0 left-0'> <div className='absolute top-0 right-0 flex items-start justify-between w-full'>
<MiniButton <MiniButton
tooltip='Сохранить изменения' tooltip='Редактировать словоформы термина'
disabled={!isModified || !isEnabled}
icon={<SaveIcon size={6} color={isModified && isEnabled ? 'text-primary' : ''}/>}
onClick={() => handleSubmit()}
/>
</div>
</div>
<div className='relative'>
<div className='absolute top-0 right-0 flex justify-end'>
<MiniButton
tooltip='Удалить редактируемую конституенту'
disabled={!isEnabled} disabled={!isEnabled}
onClick={handleDelete} dimensions='w-fit pl-[3.2rem] pt-[0.4rem]'
icon={<DumpBinIcon size={5} color={isEnabled ? 'text-warning' : ''} />} noHover
onClick={onEditTerm}
icon={<PenIcon size={4} color={isEnabled ? 'text-primary' : ''} />}
/> />
<MiniButton <div className='flex items-center justify-center w-full gap-1'>
tooltip='Создать конституенты после данной'
disabled={!isEnabled}
onClick={handleCreateCst}
icon={<SmallPlusIcon size={5} color={isEnabled ? 'text-success' : ''} />}
/>
<div id='cst-help' className='flex items-center ml-[6px]'>
<HelpIcon color='text-primary' size={5} />
</div>
<ConceptTooltip anchorSelect='#cst-help'>
<HelpConstituenta />
</ConceptTooltip>
</div>
</div>
<div className='flex items-center justify-center w-full gap-1 pr-10'>
<div className='font-semibold w-fit'> <div className='font-semibold w-fit'>
<span className=''>Конституента </span> <span className=''>Конституента </span>
<span className='ml-4'>{alias}</span> <span className='ml-4'>{alias}</span>
@ -183,17 +161,35 @@ function EditorConstituenta({
icon={<PenIcon size={4} color={isEnabled ? 'text-primary' : ''} />} icon={<PenIcon size={4} color={isEnabled ? 'text-primary' : ''} />}
/> />
</div> </div>
<div className='relative'> <div className='flex justify-end min-w-fit'>
<div className='absolute left-[3.2rem] top-[0.5rem]'>
<MiniButton <MiniButton
tooltip='Редактировать словоформы термина' tooltip='Сохранить изменения'
disabled={!isEnabled} disabled={!isModified || !isEnabled}
noHover icon={<SaveIcon size={5} color={isModified && isEnabled ? 'text-primary' : ''}/>}
onClick={onEditTerm} onClick={() => handleSubmit()}
icon={<PenIcon size={4} color={isEnabled ? 'text-primary' : ''} />}
/> />
<MiniButton
tooltip='Создать конституенты после данной'
disabled={!isEnabled}
onClick={handleCreateCst}
icon={<SmallPlusIcon size={5} color={isEnabled ? 'text-success' : ''} />}
/>
<MiniButton
tooltip='Удалить редактируемую конституенту'
disabled={!isEnabled}
onClick={handleDelete}
icon={<DumpBinIcon size={5} color={isEnabled ? 'text-warning' : ''} />}
/>
<div id='cst-help' className='px-1 py-1'>
<HelpIcon color='text-primary' size={5} />
</div>
<ConceptTooltip anchorSelect='#cst-help' offset={4}>
<HelpConstituenta />
</ConceptTooltip>
</div> </div>
</div> </div>
</div>
<div className='flex flex-col gap-2 mt-1'>
<ReferenceInput id='term' label='Термин' <ReferenceInput id='term' label='Термин'
placeholder='Обозначение, используемое в текстовых определениях данной схемы' placeholder='Обозначение, используемое в текстовых определениях данной схемы'
rows={2} rows={2}
@ -242,16 +238,17 @@ function EditorConstituenta({
onChange={event => setConvention(event.target.value)} onChange={event => setConvention(event.target.value)}
onFocus={() => setEditMode(EditMode.TEXT)} onFocus={() => setEditMode(EditMode.TEXT)}
/> />
<div className='flex justify-center w-full mt-4 mb-2'> <div className='flex justify-center w-full mt-2'>
<SubmitButton <SubmitButton
text='Сохранить изменения' text='Сохранить изменения'
disabled={!isModified || !isEnabled} disabled={!isModified || !isEnabled}
icon={<SaveIcon size={6} />} icon={<SaveIcon size={6} />}
/> />
</div> </div>
</div>
</form> </form>
{(windowSize.width ?? 0) >= SIDELIST_HIDE_THRESHOLD && {(windowSize.width ?? 0) >= SIDELIST_HIDE_THRESHOLD &&
<div className='self-stretch w-full pb-1 border'> <div className='self-stretch w-full border'>
<ViewSideConstituents <ViewSideConstituents
expression={expression} expression={expression}
baseHeight={UNFOLDED_HEIGHT} baseHeight={UNFOLDED_HEIGHT}
@ -259,8 +256,7 @@ function EditorConstituenta({
onOpenEdit={onOpenEdit} onOpenEdit={onOpenEdit}
/> />
</div>} </div>}
</div> </div>);
);
} }
export default EditorConstituenta; export default EditorConstituenta;

View File

@ -224,7 +224,7 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
return (<> return (<>
<div <div
id={`${prefixes.cst_list}${cst.alias}`} id={`${prefixes.cst_list}${cst.alias}`}
className='w-full min-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap' className='w-full min-w-[3.1rem] max-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap'
style={{ style={{
borderWidth: "1px", borderWidth: "1px",
borderColor: getCstStatusFgColor(cst.status, colors), borderColor: getCstStatusFgColor(cst.status, colors),
@ -251,7 +251,7 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
minSize: 150, minSize: 150,
maxSize: 150, maxSize: 150,
enableHiding: true, enableHiding: true,
cell: props => <div className='text-sm min-w-[8.4rem]'>{props.getValue()}</div> cell: props => <div className='text-sm min-w-[9.3rem] max-w-[9.3rem] break-words'>{props.getValue()}</div>
}), }),
columnHelper.accessor(cst => cst.term_resolved || cst.term_raw || '', { columnHelper.accessor(cst => cst.term_resolved || cst.term_raw || '', {
id: 'term', id: 'term',
@ -265,7 +265,8 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
header: 'Формальное определение', header: 'Формальное определение',
size: 1000, size: 1000,
minSize: 300, minSize: 300,
maxSize: 1000 maxSize: 1000,
cell: props => <div className='break-words'>{props.getValue()}</div>
}), }),
columnHelper.accessor(cst => cst.definition_resolved || cst.definition_raw || '', { columnHelper.accessor(cst => cst.definition_resolved || cst.definition_raw || '', {
id: 'definition', id: 'definition',
@ -283,19 +284,14 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
maxSize: 500, maxSize: 500,
enableHiding: true, enableHiding: true,
cell: props => <div className='text-xs'>{props.getValue()}</div> cell: props => <div className='text-xs'>{props.getValue()}</div>
}), })
], [colors]); ], [colors]);
return ( return (
<div className='w-full'> <div className='w-full'>
<div <div className='sticky top-0 flex justify-start w-full gap-1 px-2 py-1 border-b items-center h-[2.2rem] select-none clr-app'>
className='sticky top-0 flex justify-start w-full gap-1 px-2 py-1 border-y items-center h-[2.2rem] select-none clr-app' <div className='mr-3 min-w-[9rem] whitespace-nowrap'>
> Выбор {selected.length} из {schema?.stats?.count_all ?? 0}
<div className='mr-3 whitespace-nowrap'>
Выбраны
<span className='ml-2'>
{selected.length} из {schema?.stats?.count_all ?? 0}
</span>
</div> </div>
<div className='flex items-center justify-start w-full gap-1'> <div className='flex items-center justify-start w-full gap-1'>
<Button <Button
@ -342,7 +338,7 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
text={getCstTypePrefix(type)} text={getCstTypePrefix(type)}
tooltip={getCstTypeShortcut(type)} tooltip={getCstTypeShortcut(type)}
dense dense
widthClass='w-[1.4rem]' dimensions='w-[1.4rem]'
disabled={!isEditable} disabled={!isEditable}
tabIndex={-1} tabIndex={-1}
onClick={() => handleCreateCst(type)} onClick={() => handleCreateCst(type)}
@ -378,7 +374,8 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
<p>Список пуст</p> <p>Список пуст</p>
<p <p
className='cursor-pointer text-primary hover:underline' className='cursor-pointer text-primary hover:underline'
onClick={() => handleCreateCst()}> onClick={() => handleCreateCst()}
>
Создать новую конституенту Создать новую конституенту
</p> </p>
</span> </span>

View File

@ -107,7 +107,8 @@ function EditorRSExpression({
}, []); }, []);
const EditButtons = useMemo(() => { const EditButtons = useMemo(() => {
return (<div className='flex items-center justify-between w-full'> return (
<div className='flex items-center justify-between w-full'>
<div className='text-sm w-fit'> <div className='text-sm w-fit'>
<div className='flex justify-start'> <div className='flex justify-start'>
<RSTokenButton id={TokenID.NT_DECLARATIVE_EXPR} onInsert={handleEdit}/> <RSTokenButton id={TokenID.NT_DECLARATIVE_EXPR} onInsert={handleEdit}/>
@ -185,7 +186,7 @@ function EditorRSExpression({
}, [handleEdit]); }, [handleEdit]);
return ( return (
<div className='flex flex-col items-start [&:not(:first-child)]:mt-3 w-full min-h-[15.75rem]'> <div className='flex flex-col items-start w-full min-h-[15.75rem]'>
<div className='relative w-full'> <div className='relative w-full'>
<div className='absolute top-[-0.3rem] right-0'> <div className='absolute top-[-0.3rem] right-0'>
<StatusBar <StatusBar
@ -204,12 +205,12 @@ function EditorRSExpression({
onFocus={handleFocusIn} onFocus={handleFocusIn}
{...props} {...props}
/> />
<div className='flex w-full gap-4 py-1 mt-1 justify-stretch'> <div className='flex items-stretch w-full gap-4 py-1 mt-1 justify-stretch'>
<div className='flex flex-col gap-2'> <div>
<Button <Button
tooltip='Проверить формальное выражение' tooltip='Проверить формальное выражение'
text='Проверить' text='Проверить'
widthClass='h-full w-fit' dimensions='h-full w-fit'
colorClass='clr-btn-default' colorClass='clr-btn-default'
onClick={handleCheckExpression} onClick={handleCheckExpression}
/> />
@ -217,7 +218,7 @@ function EditorRSExpression({
{isActive && !disabled && EditButtons} {isActive && !disabled && EditButtons}
</div> </div>
{ (isActive || loading || parseData) && { (isActive || loading || parseData) &&
<div className='w-full overflow-y-auto border mt-2 max-h-[14rem] min-h-[4.2rem]'> <div className='w-full overflow-y-auto border mt-1 max-h-[14rem] min-h-[4.2rem]'>
{ loading && <ConceptLoader size={6} />} { loading && <ConceptLoader size={6} />}
{ !loading && parseData && { !loading && parseData &&
<ParsingResult <ParsingResult
@ -232,8 +233,7 @@ function EditorRSExpression({
placeholder='Результаты проверки выражения' placeholder='Результаты проверки выражения'
/>} />}
</div>} </div>}
</div> </div>);
);
} }
export default EditorRSExpression; export default EditorRSExpression;

View File

@ -13,8 +13,8 @@ import { CrownIcon, DownloadIcon, DumpBinIcon, HelpIcon, SaveIcon, ShareIcon } f
import { useAuth } from '../../context/AuthContext'; import { useAuth } from '../../context/AuthContext';
import { useRSForm } from '../../context/RSFormContext'; import { useRSForm } from '../../context/RSFormContext';
import { useUsers } from '../../context/UsersContext'; import { useUsers } from '../../context/UsersContext';
import { IRSFormCreateData } from '../../models/rsform';
import { LibraryItemType } from '../../models/library'; import { LibraryItemType } from '../../models/library';
import { IRSFormCreateData } from '../../models/rsform';
interface EditorRSFormProps { interface EditorRSFormProps {
onDestroy: () => void onDestroy: () => void
@ -114,6 +114,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified,
</ConceptTooltip> </ConceptTooltip>
</div> </div>
</div> </div>
<div className='flex flex-col gap-3 mt-2'>
<TextInput id='title' label='Полное название' type='text' <TextInput id='title' label='Полное название' type='text'
required required
value={title} value={title}
@ -124,7 +125,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified,
required required
value={alias} value={alias}
disabled={!isEditable} disabled={!isEditable}
widthClass='max-w-sm' dimensions='max-w-sm'
onChange={event => setAlias(event.target.value)} onChange={event => setAlias(event.target.value)}
/> />
<TextArea id='comment' label='Комментарий' <TextArea id='comment' label='Комментарий'
@ -135,12 +136,12 @@ function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified,
<div className='flex justify-between whitespace-nowrap'> <div className='flex justify-between whitespace-nowrap'>
<Checkbox id='common' label='Общедоступная схема' <Checkbox id='common' label='Общедоступная схема'
value={common} value={common}
widthClass='w-fit mt-3' dimensions='w-fit'
disabled={!isEditable} disabled={!isEditable}
setValue={value => setCommon(value)} setValue={value => setCommon(value)}
/> />
<Checkbox id='canonical' label='Неизменная схема' <Checkbox id='canonical' label='Неизменная схема'
widthClass='w-fit' dimensions='w-fit'
value={canonical} value={canonical}
tooltip='Только администраторы могут присваивать схемам неизменный статус' tooltip='Только администраторы могут присваивать схемам неизменный статус'
disabled={!isEditable || !isForceAdmin} disabled={!isEditable || !isForceAdmin}
@ -148,35 +149,37 @@ function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified,
/> />
</div> </div>
<div className='flex items-center justify-between gap-1 py-2 mt-2'>
<SubmitButton <SubmitButton
text='Сохранить изменения' text='Сохранить изменения'
loading={processing} loading={processing}
disabled={!isModified || !isEditable} disabled={!isModified || !isEditable}
icon={<SaveIcon size={6} />} icon={<SaveIcon size={6} />}
dimensions='my-2 w-fit'
/> />
</div>
<div className='flex justify-start mt-2'> <div className='flex flex-col gap-1'>
<div className='flex justify-start'>
<label className='font-semibold'>Владелец:</label> <label className='font-semibold'>Владелец:</label>
<span className='min-w-[200px] ml-2 overflow-ellipsis overflow-hidden whitespace-nowrap'> <span className='min-w-[200px] ml-2 overflow-ellipsis overflow-hidden whitespace-nowrap'>
{getUserLabel(schema?.owner ?? null)} {getUserLabel(schema?.owner ?? null)}
</span> </span>
</div> </div>
<div className='flex justify-start mt-2'> <div className='flex justify-start'>
<label className='font-semibold'>Отслеживают:</label> <label className='font-semibold'>Отслеживают:</label>
<span id='subscriber-count' className='ml-2'> <span id='subscriber-count' className='ml-2'>
{ schema?.subscribers.length ?? 0 } { schema?.subscribers.length ?? 0 }
</span> </span>
</div> </div>
<div className='flex justify-start mt-2'> <div className='flex justify-start'>
<label className='font-semibold'>Дата обновления:</label> <label className='font-semibold'>Дата обновления:</label>
<span className='ml-2'>{schema && new Date(schema?.time_update).toLocaleString(intl.locale)}</span> <span className='ml-2'>{schema && new Date(schema?.time_update).toLocaleString(intl.locale)}</span>
</div> </div>
<div className='flex justify-start mt-2'> <div className='flex justify-start'>
<label className='font-semibold'>Дата создания:</label> <label className='font-semibold'>Дата создания:</label>
<span className='ml-8'>{schema && new Date(schema?.time_create).toLocaleString(intl.locale)}</span> <span className='ml-8'>{schema && new Date(schema?.time_create).toLocaleString(intl.locale)}</span>
</div> </div>
</div>
</div>
</form> </form>
); );
} }

View File

@ -376,25 +376,22 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
</div>} </div>}
<div className='flex items-center justify-between py-1'> <div className='flex items-center justify-between py-1'>
<div className='mr-3 whitespace-nowrap text-base'> <div className='mr-3 text-base'>
Выбраны Выбор {allSelected.length} из {schema?.stats?.count_all ?? 0}
<span className='ml-1'>
{allSelected.length} из {schema?.stats?.count_all ?? 0}
</span>
</div> </div>
<div> <div className='min-w-fit'>
<MiniButton
tooltip='Удалить выбранные'
icon={<DumpBinIcon color={!nothingSelected ? 'text-warning' : ''} size={5}/>}
disabled={!isEditable || nothingSelected}
onClick={handleDeleteCst}
/>
<MiniButton <MiniButton
tooltip='Новая конституента' tooltip='Новая конституента'
icon={<SmallPlusIcon color='text-success' size={5}/>} icon={<SmallPlusIcon color={isEditable ? 'text-success': ''} size={5}/>}
disabled={!isEditable} disabled={!isEditable}
onClick={handleCreateCst} onClick={handleCreateCst}
/> />
<MiniButton
tooltip='Удалить выбранные'
icon={<DumpBinIcon color={isEditable && !nothingSelected ? 'text-warning' : ''} size={5}/>}
disabled={!isEditable || nothingSelected}
onClick={handleDeleteCst}
/>
</div> </div>
</div> </div>
<div className='flex items-center w-full gap-1'> <div className='flex items-center w-full gap-1'>
@ -402,7 +399,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
icon={<FilterCogIcon size={7} />} icon={<FilterCogIcon size={7} />}
dense dense
tooltip='Настройки фильтрации узлов и связей' tooltip='Настройки фильтрации узлов и связей'
widthClass='h-full' dimensions='h-full'
onClick={() => setShowOptions(true)} onClick={() => setShowOptions(true)}
/> />
<SelectSingle <SelectSingle
@ -423,6 +420,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
value={layout ? { value: layout, label: mapLayoutLabels.get(layout) } : null} value={layout ? { value: layout, label: mapLayoutLabels.get(layout) } : null}
onChange={data => handleChangeLayout(data?.value ?? SelectorGraphLayout[0].value)} onChange={data => handleChangeLayout(data?.value ?? SelectorGraphLayout[0].value)}
/> />
<div className='flex flex-col gap-1 mt-2'>
<Checkbox <Checkbox
label='Скрыть текст' label='Скрыть текст'
value={noTerms} value={noTerms}
@ -439,6 +437,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
value={orbit} value={orbit}
setValue={ value => setOrbit(value) } setValue={ value => setOrbit(value) }
/> />
</div>
<Divider margins='mt-3 mb-2' /> <Divider margins='mt-3 mb-2' />

View File

@ -73,7 +73,7 @@ function RSTabsMenu({
tooltip='Действия' tooltip='Действия'
icon={<MenuIcon color='text-controls' size={5}/>} icon={<MenuIcon color='text-controls' size={5}/>}
borderClass='' borderClass=''
widthClass='h-full w-fit' dimensions='h-full w-fit'
style={{outlineColor: 'transparent'}} style={{outlineColor: 'transparent'}}
dense dense
onClick={schemaMenu.toggle} onClick={schemaMenu.toggle}
@ -123,7 +123,7 @@ function RSTabsMenu({
<Button <Button
tooltip={'измнение: ' + (isEditable ? '[доступно]' : '[запрещено]')} tooltip={'измнение: ' + (isEditable ? '[доступно]' : '[запрещено]')}
borderClass='' borderClass=''
widthClass='h-full w-fit' dimensions='h-full w-fit'
style={{outlineColor: 'transparent'}} style={{outlineColor: 'transparent'}}
icon={<PenIcon size={5} color={isEditable ? 'text-success' : 'text-warning'}/>} icon={<PenIcon size={5} color={isEditable ? 'text-success' : 'text-warning'}/>}
dense dense
@ -169,7 +169,7 @@ function RSTabsMenu({
? <EyeIcon color='text-primary' size={5}/> ? <EyeIcon color='text-primary' size={5}/>
: <EyeOffIcon color='text-controls' size={5}/> : <EyeOffIcon color='text-controls' size={5}/>
} }
widthClass='h-full w-fit' dimensions='h-full w-fit'
borderClass='' borderClass=''
style={{outlineColor: 'transparent'}} style={{outlineColor: 'transparent'}}
dense dense

View File

@ -17,7 +17,7 @@ function RSTokenButton({ id, disabled, onInsert }: RSTokenButtonProps) {
onClick={() => onInsert(id)} onClick={() => onInsert(id)}
title={data.tooltip} title={data.tooltip}
tabIndex={-1} tabIndex={-1}
className={`px-1 cursor-pointer border rounded-none h-7 ${width} clr-outline clr-btn-clear`} className={`px-1 cursor-pointer border rounded-none h-7 ${width} clr-outline clr-hover clr-btn-clear`}
> >
{data.text && <span className='whitespace-nowrap'>{data.text}</span>} {data.text && <span className='whitespace-nowrap'>{data.text}</span>}
</button> </button>

View File

@ -121,7 +121,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
return (<> return (<>
<div <div
id={`${prefixes.cst_list}${cst.alias}`} id={`${prefixes.cst_list}${cst.alias}`}
className='w-full px-1 text-center rounded-md whitespace-nowrap' className='min-w-[3.1rem] max-w-[3.1rem] px-1 text-center rounded-md whitespace-nowrap'
style={{ style={{
borderWidth: '1px', borderWidth: '1px',
borderColor: getCstStatusFgColor(cst.status, colors), borderColor: getCstStatusFgColor(cst.status, colors),

View File

@ -61,7 +61,7 @@ function RegisterPage() {
<Form <Form
title='Регистрация' title='Регистрация'
onSubmit={handleSubmit} onSubmit={handleSubmit}
widthClass='w-[24rem]' dimensions='w-[24rem]'
> >
<TextInput id='username' label='Имя пользователя' type='text' <TextInput id='username' label='Имя пользователя' type='text'
required required
@ -104,12 +104,12 @@ function RegisterPage() {
<SubmitButton <SubmitButton
text='Регистрировать' text='Регистрировать'
loading={loading} loading={loading}
widthClass='min-w-[10rem]' dimensions='min-w-[10rem]'
/> />
<Button <Button
text='Отмена' text='Отмена'
onClick={() => handleCancel()} onClick={() => handleCancel()}
widthClass='min-w-[10rem]' dimensions='min-w-[10rem]'
/> />
</div> </div>
{ error && <BackendError error={error} />} { error && <BackendError error={error} />}

View File

@ -1,13 +1,25 @@
import axios from 'axios';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';
import BackendError from '../../components/BackendError'; import BackendError, { ErrorInfo } from '../../components/BackendError';
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 { useAuth } from '../../context/AuthContext'; import { useAuth } from '../../context/AuthContext';
import { useConceptNavigation } from '../../context/NagivationContext'; import { useConceptNavigation } from '../../context/NagivationContext';
import { IUserUpdatePassword } from '../../models/library'; import { IUserUpdatePassword } from '../../models/library';
function ProcessError({error}: {error: ErrorInfo}): React.ReactElement {
if (axios.isAxiosError(error) && error.response && error.response.status === 400) {
return (
<div className='text-sm select-text text-warning'>
Неверно введен старый пароль
</div>
);
} else {
return (<BackendError error={error} />);
}
}
function EditorPassword() { function EditorPassword() {
const { navigateTo } = useConceptNavigation(); const { navigateTo } = useConceptNavigation();
@ -50,7 +62,7 @@ function EditorPassword() {
return ( return (
<div className='flex py-2 border-l-2 max-w-[14rem]'> <div className='flex py-2 border-l-2 max-w-[14rem]'>
<form onSubmit={handleSubmit} className='flex flex-col justify-between px-6 min-w-fit'> <form onSubmit={handleSubmit} className='flex flex-col justify-between px-6 min-w-fit'>
<div> <div className='flex flex-col gap-3'>
<TextInput id='old_password' <TextInput id='old_password'
type='password' type='password'
label='Старый пароль' label='Старый пароль'
@ -74,7 +86,7 @@ function EditorPassword() {
}} }}
/> />
</div> </div>
{ error && <BackendError error={error} />} { error && <ProcessError error={error} />}
<div className='flex justify-center w-full'> <div className='flex justify-center w-full'>
<SubmitButton <SubmitButton
disabled={!canSubmit} disabled={!canSubmit}

View File

@ -50,9 +50,8 @@ function EditorProfile() {
} }
return ( return (
<div className='flex py-2'> <form onSubmit={handleSubmit} className='px-6 py-2 flex flex-col gap-8 min-w-[18rem]'>
<form onSubmit={handleSubmit} className='px-6 min-w-[18rem]'> <div className='flex flex-col gap-3'>
<div>
<TextInput id='username' <TextInput id='username'
label='Логин' label='Логин'
tooltip='Логин изменить нельзя' tooltip='Логин изменить нельзя'
@ -68,7 +67,7 @@ function EditorProfile() {
<TextInput id='last_name' label='Фамилия' value={last_name} onChange={event => setLastName(event.target.value)}/> <TextInput id='last_name' label='Фамилия' value={last_name} onChange={event => setLastName(event.target.value)}/>
<TextInput id='email' label='Электронная почта' value={email} onChange={event => setEmail(event.target.value)}/> <TextInput id='email' label='Электронная почта' value={email} onChange={event => setEmail(event.target.value)}/>
</div> </div>
<div className='flex justify-center w-full mt-10'> <div className='flex justify-center w-full'>
<SubmitButton <SubmitButton
text='Сохранить данные' text='Сохранить данные'
loading={processing} loading={processing}
@ -76,7 +75,6 @@ function EditorProfile() {
/> />
</div> </div>
</form> </form>
</div>
) )
} }

View File

@ -458,7 +458,7 @@ export function getTypificationLabel({isValid, resultType, args}: {
return 'N/A'; return 'N/A';
} }
if (resultType === '' || resultType === 'LOGIC') { if (resultType === '' || resultType === 'LOGIC') {
resultType = 'Логический'; resultType = 'Logical';
} }
if (args.length === 0) { if (args.length === 0) {
return resultType; return resultType;