mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
UI improvements
This commit is contained in:
parent
3f4f9b03dc
commit
c71bfbef34
|
@ -10,7 +10,7 @@ extends Omit<TabProps, 'className' | 'title'> {
|
||||||
function ConceptTab({ children, tooltip, className, ...otherProps }: ConceptTabProps) {
|
function ConceptTab({ children, tooltip, className, ...otherProps }: ConceptTabProps) {
|
||||||
return (
|
return (
|
||||||
<Tab
|
<Tab
|
||||||
className={`px-2 py-1 h-full text-sm hover:cursor-pointer clr-tab whitespace-nowrap ${className}`}
|
className={`px-2 py-1 h-full flex justify-center text-sm hover:cursor-pointer clr-tab whitespace-nowrap min-w-[6rem] ${className}`}
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,7 +5,7 @@ interface DividerProps {
|
||||||
|
|
||||||
function Divider({ vertical, margins = 'mx-2' }: DividerProps) {
|
function Divider({ vertical, margins = 'mx-2' }: DividerProps) {
|
||||||
return (
|
return (
|
||||||
<div className={`${margins} ${vertical ? 'border-x-2 h-full': 'border-y-2 w-full'}`} />
|
<div className={`${margins} ${vertical ? 'border-x h-full': 'border-y w-full'}`} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,12 +7,13 @@ interface DropdownButtonProps {
|
||||||
|
|
||||||
function DropdownButton({ tooltip, onClick, disabled, children }: DropdownButtonProps) {
|
function DropdownButton({ tooltip, onClick, disabled, children }: DropdownButtonProps) {
|
||||||
const behavior = (onClick ? 'cursor-pointer disabled:cursor-not-allowed clr-hover' : 'cursor-default');
|
const behavior = (onClick ? 'cursor-pointer disabled:cursor-not-allowed clr-hover' : 'cursor-default');
|
||||||
|
const text = disabled ? 'text-controls' : '';
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
title={tooltip}
|
title={tooltip}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={`px-3 py-1 text-left overflow-ellipsis ${behavior} whitespace-nowrap`}
|
className={`px-3 py-1 text-left overflow-ellipsis whitespace-nowrap ${behavior} ${text}`}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -9,10 +9,10 @@ extends IEditorProps, IColorsProps, Omit<TextareaHTMLAttributes<HTMLTextAreaElem
|
||||||
}
|
}
|
||||||
|
|
||||||
function TextArea({
|
function TextArea({
|
||||||
id, label, required, tooltip, dense, noBorder, noOutline,
|
id, label, required, tooltip, rows,
|
||||||
|
dense, noBorder, noOutline,
|
||||||
dimensions = 'w-full',
|
dimensions = 'w-full',
|
||||||
colors = 'clr-input',
|
colors = 'clr-input',
|
||||||
rows = 4,
|
|
||||||
...props
|
...props
|
||||||
}: TextAreaProps) {
|
}: TextAreaProps) {
|
||||||
const borderClass = noBorder ? '': 'border';
|
const borderClass = noBorder ? '': 'border';
|
||||||
|
|
|
@ -56,7 +56,8 @@ extends Pick<ReactCodeMirrorProps,
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSInput({
|
function RSInput({
|
||||||
id, label, innerref, onChange, disabled, noTooltip,
|
id, label, innerref, onChange,
|
||||||
|
disabled, noTooltip,
|
||||||
dimensions = 'w-full',
|
dimensions = 'w-full',
|
||||||
...props
|
...props
|
||||||
}: RSInputProps) {
|
}: RSInputProps) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ function ConstituentaPicker({
|
||||||
})
|
})
|
||||||
], [colors, prefixID, describeFunc]);
|
], [colors, prefixID, describeFunc]);
|
||||||
|
|
||||||
const size = useMemo(() => (`${0.125 + 1.94*rows}rem`), [rows]);
|
const size = useMemo(() => (`calc(2px + (2px + 1.8rem)*${rows})`), [rows]);
|
||||||
|
|
||||||
const conditionalRowStyles = useMemo(
|
const conditionalRowStyles = useMemo(
|
||||||
(): IConditionalStyle<IConstituenta>[] => [{
|
(): IConditionalStyle<IConstituenta>[] => [{
|
||||||
|
|
|
@ -158,7 +158,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Подставить значение аргумента'
|
tooltip='Подставить значение аргумента'
|
||||||
icon={<CheckIcon
|
icon={<CheckIcon
|
||||||
size={6}
|
size={5}
|
||||||
color={!argumentValue || !selectedArgument ? 'text-disabled' : 'text-success'}
|
color={!argumentValue || !selectedArgument ? 'text-disabled' : 'text-success'}
|
||||||
/>}
|
/>}
|
||||||
disabled={!argumentValue || !selectedArgument}
|
disabled={!argumentValue || !selectedArgument}
|
||||||
|
@ -177,6 +177,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
<RSInput id='result'
|
<RSInput id='result'
|
||||||
placeholder='Итоговое определение'
|
placeholder='Итоговое определение'
|
||||||
height='5.1rem'
|
height='5.1rem'
|
||||||
|
dimensions='w-full mt-[0.45rem]'
|
||||||
value={state.definition}
|
value={state.definition}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -86,35 +86,37 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-3'>
|
<div className='flex flex-col gap-3'>
|
||||||
<div className='flex justify-between gap-3'>
|
<div>
|
||||||
<SelectSingle
|
<div className='flex justify-between gap-6'>
|
||||||
className='w-full'
|
<SelectSingle
|
||||||
options={categorySelector}
|
className='w-full'
|
||||||
placeholder='Выберите категорию'
|
options={categorySelector}
|
||||||
value={state.filterCategory && selectedSchema ? {
|
placeholder='Выберите категорию'
|
||||||
value: state.filterCategory.id,
|
value={state.filterCategory && selectedSchema ? {
|
||||||
label: state.filterCategory.term_raw
|
value: state.filterCategory.id,
|
||||||
} : null}
|
label: state.filterCategory.term_raw
|
||||||
onChange={data => partialUpdate({filterCategory: selectedSchema?.items.find(cst => cst.id === data?.value) })}
|
} : null}
|
||||||
isClearable
|
onChange={data => partialUpdate({filterCategory: selectedSchema?.items.find(cst => cst.id === data?.value) })}
|
||||||
/>
|
isClearable
|
||||||
<SelectSingle
|
/>
|
||||||
className='min-w-[15rem]'
|
<SelectSingle
|
||||||
options={templateSelector}
|
className='min-w-[15rem]'
|
||||||
placeholder='Выберите источник'
|
options={templateSelector}
|
||||||
value={state.templateID ? { value: state.templateID, label: templates.find(item => item.id == state.templateID)!.title }: null}
|
placeholder='Выберите источник'
|
||||||
onChange={data => partialUpdate({templateID: (data ? data.value : undefined)})}
|
value={state.templateID ? { value: state.templateID, label: templates.find(item => item.id == state.templateID)!.title }: null}
|
||||||
|
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>
|
||||||
<ConstituentaPicker
|
|
||||||
value={state.prototype}
|
|
||||||
data={filteredData}
|
|
||||||
onSelectValue={cst => partialUpdate( { prototype: cst } )}
|
|
||||||
prefixID={prefixes.cst_template_ist}
|
|
||||||
rows={9}
|
|
||||||
/>
|
|
||||||
<TextArea id='term'
|
<TextArea id='term'
|
||||||
rows={1}
|
rows={2}
|
||||||
disabled
|
disabled
|
||||||
placeholder='Шаблон конституенты не выбран'
|
placeholder='Шаблон конституенты не выбран'
|
||||||
value={prototypeInfo}
|
value={prototypeInfo}
|
||||||
|
|
|
@ -239,9 +239,13 @@ function EditorConstituenta({
|
||||||
/>
|
/>
|
||||||
<TextArea id='typification' label='Типизация'
|
<TextArea id='typification' label='Типизация'
|
||||||
dense noBorder
|
dense noBorder
|
||||||
rows={1}
|
rows={typification.length > 70 ? 2 : 1}
|
||||||
value={typification}
|
value={typification}
|
||||||
colors='clr-app'
|
colors='clr-app'
|
||||||
|
dimensions='w-full'
|
||||||
|
style={{
|
||||||
|
resize: 'none'
|
||||||
|
}}
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<EditorRSExpression id='expression' label='Формальное определение'
|
<EditorRSExpression id='expression' label='Формальное определение'
|
||||||
|
@ -265,7 +269,6 @@ function EditorConstituenta({
|
||||||
/>
|
/>
|
||||||
<TextArea id='convention' label='Конвенция / Комментарий'
|
<TextArea id='convention' label='Конвенция / Комментарий'
|
||||||
placeholder='Договоренность об интерпретации или пояснение'
|
placeholder='Договоренность об интерпретации или пояснение'
|
||||||
rows={2}
|
|
||||||
value={convention}
|
value={convention}
|
||||||
disabled={!isEnabled}
|
disabled={!isEnabled}
|
||||||
spellCheck
|
spellCheck
|
||||||
|
|
|
@ -130,7 +130,7 @@ function EditorRSExpression({
|
||||||
</div>
|
</div>
|
||||||
<RSInput innerref={rsInput}
|
<RSInput innerref={rsInput}
|
||||||
value={value}
|
value={value}
|
||||||
minHeight='3.5rem'
|
minHeight='3.8rem'
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -139,12 +139,12 @@ function EditorRSExpression({
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onEdit={handleEdit}
|
onEdit={handleEdit}
|
||||||
/>
|
/>
|
||||||
<div className='w-full max-h-[5rem] min-h-[5rem] flex'>
|
<div className='w-full max-h-[4.5rem] min-h-[4.5rem] flex'>
|
||||||
<div className='flex flex-col'>
|
<div className='flex flex-col text-sm'>
|
||||||
<Button
|
<Button
|
||||||
tooltip='Проверить формальное определение'
|
tooltip='Проверить формальное определение'
|
||||||
text='Проверить'
|
text='Проверить'
|
||||||
dimensions='w-fit h-[3rem] z-pop rounded-none'
|
dimensions='w-[6.75rem] min-h-[3rem] z-pop rounded-none'
|
||||||
colors='clr-btn-default'
|
colors='clr-btn-default'
|
||||||
noOutline
|
noOutline
|
||||||
onClick={() => handleCheckExpression()}
|
onClick={() => handleCheckExpression()}
|
||||||
|
|
|
@ -97,6 +97,12 @@ function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified,
|
||||||
<div tabIndex={-1} onKeyDown={handleInput}>
|
<div tabIndex={-1} onKeyDown={handleInput}>
|
||||||
<div className='relative flex items-start justify-center w-full'>
|
<div className='relative flex items-start justify-center w-full'>
|
||||||
<div className='absolute flex mt-1'>
|
<div className='absolute flex mt-1'>
|
||||||
|
<MiniButton
|
||||||
|
tooltip='Сохранить изменения'
|
||||||
|
disabled={!isModified || !isEditable}
|
||||||
|
icon={<SaveIcon size={5} color={isModified && isEditable ? 'text-primary' : ''}/>}
|
||||||
|
onClick={() => handleSubmit()}
|
||||||
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
tooltip='Поделиться схемой'
|
tooltip='Поделиться схемой'
|
||||||
icon={<ShareIcon size={5} color='text-primary'/>}
|
icon={<ShareIcon size={5} color='text-primary'/>}
|
||||||
|
@ -165,14 +171,15 @@ function EditorRSForm({ onDestroy, onClaim, onShare, isModified, setIsModified,
|
||||||
setValue={value => setCanonical(value)}
|
setValue={value => setCanonical(value)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className='flex justify-center w-full'>
|
||||||
<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'
|
dimensions='my-2 w-fit'
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className='flex flex-col gap-1'>
|
<div className='flex flex-col gap-1'>
|
||||||
<div className='flex justify-start'>
|
<div className='flex justify-start'>
|
||||||
|
|
|
@ -394,7 +394,6 @@ function RSTabs() {
|
||||||
onClaim={onClaimSchema}
|
onClaim={onClaimSchema}
|
||||||
onShare={onShareSchema}
|
onShare={onShareSchema}
|
||||||
onToggleSubscribe={handleToggleSubscribe}
|
onToggleSubscribe={handleToggleSubscribe}
|
||||||
onTemplates={onShowTemplates}
|
|
||||||
showCloneDialog={promptClone}
|
showCloneDialog={promptClone}
|
||||||
showUploadDialog={() => setShowUpload(true)}
|
showUploadDialog={() => setShowUpload(true)}
|
||||||
/>
|
/>
|
||||||
|
@ -402,13 +401,13 @@ function RSTabs() {
|
||||||
className='border-x-2'
|
className='border-x-2'
|
||||||
tooltip={`Название схемы: ${schema.title ?? ''}`}
|
tooltip={`Название схемы: ${schema.title ?? ''}`}
|
||||||
>
|
>
|
||||||
Паспорт схемы
|
Карточка
|
||||||
</ConceptTab>
|
</ConceptTab>
|
||||||
<ConceptTab
|
<ConceptTab
|
||||||
className='border-r-2'
|
className='border-r-2'
|
||||||
tooltip={`Всего конституент: ${schema.stats?.count_all ?? 0}\nКоличество ошибок: ${schema.stats?.count_errors ?? 0}`}
|
tooltip={`Всего конституент: ${schema.stats?.count_all ?? 0}\nКоличество ошибок: ${schema.stats?.count_errors ?? 0}`}
|
||||||
>
|
>
|
||||||
Конституенты
|
Содержание
|
||||||
</ConceptTab>
|
</ConceptTab>
|
||||||
<ConceptTab className='border-r-2'>
|
<ConceptTab className='border-r-2'>
|
||||||
Редактор
|
Редактор
|
||||||
|
|
|
@ -12,7 +12,7 @@ function ParsingResult({ data, onShowError }: ParsingResultProps) {
|
||||||
const warningsCount = data.errors.length - errorCount;
|
const warningsCount = data.errors.length - errorCount;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='px-3 py-2'>
|
<div className='px-2 py-1'>
|
||||||
<p>Ошибок: <b>{errorCount}</b> | Предупреждений: <b>{warningsCount}</b></p>
|
<p>Ошибок: <b>{errorCount}</b> | Предупреждений: <b>{warningsCount}</b></p>
|
||||||
{data.errors.map((error, index) => {
|
{data.errors.map((error, index) => {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -81,7 +81,7 @@ function RSFormStats({ stats }: RSFormStatsProps) {
|
||||||
/>}
|
/>}
|
||||||
{ stats.count_theorem > 0 &&
|
{ stats.count_theorem > 0 &&
|
||||||
<LabeledText id='count_theorem'
|
<LabeledText id='count_theorem'
|
||||||
label='Теормы '
|
label='Теоремы '
|
||||||
text={stats.count_theorem}
|
text={stats.count_theorem}
|
||||||
/>}
|
/>}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Dropdown from '../../../components/Common/Dropdown';
|
||||||
import DropdownButton from '../../../components/Common/DropdownButton';
|
import DropdownButton from '../../../components/Common/DropdownButton';
|
||||||
import DropdownCheckbox from '../../../components/Common/DropdownCheckbox';
|
import DropdownCheckbox from '../../../components/Common/DropdownCheckbox';
|
||||||
import {
|
import {
|
||||||
CloneIcon, DiamondIcon, DownloadIcon, DumpBinIcon, EditIcon, MenuIcon, NotSubscribedIcon,
|
CloneIcon, DownloadIcon, DumpBinIcon, EditIcon, MenuIcon, NotSubscribedIcon,
|
||||||
OwnerIcon, ShareIcon, SmallPlusIcon, SubscribedIcon, UploadIcon
|
OwnerIcon, ShareIcon, SmallPlusIcon, SubscribedIcon, UploadIcon
|
||||||
} from '../../../components/Icons';
|
} from '../../../components/Icons';
|
||||||
import { useAuth } from '../../../context/AuthContext';
|
import { useAuth } from '../../../context/AuthContext';
|
||||||
|
@ -20,12 +20,11 @@ interface RSTabsMenuProps {
|
||||||
onShare: () => void
|
onShare: () => void
|
||||||
onDownload: () => void
|
onDownload: () => void
|
||||||
onToggleSubscribe: () => void
|
onToggleSubscribe: () => void
|
||||||
onTemplates: () => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function RSTabsMenu({
|
function RSTabsMenu({
|
||||||
showUploadDialog, showCloneDialog,
|
showUploadDialog, showCloneDialog,
|
||||||
onDestroy, onShare, onDownload, onClaim, onToggleSubscribe, onTemplates
|
onDestroy, onShare, onDownload, onClaim, onToggleSubscribe
|
||||||
}: RSTabsMenuProps) {
|
}: RSTabsMenuProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
@ -45,11 +44,6 @@ function RSTabsMenu({
|
||||||
schemaMenu.hide();
|
schemaMenu.hide();
|
||||||
onDestroy();
|
onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleTemplates() {
|
|
||||||
schemaMenu.hide();
|
|
||||||
onTemplates();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleDownload () {
|
function handleDownload () {
|
||||||
schemaMenu.hide();
|
schemaMenu.hide();
|
||||||
|
@ -102,12 +96,6 @@ function RSTabsMenu({
|
||||||
<p>Клонировать</p>
|
<p>Клонировать</p>
|
||||||
</div>
|
</div>
|
||||||
</DropdownButton>
|
</DropdownButton>
|
||||||
<DropdownButton onClick={handleTemplates} disabled={!isEditable} >
|
|
||||||
<div className='inline-flex items-center justify-start gap-2'>
|
|
||||||
<DiamondIcon color={isEditable ? 'text-success' : ''} size={4}/>
|
|
||||||
<p>Банк выражений</p>
|
|
||||||
</div>
|
|
||||||
</DropdownButton>
|
|
||||||
<DropdownButton onClick={handleDownload}>
|
<DropdownButton onClick={handleDownload}>
|
||||||
<div className='inline-flex items-center justify-start gap-2'>
|
<div className='inline-flex items-center justify-start gap-2'>
|
||||||
<DownloadIcon color='text-primary' size={4}/>
|
<DownloadIcon color='text-primary' size={4}/>
|
||||||
|
@ -150,7 +138,7 @@ function RSTabsMenu({
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
disabled={!user || !isClaimable}
|
disabled={!user || !isClaimable}
|
||||||
onClick={!isOwned ? handleClaimOwner : undefined}
|
onClick={!isOwned ? handleClaimOwner : undefined}
|
||||||
tooltip={!user || !isClaimable ? 'Стать владельцем можно только для общей изменяемой схемы' : ''}
|
tooltip={!user || !isClaimable ? 'Взять во владение можно общую изменяемую схему' : ''}
|
||||||
>
|
>
|
||||||
<div className='flex items-center gap-2 pl-1'>
|
<div className='flex items-center gap-2 pl-1'>
|
||||||
<span><OwnerIcon size={5} color={isOwned ? 'text-success' : 'text-controls'} /></span>
|
<span><OwnerIcon size={5} color={isOwned ? 'text-success' : 'text-controls'} /></span>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user