mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 21:10:38 +03:00
UI fixes
This commit is contained in:
parent
2ab01cda42
commit
1cc41320ac
|
@ -7,7 +7,6 @@ export interface CheckboxProps
|
||||||
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children' | 'title' | 'value' | 'onClick' > {
|
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children' | 'title' | 'value' | 'onClick' > {
|
||||||
id?: string
|
id?: string
|
||||||
label?: string
|
label?: string
|
||||||
required?: boolean
|
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
dimensions?: string
|
dimensions?: string
|
||||||
tooltip?: string
|
tooltip?: string
|
||||||
|
@ -17,7 +16,7 @@ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'child
|
||||||
}
|
}
|
||||||
|
|
||||||
function Checkbox({
|
function Checkbox({
|
||||||
id, required, disabled, tooltip, label,
|
id, disabled, tooltip, label,
|
||||||
dimensions = 'w-fit', value, setValue, ...props
|
dimensions = 'w-fit', value, setValue, ...props
|
||||||
}: CheckboxProps) {
|
}: CheckboxProps) {
|
||||||
const cursor = useMemo(
|
const cursor = useMemo(
|
||||||
|
@ -59,7 +58,6 @@ function Checkbox({
|
||||||
<Label
|
<Label
|
||||||
className={`${cursor} px-2 text-start`}
|
className={`${cursor} px-2 text-start`}
|
||||||
text={label}
|
text={label}
|
||||||
required={required}
|
|
||||||
htmlFor={id}
|
htmlFor={id}
|
||||||
/>}
|
/>}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
import { LabelHTMLAttributes } from 'react';
|
import { LabelHTMLAttributes } from 'react';
|
||||||
|
|
||||||
interface LabelProps
|
interface LabelProps
|
||||||
extends Omit<React.DetailedHTMLProps<LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, 'children'> {
|
extends Omit<React.DetailedHTMLProps<LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, 'children' | 'title'> {
|
||||||
text: string
|
text: string
|
||||||
required?: boolean
|
tooltip?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function Label({ text, required, title, className, ...props }: LabelProps) {
|
function Label({ text, tooltip, className, ...props }: LabelProps) {
|
||||||
return (
|
return (
|
||||||
<label
|
<label
|
||||||
className={`text-sm font-semibold ${className}`}
|
className={`text-sm font-semibold ${className}`}
|
||||||
title={ (required && !title) ? 'обязательное поле' : title }
|
title={tooltip}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{text + (required ? '*' : '')}
|
{text}
|
||||||
</label>
|
</label>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@ function TextArea({
|
||||||
}: TextAreaProps) {
|
}: TextAreaProps) {
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col items-start gap-2'>
|
<div className='flex flex-col items-start gap-2'>
|
||||||
{label && <Label
|
{label &&
|
||||||
|
<Label
|
||||||
text={label}
|
text={label}
|
||||||
required={!props.disabled && required}
|
|
||||||
htmlFor={id}
|
htmlFor={id}
|
||||||
/>}
|
/>}
|
||||||
<textarea id={id}
|
<textarea id={id}
|
||||||
|
|
|
@ -23,7 +23,6 @@ function TextInput({
|
||||||
{label &&
|
{label &&
|
||||||
<Label
|
<Label
|
||||||
text={label}
|
text={label}
|
||||||
required={!props.disabled && required}
|
|
||||||
htmlFor={id}
|
htmlFor={id}
|
||||||
/>}
|
/>}
|
||||||
<input id={id}
|
<input id={id}
|
||||||
|
|
|
@ -12,7 +12,7 @@ extends Omit<CheckboxProps, 'value' | 'setValue'> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function Tristate({
|
function Tristate({
|
||||||
id, required, disabled, tooltip, label,
|
id, disabled, tooltip, label,
|
||||||
dimensions = 'w-fit', value, setValue, ...props
|
dimensions = 'w-fit', value, setValue, ...props
|
||||||
}: TristateProps) {
|
}: TristateProps) {
|
||||||
const cursor = useMemo(
|
const cursor = useMemo(
|
||||||
|
@ -61,7 +61,6 @@ function Tristate({
|
||||||
<Label
|
<Label
|
||||||
className={`${cursor} px-2 text-start`}
|
className={`${cursor} px-2 text-start`}
|
||||||
text={label}
|
text={label}
|
||||||
required={required}
|
|
||||||
htmlFor={id}
|
htmlFor={id}
|
||||||
/>}
|
/>}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -109,15 +109,14 @@ export default function DataTable<TData extends RowData>({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full'>
|
<div className='w-full'>
|
||||||
{isEmpty && (noDataComponent ?? <DefaultNoData />)}
|
|
||||||
{!isEmpty &&
|
|
||||||
<div className='flex flex-col items-stretch'>
|
<div className='flex flex-col items-stretch'>
|
||||||
<table>
|
<table>
|
||||||
<thead
|
<thead
|
||||||
className='clr-app shadow-border'
|
className={`clr-app shadow-border`}
|
||||||
style={{
|
style={{
|
||||||
top: headPosition,
|
top: headPosition,
|
||||||
position: 'sticky'
|
position: 'sticky',
|
||||||
|
visibility: !isEmpty ? 'visible' : 'hidden'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{tableImpl.getHeaderGroups().map(
|
{tableImpl.getHeaderGroups().map(
|
||||||
|
@ -149,7 +148,7 @@ export default function DataTable<TData extends RowData>({
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{tableImpl.getRowModel().rows.map(
|
{tableImpl.getRowModel().rows.map(
|
||||||
(row: Row<TData>, index) => (
|
(row: Row<TData>, index) => (
|
||||||
|
@ -202,12 +201,13 @@ export default function DataTable<TData extends RowData>({
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{enablePagination &&
|
{enablePagination && !isEmpty &&
|
||||||
<PaginationTools
|
<PaginationTools
|
||||||
table={tableImpl}
|
table={tableImpl}
|
||||||
paginationOptions={paginationOptions}
|
paginationOptions={paginationOptions}
|
||||||
onChangePaginationOption={onChangePaginationOption}
|
onChangePaginationOption={onChangePaginationOption}
|
||||||
/>}
|
/>}
|
||||||
</div>}
|
</div>
|
||||||
|
{isEmpty && (noDataComponent ?? <DefaultNoData />)}
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,6 @@ function RSInput({
|
||||||
{label &&
|
{label &&
|
||||||
<Label
|
<Label
|
||||||
text={label}
|
text={label}
|
||||||
required={false}
|
|
||||||
htmlFor={id}
|
htmlFor={id}
|
||||||
className='mb-2'
|
className='mb-2'
|
||||||
/>}
|
/>}
|
||||||
|
|
|
@ -203,7 +203,6 @@ function RefsInput({
|
||||||
{label &&
|
{label &&
|
||||||
<Label
|
<Label
|
||||||
text={label}
|
text={label}
|
||||||
required={false}
|
|
||||||
htmlFor={id}
|
htmlFor={id}
|
||||||
className='mb-2'
|
className='mb-2'
|
||||||
/>}
|
/>}
|
||||||
|
|
|
@ -111,7 +111,7 @@
|
||||||
.dark & {
|
.dark & {
|
||||||
background: var(--cd-prim-bg-60);
|
background: var(--cd-prim-bg-60);
|
||||||
}
|
}
|
||||||
:hover& {
|
tr :hover& {
|
||||||
background: var(--cl-red-bg-100);
|
background: var(--cl-red-bg-100);
|
||||||
.dark & {
|
.dark & {
|
||||||
background: var(--cd-red-bg-100);
|
background: var(--cd-red-bg-100);
|
||||||
|
|
|
@ -15,7 +15,7 @@ function TopicsList({ activeTopic, onChangeTopic }: TopicsListProps) {
|
||||||
(topic, index) => {
|
(topic, index) => {
|
||||||
return (
|
return (
|
||||||
<div key={`${prefixes.topic_list}${index}`}
|
<div key={`${prefixes.topic_list}${index}`}
|
||||||
className={`px-3 py-1 border-y cursor-pointer clr-hover ${activeTopic === topic ? 'font-semibold clr-selected ' : ''}`}
|
className={`px-3 py-1 border-y cursor-pointer clr-hover ${activeTopic === topic ? 'clr-selected ' : ''}`}
|
||||||
title={describeHelpTopic(topic)}
|
title={describeHelpTopic(topic)}
|
||||||
onClick={() => onChangeTopic(topic)}
|
onClick={() => onChangeTopic(topic)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -150,9 +150,9 @@ function EditorConstituenta({
|
||||||
icon={<PenIcon size={4} color={isEnabled ? 'text-primary' : ''} />}
|
icon={<PenIcon size={4} color={isEnabled ? 'text-primary' : ''} />}
|
||||||
/>}
|
/>}
|
||||||
<div className='flex items-center justify-center w-full'>
|
<div className='flex items-center justify-center w-full'>
|
||||||
<div className='font-semibold w-fit'>
|
<div className='font-semibold w-fit pointer-events-none'>
|
||||||
<span className='small-caps'>Конституента</span>
|
<span className='small-caps'>Конституента </span>
|
||||||
<span className='ml-2 small-caps'>{alias}</span>
|
<span className='ml-1 small-caps'>{alias}</span>
|
||||||
</div>
|
</div>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Переименовать конституенту'
|
tooltip='Переименовать конституенту'
|
||||||
|
|
|
@ -397,10 +397,10 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
|
||||||
</div>
|
</div>
|
||||||
<div className='flex items-center w-full gap-1'>
|
<div className='flex items-center w-full gap-1'>
|
||||||
<Button
|
<Button
|
||||||
icon={<FilterCogIcon size={7} />}
|
icon={<FilterCogIcon size={6} />}
|
||||||
dense
|
dense
|
||||||
tooltip='Настройки фильтрации узлов и связей'
|
tooltip='Настройки фильтрации узлов и связей'
|
||||||
dimensions='h-full'
|
dimensions='min-h-[2.3rem] min-w-[2.3rem]'
|
||||||
onClick={() => setShowOptions(true)}
|
onClick={() => setShowOptions(true)}
|
||||||
/>
|
/>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
|
@ -411,7 +411,6 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
|
||||||
value={coloringScheme ? { value: coloringScheme, label: mapLabelColoring.get(coloringScheme) } : null}
|
value={coloringScheme ? { value: coloringScheme, label: mapLabelColoring.get(coloringScheme) } : null}
|
||||||
onChange={data => setColoringScheme(data?.value ?? SelectorGraphColoring[0].value)}
|
onChange={data => setColoringScheme(data?.value ?? SelectorGraphColoring[0].value)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
className='w-full mt-1'
|
className='w-full mt-1'
|
||||||
|
|
|
@ -384,13 +384,25 @@ function RSTabs() {
|
||||||
showCloneDialog={promptClone}
|
showCloneDialog={promptClone}
|
||||||
showUploadDialog={() => setShowUpload(true)}
|
showUploadDialog={() => setShowUpload(true)}
|
||||||
/>
|
/>
|
||||||
<ConceptTab className='border-x-2 min-w-[7.8rem]'>Паспорт схемы</ConceptTab>
|
<ConceptTab
|
||||||
<ConceptTab className='border-r-2 min-w-[10rem] flex justify-between gap-2'>
|
className='border-x-2 min-w-[7.8rem]'
|
||||||
|
title={`Название схемы: ${schema.title ?? ''}`}
|
||||||
|
>
|
||||||
|
Паспорт схемы
|
||||||
|
</ConceptTab>
|
||||||
|
<ConceptTab
|
||||||
|
className='border-r-2 w-fit flex justify-between gap-2'
|
||||||
|
title={`Всего конституент: ${schema.stats?.count_all ?? 0}\nКоличество ошибок: ${schema.stats?.count_errors ?? 0}`}
|
||||||
|
>
|
||||||
<span>Конституенты</span>
|
<span>Конституенты</span>
|
||||||
<span>{`${schema.stats?.count_errors ?? 0} | ${schema.stats?.count_all ?? 0}`}</span>
|
<span>{`${schema.stats?.count_errors ?? 0} | ${schema.stats?.count_all ?? 0}`}</span>
|
||||||
</ConceptTab>
|
</ConceptTab>
|
||||||
<ConceptTab className='border-r-2 min-w-[5.2rem]'>Редактор</ConceptTab>
|
<ConceptTab className='border-r-2 min-w-[5.2rem]'>
|
||||||
<ConceptTab className='min-w-[6.5rem]'>Граф термов</ConceptTab>
|
Редактор
|
||||||
|
</ConceptTab>
|
||||||
|
<ConceptTab className='min-w-[6.5rem]'>
|
||||||
|
Граф термов
|
||||||
|
</ConceptTab>
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<div className='overflow-y-auto' style={{ maxHeight: panelHeight}}>
|
<div className='overflow-y-auto' style={{ maxHeight: panelHeight}}>
|
||||||
|
|
|
@ -211,7 +211,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
|
||||||
}, [noNavigation, baseHeight]);
|
}, [noNavigation, baseHeight]);
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
<div className='sticky top-0 left-0 right-0 flex items-stretch justify-start w-full gap-1 px-2 border-b rounded clr-input'>
|
<div className='sticky top-0 left-0 right-0 flex items-stretch justify-between w-full gap-1 pl-2 border-b clr-input'>
|
||||||
<div className='absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-controls'>
|
<div className='absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-controls'>
|
||||||
<MagnifyingGlassIcon />
|
<MagnifyingGlassIcon />
|
||||||
</div>
|
</div>
|
||||||
|
@ -221,56 +221,58 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
|
||||||
value={filterText}
|
value={filterText}
|
||||||
onChange={event => setFilterText(event.target.value)}
|
onChange={event => setFilterText(event.target.value)}
|
||||||
/>
|
/>
|
||||||
<div ref={matchModeMenu.ref}>
|
<div className='flex'>
|
||||||
<SelectorButton
|
<div ref={matchModeMenu.ref}>
|
||||||
tooltip='Настройка атрибутов для фильтрации'
|
<SelectorButton
|
||||||
dimensions='w-fit h-full'
|
tooltip='Настройка атрибутов для фильтрации'
|
||||||
transparent
|
dimensions='w-fit h-full'
|
||||||
icon={<FilterCogIcon size={5} />}
|
transparent
|
||||||
text={labelCstMathchMode(filterMatch)}
|
icon={<FilterCogIcon size={5} />}
|
||||||
tabIndex={-1}
|
text={labelCstMathchMode(filterMatch)}
|
||||||
onClick={matchModeMenu.toggle}
|
tabIndex={-1}
|
||||||
/>
|
onClick={matchModeMenu.toggle}
|
||||||
{ matchModeMenu.isActive &&
|
/>
|
||||||
<Dropdown stretchLeft>
|
{ matchModeMenu.isActive &&
|
||||||
{ Object.values(CstMatchMode).filter(value => !isNaN(Number(value))).map(
|
<Dropdown stretchLeft>
|
||||||
(value, index) => {
|
{ Object.values(CstMatchMode).filter(value => !isNaN(Number(value))).map(
|
||||||
const matchMode = value as CstMatchMode;
|
(value, index) => {
|
||||||
return (
|
const matchMode = value as CstMatchMode;
|
||||||
<DropdownButton
|
return (
|
||||||
key={`${prefixes.cst_match_mode_list}${index}`}
|
<DropdownButton
|
||||||
onClick={() => handleMatchModeChange(matchMode)}
|
key={`${prefixes.cst_match_mode_list}${index}`}
|
||||||
>
|
onClick={() => handleMatchModeChange(matchMode)}
|
||||||
<p><span className='font-semibold'>{labelCstMathchMode(matchMode)}:</span> {describeCstMathchMode(matchMode)}</p>
|
>
|
||||||
</DropdownButton>);
|
<p><span className='font-semibold'>{labelCstMathchMode(matchMode)}:</span> {describeCstMathchMode(matchMode)}</p>
|
||||||
})}
|
</DropdownButton>);
|
||||||
</Dropdown>}
|
})}
|
||||||
</div>
|
</Dropdown>}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div ref={sourceMenu.ref}>
|
<div ref={sourceMenu.ref}>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
tooltip='Настройка фильтрации по графу термов'
|
tooltip='Настройка фильтрации по графу термов'
|
||||||
dimensions='w-fit h-full'
|
dimensions='w-fit h-full'
|
||||||
transparent
|
transparent
|
||||||
icon={<CogIcon size={4} />}
|
icon={<CogIcon size={4} />}
|
||||||
text={labelCstSource(filterSource)}
|
text={labelCstSource(filterSource)}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
onClick={sourceMenu.toggle}
|
onClick={sourceMenu.toggle}
|
||||||
/>
|
/>
|
||||||
{ sourceMenu.isActive &&
|
{ sourceMenu.isActive &&
|
||||||
<Dropdown stretchLeft>
|
<Dropdown stretchLeft>
|
||||||
{ Object.values(CstSource).filter(value => !isNaN(Number(value))).map(
|
{ Object.values(CstSource).filter(value => !isNaN(Number(value))).map(
|
||||||
(value, index) => {
|
(value, index) => {
|
||||||
const source = value as CstSource;
|
const source = value as CstSource;
|
||||||
return (
|
return (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
key={`${prefixes.cst_source_list}${index}`}
|
key={`${prefixes.cst_source_list}${index}`}
|
||||||
onClick={() => handleSourceChange(source)}
|
onClick={() => handleSourceChange(source)}
|
||||||
>
|
>
|
||||||
<p><span className='font-semibold'>{labelCstSource(source)}:</span> {describeCstSource(source)}</p>
|
<p><span className='font-semibold'>{labelCstSource(source)}:</span> {describeCstSource(source)}</p>
|
||||||
</DropdownButton>);
|
</DropdownButton>);
|
||||||
})}
|
})}
|
||||||
</Dropdown>}
|
</Dropdown>}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='overflow-y-auto text-sm' style={{maxHeight : `${maxHeight}`}}>
|
<div className='overflow-y-auto text-sm' style={{maxHeight : `${maxHeight}`}}>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user