mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Components refactoring and small fixes
This commit is contained in:
parent
6e610b5806
commit
bdbf77faa2
|
@ -1,35 +1,35 @@
|
||||||
|
import { IColorsProps, IControlProps } from '../commonInterfaces'
|
||||||
|
|
||||||
interface ButtonProps
|
interface ButtonProps
|
||||||
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children' | 'title'| 'type'> {
|
extends IControlProps, IColorsProps, Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children' | 'title'| 'type'> {
|
||||||
text?: string
|
text?: string
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
tooltip?: string
|
|
||||||
dense?: boolean
|
dense?: boolean
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
dimensions?: string
|
|
||||||
borderClass?: string
|
|
||||||
colorClass?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Button({
|
function Button({
|
||||||
text, icon, tooltip,
|
text, icon, tooltip,
|
||||||
dense, disabled,
|
dense, disabled, noBorder, noOutline,
|
||||||
borderClass = 'border rounded',
|
colors = 'clr-btn-default',
|
||||||
colorClass = 'clr-btn-default',
|
|
||||||
dimensions = 'w-fit h-fit',
|
dimensions = 'w-fit h-fit',
|
||||||
loading,
|
loading,
|
||||||
...props
|
...props
|
||||||
}: ButtonProps) {
|
}: ButtonProps) {
|
||||||
|
const borderClass = noBorder ? '' : 'border rounded';
|
||||||
const padding = dense ? 'px-1' : 'px-3 py-2';
|
const padding = dense ? 'px-1' : 'px-3 py-2';
|
||||||
|
const outlineClass = noOutline ? 'outline-none': 'clr-outline';
|
||||||
const cursor = 'disabled:cursor-not-allowed ' + (loading ? 'cursor-progress ' : 'cursor-pointer ');
|
const cursor = 'disabled:cursor-not-allowed ' + (loading ? 'cursor-progress ' : 'cursor-pointer ');
|
||||||
return (
|
return (
|
||||||
<button type='button'
|
<button type='button'
|
||||||
disabled={disabled ?? loading}
|
disabled={disabled ?? loading}
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
className={`inline-flex items-center gap-2 align-middle justify-center select-none ${padding} ${colorClass} ${dimensions} ${borderClass} ${cursor}`}
|
className={`inline-flex items-center gap-2 align-middle justify-center select-none ${padding} ${colors} ${outlineClass} ${borderClass} ${dimensions} ${cursor}`}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{icon && icon}
|
{icon && icon}
|
||||||
{text && <span className={'font-semibold'}>{text}</span>}
|
{text && <span className='font-semibold'>{text}</span>}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,18 @@ extends Omit<ITooltip, 'variant'> {
|
||||||
layer?: string
|
layer?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function ConceptTooltip({ className, layer, place='bottom', ...props }: ConceptTooltipProps) {
|
function ConceptTooltip({
|
||||||
|
className,
|
||||||
|
layer='z-tooltip',
|
||||||
|
place='bottom',
|
||||||
|
...props
|
||||||
|
}: ConceptTooltipProps) {
|
||||||
const { darkMode } = useConceptTheme();
|
const { darkMode } = useConceptTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
opacity={0.97}
|
opacity={0.97}
|
||||||
className={`overflow-auto border shadow-md ${layer ?? 'z-tooltip'} ${className}`}
|
className={`overflow-auto border shadow-md ${layer} ${className}`}
|
||||||
variant={(darkMode ? 'dark' : 'light')}
|
variant={(darkMode ? 'dark' : 'light')}
|
||||||
place={place}
|
place={place}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -8,8 +8,9 @@ interface FileInputProps
|
||||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title' | 'style' | 'accept' | 'type'> {
|
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title' | 'style' | 'accept' | 'type'> {
|
||||||
label: string
|
label: string
|
||||||
tooltip?: string
|
tooltip?: string
|
||||||
acceptType?: string
|
|
||||||
dimensions?: string
|
dimensions?: string
|
||||||
|
|
||||||
|
acceptType?: string
|
||||||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
interface MiniButtonProps
|
interface MiniButtonProps
|
||||||
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'title' |'children' > {
|
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'title' | 'children' > {
|
||||||
icon: React.ReactNode
|
icon: React.ReactNode
|
||||||
tooltip?: string
|
tooltip?: string
|
||||||
noHover?: boolean
|
noHover?: boolean
|
||||||
|
|
|
@ -52,7 +52,7 @@ function Modal({
|
||||||
text={submitText}
|
text={submitText}
|
||||||
tooltip={!canSubmit ? submitInvalidTooltip: ''}
|
tooltip={!canSubmit ? submitInvalidTooltip: ''}
|
||||||
dimensions='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'
|
colors='clr-btn-primary'
|
||||||
disabled={!canSubmit}
|
disabled={!canSubmit}
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|
|
@ -5,14 +5,14 @@ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'child
|
||||||
tooltip?: string
|
tooltip?: string
|
||||||
dimensions?: string
|
dimensions?: string
|
||||||
borderClass?: string
|
borderClass?: string
|
||||||
colorClass?: string
|
colors?: string
|
||||||
transparent?: boolean
|
transparent?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function SelectorButton({
|
function SelectorButton({
|
||||||
text, icon, tooltip,
|
text, icon, tooltip,
|
||||||
colorClass = 'clr-btn-default',
|
colors = 'clr-btn-default',
|
||||||
dimensions = 'w-fit h-fit',
|
dimensions = 'w-fit h-fit',
|
||||||
transparent,
|
transparent,
|
||||||
...props
|
...props
|
||||||
|
@ -21,7 +21,7 @@ function SelectorButton({
|
||||||
const position = `px-1 flex flex-start items-center gap-1 ${dimensions}`
|
const position = `px-1 flex flex-start items-center gap-1 ${dimensions}`
|
||||||
return (
|
return (
|
||||||
<button type='button'
|
<button type='button'
|
||||||
className={`text-sm small-caps ${!transparent && 'border'} ${cursor} ${position} text-btn text-controls select-none ${transparent ? 'clr-hover' : colorClass}`}
|
className={`text-sm small-caps ${!transparent && 'border'} ${cursor} ${position} text-btn text-controls select-none ${transparent ? 'clr-hover' : colors}`}
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
import { TextareaHTMLAttributes } from 'react';
|
import { TextareaHTMLAttributes } from 'react';
|
||||||
|
|
||||||
|
import { IColorsProps, IEditorProps } from '../commonInterfaces';
|
||||||
import Label from './Label';
|
import Label from './Label';
|
||||||
|
|
||||||
export interface TextAreaProps
|
export interface TextAreaProps
|
||||||
extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'className' | 'title'> {
|
extends IEditorProps, IColorsProps, Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'className' | 'title'> {
|
||||||
label?: string
|
|
||||||
tooltip?: string
|
|
||||||
dimensions?: string
|
|
||||||
dense?: boolean
|
dense?: boolean
|
||||||
colorClass?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextArea({
|
function TextArea({
|
||||||
id, label, required, tooltip, dense,
|
id, label, required, tooltip, dense, noBorder, noOutline,
|
||||||
dimensions = 'w-full',
|
dimensions = 'w-full',
|
||||||
colorClass = 'clr-input',
|
colors = 'clr-input',
|
||||||
rows = 4,
|
rows = 4,
|
||||||
...props
|
...props
|
||||||
}: TextAreaProps) {
|
}: TextAreaProps) {
|
||||||
|
const borderClass = noBorder ? '': 'border';
|
||||||
|
const outlineClass = noOutline ? '': 'clr-outline';
|
||||||
return (
|
return (
|
||||||
<div className={`flex ${dense ? 'items-center gap-4 ' + dimensions : 'flex-col items-start gap-2'}`}>
|
<div className={`flex ${dense ? 'items-center gap-4 ' + dimensions : 'flex-col items-start gap-2'}`}>
|
||||||
{label &&
|
{label &&
|
||||||
|
@ -27,7 +26,7 @@ function TextArea({
|
||||||
/>}
|
/>}
|
||||||
<textarea id={id}
|
<textarea id={id}
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
className={`px-3 py-2 leading-tight border clr-outline ${colorClass} ${dense ? 'w-full' : dimensions}`}
|
className={`px-3 py-2 leading-tight ${outlineClass} ${borderClass} ${colors} ${dense ? 'w-full' : dimensions}`}
|
||||||
rows={rows}
|
rows={rows}
|
||||||
required={required}
|
required={required}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
|
import { IColorsProps, IEditorProps } from '../commonInterfaces';
|
||||||
import Label from './Label';
|
import Label from './Label';
|
||||||
|
|
||||||
interface TextInputProps
|
interface TextInputProps
|
||||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title'> {
|
extends IEditorProps, IColorsProps, Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className' | 'title'> {
|
||||||
id?: string
|
|
||||||
label?: string
|
|
||||||
tooltip?: string
|
|
||||||
dimensions?: string
|
|
||||||
colorClass?: string
|
|
||||||
dense?: boolean
|
dense?: boolean
|
||||||
noBorder?: boolean
|
allowEnter?: boolean
|
||||||
noOutline?: boolean
|
}
|
||||||
|
|
||||||
|
function preventEnterCapture(event: React.KeyboardEvent<HTMLInputElement>) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextInput({
|
function TextInput({
|
||||||
id, required, label, dense, tooltip, noBorder, noOutline,
|
id, label, dense, tooltip, noBorder, noOutline, allowEnter, onKeyDown,
|
||||||
dimensions = 'w-full',
|
dimensions = 'w-full',
|
||||||
colorClass = 'clr-input',
|
colors = 'clr-input',
|
||||||
...props
|
...props
|
||||||
}: TextInputProps) {
|
}: TextInputProps) {
|
||||||
const borderClass = noBorder ? '': 'border';
|
const borderClass = noBorder ? '': 'border';
|
||||||
|
@ -29,8 +30,9 @@ function TextInput({
|
||||||
/>}
|
/>}
|
||||||
<input id={id}
|
<input id={id}
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
className={`px-3 py-2 leading-tight truncate hover:text-clip ${outlineClass} ${borderClass} ${colorClass} ${dense ? 'w-full' : dimensions}`}
|
|
||||||
required={required}
|
onKeyDown={!allowEnter && !onKeyDown ? preventEnterCapture: onKeyDown}
|
||||||
|
className={`px-3 py-2 leading-tight truncate hover:text-clip ${colors} ${outlineClass} ${borderClass} ${dense ? 'w-full' : dimensions}`}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
17
rsconcept/frontend/src/components/commonInterfaces.ts
Normal file
17
rsconcept/frontend/src/components/commonInterfaces.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// =========== Module contains interfaces for common UI elements. ==========
|
||||||
|
export interface IControlProps {
|
||||||
|
tooltip?: string
|
||||||
|
dimensions?: string
|
||||||
|
|
||||||
|
disabled?: boolean
|
||||||
|
noBorder?: boolean
|
||||||
|
noOutline?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IEditorProps extends IControlProps {
|
||||||
|
label?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IColorsProps {
|
||||||
|
colors?: string
|
||||||
|
}
|
|
@ -243,7 +243,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(.clr-outline,
|
:is(.clr-outline,
|
||||||
.clr-btn-default,
|
|
||||||
.clr-btn-primary
|
.clr-btn-primary
|
||||||
):focus {
|
):focus {
|
||||||
outline-width: 2px;
|
outline-width: 2px;
|
||||||
|
|
|
@ -91,18 +91,18 @@ function LoginPage() {
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
dimensions='w-[24rem]'
|
dimensions='w-[24rem]'
|
||||||
>
|
>
|
||||||
<TextInput id='username'
|
<TextInput id='username' type='text'
|
||||||
label='Имя пользователя'
|
label='Имя пользователя'
|
||||||
required
|
required
|
||||||
type='text'
|
allowEnter
|
||||||
value={username}
|
value={username}
|
||||||
autoFocus
|
autoFocus
|
||||||
onChange={event => setUsername(event.target.value)}
|
onChange={event => setUsername(event.target.value)}
|
||||||
/>
|
/>
|
||||||
<TextInput id='password'
|
<TextInput id='password' type='password'
|
||||||
label='Пароль'
|
label='Пароль'
|
||||||
required
|
required
|
||||||
type='password'
|
allowEnter
|
||||||
value={password}
|
value={password}
|
||||||
onChange={event => setPassword(event.target.value)}
|
onChange={event => setPassword(event.target.value)}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -226,7 +226,7 @@ function EditorConstituenta({
|
||||||
dense
|
dense
|
||||||
rows={1}
|
rows={1}
|
||||||
value={typification}
|
value={typification}
|
||||||
colorClass='clr-app'
|
colors='clr-app'
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<EditorRSExpression id='expression' label='Формальное определение'
|
<EditorRSExpression id='expression' label='Формальное определение'
|
||||||
|
|
|
@ -143,9 +143,9 @@ function EditorRSExpression({
|
||||||
<Button
|
<Button
|
||||||
tooltip='Проверить формальное определение'
|
tooltip='Проверить формальное определение'
|
||||||
text='Проверить'
|
text='Проверить'
|
||||||
dimensions='w-fit h-[3rem] z-pop'
|
dimensions='w-fit h-[3rem] z-pop rounded-none'
|
||||||
colorClass='clr-btn-default'
|
colors='clr-btn-default'
|
||||||
borderClass='rounded-none border'
|
noOutline
|
||||||
onClick={() => handleCheckExpression()}
|
onClick={() => handleCheckExpression()}
|
||||||
/>
|
/>
|
||||||
<StatusBar
|
<StatusBar
|
||||||
|
|
|
@ -81,9 +81,9 @@ function RSTabsMenu({
|
||||||
<Button
|
<Button
|
||||||
tooltip='Действия'
|
tooltip='Действия'
|
||||||
icon={<MenuIcon color='text-controls' size={5}/>}
|
icon={<MenuIcon color='text-controls' size={5}/>}
|
||||||
borderClass=''
|
|
||||||
dimensions='h-full w-fit pl-2'
|
dimensions='h-full w-fit pl-2'
|
||||||
style={{outlineColor: 'transparent'}}
|
style={{outlineColor: 'transparent'}}
|
||||||
|
noBorder
|
||||||
dense
|
dense
|
||||||
onClick={schemaMenu.toggle}
|
onClick={schemaMenu.toggle}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
|
@ -137,11 +137,11 @@ function RSTabsMenu({
|
||||||
<div ref={editMenu.ref}>
|
<div ref={editMenu.ref}>
|
||||||
<Button
|
<Button
|
||||||
tooltip={'измнение: ' + (isEditable ? '[доступно]' : '[запрещено]')}
|
tooltip={'измнение: ' + (isEditable ? '[доступно]' : '[запрещено]')}
|
||||||
borderClass=''
|
|
||||||
dimensions='h-full w-fit'
|
dimensions='h-full w-fit'
|
||||||
style={{outlineColor: 'transparent'}}
|
style={{outlineColor: 'transparent'}}
|
||||||
icon={<EditIcon size={5} color={isEditable ? 'text-success' : 'text-warning'}/>}
|
icon={<EditIcon size={5} color={isEditable ? 'text-success' : 'text-warning'}/>}
|
||||||
dense
|
dense
|
||||||
|
noBorder
|
||||||
onClick={editMenu.toggle}
|
onClick={editMenu.toggle}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
/>
|
/>
|
||||||
|
@ -185,9 +185,9 @@ function RSTabsMenu({
|
||||||
: <NotSubscribedIcon color='text-controls' size={5}/>
|
: <NotSubscribedIcon color='text-controls' size={5}/>
|
||||||
}
|
}
|
||||||
dimensions='h-full w-fit pr-2'
|
dimensions='h-full w-fit pr-2'
|
||||||
borderClass=''
|
|
||||||
style={{outlineColor: 'transparent'}}
|
style={{outlineColor: 'transparent'}}
|
||||||
dense
|
dense
|
||||||
|
noBorder
|
||||||
onClick={onToggleSubscribe}
|
onClick={onToggleSubscribe}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -70,7 +70,7 @@ function EditorPassword() {
|
||||||
onChange={event => setOldPassword(event.target.value)}
|
onChange={event => setOldPassword(event.target.value)}
|
||||||
/>
|
/>
|
||||||
<TextInput id='new_password' type='password'
|
<TextInput id='new_password' type='password'
|
||||||
colorClass={passwordColor}
|
colors={passwordColor}
|
||||||
label='Новый пароль'
|
label='Новый пароль'
|
||||||
value={newPassword}
|
value={newPassword}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
|
@ -78,7 +78,7 @@ function EditorPassword() {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<TextInput id='new_password_repeat' type='password'
|
<TextInput id='new_password_repeat' type='password'
|
||||||
colorClass={passwordColor}
|
colors={passwordColor}
|
||||||
label='Повторите новый'
|
label='Повторите новый'
|
||||||
value={newPasswordRepeat}
|
value={newPasswordRepeat}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
|
|
|
@ -52,7 +52,7 @@ function EditorProfile() {
|
||||||
return (
|
return (
|
||||||
<form onSubmit={handleSubmit} className='px-6 py-2 flex flex-col gap-8 min-w-[18rem]'>
|
<form onSubmit={handleSubmit} className='px-6 py-2 flex flex-col gap-8 min-w-[18rem]'>
|
||||||
<div className='flex flex-col gap-3'>
|
<div className='flex flex-col gap-3'>
|
||||||
<TextInput id='username'
|
<TextInput id='username'
|
||||||
label='Логин'
|
label='Логин'
|
||||||
tooltip='Логин изменить нельзя'
|
tooltip='Логин изменить нельзя'
|
||||||
disabled={true}
|
disabled={true}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// =========== Modules contains all text descriptors ==========
|
// =========== Module contains all text descriptors. ==========
|
||||||
|
|
||||||
import { GramData,Grammeme, ReferenceType } from '../models/language';
|
import { GramData,Grammeme, ReferenceType } from '../models/language';
|
||||||
import { CstMatchMode, DependencyMode, HelpTopic, LibraryFilterStrategy } from '../models/miscelanious';
|
import { CstMatchMode, DependencyMode, HelpTopic, LibraryFilterStrategy } from '../models/miscelanious';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user